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

Side by Side Diff: sdk/lib/convert/base64.dart

Issue 2754013002: Format all dart: library files (Closed)
Patch Set: Created 3 years, 9 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
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 part of dart.convert; 5 part of dart.convert;
6 6
7 /** 7 /**
8 * A [base64](https://tools.ietf.org/html/rfc4648) encoder and decoder. 8 * A [base64](https://tools.ietf.org/html/rfc4648) encoder and decoder.
9 * 9 *
10 * It encodes using the default base64 alphabet, 10 * It encodes using the default base64 alphabet,
(...skipping 17 matching lines...) Expand all
28 * 28 *
29 * Examples: 29 * Examples:
30 * 30 *
31 * var encoded = BASE64URL.encode([0x62, 0x6c, 0xc3, 0xa5, 0x62, 0xc3, 0xa6, 31 * var encoded = BASE64URL.encode([0x62, 0x6c, 0xc3, 0xa5, 0x62, 0xc3, 0xa6,
32 * 0x72, 0x67, 0x72, 0xc3, 0xb8, 0x64]); 32 * 0x72, 0x67, 0x72, 0xc3, 0xb8, 0x64]);
33 * var decoded = BASE64URL.decode("YmzDpWLDpnJncsO4ZAo="); 33 * var decoded = BASE64URL.decode("YmzDpWLDpnJncsO4ZAo=");
34 */ 34 */
35 const Base64Codec BASE64URL = const Base64Codec.urlSafe(); 35 const Base64Codec BASE64URL = const Base64Codec.urlSafe();
36 36
37 // Constants used in more than one class. 37 // Constants used in more than one class.
38 const int _paddingChar = 0x3d; // '='. 38 const int _paddingChar = 0x3d; // '='.
39 39
40 /** 40 /**
41 * A [base64](https://tools.ietf.org/html/rfc4648) encoder and decoder. 41 * A [base64](https://tools.ietf.org/html/rfc4648) encoder and decoder.
42 * 42 *
43 * A [Base64Codec] allows base64 encoding bytes into ASCII strings and 43 * A [Base64Codec] allows base64 encoding bytes into ASCII strings and
44 * decoding valid encodings back to bytes. 44 * decoding valid encodings back to bytes.
45 * 45 *
46 * This implementation only handles the simplest RFC 4648 base64 and base64url 46 * This implementation only handles the simplest RFC 4648 base64 and base64url
47 * encodings. 47 * encodings.
48 * It does not allow invalid characters when decoding and it requires, 48 * It does not allow invalid characters when decoding and it requires,
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
83 int firstPadding = -1; 83 int firstPadding = -1;
84 int firstPaddingSourceIndex = -1; 84 int firstPaddingSourceIndex = -1;
85 int paddingCount = 0; 85 int paddingCount = 0;
86 for (int i = start; i < end;) { 86 for (int i = start; i < end;) {
87 int sliceEnd = i; 87 int sliceEnd = i;
88 int char = source.codeUnitAt(i++); 88 int char = source.codeUnitAt(i++);
89 int originalChar = char; 89 int originalChar = char;
90 // Normalize char, keep originalChar to see if it matches the source. 90 // Normalize char, keep originalChar to see if it matches the source.
91 if (char == percent) { 91 if (char == percent) {
92 if (i + 2 <= end) { 92 if (i + 2 <= end) {
93 char = parseHexByte(source, i); // May be negative. 93 char = parseHexByte(source, i); // May be negative.
94 i += 2; 94 i += 2;
95 // We know that %25 isn't valid, but our table considers it 95 // We know that %25 isn't valid, but our table considers it
96 // a potential padding start, so skip the checks. 96 // a potential padding start, so skip the checks.
97 if (char == percent) char = -1; 97 if (char == percent) char = -1;
98 } else { 98 } else {
99 // An invalid HEX escape (too short). 99 // An invalid HEX escape (too short).
100 // Just skip past the handling and reach the throw below. 100 // Just skip past the handling and reach the throw below.
101 char = -1; 101 char = -1;
102 } 102 }
103 } 103 }
(...skipping 23 matching lines...) Expand all
127 } 127 }
128 } 128 }
129 throw new FormatException("Invalid base64 data", source, sliceEnd); 129 throw new FormatException("Invalid base64 data", source, sliceEnd);
130 } 130 }
131 if (buffer != null) { 131 if (buffer != null) {
132 buffer.write(source.substring(sliceStart, end)); 132 buffer.write(source.substring(sliceStart, end));
133 if (firstPadding >= 0) { 133 if (firstPadding >= 0) {
134 // There was padding in the source. Check that it is valid: 134 // There was padding in the source. Check that it is valid:
135 // * result length a multiple of four 135 // * result length a multiple of four
136 // * one or two padding characters at the end. 136 // * one or two padding characters at the end.
137 _checkPadding(source, firstPaddingSourceIndex, end, 137 _checkPadding(source, firstPaddingSourceIndex, end, firstPadding,
138 firstPadding, paddingCount, buffer.length); 138 paddingCount, buffer.length);
139 } else { 139 } else {
140 // Length of last chunk (1-4 chars) in the encoding. 140 // Length of last chunk (1-4 chars) in the encoding.
141 int endLength = ((buffer.length - 1) % 4) + 1; 141 int endLength = ((buffer.length - 1) % 4) + 1;
142 if (endLength == 1) { 142 if (endLength == 1) {
143 // The data must have length 0, 2 or 3 modulo 4. 143 // The data must have length 0, 2 or 3 modulo 4.
144 throw new FormatException("Invalid base64 encoding length ", 144 throw new FormatException(
145 source, end); 145 "Invalid base64 encoding length ", source, end);
146 } 146 }
147 while (endLength < 4) { 147 while (endLength < 4) {
148 buffer.write("="); 148 buffer.write("=");
149 endLength++; 149 endLength++;
150 } 150 }
151 } 151 }
152 return source.replaceRange(start, end, buffer.toString()); 152 return source.replaceRange(start, end, buffer.toString());
153 } 153 }
154 // Original was already normalized, only check padding. 154 // Original was already normalized, only check padding.
155 int length = end - start; 155 int length = end - start;
156 if (firstPadding >= 0) { 156 if (firstPadding >= 0) {
157 _checkPadding(source, firstPaddingSourceIndex, end, 157 _checkPadding(source, firstPaddingSourceIndex, end, firstPadding,
158 firstPadding, paddingCount, length); 158 paddingCount, length);
159 } else { 159 } else {
160 // No padding given, so add some if needed it. 160 // No padding given, so add some if needed it.
161 int endLength = length % 4; 161 int endLength = length % 4;
162 if (endLength == 1) { 162 if (endLength == 1) {
163 // The data must have length 0, 2 or 3 modulo 4. 163 // The data must have length 0, 2 or 3 modulo 4.
164 throw new FormatException("Invalid base64 encoding length ", 164 throw new FormatException(
165 source, end); 165 "Invalid base64 encoding length ", source, end);
166 } 166 }
167 if (endLength > 1) { 167 if (endLength > 1) {
168 // There is no "insertAt" on String, but this works as well. 168 // There is no "insertAt" on String, but this works as well.
169 source = source.replaceRange(end, end, (endLength == 2) ? "==" : "="); 169 source = source.replaceRange(end, end, (endLength == 2) ? "==" : "=");
170 } 170 }
171 } 171 }
172 return source; 172 return source;
173 } 173 }
174 174
175 static int _checkPadding(String source, int sourceIndex, int sourceEnd, 175 static int _checkPadding(String source, int sourceIndex, int sourceEnd,
176 int firstPadding, int paddingCount, int length) { 176 int firstPadding, int paddingCount, int length) {
177 if (length % 4 != 0) { 177 if (length % 4 != 0) {
178 throw new FormatException( 178 throw new FormatException(
179 "Invalid base64 padding, padded length must be multiple of four, " 179 "Invalid base64 padding, padded length must be multiple of four, "
180 "is $length", 180 "is $length",
181 source, sourceEnd); 181 source,
182 sourceEnd);
182 } 183 }
183 if (firstPadding + paddingCount != length) { 184 if (firstPadding + paddingCount != length) {
184 throw new FormatException( 185 throw new FormatException(
185 "Invalid base64 padding, '=' not at the end", 186 "Invalid base64 padding, '=' not at the end", source, sourceIndex);
186 source, sourceIndex);
187 } 187 }
188 if (paddingCount > 2) { 188 if (paddingCount > 2) {
189 throw new FormatException( 189 throw new FormatException(
190 "Invalid base64 padding, more than two '=' characters", 190 "Invalid base64 padding, more than two '=' characters",
191 source, sourceIndex); 191 source,
192 sourceIndex);
192 } 193 }
193 } 194 }
194 } 195 }
195 196
196 // ------------------------------------------------------------------------ 197 // ------------------------------------------------------------------------
197 // Encoder 198 // Encoder
198 // ------------------------------------------------------------------------ 199 // ------------------------------------------------------------------------
199 200
200 /** 201 /**
201 * Base64 and base64url encoding converter. 202 * Base64 and base64url encoding converter.
202 * 203 *
203 * Encodes lists of bytes using base64 or base64url encoding. 204 * Encodes lists of bytes using base64 or base64url encoding.
204 * 205 *
205 * The results are ASCII strings using a restricted alphabet. 206 * The results are ASCII strings using a restricted alphabet.
206 */ 207 */
207 class Base64Encoder extends Converter<List<int>, String> 208 class Base64Encoder extends Converter<List<int>, String>
208 implements ChunkedConverter<List<int>, String, List<int>, String> { 209 implements ChunkedConverter<List<int>, String, List<int>, String> {
209
210 final bool _urlSafe; 210 final bool _urlSafe;
211 211
212 const Base64Encoder() : _urlSafe = false; 212 const Base64Encoder() : _urlSafe = false;
213 const Base64Encoder.urlSafe() : _urlSafe = true; 213 const Base64Encoder.urlSafe() : _urlSafe = true;
214 214
215 String convert(List<int> input) { 215 String convert(List<int> input) {
216 if (input.isEmpty) return ""; 216 if (input.isEmpty) return "";
217 var encoder = new _Base64Encoder(_urlSafe); 217 var encoder = new _Base64Encoder(_urlSafe);
218 Uint8List buffer = encoder.encode(input, 0, input.length, true); 218 Uint8List buffer = encoder.encode(input, 0, input.length, true);
219 return new String.fromCharCodes(buffer); 219 return new String.fromCharCodes(buffer);
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 assert(start <= end); 297 assert(start <= end);
298 assert(bytes == null || end <= bytes.length); 298 assert(bytes == null || end <= bytes.length);
299 int length = end - start; 299 int length = end - start;
300 300
301 int count = _stateCount(_state); 301 int count = _stateCount(_state);
302 int byteCount = (count + length); 302 int byteCount = (count + length);
303 int fullChunks = byteCount ~/ 3; 303 int fullChunks = byteCount ~/ 3;
304 int partialChunkLength = byteCount - fullChunks * 3; 304 int partialChunkLength = byteCount - fullChunks * 3;
305 int bufferLength = fullChunks * 4; 305 int bufferLength = fullChunks * 4;
306 if (isLast && partialChunkLength > 0) { 306 if (isLast && partialChunkLength > 0) {
307 bufferLength += 4; // Room for padding. 307 bufferLength += 4; // Room for padding.
308 } 308 }
309 var output = createBuffer(bufferLength); 309 var output = createBuffer(bufferLength);
310 _state = encodeChunk(_alphabet, bytes, start, end, isLast, 310 _state =
311 output, 0, _state); 311 encodeChunk(_alphabet, bytes, start, end, isLast, output, 0, _state);
312 if (bufferLength > 0) return output; 312 if (bufferLength > 0) return output;
313 // If the input plus the data in state is still less than three bytes, 313 // If the input plus the data in state is still less than three bytes,
314 // there may not be any output. 314 // there may not be any output.
315 return null; 315 return null;
316 } 316 }
317 317
318 static int encodeChunk(String alphabet, 318 static int encodeChunk(String alphabet, List<int> bytes, int start, int end,
319 List<int> bytes, int start, int end, bool isLast, 319 bool isLast, Uint8List output, int outputIndex, int state) {
320 Uint8List output, int outputIndex, int state) {
321 int bits = _stateBits(state); 320 int bits = _stateBits(state);
322 // Count number of missing bytes in three-byte chunk. 321 // Count number of missing bytes in three-byte chunk.
323 int expectedChars = 3 - _stateCount(state); 322 int expectedChars = 3 - _stateCount(state);
324 323
325 // The input must be a list of bytes (integers in the range 0..255). 324 // The input must be a list of bytes (integers in the range 0..255).
326 // The value of `byteOr` will be the bitwise or of all the values in 325 // The value of `byteOr` will be the bitwise or of all the values in
327 // `bytes` and a later check will validate that they were all valid bytes. 326 // `bytes` and a later check will validate that they were all valid bytes.
328 int byteOr = 0; 327 int byteOr = 0;
329 for (int i = start; i < end; i++) { 328 for (int i = start; i < end; i++) {
330 int byte = bytes[i]; 329 int byte = bytes[i];
331 byteOr |= byte; 330 byteOr |= byte;
332 bits = ((bits << 8) | byte) & 0xFFFFFF; // Never store more than 24 bits. 331 bits = ((bits << 8) | byte) & 0xFFFFFF; // Never store more than 24 bits.
333 expectedChars--; 332 expectedChars--;
334 if (expectedChars == 0) { 333 if (expectedChars == 0) {
335 output[outputIndex++] = 334 output[outputIndex++] = alphabet.codeUnitAt((bits >> 18) & _sixBitMask);
336 alphabet.codeUnitAt((bits >> 18) & _sixBitMask); 335 output[outputIndex++] = alphabet.codeUnitAt((bits >> 12) & _sixBitMask);
337 output[outputIndex++] = 336 output[outputIndex++] = alphabet.codeUnitAt((bits >> 6) & _sixBitMask);
338 alphabet.codeUnitAt((bits >> 12) & _sixBitMask); 337 output[outputIndex++] = alphabet.codeUnitAt(bits & _sixBitMask);
339 output[outputIndex++] =
340 alphabet.codeUnitAt((bits >> 6) & _sixBitMask);
341 output[outputIndex++] =
342 alphabet.codeUnitAt(bits & _sixBitMask);
343 expectedChars = 3; 338 expectedChars = 3;
344 bits = 0; 339 bits = 0;
345 } 340 }
346 } 341 }
347 if (byteOr >= 0 && byteOr <= 255) { 342 if (byteOr >= 0 && byteOr <= 255) {
348 if (isLast && expectedChars < 3) { 343 if (isLast && expectedChars < 3) {
349 writeFinalChunk(alphabet, output, outputIndex, 3 - expectedChars, bits); 344 writeFinalChunk(alphabet, output, outputIndex, 3 - expectedChars, bits);
350 return 0; 345 return 0;
351 } 346 }
352 return _encodeState(3 - expectedChars, bits); 347 return _encodeState(3 - expectedChars, bits);
353 } 348 }
354 349
355 // There was an invalid byte value somewhere in the input - find it! 350 // There was an invalid byte value somewhere in the input - find it!
356 int i = start; 351 int i = start;
357 while (i < end) { 352 while (i < end) {
358 int byte = bytes[i]; 353 int byte = bytes[i];
359 if (byte < 0 || byte > 255) break; 354 if (byte < 0 || byte > 255) break;
360 i++; 355 i++;
361 } 356 }
362 throw new ArgumentError.value(bytes, 357 throw new ArgumentError.value(
363 "Not a byte value at index $i: 0x${bytes[i].toRadixString(16)}"); 358 bytes, "Not a byte value at index $i: 0x${bytes[i].toRadixString(16)}");
364 } 359 }
365 360
366 /** 361 /**
367 * Writes a final encoded four-character chunk. 362 * Writes a final encoded four-character chunk.
368 * 363 *
369 * Only used when the [_state] contains a partial (1 or 2 byte) 364 * Only used when the [_state] contains a partial (1 or 2 byte)
370 * input. 365 * input.
371 */ 366 */
372 static void writeFinalChunk(String alphabet, 367 static void writeFinalChunk(
373 Uint8List output, int outputIndex, 368 String alphabet, Uint8List output, int outputIndex, int count, int bits) {
374 int count, int bits) {
375 assert(count > 0); 369 assert(count > 0);
376 if (count == 1) { 370 if (count == 1) {
377 output[outputIndex++] = 371 output[outputIndex++] = alphabet.codeUnitAt((bits >> 2) & _sixBitMask);
378 alphabet.codeUnitAt((bits >> 2) & _sixBitMask); 372 output[outputIndex++] = alphabet.codeUnitAt((bits << 4) & _sixBitMask);
379 output[outputIndex++] =
380 alphabet.codeUnitAt((bits << 4) & _sixBitMask);
381 output[outputIndex++] = _paddingChar; 373 output[outputIndex++] = _paddingChar;
382 output[outputIndex++] = _paddingChar; 374 output[outputIndex++] = _paddingChar;
383 } else { 375 } else {
384 assert(count == 2); 376 assert(count == 2);
385 output[outputIndex++] = 377 output[outputIndex++] = alphabet.codeUnitAt((bits >> 10) & _sixBitMask);
386 alphabet.codeUnitAt((bits >> 10) & _sixBitMask); 378 output[outputIndex++] = alphabet.codeUnitAt((bits >> 4) & _sixBitMask);
387 output[outputIndex++] = 379 output[outputIndex++] = alphabet.codeUnitAt((bits << 2) & _sixBitMask);
388 alphabet.codeUnitAt((bits >> 4) & _sixBitMask);
389 output[outputIndex++] =
390 alphabet.codeUnitAt((bits << 2) & _sixBitMask);
391 output[outputIndex++] = _paddingChar; 380 output[outputIndex++] = _paddingChar;
392 } 381 }
393 } 382 }
394 } 383 }
395 384
396 class _BufferCachingBase64Encoder extends _Base64Encoder { 385 class _BufferCachingBase64Encoder extends _Base64Encoder {
397 /** 386 /**
398 * Reused buffer. 387 * Reused buffer.
399 * 388 *
400 * When the buffer isn't released to the sink, only used to create another 389 * When the buffer isn't released to the sink, only used to create another
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
471 460
472 /** 461 /**
473 * Decoder for base64 encoded data. 462 * Decoder for base64 encoded data.
474 * 463 *
475 * This decoder accepts both base64 and base64url ("url-safe") encodings. 464 * This decoder accepts both base64 and base64url ("url-safe") encodings.
476 * 465 *
477 * The encoding is required to be properly padded. 466 * The encoding is required to be properly padded.
478 */ 467 */
479 class Base64Decoder extends Converter<String, List<int>> 468 class Base64Decoder extends Converter<String, List<int>>
480 implements ChunkedConverter<String, List<int>, String, List<int>> { 469 implements ChunkedConverter<String, List<int>, String, List<int>> {
481
482 const Base64Decoder(); 470 const Base64Decoder();
483 471
484 List<int> convert(String input, [int start = 0, int end]) { 472 List<int> convert(String input, [int start = 0, int end]) {
485 end = RangeError.checkValidRange(start, end, input.length); 473 end = RangeError.checkValidRange(start, end, input.length);
486 if (start == end) return new Uint8List(0); 474 if (start == end) return new Uint8List(0);
487 var decoder = new _Base64Decoder(); 475 var decoder = new _Base64Decoder();
488 Uint8List buffer = decoder.decode(input, start, end); 476 Uint8List buffer = decoder.decode(input, start, end);
489 decoder.close(input, end); 477 decoder.close(input, end);
490 return buffer; 478 return buffer;
491 } 479 }
(...skipping 28 matching lines...) Expand all
520 * 508 *
521 * Uses [_invalid] for invalid indices and [_padding] for the padding 509 * Uses [_invalid] for invalid indices and [_padding] for the padding
522 * character. 510 * character.
523 * 511 *
524 * Accepts the "URL-safe" alphabet as well (`-` and `_` are the 512 * Accepts the "URL-safe" alphabet as well (`-` and `_` are the
525 * 62nd and 63rd alphabet characters), and considers `%` a padding 513 * 62nd and 63rd alphabet characters), and considers `%` a padding
526 * character, which must then be followed by `3D`, the percent-escape 514 * character, which must then be followed by `3D`, the percent-escape
527 * for `=`. 515 * for `=`.
528 */ 516 */
529 static final List<int> _inverseAlphabet = new Int8List.fromList([ 517 static final List<int> _inverseAlphabet = new Int8List.fromList([
530 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, 518 __,
floitsch 2017/03/16 10:37:54 There is a reason these were aligned in blocks of
531 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, 519 __,
532 __, __, __, __, __, _p, __, __, __, __, __, 62, __, 62, __, 63, 520 __,
533 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, __, __, __, _p, __, __, 521 __,
534 __, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 522 __,
535 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, __, __, __, __, 63, 523 __,
536 __, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 524 __,
537 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, __, __, __, __, __, 525 __,
526 __,
527 __,
528 __,
529 __,
530 __,
531 __,
532 __,
533 __,
534 __,
535 __,
536 __,
537 __,
538 __,
539 __,
540 __,
541 __,
542 __,
543 __,
544 __,
545 __,
546 __,
547 __,
548 __,
549 __,
550 __,
551 __,
552 __,
553 __,
554 __,
555 _p,
556 __,
557 __,
558 __,
559 __,
560 __,
561 62,
562 __,
563 62,
564 __,
565 63,
566 52,
567 53,
568 54,
569 55,
570 56,
571 57,
572 58,
573 59,
574 60,
575 61,
576 __,
577 __,
578 __,
579 _p,
580 __,
581 __,
582 __,
583 0,
584 1,
585 2,
586 3,
587 4,
588 5,
589 6,
590 7,
591 8,
592 9,
593 10,
594 11,
595 12,
596 13,
597 14,
598 15,
599 16,
600 17,
601 18,
602 19,
603 20,
604 21,
605 22,
606 23,
607 24,
608 25,
609 __,
610 __,
611 __,
612 __,
613 63,
614 __,
615 26,
616 27,
617 28,
618 29,
619 30,
620 31,
621 32,
622 33,
623 34,
624 35,
625 36,
626 37,
627 38,
628 39,
629 40,
630 41,
631 42,
632 43,
633 44,
634 45,
635 46,
636 47,
637 48,
638 49,
639 50,
640 51,
641 __,
642 __,
643 __,
644 __,
645 __,
538 ]); 646 ]);
539 647
540 // Character constants. 648 // Character constants.
541 static const int _char_percent = 0x25; // '%'. 649 static const int _char_percent = 0x25; // '%'.
542 static const int _char_3 = 0x33; // '3'. 650 static const int _char_3 = 0x33; // '3'.
543 static const int _char_d = 0x64; // 'd'. 651 static const int _char_d = 0x64; // 'd'.
544 652
545 /** 653 /**
546 * Maintains the intermediate state of a partly-decoded input. 654 * Maintains the intermediate state of a partly-decoded input.
547 * 655 *
548 * Base64 is decoded in chunks of four characters. If a chunk does not 656 * Base64 is decoded in chunks of four characters. If a chunk does not
549 * contain a full block, the decoded bits (six per character) of the 657 * contain a full block, the decoded bits (six per character) of the
550 * available characters are stored in [_state] until the next call to 658 * available characters are stored in [_state] until the next call to
551 * [_decode] or [_close]. 659 * [_decode] or [_close].
552 * 660 *
553 * If no padding has been seen, the value is 661 * If no padding has been seen, the value is
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
586 assert(state >= 0); 694 assert(state >= 0);
587 return state >> _valueShift; 695 return state >> _valueShift;
588 } 696 }
589 697
590 /** 698 /**
591 * Encodes a number of expected padding characters to be stored in [_state]. 699 * Encodes a number of expected padding characters to be stored in [_state].
592 */ 700 */
593 static int _encodePaddingState(int expectedPadding) { 701 static int _encodePaddingState(int expectedPadding) {
594 assert(expectedPadding >= 0); 702 assert(expectedPadding >= 0);
595 assert(expectedPadding <= 5); 703 assert(expectedPadding <= 5);
596 return -expectedPadding - 1; // ~expectedPadding adapted to dart2js. 704 return -expectedPadding - 1; // ~expectedPadding adapted to dart2js.
597 } 705 }
598 706
599 /** 707 /**
600 * Extracts expected padding character count from a [_state] value. 708 * Extracts expected padding character count from a [_state] value.
601 */ 709 */
602 static int _statePadding(int state) { 710 static int _statePadding(int state) {
603 assert(state < 0); 711 assert(state < 0);
604 return -state - 1; // ~state adapted to dart2js. 712 return -state - 1; // ~state adapted to dart2js.
605 } 713 }
606 714
607 static bool _hasSeenPadding(int state) => state < 0; 715 static bool _hasSeenPadding(int state) => state < 0;
608 716
609 /** 717 /**
610 * Decodes [input] from [start] to [end]. 718 * Decodes [input] from [start] to [end].
611 * 719 *
612 * Returns a [Uint8List] with the decoded bytes. 720 * Returns a [Uint8List] with the decoded bytes.
613 * If a previous call had an incomplete four-character block, the bits from 721 * If a previous call had an incomplete four-character block, the bits from
614 * those are included in decoding 722 * those are included in decoding
(...skipping 11 matching lines...) Expand all
626 _state = decodeChunk(input, start, end, buffer, 0, _state); 734 _state = decodeChunk(input, start, end, buffer, 0, _state);
627 return buffer; 735 return buffer;
628 } 736 }
629 737
630 /** Checks that [_state] represents a valid decoding. */ 738 /** Checks that [_state] represents a valid decoding. */
631 void close(String input, int end) { 739 void close(String input, int end) {
632 if (_state < _encodePaddingState(0)) { 740 if (_state < _encodePaddingState(0)) {
633 throw new FormatException("Missing padding character", input, end); 741 throw new FormatException("Missing padding character", input, end);
634 } 742 }
635 if (_state > 0) { 743 if (_state > 0) {
636 throw new FormatException("Invalid length, must be multiple of four", 744 throw new FormatException(
637 input, end); 745 "Invalid length, must be multiple of four", input, end);
638 } 746 }
639 _state = _encodePaddingState(0); 747 _state = _encodePaddingState(0);
640 } 748 }
641 749
642 /** 750 /**
643 * Decodes [input] from [start] to [end]. 751 * Decodes [input] from [start] to [end].
644 * 752 *
645 * Includes the state returned by a previous call in the decoding. 753 * Includes the state returned by a previous call in the decoding.
646 * Writes the decoding to [output] at [outIndex], and there must 754 * Writes the decoding to [output] at [outIndex], and there must
647 * be room in the output. 755 * be room in the output.
648 */ 756 */
649 static int decodeChunk(String input, int start, int end, 757 static int decodeChunk(String input, int start, int end, Uint8List output,
650 Uint8List output, int outIndex, 758 int outIndex, int state) {
651 int state) {
652 assert(!_hasSeenPadding(state)); 759 assert(!_hasSeenPadding(state));
653 const int asciiMask = 127; 760 const int asciiMask = 127;
654 const int asciiMax = 127; 761 const int asciiMax = 127;
655 const int eightBitMask = 0xFF; 762 const int eightBitMask = 0xFF;
656 const int bitsPerCharacter = 6; 763 const int bitsPerCharacter = 6;
657 764
658 int bits = _stateBits(state); 765 int bits = _stateBits(state);
659 int count = _stateCount(state); 766 int count = _stateCount(state);
660 // String contents should be all ASCII. 767 // String contents should be all ASCII.
661 // Instead of checking for each character, we collect the bitwise-or of 768 // Instead of checking for each character, we collect the bitwise-or of
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
715 if (char < 0 || char > asciiMax) break; 822 if (char < 0 || char > asciiMax) break;
716 } 823 }
717 throw new FormatException("Invalid character", input, i); 824 throw new FormatException("Invalid character", input, i);
718 } 825 }
719 826
720 /** 827 /**
721 * Allocates a buffer with room for the decoding of a substring of [input]. 828 * Allocates a buffer with room for the decoding of a substring of [input].
722 * 829 *
723 * Includes room for the characters in [state], and handles padding correctly. 830 * Includes room for the characters in [state], and handles padding correctly.
724 */ 831 */
725 static Uint8List _allocateBuffer(String input, int start, int end, 832 static Uint8List _allocateBuffer(
726 int state) { 833 String input, int start, int end, int state) {
727 assert(state >= 0); 834 assert(state >= 0);
728 int paddingStart = _trimPaddingChars(input, start, end); 835 int paddingStart = _trimPaddingChars(input, start, end);
729 int length = _stateCount(state) + (paddingStart - start); 836 int length = _stateCount(state) + (paddingStart - start);
730 // Three bytes per full four bytes in the input. 837 // Three bytes per full four bytes in the input.
731 int bufferLength = (length >> 2) * 3; 838 int bufferLength = (length >> 2) * 3;
732 // If padding was seen, then this is the last chunk, and the final partial 839 // If padding was seen, then this is the last chunk, and the final partial
733 // chunk should be decoded too. 840 // chunk should be decoded too.
734 int remainderLength = length & 3; 841 int remainderLength = length & 3;
735 if (remainderLength != 0 && paddingStart < end) { 842 if (remainderLength != 0 && paddingStart < end) {
736 bufferLength += remainderLength - 1; 843 bufferLength += remainderLength - 1;
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
842 if (start == end) break; 949 if (start == end) break;
843 char = input.codeUnitAt(start); 950 char = input.codeUnitAt(start);
844 } 951 }
845 // Expects 'D' or 'd'. 952 // Expects 'D' or 'd'.
846 if ((char | 0x20) != _char_d) break; 953 if ((char | 0x20) != _char_d) break;
847 start++; 954 start++;
848 expectedPadding--; 955 expectedPadding--;
849 if (start == end) break; 956 if (start == end) break;
850 } 957 }
851 if (start != end) { 958 if (start != end) {
852 throw new FormatException("Invalid padding character", 959 throw new FormatException("Invalid padding character", input, start);
853 input, start);
854 } 960 }
855 return _encodePaddingState(expectedPadding); 961 return _encodePaddingState(expectedPadding);
856 } 962 }
857 } 963 }
858 964
859 class _Base64DecoderSink extends StringConversionSinkBase { 965 class _Base64DecoderSink extends StringConversionSinkBase {
860 /** Output sink */ 966 /** Output sink */
861 final Sink<List<int>> _sink; 967 final Sink<List<int>> _sink;
862 final _Base64Decoder _decoder = new _Base64Decoder(); 968 final _Base64Decoder _decoder = new _Base64Decoder();
863 969
(...skipping 14 matching lines...) Expand all
878 end = RangeError.checkValidRange(start, end, string.length); 984 end = RangeError.checkValidRange(start, end, string.length);
879 if (start == end) return; 985 if (start == end) return;
880 Uint8List buffer = _decoder.decode(string, start, end); 986 Uint8List buffer = _decoder.decode(string, start, end);
881 if (buffer != null) _sink.add(buffer); 987 if (buffer != null) _sink.add(buffer);
882 if (isLast) { 988 if (isLast) {
883 _decoder.close(string, end); 989 _decoder.close(string, end);
884 _sink.close(); 990 _sink.close();
885 } 991 }
886 } 992 }
887 } 993 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698