Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(98)

Side by Side Diff: lib/protobuf/runtime/PbCodec.dart

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

Powered by Google App Engine
This is Rietveld 408576698