• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc.  All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9//     * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11//     * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15//     * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31/**
32 * @fileoverview This file contains utilities for 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@google.com (Austin Appleby)
45 */
46
47goog.provide('jspb.BinaryReader');
48
49goog.require('goog.asserts');
50goog.require('jspb.BinaryConstants');
51goog.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 */
66jspb.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 */
110jspb.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 */
122jspb.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 */
144jspb.BinaryReader.prototype.alloc = jspb.BinaryReader.alloc;
145
146
147/**
148 * Puts this instance back in the instance cache.
149 */
150jspb.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 */
167jspb.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 */
176jspb.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 */
185jspb.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 */
194jspb.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 */
203jspb.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 */
212jspb.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 */
221jspb.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 */
232jspb.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 */
243jspb.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 */
254jspb.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 */
265jspb.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 */
308jspb.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 */
316jspb.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 */
333jspb.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 */
347jspb.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 */
362jspb.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 */
376jspb.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 */
390jspb.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 */
420jspb.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 */
448jspb.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 */
463jspb.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 */
476jspb.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 */
535jspb.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 */
564jspb.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 */
587jspb.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 */
608jspb.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 */
624jspb.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 */
637jspb.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 */
653jspb.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 */
666jspb.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 */
682jspb.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 */
695jspb.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 */
711jspb.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 */
725jspb.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 */
739jspb.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 */
753jspb.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 */
767jspb.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 */
781jspb.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 */
795jspb.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 */
808jspb.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 */
821jspb.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 */
834jspb.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 */
847jspb.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 */
860jspb.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 */
874jspb.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 */
889jspb.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 */
903jspb.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 */
916jspb.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 */
935jspb.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 */
945jspb.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 */
955jspb.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 */
965jspb.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 */
975jspb.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 */
985jspb.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 */
995jspb.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 */
1005jspb.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 */
1015jspb.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 */
1025jspb.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 */
1035jspb.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 */
1045jspb.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 */
1055jspb.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 */
1065jspb.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 */
1075jspb.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 */
1085jspb.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 */
1095jspb.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 */
1105jspb.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 */
1115jspb.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 */
1125jspb.BinaryReader.prototype.readPackedFixedHash64 = function() {
1126  return this.readPackedField_(this.decoder_.readFixedHash64);
1127};
1128