Chromium Code Reviews| 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 |