OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2011, 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 // Utility class which can deliver bytes one by one from a number of |
| 6 // buffers added. |
| 7 class BufferList { |
| 8 BufferList() : _index = 0, _length = 0, _buffers = new Queue(); |
| 9 |
| 10 void add(List<int> buffer) { |
| 11 _buffers.addLast(buffer); |
| 12 _length += buffer.length; |
| 13 } |
| 14 |
| 15 int peek() { |
| 16 return _buffers.first()[_index]; |
| 17 } |
| 18 |
| 19 int next() { |
| 20 int value = _buffers.first()[_index++]; |
| 21 _length--; |
| 22 if (_index == _buffers.first().length) { |
| 23 _buffers.removeFirst(); |
| 24 _index = 0; |
| 25 } |
| 26 return value; |
| 27 } |
| 28 |
| 29 int get length() => _length; |
| 30 |
| 31 int _length; |
| 32 Queue<List<int>> _buffers; |
| 33 int _index; |
| 34 } |
| 35 |
| 36 |
| 37 // Utility class for decoding UTF-8 from data delivered as a stream of |
| 38 // bytes. |
| 39 class UTF8Decoder { |
| 40 UTF8Decoder() |
| 41 : _bufferList = new BufferList(), |
| 42 _result = new StringBuffer(); |
| 43 |
| 44 // Add UTF-8 encoded data. |
| 45 int write(List<int> buffer) { |
| 46 _bufferList.add(buffer); |
| 47 // Decode as many bytes into characters as possible. |
| 48 while (_bufferList.length > 0) { |
| 49 if (!_processNext()) { |
| 50 break; |
| 51 } |
| 52 } |
| 53 } |
| 54 |
| 55 // Check if any characters have been decoded so far. |
| 56 bool isEmpty() { |
| 57 return _result.isEmpty(); |
| 58 } |
| 59 |
| 60 // Return the string decoded so far. |
| 61 String get decodedString() { |
| 62 if (isEmpty()) { |
| 63 return null; |
| 64 } else { |
| 65 String result = _result.toString(); |
| 66 _result = new StringBuffer(); |
| 67 return result; |
| 68 } |
| 69 } |
| 70 |
| 71 // Process the next UTF-8 encoded character. |
| 72 bool _processNext() { |
| 73 // Peek the next byte to calculate the number of bytes required |
| 74 // for the next character. |
| 75 int value = _bufferList.peek() & 0xFF; |
| 76 if ((value & 0x80) == 0x80) { |
| 77 int additionalBytes; |
| 78 if ((value & 0xe0) == 0xc0) { // 110xxxxx |
| 79 value = value & 0x1F; |
| 80 additionalBytes = 1; |
| 81 } else if ((value & 0xf0) == 0xe0) { // 1110xxxx |
| 82 value = value & 0x0F; |
| 83 additionalBytes = 2; |
| 84 } else { // 11110xxx |
| 85 value = value & 0x07; |
| 86 additionalBytes = 3; |
| 87 } |
| 88 // Check if there are not enough bytes to decode the character |
| 89 // return false. |
| 90 if (_bufferList.length < additionalBytes + 1) { |
| 91 return false; |
| 92 } |
| 93 // Remove the value peeked from the buffer list. |
| 94 _bufferList.next(); |
| 95 for (int i = 0; i < additionalBytes; i++) { |
| 96 int byte = _bufferList.next(); |
| 97 value = value << 6 | (byte & 0x3F); |
| 98 } |
| 99 } else { |
| 100 // Remove the value peeked from the buffer list. |
| 101 _bufferList.next(); |
| 102 } |
| 103 _result.addCharCode(value); |
| 104 return true; |
| 105 } |
| 106 |
| 107 BufferList _bufferList; |
| 108 StringBuffer _result; |
| 109 } |
| 110 |
| 111 |
| 112 class _StringInputStream implements StringInputStream { |
| 113 _StringInputStream(InputStream2 this._input, [String this._encoding]) { |
| 114 if (_encoding == null) { |
| 115 _encoding = "UTF-8"; |
| 116 } |
| 117 if (_encoding != "UTF-8") { |
| 118 throw new StreamException("Unsupported encoding $_encoding"); |
| 119 } |
| 120 _decoder = new UTF8Decoder(); |
| 121 _input.dataHandler = _dataHandler; |
| 122 } |
| 123 |
| 124 String read() { |
| 125 return _decoder.decodedString; |
| 126 } |
| 127 |
| 128 String get encoding() => _encoding; |
| 129 |
| 130 void set dataHandler(void callback()) { |
| 131 _clientDataHandler = callback; |
| 132 } |
| 133 |
| 134 void _dataHandler() { |
| 135 List<int> buffer = _input.read(); |
| 136 if (buffer != null) { |
| 137 _decoder.write(buffer); |
| 138 } |
| 139 if (!_decoder.isEmpty() && _clientDataHandler != null) { |
| 140 _clientDataHandler(); |
| 141 } |
| 142 } |
| 143 |
| 144 InputStream2 _input; |
| 145 String _encoding; |
| 146 UTF8Decoder _decoder; |
| 147 var _clientDataHandler; |
| 148 } |
OLD | NEW |