| 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 |