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 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/** 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. 954 * @return {!Uint8Array} The decoded block of bytes, or an empty block if the 955 * length was invalid. 956 */ 957jspb.BinaryDecoder.prototype.readBytes = function(length) { 958 if (length < 0 || 959 this.cursor_ + length > this.bytes_.length) { 960 this.error_ = true; 961 goog.asserts.fail('Invalid byte length!'); 962 return new Uint8Array(0); 963 } 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}; 1008