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

Unified Diff: runtime/bin/string_stream.dart

Issue 8772008: Add line handler to string stream (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 9 years, 1 month 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « runtime/bin/input_stream.dart ('k') | tests/standalone/src/StringStreamTest.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: runtime/bin/string_stream.dart
diff --git a/runtime/bin/string_stream.dart b/runtime/bin/string_stream.dart
index 93ec846b6f3e47aaeb9a8b052ffa01a2cfc84fe8..1038900f074186a1b90a72f7041edced8ed5ecba 100644
--- a/runtime/bin/string_stream.dart
+++ b/runtime/bin/string_stream.dart
@@ -2,8 +2,9 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// Interface for decoders decoding binary data into objects of type T.
-interface _Decoder<T> {
+// Interface for decoders decoding binary data into string data. The
+// decoder keeps track of line breaks during decoding.
+interface _StringDecoder {
// Add more binary data to be decoded. The ownership of the buffer
// is transfered to the decoder and the caller most not modify it any more.
int write(List<int> buffer);
@@ -11,8 +12,19 @@ interface _Decoder<T> {
// Returns whether any decoded data is available.
bool isEmpty();
- // Get the data decoded since the last call to decode.
- T get decoded();
+ // Get the number of line breaks present in the current decoded
+ // data.
+ int lineBreaks();
+
+ // Get the string data decoded since the last call to [decode] or
+ // [decodeLine]. Returns null if no decoded data is available.
+ String get decoded();
+
+ // Get the string data decoded since the last call to [decode] or
+ // [decodeLine] up to the next line break present. Returns null if
+ // no line break is present. The line break character sequence is
+ // discarded.
+ String get decodedLine();
}
@@ -25,12 +37,12 @@ class DecoderException implements Exception {
// Utility class for decoding UTF-8 from data delivered as a stream of
// bytes.
-class _StringDecoderBase implements _Decoder<String> {
+class _StringDecoderBase implements _StringDecoder {
_StringDecoderBase()
: _bufferList = new _BufferList(),
- _result = new List<int>();
+ _result = new List<int>(),
+ _lineBreakEnds = new Queue<int>();
- // Add UTF-8 encoded data.
int write(List<int> buffer) {
_bufferList.add(buffer);
// Decode as many bytes into characters as possible.
@@ -42,26 +54,75 @@ class _StringDecoderBase implements _Decoder<String> {
return buffer.length;
}
- // Check if any characters have been decoded since the last call to decode.
bool isEmpty() {
return _result.isEmpty();
}
- // Return the string decoded since the last call to decode.
+ int get lineBreaks() => _lineBreaks;
+
String get decoded() {
- if (isEmpty()) {
- return null;
- } else {
- String result = new String.fromCharCodes(_result);
- _result = new List<int>();
- return result;
+ if (isEmpty()) return null;
+
+ String result = new String.fromCharCodes(_result);
+ _charOffset += result.length;
+ while (!_lineBreakEnds.isEmpty() && _lineBreakEnds.first() < _charOffset) {
+ _lineBreakEnds.removeFirst();
+ _lineBreaks--;
+ }
+ _result = new List<int>();
+ return result;
+ }
+
+ String get decodedLine() {
+ if (_lineBreakEnds.isEmpty()) return null;
+ int lineEnd = _lineBreakEnds.removeFirst();
+ int terminationSequenceLength = 1;
+ if (_result[lineEnd - _charOffset] == LF &&
+ lineEnd > _charOffset &&
+ _result[lineEnd - _charOffset - 1] == CR) {
+ terminationSequenceLength = 2;
+ }
+ var lineLength = lineEnd - _charOffset - terminationSequenceLength + 1;
+ String result = new String.fromCharCodes(_result.getRange(0, lineLength));
+ _lineBreaks--;
+ int removeCount = lineLength + terminationSequenceLength;
+ _result = _result.getRange(removeCount, _result.length - removeCount);
+ _charOffset = lineEnd + 1;
+ return result;
+ }
+
+ // Add another decoded character.
+ void addChar(int charCode) {
+ _result.add(charCode);
+ _charCount++;
+ // Check for line ends (\r, \n and \r\n).
+ if (charCode == LF) {
+ _recordLineBreakEnd(_charCount - 1);
+ } else if (_lastCharCode == CR) {
+ _recordLineBreakEnd(_charCount - 2);
}
+ _lastCharCode = charCode;
+ }
+
+ void _recordLineBreakEnd(int charPos) {
+ _lineBreakEnds.add(charPos);
+ _lineBreaks++;
}
abstract bool _processNext();
_BufferList _bufferList;
List<int> _result;
+ int _lineBreaks = 0; // Number of line breaks in the current list.
+ // The positions of the line breaks are tracked in terms of absolute
+ // character positions from the begining of the decoded data.
+ Queue<int> _lineBreakEnds; // Character position of known line breaks.
+ int _charOffset = 0; // Character number of the first character in the list.
+ int _charCount = 0; // Total number of characters decodes.
+ int _lastCharCode = -1;
+
+ final int LF = 10;
+ final int CR = 13;
}
@@ -75,7 +136,7 @@ class _AsciiDecoder extends _StringDecoderBase {
if (byte > 127) {
throw new DecoderException("Illegal ASCII character $byte");
}
- _result.add(byte);
+ addChar(byte);
}
return true;
}
@@ -89,7 +150,7 @@ class _Latin1Decoder extends _StringDecoderBase {
bool _processNext() {
while (_bufferList.length > 0) {
int byte = _bufferList.next();
- _result.add(byte);
+ addChar(byte);
}
return true;
}
@@ -131,7 +192,7 @@ class _UTF8Decoder extends _StringDecoderBase {
// Remove the value peeked from the buffer list.
_bufferList.next();
}
- _result.add(value);
+ addChar(value);
return true;
}
}
@@ -159,38 +220,40 @@ class _StringInputStream implements StringInputStream {
String read() {
// If there is buffered data return that first.
var decodedString = _decoder.decoded;
- if (_buffer !== null) {
- var result = _buffer;
- _resetBuffer();
- if (decodedString !== null) result += decodedString;
- return result;
- } else {
- if (decodedString !== null) {
- return decodedString;
- } else if (_inputClosed) {
+ if (decodedString !== null) {
+ if (_inputClosed && _decoder.isEmpty()) {
_streamClosed();
- return null;
- } else {
- _readData();
- return _decoder.decoded;
}
+ return decodedString;
+ } else if (_inputClosed) {
+ _streamClosed();
+ return null;
+ } else {
+ _readData();
+ return _decoder.decoded;
}
}
String readLine() {
if (_closed) return null;
- // Get line from the buffer if possible.
- if (_buffer !== null) {
- var result = _readLineFromBuffer();
- if (result !== null) return result;
+
+ if (_decoder.lineBreaks == 0) {
+ _readData();
}
- // Try to fill more data into the buffer and read a line.
- if (_fillBuffer()) {
- if (_eof && _buffer === null) {
+ var decodedLine = _decoder.decodedLine;
+ if (decodedLine !== null) {
+ if (_inputClosed && _decoder.isEmpty()) {
_streamClosed();
- return null;
}
- return _readLineFromBuffer();
+ return decodedLine;
+ }
+ if (_inputClosed) {
+ decodedLine = _decoder.decoded;
+ if (decodedLine[decodedLine.length - 1] == '\r') {
+ decodedLine = decodedLine.substring(0, decodedLine.length - 1);
+ }
+ _streamClosed();
+ return decodedLine;
}
return null;
}
@@ -201,6 +264,12 @@ class _StringInputStream implements StringInputStream {
void set dataHandler(void callback()) {
_clientDataHandler = callback;
+ _clientLineHandler = null;
+ }
+
+ void set lineHandler(void callback()) {
+ _clientLineHandler = callback;
+ _clientDataHandler = null;
}
void set closeHandler(void callback()) {
@@ -212,14 +281,17 @@ class _StringInputStream implements StringInputStream {
if (!_decoder.isEmpty() && _clientDataHandler !== null) {
_clientDataHandler();
}
+ if (_decoder.lineBreaks > 0 && _clientLineHandler !== null) {
+ _clientLineHandler();
+ }
}
void _closeHandler() {
_inputClosed = true;
- if (_buffer !== null || !_decoder.isEmpty()) {
- // If there is still data buffered in either the buffer or the
- // decoder call the data handler.
+ if (!_decoder.isEmpty()) {
+ // If there is still data buffered call the data handler.
if (_clientDataHandler !== null) _clientDataHandler();
+ if (_clientLineHandler !== null) _clientLineHandler();
} else {
_closed = true;
if (_clientCloseHandler !== null) _clientCloseHandler();
@@ -233,72 +305,6 @@ class _StringInputStream implements StringInputStream {
}
}
- String _readLineFromBuffer() {
- // Both \n or \r indicates a new line. If \r is followed by \n the
- // \n is part of the line breaking character.
- for (int i = _bufferLineStart; i < _buffer.length; i++) {
- String char = _buffer[i];
- if (char == '\r') {
- if (i == _buffer.length - 1) {
- if (_eof) {
- var result = _buffer.substring(_bufferLineStart, i);
- _resetBuffer();
- _streamClosed();
- return result;
- } else {
- return null;
- }
- }
- var result = _buffer.substring(_bufferLineStart, i);
- _bufferLineStart = i + 1;
- if (_buffer[_bufferLineStart] == '\n') _bufferLineStart++;
- if (_bufferLineStart == _buffer.length) _resetBuffer();
- return result;
- } else if (char == '\n') {
- var result = _buffer.substring(_bufferLineStart, i);
- _bufferLineStart = i + 1;
- if (_bufferLineStart == _buffer.length) _resetBuffer();
- return result;
- }
- }
- if (_eof) {
- var result = _buffer;
- _resetBuffer();
- _streamClosed();
- return result;
- }
- return null;
- }
-
- void _resetBuffer() {
- _buffer = null;
- _bufferLineStart = null;
- }
-
- // Fill decoded data into the buffer. Returns true if more data was
- // added or end of file was reached.
- bool _fillBuffer() {
- if (_eof) return false;
- if (!_inputClosed) _readData();
- var decodedString = _decoder.decoded;
- if (decodedString === null && _inputClosed) {
- _eof = true;
- return true;
- }
- if (_buffer === null) {
- _buffer = decodedString;
- if (_buffer !== null) {
- _bufferLineStart = 0;
- return true;
- }
- } else if (decodedString !== null) {
- _buffer = _buffer.substring(_bufferLineStart) + decodedString;
- _bufferLineStart = 0;
- return true;
- }
- return false;
- }
-
void _streamClosed() {
_closed = true;
@@ -312,12 +318,11 @@ class _StringInputStream implements StringInputStream {
InputStream _input;
String _encoding;
- _Decoder _decoder;
- String _buffer; // String can be buffered here if readLine is used.
- int _bufferLineStart; // Current offset into _buffer if any.
+ _StringDecoder _decoder;
bool _inputClosed = false; // Is the underlying input stream closed?
bool _closed = false; // Is this stream closed.
bool _eof = false; // Has all data been read from the decoder?
var _clientDataHandler;
+ var _clientLineHandler;
var _clientCloseHandler;
}
« no previous file with comments | « runtime/bin/input_stream.dart ('k') | tests/standalone/src/StringStreamTest.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698