| 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.utf; | |
| 6 | |
| 7 abstract class _StringDecoder | |
| 8 implements StreamTransformer<List<int>, String>, EventSink<List<int>> { | |
| 9 List<int> _carry; | |
| 10 List<int> _buffer; | |
| 11 int _replacementChar; | |
| 12 | |
| 13 EventSink<String> _outSink; | |
| 14 | |
| 15 _StringDecoder(int this._replacementChar); | |
| 16 | |
| 17 Stream<String> bind(Stream<List<int>> stream) { | |
| 18 return new Stream.eventTransformed( | |
| 19 stream, | |
| 20 (EventSink<String> sink) { | |
| 21 if (_outSink != null) { | |
| 22 throw new StateError("String decoder already used"); | |
| 23 } | |
| 24 _outSink = sink; | |
| 25 return this; | |
| 26 }); | |
| 27 } | |
| 28 | |
| 29 void add(List<int> bytes) { | |
| 30 try { | |
| 31 _buffer = <int>[]; | |
| 32 List<int> carry = _carry; | |
| 33 _carry = null; | |
| 34 int pos = 0; | |
| 35 int available = bytes.length; | |
| 36 // If we have carry-over data, start from negative index, indicating carry | |
| 37 // index. | |
| 38 int goodChars = 0; | |
| 39 if (carry != null) pos = -carry.length; | |
| 40 while (pos < available) { | |
| 41 int currentPos = pos; | |
| 42 int getNext() { | |
| 43 if (pos < 0) { | |
| 44 return carry[pos++ + carry.length]; | |
| 45 } else if (pos < available) { | |
| 46 return bytes[pos++]; | |
| 47 } | |
| 48 return null; | |
| 49 } | |
| 50 int consumed = _processBytes(getNext); | |
| 51 if (consumed > 0) { | |
| 52 goodChars = _buffer.length; | |
| 53 } else if (consumed == 0) { | |
| 54 _buffer.length = goodChars; | |
| 55 if (currentPos < 0) { | |
| 56 _carry = []; | |
| 57 _carry.addAll(carry); | |
| 58 _carry.addAll(bytes); | |
| 59 } else { | |
| 60 _carry = bytes.sublist(currentPos); | |
| 61 } | |
| 62 break; | |
| 63 } else { | |
| 64 // Invalid byte at position pos - 1 | |
| 65 _buffer.length = goodChars; | |
| 66 _addChar(-1); | |
| 67 goodChars = _buffer.length; | |
| 68 } | |
| 69 } | |
| 70 if (_buffer.length > 0) { | |
| 71 // Limit to 'goodChars', if lower than actual charCodes in the buffer. | |
| 72 _outSink.add(new String.fromCharCodes(_buffer)); | |
| 73 } | |
| 74 _buffer = null; | |
| 75 } catch (e, stackTrace) { | |
| 76 _outSink.addError(e, stackTrace); | |
| 77 } | |
| 78 } | |
| 79 | |
| 80 void addError(Object error, [StackTrace stackTrace]) { | |
| 81 _outSink.addError(error, stackTrace); | |
| 82 } | |
| 83 | |
| 84 void close() { | |
| 85 if (_carry != null) { | |
| 86 if (_replacementChar != null) { | |
| 87 _outSink.add(new String.fromCharCodes( | |
| 88 new List.filled(_carry.length, _replacementChar))); | |
| 89 } else { | |
| 90 throw new ArgumentError('Invalid codepoint'); | |
| 91 } | |
| 92 } | |
| 93 _outSink.close(); | |
| 94 } | |
| 95 | |
| 96 int _processBytes(int getNext()); | |
| 97 | |
| 98 void _addChar(int char) { | |
| 99 void error() { | |
| 100 if (_replacementChar != null) { | |
| 101 char = _replacementChar; | |
| 102 } else { | |
| 103 throw new ArgumentError('Invalid codepoint'); | |
| 104 } | |
| 105 } | |
| 106 if (char < 0) error(); | |
| 107 if (char >= 0xD800 && char <= 0xDFFF) error(); | |
| 108 if (char > 0x10FFFF) error(); | |
| 109 _buffer.add(char); | |
| 110 } | |
| 111 } | |
| 112 | |
| 113 /** | |
| 114 * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert` | |
| 115 * instead. | |
| 116 */ | |
| 117 @deprecated | |
| 118 class Utf8DecoderTransformer extends _StringDecoder { | |
| 119 Utf8DecoderTransformer( | |
| 120 [int replacementChar = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT]) | |
| 121 : super(replacementChar); | |
| 122 | |
| 123 int _processBytes(int getNext()) { | |
| 124 int value = getNext(); | |
| 125 if ((value & 0xFF) != value) return -1; // Not a byte. | |
| 126 if ((value & 0x80) == 0x80) { | |
| 127 int additionalBytes; | |
| 128 int min; | |
| 129 if ((value & 0xe0) == 0xc0) { // 110xxxxx | |
| 130 value = value & 0x1F; | |
| 131 additionalBytes = 1; | |
| 132 min = 0x80; | |
| 133 } else if ((value & 0xf0) == 0xe0) { // 1110xxxx | |
| 134 value = value & 0x0F; | |
| 135 additionalBytes = 2; | |
| 136 min = 0x800; | |
| 137 } else if ((value & 0xf8) == 0xf0) { // 11110xxx | |
| 138 value = value & 0x07; | |
| 139 additionalBytes = 3; | |
| 140 min = 0x10000; | |
| 141 } else if ((value & 0xfc) == 0xf8) { // 111110xx | |
| 142 value = value & 0x03; | |
| 143 additionalBytes = 4; | |
| 144 min = 0x200000; | |
| 145 } else if ((value & 0xfe) == 0xfc) { // 1111110x | |
| 146 value = value & 0x01; | |
| 147 additionalBytes = 5; | |
| 148 min = 0x4000000; | |
| 149 } else { | |
| 150 return -1; | |
| 151 } | |
| 152 for (int i = 0; i < additionalBytes; i++) { | |
| 153 int next = getNext(); | |
| 154 if (next == null) return 0; // Not enough chars, reset. | |
| 155 if ((next & 0xc0) != 0x80 || (next & 0xff) != next) return -1; | |
| 156 value = value << 6 | (next & 0x3f); | |
| 157 if (additionalBytes >= 3 && i == 0 && value << 12 > 0x10FFFF) { | |
| 158 _addChar(-1); | |
| 159 } | |
| 160 } | |
| 161 // Invalid charCode if less then minimum expected. | |
| 162 if (value < min) value = -1; | |
| 163 _addChar(value); | |
| 164 return 1 + additionalBytes; | |
| 165 } | |
| 166 _addChar(value); | |
| 167 return 1; | |
| 168 } | |
| 169 } | |
| 170 | |
| 171 | |
| 172 abstract class _StringEncoder | |
| 173 implements StreamTransformer<String, List<int>>, EventSink<String> { | |
| 174 | |
| 175 EventSink<List<int>> _outSink; | |
| 176 | |
| 177 Stream<List<int>> bind(Stream<String> stream) { | |
| 178 return new Stream.eventTransformed( | |
| 179 stream, | |
| 180 (EventSink<List<int>> sink) { | |
| 181 if (_outSink != null) { | |
| 182 throw new StateError("String encoder already used"); | |
| 183 } | |
| 184 _outSink = sink; | |
| 185 return this; | |
| 186 }); | |
| 187 } | |
| 188 | |
| 189 void add(String data) { | |
| 190 _outSink.add(_processString(data)); | |
| 191 } | |
| 192 | |
| 193 void addError(Object error, [StackTrace stackTrace]) { | |
| 194 _outSink.addError(error, stackTrace); | |
| 195 } | |
| 196 | |
| 197 void close() { _outSink.close(); } | |
| 198 | |
| 199 List<int> _processString(String string); | |
| 200 } | |
| 201 | |
| 202 /** | |
| 203 * *DEPRECATED*: Use `package:utf/utf.dart` or, when applicable, `dart:convert` | |
| 204 * instead. | |
| 205 */ | |
| 206 @deprecated | |
| 207 class Utf8EncoderTransformer extends _StringEncoder { | |
| 208 List<int> _processString(String string) { | |
| 209 var bytes = []; | |
| 210 int pos = 0; | |
| 211 List<int> codepoints = _utf16CodeUnitsToCodepoints(string.codeUnits); | |
| 212 int length = codepoints.length; | |
| 213 for (int i = 0; i < length; i++) { | |
| 214 int additionalBytes; | |
| 215 int charCode = codepoints[i]; | |
| 216 if (charCode <= 0x007F) { | |
| 217 additionalBytes = 0; | |
| 218 bytes.add(charCode); | |
| 219 } else if (charCode <= 0x07FF) { | |
| 220 // 110xxxxx (xxxxx is top 5 bits). | |
| 221 bytes.add(((charCode >> 6) & 0x1F) | 0xC0); | |
| 222 additionalBytes = 1; | |
| 223 } else if (charCode <= 0xFFFF) { | |
| 224 // 1110xxxx (xxxx is top 4 bits) | |
| 225 bytes.add(((charCode >> 12) & 0x0F)| 0xE0); | |
| 226 additionalBytes = 2; | |
| 227 } else { | |
| 228 // 11110xxx (xxx is top 3 bits) | |
| 229 bytes.add(((charCode >> 18) & 0x07) | 0xF0); | |
| 230 additionalBytes = 3; | |
| 231 } | |
| 232 for (int i = additionalBytes; i > 0; i--) { | |
| 233 // 10xxxxxx (xxxxxx is next 6 bits from the top). | |
| 234 bytes.add(((charCode >> (6 * (i - 1))) & 0x3F) | 0x80); | |
| 235 } | |
| 236 pos += additionalBytes + 1; | |
| 237 } | |
| 238 return bytes; | |
| 239 } | |
| 240 } | |
| OLD | NEW |