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 abstract class _StringDecoder { | 7 abstract class _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); |
11 | 11 |
12 // Returns whether any decoded data is available. | 12 // Returns whether any decoded data is available. |
13 bool isEmpty(); | 13 bool get isEmpty; |
14 | 14 |
15 // Returns the number of available decoded characters. | 15 // Returns the number of available decoded characters. |
16 int available(); | 16 int available(); |
17 | 17 |
18 // Get the number of line breaks present in the current decoded | 18 // Get the number of line breaks present in the current decoded |
19 // data. | 19 // data. |
20 int get lineBreaks; | 20 int get lineBreaks; |
21 | 21 |
22 // Get up to [len] characters of string data decoded since the last | 22 // Get up to [len] characters of string data decoded since the last |
23 // call to [decode] or [decodeLine]. Returns null if no decoded data | 23 // call to [decode] or [decodeLine]. Returns null if no decoded data |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
71 _bufferList.add(buffer); | 71 _bufferList.add(buffer); |
72 // Decode as many bytes into characters as possible. | 72 // Decode as many bytes into characters as possible. |
73 while (_bufferList.length > 0) { | 73 while (_bufferList.length > 0) { |
74 if (!_processNext()) { | 74 if (!_processNext()) { |
75 break; | 75 break; |
76 } | 76 } |
77 } | 77 } |
78 return buffer.length; | 78 return buffer.length; |
79 } | 79 } |
80 | 80 |
81 bool isEmpty() => _result.isEmpty(); | 81 bool get isEmpty => _result.isEmpty; |
82 | 82 |
83 int get lineBreaks => _lineBreaks; | 83 int get lineBreaks => _lineBreaks; |
84 | 84 |
85 String decoded([int len]) { | 85 String decoded([int len]) { |
86 if (isEmpty()) return null; | 86 if (isEmpty) return null; |
87 | 87 |
88 String result; | 88 String result; |
89 if (len !== null && len < available()) { | 89 if (len !== null && len < available()) { |
90 result = new String.fromCharCodes(_result.getRange(_resultOffset, len)); | 90 result = new String.fromCharCodes(_result.getRange(_resultOffset, len)); |
91 } else { | 91 } else { |
92 if (_resultOffset == 0) { | 92 if (_resultOffset == 0) { |
93 result = new String.fromCharCodes(_result); | 93 result = new String.fromCharCodes(_result); |
94 } else { | 94 } else { |
95 result = | 95 result = |
96 new String.fromCharCodes( | 96 new String.fromCharCodes( |
97 _result.getRange(_resultOffset, | 97 _result.getRange(_resultOffset, |
98 _result.length - _resultOffset)); | 98 _result.length - _resultOffset)); |
99 } | 99 } |
100 } | 100 } |
101 _resultOffset += result.length; | 101 _resultOffset += result.length; |
102 while (!_lineBreakEnds.isEmpty() && | 102 while (!_lineBreakEnds.isEmpty && |
103 _lineBreakEnds.first() < _charOffset + _resultOffset) { | 103 _lineBreakEnds.first() < _charOffset + _resultOffset) { |
104 _lineBreakEnds.removeFirst(); | 104 _lineBreakEnds.removeFirst(); |
105 _lineBreaks--; | 105 _lineBreaks--; |
106 } | 106 } |
107 if (_result.length == _resultOffset) _resetResult(); | 107 if (_result.length == _resultOffset) _resetResult(); |
108 return result; | 108 return result; |
109 } | 109 } |
110 | 110 |
111 String get decodedLine { | 111 String get decodedLine { |
112 if (_lineBreakEnds.isEmpty()) return null; | 112 if (_lineBreakEnds.isEmpty) return null; |
113 int lineEnd = _lineBreakEnds.removeFirst(); | 113 int lineEnd = _lineBreakEnds.removeFirst(); |
114 int terminationSequenceLength = 1; | 114 int terminationSequenceLength = 1; |
115 if (_result[lineEnd - _charOffset] == LF && | 115 if (_result[lineEnd - _charOffset] == LF && |
116 lineEnd > _charOffset && | 116 lineEnd > _charOffset && |
117 _resultOffset < lineEnd && | 117 _resultOffset < lineEnd && |
118 _result[lineEnd - _charOffset - 1] == CR) { | 118 _result[lineEnd - _charOffset - 1] == CR) { |
119 terminationSequenceLength = 2; | 119 terminationSequenceLength = 2; |
120 } | 120 } |
121 var lineLength = | 121 var lineLength = |
122 lineEnd - _charOffset - _resultOffset - terminationSequenceLength + 1; | 122 lineEnd - _charOffset - _resultOffset - terminationSequenceLength + 1; |
(...skipping 257 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
380 } | 380 } |
381 } | 381 } |
382 _checkInstallDataHandler(); | 382 _checkInstallDataHandler(); |
383 return decodedLine; | 383 return decodedLine; |
384 } | 384 } |
385 | 385 |
386 int available() => _decoder.available(); | 386 int available() => _decoder.available(); |
387 | 387 |
388 Encoding get encoding => _encoding; | 388 Encoding get encoding => _encoding; |
389 | 389 |
390 bool get closed => _inputClosed && _decoder.isEmpty(); | 390 bool get closed => _inputClosed && _decoder.isEmpty; |
391 | 391 |
392 void set onData(void callback()) { | 392 void set onData(void callback()) { |
393 _clientDataHandler = callback; | 393 _clientDataHandler = callback; |
394 _clientLineHandler = null; | 394 _clientLineHandler = null; |
395 _checkInstallDataHandler(); | 395 _checkInstallDataHandler(); |
396 _checkScheduleCallback(); | 396 _checkScheduleCallback(); |
397 } | 397 } |
398 | 398 |
399 void set onLine(void callback()) { | 399 void set onLine(void callback()) { |
400 _clientLineHandler = callback; | 400 _clientLineHandler = callback; |
401 _clientDataHandler = null; | 401 _clientDataHandler = null; |
402 _checkInstallDataHandler(); | 402 _checkInstallDataHandler(); |
403 _checkScheduleCallback(); | 403 _checkScheduleCallback(); |
404 } | 404 } |
405 | 405 |
406 void set onClosed(void callback()) { | 406 void set onClosed(void callback()) { |
407 _clientCloseHandler = callback; | 407 _clientCloseHandler = callback; |
408 } | 408 } |
409 | 409 |
410 void set onError(void callback(e)) { | 410 void set onError(void callback(e)) { |
411 _input.onError = callback; | 411 _input.onError = callback; |
412 } | 412 } |
413 | 413 |
414 void _onData() { | 414 void _onData() { |
415 _readData(); | 415 _readData(); |
416 if (!_decoder.isEmpty() && _clientDataHandler !== null) { | 416 if (!_decoder.isEmpty && _clientDataHandler !== null) { |
417 _clientDataHandler(); | 417 _clientDataHandler(); |
418 } | 418 } |
419 if (_decoder.lineBreaks > 0 && _clientLineHandler !== null) { | 419 if (_decoder.lineBreaks > 0 && _clientLineHandler !== null) { |
420 _clientLineHandler(); | 420 _clientLineHandler(); |
421 } | 421 } |
422 _checkScheduleCallback(); | 422 _checkScheduleCallback(); |
423 _checkInstallDataHandler(); | 423 _checkInstallDataHandler(); |
424 } | 424 } |
425 | 425 |
426 void _onClosed() { | 426 void _onClosed() { |
427 _inputClosed = true; | 427 _inputClosed = true; |
428 if (_decoder.isEmpty() && _clientCloseHandler != null) { | 428 if (_decoder.isEmpty && _clientCloseHandler != null) { |
429 _clientCloseHandler(); | 429 _clientCloseHandler(); |
430 _closed = true; | 430 _closed = true; |
431 } else { | 431 } else { |
432 _checkScheduleCallback(); | 432 _checkScheduleCallback(); |
433 } | 433 } |
434 } | 434 } |
435 | 435 |
436 void _readData() { | 436 void _readData() { |
437 List<int> data = _input.read(); | 437 List<int> data = _input.read(); |
438 if (data !== null) { | 438 if (data !== null) { |
439 _decoder.write(data); | 439 _decoder.write(data); |
440 } | 440 } |
441 } | 441 } |
442 | 442 |
443 void _checkInstallDataHandler() { | 443 void _checkInstallDataHandler() { |
444 if (_inputClosed || | 444 if (_inputClosed || |
445 (_clientDataHandler === null && _clientLineHandler === null)) { | 445 (_clientDataHandler === null && _clientLineHandler === null)) { |
446 _input.onData = null; | 446 _input.onData = null; |
447 } else if (_clientDataHandler !== null) { | 447 } else if (_clientDataHandler !== null) { |
448 if (_decoder.isEmpty()) { | 448 if (_decoder.isEmpty) { |
449 _input.onData = _onData; | 449 _input.onData = _onData; |
450 } else { | 450 } else { |
451 _input.onData = null; | 451 _input.onData = null; |
452 } | 452 } |
453 } else { | 453 } else { |
454 assert(_clientLineHandler !== null); | 454 assert(_clientLineHandler !== null); |
455 if (_decoder.lineBreaks == 0) { | 455 if (_decoder.lineBreaks == 0) { |
456 _input.onData = _onData; | 456 _input.onData = _onData; |
457 } else { | 457 } else { |
458 _input.onData = null; | 458 _input.onData = null; |
(...skipping 24 matching lines...) Expand all Loading... |
483 _scheduledCloseCallback = null; | 483 _scheduledCloseCallback = null; |
484 if (!_closed) { | 484 if (!_closed) { |
485 if (_clientCloseHandler !== null) _clientCloseHandler(); | 485 if (_clientCloseHandler !== null) _clientCloseHandler(); |
486 _closed = true; | 486 _closed = true; |
487 } | 487 } |
488 } | 488 } |
489 | 489 |
490 if (!_closed) { | 490 if (!_closed) { |
491 // Schedule data callback if string data available. | 491 // Schedule data callback if string data available. |
492 if (_clientDataHandler != null && | 492 if (_clientDataHandler != null && |
493 !_decoder.isEmpty() && | 493 !_decoder.isEmpty && |
494 _scheduledDataCallback == null) { | 494 _scheduledDataCallback == null) { |
495 if (_scheduledLineCallback != null) { | 495 if (_scheduledLineCallback != null) { |
496 _scheduledLineCallback.cancel(); | 496 _scheduledLineCallback.cancel(); |
497 } | 497 } |
498 _scheduledDataCallback = new Timer(0, issueDataCallback); | 498 _scheduledDataCallback = new Timer(0, issueDataCallback); |
499 } | 499 } |
500 | 500 |
501 // Schedule line callback if a line is available. | 501 // Schedule line callback if a line is available. |
502 if (_clientLineHandler != null && | 502 if (_clientLineHandler != null && |
503 (_decoder.lineBreaks > 0 || (!_decoder.isEmpty() && _inputClosed)) && | 503 (_decoder.lineBreaks > 0 || (!_decoder.isEmpty && _inputClosed)) && |
504 _scheduledLineCallback == null) { | 504 _scheduledLineCallback == null) { |
505 if (_scheduledDataCallback != null) { | 505 if (_scheduledDataCallback != null) { |
506 _scheduledDataCallback.cancel(); | 506 _scheduledDataCallback.cancel(); |
507 } | 507 } |
508 _scheduledLineCallback = new Timer(0, issueLineCallback); | 508 _scheduledLineCallback = new Timer(0, issueLineCallback); |
509 } | 509 } |
510 | 510 |
511 // Schedule close callback if no more data and input is closed. | 511 // Schedule close callback if no more data and input is closed. |
512 if (_decoder.isEmpty() && | 512 if (_decoder.isEmpty && |
513 _inputClosed && | 513 _inputClosed && |
514 _scheduledCloseCallback == null) { | 514 _scheduledCloseCallback == null) { |
515 _scheduledCloseCallback = new Timer(0, issueCloseCallback); | 515 _scheduledCloseCallback = new Timer(0, issueCloseCallback); |
516 } | 516 } |
517 } | 517 } |
518 } | 518 } |
519 | 519 |
520 InputStream _input; | 520 InputStream _input; |
521 Encoding _encoding; | 521 Encoding _encoding; |
522 _StringDecoder _decoder; | 522 _StringDecoder _decoder; |
523 bool _inputClosed = false; // Is the underlying input stream closed? | 523 bool _inputClosed = false; // Is the underlying input stream closed? |
524 bool _closed = false; // Is this stream closed. | 524 bool _closed = false; // Is this stream closed. |
525 bool _eof = false; // Has all data been read from the decoder? | 525 bool _eof = false; // Has all data been read from the decoder? |
526 Timer _scheduledDataCallback; | 526 Timer _scheduledDataCallback; |
527 Timer _scheduledLineCallback; | 527 Timer _scheduledLineCallback; |
528 Timer _scheduledCloseCallback; | 528 Timer _scheduledCloseCallback; |
529 Function _clientDataHandler; | 529 Function _clientDataHandler; |
530 Function _clientLineHandler; | 530 Function _clientLineHandler; |
531 Function _clientCloseHandler; | 531 Function _clientCloseHandler; |
532 } | 532 } |
OLD | NEW |