| OLD | NEW |
| (Empty) | |
| 1 // Copyright (c) 2013, 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 dart.convert; |
| 6 |
| 7 // UTF-8 constants. |
| 8 const int _ONE_BYTE_LIMIT = 0x7f; // 7 bytes |
| 9 const int _TWO_BYTE_LIMIT = 0x7ff; // 11 bytes |
| 10 const int _THREE_BYTE_LIMIT = 0xffff; // 16 bytes |
| 11 const int _FOUR_BYTE_LIMIT = 0x10ffff; // 21 bytes, truncated to Unicode max. |
| 12 |
| 13 // UTF-16 constants. |
| 14 const int _SURROGATE_MASK = 0xF800; |
| 15 const int _SURROGATE_TAG_MASK = 0xFC00; |
| 16 const int _SURROGATE_VALUE_MASK = 0x3FF; |
| 17 const int _LEAD_SURROGATE_MIN = 0xD800; |
| 18 const int _TAIL_SURROGATE_MIN = 0xDC00; |
| 19 |
| 20 bool _isSurrogate(int codeUnit) => |
| 21 (codeUnit & _SURROGATE_MASK) == _LEAD_SURROGATE_MIN; |
| 22 bool _isLeadSurrogate(int codeUnit) => |
| 23 (codeUnit & _SURROGATE_TAG_MASK) == _LEAD_SURROGATE_MIN; |
| 24 bool _isTailSurrogate(int codeUnit) => |
| 25 (codeUnit & _SURROGATE_TAG_MASK) == _TAIL_SURROGATE_MIN; |
| 26 int _combineSurrogatePair(int lead, int tail) => |
| 27 0x10000 | ((lead & _SURROGATE_VALUE_MASK) << 10) |
| 28 | (tail & _SURROGATE_VALUE_MASK); |
| 29 |
| 30 |
| 31 class _Utf8EncoderToken { const _Utf8EncoderToken(); } |
| 32 |
| 33 class Utf8Encoder extends Converter<String, List<int>> { |
| 34 fuse(Converter other) => other.fuseInput(this); |
| 35 fuseInput(Converter other) => new FusedConverter(other, this); |
| 36 |
| 37 Object get id => const _Utf8EncoderToken(); |
| 38 |
| 39 ChunkedConversionSink startChunkedConversion(ChunkedConversionSink sink) { |
| 40 return new _Utf8EncoderSink(outputInterface.adapt(sink)); |
| 41 } |
| 42 |
| 43 ChunkedConversionInterface get inputInterface => |
| 44 StringConversionSink.INTERFACE; |
| 45 ChunkedConversionInterface get outputInterface => |
| 46 ByteConversionSink.INTERFACE; |
| 47 } |
| 48 |
| 49 class _Utf8DecoderToken { const _Utf8DecoderToken(); } |
| 50 |
| 51 class Utf8Decoder extends Converter<List<int>, String> { |
| 52 String convert(List<int> input) { |
| 53 Utf8Handler handler = new Utf8Handler(); |
| 54 String result = handler.convert(input, 0, input.length); |
| 55 if (handler.hasPartialInput) { |
| 56 throw new ArgumentError("Incomplete UTF8 sequence"); |
| 57 } |
| 58 return result; |
| 59 } |
| 60 |
| 61 fuse(Converter other) => other.fuseInput(this); |
| 62 fuseInput(Converter other) => new FusedConverter(other, this); |
| 63 |
| 64 Object get id => const _Utf8DecoderToken(); |
| 65 |
| 66 ChunkedConversionSink startChunkedConversion(ChunkedConversionSink sink) { |
| 67 return new _Utf8DecoderSink(outputInterface.adapt(sink)); |
| 68 } |
| 69 |
| 70 ChunkedConversionInterface get inputInterface => |
| 71 ByteConversionSink.INTERFACE; |
| 72 ChunkedConversionInterface get outputInterface => |
| 73 StringConversionSink.INTERFACE; |
| 74 |
| 75 } |
| 76 |
| 77 class _Utf8DecoderSink extends ByteConversionSinkBase { |
| 78 StringConversionSink _sink; |
| 79 _Utf8DecoderSink(this._sink); |
| 80 |
| 81 void addChunk(List<int> input, int start, int end, bool isLast) { |
| 82 _sink.addUtf8(input, start, end, isLast); |
| 83 } |
| 84 |
| 85 void add(List<int> input) { |
| 86 _sink.addUtf8(input, 0, input.length, false); |
| 87 } |
| 88 |
| 89 void close() => _sink.close(); |
| 90 } |
| 91 |
| 92 class _Utf8EncoderSink extends StringConversionSinkBase { |
| 93 ByteConversionSink _sink; |
| 94 _Utf8EncoderSink(this._sink); |
| 95 |
| 96 void add(String str) => addString(str, false); |
| 97 |
| 98 void addString(String str, bool isLast) { |
| 99 // TODO(floitsch): Use an iterator that works directly with codeUnits. |
| 100 _sink.iterateBytes(new _Utf8EncoderIterator(str.runes.iterator), isLast); |
| 101 } |
| 102 |
| 103 void addRunes(List<int> runes, int start, int end, bool isLast) { |
| 104 Iterator iterator; |
| 105 if (start == 0 && end == runes.length) { |
| 106 iterator = runes.iterator; |
| 107 } else { |
| 108 iterator = runes.getRange(start, end).iterator; |
| 109 } |
| 110 _sink.iterateBytes(new _Utf8EncoderIterator(iterator), isLast); |
| 111 } |
| 112 |
| 113 void addUtf8(List<int> utf8Units, int start, int end, bool isLast) { |
| 114 _sink.addChunk(utf8Units, start, end, isLast); |
| 115 } |
| 116 |
| 117 void addAscii(List<int> codeUnits, int start, int end, bool isLast) { |
| 118 _sink.addChunk(codeUnits, start, end, isLast); |
| 119 } |
| 120 |
| 121 void iterateCodeUnits(StringIterator iterator, bool isLast) { |
| 122 _sink.iterateBytes(new _StringIteratorWrapper(iterator.asUtf8()), isLast); |
| 123 } |
| 124 |
| 125 void iterateRunes(StringIterator iterator, bool isLast) { |
| 126 _sink.iterateBytes(new _StringIteratorWrapper(iterator.asUtf8()), isLast); |
| 127 } |
| 128 |
| 129 void iterateUtf8(StringIterator iterator, bool isLast) { |
| 130 _sink.iterateBytes(new _StringIteratorWrapper(iterator), isLast); |
| 131 } |
| 132 |
| 133 void iterateIsoLatin1(StringIterator iterator, bool isLast) { |
| 134 _sink.iterateBytes(new _StringIteratorWrapper(iterator), isLast); |
| 135 } |
| 136 |
| 137 void iterateAscii(StringIterator iterator, bool isLast) { |
| 138 _sink.iterateBytes(new _StringIteratorWrapper(iterator), isLast); |
| 139 } |
| 140 } |
| 141 |
| 142 class _StringIteratorWrapper implements ByteIterator { |
| 143 StringIterator _iterator; |
| 144 |
| 145 _StringIteratorWrapper(StringIterator this._iterator); |
| 146 |
| 147 int get current => _iterator.current; |
| 148 bool moveNext() => _iterator.moveNext(); |
| 149 int fill(List<int> list, int startIndex, int endIndex) => |
| 150 _iterator.fill(list, startIndex, endIndex); |
| 151 |
| 152 List<int> convertToByteList() { |
| 153 List<int> list = new Uint8List(32); |
| 154 int startIndex = 0; |
| 155 do { |
| 156 int filled = fill(list, startIndex, list.length); |
| 157 if (filled < list.length) { |
| 158 List<int> result = new Uint8List(filled); |
| 159 result.setRange(0, filled, list); |
| 160 return result; |
| 161 } |
| 162 // Double in size. |
| 163 List<int> biggerList = new Uint8List(list.length * 2); |
| 164 biggerList.setRange(0, list.length, list); |
| 165 startIndex = list.length; |
| 166 list = biggerList; |
| 167 } while(true); |
| 168 } |
| 169 } |
| 170 |
| 171 class _Utf8EncoderIterator implements ByteIterator { |
| 172 List<int> _carry; |
| 173 final Iterator _runeIterator; |
| 174 int _carryPos = 0; |
| 175 int _current; |
| 176 |
| 177 _Utf8EncoderIterator(this._runeIterator); |
| 178 |
| 179 void _addRune(int rune) { |
| 180 assert(rune > _ONE_BYTE_LIMIT); |
| 181 if (_carry == null) { |
| 182 _carry = new List<int>(3); |
| 183 } |
| 184 _carryPos = 0; |
| 185 if (rune <= _TWO_BYTE_LIMIT) { |
| 186 _carry[_carryPos++] = 0x80 | (rune & 0x3f); |
| 187 _current = 0xC0 | (rune >> 6); |
| 188 } else if (rune <= _THREE_BYTE_LIMIT) { |
| 189 _carry[_carryPos++] = 0x80 | (rune & 0x3f); |
| 190 _carry[_carryPos++] = 0x80 | ((rune >> 6) & 0x3f); |
| 191 _current = 0xE0 | (rune >> 12); |
| 192 } else { |
| 193 assert(rune <= _FOUR_BYTE_LIMIT); |
| 194 _carry[_carryPos++] = 0x80 | (rune & 0x3f); |
| 195 _carry[_carryPos++] = 0x80 | ((rune >> 6) & 0x3f); |
| 196 _carry[_carryPos++] = 0x80 | ((rune >> 12) & 0x3f); |
| 197 _current = 0xF0 | (rune >> 18); |
| 198 } |
| 199 } |
| 200 |
| 201 bool moveNext() { |
| 202 if (_carryPos > 0) { |
| 203 _carryPos--; |
| 204 _current = _carry[_carryPos]; |
| 205 return true; |
| 206 } |
| 207 bool hasNext = _runeIterator.moveNext(); |
| 208 if (!hasNext) { |
| 209 _current = null; |
| 210 return false; |
| 211 } |
| 212 int rune = _runeIterator.current; |
| 213 if (rune < _ONE_BYTE_LIMIT) { |
| 214 _current = rune; |
| 215 } else { |
| 216 _addRune(rune); |
| 217 } |
| 218 return true; |
| 219 } |
| 220 |
| 221 int get current => _current; |
| 222 |
| 223 int fill(List<int> list, int startIndex, int endIndex) { |
| 224 int i = startIndex; |
| 225 while (i < endIndex && _carryPos > 0) { |
| 226 _carryPos--; |
| 227 list[i++] = _carry[_carryPos]; |
| 228 } |
| 229 while (i < endIndex - 4 && _runeIterator.moveNext()) { |
| 230 int rune = _runeIterator.current; |
| 231 if (rune < _ONE_BYTE_LIMIT) { |
| 232 list[i++] = rune; |
| 233 } else if (rune <= _TWO_BYTE_LIMIT) { |
| 234 list[i++] = 0xC0 | (rune >> 6); |
| 235 list[i++] = 0x80 | (rune & 0x3f); |
| 236 } else if (rune <= _THREE_BYTE_LIMIT) { |
| 237 list[i++] = 0xE0 | (rune >> 12); |
| 238 list[i++] = 0x80 | ((rune >> 6) & 0x3f); |
| 239 list[i++] = 0x80 | (rune & 0x3f); |
| 240 } else { |
| 241 assert(rune <= _FOUR_BYTE_LIMIT); |
| 242 list[i++] = 0xF0 | (rune >> 18); |
| 243 list[i++] = 0x80 | ((rune >> 12) & 0x3f); |
| 244 list[i++] = 0x80 | ((rune >> 6) & 0x3f); |
| 245 list[i++] = 0x80 | (rune & 0x3f); |
| 246 } |
| 247 } |
| 248 while (i < endIndex && _runeIterator.moveNext()) { |
| 249 int rune = _runeIterator.current; |
| 250 if (rune < _ONE_BYTE_LIMIT) { |
| 251 list[i++] = rune; |
| 252 continue; |
| 253 } |
| 254 if (rune <= _TWO_BYTE_LIMIT) { |
| 255 if (i + 2 <= endIndex) { |
| 256 list[i++] = 0xC0 | (rune >> 6); |
| 257 list[i++] = 0x80 | (rune & 0x3f); |
| 258 continue; |
| 259 } |
| 260 } else if (rune <= _THREE_BYTE_LIMIT) { |
| 261 if (i + 3 <= endIndex) { |
| 262 list[i++] = 0xE0 | (rune >> 12); |
| 263 list[i++] = 0x80 | ((rune >> 6) & 0x3f); |
| 264 list[i++] = 0x80 | (rune & 0x3f); |
| 265 continue; |
| 266 } |
| 267 } else { |
| 268 assert(rune <= _FOUR_BYTE_LIMIT); |
| 269 if (i + 4 <= endIndex) { |
| 270 list[i++] = 0xF0 | (rune >> 18); |
| 271 list[i++] = 0x80 | ((rune >> 12) & 0x3f); |
| 272 list[i++] = 0x80 | ((rune >> 6) & 0x3f); |
| 273 list[i++] = 0x80 | (rune & 0x3f); |
| 274 continue; |
| 275 } |
| 276 } |
| 277 // We don't have enough space to fill the list. |
| 278 // Store the remainder in the carry. |
| 279 _addRune(rune); |
| 280 while (i < endIndex) { |
| 281 _carryPos--; |
| 282 list[i++] = _carry[_carryPos]; |
| 283 } |
| 284 } |
| 285 return i; |
| 286 } |
| 287 |
| 288 List<int> convertToByteList() { |
| 289 List<int> list = new Uint8List(32); |
| 290 int startIndex = 0; |
| 291 do { |
| 292 int filled = fill(list, startIndex, list.length); |
| 293 if (filled < list.length) { |
| 294 List<int> result = new Uint8List(filled); |
| 295 result.setRange(0, filled, list); |
| 296 return result; |
| 297 } |
| 298 // Double in size. |
| 299 List<int> biggerList = new Uint8List(list.length * 2); |
| 300 biggerList.setRange(0, list.length, list); |
| 301 startIndex = list.length; |
| 302 list = biggerList; |
| 303 } while(true); |
| 304 } |
| 305 } |
| OLD | NEW |