Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 | |
| 3 // BSD-style license that can be found in the LICENSE file. | |
| 4 | |
| 5 part of crypto; | 1 part of crypto; |
| 6 | 2 |
| 7 abstract class _CryptoUtils { | 3 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.
| |
| 8 static String bytesToHex(List<int> bytes) { | |
| 9 var result = new StringBuffer(); | |
| 10 for (var part in bytes) { | |
| 11 result.write('${part < 16 ? '0' : ''}${part.toRadixString(16)}'); | |
| 12 } | |
| 13 return result.toString(); | |
| 14 } | |
| 15 | 4 |
| 16 static const int PAD = 61; // '=' | 5 const List<int> _decodeTable = |
| 17 static const int CR = 13; // '\r' | |
| 18 static const int LF = 10; // '\n' | |
| 19 static const int LINE_LENGTH = 76; | |
| 20 | |
| 21 static const String _encodeTable = | |
| 22 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
| 23 | |
| 24 static const String _encodeTableUrlSafe = | |
| 25 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; | |
| 26 | |
| 27 // Lookup table used for finding Base 64 alphabet index of a given byte. | |
| 28 // -2 : Outside Base 64 alphabet. | |
| 29 // -1 : '\r' or '\n' | |
| 30 // 0 : = (Padding character). | |
| 31 // >0 : Base 64 alphabet index of given byte. | |
| 32 static const List<int> _decodeTable = | |
| 33 const [ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -1, -2, -2, | 6 const [ -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -1, -2, -2, -1, -2, -2, |
| 34 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 7 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 35 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, 62, -2, 63, | 8 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, 62, -2, 62, -2, 63, |
| 36 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, 0, -2, -2, | 9 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -2, -2, -2, 0, -2, -2, |
| 37 -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, | 10 -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
| 38 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, 63, | 11 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -2, -2, -2, -2, 63, |
| 39 -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, | 12 -2, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
| 40 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2, | 13 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -2, -2, -2, -2, -2, |
| 41 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 14 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 42 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 15 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 43 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 16 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 44 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 17 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 45 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 18 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 46 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 19 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 47 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, | 20 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, |
| 48 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2 ]; | 21 -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2, -2 ]; |
| 49 | 22 |
| 50 static String bytesToBase64(List<int> bytes, | 23 const String _encodeTableUrlSafe = |
| 51 [bool urlSafe = false, | 24 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; |
| 52 bool addLineSeparator = false]) { | 25 |
| 26 const String _encodeTable = | |
| 27 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
| 28 | |
| 29 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.
| |
| 30 const int PAD = 61; // '=' | |
| 31 const int CR = 13; // '\r' | |
| 32 const int LF = 10; // '\n' | |
| 33 | |
| 34 class Base64Codec extends Codec<List<int>, String> { | |
| 35 | |
| 36 final bool _urlSafe; | |
| 37 final bool _addLineSeparator; | |
| 38 | |
| 39 /** | |
| 40 * 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.
| |
| 41 * | |
| 42 */ | |
| 43 | |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
No empty line here.
Alexander Ivanov
2015/05/29 13:12:05
Done.
| |
| 44 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.
| |
| 45 : _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.
| |
| 46 _addLineSeparator = addLineSeparator; | |
| 47 | |
| 48 String get name => "base64"; | |
| 49 | |
| 50 String encode(List<int> bytes, | |
| 51 { 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.
| |
| 52 bool addLineSeparator }) { | |
| 53 if (urlSafe == null) urlSafe = _urlSafe; | |
| 54 if (addLineSeparator == null) addLineSeparator = _addLineSeparator; | |
| 55 return new Base64Encoder(urlSafe: urlSafe, addLineSeparator: addLineSeparato r) | |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
Long line, break it somewhere.
Alexander Ivanov
2015/05/29 13:12:05
Done.
| |
| 56 .convert(bytes); | |
| 57 } | |
| 58 | |
| 59 Base64Encoder get encoder => new Base64Encoder(urlSafe: _urlSafe, addLineSepar ator: _addLineSeparator); | |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
Long line.
Alexander Ivanov
2015/05/29 13:12:04
Done.
| |
| 60 Base64Decoder get decoder => new Base64Decoder(); | |
| 61 | |
| 62 } | |
| 63 | |
| 64 | |
| 65 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.
| |
| 66 final bool _urlSafe; | |
| 67 final bool _addLineSeparator; | |
| 68 | |
| 69 const Base64Encoder({ bool urlSafe: false, bool addLineSeparator: false}) | |
| 70 : _urlSafe = urlSafe, | |
| 71 _addLineSeparator = addLineSeparator; | |
| 72 | |
| 73 String convert(List<int> bytes) { | |
| 53 int len = bytes.length; | 74 int len = bytes.length; |
| 54 if (len == 0) { | 75 if (len == 0) { |
| 55 return ""; | 76 return ""; |
| 56 } | 77 } |
| 57 final String lookup = urlSafe ? _encodeTableUrlSafe : _encodeTable; | 78 final String lookup = _urlSafe ? _encodeTableUrlSafe : _encodeTable; |
| 58 // Size of 24 bit chunks. | 79 // Size of 24 bit chunks. |
| 59 final int remainderLength = len.remainder(3); | 80 final int remainderLength = len.remainder(3); |
| 60 final int chunkLength = len - remainderLength; | 81 final int chunkLength = len - remainderLength; |
| 61 // Size of base output. | 82 // Size of base output. |
| 62 int outputLen = ((len ~/ 3) * 4) + ((remainderLength > 0) ? 4 : 0); | 83 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.
| |
| 63 // Add extra for line separators. | 84 // Add extra for line separators. |
| 64 if (addLineSeparator) { | 85 if (_addLineSeparator) { |
| 65 outputLen += ((outputLen - 1) ~/ LINE_LENGTH) << 1; | 86 outputLen += ((outputLen - 1) ~/ LINE_LENGTH) << 1; |
| 66 } | 87 } |
| 67 List<int> out = new List<int>(outputLen); | 88 List<int> out = new List<int>(outputLen); |
| 68 | 89 |
| 69 // Encode 24 bit chunks. | 90 // Encode 24 bit chunks. |
| 70 int j = 0, i = 0, c = 0; | 91 int j = 0, i = 0, c = 0; |
| 71 while (i < chunkLength) { | 92 while (i < chunkLength) { |
| 72 int x = ((bytes[i++] << 16) & 0xFFFFFF) | | 93 int x = ((bytes[i++] << 16) & 0xFFFFFF) | |
| 73 ((bytes[i++] << 8) & 0xFFFFFF) | | 94 ((bytes[i++] << 8) & 0xFFFFFF) | |
| 74 bytes[i++]; | 95 bytes[i++]; |
| 75 out[j++] = lookup.codeUnitAt(x >> 18); | 96 out[j++] = lookup.codeUnitAt(x >> 18); |
| 76 out[j++] = lookup.codeUnitAt((x >> 12) & 0x3F); | 97 out[j++] = lookup.codeUnitAt((x >> 12) & 0x3F); |
| 77 out[j++] = lookup.codeUnitAt((x >> 6) & 0x3F); | 98 out[j++] = lookup.codeUnitAt((x >> 6) & 0x3F); |
| 78 out[j++] = lookup.codeUnitAt(x & 0x3f); | 99 out[j++] = lookup.codeUnitAt(x & 0x3f); |
| 79 // Add optional line separator for each 76 char output. | 100 // Add optional line separator for each 76 char output. |
| 80 if (addLineSeparator && ++c == 19 && j < outputLen - 2) { | 101 if (_addLineSeparator && ++c == 19 && j < outputLen - 2) { |
| 81 out[j++] = CR; | 102 out[j++] = CR; |
| 82 out[j++] = LF; | 103 out[j++] = LF; |
| 83 c = 0; | 104 c = 0; |
| 84 } | 105 } |
| 85 } | 106 } |
| 86 | 107 |
| 87 // If input length if not a multiple of 3, encode remaining bytes and | 108 // If input length if not a multiple of 3, encode remaining bytes and |
| 88 // add padding. | 109 // add padding. |
| 89 if (remainderLength == 1) { | 110 if (remainderLength == 1) { |
| 90 int x = bytes[i]; | 111 int x = bytes[i]; |
| 91 out[j++] = lookup.codeUnitAt(x >> 2); | 112 out[j++] = lookup.codeUnitAt(x >> 2); |
| 92 out[j++] = lookup.codeUnitAt((x << 4) & 0x3F); | 113 out[j++] = lookup.codeUnitAt((x << 4) & 0x3F); |
| 93 out[j++] = PAD; | 114 out[j++] = PAD; |
| 94 out[j++] = PAD; | 115 out[j++] = PAD; |
| 95 } else if (remainderLength == 2) { | 116 } else if (remainderLength == 2) { |
| 96 int x = bytes[i]; | 117 int x = bytes[i]; |
| 97 int y = bytes[i + 1]; | 118 int y = bytes[i + 1]; |
| 98 out[j++] = lookup.codeUnitAt(x >> 2); | 119 out[j++] = lookup.codeUnitAt(x >> 2); |
| 99 out[j++] = lookup.codeUnitAt(((x << 4) | (y >> 4)) & 0x3F); | 120 out[j++] = lookup.codeUnitAt(((x << 4) | (y >> 4)) & 0x3F); |
| 100 out[j++] = lookup.codeUnitAt((y << 2) & 0x3F); | 121 out[j++] = lookup.codeUnitAt((y << 2) & 0x3F); |
| 101 out[j++] = PAD; | 122 out[j++] = PAD; |
| 102 } | 123 } |
| 103 | 124 |
| 104 return new String.fromCharCodes(out); | 125 return new String.fromCharCodes(out); |
| 105 } | 126 } |
| 106 | 127 |
| 107 static List<int> base64StringToBytes(String input) { | 128 _Base64EncoderSink startChunkedConversion(Sink<String> sink) { |
| 129 StringConversionSink stringSink; | |
| 130 if (sink is StringConversionSink) { | |
| 131 stringSink = sink; | |
| 132 } else { | |
| 133 stringSink = new StringConversionSink.from(sink); | |
| 134 } | |
| 135 return new _Base64EncoderSink(stringSink, _urlSafe, _addLineSeparator); | |
| 136 } | |
| 137 } | |
| 138 | |
| 139 class _Base64EncoderSink extends ChunkedConversionSink<List<int>> { | |
| 140 | |
| 141 final Base64Encoder _encoder; | |
| 142 final ChunkedConversionSink<String> _outSink; | |
| 143 final List<int> _buffer = new List<int>(3); | |
| 144 int _buffer_count = 0; | |
|
Lasse Reichstein Nielsen
2015/05/29 07:15:16
_bufferCount.
Alexander Ivanov
2015/05/29 13:12:05
Done.
| |
| 145 | |
| 146 _Base64EncoderSink(this._outSink, urlSafe, addLineSeparator) | |
| 147 : _encoder = new Base64Encoder(urlSafe: urlSafe, addLineSeparator: addLineSe parator); | |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
long line, indent : by four.
Alexander Ivanov
2015/05/29 13:12:05
Done.
| |
| 148 | |
| 149 void add(List<int> chunk) { | |
| 150 | |
|
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.
| |
| 151 var next_buffer_length = (chunk.length + _buffer_count) % 3; | |
| 152 | |
| 153 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.
| |
| 154 int remainder = chunk.length - next_buffer_length; | |
| 155 var decodable = new List.from(_buffer.sublist(0, _buffer_count))..addAll(c hunk.sublist(0, remainder)); | |
|
Lasse Reichstein Nielsen
2015/05/29 06:48:42
long line
Alexander Ivanov
2015/05/29 13:12:05
Done.
| |
| 156 _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.
| |
| 157 | |
| 158 _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.
| |
| 159 } | |
| 160 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.
| |
| 161 _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.
| |
| 162 } | |
| 163 _buffer_count = next_buffer_length; | |
| 164 } | |
| 165 | |
| 166 void close() { | |
| 167 if(_buffer_count > 0) { | |
| 168 _outSink.add(_encoder.convert(_buffer.sublist(0, _buffer_count))); | |
| 169 } | |
| 170 _outSink.close(); | |
| 171 } | |
| 172 } | |
| 173 | |
| 174 class Base64Decoder extends Converter<String, List<int>> { | |
| 175 const Base64Decoder(); | |
| 176 | |
| 177 List<int> convert(String input, {bool alwaysPadding: false}) { | |
| 108 int len = input.length; | 178 int len = input.length; |
| 109 if (len == 0) { | 179 if (len == 0) { |
| 110 return new List<int>(0); | 180 return new List<int>(0); |
| 111 } | 181 } |
| 112 | 182 |
| 113 // Count '\r', '\n' and illegal characters, For illegal characters, | 183 // Count '\r', '\n' and illegal characters, For illegal characters, |
| 114 // throw an exception. | 184 // throw an exception. |
| 115 int extrasLen = 0; | 185 int extrasLen = 0; |
| 116 for (int i = 0; i < len; i++) { | 186 for (int i = 0; i < len; i++) { |
| 117 int c = _decodeTable[input.codeUnitAt(i)]; | 187 int c = _decodeTable[input.codeUnitAt(i)]; |
| (...skipping 29 matching lines...) Expand all Loading... | |
| 147 x = ((x << 6) & 0xFFFFFF) | c; | 217 x = ((x << 6) & 0xFFFFFF) | c; |
| 148 j--; | 218 j--; |
| 149 } | 219 } |
| 150 } | 220 } |
| 151 out[o++] = x >> 16; | 221 out[o++] = x >> 16; |
| 152 if (o < outputLen) { | 222 if (o < outputLen) { |
| 153 out[o++] = (x >> 8) & 0xFF; | 223 out[o++] = (x >> 8) & 0xFF; |
| 154 if (o < outputLen) out[o++] = x & 0xFF; | 224 if (o < outputLen) out[o++] = x & 0xFF; |
| 155 } | 225 } |
| 156 } | 226 } |
| 227 | |
| 157 return out; | 228 return out; |
| 158 } | 229 } |
| 159 | 230 |
| 231 _Base64DecoderSink startChunkedConversion(Sink<List<int>> sink) { | |
| 232 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.
| |
| 233 sink = new ByteConversionSink.from(sink); | |
| 234 } | |
| 235 return new _Base64DecoderSink(sink); | |
| 236 } | |
| 160 } | 237 } |
| 238 | |
| 239 | |
| 240 class _Base64DecoderSink extends ChunkedConversionSink<String> { | |
| 241 | |
| 242 final Base64Decoder _decoder = new Base64Decoder(); | |
| 243 final ChunkedConversionSink<List<int>> _outSink; | |
| 244 String _buffer = ""; | |
| 245 | |
| 246 _Base64DecoderSink(this._outSink); | |
| 247 | |
| 248 void add(String chunk) { | |
| 249 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.
| |
| 250 | |
| 251 if(chunk.length + _buffer.length >= 4) { | |
| 252 int remainder = chunk.length - next_buffer_length; | |
| 253 String decodable = _buffer + chunk.substring(0, remainder); | |
| 254 _buffer = chunk.substring(remainder); | |
| 255 | |
| 256 _outSink.add(_decoder.convert(decodable)); | |
| 257 } | |
| 258 else { | |
| 259 _buffer += chunk; | |
| 260 } | |
| 261 } | |
| 262 | |
| 263 void close() { | |
| 264 if (!_buffer.isEmpty) { | |
| 265 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.
| |
| 266 } | |
| 267 _outSink.close(); | |
| 268 } | |
| 269 } | |
| 270 | |
| OLD | NEW |