| OLD | NEW |
| 1 part of dart.convert; | 1 part of dart.convert; |
| 2 | 2 const int UNICODE_REPLACEMENT_CHARACTER_RUNE = 0xFFFD; |
| 3 const int UNICODE_REPLACEMENT_CHARACTER_RUNE = 0xFFFD; | 3 const int UNICODE_BOM_CHARACTER_RUNE = 0xFEFF; |
| 4 const int UNICODE_BOM_CHARACTER_RUNE = 0xFEFF; | 4 const Utf8Codec UTF8 = const Utf8Codec(); |
| 5 const Utf8Codec UTF8 = const Utf8Codec(); | 5 class Utf8Codec extends Encoding {final bool _allowMalformed; |
| 6 class Utf8Codec extends Encoding { | 6 const Utf8Codec({ |
| 7 final bool _allowMalformed; | 7 bool allowMalformed : false} |
| 8 const Utf8Codec({bool allowMalformed: false}) | 8 ) : _allowMalformed = allowMalformed; |
| 9 : _allowMalformed = allowMalformed; | 9 String get name => "utf-8"; |
| 10 String get name => "utf-8"; | 10 String decode(List<int> codeUnits, { |
| 11 String decode(List<int> codeUnits, {bool allowMalformed}) { | 11 bool allowMalformed} |
| 12 if (allowMalformed == null) allowMalformed = _allowMalformed; | 12 ) { |
| 13 return new Utf8Decoder(allowMalformed: allowMalformed).convert(codeUnits); | 13 if (allowMalformed == null) allowMalformed = _allowMalformed; |
| 14 } | 14 return new Utf8Decoder(allowMalformed: allowMalformed).convert(codeUnits); |
| 15 Utf8Encoder get encoder => new Utf8Encoder(); | 15 } |
| 16 Utf8Decoder get decoder { | 16 Utf8Encoder get encoder => new Utf8Encoder(); |
| 17 return new Utf8Decoder(allowMalformed: _allowMalformed); | 17 Utf8Decoder get decoder { |
| 18 } | 18 return new Utf8Decoder(allowMalformed: _allowMalformed); |
| 19 } | 19 } |
| 20 class Utf8Encoder extends Converter<String, List<int>> { | 20 } |
| 21 const Utf8Encoder(); | 21 class Utf8Encoder extends Converter<String, List<int>> {const Utf8Encoder(); |
| 22 List<int> convert(String string, [int start = 0, int end]) { | 22 List<int> convert(String string, [int start = 0, int end]) { |
| 23 int stringLength = string.length; | 23 int stringLength = string.length; |
| 24 RangeError.checkValidRange(start, end, stringLength); | 24 RangeError.checkValidRange(start, end, stringLength); |
| 25 if (end == null) end = stringLength; | 25 if (end == null) end = stringLength; |
| 26 int length = end - start; | 26 int length = end - start; |
| 27 if (length == 0) return new Uint8List(0); | 27 if (length == 0) return new Uint8List(0); |
| 28 _Utf8Encoder encoder = new _Utf8Encoder.withBufferSize(length * 3); | 28 _Utf8Encoder encoder = new _Utf8Encoder.withBufferSize(length * 3); |
| 29 int endPosition = encoder._fillBuffer(string, start, end); | 29 int endPosition = encoder._fillBuffer(string, start, end); |
| 30 assert(endPosition >= end - 1); | 30 assert (endPosition >= end - 1); if (endPosition != end) { |
| 31 if (endPosition != end) { | 31 int lastCodeUnit = string.codeUnitAt(end - 1); |
| 32 int lastCodeUnit = string.codeUnitAt(end - 1); | 32 assert (_isLeadSurrogate(lastCodeUnit)); bool wasCombined = encoder._writeSur
rogate(lastCodeUnit, 0); |
| 33 assert(_isLeadSurrogate(lastCodeUnit)); | 33 assert (!wasCombined);} |
| 34 bool wasCombined = encoder._writeSurrogate(lastCodeUnit, 0); | 34 return encoder._buffer.sublist(0, encoder._bufferIndex); |
| 35 assert(!wasCombined); | 35 } |
| 36 StringConversionSink startChunkedConversion(Sink<List<int>> sink) { |
| 37 if (sink is! ByteConversionSink) { |
| 38 sink = new ByteConversionSink.from(sink); |
| 39 } |
| 40 return new _Utf8EncoderSink(sink); |
| 41 } |
| 42 Stream<List<int>> bind(Stream<String> stream) => ((__x30) => DDC$RT.cast(__x30,
DDC$RT.type((DDC$async$.Stream<dynamic> _) { |
| 43 } |
| 44 ), DDC$RT.type((DDC$async$.Stream<List<int>> _) { |
| 45 } |
| 46 ), "CastDynamic", """line 129, column 52 of dart:convert/utf.dart: """, __x30 is
DDC$async$.Stream<List<int>>, false))(super.bind(stream)); |
| 47 } |
| 48 class _Utf8Encoder {int _carry = 0; |
| 49 int _bufferIndex = 0; |
| 50 final List<int> _buffer; |
| 51 static const _DEFAULT_BYTE_BUFFER_SIZE = 1024; |
| 52 _Utf8Encoder() : this.withBufferSize(DDC$RT.cast(_DEFAULT_BYTE_BUFFER_SIZE, dyn
amic, int, "CastGeneral", """line 143, column 40 of dart:convert/utf.dart: """,
_DEFAULT_BYTE_BUFFER_SIZE is int, true)); |
| 53 _Utf8Encoder.withBufferSize(int bufferSize) : _buffer = _createBuffer(bufferSiz
e); |
| 54 static List<int> _createBuffer(int size) => new Uint8List(size); |
| 55 bool _writeSurrogate(int leadingSurrogate, int nextCodeUnit) { |
| 56 if (_isTailSurrogate(nextCodeUnit)) { |
| 57 int rune = _combineSurrogatePair(leadingSurrogate, nextCodeUnit); |
| 58 assert (rune > _THREE_BYTE_LIMIT); assert (rune <= _FOUR_BYTE_LIMIT); _buffer[_
bufferIndex++] = 0xF0 | (rune >> 18); |
| 59 _buffer[_bufferIndex++] = 0x80 | ((rune >> 12) & 0x3f); |
| 60 _buffer[_bufferIndex++] = 0x80 | ((rune >> 6) & 0x3f); |
| 61 _buffer[_bufferIndex++] = 0x80 | (rune & 0x3f); |
| 62 return true; |
| 63 } |
| 64 else { |
| 65 _buffer[_bufferIndex++] = 0xE0 | (leadingSurrogate >> 12); |
| 66 _buffer[_bufferIndex++] = 0x80 | ((leadingSurrogate >> 6) & 0x3f); |
| 67 _buffer[_bufferIndex++] = 0x80 | (leadingSurrogate & 0x3f); |
| 68 return false; |
| 69 } |
| 70 } |
| 71 int _fillBuffer(String str, int start, int end) { |
| 72 if (start != end && _isLeadSurrogate(str.codeUnitAt(end - 1))) { |
| 73 end--; |
| 74 } |
| 75 int stringIndex; |
| 76 for (stringIndex = start; |
| 77 stringIndex < end; |
| 78 stringIndex++) { |
| 79 int codeUnit = str.codeUnitAt(stringIndex); |
| 80 if (codeUnit <= _ONE_BYTE_LIMIT) { |
| 81 if (_bufferIndex >= _buffer.length) break; |
| 82 _buffer[_bufferIndex++] = codeUnit; |
| 83 } |
| 84 else if (_isLeadSurrogate(codeUnit)) { |
| 85 if (_bufferIndex + 3 >= _buffer.length) break; |
| 86 int nextCodeUnit = str.codeUnitAt(stringIndex + 1); |
| 87 bool wasCombined = _writeSurrogate(codeUnit, nextCodeUnit); |
| 88 if (wasCombined) stringIndex++; |
| 89 } |
| 90 else { |
| 91 int rune = codeUnit; |
| 92 if (rune <= _TWO_BYTE_LIMIT) { |
| 93 if (_bufferIndex + 1 >= _buffer.length) break; |
| 94 _buffer[_bufferIndex++] = 0xC0 | (rune >> 6); |
| 95 _buffer[_bufferIndex++] = 0x80 | (rune & 0x3f); |
| 36 } | 96 } |
| 37 return encoder._buffer.sublist(0, encoder._bufferIndex); | 97 else { |
| 38 } | 98 assert (rune <= _THREE_BYTE_LIMIT); if (_bufferIndex + 2 >= _buffer.length)
break; |
| 39 StringConversionSink startChunkedConversion(Sink<List<int>> sink) { | 99 _buffer[_bufferIndex++] = 0xE0 | (rune >> 12); |
| 40 if (sink is! ByteConversionSink) { | 100 _buffer[_bufferIndex++] = 0x80 | ((rune >> 6) & 0x3f); |
| 41 sink = new ByteConversionSink.from(sink); | 101 _buffer[_bufferIndex++] = 0x80 | (rune & 0x3f); |
| 42 } | 102 } |
| 43 return new _Utf8EncoderSink(sink); | 103 } |
| 44 } | 104 } |
| 45 Stream<List<int>> bind(Stream<String> stream) => ((__x30) => DDC$RT.cast( | 105 return stringIndex; |
| 46 __x30, DDC$RT.type((DDC$async$.Stream<dynamic> _) {}), | 106 } |
| 47 DDC$RT.type((DDC$async$.Stream<List<int>> _) {}), "CastDynamic", | 107 } |
| 48 """line 129, column 52 of dart:convert/utf.dart: """, | 108 class _Utf8EncoderSink extends _Utf8Encoder with StringConversionSinkMixin {fin
al ByteConversionSink _sink; |
| 49 __x30 is DDC$async$.Stream<List<int>>, false))(super.bind(stream)); | 109 _Utf8EncoderSink(this._sink); |
| 50 } | 110 void close() { |
| 51 class _Utf8Encoder { | 111 if (_carry != 0) { |
| 52 int _carry = 0; | 112 addSlice("", 0, 0, true); |
| 53 int _bufferIndex = 0; | 113 return;} |
| 54 final List<int> _buffer; | 114 _sink.close(); |
| 55 static const _DEFAULT_BYTE_BUFFER_SIZE = 1024; | 115 } |
| 56 _Utf8Encoder() : this.withBufferSize(DDC$RT.cast(_DEFAULT_BYTE_BUFFER_SIZE, | 116 void addSlice(String str, int start, int end, bool isLast) { |
| 57 dynamic, int, "CastGeneral", | 117 _bufferIndex = 0; |
| 58 """line 143, column 40 of dart:convert/utf.dart: """, | 118 if (start == end && !isLast) { |
| 59 _DEFAULT_BYTE_BUFFER_SIZE is int, true)); | 119 return;} |
| 60 _Utf8Encoder.withBufferSize(int bufferSize) | 120 if (_carry != 0) { |
| 61 : _buffer = _createBuffer(bufferSize); | 121 int nextCodeUnit = 0; |
| 62 static List<int> _createBuffer(int size) => new Uint8List(size); | 122 if (start != end) { |
| 63 bool _writeSurrogate(int leadingSurrogate, int nextCodeUnit) { | 123 nextCodeUnit = str.codeUnitAt(start); |
| 64 if (_isTailSurrogate(nextCodeUnit)) { | 124 } |
| 65 int rune = _combineSurrogatePair(leadingSurrogate, nextCodeUnit); | 125 else { |
| 66 assert(rune > _THREE_BYTE_LIMIT); | 126 assert (isLast);} |
| 67 assert(rune <= _FOUR_BYTE_LIMIT); | 127 bool wasCombined = _writeSurrogate(_carry, nextCodeUnit); |
| 68 _buffer[_bufferIndex++] = 0xF0 | (rune >> 18); | 128 assert (!wasCombined || start != end); if (wasCombined) start++; |
| 69 _buffer[_bufferIndex++] = 0x80 | ((rune >> 12) & 0x3f); | 129 _carry = 0; |
| 70 _buffer[_bufferIndex++] = 0x80 | ((rune >> 6) & 0x3f); | 130 } |
| 71 _buffer[_bufferIndex++] = 0x80 | (rune & 0x3f); | 131 do { |
| 72 return true; | 132 start = _fillBuffer(str, start, end); |
| 73 } else { | 133 bool isLastSlice = isLast && (start == end); |
| 74 _buffer[_bufferIndex++] = 0xE0 | (leadingSurrogate >> 12); | 134 if (start == end - 1 && _isLeadSurrogate(str.codeUnitAt(start))) { |
| 75 _buffer[_bufferIndex++] = 0x80 | ((leadingSurrogate >> 6) & 0x3f); | 135 if (isLast && _bufferIndex < _buffer.length - 3) { |
| 76 _buffer[_bufferIndex++] = 0x80 | (leadingSurrogate & 0x3f); | 136 bool hasBeenCombined = _writeSurrogate(str.codeUnitAt(start), 0); |
| 77 return false; | 137 assert (!hasBeenCombined);} |
| 78 } | 138 else { |
| 79 } | 139 _carry = str.codeUnitAt(start); |
| 80 int _fillBuffer(String str, int start, int end) { | 140 } |
| 81 if (start != end && _isLeadSurrogate(str.codeUnitAt(end - 1))) { | 141 start++; |
| 82 end--; | 142 } |
| 83 } | 143 _sink.addSlice(_buffer, 0, _bufferIndex, isLastSlice); |
| 84 int stringIndex; | 144 _bufferIndex = 0; |
| 85 for (stringIndex = start; stringIndex < end; stringIndex++) { | 145 } |
| 86 int codeUnit = str.codeUnitAt(stringIndex); | 146 while (start < end); if (isLast) close(); |
| 87 if (codeUnit <= _ONE_BYTE_LIMIT) { | 147 } |
| 88 if (_bufferIndex >= _buffer.length) break; | 148 } |
| 89 _buffer[_bufferIndex++] = codeUnit; | 149 class Utf8Decoder extends Converter<List<int>, String> {final bool _allowMalfor
med; |
| 90 } else if (_isLeadSurrogate(codeUnit)) { | 150 const Utf8Decoder({ |
| 91 if (_bufferIndex + 3 >= _buffer.length) break; | 151 bool allowMalformed : false} |
| 92 int nextCodeUnit = str.codeUnitAt(stringIndex + 1); | 152 ) : this._allowMalformed = allowMalformed; |
| 93 bool wasCombined = _writeSurrogate(codeUnit, nextCodeUnit); | 153 String convert(List<int> codeUnits, [int start = 0, int end]) { |
| 94 if (wasCombined) stringIndex++; | 154 int length = codeUnits.length; |
| 95 } else { | 155 RangeError.checkValidRange(start, end, length); |
| 96 int rune = codeUnit; | 156 if (end == null) end = length; |
| 97 if (rune <= _TWO_BYTE_LIMIT) { | 157 StringBuffer buffer = new StringBuffer(); |
| 98 if (_bufferIndex + 1 >= _buffer.length) break; | 158 _Utf8Decoder decoder = new _Utf8Decoder(buffer, _allowMalformed); |
| 99 _buffer[_bufferIndex++] = 0xC0 | (rune >> 6); | 159 decoder.convert(codeUnits, start, end); |
| 100 _buffer[_bufferIndex++] = 0x80 | (rune & 0x3f); | 160 decoder.close(); |
| 101 } else { | 161 return buffer.toString(); |
| 102 assert(rune <= _THREE_BYTE_LIMIT); | 162 } |
| 103 if (_bufferIndex + 2 >= _buffer.length) break; | 163 ByteConversionSink startChunkedConversion(Sink<String> sink) { |
| 104 _buffer[_bufferIndex++] = 0xE0 | (rune >> 12); | 164 StringConversionSink stringSink; |
| 105 _buffer[_bufferIndex++] = 0x80 | ((rune >> 6) & 0x3f); | 165 if (sink is StringConversionSink) { |
| 106 _buffer[_bufferIndex++] = 0x80 | (rune & 0x3f); | 166 stringSink = sink; |
| 107 } | 167 } |
| 108 } | 168 else { |
| 109 } | 169 stringSink = new StringConversionSink.from(sink); |
| 110 return stringIndex; | 170 } |
| 111 } | 171 return stringSink.asUtf8Sink(_allowMalformed); |
| 112 } | 172 } |
| 113 class _Utf8EncoderSink extends _Utf8Encoder with StringConversionSinkMixin { | 173 Stream<String> bind(Stream<List<int>> stream) => ((__x31) => DDC$RT.cast(__x31,
DDC$RT.type((DDC$async$.Stream<dynamic> _) { |
| 114 final ByteConversionSink _sink; | 174 } |
| 115 _Utf8EncoderSink(this._sink); | 175 ), DDC$RT.type((DDC$async$.Stream<String> _) { |
| 116 void close() { | 176 } |
| 117 if (_carry != 0) { | 177 ), "CastDynamic", """line 361, column 52 of dart:convert/utf.dart: """, __x31 is
DDC$async$.Stream<String>, false))(super.bind(stream)); |
| 118 addSlice("", 0, 0, true); | 178 Converter<List<int>, dynamic> fuse(Converter<String, dynamic> next) { |
| 119 return; | 179 return super.fuse(next); |
| 120 } | 180 } |
| 121 _sink.close(); | 181 } |
| 122 } | 182 const int _ONE_BYTE_LIMIT = 0x7f; |
| 123 void addSlice(String str, int start, int end, bool isLast) { | 183 const int _TWO_BYTE_LIMIT = 0x7ff; |
| 124 _bufferIndex = 0; | 184 const int _THREE_BYTE_LIMIT = 0xffff; |
| 125 if (start == end && !isLast) { | 185 const int _FOUR_BYTE_LIMIT = 0x10ffff; |
| 126 return; | 186 const int _SURROGATE_MASK = 0xF800; |
| 127 } | 187 const int _SURROGATE_TAG_MASK = 0xFC00; |
| 128 if (_carry != 0) { | 188 const int _SURROGATE_VALUE_MASK = 0x3FF; |
| 129 int nextCodeUnit = 0; | 189 const int _LEAD_SURROGATE_MIN = 0xD800; |
| 130 if (start != end) { | 190 const int _TAIL_SURROGATE_MIN = 0xDC00; |
| 131 nextCodeUnit = str.codeUnitAt(start); | 191 bool _isSurrogate(int codeUnit) => (codeUnit & _SURROGATE_MASK) == _LEAD_SURROG
ATE_MIN; |
| 132 } else { | 192 bool _isLeadSurrogate(int codeUnit) => (codeUnit & _SURROGATE_TAG_MASK) == _LEA
D_SURROGATE_MIN; |
| 133 assert(isLast); | 193 bool _isTailSurrogate(int codeUnit) => (codeUnit & _SURROGATE_TAG_MASK) == _TAI
L_SURROGATE_MIN; |
| 134 } | 194 int _combineSurrogatePair(int lead, int tail) => 0x10000 + ((lead & _SURROGATE_
VALUE_MASK) << 10) | (tail & _SURROGATE_VALUE_MASK); |
| 135 bool wasCombined = _writeSurrogate(_carry, nextCodeUnit); | 195 class _Utf8Decoder {final bool _allowMalformed; |
| 136 assert(!wasCombined || start != end); | 196 final StringSink _stringSink; |
| 137 if (wasCombined) start++; | 197 bool _isFirstCharacter = true; |
| 138 _carry = 0; | 198 int _value = 0; |
| 139 } | 199 int _expectedUnits = 0; |
| 140 do { | 200 int _extraUnits = 0; |
| 141 start = _fillBuffer(str, start, end); | 201 _Utf8Decoder(this._stringSink, this._allowMalformed); |
| 142 bool isLastSlice = isLast && (start == end); | 202 bool get hasPartialInput => _expectedUnits > 0; |
| 143 if (start == end - 1 && _isLeadSurrogate(str.codeUnitAt(start))) { | 203 static const List<int> _LIMITS = const <int> [_ONE_BYTE_LIMIT, _TWO_BYTE_LIMIT,
_THREE_BYTE_LIMIT, _FOUR_BYTE_LIMIT]; |
| 144 if (isLast && _bufferIndex < _buffer.length - 3) { | 204 void close() { |
| 145 bool hasBeenCombined = _writeSurrogate(str.codeUnitAt(start), 0); | 205 flush(); |
| 146 assert(!hasBeenCombined); | 206 } |
| 147 } else { | 207 void flush() { |
| 148 _carry = str.codeUnitAt(start); | 208 if (hasPartialInput) { |
| 149 } | 209 if (!_allowMalformed) { |
| 150 start++; | 210 throw new FormatException("Unfinished UTF-8 octet sequence"); |
| 151 } | 211 } |
| 152 _sink.addSlice(_buffer, 0, _bufferIndex, isLastSlice); | 212 _stringSink.writeCharCode(UNICODE_REPLACEMENT_CHARACTER_RUNE); |
| 153 _bufferIndex = 0; | 213 _value = 0; |
| 154 } while (start < end); | 214 _expectedUnits = 0; |
| 155 if (isLast) close(); | 215 _extraUnits = 0; |
| 156 } | 216 } |
| 157 } | 217 } |
| 158 class Utf8Decoder extends Converter<List<int>, String> { | 218 void convert(List<int> codeUnits, int startIndex, int endIndex) { |
| 159 final bool _allowMalformed; | 219 int value = _value; |
| 160 const Utf8Decoder({bool allowMalformed: false}) | 220 int expectedUnits = _expectedUnits; |
| 161 : this._allowMalformed = allowMalformed; | 221 int extraUnits = _extraUnits; |
| 162 String convert(List<int> codeUnits, [int start = 0, int end]) { | 222 _value = 0; |
| 163 int length = codeUnits.length; | 223 _expectedUnits = 0; |
| 164 RangeError.checkValidRange(start, end, length); | 224 _extraUnits = 0; |
| 165 if (end == null) end = length; | 225 int scanOneByteCharacters(units, int from) { |
| 166 StringBuffer buffer = new StringBuffer(); | 226 final to = endIndex; |
| 167 _Utf8Decoder decoder = new _Utf8Decoder(buffer, _allowMalformed); | 227 final mask = _ONE_BYTE_LIMIT; |
| 168 decoder.convert(codeUnits, start, end); | 228 for (var i = from; |
| 169 decoder.close(); | 229 i < to; |
| 170 return buffer.toString(); | 230 i++) { |
| 171 } | 231 final unit = units[i]; |
| 172 ByteConversionSink startChunkedConversion(Sink<String> sink) { | 232 if ((unit & mask) != unit) return i - from; |
| 173 StringConversionSink stringSink; | 233 } |
| 174 if (sink is StringConversionSink) { | 234 return to - from; |
| 175 stringSink = sink; | 235 } |
| 176 } else { | 236 void addSingleBytes(int from, int to) { |
| 177 stringSink = new StringConversionSink.from(sink); | 237 assert (from >= startIndex && from <= endIndex); assert (to >= startIndex && to
<= endIndex); _stringSink.write(new String.fromCharCodes(codeUnits, from, to)); |
| 178 } | 238 } |
| 179 return stringSink.asUtf8Sink(_allowMalformed); | 239 int i = startIndex; |
| 180 } | 240 loop: while (true) { |
| 181 Stream<String> bind(Stream<List<int>> stream) => ((__x31) => DDC$RT.cast( | 241 multibyte: if (expectedUnits > 0) { |
| 182 __x31, DDC$RT.type((DDC$async$.Stream<dynamic> _) {}), | 242 do { |
| 183 DDC$RT.type((DDC$async$.Stream<String> _) {}), "CastDynamic", | 243 if (i == endIndex) { |
| 184 """line 361, column 52 of dart:convert/utf.dart: """, | 244 break loop; |
| 185 __x31 is DDC$async$.Stream<String>, false))(super.bind(stream)); | 245 } |
| 186 Converter<List<int>, dynamic> fuse(Converter<String, dynamic> next) { | 246 int unit = codeUnits[i]; |
| 187 return super.fuse(next); | 247 if ((unit & 0xC0) != 0x80) { |
| 188 } | 248 expectedUnits = 0; |
| 189 } | 249 if (!_allowMalformed) { |
| 190 const int _ONE_BYTE_LIMIT = 0x7f; | 250 throw new FormatException("Bad UTF-8 encoding 0x${unit.toRadixString(16)} |
| 191 const int _TWO_BYTE_LIMIT = 0x7ff; | 251 "); |
| 192 const int _THREE_BYTE_LIMIT = 0xffff; | 252 } |
| 193 const int _FOUR_BYTE_LIMIT = 0x10ffff; | 253 _isFirstCharacter = false; |
| 194 const int _SURROGATE_MASK = 0xF800; | 254 _stringSink.writeCharCode(UNICODE_REPLACEMENT_CHARACTER_RUNE); |
| 195 const int _SURROGATE_TAG_MASK = 0xFC00; | 255 break multibyte; |
| 196 const int _SURROGATE_VALUE_MASK = 0x3FF; | 256 } |
| 197 const int _LEAD_SURROGATE_MIN = 0xD800; | 257 else { |
| 198 const int _TAIL_SURROGATE_MIN = 0xDC00; | 258 value = (value << 6) | (unit & 0x3f); |
| 199 bool _isSurrogate(int codeUnit) => | 259 expectedUnits--; |
| 200 (codeUnit & _SURROGATE_MASK) == _LEAD_SURROGATE_MIN; | 260 i++; |
| 201 bool _isLeadSurrogate(int codeUnit) => | 261 } |
| 202 (codeUnit & _SURROGATE_TAG_MASK) == _LEAD_SURROGATE_MIN; | 262 } |
| 203 bool _isTailSurrogate(int codeUnit) => | 263 while (expectedUnits > 0); if (value <= _LIMITS[extraUnits - 1]) { |
| 204 (codeUnit & _SURROGATE_TAG_MASK) == _TAIL_SURROGATE_MIN; | 264 if (!_allowMalformed) { |
| 205 int _combineSurrogatePair(int lead, int tail) => | 265 throw new FormatException("Overlong encoding of 0x${value.toRadixString(16)} |
| 206 0x10000 + ((lead & _SURROGATE_VALUE_MASK) << 10) | | 266 "); |
| 207 (tail & _SURROGATE_VALUE_MASK); | 267 } |
| 208 class _Utf8Decoder { | 268 expectedUnits = extraUnits = 0; |
| 209 final bool _allowMalformed; | 269 value = UNICODE_REPLACEMENT_CHARACTER_RUNE; |
| 210 final StringSink _stringSink; | 270 } |
| 211 bool _isFirstCharacter = true; | 271 if (value > _FOUR_BYTE_LIMIT) { |
| 212 int _value = 0; | 272 if (!_allowMalformed) { |
| 213 int _expectedUnits = 0; | 273 throw new FormatException("Character outside valid Unicode range: " "0x${value.t
oRadixString(16)} |
| 214 int _extraUnits = 0; | 274 "); |
| 215 _Utf8Decoder(this._stringSink, this._allowMalformed); | 275 } |
| 216 bool get hasPartialInput => _expectedUnits > 0; | 276 value = UNICODE_REPLACEMENT_CHARACTER_RUNE; |
| 217 static const List<int> _LIMITS = const <int>[ | 277 } |
| 218 _ONE_BYTE_LIMIT, | 278 if (!_isFirstCharacter || value != UNICODE_BOM_CHARACTER_RUNE) { |
| 219 _TWO_BYTE_LIMIT, | 279 _stringSink.writeCharCode(value); |
| 220 _THREE_BYTE_LIMIT, | 280 } |
| 221 _FOUR_BYTE_LIMIT | 281 _isFirstCharacter = false; |
| 222 ]; | 282 } |
| 223 void close() { | 283 while (i < endIndex) { |
| 224 flush(); | 284 int oneBytes = scanOneByteCharacters(codeUnits, i); |
| 225 } | 285 if (oneBytes > 0) { |
| 226 void flush() { | 286 _isFirstCharacter = false; |
| 227 if (hasPartialInput) { | 287 addSingleBytes(i, i + oneBytes); |
| 228 if (!_allowMalformed) { | 288 i += oneBytes; |
| 229 throw new FormatException("Unfinished UTF-8 octet sequence"); | 289 if (i == endIndex) break; |
| 230 } | 290 } |
| 231 _stringSink.writeCharCode(UNICODE_REPLACEMENT_CHARACTER_RUNE); | 291 int unit = codeUnits[i++]; |
| 232 _value = 0; | 292 if (unit < 0) { |
| 233 _expectedUnits = 0; | 293 if (!_allowMalformed) { |
| 234 _extraUnits = 0; | 294 throw new FormatException("Negative UTF-8 code unit: -0x${(-unit).toRadixString(
16)} |
| 235 } | 295 "); |
| 236 } | 296 } |
| 237 void convert(List<int> codeUnits, int startIndex, int endIndex) { | 297 _stringSink.writeCharCode(UNICODE_REPLACEMENT_CHARACTER_RUNE); |
| 238 int value = _value; | 298 } |
| 239 int expectedUnits = _expectedUnits; | 299 else { |
| 240 int extraUnits = _extraUnits; | 300 assert (unit > _ONE_BYTE_LIMIT); if ((unit & 0xE0) == 0xC0) { |
| 241 _value = 0; | 301 value = unit & 0x1F; |
| 242 _expectedUnits = 0; | 302 expectedUnits = extraUnits = 1; |
| 243 _extraUnits = 0; | 303 continue loop; |
| 244 int scanOneByteCharacters(units, int from) { | 304 } |
| 245 final to = endIndex; | 305 if ((unit & 0xF0) == 0xE0) { |
| 246 final mask = _ONE_BYTE_LIMIT; | 306 value = unit & 0x0F; |
| 247 for (var i = from; i < to; i++) { | 307 expectedUnits = extraUnits = 2; |
| 248 final unit = units[i]; | 308 continue loop; |
| 249 if ((unit & mask) != unit) return i - from; | 309 } |
| 250 } | 310 if ((unit & 0xF8) == 0xF0 && unit < 0xF5) { |
| 251 return to - from; | 311 value = unit & 0x07; |
| 252 } | 312 expectedUnits = extraUnits = 3; |
| 253 void addSingleBytes(int from, int to) { | 313 continue loop; |
| 254 assert(from >= startIndex && from <= endIndex); | 314 } |
| 255 assert(to >= startIndex && to <= endIndex); | 315 if (!_allowMalformed) { |
| 256 _stringSink.write(new String.fromCharCodes(codeUnits, from, to)); | 316 throw new FormatException("Bad UTF-8 encoding 0x${unit.toRadixString(16)} |
| 257 } | 317 "); |
| 258 int i = startIndex; | 318 } |
| 259 loop: while (true) { | 319 value = UNICODE_REPLACEMENT_CHARACTER_RUNE; |
| 260 multibyte: if (expectedUnits > 0) { | 320 expectedUnits = extraUnits = 0; |
| 261 do { | 321 _isFirstCharacter = false; |
| 262 if (i == endIndex) { | 322 _stringSink.writeCharCode(value); |
| 263 break loop; | 323 } |
| 264 } | 324 } |
| 265 int unit = codeUnits[i]; | 325 break loop; |
| 266 if ((unit & 0xC0) != 0x80) { | 326 } |
| 267 expectedUnits = 0; | 327 if (expectedUnits > 0) { |
| 268 if (!_allowMalformed) { | 328 _value = value; |
| 269 throw new FormatException( | 329 _expectedUnits = expectedUnits; |
| 270 "Bad UTF-8 encoding 0x${unit.toRadixString(16)}"); | 330 _extraUnits = extraUnits; |
| 271 } | 331 } |
| 272 _isFirstCharacter = false; | 332 } |
| 273 _stringSink.writeCharCode(UNICODE_REPLACEMENT_CHARACTER_RUNE); | 333 } |
| 274 break multibyte; | |
| 275 } else { | |
| 276 value = (value << 6) | (unit & 0x3f); | |
| 277 expectedUnits--; | |
| 278 i++; | |
| 279 } | |
| 280 } while (expectedUnits > 0); | |
| 281 if (value <= _LIMITS[extraUnits - 1]) { | |
| 282 if (!_allowMalformed) { | |
| 283 throw new FormatException( | |
| 284 "Overlong encoding of 0x${value.toRadixString(16)}"); | |
| 285 } | |
| 286 expectedUnits = extraUnits = 0; | |
| 287 value = UNICODE_REPLACEMENT_CHARACTER_RUNE; | |
| 288 } | |
| 289 if (value > _FOUR_BYTE_LIMIT) { | |
| 290 if (!_allowMalformed) { | |
| 291 throw new FormatException( | |
| 292 "Character outside valid Unicode range: " "0x${value.toRadixStri
ng(16)}"); | |
| 293 } | |
| 294 value = UNICODE_REPLACEMENT_CHARACTER_RUNE; | |
| 295 } | |
| 296 if (!_isFirstCharacter || value != UNICODE_BOM_CHARACTER_RUNE) { | |
| 297 _stringSink.writeCharCode(value); | |
| 298 } | |
| 299 _isFirstCharacter = false; | |
| 300 } | |
| 301 while (i < endIndex) { | |
| 302 int oneBytes = scanOneByteCharacters(codeUnits, i); | |
| 303 if (oneBytes > 0) { | |
| 304 _isFirstCharacter = false; | |
| 305 addSingleBytes(i, i + oneBytes); | |
| 306 i += oneBytes; | |
| 307 if (i == endIndex) break; | |
| 308 } | |
| 309 int unit = codeUnits[i++]; | |
| 310 if (unit < 0) { | |
| 311 if (!_allowMalformed) { | |
| 312 throw new FormatException( | |
| 313 "Negative UTF-8 code unit: -0x${(-unit).toRadixString(16)}"); | |
| 314 } | |
| 315 _stringSink.writeCharCode(UNICODE_REPLACEMENT_CHARACTER_RUNE); | |
| 316 } else { | |
| 317 assert(unit > _ONE_BYTE_LIMIT); | |
| 318 if ((unit & 0xE0) == 0xC0) { | |
| 319 value = unit & 0x1F; | |
| 320 expectedUnits = extraUnits = 1; | |
| 321 continue loop; | |
| 322 } | |
| 323 if ((unit & 0xF0) == 0xE0) { | |
| 324 value = unit & 0x0F; | |
| 325 expectedUnits = extraUnits = 2; | |
| 326 continue loop; | |
| 327 } | |
| 328 if ((unit & 0xF8) == 0xF0 && unit < 0xF5) { | |
| 329 value = unit & 0x07; | |
| 330 expectedUnits = extraUnits = 3; | |
| 331 continue loop; | |
| 332 } | |
| 333 if (!_allowMalformed) { | |
| 334 throw new FormatException( | |
| 335 "Bad UTF-8 encoding 0x${unit.toRadixString(16)}"); | |
| 336 } | |
| 337 value = UNICODE_REPLACEMENT_CHARACTER_RUNE; | |
| 338 expectedUnits = extraUnits = 0; | |
| 339 _isFirstCharacter = false; | |
| 340 _stringSink.writeCharCode(value); | |
| 341 } | |
| 342 } | |
| 343 break loop; | |
| 344 } | |
| 345 if (expectedUnits > 0) { | |
| 346 _value = value; | |
| 347 _expectedUnits = expectedUnits; | |
| 348 _extraUnits = extraUnits; | |
| 349 } | |
| 350 } | |
| 351 } | |
| OLD | NEW |