| Index: lib/protobuf/runtime/PbCodec.dart
|
| diff --git a/lib/protobuf/runtime/PbCodec.dart b/lib/protobuf/runtime/PbCodec.dart
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..0114b592af5fbb162694319db8e3ea2fa1661417
|
| --- /dev/null
|
| +++ b/lib/protobuf/runtime/PbCodec.dart
|
| @@ -0,0 +1,1148 @@
|
| +// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
|
| +// for details. All rights reserved. Use of this source code is governed by a
|
| +// BSD-style license that can be found in the LICENSE file.
|
| +
|
| +class _Constants {
|
| + static final int MIN_SINT32 = -2147483648;
|
| + static final int MAX_SINT32 = 2147483647;
|
| + static final int MAX_UINT32 = 4294967295;
|
| + static final int MIN_SINT64 = -9223372036854775808;
|
| + static final int MAX_SINT64 = 9223372036854775807;
|
| + static final int MAX_UINT64 = 18446744073709551615;
|
| + static final double MIN_FLOAT_DENORM = 1.401298464324817E-45;
|
| + static final double MAX_FLOAT = 3.4028234663852886E38;
|
| +
|
| + static final int POWER_64_INT = 18446744073709551616;
|
| + static final int POWER_63_INT = 9223372036854775808;
|
| + static final int POWER_32_INT = 4294967296;
|
| + static final int POWER_31_INT = 2147483648;
|
| + static final int POWER_25_INT = 33554432;
|
| + // use literal to avoid browser issues
|
| + static final int MAX_BITS_32 = 0xffffffff;
|
| + static final int MAX_BITS_64 = (1 << 64) - 1;
|
| + static final int MAX_BITS_8 = (1 << 8) - 1;
|
| + static final int MAX_BITS_7 = (1 << 7) - 1;
|
| + static final int MIN_BITS_8 = (1 << 7);
|
| + static final int OCTET_BIT_COUNT = 8;
|
| + static final int SEPTET_BIT_COUNT = 7;
|
| + static final int BYTES_IN_32_BITS = 4;
|
| + static final int BYTES_IN_64_BITS = 8;
|
| + static final List<int> trueBytes = const [0x01];
|
| + static final List<int> falseBytes = const [0x00];
|
| +
|
| + // 2^512, 2^-512
|
| + static final double POWER_512 = 1.3407807929942597E154;
|
| + static final double POWER_MINUS_512 = 7.458340731200207E-155;
|
| + // 2^256, 2^-256
|
| + static final double POWER_256 = 1.157920892373162E77;
|
| + static final double POWER_MINUS_256 = 8.636168555094445E-78;
|
| + // 2^128, 2^-128
|
| + static final double POWER_128 = 3.4028236692093846E38;
|
| + static final double POWER_MINUS_128 = 2.9387358770557188E-39;
|
| + // 2^64, 2^-64
|
| + static final double POWER_64 = 18446744073709551616.0;
|
| + static final double POWER_MINUS_64 = 5.421010862427522E-20;
|
| + // 2^52, 2^-52
|
| + static final double POWER_52 = 4503599627370496.0;
|
| + static final double POWER_MINUS_52 = 2.220446049250313E-16;
|
| + // 2^32, 2^-32
|
| + static final double POWER_32 = 4294967296.0;
|
| + static final double POWER_MINUS_32 = 2.3283064365386963E-10;
|
| + // 2^31
|
| + static final double POWER_31 = 2147483648.0;
|
| + // 2^20, 2^-20
|
| + static final double POWER_20 = 1048576.0;
|
| + static final double POWER_MINUS_20 = 9.5367431640625E-7;
|
| + // 2^16, 2^-16
|
| + static final double POWER_16 = 65536.0;
|
| + static final double POWER_MINUS_16 = 0.0000152587890625;
|
| + // 2^8, 2^-8
|
| + static final double POWER_8 = 256.0;
|
| + static final double POWER_MINUS_8 = 0.00390625;
|
| + // 2^4, 2^-4
|
| + static final double POWER_4 = 16.0;
|
| + static final double POWER_MINUS_4 = 0.0625;
|
| + // 2^2, 2^-2
|
| + static final double POWER_2 = 4.0;
|
| + static final double POWER_MINUS_2 = 0.25;
|
| + // 2^1, 2^-1
|
| + static final double POWER_1 = 2.0;
|
| + static final double POWER_MINUS_1 = 0.5;
|
| + // 2^-149 (smallest single non-denorm)
|
| + static final double POWER_MINUS_149 = 1.401298464324817E-45;
|
| + // 2^-1022 (smallest double non-denorm)
|
| + static final double POWER_MINUS_1022 = 2.2250738585072014E-308;
|
| +
|
| + static final List<double> powers = const [
|
| + POWER_512, POWER_256, POWER_128, POWER_64, POWER_32, POWER_16, POWER_8,
|
| + POWER_4, POWER_2, POWER_1
|
| + ];
|
| +
|
| + static final List<double> invPowers = const [
|
| + POWER_MINUS_512, POWER_MINUS_256, POWER_MINUS_128, POWER_MINUS_64,
|
| + POWER_MINUS_32, POWER_MINUS_16, POWER_MINUS_8, POWER_MINUS_4, POWER_MINUS_2,
|
| + POWER_MINUS_1
|
| + ];
|
| +}
|
| +
|
| +/**
|
| + * An unsigned 64-bit number, stored internally as two unsigned 32-bit numbers.
|
| + */
|
| +class Packed64 {
|
| +
|
| + int64 _packed;
|
| +
|
| + // Determine whether the platform supports ints greater than 2^53
|
| + // without loss of precision.
|
| + static bool _haveBigIntsCached = null;
|
| +
|
| + static bool get _haveBigInts() {
|
| + if (_haveBigIntsCached == null) {
|
| + var x = 9007199254740992;
|
| + // Defeat compile-time constant folding.
|
| + if (2 + 2 != 4) {
|
| + x = 0;
|
| + }
|
| + var y = x + 1;
|
| + var same = y == x;
|
| + _haveBigIntsCached = !same;
|
| + }
|
| + return _haveBigIntsCached;
|
| + }
|
| +
|
| + static final bool _allowSoftInts = true;
|
| +
|
| + bool get _softInts() =>
|
| + (null !== _haveBigIntsCached && _haveBigIntsCached) ||
|
| + (null !== _allowSoftInts && _allowSoftInts);
|
| +
|
| + /**
|
| + * Constructs a [Packed64] instance with given high and low 32-bit words.
|
| + * Throws [:IllegalArgumentException:] if either the [lo] or [hi] int is
|
| + * outside the range of a signed 32-bit INT.
|
| + */
|
| + Packed64(int hi, int lo) {
|
| + if (hi < -_Constants.POWER_32_INT || hi >= _Constants.POWER_32_INT) {
|
| + throw new IllegalArgumentException("Hi value out of range: $hi");
|
| + }
|
| + if (lo < -_Constants.POWER_32_INT || lo >= _Constants.POWER_32_INT) {
|
| + throw new IllegalArgumentException("Lo value out of range: $lo");
|
| + }
|
| + _packed = new int64.fromInts(hi, lo);
|
| + }
|
| +
|
| + /**
|
| + * Constructs a [Packed64] instance from a list of byte values, LSB first.
|
| + */
|
| + Packed64.fromBytes(List<int> b) {
|
| + _packed = new int64.fromBytes(b);
|
| + }
|
| +
|
| + /**
|
| + * Constructs a [Packed64] instance that will have the bit pattern of the
|
| + * given [double] value. All [:NaN:] values are converted to a canonical
|
| + * bit pattern.
|
| + */
|
| + factory Packed64.fromDouble(double d) {
|
| + if (d.isNaN()) {
|
| + return new Packed64(0x7ff80000, 0x0);
|
| + }
|
| +
|
| + bool negative = false;
|
| + if (d.isNegative()) {
|
| + negative = true;
|
| + d = -d;
|
| + }
|
| + if (d == 0.0) {
|
| + if (negative) {
|
| + return new Packed64(_Constants.POWER_31_INT, 0x0);
|
| + } else {
|
| + return new Packed64(0x0, 0x0);
|
| + }
|
| + }
|
| + if (d.isInfinite()) {
|
| + if (negative) {
|
| + return new Packed64(0xfff00000, 0x0);
|
| + } else {
|
| + return new Packed64(0x7ff00000, 0x0);
|
| + }
|
| + }
|
| +
|
| + int exp = 0;
|
| +
|
| + // Scale d by powers of 2 into the range [1.0, 2.0)
|
| + // If the exponent would go below -1023, scale into (0.0, 1.0) instead
|
| + if (d < 1.0) {
|
| + int bit = 512;
|
| + for (int i = 0; i < 10; i++, bit >>= 1) {
|
| + if (d < _Constants.invPowers[i] && exp - bit >= -1023) {
|
| + d *= _Constants.powers[i];
|
| + exp -= bit;
|
| + }
|
| + }
|
| + // Force into [1.0, 2.0) range
|
| + if (d < 1.0 && exp - 1 >= -1023) {
|
| + d *= 2.0;
|
| + exp--;
|
| + }
|
| + } else if (d >= 2.0) {
|
| + int bit = 512;
|
| + for (int i = 0; i < 10; i++, bit >>= 1) {
|
| + if (d >= _Constants.powers[i]) {
|
| + d *= _Constants.invPowers[i];
|
| + exp += bit;
|
| + }
|
| + }
|
| + }
|
| +
|
| + if (exp > -1023) {
|
| + // Remove significand of non-denormalized mantissa
|
| + d -= 1.0;
|
| + } else {
|
| + // Insert 0 bit as significand of denormalized mantissa
|
| + d *= 0.5;
|
| + }
|
| +
|
| + // Extract high 20 bits of mantissa
|
| + int ihi = (d * _Constants.POWER_20).toInt();
|
| +
|
| + // Extract low 32 bits of mantissa
|
| + d -= ihi * _Constants.POWER_MINUS_20;
|
| + int ilo = (d * _Constants.POWER_52).toInt();
|
| +
|
| + // Exponent bits
|
| + ihi |= (exp + 1023) << 20;
|
| + // Sign bit
|
| + if (negative) {
|
| + ihi += _Constants.POWER_31_INT;
|
| + }
|
| +
|
| + return new Packed64(ihi, ilo);
|
| + }
|
| +
|
| + void _orShifted(int bits, int shift) {
|
| + _packed |= new int64.fromInt(bits) << shift;
|
| + }
|
| +
|
| + /**
|
| + * Constructs a [Packed64] instance from a variable-length representation.
|
| + * Throws an [:IllegalArgumentException:] if the encoding is invalid.
|
| + */
|
| + Packed64.fromVarintBytes(List<int> b) {
|
| + try {
|
| + _packed = int64.ZERO;
|
| + int i = 0;
|
| + bool lastByte = ((b[i] & _Constants.MIN_BITS_8) === 0);
|
| + while (i < 10 && !lastByte) {
|
| + _orShifted(b[i] & _Constants.MAX_BITS_7,
|
| + _Constants.SEPTET_BIT_COUNT * i);
|
| + i++;
|
| + lastByte = (b[i] & _Constants.MIN_BITS_8) === 0;
|
| + }
|
| + _orShifted(b[i] & _Constants.MAX_BITS_7,
|
| + _Constants.SEPTET_BIT_COUNT * i);
|
| + } catch (IndexOutOfRangeException e) {
|
| + throw new IllegalArgumentException("Invalid Encoding");
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Constructs a [Packed64] instance whose value is equivalent to the given
|
| + * value. Throws an [:IllegalArgumentException:] if the value is <
|
| + * -9223372036854775808 (MIN_SINT64) or > 18446744073709551615
|
| + * (MAZ_UINT64).
|
| + */
|
| + Packed64.fromInt(int x) {
|
| + if (x < -9223372036854775808 || x > 18446744073709551615) {
|
| + throw new IllegalArgumentException("Out of range: $x");
|
| + }
|
| + _packed = new int64.fromInt(x);
|
| + }
|
| +
|
| + /**
|
| + * Compares this [Packed64] with a given [Packed64] or [int] value.
|
| + */
|
| + bool operator ==(var other) {
|
| + if (other is num) {
|
| + return this.toInt() == new Packed64.fromInt(other);
|
| + }
|
| + if (other is !Packed64) {
|
| + return false;
|
| + }
|
| + return other._packed == _packed;
|
| + }
|
| +
|
| + int hashCode() {
|
| + return _packed.hashCode();
|
| + }
|
| +
|
| + /**
|
| + * Returns the 32 high bits of this [Packed64] value as an unsigned integer
|
| + * in the range [0, 2^31 - 1].
|
| + */
|
| + int get hi() => ((_packed >> 32) & 0xffffffff).toInt();
|
| +
|
| + /**
|
| + * Returns the 32 low bits of this [Packed64] value as an unsigned integer
|
| + * in the range [0, 2^31 - 1].
|
| + */
|
| + int get lo() => (_packed & 0xffffffff).toInt();
|
| +
|
| + /**
|
| + * Decodes this [Packed64] from the zig-zag representation
|
| + * [:(n << 1) ^ (n >> 63):].
|
| + */
|
| + Packed64 decodeZigZag() {
|
| + int ihi = this.hi;
|
| + int ilo = this.lo;
|
| +
|
| + int sign = ilo % 2;
|
| + ilo = ((ihi % 2 == 1) ? _Constants.POWER_31_INT : 0) + (ilo ~/ 2);
|
| + ihi = ihi ~/ 2;
|
| + if (sign == 1) {
|
| + ihi = _bitFlip(ihi);
|
| + ilo = _bitFlip(ilo);
|
| + }
|
| + Packed64 result = new Packed64(ihi, ilo);
|
| + return result;
|
| + }
|
| +
|
| + static int _bitFlip(int x) => _Constants.MAX_BITS_32 - x;
|
| +
|
| + /**
|
| + * Encodes this [Packed64] in the zig-zag representation
|
| + * [:(n << 1) ^ (n >> 63):].
|
| + */
|
| + Packed64 encodeZigZag() {
|
| + int ihi = hi;
|
| + int ilo = lo;
|
| + bool negative = ihi >= _Constants.POWER_31_INT;
|
| + ihi = ihi * 2 + (ilo >= _Constants.POWER_31_INT ? 1 : 0);
|
| + ilo = ilo * 2;
|
| + if (ihi >= _Constants.POWER_32_INT) {
|
| + ihi -= _Constants.POWER_32_INT;
|
| + }
|
| + if (ilo >= _Constants.POWER_32_INT) {
|
| + ilo -= _Constants.POWER_32_INT;
|
| + }
|
| + if (negative) {
|
| + ihi = _bitFlip(ihi);
|
| + ilo = _bitFlip(ilo);
|
| + }
|
| + return new Packed64(ihi, ilo);
|
| + }
|
| +
|
| + /**
|
| + * Returns [true] if this [Packed64] can safely be converted to a signed
|
| + * integer in the range [-2^51, 2^51 - 1].
|
| + */
|
| + bool isSafeAsInt() {
|
| + if (_haveBigInts) {
|
| + return true;
|
| + } else {
|
| + int top = (hi >> 20) & 0xfff;
|
| + return top == 0x0 || top == 0xfff;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Returns [true] if this [Packed64] can safely be converted to an unsigned
|
| + * integer in the range [0, 2^52 - 1].
|
| + */
|
| + bool isSafeAsUint() {
|
| + if (_haveBigInts) {
|
| + return true;
|
| + } else {
|
| + int top = (hi >> 20) & 0xfff;
|
| + return top == 0x0;
|
| + }
|
| + }
|
| +
|
| + /**
|
| + * Return the number of bytes required to encdode this [Packed64] using
|
| + * the variable-length representation.
|
| + */
|
| + int sizeOfVarint() {
|
| + int ihi = this.hi;
|
| + int ilo = this.lo;
|
| +
|
| + int i = 0;
|
| + while (i < 10) {
|
| + ilo = ((ihi % 128) * _Constants.POWER_25_INT) + (ilo ~/ 128);
|
| + ihi ~/= 128;
|
| + i++;
|
| + if (ihi === 0 && ilo === 0) {
|
| + return i;
|
| + }
|
| + }
|
| + return i;
|
| + }
|
| +
|
| + /**
|
| + * Return this [Packed64] as a list of 8 ints, LSB first.
|
| + */
|
| + List<int> toBytes() => _packed.toBytes();
|
| +
|
| + /**
|
| + * Return this [Packed64] interpreted as an IEEE double-precision value.
|
| + */
|
| + double toDouble() {
|
| + int ihi = this.hi;
|
| + int ilo = this.lo;
|
| + if (ihi < 0) {
|
| + ihi += _Constants.POWER_32_INT;
|
| + }
|
| + if (ilo < 0) {
|
| + ilo += _Constants.POWER_32_INT;
|
| + }
|
| +
|
| + bool negative = (ihi & _Constants.POWER_31_INT) != 0;
|
| + int exp = (ihi >> 20) & 0x7ff;
|
| + ihi &= 0xfffff; // remove sign bit and exponent
|
| +
|
| + if (exp == 0x0) {
|
| + double d = (ihi * _Constants.POWER_MINUS_20) +
|
| + (ilo * _Constants.POWER_MINUS_52);
|
| + d *= _Constants.POWER_MINUS_1022;
|
| + return negative ? (d == 0.0 ? -0.0 : -d) : d;
|
| + } else if (exp == 0x7ff) {
|
| + if (ihi == 0 && ilo == 0) {
|
| + return negative ? double.NEGATIVE_INFINITY : double.INFINITY;
|
| + } else {
|
| + return double.NAN;
|
| + }
|
| + }
|
| +
|
| + // Normalize exponent
|
| + exp -= 1023;
|
| +
|
| + double d = 1.0 + (ihi * _Constants.POWER_MINUS_20) +
|
| + (ilo * _Constants.POWER_MINUS_52);
|
| + if (exp > 0) {
|
| + int bit = 512;
|
| + for (int i = 0; i < 10; i++, bit >>= 1) {
|
| + if (exp >= bit) {
|
| + d *= _Constants.powers[i];
|
| + exp -= bit;
|
| + }
|
| + }
|
| + } else if (exp < 0) {
|
| + while (exp < 0) {
|
| + int bit = 512;
|
| + for (int i = 0; i < 10; i++, bit >>= 1) {
|
| + if (exp <= -bit) {
|
| + d *= _Constants.invPowers[i];
|
| + exp += bit;
|
| + }
|
| + }
|
| + }
|
| + }
|
| + return negative ? -d : d;
|
| + }
|
| +
|
| + /**
|
| + * Return the value of this [Packed64] as an int if the resulting value
|
| + * is in the legal range of [-2^51, 2^51 -1], otherwise throw an
|
| + * IllegalArgumentException.
|
| + */
|
| + int toInt() => _packed.toInt();
|
| +
|
| + /**
|
| + * Return the value of this [Packed64] as an int if the resulting value
|
| + * is in the legal range of [-2^51, 2^51 -1], otherwise return [this].
|
| + */
|
| + Dynamic toIntIfSafe() {
|
| + if (_softInts && this.isSafeAsInt()) {
|
| + return this.toInt();
|
| + }
|
| + return this;
|
| + }
|
| +
|
| + /**
|
| + * Return the value of this [Packed64] as an int if the resulting value
|
| + * is in the legal range of [0, 2^52 -1], otherwise throw an
|
| + * IllegalArgumentException.
|
| + */
|
| + int toUint() {
|
| + if (!isSafeAsUint()) {
|
| + throw new IllegalArgumentException("Out of range");
|
| + }
|
| + int value = this.hi * _Constants.POWER_32_INT + this.lo;
|
| + return value;
|
| + }
|
| +
|
| + /**
|
| + * Return the value of this [Packed64] as an int if the resulting value
|
| + * is in the legal range of [0, 2^52 -1], otherwise return [this].
|
| + */
|
| + Dynamic toUintIfSafe() {
|
| + if (_softInts && this.isSafeAsUint()) {
|
| + return this.toUint();
|
| + }
|
| + return this;
|
| + }
|
| +
|
| + /**
|
| + * Return a list of up to 10 ints encoding this [Packed64] using a
|
| + * variable-length representation.
|
| + */
|
| + List<int> toVarintBytes() {
|
| + int ihi = this.hi;
|
| + int ilo = this.lo;
|
| +
|
| + List<int> b = [];
|
| + int i = 0;
|
| + while (true) {
|
| + i++;
|
| + if ((ihi != 0 || ilo >= 128) && i < 10) {
|
| + int v = 128 + (ilo % 128);
|
| + b.add(v);
|
| + } else {
|
| + int v = ilo % 128;
|
| + b.add(v);
|
| + break;
|
| + }
|
| + ilo = ((ihi % 128) * 33554432) + (ilo ~/ 128);
|
| + ihi ~/= 128;
|
| + }
|
| + return b;
|
| + }
|
| +
|
| + /**
|
| + * Return a String useful for debugging.
|
| + */
|
| + String toDebugString() {
|
| + return "Packed64[0x${hi.toRadixString(16)},0x${lo.toRadixString(16)}]";
|
| + }
|
| +
|
| + /**
|
| + * Return a String in decimal representation.
|
| + */
|
| + String toString() {
|
| + return _packed.toString();
|
| + }
|
| +}
|
| +
|
| +/*
|
| + * Provides conversion utilities from dart types to/from protocol buffer wire
|
| + * format.
|
| + */
|
| +class PbCodec {
|
| + static bool toBool(List<int> b) => b[0] !== 0;
|
| +
|
| + static int toFixed32(List<int> b) => packedToUint32(bytesToPacked(b));
|
| +
|
| + // return value may be an int or a Packed64
|
| + static Dynamic toFixed64(List<int> b) => int64ToUint64(bytesToPacked64(b));
|
| +
|
| + static int toInt32(List<int> b) => packedToInt32(varintBytesToPacked(b));
|
| +
|
| + // return value may be an int or a Packed64
|
| + static Dynamic toInt64(List<int> b) =>
|
| + int64ToSigned(varintBytesToPacked64(b));
|
| +
|
| + static int toSfixed32(List<int> b) => packedToInt32(bytesToPacked(b));
|
| +
|
| + // return value may be an int or a Packed64
|
| + static Dynamic toSfixed64(List<int> b) => bytesToPacked64(b);
|
| +
|
| + static int toSint32(List<int> b) => packedToSint32(varintBytesToPacked(b));
|
| +
|
| + // return value may be an int or a Packed64
|
| + static Dynamic toSint64(List<int> b) =>
|
| + int64ToSint64(varintBytesToPacked64(b));
|
| +
|
| + static int toUint32(List<int> b) => packedToUint32(varintBytesToPacked(b));
|
| +
|
| + // return value may be an int or a Packed64
|
| + static Dynamic toUint64(List<int> b) =>
|
| + int64ToUint64(varintBytesToPacked64(b));
|
| +
|
| + static double toFloat(List<int> b) => packedToFloat(bytesToPacked(b));
|
| +
|
| + static double toDouble(List<int> b) => int64ToDouble(bytesToPacked64(b));
|
| +
|
| + static List<int> boolToBytes(bool value) =>
|
| + value ? _Constants.trueBytes : _Constants.falseBytes;
|
| +
|
| + static List<int> fixed32ToBytes(int value) =>
|
| + packed32ToBytes(uint32ToPacked(value));
|
| +
|
| + // value may be an int or a Packed64
|
| + static List<int> fixed64ToBytes(var value) => packed64ToBytes(value);
|
| +
|
| + static List<int> int32ToBytes(int value) =>
|
| + packedToVarintBytes(int32ToPacked(value));
|
| +
|
| + // value may be an int or a Packed64
|
| + static List<int> int64ToBytes(var value) =>
|
| + int64ToVarintBytes(value);
|
| +
|
| + static List<int> sfixed32ToBytes(int value) =>
|
| + packed32ToBytes(int32ToPacked(value));
|
| +
|
| + // value may be an int or a Packed64
|
| + static List<int> sfixed64ToBytes(var value) =>
|
| + packed64ToBytes(value);
|
| +
|
| + static List<int> sint32ToBytes(int value) =>
|
| + packedToVarintBytes(sint32ToPacked(value));
|
| +
|
| + // value may be an int or a Packed64
|
| + static List<int> sint64ToBytes(var value) =>
|
| + int64ToVarintBytes(sint64ToPacked64(value));
|
| +
|
| + static List<int> uint32ToBytes(int value) =>
|
| + packedToVarintBytes(uint32ToPacked(value));
|
| +
|
| + // value may be an int or a Packed64
|
| + static List<int> uint64ToBytes(var value) =>
|
| + int64ToVarintBytes(uint64ToPacked64(value));
|
| +
|
| + static List<int> floatToBytes(double value) =>
|
| + packed32ToBytes(floatToPacked(value));
|
| +
|
| + static List<int> doubleToBytes(double value) =>
|
| + packed64ToBytes(doubleToPacked64(value));
|
| +
|
| + static final int sizeOfBool = 1;
|
| +
|
| + static int sizeOfFixed32 = _Constants.BYTES_IN_32_BITS;
|
| +
|
| + static int sizeOfFixed64 = _Constants.BYTES_IN_64_BITS;
|
| +
|
| + static int sizeOfSfixed32 = _Constants.BYTES_IN_32_BITS;
|
| +
|
| + static int sizeOfSfixed64 = _Constants.BYTES_IN_64_BITS;
|
| +
|
| + static int sizeOfInt32(int value) => value < 0 ? 5 : sizeOfVarint(value);
|
| +
|
| + // value may be an int or a Packed64
|
| + static int sizeOfInt64(var value) {
|
| + if (value is Packed64) {
|
| + return value.sizeOfVarint();
|
| + } else if (value is num) {
|
| + if (value < 0) {
|
| + return 10;
|
| + } else {
|
| + return sizeOfVarint64(new Packed64.fromInt(value.toInt()));
|
| + }
|
| + } else {
|
| + throw new IllegalArgumentException("Expected Packed64 or int");
|
| + }
|
| + }
|
| +
|
| + static int sizeOfSint32(int value) => sizeOfVarint(encodeZigZag32(value));
|
| +
|
| + // value may be an int or a Packed64
|
| + static int sizeOfSint64(var value) => sizeOfVarint64(encodeZigZag64(value));
|
| +
|
| + static int sizeOfUint32(int value) => sizeOfVarint(value);
|
| +
|
| + // value may be an int or a Packed64
|
| + static int sizeOfUint64(var value) => sizeOfVarint64(value);
|
| +
|
| + static int sizeOfVarint(int value) {
|
| + int i = 0;
|
| + while (i < 10) {
|
| + value >>= _Constants.SEPTET_BIT_COUNT;
|
| + i++;
|
| + if (value === 0) return i;
|
| + }
|
| + return i;
|
| + }
|
| +
|
| + // value may be an int or a Packed64
|
| + static int sizeOfVarint64(var value) {
|
| + if (value is Packed64) {
|
| + return value.sizeOfVarint();
|
| + } else if (value is num) {
|
| + return new Packed64.fromInt(value.toInt()).sizeOfVarint();
|
| + } else {
|
| + throw new IllegalArgumentException("Expected Packed64 or int");
|
| + }
|
| + }
|
| +
|
| + static int int32ToPacked(int value) {
|
| + if (value < 0) {
|
| + return _Constants.POWER_32_INT + value;
|
| + }
|
| + return value;
|
| + }
|
| +
|
| + static int sint32ToPacked(int value) => encodeZigZag32(value);
|
| +
|
| + // value and return may be an int or a Packed64
|
| + static Dynamic sint64ToPacked64(var value) => encodeZigZag64(value);
|
| +
|
| + static int uint32ToPacked(int value) => value;
|
| +
|
| + // value and return may be an int or a Packed64
|
| + static Dynamic uint64ToPacked64(var value) => value;
|
| +
|
| + static int packedToInt32(int packed) {
|
| + if (packed >= _Constants.POWER_32_INT) {
|
| + packed &= _Constants.MAX_BITS_32;
|
| + }
|
| + if (packed < 0 || ((packed & _Constants.POWER_31_INT) == 0)) {
|
| + return packed;
|
| + } else {
|
| + return packed - _Constants.POWER_32_INT;
|
| + }
|
| + }
|
| +
|
| + static int packedToSint32(int packed) => decodeZigZag32(packed);
|
| +
|
| + static int packedToUint32(int packed) => packed;
|
| +
|
| + // value and return may be an int or a Packed64
|
| + static Dynamic int64ToSint64(var packed) => decodeZigZag64(packed);
|
| +
|
| + // value and return may be an int or a Packed64
|
| + static Dynamic int64ToUint64(var packed) {
|
| + if (packed is Packed64) {
|
| + return packed;
|
| + } else if (packed < 0) {
|
| + return _Constants.POWER_64_INT + packed;
|
| + } else {
|
| + return packed;
|
| + }
|
| + }
|
| +
|
| + // value and return may be an int or a Packed64
|
| + static Dynamic int64ToSigned(var packed) {
|
| + if (packed is Packed64) {
|
| + return packed;
|
| + } else if (packed >= _Constants.POWER_63_INT) {
|
| + return packed - _Constants.POWER_64_INT;
|
| + } else {
|
| + return packed;
|
| + }
|
| + }
|
| +
|
| + static int bytesToPacked(List<int> b) {
|
| + int result = 0;
|
| + int factor = 1;
|
| + for (int i = 0; i < b.length && i < _Constants.BYTES_IN_64_BITS;
|
| + i++, factor *= 256) {
|
| + result += (b[i] & _Constants.MAX_BITS_8) * factor;
|
| + }
|
| + return result;
|
| + }
|
| +
|
| + static Dynamic bytesToPacked64(List<int> b) =>
|
| + new Packed64.fromBytes(b).toIntIfSafe();
|
| +
|
| + static int _unsigned(int x) => x < 0 ? x + _Constants.POWER_32_INT : x;
|
| +
|
| + static int varintBytesToPacked(List<int> b) {
|
| + try {
|
| + int result = 0;
|
| + int i = 0;
|
| + bool lastByte = ((b[i] & _Constants.MIN_BITS_8) === 0);
|
| + while (i < 10 && !lastByte) {
|
| + result |= (((b[i] & _Constants.MAX_BITS_7) <<
|
| + (_Constants.SEPTET_BIT_COUNT * i)));
|
| + i++;
|
| + lastByte = (b[i] & _Constants.MIN_BITS_8) === 0;
|
| + }
|
| + result |= (b[i] & _Constants.MAX_BITS_7) <<
|
| + (_Constants.SEPTET_BIT_COUNT * i);
|
| + return _unsigned(result);
|
| + } catch (IndexOutOfRangeException e) {
|
| + throw new IllegalArgumentException("Invalid Encoding");
|
| + }
|
| + }
|
| +
|
| + static Dynamic varintBytesToPacked64(List<int> b) =>
|
| + new Packed64.fromVarintBytes(b).toUintIfSafe();
|
| +
|
| + static List<int> packed32ToBytes(int value) {
|
| + List<int> b = new List(4);
|
| + for (int i = 0; i < 4; i++) {
|
| + if (value === 0) {
|
| + while (i < 4) {
|
| + b[i] = 0;
|
| + i++;
|
| + }
|
| + } else {
|
| + b[i] = value & _Constants.MAX_BITS_8;
|
| + value >>= _Constants.OCTET_BIT_COUNT;
|
| + }
|
| + }
|
| + return b;
|
| + }
|
| +
|
| + // value may be an int or a Packed64
|
| + static List<int> packed64ToBytes(var value) {
|
| + if (value is Packed64) {
|
| + return value.toBytes();
|
| + } else if (value is num) {
|
| + return new Packed64.fromInt(value.toInt()).toBytes();
|
| + } else {
|
| + throw new IllegalArgumentException("Expected Packed64 or int");
|
| + }
|
| + }
|
| +
|
| + static List<int> packedToVarintBytes(int value) {
|
| + List<int> b = [];
|
| + int i = 0;
|
| + while (true) {
|
| + i++;
|
| + int nextVal = value ~/ 128;
|
| + if (nextVal !== 0 && i < 10) {
|
| + int v = 128 + (value % 128);
|
| + b.add(v);
|
| + } else {
|
| + int v = value % 128;
|
| + b.add(v);
|
| + break;
|
| + }
|
| + value = nextVal;
|
| + }
|
| + return b;
|
| + }
|
| +
|
| + static List<int> int64ToVarintBytes(var value) {
|
| + if (value is Packed64) {
|
| + return value.toVarintBytes();
|
| + } else if (value is num) {
|
| + return new Packed64.fromInt(value.toInt()).toVarintBytes();
|
| + } else {
|
| + throw new IllegalArgumentException("Expected Packed64 or int");
|
| + }
|
| + }
|
| +
|
| + static int encodeZigZag32(int value) {
|
| + if (value < 0) {
|
| + return -(value * 2) - 1;
|
| + } else {
|
| + return value * 2;
|
| + }
|
| + }
|
| +
|
| + // value and return may be an int or a Packed64
|
| + static Dynamic encodeZigZag64(var value) {
|
| + if (value is Packed64) {
|
| + return value.encodeZigZag().toUintIfSafe();
|
| + } else if (value is num) {
|
| + return new Packed64.fromInt(value.toInt()).encodeZigZag().toUint();
|
| + } else {
|
| + throw new IllegalArgumentException("Expected Packed64 or int");
|
| + }
|
| + }
|
| +
|
| + static int decodeZigZag32(int value) {
|
| + if ((value & 0x1) == 0) {
|
| + return value ~/ 2;
|
| + } else {
|
| + value = (value - 1) ~/ 2;
|
| + if (value < _Constants.POWER_32_INT) {
|
| + return -value - 1;
|
| + } else {
|
| + return value;
|
| + }
|
| + }
|
| + }
|
| +
|
| + // value and return may be an int or a Packed64
|
| + static Dynamic decodeZigZag64(var value) {
|
| + if (value is Packed64) {
|
| + return value.decodeZigZag().toIntIfSafe();
|
| + } else if (value is num) {
|
| + return new Packed64.fromInt(value.toInt()).decodeZigZag().toIntIfSafe();
|
| + } else {
|
| + throw new IllegalArgumentException("Expected Packed64 or int");
|
| + }
|
| + }
|
| +
|
| + // value may be an int or a Packed64
|
| + static double int64ToDouble(var value) {
|
| + if (value is Packed64) {
|
| + return value.toDouble();
|
| + } else if (value is num) {
|
| + return new Packed64.fromInt(value.toInt()).toDouble();
|
| + } else {
|
| + throw new IllegalArgumentException("Expected Packed64 or int");
|
| + }
|
| + }
|
| +
|
| + static double packedToFloat(int packed) {
|
| + bool negative = (packed & _Constants.POWER_31_INT) != 0;
|
| + int exp = (packed >> 23) & 0xff;
|
| + packed &= 0x7fffff;
|
| +
|
| + if (exp == 0x0) {
|
| + // Handle +/- 0 here, denorms below
|
| + if (packed == 0) {
|
| + return negative ? -0.0 : 0.0;
|
| + }
|
| + } else if (exp == 0xff) {
|
| + // Inf & NaN
|
| + if (packed == 0) {
|
| + return negative ? double.NEGATIVE_INFINITY : double.INFINITY;
|
| + } else {
|
| + return double.NAN;
|
| + }
|
| + }
|
| +
|
| + // Build the bits of a 64-bit double from the incoming bits
|
| + int ihi = negative ? _Constants.POWER_31_INT : 0x0;
|
| + int ilo = 0x0;
|
| + if (exp == 0) {
|
| + // Input is denormalized, renormalize by shifting left until there is a
|
| + // leading 1
|
| + exp = 897;
|
| + while ((packed & 0x800000) == 0) {
|
| + packed <<= 1;
|
| + exp--;
|
| + }
|
| + packed &= 0x7fffff;
|
| + ihi |= exp << 20;
|
| + ihi |= packed >> 3;
|
| + ilo = (packed & 0x7) << 29;
|
| + } else {
|
| + // Normalized number, rebias exponent and shift mantissa into place
|
| + ihi |= (exp + 896) << 20;
|
| + ihi |= packed >> 3;
|
| + ilo = (packed & 0x7) << 29;
|
| + }
|
| + return int64ToDouble(new Packed64(ihi, ilo));
|
| + }
|
| +
|
| + /**
|
| + * Return the 32-bit IEEE single-precision representation that represents
|
| + * the value [d] truncated to 23 fractional bits.
|
| + */
|
| + static int floatToPacked(double d) {
|
| + // Return a canonical NaN since we have no way to detect anything else
|
| + if (d.isNaN()) {
|
| + return 0x7fc00000;
|
| + }
|
| +
|
| + bool negative = false;
|
| + if (d.isNegative()) {
|
| + negative = true;
|
| + d = -d;
|
| + }
|
| + // Numbers below min float map to 0.0
|
| + if (d < _Constants.MIN_FLOAT_DENORM) {
|
| + return negative ? _Constants.POWER_31_INT : 0x0;
|
| + }
|
| + // Numbers above max float map to Infinity
|
| + if (d.isInfinite() || d > _Constants.MAX_FLOAT) {
|
| + return negative ? 0xff800000 : 0x7f800000;
|
| + }
|
| +
|
| + // Obtain the 64-bit representation and extract its exponent and
|
| + // mantissa.
|
| + var packed = doubleToPacked64(d);
|
| + int exp, mantissa;
|
| + if (packed is Packed64) {
|
| + Packed64 packed64 = packed;
|
| + exp = ((packed64.hi >> 20) & 0x7ff) - 1023;
|
| + mantissa = ((packed64.hi & 0xfffff) << 3) | ((packed64.lo >> 29) & 0x7);
|
| + } else if (packed is num) {
|
| + var ipacked = packed.toInt();
|
| + exp = ((ipacked >> 52) & 0x7ff) - 1023;
|
| + mantissa = (ipacked & 0xfffffffffffff) >> 29;
|
| + }
|
| +
|
| + // If the number will be a denorm in the float representation
|
| + // (i.e., its exponent is -127 or smaller), add a leading 1 to the
|
| + // mantissa and shift it right to maintain an exponent of -127.
|
| + if (exp <= -127) {
|
| + mantissa = (0x800000 | mantissa) >> (-127 - exp + 1);
|
| + exp = -127;
|
| + }
|
| +
|
| + // Construct the 32-bit representation
|
| + int packed32 = negative ? _Constants.POWER_31_INT : 0x0;
|
| + packed32 |= (exp + 127) << 23;
|
| + packed32 |= mantissa;
|
| + if (packed32 < 0) {
|
| + packed32 += _Constants.POWER_32_INT;
|
| + }
|
| + return packed32;
|
| + }
|
| +
|
| + static Dynamic doubleToPacked64(double d) {
|
| + Packed64 packed = new Packed64.fromDouble(d);
|
| + if (packed.isSafeAsUint()) {
|
| + return packed.toUint();
|
| + }
|
| + return packed;
|
| + }
|
| +
|
| + // JSON
|
| +
|
| + // ('0' + x) or ('a' + x - 10)
|
| + static int _hexDigit(int x) => x < 10 ? 48 + x : 87 + x;
|
| +
|
| + // Escape a string to be suitable as a JSON value
|
| + static String escapeString(String x) {
|
| + List<int> chars = x.charCodes();
|
| + List<int> output = new List<int>();
|
| + for (int i = 0; i < chars.length; i++) {
|
| + int c = chars[i];
|
| + // Escape control characters, double-quote, and backslash
|
| + if (c < 32) { // control characters
|
| + output.add(92); // '\'
|
| + switch (c) {
|
| + case 8: // backspace
|
| + output.add(98); // 'b'
|
| + break;
|
| + case 9: // tab
|
| + output.add(116); // 't'
|
| + break;
|
| + case 10: // newline
|
| + output.add(110); // 'n'
|
| + break;
|
| + case 12: // formfeed
|
| + output.add(102); // 'f'
|
| + break;
|
| + case 13: // carriage return
|
| + output.add(114); // 'r'
|
| + break;
|
| + default:
|
| + output.add(117); // 'u'
|
| + output.add(_hexDigit((c >> 12) & 0xf));
|
| + output.add(_hexDigit((c >> 8) & 0xf));
|
| + output.add(_hexDigit((c >> 4) & 0xf));
|
| + output.add(_hexDigit(c & 0xf));
|
| + break;
|
| + }
|
| + } else if (c == 34 || c == 92) { // double-quote or backslash
|
| + output.add(92); // '\'
|
| + output.add(c);
|
| + } else {
|
| + output.add(c);
|
| + }
|
| + }
|
| + return new String.fromCharCodes(output);
|
| + }
|
| +}
|
| +
|
| +// TODO - make this a separate library
|
| +class Base64Codec {
|
| +
|
| + // MIME Base64 characters plus padding char '=' (RFC 2045)
|
| + static final String MIME_ALPHABET =
|
| + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
| +
|
| + static Base64Codec _defaultInstance = null;
|
| +
|
| + static Base64Codec get defaultInstance() {
|
| + if (_defaultInstance == null) {
|
| + _defaultInstance = new Base64Codec();
|
| + }
|
| + return _defaultInstance;
|
| + }
|
| +
|
| + List<int> _base64Chars = null;
|
| + List<int> _base64InverseChars = null;
|
| + int _padding;
|
| +
|
| + Base64Codec([String alphabet = null]) {
|
| + assert(alphabet == null || alphabet.length == 65);
|
| + if (alphabet == null) {
|
| + alphabet = MIME_ALPHABET;
|
| + }
|
| + _initTables(alphabet);
|
| + }
|
| +
|
| + void _initTables(String alphabet) {
|
| + _base64Chars = alphabet.charCodes();
|
| + _base64InverseChars = new List<int>(128);
|
| + // Use -1 to indicate an illegal character
|
| + for (int i = 0; i < 128; i++) {
|
| + _base64InverseChars[i] = -1;
|
| + }
|
| + for (int i = 0; i < 64; i++) {
|
| + _base64InverseChars[_base64Chars[i]] = i;
|
| + }
|
| + // The padding character is interpreted as 0
|
| + _padding = alphabet.charCodeAt(64);
|
| + _base64InverseChars[_padding] = 0;
|
| + }
|
| +
|
| + int _base64Inverse(int x) {
|
| + // Look at 7 low bits only
|
| + int result = _base64InverseChars[x & 0x7f];
|
| + if (result == -1) {
|
| + throw new IllegalArgumentException("Unknown character code: ${x & 0x7f}");
|
| + }
|
| + return result;
|
| + }
|
| +
|
| + List<int> decodeAsList(String s) {
|
| + int olen = 3 * (s.length ~/ 4);
|
| + // Inspect the last two characters of the input for padding
|
| + for (int i = Math.max(0, s.length - 2); i < s.length; i++) {
|
| + if (s.charCodeAt(i) == _padding) {
|
| + --olen;
|
| + }
|
| + }
|
| +
|
| + int iidx = 0;
|
| + int oidx = 0;
|
| + List<int> data = createIntArray(olen);
|
| + int lastStartIndex = s.length - 3;
|
| + while (iidx < lastStartIndex) {
|
| + int c0 = _base64Inverse(s.charCodeAt(iidx++));
|
| + int c1 = _base64Inverse(s.charCodeAt(iidx++));
|
| + int c2 = _base64Inverse(s.charCodeAt(iidx++));
|
| + int c3 = _base64Inverse(s.charCodeAt(iidx++));
|
| + int c24 = (c0 << 18) | (c1 << 12) | (c2 << 6) | c3;
|
| +
|
| + data[oidx++] = (c24 >> 16) & 0xff;
|
| + if (oidx == olen) {
|
| + break;
|
| + }
|
| + data[oidx++] = (c24 >> 8) & 0xff;
|
| + if (oidx == olen) {
|
| + break;
|
| + }
|
| + data[oidx++] = c24 & 0xff;
|
| + }
|
| +
|
| + return data;
|
| + }
|
| +
|
| + String decode(String s) => new String.fromCharCodes(decodeAsList(s));
|
| +
|
| + // Encode a String as a Base64 string. Only the low 8 bits of each
|
| + // character code are used.
|
| + String encodeList(List<int> x, [bool pad = true]) {
|
| + int idx = 0;
|
| + int bytesLeft = x.length;
|
| + List<int> data = new List<int>();
|
| + while (bytesLeft > 0) {
|
| + // Concatenate up to 3 input characters into a 24-bit chunk
|
| + int b0 = x[idx++] & 0xff;
|
| + int b1 = (bytesLeft > 1) ? x[idx++] & 0xff : 0;
|
| + int b2 = (bytesLeft > 2) ? x[idx++] & 0xff : 0;
|
| + int b24 = (b0 << 16) | (b1 << 8) | b2;
|
| +
|
| + // Extract 4 6-bit chunks
|
| + int c0 = (b24 >> 18) & 0x3f;
|
| + int c1 = (b24 >> 12) & 0x3f;
|
| + int c2 = (b24 >> 6) & 0x3f;
|
| + int c3 = b24 & 0x3f;
|
| +
|
| + // Ouput 4 characters, padding unused bits with "="
|
| + data.add(_base64Chars[c0]);
|
| + data.add(_base64Chars[c1]);
|
| + if (bytesLeft > 1 || pad) {
|
| + data.add(bytesLeft > 1 ? _base64Chars[c2] : _padding);
|
| + }
|
| + if (bytesLeft > 2 || pad) {
|
| + data.add(bytesLeft > 2 ? _base64Chars[c3] : _padding);
|
| + }
|
| + bytesLeft -= 3;
|
| + }
|
| + return new String.fromCharCodes(data);
|
| + }
|
| +
|
| + String encode(String s, [bool pad = true]) => encodeList(s.charCodes(), pad);
|
| +}
|
|
|