blob: 41094a36881ece2dee8208bdd9b2b690a16536c1 [file] [log] [blame]
Feng Xiaoe841bac2015-12-11 17:09:20 -08001// Protocol Buffers - Google's data interchange format
2// Copyright 2008 Google Inc. All rights reserved.
3// https://developers.google.com/protocol-buffers/
4//
5// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
8//
9// * Redistributions of source code must retain the above copyright
10// notice, this list of conditions and the following disclaimer.
11// * Redistributions in binary form must reproduce the above
12// copyright notice, this list of conditions and the following disclaimer
13// in the documentation and/or other materials provided with the
14// distribution.
15// * Neither the name of Google Inc. nor the names of its
16// contributors may be used to endorse or promote products derived from
17// this software without specific prior written permission.
18//
19// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30
31/**
32 * @fileoverview This file contains utilities for decoding primitive values
33 * (signed and unsigned integers, varints, booleans, enums, hashes, strings,
34 * and raw bytes) embedded in Uint8Arrays into their corresponding Javascript
35 * types.
36 *
37 * Major caveat - Javascript is unable to accurately represent integers larger
38 * than 2^53 due to its use of a double-precision floating point format or all
39 * numbers. If you need to guarantee that 64-bit values survive with all bits
40 * intact, you _must_ read them using one of the Hash64 methods, which return
41 * an 8-character string.
42 *
43 * @author aappleby@google.com (Austin Appleby)
44 */
45
46goog.provide('jspb.BinaryDecoder');
47goog.provide('jspb.BinaryIterator');
48
49goog.require('goog.asserts');
50goog.require('jspb.utils');
51
52
53
54/**
55 * Simple helper class for traversing the contents of repeated scalar fields.
56 * that may or may not have been packed into a wire-format blob.
57 * @param {?jspb.BinaryDecoder=} opt_decoder
58 * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
59 * opt_next The decoder method to use for next().
60 * @param {?Array.<number|boolean|string>=} opt_elements
61 * @constructor
62 * @struct
63 */
64jspb.BinaryIterator = function(opt_decoder, opt_next, opt_elements) {
65 /** @private {jspb.BinaryDecoder} */
66 this.decoder_ = null;
67
68 /**
69 * The BinaryDecoder member function used when iterating over packed data.
70 * @private {?function(this:jspb.BinaryDecoder):(number|boolean|string)}
71 */
72 this.nextMethod_ = null;
73
74 /** @private {Array.<number>} */
75 this.elements_ = null;
76
77 /** @private {number} */
78 this.cursor_ = 0;
79
80 /** @private {number|boolean|string|null} */
81 this.nextValue_ = null;
82
83 /** @private {boolean} */
84 this.atEnd_ = true;
85
86 this.init_(opt_decoder, opt_next, opt_elements);
87};
88
89
90/**
91 * @param {?jspb.BinaryDecoder=} opt_decoder
92 * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
93 * opt_next The decoder method to use for next().
94 * @param {?Array.<number|boolean|string>=} opt_elements
95 * @private
96 */
97jspb.BinaryIterator.prototype.init_ =
98 function(opt_decoder, opt_next, opt_elements) {
99 if (opt_decoder && opt_next) {
100 this.decoder_ = opt_decoder;
101 this.nextMethod_ = opt_next;
102 }
103 this.elements_ = opt_elements ? opt_elements : null;
104 this.cursor_ = 0;
105 this.nextValue_ = null;
106 this.atEnd_ = !this.decoder_ && !this.elements_;
107
108 this.next();
109};
110
111
112/**
113 * Global pool of BinaryIterator instances.
114 * @private {!Array.<!jspb.BinaryIterator>}
115 */
116jspb.BinaryIterator.instanceCache_ = [];
117
118
119/**
120 * Allocates a BinaryIterator from the cache, creating a new one if the cache
121 * is empty.
122 * @param {?jspb.BinaryDecoder=} opt_decoder
123 * @param {?function(this:jspb.BinaryDecoder):(number|boolean|string)=}
124 * opt_next The decoder method to use for next().
125 * @param {?Array.<number|boolean|string>=} opt_elements
126 * @return {!jspb.BinaryIterator}
127 */
128jspb.BinaryIterator.alloc = function(opt_decoder, opt_next, opt_elements) {
129 if (jspb.BinaryIterator.instanceCache_.length) {
130 var iterator = jspb.BinaryIterator.instanceCache_.pop();
131 iterator.init_(opt_decoder, opt_next, opt_elements);
132 return iterator;
133 } else {
134 return new jspb.BinaryIterator(opt_decoder, opt_next, opt_elements);
135 }
136};
137
138
139/**
140 * Puts this instance back in the instance cache.
141 */
142jspb.BinaryIterator.prototype.free = function() {
143 this.clear();
144 if (jspb.BinaryIterator.instanceCache_.length < 100) {
145 jspb.BinaryIterator.instanceCache_.push(this);
146 }
147};
148
149
150/**
151 * Clears the iterator.
152 */
153jspb.BinaryIterator.prototype.clear = function() {
154 if (this.decoder_) {
155 this.decoder_.free();
156 }
157 this.decoder_ = null;
158 this.nextMethod_ = null;
159 this.elements_ = null;
160 this.cursor_ = 0;
161 this.nextValue_ = null;
162 this.atEnd_ = true;
163};
164
165
166/**
167 * Returns the element at the iterator, or null if the iterator is invalid or
168 * past the end of the decoder/array.
169 * @return {number|boolean|string|null}
170 */
171jspb.BinaryIterator.prototype.get = function() {
172 return this.nextValue_;
173};
174
175
176/**
177 * Returns true if the iterator is at the end of the decoder/array.
178 * @return {boolean}
179 */
180jspb.BinaryIterator.prototype.atEnd = function() {
181 return this.atEnd_;
182};
183
184
185/**
186 * Returns the element at the iterator and steps to the next element,
187 * equivalent to '*pointer++' in C.
188 * @return {number|boolean|string|null}
189 */
190jspb.BinaryIterator.prototype.next = function() {
191 var lastValue = this.nextValue_;
192 if (this.decoder_) {
193 if (this.decoder_.atEnd()) {
194 this.nextValue_ = null;
195 this.atEnd_ = true;
196 } else {
197 this.nextValue_ = this.nextMethod_.call(this.decoder_);
198 }
199 } else if (this.elements_) {
200 if (this.cursor_ == this.elements_.length) {
201 this.nextValue_ = null;
202 this.atEnd_ = true;
203 } else {
204 this.nextValue_ = this.elements_[this.cursor_++];
205 }
206 }
207 return lastValue;
208};
209
210
211
212/**
213 * BinaryDecoder implements the decoders for all the wire types specified in
214 * https://developers.google.com/protocol-buffers/docs/encoding.
215 *
216 * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
217 * @param {number=} opt_start The optional offset to start reading at.
218 * @param {number=} opt_length The optional length of the block to read -
219 * we'll throw an assertion if we go off the end of the block.
220 * @constructor
221 * @struct
222 */
223jspb.BinaryDecoder = function(opt_bytes, opt_start, opt_length) {
224 /**
225 * Typed byte-wise view of the source buffer.
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700226 * @private {?Uint8Array}
Feng Xiaoe841bac2015-12-11 17:09:20 -0800227 */
228 this.bytes_ = null;
229
230 /**
231 * Start point of the block to read.
232 * @private {number}
233 */
234 this.start_ = 0;
235
236 /**
237 * End point of the block to read.
238 * @private {number}
239 */
240 this.end_ = 0;
241
242 /**
243 * Current read location in bytes_.
244 * @private {number}
245 */
246 this.cursor_ = 0;
247
248 /**
249 * Temporary storage for the low 32 bits of 64-bit data types that we're
250 * decoding.
251 * @private {number}
252 */
253 this.tempLow_ = 0;
254
255 /**
256 * Temporary storage for the high 32 bits of 64-bit data types that we're
257 * decoding.
258 * @private {number}
259 */
260 this.tempHigh_ = 0;
261
262 /**
263 * Set to true if this decoder encountered an error due to corrupt data.
264 * @private {boolean}
265 */
266 this.error_ = false;
267
268 if (opt_bytes) {
269 this.setBlock(opt_bytes, opt_start, opt_length);
270 }
271};
272
273
274/**
275 * Global pool of BinaryDecoder instances.
276 * @private {!Array.<!jspb.BinaryDecoder>}
277 */
278jspb.BinaryDecoder.instanceCache_ = [];
279
280
281/**
282 * Pops an instance off the instance cache, or creates one if the cache is
283 * empty.
284 * @param {jspb.ByteSource=} opt_bytes The bytes we're reading from.
285 * @param {number=} opt_start The optional offset to start reading at.
286 * @param {number=} opt_length The optional length of the block to read -
287 * we'll throw an assertion if we go off the end of the block.
288 * @return {!jspb.BinaryDecoder}
289 */
290jspb.BinaryDecoder.alloc = function(opt_bytes, opt_start, opt_length) {
291 if (jspb.BinaryDecoder.instanceCache_.length) {
292 var newDecoder = jspb.BinaryDecoder.instanceCache_.pop();
293 if (opt_bytes) {
294 newDecoder.setBlock(opt_bytes, opt_start, opt_length);
295 }
296 return newDecoder;
297 } else {
298 return new jspb.BinaryDecoder(opt_bytes, opt_start, opt_length);
299 }
300};
301
302
303/**
304 * Puts this instance back in the instance cache.
305 */
306jspb.BinaryDecoder.prototype.free = function() {
307 this.clear();
308 if (jspb.BinaryDecoder.instanceCache_.length < 100) {
309 jspb.BinaryDecoder.instanceCache_.push(this);
310 }
311};
312
313
314/**
315 * Makes a copy of this decoder.
316 * @return {!jspb.BinaryDecoder}
317 */
318jspb.BinaryDecoder.prototype.clone = function() {
319 return jspb.BinaryDecoder.alloc(this.bytes_,
320 this.start_, this.end_ - this.start_);
321};
322
323
324/**
325 * Clears the decoder.
326 */
327jspb.BinaryDecoder.prototype.clear = function() {
328 this.bytes_ = null;
329 this.start_ = 0;
330 this.end_ = 0;
331 this.cursor_ = 0;
332 this.error_ = false;
333};
334
335
336/**
337 * Returns the raw buffer.
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700338 * @return {?Uint8Array} The raw buffer.
Feng Xiaoe841bac2015-12-11 17:09:20 -0800339 */
340jspb.BinaryDecoder.prototype.getBuffer = function() {
341 return this.bytes_;
342};
343
344
345/**
346 * Changes the block of bytes we're decoding.
347 * @param {!jspb.ByteSource} data The bytes we're reading from.
348 * @param {number=} opt_start The optional offset to start reading at.
349 * @param {number=} opt_length The optional length of the block to read -
350 * we'll throw an assertion if we go off the end of the block.
351 */
352jspb.BinaryDecoder.prototype.setBlock =
353 function(data, opt_start, opt_length) {
354 this.bytes_ = jspb.utils.byteSourceToUint8Array(data);
355 this.start_ = goog.isDef(opt_start) ? opt_start : 0;
356 this.end_ =
357 goog.isDef(opt_length) ? this.start_ + opt_length : this.bytes_.length;
358 this.cursor_ = this.start_;
359};
360
361
362/**
363 * @return {number}
364 */
365jspb.BinaryDecoder.prototype.getEnd = function() {
366 return this.end_;
367};
368
369
370/**
371 * @param {number} end
372 */
373jspb.BinaryDecoder.prototype.setEnd = function(end) {
374 this.end_ = end;
375};
376
377
378/**
379 * Moves the read cursor back to the start of the block.
380 */
381jspb.BinaryDecoder.prototype.reset = function() {
382 this.cursor_ = this.start_;
383};
384
385
386/**
387 * Returns the internal read cursor.
388 * @return {number} The internal read cursor.
389 */
390jspb.BinaryDecoder.prototype.getCursor = function() {
391 return this.cursor_;
392};
393
394
395/**
396 * Returns the internal read cursor.
397 * @param {number} cursor The new cursor.
398 */
399jspb.BinaryDecoder.prototype.setCursor = function(cursor) {
400 this.cursor_ = cursor;
401};
402
403
404/**
405 * Advances the stream cursor by the given number of bytes.
406 * @param {number} count The number of bytes to advance by.
407 */
408jspb.BinaryDecoder.prototype.advance = function(count) {
409 this.cursor_ += count;
410 goog.asserts.assert(this.cursor_ <= this.end_);
411};
412
413
414/**
415 * Returns true if this decoder is at the end of the block.
416 * @return {boolean}
417 */
418jspb.BinaryDecoder.prototype.atEnd = function() {
419 return this.cursor_ == this.end_;
420};
421
422
423/**
424 * Returns true if this decoder is at the end of the block.
425 * @return {boolean}
426 */
427jspb.BinaryDecoder.prototype.pastEnd = function() {
428 return this.cursor_ > this.end_;
429};
430
431
432/**
433 * Returns true if this decoder encountered an error due to corrupt data.
434 * @return {boolean}
435 */
436jspb.BinaryDecoder.prototype.getError = function() {
437 return this.error_ ||
438 (this.cursor_ < 0) ||
439 (this.cursor_ > this.end_);
440};
441
442
443/**
444 * Reads an unsigned varint from the binary stream and stores it as a split
445 * 64-bit integer. Since this does not convert the value to a number, no
446 * precision is lost.
447 *
448 * It's possible for an unsigned varint to be incorrectly encoded - more than
449 * 64 bits' worth of data could be present. If this happens, this method will
450 * throw an error.
451 *
452 * Decoding varints requires doing some funny base-128 math - for more
453 * details on the format, see
454 * https://developers.google.com/protocol-buffers/docs/encoding
455 *
456 * @private
457 */
458jspb.BinaryDecoder.prototype.readSplitVarint64_ = function() {
459 var temp;
460 var lowBits = 0;
461 var highBits = 0;
462
463 // Read the first four bytes of the varint, stopping at the terminator if we
464 // see it.
465 for (var i = 0; i < 4; i++) {
466 temp = this.bytes_[this.cursor_++];
467 lowBits |= (temp & 0x7F) << (i * 7);
468 if (temp < 128) {
469 this.tempLow_ = lowBits >>> 0;
470 this.tempHigh_ = 0;
471 return;
472 }
473 }
474
475 // Read the fifth byte, which straddles the low and high dwords.
476 temp = this.bytes_[this.cursor_++];
477 lowBits |= (temp & 0x7F) << 28;
478 highBits |= (temp & 0x7F) >> 4;
479 if (temp < 128) {
480 this.tempLow_ = lowBits >>> 0;
481 this.tempHigh_ = highBits >>> 0;
482 return;
483 }
484
485 // Read the sixth through tenth byte.
486 for (var i = 0; i < 5; i++) {
487 temp = this.bytes_[this.cursor_++];
488 highBits |= (temp & 0x7F) << (i * 7 + 3);
489 if (temp < 128) {
490 this.tempLow_ = lowBits >>> 0;
491 this.tempHigh_ = highBits >>> 0;
492 return;
493 }
494 }
495
496 // If we did not see the terminator, the encoding was invalid.
497 goog.asserts.fail('Failed to read varint, encoding is invalid.');
498 this.error_ = true;
499};
500
501
502/**
503 * Skips over a varint in the block without decoding it.
504 */
505jspb.BinaryDecoder.prototype.skipVarint = function() {
506 while (this.bytes_[this.cursor_] & 0x80) {
507 this.cursor_++;
508 }
509 this.cursor_++;
510};
511
512
513/**
514 * Skips backwards over a varint in the block - to do this correctly, we have
515 * to know the value we're skipping backwards over or things are ambiguous.
516 * @param {number} value The varint value to unskip.
517 */
518jspb.BinaryDecoder.prototype.unskipVarint = function(value) {
519 while (value > 128) {
520 this.cursor_--;
521 value = value >>> 7;
522 }
523 this.cursor_--;
524};
525
526
527/**
528 * Reads a 32-bit varint from the binary stream. Due to a quirk of the encoding
529 * format and Javascript's handling of bitwise math, this actually works
530 * correctly for both signed and unsigned 32-bit varints.
531 *
532 * This function is called vastly more frequently than any other in
533 * BinaryDecoder, so it has been unrolled and tweaked for performance.
534 *
535 * If there are more than 32 bits of data in the varint, it _must_ be due to
536 * sign-extension. If we're in debug mode and the high 32 bits don't match the
537 * expected sign extension, this method will throw an error.
538 *
539 * Decoding varints requires doing some funny base-128 math - for more
540 * details on the format, see
541 * https://developers.google.com/protocol-buffers/docs/encoding
542 *
543 * @return {number} The decoded unsigned 32-bit varint.
544 */
545jspb.BinaryDecoder.prototype.readUnsignedVarint32 = function() {
546 var temp;
547 var bytes = this.bytes_;
548
549 temp = bytes[this.cursor_ + 0];
550 var x = (temp & 0x7F);
551 if (temp < 128) {
552 this.cursor_ += 1;
553 goog.asserts.assert(this.cursor_ <= this.end_);
554 return x;
555 }
556
557 temp = bytes[this.cursor_ + 1];
558 x |= (temp & 0x7F) << 7;
559 if (temp < 128) {
560 this.cursor_ += 2;
561 goog.asserts.assert(this.cursor_ <= this.end_);
562 return x;
563 }
564
565 temp = bytes[this.cursor_ + 2];
566 x |= (temp & 0x7F) << 14;
567 if (temp < 128) {
568 this.cursor_ += 3;
569 goog.asserts.assert(this.cursor_ <= this.end_);
570 return x;
571 }
572
573 temp = bytes[this.cursor_ + 3];
574 x |= (temp & 0x7F) << 21;
575 if (temp < 128) {
576 this.cursor_ += 4;
577 goog.asserts.assert(this.cursor_ <= this.end_);
578 return x;
579 }
580
581 temp = bytes[this.cursor_ + 4];
582 x |= (temp & 0x0F) << 28;
583 if (temp < 128) {
584 // We're reading the high bits of an unsigned varint. The byte we just read
585 // also contains bits 33 through 35, which we're going to discard. Those
586 // bits _must_ be zero, or the encoding is invalid.
587 goog.asserts.assert((temp & 0xF0) == 0);
588 this.cursor_ += 5;
589 goog.asserts.assert(this.cursor_ <= this.end_);
590 return x >>> 0;
591 }
592
593 // If we get here, we're reading the sign extension of a negative 32-bit int.
594 // We can skip these bytes, as we know in advance that they have to be all
595 // 1's if the varint is correctly encoded. Since we also know the value is
596 // negative, we don't have to coerce it to unsigned before we return it.
597
598 goog.asserts.assert((temp & 0xF0) == 0xF0);
599 goog.asserts.assert(bytes[this.cursor_ + 5] == 0xFF);
600 goog.asserts.assert(bytes[this.cursor_ + 6] == 0xFF);
601 goog.asserts.assert(bytes[this.cursor_ + 7] == 0xFF);
602 goog.asserts.assert(bytes[this.cursor_ + 8] == 0xFF);
603 goog.asserts.assert(bytes[this.cursor_ + 9] == 0x01);
604
605 this.cursor_ += 10;
606 goog.asserts.assert(this.cursor_ <= this.end_);
607 return x;
608};
609
610
611/**
612 * The readUnsignedVarint32 above deals with signed 32-bit varints correctly,
613 * so this is just an alias.
614 *
615 * @return {number} The decoded signed 32-bit varint.
616 */
617jspb.BinaryDecoder.prototype.readSignedVarint32 =
618 jspb.BinaryDecoder.prototype.readUnsignedVarint32;
619
620
621/**
622 * Reads a 32-bit unsigned variant and returns its value as a string.
623 *
624 * @return {string} The decoded unsigned 32-bit varint as a string.
625 */
626jspb.BinaryDecoder.prototype.readUnsignedVarint32String = function() {
627 // 32-bit integers fit in JavaScript numbers without loss of precision, so
628 // string variants of 32-bit varint readers can simply delegate then convert
629 // to string.
630 var value = this.readUnsignedVarint32();
631 return value.toString();
632};
633
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700634
Feng Xiaoe841bac2015-12-11 17:09:20 -0800635/**
636 * Reads a 32-bit signed variant and returns its value as a string.
637 *
638 * @return {string} The decoded signed 32-bit varint as a string.
639 */
640jspb.BinaryDecoder.prototype.readSignedVarint32String = function() {
641 // 32-bit integers fit in JavaScript numbers without loss of precision, so
642 // string variants of 32-bit varint readers can simply delegate then convert
643 // to string.
644 var value = this.readSignedVarint32();
645 return value.toString();
646};
647
648
649/**
650 * Reads a signed, zigzag-encoded 32-bit varint from the binary stream.
651 *
652 * Zigzag encoding is a modification of varint encoding that reduces the
653 * storage overhead for small negative integers - for more details on the
654 * format, see https://developers.google.com/protocol-buffers/docs/encoding
655 *
656 * @return {number} The decoded signed, zigzag-encoded 32-bit varint.
657 */
658jspb.BinaryDecoder.prototype.readZigzagVarint32 = function() {
659 var result = this.readUnsignedVarint32();
660 return (result >>> 1) ^ - (result & 1);
661};
662
663
664/**
665 * Reads an unsigned 64-bit varint from the binary stream. Note that since
666 * Javascript represents all numbers as double-precision floats, there will be
667 * precision lost if the absolute value of the varint is larger than 2^53.
668 *
669 * @return {number} The decoded unsigned varint. Precision will be lost if the
670 * integer exceeds 2^53.
671 */
672jspb.BinaryDecoder.prototype.readUnsignedVarint64 = function() {
673 this.readSplitVarint64_();
674 return jspb.utils.joinUint64(this.tempLow_, this.tempHigh_);
675};
676
677
678/**
679 * Reads an unsigned 64-bit varint from the binary stream and returns the value
680 * as a decimal string.
681 *
682 * @return {string} The decoded unsigned varint as a decimal string.
683 */
684jspb.BinaryDecoder.prototype.readUnsignedVarint64String = function() {
685 this.readSplitVarint64_();
686 return jspb.utils.joinUnsignedDecimalString(this.tempLow_, this.tempHigh_);
687};
688
689
690/**
691 * Reads a signed 64-bit varint from the binary stream. Note that since
692 * Javascript represents all numbers as double-precision floats, there will be
693 * precision lost if the absolute value of the varint is larger than 2^53.
694 *
695 * @return {number} The decoded signed varint. Precision will be lost if the
696 * integer exceeds 2^53.
697 */
698jspb.BinaryDecoder.prototype.readSignedVarint64 = function() {
699 this.readSplitVarint64_();
700 return jspb.utils.joinInt64(this.tempLow_, this.tempHigh_);
701};
702
703
704/**
705 * Reads an signed 64-bit varint from the binary stream and returns the value
706 * as a decimal string.
707 *
708 * @return {string} The decoded signed varint as a decimal string.
709 */
710jspb.BinaryDecoder.prototype.readSignedVarint64String = function() {
711 this.readSplitVarint64_();
712 return jspb.utils.joinSignedDecimalString(this.tempLow_, this.tempHigh_);
713};
714
715
716/**
717 * Reads a signed, zigzag-encoded 64-bit varint from the binary stream. Note
718 * that since Javascript represents all numbers as double-precision floats,
719 * there will be precision lost if the absolute value of the varint is larger
720 * than 2^53.
721 *
722 * Zigzag encoding is a modification of varint encoding that reduces the
723 * storage overhead for small negative integers - for more details on the
724 * format, see https://developers.google.com/protocol-buffers/docs/encoding
725 *
726 * @return {number} The decoded zigzag varint. Precision will be lost if the
727 * integer exceeds 2^53.
728 */
729jspb.BinaryDecoder.prototype.readZigzagVarint64 = function() {
730 this.readSplitVarint64_();
731 return jspb.utils.joinZigzag64(this.tempLow_, this.tempHigh_);
732};
733
734
735/**
736 * Reads a raw unsigned 8-bit integer from the binary stream.
737 *
738 * @return {number} The unsigned 8-bit integer read from the binary stream.
739 */
740jspb.BinaryDecoder.prototype.readUint8 = function() {
741 var a = this.bytes_[this.cursor_ + 0];
742 this.cursor_ += 1;
743 goog.asserts.assert(this.cursor_ <= this.end_);
744 return a;
745};
746
747
748/**
749 * Reads a raw unsigned 16-bit integer from the binary stream.
750 *
751 * @return {number} The unsigned 16-bit integer read from the binary stream.
752 */
753jspb.BinaryDecoder.prototype.readUint16 = function() {
754 var a = this.bytes_[this.cursor_ + 0];
755 var b = this.bytes_[this.cursor_ + 1];
756 this.cursor_ += 2;
757 goog.asserts.assert(this.cursor_ <= this.end_);
758 return (a << 0) | (b << 8);
759};
760
761
762/**
763 * Reads a raw unsigned 32-bit integer from the binary stream.
764 *
765 * @return {number} The unsigned 32-bit integer read from the binary stream.
766 */
767jspb.BinaryDecoder.prototype.readUint32 = function() {
768 var a = this.bytes_[this.cursor_ + 0];
769 var b = this.bytes_[this.cursor_ + 1];
770 var c = this.bytes_[this.cursor_ + 2];
771 var d = this.bytes_[this.cursor_ + 3];
772 this.cursor_ += 4;
773 goog.asserts.assert(this.cursor_ <= this.end_);
774 return ((a << 0) | (b << 8) | (c << 16) | (d << 24)) >>> 0;
775};
776
777
778/**
779 * Reads a raw unsigned 64-bit integer from the binary stream. Note that since
780 * Javascript represents all numbers as double-precision floats, there will be
781 * precision lost if the absolute value of the integer is larger than 2^53.
782 *
783 * @return {number} The unsigned 64-bit integer read from the binary stream.
784 * Precision will be lost if the integer exceeds 2^53.
785 */
786jspb.BinaryDecoder.prototype.readUint64 = function() {
787 var bitsLow = this.readUint32();
788 var bitsHigh = this.readUint32();
789 return jspb.utils.joinUint64(bitsLow, bitsHigh);
790};
791
792
793/**
794 * Reads a raw signed 8-bit integer from the binary stream.
795 *
796 * @return {number} The signed 8-bit integer read from the binary stream.
797 */
798jspb.BinaryDecoder.prototype.readInt8 = function() {
799 var a = this.bytes_[this.cursor_ + 0];
800 this.cursor_ += 1;
801 goog.asserts.assert(this.cursor_ <= this.end_);
802 return (a << 24) >> 24;
803};
804
805
806/**
807 * Reads a raw signed 16-bit integer from the binary stream.
808 *
809 * @return {number} The signed 16-bit integer read from the binary stream.
810 */
811jspb.BinaryDecoder.prototype.readInt16 = function() {
812 var a = this.bytes_[this.cursor_ + 0];
813 var b = this.bytes_[this.cursor_ + 1];
814 this.cursor_ += 2;
815 goog.asserts.assert(this.cursor_ <= this.end_);
816 return (((a << 0) | (b << 8)) << 16) >> 16;
817};
818
819
820/**
821 * Reads a raw signed 32-bit integer from the binary stream.
822 *
823 * @return {number} The signed 32-bit integer read from the binary stream.
824 */
825jspb.BinaryDecoder.prototype.readInt32 = function() {
826 var a = this.bytes_[this.cursor_ + 0];
827 var b = this.bytes_[this.cursor_ + 1];
828 var c = this.bytes_[this.cursor_ + 2];
829 var d = this.bytes_[this.cursor_ + 3];
830 this.cursor_ += 4;
831 goog.asserts.assert(this.cursor_ <= this.end_);
832 return (a << 0) | (b << 8) | (c << 16) | (d << 24);
833};
834
835
836/**
837 * Reads a raw signed 64-bit integer from the binary stream. Note that since
838 * Javascript represents all numbers as double-precision floats, there will be
839 * precision lost if the absolute vlaue of the integer is larger than 2^53.
840 *
841 * @return {number} The signed 64-bit integer read from the binary stream.
842 * Precision will be lost if the integer exceeds 2^53.
843 */
844jspb.BinaryDecoder.prototype.readInt64 = function() {
845 var bitsLow = this.readUint32();
846 var bitsHigh = this.readUint32();
847 return jspb.utils.joinInt64(bitsLow, bitsHigh);
848};
849
850
851/**
852 * Reads a 32-bit floating-point number from the binary stream, using the
853 * temporary buffer to realign the data.
854 *
855 * @return {number} The float read from the binary stream.
856 */
857jspb.BinaryDecoder.prototype.readFloat = function() {
858 var bitsLow = this.readUint32();
859 var bitsHigh = 0;
860 return jspb.utils.joinFloat32(bitsLow, bitsHigh);
861};
862
863
864/**
865 * Reads a 64-bit floating-point number from the binary stream, using the
866 * temporary buffer to realign the data.
867 *
868 * @return {number} The double read from the binary stream.
869 */
870jspb.BinaryDecoder.prototype.readDouble = function() {
871 var bitsLow = this.readUint32();
872 var bitsHigh = this.readUint32();
873 return jspb.utils.joinFloat64(bitsLow, bitsHigh);
874};
875
876
877/**
878 * Reads a boolean value from the binary stream.
879 * @return {boolean} The boolean read from the binary stream.
880 */
881jspb.BinaryDecoder.prototype.readBool = function() {
882 return !!this.bytes_[this.cursor_++];
883};
884
885
886/**
887 * Reads an enum value from the binary stream, which are always encoded as
888 * signed varints.
889 * @return {number} The enum value read from the binary stream.
890 */
891jspb.BinaryDecoder.prototype.readEnum = function() {
892 return this.readSignedVarint32();
893};
894
895
896/**
897 * Reads and parses a UTF-8 encoded unicode string from the stream.
898 * The code is inspired by maps.vectortown.parse.StreamedDataViewReader, with
899 * the exception that the implementation here does not get confused if it
900 * encounters characters longer than three bytes. These characters are ignored
901 * though, as they are extremely rare: three UTF-8 bytes cover virtually all
902 * characters in common use (http://en.wikipedia.org/wiki/UTF-8).
903 * @param {number} length The length of the string to read.
904 * @return {string} The decoded string.
905 */
906jspb.BinaryDecoder.prototype.readString = function(length) {
907 var bytes = this.bytes_;
908 var cursor = this.cursor_;
909 var end = cursor + length;
910 var chars = [];
911
912 while (cursor < end) {
913 var c = bytes[cursor++];
914 if (c < 128) { // Regular 7-bit ASCII.
915 chars.push(c);
916 } else if (c < 192) {
917 // UTF-8 continuation mark. We are out of sync. This
918 // might happen if we attempted to read a character
919 // with more than three bytes.
920 continue;
921 } else if (c < 224) { // UTF-8 with two bytes.
922 var c2 = bytes[cursor++];
923 chars.push(((c & 31) << 6) | (c2 & 63));
924 } else if (c < 240) { // UTF-8 with three bytes.
925 var c2 = bytes[cursor++];
926 var c3 = bytes[cursor++];
927 chars.push(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
928 }
929 }
930
931 // String.fromCharCode.apply is faster than manually appending characters on
932 // Chrome 25+, and generates no additional cons string garbage.
933 var result = String.fromCharCode.apply(null, chars);
934 this.cursor_ = cursor;
935 return result;
936};
937
938
939/**
940 * Reads and parses a UTF-8 encoded unicode string (with length prefix) from
941 * the stream.
942 * @return {string} The decoded string.
943 */
944jspb.BinaryDecoder.prototype.readStringWithLength = function() {
945 var length = this.readUnsignedVarint32();
946 return this.readString(length);
947};
948
949
950/**
951 * Reads a block of raw bytes from the binary stream.
952 *
953 * @param {number} length The number of bytes to read.
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700954 * @return {!Uint8Array} The decoded block of bytes, or an empty block if the
955 * length was invalid.
Feng Xiaoe841bac2015-12-11 17:09:20 -0800956 */
957jspb.BinaryDecoder.prototype.readBytes = function(length) {
958 if (length < 0 ||
959 this.cursor_ + length > this.bytes_.length) {
960 this.error_ = true;
Jisi Liu3b3c8ab2016-03-30 11:39:59 -0700961 goog.asserts.fail('Invalid byte length!');
962 return new Uint8Array(0);
Feng Xiaoe841bac2015-12-11 17:09:20 -0800963 }
964
965 var result = this.bytes_.subarray(this.cursor_, this.cursor_ + length);
966
967 this.cursor_ += length;
968 goog.asserts.assert(this.cursor_ <= this.end_);
969 return result;
970};
971
972
973/**
974 * Reads a 64-bit varint from the stream and returns it as an 8-character
975 * Unicode string for use as a hash table key.
976 *
977 * @return {string} The hash value.
978 */
979jspb.BinaryDecoder.prototype.readVarintHash64 = function() {
980 this.readSplitVarint64_();
981 return jspb.utils.joinHash64(this.tempLow_, this.tempHigh_);
982};
983
984
985/**
986 * Reads a 64-bit fixed-width value from the stream and returns it as an
987 * 8-character Unicode string for use as a hash table key.
988 *
989 * @return {string} The hash value.
990 */
991jspb.BinaryDecoder.prototype.readFixedHash64 = function() {
992 var bytes = this.bytes_;
993 var cursor = this.cursor_;
994
995 var a = bytes[cursor + 0];
996 var b = bytes[cursor + 1];
997 var c = bytes[cursor + 2];
998 var d = bytes[cursor + 3];
999 var e = bytes[cursor + 4];
1000 var f = bytes[cursor + 5];
1001 var g = bytes[cursor + 6];
1002 var h = bytes[cursor + 7];
1003
1004 this.cursor_ += 8;
1005
1006 return String.fromCharCode(a, b, c, d, e, f, g, h);
1007};