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