Home | History | Annotate | Download | only in binary
      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 (a] google.com (Austin Appleby)
     44  */
     45 
     46 goog.provide('jspb.BinaryDecoder');
     47 goog.provide('jspb.BinaryIterator');
     48 
     49 goog.require('goog.asserts');
     50 goog.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  */
     64 jspb.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  */
     97 jspb.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  */
    116 jspb.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  */
    128 jspb.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  */
    142 jspb.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  */
    153 jspb.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  */
    171 jspb.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  */
    180 jspb.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  */
    190 jspb.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  */
    223 jspb.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  */
    278 jspb.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  */
    290 jspb.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  */
    306 jspb.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  */
    318 jspb.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  */
    327 jspb.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  */
    340 jspb.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  */
    352 jspb.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  */
    365 jspb.BinaryDecoder.prototype.getEnd = function() {
    366   return this.end_;
    367 };
    368 
    369 
    370 /**
    371  * @param {number} end
    372  */
    373 jspb.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  */
    381 jspb.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  */
    390 jspb.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  */
    399 jspb.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  */
    408 jspb.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  */
    418 jspb.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  */
    427 jspb.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  */
    436 jspb.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  */
    458 jspb.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  */
    505 jspb.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  */
    518 jspb.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  */
    545 jspb.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  */
    617 jspb.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  */
    626 jspb.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  */
    640 jspb.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  */
    658 jspb.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  */
    672 jspb.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  */
    684 jspb.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  */
    698 jspb.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  */
    710 jspb.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  */
    729 jspb.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  */
    740 jspb.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  */
    753 jspb.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  */
    767 jspb.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  */
    786 jspb.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  */
    798 jspb.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  */
    811 jspb.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  */
    825 jspb.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  */
    844 jspb.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  */
    857 jspb.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  */
    870 jspb.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  */
    881 jspb.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  */
    891 jspb.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  */
    906 jspb.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  */
    944 jspb.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  */
    957 jspb.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  */
    979 jspb.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  */
    991 jspb.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