content: // Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
  // 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.
  
  part of dart.convert;
  
  /**
   * This class splits [String] values into individual lines.
   */
  class LineSplitter extends Converter<String, List<String>> {
  
    const LineSplitter();
  
    List<String> convert(String data) {
      var lines = new List<String>();
  
      _LineSplitterSink._addSlice(data, 0, data.length, true, lines.add);
  
      return lines;
    }
  
    StringConversionSink startChunkedConversion(
      ChunkedConversionSink<String> sink) {
  
      if (sink is! StringConversionSink) {
        sink = new StringConversionSink.from(sink);
      }
      return new _LineSplitterSink(sink);
    }
  }
  
  // TODO(floitsch): deal with utf8.
  class _LineSplitterSink extends StringConversionSinkBase {
    static const int _LF = 10;
    static const int _CR = 13;
  
    final StringConversionSink _sink;
  
    String _carry;
  
    _LineSplitterSink(this._sink);
  
    void addSlice(String chunk, int start, int end, bool isLast) {
      if (_carry != null) {
        chunk = _carry + chunk.substring(start, end);
        start = 0;
        end = chunk.length;
        _carry = null;
      }
      _carry = _addSlice(chunk, start, end, isLast, _sink.add);
      if (isLast) _sink.close();
    }
  
    void close() {
      addSlice('', 0, 0, true);
    }
  
    static String _addSlice(String chunk, int start, int end, bool isLast,
                            void adder(String val)) {
  
      int pos = start;
      while (pos < end) {
        int skip = 0;
        int char = chunk.codeUnitAt(pos);
        if (char == _LF) {
          skip = 1;
        } else if (char == _CR) {
          skip = 1;
          if (pos + 1 < end) {
            if (chunk.codeUnitAt(pos + 1) == _LF) {
              skip = 2;
            }
          } else if (!isLast) {
            return chunk.substring(start, end);
          }
        }
        if (skip > 0) {
          adder(chunk.substring(start, pos));
          start = pos = pos + skip;
        } else {
          pos++;
        }
      }
      if (pos != start) {
        var carry = chunk.substring(start, pos);
        if (isLast) {
          // Add remaining
          adder(carry);
        } else {
          return carry;
        }
      }
      return null;
    }
  }
  