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

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

Issue 2754923002: Tweak corelib files so dartfmt can do a better job. Use // comments to force line wrapping for long… (Closed)
Patch Set: Tweak corelib files so dartfmt can do a better job. Use // comments to force line wrapping for long… 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
« no previous file with comments | « no previous file | sdk/lib/core/uri.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
531 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, 519 __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, //
532 __, __, __, __, __, _p, __, __, __, __, __, 62, __, 62, __, 63, 520 __, __, __, __, __, _p, __, __, __, __, __, 62, __, 62, __, 63, //
533 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, __, __, __, _p, __, __, 521 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, __, __, __, _p, __, __, //
534 __, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 522 __, 00, 01, 02, 03, 04, 05, 06, 07, 08, 09, 10, 11, 12, 13, 14, //
535 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, __, __, __, __, 63, 523 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, __, __, __, __, 63, //
536 __, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 524 __, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, //
537 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, __, __, __, __, __, 525 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, __, __, __, __, __, //
538 ]); 526 ]);
539 527
540 // Character constants. 528 // Character constants.
541 static const int _char_percent = 0x25; // '%'. 529 static const int _char_percent = 0x25; // '%'.
542 static const int _char_3 = 0x33; // '3'. 530 static const int _char_3 = 0x33; // '3'.
543 static const int _char_d = 0x64; // 'd'. 531 static const int _char_d = 0x64; // 'd'.
544 532
545 /** 533 /**
546 * Maintains the intermediate state of a partly-decoded input. 534 * Maintains the intermediate state of a partly-decoded input.
547 * 535 *
548 * Base64 is decoded in chunks of four characters. If a chunk does not 536 * 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 537 * contain a full block, the decoded bits (six per character) of the
550 * available characters are stored in [_state] until the next call to 538 * available characters are stored in [_state] until the next call to
551 * [_decode] or [_close]. 539 * [_decode] or [_close].
552 * 540 *
553 * If no padding has been seen, the value is 541 * 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); 574 assert(state >= 0);
587 return state >> _valueShift; 575 return state >> _valueShift;
588 } 576 }
589 577
590 /** 578 /**
591 * Encodes a number of expected padding characters to be stored in [_state]. 579 * Encodes a number of expected padding characters to be stored in [_state].
592 */ 580 */
593 static int _encodePaddingState(int expectedPadding) { 581 static int _encodePaddingState(int expectedPadding) {
594 assert(expectedPadding >= 0); 582 assert(expectedPadding >= 0);
595 assert(expectedPadding <= 5); 583 assert(expectedPadding <= 5);
596 return -expectedPadding - 1; // ~expectedPadding adapted to dart2js. 584 return -expectedPadding - 1; // ~expectedPadding adapted to dart2js.
597 } 585 }
598 586
599 /** 587 /**
600 * Extracts expected padding character count from a [_state] value. 588 * Extracts expected padding character count from a [_state] value.
601 */ 589 */
602 static int _statePadding(int state) { 590 static int _statePadding(int state) {
603 assert(state < 0); 591 assert(state < 0);
604 return -state - 1; // ~state adapted to dart2js. 592 return -state - 1; // ~state adapted to dart2js.
605 } 593 }
606 594
607 static bool _hasSeenPadding(int state) => state < 0; 595 static bool _hasSeenPadding(int state) => state < 0;
608 596
609 /** 597 /**
610 * Decodes [input] from [start] to [end]. 598 * Decodes [input] from [start] to [end].
611 * 599 *
612 * Returns a [Uint8List] with the decoded bytes. 600 * Returns a [Uint8List] with the decoded bytes.
613 * If a previous call had an incomplete four-character block, the bits from 601 * If a previous call had an incomplete four-character block, the bits from
614 * those are included in decoding 602 * those are included in decoding
(...skipping 11 matching lines...) Expand all
626 _state = decodeChunk(input, start, end, buffer, 0, _state); 614 _state = decodeChunk(input, start, end, buffer, 0, _state);
627 return buffer; 615 return buffer;
628 } 616 }
629 617
630 /** Checks that [_state] represents a valid decoding. */ 618 /** Checks that [_state] represents a valid decoding. */
631 void close(String input, int end) { 619 void close(String input, int end) {
632 if (_state < _encodePaddingState(0)) { 620 if (_state < _encodePaddingState(0)) {
633 throw new FormatException("Missing padding character", input, end); 621 throw new FormatException("Missing padding character", input, end);
634 } 622 }
635 if (_state > 0) { 623 if (_state > 0) {
636 throw new FormatException("Invalid length, must be multiple of four", 624 throw new FormatException(
637 input, end); 625 "Invalid length, must be multiple of four", input, end);
638 } 626 }
639 _state = _encodePaddingState(0); 627 _state = _encodePaddingState(0);
640 } 628 }
641 629
642 /** 630 /**
643 * Decodes [input] from [start] to [end]. 631 * Decodes [input] from [start] to [end].
644 * 632 *
645 * Includes the state returned by a previous call in the decoding. 633 * Includes the state returned by a previous call in the decoding.
646 * Writes the decoding to [output] at [outIndex], and there must 634 * Writes the decoding to [output] at [outIndex], and there must
647 * be room in the output. 635 * be room in the output.
648 */ 636 */
649 static int decodeChunk(String input, int start, int end, 637 static int decodeChunk(String input, int start, int end, Uint8List output,
650 Uint8List output, int outIndex, 638 int outIndex, int state) {
651 int state) {
652 assert(!_hasSeenPadding(state)); 639 assert(!_hasSeenPadding(state));
653 const int asciiMask = 127; 640 const int asciiMask = 127;
654 const int asciiMax = 127; 641 const int asciiMax = 127;
655 const int eightBitMask = 0xFF; 642 const int eightBitMask = 0xFF;
656 const int bitsPerCharacter = 6; 643 const int bitsPerCharacter = 6;
657 644
658 int bits = _stateBits(state); 645 int bits = _stateBits(state);
659 int count = _stateCount(state); 646 int count = _stateCount(state);
660 // String contents should be all ASCII. 647 // String contents should be all ASCII.
661 // Instead of checking for each character, we collect the bitwise-or of 648 // 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; 702 if (char < 0 || char > asciiMax) break;
716 } 703 }
717 throw new FormatException("Invalid character", input, i); 704 throw new FormatException("Invalid character", input, i);
718 } 705 }
719 706
720 /** 707 /**
721 * Allocates a buffer with room for the decoding of a substring of [input]. 708 * Allocates a buffer with room for the decoding of a substring of [input].
722 * 709 *
723 * Includes room for the characters in [state], and handles padding correctly. 710 * Includes room for the characters in [state], and handles padding correctly.
724 */ 711 */
725 static Uint8List _allocateBuffer(String input, int start, int end, 712 static Uint8List _allocateBuffer(
726 int state) { 713 String input, int start, int end, int state) {
727 assert(state >= 0); 714 assert(state >= 0);
728 int paddingStart = _trimPaddingChars(input, start, end); 715 int paddingStart = _trimPaddingChars(input, start, end);
729 int length = _stateCount(state) + (paddingStart - start); 716 int length = _stateCount(state) + (paddingStart - start);
730 // Three bytes per full four bytes in the input. 717 // Three bytes per full four bytes in the input.
731 int bufferLength = (length >> 2) * 3; 718 int bufferLength = (length >> 2) * 3;
732 // If padding was seen, then this is the last chunk, and the final partial 719 // If padding was seen, then this is the last chunk, and the final partial
733 // chunk should be decoded too. 720 // chunk should be decoded too.
734 int remainderLength = length & 3; 721 int remainderLength = length & 3;
735 if (remainderLength != 0 && paddingStart < end) { 722 if (remainderLength != 0 && paddingStart < end) {
736 bufferLength += remainderLength - 1; 723 bufferLength += remainderLength - 1;
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
842 if (start == end) break; 829 if (start == end) break;
843 char = input.codeUnitAt(start); 830 char = input.codeUnitAt(start);
844 } 831 }
845 // Expects 'D' or 'd'. 832 // Expects 'D' or 'd'.
846 if ((char | 0x20) != _char_d) break; 833 if ((char | 0x20) != _char_d) break;
847 start++; 834 start++;
848 expectedPadding--; 835 expectedPadding--;
849 if (start == end) break; 836 if (start == end) break;
850 } 837 }
851 if (start != end) { 838 if (start != end) {
852 throw new FormatException("Invalid padding character", 839 throw new FormatException("Invalid padding character", input, start);
853 input, start);
854 } 840 }
855 return _encodePaddingState(expectedPadding); 841 return _encodePaddingState(expectedPadding);
856 } 842 }
857 } 843 }
858 844
859 class _Base64DecoderSink extends StringConversionSinkBase { 845 class _Base64DecoderSink extends StringConversionSinkBase {
860 /** Output sink */ 846 /** Output sink */
861 final Sink<List<int>> _sink; 847 final Sink<List<int>> _sink;
862 final _Base64Decoder _decoder = new _Base64Decoder(); 848 final _Base64Decoder _decoder = new _Base64Decoder();
863 849
(...skipping 14 matching lines...) Expand all
878 end = RangeError.checkValidRange(start, end, string.length); 864 end = RangeError.checkValidRange(start, end, string.length);
879 if (start == end) return; 865 if (start == end) return;
880 Uint8List buffer = _decoder.decode(string, start, end); 866 Uint8List buffer = _decoder.decode(string, start, end);
881 if (buffer != null) _sink.add(buffer); 867 if (buffer != null) _sink.add(buffer);
882 if (isLast) { 868 if (isLast) {
883 _decoder.close(string, end); 869 _decoder.close(string, end);
884 _sink.close(); 870 _sink.close();
885 } 871 }
886 } 872 }
887 } 873 }
OLDNEW
« no previous file with comments | « no previous file | sdk/lib/core/uri.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698