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

Unified Diff: lib/src/base64.dart

Issue 1159093002: Implement a Base64 codec (Closed) Base URL: https://github.com/dart-lang/crypto.git@master
Patch Set: Created 5 years, 7 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 side-by-side diff with in-line comments
Download patch
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();
+ }
+}
+

Powered by Google App Engine
This is Rietveld 408576698