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