Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(228)

Side by Side Diff: runtime/bin/string_stream.dart

Issue 8318009: Update the streams interfaces (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Minor fixes Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 // Interface for decoders decoding binary data into objects of type T.
38 interface _Decoder<T> {
39 // Add more binary data to be decoded.
Mads Ager (google) 2011/10/26 10:56:07 Ownership of the buffer is transferred to the Deco
Søren Gjesse 2011/10/26 12:03:31 Done.
40 int write(List<int> buffer);
41
42 // Returns whether any decoded data is available.
43 bool isEmpty();
44
45 // Get the decoded data.
Mads Ager (google) 2011/10/26 10:56:07 Get the data decoded since the last call to decode
Søren Gjesse 2011/10/26 12:03:31 Done.
46 T get decoded();
47 }
48
49
50 class DecoderException implements Exception {
51 const DecoderException([String this.message]);
52 String toString() => "DecoderException: $message";
53 final String message;
54 }
55
56
57 // Utility class for decoding UTF-8 from data delivered as a stream of
58 // bytes.
59 class _StringDecoderBase implements _Decoder<String> {
60 _StringDecoderBase()
61 : _bufferList = new _BufferList(),
62 _result = new StringBuffer();
63
64 // Add UTF-8 encoded data.
65 int write(List<int> buffer) {
66 _bufferList.add(buffer);
67 // Decode as many bytes into characters as possible.
68 while (_bufferList.length > 0) {
69 if (!_processNext()) {
70 break;
71 }
72 }
73 return buffer.length;
74 }
75
76 // Check if any characters have been decoded so far.
77 bool isEmpty() {
78 return _result.isEmpty();
79 }
80
81 // Return the string decoded so far.
Mads Ager (google) 2011/10/26 10:56:07 so far -> since the last call to decoded.
Søren Gjesse 2011/10/26 12:03:31 Done.
82 String get decoded() {
83 if (isEmpty()) {
84 return null;
85 } else {
86 String result = _result.toString();
87 _result = new StringBuffer();
88 return result;
89 }
90 }
91
92 abstract bool _processNext();
93
94 _BufferList _bufferList;
95 StringBuffer _result;
96 }
97
98
99 // Utility class for decoding ascii data delivered as a stream of
100 // bytes.
101 class _AsciiDecoder extends _StringDecoderBase {
102 // Process the next ascii encoded character.
103 bool _processNext() {
104 while (_bufferList.length > 0) {
105 int byte = _bufferList.next();
106 if (byte > 127) {
107 throw new DecoderException("Illegal ASCII character $byte");
108 }
109 _result.addCharCode(byte);
110 }
111 return true;
112 }
113 }
114
115
116 // Utility class for decoding Latin-1 data delivered as a stream of
117 // bytes.
118 class _Latin1Decoder extends _StringDecoderBase {
119 // Process the next Latin-1 encoded character.
120 bool _processNext() {
121 while (_bufferList.length > 0) {
122 int byte = _bufferList.next();
123 _result.addCharCode(byte);
124 }
125 return true;
126 }
127 }
128
129
130 // Utility class for decoding UTF-8 from data delivered as a stream of
131 // bytes.
132 class _UTF8Decoder extends _StringDecoderBase {
133 // Process the next UTF-8 encoded character.
134 bool _processNext() {
135 // Peek the next byte to calculate the number of bytes required
136 // for the next character.
137 int value = _bufferList.peek() & 0xFF;
138 if ((value & 0x80) == 0x80) {
139 int additionalBytes;
140 if ((value & 0xe0) == 0xc0) { // 110xxxxx
141 value = value & 0x1F;
142 additionalBytes = 1;
143 } else if ((value & 0xf0) == 0xe0) { // 1110xxxx
144 value = value & 0x0F;
145 additionalBytes = 2;
146 } else { // 11110xxx
147 value = value & 0x07;
148 additionalBytes = 3;
149 }
150 // Check if there are not enough bytes to decode the character
Mads Ager (google) 2011/10/26 10:56:07 Check if there are enough bytes to decode the char
Søren Gjesse 2011/10/26 12:03:31 Done.
151 // return false.
152 if (_bufferList.length < additionalBytes + 1) {
153 return false;
154 }
155 // Remove the value peeked from the buffer list.
156 _bufferList.next();
157 for (int i = 0; i < additionalBytes; i++) {
158 int byte = _bufferList.next();
159 value = value << 6 | (byte & 0x3F);
160 }
161 } else {
162 // Remove the value peeked from the buffer list.
163 _bufferList.next();
164 }
165 _result.addCharCode(value);
166 return true;
167 }
168 }
169
170
171 class _StringInputStream implements StringInputStream {
172 _StringInputStream(InputStream this._input, [String this._encoding]) {
173 if (_encoding == null) {
174 _encoding = "UTF-8";
175 }
176 if (_encoding == "UTF-8") {
177 _decoder = new _UTF8Decoder();
178 } else if (_encoding == "ISO-8859-1") {
179 _decoder = new _Latin1Decoder();
180 } else if (_encoding == "ASCII") {
181 _decoder = new _AsciiDecoder();
182 } else {
183 throw new StreamException("Unsupported encoding $_encoding");
184 }
185 _input.dataHandler = _dataHandler;
186 _input.closeHandler = _closeHandler;
187 }
188
189 String read() {
190 // If there is buffered data return that first.
191 var decodedString = _decoder.decoded;
192 if (_buffer != null) {
193 var result = _buffer;
194 _resetBuffer();
195 if (decodedString != null) result += decodedString;
196 return result;
197 } else {
198 if (decodedString != null) {
199 return decodedString;
200 } else {
201 _readData();
202 return _decoder.decoded;
203 }
204 }
205 }
206
207 String readLine() {
208 // Get line from the buffer if possible.
209 if (_buffer != null) {
210 var result = _readLineFromBuffer();
211 if (result != null) return result;
212 }
213 // Try to fill more data into the buffer and read a line.
214 if (_fillBuffer()) {
215 if (_eof && _buffer == null) return null;
216 return _readLineFromBuffer();
217 }
218 return null;
219 }
220
221 String get encoding() => _encoding;
222
223 bool get closed() => _closed;
224
225 void set dataHandler(void callback()) {
226 _clientDataHandler = callback;
227 }
228
229 void set closeHandler(void callback()) {
230 _clientCloseHandler = callback;
231 }
232
233 void _dataHandler() {
234 _readData();
235 if (!_decoder.isEmpty() && _clientDataHandler != null) {
236 _clientDataHandler();
237 }
238 }
239
240 void _closeHandler() {
241 print("close handler");
Mads Ager (google) 2011/10/26 10:56:07 Remove
Søren Gjesse 2011/10/26 12:03:31 Done.
242 _closed = true;
243 if (_clientDataHandler != null) _clientDataHandler();
244 if (_clientCloseHandler != null) _clientCloseHandler();
245 }
246
247 void _readData() {
248 List<int> data = _input.read();
249 if (data != null) {
250 _decoder.write(data);
251 }
252 }
253
254 String _readLineFromBuffer() {
255 // Both \n or \r indicates a new line. If \r is followed by \n the
256 // \n is part of the line breaking character.
257 for (int i = _bufferLineStart; i < _buffer.length; i++) {
258 String char = _buffer[i];
259 if (char == '\r') {
260 if (i == _buffer.length - 1) {
261 if (_eof) {
262 var result = _buffer.substring(_bufferLineStart, i);
263 _resetBuffer();
264 return result;
265 } else {
266 return null;
267 }
268 }
269 var result = _buffer.substring(_bufferLineStart, i);
270 _bufferLineStart = i + 1;
271 if (_buffer[_bufferLineStart] == '\n') _bufferLineStart++;
272 return result;
273 } else if (char == '\n') {
274 var result = _buffer.substring(_bufferLineStart, i);
275 _bufferLineStart = i + 1;
276 return result;
277 }
278 }
279 if (_eof) {
280 var result = _buffer;
281 _resetBuffer();
282 return result;
283 }
284 return null;
285 }
286
287 void _resetBuffer() {
288 _buffer = null;
289 _bufferLineStart = null;
290 }
291
292 // Fill decoded data into the buffer Returns true if more data was
Mads Ager (google) 2011/10/26 10:56:07 Period after 'buffer'.
Søren Gjesse 2011/10/26 12:03:31 Done.
293 // added or end of file was reached.
294 bool _fillBuffer() {
295 if (_eof) return false;
296 if (_buffer != null && _bufferLineStart == _buffer.length) {
297 _buffer = null;
298 _bufferLineStart = null;
299 }
300 _readData();
301 var decodedString = _decoder.decoded;
302 if (decodedString == null && _closed) {
303 _eof = true;
304 return true;
305 }
306 if (_buffer == null) {
307 _buffer = decodedString;
308 if (_buffer != null) {
309 _bufferLineStart = 0;
310 return true;
311 }
312 } else if (decodedString != null) {
313 _buffer = _buffer.substring(_bufferLineStart) + decodedString;
314 _bufferLineStart = 0;
315 return true;
316 }
317 return false;
318 }
319
320 InputStream _input;
321 String _encoding;
322 _Decoder _decoder;
323 String _buffer; // String can be buffered here if readLine is used.
324 int _bufferLineStart; // Current offset into _buffer if any.
325 bool _closed = false;
326 bool _eof = false; // Has all data been read from the decoder?
327 var _clientDataHandler;
328 var _clientCloseHandler;
329 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698