| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 import 'dart:convert'; | |
| 6 import 'dart:typed_data'; | |
| 7 | |
| 8 import 'package:charcode/ascii.dart'; | |
| 9 | |
| 10 import 'decoder_sink.dart'; | |
| 11 | |
| 12 /// A mapping from ASCII character codes to their corresponding Base64 values. | |
| 13 /// | |
| 14 /// Characters with a value of `null` can't be decoded directly. This includes | |
| 15 /// special values like CR, LF, `=`, and `%`. | |
| 16 const _decodeTable = const [ | |
| 17 null, null, null, null, null, null, null, null, null, null, null, null, null, | |
| 18 null, null, null, null, null, null, null, null, null, null, null, null, null, | |
| 19 null, null, null, null, null, null, null, null, null, null, null, null, null, | |
| 20 null, null, null, null, 62, null, 62, null, 63, 52, 53, 54, 55, 56, 57, 58, | |
| 21 59, 60, 61, null, null, null, null, null, null, null, 0, 1, 2, 3, 4, 5, 6, 7, | |
| 22 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, null, | |
| 23 null, null, null, 63, null, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, | |
| 24 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 | |
| 25 ]; | |
| 26 | |
| 27 /// This is deprecated. | |
| 28 /// | |
| 29 /// Use the `Base64Decoder` class in `dart:convert` instead. | |
| 30 @Deprecated("Will be removed in crypto 1.0.0.") | |
| 31 class Base64Decoder extends Converter<String, List<int>> { | |
| 32 const Base64Decoder(); | |
| 33 | |
| 34 List<int> convert(String input) { | |
| 35 if (input.length == 0) return new Uint8List(0); | |
| 36 | |
| 37 // The length of the actual data sections in the input (not CRLFs). | |
| 38 var dataLength = 0; | |
| 39 | |
| 40 // Count the data, and fail for invalid characters. | |
| 41 for (var i = 0; i < input.length; i++) { | |
| 42 var codeUnit = input.codeUnitAt(i); | |
| 43 | |
| 44 if (codeUnit == $cr || codeUnit == $lf) continue; | |
| 45 | |
| 46 if (codeUnit == $percent && | |
| 47 i < input.length - 2 && | |
| 48 input.codeUnitAt(i + 1) == $3 && | |
| 49 input.codeUnitAt(i + 2) == $D) { | |
| 50 dataLength++; | |
| 51 i += 2; | |
| 52 continue; | |
| 53 } | |
| 54 | |
| 55 if (codeUnit != $equal && | |
| 56 (codeUnit >= _decodeTable.length || _decodeTable[codeUnit] == null)) { | |
| 57 throw new FormatException('Invalid character', input, i); | |
| 58 } | |
| 59 | |
| 60 dataLength++; | |
| 61 } | |
| 62 | |
| 63 if (dataLength % 4 != 0) { | |
| 64 throw new FormatException( | |
| 65 'Base64 input must encode a multiple of 4 bytes.', | |
| 66 input, | |
| 67 dataLength); | |
| 68 } | |
| 69 | |
| 70 // Count the trailing pad characters. | |
| 71 var padLength = 0; | |
| 72 for (var i = input.length - 1; i >= 0; i--) { | |
| 73 var codeUnit = input.codeUnitAt(i); | |
| 74 if (codeUnit == $D && | |
| 75 i >= 2 && | |
| 76 input.codeUnitAt(i - 2) == $percent && | |
| 77 input.codeUnitAt(i - 1) == $3) { | |
| 78 padLength++; | |
| 79 i -= 2; | |
| 80 } else if (codeUnit == $equal) { | |
| 81 padLength++; | |
| 82 } else if (codeUnit != $cr && codeUnit != $lf) { | |
| 83 break; | |
| 84 } | |
| 85 } | |
| 86 var outputLength = ((dataLength * 6) >> 3) - padLength; | |
| 87 var out = new Uint8List(outputLength); | |
| 88 | |
| 89 var inputIndex = 0; | |
| 90 var outputIndex = 0; | |
| 91 while (outputIndex < outputLength) { | |
| 92 // Accumulate four 6-bit Base64 characters into a 32-bit chunk. | |
| 93 var chunk = 0; | |
| 94 for (var i = 0; i < 4; i++) { | |
| 95 var codeUnit = input.codeUnitAt(inputIndex++); | |
| 96 | |
| 97 if (codeUnit == $equal || codeUnit == $percent) { | |
| 98 // We've reached the end of the source. Pad out the rest of the chunk | |
| 99 // with zeroes. | |
| 100 chunk <<= (4 - i) * 6; | |
| 101 break; | |
| 102 } | |
| 103 | |
| 104 if (codeUnit == $cr || codeUnit == $lf) { | |
| 105 i--; | |
| 106 } else { | |
| 107 chunk = (chunk << 6) | _decodeTable[codeUnit]; | |
| 108 } | |
| 109 } | |
| 110 | |
| 111 // Emit 8-bit pieces of the chunk to the output buffer. | |
| 112 out[outputIndex++] = chunk >> 16; | |
| 113 if (outputIndex >= outputLength) break; | |
| 114 | |
| 115 out[outputIndex++] = (chunk >> 8) & 0xFF; | |
| 116 if (outputIndex >= outputLength) break; | |
| 117 | |
| 118 out[outputIndex++] = chunk & 0xFF; | |
| 119 } | |
| 120 | |
| 121 return out; | |
| 122 } | |
| 123 | |
| 124 Base64DecoderSink startChunkedConversion(Sink<List<int>> sink) { | |
| 125 if (sink is! ByteConversionSink) sink = new ByteConversionSink.from(sink); | |
| 126 return new Base64DecoderSink(sink); | |
| 127 } | |
| 128 } | |
| OLD | NEW |