| 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 class _StringInterface extends ChunkedConversionInterface { |
| 8 const _StringInterface(); |
| 9 |
| 10 StringConversionSink adapt(ChunkedConversionSink sink) { |
| 11 if (sink.interface == StringConversionSink.INTERFACE) return sink; |
| 12 // Common interface is ChunkedConversionSink. |
| 13 return new _StringAdapterSink(sink); |
| 14 } |
| 15 |
| 16 StringConversionSink adaptEventSink(EventSink sink) { |
| 17 return new _EventSinkStringAdapterSink(sink); |
| 18 } |
| 19 } |
| 20 |
| 21 abstract class StringConversionSink |
| 22 extends ChunkedConversionSink<String> |
| 23 implements StringSink { |
| 24 |
| 25 StringConversionSink(); |
| 26 factory StringConversionSink.withStringSink(StringSink sink) = |
| 27 _StringSinkConversionSink; |
| 28 |
| 29 void addString(String str, bool isLast); |
| 30 void addCodeUnits(List<int> codeUnits, int start, int end, bool isLast); |
| 31 void addRunes(List<int> runes, int start, int end, bool isLast); |
| 32 void addUtf8(List<int> utf8Units, int start, int end, bool isLast); |
| 33 void addIsoLatin1(List<int> codeUnits, int start, int end, bool isLast); |
| 34 void addAscii(List<int> codeUnits, int start, int end, bool isLast); |
| 35 void iterateCodeUnits(StringIterator iterator, bool isLast); |
| 36 void iterateRunes(StringIterator iterator, bool isLast); |
| 37 void iterateUtf8(StringIterator iterator, bool isLast); |
| 38 void iterateIsoLatin1(StringIterator iterator, bool isLast); |
| 39 void iterateAscii(StringIterator iterator, bool isLast); |
| 40 void close(); // Equivalent to addString("", true); |
| 41 |
| 42 static const ChunkedConversionInterface INTERFACE = const _StringInterface(); |
| 43 } |
| 44 |
| 45 class _StringSinkConversionSink extends StringConversionSinkBase { |
| 46 StringSink _sink; |
| 47 _StringSinkConversionSink(StringSink this._sink); |
| 48 |
| 49 void add(String str) => write(str); |
| 50 void close() { /* do nothing */ } |
| 51 |
| 52 void write(Object o) => _sink.write(o); |
| 53 void writeln([Object o]) => _sink.writeln(o); |
| 54 void writeCharCode(int charCode) => _sink.writeCharCode(charCode); |
| 55 void writeAll(Iterable objects, [String separator = ""]) |
| 56 => _sink.writeAll(objects, separator); |
| 57 } |
| 58 |
| 59 class _StringAdapterSink extends StringConversionSinkBase { |
| 60 final ChunkedConversionSink _otherSink; |
| 61 final StringBuffer _buffer = new StringBuffer(); |
| 62 |
| 63 _StringAdapterSink(this._otherSink); |
| 64 |
| 65 void addNonChunked(String str) => _otherSink.addNonChunked(str); |
| 66 |
| 67 void add(String str) => _buffer.write(str); |
| 68 void close() => _otherSink.addNonChunked(_buffer.toString()); |
| 69 |
| 70 void write(Object o) => _buffer.write(o); |
| 71 void writeln([Object o]) => _buffer.writeln(o); |
| 72 void writeCharCode(int charCode) => _buffer.writeCharCode(charCode); |
| 73 void writeAll(Iterable objects, [String separator = ""]) |
| 74 => _buffer.writeAll(objects, separator); |
| 75 } |
| 76 |
| 77 class _EventSinkStringAdapterSink extends StringConversionSinkBase { |
| 78 final EventSink _sink; |
| 79 |
| 80 _EventSinkStringAdapterSink(this._sink); |
| 81 |
| 82 void add(String str) => _sink.add(str); |
| 83 void close() => _sink.close(); |
| 84 } |
| 85 |
| 86 abstract class _StringMultiStringConversionSinkBase |
| 87 extends ChunkedConversionSink { |
| 88 var _handler = null; |
| 89 |
| 90 void add(String str); |
| 91 |
| 92 void addString(String str, bool isLast) { |
| 93 add(str); |
| 94 if (isLast) close(); |
| 95 } |
| 96 |
| 97 List<int> _sublist(List<int> list, int start, int end) { |
| 98 if (start != 0 || end != list.length) return list.sublist(start, end); |
| 99 return list; |
| 100 } |
| 101 void addCodeUnits(List<int> codeUnits, int start, int end, bool isLast) { |
| 102 addString(new String.fromCharCodes(_sublist(codeUnits, start, end)), |
| 103 isLast); |
| 104 } |
| 105 void addRunes(List<int> runes, int start, int end, bool isLast) { |
| 106 addString(new String.fromCharCodes(_sublist(runes, start, end)), isLast); |
| 107 } |
| 108 void addUtf8(List<int> utf8Units, int start, int end, bool isLast) { |
| 109 if (_handler == null) { |
| 110 _handler = new Utf8Handler(); |
| 111 } else if (_handler is! Utf8Handler) { |
| 112 throw new UnimplementedError("Switching handlers"); |
| 113 } |
| 114 Utf8Handler handler = _handler; |
| 115 String string = handler.convert(utf8Units, start, end); |
| 116 bool isDone = isLast && !handler.hasPartialInput; |
| 117 addString(string, isDone); |
| 118 if (isLast && handler.hasPartialInput) { |
| 119 throw new StateError("Bad input"); |
| 120 } |
| 121 } |
| 122 void addIsoLatin1(List<int> codeUnits, int start, int end, bool isLast) { |
| 123 addRunes(codeUnits, start, end, isLast); |
| 124 } |
| 125 void addAscii(List<int> codeUnits, int start, int end, bool isLast) { |
| 126 addIsoLatin1(codeUnits, start, end, isLast); |
| 127 } |
| 128 void iterateCodeUnits(StringIterator iterator, bool isLast) { |
| 129 addString(iterator.convertToString(), isLast); |
| 130 } |
| 131 void iterateRunes(StringIterator iterator, bool isLast) { |
| 132 addString(iterator.convertToString(), isLast); |
| 133 } |
| 134 void iterateUtf8(StringIterator iterator, bool isLast) { |
| 135 addString(iterator.convertToString(), isLast); |
| 136 } |
| 137 void iterateIsoLatin1(StringIterator iterator, bool isLast) { |
| 138 addString(iterator.convertToString(), isLast); |
| 139 } |
| 140 void iterateAscii(StringIterator iterator, bool isLast) { |
| 141 addString(iterator.convertToString(), isLast); |
| 142 } |
| 143 |
| 144 void write(Object o) { addString(o.toString(), false); } |
| 145 void writeln([Object o]) { |
| 146 if (o != null) { |
| 147 addString(o.toString(), false); |
| 148 } |
| 149 addString("\n", false); |
| 150 } |
| 151 void writeCharCode(int charCode) { |
| 152 addString(new String.fromCharCode(charCode), false); |
| 153 } |
| 154 void writeAll(Iterable objects, [String separator = ""]) { |
| 155 addString(objects.join(separator), false); |
| 156 } |
| 157 |
| 158 ChunkedConversionInterface get interface => StringConversionSink.INTERFACE; |
| 159 } |
| 160 |
| 161 abstract class StringConversionSinkBase |
| 162 extends _StringMultiStringConversionSinkBase |
| 163 implements StringConversionSink { |
| 164 |
| 165 void addNonChunked(String str) => addString(str, true); |
| 166 |
| 167 close() => addString("", true); |
| 168 } |
| 169 |
| 170 class Utf8Handler { |
| 171 int _value = 0; |
| 172 int _expectedUnits = 0; |
| 173 int _extraUnits = 0; |
| 174 |
| 175 bool get hasPartialInput => _expectedUnits > 0; |
| 176 |
| 177 // Limits of one through four byte encodings. |
| 178 static const List<int> _LIMITS = const <int>[ |
| 179 _ONE_BYTE_LIMIT, |
| 180 _TWO_BYTE_LIMIT, |
| 181 _THREE_BYTE_LIMIT, |
| 182 _FOUR_BYTE_LIMIT ]; |
| 183 |
| 184 /** |
| 185 * This method will call _partialState for unfinished unicode sequences. |
| 186 */ |
| 187 String convert(List<int> codeUnits, int startIndex, int endIndex) { |
| 188 StringBuffer buffer = new StringBuffer(); |
| 189 convertToSink(codeUnits, startIndex, endIndex, buffer); |
| 190 return buffer.toString(); |
| 191 } |
| 192 |
| 193 /** |
| 194 * This method will call _partialState for unfinished unicode sequences. |
| 195 */ |
| 196 void convertToSink(List<int> codeUnits, int startIndex, int endIndex, |
| 197 StringSink sink) { |
| 198 int value = _value; |
| 199 int expectedUnits = _expectedUnits; |
| 200 int extraUnits = _extraUnits; |
| 201 _value = 0; |
| 202 _expectedUnits = 0; |
| 203 _extraUnits = 0; |
| 204 |
| 205 int i = startIndex; |
| 206 loop: while (true) { |
| 207 multibyte: if (expectedUnits > 0) { |
| 208 do { |
| 209 if (i == endIndex) { |
| 210 break loop; |
| 211 } |
| 212 int unit = codeUnits[i]; |
| 213 if ((unit & 0xC0) != 0x80) { |
| 214 int partialValue = value; |
| 215 value = expectedUnits = 0; |
| 216 if (!_onError(partialValue)) break loop; |
| 217 break multibyte; |
| 218 } else { |
| 219 value = (value << 6) | (unit & 0x3f); |
| 220 expectedUnits--; |
| 221 i++; |
| 222 } |
| 223 } while (expectedUnits > 0); |
| 224 if (value <= _LIMITS[extraUnits - 1]) { |
| 225 // Overly long encoding. The value could be encoded with a shorter |
| 226 // encoding. |
| 227 if (!_onError(value)) break loop; |
| 228 } |
| 229 sink.writeCharCode(value); |
| 230 } |
| 231 |
| 232 while (i < endIndex) { |
| 233 int unit = codeUnits[i++]; |
| 234 if (unit <= _ONE_BYTE_LIMIT) { |
| 235 sink.writeCharCode(unit); |
| 236 } else { |
| 237 if ((unit & 0xE0) == 0xC0) { |
| 238 value = unit & 0x1F; |
| 239 expectedUnits = extraUnits = 1; |
| 240 continue loop; |
| 241 } |
| 242 if ((unit & 0xF0) == 0xE0) { |
| 243 value = unit & 0x0F; |
| 244 expectedUnits = extraUnits = 2; |
| 245 continue loop; |
| 246 } |
| 247 if ((unit & 0xF8) == 0xF0) { |
| 248 value = unit & 0x07; |
| 249 expectedUnits = extraUnits = 3; |
| 250 continue loop; |
| 251 } |
| 252 if (!_onError(unit)) { |
| 253 break loop; |
| 254 } |
| 255 } |
| 256 } |
| 257 break loop; |
| 258 } |
| 259 if (expectedUnits > 0) { |
| 260 _value = value; |
| 261 _expectedUnits = expectedUnits; |
| 262 _extraUnits = extraUnits; |
| 263 } |
| 264 } |
| 265 |
| 266 bool _onError(int unexpectedByte) { |
| 267 throw new StateError |
| 268 ("Unexpected byte 0x${unexpectedByte.toRadixString(16)}."); |
| 269 } |
| 270 } |
| 271 |
| 272 abstract class StringIterator extends Iterator { |
| 273 /** |
| 274 * Fills [list] at position [startIndex] up to [endIndex] (exclusive) with |
| 275 * the next elements. Returns the next unwritten index. |
| 276 */ |
| 277 int fill(List<int> list, int startIndex, int endIndex); |
| 278 |
| 279 /** |
| 280 * Returns the string representation of the full content of this iterator. |
| 281 */ |
| 282 String convertToString(); |
| 283 |
| 284 StringIterator asRunes(); |
| 285 StringIterator asCodeUnits(); |
| 286 StringIterator asUtf8(); |
| 287 } |
| 288 |
| 289 |
| 290 class _MultiStringInterface extends ChunkedConversionInterface { |
| 291 const _MultiStringInterface(); |
| 292 |
| 293 MultiStringConversionSink adapt(ChunkedConversionSink sink) { |
| 294 if (sink.interface == MultiStringConversionSink.INTERFACE) return sink; |
| 295 // Common interface is ChunkedConversionSink. |
| 296 return new _MultiStringAdapterSink(sink); |
| 297 } |
| 298 |
| 299 MultiStringConversionSink adaptEventSink(EventSink sink) { |
| 300 return new _EventSinkMultiStringAdapterSink(sink); |
| 301 } |
| 302 } |
| 303 |
| 304 abstract class MultiStringConversionSink |
| 305 extends ChunkedConversionSink<List<String>> |
| 306 implements StringSink { |
| 307 |
| 308 MultiStringConversionSink(); |
| 309 |
| 310 void addString(String str, bool isLast); |
| 311 void addCodeUnits(List<int> codeUnits, int start, int end, bool isLast); |
| 312 void addRunes(List<int> runes, int start, int end, bool isLast); |
| 313 void addUtf8(List<int> utf8Units, int start, int end, bool isLast); |
| 314 void addIsoLatin1(List<int> codeUnits, int start, int end, bool isLast); |
| 315 void addAscii(List<int> codeUnits, int start, int end, bool isLast); |
| 316 void iterateCodeUnits(StringIterator iterator, bool isLast); |
| 317 void iterateRunes(StringIterator iterator, bool isLast); |
| 318 void iterateUtf8(StringIterator iterator, bool isLast); |
| 319 void iterateIsoLatin1(StringIterator iterator, bool isLast); |
| 320 void iterateAscii(StringIterator iterator, bool isLast); |
| 321 void close(); |
| 322 |
| 323 static const ChunkedConversionInterface INTERFACE = |
| 324 const _MultiStringInterface(); |
| 325 } |
| 326 |
| 327 abstract class MultiStringConversionSinkBase |
| 328 extends _StringMultiStringConversionSinkBase |
| 329 implements MultiStringConversionSink { |
| 330 |
| 331 void addNonChunked(List<String> list) { |
| 332 for (int i = 0; i < list.length - 1; i++) { |
| 333 addString(list[i], false); |
| 334 } |
| 335 if (!list.isEmpty) { |
| 336 addString(list.last, true); |
| 337 } else { |
| 338 close(); |
| 339 } |
| 340 } |
| 341 |
| 342 ChunkedConversionInterface get interface => |
| 343 MultiStringConversionSink.INTERFACE; |
| 344 } |
| 345 |
| 346 |
| 347 class _MultiStringAdapterSink extends MultiStringConversionSinkBase |
| 348 implements MultiStringConversionSink { |
| 349 final ChunkedConversionSink _otherSink; |
| 350 final List<String> _accumulator = <String>[]; |
| 351 |
| 352 _MultiStringAdapterSink(this._otherSink); |
| 353 |
| 354 void addNonChunked(List<String> list) { |
| 355 _otherSink.addNonChunked(list.join("\n")); |
| 356 } |
| 357 |
| 358 void add(String str) => _accumulator.add(str); |
| 359 void close() { _otherSink.addNonChunked(_accumulator); } |
| 360 } |
| 361 |
| 362 class _EventSinkMultiStringAdapterSink extends MultiStringConversionSinkBase |
| 363 implements MultiStringConversionSink { |
| 364 final EventSink _sink; |
| 365 |
| 366 _EventSinkMultiStringAdapterSink(this._sink); |
| 367 |
| 368 void add(String str) => _sink.add(str); |
| 369 void close() { _sink.close(); } |
| 370 } |
| OLD | NEW |