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

Unified Diff: sdk/lib/io/string_transformer.dart

Issue 12328037: Add missing files from previous commit (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 10 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « sdk/lib/io/io_stream_consumer.dart ('k') | sdk/lib/utf/utf_stream.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/io/string_transformer.dart
diff --git a/sdk/lib/io/string_transformer.dart b/sdk/lib/io/string_transformer.dart
new file mode 100644
index 0000000000000000000000000000000000000000..ea433a01f0ffec0dfa23d1e5230bb3f21156caa3
--- /dev/null
+++ b/sdk/lib/io/string_transformer.dart
@@ -0,0 +1,397 @@
+// 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.io;
+
+/**
+ * Stream transformer that can decode a stream of bytes into a stream of
+ * strings using [encoding].
+ *
+ * Invalid or forbidden byte-sequences will not produce errors, but will instead
+ * insert [replacementChar] in the decoded strings.
+ */
+class StringDecoder implements StreamTransformer<List<int>, String> {
+ var _decoder;
+
+ /**
+ * Create a new [StringDecoder] with an optional [encoding] and
+ * [replacementChar].
+ */
+ StringDecoder([Encoding encoding = Encoding.UTF_8, int replacementChar]) {
+ switch (encoding) {
+ case Encoding.UTF_8:
+ if (replacementChar == null) {
+ replacementChar = UNICODE_REPLACEMENT_CHARACTER_CODEPOINT;
+ }
+ _decoder = new Utf8DecoderTransformer(replacementChar);
+ break;
+ case Encoding.ASCII:
+ if (replacementChar == null) {
+ replacementChar = '?'.charCodeAt(0);
+ } else if (replacementChar > 127) {
+ throw new ArgumentError("Invalid replacement character for ASCII");
+ }
+ _decoder = new _AsciiDecoder(replacementChar);
+ break;
+ case Encoding.ISO_8859_1:
+ if (replacementChar == null) {
+ replacementChar = '?'.charCodeAt(0);
+ } else if (replacementChar > 255) {
+ throw new ArgumentError(
+ "Invalid replacement character for ISO_8859_1");
+ }
+ _decoder = new _Latin1Decoder(replacementChar);
+ break;
+ case Encoding.SYSTEM:
+ if (Platform.operatingSystem == "windows") {
+ _decoder = new _WindowsCodePageDecoder();
+ } else {
+ if (replacementChar != null) {
+ // TODO(ajohnsen): Handle replacement character.
+ throw new UnsupportedError(
+ "Replacement character is not supported for SYSTEM encoding");
+ }
+ _decoder = new Utf8DecoderTransformer();
+ }
+ break;
+ default:
+ throw new ArgumentError("Unsupported encoding '$encoding'");
+ }
+ }
+
+ Stream<String> bind(Stream<List<int>> stream) => _decoder.bind(stream);
+}
+
+
+/**
+ * Stream transformer that can encode a stream of strings info a stream of
+ * bytes using [encoding].
+ *
+ * Strings that cannot be represented in the given encoding will result in an
+ * error and a close event on the stream.
+ */
+class StringEncoder implements StreamTransformer<String, List<int>> {
+ var _encoder;
+
+ /**
+ * Create a new [StringDecoder] with an optional [encoding] and
+ * [replacementChar].
+ */
+ StringEncoder([Encoding encoding = Encoding.UTF_8]) {
+ switch (encoding) {
+ case Encoding.UTF_8:
+ _encoder = new Utf8EncoderTransformer();
+ break;
+ case Encoding.ASCII:
+ _encoder = new _AsciiEncoder();
+ break;
+ case Encoding.ISO_8859_1:
+ _encoder = new _Latin1Encoder();
+ break;
+ case Encoding.SYSTEM:
+ if (Platform.operatingSystem == "windows") {
+ _encoder = new _WindowsCodePageEncoder();
+ } else {
+ _encoder = new Utf8EncoderTransformer();
+ }
+ break;
+ default:
+ throw new ArgumentError("Unsupported encoding '$encoding'");
+ }
+ }
+
+ Stream<List<int>> bind(Stream<String> stream) => _encoder.bind(stream);
+}
+
+
+// Utility function to synchronously decode a list of bytes.
+String _decodeString(List<int> bytes, [Encoding encoding = Encoding.UTF_8]) {
+ if (bytes.length == 0) return "";
+ var string;
+ var controller = new StreamController();
+ controller.stream
+ .transform(new StringDecoder(encoding))
+ .listen((data) => string = data);
+ controller.add(bytes);
+ controller.close();
+ assert(string != null);
+ return string;
+}
+
+
+// Utility function to synchronously encode a String.
+// Will throw an exception if the encoding is invalid.
+List<int> _encodeString(String string, [Encoding encoding = Encoding.UTF_8]) {
+ if (string.length == 0) return [];
+ var bytes;
+ var controller = new StreamController();
+ controller.stream
+ .transform(new StringEncoder(encoding))
+ .listen((data) => bytes = data);
+ controller.add(string);
+ controller.close();
+ assert(bytes != null);
+ return bytes;
+}
+
+
+class LineTransformer implements StreamTransformer<String, String> {
+ const int _LF = 10;
+ const int _CR = 13;
+
+ final StringBuffer _buffer = new StringBuffer();
+
+ StreamSubscription<String> _subscription;
+ StreamController<String> _controller;
+ String _carry;
+
+ Stream<String> bind(Stream<String> stream) {
+ _controller = new StreamController<String>(
+ onPauseStateChange: _pauseChanged,
+ onSubscriptionStateChange: _subscriptionChanged);
+
+ void handle(String data, bool isClosing) {
+ if (_carry != null) {
+ data = _carry.concat(data);
+ _carry = null;
+ }
+ int startPos = 0;
+ int pos = 0;
+ while (pos < data.length) {
+ int skip = 0;
+ int char = data.charCodeAt(pos);
+ if (char == _LF) {
+ skip = 1;
+ } else if (char == _CR) {
+ skip = 1;
+ if (pos + 1 < data.length) {
+ if (data.charCodeAt(pos + 1) == _LF) {
+ skip = 2;
+ }
+ } else if (!isClosing) {
+ _carry = data.substring(startPos);
+ return;
+ }
+ }
+ if (skip > 0) {
+ _buffer.add(data.substring(startPos, pos));
+ _controller.add(_buffer.toString());
+ _buffer.clear();
+ startPos = pos = pos + skip;
+ } else {
+ pos++;
+ }
+ }
+ if (pos != startPos) {
+ // Add remaining
+ _buffer.add(data.substring(startPos, pos));
+ }
+ if (isClosing && !_buffer.isEmpty) {
+ _controller.add(_buffer.toString());
+ _buffer.clear();
+ }
+ }
+
+ _subscription = stream.listen(
+ (data) => handle(data, false),
+ onDone: () {
+ // Handle remaining data (mainly _carry).
+ handle("", true);
+ _controller.close();
+ },
+ onError: _controller.signalError);
+ return _controller.stream;
+ }
+
+ void _pauseChanged() {
+ if (_controller.isPaused) {
+ _subscription.pause();
+ } else {
+ _subscription.resume();
+ }
+ }
+
+ void _subscriptionChanged() {
+ if (!_controller.hasSubscribers) {
+ _subscription.cancel();
+ }
+ }
+}
+
+
+class _SingleByteDecoder implements StreamTransformer<List<int>, String> {
+ StreamSubscription<List<int>> _subscription;
+ StreamController<String> _controller;
+ final int _replacementChar;
+
+ _SingleByteDecoder(this._replacementChar);
+
+ Stream<String> bind(Stream<List<int>> stream) {
+ _controller = new StreamController<String>(
+ onPauseStateChange: _pauseChanged,
+ onSubscriptionStateChange: _subscriptionChanged);
+ _subscription = stream.listen(
+ (data) {
+ var buffer = new List<int>.fixedLength(data.length);
+ for (int i = 0; i < data.length; i++) {
+ int char = _decodeByte(data[i]);
+ if (char < 0) char = _replacementChar;
+ buffer[i] = char;
+ }
+ _controller.add(new String.fromCharCodes(buffer));
+ },
+ onDone: _controller.close,
+ onError: _controller.signalError);
+ return _controller.stream;
+ }
+
+ int _decodeByte(int byte);
+
+ void _pauseChanged() {
+ if (_controller.isPaused) {
+ _subscription.pause();
+ } else {
+ _subscription.resume();
+ }
+ }
+
+ void _subscriptionChanged() {
+ if (!_controller.hasSubscribers) {
+ _subscription.cancel();
+ }
+ }
+}
+
+
+// Utility class for decoding ascii data delivered as a stream of
+// bytes.
+class _AsciiDecoder extends _SingleByteDecoder {
+ _AsciiDecoder(int replacementChar) : super(replacementChar);
+
+ int _decodeByte(int byte) => ((byte & 0x7f) == byte) ? byte : -1;
+}
+
+
+// Utility class for decoding Latin-1 data delivered as a stream of
+// bytes.
+class _Latin1Decoder extends _SingleByteDecoder {
+ _Latin1Decoder(int replacementChar) : super(replacementChar);
+
+ int _decodeByte(int byte) => ((byte & 0xFF) == byte) ? byte : -1;
+}
+
+
+class _SingleByteEncoder implements StreamTransformer<String, List<int>> {
+ StreamSubscription<String> _subscription;
+ StreamController<List<int>> _controller;
+
+ Stream<List<int>> bind(Stream<String> stream) {
+ _controller = new StreamController<List<int>>(
+ onPauseStateChange: _pauseChanged,
+ onSubscriptionStateChange: _subscriptionChanged);
+ _subscription = stream.listen(
+ (string) {
+ var bytes = _encode(string);
+ if (bytes == null) {
+ _controller.signalError(new FormatException(
+ "Invalid character for encoding"));
+ _controller.close();
+ _subscription.cancel();
+ } else {
+ _controller.add(bytes);
+ }
+ },
+ onDone: _controller.close,
+ onError: _controller.signalError);
+ return _controller.stream;
+ }
+
+ List<int> _encode(String string);
+
+ void _pauseChanged() {
+ if (_controller.isPaused) {
+ _subscription.pause();
+ } else {
+ _subscription.resume();
+ }
+ }
+
+ void _subscriptionChanged() {
+ if (!_controller.hasSubscribers) {
+ _subscription.cancel();
+ }
+ }
+}
+
+
+// Utility class for encoding a string into an ASCII byte stream.
+class _AsciiEncoder extends _SingleByteEncoder {
+ List<int> _encode(String string) {
+ var bytes = string.charCodes;
+ for (var byte in bytes) {
+ if (byte > 127) return null;
+ }
+ return bytes;
+ }
+}
+
+
+// Utility class for encoding a string into a Latin1 byte stream.
+class _Latin1Encoder extends _SingleByteEncoder {
+ List<int> _encode(String string) {
+ var bytes = string.charCodes;
+ for (var byte in bytes) {
+ if (byte > 255) return null;
+ }
+ return bytes;
+ }
+}
+
+
+// Utility class for encoding a string into a current windows
+// code page byte list.
+// Implemented on top of a _SingleByteEncoder, even though it's not really a
+// single byte encoder, to avoid copying boilerplate.
+class _WindowsCodePageEncoder extends _SingleByteEncoder {
+ List<int> _encode(String string) => _encodeString(string);
+
+ external static List<int> _encodeString(String string);
+}
+
+
+// Utility class for decoding Windows current code page data delivered
+// as a stream of bytes.
+class _WindowsCodePageDecoder implements StreamTransformer<List<int>, String> {
+ StreamSubscription<List<int>> _subscription;
+ StreamController<String> _controller;
+
+ Stream<String> bind(Stream<List<int>> stream) {
+ _controller = new StreamController<String>(
+ onPauseStateChange: _pauseChanged,
+ onSubscriptionStateChange: _subscriptionChanged);
+ _subscription = stream.listen(
+ (data) {
+ _controller.add(_decodeBytes(data));
+ },
+ onDone: _controller.close,
+ onError: _controller.signalError);
+ return _controller.stream;
+ }
+
+ external static String _decodeBytes(List<int> bytes);
+
+ void _pauseChanged() {
+ if (_controller.isPaused) {
+ _subscription.pause();
+ } else {
+ _subscription.resume();
+ }
+ }
+
+ void _subscriptionChanged() {
+ if (!_controller.hasSubscribers) {
+ _subscription.cancel();
+ }
+ }
+}
« no previous file with comments | « sdk/lib/io/io_stream_consumer.dart ('k') | sdk/lib/utf/utf_stream.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698