reader.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416
  1. "use strict";
  2. module.exports = Reader;
  3. var util = require("./util/minimal");
  4. var BufferReader; // cyclic
  5. var LongBits = util.LongBits,
  6. utf8 = util.utf8;
  7. /* istanbul ignore next */
  8. function indexOutOfRange(reader, writeLength) {
  9. return RangeError("index out of range: " + reader.pos + " + " + (writeLength || 1) + " > " + reader.len);
  10. }
  11. /**
  12. * Constructs a new reader instance using the specified buffer.
  13. * @classdesc Wire format reader using `Uint8Array` if available, otherwise `Array`.
  14. * @constructor
  15. * @param {Uint8Array} buffer Buffer to read from
  16. */
  17. function Reader(buffer) {
  18. /**
  19. * Read buffer.
  20. * @type {Uint8Array}
  21. */
  22. this.buf = buffer;
  23. /**
  24. * Read buffer position.
  25. * @type {number}
  26. */
  27. this.pos = 0;
  28. /**
  29. * Read buffer length.
  30. * @type {number}
  31. */
  32. this.len = buffer.length;
  33. }
  34. var create_array = typeof Uint8Array !== "undefined"
  35. ? function create_typed_array(buffer) {
  36. if (buffer instanceof Uint8Array || Array.isArray(buffer))
  37. return new Reader(buffer);
  38. throw Error("illegal buffer");
  39. }
  40. /* istanbul ignore next */
  41. : function create_array(buffer) {
  42. if (Array.isArray(buffer))
  43. return new Reader(buffer);
  44. throw Error("illegal buffer");
  45. };
  46. var create = function create() {
  47. return util.Buffer
  48. ? function create_buffer_setup(buffer) {
  49. return (Reader.create = function create_buffer(buffer) {
  50. return util.Buffer.isBuffer(buffer)
  51. ? new BufferReader(buffer)
  52. /* istanbul ignore next */
  53. : create_array(buffer);
  54. })(buffer);
  55. }
  56. /* istanbul ignore next */
  57. : create_array;
  58. };
  59. /**
  60. * Creates a new reader using the specified buffer.
  61. * @function
  62. * @param {Uint8Array|Buffer} buffer Buffer to read from
  63. * @returns {Reader|BufferReader} A {@link BufferReader} if `buffer` is a Buffer, otherwise a {@link Reader}
  64. * @throws {Error} If `buffer` is not a valid buffer
  65. */
  66. Reader.create = create();
  67. Reader.prototype._slice = util.Array.prototype.subarray || /* istanbul ignore next */ util.Array.prototype.slice;
  68. /**
  69. * Reads a varint as an unsigned 32 bit value.
  70. * @function
  71. * @returns {number} Value read
  72. */
  73. Reader.prototype.uint32 = (function read_uint32_setup() {
  74. var value = 4294967295; // optimizer type-hint, tends to deopt otherwise (?!)
  75. return function read_uint32() {
  76. value = ( this.buf[this.pos] & 127 ) >>> 0; if (this.buf[this.pos++] < 128) return value;
  77. value = (value | (this.buf[this.pos] & 127) << 7) >>> 0; if (this.buf[this.pos++] < 128) return value;
  78. value = (value | (this.buf[this.pos] & 127) << 14) >>> 0; if (this.buf[this.pos++] < 128) return value;
  79. value = (value | (this.buf[this.pos] & 127) << 21) >>> 0; if (this.buf[this.pos++] < 128) return value;
  80. value = (value | (this.buf[this.pos] & 15) << 28) >>> 0; if (this.buf[this.pos++] < 128) return value;
  81. /* istanbul ignore if */
  82. if ((this.pos += 5) > this.len) {
  83. this.pos = this.len;
  84. throw indexOutOfRange(this, 10);
  85. }
  86. return value;
  87. };
  88. })();
  89. /**
  90. * Reads a varint as a signed 32 bit value.
  91. * @returns {number} Value read
  92. */
  93. Reader.prototype.int32 = function read_int32() {
  94. return this.uint32() | 0;
  95. };
  96. /**
  97. * Reads a zig-zag encoded varint as a signed 32 bit value.
  98. * @returns {number} Value read
  99. */
  100. Reader.prototype.sint32 = function read_sint32() {
  101. var value = this.uint32();
  102. return value >>> 1 ^ -(value & 1) | 0;
  103. };
  104. /* eslint-disable no-invalid-this */
  105. function readLongVarint() {
  106. // tends to deopt with local vars for octet etc.
  107. var bits = new LongBits(0, 0);
  108. var i = 0;
  109. if (this.len - this.pos > 4) { // fast route (lo)
  110. for (; i < 4; ++i) {
  111. // 1st..4th
  112. bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0;
  113. if (this.buf[this.pos++] < 128)
  114. return bits;
  115. }
  116. // 5th
  117. bits.lo = (bits.lo | (this.buf[this.pos] & 127) << 28) >>> 0;
  118. bits.hi = (bits.hi | (this.buf[this.pos] & 127) >> 4) >>> 0;
  119. if (this.buf[this.pos++] < 128)
  120. return bits;
  121. i = 0;
  122. } else {
  123. for (; i < 3; ++i) {
  124. /* istanbul ignore if */
  125. if (this.pos >= this.len)
  126. throw indexOutOfRange(this);
  127. // 1st..3th
  128. bits.lo = (bits.lo | (this.buf[this.pos] & 127) << i * 7) >>> 0;
  129. if (this.buf[this.pos++] < 128)
  130. return bits;
  131. }
  132. // 4th
  133. bits.lo = (bits.lo | (this.buf[this.pos++] & 127) << i * 7) >>> 0;
  134. return bits;
  135. }
  136. if (this.len - this.pos > 4) { // fast route (hi)
  137. for (; i < 5; ++i) {
  138. // 6th..10th
  139. bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0;
  140. if (this.buf[this.pos++] < 128)
  141. return bits;
  142. }
  143. } else {
  144. for (; i < 5; ++i) {
  145. /* istanbul ignore if */
  146. if (this.pos >= this.len)
  147. throw indexOutOfRange(this);
  148. // 6th..10th
  149. bits.hi = (bits.hi | (this.buf[this.pos] & 127) << i * 7 + 3) >>> 0;
  150. if (this.buf[this.pos++] < 128)
  151. return bits;
  152. }
  153. }
  154. /* istanbul ignore next */
  155. throw Error("invalid varint encoding");
  156. }
  157. /* eslint-enable no-invalid-this */
  158. /**
  159. * Reads a varint as a signed 64 bit value.
  160. * @name Reader#int64
  161. * @function
  162. * @returns {Long} Value read
  163. */
  164. /**
  165. * Reads a varint as an unsigned 64 bit value.
  166. * @name Reader#uint64
  167. * @function
  168. * @returns {Long} Value read
  169. */
  170. /**
  171. * Reads a zig-zag encoded varint as a signed 64 bit value.
  172. * @name Reader#sint64
  173. * @function
  174. * @returns {Long} Value read
  175. */
  176. /**
  177. * Reads a varint as a boolean.
  178. * @returns {boolean} Value read
  179. */
  180. Reader.prototype.bool = function read_bool() {
  181. return this.uint32() !== 0;
  182. };
  183. function readFixed32_end(buf, end) { // note that this uses `end`, not `pos`
  184. return (buf[end - 4]
  185. | buf[end - 3] << 8
  186. | buf[end - 2] << 16
  187. | buf[end - 1] << 24) >>> 0;
  188. }
  189. /**
  190. * Reads fixed 32 bits as an unsigned 32 bit integer.
  191. * @returns {number} Value read
  192. */
  193. Reader.prototype.fixed32 = function read_fixed32() {
  194. /* istanbul ignore if */
  195. if (this.pos + 4 > this.len)
  196. throw indexOutOfRange(this, 4);
  197. return readFixed32_end(this.buf, this.pos += 4);
  198. };
  199. /**
  200. * Reads fixed 32 bits as a signed 32 bit integer.
  201. * @returns {number} Value read
  202. */
  203. Reader.prototype.sfixed32 = function read_sfixed32() {
  204. /* istanbul ignore if */
  205. if (this.pos + 4 > this.len)
  206. throw indexOutOfRange(this, 4);
  207. return readFixed32_end(this.buf, this.pos += 4) | 0;
  208. };
  209. /* eslint-disable no-invalid-this */
  210. function readFixed64(/* this: Reader */) {
  211. /* istanbul ignore if */
  212. if (this.pos + 8 > this.len)
  213. throw indexOutOfRange(this, 8);
  214. return new LongBits(readFixed32_end(this.buf, this.pos += 4), readFixed32_end(this.buf, this.pos += 4));
  215. }
  216. /* eslint-enable no-invalid-this */
  217. /**
  218. * Reads fixed 64 bits.
  219. * @name Reader#fixed64
  220. * @function
  221. * @returns {Long} Value read
  222. */
  223. /**
  224. * Reads zig-zag encoded fixed 64 bits.
  225. * @name Reader#sfixed64
  226. * @function
  227. * @returns {Long} Value read
  228. */
  229. /**
  230. * Reads a float (32 bit) as a number.
  231. * @function
  232. * @returns {number} Value read
  233. */
  234. Reader.prototype.float = function read_float() {
  235. /* istanbul ignore if */
  236. if (this.pos + 4 > this.len)
  237. throw indexOutOfRange(this, 4);
  238. var value = util.float.readFloatLE(this.buf, this.pos);
  239. this.pos += 4;
  240. return value;
  241. };
  242. /**
  243. * Reads a double (64 bit float) as a number.
  244. * @function
  245. * @returns {number} Value read
  246. */
  247. Reader.prototype.double = function read_double() {
  248. /* istanbul ignore if */
  249. if (this.pos + 8 > this.len)
  250. throw indexOutOfRange(this, 4);
  251. var value = util.float.readDoubleLE(this.buf, this.pos);
  252. this.pos += 8;
  253. return value;
  254. };
  255. /**
  256. * Reads a sequence of bytes preceeded by its length as a varint.
  257. * @returns {Uint8Array} Value read
  258. */
  259. Reader.prototype.bytes = function read_bytes() {
  260. var length = this.uint32(),
  261. start = this.pos,
  262. end = this.pos + length;
  263. /* istanbul ignore if */
  264. if (end > this.len)
  265. throw indexOutOfRange(this, length);
  266. this.pos += length;
  267. if (Array.isArray(this.buf)) // plain array
  268. return this.buf.slice(start, end);
  269. if (start === end) { // fix for IE 10/Win8 and others' subarray returning array of size 1
  270. var nativeBuffer = util.Buffer;
  271. return nativeBuffer
  272. ? nativeBuffer.alloc(0)
  273. : new this.buf.constructor(0);
  274. }
  275. return this._slice.call(this.buf, start, end);
  276. };
  277. /**
  278. * Reads a string preceeded by its byte length as a varint.
  279. * @returns {string} Value read
  280. */
  281. Reader.prototype.string = function read_string() {
  282. var bytes = this.bytes();
  283. return utf8.read(bytes, 0, bytes.length);
  284. };
  285. /**
  286. * Skips the specified number of bytes if specified, otherwise skips a varint.
  287. * @param {number} [length] Length if known, otherwise a varint is assumed
  288. * @returns {Reader} `this`
  289. */
  290. Reader.prototype.skip = function skip(length) {
  291. if (typeof length === "number") {
  292. /* istanbul ignore if */
  293. if (this.pos + length > this.len)
  294. throw indexOutOfRange(this, length);
  295. this.pos += length;
  296. } else {
  297. do {
  298. /* istanbul ignore if */
  299. if (this.pos >= this.len)
  300. throw indexOutOfRange(this);
  301. } while (this.buf[this.pos++] & 128);
  302. }
  303. return this;
  304. };
  305. /**
  306. * Skips the next element of the specified wire type.
  307. * @param {number} wireType Wire type received
  308. * @returns {Reader} `this`
  309. */
  310. Reader.prototype.skipType = function(wireType) {
  311. switch (wireType) {
  312. case 0:
  313. this.skip();
  314. break;
  315. case 1:
  316. this.skip(8);
  317. break;
  318. case 2:
  319. this.skip(this.uint32());
  320. break;
  321. case 3:
  322. while ((wireType = this.uint32() & 7) !== 4) {
  323. this.skipType(wireType);
  324. }
  325. break;
  326. case 5:
  327. this.skip(4);
  328. break;
  329. /* istanbul ignore next */
  330. default:
  331. throw Error("invalid wire type " + wireType + " at offset " + this.pos);
  332. }
  333. return this;
  334. };
  335. Reader._configure = function(BufferReader_) {
  336. BufferReader = BufferReader_;
  337. Reader.create = create();
  338. BufferReader._configure();
  339. var fn = util.Long ? "toLong" : /* istanbul ignore next */ "toNumber";
  340. util.merge(Reader.prototype, {
  341. int64: function read_int64() {
  342. return readLongVarint.call(this)[fn](false);
  343. },
  344. uint64: function read_uint64() {
  345. return readLongVarint.call(this)[fn](true);
  346. },
  347. sint64: function read_sint64() {
  348. return readLongVarint.call(this).zzDecode()[fn](false);
  349. },
  350. fixed64: function read_fixed64() {
  351. return readFixed64.call(this)[fn](true);
  352. },
  353. sfixed64: function read_sfixed64() {
  354. return readFixed64.call(this)[fn](false);
  355. }
  356. });
  357. };