PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/runtime/PbCodec.dart

https://github.com/ucam-cl-dtg/dart-protobuf
Dart | 1152 lines | 821 code | 147 blank | 184 comment | 228 complexity | 21c6532ea36dbe532ea5981f2867ca6a MD5 | raw file
  1. // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
  2. // for details. All rights reserved. Use of this source code is governed by a
  3. // BSD-style license that can be found in the LICENSE file.
  4. part of protobuf;
  5. class _Constants {
  6. static final int MIN_SINT32 = -2147483648;
  7. static final int MAX_SINT32 = 2147483647;
  8. static final int MAX_UINT32 = 4294967295;
  9. static final int MIN_SINT64 = -9223372036854775808;
  10. static final int MAX_SINT64 = 9223372036854775807;
  11. static final int MAX_UINT64 = 18446744073709551615;
  12. static final double MIN_FLOAT_DENORM = 1.401298464324817E-45;
  13. static final double MAX_FLOAT = 3.4028234663852886E38;
  14. static final int POWER_64_INT = 18446744073709551616;
  15. static final int POWER_63_INT = 9223372036854775808;
  16. static final int POWER_32_INT = 4294967296;
  17. static final int POWER_31_INT = 2147483648;
  18. static final int POWER_25_INT = 33554432;
  19. // use literal to avoid browser issues
  20. static final int MAX_BITS_32 = 0xffffffff;
  21. static final int MAX_BITS_64 = (1 << 64) - 1;
  22. static final int MAX_BITS_8 = (1 << 8) - 1;
  23. static final int MAX_BITS_7 = (1 << 7) - 1;
  24. static final int MIN_BITS_8 = (1 << 7);
  25. static final int OCTET_BIT_COUNT = 8;
  26. static final int SEPTET_BIT_COUNT = 7;
  27. static final int BYTES_IN_32_BITS = 4;
  28. static final int BYTES_IN_64_BITS = 8;
  29. static final List<int> trueBytes = const [0x01];
  30. static final List<int> falseBytes = const [0x00];
  31. // 2^512, 2^-512
  32. static final double POWER_512 = 1.3407807929942597E154;
  33. static final double POWER_MINUS_512 = 7.458340731200207E-155;
  34. // 2^256, 2^-256
  35. static final double POWER_256 = 1.157920892373162E77;
  36. static final double POWER_MINUS_256 = 8.636168555094445E-78;
  37. // 2^128, 2^-128
  38. static final double POWER_128 = 3.4028236692093846E38;
  39. static final double POWER_MINUS_128 = 2.9387358770557188E-39;
  40. // 2^64, 2^-64
  41. static final double POWER_64 = 18446744073709551616.0;
  42. static final double POWER_MINUS_64 = 5.421010862427522E-20;
  43. // 2^52, 2^-52
  44. static final double POWER_52 = 4503599627370496.0;
  45. static final double POWER_MINUS_52 = 2.220446049250313E-16;
  46. // 2^32, 2^-32
  47. static final double POWER_32 = 4294967296.0;
  48. static final double POWER_MINUS_32 = 2.3283064365386963E-10;
  49. // 2^31
  50. static final double POWER_31 = 2147483648.0;
  51. // 2^20, 2^-20
  52. static final double POWER_20 = 1048576.0;
  53. static final double POWER_MINUS_20 = 9.5367431640625E-7;
  54. // 2^16, 2^-16
  55. static final double POWER_16 = 65536.0;
  56. static final double POWER_MINUS_16 = 0.0000152587890625;
  57. // 2^8, 2^-8
  58. static final double POWER_8 = 256.0;
  59. static final double POWER_MINUS_8 = 0.00390625;
  60. // 2^4, 2^-4
  61. static final double POWER_4 = 16.0;
  62. static final double POWER_MINUS_4 = 0.0625;
  63. // 2^2, 2^-2
  64. static final double POWER_2 = 4.0;
  65. static final double POWER_MINUS_2 = 0.25;
  66. // 2^1, 2^-1
  67. static final double POWER_1 = 2.0;
  68. static final double POWER_MINUS_1 = 0.5;
  69. // 2^-149 (smallest single non-denorm)
  70. static final double POWER_MINUS_149 = 1.401298464324817E-45;
  71. // 2^-1022 (smallest double non-denorm)
  72. static final double POWER_MINUS_1022 = 2.2250738585072014E-308;
  73. static final List<double> powers = [
  74. POWER_512, POWER_256, POWER_128, POWER_64, POWER_32, POWER_16, POWER_8,
  75. POWER_4, POWER_2, POWER_1
  76. ];
  77. static final List<double> invPowers = [
  78. POWER_MINUS_512, POWER_MINUS_256, POWER_MINUS_128, POWER_MINUS_64,
  79. POWER_MINUS_32, POWER_MINUS_16, POWER_MINUS_8, POWER_MINUS_4, POWER_MINUS_2,
  80. POWER_MINUS_1
  81. ];
  82. }
  83. /**
  84. * An unsigned 64-bit number, stored internally as two unsigned 32-bit numbers.
  85. */
  86. class Packed64 {
  87. int64 _packed;
  88. // Determine whether the platform supports ints greater than 2^53
  89. // without loss of precision.
  90. static bool _haveBigIntsCached = null;
  91. static bool get _haveBigInts {
  92. if (_haveBigIntsCached == null) {
  93. int x = 9007199254740992;
  94. // Defeat compile-time constant folding.
  95. if (2 + 2 != 4) {
  96. x = 0;
  97. }
  98. int y = x + 1;
  99. bool same = y == x;
  100. _haveBigIntsCached = !same;
  101. }
  102. return _haveBigIntsCached;
  103. }
  104. static final bool _allowSoftInts = true;
  105. bool get _softInts =>
  106. (null != _haveBigIntsCached && _haveBigIntsCached) ||
  107. (null != _allowSoftInts && _allowSoftInts);
  108. /**
  109. * Constructs a [Packed64] instance with given high and low 32-bit words.
  110. * Throws [:ArgumentError:] if either the [lo] or [hi] int is
  111. * outside the range of a signed 32-bit INT.
  112. */
  113. Packed64(int hi, int lo) {
  114. if (hi < -_Constants.POWER_32_INT || hi >= _Constants.POWER_32_INT) {
  115. throw new ArgumentError("Hi value out of range: $hi");
  116. }
  117. if (lo < -_Constants.POWER_32_INT || lo >= _Constants.POWER_32_INT) {
  118. throw new ArgumentError("Lo value out of range: $lo");
  119. }
  120. _packed = new int64.fromInts(hi, lo);
  121. }
  122. /**
  123. * Constructs a [Packed64] instance from a list of byte values, LSB first.
  124. */
  125. Packed64.fromBytes(List<int> b) {
  126. _packed = new int64.fromBytes(b);
  127. }
  128. /**
  129. * Constructs a [Packed64] instance that will have the bit pattern of the
  130. * given [double] value. All [:NaN:] values are converted to a canonical
  131. * bit pattern.
  132. */
  133. factory Packed64.fromDouble(double d) {
  134. if (d.isNaN) {
  135. return new Packed64(0x7ff80000, 0x0);
  136. }
  137. bool negative = false;
  138. if (d.isNegative) {
  139. negative = true;
  140. d = -d;
  141. }
  142. if (d == 0.0) {
  143. if (negative) {
  144. return new Packed64(_Constants.POWER_31_INT, 0x0);
  145. } else {
  146. return new Packed64(0x0, 0x0);
  147. }
  148. }
  149. if (d.isInfinite) {
  150. if (negative) {
  151. return new Packed64(0xfff00000, 0x0);
  152. } else {
  153. return new Packed64(0x7ff00000, 0x0);
  154. }
  155. }
  156. int exp = 0;
  157. // Scale d by powers of 2 into the range [1.0, 2.0)
  158. // If the exponent would go below -1023, scale into (0.0, 1.0) instead
  159. if (d < 1.0) {
  160. int bit = 512;
  161. for (int i = 0; i < 10; i++, bit >>= 1) {
  162. if (d < _Constants.invPowers[i] && exp - bit >= -1023) {
  163. d *= _Constants.powers[i];
  164. exp -= bit;
  165. }
  166. }
  167. // Force into [1.0, 2.0) range
  168. if (d < 1.0 && exp - 1 >= -1023) {
  169. d *= 2.0;
  170. exp--;
  171. }
  172. } else if (d >= 2.0) {
  173. int bit = 512;
  174. for (int i = 0; i < 10; i++, bit >>= 1) {
  175. if (d >= _Constants.powers[i]) {
  176. d *= _Constants.invPowers[i];
  177. exp += bit;
  178. }
  179. }
  180. }
  181. if (exp > -1023) {
  182. // Remove significand of non-denormalized mantissa
  183. d -= 1.0;
  184. } else {
  185. // Insert 0 bit as significand of denormalized mantissa
  186. d *= 0.5;
  187. }
  188. // Extract high 20 bits of mantissa
  189. int ihi = (d * _Constants.POWER_20).toInt();
  190. // Extract low 32 bits of mantissa
  191. d -= ihi * _Constants.POWER_MINUS_20;
  192. int ilo = (d * _Constants.POWER_52).toInt();
  193. // Exponent bits
  194. ihi |= (exp + 1023) << 20;
  195. // Sign bit
  196. if (negative) {
  197. ihi += _Constants.POWER_31_INT;
  198. }
  199. return new Packed64(ihi, ilo);
  200. }
  201. void _orShifted(int bits, int shift) {
  202. _packed |= new int64.fromInt(bits) << shift;
  203. }
  204. /**
  205. * Constructs a [Packed64] instance from a variable-length representation.
  206. * Throws an [:ArgumentError:] if the encoding is invalid.
  207. */
  208. Packed64.fromVarintBytes(List<int> b) {
  209. try {
  210. _packed = int64.ZERO;
  211. int i = 0;
  212. bool lastByte = ((b[i] & _Constants.MIN_BITS_8) == 0);
  213. while (i < 10 && !lastByte) {
  214. _orShifted(b[i] & _Constants.MAX_BITS_7,
  215. _Constants.SEPTET_BIT_COUNT * i);
  216. i++;
  217. lastByte = (b[i] & _Constants.MIN_BITS_8) == 0;
  218. }
  219. _orShifted(b[i] & _Constants.MAX_BITS_7,
  220. _Constants.SEPTET_BIT_COUNT * i);
  221. } on RangeError catch (e) {
  222. throw new ArgumentError("Invalid Encoding");
  223. }
  224. }
  225. /**
  226. * Constructs a [Packed64] instance whose value is equivalent to the given
  227. * value. Throws an [:ArgumentError:] if the value is &lt;
  228. * -9223372036854775808 (MIN_SINT64) or &gt; 18446744073709551615
  229. * (MAZ_UINT64).
  230. */
  231. Packed64.fromInt(int x) {
  232. if (x < -9223372036854775808 || x > 18446744073709551615) {
  233. throw new ArgumentError("Out of range: $x");
  234. }
  235. _packed = new int64.fromInt(x);
  236. }
  237. /**
  238. * Compares this [Packed64] with a given [Packed64] or [int] value.
  239. */
  240. bool operator ==(var other) {
  241. if (other is num) {
  242. return this.toInt() == new Packed64.fromInt(other);
  243. }
  244. if (other is !Packed64) {
  245. return false;
  246. }
  247. return other._packed == _packed;
  248. }
  249. int get hashCode {
  250. return _packed.hashCode;
  251. }
  252. /**
  253. * Returns the 32 high bits of this [Packed64] value as an unsigned integer
  254. * in the range [0, 2^31 - 1].
  255. */
  256. int get hi => ((_packed >> 32) & 0xffffffff).toInt();
  257. /**
  258. * Returns the 32 low bits of this [Packed64] value as an unsigned integer
  259. * in the range [0, 2^31 - 1].
  260. */
  261. int get lo => (_packed & 0xffffffff).toInt();
  262. /**
  263. * Decodes this [Packed64] from the zig-zag representation
  264. * [:(n << 1) ^ (n >> 63):].
  265. */
  266. Packed64 decodeZigZag() {
  267. int ihi = this.hi;
  268. int ilo = this.lo;
  269. int sign = ilo % 2;
  270. ilo = ((ihi % 2 == 1) ? _Constants.POWER_31_INT : 0) + (ilo ~/ 2);
  271. ihi = ihi ~/ 2;
  272. if (sign == 1) {
  273. ihi = _bitFlip(ihi);
  274. ilo = _bitFlip(ilo);
  275. }
  276. Packed64 result = new Packed64(ihi, ilo);
  277. return result;
  278. }
  279. static int _bitFlip(int x) => _Constants.MAX_BITS_32 - x;
  280. /**
  281. * Encodes this [Packed64] in the zig-zag representation
  282. * [:(n << 1) ^ (n >> 63):].
  283. */
  284. Packed64 encodeZigZag() {
  285. int ihi = hi;
  286. int ilo = lo;
  287. bool negative = ihi >= _Constants.POWER_31_INT;
  288. ihi = ihi * 2 + (ilo >= _Constants.POWER_31_INT ? 1 : 0);
  289. ilo = ilo * 2;
  290. if (ihi >= _Constants.POWER_32_INT) {
  291. ihi -= _Constants.POWER_32_INT;
  292. }
  293. if (ilo >= _Constants.POWER_32_INT) {
  294. ilo -= _Constants.POWER_32_INT;
  295. }
  296. if (negative) {
  297. ihi = _bitFlip(ihi);
  298. ilo = _bitFlip(ilo);
  299. }
  300. return new Packed64(ihi, ilo);
  301. }
  302. /**
  303. * Returns [true] if this [Packed64] can safely be converted to a signed
  304. * integer in the range [-2^51, 2^51 - 1].
  305. */
  306. bool isSafeAsInt() {
  307. if (_haveBigInts) {
  308. return true;
  309. } else {
  310. int top = (hi >> 20) & 0xfff;
  311. return top == 0x0 || top == 0xfff;
  312. }
  313. }
  314. /**
  315. * Returns [true] if this [Packed64] can safely be converted to an unsigned
  316. * integer in the range [0, 2^52 - 1].
  317. */
  318. bool isSafeAsUint() {
  319. if (_haveBigInts) {
  320. return true;
  321. } else {
  322. int top = (hi >> 20) & 0xfff;
  323. return top == 0x0;
  324. }
  325. }
  326. /**
  327. * Return the number of bytes required to encdode this [Packed64] using
  328. * the variable-length representation.
  329. */
  330. int sizeOfVarint() {
  331. int ihi = this.hi;
  332. int ilo = this.lo;
  333. int i = 0;
  334. while (i < 10) {
  335. ilo = ((ihi % 128) * _Constants.POWER_25_INT) + (ilo ~/ 128);
  336. ihi ~/= 128;
  337. i++;
  338. if (ihi == 0 && ilo == 0) {
  339. return i;
  340. }
  341. }
  342. return i;
  343. }
  344. /**
  345. * Return this [Packed64] as a list of 8 ints, LSB first.
  346. */
  347. List<int> toBytes() => _packed.toBytes();
  348. /**
  349. * Return this [Packed64] interpreted as an IEEE double-precision value.
  350. */
  351. double toDouble() {
  352. int ihi = this.hi;
  353. int ilo = this.lo;
  354. if (ihi < 0) {
  355. ihi += _Constants.POWER_32_INT;
  356. }
  357. if (ilo < 0) {
  358. ilo += _Constants.POWER_32_INT;
  359. }
  360. bool negative = (ihi & _Constants.POWER_31_INT) != 0;
  361. int exp = (ihi >> 20) & 0x7ff;
  362. ihi &= 0xfffff; // remove sign bit and exponent
  363. if (exp == 0x0) {
  364. double d = (ihi * _Constants.POWER_MINUS_20) +
  365. (ilo * _Constants.POWER_MINUS_52);
  366. d *= _Constants.POWER_MINUS_1022;
  367. return negative ? (d == 0.0 ? -0.0 : -d) : d;
  368. } else if (exp == 0x7ff) {
  369. if (ihi == 0 && ilo == 0) {
  370. return negative ? double.NEGATIVE_INFINITY : double.INFINITY;
  371. } else {
  372. return double.NAN;
  373. }
  374. }
  375. // Normalize exponent
  376. exp -= 1023;
  377. double d = 1.0 + (ihi * _Constants.POWER_MINUS_20) +
  378. (ilo * _Constants.POWER_MINUS_52);
  379. if (exp > 0) {
  380. int bit = 512;
  381. for (int i = 0; i < 10; i++, bit >>= 1) {
  382. if (exp >= bit) {
  383. d *= _Constants.powers[i];
  384. exp -= bit;
  385. }
  386. }
  387. } else if (exp < 0) {
  388. while (exp < 0) {
  389. int bit = 512;
  390. for (int i = 0; i < 10; i++, bit >>= 1) {
  391. if (exp <= -bit) {
  392. d *= _Constants.invPowers[i];
  393. exp += bit;
  394. }
  395. }
  396. }
  397. }
  398. return negative ? -d : d;
  399. }
  400. /**
  401. * Return the value of this [Packed64] as an int if the resulting value
  402. * is in the legal range of [-2^51, 2^51 -1], otherwise throw an
  403. * ArgumentError.
  404. */
  405. int toInt() => _packed.toInt();
  406. /**
  407. * Return the value of this [Packed64] as an int if the resulting value
  408. * is in the legal range of [-2^51, 2^51 -1], otherwise return [this].
  409. */
  410. toIntIfSafe() {
  411. if (_softInts && this.isSafeAsInt()) {
  412. return this.toInt();
  413. }
  414. return this;
  415. }
  416. /**
  417. * Return the value of this [Packed64] as an int if the resulting value
  418. * is in the legal range of [0, 2^52 -1], otherwise throw an
  419. * ArgumentError.
  420. */
  421. int toUint() {
  422. if (!isSafeAsUint()) {
  423. throw new ArgumentError("Out of range");
  424. }
  425. int value = this.hi * _Constants.POWER_32_INT + this.lo;
  426. return value;
  427. }
  428. /**
  429. * Return the value of this [Packed64] as an int if the resulting value
  430. * is in the legal range of [0, 2^52 -1], otherwise return [this].
  431. */
  432. toUintIfSafe() {
  433. if (_softInts && this.isSafeAsUint()) {
  434. return this.toUint();
  435. }
  436. return this;
  437. }
  438. /**
  439. * Return a list of up to 10 ints encoding this [Packed64] using a
  440. * variable-length representation.
  441. */
  442. List<int> toVarintBytes() {
  443. int ihi = this.hi;
  444. int ilo = this.lo;
  445. List<int> b = [];
  446. int i = 0;
  447. while (true) {
  448. i++;
  449. if ((ihi != 0 || ilo >= 128) && i < 10) {
  450. int v = 128 + (ilo % 128);
  451. b.add(v);
  452. } else {
  453. int v = ilo % 128;
  454. b.add(v);
  455. break;
  456. }
  457. ilo = ((ihi % 128) * 33554432) + (ilo ~/ 128);
  458. ihi ~/= 128;
  459. }
  460. return b;
  461. }
  462. /**
  463. * Return a String useful for debugging.
  464. */
  465. String toDebugString() {
  466. return "Packed64[0x${hi.toRadixString(16)},0x${lo.toRadixString(16)}]";
  467. }
  468. /**
  469. * Return a String in decimal representation.
  470. */
  471. String toString() {
  472. return _packed.toString();
  473. }
  474. }
  475. /*
  476. * Provides conversion utilities from dart types to/from protocol buffer wire
  477. * format.
  478. */
  479. class PbCodec {
  480. static bool toBool(List<int> b) => b[0] != 0;
  481. static int toFixed32(List<int> b) => packedToUint32(bytesToPacked(b));
  482. // return value may be an int or a Packed64
  483. static toFixed64(List<int> b) => int64ToUint64(bytesToPacked64(b));
  484. static int toInt32(List<int> b) => packedToInt32(varintBytesToPacked(b));
  485. // return value may be an int or a Packed64
  486. static toInt64(List<int> b) =>
  487. int64ToSigned(varintBytesToPacked64(b));
  488. static int toSfixed32(List<int> b) => packedToInt32(bytesToPacked(b));
  489. // return value may be an int or a Packed64
  490. static toSfixed64(List<int> b) => bytesToPacked64(b);
  491. static int toSint32(List<int> b) => packedToSint32(varintBytesToPacked(b));
  492. // return value may be an int or a Packed64
  493. static toSint64(List<int> b) =>
  494. int64ToSint64(varintBytesToPacked64(b));
  495. static int toUint32(List<int> b) => packedToUint32(varintBytesToPacked(b));
  496. // return value may be an int or a Packed64
  497. static toUint64(List<int> b) =>
  498. int64ToUint64(varintBytesToPacked64(b));
  499. static double toFloat(List<int> b) => packedToFloat(bytesToPacked(b));
  500. static double toDouble(List<int> b) => int64ToDouble(bytesToPacked64(b));
  501. static List<int> boolToBytes(bool value) =>
  502. value ? _Constants.trueBytes : _Constants.falseBytes;
  503. static List<int> fixed32ToBytes(int value) =>
  504. packed32ToBytes(uint32ToPacked(value));
  505. // value may be an int or a Packed64
  506. static List<int> fixed64ToBytes(var value) => packed64ToBytes(value);
  507. static List<int> int32ToBytes(int value) =>
  508. packedToVarintBytes(int32ToPacked(value));
  509. // value may be an int or a Packed64
  510. static List<int> int64ToBytes(var value) =>
  511. int64ToVarintBytes(value);
  512. static List<int> sfixed32ToBytes(int value) =>
  513. packed32ToBytes(int32ToPacked(value));
  514. // value may be an int or a Packed64
  515. static List<int> sfixed64ToBytes(var value) =>
  516. packed64ToBytes(value);
  517. static List<int> sint32ToBytes(int value) =>
  518. packedToVarintBytes(sint32ToPacked(value));
  519. // value may be an int or a Packed64
  520. static List<int> sint64ToBytes(var value) =>
  521. int64ToVarintBytes(sint64ToPacked64(value));
  522. static List<int> uint32ToBytes(int value) =>
  523. packedToVarintBytes(uint32ToPacked(value));
  524. // value may be an int or a Packed64
  525. static List<int> uint64ToBytes(var value) =>
  526. int64ToVarintBytes(uint64ToPacked64(value));
  527. static List<int> floatToBytes(double value) =>
  528. packed32ToBytes(floatToPacked(value));
  529. static List<int> doubleToBytes(double value) =>
  530. packed64ToBytes(doubleToPacked64(value));
  531. static final int sizeOfBool = 1;
  532. static int sizeOfFixed32 = _Constants.BYTES_IN_32_BITS;
  533. static int sizeOfFixed64 = _Constants.BYTES_IN_64_BITS;
  534. static int sizeOfSfixed32 = _Constants.BYTES_IN_32_BITS;
  535. static int sizeOfSfixed64 = _Constants.BYTES_IN_64_BITS;
  536. static int sizeOfInt32(int value) => value < 0 ? 5 : sizeOfVarint(value);
  537. // value may be an int or a Packed64
  538. static int sizeOfInt64(var value) {
  539. if (value is Packed64) {
  540. return value.sizeOfVarint();
  541. } else if (value is num) {
  542. if (value < 0) {
  543. return 10;
  544. } else {
  545. return sizeOfVarint64(new Packed64.fromInt(value.toInt()));
  546. }
  547. } else {
  548. throw new ArgumentError("Expected Packed64 or int");
  549. }
  550. }
  551. static int sizeOfSint32(int value) => sizeOfVarint(encodeZigZag32(value));
  552. // value may be an int or a Packed64
  553. static int sizeOfSint64(var value) => sizeOfVarint64(encodeZigZag64(value));
  554. static int sizeOfUint32(int value) => sizeOfVarint(value);
  555. // value may be an int or a Packed64
  556. static int sizeOfUint64(var value) => sizeOfVarint64(value);
  557. static int sizeOfVarint(int value) {
  558. int i = 0;
  559. while (i < 10) {
  560. value >>= _Constants.SEPTET_BIT_COUNT;
  561. i++;
  562. if (value == 0) return i;
  563. }
  564. return i;
  565. }
  566. // value may be an int or a Packed64
  567. static int sizeOfVarint64(var value) {
  568. if (value is Packed64) {
  569. return value.sizeOfVarint();
  570. } else if (value is num) {
  571. return new Packed64.fromInt(value.toInt()).sizeOfVarint();
  572. } else {
  573. throw new ArgumentError("Expected Packed64 or int");
  574. }
  575. }
  576. static int int32ToPacked(int value) {
  577. if (value < 0) {
  578. return _Constants.POWER_32_INT + value;
  579. }
  580. return value;
  581. }
  582. static int sint32ToPacked(int value) => encodeZigZag32(value);
  583. // value and return may be an int or a Packed64
  584. static sint64ToPacked64(var value) => encodeZigZag64(value);
  585. static int uint32ToPacked(int value) => value;
  586. // value and return may be an int or a Packed64
  587. static uint64ToPacked64(var value) => value;
  588. static int packedToInt32(int packed) {
  589. if (packed >= _Constants.POWER_32_INT) {
  590. packed &= _Constants.MAX_BITS_32;
  591. }
  592. if (packed < 0 || ((packed & _Constants.POWER_31_INT) == 0)) {
  593. return packed;
  594. } else {
  595. return packed - _Constants.POWER_32_INT;
  596. }
  597. }
  598. static int packedToSint32(int packed) => decodeZigZag32(packed);
  599. static int packedToUint32(int packed) => packed;
  600. // value and return may be an int or a Packed64
  601. static int64ToSint64(var packed) => decodeZigZag64(packed);
  602. // value and return may be an int or a Packed64
  603. static int64ToUint64(var packed) {
  604. if (packed is Packed64) {
  605. return packed;
  606. } else if (packed < 0) {
  607. return _Constants.POWER_64_INT + packed;
  608. } else {
  609. return packed;
  610. }
  611. }
  612. // value and return may be an int or a Packed64
  613. static int64ToSigned(var packed) {
  614. if (packed is Packed64) {
  615. return packed;
  616. } else if (packed >= _Constants.POWER_63_INT) {
  617. return packed - _Constants.POWER_64_INT;
  618. } else {
  619. return packed;
  620. }
  621. }
  622. static int bytesToPacked(List<int> b) {
  623. int result = 0;
  624. int factor = 1;
  625. for (int i = 0; i < b.length && i < _Constants.BYTES_IN_64_BITS;
  626. i++, factor *= 256) {
  627. result += (b[i] & _Constants.MAX_BITS_8) * factor;
  628. }
  629. return result;
  630. }
  631. static bytesToPacked64(List<int> b) =>
  632. new Packed64.fromBytes(b).toIntIfSafe();
  633. static int _unsigned(int x) => x < 0 ? x + _Constants.POWER_32_INT : x;
  634. static int varintBytesToPacked(List<int> b) {
  635. try {
  636. int result = 0;
  637. int i = 0;
  638. bool lastByte = ((b[i] & _Constants.MIN_BITS_8) == 0);
  639. while (i < 10 && !lastByte) {
  640. result |= (((b[i] & _Constants.MAX_BITS_7) <<
  641. (_Constants.SEPTET_BIT_COUNT * i)));
  642. i++;
  643. lastByte = (b[i] & _Constants.MIN_BITS_8) == 0;
  644. }
  645. result |= (b[i] & _Constants.MAX_BITS_7) <<
  646. (_Constants.SEPTET_BIT_COUNT * i);
  647. return _unsigned(result);
  648. } on RangeError catch ( e) {
  649. throw new ArgumentError("Invalid Encoding");
  650. }
  651. }
  652. static varintBytesToPacked64(List<int> b) =>
  653. new Packed64.fromVarintBytes(b).toUintIfSafe();
  654. static List<int> packed32ToBytes(int value) {
  655. List<int> b = new List(4);
  656. for (int i = 0; i < 4; i++) {
  657. if (value == 0) {
  658. while (i < 4) {
  659. b[i] = 0;
  660. i++;
  661. }
  662. } else {
  663. b[i] = value & _Constants.MAX_BITS_8;
  664. value >>= _Constants.OCTET_BIT_COUNT;
  665. }
  666. }
  667. return b;
  668. }
  669. // value may be an int or a Packed64
  670. static List<int> packed64ToBytes(var value) {
  671. if (value is Packed64) {
  672. return value.toBytes();
  673. } else if (value is num) {
  674. return new Packed64.fromInt(value.toInt()).toBytes();
  675. } else {
  676. throw new ArgumentError("Expected Packed64 or int");
  677. }
  678. }
  679. static List<int> packedToVarintBytes(int value) {
  680. List<int> b = [];
  681. int i = 0;
  682. while (true) {
  683. i++;
  684. int nextVal = value ~/ 128;
  685. if (nextVal != 0 && i < 10) {
  686. int v = 128 + (value % 128);
  687. b.add(v);
  688. } else {
  689. int v = value % 128;
  690. b.add(v);
  691. break;
  692. }
  693. value = nextVal;
  694. }
  695. return b;
  696. }
  697. static List<int> int64ToVarintBytes(var value) {
  698. if (value is Packed64) {
  699. return value.toVarintBytes();
  700. } else if (value is num) {
  701. return new Packed64.fromInt(value.toInt()).toVarintBytes();
  702. } else {
  703. throw new ArgumentError("Expected Packed64 or int");
  704. }
  705. }
  706. static int encodeZigZag32(int value) {
  707. if (value < 0) {
  708. return -(value * 2) - 1;
  709. } else {
  710. return value * 2;
  711. }
  712. }
  713. // value and return may be an int or a Packed64
  714. static encodeZigZag64(var value) {
  715. if (value is Packed64) {
  716. return value.encodeZigZag().toUintIfSafe();
  717. } else if (value is num) {
  718. return new Packed64.fromInt(value.toInt()).encodeZigZag().toUint();
  719. } else {
  720. throw new ArgumentError("Expected Packed64 or int");
  721. }
  722. }
  723. static int decodeZigZag32(int value) {
  724. if ((value & 0x1) == 0) {
  725. return value ~/ 2;
  726. } else {
  727. value = (value - 1) ~/ 2;
  728. if (value < _Constants.POWER_32_INT) {
  729. return -value - 1;
  730. } else {
  731. return value;
  732. }
  733. }
  734. }
  735. // value and return may be an int or a Packed64
  736. static decodeZigZag64(var value) {
  737. if (value is Packed64) {
  738. return value.decodeZigZag().toIntIfSafe();
  739. } else if (value is num) {
  740. return new Packed64.fromInt(value.toInt()).decodeZigZag().toIntIfSafe();
  741. } else {
  742. throw new ArgumentError("Expected Packed64 or int");
  743. }
  744. }
  745. // value may be an int or a Packed64
  746. static double int64ToDouble(var value) {
  747. if (value is Packed64) {
  748. return value.toDouble();
  749. } else if (value is num) {
  750. return new Packed64.fromInt(value.toInt()).toDouble();
  751. } else {
  752. throw new ArgumentError("Expected Packed64 or int");
  753. }
  754. }
  755. static double packedToFloat(int packed) {
  756. bool negative = (packed & _Constants.POWER_31_INT) != 0;
  757. int exp = (packed >> 23) & 0xff;
  758. packed &= 0x7fffff;
  759. if (exp == 0x0) {
  760. // Handle +/- 0 here, denorms below
  761. if (packed == 0) {
  762. return negative ? -0.0 : 0.0;
  763. }
  764. } else if (exp == 0xff) {
  765. // Inf & NaN
  766. if (packed == 0) {
  767. return negative ? double.NEGATIVE_INFINITY : double.INFINITY;
  768. } else {
  769. return double.NAN;
  770. }
  771. }
  772. // Build the bits of a 64-bit double from the incoming bits
  773. int ihi = negative ? _Constants.POWER_31_INT : 0x0;
  774. int ilo = 0x0;
  775. if (exp == 0) {
  776. // Input is denormalized, renormalize by shifting left until there is a
  777. // leading 1
  778. exp = 897;
  779. while ((packed & 0x800000) == 0) {
  780. packed <<= 1;
  781. exp--;
  782. }
  783. packed &= 0x7fffff;
  784. ihi |= exp << 20;
  785. ihi |= packed >> 3;
  786. ilo = (packed & 0x7) << 29;
  787. } else {
  788. // Normalized number, rebias exponent and shift mantissa into place
  789. ihi |= (exp + 896) << 20;
  790. ihi |= packed >> 3;
  791. ilo = (packed & 0x7) << 29;
  792. }
  793. return int64ToDouble(new Packed64(ihi, ilo));
  794. }
  795. /**
  796. * Return the 32-bit IEEE single-precision representation that represents
  797. * the value [d] truncated to 23 fractional bits.
  798. */
  799. static int floatToPacked(double d) {
  800. // Return a canonical NaN since we have no way to detect anything else
  801. if (d.isNaN) {
  802. return 0x7fc00000;
  803. }
  804. bool negative = false;
  805. if (d.isNegative) {
  806. negative = true;
  807. d = -d;
  808. }
  809. // Numbers below min float map to 0.0
  810. if (d < _Constants.MIN_FLOAT_DENORM) {
  811. return negative ? _Constants.POWER_31_INT : 0x0;
  812. }
  813. // Numbers above max float map to Infinity
  814. if (d.isInfinite || d > _Constants.MAX_FLOAT) {
  815. return negative ? 0xff800000 : 0x7f800000;
  816. }
  817. // Obtain the 64-bit representation and extract its exponent and
  818. // mantissa.
  819. var packed = doubleToPacked64(d);
  820. int exp, mantissa;
  821. if (packed is Packed64) {
  822. Packed64 packed64 = packed;
  823. exp = ((packed64.hi >> 20) & 0x7ff) - 1023;
  824. mantissa = ((packed64.hi & 0xfffff) << 3) | ((packed64.lo >> 29) & 0x7);
  825. } else if (packed is num) {
  826. int ipacked = packed.toInt();
  827. exp = ((ipacked >> 52) & 0x7ff) - 1023;
  828. mantissa = (ipacked & 0xfffffffffffff) >> 29;
  829. }
  830. // If the number will be a denorm in the float representation
  831. // (i.e., its exponent is -127 or smaller), add a leading 1 to the
  832. // mantissa and shift it right to maintain an exponent of -127.
  833. if (exp <= -127) {
  834. mantissa = (0x800000 | mantissa) >> (-127 - exp + 1);
  835. exp = -127;
  836. }
  837. // Construct the 32-bit representation
  838. int packed32 = negative ? _Constants.POWER_31_INT : 0x0;
  839. packed32 |= (exp + 127) << 23;
  840. packed32 |= mantissa;
  841. if (packed32 < 0) {
  842. packed32 += _Constants.POWER_32_INT;
  843. }
  844. return packed32;
  845. }
  846. static doubleToPacked64(double d) {
  847. Packed64 packed = new Packed64.fromDouble(d);
  848. if (packed.isSafeAsUint()) {
  849. return packed.toUint();
  850. }
  851. return packed;
  852. }
  853. // JSON
  854. // ('0' + x) or ('a' + x - 10)
  855. static int _hexDigit(int x) => x < 10 ? 48 + x : 87 + x;
  856. // Escape a string to be suitable as a JSON value
  857. static String escapeString(String x) {
  858. List<int> chars = x.charCodes;
  859. List<int> output = new List<int>();
  860. for (int i = 0; i < chars.length; i++) {
  861. int c = chars[i];
  862. // Escape control characters, double-quote, and backslash
  863. if (c < 32) { // control characters
  864. output.add(92); // '\'
  865. switch (c) {
  866. case 8: // backspace
  867. output.add(98); // 'b'
  868. break;
  869. case 9: // tab
  870. output.add(116); // 't'
  871. break;
  872. case 10: // newline
  873. output.add(110); // 'n'
  874. break;
  875. case 12: // formfeed
  876. output.add(102); // 'f'
  877. break;
  878. case 13: // carriage return
  879. output.add(114); // 'r'
  880. break;
  881. default:
  882. output.add(117); // 'u'
  883. output.add(_hexDigit((c >> 12) & 0xf));
  884. output.add(_hexDigit((c >> 8) & 0xf));
  885. output.add(_hexDigit((c >> 4) & 0xf));
  886. output.add(_hexDigit(c & 0xf));
  887. break;
  888. }
  889. } else if (c == 34 || c == 92) { // double-quote or backslash
  890. output.add(92); // '\'
  891. output.add(c);
  892. } else {
  893. output.add(c);
  894. }
  895. }
  896. return new String.fromCharCodes(output);
  897. }
  898. }
  899. // TODO - make this a separate library
  900. class Base64Codec {
  901. // MIME Base64 characters plus padding char '=' (RFC 2045)
  902. static final String MIME_ALPHABET =
  903. "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  904. static Base64Codec _defaultInstance = null;
  905. static Base64Codec get defaultInstance {
  906. if (_defaultInstance == null) {
  907. _defaultInstance = new Base64Codec();
  908. }
  909. return _defaultInstance;
  910. }
  911. List<int> _base64Chars = null;
  912. List<int> _base64InverseChars = null;
  913. int _padding;
  914. Base64Codec({String alphabet: null}) {
  915. assert(alphabet == null || alphabet.length == 65);
  916. if (alphabet == null) {
  917. alphabet = MIME_ALPHABET;
  918. }
  919. _initTables(alphabet);
  920. }
  921. void _initTables(String alphabet) {
  922. _base64Chars = alphabet.charCodes;
  923. _base64InverseChars = new List<int>(128);
  924. // Use -1 to indicate an illegal character
  925. for (int i = 0; i < 128; i++) {
  926. _base64InverseChars[i] = -1;
  927. }
  928. for (int i = 0; i < 64; i++) {
  929. _base64InverseChars[_base64Chars[i]] = i;
  930. }
  931. // The padding character is interpreted as 0
  932. _padding = alphabet.charCodeAt(64);
  933. _base64InverseChars[_padding] = 0;
  934. }
  935. int _base64Inverse(int x) {
  936. // Look at 7 low bits only
  937. int result = _base64InverseChars[x & 0x7f];
  938. if (result == -1) {
  939. throw new ArgumentError("Unknown character code: ${x & 0x7f}");
  940. }
  941. return result;
  942. }
  943. List<int> decodeAsList(String s) {
  944. int olen = 3 * (s.length ~/ 4);
  945. // Inspect the last two characters of the input for padding
  946. for (int i = Math.max(0, s.length - 2); i < s.length; i++) {
  947. if (s.charCodeAt(i) == _padding) {
  948. --olen;
  949. }
  950. }
  951. int iidx = 0;
  952. int oidx = 0;
  953. List<int> data = createIntArray(olen);
  954. int lastStartIndex = s.length - 3;
  955. while (iidx < lastStartIndex) {
  956. int c0 = _base64Inverse(s.charCodeAt(iidx++));
  957. int c1 = _base64Inverse(s.charCodeAt(iidx++));
  958. int c2 = _base64Inverse(s.charCodeAt(iidx++));
  959. int c3 = _base64Inverse(s.charCodeAt(iidx++));
  960. int c24 = (c0 << 18) | (c1 << 12) | (c2 << 6) | c3;
  961. data[oidx++] = (c24 >> 16) & 0xff;
  962. if (oidx == olen) {
  963. break;
  964. }
  965. data[oidx++] = (c24 >> 8) & 0xff;
  966. if (oidx == olen) {
  967. break;
  968. }
  969. data[oidx++] = c24 & 0xff;
  970. }
  971. return data;
  972. }
  973. String decode(String s) => new String.fromCharCodes(decodeAsList(s));
  974. // Encode a String as a Base64 string. Only the low 8 bits of each
  975. // character code are used.
  976. String encodeList(List<int> x, [bool pad = true]) {
  977. int idx = 0;
  978. int bytesLeft = x.length;
  979. List<int> data = new List<int>();
  980. while (bytesLeft > 0) {
  981. // Concatenate up to 3 input characters into a 24-bit chunk
  982. int b0 = x[idx++] & 0xff;
  983. int b1 = (bytesLeft > 1) ? x[idx++] & 0xff : 0;
  984. int b2 = (bytesLeft > 2) ? x[idx++] & 0xff : 0;
  985. int b24 = (b0 << 16) | (b1 << 8) | b2;
  986. // Extract 4 6-bit chunks
  987. int c0 = (b24 >> 18) & 0x3f;
  988. int c1 = (b24 >> 12) & 0x3f;
  989. int c2 = (b24 >> 6) & 0x3f;
  990. int c3 = b24 & 0x3f;
  991. // Ouput 4 characters, padding unused bits with "="
  992. data.add(_base64Chars[c0]);
  993. data.add(_base64Chars[c1]);
  994. if (bytesLeft > 1 || pad) {
  995. data.add(bytesLeft > 1 ? _base64Chars[c2] : _padding);
  996. }
  997. if (bytesLeft > 2 || pad) {
  998. data.add(bytesLeft > 2 ? _base64Chars[c3] : _padding);
  999. }
  1000. bytesLeft -= 3;
  1001. }
  1002. return new String.fromCharCodes(data);
  1003. }
  1004. String encode(String s, [bool pad = true]) => encodeList(s.charCodes, pad);
  1005. }