You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
315 lines
11 KiB
315 lines
11 KiB
// Copyright 2008 Google Inc. All rights reserved.
|
|
//
|
|
// Redistribution and use in source and binary forms, with or without
|
|
// modification, are permitted provided that the following conditions are
|
|
// met:
|
|
//
|
|
// * Redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
// * Redistributions in binary form must reproduce the above
|
|
// copyright notice, this list of conditions and the following disclaimer
|
|
// in the documentation and/or other materials provided with the
|
|
// distribution.
|
|
// * Neither the name of Google Inc. nor the names of its
|
|
// contributors may be used to endorse or promote products derived from
|
|
// this software without specific prior written permission.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
|
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
|
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
|
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
//
|
|
// Code generated by the Protocol Buffer compiler is owned by the owner
|
|
// of the input file used when generating it. This code is not
|
|
// standalone and requires a support library to be linked with it. This
|
|
// support library is itself covered by the above license.
|
|
/* eslint-disable prefer-const,@typescript-eslint/restrict-plus-operands */
|
|
/**
|
|
* Read a 64 bit varint as two JS numbers.
|
|
*
|
|
* Returns tuple:
|
|
* [0]: low bits
|
|
* [1]: high bits
|
|
*
|
|
* Copyright 2008 Google Inc. All rights reserved.
|
|
*
|
|
* See https://github.com/protocolbuffers/protobuf/blob/8a71927d74a4ce34efe2d8769fda198f52d20d12/js/experimental/runtime/kernel/buffer_decoder.js#L175
|
|
*/
|
|
export function varint64read() {
|
|
let lowBits = 0;
|
|
let highBits = 0;
|
|
for (let shift = 0; shift < 28; shift += 7) {
|
|
let b = this.buf[this.pos++];
|
|
lowBits |= (b & 0x7f) << shift;
|
|
if ((b & 0x80) == 0) {
|
|
this.assertBounds();
|
|
return [lowBits, highBits];
|
|
}
|
|
}
|
|
let middleByte = this.buf[this.pos++];
|
|
// last four bits of the first 32 bit number
|
|
lowBits |= (middleByte & 0x0f) << 28;
|
|
// 3 upper bits are part of the next 32 bit number
|
|
highBits = (middleByte & 0x70) >> 4;
|
|
if ((middleByte & 0x80) == 0) {
|
|
this.assertBounds();
|
|
return [lowBits, highBits];
|
|
}
|
|
for (let shift = 3; shift <= 31; shift += 7) {
|
|
let b = this.buf[this.pos++];
|
|
highBits |= (b & 0x7f) << shift;
|
|
if ((b & 0x80) == 0) {
|
|
this.assertBounds();
|
|
return [lowBits, highBits];
|
|
}
|
|
}
|
|
throw new Error("invalid varint");
|
|
}
|
|
/**
|
|
* Write a 64 bit varint, given as two JS numbers, to the given bytes array.
|
|
*
|
|
* Copyright 2008 Google Inc. All rights reserved.
|
|
*
|
|
* See https://github.com/protocolbuffers/protobuf/blob/8a71927d74a4ce34efe2d8769fda198f52d20d12/js/experimental/runtime/kernel/writer.js#L344
|
|
*/
|
|
export function varint64write(lo, hi, bytes) {
|
|
for (let i = 0; i < 28; i = i + 7) {
|
|
const shift = lo >>> i;
|
|
const hasNext = !(shift >>> 7 == 0 && hi == 0);
|
|
const byte = (hasNext ? shift | 0x80 : shift) & 0xff;
|
|
bytes.push(byte);
|
|
if (!hasNext) {
|
|
return;
|
|
}
|
|
}
|
|
const splitBits = ((lo >>> 28) & 0x0f) | ((hi & 0x07) << 4);
|
|
const hasMoreBits = !(hi >> 3 == 0);
|
|
bytes.push((hasMoreBits ? splitBits | 0x80 : splitBits) & 0xff);
|
|
if (!hasMoreBits) {
|
|
return;
|
|
}
|
|
for (let i = 3; i < 31; i = i + 7) {
|
|
const shift = hi >>> i;
|
|
const hasNext = !(shift >>> 7 == 0);
|
|
const byte = (hasNext ? shift | 0x80 : shift) & 0xff;
|
|
bytes.push(byte);
|
|
if (!hasNext) {
|
|
return;
|
|
}
|
|
}
|
|
bytes.push((hi >>> 31) & 0x01);
|
|
}
|
|
// constants for binary math
|
|
const TWO_PWR_32_DBL = 0x100000000;
|
|
/**
|
|
* Parse decimal string of 64 bit integer value as two JS numbers.
|
|
*
|
|
* Copyright 2008 Google Inc. All rights reserved.
|
|
*
|
|
* See https://github.com/protocolbuffers/protobuf-javascript/blob/a428c58273abad07c66071d9753bc4d1289de426/experimental/runtime/int64.js#L10
|
|
*/
|
|
export function int64FromString(dec) {
|
|
// Check for minus sign.
|
|
const minus = dec[0] === "-";
|
|
if (minus) {
|
|
dec = dec.slice(1);
|
|
}
|
|
// Work 6 decimal digits at a time, acting like we're converting base 1e6
|
|
// digits to binary. This is safe to do with floating point math because
|
|
// Number.isSafeInteger(ALL_32_BITS * 1e6) == true.
|
|
const base = 1e6;
|
|
let lowBits = 0;
|
|
let highBits = 0;
|
|
function add1e6digit(begin, end) {
|
|
// Note: Number('') is 0.
|
|
const digit1e6 = Number(dec.slice(begin, end));
|
|
highBits *= base;
|
|
lowBits = lowBits * base + digit1e6;
|
|
// Carry bits from lowBits to
|
|
if (lowBits >= TWO_PWR_32_DBL) {
|
|
highBits = highBits + ((lowBits / TWO_PWR_32_DBL) | 0);
|
|
lowBits = lowBits % TWO_PWR_32_DBL;
|
|
}
|
|
}
|
|
add1e6digit(-24, -18);
|
|
add1e6digit(-18, -12);
|
|
add1e6digit(-12, -6);
|
|
add1e6digit(-6);
|
|
return minus ? negate(lowBits, highBits) : newBits(lowBits, highBits);
|
|
}
|
|
/**
|
|
* Losslessly converts a 64-bit signed integer in 32:32 split representation
|
|
* into a decimal string.
|
|
*
|
|
* Copyright 2008 Google Inc. All rights reserved.
|
|
*
|
|
* See https://github.com/protocolbuffers/protobuf-javascript/blob/a428c58273abad07c66071d9753bc4d1289de426/experimental/runtime/int64.js#L10
|
|
*/
|
|
export function int64ToString(lo, hi) {
|
|
let bits = newBits(lo, hi);
|
|
// If we're treating the input as a signed value and the high bit is set, do
|
|
// a manual two's complement conversion before the decimal conversion.
|
|
const negative = bits.hi & 0x80000000;
|
|
if (negative) {
|
|
bits = negate(bits.lo, bits.hi);
|
|
}
|
|
const result = uInt64ToString(bits.lo, bits.hi);
|
|
return negative ? "-" + result : result;
|
|
}
|
|
/**
|
|
* Losslessly converts a 64-bit unsigned integer in 32:32 split representation
|
|
* into a decimal string.
|
|
*
|
|
* Copyright 2008 Google Inc. All rights reserved.
|
|
*
|
|
* See https://github.com/protocolbuffers/protobuf-javascript/blob/a428c58273abad07c66071d9753bc4d1289de426/experimental/runtime/int64.js#L10
|
|
*/
|
|
export function uInt64ToString(lo, hi) {
|
|
({ lo, hi } = toUnsigned(lo, hi));
|
|
// Skip the expensive conversion if the number is small enough to use the
|
|
// built-in conversions.
|
|
// Number.MAX_SAFE_INTEGER = 0x001FFFFF FFFFFFFF, thus any number with
|
|
// highBits <= 0x1FFFFF can be safely expressed with a double and retain
|
|
// integer precision.
|
|
// Proven by: Number.isSafeInteger(0x1FFFFF * 2**32 + 0xFFFFFFFF) == true.
|
|
if (hi <= 0x1fffff) {
|
|
return String(TWO_PWR_32_DBL * hi + lo);
|
|
}
|
|
// What this code is doing is essentially converting the input number from
|
|
// base-2 to base-1e7, which allows us to represent the 64-bit range with
|
|
// only 3 (very large) digits. Those digits are then trivial to convert to
|
|
// a base-10 string.
|
|
// The magic numbers used here are -
|
|
// 2^24 = 16777216 = (1,6777216) in base-1e7.
|
|
// 2^48 = 281474976710656 = (2,8147497,6710656) in base-1e7.
|
|
// Split 32:32 representation into 16:24:24 representation so our
|
|
// intermediate digits don't overflow.
|
|
const low = lo & 0xffffff;
|
|
const mid = ((lo >>> 24) | (hi << 8)) & 0xffffff;
|
|
const high = (hi >> 16) & 0xffff;
|
|
// Assemble our three base-1e7 digits, ignoring carries. The maximum
|
|
// value in a digit at this step is representable as a 48-bit integer, which
|
|
// can be stored in a 64-bit floating point number.
|
|
let digitA = low + mid * 6777216 + high * 6710656;
|
|
let digitB = mid + high * 8147497;
|
|
let digitC = high * 2;
|
|
// Apply carries from A to B and from B to C.
|
|
const base = 10000000;
|
|
if (digitA >= base) {
|
|
digitB += Math.floor(digitA / base);
|
|
digitA %= base;
|
|
}
|
|
if (digitB >= base) {
|
|
digitC += Math.floor(digitB / base);
|
|
digitB %= base;
|
|
}
|
|
// If digitC is 0, then we should have returned in the trivial code path
|
|
// at the top for non-safe integers. Given this, we can assume both digitB
|
|
// and digitA need leading zeros.
|
|
return (digitC.toString() +
|
|
decimalFrom1e7WithLeadingZeros(digitB) +
|
|
decimalFrom1e7WithLeadingZeros(digitA));
|
|
}
|
|
function toUnsigned(lo, hi) {
|
|
return { lo: lo >>> 0, hi: hi >>> 0 };
|
|
}
|
|
function newBits(lo, hi) {
|
|
return { lo: lo | 0, hi: hi | 0 };
|
|
}
|
|
/**
|
|
* Returns two's compliment negation of input.
|
|
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators#Signed_32-bit_integers
|
|
*/
|
|
function negate(lowBits, highBits) {
|
|
highBits = ~highBits;
|
|
if (lowBits) {
|
|
lowBits = ~lowBits + 1;
|
|
}
|
|
else {
|
|
// If lowBits is 0, then bitwise-not is 0xFFFFFFFF,
|
|
// adding 1 to that, results in 0x100000000, which leaves
|
|
// the low bits 0x0 and simply adds one to the high bits.
|
|
highBits += 1;
|
|
}
|
|
return newBits(lowBits, highBits);
|
|
}
|
|
/**
|
|
* Returns decimal representation of digit1e7 with leading zeros.
|
|
*/
|
|
const decimalFrom1e7WithLeadingZeros = (digit1e7) => {
|
|
const partial = String(digit1e7);
|
|
return "0000000".slice(partial.length) + partial;
|
|
};
|
|
/**
|
|
* Write a 32 bit varint, signed or unsigned. Same as `varint64write(0, value, bytes)`
|
|
*
|
|
* Copyright 2008 Google Inc. All rights reserved.
|
|
*
|
|
* See https://github.com/protocolbuffers/protobuf/blob/1b18833f4f2a2f681f4e4a25cdf3b0a43115ec26/js/binary/encoder.js#L144
|
|
*/
|
|
export function varint32write(value, bytes) {
|
|
if (value >= 0) {
|
|
// write value as varint 32
|
|
while (value > 0x7f) {
|
|
bytes.push((value & 0x7f) | 0x80);
|
|
value = value >>> 7;
|
|
}
|
|
bytes.push(value);
|
|
}
|
|
else {
|
|
for (let i = 0; i < 9; i++) {
|
|
bytes.push((value & 127) | 128);
|
|
value = value >> 7;
|
|
}
|
|
bytes.push(1);
|
|
}
|
|
}
|
|
/**
|
|
* Read an unsigned 32 bit varint.
|
|
*
|
|
* See https://github.com/protocolbuffers/protobuf/blob/8a71927d74a4ce34efe2d8769fda198f52d20d12/js/experimental/runtime/kernel/buffer_decoder.js#L220
|
|
*/
|
|
export function varint32read() {
|
|
let b = this.buf[this.pos++];
|
|
let result = b & 0x7f;
|
|
if ((b & 0x80) == 0) {
|
|
this.assertBounds();
|
|
return result;
|
|
}
|
|
b = this.buf[this.pos++];
|
|
result |= (b & 0x7f) << 7;
|
|
if ((b & 0x80) == 0) {
|
|
this.assertBounds();
|
|
return result;
|
|
}
|
|
b = this.buf[this.pos++];
|
|
result |= (b & 0x7f) << 14;
|
|
if ((b & 0x80) == 0) {
|
|
this.assertBounds();
|
|
return result;
|
|
}
|
|
b = this.buf[this.pos++];
|
|
result |= (b & 0x7f) << 21;
|
|
if ((b & 0x80) == 0) {
|
|
this.assertBounds();
|
|
return result;
|
|
}
|
|
// Extract only last 4 bits
|
|
b = this.buf[this.pos++];
|
|
result |= (b & 0x0f) << 28;
|
|
for (let readBytes = 5; (b & 0x80) !== 0 && readBytes < 10; readBytes++)
|
|
b = this.buf[this.pos++];
|
|
if ((b & 0x80) != 0)
|
|
throw new Error("invalid varint");
|
|
this.assertBounds();
|
|
// Result can have 32 bits, convert it to unsigned
|
|
return result >>> 0;
|
|
}
|