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 part of crypto; | 5 part of crypto; |
6 | 6 |
7 const Base64Codec BASE64 = const Base64Codec(); | 7 const Base64Codec BASE64 = const Base64Codec(); |
8 | 8 |
9 const List<int> _decodeTable = | 9 const List<int> _decodeTable = |
10 const [ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -1, -2, -2, | 10 const [ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -1, -2, -2, |
(...skipping 13 matching lines...) Expand all Loading... | |
24 -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, |
25 -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 ]; |
26 | 26 |
27 const String _encodeTableUrlSafe = | 27 const String _encodeTableUrlSafe = |
28 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; | 28 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; |
29 | 29 |
30 const String _encodeTable = | 30 const String _encodeTable = |
31 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | 31 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
32 | 32 |
33 const List<String> _URL_SAFE_CHARACTERS = const ['+', '/']; | 33 const List<String> _URL_SAFE_CHARACTERS = const ['+', '/']; |
34 const List<String> _URL_UNSAFE_CHARACTERS = const ['-', '_']; | 34 const List<String> _URL_UNSAFE_CHARACTERS = const ['-', '_']; |
Søren Gjesse
2015/08/05 07:18:33
Remove these two constants as well.
| |
35 | 35 |
36 const int _LINE_LENGTH = 76; | 36 const int _LINE_LENGTH = 76; |
37 const int _CR = 13; // '\r' | 37 const int _CR = 13; // '\r' |
38 const int _LF = 10; // '\n' | 38 const int _LF = 10; // '\n' |
39 const List<int> _PAD_BYTES = const [61]; // '=' | 39 const List<int> _PAD_BYTES = const [61]; // '=' |
40 const List<int> _ENCODED_PAD_BYTES = const [37, 51, 68]; // '%3D' | 40 const List<int> _ENCODED_PAD_BYTES = const [37, 51, 68]; // '%3D' |
41 const String _PAD = "="; | 41 const String _PAD = "="; |
42 const String _ENCODED_PAD = "%3D"; | 42 const String _ENCODED_PAD = "%3D"; |
43 | 43 |
44 class Base64Codec extends Codec<List<int>, String> { | 44 class Base64Codec extends Codec<List<int>, String> { |
(...skipping 232 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
277 * Instantiates a new [Base64Decoder] | 277 * Instantiates a new [Base64Decoder] |
278 */ | 278 */ |
279 const Base64Decoder(); | 279 const Base64Decoder(); |
280 | 280 |
281 List<int> convert(String input) { | 281 List<int> convert(String input) { |
282 int length = input.length; | 282 int length = input.length; |
283 if (length == 0) { | 283 if (length == 0) { |
284 return new List<int>(0); | 284 return new List<int>(0); |
285 } | 285 } |
286 | 286 |
287 bool expectedSafe = false; | |
288 bool expectedUnsafe = false; | |
289 | |
290 int normalLength = 0; | 287 int normalLength = 0; |
291 int i = 0; | 288 int i = 0; |
292 // Count '\r', '\n' and illegal characters, check if | 289 // Count '\r', '\n' and illegal characters, check if |
293 // '/', '+' / '-', '_' are used consistently, for illegal characters, | 290 // '/', '+' / '-', '_' are used consistently, for illegal characters, |
294 // throw an exception. | 291 // throw an exception. |
295 | 292 |
296 while (i < length) { | 293 while (i < length) { |
297 int codeUnit = input.codeUnitAt(i); | 294 int codeUnit = input.codeUnitAt(i); |
298 int c = _decodeTable[codeUnit]; | 295 int c = _decodeTable[codeUnit]; |
299 if (c == -2) { | 296 if (c == -2) { |
300 if (codeUnit == _ENCODED_PAD_BYTES[0] && | 297 if (codeUnit == _ENCODED_PAD_BYTES[0] && |
301 i < length - 2 && | 298 i < length - 2 && |
302 input.codeUnitAt(i + 1) == _ENCODED_PAD_BYTES[1] && | 299 input.codeUnitAt(i + 1) == _ENCODED_PAD_BYTES[1] && |
303 input.codeUnitAt(i + 2) == _ENCODED_PAD_BYTES[2]) { | 300 input.codeUnitAt(i + 2) == _ENCODED_PAD_BYTES[2]) { |
304 normalLength++; | 301 normalLength++; |
305 i += 2; | 302 i += 2; |
306 } else { | 303 } else { |
307 throw new FormatException('Invalid character', input, i); | 304 throw new FormatException('Invalid character', input, i); |
308 } | 305 } |
309 } else if (input[i] == _URL_UNSAFE_CHARACTERS[0] || | |
310 input[i] == _URL_UNSAFE_CHARACTERS[1]) { | |
311 | |
312 if (expectedSafe) { | |
313 throw new FormatException('Unsafe character in URL-safe string', | |
314 input, i); | |
315 } | |
316 expectedUnsafe = true; | |
317 } else if (input[i] == _URL_SAFE_CHARACTERS[0] || | |
318 input[i] == _URL_SAFE_CHARACTERS[1]) { | |
319 if (expectedUnsafe) { | |
320 throw new FormatException('Invalid character', input, i); | |
321 } | |
322 expectedSafe = true; | |
323 } | 306 } |
324 if (c >= 0) normalLength++; | 307 if (c >= 0) normalLength++; |
325 i++; | 308 i++; |
326 } | 309 } |
327 | 310 |
328 if (normalLength % 4 != 0) { | 311 if (normalLength % 4 != 0) { |
329 throw new FormatException('''Size of Base 64 characters in Input | 312 throw new FormatException('''Size of Base 64 characters in Input |
330 must be a multiple of 4''', input, normalLength); | 313 must be a multiple of 4''', input, normalLength); |
331 } | 314 } |
332 | 315 |
(...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
377 } | 360 } |
378 return new _Base64DecoderSink(sink); | 361 return new _Base64DecoderSink(sink); |
379 } | 362 } |
380 } | 363 } |
381 | 364 |
382 | 365 |
383 class _Base64DecoderSink extends ChunkedConversionSink<String> { | 366 class _Base64DecoderSink extends ChunkedConversionSink<String> { |
384 | 367 |
385 final Base64Decoder _decoder = new Base64Decoder(); | 368 final Base64Decoder _decoder = new Base64Decoder(); |
386 final ChunkedConversionSink<List<int>> _outSink; | 369 final ChunkedConversionSink<List<int>> _outSink; |
387 String _buffer = ""; | 370 String _unconverted = ""; |
388 bool _isSafe = false; | |
389 bool _isUnsafe = false; | |
390 int _expectPaddingCount = 3; | |
391 | 371 |
392 _Base64DecoderSink(this._outSink); | 372 _Base64DecoderSink(this._outSink); |
393 | 373 |
394 void add(String chunk) { | 374 void add(String chunk) { |
395 if (chunk.isEmpty) return; | 375 if (chunk.isEmpty) return; |
396 | 376 if (_unconverted.isNotEmpty) { |
397 int nextBufferLength = (chunk.length + _buffer.length) % 4; | 377 chunk = _unconverted + chunk; |
398 | |
399 if (chunk.length >= _expectPaddingCount && | |
400 chunk.substring(0, _expectPaddingCount) == | |
401 _ENCODED_PAD.substring(3 - _expectPaddingCount, 3)) { | |
402 chunk = _PAD + chunk.substring(_expectPaddingCount); | |
403 _expectPaddingCount = 3; | |
404 } else if(chunk.length < _expectPaddingCount && | |
405 chunk == _ENCODED_PAD.substring( | |
406 3 - _expectPaddingCount, | |
407 3 - _expectPaddingCount + chunk.length)) { | |
408 _expectPaddingCount -= chunk.length; | |
409 chunk = ""; | |
410 } | 378 } |
411 | 379 chunk = chunk.replaceAll(_ENCODED_PAD, _PAD); |
412 if (chunk.length > 1 && | 380 int decodableLength = chunk.length; |
413 chunk[chunk.length - 2] == _ENCODED_PAD[0] && | 381 // If chunk ends in "%" or "%3", it may be a partial encoded pad. |
414 chunk[chunk.length - 1] == _ENCODED_PAD[1]) { | 382 // If chunk is smaller than 4 characters, don't bother checking. |
415 _expectPaddingCount = 1; | 383 if (chunk.length > 3 && |
416 chunk = chunk.substring(0, chunk.length - 2); | 384 chunk.contains(_ENCODED_PAD[0], chunk.length - 2)) { |
417 } else if (!chunk.isEmpty && chunk[chunk.length - 1] == _ENCODED_PAD[0]) { | 385 decodableLength = chunk.lastIndexOf(_ENCODED_PAD[0]); |
418 _expectPaddingCount = 2; | |
419 chunk = chunk.substring(0, chunk.length - 1); | |
420 } | 386 } |
421 | 387 decodableLength -= decodableLength % 4; |
422 chunk = chunk.replaceAll(_ENCODED_PAD, _PAD); | 388 _unconverted = chunk.substring(decodableLength); |
423 | 389 if (decodableLength > 0) { |
424 if (chunk.length + _buffer.length >= 4) { | 390 _outSink.add(_decoder.convert(chunk.substring(0, decodableLength))); |
425 int remainder = chunk.length - nextBufferLength; | |
426 String decodable = _buffer + chunk.substring(0, remainder); | |
427 _buffer = chunk.substring(remainder); | |
428 | |
429 for (int i = 0;i < decodable.length; i++) { | |
430 if (decodable[i] == _URL_UNSAFE_CHARACTERS[0] || | |
431 decodable[i] == _URL_UNSAFE_CHARACTERS[1]) { | |
432 if (_isSafe) { | |
433 throw new FormatException('Unsafe character in URL-safe string', | |
434 decodable, i); | |
435 } | |
436 _isUnsafe = true; | |
437 } else if (decodable[i] == _URL_SAFE_CHARACTERS[0] || | |
438 decodable[i] == _URL_SAFE_CHARACTERS[1]) { | |
439 if (_isUnsafe) { | |
440 throw new FormatException('Invalid character', decodable, i); | |
441 } | |
442 _isSafe = true; | |
443 } | |
444 } | |
445 | |
446 _outSink.add(_decoder.convert(decodable)); | |
447 } else { | |
448 _buffer += chunk; | |
449 } | 391 } |
450 } | 392 } |
451 | 393 |
452 void close() { | 394 void close() { |
453 if (_expectPaddingCount == 0 && | 395 if (_unconverted.isNotEmpty) { |
454 _buffer.length == 3) { | 396 _outSink.add(_decoder.convert(_unconverted)); |
455 _outSink.add(_buffer + _PAD); | |
Bill Hesse
2015/08/04 16:33:33
This line was wrong, should have been .add(_decode
| |
456 } else if (_expectPaddingCount < 3 && | |
457 _buffer.length + 3 - _expectPaddingCount == 4) { | |
458 _outSink.add(_buffer + _ENCODED_PAD.substring(0, 3 - _expectPaddingCount)) ; | |
459 } else if (_expectPaddingCount != 3 || !_buffer.isEmpty) { | |
460 throw new FormatException( | |
461 "Size of Base 64 input must be a multiple of 4", | |
462 _buffer + _PAD.substring(0, 3 - _expectPaddingCount), | |
463 _buffer.length + 3 - _expectPaddingCount); | |
464 } | 397 } |
465 _outSink.close(); | 398 _outSink.close(); |
466 } | 399 } |
467 } | 400 } |
468 | 401 |
469 | 402 |
OLD | NEW |