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