pkt-line.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. "use strict";
  2. var bodec = require('bodec');
  3. var PACK = bodec.fromRaw("PACK");
  4. module.exports = {
  5. deframer: deframer,
  6. framer: framer
  7. };
  8. function deframer(emit) {
  9. var state = 0;
  10. var offset = 4;
  11. var length = 0;
  12. var data;
  13. var more = true;
  14. return function (item) {
  15. // Forward the EOS marker
  16. if (item === undefined) return emit();
  17. // Once we're in pack mode, everything goes straight through
  18. if (state === 3) return emit(item);
  19. // Otherwise parse the data using a state machine.
  20. for (var i = 0, l = item.length; i < l; i++) {
  21. var byte = item[i];
  22. if (state === 0) {
  23. var val = fromHexChar(byte);
  24. if (val === -1) {
  25. if (byte === PACK[0]) {
  26. offset = 1;
  27. state = 2;
  28. continue;
  29. }
  30. state = -1;
  31. throw new SyntaxError("Not a hex char: " + String.fromCharCode(byte));
  32. }
  33. length |= val << ((--offset) * 4);
  34. if (offset === 0) {
  35. if (length === 4) {
  36. offset = 4;
  37. more = emit("");
  38. }
  39. else if (length === 0) {
  40. offset = 4;
  41. more = emit(null);
  42. }
  43. else if (length > 4) {
  44. length -= 4;
  45. data = bodec.create(length);
  46. state = 1;
  47. }
  48. else {
  49. state = -1;
  50. throw new SyntaxError("Invalid length: " + length);
  51. }
  52. }
  53. }
  54. else if (state === 1) {
  55. data[offset++] = byte;
  56. if (offset === length) {
  57. offset = 4;
  58. state = 0;
  59. length = 0;
  60. if (data[0] === 1) {
  61. more = emit(bodec.slice(data, 1));
  62. }
  63. else if (data[0] === 2) {
  64. more = emit({progress: bodec.toUnicode(data, 1)});
  65. }
  66. else if (data[0] === 3) {
  67. more = emit({error: bodec.toUnicode(data, 1)});
  68. }
  69. else {
  70. more = emit(bodec.toUnicode(data).trim());
  71. }
  72. }
  73. }
  74. else if (state === 2) {
  75. if (offset < 4 && byte === PACK[offset++]) {
  76. continue;
  77. }
  78. state = 3;
  79. more = emit(bodec.join([PACK, bodec.subarray(item, i)]));
  80. break;
  81. }
  82. else {
  83. throw new Error("pkt-line decoder in invalid state");
  84. }
  85. }
  86. return more;
  87. };
  88. }
  89. function framer(emit) {
  90. return function (item) {
  91. if (item === undefined) return emit();
  92. if (item === null) {
  93. return emit(bodec.fromRaw("0000"));
  94. }
  95. if (typeof item === "string") {
  96. item = bodec.fromUnicode(item);
  97. }
  98. return emit(bodec.join([frameHead(item.length + 4), item]));
  99. };
  100. }
  101. function frameHead(length) {
  102. var buffer = bodec.create(4);
  103. buffer[0] = toHexChar(length >>> 12);
  104. buffer[1] = toHexChar((length >>> 8) & 0xf);
  105. buffer[2] = toHexChar((length >>> 4) & 0xf);
  106. buffer[3] = toHexChar(length & 0xf);
  107. return buffer;
  108. }
  109. function fromHexChar(val) {
  110. return (val >= 0x30 && val < 0x40) ? val - 0x30 :
  111. ((val > 0x60 && val <= 0x66) ? val - 0x57 : -1);
  112. }
  113. function toHexChar(val) {
  114. return val < 0x0a ? val + 0x30 : val + 0x57;
  115. }