decoder.js 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // https://developers.google.com/protocol-buffers/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. /**
  31. * @fileoverview This file contains utilities for decoding primitive values
  32. * (signed and unsigned integers, varints, booleans, enums, hashes, strings,
  33. * and raw bytes) embedded in Uint8Arrays into their corresponding Javascript
  34. * types.
  35. *
  36. * Major caveat - Javascript is unable to accurately represent integers larger
  37. * than 2^53 due to its use of a double-precision floating point format or all
  38. * numbers. If you need to guarantee that 64-bit values survive with all bits
  39. * intact, you _must_ read them using one of the Hash64 methods, which return
  40. * an 8-character string.
  41. *
  42. * @suppress {missingRequire} TODO(b/152540451): this shouldn't be needed
  43. * @author aappleby@google.com (Austin Appleby)
  44. */
  45. goog.provide('jspb.BinaryDecoder');
  46. goog.require('goog.asserts');
  47. goog.require('goog.crypt');
  48. goog.require('jspb.utils');
  49. /**
  50. * BinaryDecoder implements the decoders for all the wire types specified in
  51. * https://developers.google.com/protocol-buffers/docs/encoding.
  52. *
  53. * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
  54. * @param {number=} opt_start The optional offset to start reading at.
  55. * @param {number=} opt_length The optional length of the block to read -
  56. * we'll throw an assertion if we go off the end of the block.
  57. * @constructor
  58. * @struct
  59. */
  60. jspb.BinaryDecoder = function(opt_bytes, opt_start, opt_length) {
  61. /**
  62. * Typed byte-wise view of the source buffer.
  63. * @private {?Uint8Array}
  64. */
  65. this.bytes_ = null;
  66. /**
  67. * Start point of the block to read.
  68. * @private {number}
  69. */
  70. this.start_ = 0;
  71. /**
  72. * End point of the block to read.
  73. * @private {number}
  74. */
  75. this.end_ = 0;
  76. /**
  77. * Current read location in bytes_.
  78. * @private {number}
  79. */
  80. this.cursor_ = 0;
  81. /**
  82. * Set to true if this decoder encountered an error due to corrupt data.
  83. * @private {boolean}
  84. */
  85. this.error_ = false;
  86. if (opt_bytes) {
  87. this.setBlock(opt_bytes, opt_start, opt_length);
  88. }
  89. };
  90. /**
  91. * Global pool of BinaryDecoder instances.
  92. * @private {!Array<!jspb.BinaryDecoder>}
  93. */
  94. jspb.BinaryDecoder.instanceCache_ = [];
  95. /**
  96. * Pops an instance off the instance cache, or creates one if the cache is
  97. * empty.
  98. * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
  99. * @param {number=} opt_start The optional offset to start reading at.
  100. * @param {number=} opt_length The optional length of the block to read -
  101. * we'll throw an assertion if we go off the end of the block.
  102. * @return {!jspb.BinaryDecoder}
  103. */
  104. jspb.BinaryDecoder.alloc = function(opt_bytes, opt_start, opt_length) {
  105. if (jspb.BinaryDecoder.instanceCache_.length) {
  106. var newDecoder = jspb.BinaryDecoder.instanceCache_.pop();
  107. if (opt_bytes) {
  108. newDecoder.setBlock(opt_bytes, opt_start, opt_length);
  109. }
  110. return newDecoder;
  111. } else {
  112. return new jspb.BinaryDecoder(opt_bytes, opt_start, opt_length);
  113. }
  114. };
  115. /**
  116. * Puts this instance back in the instance cache.
  117. */
  118. jspb.BinaryDecoder.prototype.free = function() {
  119. this.clear();
  120. if (jspb.BinaryDecoder.instanceCache_.length < 100) {
  121. jspb.BinaryDecoder.instanceCache_.push(this);
  122. }
  123. };
  124. /**
  125. * Makes a copy of this decoder.
  126. * @return {!jspb.BinaryDecoder}
  127. */
  128. jspb.BinaryDecoder.prototype.clone = function() {
  129. return jspb.BinaryDecoder.alloc(this.bytes_,
  130. this.start_, this.end_ - this.start_);
  131. };
  132. /**
  133. * Clears the decoder.
  134. */
  135. jspb.BinaryDecoder.prototype.clear = function() {
  136. this.bytes_ = null;
  137. this.start_ = 0;
  138. this.end_ = 0;
  139. this.cursor_ = 0;
  140. this.error_ = false;
  141. };
  142. /**
  143. * Returns the raw buffer.
  144. * @return {?Uint8Array} The raw buffer.
  145. */
  146. jspb.BinaryDecoder.prototype.getBuffer = function() {
  147. return this.bytes_;
  148. };
  149. /**
  150. * Changes the block of bytes we're decoding.
  151. * @param {!jspb.ByteSource} data The bytes we're reading from.
  152. * @param {number=} opt_start The optional offset to start reading at.
  153. * @param {number=} opt_length The optional length of the block to read -
  154. * we'll throw an assertion if we go off the end of the block.
  155. */
  156. jspb.BinaryDecoder.prototype.setBlock =
  157. function(data, opt_start, opt_length) {
  158. this.bytes_ = jspb.utils.byteSourceToUint8Array(data);
  159. this.start_ = (opt_start !== undefined) ? opt_start : 0;
  160. this.end_ = (opt_length !== undefined) ? this.start_ + opt_length :
  161. this.bytes_.length;
  162. this.cursor_ = this.start_;
  163. };
  164. /**
  165. * @return {number}
  166. */
  167. jspb.BinaryDecoder.prototype.getEnd = function() {
  168. return this.end_;
  169. };
  170. /**
  171. * @param {number} end
  172. */
  173. jspb.BinaryDecoder.prototype.setEnd = function(end) {
  174. this.end_ = end;
  175. };
  176. /**
  177. * Moves the read cursor back to the start of the block.
  178. */
  179. jspb.BinaryDecoder.prototype.reset = function() {
  180. this.cursor_ = this.start_;
  181. };
  182. /**
  183. * Returns the internal read cursor.
  184. * @return {number} The internal read cursor.
  185. */
  186. jspb.BinaryDecoder.prototype.getCursor = function() {
  187. return this.cursor_;
  188. };
  189. /**
  190. * Returns the internal read cursor.
  191. * @param {number} cursor The new cursor.
  192. */
  193. jspb.BinaryDecoder.prototype.setCursor = function(cursor) {
  194. this.cursor_ = cursor;
  195. };
  196. /**
  197. * Advances the stream cursor by the given number of bytes.
  198. * @param {number} count The number of bytes to advance by.
  199. */
  200. jspb.BinaryDecoder.prototype.advance = function(count) {
  201. this.cursor_ += count;
  202. goog.asserts.assert(this.cursor_ <= this.end_);
  203. };
  204. /**
  205. * Returns true if this decoder is at the end of the block.
  206. * @return {boolean}
  207. */
  208. jspb.BinaryDecoder.prototype.atEnd = function() {
  209. return this.cursor_ == this.end_;
  210. };
  211. /**
  212. * Returns true if this decoder is at the end of the block.
  213. * @return {boolean}
  214. */
  215. jspb.BinaryDecoder.prototype.pastEnd = function() {
  216. return this.cursor_ > this.end_;
  217. };
  218. /**
  219. * Returns true if this decoder encountered an error due to corrupt data.
  220. * @return {boolean}
  221. */
  222. jspb.BinaryDecoder.prototype.getError = function() {
  223. return this.error_ ||
  224. (this.cursor_ < 0) ||
  225. (this.cursor_ > this.end_);
  226. };
  227. /**
  228. * Reads an unsigned varint from the binary stream and invokes the conversion
  229. * function with the value in two signed 32 bit integers to produce the result.
  230. * Since this does not convert the value to a number, no precision is lost.
  231. *
  232. * It's possible for an unsigned varint to be incorrectly encoded - more than
  233. * 64 bits' worth of data could be present. If this happens, this method will
  234. * throw an error.
  235. *
  236. * Decoding varints requires doing some funny base-128 math - for more
  237. * details on the format, see
  238. * https://developers.google.com/protocol-buffers/docs/encoding
  239. *
  240. * @param {function(number, number): T} convert Conversion function to produce
  241. * the result value, takes parameters (lowBits, highBits).
  242. * @return {T}
  243. * @template T
  244. */
  245. jspb.BinaryDecoder.prototype.readSplitVarint64 = function(convert) {
  246. var temp = 128;
  247. var lowBits = 0;
  248. var highBits = 0;
  249. // Read the first four bytes of the varint, stopping at the terminator if we
  250. // see it.
  251. for (var i = 0; i < 4 && temp >= 128; i++) {
  252. temp = this.bytes_[this.cursor_++];
  253. lowBits |= (temp & 0x7F) << (i * 7);
  254. }
  255. if (temp >= 128) {
  256. // Read the fifth byte, which straddles the low and high dwords.
  257. temp = this.bytes_[this.cursor_++];
  258. lowBits |= (temp & 0x7F) << 28;
  259. highBits |= (temp & 0x7F) >> 4;
  260. }
  261. if (temp >= 128) {
  262. // Read the sixth through tenth byte.
  263. for (var i = 0; i < 5 && temp >= 128; i++) {
  264. temp = this.bytes_[this.cursor_++];
  265. highBits |= (temp & 0x7F) << (i * 7 + 3);
  266. }
  267. }
  268. if (temp < 128) {
  269. return convert(lowBits >>> 0, highBits >>> 0);
  270. }
  271. // If we did not see the terminator, the encoding was invalid.
  272. goog.asserts.fail('Failed to read varint, encoding is invalid.');
  273. this.error_ = true;
  274. };
  275. /**
  276. * Reads a signed zigzag encoded varint from the binary stream and invokes
  277. * the conversion function with the value in two signed 32 bit integers to
  278. * produce the result. Since this does not convert the value to a number, no
  279. * precision is lost.
  280. *
  281. * It's possible for an unsigned varint to be incorrectly encoded - more than
  282. * 64 bits' worth of data could be present. If this happens, this method will
  283. * throw an error.
  284. *
  285. * Zigzag encoding is a modification of varint encoding that reduces the
  286. * storage overhead for small negative integers - for more details on the
  287. * format, see https://developers.google.com/protocol-buffers/docs/encoding
  288. *
  289. * @param {function(number, number): T} convert Conversion function to produce
  290. * the result value, takes parameters (lowBits, highBits).
  291. * @return {T}
  292. * @template T
  293. */
  294. jspb.BinaryDecoder.prototype.readSplitZigzagVarint64 = function(convert) {
  295. return this.readSplitVarint64(function(low, high) {
  296. return jspb.utils.fromZigzag64(low, high, convert);
  297. });
  298. };
  299. /**
  300. * Reads a 64-bit fixed-width value from the stream and invokes the conversion
  301. * function with the value in two signed 32 bit integers to produce the result.
  302. * Since this does not convert the value to a number, no precision is lost.
  303. *
  304. * @param {function(number, number): T} convert Conversion function to produce
  305. * the result value, takes parameters (lowBits, highBits).
  306. * @return {T}
  307. * @template T
  308. */
  309. jspb.BinaryDecoder.prototype.readSplitFixed64 = function(convert) {
  310. var bytes = this.bytes_;
  311. var cursor = this.cursor_;
  312. this.cursor_ += 8;
  313. var lowBits = 0;
  314. var highBits = 0;
  315. for (var i = cursor + 7; i >= cursor; i--) {
  316. lowBits = (lowBits << 8) | bytes[i];
  317. highBits = (highBits << 8) | bytes[i + 4];
  318. }
  319. return convert(lowBits, highBits);
  320. };
  321. /**
  322. * Skips over a varint in the block without decoding it.
  323. */
  324. jspb.BinaryDecoder.prototype.skipVarint = function() {
  325. while (this.bytes_[this.cursor_] & 0x80) {
  326. this.cursor_++;
  327. }
  328. this.cursor_++;
  329. };
  330. /**
  331. * Skips backwards over a varint in the block - to do this correctly, we have
  332. * to know the value we're skipping backwards over or things are ambiguous.
  333. * @param {number} value The varint value to unskip.
  334. */
  335. jspb.BinaryDecoder.prototype.unskipVarint = function(value) {
  336. while (value > 128) {
  337. this.cursor_--;
  338. value = value >>> 7;
  339. }
  340. this.cursor_--;
  341. };
  342. /**
  343. * Reads a 32-bit varint from the binary stream. Due to a quirk of the encoding
  344. * format and Javascript's handling of bitwise math, this actually works
  345. * correctly for both signed and unsigned 32-bit varints.
  346. *
  347. * This function is called vastly more frequently than any other in
  348. * BinaryDecoder, so it has been unrolled and tweaked for performance.
  349. *
  350. * If there are more than 32 bits of data in the varint, it _must_ be due to
  351. * sign-extension. If we're in debug mode and the high 32 bits don't match the
  352. * expected sign extension, this method will throw an error.
  353. *
  354. * Decoding varints requires doing some funny base-128 math - for more
  355. * details on the format, see
  356. * https://developers.google.com/protocol-buffers/docs/encoding
  357. *
  358. * @return {number} The decoded unsigned 32-bit varint.
  359. */
  360. jspb.BinaryDecoder.prototype.readUnsignedVarint32 = function() {
  361. var temp;
  362. var bytes = this.bytes_;
  363. temp = bytes[this.cursor_ + 0];
  364. var x = (temp & 0x7F);
  365. if (temp < 128) {
  366. this.cursor_ += 1;
  367. goog.asserts.assert(this.cursor_ <= this.end_);
  368. return x;
  369. }
  370. temp = bytes[this.cursor_ + 1];
  371. x |= (temp & 0x7F) << 7;
  372. if (temp < 128) {
  373. this.cursor_ += 2;
  374. goog.asserts.assert(this.cursor_ <= this.end_);
  375. return x;
  376. }
  377. temp = bytes[this.cursor_ + 2];
  378. x |= (temp & 0x7F) << 14;
  379. if (temp < 128) {
  380. this.cursor_ += 3;
  381. goog.asserts.assert(this.cursor_ <= this.end_);
  382. return x;
  383. }
  384. temp = bytes[this.cursor_ + 3];
  385. x |= (temp & 0x7F) << 21;
  386. if (temp < 128) {
  387. this.cursor_ += 4;
  388. goog.asserts.assert(this.cursor_ <= this.end_);
  389. return x;
  390. }
  391. temp = bytes[this.cursor_ + 4];
  392. x |= (temp & 0x0F) << 28;
  393. if (temp < 128) {
  394. // We're reading the high bits of an unsigned varint. The byte we just read
  395. // also contains bits 33 through 35, which we're going to discard.
  396. this.cursor_ += 5;
  397. goog.asserts.assert(this.cursor_ <= this.end_);
  398. return x >>> 0;
  399. }
  400. // If we get here, we need to truncate coming bytes. However we need to make
  401. // sure cursor place is correct.
  402. this.cursor_ += 5;
  403. if (bytes[this.cursor_++] >= 128 &&
  404. bytes[this.cursor_++] >= 128 &&
  405. bytes[this.cursor_++] >= 128 &&
  406. bytes[this.cursor_++] >= 128 &&
  407. bytes[this.cursor_++] >= 128) {
  408. // If we get here, the varint is too long.
  409. goog.asserts.assert(false);
  410. }
  411. goog.asserts.assert(this.cursor_ <= this.end_);
  412. return x;
  413. };
  414. /**
  415. * The readUnsignedVarint32 above deals with signed 32-bit varints correctly,
  416. * so this is just an alias.
  417. *
  418. * @return {number} The decoded signed 32-bit varint.
  419. */
  420. jspb.BinaryDecoder.prototype.readSignedVarint32 =
  421. jspb.BinaryDecoder.prototype.readUnsignedVarint32;
  422. /**
  423. * Reads a 32-bit unsigned variant and returns its value as a string.
  424. *
  425. * @return {string} The decoded unsigned 32-bit varint as a string.
  426. */
  427. jspb.BinaryDecoder.prototype.readUnsignedVarint32String = function() {
  428. // 32-bit integers fit in JavaScript numbers without loss of precision, so
  429. // string variants of 32-bit varint readers can simply delegate then convert
  430. // to string.
  431. var value = this.readUnsignedVarint32();
  432. return value.toString();
  433. };
  434. /**
  435. * Reads a 32-bit signed variant and returns its value as a string.
  436. *
  437. * @return {string} The decoded signed 32-bit varint as a string.
  438. */
  439. jspb.BinaryDecoder.prototype.readSignedVarint32String = function() {
  440. // 32-bit integers fit in JavaScript numbers without loss of precision, so
  441. // string variants of 32-bit varint readers can simply delegate then convert
  442. // to string.
  443. var value = this.readSignedVarint32();
  444. return value.toString();
  445. };
  446. /**
  447. * Reads a signed, zigzag-encoded 32-bit varint from the binary stream.
  448. *
  449. * Zigzag encoding is a modification of varint encoding that reduces the
  450. * storage overhead for small negative integers - for more details on the
  451. * format, see https://developers.google.com/protocol-buffers/docs/encoding
  452. *
  453. * @return {number} The decoded signed, zigzag-encoded 32-bit varint.
  454. */
  455. jspb.BinaryDecoder.prototype.readZigzagVarint32 = function() {
  456. var result = this.readUnsignedVarint32();
  457. return (result >>> 1) ^ - (result & 1);
  458. };
  459. /**
  460. * Reads an unsigned 64-bit varint from the binary stream. Note that since
  461. * Javascript represents all numbers as double-precision floats, there will be
  462. * precision lost if the absolute value of the varint is larger than 2^53.
  463. *
  464. * @return {number} The decoded unsigned varint. Precision will be lost if the
  465. * integer exceeds 2^53.
  466. */
  467. jspb.BinaryDecoder.prototype.readUnsignedVarint64 = function() {
  468. return this.readSplitVarint64(jspb.utils.joinUint64);
  469. };
  470. /**
  471. * Reads an unsigned 64-bit varint from the binary stream and returns the value
  472. * as a decimal string.
  473. *
  474. * @return {string} The decoded unsigned varint as a decimal string.
  475. */
  476. jspb.BinaryDecoder.prototype.readUnsignedVarint64String = function() {
  477. return this.readSplitVarint64(jspb.utils.joinUnsignedDecimalString);
  478. };
  479. /**
  480. * Reads a signed 64-bit varint from the binary stream. Note that since
  481. * Javascript represents all numbers as double-precision floats, there will be
  482. * precision lost if the absolute value of the varint is larger than 2^53.
  483. *
  484. * @return {number} The decoded signed varint. Precision will be lost if the
  485. * integer exceeds 2^53.
  486. */
  487. jspb.BinaryDecoder.prototype.readSignedVarint64 = function() {
  488. return this.readSplitVarint64(jspb.utils.joinInt64);
  489. };
  490. /**
  491. * Reads an signed 64-bit varint from the binary stream and returns the value
  492. * as a decimal string.
  493. *
  494. * @return {string} The decoded signed varint as a decimal string.
  495. */
  496. jspb.BinaryDecoder.prototype.readSignedVarint64String = function() {
  497. return this.readSplitVarint64(jspb.utils.joinSignedDecimalString);
  498. };
  499. /**
  500. * Reads a signed, zigzag-encoded 64-bit varint from the binary stream. Note
  501. * that since Javascript represents all numbers as double-precision floats,
  502. * there will be precision lost if the absolute value of the varint is larger
  503. * than 2^53.
  504. *
  505. * Zigzag encoding is a modification of varint encoding that reduces the
  506. * storage overhead for small negative integers - for more details on the
  507. * format, see https://developers.google.com/protocol-buffers/docs/encoding
  508. *
  509. * @return {number} The decoded zigzag varint. Precision will be lost if the
  510. * integer exceeds 2^53.
  511. */
  512. jspb.BinaryDecoder.prototype.readZigzagVarint64 = function() {
  513. return this.readSplitVarint64(jspb.utils.joinZigzag64);
  514. };
  515. /**
  516. * Reads a signed, zigzag-encoded 64-bit varint from the binary stream
  517. * losslessly and returns it as an 8-character Unicode string for use as a hash
  518. * table key.
  519. *
  520. * Zigzag encoding is a modification of varint encoding that reduces the
  521. * storage overhead for small negative integers - for more details on the
  522. * format, see https://developers.google.com/protocol-buffers/docs/encoding
  523. *
  524. * @return {string} The decoded zigzag varint in hash64 format.
  525. */
  526. jspb.BinaryDecoder.prototype.readZigzagVarintHash64 = function() {
  527. return this.readSplitZigzagVarint64(jspb.utils.joinHash64);
  528. };
  529. /**
  530. * Reads a signed, zigzag-encoded 64-bit varint from the binary stream and
  531. * returns its value as a string.
  532. *
  533. * Zigzag encoding is a modification of varint encoding that reduces the
  534. * storage overhead for small negative integers - for more details on the
  535. * format, see https://developers.google.com/protocol-buffers/docs/encoding
  536. *
  537. * @return {string} The decoded signed, zigzag-encoded 64-bit varint as a
  538. * string.
  539. */
  540. jspb.BinaryDecoder.prototype.readZigzagVarint64String = function() {
  541. return this.readSplitZigzagVarint64(jspb.utils.joinSignedDecimalString);
  542. };
  543. /**
  544. * Reads a raw unsigned 8-bit integer from the binary stream.
  545. *
  546. * @return {number} The unsigned 8-bit integer read from the binary stream.
  547. */
  548. jspb.BinaryDecoder.prototype.readUint8 = function() {
  549. var a = this.bytes_[this.cursor_ + 0];
  550. this.cursor_ += 1;
  551. goog.asserts.assert(this.cursor_ <= this.end_);
  552. return a;
  553. };
  554. /**
  555. * Reads a raw unsigned 16-bit integer from the binary stream.
  556. *
  557. * @return {number} The unsigned 16-bit integer read from the binary stream.
  558. */
  559. jspb.BinaryDecoder.prototype.readUint16 = function() {
  560. var a = this.bytes_[this.cursor_ + 0];
  561. var b = this.bytes_[this.cursor_ + 1];
  562. this.cursor_ += 2;
  563. goog.asserts.assert(this.cursor_ <= this.end_);
  564. return (a << 0) | (b << 8);
  565. };
  566. /**
  567. * Reads a raw unsigned 32-bit integer from the binary stream.
  568. *
  569. * @return {number} The unsigned 32-bit integer read from the binary stream.
  570. */
  571. jspb.BinaryDecoder.prototype.readUint32 = function() {
  572. var a = this.bytes_[this.cursor_ + 0];
  573. var b = this.bytes_[this.cursor_ + 1];
  574. var c = this.bytes_[this.cursor_ + 2];
  575. var d = this.bytes_[this.cursor_ + 3];
  576. this.cursor_ += 4;
  577. goog.asserts.assert(this.cursor_ <= this.end_);
  578. return ((a << 0) | (b << 8) | (c << 16) | (d << 24)) >>> 0;
  579. };
  580. /**
  581. * Reads a raw unsigned 64-bit integer from the binary stream. Note that since
  582. * Javascript represents all numbers as double-precision floats, there will be
  583. * precision lost if the absolute value of the integer is larger than 2^53.
  584. *
  585. * @return {number} The unsigned 64-bit integer read from the binary stream.
  586. * Precision will be lost if the integer exceeds 2^53.
  587. */
  588. jspb.BinaryDecoder.prototype.readUint64 = function() {
  589. var bitsLow = this.readUint32();
  590. var bitsHigh = this.readUint32();
  591. return jspb.utils.joinUint64(bitsLow, bitsHigh);
  592. };
  593. /**
  594. * Reads a raw unsigned 64-bit integer from the binary stream. Note that since
  595. * Javascript represents all numbers as double-precision floats, there will be
  596. * precision lost if the absolute value of the integer is larger than 2^53.
  597. *
  598. * @return {string} The unsigned 64-bit integer read from the binary stream.
  599. */
  600. jspb.BinaryDecoder.prototype.readUint64String = function() {
  601. var bitsLow = this.readUint32();
  602. var bitsHigh = this.readUint32();
  603. return jspb.utils.joinUnsignedDecimalString(bitsLow, bitsHigh);
  604. };
  605. /**
  606. * Reads a raw signed 8-bit integer from the binary stream.
  607. *
  608. * @return {number} The signed 8-bit integer read from the binary stream.
  609. */
  610. jspb.BinaryDecoder.prototype.readInt8 = function() {
  611. var a = this.bytes_[this.cursor_ + 0];
  612. this.cursor_ += 1;
  613. goog.asserts.assert(this.cursor_ <= this.end_);
  614. return (a << 24) >> 24;
  615. };
  616. /**
  617. * Reads a raw signed 16-bit integer from the binary stream.
  618. *
  619. * @return {number} The signed 16-bit integer read from the binary stream.
  620. */
  621. jspb.BinaryDecoder.prototype.readInt16 = function() {
  622. var a = this.bytes_[this.cursor_ + 0];
  623. var b = this.bytes_[this.cursor_ + 1];
  624. this.cursor_ += 2;
  625. goog.asserts.assert(this.cursor_ <= this.end_);
  626. return (((a << 0) | (b << 8)) << 16) >> 16;
  627. };
  628. /**
  629. * Reads a raw signed 32-bit integer from the binary stream.
  630. *
  631. * @return {number} The signed 32-bit integer read from the binary stream.
  632. */
  633. jspb.BinaryDecoder.prototype.readInt32 = function() {
  634. var a = this.bytes_[this.cursor_ + 0];
  635. var b = this.bytes_[this.cursor_ + 1];
  636. var c = this.bytes_[this.cursor_ + 2];
  637. var d = this.bytes_[this.cursor_ + 3];
  638. this.cursor_ += 4;
  639. goog.asserts.assert(this.cursor_ <= this.end_);
  640. return (a << 0) | (b << 8) | (c << 16) | (d << 24);
  641. };
  642. /**
  643. * Reads a raw signed 64-bit integer from the binary stream. Note that since
  644. * Javascript represents all numbers as double-precision floats, there will be
  645. * precision lost if the absolute value of the integer is larger than 2^53.
  646. *
  647. * @return {number} The signed 64-bit integer read from the binary stream.
  648. * Precision will be lost if the integer exceeds 2^53.
  649. */
  650. jspb.BinaryDecoder.prototype.readInt64 = function() {
  651. var bitsLow = this.readUint32();
  652. var bitsHigh = this.readUint32();
  653. return jspb.utils.joinInt64(bitsLow, bitsHigh);
  654. };
  655. /**
  656. * Reads a raw signed 64-bit integer from the binary stream and returns it as a
  657. * string.
  658. *
  659. * @return {string} The signed 64-bit integer read from the binary stream.
  660. * Precision will be lost if the integer exceeds 2^53.
  661. */
  662. jspb.BinaryDecoder.prototype.readInt64String = function() {
  663. var bitsLow = this.readUint32();
  664. var bitsHigh = this.readUint32();
  665. return jspb.utils.joinSignedDecimalString(bitsLow, bitsHigh);
  666. };
  667. /**
  668. * Reads a 32-bit floating-point number from the binary stream, using the
  669. * temporary buffer to realign the data.
  670. *
  671. * @return {number} The float read from the binary stream.
  672. */
  673. jspb.BinaryDecoder.prototype.readFloat = function() {
  674. var bitsLow = this.readUint32();
  675. var bitsHigh = 0;
  676. return jspb.utils.joinFloat32(bitsLow, bitsHigh);
  677. };
  678. /**
  679. * Reads a 64-bit floating-point number from the binary stream, using the
  680. * temporary buffer to realign the data.
  681. *
  682. * @return {number} The double read from the binary stream.
  683. */
  684. jspb.BinaryDecoder.prototype.readDouble = function() {
  685. var bitsLow = this.readUint32();
  686. var bitsHigh = this.readUint32();
  687. return jspb.utils.joinFloat64(bitsLow, bitsHigh);
  688. };
  689. /**
  690. * Reads a boolean value from the binary stream.
  691. * @return {boolean} The boolean read from the binary stream.
  692. */
  693. jspb.BinaryDecoder.prototype.readBool = function() {
  694. return !!this.bytes_[this.cursor_++];
  695. };
  696. /**
  697. * Reads an enum value from the binary stream, which are always encoded as
  698. * signed varints.
  699. * @return {number} The enum value read from the binary stream.
  700. */
  701. jspb.BinaryDecoder.prototype.readEnum = function() {
  702. return this.readSignedVarint32();
  703. };
  704. /**
  705. * Reads and parses a UTF-8 encoded unicode string from the stream.
  706. * The code is inspired by maps.vectortown.parse.StreamedDataViewReader.
  707. * Supports codepoints from U+0000 up to U+10FFFF.
  708. * (http://en.wikipedia.org/wiki/UTF-8).
  709. * @param {number} length The length of the string to read.
  710. * @return {string} The decoded string.
  711. */
  712. jspb.BinaryDecoder.prototype.readString = function(length) {
  713. var bytes = this.bytes_;
  714. var cursor = this.cursor_;
  715. var end = cursor + length;
  716. var codeUnits = [];
  717. var result = '';
  718. while (cursor < end) {
  719. var c = bytes[cursor++];
  720. if (c < 128) { // Regular 7-bit ASCII.
  721. codeUnits.push(c);
  722. } else if (c < 192) {
  723. // UTF-8 continuation mark. We are out of sync. This
  724. // might happen if we attempted to read a character
  725. // with more than four bytes.
  726. continue;
  727. } else if (c < 224) { // UTF-8 with two bytes.
  728. var c2 = bytes[cursor++];
  729. codeUnits.push(((c & 31) << 6) | (c2 & 63));
  730. } else if (c < 240) { // UTF-8 with three bytes.
  731. var c2 = bytes[cursor++];
  732. var c3 = bytes[cursor++];
  733. codeUnits.push(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
  734. } else if (c < 248) { // UTF-8 with 4 bytes.
  735. var c2 = bytes[cursor++];
  736. var c3 = bytes[cursor++];
  737. var c4 = bytes[cursor++];
  738. // Characters written on 4 bytes have 21 bits for a codepoint.
  739. // We can't fit that on 16bit characters, so we use surrogates.
  740. var codepoint = ((c & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63);
  741. // Surrogates formula from wikipedia.
  742. // 1. Subtract 0x10000 from codepoint
  743. codepoint -= 0x10000;
  744. // 2. Split this into the high 10-bit value and the low 10-bit value
  745. // 3. Add 0xD800 to the high value to form the high surrogate
  746. // 4. Add 0xDC00 to the low value to form the low surrogate:
  747. var low = (codepoint & 1023) + 0xDC00;
  748. var high = ((codepoint >> 10) & 1023) + 0xD800;
  749. codeUnits.push(high, low);
  750. }
  751. // Avoid exceeding the maximum stack size when calling `apply`.
  752. if (codeUnits.length >= 8192) {
  753. result += String.fromCharCode.apply(null, codeUnits);
  754. codeUnits.length = 0;
  755. }
  756. }
  757. result += goog.crypt.byteArrayToString(codeUnits);
  758. this.cursor_ = cursor;
  759. return result;
  760. };
  761. /**
  762. * Reads and parses a UTF-8 encoded unicode string (with length prefix) from
  763. * the stream.
  764. * @return {string} The decoded string.
  765. */
  766. jspb.BinaryDecoder.prototype.readStringWithLength = function() {
  767. var length = this.readUnsignedVarint32();
  768. return this.readString(length);
  769. };
  770. /**
  771. * Reads a block of raw bytes from the binary stream.
  772. *
  773. * @param {number} length The number of bytes to read.
  774. * @return {!Uint8Array} The decoded block of bytes, or an empty block if the
  775. * length was invalid.
  776. */
  777. jspb.BinaryDecoder.prototype.readBytes = function(length) {
  778. if (length < 0 ||
  779. this.cursor_ + length > this.bytes_.length) {
  780. this.error_ = true;
  781. goog.asserts.fail('Invalid byte length!');
  782. return new Uint8Array(0);
  783. }
  784. var result = this.bytes_.subarray(this.cursor_, this.cursor_ + length);
  785. this.cursor_ += length;
  786. goog.asserts.assert(this.cursor_ <= this.end_);
  787. return result;
  788. };
  789. /**
  790. * Reads a 64-bit varint from the stream and returns it as an 8-character
  791. * Unicode string for use as a hash table key.
  792. *
  793. * @return {string} The hash value.
  794. */
  795. jspb.BinaryDecoder.prototype.readVarintHash64 = function() {
  796. return this.readSplitVarint64(jspb.utils.joinHash64);
  797. };
  798. /**
  799. * Reads a 64-bit fixed-width value from the stream and returns it as an
  800. * 8-character Unicode string for use as a hash table key.
  801. *
  802. * @return {string} The hash value.
  803. */
  804. jspb.BinaryDecoder.prototype.readFixedHash64 = function() {
  805. var bytes = this.bytes_;
  806. var cursor = this.cursor_;
  807. var a = bytes[cursor + 0];
  808. var b = bytes[cursor + 1];
  809. var c = bytes[cursor + 2];
  810. var d = bytes[cursor + 3];
  811. var e = bytes[cursor + 4];
  812. var f = bytes[cursor + 5];
  813. var g = bytes[cursor + 6];
  814. var h = bytes[cursor + 7];
  815. this.cursor_ += 8;
  816. return String.fromCharCode(a, b, c, d, e, f, g, h);
  817. };