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

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

Issue 9653026: Add writeString method to OutputStream (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Rebased Created 8 years, 9 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
« no previous file with comments | « runtime/bin/stream_util.dart ('k') | samples/chat/chat_server_lib.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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 }
OLDNEW
« no previous file with comments | « runtime/bin/stream_util.dart ('k') | samples/chat/chat_server_lib.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698