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 encoding Javascript objects
     33  * into binary, wire-format protocol buffers (in the form of Uint8Arrays) that
     34  * a server can consume directly.
     35  *
     36  * jspb's BinaryWriter class defines methods for efficiently encoding
     37  * Javascript objects into binary, wire-format protocol buffers and supports
     38  * all the fundamental field types used in protocol buffers.
     39  *
     40  * Major caveat 1 - Users of this library _must_ keep their Javascript proto
     41  * parsing code in sync with the original .proto file - presumably you'll be
     42  * using the typed jspb code generator, but if you bypass that you'll need
     43  * to keep things in sync by hand.
     44  *
     45  * Major caveat 2 - Javascript is unable to accurately represent integers
     46  * larger than 2^53 due to its use of a double-precision floating point format
     47  * for all numbers. BinaryWriter does not make any special effort to preserve
     48  * precision for values above this limit - if you need to pass 64-bit integers
     49  * (hash codes, for example) between the client and server without precision
     50  * loss, do _not_ use this library.
     51  *
     52  * Major caveat 3 - This class uses typed arrays and must not be used on older
     53  * browsers that do not support them.
     54  *
     55  * @author aappleby (a] google.com (Austin Appleby)
     56  */
     57 
     58 goog.provide('jspb.BinaryWriter');
     59 
     60 goog.require('goog.asserts');
     61 goog.require('goog.crypt.base64');
     62 goog.require('jspb.BinaryConstants');
     63 goog.require('jspb.BinaryEncoder');
     64 goog.require('jspb.arith.Int64');
     65 goog.require('jspb.arith.UInt64');
     66 goog.require('jspb.utils');
     67 
     68 
     69 
     70 /**
     71  * BinaryWriter implements encoders for all the wire types specified in
     72  * https://developers.google.com/protocol-buffers/docs/encoding.
     73  *
     74  * @constructor
     75  * @struct
     76  */
     77 jspb.BinaryWriter = function() {
     78   /**
     79    * Blocks of serialized data that will be concatenated once all messages have
     80    * been written.
     81    * @private {!Array<!Uint8Array|!Array<number>>}
     82    */
     83   this.blocks_ = [];
     84 
     85   /**
     86    * Total number of bytes in the blocks_ array. Does _not_ include bytes in
     87    * the encoder below.
     88    * @private {number}
     89    */
     90   this.totalLength_ = 0;
     91 
     92   /**
     93    * Binary encoder holding pieces of a message that we're still serializing.
     94    * When we get to a stopping point (either the start of a new submessage, or
     95    * when we need to append a raw Uint8Array), the encoder's buffer will be
     96    * added to the block array above and the encoder will be reset.
     97    * @private {!jspb.BinaryEncoder}
     98    */
     99   this.encoder_ = new jspb.BinaryEncoder();
    100 
    101   /**
    102    * A stack of bookmarks containing the parent blocks for each message started
    103    * via beginSubMessage(), needed as bookkeeping for endSubMessage().
    104    * TODO(aappleby): Deprecated, users should be calling writeMessage().
    105    * @private {!Array.<!Array.<number>>}
    106    */
    107   this.bookmarks_ = [];
    108 };
    109 
    110 
    111 /**
    112  * Append a typed array of bytes onto the buffer.
    113  *
    114  * @param {!Uint8Array} arr The byte array to append.
    115  * @private
    116  */
    117 jspb.BinaryWriter.prototype.appendUint8Array_ = function(arr) {
    118   var temp = this.encoder_.end();
    119   this.blocks_.push(temp);
    120   this.blocks_.push(arr);
    121   this.totalLength_ += temp.length + arr.length;
    122 };
    123 
    124 
    125 /**
    126  * Begins a new message by writing the field header and returning a bookmark
    127  * which we will use to patch in the message length to in endDelimited_ below.
    128  * @param {number} field
    129  * @return {!Array.<number>}
    130  * @private
    131  */
    132 jspb.BinaryWriter.prototype.beginDelimited_ = function(field) {
    133   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
    134   var bookmark = this.encoder_.end();
    135   this.blocks_.push(bookmark);
    136   this.totalLength_ += bookmark.length;
    137   bookmark.push(this.totalLength_);
    138   return bookmark;
    139 };
    140 
    141 
    142 /**
    143  * Ends a message by encoding the _change_ in length of the buffer to the
    144  * parent block and adds the number of bytes needed to encode that length to
    145  * the total byte length.
    146  * @param {!Array.<number>} bookmark
    147  * @private
    148  */
    149 jspb.BinaryWriter.prototype.endDelimited_ = function(bookmark) {
    150   var oldLength = bookmark.pop();
    151   var messageLength = this.totalLength_ + this.encoder_.length() - oldLength;
    152   goog.asserts.assert(messageLength >= 0);
    153 
    154   while (messageLength > 127) {
    155     bookmark.push((messageLength & 0x7f) | 0x80);
    156     messageLength = messageLength >>> 7;
    157     this.totalLength_++;
    158   }
    159 
    160   bookmark.push(messageLength);
    161   this.totalLength_++;
    162 };
    163 
    164 
    165 /**
    166  * Writes a pre-serialized message to the buffer.
    167  * @param {!Uint8Array} bytes The array of bytes to write.
    168  * @param {number} start The start of the range to write.
    169  * @param {number} end The end of the range to write.
    170  */
    171 jspb.BinaryWriter.prototype.writeSerializedMessage = function(
    172     bytes, start, end) {
    173   this.appendUint8Array_(bytes.subarray(start, end));
    174 };
    175 
    176 
    177 /**
    178  * Writes a pre-serialized message to the buffer if the message and endpoints
    179  * are non-null.
    180  * @param {?Uint8Array} bytes The array of bytes to write.
    181  * @param {?number} start The start of the range to write.
    182  * @param {?number} end The end of the range to write.
    183  */
    184 jspb.BinaryWriter.prototype.maybeWriteSerializedMessage = function(
    185     bytes, start, end) {
    186   if (bytes != null && start != null && end != null) {
    187     this.writeSerializedMessage(bytes, start, end);
    188   }
    189 };
    190 
    191 
    192 /**
    193  * Resets the writer, throwing away any accumulated buffers.
    194  */
    195 jspb.BinaryWriter.prototype.reset = function() {
    196   this.blocks_ = [];
    197   this.encoder_.end();
    198   this.totalLength_ = 0;
    199   this.bookmarks_ = [];
    200 };
    201 
    202 
    203 /**
    204  * Converts the encoded data into a Uint8Array.
    205  * @return {!Uint8Array}
    206  */
    207 jspb.BinaryWriter.prototype.getResultBuffer = function() {
    208   goog.asserts.assert(this.bookmarks_.length == 0);
    209 
    210   var flat = new Uint8Array(this.totalLength_ + this.encoder_.length());
    211 
    212   var blocks = this.blocks_;
    213   var blockCount = blocks.length;
    214   var offset = 0;
    215 
    216   for (var i = 0; i < blockCount; i++) {
    217     var block = blocks[i];
    218     flat.set(block, offset);
    219     offset += block.length;
    220   }
    221 
    222   var tail = this.encoder_.end();
    223   flat.set(tail, offset);
    224   offset += tail.length;
    225 
    226   // Post condition: `flattened` must have had every byte written.
    227   goog.asserts.assert(offset == flat.length);
    228 
    229   // Replace our block list with the flattened block, which lets GC reclaim
    230   // the temp blocks sooner.
    231   this.blocks_ = [flat];
    232 
    233   return flat;
    234 };
    235 
    236 
    237 /**
    238  * Converts the encoded data into a bas64-encoded string.
    239  * @return {string}
    240  */
    241 jspb.BinaryWriter.prototype.getResultBase64String = function() {
    242   return goog.crypt.base64.encodeByteArray(this.getResultBuffer());
    243 };
    244 
    245 
    246 /**
    247  * Begins a new sub-message. The client must call endSubMessage() when they're
    248  * done.
    249  * TODO(aappleby): Deprecated. Move callers to writeMessage().
    250  * @param {number} field The field number of the sub-message.
    251  */
    252 jspb.BinaryWriter.prototype.beginSubMessage = function(field) {
    253   this.bookmarks_.push(this.beginDelimited_(field));
    254 };
    255 
    256 
    257 /**
    258  * Finishes a sub-message and packs it into the parent messages' buffer.
    259  * TODO(aappleby): Deprecated. Move callers to writeMessage().
    260  */
    261 jspb.BinaryWriter.prototype.endSubMessage = function() {
    262   goog.asserts.assert(this.bookmarks_.length >= 0);
    263   this.endDelimited_(this.bookmarks_.pop());
    264 };
    265 
    266 
    267 /**
    268  * Encodes a (field number, wire type) tuple into a wire-format field header
    269  * and stores it in the buffer as a varint.
    270  * @param {number} field The field number.
    271  * @param {number} wireType The wire-type of the field, as specified in the
    272  *     protocol buffer documentation.
    273  * @private
    274  */
    275 jspb.BinaryWriter.prototype.writeFieldHeader_ =
    276     function(field, wireType) {
    277   goog.asserts.assert(field >= 1 && field == Math.floor(field));
    278   var x = field * 8 + wireType;
    279   this.encoder_.writeUnsignedVarint32(x);
    280 };
    281 
    282 
    283 /**
    284  * Writes a field of any valid scalar type to the binary stream.
    285  * @param {jspb.BinaryConstants.FieldType} fieldType
    286  * @param {number} field
    287  * @param {jspb.AnyFieldType} value
    288  */
    289 jspb.BinaryWriter.prototype.writeAny = function(fieldType, field, value) {
    290   var fieldTypes = jspb.BinaryConstants.FieldType;
    291   switch (fieldType) {
    292     case fieldTypes.DOUBLE:
    293       this.writeDouble(field, /** @type {number} */(value));
    294       return;
    295     case fieldTypes.FLOAT:
    296       this.writeFloat(field, /** @type {number} */(value));
    297       return;
    298     case fieldTypes.INT64:
    299       this.writeInt64(field, /** @type {number} */(value));
    300       return;
    301     case fieldTypes.UINT64:
    302       this.writeUint64(field, /** @type {number} */(value));
    303       return;
    304     case fieldTypes.INT32:
    305       this.writeInt32(field, /** @type {number} */(value));
    306       return;
    307     case fieldTypes.FIXED64:
    308       this.writeFixed64(field, /** @type {number} */(value));
    309       return;
    310     case fieldTypes.FIXED32:
    311       this.writeFixed32(field, /** @type {number} */(value));
    312       return;
    313     case fieldTypes.BOOL:
    314       this.writeBool(field, /** @type {boolean} */(value));
    315       return;
    316     case fieldTypes.STRING:
    317       this.writeString(field, /** @type {string} */(value));
    318       return;
    319     case fieldTypes.GROUP:
    320       goog.asserts.fail('Group field type not supported in writeAny()');
    321       return;
    322     case fieldTypes.MESSAGE:
    323       goog.asserts.fail('Message field type not supported in writeAny()');
    324       return;
    325     case fieldTypes.BYTES:
    326       this.writeBytes(field, /** @type {?Uint8Array} */(value));
    327       return;
    328     case fieldTypes.UINT32:
    329       this.writeUint32(field, /** @type {number} */(value));
    330       return;
    331     case fieldTypes.ENUM:
    332       this.writeEnum(field, /** @type {number} */(value));
    333       return;
    334     case fieldTypes.SFIXED32:
    335       this.writeSfixed32(field, /** @type {number} */(value));
    336       return;
    337     case fieldTypes.SFIXED64:
    338       this.writeSfixed64(field, /** @type {number} */(value));
    339       return;
    340     case fieldTypes.SINT32:
    341       this.writeSint32(field, /** @type {number} */(value));
    342       return;
    343     case fieldTypes.SINT64:
    344       this.writeSint64(field, /** @type {number} */(value));
    345       return;
    346     case fieldTypes.FHASH64:
    347       this.writeFixedHash64(field, /** @type {string} */(value));
    348       return;
    349     case fieldTypes.VHASH64:
    350       this.writeVarintHash64(field, /** @type {string} */(value));
    351       return;
    352     default:
    353       goog.asserts.fail('Invalid field type in writeAny()');
    354       return;
    355   }
    356 };
    357 
    358 
    359 /**
    360  * Writes a varint field to the buffer without range checking.
    361  * @param {number} field The field number.
    362  * @param {number?} value The value to write.
    363  * @private
    364  */
    365 jspb.BinaryWriter.prototype.writeUnsignedVarint32_ = function(field, value) {
    366   if (value == null) return;
    367   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
    368   this.encoder_.writeUnsignedVarint32(value);
    369 };
    370 
    371 
    372 /**
    373  * Writes a varint field to the buffer without range checking.
    374  * @param {number} field The field number.
    375  * @param {number?} value The value to write.
    376  * @private
    377  */
    378 jspb.BinaryWriter.prototype.writeSignedVarint32_ = function(field, value) {
    379   if (value == null) return;
    380   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
    381   this.encoder_.writeSignedVarint32(value);
    382 };
    383 
    384 
    385 /**
    386  * Writes a varint field to the buffer without range checking.
    387  * @param {number} field The field number.
    388  * @param {number?} value The value to write.
    389  * @private
    390  */
    391 jspb.BinaryWriter.prototype.writeUnsignedVarint64_ = function(field, value) {
    392   if (value == null) return;
    393   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
    394   this.encoder_.writeUnsignedVarint64(value);
    395 };
    396 
    397 
    398 /**
    399  * Writes a varint field to the buffer without range checking.
    400  * @param {number} field The field number.
    401  * @param {number?} value The value to write.
    402  * @private
    403  */
    404 jspb.BinaryWriter.prototype.writeSignedVarint64_ = function(field, value) {
    405   if (value == null) return;
    406   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
    407   this.encoder_.writeSignedVarint64(value);
    408 };
    409 
    410 
    411 /**
    412  * Writes a zigzag varint field to the buffer without range checking.
    413  * @param {number} field The field number.
    414  * @param {number?} value The value to write.
    415  * @private
    416  */
    417 jspb.BinaryWriter.prototype.writeZigzagVarint32_ = function(field, value) {
    418   if (value == null) return;
    419   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
    420   this.encoder_.writeZigzagVarint32(value);
    421 };
    422 
    423 
    424 /**
    425  * Writes a zigzag varint field to the buffer without range checking.
    426  * @param {number} field The field number.
    427  * @param {number?} value The value to write.
    428  * @private
    429  */
    430 jspb.BinaryWriter.prototype.writeZigzagVarint64_ = function(field, value) {
    431   if (value == null) return;
    432   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
    433   this.encoder_.writeZigzagVarint64(value);
    434 };
    435 
    436 
    437 /**
    438  * Writes an int32 field to the buffer. Numbers outside the range [-2^31,2^31)
    439  * will be truncated.
    440  * @param {number} field The field number.
    441  * @param {number?} value The value to write.
    442  */
    443 jspb.BinaryWriter.prototype.writeInt32 = function(field, value) {
    444   if (value == null) return;
    445   goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
    446                       (value < jspb.BinaryConstants.TWO_TO_31));
    447   this.writeSignedVarint32_(field, value);
    448 };
    449 
    450 
    451 /**
    452  * Writes an int32 field represented as a string to the buffer. Numbers outside
    453  * the range [-2^31,2^31) will be truncated.
    454  * @param {number} field The field number.
    455  * @param {string?} value The value to write.
    456  */
    457 jspb.BinaryWriter.prototype.writeInt32String = function(field, value) {
    458   if (value == null) return;
    459   var intValue = /** {number} */ parseInt(value, 10);
    460   goog.asserts.assert((intValue >= -jspb.BinaryConstants.TWO_TO_31) &&
    461                       (intValue < jspb.BinaryConstants.TWO_TO_31));
    462   this.writeSignedVarint32_(field, intValue);
    463 };
    464 
    465 
    466 /**
    467  * Writes an int64 field to the buffer. Numbers outside the range [-2^63,2^63)
    468  * will be truncated.
    469  * @param {number} field The field number.
    470  * @param {number?} value The value to write.
    471  */
    472 jspb.BinaryWriter.prototype.writeInt64 = function(field, value) {
    473   if (value == null) return;
    474   goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
    475                       (value < jspb.BinaryConstants.TWO_TO_63));
    476   this.writeSignedVarint64_(field, value);
    477 };
    478 
    479 
    480 /**
    481  * Writes a int64 field (with value as a string) to the buffer.
    482  * @param {number} field The field number.
    483  * @param {string?} value The value to write.
    484  */
    485 jspb.BinaryWriter.prototype.writeInt64String = function(field, value) {
    486   if (value == null) return;
    487   var num = jspb.arith.Int64.fromString(value);
    488   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
    489   this.encoder_.writeSplitVarint64(num.lo, num.hi);
    490 };
    491 
    492 
    493 /**
    494  * Writes a uint32 field to the buffer. Numbers outside the range [0,2^32)
    495  * will be truncated.
    496  * @param {number} field The field number.
    497  * @param {number?} value The value to write.
    498  */
    499 jspb.BinaryWriter.prototype.writeUint32 = function(field, value) {
    500   if (value == null) return;
    501   goog.asserts.assert((value >= 0) &&
    502                       (value < jspb.BinaryConstants.TWO_TO_32));
    503   this.writeUnsignedVarint32_(field, value);
    504 };
    505 
    506 
    507 /**
    508  * Writes a uint32 field represented as a string to the buffer. Numbers outside
    509  * the range [0,2^32) will be truncated.
    510  * @param {number} field The field number.
    511  * @param {string?} value The value to write.
    512  */
    513 jspb.BinaryWriter.prototype.writeUint32String = function(field, value) {
    514   if (value == null) return;
    515   var intValue = /** {number} */ parseInt(value, 10);
    516   goog.asserts.assert((intValue >= 0) &&
    517                       (intValue < jspb.BinaryConstants.TWO_TO_32));
    518   this.writeUnsignedVarint32_(field, intValue);
    519 };
    520 
    521 
    522 /**
    523  * Writes a uint64 field to the buffer. Numbers outside the range [0,2^64)
    524  * will be truncated.
    525  * @param {number} field The field number.
    526  * @param {number?} value The value to write.
    527  */
    528 jspb.BinaryWriter.prototype.writeUint64 = function(field, value) {
    529   if (value == null) return;
    530   goog.asserts.assert((value >= 0) &&
    531                       (value < jspb.BinaryConstants.TWO_TO_64));
    532   this.writeUnsignedVarint64_(field, value);
    533 };
    534 
    535 
    536 /**
    537  * Writes a uint64 field (with value as a string) to the buffer.
    538  * @param {number} field The field number.
    539  * @param {string?} value The value to write.
    540  */
    541 jspb.BinaryWriter.prototype.writeUint64String = function(field, value) {
    542   if (value == null) return;
    543   var num = jspb.arith.UInt64.fromString(value);
    544   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
    545   this.encoder_.writeSplitVarint64(num.lo, num.hi);
    546 };
    547 
    548 
    549 /**
    550  * Writes a sint32 field to the buffer. Numbers outside the range [-2^31,2^31)
    551  * will be truncated.
    552  * @param {number} field The field number.
    553  * @param {number?} value The value to write.
    554  */
    555 jspb.BinaryWriter.prototype.writeSint32 = function(field, value) {
    556   if (value == null) return;
    557   goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
    558                       (value < jspb.BinaryConstants.TWO_TO_31));
    559   this.writeZigzagVarint32_(field, value);
    560 };
    561 
    562 
    563 /**
    564  * Writes a sint64 field to the buffer. Numbers outside the range [-2^63,2^63)
    565  * will be truncated.
    566  * @param {number} field The field number.
    567  * @param {number?} value The value to write.
    568  */
    569 jspb.BinaryWriter.prototype.writeSint64 = function(field, value) {
    570   if (value == null) return;
    571   goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
    572                       (value < jspb.BinaryConstants.TWO_TO_63));
    573   this.writeZigzagVarint64_(field, value);
    574 };
    575 
    576 
    577 /**
    578  * Writes a fixed32 field to the buffer. Numbers outside the range [0,2^32)
    579  * will be truncated.
    580  * @param {number} field The field number.
    581  * @param {number?} value The value to write.
    582  */
    583 jspb.BinaryWriter.prototype.writeFixed32 = function(field, value) {
    584   if (value == null) return;
    585   goog.asserts.assert((value >= 0) &&
    586                       (value < jspb.BinaryConstants.TWO_TO_32));
    587   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
    588   this.encoder_.writeUint32(value);
    589 };
    590 
    591 
    592 /**
    593  * Writes a fixed64 field to the buffer. Numbers outside the range [0,2^64)
    594  * will be truncated.
    595  * @param {number} field The field number.
    596  * @param {number?} value The value to write.
    597  */
    598 jspb.BinaryWriter.prototype.writeFixed64 = function(field, value) {
    599   if (value == null) return;
    600   goog.asserts.assert((value >= 0) &&
    601                       (value < jspb.BinaryConstants.TWO_TO_64));
    602   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
    603   this.encoder_.writeUint64(value);
    604 };
    605 
    606 
    607 /**
    608  * Writes a sfixed32 field to the buffer. Numbers outside the range
    609  * [-2^31,2^31) will be truncated.
    610  * @param {number} field The field number.
    611  * @param {number?} value The value to write.
    612  */
    613 jspb.BinaryWriter.prototype.writeSfixed32 = function(field, value) {
    614   if (value == null) return;
    615   goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
    616                       (value < jspb.BinaryConstants.TWO_TO_31));
    617   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
    618   this.encoder_.writeInt32(value);
    619 };
    620 
    621 
    622 /**
    623  * Writes a sfixed64 field to the buffer. Numbers outside the range
    624  * [-2^63,2^63) will be truncated.
    625  * @param {number} field The field number.
    626  * @param {number?} value The value to write.
    627  */
    628 jspb.BinaryWriter.prototype.writeSfixed64 = function(field, value) {
    629   if (value == null) return;
    630   goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_63) &&
    631                       (value < jspb.BinaryConstants.TWO_TO_63));
    632   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
    633   this.encoder_.writeInt64(value);
    634 };
    635 
    636 
    637 /**
    638  * Writes a single-precision floating point field to the buffer. Numbers
    639  * requiring more than 32 bits of precision will be truncated.
    640  * @param {number} field The field number.
    641  * @param {number?} value The value to write.
    642  */
    643 jspb.BinaryWriter.prototype.writeFloat = function(field, value) {
    644   if (value == null) return;
    645   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED32);
    646   this.encoder_.writeFloat(value);
    647 };
    648 
    649 
    650 /**
    651  * Writes a double-precision floating point field to the buffer. As this is the
    652  * native format used by JavaScript, no precision will be lost.
    653  * @param {number} field The field number.
    654  * @param {number?} value The value to write.
    655  */
    656 jspb.BinaryWriter.prototype.writeDouble = function(field, value) {
    657   if (value == null) return;
    658   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
    659   this.encoder_.writeDouble(value);
    660 };
    661 
    662 
    663 /**
    664  * Writes a boolean field to the buffer.
    665  * @param {number} field The field number.
    666  * @param {boolean?} value The value to write.
    667  */
    668 jspb.BinaryWriter.prototype.writeBool = function(field, value) {
    669   if (value == null) return;
    670   goog.asserts.assert(goog.isBoolean(value));
    671   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
    672   this.encoder_.writeBool(value);
    673 };
    674 
    675 
    676 /**
    677  * Writes an enum field to the buffer.
    678  * @param {number} field The field number.
    679  * @param {number?} value The value to write.
    680  */
    681 jspb.BinaryWriter.prototype.writeEnum = function(field, value) {
    682   if (value == null) return;
    683   goog.asserts.assert((value >= -jspb.BinaryConstants.TWO_TO_31) &&
    684                       (value < jspb.BinaryConstants.TWO_TO_31));
    685   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
    686   this.encoder_.writeSignedVarint32(value);
    687 };
    688 
    689 
    690 /**
    691  * Writes a string field to the buffer.
    692  * @param {number} field The field number.
    693  * @param {string?} value The string to write.
    694  */
    695 jspb.BinaryWriter.prototype.writeString = function(field, value) {
    696   if (value == null) return;
    697   var bookmark = this.beginDelimited_(field);
    698   this.encoder_.writeString(value);
    699   this.endDelimited_(bookmark);
    700 };
    701 
    702 
    703 /**
    704  * Writes an arbitrary byte field to the buffer. Note - to match the behavior
    705  * of the C++ implementation, empty byte arrays _are_ serialized.
    706  * @param {number} field The field number.
    707  * @param {?jspb.ByteSource} value The array of bytes to write.
    708  */
    709 jspb.BinaryWriter.prototype.writeBytes = function(field, value) {
    710   if (value == null) return;
    711   var bytes = jspb.utils.byteSourceToUint8Array(value);
    712   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
    713   this.encoder_.writeUnsignedVarint32(bytes.length);
    714   this.appendUint8Array_(bytes);
    715 };
    716 
    717 
    718 /**
    719  * Writes a message to the buffer.
    720  * @template MessageType
    721  * @param {number} field The field number.
    722  * @param {?MessageType} value The message to write.
    723  * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
    724  *     to write and the writer to write it with.
    725  */
    726 jspb.BinaryWriter.prototype.writeMessage = function(
    727     field, value, writerCallback) {
    728   if (value == null) return;
    729   var bookmark = this.beginDelimited_(field);
    730   writerCallback(value, this);
    731   this.endDelimited_(bookmark);
    732 };
    733 
    734 
    735 /**
    736  * Writes a group message to the buffer.
    737  *
    738  * @template MessageType
    739  * @param {number} field The field number.
    740  * @param {?MessageType} value The message to write, wrapped with START_GROUP /
    741  *     END_GROUP tags. Will be a no-op if 'value' is null.
    742  * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
    743  *     to write and the writer to write it with.
    744  */
    745 jspb.BinaryWriter.prototype.writeGroup = function(
    746     field, value, writerCallback) {
    747   if (value == null) return;
    748   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.START_GROUP);
    749   writerCallback(value, this);
    750   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.END_GROUP);
    751 };
    752 
    753 
    754 /**
    755  * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
    756  * the buffer.
    757  * @param {number} field The field number.
    758  * @param {string?} value The hash string.
    759  */
    760 jspb.BinaryWriter.prototype.writeFixedHash64 = function(field, value) {
    761   if (value == null) return;
    762   goog.asserts.assert(value.length == 8);
    763   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.FIXED64);
    764   this.encoder_.writeFixedHash64(value);
    765 };
    766 
    767 
    768 /**
    769  * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
    770  * the buffer.
    771  * @param {number} field The field number.
    772  * @param {string?} value The hash string.
    773  */
    774 jspb.BinaryWriter.prototype.writeVarintHash64 = function(field, value) {
    775   if (value == null) return;
    776   goog.asserts.assert(value.length == 8);
    777   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.VARINT);
    778   this.encoder_.writeVarintHash64(value);
    779 };
    780 
    781 
    782 /**
    783  * Writes an array of numbers to the buffer as a repeated varint field.
    784  * @param {number} field The field number.
    785  * @param {?Array.<number>} value The array of ints to write.
    786  * @private
    787  */
    788 jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint32_ =
    789     function(field, value) {
    790   if (value == null) return;
    791   for (var i = 0; i < value.length; i++) {
    792     this.writeUnsignedVarint32_(field, value[i]);
    793   }
    794 };
    795 
    796 
    797 /**
    798  * Writes an array of numbers to the buffer as a repeated varint field.
    799  * @param {number} field The field number.
    800  * @param {?Array.<number>} value The array of ints to write.
    801  * @private
    802  */
    803 jspb.BinaryWriter.prototype.writeRepeatedSignedVarint32_ =
    804     function(field, value) {
    805   if (value == null) return;
    806   for (var i = 0; i < value.length; i++) {
    807     this.writeSignedVarint32_(field, value[i]);
    808   }
    809 };
    810 
    811 
    812 /**
    813  * Writes an array of numbers to the buffer as a repeated varint field.
    814  * @param {number} field The field number.
    815  * @param {?Array.<number>} value The array of ints to write.
    816  * @private
    817  */
    818 jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint64_ =
    819     function(field, value) {
    820   if (value == null) return;
    821   for (var i = 0; i < value.length; i++) {
    822     this.writeUnsignedVarint64_(field, value[i]);
    823   }
    824 };
    825 
    826 
    827 /**
    828  * Writes an array of numbers to the buffer as a repeated varint field.
    829  * @param {number} field The field number.
    830  * @param {?Array.<number>} value The array of ints to write.
    831  * @private
    832  */
    833 jspb.BinaryWriter.prototype.writeRepeatedSignedVarint64_ =
    834     function(field, value) {
    835   if (value == null) return;
    836   for (var i = 0; i < value.length; i++) {
    837     this.writeSignedVarint64_(field, value[i]);
    838   }
    839 };
    840 
    841 
    842 /**
    843  * Writes an array of numbers to the buffer as a repeated zigzag field.
    844  * @param {number} field The field number.
    845  * @param {?Array.<number>} value The array of ints to write.
    846  * @private
    847  */
    848 jspb.BinaryWriter.prototype.writeRepeatedZigzag32_ = function(field, value) {
    849   if (value == null) return;
    850   for (var i = 0; i < value.length; i++) {
    851     this.writeZigzagVarint32_(field, value[i]);
    852   }
    853 };
    854 
    855 
    856 /**
    857  * Writes an array of numbers to the buffer as a repeated zigzag field.
    858  * @param {number} field The field number.
    859  * @param {?Array.<number>} value The array of ints to write.
    860  * @private
    861  */
    862 jspb.BinaryWriter.prototype.writeRepeatedZigzag_ = function(field, value) {
    863   if (value == null) return;
    864   for (var i = 0; i < value.length; i++) {
    865     this.writeZigzagVarint64_(field, value[i]);
    866   }
    867 };
    868 
    869 
    870 /**
    871  * Writes an array of numbers to the buffer as a repeated 32-bit int field.
    872  * @param {number} field The field number.
    873  * @param {?Array.<number>} value The array of ints to write.
    874  */
    875 jspb.BinaryWriter.prototype.writeRepeatedInt32 =
    876     jspb.BinaryWriter.prototype.writeRepeatedSignedVarint32_;
    877 
    878 
    879 /**
    880  * Writes an array of numbers formatted as strings to the buffer as a repeated
    881  * 32-bit int field.
    882  * @param {number} field The field number.
    883  * @param {?Array.<string>} value The array of ints to write.
    884  */
    885 jspb.BinaryWriter.prototype.writeRepeatedInt32String =
    886     function(field, value) {
    887   if (value == null) return;
    888   for (var i = 0; i < value.length; i++) {
    889     this.writeInt32String(field, value[i]);
    890   }
    891 };
    892 
    893 
    894 /**
    895  * Writes an array of numbers to the buffer as a repeated 64-bit int field.
    896  * @param {number} field The field number.
    897  * @param {?Array.<number>} value The array of ints to write.
    898  */
    899 jspb.BinaryWriter.prototype.writeRepeatedInt64 =
    900     jspb.BinaryWriter.prototype.writeRepeatedSignedVarint64_;
    901 
    902 
    903 /**
    904  * Writes an array of numbers formatted as strings to the buffer as a repeated
    905  * 64-bit int field.
    906  * @param {number} field The field number.
    907  * @param {?Array.<string>} value The array of ints to write.
    908  */
    909 jspb.BinaryWriter.prototype.writeRepeatedInt64String =
    910     function(field, value) {
    911   if (value == null) return;
    912   for (var i = 0; i < value.length; i++) {
    913     this.writeInt64String(field, value[i]);
    914   }
    915 };
    916 
    917 
    918 /**
    919  * Writes an array numbers to the buffer as a repeated unsigned 32-bit int
    920  *     field.
    921  * @param {number} field The field number.
    922  * @param {?Array.<number>} value The array of ints to write.
    923  */
    924 jspb.BinaryWriter.prototype.writeRepeatedUint32 =
    925     jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint32_;
    926 
    927 
    928 /**
    929  * Writes an array of numbers formatted as strings to the buffer as a repeated
    930  * unsigned 32-bit int field.
    931  * @param {number} field The field number.
    932  * @param {?Array.<string>} value The array of ints to write.
    933  */
    934 jspb.BinaryWriter.prototype.writeRepeatedUint32String =
    935     function(field, value) {
    936   if (value == null) return;
    937   for (var i = 0; i < value.length; i++) {
    938     this.writeUint32String(field, value[i]);
    939   }
    940 };
    941 
    942 
    943 /**
    944  * Writes an array numbers to the buffer as a repeated unsigned 64-bit int
    945  *     field.
    946  * @param {number} field The field number.
    947  * @param {?Array.<number>} value The array of ints to write.
    948  */
    949 jspb.BinaryWriter.prototype.writeRepeatedUint64 =
    950     jspb.BinaryWriter.prototype.writeRepeatedUnsignedVarint64_;
    951 
    952 
    953 /**
    954  * Writes an array of numbers formatted as strings to the buffer as a repeated
    955  * unsigned 64-bit int field.
    956  * @param {number} field The field number.
    957  * @param {?Array.<string>} value The array of ints to write.
    958  */
    959 jspb.BinaryWriter.prototype.writeRepeatedUint64String =
    960     function(field, value) {
    961   if (value == null) return;
    962   for (var i = 0; i < value.length; i++) {
    963     this.writeUint64String(field, value[i]);
    964   }
    965 };
    966 
    967 
    968 /**
    969  * Writes an array numbers to the buffer as a repeated signed 32-bit int field.
    970  * @param {number} field The field number.
    971  * @param {?Array.<number>} value The array of ints to write.
    972  */
    973 jspb.BinaryWriter.prototype.writeRepeatedSint32 =
    974     jspb.BinaryWriter.prototype.writeRepeatedZigzag32_;
    975 
    976 
    977 /**
    978  * Writes an array numbers to the buffer as a repeated signed 64-bit int field.
    979  * @param {number} field The field number.
    980  * @param {?Array.<number>} value The array of ints to write.
    981  */
    982 jspb.BinaryWriter.prototype.writeRepeatedSint64 =
    983     jspb.BinaryWriter.prototype.writeRepeatedZigzag_;
    984 
    985 
    986 /**
    987  * Writes an array of numbers to the buffer as a repeated fixed32 field. This
    988  * works for both signed and unsigned fixed32s.
    989  * @param {number} field The field number.
    990  * @param {?Array.<number>} value The array of ints to write.
    991  */
    992 jspb.BinaryWriter.prototype.writeRepeatedFixed32 = function(field, value) {
    993   if (value == null) return;
    994   for (var i = 0; i < value.length; i++) {
    995     this.writeFixed32(field, value[i]);
    996   }
    997 };
    998 
    999 
   1000 /**
   1001  * Writes an array of numbers to the buffer as a repeated fixed64 field. This
   1002  * works for both signed and unsigned fixed64s.
   1003  * @param {number} field The field number.
   1004  * @param {?Array.<number>} value The array of ints to write.
   1005  */
   1006 jspb.BinaryWriter.prototype.writeRepeatedFixed64 = function(field, value) {
   1007   if (value == null) return;
   1008   for (var i = 0; i < value.length; i++) {
   1009     this.writeFixed64(field, value[i]);
   1010   }
   1011 };
   1012 
   1013 
   1014 /**
   1015  * Writes an array of numbers to the buffer as a repeated sfixed32 field.
   1016  * @param {number} field The field number.
   1017  * @param {?Array.<number>} value The array of ints to write.
   1018  */
   1019 jspb.BinaryWriter.prototype.writeRepeatedSfixed32 = function(field, value) {
   1020   if (value == null) return;
   1021   for (var i = 0; i < value.length; i++) {
   1022     this.writeSfixed32(field, value[i]);
   1023   }
   1024 };
   1025 
   1026 
   1027 /**
   1028  * Writes an array of numbers to the buffer as a repeated sfixed64 field.
   1029  * @param {number} field The field number.
   1030  * @param {?Array.<number>} value The array of ints to write.
   1031  */
   1032 jspb.BinaryWriter.prototype.writeRepeatedSfixed64 = function(field, value) {
   1033   if (value == null) return;
   1034   for (var i = 0; i < value.length; i++) {
   1035     this.writeSfixed64(field, value[i]);
   1036   }
   1037 };
   1038 
   1039 
   1040 /**
   1041  * Writes an array of numbers to the buffer as a repeated float field.
   1042  * @param {number} field The field number.
   1043  * @param {?Array.<number>} value The array of ints to write.
   1044  */
   1045 jspb.BinaryWriter.prototype.writeRepeatedFloat = function(field, value) {
   1046   if (value == null) return;
   1047   for (var i = 0; i < value.length; i++) {
   1048     this.writeFloat(field, value[i]);
   1049   }
   1050 };
   1051 
   1052 
   1053 /**
   1054  * Writes an array of numbers to the buffer as a repeated double field.
   1055  * @param {number} field The field number.
   1056  * @param {?Array.<number>} value The array of ints to write.
   1057  */
   1058 jspb.BinaryWriter.prototype.writeRepeatedDouble = function(field, value) {
   1059   if (value == null) return;
   1060   for (var i = 0; i < value.length; i++) {
   1061     this.writeDouble(field, value[i]);
   1062   }
   1063 };
   1064 
   1065 
   1066 /**
   1067  * Writes an array of booleans to the buffer as a repeated bool field.
   1068  * @param {number} field The field number.
   1069  * @param {?Array.<boolean>} value The array of ints to write.
   1070  */
   1071 jspb.BinaryWriter.prototype.writeRepeatedBool = function(field, value) {
   1072   if (value == null) return;
   1073   for (var i = 0; i < value.length; i++) {
   1074     this.writeBool(field, value[i]);
   1075   }
   1076 };
   1077 
   1078 
   1079 /**
   1080  * Writes an array of enums to the buffer as a repeated enum field.
   1081  * @param {number} field The field number.
   1082  * @param {?Array.<number>} value The array of ints to write.
   1083  */
   1084 jspb.BinaryWriter.prototype.writeRepeatedEnum = function(field, value) {
   1085   if (value == null) return;
   1086   for (var i = 0; i < value.length; i++) {
   1087     this.writeEnum(field, value[i]);
   1088   }
   1089 };
   1090 
   1091 
   1092 /**
   1093  * Writes an array of strings to the buffer as a repeated string field.
   1094  * @param {number} field The field number.
   1095  * @param {?Array.<string>} value The array of strings to write.
   1096  */
   1097 jspb.BinaryWriter.prototype.writeRepeatedString = function(field, value) {
   1098   if (value == null) return;
   1099   for (var i = 0; i < value.length; i++) {
   1100     this.writeString(field, value[i]);
   1101   }
   1102 };
   1103 
   1104 
   1105 /**
   1106  * Writes an array of arbitrary byte fields to the buffer.
   1107  * @param {number} field The field number.
   1108  * @param {?Array.<!jspb.ByteSource>} value The arrays of arrays of bytes to
   1109  *     write.
   1110  */
   1111 jspb.BinaryWriter.prototype.writeRepeatedBytes = function(field, value) {
   1112   if (value == null) return;
   1113   for (var i = 0; i < value.length; i++) {
   1114     this.writeBytes(field, value[i]);
   1115   }
   1116 };
   1117 
   1118 
   1119 /**
   1120  * Writes an array of messages to the buffer.
   1121  * @template MessageType
   1122  * @param {number} field The field number.
   1123  * @param {?Array.<MessageType>} value The array of messages to
   1124  *    write.
   1125  * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
   1126  *     to write and the writer to write it with.
   1127  */
   1128 jspb.BinaryWriter.prototype.writeRepeatedMessage = function(
   1129     field, value, writerCallback) {
   1130   if (value == null) return;
   1131   for (var i = 0; i < value.length; i++) {
   1132     var bookmark = this.beginDelimited_(field);
   1133     writerCallback(value[i], this);
   1134     this.endDelimited_(bookmark);
   1135   }
   1136 };
   1137 
   1138 
   1139 /**
   1140  * Writes an array of group messages to the buffer.
   1141  * @template MessageType
   1142  * @param {number} field The field number.
   1143  * @param {?Array.<MessageType>} value The array of messages to
   1144  *    write.
   1145  * @param {!jspb.WriterFunction} writerCallback Will be invoked with the value
   1146  *     to write and the writer to write it with.
   1147  */
   1148 jspb.BinaryWriter.prototype.writeRepeatedGroup = function(
   1149     field, value, writerCallback) {
   1150   if (value == null) return;
   1151   for (var i = 0; i < value.length; i++) {
   1152     this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.START_GROUP);
   1153     writerCallback(value[i], this);
   1154     this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.END_GROUP);
   1155   }
   1156 };
   1157 
   1158 
   1159 /**
   1160  * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
   1161  * the buffer.
   1162  * @param {number} field The field number.
   1163  * @param {?Array.<string>} value The array of hashes to write.
   1164  */
   1165 jspb.BinaryWriter.prototype.writeRepeatedFixedHash64 =
   1166     function(field, value) {
   1167   if (value == null) return;
   1168   for (var i = 0; i < value.length; i++) {
   1169     this.writeFixedHash64(field, value[i]);
   1170   }
   1171 };
   1172 
   1173 
   1174 /**
   1175  * Writes a repeated 64-bit hash string field (8 characters @ 8 bits of data
   1176  * each) to the buffer.
   1177  * @param {number} field The field number.
   1178  * @param {?Array.<string>} value The array of hashes to write.
   1179  */
   1180 jspb.BinaryWriter.prototype.writeRepeatedVarintHash64 =
   1181     function(field, value) {
   1182   if (value == null) return;
   1183   for (var i = 0; i < value.length; i++) {
   1184     this.writeVarintHash64(field, value[i]);
   1185   }
   1186 };
   1187 
   1188 
   1189 /**
   1190  * Writes an array of numbers to the buffer as a packed varint field.
   1191  * @param {number} field The field number.
   1192  * @param {?Array.<number>} value The array of ints to write.
   1193  * @private
   1194  */
   1195 jspb.BinaryWriter.prototype.writePackedUnsignedVarint32_ = function(
   1196     field, value) {
   1197   if (value == null || !value.length) return;
   1198   var bookmark = this.beginDelimited_(field);
   1199   for (var i = 0; i < value.length; i++) {
   1200     this.encoder_.writeUnsignedVarint32(value[i]);
   1201   }
   1202   this.endDelimited_(bookmark);
   1203 };
   1204 
   1205 
   1206 /**
   1207  * Writes an array of numbers to the buffer as a packed varint field.
   1208  * @param {number} field The field number.
   1209  * @param {?Array.<number>} value The array of ints to write.
   1210  * @private
   1211  */
   1212 jspb.BinaryWriter.prototype.writePackedSignedVarint32_ = function(
   1213     field, value) {
   1214   if (value == null || !value.length) return;
   1215   var bookmark = this.beginDelimited_(field);
   1216   for (var i = 0; i < value.length; i++) {
   1217     this.encoder_.writeSignedVarint32(value[i]);
   1218   }
   1219   this.endDelimited_(bookmark);
   1220 };
   1221 
   1222 
   1223 /**
   1224  * Writes an array of numbers to the buffer as a packed varint field.
   1225  * @param {number} field The field number.
   1226  * @param {?Array.<number>} value The array of ints to write.
   1227  * @private
   1228  */
   1229 jspb.BinaryWriter.prototype.writePackedUnsignedVarint64_ = function(
   1230     field, value) {
   1231   if (value == null || !value.length) return;
   1232   var bookmark = this.beginDelimited_(field);
   1233   for (var i = 0; i < value.length; i++) {
   1234     this.encoder_.writeUnsignedVarint64(value[i]);
   1235   }
   1236   this.endDelimited_(bookmark);
   1237 };
   1238 
   1239 
   1240 /**
   1241  * Writes an array of numbers to the buffer as a packed varint field.
   1242  * @param {number} field The field number.
   1243  * @param {?Array.<number>} value The array of ints to write.
   1244  * @private
   1245  */
   1246 jspb.BinaryWriter.prototype.writePackedSignedVarint64_ = function(
   1247     field, value) {
   1248   if (value == null || !value.length) return;
   1249   var bookmark = this.beginDelimited_(field);
   1250   for (var i = 0; i < value.length; i++) {
   1251     this.encoder_.writeSignedVarint64(value[i]);
   1252   }
   1253   this.endDelimited_(bookmark);
   1254 };
   1255 
   1256 
   1257 /**
   1258  * Writes an array of numbers to the buffer as a packed zigzag field.
   1259  * @param {number} field The field number.
   1260  * @param {?Array.<number>} value The array of ints to write.
   1261  * @private
   1262  */
   1263 jspb.BinaryWriter.prototype.writePackedZigzag32_ = function(field, value) {
   1264   if (value == null || !value.length) return;
   1265   var bookmark = this.beginDelimited_(field);
   1266   for (var i = 0; i < value.length; i++) {
   1267     this.encoder_.writeZigzagVarint32(value[i]);
   1268   }
   1269   this.endDelimited_(bookmark);
   1270 };
   1271 
   1272 
   1273 /**
   1274  * Writes an array of numbers to the buffer as a packed zigzag field.
   1275  * @param {number} field The field number.
   1276  * @param {?Array.<number>} value The array of ints to write.
   1277  * @private
   1278  */
   1279 jspb.BinaryWriter.prototype.writePackedZigzag64_ = function(field, value) {
   1280   if (value == null || !value.length) return;
   1281   var bookmark = this.beginDelimited_(field);
   1282   for (var i = 0; i < value.length; i++) {
   1283     this.encoder_.writeZigzagVarint64(value[i]);
   1284   }
   1285   this.endDelimited_(bookmark);
   1286 };
   1287 
   1288 
   1289 /**
   1290  * Writes an array of numbers to the buffer as a packed 32-bit int field.
   1291  * @param {number} field The field number.
   1292  * @param {?Array.<number>} value The array of ints to write.
   1293  */
   1294 jspb.BinaryWriter.prototype.writePackedInt32 =
   1295     jspb.BinaryWriter.prototype.writePackedSignedVarint32_;
   1296 
   1297 
   1298 /**
   1299  * Writes an array of numbers represented as strings to the buffer as a packed
   1300  * 32-bit int field.
   1301  * @param {number} field
   1302  * @param {?Array.<string>} value
   1303  */
   1304 jspb.BinaryWriter.prototype.writePackedInt32String = function(field, value) {
   1305   if (value == null || !value.length) return;
   1306   var bookmark = this.beginDelimited_(field);
   1307   for (var i = 0; i < value.length; i++) {
   1308     this.encoder_.writeSignedVarint32(parseInt(value[i], 10));
   1309   }
   1310   this.endDelimited_(bookmark);
   1311 };
   1312 
   1313 
   1314 /**
   1315  * Writes an array of numbers to the buffer as a packed 64-bit int field.
   1316  * @param {number} field The field number.
   1317  * @param {?Array.<number>} value The array of ints to write.
   1318  */
   1319 jspb.BinaryWriter.prototype.writePackedInt64 =
   1320     jspb.BinaryWriter.prototype.writePackedSignedVarint64_;
   1321 
   1322 
   1323 /**
   1324  * Writes an array of numbers represented as strings to the buffer as a packed
   1325  * 64-bit int field.
   1326  * @param {number} field
   1327  * @param {?Array.<string>} value
   1328  */
   1329 jspb.BinaryWriter.prototype.writePackedInt64String =
   1330     function(field, value) {
   1331   if (value == null || !value.length) return;
   1332   var bookmark = this.beginDelimited_(field);
   1333   for (var i = 0; i < value.length; i++) {
   1334     var num = jspb.arith.Int64.fromString(value[i]);
   1335     this.encoder_.writeSplitVarint64(num.lo, num.hi);
   1336   }
   1337   this.endDelimited_(bookmark);
   1338 };
   1339 
   1340 
   1341 /**
   1342  * Writes an array numbers to the buffer as a packed unsigned 32-bit int field.
   1343  * @param {number} field The field number.
   1344  * @param {?Array.<number>} value The array of ints to write.
   1345  */
   1346 jspb.BinaryWriter.prototype.writePackedUint32 =
   1347     jspb.BinaryWriter.prototype.writePackedUnsignedVarint32_;
   1348 
   1349 
   1350 /**
   1351  * Writes an array of numbers represented as strings to the buffer as a packed
   1352  * unsigned 32-bit int field.
   1353  * @param {number} field
   1354  * @param {?Array.<string>} value
   1355  */
   1356 jspb.BinaryWriter.prototype.writePackedUint32String =
   1357     function(field, value) {
   1358   if (value == null || !value.length) return;
   1359   var bookmark = this.beginDelimited_(field);
   1360   for (var i = 0; i < value.length; i++) {
   1361     this.encoder_.writeUnsignedVarint32(parseInt(value[i], 10));
   1362   }
   1363   this.endDelimited_(bookmark);
   1364 };
   1365 
   1366 
   1367 /**
   1368  * Writes an array numbers to the buffer as a packed unsigned 64-bit int field.
   1369  * @param {number} field The field number.
   1370  * @param {?Array.<number>} value The array of ints to write.
   1371  */
   1372 jspb.BinaryWriter.prototype.writePackedUint64 =
   1373     jspb.BinaryWriter.prototype.writePackedUnsignedVarint64_;
   1374 
   1375 
   1376 /**
   1377  * Writes an array of numbers represented as strings to the buffer as a packed
   1378  * unsigned 64-bit int field.
   1379  * @param {number} field
   1380  * @param {?Array.<string>} value
   1381  */
   1382 jspb.BinaryWriter.prototype.writePackedUint64String =
   1383     function(field, value) {
   1384   if (value == null || !value.length) return;
   1385   var bookmark = this.beginDelimited_(field);
   1386   for (var i = 0; i < value.length; i++) {
   1387     var num = jspb.arith.UInt64.fromString(value[i]);
   1388     this.encoder_.writeSplitVarint64(num.lo, num.hi);
   1389   }
   1390   this.endDelimited_(bookmark);
   1391 };
   1392 
   1393 
   1394 /**
   1395  * Writes an array numbers to the buffer as a packed signed 32-bit int field.
   1396  * @param {number} field The field number.
   1397  * @param {?Array.<number>} value The array of ints to write.
   1398  */
   1399 jspb.BinaryWriter.prototype.writePackedSint32 =
   1400     jspb.BinaryWriter.prototype.writePackedZigzag32_;
   1401 
   1402 
   1403 /**
   1404  * Writes an array numbers to the buffer as a packed signed 64-bit int field.
   1405  * @param {number} field The field number.
   1406  * @param {?Array.<number>} value The array of ints to write.
   1407  */
   1408 jspb.BinaryWriter.prototype.writePackedSint64 =
   1409     jspb.BinaryWriter.prototype.writePackedZigzag64_;
   1410 
   1411 
   1412 /**
   1413  * Writes an array of numbers to the buffer as a packed fixed32 field.
   1414  * @param {number} field The field number.
   1415  * @param {?Array.<number>} value The array of ints to write.
   1416  */
   1417 jspb.BinaryWriter.prototype.writePackedFixed32 = function(field, value) {
   1418   if (value == null || !value.length) return;
   1419   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
   1420   this.encoder_.writeUnsignedVarint32(value.length * 4);
   1421   for (var i = 0; i < value.length; i++) {
   1422     this.encoder_.writeUint32(value[i]);
   1423   }
   1424 };
   1425 
   1426 
   1427 /**
   1428  * Writes an array of numbers to the buffer as a packed fixed64 field.
   1429  * @param {number} field The field number.
   1430  * @param {?Array.<number>} value The array of ints to write.
   1431  */
   1432 jspb.BinaryWriter.prototype.writePackedFixed64 = function(field, value) {
   1433   if (value == null || !value.length) return;
   1434   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
   1435   this.encoder_.writeUnsignedVarint32(value.length * 8);
   1436   for (var i = 0; i < value.length; i++) {
   1437     this.encoder_.writeUint64(value[i]);
   1438   }
   1439 };
   1440 
   1441 
   1442 /**
   1443  * Writes an array of numbers to the buffer as a packed sfixed32 field.
   1444  * @param {number} field The field number.
   1445  * @param {?Array.<number>} value The array of ints to write.
   1446  */
   1447 jspb.BinaryWriter.prototype.writePackedSfixed32 = function(field, value) {
   1448   if (value == null || !value.length) return;
   1449   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
   1450   this.encoder_.writeUnsignedVarint32(value.length * 4);
   1451   for (var i = 0; i < value.length; i++) {
   1452     this.encoder_.writeInt32(value[i]);
   1453   }
   1454 };
   1455 
   1456 
   1457 /**
   1458  * Writes an array of numbers to the buffer as a packed sfixed64 field.
   1459  * @param {number} field The field number.
   1460  * @param {?Array.<number>} value The array of ints to write.
   1461  */
   1462 jspb.BinaryWriter.prototype.writePackedSfixed64 = function(field, value) {
   1463   if (value == null || !value.length) return;
   1464   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
   1465   this.encoder_.writeUnsignedVarint32(value.length * 8);
   1466   for (var i = 0; i < value.length; i++) {
   1467     this.encoder_.writeInt64(value[i]);
   1468   }
   1469 };
   1470 
   1471 
   1472 /**
   1473  * Writes an array of numbers to the buffer as a packed float field.
   1474  * @param {number} field The field number.
   1475  * @param {?Array.<number>} value The array of ints to write.
   1476  */
   1477 jspb.BinaryWriter.prototype.writePackedFloat = function(field, value) {
   1478   if (value == null || !value.length) return;
   1479   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
   1480   this.encoder_.writeUnsignedVarint32(value.length * 4);
   1481   for (var i = 0; i < value.length; i++) {
   1482     this.encoder_.writeFloat(value[i]);
   1483   }
   1484 };
   1485 
   1486 
   1487 /**
   1488  * Writes an array of numbers to the buffer as a packed double field.
   1489  * @param {number} field The field number.
   1490  * @param {?Array.<number>} value The array of ints to write.
   1491  */
   1492 jspb.BinaryWriter.prototype.writePackedDouble = function(field, value) {
   1493   if (value == null || !value.length) return;
   1494   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
   1495   this.encoder_.writeUnsignedVarint32(value.length * 8);
   1496   for (var i = 0; i < value.length; i++) {
   1497     this.encoder_.writeDouble(value[i]);
   1498   }
   1499 };
   1500 
   1501 
   1502 /**
   1503  * Writes an array of booleans to the buffer as a packed bool field.
   1504  * @param {number} field The field number.
   1505  * @param {?Array.<boolean>} value The array of ints to write.
   1506  */
   1507 jspb.BinaryWriter.prototype.writePackedBool = function(field, value) {
   1508   if (value == null || !value.length) return;
   1509   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
   1510   this.encoder_.writeUnsignedVarint32(value.length);
   1511   for (var i = 0; i < value.length; i++) {
   1512     this.encoder_.writeBool(value[i]);
   1513   }
   1514 };
   1515 
   1516 
   1517 /**
   1518  * Writes an array of enums to the buffer as a packed enum field.
   1519  * @param {number} field The field number.
   1520  * @param {?Array.<number>} value The array of ints to write.
   1521  */
   1522 jspb.BinaryWriter.prototype.writePackedEnum = function(field, value) {
   1523   if (value == null || !value.length) return;
   1524   var bookmark = this.beginDelimited_(field);
   1525   for (var i = 0; i < value.length; i++) {
   1526     this.encoder_.writeEnum(value[i]);
   1527   }
   1528   this.endDelimited_(bookmark);
   1529 };
   1530 
   1531 
   1532 /**
   1533  * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
   1534  * the buffer.
   1535  * @param {number} field The field number.
   1536  * @param {?Array.<string>} value The array of hashes to write.
   1537  */
   1538 jspb.BinaryWriter.prototype.writePackedFixedHash64 = function(field, value) {
   1539   if (value == null || !value.length) return;
   1540   this.writeFieldHeader_(field, jspb.BinaryConstants.WireType.DELIMITED);
   1541   this.encoder_.writeUnsignedVarint32(value.length * 8);
   1542   for (var i = 0; i < value.length; i++) {
   1543     this.encoder_.writeFixedHash64(value[i]);
   1544   }
   1545 };
   1546 
   1547 
   1548 /**
   1549  * Writes a 64-bit hash string field (8 characters @ 8 bits of data each) to
   1550  * the buffer.
   1551  * @param {number} field The field number.
   1552  * @param {?Array.<string>} value The array of hashes to write.
   1553  */
   1554 jspb.BinaryWriter.prototype.writePackedVarintHash64 = function(field, value) {
   1555   if (value == null || !value.length) return;
   1556   var bookmark = this.beginDelimited_(field);
   1557   for (var i = 0; i < value.length; i++) {
   1558     this.encoder_.writeVarintHash64(value[i]);
   1559   }
   1560   this.endDelimited_(bookmark);
   1561 };
   1562