You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

binary-parser.js 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. "use strict";
  2. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  3. if (k2 === undefined) k2 = k;
  4. var desc = Object.getOwnPropertyDescriptor(m, k);
  5. if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
  6. desc = { enumerable: true, get: function() { return m[k]; } };
  7. }
  8. Object.defineProperty(o, k2, desc);
  9. }) : (function(o, m, k, k2) {
  10. if (k2 === undefined) k2 = k;
  11. o[k2] = m[k];
  12. }));
  13. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  14. Object.defineProperty(o, "default", { enumerable: true, value: v });
  15. }) : function(o, v) {
  16. o["default"] = v;
  17. });
  18. var __importStar = (this && this.__importStar) || function (mod) {
  19. if (mod && mod.__esModule) return mod;
  20. var result = {};
  21. if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  22. __setModuleDefault(result, mod);
  23. return result;
  24. };
  25. Object.defineProperty(exports, "__esModule", { value: true });
  26. exports.BinaryParser = void 0;
  27. const assert = __importStar(require("assert"));
  28. const enums_1 = require("../enums");
  29. const buffer_1 = require("buffer/");
  30. /**
  31. * BinaryParser is used to compute fields and values from a HexString
  32. */
  33. class BinaryParser {
  34. /**
  35. * Initialize bytes to a hex string
  36. *
  37. * @param hexBytes a hex string
  38. */
  39. constructor(hexBytes) {
  40. this.bytes = buffer_1.Buffer.from(hexBytes, 'hex');
  41. }
  42. /**
  43. * Peek the first byte of the BinaryParser
  44. *
  45. * @returns The first byte of the BinaryParser
  46. */
  47. peek() {
  48. assert.ok(this.bytes.byteLength !== 0);
  49. return this.bytes[0];
  50. }
  51. /**
  52. * Consume the first n bytes of the BinaryParser
  53. *
  54. * @param n the number of bytes to skip
  55. */
  56. skip(n) {
  57. assert.ok(n <= this.bytes.byteLength);
  58. this.bytes = this.bytes.slice(n);
  59. }
  60. /**
  61. * read the first n bytes from the BinaryParser
  62. *
  63. * @param n The number of bytes to read
  64. * @return The bytes
  65. */
  66. read(n) {
  67. assert.ok(n <= this.bytes.byteLength);
  68. const slice = this.bytes.slice(0, n);
  69. this.skip(n);
  70. return slice;
  71. }
  72. /**
  73. * Read an integer of given size
  74. *
  75. * @param n The number of bytes to read
  76. * @return The number represented by those bytes
  77. */
  78. readUIntN(n) {
  79. assert.ok(0 < n && n <= 4, 'invalid n');
  80. return this.read(n).reduce((a, b) => (a << 8) | b) >>> 0;
  81. }
  82. readUInt8() {
  83. return this.readUIntN(1);
  84. }
  85. readUInt16() {
  86. return this.readUIntN(2);
  87. }
  88. readUInt32() {
  89. return this.readUIntN(4);
  90. }
  91. size() {
  92. return this.bytes.byteLength;
  93. }
  94. end(customEnd) {
  95. const length = this.bytes.byteLength;
  96. return length === 0 || (customEnd !== undefined && length <= customEnd);
  97. }
  98. /**
  99. * Reads variable length encoded bytes
  100. *
  101. * @return The variable length bytes
  102. */
  103. readVariableLength() {
  104. return this.read(this.readVariableLengthLength());
  105. }
  106. /**
  107. * Reads the length of the variable length encoded bytes
  108. *
  109. * @return The length of the variable length encoded bytes
  110. */
  111. readVariableLengthLength() {
  112. const b1 = this.readUInt8();
  113. if (b1 <= 192) {
  114. return b1;
  115. }
  116. else if (b1 <= 240) {
  117. const b2 = this.readUInt8();
  118. return 193 + (b1 - 193) * 256 + b2;
  119. }
  120. else if (b1 <= 254) {
  121. const b2 = this.readUInt8();
  122. const b3 = this.readUInt8();
  123. return 12481 + (b1 - 241) * 65536 + b2 * 256 + b3;
  124. }
  125. throw new Error('Invalid variable length indicator');
  126. }
  127. /**
  128. * Reads the field ordinal from the BinaryParser
  129. *
  130. * @return Field ordinal
  131. */
  132. readFieldOrdinal() {
  133. let type = this.readUInt8();
  134. let nth = type & 15;
  135. type >>= 4;
  136. if (type === 0) {
  137. type = this.readUInt8();
  138. if (type === 0 || type < 16) {
  139. throw new Error('Cannot read FieldOrdinal, type_code out of range');
  140. }
  141. }
  142. if (nth === 0) {
  143. nth = this.readUInt8();
  144. if (nth === 0 || nth < 16) {
  145. throw new Error('Cannot read FieldOrdinal, field_code out of range');
  146. }
  147. }
  148. return (type << 16) | nth;
  149. }
  150. /**
  151. * Read the field from the BinaryParser
  152. *
  153. * @return The field represented by the bytes at the head of the BinaryParser
  154. */
  155. readField() {
  156. return enums_1.Field.fromString(this.readFieldOrdinal().toString());
  157. }
  158. /**
  159. * Read a given type from the BinaryParser
  160. *
  161. * @param type The type that you want to read from the BinaryParser
  162. * @return The instance of that type read from the BinaryParser
  163. */
  164. readType(type) {
  165. return type.fromParser(this);
  166. }
  167. /**
  168. * Get the type associated with a given field
  169. *
  170. * @param field The field that you wan to get the type of
  171. * @return The type associated with the given field
  172. */
  173. typeForField(field) {
  174. return field.associatedType;
  175. }
  176. /**
  177. * Read value of the type specified by field from the BinaryParser
  178. *
  179. * @param field The field that you want to get the associated value for
  180. * @return The value associated with the given field
  181. */
  182. readFieldValue(field) {
  183. const type = this.typeForField(field);
  184. if (!type) {
  185. throw new Error(`unsupported: (${field.name}, ${field.type.name})`);
  186. }
  187. const sizeHint = field.isVariableLengthEncoded
  188. ? this.readVariableLengthLength()
  189. : undefined;
  190. const value = type.fromParser(this, sizeHint);
  191. if (value === undefined) {
  192. throw new Error(`fromParser for (${field.name}, ${field.type.name}) -> undefined `);
  193. }
  194. return value;
  195. }
  196. /**
  197. * Get the next field and value from the BinaryParser
  198. *
  199. * @return The field and value
  200. */
  201. readFieldAndValue() {
  202. const field = this.readField();
  203. return [field, this.readFieldValue(field)];
  204. }
  205. }
  206. exports.BinaryParser = BinaryParser;
  207. //# sourceMappingURL=binary-parser.js.map