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