• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/**
32 * @fileoverview This file contains utilities for decoding primitive values
33 * (signed and unsigned integers, varints, booleans, enums, hashes, strings,
34 * and raw bytes) embedded in Uint8Arrays into their corresponding Javascript
35 * types.
36 *
37 * Major caveat - Javascript is unable to accurately represent integers larger
38 * than 2^53 due to its use of a double-precision floating point format or all
39 * numbers. If you need to guarantee that 64-bit values survive with all bits
40 * intact, you _must_ read them using one of the Hash64 methods, which return
41 * an 8-character string.
42 *
43 * @author aappleby@google.com (Austin Appleby)
44 */
45
46goog.provide('jspb.BinaryDecoder');
47goog.provide('jspb.BinaryIterator');
48
49goog.require('goog.asserts');
50goog.require('goog.crypt');
51goog.require('jspb.utils');
52
53
54
55/**
56 * Simple helper class for traversing the contents of repeated scalar fields.
57 * that may or may not have been packed into a wire-format blob.
58 * @param {?jspb.BinaryDecoder=} opt_decoder
59 * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
60 *     opt_next The decoder method to use for next().
61 * @param {?Array<number|boolean|string>=} opt_elements
62 * @constructor
63 * @struct
64 */
65jspb.BinaryIterator = function(opt_decoder, opt_next, opt_elements) {
66  /** @private {?jspb.BinaryDecoder} */
67  this.decoder_ = null;
68
69  /**
70   * The BinaryDecoder member function used when iterating over packed data.
71   * @private {?function(this:jspb.BinaryDecoder):(number|boolean|string)}
72   */
73  this.nextMethod_ = null;
74
75  /** @private {?Array<number|boolean|string>} */
76  this.elements_ = null;
77
78  /** @private {number} */
79  this.cursor_ = 0;
80
81  /** @private {number|boolean|string|null} */
82  this.nextValue_ = null;
83
84  /** @private {boolean} */
85  this.atEnd_ = true;
86
87  this.init_(opt_decoder, opt_next, opt_elements);
88};
89
90
91/**
92 * @param {?jspb.BinaryDecoder=} opt_decoder
93 * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
94 *     opt_next The decoder method to use for next().
95 * @param {?Array<number|boolean|string>=} opt_elements
96 * @private
97 */
98jspb.BinaryIterator.prototype.init_ =
99    function(opt_decoder, opt_next, opt_elements) {
100  if (opt_decoder && opt_next) {
101    this.decoder_ = opt_decoder;
102    this.nextMethod_ = opt_next;
103  }
104  this.elements_ = opt_elements || null;
105  this.cursor_ = 0;
106  this.nextValue_ = null;
107  this.atEnd_ = !this.decoder_ && !this.elements_;
108
109  this.next();
110};
111
112
113/**
114 * Global pool of BinaryIterator instances.
115 * @private {!Array<!jspb.BinaryIterator>}
116 */
117jspb.BinaryIterator.instanceCache_ = [];
118
119
120/**
121 * Allocates a BinaryIterator from the cache, creating a new one if the cache
122 * is empty.
123 * @param {?jspb.BinaryDecoder=} opt_decoder
124 * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
125 *     opt_next The decoder method to use for next().
126 * @param {?Array<number|boolean|string>=} opt_elements
127 * @return {!jspb.BinaryIterator}
128 */
129jspb.BinaryIterator.alloc = function(opt_decoder, opt_next, opt_elements) {
130  if (jspb.BinaryIterator.instanceCache_.length) {
131    var iterator = jspb.BinaryIterator.instanceCache_.pop();
132    iterator.init_(opt_decoder, opt_next, opt_elements);
133    return iterator;
134  } else {
135    return new jspb.BinaryIterator(opt_decoder, opt_next, opt_elements);
136  }
137};
138
139
140/**
141 * Puts this instance back in the instance cache.
142 */
143jspb.BinaryIterator.prototype.free = function() {
144  this.clear();
145  if (jspb.BinaryIterator.instanceCache_.length < 100) {
146    jspb.BinaryIterator.instanceCache_.push(this);
147  }
148};
149
150
151/**
152 * Clears the iterator.
153 */
154jspb.BinaryIterator.prototype.clear = function() {
155  if (this.decoder_) {
156    this.decoder_.free();
157  }
158  this.decoder_ = null;
159  this.nextMethod_ = null;
160  this.elements_ = null;
161  this.cursor_ = 0;
162  this.nextValue_ = null;
163  this.atEnd_ = true;
164};
165
166
167/**
168 * Returns the element at the iterator, or null if the iterator is invalid or
169 * past the end of the decoder/array.
170 * @return {number|boolean|string|null}
171 */
172jspb.BinaryIterator.prototype.get = function() {
173  return this.nextValue_;
174};
175
176
177/**
178 * Returns true if the iterator is at the end of the decoder/array.
179 * @return {boolean}
180 */
181jspb.BinaryIterator.prototype.atEnd = function() {
182  return this.atEnd_;
183};
184
185
186/**
187 * Returns the element at the iterator and steps to the next element,
188 * equivalent to '*pointer++' in C.
189 * @return {number|boolean|string|null}
190 */
191jspb.BinaryIterator.prototype.next = function() {
192  var lastValue = this.nextValue_;
193  if (this.decoder_) {
194    if (this.decoder_.atEnd()) {
195      this.nextValue_ = null;
196      this.atEnd_ = true;
197    } else {
198      this.nextValue_ = this.nextMethod_.call(this.decoder_);
199    }
200  } else if (this.elements_) {
201    if (this.cursor_ == this.elements_.length) {
202      this.nextValue_ = null;
203      this.atEnd_ = true;
204    } else {
205      this.nextValue_ = this.elements_[this.cursor_++];
206    }
207  }
208  return lastValue;
209};
210
211
212
213/**
214 * BinaryDecoder implements the decoders for all the wire types specified in
215 * https://developers.google.com/protocol-buffers/docs/encoding.
216 *
217 * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
218 * @param {number=} opt_start The optional offset to start reading at.
219 * @param {number=} opt_length The optional length of the block to read -
220 *     we'll throw an assertion if we go off the end of the block.
221 * @constructor
222 * @struct
223 */
224jspb.BinaryDecoder = function(opt_bytes, opt_start, opt_length) {
225  /**
226   * Typed byte-wise view of the source buffer.
227   * @private {?Uint8Array}
228   */
229  this.bytes_ = null;
230
231  /**
232   * Start point of the block to read.
233   * @private {number}
234   */
235  this.start_ = 0;
236
237  /**
238   * End point of the block to read.
239   * @private {number}
240   */
241  this.end_ = 0;
242
243  /**
244   * Current read location in bytes_.
245   * @private {number}
246   */
247  this.cursor_ = 0;
248
249  /**
250   * Temporary storage for the low 32 bits of 64-bit data types that we're
251   * decoding.
252   * @private {number}
253   */
254  this.tempLow_ = 0;
255
256  /**
257   * Temporary storage for the high 32 bits of 64-bit data types that we're
258   * decoding.
259   * @private {number}
260   */
261  this.tempHigh_ = 0;
262
263  /**
264   * Set to true if this decoder encountered an error due to corrupt data.
265   * @private {boolean}
266   */
267  this.error_ = false;
268
269  if (opt_bytes) {
270    this.setBlock(opt_bytes, opt_start, opt_length);
271  }
272};
273
274
275/**
276 * Global pool of BinaryDecoder instances.
277 * @private {!Array<!jspb.BinaryDecoder>}
278 */
279jspb.BinaryDecoder.instanceCache_ = [];
280
281
282/**
283 * Pops an instance off the instance cache, or creates one if the cache is
284 * empty.
285 * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
286 * @param {number=} opt_start The optional offset to start reading at.
287 * @param {number=} opt_length The optional length of the block to read -
288 *     we'll throw an assertion if we go off the end of the block.
289 * @return {!jspb.BinaryDecoder}
290 */
291jspb.BinaryDecoder.alloc = function(opt_bytes, opt_start, opt_length) {
292  if (jspb.BinaryDecoder.instanceCache_.length) {
293    var newDecoder = jspb.BinaryDecoder.instanceCache_.pop();
294    if (opt_bytes) {
295      newDecoder.setBlock(opt_bytes, opt_start, opt_length);
296    }
297    return newDecoder;
298  } else {
299    return new jspb.BinaryDecoder(opt_bytes, opt_start, opt_length);
300  }
301};
302
303
304/**
305 * Puts this instance back in the instance cache.
306 */
307jspb.BinaryDecoder.prototype.free = function() {
308  this.clear();
309  if (jspb.BinaryDecoder.instanceCache_.length < 100) {
310    jspb.BinaryDecoder.instanceCache_.push(this);
311  }
312};
313
314
315/**
316 * Makes a copy of this decoder.
317 * @return {!jspb.BinaryDecoder}
318 */
319jspb.BinaryDecoder.prototype.clone = function() {
320  return jspb.BinaryDecoder.alloc(this.bytes_,
321      this.start_, this.end_ - this.start_);
322};
323
324
325/**
326 * Clears the decoder.
327 */
328jspb.BinaryDecoder.prototype.clear = function() {
329  this.bytes_ = null;
330  this.start_ = 0;
331  this.end_ = 0;
332  this.cursor_ = 0;
333  this.error_ = false;
334};
335
336
337/**
338 * Returns the raw buffer.
339 * @return {?Uint8Array} The raw buffer.
340 */
341jspb.BinaryDecoder.prototype.getBuffer = function() {
342  return this.bytes_;
343};
344
345
346/**
347 * Changes the block of bytes we're decoding.
348 * @param {!jspb.ByteSource} data The bytes we're reading from.
349 * @param {number=} opt_start The optional offset to start reading at.
350 * @param {number=} opt_length The optional length of the block to read -
351 *     we'll throw an assertion if we go off the end of the block.
352 */
353jspb.BinaryDecoder.prototype.setBlock =
354    function(data, opt_start, opt_length) {
355  this.bytes_ = jspb.utils.byteSourceToUint8Array(data);
356  this.start_ = goog.isDef(opt_start) ? opt_start : 0;
357  this.end_ =
358      goog.isDef(opt_length) ? this.start_ + opt_length : this.bytes_.length;
359  this.cursor_ = this.start_;
360};
361
362
363/**
364 * @return {number}
365 */
366jspb.BinaryDecoder.prototype.getEnd = function() {
367  return this.end_;
368};
369
370
371/**
372 * @param {number} end
373 */
374jspb.BinaryDecoder.prototype.setEnd = function(end) {
375  this.end_ = end;
376};
377
378
379/**
380 * Moves the read cursor back to the start of the block.
381 */
382jspb.BinaryDecoder.prototype.reset = function() {
383  this.cursor_ = this.start_;
384};
385
386
387/**
388 * Returns the internal read cursor.
389 * @return {number} The internal read cursor.
390 */
391jspb.BinaryDecoder.prototype.getCursor = function() {
392  return this.cursor_;
393};
394
395
396/**
397 * Returns the internal read cursor.
398 * @param {number} cursor The new cursor.
399 */
400jspb.BinaryDecoder.prototype.setCursor = function(cursor) {
401  this.cursor_ = cursor;
402};
403
404
405/**
406 * Advances the stream cursor by the given number of bytes.
407 * @param {number} count The number of bytes to advance by.
408 */
409jspb.BinaryDecoder.prototype.advance = function(count) {
410  this.cursor_ += count;
411  goog.asserts.assert(this.cursor_ <= this.end_);
412};
413
414
415/**
416 * Returns true if this decoder is at the end of the block.
417 * @return {boolean}
418 */
419jspb.BinaryDecoder.prototype.atEnd = function() {
420  return this.cursor_ == this.end_;
421};
422
423
424/**
425 * Returns true if this decoder is at the end of the block.
426 * @return {boolean}
427 */
428jspb.BinaryDecoder.prototype.pastEnd = function() {
429  return this.cursor_ > this.end_;
430};
431
432
433/**
434 * Returns true if this decoder encountered an error due to corrupt data.
435 * @return {boolean}
436 */
437jspb.BinaryDecoder.prototype.getError = function() {
438  return this.error_ ||
439         (this.cursor_ < 0) ||
440         (this.cursor_ > this.end_);
441};
442
443
444/**
445 * Reads an unsigned varint from the binary stream and stores it as a split
446 * 64-bit integer. Since this does not convert the value to a number, no
447 * precision is lost.
448 *
449 * It's possible for an unsigned varint to be incorrectly encoded - more than
450 * 64 bits' worth of data could be present. If this happens, this method will
451 * throw an error.
452 *
453 * Decoding varints requires doing some funny base-128 math - for more
454 * details on the format, see
455 * https://developers.google.com/protocol-buffers/docs/encoding
456 *
457 * @private
458 */
459jspb.BinaryDecoder.prototype.readSplitVarint64_ = function() {
460  var temp;
461  var lowBits = 0;
462  var highBits = 0;
463
464  // Read the first four bytes of the varint, stopping at the terminator if we
465  // see it.
466  for (var i = 0; i < 4; i++) {
467    temp = this.bytes_[this.cursor_++];
468    lowBits |= (temp & 0x7F) << (i * 7);
469    if (temp < 128) {
470      this.tempLow_ = lowBits >>> 0;
471      this.tempHigh_ = 0;
472      return;
473    }
474  }
475
476  // Read the fifth byte, which straddles the low and high dwords.
477  temp = this.bytes_[this.cursor_++];
478  lowBits |= (temp & 0x7F) << 28;
479  highBits |= (temp & 0x7F) >> 4;
480  if (temp < 128) {
481    this.tempLow_ = lowBits >>> 0;
482    this.tempHigh_ = highBits >>> 0;
483    return;
484  }
485
486  // Read the sixth through tenth byte.
487  for (var i = 0; i < 5; i++) {
488    temp = this.bytes_[this.cursor_++];
489    highBits |= (temp & 0x7F) << (i * 7 + 3);
490    if (temp < 128) {
491      this.tempLow_ = lowBits >>> 0;
492      this.tempHigh_ = highBits >>> 0;
493      return;
494    }
495  }
496
497  // If we did not see the terminator, the encoding was invalid.
498  goog.asserts.fail('Failed to read varint, encoding is invalid.');
499  this.error_ = true;
500};
501
502
503/**
504 * Skips over a varint in the block without decoding it.
505 */
506jspb.BinaryDecoder.prototype.skipVarint = function() {
507  while (this.bytes_[this.cursor_] & 0x80) {
508    this.cursor_++;
509  }
510  this.cursor_++;
511};
512
513
514/**
515 * Skips backwards over a varint in the block - to do this correctly, we have
516 * to know the value we're skipping backwards over or things are ambiguous.
517 * @param {number} value The varint value to unskip.
518 */
519jspb.BinaryDecoder.prototype.unskipVarint = function(value) {
520  while (value > 128) {
521    this.cursor_--;
522    value = value >>> 7;
523  }
524  this.cursor_--;
525};
526
527
528/**
529 * Reads a 32-bit varint from the binary stream. Due to a quirk of the encoding
530 * format and Javascript's handling of bitwise math, this actually works
531 * correctly for both signed and unsigned 32-bit varints.
532 *
533 * This function is called vastly more frequently than any other in
534 * BinaryDecoder, so it has been unrolled and tweaked for performance.
535 *
536 * If there are more than 32 bits of data in the varint, it _must_ be due to
537 * sign-extension. If we're in debug mode and the high 32 bits don't match the
538 * expected sign extension, this method will throw an error.
539 *
540 * Decoding varints requires doing some funny base-128 math - for more
541 * details on the format, see
542 * https://developers.google.com/protocol-buffers/docs/encoding
543 *
544 * @return {number} The decoded unsigned 32-bit varint.
545 */
546jspb.BinaryDecoder.prototype.readUnsignedVarint32 = function() {
547  var temp;
548  var bytes = this.bytes_;
549
550  temp = bytes[this.cursor_ + 0];
551  var x = (temp & 0x7F);
552  if (temp < 128) {
553    this.cursor_ += 1;
554    goog.asserts.assert(this.cursor_ <= this.end_);
555    return x;
556  }
557
558  temp = bytes[this.cursor_ + 1];
559  x |= (temp & 0x7F) << 7;
560  if (temp < 128) {
561    this.cursor_ += 2;
562    goog.asserts.assert(this.cursor_ <= this.end_);
563    return x;
564  }
565
566  temp = bytes[this.cursor_ + 2];
567  x |= (temp & 0x7F) << 14;
568  if (temp < 128) {
569    this.cursor_ += 3;
570    goog.asserts.assert(this.cursor_ <= this.end_);
571    return x;
572  }
573
574  temp = bytes[this.cursor_ + 3];
575  x |= (temp & 0x7F) << 21;
576  if (temp < 128) {
577    this.cursor_ += 4;
578    goog.asserts.assert(this.cursor_ <= this.end_);
579    return x;
580  }
581
582  temp = bytes[this.cursor_ + 4];
583  x |= (temp & 0x0F) << 28;
584  if (temp < 128) {
585    // We're reading the high bits of an unsigned varint. The byte we just read
586    // also contains bits 33 through 35, which we're going to discard.
587    this.cursor_ += 5;
588    goog.asserts.assert(this.cursor_ <= this.end_);
589    return x >>> 0;
590  }
591
592  // If we get here, we need to truncate coming bytes. However we need to make
593  // sure cursor place is correct.
594  this.cursor_ += 5;
595  if (bytes[this.cursor_++] >= 128 &&
596      bytes[this.cursor_++] >= 128 &&
597      bytes[this.cursor_++] >= 128 &&
598      bytes[this.cursor_++] >= 128 &&
599      bytes[this.cursor_++] >= 128) {
600    // If we get here, the varint is too long.
601    goog.asserts.assert(false);
602  }
603
604  goog.asserts.assert(this.cursor_ <= this.end_);
605  return x;
606};
607
608
609/**
610 * The readUnsignedVarint32 above deals with signed 32-bit varints correctly,
611 * so this is just an alias.
612 *
613 * @return {number} The decoded signed 32-bit varint.
614 */
615jspb.BinaryDecoder.prototype.readSignedVarint32 =
616    jspb.BinaryDecoder.prototype.readUnsignedVarint32;
617
618
619/**
620 * Reads a 32-bit unsigned variant and returns its value as a string.
621 *
622 * @return {string} The decoded unsigned 32-bit varint as a string.
623 */
624jspb.BinaryDecoder.prototype.readUnsignedVarint32String = function() {
625  // 32-bit integers fit in JavaScript numbers without loss of precision, so
626  // string variants of 32-bit varint readers can simply delegate then convert
627  // to string.
628  var value = this.readUnsignedVarint32();
629  return value.toString();
630};
631
632
633/**
634 * Reads a 32-bit signed variant and returns its value as a string.
635 *
636 * @return {string} The decoded signed 32-bit varint as a string.
637 */
638jspb.BinaryDecoder.prototype.readSignedVarint32String = function() {
639  // 32-bit integers fit in JavaScript numbers without loss of precision, so
640  // string variants of 32-bit varint readers can simply delegate then convert
641  // to string.
642  var value = this.readSignedVarint32();
643  return value.toString();
644};
645
646
647/**
648 * Reads a signed, zigzag-encoded 32-bit varint from the binary stream.
649 *
650 * Zigzag encoding is a modification of varint encoding that reduces the
651 * storage overhead for small negative integers - for more details on the
652 * format, see https://developers.google.com/protocol-buffers/docs/encoding
653 *
654 * @return {number} The decoded signed, zigzag-encoded 32-bit varint.
655 */
656jspb.BinaryDecoder.prototype.readZigzagVarint32 = function() {
657  var result = this.readUnsignedVarint32();
658  return (result >>> 1) ^ - (result & 1);
659};
660
661
662/**
663 * Reads an unsigned 64-bit varint from the binary stream. Note that since
664 * Javascript represents all numbers as double-precision floats, there will be
665 * precision lost if the absolute value of the varint is larger than 2^53.
666 *
667 * @return {number} The decoded unsigned varint. Precision will be lost if the
668 *     integer exceeds 2^53.
669 */
670jspb.BinaryDecoder.prototype.readUnsignedVarint64 = function() {
671  this.readSplitVarint64_();
672  return jspb.utils.joinUint64(this.tempLow_, this.tempHigh_);
673};
674
675
676/**
677 * Reads an unsigned 64-bit varint from the binary stream and returns the value
678 * as a decimal string.
679 *
680 * @return {string} The decoded unsigned varint as a decimal string.
681 */
682jspb.BinaryDecoder.prototype.readUnsignedVarint64String = function() {
683  this.readSplitVarint64_();
684  return jspb.utils.joinUnsignedDecimalString(this.tempLow_, this.tempHigh_);
685};
686
687
688/**
689 * Reads a signed 64-bit varint from the binary stream. Note that since
690 * Javascript represents all numbers as double-precision floats, there will be
691 * precision lost if the absolute value of the varint is larger than 2^53.
692 *
693 * @return {number} The decoded signed varint. Precision will be lost if the
694 *     integer exceeds 2^53.
695 */
696jspb.BinaryDecoder.prototype.readSignedVarint64 = function() {
697  this.readSplitVarint64_();
698  return jspb.utils.joinInt64(this.tempLow_, this.tempHigh_);
699};
700
701
702/**
703 * Reads an signed 64-bit varint from the binary stream and returns the value
704 * as a decimal string.
705 *
706 * @return {string} The decoded signed varint as a decimal string.
707 */
708jspb.BinaryDecoder.prototype.readSignedVarint64String = function() {
709  this.readSplitVarint64_();
710  return jspb.utils.joinSignedDecimalString(this.tempLow_, this.tempHigh_);
711};
712
713
714/**
715 * Reads a signed, zigzag-encoded 64-bit varint from the binary stream. Note
716 * that since Javascript represents all numbers as double-precision floats,
717 * there will be precision lost if the absolute value of the varint is larger
718 * than 2^53.
719 *
720 * Zigzag encoding is a modification of varint encoding that reduces the
721 * storage overhead for small negative integers - for more details on the
722 * format, see https://developers.google.com/protocol-buffers/docs/encoding
723 *
724 * @return {number} The decoded zigzag varint. Precision will be lost if the
725 *     integer exceeds 2^53.
726 */
727jspb.BinaryDecoder.prototype.readZigzagVarint64 = function() {
728  this.readSplitVarint64_();
729  return jspb.utils.joinZigzag64(this.tempLow_, this.tempHigh_);
730};
731
732
733/**
734 * Reads a signed, zigzag-encoded 64-bit varint from the binary stream and
735 * returns its valud as a string.
736 *
737 * Zigzag encoding is a modification of varint encoding that reduces the
738 * storage overhead for small negative integers - for more details on the
739 * format, see https://developers.google.com/protocol-buffers/docs/encoding
740 *
741 * @return {string} The decoded signed, zigzag-encoded 64-bit varint as a
742 * string.
743 */
744jspb.BinaryDecoder.prototype.readZigzagVarint64String = function() {
745  // TODO(haberman): write lossless 64-bit zig-zag math.
746  var value = this.readZigzagVarint64();
747  return value.toString();
748};
749
750
751/**
752 * Reads a raw unsigned 8-bit integer from the binary stream.
753 *
754 * @return {number} The unsigned 8-bit integer read from the binary stream.
755 */
756jspb.BinaryDecoder.prototype.readUint8 = function() {
757  var a = this.bytes_[this.cursor_ + 0];
758  this.cursor_ += 1;
759  goog.asserts.assert(this.cursor_ <= this.end_);
760  return a;
761};
762
763
764/**
765 * Reads a raw unsigned 16-bit integer from the binary stream.
766 *
767 * @return {number} The unsigned 16-bit integer read from the binary stream.
768 */
769jspb.BinaryDecoder.prototype.readUint16 = function() {
770  var a = this.bytes_[this.cursor_ + 0];
771  var b = this.bytes_[this.cursor_ + 1];
772  this.cursor_ += 2;
773  goog.asserts.assert(this.cursor_ <= this.end_);
774  return (a << 0) | (b << 8);
775};
776
777
778/**
779 * Reads a raw unsigned 32-bit integer from the binary stream.
780 *
781 * @return {number} The unsigned 32-bit integer read from the binary stream.
782 */
783jspb.BinaryDecoder.prototype.readUint32 = function() {
784  var a = this.bytes_[this.cursor_ + 0];
785  var b = this.bytes_[this.cursor_ + 1];
786  var c = this.bytes_[this.cursor_ + 2];
787  var d = this.bytes_[this.cursor_ + 3];
788  this.cursor_ += 4;
789  goog.asserts.assert(this.cursor_ <= this.end_);
790  return ((a << 0) | (b << 8) | (c << 16) | (d << 24)) >>> 0;
791};
792
793
794/**
795 * Reads a raw unsigned 64-bit integer from the binary stream. Note that since
796 * Javascript represents all numbers as double-precision floats, there will be
797 * precision lost if the absolute value of the integer is larger than 2^53.
798 *
799 * @return {number} The unsigned 64-bit integer read from the binary stream.
800 *     Precision will be lost if the integer exceeds 2^53.
801 */
802jspb.BinaryDecoder.prototype.readUint64 = function() {
803  var bitsLow = this.readUint32();
804  var bitsHigh = this.readUint32();
805  return jspb.utils.joinUint64(bitsLow, bitsHigh);
806};
807
808
809/**
810 * Reads a raw unsigned 64-bit integer from the binary stream. Note that since
811 * Javascript represents all numbers as double-precision floats, there will be
812 * precision lost if the absolute value of the integer is larger than 2^53.
813 *
814 * @return {string} The unsigned 64-bit integer read from the binary stream.
815 */
816jspb.BinaryDecoder.prototype.readUint64String = function() {
817  var bitsLow = this.readUint32();
818  var bitsHigh = this.readUint32();
819  return jspb.utils.joinUnsignedDecimalString(bitsLow, bitsHigh);
820};
821
822
823/**
824 * Reads a raw signed 8-bit integer from the binary stream.
825 *
826 * @return {number} The signed 8-bit integer read from the binary stream.
827 */
828jspb.BinaryDecoder.prototype.readInt8 = function() {
829  var a = this.bytes_[this.cursor_ + 0];
830  this.cursor_ += 1;
831  goog.asserts.assert(this.cursor_ <= this.end_);
832  return (a << 24) >> 24;
833};
834
835
836/**
837 * Reads a raw signed 16-bit integer from the binary stream.
838 *
839 * @return {number} The signed 16-bit integer read from the binary stream.
840 */
841jspb.BinaryDecoder.prototype.readInt16 = function() {
842  var a = this.bytes_[this.cursor_ + 0];
843  var b = this.bytes_[this.cursor_ + 1];
844  this.cursor_ += 2;
845  goog.asserts.assert(this.cursor_ <= this.end_);
846  return (((a << 0) | (b << 8)) << 16) >> 16;
847};
848
849
850/**
851 * Reads a raw signed 32-bit integer from the binary stream.
852 *
853 * @return {number} The signed 32-bit integer read from the binary stream.
854 */
855jspb.BinaryDecoder.prototype.readInt32 = function() {
856  var a = this.bytes_[this.cursor_ + 0];
857  var b = this.bytes_[this.cursor_ + 1];
858  var c = this.bytes_[this.cursor_ + 2];
859  var d = this.bytes_[this.cursor_ + 3];
860  this.cursor_ += 4;
861  goog.asserts.assert(this.cursor_ <= this.end_);
862  return (a << 0) | (b << 8) | (c << 16) | (d << 24);
863};
864
865
866/**
867 * Reads a raw signed 64-bit integer from the binary stream. Note that since
868 * Javascript represents all numbers as double-precision floats, there will be
869 * precision lost if the absolute vlaue of the integer is larger than 2^53.
870 *
871 * @return {number} The signed 64-bit integer read from the binary stream.
872 *     Precision will be lost if the integer exceeds 2^53.
873 */
874jspb.BinaryDecoder.prototype.readInt64 = function() {
875  var bitsLow = this.readUint32();
876  var bitsHigh = this.readUint32();
877  return jspb.utils.joinInt64(bitsLow, bitsHigh);
878};
879
880
881/**
882 * Reads a raw signed 64-bit integer from the binary stream and returns it as a
883 * string.
884 *
885 * @return {string} The signed 64-bit integer read from the binary stream.
886 *     Precision will be lost if the integer exceeds 2^53.
887 */
888jspb.BinaryDecoder.prototype.readInt64String = function() {
889  var bitsLow = this.readUint32();
890  var bitsHigh = this.readUint32();
891  return jspb.utils.joinSignedDecimalString(bitsLow, bitsHigh);
892};
893
894
895/**
896 * Reads a 32-bit floating-point number from the binary stream, using the
897 * temporary buffer to realign the data.
898 *
899 * @return {number} The float read from the binary stream.
900 */
901jspb.BinaryDecoder.prototype.readFloat = function() {
902  var bitsLow = this.readUint32();
903  var bitsHigh = 0;
904  return jspb.utils.joinFloat32(bitsLow, bitsHigh);
905};
906
907
908/**
909 * Reads a 64-bit floating-point number from the binary stream, using the
910 * temporary buffer to realign the data.
911 *
912 * @return {number} The double read from the binary stream.
913 */
914jspb.BinaryDecoder.prototype.readDouble = function() {
915  var bitsLow = this.readUint32();
916  var bitsHigh = this.readUint32();
917  return jspb.utils.joinFloat64(bitsLow, bitsHigh);
918};
919
920
921/**
922 * Reads a boolean value from the binary stream.
923 * @return {boolean} The boolean read from the binary stream.
924 */
925jspb.BinaryDecoder.prototype.readBool = function() {
926  return !!this.bytes_[this.cursor_++];
927};
928
929
930/**
931 * Reads an enum value from the binary stream, which are always encoded as
932 * signed varints.
933 * @return {number} The enum value read from the binary stream.
934 */
935jspb.BinaryDecoder.prototype.readEnum = function() {
936  return this.readSignedVarint32();
937};
938
939
940/**
941 * Reads and parses a UTF-8 encoded unicode string from the stream.
942 * The code is inspired by maps.vectortown.parse.StreamedDataViewReader.
943 * Supports codepoints from U+0000 up to U+10FFFF.
944 * (http://en.wikipedia.org/wiki/UTF-8).
945 * @param {number} length The length of the string to read.
946 * @return {string} The decoded string.
947 */
948jspb.BinaryDecoder.prototype.readString = function(length) {
949  var bytes = this.bytes_;
950  var cursor = this.cursor_;
951  var end = cursor + length;
952  var codeUnits = [];
953
954  var result = '';
955  while (cursor < end) {
956    var c = bytes[cursor++];
957    if (c < 128) { // Regular 7-bit ASCII.
958      codeUnits.push(c);
959    } else if (c < 192) {
960      // UTF-8 continuation mark. We are out of sync. This
961      // might happen if we attempted to read a character
962      // with more than four bytes.
963      continue;
964    } else if (c < 224) { // UTF-8 with two bytes.
965      var c2 = bytes[cursor++];
966      codeUnits.push(((c & 31) << 6) | (c2 & 63));
967    } else if (c < 240) { // UTF-8 with three bytes.
968      var c2 = bytes[cursor++];
969      var c3 = bytes[cursor++];
970      codeUnits.push(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
971    } else if (c < 248) { // UTF-8 with 4 bytes.
972      var c2 = bytes[cursor++];
973      var c3 = bytes[cursor++];
974      var c4 = bytes[cursor++];
975      // Characters written on 4 bytes have 21 bits for a codepoint.
976      // We can't fit that on 16bit characters, so we use surrogates.
977      var codepoint = ((c & 7) << 18) | ((c2 & 63) << 12) | ((c3 & 63) << 6) | (c4 & 63);
978      // Surrogates formula from wikipedia.
979      // 1. Subtract 0x10000 from codepoint
980      codepoint -= 0x10000;
981      // 2. Split this into the high 10-bit value and the low 10-bit value
982      // 3. Add 0xD800 to the high value to form the high surrogate
983      // 4. Add 0xDC00 to the low value to form the low surrogate:
984      var low = (codepoint & 1023) + 0xDC00;
985      var high = ((codepoint >> 10) & 1023) + 0xD800;
986      codeUnits.push(high, low);
987    }
988
989    // Avoid exceeding the maximum stack size when calling `apply`.
990    if (codeUnits.length >= 8192) {
991      result += String.fromCharCode.apply(null, codeUnits);
992      codeUnits.length = 0;
993    }
994  }
995  result += goog.crypt.byteArrayToString(codeUnits);
996  this.cursor_ = cursor;
997  return result;
998};
999
1000
1001/**
1002 * Reads and parses a UTF-8 encoded unicode string (with length prefix) from
1003 * the stream.
1004 * @return {string} The decoded string.
1005 */
1006jspb.BinaryDecoder.prototype.readStringWithLength = function() {
1007  var length = this.readUnsignedVarint32();
1008  return this.readString(length);
1009};
1010
1011
1012/**
1013 * Reads a block of raw bytes from the binary stream.
1014 *
1015 * @param {number} length The number of bytes to read.
1016 * @return {!Uint8Array} The decoded block of bytes, or an empty block if the
1017 *     length was invalid.
1018 */
1019jspb.BinaryDecoder.prototype.readBytes = function(length) {
1020  if (length < 0 ||
1021      this.cursor_ + length > this.bytes_.length) {
1022    this.error_ = true;
1023    goog.asserts.fail('Invalid byte length!');
1024    return new Uint8Array(0);
1025  }
1026
1027  var result = this.bytes_.subarray(this.cursor_, this.cursor_ + length);
1028
1029  this.cursor_ += length;
1030  goog.asserts.assert(this.cursor_ <= this.end_);
1031  return result;
1032};
1033
1034
1035/**
1036 * Reads a 64-bit varint from the stream and returns it as an 8-character
1037 * Unicode string for use as a hash table key.
1038 *
1039 * @return {string} The hash value.
1040 */
1041jspb.BinaryDecoder.prototype.readVarintHash64 = function() {
1042  this.readSplitVarint64_();
1043  return jspb.utils.joinHash64(this.tempLow_, this.tempHigh_);
1044};
1045
1046
1047/**
1048 * Reads a 64-bit fixed-width value from the stream and returns it as an
1049 * 8-character Unicode string for use as a hash table key.
1050 *
1051 * @return {string} The hash value.
1052 */
1053jspb.BinaryDecoder.prototype.readFixedHash64 = function() {
1054  var bytes = this.bytes_;
1055  var cursor = this.cursor_;
1056
1057  var a = bytes[cursor + 0];
1058  var b = bytes[cursor + 1];
1059  var c = bytes[cursor + 2];
1060  var d = bytes[cursor + 3];
1061  var e = bytes[cursor + 4];
1062  var f = bytes[cursor + 5];
1063  var g = bytes[cursor + 6];
1064  var h = bytes[cursor + 7];
1065
1066  this.cursor_ += 8;
1067
1068  return String.fromCharCode(a, b, c, d, e, f, g, h);
1069};
1070