Chromium Code Reviews| Index: lib/src/base64.dart |
| diff --git a/lib/src/crypto_utils.dart b/lib/src/base64.dart |
| similarity index 51% |
| copy from lib/src/crypto_utils.dart |
| copy to lib/src/base64.dart |
| index 515c1e95eaffa121ac3482497adb86d3efc1acfd..9e52cea20b27cb245d04b04fac59213625b556ad 100644 |
| --- a/lib/src/crypto_utils.dart |
| +++ b/lib/src/base64.dart |
| @@ -1,35 +1,8 @@ |
| -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| -// for details. All rights reserved. Use of this source code is governed by a |
| -// BSD-style license that can be found in the LICENSE file. |
| - |
| part of crypto; |
| -abstract class _CryptoUtils { |
| - static String bytesToHex(List<int> bytes) { |
| - var result = new StringBuffer(); |
| - for (var part in bytes) { |
| - result.write('${part < 16 ? '0' : ''}${part.toRadixString(16)}'); |
| - } |
| - return result.toString(); |
| - } |
| - |
| - static const int PAD = 61; // '=' |
| - static const int CR = 13; // '\r' |
| - static const int LF = 10; // '\n' |
| - static const int LINE_LENGTH = 76; |
| - |
| - static const String _encodeTable = |
| - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
| - |
| - static const String _encodeTableUrlSafe = |
| - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; |
| +const Base64Codec Base64 = const Base64Codec(); |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:41
Name it either "BASE64" or "base64" (style guide f
Alexander Ivanov
2015/05/29 13:12:06
Done.
|
| - // Lookup table used for finding Base 64 alphabet index of a given byte. |
| - // -2 : Outside Base 64 alphabet. |
| - // -1 : '\r' or '\n' |
| - // 0 : = (Padding character). |
| - // >0 : Base 64 alphabet index of given byte. |
| - static const List<int> _decodeTable = |
| +const List<int> _decodeTable = |
| const [ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -1, -2, -2, |
| -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, 62, -2, 63, |
| @@ -47,21 +20,69 @@ abstract class _CryptoUtils { |
| -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2 ]; |
| - static String bytesToBase64(List<int> bytes, |
| - [bool urlSafe = false, |
| - bool addLineSeparator = false]) { |
| +const String _encodeTableUrlSafe = |
| + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; |
| + |
| +const String _encodeTable = |
| + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
| + |
| +const int LINE_LENGTH = 76; |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
These should probably be private.
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| +const int PAD = 61; // '=' |
| +const int CR = 13; // '\r' |
| +const int LF = 10; // '\n' |
| + |
| +class Base64Codec extends Codec<List<int>, String> { |
| + |
| + final bool _urlSafe; |
| + final bool _addLineSeparator; |
| + |
| + /** |
| + * Instantiates a new [Base64Codec]. |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
Document the parameters, say what they do and what
Alexander Ivanov
2015/05/29 13:12:04
Done.
|
| + * |
| + */ |
| + |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
No empty line here.
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + const Base64Codec({ bool urlSafe: false, bool addLineSeparator: false }) |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:41
No space between "{" and "bool" (or before "}").
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + : _urlSafe = urlSafe, |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
indent four spaces before :, then one space after.
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + _addLineSeparator = addLineSeparator; |
| + |
| + String get name => "base64"; |
| + |
| + String encode(List<int> bytes, |
| + { bool urlSafe, |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
Again no space after '{' or before '}' (becaue sty
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + bool addLineSeparator }) { |
| + if (urlSafe == null) urlSafe = _urlSafe; |
| + if (addLineSeparator == null) addLineSeparator = _addLineSeparator; |
| + return new Base64Encoder(urlSafe: urlSafe, addLineSeparator: addLineSeparator) |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
Long line, break it somewhere.
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + .convert(bytes); |
| + } |
| + |
| + Base64Encoder get encoder => new Base64Encoder(urlSafe: _urlSafe, addLineSeparator: _addLineSeparator); |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
Long line.
Alexander Ivanov
2015/05/29 13:12:04
Done.
|
| + Base64Decoder get decoder => new Base64Decoder(); |
| + |
| +} |
| + |
| + |
| +class Base64Encoder extends Converter<List<int>, String> { |
|
Lasse Reichstein Nielsen
2015/05/29 07:15:15
Could generally use more comments, but ok for now.
Alexander Ivanov
2015/05/29 13:12:06
Done.
|
| + final bool _urlSafe; |
| + final bool _addLineSeparator; |
| + |
| + const Base64Encoder({ bool urlSafe: false, bool addLineSeparator: false}) |
| + : _urlSafe = urlSafe, |
| + _addLineSeparator = addLineSeparator; |
| + |
| + String convert(List<int> bytes) { |
| int len = bytes.length; |
| if (len == 0) { |
| return ""; |
| } |
| - final String lookup = urlSafe ? _encodeTableUrlSafe : _encodeTable; |
| + final String lookup = _urlSafe ? _encodeTableUrlSafe : _encodeTable; |
| // Size of 24 bit chunks. |
| final int remainderLength = len.remainder(3); |
| final int chunkLength = len - remainderLength; |
| // Size of base output. |
| int outputLen = ((len ~/ 3) * 4) + ((remainderLength > 0) ? 4 : 0); |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:41
This seems too complex. Let's look at that later :
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| // Add extra for line separators. |
| - if (addLineSeparator) { |
| + if (_addLineSeparator) { |
| outputLen += ((outputLen - 1) ~/ LINE_LENGTH) << 1; |
| } |
| List<int> out = new List<int>(outputLen); |
| @@ -77,7 +98,7 @@ abstract class _CryptoUtils { |
| out[j++] = lookup.codeUnitAt((x >> 6) & 0x3F); |
| out[j++] = lookup.codeUnitAt(x & 0x3f); |
| // Add optional line separator for each 76 char output. |
| - if (addLineSeparator && ++c == 19 && j < outputLen - 2) { |
| + if (_addLineSeparator && ++c == 19 && j < outputLen - 2) { |
| out[j++] = CR; |
| out[j++] = LF; |
| c = 0; |
| @@ -104,7 +125,56 @@ abstract class _CryptoUtils { |
| return new String.fromCharCodes(out); |
| } |
| - static List<int> base64StringToBytes(String input) { |
| + _Base64EncoderSink startChunkedConversion(Sink<String> sink) { |
| + StringConversionSink stringSink; |
| + if (sink is StringConversionSink) { |
| + stringSink = sink; |
| + } else { |
| + stringSink = new StringConversionSink.from(sink); |
| + } |
| + return new _Base64EncoderSink(stringSink, _urlSafe, _addLineSeparator); |
| + } |
| +} |
| + |
| +class _Base64EncoderSink extends ChunkedConversionSink<List<int>> { |
| + |
| + final Base64Encoder _encoder; |
| + final ChunkedConversionSink<String> _outSink; |
| + final List<int> _buffer = new List<int>(3); |
| + int _buffer_count = 0; |
|
Lasse Reichstein Nielsen
2015/05/29 07:15:16
_bufferCount.
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + |
| + _Base64EncoderSink(this._outSink, urlSafe, addLineSeparator) |
| + : _encoder = new Base64Encoder(urlSafe: urlSafe, addLineSeparator: addLineSeparator); |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
long line, indent : by four.
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + |
| + void add(List<int> chunk) { |
| + |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
We usually don't have an empty line at the beginni
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + var next_buffer_length = (chunk.length + _buffer_count) % 3; |
| + |
| + if(chunk.length + _buffer_count >= 3) { |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
space between "if" and "(". More cases below.
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + int remainder = chunk.length - next_buffer_length; |
| + var decodable = new List.from(_buffer.sublist(0, _buffer_count))..addAll(chunk.sublist(0, remainder)); |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
long line
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + _buffer.setRange(0, next_buffer_length, chunk.sublist(remainder)); |
|
Lasse Reichstein Nielsen
2015/05/29 07:15:16
Use the fourth argument to setRange instead of cre
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + |
| + _outSink.add(_encoder.convert(decodable)); |
|
Lasse Reichstein Nielsen
2015/05/29 07:15:16
The current thing works, which is great, so this i
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + } |
| + else { |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
Else goes on the same line as '}'.
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + _buffer.setRange(_buffer_count, _buffer_count + chunk.length, chunk); |
|
Lasse Reichstein Nielsen
2015/05/29 07:15:16
_buffer_cunt + chunk.length => nextBufferLength
Alexander Ivanov
2015/05/29 13:12:04
Done.
|
| + } |
| + _buffer_count = next_buffer_length; |
| + } |
| + |
| + void close() { |
| + if(_buffer_count > 0) { |
| + _outSink.add(_encoder.convert(_buffer.sublist(0, _buffer_count))); |
| + } |
| + _outSink.close(); |
| + } |
| +} |
| + |
| +class Base64Decoder extends Converter<String, List<int>> { |
| + const Base64Decoder(); |
| + |
| + List<int> convert(String input, {bool alwaysPadding: false}) { |
| int len = input.length; |
| if (len == 0) { |
| return new List<int>(0); |
| @@ -154,7 +224,47 @@ abstract class _CryptoUtils { |
| if (o < outputLen) out[o++] = x & 0xFF; |
| } |
| } |
| + |
| return out; |
| } |
| + _Base64DecoderSink startChunkedConversion(Sink<List<int>> sink) { |
| + if(sink is! ByteConversionSink) { |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:41
Indent by 2 only.
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + sink = new ByteConversionSink.from(sink); |
| + } |
| + return new _Base64DecoderSink(sink); |
| + } |
| } |
| + |
| + |
| +class _Base64DecoderSink extends ChunkedConversionSink<String> { |
| + |
| + final Base64Decoder _decoder = new Base64Decoder(); |
| + final ChunkedConversionSink<List<int>> _outSink; |
| + String _buffer = ""; |
| + |
| + _Base64DecoderSink(this._outSink); |
| + |
| + void add(String chunk) { |
| + int next_buffer_length = (chunk.length + _buffer.length) % 4; |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
We use camelCase for variables, so "nextBufferLeng
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + |
| + if(chunk.length + _buffer.length >= 4) { |
| + int remainder = chunk.length - next_buffer_length; |
| + String decodable = _buffer + chunk.substring(0, remainder); |
| + _buffer = chunk.substring(remainder); |
| + |
| + _outSink.add(_decoder.convert(decodable)); |
| + } |
| + else { |
| + _buffer += chunk; |
| + } |
| + } |
| + |
| + void close() { |
| + if (!_buffer.isEmpty) { |
| + throw new FormatException("Size of Base 64 input must be a multiple of 4 : ${_buffer.toString()}"); |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:41
Use other arguments to FormatException (source and
Alexander Ivanov
2015/05/29 13:12:05
Done.
|
| + } |
| + _outSink.close(); |
| + } |
| +} |
| + |