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