blob: 9004eff008c8dac4da249de01db2964765ecec9f [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.
226 * @private {Uint8Array}
227 */
228 this.bytes_ = null;
229
230 /**
231 * Start point of the block to read.
232 * @private {number}
233 */
234 this.start_ = 0;
235
236 /**
237 * End point of the block to read.
238 * @private {number}
239 */
240 this.end_ = 0;
241
242 /**
243 * Current read location in bytes_.
244 * @private {number}
245 */
246 this.cursor_ = 0;
247
248 /**
249 * Temporary storage for the low 32 bits of 64-bit data types that we're
250 * decoding.
251 * @private {number}
252 */
253 this.tempLow_ = 0;
254
255 /**
256 * Temporary storage for the high 32 bits of 64-bit data types that we're
257 * decoding.
258 * @private {number}
259 */
260 this.tempHigh_ = 0;
261
262 /**
263 * Set to true if this decoder encountered an error due to corrupt data.
264 * @private {boolean}
265 */
266 this.error_ = false;
267
268 if (opt_bytes) {
269 this.setBlock(opt_bytes, opt_start, opt_length);
270 }
271};
272
273
274/**
275 * Global pool of BinaryDecoder instances.
276 * @private {!Array.<!jspb.BinaryDecoder>}
277 */
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.
338 * @return {Uint8Array} The raw buffer.
339 */
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
634/**
635 * Reads a 32-bit signed variant and returns its value as a string.
636 *
637 * @return {string} The decoded signed 32-bit varint as a string.
638 */
639jspb.BinaryDecoder.prototype.readSignedVarint32String = function() {
640 // 32-bit integers fit in JavaScript numbers without loss of precision, so
641 // string variants of 32-bit varint readers can simply delegate then convert
642 // to string.
643 var value = this.readSignedVarint32();
644 return value.toString();
645};
646
647
648/**
649 * Reads a signed, zigzag-encoded 32-bit varint from the binary stream.
650 *
651 * Zigzag encoding is a modification of varint encoding that reduces the
652 * storage overhead for small negative integers - for more details on the
653 * format, see https://developers.google.com/protocol-buffers/docs/encoding
654 *
655 * @return {number} The decoded signed, zigzag-encoded 32-bit varint.
656 */
657jspb.BinaryDecoder.prototype.readZigzagVarint32 = function() {
658 var result = this.readUnsignedVarint32();
659 return (result >>> 1) ^ - (result & 1);
660};
661
662
663/**
664 * Reads an unsigned 64-bit varint from the binary stream. Note that since
665 * Javascript represents all numbers as double-precision floats, there will be
666 * precision lost if the absolute value of the varint is larger than 2^53.
667 *
668 * @return {number} The decoded unsigned varint. Precision will be lost if the
669 * integer exceeds 2^53.
670 */
671jspb.BinaryDecoder.prototype.readUnsignedVarint64 = function() {
672 this.readSplitVarint64_();
673 return jspb.utils.joinUint64(this.tempLow_, this.tempHigh_);
674};
675
676
677/**
678 * Reads an unsigned 64-bit varint from the binary stream and returns the value
679 * as a decimal string.
680 *
681 * @return {string} The decoded unsigned varint as a decimal string.
682 */
683jspb.BinaryDecoder.prototype.readUnsignedVarint64String = function() {
684 this.readSplitVarint64_();
685 return jspb.utils.joinUnsignedDecimalString(this.tempLow_, this.tempHigh_);
686};
687
688
689/**
690 * Reads a signed 64-bit varint from the binary stream. Note that since
691 * Javascript represents all numbers as double-precision floats, there will be
692 * precision lost if the absolute value of the varint is larger than 2^53.
693 *
694 * @return {number} The decoded signed varint. Precision will be lost if the
695 * integer exceeds 2^53.
696 */
697jspb.BinaryDecoder.prototype.readSignedVarint64 = function() {
698 this.readSplitVarint64_();
699 return jspb.utils.joinInt64(this.tempLow_, this.tempHigh_);
700};
701
702
703/**
704 * Reads an signed 64-bit varint from the binary stream and returns the value
705 * as a decimal string.
706 *
707 * @return {string} The decoded signed varint as a decimal string.
708 */
709jspb.BinaryDecoder.prototype.readSignedVarint64String = function() {
710 this.readSplitVarint64_();
711 return jspb.utils.joinSignedDecimalString(this.tempLow_, this.tempHigh_);
712};
713
714
715/**
716 * Reads a signed, zigzag-encoded 64-bit varint from the binary stream. Note
717 * that since Javascript represents all numbers as double-precision floats,
718 * there will be precision lost if the absolute value of the varint is larger
719 * than 2^53.
720 *
721 * Zigzag encoding is a modification of varint encoding that reduces the
722 * storage overhead for small negative integers - for more details on the
723 * format, see https://developers.google.com/protocol-buffers/docs/encoding
724 *
725 * @return {number} The decoded zigzag varint. Precision will be lost if the
726 * integer exceeds 2^53.
727 */
728jspb.BinaryDecoder.prototype.readZigzagVarint64 = function() {
729 this.readSplitVarint64_();
730 return jspb.utils.joinZigzag64(this.tempLow_, this.tempHigh_);
731};
732
733
734/**
735 * Reads a raw unsigned 8-bit integer from the binary stream.
736 *
737 * @return {number} The unsigned 8-bit integer read from the binary stream.
738 */
739jspb.BinaryDecoder.prototype.readUint8 = function() {
740 var a = this.bytes_[this.cursor_ + 0];
741 this.cursor_ += 1;
742 goog.asserts.assert(this.cursor_ <= this.end_);
743 return a;
744};
745
746
747/**
748 * Reads a raw unsigned 16-bit integer from the binary stream.
749 *
750 * @return {number} The unsigned 16-bit integer read from the binary stream.
751 */
752jspb.BinaryDecoder.prototype.readUint16 = function() {
753 var a = this.bytes_[this.cursor_ + 0];
754 var b = this.bytes_[this.cursor_ + 1];
755 this.cursor_ += 2;
756 goog.asserts.assert(this.cursor_ <= this.end_);
757 return (a << 0) | (b << 8);
758};
759
760
761/**
762 * Reads a raw unsigned 32-bit integer from the binary stream.
763 *
764 * @return {number} The unsigned 32-bit integer read from the binary stream.
765 */
766jspb.BinaryDecoder.prototype.readUint32 = function() {
767 var a = this.bytes_[this.cursor_ + 0];
768 var b = this.bytes_[this.cursor_ + 1];
769 var c = this.bytes_[this.cursor_ + 2];
770 var d = this.bytes_[this.cursor_ + 3];
771 this.cursor_ += 4;
772 goog.asserts.assert(this.cursor_ <= this.end_);
773 return ((a << 0) | (b << 8) | (c << 16) | (d << 24)) >>> 0;
774};
775
776
777/**
778 * Reads a raw unsigned 64-bit integer from the binary stream. Note that since
779 * Javascript represents all numbers as double-precision floats, there will be
780 * precision lost if the absolute value of the integer is larger than 2^53.
781 *
782 * @return {number} The unsigned 64-bit integer read from the binary stream.
783 * Precision will be lost if the integer exceeds 2^53.
784 */
785jspb.BinaryDecoder.prototype.readUint64 = function() {
786 var bitsLow = this.readUint32();
787 var bitsHigh = this.readUint32();
788 return jspb.utils.joinUint64(bitsLow, bitsHigh);
789};
790
791
792/**
793 * Reads a raw signed 8-bit integer from the binary stream.
794 *
795 * @return {number} The signed 8-bit integer read from the binary stream.
796 */
797jspb.BinaryDecoder.prototype.readInt8 = function() {
798 var a = this.bytes_[this.cursor_ + 0];
799 this.cursor_ += 1;
800 goog.asserts.assert(this.cursor_ <= this.end_);
801 return (a << 24) >> 24;
802};
803
804
805/**
806 * Reads a raw signed 16-bit integer from the binary stream.
807 *
808 * @return {number} The signed 16-bit integer read from the binary stream.
809 */
810jspb.BinaryDecoder.prototype.readInt16 = function() {
811 var a = this.bytes_[this.cursor_ + 0];
812 var b = this.bytes_[this.cursor_ + 1];
813 this.cursor_ += 2;
814 goog.asserts.assert(this.cursor_ <= this.end_);
815 return (((a << 0) | (b << 8)) << 16) >> 16;
816};
817
818
819/**
820 * Reads a raw signed 32-bit integer from the binary stream.
821 *
822 * @return {number} The signed 32-bit integer read from the binary stream.
823 */
824jspb.BinaryDecoder.prototype.readInt32 = function() {
825 var a = this.bytes_[this.cursor_ + 0];
826 var b = this.bytes_[this.cursor_ + 1];
827 var c = this.bytes_[this.cursor_ + 2];
828 var d = this.bytes_[this.cursor_ + 3];
829 this.cursor_ += 4;
830 goog.asserts.assert(this.cursor_ <= this.end_);
831 return (a << 0) | (b << 8) | (c << 16) | (d << 24);
832};
833
834
835/**
836 * Reads a raw signed 64-bit integer from the binary stream. Note that since
837 * Javascript represents all numbers as double-precision floats, there will be
838 * precision lost if the absolute vlaue of the integer is larger than 2^53.
839 *
840 * @return {number} The signed 64-bit integer read from the binary stream.
841 * Precision will be lost if the integer exceeds 2^53.
842 */
843jspb.BinaryDecoder.prototype.readInt64 = function() {
844 var bitsLow = this.readUint32();
845 var bitsHigh = this.readUint32();
846 return jspb.utils.joinInt64(bitsLow, bitsHigh);
847};
848
849
850/**
851 * Reads a 32-bit floating-point number from the binary stream, using the
852 * temporary buffer to realign the data.
853 *
854 * @return {number} The float read from the binary stream.
855 */
856jspb.BinaryDecoder.prototype.readFloat = function() {
857 var bitsLow = this.readUint32();
858 var bitsHigh = 0;
859 return jspb.utils.joinFloat32(bitsLow, bitsHigh);
860};
861
862
863/**
864 * Reads a 64-bit floating-point number from the binary stream, using the
865 * temporary buffer to realign the data.
866 *
867 * @return {number} The double read from the binary stream.
868 */
869jspb.BinaryDecoder.prototype.readDouble = function() {
870 var bitsLow = this.readUint32();
871 var bitsHigh = this.readUint32();
872 return jspb.utils.joinFloat64(bitsLow, bitsHigh);
873};
874
875
876/**
877 * Reads a boolean value from the binary stream.
878 * @return {boolean} The boolean read from the binary stream.
879 */
880jspb.BinaryDecoder.prototype.readBool = function() {
881 return !!this.bytes_[this.cursor_++];
882};
883
884
885/**
886 * Reads an enum value from the binary stream, which are always encoded as
887 * signed varints.
888 * @return {number} The enum value read from the binary stream.
889 */
890jspb.BinaryDecoder.prototype.readEnum = function() {
891 return this.readSignedVarint32();
892};
893
894
895/**
896 * Reads and parses a UTF-8 encoded unicode string from the stream.
897 * The code is inspired by maps.vectortown.parse.StreamedDataViewReader, with
898 * the exception that the implementation here does not get confused if it
899 * encounters characters longer than three bytes. These characters are ignored
900 * though, as they are extremely rare: three UTF-8 bytes cover virtually all
901 * characters in common use (http://en.wikipedia.org/wiki/UTF-8).
902 * @param {number} length The length of the string to read.
903 * @return {string} The decoded string.
904 */
905jspb.BinaryDecoder.prototype.readString = function(length) {
906 var bytes = this.bytes_;
907 var cursor = this.cursor_;
908 var end = cursor + length;
909 var chars = [];
910
911 while (cursor < end) {
912 var c = bytes[cursor++];
913 if (c < 128) { // Regular 7-bit ASCII.
914 chars.push(c);
915 } else if (c < 192) {
916 // UTF-8 continuation mark. We are out of sync. This
917 // might happen if we attempted to read a character
918 // with more than three bytes.
919 continue;
920 } else if (c < 224) { // UTF-8 with two bytes.
921 var c2 = bytes[cursor++];
922 chars.push(((c & 31) << 6) | (c2 & 63));
923 } else if (c < 240) { // UTF-8 with three bytes.
924 var c2 = bytes[cursor++];
925 var c3 = bytes[cursor++];
926 chars.push(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
927 }
928 }
929
930 // String.fromCharCode.apply is faster than manually appending characters on
931 // Chrome 25+, and generates no additional cons string garbage.
932 var result = String.fromCharCode.apply(null, chars);
933 this.cursor_ = cursor;
934 return result;
935};
936
937
938/**
939 * Reads and parses a UTF-8 encoded unicode string (with length prefix) from
940 * the stream.
941 * @return {string} The decoded string.
942 */
943jspb.BinaryDecoder.prototype.readStringWithLength = function() {
944 var length = this.readUnsignedVarint32();
945 return this.readString(length);
946};
947
948
949/**
950 * Reads a block of raw bytes from the binary stream.
951 *
952 * @param {number} length The number of bytes to read.
953 * @return {Uint8Array} The decoded block of bytes, or null if the length was
954 * invalid.
955 */
956jspb.BinaryDecoder.prototype.readBytes = function(length) {
957 if (length < 0 ||
958 this.cursor_ + length > this.bytes_.length) {
959 this.error_ = true;
960 return null;
961 }
962
963 var result = this.bytes_.subarray(this.cursor_, this.cursor_ + length);
964
965 this.cursor_ += length;
966 goog.asserts.assert(this.cursor_ <= this.end_);
967 return result;
968};
969
970
971/**
972 * Reads a 64-bit varint from the stream and returns it as an 8-character
973 * Unicode string for use as a hash table key.
974 *
975 * @return {string} The hash value.
976 */
977jspb.BinaryDecoder.prototype.readVarintHash64 = function() {
978 this.readSplitVarint64_();
979 return jspb.utils.joinHash64(this.tempLow_, this.tempHigh_);
980};
981
982
983/**
984 * Reads a 64-bit fixed-width value from the stream and returns it as an
985 * 8-character Unicode string for use as a hash table key.
986 *
987 * @return {string} The hash value.
988 */
989jspb.BinaryDecoder.prototype.readFixedHash64 = function() {
990 var bytes = this.bytes_;
991 var cursor = this.cursor_;
992
993 var a = bytes[cursor + 0];
994 var b = bytes[cursor + 1];
995 var c = bytes[cursor + 2];
996 var d = bytes[cursor + 3];
997 var e = bytes[cursor + 4];
998 var f = bytes[cursor + 5];
999 var g = bytes[cursor + 6];
1000 var h = bytes[cursor + 7];
1001
1002 this.cursor_ += 8;
1003
1004 return String.fromCharCode(a, b, c, d, e, f, g, h);
1005};