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