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 converting binary,
     33  * wire-format protocol buffers into Javascript data structures.
     34  *
     35  * jspb's BinaryReader class wraps the BinaryDecoder class to add methods
     36  * that understand the protocol buffer syntax and can do the type checking and
     37  * bookkeeping necessary to parse trees of nested messages.
     38  *
     39  * Major caveat - Users of this library _must_ keep their Javascript proto
     40  * parsing code in sync with the original .proto file - presumably you'll be
     41  * using the typed jspb code generator, but if you bypass that you'll need
     42  * to keep things in sync by hand.
     43  *
     44  * @author aappleby (a] google.com (Austin Appleby)
     45  */
     46 
     47 goog.provide('jspb.BinaryReader');
     48 
     49 goog.require('goog.asserts');
     50 goog.require('jspb.BinaryConstants');
     51 goog.require('jspb.BinaryDecoder');
     52 
     53 
     54 
     55 /**
     56  * BinaryReader implements the decoders for all the wire types specified in
     57  * https://developers.google.com/protocol-buffers/docs/encoding.
     58  *
     59  * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
     60  * @param {number=} opt_start The optional offset to start reading at.
     61  * @param {number=} opt_length The optional length of the block to read -
     62  *     we'll throw an assertion if we go off the end of the block.
     63  * @constructor
     64  * @struct
     65  */
     66 jspb.BinaryReader = function(opt_bytes, opt_start, opt_length) {
     67   /**
     68    * Wire-format decoder.
     69    * @private {!jspb.BinaryDecoder}
     70    */
     71   this.decoder_ = jspb.BinaryDecoder.alloc(opt_bytes, opt_start, opt_length);
     72 
     73   /**
     74    * Cursor immediately before the field tag.
     75    * @private {number}
     76    */
     77   this.fieldCursor_ = this.decoder_.getCursor();
     78 
     79   /**
     80    * Field number of the next field in the buffer, filled in by nextField().
     81    * @private {number}
     82    */
     83   this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER;
     84 
     85   /**
     86    * Wire type of the next proto field in the buffer, filled in by
     87    * nextField().
     88    * @private {jspb.BinaryConstants.WireType}
     89    */
     90   this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID;
     91 
     92   /**
     93    * Set to true if this reader encountered an error due to corrupt data.
     94    * @private {boolean}
     95    */
     96   this.error_ = false;
     97 
     98   /**
     99    * User-defined reader callbacks.
    100    * @private {Object.<string, function(!jspb.BinaryReader):*>}
    101    */
    102   this.readCallbacks_ = null;
    103 };
    104 
    105 
    106 /**
    107  * Global pool of BinaryReader instances.
    108  * @private {!Array.<!jspb.BinaryReader>}
    109  */
    110 jspb.BinaryReader.instanceCache_ = [];
    111 
    112 
    113 /**
    114  * Pops an instance off the instance cache, or creates one if the cache is
    115  * empty.
    116  * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
    117  * @param {number=} opt_start The optional offset to start reading at.
    118  * @param {number=} opt_length The optional length of the block to read -
    119  *     we'll throw an assertion if we go off the end of the block.
    120  * @return {!jspb.BinaryReader}
    121  */
    122 jspb.BinaryReader.alloc =
    123     function(opt_bytes, opt_start, opt_length) {
    124   if (jspb.BinaryReader.instanceCache_.length) {
    125     var newReader = jspb.BinaryReader.instanceCache_.pop();
    126     if (opt_bytes) {
    127       newReader.decoder_.setBlock(opt_bytes, opt_start, opt_length);
    128     }
    129     return newReader;
    130   } else {
    131     return new jspb.BinaryReader(opt_bytes, opt_start, opt_length);
    132   }
    133 };
    134 
    135 
    136 /**
    137  * Alias for the above method.
    138  * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
    139  * @param {number=} opt_start The optional offset to start reading at.
    140  * @param {number=} opt_length The optional length of the block to read -
    141  *     we'll throw an assertion if we go off the end of the block.
    142  * @return {!jspb.BinaryReader}
    143  */
    144 jspb.BinaryReader.prototype.alloc = jspb.BinaryReader.alloc;
    145 
    146 
    147 /**
    148  * Puts this instance back in the instance cache.
    149  */
    150 jspb.BinaryReader.prototype.free = function() {
    151   this.decoder_.clear();
    152   this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER;
    153   this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID;
    154   this.error_ = false;
    155   this.readCallbacks_ = null;
    156 
    157   if (jspb.BinaryReader.instanceCache_.length < 100) {
    158     jspb.BinaryReader.instanceCache_.push(this);
    159   }
    160 };
    161 
    162 
    163 /**
    164  * Returns the cursor immediately before the current field's tag.
    165  * @return {number} The internal read cursor.
    166  */
    167 jspb.BinaryReader.prototype.getFieldCursor = function() {
    168   return this.fieldCursor_;
    169 };
    170 
    171 
    172 /**
    173  * Returns the internal read cursor.
    174  * @return {number} The internal read cursor.
    175  */
    176 jspb.BinaryReader.prototype.getCursor = function() {
    177   return this.decoder_.getCursor();
    178 };
    179 
    180 
    181 /**
    182  * Returns the raw buffer.
    183  * @return {?Uint8Array} The raw buffer.
    184  */
    185 jspb.BinaryReader.prototype.getBuffer = function() {
    186   return this.decoder_.getBuffer();
    187 };
    188 
    189 
    190 /**
    191  * @return {number} The field number of the next field in the buffer, or
    192  *     INVALID_FIELD_NUMBER if there is no next field.
    193  */
    194 jspb.BinaryReader.prototype.getFieldNumber = function() {
    195   return this.nextField_;
    196 };
    197 
    198 
    199 /**
    200  * @return {jspb.BinaryConstants.WireType} The wire type of the next field
    201  *     in the stream, or WireType.INVALID if there is no next field.
    202  */
    203 jspb.BinaryReader.prototype.getWireType = function() {
    204   return this.nextWireType_;
    205 };
    206 
    207 
    208 /**
    209  * @return {boolean} Whether the current wire type is an end-group tag. Used as
    210  * an exit condition in decoder loops in generated code.
    211  */
    212 jspb.BinaryReader.prototype.isEndGroup = function() {
    213   return this.nextWireType_ == jspb.BinaryConstants.WireType.END_GROUP;
    214 };
    215 
    216 
    217 /**
    218  * Returns true if this reader hit an error due to corrupt data.
    219  * @return {boolean}
    220  */
    221 jspb.BinaryReader.prototype.getError = function() {
    222   return this.error_ || this.decoder_.getError();
    223 };
    224 
    225 
    226 /**
    227  * Points this reader at a new block of bytes.
    228  * @param {!Uint8Array} bytes The block of bytes we're reading from.
    229  * @param {number} start The offset to start reading at.
    230  * @param {number} length The length of the block to read.
    231  */
    232 jspb.BinaryReader.prototype.setBlock = function(bytes, start, length) {
    233   this.decoder_.setBlock(bytes, start, length);
    234   this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER;
    235   this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID;
    236 };
    237 
    238 
    239 /**
    240  * Rewinds the stream cursor to the beginning of the buffer and resets all
    241  * internal state.
    242  */
    243 jspb.BinaryReader.prototype.reset = function() {
    244   this.decoder_.reset();
    245   this.nextField_ = jspb.BinaryConstants.INVALID_FIELD_NUMBER;
    246   this.nextWireType_ = jspb.BinaryConstants.WireType.INVALID;
    247 };
    248 
    249 
    250 /**
    251  * Advances the stream cursor by the given number of bytes.
    252  * @param {number} count The number of bytes to advance by.
    253  */
    254 jspb.BinaryReader.prototype.advance = function(count) {
    255   this.decoder_.advance(count);
    256 };
    257 
    258 
    259 /**
    260  * Reads the next field header in the stream if there is one, returns true if
    261  * we saw a valid field header or false if we've read the whole stream.
    262  * Throws an error if we encountered a deprecated START_GROUP/END_GROUP field.
    263  * @return {boolean} True if the stream contains more fields.
    264  */
    265 jspb.BinaryReader.prototype.nextField = function() {
    266   // If we're at the end of the block, there are no more fields.
    267   if (this.decoder_.atEnd()) {
    268     return false;
    269   }
    270 
    271   // If we hit an error decoding the previous field, stop now before we
    272   // try to decode anything else
    273   if (this.getError()) {
    274     goog.asserts.fail('Decoder hit an error');
    275     return false;
    276   }
    277 
    278   // Otherwise just read the header of the next field.
    279   this.fieldCursor_ = this.decoder_.getCursor();
    280   var header = this.decoder_.readUnsignedVarint32();
    281 
    282   var nextField = header >>> 3;
    283   var nextWireType = /** @type {jspb.BinaryConstants.WireType} */
    284       (header & 0x7);
    285 
    286   // If the wire type isn't one of the valid ones, something's broken.
    287   if (nextWireType != jspb.BinaryConstants.WireType.VARINT &&
    288       nextWireType != jspb.BinaryConstants.WireType.FIXED32 &&
    289       nextWireType != jspb.BinaryConstants.WireType.FIXED64 &&
    290       nextWireType != jspb.BinaryConstants.WireType.DELIMITED &&
    291       nextWireType != jspb.BinaryConstants.WireType.START_GROUP &&
    292       nextWireType != jspb.BinaryConstants.WireType.END_GROUP) {
    293     goog.asserts.fail('Invalid wire type');
    294     this.error_ = true;
    295     return false;
    296   }
    297 
    298   this.nextField_ = nextField;
    299   this.nextWireType_ = nextWireType;
    300 
    301   return true;
    302 };
    303 
    304 
    305 /**
    306  * Winds the reader back to just before this field's header.
    307  */
    308 jspb.BinaryReader.prototype.unskipHeader = function() {
    309   this.decoder_.unskipVarint((this.nextField_ << 3) | this.nextWireType_);
    310 };
    311 
    312 
    313 /**
    314  * Skips all contiguous fields whose header matches the one we just read.
    315  */
    316 jspb.BinaryReader.prototype.skipMatchingFields = function() {
    317   var field = this.nextField_;
    318   this.unskipHeader();
    319 
    320   while (this.nextField() && (this.getFieldNumber() == field)) {
    321     this.skipField();
    322   }
    323 
    324   if (!this.decoder_.atEnd()) {
    325     this.unskipHeader();
    326   }
    327 };
    328 
    329 
    330 /**
    331  * Skips over the next varint field in the binary stream.
    332  */
    333 jspb.BinaryReader.prototype.skipVarintField = function() {
    334   if (this.nextWireType_ != jspb.BinaryConstants.WireType.VARINT) {
    335     goog.asserts.fail('Invalid wire type for skipVarintField');
    336     this.skipField();
    337     return;
    338   }
    339 
    340   this.decoder_.skipVarint();
    341 };
    342 
    343 
    344 /**
    345  * Skips over the next delimited field in the binary stream.
    346  */
    347 jspb.BinaryReader.prototype.skipDelimitedField = function() {
    348   if (this.nextWireType_ != jspb.BinaryConstants.WireType.DELIMITED) {
    349     goog.asserts.fail('Invalid wire type for skipDelimitedField');
    350     this.skipField();
    351     return;
    352   }
    353 
    354   var length = this.decoder_.readUnsignedVarint32();
    355   this.decoder_.advance(length);
    356 };
    357 
    358 
    359 /**
    360  * Skips over the next fixed32 field in the binary stream.
    361  */
    362 jspb.BinaryReader.prototype.skipFixed32Field = function() {
    363   if (this.nextWireType_ != jspb.BinaryConstants.WireType.FIXED32) {
    364     goog.asserts.fail('Invalid wire type for skipFixed32Field');
    365     this.skipField();
    366     return;
    367   }
    368 
    369   this.decoder_.advance(4);
    370 };
    371 
    372 
    373 /**
    374  * Skips over the next fixed64 field in the binary stream.
    375  */
    376 jspb.BinaryReader.prototype.skipFixed64Field = function() {
    377   if (this.nextWireType_ != jspb.BinaryConstants.WireType.FIXED64) {
    378     goog.asserts.fail('Invalid wire type for skipFixed64Field');
    379     this.skipField();
    380     return;
    381   }
    382 
    383   this.decoder_.advance(8);
    384 };
    385 
    386 
    387 /**
    388  * Skips over the next group field in the binary stream.
    389  */
    390 jspb.BinaryReader.prototype.skipGroup = function() {
    391   // Keep a stack of start-group tags that must be matched by end-group tags.
    392   var nestedGroups = [this.nextField_];
    393   do {
    394     if (!this.nextField()) {
    395       goog.asserts.fail('Unmatched start-group tag: stream EOF');
    396       this.error_ = true;
    397       return;
    398     }
    399     if (this.nextWireType_ ==
    400         jspb.BinaryConstants.WireType.START_GROUP) {
    401       // Nested group start.
    402       nestedGroups.push(this.nextField_);
    403     } else if (this.nextWireType_ ==
    404                jspb.BinaryConstants.WireType.END_GROUP) {
    405       // Group end: check that it matches top-of-stack.
    406       if (this.nextField_ != nestedGroups.pop()) {
    407         goog.asserts.fail('Unmatched end-group tag');
    408         this.error_ = true;
    409         return;
    410       }
    411     }
    412   } while (nestedGroups.length > 0);
    413 };
    414 
    415 
    416 /**
    417  * Skips over the next field in the binary stream - this is useful if we're
    418  * decoding a message that contain unknown fields.
    419  */
    420 jspb.BinaryReader.prototype.skipField = function() {
    421   switch (this.nextWireType_) {
    422     case jspb.BinaryConstants.WireType.VARINT:
    423       this.skipVarintField();
    424       break;
    425     case jspb.BinaryConstants.WireType.FIXED64:
    426       this.skipFixed64Field();
    427       break;
    428     case jspb.BinaryConstants.WireType.DELIMITED:
    429       this.skipDelimitedField();
    430       break;
    431     case jspb.BinaryConstants.WireType.FIXED32:
    432       this.skipFixed32Field();
    433       break;
    434     case jspb.BinaryConstants.WireType.START_GROUP:
    435       this.skipGroup();
    436       break;
    437     default:
    438       goog.asserts.fail('Invalid wire encoding for field.');
    439   }
    440 };
    441 
    442 
    443 /**
    444  * Registers a user-defined read callback.
    445  * @param {string} callbackName
    446  * @param {function(!jspb.BinaryReader):*} callback
    447  */
    448 jspb.BinaryReader.prototype.registerReadCallback =
    449     function(callbackName, callback) {
    450   if (goog.isNull(this.readCallbacks_)) {
    451     this.readCallbacks_ = {};
    452   }
    453   goog.asserts.assert(!this.readCallbacks_[callbackName]);
    454   this.readCallbacks_[callbackName] = callback;
    455 };
    456 
    457 
    458 /**
    459  * Runs a registered read callback.
    460  * @param {string} callbackName The name the callback is registered under.
    461  * @return {*} The value returned by the callback.
    462  */
    463 jspb.BinaryReader.prototype.runReadCallback = function(callbackName) {
    464   goog.asserts.assert(!goog.isNull(this.readCallbacks_));
    465   var callback = this.readCallbacks_[callbackName];
    466   goog.asserts.assert(callback);
    467   return callback(this);
    468 };
    469 
    470 
    471 /**
    472  * Reads a field of any valid non-message type from the binary stream.
    473  * @param {jspb.BinaryConstants.FieldType} fieldType
    474  * @return {jspb.AnyFieldType}
    475  */
    476 jspb.BinaryReader.prototype.readAny = function(fieldType) {
    477   this.nextWireType_ = jspb.BinaryConstants.FieldTypeToWireType(fieldType);
    478   var fieldTypes = jspb.BinaryConstants.FieldType;
    479   switch (fieldType) {
    480     case fieldTypes.DOUBLE:
    481       return this.readDouble();
    482     case fieldTypes.FLOAT:
    483       return this.readFloat();
    484     case fieldTypes.INT64:
    485       return this.readInt64();
    486     case fieldTypes.UINT64:
    487       return this.readUint64();
    488     case fieldTypes.INT32:
    489       return this.readInt32();
    490     case fieldTypes.FIXED64:
    491       return this.readFixed64();
    492     case fieldTypes.FIXED32:
    493       return this.readFixed32();
    494     case fieldTypes.BOOL:
    495       return this.readBool();
    496     case fieldTypes.STRING:
    497       return this.readString();
    498     case fieldTypes.GROUP:
    499       goog.asserts.fail('Group field type not supported in readAny()');
    500     case fieldTypes.MESSAGE:
    501       goog.asserts.fail('Message field type not supported in readAny()');
    502     case fieldTypes.BYTES:
    503       return this.readBytes();
    504     case fieldTypes.UINT32:
    505       return this.readUint32();
    506     case fieldTypes.ENUM:
    507       return this.readEnum();
    508     case fieldTypes.SFIXED32:
    509       return this.readSfixed32();
    510     case fieldTypes.SFIXED64:
    511       return this.readSfixed64();
    512     case fieldTypes.SINT32:
    513       return this.readSint32();
    514     case fieldTypes.SINT64:
    515       return this.readSint64();
    516     case fieldTypes.FHASH64:
    517       return this.readFixedHash64();
    518     case fieldTypes.VHASH64:
    519       return this.readVarintHash64();
    520     default:
    521       goog.asserts.fail('Invalid field type in readAny()');
    522   }
    523   return 0;
    524 };
    525 
    526 
    527 /**
    528  * Deserialize a proto into the provided message object using the provided
    529  * reader function. This function is templated as we currently have one client
    530  * who is using manual deserialization instead of the code-generated versions.
    531  * @template T
    532  * @param {T} message
    533  * @param {function(T, !jspb.BinaryReader)} reader
    534  */
    535 jspb.BinaryReader.prototype.readMessage = function(message, reader) {
    536   goog.asserts.assert(
    537       this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED);
    538 
    539   // Save the current endpoint of the decoder and move it to the end of the
    540   // embedded message.
    541   var oldEnd = this.decoder_.getEnd();
    542   var length = this.decoder_.readUnsignedVarint32();
    543   var newEnd = this.decoder_.getCursor() + length;
    544   this.decoder_.setEnd(newEnd);
    545 
    546   // Deserialize the embedded message.
    547   reader(message, this);
    548 
    549   // Advance the decoder past the embedded message and restore the endpoint.
    550   this.decoder_.setCursor(newEnd);
    551   this.decoder_.setEnd(oldEnd);
    552 };
    553 
    554 
    555 /**
    556  * Deserialize a proto into the provided message object using the provided
    557  * reader function, assuming that the message is serialized as a group
    558  * with the given tag.
    559  * @template T
    560  * @param {number} field
    561  * @param {T} message
    562  * @param {function(T, !jspb.BinaryReader)} reader
    563  */
    564 jspb.BinaryReader.prototype.readGroup =
    565     function(field, message, reader) {
    566   // Ensure that the wire type is correct.
    567   goog.asserts.assert(
    568       this.nextWireType_ == jspb.BinaryConstants.WireType.START_GROUP);
    569   // Ensure that the field number is correct.
    570   goog.asserts.assert(this.nextField_ == field);
    571 
    572   // Deserialize the message. The deserialization will stop at an END_GROUP tag.
    573   reader(message, this);
    574 
    575   if (!this.error_ &&
    576       this.nextWireType_ != jspb.BinaryConstants.WireType.END_GROUP) {
    577     goog.asserts.fail('Group submessage did not end with an END_GROUP tag');
    578     this.error_ = true;
    579   }
    580 };
    581 
    582 
    583 /**
    584  * Return a decoder that wraps the current delimited field.
    585  * @return {!jspb.BinaryDecoder}
    586  */
    587 jspb.BinaryReader.prototype.getFieldDecoder = function() {
    588   goog.asserts.assert(
    589       this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED);
    590 
    591   var length = this.decoder_.readUnsignedVarint32();
    592   var start = this.decoder_.getCursor();
    593   var end = start + length;
    594 
    595   var innerDecoder =
    596       jspb.BinaryDecoder.alloc(this.decoder_.getBuffer(), start, length);
    597   this.decoder_.setCursor(end);
    598   return innerDecoder;
    599 };
    600 
    601 
    602 /**
    603  * Reads a signed 32-bit integer field from the binary stream, or throws an
    604  * error if the next field in the stream is not of the correct wire type.
    605  *
    606  * @return {number} The value of the signed 32-bit integer field.
    607  */
    608 jspb.BinaryReader.prototype.readInt32 = function() {
    609   goog.asserts.assert(
    610       this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
    611   return this.decoder_.readSignedVarint32();
    612 };
    613 
    614 
    615 /**
    616  * Reads a signed 32-bit integer field from the binary stream, or throws an
    617  * error if the next field in the stream is not of the correct wire type.
    618  *
    619  * Returns the value as a string.
    620  *
    621  * @return {string} The value of the signed 32-bit integer field as a decimal
    622  * string.
    623  */
    624 jspb.BinaryReader.prototype.readInt32String = function() {
    625   goog.asserts.assert(
    626       this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
    627   return this.decoder_.readSignedVarint32String();
    628 };
    629 
    630 
    631 /**
    632  * Reads a signed 64-bit integer field from the binary stream, or throws an
    633  * error if the next field in the stream is not of the correct wire type.
    634  *
    635  * @return {number} The value of the signed 64-bit integer field.
    636  */
    637 jspb.BinaryReader.prototype.readInt64 = function() {
    638   goog.asserts.assert(
    639       this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
    640   return this.decoder_.readSignedVarint64();
    641 };
    642 
    643 
    644 /**
    645  * Reads a signed 64-bit integer field from the binary stream, or throws an
    646  * error if the next field in the stream is not of the correct wire type.
    647  *
    648  * Returns the value as a string.
    649  *
    650  * @return {string} The value of the signed 64-bit integer field as a decimal
    651  * string.
    652  */
    653 jspb.BinaryReader.prototype.readInt64String = function() {
    654   goog.asserts.assert(
    655       this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
    656   return this.decoder_.readSignedVarint64String();
    657 };
    658 
    659 
    660 /**
    661  * Reads an unsigned 32-bit integer field from the binary stream, or throws an
    662  * error if the next field in the stream is not of the correct wire type.
    663  *
    664  * @return {number} The value of the unsigned 32-bit integer field.
    665  */
    666 jspb.BinaryReader.prototype.readUint32 = function() {
    667   goog.asserts.assert(
    668       this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
    669   return this.decoder_.readUnsignedVarint32();
    670 };
    671 
    672 
    673 /**
    674  * Reads an unsigned 32-bit integer field from the binary stream, or throws an
    675  * error if the next field in the stream is not of the correct wire type.
    676  *
    677  * Returns the value as a string.
    678  *
    679  * @return {string} The value of the unsigned 32-bit integer field as a decimal
    680  * string.
    681  */
    682 jspb.BinaryReader.prototype.readUint32String = function() {
    683   goog.asserts.assert(
    684       this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
    685   return this.decoder_.readUnsignedVarint32String();
    686 };
    687 
    688 
    689 /**
    690  * Reads an unsigned 64-bit integer field from the binary stream, or throws an
    691  * error if the next field in the stream is not of the correct wire type.
    692  *
    693  * @return {number} The value of the unsigned 64-bit integer field.
    694  */
    695 jspb.BinaryReader.prototype.readUint64 = function() {
    696   goog.asserts.assert(
    697       this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
    698   return this.decoder_.readUnsignedVarint64();
    699 };
    700 
    701 
    702 /**
    703  * Reads an unsigned 64-bit integer field from the binary stream, or throws an
    704  * error if the next field in the stream is not of the correct wire type.
    705  *
    706  * Returns the value as a string.
    707  *
    708  * @return {string} The value of the unsigned 64-bit integer field as a decimal
    709  * string.
    710  */
    711 jspb.BinaryReader.prototype.readUint64String = function() {
    712   goog.asserts.assert(
    713       this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
    714   return this.decoder_.readUnsignedVarint64String();
    715 };
    716 
    717 
    718 /**
    719  * Reads a signed zigzag-encoded 32-bit integer field from the binary stream,
    720  * or throws an error if the next field in the stream is not of the correct
    721  * wire type.
    722  *
    723  * @return {number} The value of the signed 32-bit integer field.
    724  */
    725 jspb.BinaryReader.prototype.readSint32 = function() {
    726   goog.asserts.assert(
    727       this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
    728   return this.decoder_.readZigzagVarint32();
    729 };
    730 
    731 
    732 /**
    733  * Reads a signed zigzag-encoded 64-bit integer field from the binary stream,
    734  * or throws an error if the next field in the stream is not of the correct
    735  * wire type.
    736  *
    737  * @return {number} The value of the signed 64-bit integer field.
    738  */
    739 jspb.BinaryReader.prototype.readSint64 = function() {
    740   goog.asserts.assert(
    741       this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
    742   return this.decoder_.readZigzagVarint64();
    743 };
    744 
    745 
    746 /**
    747  * Reads an unsigned 32-bit fixed-length integer fiield from the binary stream,
    748  * or throws an error if the next field in the stream is not of the correct
    749  * wire type.
    750  *
    751  * @return {number} The value of the double field.
    752  */
    753 jspb.BinaryReader.prototype.readFixed32 = function() {
    754   goog.asserts.assert(
    755       this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED32);
    756   return this.decoder_.readUint32();
    757 };
    758 
    759 
    760 /**
    761  * Reads an unsigned 64-bit fixed-length integer fiield from the binary stream,
    762  * or throws an error if the next field in the stream is not of the correct
    763  * wire type.
    764  *
    765  * @return {number} The value of the float field.
    766  */
    767 jspb.BinaryReader.prototype.readFixed64 = function() {
    768   goog.asserts.assert(
    769       this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64);
    770   return this.decoder_.readUint64();
    771 };
    772 
    773 
    774 /**
    775  * Reads a signed 32-bit fixed-length integer fiield from the binary stream, or
    776  * throws an error if the next field in the stream is not of the correct wire
    777  * type.
    778  *
    779  * @return {number} The value of the double field.
    780  */
    781 jspb.BinaryReader.prototype.readSfixed32 = function() {
    782   goog.asserts.assert(
    783       this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED32);
    784   return this.decoder_.readInt32();
    785 };
    786 
    787 
    788 /**
    789  * Reads a signed 64-bit fixed-length integer fiield from the binary stream, or
    790  * throws an error if the next field in the stream is not of the correct wire
    791  * type.
    792  *
    793  * @return {number} The value of the float field.
    794  */
    795 jspb.BinaryReader.prototype.readSfixed64 = function() {
    796   goog.asserts.assert(
    797       this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64);
    798   return this.decoder_.readInt64();
    799 };
    800 
    801 
    802 /**
    803  * Reads a 32-bit floating-point field from the binary stream, or throws an
    804  * error if the next field in the stream is not of the correct wire type.
    805  *
    806  * @return {number} The value of the float field.
    807  */
    808 jspb.BinaryReader.prototype.readFloat = function() {
    809   goog.asserts.assert(
    810       this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED32);
    811   return this.decoder_.readFloat();
    812 };
    813 
    814 
    815 /**
    816  * Reads a 64-bit floating-point field from the binary stream, or throws an
    817  * error if the next field in the stream is not of the correct wire type.
    818  *
    819  * @return {number} The value of the double field.
    820  */
    821 jspb.BinaryReader.prototype.readDouble = function() {
    822   goog.asserts.assert(
    823       this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64);
    824   return this.decoder_.readDouble();
    825 };
    826 
    827 
    828 /**
    829  * Reads a boolean field from the binary stream, or throws an error if the next
    830  * field in the stream is not of the correct wire type.
    831  *
    832  * @return {boolean} The value of the boolean field.
    833  */
    834 jspb.BinaryReader.prototype.readBool = function() {
    835   goog.asserts.assert(
    836       this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
    837   return !!this.decoder_.readUnsignedVarint32();
    838 };
    839 
    840 
    841 /**
    842  * Reads an enum field from the binary stream, or throws an error if the next
    843  * field in the stream is not of the correct wire type.
    844  *
    845  * @return {number} The value of the enum field.
    846  */
    847 jspb.BinaryReader.prototype.readEnum = function() {
    848   goog.asserts.assert(
    849       this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
    850   return this.decoder_.readSignedVarint64();
    851 };
    852 
    853 
    854 /**
    855  * Reads a string field from the binary stream, or throws an error if the next
    856  * field in the stream is not of the correct wire type.
    857  *
    858  * @return {string} The value of the string field.
    859  */
    860 jspb.BinaryReader.prototype.readString = function() {
    861   goog.asserts.assert(
    862       this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED);
    863   var length = this.decoder_.readUnsignedVarint32();
    864   return this.decoder_.readString(length);
    865 };
    866 
    867 
    868 /**
    869  * Reads a length-prefixed block of bytes from the binary stream, or returns
    870  * null if the next field in the stream has an invalid length value.
    871  *
    872  * @return {!Uint8Array} The block of bytes.
    873  */
    874 jspb.BinaryReader.prototype.readBytes = function() {
    875   goog.asserts.assert(
    876       this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED);
    877   var length = this.decoder_.readUnsignedVarint32();
    878   return this.decoder_.readBytes(length);
    879 };
    880 
    881 
    882 /**
    883  * Reads a 64-bit varint or fixed64 field from the stream and returns it as a
    884  * 8-character Unicode string for use as a hash table key, or throws an error
    885  * if the next field in the stream is not of the correct wire type.
    886  *
    887  * @return {string} The hash value.
    888  */
    889 jspb.BinaryReader.prototype.readVarintHash64 = function() {
    890   goog.asserts.assert(
    891       this.nextWireType_ == jspb.BinaryConstants.WireType.VARINT);
    892   return this.decoder_.readVarintHash64();
    893 };
    894 
    895 
    896 /**
    897  * Reads a 64-bit varint or fixed64 field from the stream and returns it as a
    898  * 8-character Unicode string for use as a hash table key, or throws an error
    899  * if the next field in the stream is not of the correct wire type.
    900  *
    901  * @return {string} The hash value.
    902  */
    903 jspb.BinaryReader.prototype.readFixedHash64 = function() {
    904   goog.asserts.assert(
    905       this.nextWireType_ == jspb.BinaryConstants.WireType.FIXED64);
    906   return this.decoder_.readFixedHash64();
    907 };
    908 
    909 
    910 /**
    911  * Reads a packed scalar field using the supplied raw reader function.
    912  * @param {function()} decodeMethod
    913  * @return {!Array}
    914  * @private
    915  */
    916 jspb.BinaryReader.prototype.readPackedField_ = function(decodeMethod) {
    917   goog.asserts.assert(
    918       this.nextWireType_ == jspb.BinaryConstants.WireType.DELIMITED);
    919   var length = this.decoder_.readUnsignedVarint32();
    920   var end = this.decoder_.getCursor() + length;
    921   var result = [];
    922   while (this.decoder_.getCursor() < end) {
    923     // TODO(aappleby): .call is slow
    924     result.push(decodeMethod.call(this.decoder_));
    925   }
    926   return result;
    927 };
    928 
    929 
    930 /**
    931  * Reads a packed int32 field, which consists of a length header and a list of
    932  * signed varints.
    933  * @return {!Array.<number>}
    934  */
    935 jspb.BinaryReader.prototype.readPackedInt32 = function() {
    936   return this.readPackedField_(this.decoder_.readSignedVarint32);
    937 };
    938 
    939 
    940 /**
    941  * Reads a packed int32 field, which consists of a length header and a list of
    942  * signed varints. Returns a list of strings.
    943  * @return {!Array.<string>}
    944  */
    945 jspb.BinaryReader.prototype.readPackedInt32String = function() {
    946   return this.readPackedField_(this.decoder_.readSignedVarint32String);
    947 };
    948 
    949 
    950 /**
    951  * Reads a packed int64 field, which consists of a length header and a list of
    952  * signed varints.
    953  * @return {!Array.<number>}
    954  */
    955 jspb.BinaryReader.prototype.readPackedInt64 = function() {
    956   return this.readPackedField_(this.decoder_.readSignedVarint64);
    957 };
    958 
    959 
    960 /**
    961  * Reads a packed int64 field, which consists of a length header and a list of
    962  * signed varints. Returns a list of strings.
    963  * @return {!Array.<string>}
    964  */
    965 jspb.BinaryReader.prototype.readPackedInt64String = function() {
    966   return this.readPackedField_(this.decoder_.readSignedVarint64String);
    967 };
    968 
    969 
    970 /**
    971  * Reads a packed uint32 field, which consists of a length header and a list of
    972  * unsigned varints.
    973  * @return {!Array.<number>}
    974  */
    975 jspb.BinaryReader.prototype.readPackedUint32 = function() {
    976   return this.readPackedField_(this.decoder_.readUnsignedVarint32);
    977 };
    978 
    979 
    980 /**
    981  * Reads a packed uint32 field, which consists of a length header and a list of
    982  * unsigned varints. Returns a list of strings.
    983  * @return {!Array.<string>}
    984  */
    985 jspb.BinaryReader.prototype.readPackedUint32String = function() {
    986   return this.readPackedField_(this.decoder_.readUnsignedVarint32String);
    987 };
    988 
    989 
    990 /**
    991  * Reads a packed uint64 field, which consists of a length header and a list of
    992  * unsigned varints.
    993  * @return {!Array.<number>}
    994  */
    995 jspb.BinaryReader.prototype.readPackedUint64 = function() {
    996   return this.readPackedField_(this.decoder_.readUnsignedVarint64);
    997 };
    998 
    999 
   1000 /**
   1001  * Reads a packed uint64 field, which consists of a length header and a list of
   1002  * unsigned varints. Returns a list of strings.
   1003  * @return {!Array.<string>}
   1004  */
   1005 jspb.BinaryReader.prototype.readPackedUint64String = function() {
   1006   return this.readPackedField_(this.decoder_.readUnsignedVarint64String);
   1007 };
   1008 
   1009 
   1010 /**
   1011  * Reads a packed sint32 field, which consists of a length header and a list of
   1012  * zigzag varints.
   1013  * @return {!Array.<number>}
   1014  */
   1015 jspb.BinaryReader.prototype.readPackedSint32 = function() {
   1016   return this.readPackedField_(this.decoder_.readZigzagVarint32);
   1017 };
   1018 
   1019 
   1020 /**
   1021  * Reads a packed sint64 field, which consists of a length header and a list of
   1022  * zigzag varints.
   1023  * @return {!Array.<number>}
   1024  */
   1025 jspb.BinaryReader.prototype.readPackedSint64 = function() {
   1026   return this.readPackedField_(this.decoder_.readZigzagVarint64);
   1027 };
   1028 
   1029 
   1030 /**
   1031  * Reads a packed fixed32 field, which consists of a length header and a list
   1032  * of unsigned 32-bit ints.
   1033  * @return {!Array.<number>}
   1034  */
   1035 jspb.BinaryReader.prototype.readPackedFixed32 = function() {
   1036   return this.readPackedField_(this.decoder_.readUint32);
   1037 };
   1038 
   1039 
   1040 /**
   1041  * Reads a packed fixed64 field, which consists of a length header and a list
   1042  * of unsigned 64-bit ints.
   1043  * @return {!Array.<number>}
   1044  */
   1045 jspb.BinaryReader.prototype.readPackedFixed64 = function() {
   1046   return this.readPackedField_(this.decoder_.readUint64);
   1047 };
   1048 
   1049 
   1050 /**
   1051  * Reads a packed sfixed32 field, which consists of a length header and a list
   1052  * of 32-bit ints.
   1053  * @return {!Array.<number>}
   1054  */
   1055 jspb.BinaryReader.prototype.readPackedSfixed32 = function() {
   1056   return this.readPackedField_(this.decoder_.readInt32);
   1057 };
   1058 
   1059 
   1060 /**
   1061  * Reads a packed sfixed64 field, which consists of a length header and a list
   1062  * of 64-bit ints.
   1063  * @return {!Array.<number>}
   1064  */
   1065 jspb.BinaryReader.prototype.readPackedSfixed64 = function() {
   1066   return this.readPackedField_(this.decoder_.readInt64);
   1067 };
   1068 
   1069 
   1070 /**
   1071  * Reads a packed float field, which consists of a length header and a list of
   1072  * floats.
   1073  * @return {!Array.<number>}
   1074  */
   1075 jspb.BinaryReader.prototype.readPackedFloat = function() {
   1076   return this.readPackedField_(this.decoder_.readFloat);
   1077 };
   1078 
   1079 
   1080 /**
   1081  * Reads a packed double field, which consists of a length header and a list of
   1082  * doubles.
   1083  * @return {!Array.<number>}
   1084  */
   1085 jspb.BinaryReader.prototype.readPackedDouble = function() {
   1086   return this.readPackedField_(this.decoder_.readDouble);
   1087 };
   1088 
   1089 
   1090 /**
   1091  * Reads a packed bool field, which consists of a length header and a list of
   1092  * unsigned varints.
   1093  * @return {!Array.<boolean>}
   1094  */
   1095 jspb.BinaryReader.prototype.readPackedBool = function() {
   1096   return this.readPackedField_(this.decoder_.readBool);
   1097 };
   1098 
   1099 
   1100 /**
   1101  * Reads a packed enum field, which consists of a length header and a list of
   1102  * unsigned varints.
   1103  * @return {!Array.<number>}
   1104  */
   1105 jspb.BinaryReader.prototype.readPackedEnum = function() {
   1106   return this.readPackedField_(this.decoder_.readEnum);
   1107 };
   1108 
   1109 
   1110 /**
   1111  * Reads a packed varint hash64 field, which consists of a length header and a
   1112  * list of varint hash64s.
   1113  * @return {!Array.<string>}
   1114  */
   1115 jspb.BinaryReader.prototype.readPackedVarintHash64 = function() {
   1116   return this.readPackedField_(this.decoder_.readVarintHash64);
   1117 };
   1118 
   1119 
   1120 /**
   1121  * Reads a packed fixed hash64 field, which consists of a length header and a
   1122  * list of fixed hash64s.
   1123  * @return {!Array.<string>}
   1124  */
   1125 jspb.BinaryReader.prototype.readPackedFixedHash64 = function() {
   1126   return this.readPackedField_(this.decoder_.readFixedHash64);
   1127 };
   1128