| OLD | NEW | 
|---|
| 1 // Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file | 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 | 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. | 3 // BSD-style license that can be found in the LICENSE file. | 
| 4 | 4 | 
| 5 // Interface for decoders decoding binary data into string data. The | 5 // Interface for decoders decoding binary data into string data. The | 
| 6 // decoder keeps track of line breaks during decoding. | 6 // decoder keeps track of line breaks during decoding. | 
| 7 interface _StringDecoder { | 7 interface _StringDecoder { | 
| 8   // Add more binary data to be decoded. The ownership of the buffer | 8   // Add more binary data to be decoded. The ownership of the buffer | 
| 9   // is transfered to the decoder and the caller most not modify it any more. | 9   // is transfered to the decoder and the caller most not modify it any more. | 
| 10   int write(List<int> buffer); | 10   int write(List<int> buffer); | 
| (...skipping 10 matching lines...) Expand all  Loading... | 
| 21   String get decoded(); | 21   String get decoded(); | 
| 22 | 22 | 
| 23   // Get the string data decoded since the last call to [decode] or | 23   // Get the string data decoded since the last call to [decode] or | 
| 24   // [decodeLine] up to the next line break present. Returns null if | 24   // [decodeLine] up to the next line break present. Returns null if | 
| 25   // no line break is present. The line break character sequence is | 25   // no line break is present. The line break character sequence is | 
| 26   // discarded. | 26   // discarded. | 
| 27   String get decodedLine(); | 27   String get decodedLine(); | 
| 28 } | 28 } | 
| 29 | 29 | 
| 30 | 30 | 
|  | 31 class _StringDecoders { | 
|  | 32   static _StringDecoder decoder(Encoding encoding) { | 
|  | 33     if (encoding == Encoding.UTF_8) { | 
|  | 34       return new _UTF8Decoder(); | 
|  | 35     } else if (encoding == Encoding.ISO_8859_1) { | 
|  | 36       return new _Latin1Decoder(); | 
|  | 37     } else if (encoding == Encoding.ASCII) { | 
|  | 38       return new _AsciiDecoder(); | 
|  | 39     } else { | 
|  | 40       throw new StreamException("Unsupported encoding ${encoding.name}"); | 
|  | 41     } | 
|  | 42   } | 
|  | 43 } | 
|  | 44 | 
|  | 45 | 
| 31 class DecoderException implements Exception { | 46 class DecoderException implements Exception { | 
| 32   const DecoderException([String this.message]); | 47   const DecoderException([String this.message]); | 
| 33   String toString() => "DecoderException: $message"; | 48   String toString() => "DecoderException: $message"; | 
| 34   final String message; | 49   final String message; | 
| 35 } | 50 } | 
| 36 | 51 | 
| 37 | 52 | 
| 38 // Utility class for decoding UTF-8 from data delivered as a stream of | 53 // Utility class for decoding UTF-8 from data delivered as a stream of | 
| 39 // bytes. | 54 // bytes. | 
| 40 class _StringDecoderBase implements _StringDecoder { | 55 class _StringDecoderBase implements _StringDecoder { | 
| (...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 135   Queue<int> _lineBreakEnds;  // Character position of known line breaks. | 150   Queue<int> _lineBreakEnds;  // Character position of known line breaks. | 
| 136   int _charOffset = 0;  // Character number of the first character in the list. | 151   int _charOffset = 0;  // Character number of the first character in the list. | 
| 137   int _charCount = 0;  // Total number of characters decoded. | 152   int _charCount = 0;  // Total number of characters decoded. | 
| 138   int _lastCharCode = -1; | 153   int _lastCharCode = -1; | 
| 139 | 154 | 
| 140   final int LF = 10; | 155   final int LF = 10; | 
| 141   final int CR = 13; | 156   final int CR = 13; | 
| 142 } | 157 } | 
| 143 | 158 | 
| 144 | 159 | 
|  | 160 // Utility class for decoding UTF-8 from data delivered as a stream of | 
|  | 161 // bytes. | 
|  | 162 class _UTF8Decoder extends _StringDecoderBase { | 
|  | 163   // Process the next UTF-8 encoded character. | 
|  | 164   bool _processNext() { | 
|  | 165     // Peek the next byte to calculate the number of bytes required for | 
|  | 166     // the next character. | 
|  | 167     int value = _bufferList.peek() & 0xFF; | 
|  | 168     if ((value & 0x80) == 0x80) { | 
|  | 169       int additionalBytes; | 
|  | 170       if ((value & 0xe0) == 0xc0) {  // 110xxxxx | 
|  | 171         value = value & 0x1F; | 
|  | 172         additionalBytes = 1; | 
|  | 173       } else if ((value & 0xf0) == 0xe0) {  // 1110xxxx | 
|  | 174         value = value & 0x0F; | 
|  | 175         additionalBytes = 2; | 
|  | 176       } else {  // 11110xxx | 
|  | 177         value = value & 0x07; | 
|  | 178         additionalBytes = 3; | 
|  | 179       } | 
|  | 180       // Check if there are enough bytes to decode the character. Otherwise | 
|  | 181       // return false. | 
|  | 182       if (_bufferList.length < additionalBytes + 1) { | 
|  | 183         return false; | 
|  | 184       } | 
|  | 185       // Remove the value peeked from the buffer list. | 
|  | 186       _bufferList.next(); | 
|  | 187       for (int i = 0; i < additionalBytes; i++) { | 
|  | 188         int byte = _bufferList.next(); | 
|  | 189         value = value << 6 | (byte & 0x3F); | 
|  | 190       } | 
|  | 191     } else { | 
|  | 192       // Remove the value peeked from the buffer list. | 
|  | 193       _bufferList.next(); | 
|  | 194     } | 
|  | 195     addChar(value); | 
|  | 196     return true; | 
|  | 197   } | 
|  | 198 } | 
|  | 199 | 
|  | 200 | 
| 145 // Utility class for decoding ascii data delivered as a stream of | 201 // Utility class for decoding ascii data delivered as a stream of | 
| 146 // bytes. | 202 // bytes. | 
| 147 class _AsciiDecoder extends _StringDecoderBase { | 203 class _AsciiDecoder extends _StringDecoderBase { | 
| 148   // Process the next ascii encoded character. | 204   // Process the next ascii encoded character. | 
| 149   bool _processNext() { | 205   bool _processNext() { | 
| 150     while (_bufferList.length > 0) { | 206     while (_bufferList.length > 0) { | 
| 151       int byte = _bufferList.next(); | 207       int byte = _bufferList.next(); | 
| 152       if (byte > 127) { | 208       if (byte > 127) { | 
| 153         throw new DecoderException("Illegal ASCII character $byte"); | 209         throw new DecoderException("Illegal ASCII character $byte"); | 
| 154       } | 210       } | 
| (...skipping 11 matching lines...) Expand all  Loading... | 
| 166   bool _processNext() { | 222   bool _processNext() { | 
| 167     while (_bufferList.length > 0) { | 223     while (_bufferList.length > 0) { | 
| 168       int byte = _bufferList.next(); | 224       int byte = _bufferList.next(); | 
| 169       addChar(byte); | 225       addChar(byte); | 
| 170     } | 226     } | 
| 171     return true; | 227     return true; | 
| 172   } | 228   } | 
| 173 } | 229 } | 
| 174 | 230 | 
| 175 | 231 | 
| 176 // Utility class for decoding UTF-8 from data delivered as a stream of | 232 // Interface for encoders encoding string data into binary data. | 
| 177 // bytes. | 233 interface _StringEncoder { | 
| 178 class _UTF8Decoder extends _StringDecoderBase { | 234   List<int> encodeString(String string); | 
| 179   // Process the next UTF-8 encoded character. | 235 } | 
| 180   bool _processNext() { | 236 | 
| 181     // Peek the next byte to calculate the number of bytes required for | 237 | 
| 182     // the next character. | 238 // Utility class for encoding a string into UTF-8 byte stream. | 
| 183     int value = _bufferList.peek() & 0xFF; | 239 class _UTF8Encoder implements _StringEncoder { | 
| 184     if ((value & 0x80) == 0x80) { | 240   List<int> encodeString(String string) { | 
|  | 241     int size = _encodingSize(string); | 
|  | 242     ByteArray result = new ByteArray(size); | 
|  | 243     _encodeString(string, result); | 
|  | 244     return result; | 
|  | 245   } | 
|  | 246 | 
|  | 247   static int _encodingSize(String string) => _encodeString(string, null); | 
|  | 248 | 
|  | 249   static int _encodeString(String string, List<int> buffer) { | 
|  | 250     int pos = 0; | 
|  | 251     int length = string.length; | 
|  | 252     for (int i = 0; i < length; i++) { | 
| 185       int additionalBytes; | 253       int additionalBytes; | 
| 186       if ((value & 0xe0) == 0xc0) {  // 110xxxxx | 254       int charCode = string.charCodeAt(i); | 
| 187         value = value & 0x1F; | 255       if (charCode <= 0x007F) { | 
|  | 256         additionalBytes = 0; | 
|  | 257         if (buffer != null) buffer[pos] = charCode; | 
|  | 258       } else if (charCode <= 0x07FF) { | 
|  | 259         // 110xxxxx (xxxxx is top 5 bits). | 
|  | 260         if (buffer != null) buffer[pos] = ((charCode >> 6) & 0x1F) | 0xC0; | 
| 188         additionalBytes = 1; | 261         additionalBytes = 1; | 
| 189       } else if ((value & 0xf0) == 0xe0) {  // 1110xxxx | 262       } else if (charCode <= 0xFFFF) { | 
| 190         value = value & 0x0F; | 263         // 1110xxxx (xxxx is top 4 bits) | 
|  | 264         if (buffer != null) buffer[pos] = ((charCode >> 12) & 0x0F)| 0xE0; | 
| 191         additionalBytes = 2; | 265         additionalBytes = 2; | 
| 192       } else {  // 11110xxx | 266       } else { | 
| 193         value = value & 0x07; | 267         // 11110xxx (xxx is top 3 bits) | 
|  | 268         if (buffer != null) buffer[pos] = ((charCode >> 18) & 0x07) | 0xF0; | 
| 194         additionalBytes = 3; | 269         additionalBytes = 3; | 
| 195       } | 270       } | 
| 196       // Check if there are enough bytes to decode the character. Otherwise | 271       pos++; | 
| 197       // return false. | 272       if (buffer != null) { | 
| 198       if (_bufferList.length < additionalBytes + 1) { | 273         for (int i = additionalBytes; i > 0; i--) { | 
| 199         return false; | 274           // 10xxxxxx (xxxxxx is next 6 bits from the top). | 
|  | 275           buffer[pos++] = ((charCode >> (6 * (i - 1))) & 0x3F) | 0x80; | 
|  | 276         } | 
|  | 277       } else { | 
|  | 278         pos += additionalBytes; | 
| 200       } | 279       } | 
| 201       // Remove the value peeked from the buffer list. |  | 
| 202       _bufferList.next(); |  | 
| 203       for (int i = 0; i < additionalBytes; i++) { |  | 
| 204         int byte = _bufferList.next(); |  | 
| 205         value = value << 6 | (byte & 0x3F); |  | 
| 206       } |  | 
| 207     } else { |  | 
| 208       // Remove the value peeked from the buffer list. |  | 
| 209       _bufferList.next(); |  | 
| 210     } | 280     } | 
| 211     addChar(value); | 281     return pos; | 
| 212     return true; |  | 
| 213   } | 282   } | 
| 214 } | 283 } | 
| 215 | 284 | 
| 216 | 285 | 
|  | 286 // Utility class for encoding a string into a Latin1 byte stream. | 
|  | 287 class _Latin1Encoder implements _StringEncoder { | 
|  | 288   List<int> encodeString(String string) { | 
|  | 289     ByteArray result = new ByteArray(string.length); | 
|  | 290     for (int i = 0; i < string.length; i++) { | 
|  | 291       int charCode = string.charCodeAt(i); | 
|  | 292       if (charCode > 255) { | 
|  | 293         throw new EncoderException( | 
|  | 294             "No ISO_8859_1 encoding for code point $charCode"); | 
|  | 295       } | 
|  | 296       result[i] = charCode; | 
|  | 297     } | 
|  | 298     return result; | 
|  | 299   } | 
|  | 300 } | 
|  | 301 | 
|  | 302 | 
|  | 303 // Utility class for encoding a string into an ASCII byte stream. | 
|  | 304 class _AsciiEncoder implements _StringEncoder { | 
|  | 305   List<int> encodeString(String string) { | 
|  | 306     ByteArray result = new ByteArray(string.length); | 
|  | 307     for (int i = 0; i < string.length; i++) { | 
|  | 308       int charCode = string.charCodeAt(i); | 
|  | 309       if (charCode > 127) { | 
|  | 310         throw new EncoderException( | 
|  | 311             "No ASCII encoding for code point $charCode"); | 
|  | 312       } | 
|  | 313       result[i] = charCode; | 
|  | 314     } | 
|  | 315     return result; | 
|  | 316   } | 
|  | 317 } | 
|  | 318 | 
|  | 319 | 
|  | 320 class _StringEncoders { | 
|  | 321   static _StringEncoder encoder(Encoding encoding) { | 
|  | 322     if (encoding == Encoding.UTF_8) { | 
|  | 323       return new _UTF8Encoder(); | 
|  | 324     } else if (encoding == Encoding.ISO_8859_1) { | 
|  | 325       return new _Latin1Encoder(); | 
|  | 326     } else if (encoding == Encoding.ASCII) { | 
|  | 327       return new _AsciiEncoder(); | 
|  | 328     } else { | 
|  | 329       throw new StreamException("Unsupported encoding ${encoding.name}"); | 
|  | 330     } | 
|  | 331   } | 
|  | 332 } | 
|  | 333 | 
|  | 334 | 
|  | 335 class EncoderException implements Exception { | 
|  | 336   const EncoderException([String this.message]); | 
|  | 337   String toString() => "EncoderException: $message"; | 
|  | 338   final String message; | 
|  | 339 } | 
|  | 340 | 
|  | 341 | 
| 217 class _StringInputStream implements StringInputStream { | 342 class _StringInputStream implements StringInputStream { | 
| 218   _StringInputStream(InputStream this._input, [String encoding]) | 343   _StringInputStream(InputStream this._input, | 
|  | 344                      [Encoding encoding = Encoding.UTF_8]) | 
| 219       : _encoding = encoding { | 345       : _encoding = encoding { | 
| 220     if (_encoding === null) { | 346     _decoder = _StringDecoders.decoder(encoding); | 
| 221       _encoding = "UTF-8"; |  | 
| 222     } |  | 
| 223     if (_encoding == "UTF-8") { |  | 
| 224       _decoder = new _UTF8Decoder(); |  | 
| 225     } else if (_encoding == "ISO-8859-1") { |  | 
| 226       _decoder = new _Latin1Decoder(); |  | 
| 227     } else if (_encoding == "ASCII") { |  | 
| 228       _decoder = new _AsciiDecoder(); |  | 
| 229     } else { |  | 
| 230       throw new StreamException("Unsupported encoding $_encoding"); |  | 
| 231     } |  | 
| 232     _input.onData = _onData; | 347     _input.onData = _onData; | 
| 233     _input.onClosed = _onClosed; | 348     _input.onClosed = _onClosed; | 
| 234   } | 349   } | 
| 235 | 350 | 
| 236   String read() { | 351   String read() { | 
| 237     String result = _decoder.decoded; | 352     String result = _decoder.decoded; | 
| 238     _checkInstallDataHandler(); | 353     _checkInstallDataHandler(); | 
| 239     return result; | 354     return result; | 
| 240   } | 355   } | 
| 241 | 356 | 
| 242   String readLine() { | 357   String readLine() { | 
| 243     String decodedLine = _decoder.decodedLine; | 358     String decodedLine = _decoder.decodedLine; | 
| 244     if (decodedLine == null) { | 359     if (decodedLine == null) { | 
| 245       if (_inputClosed) { | 360       if (_inputClosed) { | 
| 246         // Last line might not have a line separator. | 361         // Last line might not have a line separator. | 
| 247         decodedLine = _decoder.decoded; | 362         decodedLine = _decoder.decoded; | 
| 248         if (decodedLine != null && | 363         if (decodedLine != null && | 
| 249             decodedLine[decodedLine.length - 1] == '\r') { | 364             decodedLine[decodedLine.length - 1] == '\r') { | 
| 250           decodedLine = decodedLine.substring(0, decodedLine.length - 1); | 365           decodedLine = decodedLine.substring(0, decodedLine.length - 1); | 
| 251         } | 366         } | 
| 252       } | 367       } | 
| 253     } | 368     } | 
| 254     _checkInstallDataHandler(); | 369     _checkInstallDataHandler(); | 
| 255     return decodedLine; | 370     return decodedLine; | 
| 256   } | 371   } | 
| 257 | 372 | 
| 258   int available() => _decoder.available(); | 373   int available() => _decoder.available(); | 
| 259 | 374 | 
| 260   String get encoding() => _encoding; | 375   Encoding get encoding() => _encoding; | 
| 261 | 376 | 
| 262   bool get closed() => _inputClosed && _decoder.isEmpty(); | 377   bool get closed() => _inputClosed && _decoder.isEmpty(); | 
| 263 | 378 | 
| 264   void set onData(void callback()) { | 379   void set onData(void callback()) { | 
| 265     _clientDataHandler = callback; | 380     _clientDataHandler = callback; | 
| 266     _clientLineHandler = null; | 381     _clientLineHandler = null; | 
| 267     _checkInstallDataHandler(); | 382     _checkInstallDataHandler(); | 
| 268     _checkScheduleCallback(); | 383     _checkScheduleCallback(); | 
| 269   } | 384   } | 
| 270 | 385 | 
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after  Loading... | 
| 383       // Schedule close callback if no more data and input is closed. | 498       // Schedule close callback if no more data and input is closed. | 
| 384       if (_decoder.isEmpty() && | 499       if (_decoder.isEmpty() && | 
| 385           _inputClosed && | 500           _inputClosed && | 
| 386           _scheduledCloseCallback == null) { | 501           _scheduledCloseCallback == null) { | 
| 387         _scheduledCloseCallback = new Timer(0, issueCloseCallback); | 502         _scheduledCloseCallback = new Timer(0, issueCloseCallback); | 
| 388       } | 503       } | 
| 389     } | 504     } | 
| 390   } | 505   } | 
| 391 | 506 | 
| 392   InputStream _input; | 507   InputStream _input; | 
| 393   String _encoding; | 508   Encoding _encoding; | 
| 394   _StringDecoder _decoder; | 509   _StringDecoder _decoder; | 
| 395   bool _inputClosed = false;  // Is the underlying input stream closed? | 510   bool _inputClosed = false;  // Is the underlying input stream closed? | 
| 396   bool _closed = false;  // Is this stream closed. | 511   bool _closed = false;  // Is this stream closed. | 
| 397   bool _eof = false;  // Has all data been read from the decoder? | 512   bool _eof = false;  // Has all data been read from the decoder? | 
| 398   Timer _scheduledDataCallback; | 513   Timer _scheduledDataCallback; | 
| 399   Timer _scheduledLineCallback; | 514   Timer _scheduledLineCallback; | 
| 400   Timer _scheduledCloseCallback; | 515   Timer _scheduledCloseCallback; | 
| 401   Function _clientDataHandler; | 516   Function _clientDataHandler; | 
| 402   Function _clientLineHandler; | 517   Function _clientLineHandler; | 
| 403   Function _clientCloseHandler; | 518   Function _clientCloseHandler; | 
| 404 } | 519 } | 
| OLD | NEW | 
|---|