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

Side by Side Diff: lib/src/base64.dart

Issue 1255293010: Simplify base64 streaming decoder, drop decoding check. (Closed) Base URL: git@github.com:dart-lang/crypto.git@master
Patch Set: Created 5 years, 4 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 | test/base64_test.dart » ('j') | test/base64_test.dart » ('J')
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « no previous file | test/base64_test.dart » ('j') | test/base64_test.dart » ('J')

Powered by Google App Engine
This is Rietveld 408576698