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 helper code used by jspb.BinaryReader
33ffe3c632Sopenharmony_ci * and BinaryWriter.
34ffe3c632Sopenharmony_ci *
35ffe3c632Sopenharmony_ci * @author aappleby@google.com (Austin Appleby)
36ffe3c632Sopenharmony_ci */
37ffe3c632Sopenharmony_ci
38ffe3c632Sopenharmony_cigoog.provide('jspb.utils');
39ffe3c632Sopenharmony_ci
40ffe3c632Sopenharmony_cigoog.require('goog.asserts');
41ffe3c632Sopenharmony_cigoog.require('goog.crypt');
42ffe3c632Sopenharmony_cigoog.require('goog.crypt.base64');
43ffe3c632Sopenharmony_cigoog.require('goog.string');
44ffe3c632Sopenharmony_cigoog.require('jspb.BinaryConstants');
45ffe3c632Sopenharmony_ci
46ffe3c632Sopenharmony_ci
47ffe3c632Sopenharmony_ci/**
48ffe3c632Sopenharmony_ci * Javascript can't natively handle 64-bit data types, so to manipulate them we
49ffe3c632Sopenharmony_ci * have to split them into two 32-bit halves and do the math manually.
50ffe3c632Sopenharmony_ci *
51ffe3c632Sopenharmony_ci * Instead of instantiating and passing small structures around to do this, we
52ffe3c632Sopenharmony_ci * instead just use two global temporary values. This one stores the low 32
53ffe3c632Sopenharmony_ci * bits of a split value - for example, if the original value was a 64-bit
54ffe3c632Sopenharmony_ci * integer, this temporary value will contain the low 32 bits of that integer.
55ffe3c632Sopenharmony_ci * If the original value was a double, this temporary value will contain the
56ffe3c632Sopenharmony_ci * low 32 bits of the binary representation of that double, etcetera.
57ffe3c632Sopenharmony_ci * @type {number}
58ffe3c632Sopenharmony_ci */
59ffe3c632Sopenharmony_cijspb.utils.split64Low = 0;
60ffe3c632Sopenharmony_ci
61ffe3c632Sopenharmony_ci
62ffe3c632Sopenharmony_ci/**
63ffe3c632Sopenharmony_ci * And correspondingly, this temporary variable will contain the high 32 bits
64ffe3c632Sopenharmony_ci * of whatever value was split.
65ffe3c632Sopenharmony_ci * @type {number}
66ffe3c632Sopenharmony_ci */
67ffe3c632Sopenharmony_cijspb.utils.split64High = 0;
68ffe3c632Sopenharmony_ci
69ffe3c632Sopenharmony_ci
70ffe3c632Sopenharmony_ci/**
71ffe3c632Sopenharmony_ci * Splits an unsigned Javascript integer into two 32-bit halves and stores it
72ffe3c632Sopenharmony_ci * in the temp values above.
73ffe3c632Sopenharmony_ci * @param {number} value The number to split.
74ffe3c632Sopenharmony_ci */
75ffe3c632Sopenharmony_cijspb.utils.splitUint64 = function(value) {
76ffe3c632Sopenharmony_ci  // Extract low 32 bits and high 32 bits as unsigned integers.
77ffe3c632Sopenharmony_ci  var lowBits = value >>> 0;
78ffe3c632Sopenharmony_ci  var highBits = Math.floor((value - lowBits) /
79ffe3c632Sopenharmony_ci                            jspb.BinaryConstants.TWO_TO_32) >>> 0;
80ffe3c632Sopenharmony_ci
81ffe3c632Sopenharmony_ci  jspb.utils.split64Low = lowBits;
82ffe3c632Sopenharmony_ci  jspb.utils.split64High = highBits;
83ffe3c632Sopenharmony_ci};
84ffe3c632Sopenharmony_ci
85ffe3c632Sopenharmony_ci
86ffe3c632Sopenharmony_ci/**
87ffe3c632Sopenharmony_ci * Splits a signed Javascript integer into two 32-bit halves and stores it in
88ffe3c632Sopenharmony_ci * the temp values above.
89ffe3c632Sopenharmony_ci * @param {number} value The number to split.
90ffe3c632Sopenharmony_ci */
91ffe3c632Sopenharmony_cijspb.utils.splitInt64 = function(value) {
92ffe3c632Sopenharmony_ci  // Convert to sign-magnitude representation.
93ffe3c632Sopenharmony_ci  var sign = (value < 0);
94ffe3c632Sopenharmony_ci  value = Math.abs(value);
95ffe3c632Sopenharmony_ci
96ffe3c632Sopenharmony_ci  // Extract low 32 bits and high 32 bits as unsigned integers.
97ffe3c632Sopenharmony_ci  var lowBits = value >>> 0;
98ffe3c632Sopenharmony_ci  var highBits = Math.floor((value - lowBits) /
99ffe3c632Sopenharmony_ci                            jspb.BinaryConstants.TWO_TO_32);
100ffe3c632Sopenharmony_ci  highBits = highBits >>> 0;
101ffe3c632Sopenharmony_ci
102ffe3c632Sopenharmony_ci  // Perform two's complement conversion if the sign bit was set.
103ffe3c632Sopenharmony_ci  if (sign) {
104ffe3c632Sopenharmony_ci    highBits = ~highBits >>> 0;
105ffe3c632Sopenharmony_ci    lowBits = ~lowBits >>> 0;
106ffe3c632Sopenharmony_ci    lowBits += 1;
107ffe3c632Sopenharmony_ci    if (lowBits > 0xFFFFFFFF) {
108ffe3c632Sopenharmony_ci      lowBits = 0;
109ffe3c632Sopenharmony_ci      highBits++;
110ffe3c632Sopenharmony_ci      if (highBits > 0xFFFFFFFF) highBits = 0;
111ffe3c632Sopenharmony_ci    }
112ffe3c632Sopenharmony_ci  }
113ffe3c632Sopenharmony_ci
114ffe3c632Sopenharmony_ci  jspb.utils.split64Low = lowBits;
115ffe3c632Sopenharmony_ci  jspb.utils.split64High = highBits;
116ffe3c632Sopenharmony_ci};
117ffe3c632Sopenharmony_ci
118ffe3c632Sopenharmony_ci
119ffe3c632Sopenharmony_ci/**
120ffe3c632Sopenharmony_ci * Converts a signed Javascript integer into zigzag format, splits it into two
121ffe3c632Sopenharmony_ci * 32-bit halves, and stores it in the temp values above.
122ffe3c632Sopenharmony_ci * @param {number} value The number to split.
123ffe3c632Sopenharmony_ci */
124ffe3c632Sopenharmony_cijspb.utils.splitZigzag64 = function(value) {
125ffe3c632Sopenharmony_ci  // Convert to sign-magnitude and scale by 2 before we split the value.
126ffe3c632Sopenharmony_ci  var sign = (value < 0);
127ffe3c632Sopenharmony_ci  value = Math.abs(value) * 2;
128ffe3c632Sopenharmony_ci
129ffe3c632Sopenharmony_ci  jspb.utils.splitUint64(value);
130ffe3c632Sopenharmony_ci  var lowBits = jspb.utils.split64Low;
131ffe3c632Sopenharmony_ci  var highBits = jspb.utils.split64High;
132ffe3c632Sopenharmony_ci
133ffe3c632Sopenharmony_ci  // If the value is negative, subtract 1 from the split representation so we
134ffe3c632Sopenharmony_ci  // don't lose the sign bit due to precision issues.
135ffe3c632Sopenharmony_ci  if (sign) {
136ffe3c632Sopenharmony_ci    if (lowBits == 0) {
137ffe3c632Sopenharmony_ci      if (highBits == 0) {
138ffe3c632Sopenharmony_ci        lowBits = 0xFFFFFFFF;
139ffe3c632Sopenharmony_ci        highBits = 0xFFFFFFFF;
140ffe3c632Sopenharmony_ci      } else {
141ffe3c632Sopenharmony_ci        highBits--;
142ffe3c632Sopenharmony_ci        lowBits = 0xFFFFFFFF;
143ffe3c632Sopenharmony_ci      }
144ffe3c632Sopenharmony_ci    } else {
145ffe3c632Sopenharmony_ci      lowBits--;
146ffe3c632Sopenharmony_ci    }
147ffe3c632Sopenharmony_ci  }
148ffe3c632Sopenharmony_ci
149ffe3c632Sopenharmony_ci  jspb.utils.split64Low = lowBits;
150ffe3c632Sopenharmony_ci  jspb.utils.split64High = highBits;
151ffe3c632Sopenharmony_ci};
152ffe3c632Sopenharmony_ci
153ffe3c632Sopenharmony_ci
154ffe3c632Sopenharmony_ci/**
155ffe3c632Sopenharmony_ci * Converts a floating-point number into 32-bit IEEE representation and stores
156ffe3c632Sopenharmony_ci * it in the temp values above.
157ffe3c632Sopenharmony_ci * @param {number} value
158ffe3c632Sopenharmony_ci */
159ffe3c632Sopenharmony_cijspb.utils.splitFloat32 = function(value) {
160ffe3c632Sopenharmony_ci  var sign = (value < 0) ? 1 : 0;
161ffe3c632Sopenharmony_ci  value = sign ? -value : value;
162ffe3c632Sopenharmony_ci  var exp;
163ffe3c632Sopenharmony_ci  var mant;
164ffe3c632Sopenharmony_ci
165ffe3c632Sopenharmony_ci  // Handle zeros.
166ffe3c632Sopenharmony_ci  if (value === 0) {
167ffe3c632Sopenharmony_ci    if ((1 / value) > 0) {
168ffe3c632Sopenharmony_ci      // Positive zero.
169ffe3c632Sopenharmony_ci      jspb.utils.split64High = 0;
170ffe3c632Sopenharmony_ci      jspb.utils.split64Low = 0x00000000;
171ffe3c632Sopenharmony_ci    } else {
172ffe3c632Sopenharmony_ci      // Negative zero.
173ffe3c632Sopenharmony_ci      jspb.utils.split64High = 0;
174ffe3c632Sopenharmony_ci      jspb.utils.split64Low = 0x80000000;
175ffe3c632Sopenharmony_ci    }
176ffe3c632Sopenharmony_ci    return;
177ffe3c632Sopenharmony_ci  }
178ffe3c632Sopenharmony_ci
179ffe3c632Sopenharmony_ci  // Handle nans.
180ffe3c632Sopenharmony_ci  if (isNaN(value)) {
181ffe3c632Sopenharmony_ci    jspb.utils.split64High = 0;
182ffe3c632Sopenharmony_ci    jspb.utils.split64Low = 0x7FFFFFFF;
183ffe3c632Sopenharmony_ci    return;
184ffe3c632Sopenharmony_ci  }
185ffe3c632Sopenharmony_ci
186ffe3c632Sopenharmony_ci  // Handle infinities.
187ffe3c632Sopenharmony_ci  if (value > jspb.BinaryConstants.FLOAT32_MAX) {
188ffe3c632Sopenharmony_ci    jspb.utils.split64High = 0;
189ffe3c632Sopenharmony_ci    jspb.utils.split64Low = ((sign << 31) | (0x7F800000)) >>> 0;
190ffe3c632Sopenharmony_ci    return;
191ffe3c632Sopenharmony_ci  }
192ffe3c632Sopenharmony_ci
193ffe3c632Sopenharmony_ci  // Handle denormals.
194ffe3c632Sopenharmony_ci  if (value < jspb.BinaryConstants.FLOAT32_MIN) {
195ffe3c632Sopenharmony_ci    // Number is a denormal.
196ffe3c632Sopenharmony_ci    mant = Math.round(value / Math.pow(2, -149));
197ffe3c632Sopenharmony_ci    jspb.utils.split64High = 0;
198ffe3c632Sopenharmony_ci    jspb.utils.split64Low = ((sign << 31) | mant) >>> 0;
199ffe3c632Sopenharmony_ci    return;
200ffe3c632Sopenharmony_ci  }
201ffe3c632Sopenharmony_ci
202ffe3c632Sopenharmony_ci  exp = Math.floor(Math.log(value) / Math.LN2);
203ffe3c632Sopenharmony_ci  mant = value * Math.pow(2, -exp);
204ffe3c632Sopenharmony_ci  mant = Math.round(mant * jspb.BinaryConstants.TWO_TO_23) & 0x7FFFFF;
205ffe3c632Sopenharmony_ci
206ffe3c632Sopenharmony_ci  jspb.utils.split64High = 0;
207ffe3c632Sopenharmony_ci  jspb.utils.split64Low = ((sign << 31) | ((exp + 127) << 23) | mant) >>> 0;
208ffe3c632Sopenharmony_ci};
209ffe3c632Sopenharmony_ci
210ffe3c632Sopenharmony_ci
211ffe3c632Sopenharmony_ci/**
212ffe3c632Sopenharmony_ci * Converts a floating-point number into 64-bit IEEE representation and stores
213ffe3c632Sopenharmony_ci * it in the temp values above.
214ffe3c632Sopenharmony_ci * @param {number} value
215ffe3c632Sopenharmony_ci */
216ffe3c632Sopenharmony_cijspb.utils.splitFloat64 = function(value) {
217ffe3c632Sopenharmony_ci  var sign = (value < 0) ? 1 : 0;
218ffe3c632Sopenharmony_ci  value = sign ? -value : value;
219ffe3c632Sopenharmony_ci
220ffe3c632Sopenharmony_ci  // Handle zeros.
221ffe3c632Sopenharmony_ci  if (value === 0) {
222ffe3c632Sopenharmony_ci    if ((1 / value) > 0) {
223ffe3c632Sopenharmony_ci      // Positive zero.
224ffe3c632Sopenharmony_ci      jspb.utils.split64High = 0x00000000;
225ffe3c632Sopenharmony_ci      jspb.utils.split64Low = 0x00000000;
226ffe3c632Sopenharmony_ci    } else {
227ffe3c632Sopenharmony_ci      // Negative zero.
228ffe3c632Sopenharmony_ci      jspb.utils.split64High = 0x80000000;
229ffe3c632Sopenharmony_ci      jspb.utils.split64Low = 0x00000000;
230ffe3c632Sopenharmony_ci    }
231ffe3c632Sopenharmony_ci    return;
232ffe3c632Sopenharmony_ci  }
233ffe3c632Sopenharmony_ci
234ffe3c632Sopenharmony_ci  // Handle nans.
235ffe3c632Sopenharmony_ci  if (isNaN(value)) {
236ffe3c632Sopenharmony_ci    jspb.utils.split64High = 0x7FFFFFFF;
237ffe3c632Sopenharmony_ci    jspb.utils.split64Low = 0xFFFFFFFF;
238ffe3c632Sopenharmony_ci    return;
239ffe3c632Sopenharmony_ci  }
240ffe3c632Sopenharmony_ci
241ffe3c632Sopenharmony_ci  // Handle infinities.
242ffe3c632Sopenharmony_ci  if (value > jspb.BinaryConstants.FLOAT64_MAX) {
243ffe3c632Sopenharmony_ci    jspb.utils.split64High = ((sign << 31) | (0x7FF00000)) >>> 0;
244ffe3c632Sopenharmony_ci    jspb.utils.split64Low = 0;
245ffe3c632Sopenharmony_ci    return;
246ffe3c632Sopenharmony_ci  }
247ffe3c632Sopenharmony_ci
248ffe3c632Sopenharmony_ci  // Handle denormals.
249ffe3c632Sopenharmony_ci  if (value < jspb.BinaryConstants.FLOAT64_MIN) {
250ffe3c632Sopenharmony_ci    // Number is a denormal.
251ffe3c632Sopenharmony_ci    var mant = value / Math.pow(2, -1074);
252ffe3c632Sopenharmony_ci    var mantHigh = (mant / jspb.BinaryConstants.TWO_TO_32);
253ffe3c632Sopenharmony_ci    jspb.utils.split64High = ((sign << 31) | mantHigh) >>> 0;
254ffe3c632Sopenharmony_ci    jspb.utils.split64Low = (mant >>> 0);
255ffe3c632Sopenharmony_ci    return;
256ffe3c632Sopenharmony_ci  }
257ffe3c632Sopenharmony_ci
258ffe3c632Sopenharmony_ci  // Compute the least significant exponent needed to represent the magnitude of
259ffe3c632Sopenharmony_ci  // the value by repeadly dividing/multiplying by 2 until the magnitude
260ffe3c632Sopenharmony_ci  // crosses 2. While tempting to use log math to find the exponent, at the
261ffe3c632Sopenharmony_ci  // bounadaries of precision, the result can be off by one.
262ffe3c632Sopenharmony_ci  var maxDoubleExponent = 1023;
263ffe3c632Sopenharmony_ci  var minDoubleExponent = -1022;
264ffe3c632Sopenharmony_ci  var x = value;
265ffe3c632Sopenharmony_ci  var exp = 0;
266ffe3c632Sopenharmony_ci  if (x >= 2) {
267ffe3c632Sopenharmony_ci    while (x >= 2 && exp < maxDoubleExponent) {
268ffe3c632Sopenharmony_ci      exp++;
269ffe3c632Sopenharmony_ci      x = x / 2;
270ffe3c632Sopenharmony_ci    }
271ffe3c632Sopenharmony_ci  } else {
272ffe3c632Sopenharmony_ci    while (x < 1 && exp > minDoubleExponent) {
273ffe3c632Sopenharmony_ci      x = x * 2;
274ffe3c632Sopenharmony_ci      exp--;
275ffe3c632Sopenharmony_ci    }
276ffe3c632Sopenharmony_ci  }
277ffe3c632Sopenharmony_ci  var mant = value * Math.pow(2, -exp);
278ffe3c632Sopenharmony_ci
279ffe3c632Sopenharmony_ci  var mantHigh = (mant * jspb.BinaryConstants.TWO_TO_20) & 0xFFFFF;
280ffe3c632Sopenharmony_ci  var mantLow = (mant * jspb.BinaryConstants.TWO_TO_52) >>> 0;
281ffe3c632Sopenharmony_ci
282ffe3c632Sopenharmony_ci  jspb.utils.split64High =
283ffe3c632Sopenharmony_ci      ((sign << 31) | ((exp + 1023) << 20) | mantHigh) >>> 0;
284ffe3c632Sopenharmony_ci  jspb.utils.split64Low = mantLow;
285ffe3c632Sopenharmony_ci};
286ffe3c632Sopenharmony_ci
287ffe3c632Sopenharmony_ci
288ffe3c632Sopenharmony_ci/**
289ffe3c632Sopenharmony_ci * Converts an 8-character hash string into two 32-bit numbers and stores them
290ffe3c632Sopenharmony_ci * in the temp values above.
291ffe3c632Sopenharmony_ci * @param {string} hash
292ffe3c632Sopenharmony_ci */
293ffe3c632Sopenharmony_cijspb.utils.splitHash64 = function(hash) {
294ffe3c632Sopenharmony_ci  var a = hash.charCodeAt(0);
295ffe3c632Sopenharmony_ci  var b = hash.charCodeAt(1);
296ffe3c632Sopenharmony_ci  var c = hash.charCodeAt(2);
297ffe3c632Sopenharmony_ci  var d = hash.charCodeAt(3);
298ffe3c632Sopenharmony_ci  var e = hash.charCodeAt(4);
299ffe3c632Sopenharmony_ci  var f = hash.charCodeAt(5);
300ffe3c632Sopenharmony_ci  var g = hash.charCodeAt(6);
301ffe3c632Sopenharmony_ci  var h = hash.charCodeAt(7);
302ffe3c632Sopenharmony_ci
303ffe3c632Sopenharmony_ci  jspb.utils.split64Low = (a + (b << 8) + (c << 16) + (d << 24)) >>> 0;
304ffe3c632Sopenharmony_ci  jspb.utils.split64High = (e + (f << 8) + (g << 16) + (h << 24)) >>> 0;
305ffe3c632Sopenharmony_ci};
306ffe3c632Sopenharmony_ci
307ffe3c632Sopenharmony_ci
308ffe3c632Sopenharmony_ci/**
309ffe3c632Sopenharmony_ci * Joins two 32-bit values into a 64-bit unsigned integer. Precision will be
310ffe3c632Sopenharmony_ci * lost if the result is greater than 2^52.
311ffe3c632Sopenharmony_ci * @param {number} bitsLow
312ffe3c632Sopenharmony_ci * @param {number} bitsHigh
313ffe3c632Sopenharmony_ci * @return {number}
314ffe3c632Sopenharmony_ci */
315ffe3c632Sopenharmony_cijspb.utils.joinUint64 = function(bitsLow, bitsHigh) {
316ffe3c632Sopenharmony_ci  return bitsHigh * jspb.BinaryConstants.TWO_TO_32 + (bitsLow >>> 0);
317ffe3c632Sopenharmony_ci};
318ffe3c632Sopenharmony_ci
319ffe3c632Sopenharmony_ci
320ffe3c632Sopenharmony_ci/**
321ffe3c632Sopenharmony_ci * Joins two 32-bit values into a 64-bit signed integer. Precision will be lost
322ffe3c632Sopenharmony_ci * if the result is greater than 2^52.
323ffe3c632Sopenharmony_ci * @param {number} bitsLow
324ffe3c632Sopenharmony_ci * @param {number} bitsHigh
325ffe3c632Sopenharmony_ci * @return {number}
326ffe3c632Sopenharmony_ci */
327ffe3c632Sopenharmony_cijspb.utils.joinInt64 = function(bitsLow, bitsHigh) {
328ffe3c632Sopenharmony_ci  // If the high bit is set, do a manual two's complement conversion.
329ffe3c632Sopenharmony_ci  var sign = (bitsHigh & 0x80000000);
330ffe3c632Sopenharmony_ci  if (sign) {
331ffe3c632Sopenharmony_ci    bitsLow = (~bitsLow + 1) >>> 0;
332ffe3c632Sopenharmony_ci    bitsHigh = ~bitsHigh >>> 0;
333ffe3c632Sopenharmony_ci    if (bitsLow == 0) {
334ffe3c632Sopenharmony_ci      bitsHigh = (bitsHigh + 1) >>> 0;
335ffe3c632Sopenharmony_ci    }
336ffe3c632Sopenharmony_ci  }
337ffe3c632Sopenharmony_ci
338ffe3c632Sopenharmony_ci  var result = jspb.utils.joinUint64(bitsLow, bitsHigh);
339ffe3c632Sopenharmony_ci  return sign ? -result : result;
340ffe3c632Sopenharmony_ci};
341ffe3c632Sopenharmony_ci
342ffe3c632Sopenharmony_ci/**
343ffe3c632Sopenharmony_ci * Converts split 64-bit values from standard two's complement encoding to
344ffe3c632Sopenharmony_ci * zig-zag encoding. Invokes the provided function to produce final result.
345ffe3c632Sopenharmony_ci *
346ffe3c632Sopenharmony_ci * @param {number} bitsLow
347ffe3c632Sopenharmony_ci * @param {number} bitsHigh
348ffe3c632Sopenharmony_ci * @param {function(number, number): T} convert Conversion function to produce
349ffe3c632Sopenharmony_ci *     the result value, takes parameters (lowBits, highBits).
350ffe3c632Sopenharmony_ci * @return {T}
351ffe3c632Sopenharmony_ci * @template T
352ffe3c632Sopenharmony_ci */
353ffe3c632Sopenharmony_cijspb.utils.toZigzag64 = function(bitsLow, bitsHigh, convert) {
354ffe3c632Sopenharmony_ci  // See
355ffe3c632Sopenharmony_ci  // https://engdoc.corp.google.com/eng/howto/protocolbuffers/developerguide/encoding.shtml?cl=head#types
356ffe3c632Sopenharmony_ci  // 64-bit math is: (n << 1) ^ (n >> 63)
357ffe3c632Sopenharmony_ci  //
358ffe3c632Sopenharmony_ci  // To do this in 32 bits, we can get a 32-bit sign-flipping mask from the
359ffe3c632Sopenharmony_ci  // high word.
360ffe3c632Sopenharmony_ci  // Then we can operate on each word individually, with the addition of the
361ffe3c632Sopenharmony_ci  // "carry" to get the most significant bit from the low word into the high
362ffe3c632Sopenharmony_ci  // word.
363ffe3c632Sopenharmony_ci  var signFlipMask = bitsHigh >> 31;
364ffe3c632Sopenharmony_ci  bitsHigh = (bitsHigh << 1 | bitsLow >>> 31) ^ signFlipMask;
365ffe3c632Sopenharmony_ci  bitsLow = (bitsLow << 1) ^ signFlipMask;
366ffe3c632Sopenharmony_ci  return convert(bitsLow, bitsHigh);
367ffe3c632Sopenharmony_ci};
368ffe3c632Sopenharmony_ci
369ffe3c632Sopenharmony_ci
370ffe3c632Sopenharmony_ci/**
371ffe3c632Sopenharmony_ci * Joins two 32-bit values into a 64-bit unsigned integer and applies zigzag
372ffe3c632Sopenharmony_ci * decoding. Precision will be lost if the result is greater than 2^52.
373ffe3c632Sopenharmony_ci * @param {number} bitsLow
374ffe3c632Sopenharmony_ci * @param {number} bitsHigh
375ffe3c632Sopenharmony_ci * @return {number}
376ffe3c632Sopenharmony_ci */
377ffe3c632Sopenharmony_cijspb.utils.joinZigzag64 = function(bitsLow, bitsHigh) {
378ffe3c632Sopenharmony_ci  return jspb.utils.fromZigzag64(bitsLow, bitsHigh, jspb.utils.joinInt64);
379ffe3c632Sopenharmony_ci};
380ffe3c632Sopenharmony_ci
381ffe3c632Sopenharmony_ci
382ffe3c632Sopenharmony_ci/**
383ffe3c632Sopenharmony_ci * Converts split 64-bit values from zigzag encoding to standard two's
384ffe3c632Sopenharmony_ci * complement encoding. Invokes the provided function to produce final result.
385ffe3c632Sopenharmony_ci *
386ffe3c632Sopenharmony_ci * @param {number} bitsLow
387ffe3c632Sopenharmony_ci * @param {number} bitsHigh
388ffe3c632Sopenharmony_ci * @param {function(number, number): T} convert Conversion function to produce
389ffe3c632Sopenharmony_ci *     the result value, takes parameters (lowBits, highBits).
390ffe3c632Sopenharmony_ci * @return {T}
391ffe3c632Sopenharmony_ci * @template T
392ffe3c632Sopenharmony_ci */
393ffe3c632Sopenharmony_cijspb.utils.fromZigzag64 = function(bitsLow, bitsHigh, convert) {
394ffe3c632Sopenharmony_ci  // 64 bit math is:
395ffe3c632Sopenharmony_ci  //   signmask = (zigzag & 1) ? -1 : 0;
396ffe3c632Sopenharmony_ci  //   twosComplement = (zigzag >> 1) ^ signmask;
397ffe3c632Sopenharmony_ci  //
398ffe3c632Sopenharmony_ci  // To work with 32 bit, we can operate on both but "carry" the lowest bit
399ffe3c632Sopenharmony_ci  // from the high word by shifting it up 31 bits to be the most significant bit
400ffe3c632Sopenharmony_ci  // of the low word.
401ffe3c632Sopenharmony_ci  var signFlipMask = -(bitsLow & 1);
402ffe3c632Sopenharmony_ci  bitsLow = ((bitsLow >>> 1) | (bitsHigh << 31)) ^ signFlipMask;
403ffe3c632Sopenharmony_ci  bitsHigh = (bitsHigh >>> 1) ^ signFlipMask;
404ffe3c632Sopenharmony_ci  return convert(bitsLow, bitsHigh);
405ffe3c632Sopenharmony_ci};
406ffe3c632Sopenharmony_ci
407ffe3c632Sopenharmony_ci
408ffe3c632Sopenharmony_ci/**
409ffe3c632Sopenharmony_ci * Joins two 32-bit values into a 32-bit IEEE floating point number and
410ffe3c632Sopenharmony_ci * converts it back into a Javascript number.
411ffe3c632Sopenharmony_ci * @param {number} bitsLow The low 32 bits of the binary number;
412ffe3c632Sopenharmony_ci * @param {number} bitsHigh The high 32 bits of the binary number.
413ffe3c632Sopenharmony_ci * @return {number}
414ffe3c632Sopenharmony_ci */
415ffe3c632Sopenharmony_cijspb.utils.joinFloat32 = function(bitsLow, bitsHigh) {
416ffe3c632Sopenharmony_ci  var sign = ((bitsLow >> 31) * 2 + 1);
417ffe3c632Sopenharmony_ci  var exp = (bitsLow >>> 23) & 0xFF;
418ffe3c632Sopenharmony_ci  var mant = bitsLow & 0x7FFFFF;
419ffe3c632Sopenharmony_ci
420ffe3c632Sopenharmony_ci  if (exp == 0xFF) {
421ffe3c632Sopenharmony_ci    if (mant) {
422ffe3c632Sopenharmony_ci      return NaN;
423ffe3c632Sopenharmony_ci    } else {
424ffe3c632Sopenharmony_ci      return sign * Infinity;
425ffe3c632Sopenharmony_ci    }
426ffe3c632Sopenharmony_ci  }
427ffe3c632Sopenharmony_ci
428ffe3c632Sopenharmony_ci  if (exp == 0) {
429ffe3c632Sopenharmony_ci    // Denormal.
430ffe3c632Sopenharmony_ci    return sign * Math.pow(2, -149) * mant;
431ffe3c632Sopenharmony_ci  } else {
432ffe3c632Sopenharmony_ci    return sign * Math.pow(2, exp - 150) *
433ffe3c632Sopenharmony_ci           (mant + Math.pow(2, 23));
434ffe3c632Sopenharmony_ci  }
435ffe3c632Sopenharmony_ci};
436ffe3c632Sopenharmony_ci
437ffe3c632Sopenharmony_ci
438ffe3c632Sopenharmony_ci/**
439ffe3c632Sopenharmony_ci * Joins two 32-bit values into a 64-bit IEEE floating point number and
440ffe3c632Sopenharmony_ci * converts it back into a Javascript number.
441ffe3c632Sopenharmony_ci * @param {number} bitsLow The low 32 bits of the binary number;
442ffe3c632Sopenharmony_ci * @param {number} bitsHigh The high 32 bits of the binary number.
443ffe3c632Sopenharmony_ci * @return {number}
444ffe3c632Sopenharmony_ci */
445ffe3c632Sopenharmony_cijspb.utils.joinFloat64 = function(bitsLow, bitsHigh) {
446ffe3c632Sopenharmony_ci  var sign = ((bitsHigh >> 31) * 2 + 1);
447ffe3c632Sopenharmony_ci  var exp = (bitsHigh >>> 20) & 0x7FF;
448ffe3c632Sopenharmony_ci  var mant = jspb.BinaryConstants.TWO_TO_32 * (bitsHigh & 0xFFFFF) + bitsLow;
449ffe3c632Sopenharmony_ci
450ffe3c632Sopenharmony_ci  if (exp == 0x7FF) {
451ffe3c632Sopenharmony_ci    if (mant) {
452ffe3c632Sopenharmony_ci      return NaN;
453ffe3c632Sopenharmony_ci    } else {
454ffe3c632Sopenharmony_ci      return sign * Infinity;
455ffe3c632Sopenharmony_ci    }
456ffe3c632Sopenharmony_ci  }
457ffe3c632Sopenharmony_ci
458ffe3c632Sopenharmony_ci  if (exp == 0) {
459ffe3c632Sopenharmony_ci    // Denormal.
460ffe3c632Sopenharmony_ci    return sign * Math.pow(2, -1074) * mant;
461ffe3c632Sopenharmony_ci  } else {
462ffe3c632Sopenharmony_ci    return sign * Math.pow(2, exp - 1075) *
463ffe3c632Sopenharmony_ci           (mant + jspb.BinaryConstants.TWO_TO_52);
464ffe3c632Sopenharmony_ci  }
465ffe3c632Sopenharmony_ci};
466ffe3c632Sopenharmony_ci
467ffe3c632Sopenharmony_ci
468ffe3c632Sopenharmony_ci/**
469ffe3c632Sopenharmony_ci * Joins two 32-bit values into an 8-character hash string.
470ffe3c632Sopenharmony_ci * @param {number} bitsLow
471ffe3c632Sopenharmony_ci * @param {number} bitsHigh
472ffe3c632Sopenharmony_ci * @return {string}
473ffe3c632Sopenharmony_ci */
474ffe3c632Sopenharmony_cijspb.utils.joinHash64 = function(bitsLow, bitsHigh) {
475ffe3c632Sopenharmony_ci  var a = (bitsLow >>> 0) & 0xFF;
476ffe3c632Sopenharmony_ci  var b = (bitsLow >>> 8) & 0xFF;
477ffe3c632Sopenharmony_ci  var c = (bitsLow >>> 16) & 0xFF;
478ffe3c632Sopenharmony_ci  var d = (bitsLow >>> 24) & 0xFF;
479ffe3c632Sopenharmony_ci  var e = (bitsHigh >>> 0) & 0xFF;
480ffe3c632Sopenharmony_ci  var f = (bitsHigh >>> 8) & 0xFF;
481ffe3c632Sopenharmony_ci  var g = (bitsHigh >>> 16) & 0xFF;
482ffe3c632Sopenharmony_ci  var h = (bitsHigh >>> 24) & 0xFF;
483ffe3c632Sopenharmony_ci
484ffe3c632Sopenharmony_ci  return String.fromCharCode(a, b, c, d, e, f, g, h);
485ffe3c632Sopenharmony_ci};
486ffe3c632Sopenharmony_ci
487ffe3c632Sopenharmony_ci/**
488ffe3c632Sopenharmony_ci * Individual digits for number->string conversion.
489ffe3c632Sopenharmony_ci * @const {!Array<string>}
490ffe3c632Sopenharmony_ci */
491ffe3c632Sopenharmony_cijspb.utils.DIGITS = [
492ffe3c632Sopenharmony_ci  '0', '1', '2', '3', '4', '5', '6', '7',
493ffe3c632Sopenharmony_ci  '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
494ffe3c632Sopenharmony_ci];
495ffe3c632Sopenharmony_ci
496ffe3c632Sopenharmony_ci/** @const @private {number} '0' */
497ffe3c632Sopenharmony_cijspb.utils.ZERO_CHAR_CODE_ = 48;
498ffe3c632Sopenharmony_ci
499ffe3c632Sopenharmony_ci/** @const @private {number} 'a' */
500ffe3c632Sopenharmony_cijspb.utils.A_CHAR_CODE_ = 97;
501ffe3c632Sopenharmony_ci
502ffe3c632Sopenharmony_ci/**
503ffe3c632Sopenharmony_ci * Losslessly converts a 64-bit unsigned integer in 32:32 split representation
504ffe3c632Sopenharmony_ci * into a decimal string.
505ffe3c632Sopenharmony_ci * @param {number} bitsLow The low 32 bits of the binary number;
506ffe3c632Sopenharmony_ci * @param {number} bitsHigh The high 32 bits of the binary number.
507ffe3c632Sopenharmony_ci * @return {string} The binary number represented as a string.
508ffe3c632Sopenharmony_ci */
509ffe3c632Sopenharmony_cijspb.utils.joinUnsignedDecimalString = function(bitsLow, bitsHigh) {
510ffe3c632Sopenharmony_ci  // Skip the expensive conversion if the number is small enough to use the
511ffe3c632Sopenharmony_ci  // built-in conversions.
512ffe3c632Sopenharmony_ci  if (bitsHigh <= 0x1FFFFF) {
513ffe3c632Sopenharmony_ci    return '' + (jspb.BinaryConstants.TWO_TO_32 * bitsHigh + bitsLow);
514ffe3c632Sopenharmony_ci  }
515ffe3c632Sopenharmony_ci
516ffe3c632Sopenharmony_ci  // What this code is doing is essentially converting the input number from
517ffe3c632Sopenharmony_ci  // base-2 to base-1e7, which allows us to represent the 64-bit range with
518ffe3c632Sopenharmony_ci  // only 3 (very large) digits. Those digits are then trivial to convert to
519ffe3c632Sopenharmony_ci  // a base-10 string.
520ffe3c632Sopenharmony_ci
521ffe3c632Sopenharmony_ci  // The magic numbers used here are -
522ffe3c632Sopenharmony_ci  // 2^24 = 16777216 = (1,6777216) in base-1e7.
523ffe3c632Sopenharmony_ci  // 2^48 = 281474976710656 = (2,8147497,6710656) in base-1e7.
524ffe3c632Sopenharmony_ci
525ffe3c632Sopenharmony_ci  // Split 32:32 representation into 16:24:24 representation so our
526ffe3c632Sopenharmony_ci  // intermediate digits don't overflow.
527ffe3c632Sopenharmony_ci  var low = bitsLow & 0xFFFFFF;
528ffe3c632Sopenharmony_ci  var mid = (((bitsLow >>> 24) | (bitsHigh << 8)) >>> 0) & 0xFFFFFF;
529ffe3c632Sopenharmony_ci  var high = (bitsHigh >> 16) & 0xFFFF;
530ffe3c632Sopenharmony_ci
531ffe3c632Sopenharmony_ci  // Assemble our three base-1e7 digits, ignoring carries. The maximum
532ffe3c632Sopenharmony_ci  // value in a digit at this step is representable as a 48-bit integer, which
533ffe3c632Sopenharmony_ci  // can be stored in a 64-bit floating point number.
534ffe3c632Sopenharmony_ci  var digitA = low + (mid * 6777216) + (high * 6710656);
535ffe3c632Sopenharmony_ci  var digitB = mid + (high * 8147497);
536ffe3c632Sopenharmony_ci  var digitC = (high * 2);
537ffe3c632Sopenharmony_ci
538ffe3c632Sopenharmony_ci  // Apply carries from A to B and from B to C.
539ffe3c632Sopenharmony_ci  var base = 10000000;
540ffe3c632Sopenharmony_ci  if (digitA >= base) {
541ffe3c632Sopenharmony_ci    digitB += Math.floor(digitA / base);
542ffe3c632Sopenharmony_ci    digitA %= base;
543ffe3c632Sopenharmony_ci  }
544ffe3c632Sopenharmony_ci
545ffe3c632Sopenharmony_ci  if (digitB >= base) {
546ffe3c632Sopenharmony_ci    digitC += Math.floor(digitB / base);
547ffe3c632Sopenharmony_ci    digitB %= base;
548ffe3c632Sopenharmony_ci  }
549ffe3c632Sopenharmony_ci
550ffe3c632Sopenharmony_ci  // Convert base-1e7 digits to base-10, with optional leading zeroes.
551ffe3c632Sopenharmony_ci  function decimalFrom1e7(digit1e7, needLeadingZeros) {
552ffe3c632Sopenharmony_ci    var partial = digit1e7 ? String(digit1e7) : '';
553ffe3c632Sopenharmony_ci    if (needLeadingZeros) {
554ffe3c632Sopenharmony_ci      return '0000000'.slice(partial.length) + partial;
555ffe3c632Sopenharmony_ci    }
556ffe3c632Sopenharmony_ci    return partial;
557ffe3c632Sopenharmony_ci  }
558ffe3c632Sopenharmony_ci
559ffe3c632Sopenharmony_ci  return decimalFrom1e7(digitC, /*needLeadingZeros=*/ 0) +
560ffe3c632Sopenharmony_ci      decimalFrom1e7(digitB, /*needLeadingZeros=*/ digitC) +
561ffe3c632Sopenharmony_ci      // If the final 1e7 digit didn't need leading zeros, we would have
562ffe3c632Sopenharmony_ci      // returned via the trivial code path at the top.
563ffe3c632Sopenharmony_ci      decimalFrom1e7(digitA, /*needLeadingZeros=*/ 1);
564ffe3c632Sopenharmony_ci};
565ffe3c632Sopenharmony_ci
566ffe3c632Sopenharmony_ci
567ffe3c632Sopenharmony_ci/**
568ffe3c632Sopenharmony_ci * Losslessly converts a 64-bit signed integer in 32:32 split representation
569ffe3c632Sopenharmony_ci * into a decimal string.
570ffe3c632Sopenharmony_ci * @param {number} bitsLow The low 32 bits of the binary number;
571ffe3c632Sopenharmony_ci * @param {number} bitsHigh The high 32 bits of the binary number.
572ffe3c632Sopenharmony_ci * @return {string} The binary number represented as a string.
573ffe3c632Sopenharmony_ci */
574ffe3c632Sopenharmony_cijspb.utils.joinSignedDecimalString = function(bitsLow, bitsHigh) {
575ffe3c632Sopenharmony_ci  // If we're treating the input as a signed value and the high bit is set, do
576ffe3c632Sopenharmony_ci  // a manual two's complement conversion before the decimal conversion.
577ffe3c632Sopenharmony_ci  var negative = (bitsHigh & 0x80000000);
578ffe3c632Sopenharmony_ci  if (negative) {
579ffe3c632Sopenharmony_ci    bitsLow = (~bitsLow + 1) >>> 0;
580ffe3c632Sopenharmony_ci    var carry = (bitsLow == 0) ? 1 : 0;
581ffe3c632Sopenharmony_ci    bitsHigh = (~bitsHigh + carry) >>> 0;
582ffe3c632Sopenharmony_ci  }
583ffe3c632Sopenharmony_ci
584ffe3c632Sopenharmony_ci  var result = jspb.utils.joinUnsignedDecimalString(bitsLow, bitsHigh);
585ffe3c632Sopenharmony_ci  return negative ? '-' + result : result;
586ffe3c632Sopenharmony_ci};
587ffe3c632Sopenharmony_ci
588ffe3c632Sopenharmony_ci
589ffe3c632Sopenharmony_ci/**
590ffe3c632Sopenharmony_ci * Convert an 8-character hash string representing either a signed or unsigned
591ffe3c632Sopenharmony_ci * 64-bit integer into its decimal representation without losing accuracy.
592ffe3c632Sopenharmony_ci * @param {string} hash The hash string to convert.
593ffe3c632Sopenharmony_ci * @param {boolean} signed True if we should treat the hash string as encoding
594ffe3c632Sopenharmony_ci *     a signed integer.
595ffe3c632Sopenharmony_ci * @return {string}
596ffe3c632Sopenharmony_ci */
597ffe3c632Sopenharmony_cijspb.utils.hash64ToDecimalString = function(hash, signed) {
598ffe3c632Sopenharmony_ci  jspb.utils.splitHash64(hash);
599ffe3c632Sopenharmony_ci  var bitsLow = jspb.utils.split64Low;
600ffe3c632Sopenharmony_ci  var bitsHigh = jspb.utils.split64High;
601ffe3c632Sopenharmony_ci  return signed ?
602ffe3c632Sopenharmony_ci      jspb.utils.joinSignedDecimalString(bitsLow, bitsHigh) :
603ffe3c632Sopenharmony_ci      jspb.utils.joinUnsignedDecimalString(bitsLow, bitsHigh);
604ffe3c632Sopenharmony_ci};
605ffe3c632Sopenharmony_ci
606ffe3c632Sopenharmony_ci
607ffe3c632Sopenharmony_ci/**
608ffe3c632Sopenharmony_ci * Converts an array of 8-character hash strings into their decimal
609ffe3c632Sopenharmony_ci * representations.
610ffe3c632Sopenharmony_ci * @param {!Array<string>} hashes The array of hash strings to convert.
611ffe3c632Sopenharmony_ci * @param {boolean} signed True if we should treat the hash string as encoding
612ffe3c632Sopenharmony_ci *     a signed integer.
613ffe3c632Sopenharmony_ci * @return {!Array<string>}
614ffe3c632Sopenharmony_ci */
615ffe3c632Sopenharmony_cijspb.utils.hash64ArrayToDecimalStrings = function(hashes, signed) {
616ffe3c632Sopenharmony_ci  var result = new Array(hashes.length);
617ffe3c632Sopenharmony_ci  for (var i = 0; i < hashes.length; i++) {
618ffe3c632Sopenharmony_ci    result[i] = jspb.utils.hash64ToDecimalString(hashes[i], signed);
619ffe3c632Sopenharmony_ci  }
620ffe3c632Sopenharmony_ci  return result;
621ffe3c632Sopenharmony_ci};
622ffe3c632Sopenharmony_ci
623ffe3c632Sopenharmony_ci
624ffe3c632Sopenharmony_ci/**
625ffe3c632Sopenharmony_ci * Converts a signed or unsigned decimal string into its hash string
626ffe3c632Sopenharmony_ci * representation.
627ffe3c632Sopenharmony_ci * @param {string} dec
628ffe3c632Sopenharmony_ci * @return {string}
629ffe3c632Sopenharmony_ci */
630ffe3c632Sopenharmony_cijspb.utils.decimalStringToHash64 = function(dec) {
631ffe3c632Sopenharmony_ci  goog.asserts.assert(dec.length > 0);
632ffe3c632Sopenharmony_ci
633ffe3c632Sopenharmony_ci  // Check for minus sign.
634ffe3c632Sopenharmony_ci  var minus = false;
635ffe3c632Sopenharmony_ci  if (dec[0] === '-') {
636ffe3c632Sopenharmony_ci    minus = true;
637ffe3c632Sopenharmony_ci    dec = dec.slice(1);
638ffe3c632Sopenharmony_ci  }
639ffe3c632Sopenharmony_ci
640ffe3c632Sopenharmony_ci  // Store result as a byte array.
641ffe3c632Sopenharmony_ci  var resultBytes = [0, 0, 0, 0, 0, 0, 0, 0];
642ffe3c632Sopenharmony_ci
643ffe3c632Sopenharmony_ci  // Set result to m*result + c.
644ffe3c632Sopenharmony_ci  function muladd(m, c) {
645ffe3c632Sopenharmony_ci    for (var i = 0; i < 8 && (m !== 1 || c > 0); i++) {
646ffe3c632Sopenharmony_ci      var r = m * resultBytes[i] + c;
647ffe3c632Sopenharmony_ci      resultBytes[i] = r & 0xFF;
648ffe3c632Sopenharmony_ci      c = r >>> 8;
649ffe3c632Sopenharmony_ci    }
650ffe3c632Sopenharmony_ci  }
651ffe3c632Sopenharmony_ci
652ffe3c632Sopenharmony_ci  // Negate the result bits.
653ffe3c632Sopenharmony_ci  function neg() {
654ffe3c632Sopenharmony_ci    for (var i = 0; i < 8; i++) {
655ffe3c632Sopenharmony_ci      resultBytes[i] = (~resultBytes[i]) & 0xFF;
656ffe3c632Sopenharmony_ci    }
657ffe3c632Sopenharmony_ci  }
658ffe3c632Sopenharmony_ci
659ffe3c632Sopenharmony_ci  // For each decimal digit, set result to 10*result + digit.
660ffe3c632Sopenharmony_ci  for (var i = 0; i < dec.length; i++) {
661ffe3c632Sopenharmony_ci    muladd(10, dec.charCodeAt(i) - jspb.utils.ZERO_CHAR_CODE_);
662ffe3c632Sopenharmony_ci  }
663ffe3c632Sopenharmony_ci
664ffe3c632Sopenharmony_ci  // If there's a minus sign, convert into two's complement.
665ffe3c632Sopenharmony_ci  if (minus) {
666ffe3c632Sopenharmony_ci    neg();
667ffe3c632Sopenharmony_ci    muladd(1, 1);
668ffe3c632Sopenharmony_ci  }
669ffe3c632Sopenharmony_ci
670ffe3c632Sopenharmony_ci  return goog.crypt.byteArrayToString(resultBytes);
671ffe3c632Sopenharmony_ci};
672ffe3c632Sopenharmony_ci
673ffe3c632Sopenharmony_ci
674ffe3c632Sopenharmony_ci/**
675ffe3c632Sopenharmony_ci * Converts a signed or unsigned decimal string into two 32-bit halves, and
676ffe3c632Sopenharmony_ci * stores them in the temp variables listed above.
677ffe3c632Sopenharmony_ci * @param {string} value The decimal string to convert.
678ffe3c632Sopenharmony_ci */
679ffe3c632Sopenharmony_cijspb.utils.splitDecimalString = function(value) {
680ffe3c632Sopenharmony_ci  jspb.utils.splitHash64(jspb.utils.decimalStringToHash64(value));
681ffe3c632Sopenharmony_ci};
682ffe3c632Sopenharmony_ci
683ffe3c632Sopenharmony_ci/**
684ffe3c632Sopenharmony_ci * @param {number} nibble A 4-bit integer.
685ffe3c632Sopenharmony_ci * @return {string}
686ffe3c632Sopenharmony_ci * @private
687ffe3c632Sopenharmony_ci */
688ffe3c632Sopenharmony_cijspb.utils.toHexDigit_ = function(nibble) {
689ffe3c632Sopenharmony_ci  return String.fromCharCode(
690ffe3c632Sopenharmony_ci      nibble < 10 ? jspb.utils.ZERO_CHAR_CODE_ + nibble :
691ffe3c632Sopenharmony_ci                    jspb.utils.A_CHAR_CODE_ - 10 + nibble);
692ffe3c632Sopenharmony_ci};
693ffe3c632Sopenharmony_ci
694ffe3c632Sopenharmony_ci/**
695ffe3c632Sopenharmony_ci * @param {number} hexCharCode
696ffe3c632Sopenharmony_ci * @return {number}
697ffe3c632Sopenharmony_ci * @private
698ffe3c632Sopenharmony_ci */
699ffe3c632Sopenharmony_cijspb.utils.fromHexCharCode_ = function(hexCharCode) {
700ffe3c632Sopenharmony_ci  if (hexCharCode >= jspb.utils.A_CHAR_CODE_) {
701ffe3c632Sopenharmony_ci    return hexCharCode - jspb.utils.A_CHAR_CODE_ + 10;
702ffe3c632Sopenharmony_ci  }
703ffe3c632Sopenharmony_ci  return hexCharCode - jspb.utils.ZERO_CHAR_CODE_;
704ffe3c632Sopenharmony_ci};
705ffe3c632Sopenharmony_ci
706ffe3c632Sopenharmony_ci/**
707ffe3c632Sopenharmony_ci * Converts an 8-character hash string into its hexadecimal representation.
708ffe3c632Sopenharmony_ci * @param {string} hash
709ffe3c632Sopenharmony_ci * @return {string}
710ffe3c632Sopenharmony_ci */
711ffe3c632Sopenharmony_cijspb.utils.hash64ToHexString = function(hash) {
712ffe3c632Sopenharmony_ci  var temp = new Array(18);
713ffe3c632Sopenharmony_ci  temp[0] = '0';
714ffe3c632Sopenharmony_ci  temp[1] = 'x';
715ffe3c632Sopenharmony_ci
716ffe3c632Sopenharmony_ci  for (var i = 0; i < 8; i++) {
717ffe3c632Sopenharmony_ci    var c = hash.charCodeAt(7 - i);
718ffe3c632Sopenharmony_ci    temp[i * 2 + 2] = jspb.utils.toHexDigit_(c >> 4);
719ffe3c632Sopenharmony_ci    temp[i * 2 + 3] = jspb.utils.toHexDigit_(c & 0xF);
720ffe3c632Sopenharmony_ci  }
721ffe3c632Sopenharmony_ci
722ffe3c632Sopenharmony_ci  var result = temp.join('');
723ffe3c632Sopenharmony_ci  return result;
724ffe3c632Sopenharmony_ci};
725ffe3c632Sopenharmony_ci
726ffe3c632Sopenharmony_ci
727ffe3c632Sopenharmony_ci/**
728ffe3c632Sopenharmony_ci * Converts a '0x<16 digits>' hex string into its hash string representation.
729ffe3c632Sopenharmony_ci * @param {string} hex
730ffe3c632Sopenharmony_ci * @return {string}
731ffe3c632Sopenharmony_ci */
732ffe3c632Sopenharmony_cijspb.utils.hexStringToHash64 = function(hex) {
733ffe3c632Sopenharmony_ci  hex = hex.toLowerCase();
734ffe3c632Sopenharmony_ci  goog.asserts.assert(hex.length == 18);
735ffe3c632Sopenharmony_ci  goog.asserts.assert(hex[0] == '0');
736ffe3c632Sopenharmony_ci  goog.asserts.assert(hex[1] == 'x');
737ffe3c632Sopenharmony_ci
738ffe3c632Sopenharmony_ci  var result = '';
739ffe3c632Sopenharmony_ci  for (var i = 0; i < 8; i++) {
740ffe3c632Sopenharmony_ci    var hi = jspb.utils.fromHexCharCode_(hex.charCodeAt(i * 2 + 2));
741ffe3c632Sopenharmony_ci    var lo = jspb.utils.fromHexCharCode_(hex.charCodeAt(i * 2 + 3));
742ffe3c632Sopenharmony_ci    result = String.fromCharCode(hi * 16 + lo) + result;
743ffe3c632Sopenharmony_ci  }
744ffe3c632Sopenharmony_ci
745ffe3c632Sopenharmony_ci  return result;
746ffe3c632Sopenharmony_ci};
747ffe3c632Sopenharmony_ci
748ffe3c632Sopenharmony_ci
749ffe3c632Sopenharmony_ci/**
750ffe3c632Sopenharmony_ci * Convert an 8-character hash string representing either a signed or unsigned
751ffe3c632Sopenharmony_ci * 64-bit integer into a Javascript number. Will lose accuracy if the result is
752ffe3c632Sopenharmony_ci * larger than 2^52.
753ffe3c632Sopenharmony_ci * @param {string} hash The hash string to convert.
754ffe3c632Sopenharmony_ci * @param {boolean} signed True if the has should be interpreted as a signed
755ffe3c632Sopenharmony_ci *     number.
756ffe3c632Sopenharmony_ci * @return {number}
757ffe3c632Sopenharmony_ci */
758ffe3c632Sopenharmony_cijspb.utils.hash64ToNumber = function(hash, signed) {
759ffe3c632Sopenharmony_ci  jspb.utils.splitHash64(hash);
760ffe3c632Sopenharmony_ci  var bitsLow = jspb.utils.split64Low;
761ffe3c632Sopenharmony_ci  var bitsHigh = jspb.utils.split64High;
762ffe3c632Sopenharmony_ci  return signed ? jspb.utils.joinInt64(bitsLow, bitsHigh) :
763ffe3c632Sopenharmony_ci                  jspb.utils.joinUint64(bitsLow, bitsHigh);
764ffe3c632Sopenharmony_ci};
765ffe3c632Sopenharmony_ci
766ffe3c632Sopenharmony_ci
767ffe3c632Sopenharmony_ci/**
768ffe3c632Sopenharmony_ci * Convert a Javascript number into an 8-character hash string. Will lose
769ffe3c632Sopenharmony_ci * precision if the value is non-integral or greater than 2^64.
770ffe3c632Sopenharmony_ci * @param {number} value The integer to convert.
771ffe3c632Sopenharmony_ci * @return {string}
772ffe3c632Sopenharmony_ci */
773ffe3c632Sopenharmony_cijspb.utils.numberToHash64 = function(value) {
774ffe3c632Sopenharmony_ci  jspb.utils.splitInt64(value);
775ffe3c632Sopenharmony_ci  return jspb.utils.joinHash64(jspb.utils.split64Low,
776ffe3c632Sopenharmony_ci                                  jspb.utils.split64High);
777ffe3c632Sopenharmony_ci};
778ffe3c632Sopenharmony_ci
779ffe3c632Sopenharmony_ci
780ffe3c632Sopenharmony_ci/**
781ffe3c632Sopenharmony_ci * Counts the number of contiguous varints in a buffer.
782ffe3c632Sopenharmony_ci * @param {!Uint8Array} buffer The buffer to scan.
783ffe3c632Sopenharmony_ci * @param {number} start The starting point in the buffer to scan.
784ffe3c632Sopenharmony_ci * @param {number} end The end point in the buffer to scan.
785ffe3c632Sopenharmony_ci * @return {number} The number of varints in the buffer.
786ffe3c632Sopenharmony_ci */
787ffe3c632Sopenharmony_cijspb.utils.countVarints = function(buffer, start, end) {
788ffe3c632Sopenharmony_ci  // Count how many high bits of each byte were set in the buffer.
789ffe3c632Sopenharmony_ci  var count = 0;
790ffe3c632Sopenharmony_ci  for (var i = start; i < end; i++) {
791ffe3c632Sopenharmony_ci    count += buffer[i] >> 7;
792ffe3c632Sopenharmony_ci  }
793ffe3c632Sopenharmony_ci
794ffe3c632Sopenharmony_ci  // The number of varints in the buffer equals the size of the buffer minus
795ffe3c632Sopenharmony_ci  // the number of non-terminal bytes in the buffer (those with the high bit
796ffe3c632Sopenharmony_ci  // set).
797ffe3c632Sopenharmony_ci  return (end - start) - count;
798ffe3c632Sopenharmony_ci};
799ffe3c632Sopenharmony_ci
800ffe3c632Sopenharmony_ci
801ffe3c632Sopenharmony_ci/**
802ffe3c632Sopenharmony_ci * Counts the number of contiguous varint fields with the given field number in
803ffe3c632Sopenharmony_ci * the buffer.
804ffe3c632Sopenharmony_ci * @param {!Uint8Array} buffer The buffer to scan.
805ffe3c632Sopenharmony_ci * @param {number} start The starting point in the buffer to scan.
806ffe3c632Sopenharmony_ci * @param {number} end The end point in the buffer to scan.
807ffe3c632Sopenharmony_ci * @param {number} field The field number to count.
808ffe3c632Sopenharmony_ci * @return {number} The number of matching fields in the buffer.
809ffe3c632Sopenharmony_ci */
810ffe3c632Sopenharmony_cijspb.utils.countVarintFields = function(buffer, start, end, field) {
811ffe3c632Sopenharmony_ci  var count = 0;
812ffe3c632Sopenharmony_ci  var cursor = start;
813ffe3c632Sopenharmony_ci  var tag = field * 8 + jspb.BinaryConstants.WireType.VARINT;
814ffe3c632Sopenharmony_ci
815ffe3c632Sopenharmony_ci  if (tag < 128) {
816ffe3c632Sopenharmony_ci    // Single-byte field tag, we can use a slightly quicker count.
817ffe3c632Sopenharmony_ci    while (cursor < end) {
818ffe3c632Sopenharmony_ci      // Skip the field tag, or exit if we find a non-matching tag.
819ffe3c632Sopenharmony_ci      if (buffer[cursor++] != tag) return count;
820ffe3c632Sopenharmony_ci
821ffe3c632Sopenharmony_ci      // Field tag matches, we've found a valid field.
822ffe3c632Sopenharmony_ci      count++;
823ffe3c632Sopenharmony_ci
824ffe3c632Sopenharmony_ci      // Skip the varint.
825ffe3c632Sopenharmony_ci      while (1) {
826ffe3c632Sopenharmony_ci        var x = buffer[cursor++];
827ffe3c632Sopenharmony_ci        if ((x & 0x80) == 0) break;
828ffe3c632Sopenharmony_ci      }
829ffe3c632Sopenharmony_ci    }
830ffe3c632Sopenharmony_ci  } else {
831ffe3c632Sopenharmony_ci    while (cursor < end) {
832ffe3c632Sopenharmony_ci      // Skip the field tag, or exit if we find a non-matching tag.
833ffe3c632Sopenharmony_ci      var temp = tag;
834ffe3c632Sopenharmony_ci      while (temp > 128) {
835ffe3c632Sopenharmony_ci        if (buffer[cursor] != ((temp & 0x7F) | 0x80)) return count;
836ffe3c632Sopenharmony_ci        cursor++;
837ffe3c632Sopenharmony_ci        temp >>= 7;
838ffe3c632Sopenharmony_ci      }
839ffe3c632Sopenharmony_ci      if (buffer[cursor++] != temp) return count;
840ffe3c632Sopenharmony_ci
841ffe3c632Sopenharmony_ci      // Field tag matches, we've found a valid field.
842ffe3c632Sopenharmony_ci      count++;
843ffe3c632Sopenharmony_ci
844ffe3c632Sopenharmony_ci      // Skip the varint.
845ffe3c632Sopenharmony_ci      while (1) {
846ffe3c632Sopenharmony_ci        var x = buffer[cursor++];
847ffe3c632Sopenharmony_ci        if ((x & 0x80) == 0) break;
848ffe3c632Sopenharmony_ci      }
849ffe3c632Sopenharmony_ci    }
850ffe3c632Sopenharmony_ci  }
851ffe3c632Sopenharmony_ci  return count;
852ffe3c632Sopenharmony_ci};
853ffe3c632Sopenharmony_ci
854ffe3c632Sopenharmony_ci
855ffe3c632Sopenharmony_ci/**
856ffe3c632Sopenharmony_ci * Counts the number of contiguous fixed32 fields with the given tag in the
857ffe3c632Sopenharmony_ci * buffer.
858ffe3c632Sopenharmony_ci * @param {!Uint8Array} buffer The buffer to scan.
859ffe3c632Sopenharmony_ci * @param {number} start The starting point in the buffer to scan.
860ffe3c632Sopenharmony_ci * @param {number} end The end point in the buffer to scan.
861ffe3c632Sopenharmony_ci * @param {number} tag The tag value to count.
862ffe3c632Sopenharmony_ci * @param {number} stride The number of bytes to skip per field.
863ffe3c632Sopenharmony_ci * @return {number} The number of fields with a matching tag in the buffer.
864ffe3c632Sopenharmony_ci * @private
865ffe3c632Sopenharmony_ci */
866ffe3c632Sopenharmony_cijspb.utils.countFixedFields_ =
867ffe3c632Sopenharmony_ci    function(buffer, start, end, tag, stride) {
868ffe3c632Sopenharmony_ci  var count = 0;
869ffe3c632Sopenharmony_ci  var cursor = start;
870ffe3c632Sopenharmony_ci
871ffe3c632Sopenharmony_ci  if (tag < 128) {
872ffe3c632Sopenharmony_ci    // Single-byte field tag, we can use a slightly quicker count.
873ffe3c632Sopenharmony_ci    while (cursor < end) {
874ffe3c632Sopenharmony_ci      // Skip the field tag, or exit if we find a non-matching tag.
875ffe3c632Sopenharmony_ci      if (buffer[cursor++] != tag) return count;
876ffe3c632Sopenharmony_ci
877ffe3c632Sopenharmony_ci      // Field tag matches, we've found a valid field.
878ffe3c632Sopenharmony_ci      count++;
879ffe3c632Sopenharmony_ci
880ffe3c632Sopenharmony_ci      // Skip the value.
881ffe3c632Sopenharmony_ci      cursor += stride;
882ffe3c632Sopenharmony_ci    }
883ffe3c632Sopenharmony_ci  } else {
884ffe3c632Sopenharmony_ci    while (cursor < end) {
885ffe3c632Sopenharmony_ci      // Skip the field tag, or exit if we find a non-matching tag.
886ffe3c632Sopenharmony_ci      var temp = tag;
887ffe3c632Sopenharmony_ci      while (temp > 128) {
888ffe3c632Sopenharmony_ci        if (buffer[cursor++] != ((temp & 0x7F) | 0x80)) return count;
889ffe3c632Sopenharmony_ci        temp >>= 7;
890ffe3c632Sopenharmony_ci      }
891ffe3c632Sopenharmony_ci      if (buffer[cursor++] != temp) return count;
892ffe3c632Sopenharmony_ci
893ffe3c632Sopenharmony_ci      // Field tag matches, we've found a valid field.
894ffe3c632Sopenharmony_ci      count++;
895ffe3c632Sopenharmony_ci
896ffe3c632Sopenharmony_ci      // Skip the value.
897ffe3c632Sopenharmony_ci      cursor += stride;
898ffe3c632Sopenharmony_ci    }
899ffe3c632Sopenharmony_ci  }
900ffe3c632Sopenharmony_ci  return count;
901ffe3c632Sopenharmony_ci};
902ffe3c632Sopenharmony_ci
903ffe3c632Sopenharmony_ci
904ffe3c632Sopenharmony_ci/**
905ffe3c632Sopenharmony_ci * Counts the number of contiguous fixed32 fields with the given field number
906ffe3c632Sopenharmony_ci * in the buffer.
907ffe3c632Sopenharmony_ci * @param {!Uint8Array} buffer The buffer to scan.
908ffe3c632Sopenharmony_ci * @param {number} start The starting point in the buffer to scan.
909ffe3c632Sopenharmony_ci * @param {number} end The end point in the buffer to scan.
910ffe3c632Sopenharmony_ci * @param {number} field The field number to count.
911ffe3c632Sopenharmony_ci * @return {number} The number of matching fields in the buffer.
912ffe3c632Sopenharmony_ci */
913ffe3c632Sopenharmony_cijspb.utils.countFixed32Fields = function(buffer, start, end, field) {
914ffe3c632Sopenharmony_ci  var tag = field * 8 + jspb.BinaryConstants.WireType.FIXED32;
915ffe3c632Sopenharmony_ci  return jspb.utils.countFixedFields_(buffer, start, end, tag, 4);
916ffe3c632Sopenharmony_ci};
917ffe3c632Sopenharmony_ci
918ffe3c632Sopenharmony_ci
919ffe3c632Sopenharmony_ci/**
920ffe3c632Sopenharmony_ci * Counts the number of contiguous fixed64 fields with the given field number
921ffe3c632Sopenharmony_ci * in the buffer.
922ffe3c632Sopenharmony_ci * @param {!Uint8Array} buffer The buffer to scan.
923ffe3c632Sopenharmony_ci * @param {number} start The starting point in the buffer to scan.
924ffe3c632Sopenharmony_ci * @param {number} end The end point in the buffer to scan.
925ffe3c632Sopenharmony_ci * @param {number} field The field number to count
926ffe3c632Sopenharmony_ci * @return {number} The number of matching fields in the buffer.
927ffe3c632Sopenharmony_ci */
928ffe3c632Sopenharmony_cijspb.utils.countFixed64Fields = function(buffer, start, end, field) {
929ffe3c632Sopenharmony_ci  var tag = field * 8 + jspb.BinaryConstants.WireType.FIXED64;
930ffe3c632Sopenharmony_ci  return jspb.utils.countFixedFields_(buffer, start, end, tag, 8);
931ffe3c632Sopenharmony_ci};
932ffe3c632Sopenharmony_ci
933ffe3c632Sopenharmony_ci
934ffe3c632Sopenharmony_ci/**
935ffe3c632Sopenharmony_ci * Counts the number of contiguous delimited fields with the given field number
936ffe3c632Sopenharmony_ci * in the buffer.
937ffe3c632Sopenharmony_ci * @param {!Uint8Array} buffer The buffer to scan.
938ffe3c632Sopenharmony_ci * @param {number} start The starting point in the buffer to scan.
939ffe3c632Sopenharmony_ci * @param {number} end The end point in the buffer to scan.
940ffe3c632Sopenharmony_ci * @param {number} field The field number to count.
941ffe3c632Sopenharmony_ci * @return {number} The number of matching fields in the buffer.
942ffe3c632Sopenharmony_ci */
943ffe3c632Sopenharmony_cijspb.utils.countDelimitedFields = function(buffer, start, end, field) {
944ffe3c632Sopenharmony_ci  var count = 0;
945ffe3c632Sopenharmony_ci  var cursor = start;
946ffe3c632Sopenharmony_ci  var tag = field * 8 + jspb.BinaryConstants.WireType.DELIMITED;
947ffe3c632Sopenharmony_ci
948ffe3c632Sopenharmony_ci  while (cursor < end) {
949ffe3c632Sopenharmony_ci    // Skip the field tag, or exit if we find a non-matching tag.
950ffe3c632Sopenharmony_ci    var temp = tag;
951ffe3c632Sopenharmony_ci    while (temp > 128) {
952ffe3c632Sopenharmony_ci      if (buffer[cursor++] != ((temp & 0x7F) | 0x80)) return count;
953ffe3c632Sopenharmony_ci      temp >>= 7;
954ffe3c632Sopenharmony_ci    }
955ffe3c632Sopenharmony_ci    if (buffer[cursor++] != temp) return count;
956ffe3c632Sopenharmony_ci
957ffe3c632Sopenharmony_ci    // Field tag matches, we've found a valid field.
958ffe3c632Sopenharmony_ci    count++;
959ffe3c632Sopenharmony_ci
960ffe3c632Sopenharmony_ci    // Decode the length prefix.
961ffe3c632Sopenharmony_ci    var length = 0;
962ffe3c632Sopenharmony_ci    var shift = 1;
963ffe3c632Sopenharmony_ci    while (1) {
964ffe3c632Sopenharmony_ci      temp = buffer[cursor++];
965ffe3c632Sopenharmony_ci      length += (temp & 0x7f) * shift;
966ffe3c632Sopenharmony_ci      shift *= 128;
967ffe3c632Sopenharmony_ci      if ((temp & 0x80) == 0) break;
968ffe3c632Sopenharmony_ci    }
969ffe3c632Sopenharmony_ci
970ffe3c632Sopenharmony_ci    // Advance the cursor past the blob.
971ffe3c632Sopenharmony_ci    cursor += length;
972ffe3c632Sopenharmony_ci  }
973ffe3c632Sopenharmony_ci  return count;
974ffe3c632Sopenharmony_ci};
975ffe3c632Sopenharmony_ci
976ffe3c632Sopenharmony_ci
977ffe3c632Sopenharmony_ci/**
978ffe3c632Sopenharmony_ci * String-ify bytes for text format. Should be optimized away in non-debug.
979ffe3c632Sopenharmony_ci * The returned string uses \xXX escapes for all values and is itself quoted.
980ffe3c632Sopenharmony_ci * [1, 31] serializes to '"\x01\x1f"'.
981ffe3c632Sopenharmony_ci * @param {jspb.ByteSource} byteSource The bytes to serialize.
982ffe3c632Sopenharmony_ci * @return {string} Stringified bytes for text format.
983ffe3c632Sopenharmony_ci */
984ffe3c632Sopenharmony_cijspb.utils.debugBytesToTextFormat = function(byteSource) {
985ffe3c632Sopenharmony_ci  var s = '"';
986ffe3c632Sopenharmony_ci  if (byteSource) {
987ffe3c632Sopenharmony_ci    var bytes = jspb.utils.byteSourceToUint8Array(byteSource);
988ffe3c632Sopenharmony_ci    for (var i = 0; i < bytes.length; i++) {
989ffe3c632Sopenharmony_ci      s += '\\x';
990ffe3c632Sopenharmony_ci      if (bytes[i] < 16) s += '0';
991ffe3c632Sopenharmony_ci      s += bytes[i].toString(16);
992ffe3c632Sopenharmony_ci    }
993ffe3c632Sopenharmony_ci  }
994ffe3c632Sopenharmony_ci  return s + '"';
995ffe3c632Sopenharmony_ci};
996ffe3c632Sopenharmony_ci
997ffe3c632Sopenharmony_ci
998ffe3c632Sopenharmony_ci/**
999ffe3c632Sopenharmony_ci * String-ify a scalar for text format. Should be optimized away in non-debug.
1000ffe3c632Sopenharmony_ci * @param {string|number|boolean} scalar The scalar to stringify.
1001ffe3c632Sopenharmony_ci * @return {string} Stringified scalar for text format.
1002ffe3c632Sopenharmony_ci */
1003ffe3c632Sopenharmony_cijspb.utils.debugScalarToTextFormat = function(scalar) {
1004ffe3c632Sopenharmony_ci  if (typeof scalar === 'string') {
1005ffe3c632Sopenharmony_ci    return goog.string.quote(scalar);
1006ffe3c632Sopenharmony_ci  } else {
1007ffe3c632Sopenharmony_ci    return scalar.toString();
1008ffe3c632Sopenharmony_ci  }
1009ffe3c632Sopenharmony_ci};
1010ffe3c632Sopenharmony_ci
1011ffe3c632Sopenharmony_ci
1012ffe3c632Sopenharmony_ci/**
1013ffe3c632Sopenharmony_ci * Utility function: convert a string with codepoints 0--255 inclusive to a
1014ffe3c632Sopenharmony_ci * Uint8Array. If any codepoints greater than 255 exist in the string, throws an
1015ffe3c632Sopenharmony_ci * exception.
1016ffe3c632Sopenharmony_ci * @param {string} str
1017ffe3c632Sopenharmony_ci * @return {!Uint8Array}
1018ffe3c632Sopenharmony_ci */
1019ffe3c632Sopenharmony_cijspb.utils.stringToByteArray = function(str) {
1020ffe3c632Sopenharmony_ci  var arr = new Uint8Array(str.length);
1021ffe3c632Sopenharmony_ci  for (var i = 0; i < str.length; i++) {
1022ffe3c632Sopenharmony_ci    var codepoint = str.charCodeAt(i);
1023ffe3c632Sopenharmony_ci    if (codepoint > 255) {
1024ffe3c632Sopenharmony_ci      throw new Error('Conversion error: string contains codepoint ' +
1025ffe3c632Sopenharmony_ci                      'outside of byte range');
1026ffe3c632Sopenharmony_ci    }
1027ffe3c632Sopenharmony_ci    arr[i] = codepoint;
1028ffe3c632Sopenharmony_ci  }
1029ffe3c632Sopenharmony_ci  return arr;
1030ffe3c632Sopenharmony_ci};
1031ffe3c632Sopenharmony_ci
1032ffe3c632Sopenharmony_ci
1033ffe3c632Sopenharmony_ci/**
1034ffe3c632Sopenharmony_ci * Converts any type defined in jspb.ByteSource into a Uint8Array.
1035ffe3c632Sopenharmony_ci * @param {!jspb.ByteSource} data
1036ffe3c632Sopenharmony_ci * @return {!Uint8Array}
1037ffe3c632Sopenharmony_ci * @suppress {invalidCasts}
1038ffe3c632Sopenharmony_ci */
1039ffe3c632Sopenharmony_cijspb.utils.byteSourceToUint8Array = function(data) {
1040ffe3c632Sopenharmony_ci  if (data.constructor === Uint8Array) {
1041ffe3c632Sopenharmony_ci    return /** @type {!Uint8Array} */(data);
1042ffe3c632Sopenharmony_ci  }
1043ffe3c632Sopenharmony_ci
1044ffe3c632Sopenharmony_ci  if (data.constructor === ArrayBuffer) {
1045ffe3c632Sopenharmony_ci    data = /** @type {!ArrayBuffer} */(data);
1046ffe3c632Sopenharmony_ci    return /** @type {!Uint8Array} */(new Uint8Array(data));
1047ffe3c632Sopenharmony_ci  }
1048ffe3c632Sopenharmony_ci
1049ffe3c632Sopenharmony_ci  if (typeof Buffer != 'undefined' && data.constructor === Buffer) {
1050ffe3c632Sopenharmony_ci    return /** @type {!Uint8Array} */ (
1051ffe3c632Sopenharmony_ci        new Uint8Array(/** @type {?} */ (data)));
1052ffe3c632Sopenharmony_ci  }
1053ffe3c632Sopenharmony_ci
1054ffe3c632Sopenharmony_ci  if (data.constructor === Array) {
1055ffe3c632Sopenharmony_ci    data = /** @type {!Array<number>} */(data);
1056ffe3c632Sopenharmony_ci    return /** @type {!Uint8Array} */(new Uint8Array(data));
1057ffe3c632Sopenharmony_ci  }
1058ffe3c632Sopenharmony_ci
1059ffe3c632Sopenharmony_ci  if (data.constructor === String) {
1060ffe3c632Sopenharmony_ci    data = /** @type {string} */(data);
1061ffe3c632Sopenharmony_ci    return goog.crypt.base64.decodeStringToUint8Array(data);
1062ffe3c632Sopenharmony_ci  }
1063ffe3c632Sopenharmony_ci
1064ffe3c632Sopenharmony_ci  goog.asserts.fail('Type not convertible to Uint8Array.');
1065ffe3c632Sopenharmony_ci  return /** @type {!Uint8Array} */(new Uint8Array(0));
1066ffe3c632Sopenharmony_ci};
1067