| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, 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 library crypto.base64; | 5 library crypto.base64; |
| 6 | 6 |
| 7 import 'dart:convert'; | 7 import 'dart:convert'; |
| 8 import 'dart:typed_data'; | 8 import 'dart:typed_data'; |
| 9 | 9 |
| 10 /// An instance of the default implementation of [Base64Codec]. |
| 11 /// |
| 12 /// This provides convenient access to most common Base64 use-cases. |
| 10 const Base64Codec BASE64 = const Base64Codec(); | 13 const Base64Codec BASE64 = const Base64Codec(); |
| 11 | 14 |
| 15 /// A mapping from ASCII character codes to their corresponding Base64 values. |
| 16 /// |
| 17 /// Characters with a value of -2 are invalid. Characters with a value of -1 |
| 18 /// should be ignored. The padding character, "=", is represented as 0. |
| 12 const List<int> _decodeTable = const [ | 19 const List<int> _decodeTable = const [ |
| 13 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -1, -2, -2, | 20 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -1, -2, -2, |
| 14 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 21 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 15 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, 62, -2, 63, | 22 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, 62, -2, 63, |
| 16 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, 0, -2, -2, | 23 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, 0, -2, -2, |
| 17 -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | 24 -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
| 18 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, 63, | 25 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, 63, |
| 19 -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, | 26 -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
| 20 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2, | 27 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2, |
| 21 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 28 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 22 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 29 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 23 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 30 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 24 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 31 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 25 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 32 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 26 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 33 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 27 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 34 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 28 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2 | 35 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2 |
| 29 ]; | 36 ]; |
| 30 | 37 |
| 38 /// A String representing a mapping from numbers between 0 and 63, inclusive, to |
| 39 /// their corresponding encoded character. |
| 40 /// |
| 41 /// This is the table for URL-safe encodings. |
| 31 const String _encodeTableUrlSafe = | 42 const String _encodeTableUrlSafe = |
| 32 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; | 43 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; |
| 33 | 44 |
| 45 /// A String representing a mapping from numbers between 0 and 63, inclusive, to |
| 46 /// their corresponding encoded character. |
| 47 /// |
| 48 /// This is the table for URL-unsafe encodings. |
| 34 const String _encodeTable = | 49 const String _encodeTable = |
| 35 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | 50 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
| 36 | 51 |
| 52 /// The line length for Base64 strings with line separators. |
| 37 const int _LINE_LENGTH = 76; | 53 const int _LINE_LENGTH = 76; |
| 54 |
| 55 /// A carriage return. |
| 38 const int _CR = 13; // '\r' | 56 const int _CR = 13; // '\r' |
| 57 |
| 58 /// A line feed. |
| 39 const int _LF = 10; // '\n' | 59 const int _LF = 10; // '\n' |
| 60 |
| 61 /// The byte sequence representing non-URL-encoded padding. |
| 40 const List<int> _PAD_BYTES = const [61]; // '=' | 62 const List<int> _PAD_BYTES = const [61]; // '=' |
| 63 |
| 64 /// The byte sequence representing URL-encoded padding. |
| 41 const List<int> _ENCODED_PAD_BYTES = const [37, 51, 68]; // '%3D' | 65 const List<int> _ENCODED_PAD_BYTES = const [37, 51, 68]; // '%3D' |
| 66 |
| 67 /// The string representing non-URL-encoded padding. |
| 42 const String _PAD = "="; | 68 const String _PAD = "="; |
| 69 |
| 70 /// The string representing URL-encoded padding. |
| 43 const String _ENCODED_PAD = "%3D"; | 71 const String _ENCODED_PAD = "%3D"; |
| 44 | 72 |
| 73 /// A codec that converts between binary data and [Base64][rfc]-encoded strings. |
| 74 /// |
| 75 /// [rfc]: https://tools.ietf.org/html/rfc4648 |
| 45 class Base64Codec extends Codec<List<int>, String> { | 76 class Base64Codec extends Codec<List<int>, String> { |
| 46 final bool _urlSafe; | 77 final bool _urlSafe; |
| 47 final bool _addLineSeparator; | 78 final bool _addLineSeparator; |
| 48 final bool _encodePaddingCharacter; | 79 final bool _encodePaddingCharacter; |
| 49 | 80 |
| 50 /** | 81 /// Creates a new [Base64Codec]. |
| 51 * Instantiates a new [Base64Codec]. | 82 /// |
| 52 * | 83 /// The default [BASE64] codec will be good enough for most cases. A new codec |
| 53 * The optional [urlSafe] argument specifies if [encoder] and [encode] | 84 /// only needs to be instantiated when you want to do multiple conversions |
| 54 * should generate a string, that is safe to use in an URL. | 85 /// with the same configuration. |
| 55 * | 86 /// |
| 56 * If [urlSafe] is `true` (and not overriden at the method invocation) | 87 /// If [urlSafe] is `true`, a URL-safe alphabet will be used when encoding. |
| 57 * the [encoder] and [encode] use '-' instead of '+' and '_' instead of '/'. | 88 /// Specifically, the characters `-` and `_` will be used instead of `+` and |
| 58 * | 89 /// `/`. |
| 59 * The default value of [urlSafe] is `false`. | 90 /// |
| 60 * | 91 /// If [addLineSeparator] is `true`, `\r\n` line separators will be added |
| 61 * The optional [addLineSeparator] argument specifies if the [encoder] and | 92 /// every 76 characters when encoding. |
| 62 * [encode] should add line separators. | 93 /// |
| 63 * | 94 /// If [encodePaddingCharacter] is `true`, the padding character `=` will be |
| 64 * If `addLineSeparator` is `true` [encode] adds an | 95 /// written as `%3D` when encoding. |
| 65 * optional line separator (CR + LF) for each 76 char output. | |
| 66 * | |
| 67 * The default value of [addLineSeparator] if `false`. | |
| 68 * | |
| 69 * If [encodePaddingCharacter] is `true` `encode` converts `=` to `%3D`. | |
| 70 * The default value of [encodePaddingCharacter] is `false`. | |
| 71 */ | |
| 72 const Base64Codec( | 96 const Base64Codec( |
| 73 {bool urlSafe: false, | 97 {bool urlSafe: false, |
| 74 bool addLineSeparator: false, | 98 bool addLineSeparator: false, |
| 75 bool encodePaddingCharacter: false}) | 99 bool encodePaddingCharacter: false}) |
| 76 : _urlSafe = urlSafe, | 100 : _urlSafe = urlSafe, |
| 77 _addLineSeparator = addLineSeparator, | 101 _addLineSeparator = addLineSeparator, |
| 78 _encodePaddingCharacter = encodePaddingCharacter; | 102 _encodePaddingCharacter = encodePaddingCharacter; |
| 79 | 103 |
| 80 String get name => "base64"; | 104 String get name => "base64"; |
| 81 | 105 |
| 106 /// Encodes [bytes] into a Base64 string. |
| 107 /// |
| 108 /// If [urlSafe] is `true`, a URL-safe alphabet will be used when encoding. |
| 109 /// Specifically, the characters `-` and `_` will be used instead of `+` and |
| 110 /// `/`. |
| 111 /// |
| 112 /// If [addLineSeparator] is `true`, `\r\n` line separators will be added |
| 113 /// every 76 characters when encoding. |
| 114 /// |
| 115 /// If [encodePaddingCharacter] is `true`, the padding character `=` will be |
| 116 /// written as `%3D` when encoding. |
| 117 /// |
| 118 /// Any flags passed to this method take precedence over the flags passed to |
| 119 /// the codec itself. |
| 82 String encode(List<int> bytes, | 120 String encode(List<int> bytes, |
| 83 {bool urlSafe, bool addLineSeparator, bool encodePaddingCharacter}) { | 121 {bool urlSafe, bool addLineSeparator, bool encodePaddingCharacter}) { |
| 84 if (urlSafe == null) urlSafe = _urlSafe; | 122 if (urlSafe == null) urlSafe = _urlSafe; |
| 85 if (addLineSeparator == null) addLineSeparator = _addLineSeparator; | 123 if (addLineSeparator == null) addLineSeparator = _addLineSeparator; |
| 86 if (encodePaddingCharacter == null) { | 124 if (encodePaddingCharacter == null) { |
| 87 encodePaddingCharacter = _encodePaddingCharacter; | 125 encodePaddingCharacter = _encodePaddingCharacter; |
| 88 } | 126 } |
| 89 return new Base64Encoder( | 127 return new Base64Encoder( |
| 90 urlSafe: urlSafe, | 128 urlSafe: urlSafe, |
| 91 addLineSeparator: addLineSeparator, | 129 addLineSeparator: addLineSeparator, |
| 92 encodePaddingCharacter: encodePaddingCharacter).convert(bytes); | 130 encodePaddingCharacter: encodePaddingCharacter).convert(bytes); |
| 93 } | 131 } |
| 94 | 132 |
| 95 Base64Encoder get encoder => new Base64Encoder( | 133 Base64Encoder get encoder => new Base64Encoder( |
| 96 urlSafe: _urlSafe, | 134 urlSafe: _urlSafe, |
| 97 addLineSeparator: _addLineSeparator, | 135 addLineSeparator: _addLineSeparator, |
| 98 encodePaddingCharacter: _encodePaddingCharacter); | 136 encodePaddingCharacter: _encodePaddingCharacter); |
| 99 | 137 |
| 100 Base64Decoder get decoder => new Base64Decoder(); | 138 Base64Decoder get decoder => new Base64Decoder(); |
| 101 } | 139 } |
| 102 | 140 |
| 103 /** | 141 /// An encoder that converts sequences of bytes to strings using [Base64][rfc]. |
| 104 * This class encodes byte strings (lists of unsigned | 142 /// |
| 105 * 8-bit integers) to strings according to Base64. | 143 /// [rfc]: https://tools.ietf.org/html/rfc4648 |
| 106 */ | |
| 107 class Base64Encoder extends Converter<List<int>, String> { | 144 class Base64Encoder extends Converter<List<int>, String> { |
| 145 /// Whether this encoder generates URL-safe strings. |
| 108 final bool _urlSafe; | 146 final bool _urlSafe; |
| 147 |
| 148 /// Whether this encoder adds line breaks to the output. |
| 109 final bool _addLineSeparator; | 149 final bool _addLineSeparator; |
| 150 |
| 151 /// Whether this encoder URL-encodes trailing padding characters. |
| 110 final bool _encodePaddingCharacter; | 152 final bool _encodePaddingCharacter; |
| 153 |
| 154 /// The sequence of bytes to use as a padding character. |
| 111 final List<int> _pad; | 155 final List<int> _pad; |
| 112 | 156 |
| 113 /** | 157 /// Creates a new [Base64Encoder]. |
| 114 * Instantiates a new [Base64Encoder]. | 158 /// |
| 115 * | 159 /// The default [BASE64.encoder] will be good enough for most cases. A new |
| 116 * The optional [urlSafe] argument specifies if [convert] | 160 /// codec only needs to be instantiated when you want to do multiple |
| 117 * should generate a string, that is safe to use in an URL. | 161 /// conversions with the same configuration. |
| 118 * | 162 /// |
| 119 * If it is `true` the [convert] use | 163 /// If [urlSafe] is `true`, a URL-safe alphabet will be used. Specifically, |
| 120 * '-' instead of '+' and '_' instead of '/'. | 164 /// the characters `-` and `_` will be used instead of `+` and `/`. |
| 121 * | 165 /// |
| 122 * The default value of [urlSafe] is `false`. | 166 /// If [addLineSeparator] is `true`, `\r\n` line separators will be added |
| 123 * | 167 /// every 76 characters. |
| 124 * The optional [addLineSeparator] argument specifies if [convert] | 168 /// |
| 125 * should add line separators. | 169 /// If [encodePaddingCharacter] is `true`, the padding character `=` will be |
| 126 * | 170 /// written as `%3D`. |
| 127 * If it is `true` [convert] adds an optional line separator(CR + LF) | |
| 128 * for each 76 char output. | |
| 129 * | |
| 130 * The default value of [addLineSeparator] if `false`. | |
| 131 * | |
| 132 * If [encodePaddingCharacter] is `true` `encode` converts `=` to `%3D`. | |
| 133 * The default value of [encodePaddingCharacter] is `false`. | |
| 134 */ | |
| 135 const Base64Encoder( | 171 const Base64Encoder( |
| 136 {bool urlSafe: false, | 172 {bool urlSafe: false, |
| 137 bool addLineSeparator: false, | 173 bool addLineSeparator: false, |
| 138 bool encodePaddingCharacter: false}) | 174 bool encodePaddingCharacter: false}) |
| 139 : _urlSafe = urlSafe, | 175 : _urlSafe = urlSafe, |
| 140 _addLineSeparator = addLineSeparator, | 176 _addLineSeparator = addLineSeparator, |
| 141 _encodePaddingCharacter = encodePaddingCharacter, | 177 _encodePaddingCharacter = encodePaddingCharacter, |
| 142 _pad = encodePaddingCharacter == true ? _ENCODED_PAD_BYTES : _PAD_BYTES; | 178 _pad = encodePaddingCharacter == true ? _ENCODED_PAD_BYTES : _PAD_BYTES; |
| 143 | 179 |
| 144 /** | 180 /// Converts [bytes] to Base64. |
| 145 * Converts [bytes] to its Base64 representation as a string. | 181 /// |
| 146 * | 182 /// If [start] and [end] are provided, only the sublist `bytes.sublist(start, |
| 147 * if [start] and [end] are provided, only the sublist | 183 /// end)` is converted. |
| 148 * `bytes.sublist(start, end)` is converted. | |
| 149 */ | |
| 150 String convert(List<int> bytes, [int start = 0, int end]) { | 184 String convert(List<int> bytes, [int start = 0, int end]) { |
| 151 int bytes_length = bytes.length; | 185 int bytes_length = bytes.length; |
| 152 RangeError.checkValidRange(start, end, bytes_length); | 186 RangeError.checkValidRange(start, end, bytes_length); |
| 153 if (end == null) end = bytes_length; | 187 if (end == null) end = bytes_length; |
| 154 int length = end - start; | 188 int length = end - start; |
| 155 if (length == 0) { | 189 if (length == 0) { |
| 156 return ""; | 190 return ""; |
| 157 } | 191 } |
| 158 final String lookup = _urlSafe ? _encodeTableUrlSafe : _encodeTable; | 192 final String lookup = _urlSafe ? _encodeTableUrlSafe : _encodeTable; |
| 159 // Size of 24 bit chunks. | 193 // Size of 24 bit chunks. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 StringConversionSink stringSink; | 251 StringConversionSink stringSink; |
| 218 if (sink is StringConversionSink) { | 252 if (sink is StringConversionSink) { |
| 219 stringSink = sink; | 253 stringSink = sink; |
| 220 } else { | 254 } else { |
| 221 stringSink = new StringConversionSink.from(sink); | 255 stringSink = new StringConversionSink.from(sink); |
| 222 } | 256 } |
| 223 return new _Base64EncoderSink(stringSink, _urlSafe, _addLineSeparator); | 257 return new _Base64EncoderSink(stringSink, _urlSafe, _addLineSeparator); |
| 224 } | 258 } |
| 225 } | 259 } |
| 226 | 260 |
| 261 /// A [ChunkedConversionSink] for encoding chunks of data to Base64. |
| 227 class _Base64EncoderSink extends ChunkedConversionSink<List<int>> { | 262 class _Base64EncoderSink extends ChunkedConversionSink<List<int>> { |
| 263 /// The encoder used to encode each chunk. |
| 228 final Base64Encoder _encoder; | 264 final Base64Encoder _encoder; |
| 265 |
| 266 /// The underlying sink to which to emit the encoded strings. |
| 229 final ChunkedConversionSink<String> _outSink; | 267 final ChunkedConversionSink<String> _outSink; |
| 268 |
| 269 /// The buffer of as-yet-unconverted bytes. |
| 270 /// |
| 271 /// This is used to ensure that we don't generate interstitial padding |
| 272 /// characters. |
| 230 final List<int> _buffer = new List<int>(); | 273 final List<int> _buffer = new List<int>(); |
| 274 |
| 275 /// The length of [_buffer]; that is, the number of unconverted bytes. |
| 231 int _bufferCount = 0; | 276 int _bufferCount = 0; |
| 232 | 277 |
| 233 _Base64EncoderSink(this._outSink, urlSafe, addLineSeparator) | 278 _Base64EncoderSink(this._outSink, urlSafe, addLineSeparator) |
| 234 : _encoder = new Base64Encoder( | 279 : _encoder = new Base64Encoder( |
| 235 urlSafe: urlSafe, addLineSeparator: addLineSeparator); | 280 urlSafe: urlSafe, addLineSeparator: addLineSeparator); |
| 236 | 281 |
| 237 void add(List<int> chunk) { | 282 void add(List<int> chunk) { |
| 238 var nextBufferCount = (chunk.length + _bufferCount) % 3; | 283 var nextBufferCount = (chunk.length + _bufferCount) % 3; |
| 239 | 284 |
| 240 int decodableLength = _bufferCount + chunk.length - nextBufferCount; | 285 int decodableLength = _bufferCount + chunk.length - nextBufferCount; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 253 } | 298 } |
| 254 | 299 |
| 255 void close() { | 300 void close() { |
| 256 if (_bufferCount > 0) { | 301 if (_bufferCount > 0) { |
| 257 _outSink.add(_encoder.convert(_buffer.sublist(0, _bufferCount))); | 302 _outSink.add(_encoder.convert(_buffer.sublist(0, _bufferCount))); |
| 258 } | 303 } |
| 259 _outSink.close(); | 304 _outSink.close(); |
| 260 } | 305 } |
| 261 } | 306 } |
| 262 | 307 |
| 263 /** | 308 /// An encoder that converts [Base64][rfc] strings to sequences of bytes. |
| 264 * This class decodes strings to lists of bytes(lists of | 309 /// |
| 265 * unsigned 8-bit integers) according to Base64. | 310 /// [rfc]: https://tools.ietf.org/html/rfc4648 |
| 266 */ | |
| 267 class Base64Decoder extends Converter<String, List<int>> { | 311 class Base64Decoder extends Converter<String, List<int>> { |
| 268 /** | |
| 269 * Instantiates a new [Base64Decoder] | |
| 270 */ | |
| 271 const Base64Decoder(); | 312 const Base64Decoder(); |
| 272 | 313 |
| 273 List<int> convert(String input) { | 314 List<int> convert(String input) { |
| 274 int length = input.length; | 315 int length = input.length; |
| 275 if (length == 0) { | 316 if (length == 0) { |
| 276 return new Uint8List(0); | 317 return new Uint8List(0); |
| 277 } | 318 } |
| 278 | 319 |
| 279 int normalLength = 0; | 320 int normalLength = 0; |
| 280 int i = 0; | 321 int i = 0; |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 350 } | 391 } |
| 351 | 392 |
| 352 _Base64DecoderSink startChunkedConversion(Sink<List<int>> sink) { | 393 _Base64DecoderSink startChunkedConversion(Sink<List<int>> sink) { |
| 353 if (sink is! ByteConversionSink) { | 394 if (sink is! ByteConversionSink) { |
| 354 sink = new ByteConversionSink.from(sink); | 395 sink = new ByteConversionSink.from(sink); |
| 355 } | 396 } |
| 356 return new _Base64DecoderSink(sink); | 397 return new _Base64DecoderSink(sink); |
| 357 } | 398 } |
| 358 } | 399 } |
| 359 | 400 |
| 401 /// A [ChunkedConversionSink] for decoding chunks of Base64 strings to data. |
| 360 class _Base64DecoderSink extends ChunkedConversionSink<String> { | 402 class _Base64DecoderSink extends ChunkedConversionSink<String> { |
| 403 /// The encoder used to decode each chunk. |
| 361 final Base64Decoder _decoder = new Base64Decoder(); | 404 final Base64Decoder _decoder = new Base64Decoder(); |
| 405 |
| 406 /// The underlying sink to which to emit the decoded strings. |
| 362 final ChunkedConversionSink<List<int>> _outSink; | 407 final ChunkedConversionSink<List<int>> _outSink; |
| 408 |
| 409 /// The as-yet-unconverted text. |
| 410 /// |
| 411 /// This is used to handle a chunk stopping partway in the middle of a |
| 412 /// URL-encoded `=` character. |
| 363 String _unconverted = ""; | 413 String _unconverted = ""; |
| 364 | 414 |
| 365 _Base64DecoderSink(this._outSink); | 415 _Base64DecoderSink(this._outSink); |
| 366 | 416 |
| 367 void add(String chunk) { | 417 void add(String chunk) { |
| 368 if (chunk.isEmpty) return; | 418 if (chunk.isEmpty) return; |
| 369 if (_unconverted.isNotEmpty) { | 419 if (_unconverted.isNotEmpty) { |
| 370 chunk = _unconverted + chunk; | 420 chunk = _unconverted + chunk; |
| 371 } | 421 } |
| 372 chunk = chunk.replaceAll(_ENCODED_PAD, _PAD); | 422 chunk = chunk.replaceAll(_ENCODED_PAD, _PAD); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 383 } | 433 } |
| 384 } | 434 } |
| 385 | 435 |
| 386 void close() { | 436 void close() { |
| 387 if (_unconverted.isNotEmpty) { | 437 if (_unconverted.isNotEmpty) { |
| 388 _outSink.add(_decoder.convert(_unconverted)); | 438 _outSink.add(_decoder.convert(_unconverted)); |
| 389 } | 439 } |
| 390 _outSink.close(); | 440 _outSink.close(); |
| 391 } | 441 } |
| 392 } | 442 } |
| OLD | NEW |