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

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

Issue 22867033: Update ZLib/GZip in dart:io to be a Codec/Converter from dart:convert. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add documentation and convert impl. Created 7 years, 4 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 | « runtime/bin/io_natives.cc ('k') | sdk/lib/io/http_impl.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/io/data_transformer.dart
diff --git a/sdk/lib/io/data_transformer.dart b/sdk/lib/io/data_transformer.dart
index c7c53adc7938ef6a2558bd734441bd05f5679fa8..2cfa3e9e7ed78edd774a44f8a2a6b292925177c0 100644
--- a/sdk/lib/io/data_transformer.dart
+++ b/sdk/lib/io/data_transformer.dart
@@ -4,95 +4,287 @@
part of dart.io;
+
/**
- * Private helper-class to handle native filters.
+ * An instance of the default implementation of the [ZLibCodec].
*/
-abstract class _Filter {
+const ZLIB = const ZLibCodec();
+
+
+/**
+ * The [ZLibCodec] encodes raw bytes to ZLib compressed bytes and decodes ZLib
+ * compressed bytes to raw bytes.
+ */
+class ZLibCodec extends Codec<List<int>, List<int>> {
/**
- * Call to process a chunk of data. A call to [process] should only be made
- * when [processed] returns [null].
+ * The compression level of the [ZLibCodec].
*/
- void process(List<int> data);
+ final int level;
/**
- * Get a chunk of processed data. When there are no more data available,
- * [processed] will return [null]. Set [flush] to [false] for non-final
- * calls to improve performance of some filters.
- *
- * The last call to [processed] should have [end] set to [true]. This will make
- * sure a 'end' packet is written on the stream.
+ * Get a [Converter] for encoding to `ZLib` compressed data.
*/
- List<int> processed({bool flush: true, bool end: false});
+ Converter<List<int>, List<int>> get encoder =>
+ const ZLibEncoder(gzip: false, level: level);
/**
- * Mark the filter as closed. Always call this method for any filter created
- * to avoid leaking resources. [end] can be called at any time, but any
- * successive calls to [process] or [processed] will fail.
+ * Get a [Converter] for decoding `ZLib` compressed data.
*/
- void end();
+ Converter<List<int>, List<int>> get decoder => const ZLibDecoder();
- external static _Filter newZLibDeflateFilter(bool gzip, int level);
- external static _Filter newZLibInflateFilter();
+ /**
+ * The compression-[level] can be set in the range of `1..10`, with `6` being
+ * the default compression level. Levels above 6 will have higher compression
+ * rates at the cost of more CPU and memory usage. Levels below 6 will use
+ * less CPU and memory, but at the cost of lower compression rates.
+ */
+ const ZLibCodec({this.level: 6});
+}
+
+
+/**
+ * An instance of the default implementation of the [GZipCodec].
+ */
+const GZIP = const GZipCodec();
+
+
+/**
+ * The [GZipCodec] encodes raw bytes to GZip compressed bytes and decodes GZip
+ * compressed bytes to raw bytes.
+ *
+ * The difference between [ZLibCodec] and [GZipCodec] is that the [GZipCodec]
+ * wraps the `ZLib` compressed bytes in `GZip` frames.
+ */
+class GZipCodec extends Codec<List<int>, List<int>> {
+ /**
+ * The compression level of the [ZLibCodec].
+ */
+ final int level;
+
+ /**
+ * Get a [Converter] for encoding to `GZip` compressed data.
+ */
+ final Converter<List<int>, List<int>> encoder =
+ const ZLibEncoder(gzip: true, level: level);
+
+ /**
+ * Get a [Converter] for decoding `GZip` compressed data.
+ */
+ final Converter<List<int>, List<int>> decoder = const ZLibDecoder();
+
+ /**
+ * The compression-[level] can be set in the range of `1..10`, with `6` being
+ * the default compression level. Levels above 6 will have higher compression
+ * rates at the cost of more CPU and memory usage. Levels below 6 will use
+ * less CPU and memory, but at the cost of lower compression rates.
+ */
+ const GZipCodec({this.level: 6});
+}
+
+
+/**
+ * The [ZLibEncoder] is the encoder used by [ZLibCodec] and [GZipCodec] to
+ * compress data.
+ */
+class ZLibEncoder extends Converter<List<int>, List<int>> {
Søren Gjesse 2013/08/22 16:07:26 We could consider making this and ZLibDecoder priv
Anders Johnsen 2013/08/23 07:11:53 Exposing both codecs and converters is in sync wit
+ /**
+ * If [gzip] is true, `GZip` frames will be added to the compressed data.
+ */
+ final bool gzip;
+
+ /**
+ * The compression level used by the encoder.
+ */
+ final int level;
+
+ /**
+ * Create a new [ZLibEncoder] converter. If the [gzip] flag is set, the
+ * encoder will wrap the encoded ZLib data in GZip frames.
+ */
+ const ZLibEncoder({this.gzip: false, this.level: 6});
+
+
+ /**
+ * Convert a list of bytes using the options given to the [ZLibEncoder]
+ * constructor.
+ */
+ List<int> convert(List<int> bytes) {
+ _BufferSink sink = new _BufferSink();
+ startChunkedConversion(sink)
+ ..add(bytes)
+ ..close();
+ return sink.builder.takeBytes();
+ }
+
+ /**
+ * Start a chunked conversion using the options given to the [ZLibEncoder]
+ * constructor. While it accepts any [ChunkedConversionSink] taking
+ * [List<int>]'s, the optimal sink to be passed as [sink] is a
+ * [ByteConversionSink].
+ */
+ ByteConversionSink startChunkedConversion(
+ ChunkedConversionSink<List<int>> sink) {
+ if (sink is! ByteConversionSink) {
+ sink = new ByteConversionSink.from(sink);
+ }
+ return new _ZLibEncoderSink(sink, gzip, level);
+ }
}
-class _FilterTransformer extends StreamEventTransformer<List<int>, List<int>> {
+/**
+ * The [ZLibDecoder] is the decoder used by [ZLibCodec] and [GZipCodec] to
+ * decompress data.
+ */
+class ZLibDecoder extends Converter<List<int>, List<int>> {
+
+ /**
+ * Create a new [ZLibEncoder] converter.
+ */
+ const ZLibDecoder();
+
+ /**
+ * Convert a list of bytes using the options given to the [ZLibDecoder]
+ * constructor.
+ */
+ List<int> convert(List<int> bytes) {
+ _BufferSink sink = new _BufferSink();
+ startChunkedConversion(sink)
+ ..add(bytes)
+ ..close();
+ return sink.builder.takeBytes();
+ }
+
+ /**
+ * Start a chunked conversion. While it accepts any [ChunkedConversionSink]
+ * taking [List<int>]'s, the optimal sink to be passed as [sink] is a
+ * [ByteConversionSink].
+ */
+ ByteConversionSink startChunkedConversion(
+ ChunkedConversionSink<List<int>> sink) {
+ if (sink is! ByteConversionSink) {
+ sink = new ByteConversionSink.from(sink);
+ }
+ return new _ZLibDecoderSink(sink);
+ }
+}
+
+
+class _BufferSink extends ByteConversionSink {
+ final BytesBuilder builder = new BytesBuilder();
+
+ void add(List<int> chunk) {
+ builder.add(chunk);
+ }
+
+ void addSlice(List<int> chunk, int start, int end, bool isLast) {
+ if (chunk is Uint8List) {
+ builder.add(Uint8List.view(chunk, start, end - start));
+ } else {
+ buidler.add(chunk.sublist(start, end));
+ }
+ }
+
+ void close() {}
+}
+
+
+class _ZLibEncoderSink extends _FilterSink {
+ _ZLibEncoderSink(ByteConversionSink sink, bool gzip, int level)
+ : super(sink, _Filter.newZLibDeflateFilter(gzip, level));
+}
+
+
+class _ZLibDecoderSink extends _FilterSink {
+ _ZLibDecoderSink(ByteConversionSink sink)
+ : super(sink, _Filter.newZLibInflateFilter());
+}
+
+
+class _FilterSink extends ByteConversionSink {
final _Filter _filter;
+ final ByteConversionSink _sink;
bool _closed = false;
bool _empty = true;
- _FilterTransformer(_Filter this._filter);
+ _FilterSink(ByteConversionSink this._sink, _Filter this._filter);
+
+ void add(List<int> data) {
+ addSlice(data, 0, data.length, false);
+ }
- void handleData(List<int> data, EventSink<List<int>> sink) {
+ void addSlice(List<int> data, int start, int end, bool isLast) {
if (_closed) return;
+ if (start < 0 || start > data.length) {
+ throw ArgumentError("Invalid start position");
+ }
+ if (end < 0 || end > data.length || end < start) {
+ throw ArgumentError("Invalid end position");
+ }
try {
_empty = false;
- _filter.process(data);
+ _filter.process(data, start, end);
var out;
while ((out = _filter.processed(flush: false)) != null) {
- sink.add(out);
+ _sink.add(out);
}
- } catch (e, s) {
+ } catch (e) {
_closed = true;
- // TODO(floitsch): we are losing the stack trace.
- sink.addError(e);
- sink.close();
+ throw e;
}
+
+ if (isLast) close();
}
- void handleDone(EventSink<List<int>> sink) {
+ void close() {
if (_closed) return;
- if (_empty) _filter.process(const []);
+ // Be sure to send process an empty chunk of data. Without this, the empty
+ // message would not have a GZip frame (if compressed with GZip).
+ if (_empty) _filter.process(const [], 0, 0);
try {
var out;
while ((out = _filter.processed(end: true)) != null) {
- sink.add(out);
+ _sink.add(out);
}
- } catch (e, s) {
- // TODO(floitsch): we are losing the stack trace.
- sink.addError(e);
+ } catch (e) {
_closed = true;
+ throw e;
}
if (!_closed) _filter.end();
_closed = true;
- sink.close();
+ _sink.close();
}
}
+
/**
- * ZLibDeflater class used to deflate a stream of bytes, using zlib.
+ * Private helper-class to handle native filters.
*/
-class ZLibDeflater extends _FilterTransformer {
- ZLibDeflater({bool gzip: true, int level: 6})
- : super(_Filter.newZLibDeflateFilter(gzip, level));
-}
+abstract class _Filter {
+ /**
+ * Call to process a chunk of data. A call to [process] should only be made
+ * when [processed] returns [null].
+ */
+ void process(List<int> data, int start, int end);
+ /**
+ * Get a chunk of processed data. When there are no more data available,
+ * [processed] will return [null]. Set [flush] to [false] for non-final
+ * calls to improve performance of some filters.
+ *
+ * The last call to [processed] should have [end] set to [true]. This will make
+ * sure a 'end' packet is written on the stream.
+ */
+ List<int> processed({bool flush: true, bool end: false});
-/**
- * ZLibInflater class used to inflate a stream of bytes, using zlib.
- */
-class ZLibInflater extends _FilterTransformer {
- ZLibInflater() : super(_Filter.newZLibInflateFilter());
-}
+ /**
+ * Mark the filter as closed. Always call this method for any filter created
+ * to avoid leaking resources. [end] can be called at any time, but any
+ * successive calls to [process] or [processed] will fail.
+ */
+ void end();
+ external static _Filter newZLibDeflateFilter(bool gzip, int level);
+ external static _Filter newZLibInflateFilter();
+}
« no previous file with comments | « runtime/bin/io_natives.cc ('k') | sdk/lib/io/http_impl.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698