Chromium Code Reviews| Index: sdk/lib/io/data_transformer.dart |
| diff --git a/sdk/lib/io/data_transformer.dart b/sdk/lib/io/data_transformer.dart |
| index dec5c5df7f5fc3bde60bb76dbf2fb4cd0d1e667c..d0e720812bd72b94692d1ef174f12425f01ef365 100644 |
| --- a/sdk/lib/io/data_transformer.dart |
| +++ b/sdk/lib/io/data_transformer.dart |
| @@ -5,11 +5,40 @@ |
| part of dart.io; |
| +abstract class ZLibConstant { |
| + /// Minimal value for [windowBits] |
|
Lasse Reichstein Nielsen
2014/02/05 10:33:32
There is no [windowBits] declaration in scope, so
vicb
2014/02/06 13:54:06
fixed
|
| + static const int MIN_WINDOW_BITS = 8; |
| + /// Maximal value for [windowBits] |
| + static const int MAX_WINDOW_BITS = 15; |
| + /// Default value for [windowBits] |
| + static const int DEFAULT_WINDOW_BITS = 15; |
| + |
| + /// Minimal value for [level] |
| + static const int MIN_LEVEL = -1; |
| + /// Maximal value for [level] |
| + static const int MAX_LEVEL = 9; |
| + /// Default value for [level] |
| + static const int DEFAULT_LEVEL = 6; |
| + |
| + /// Minimal value for [memLevel] |
| + static const int MIN_MEM_LEVEL = 1; |
| + /// Maximal value for [memLevel] |
| + static const int MAX_MEM_LEVEL = 9; |
| + /// Default value for [memLevel] |
| + static const int DEFAULT_MEM_LEVEL = 8; |
| + |
| + /// Compression strategies |
|
Lasse Reichstein Nielsen
2014/02/05 10:33:32
This dartdoc only attaches to STRATEGY_FILTERED.
E
vicb
2014/02/06 13:54:06
fixed
|
| + static const int STRATEGY_FILTERED = 1; |
| + static const int STRATEGY_HUFFMAN_ONLY = 2; |
| + static const int STRATEGY_RLE = 3; |
| + static const int STRATEGY_FIXED = 4; |
| + static const int STRATEGY_DEFAULT = 0; |
| +} |
| + |
| /** |
| * An instance of the default implementation of the [ZLibCodec]. |
| */ |
| -const ZLibCodec ZLIB = const ZLibCodec(); |
| - |
| +const ZLibCodec ZLIB = const ZLibCodec._default(); |
| /** |
| * The [ZLibCodec] encodes raw bytes to ZLib compressed bytes and decodes ZLib |
| @@ -17,102 +46,293 @@ const ZLibCodec ZLIB = const ZLibCodec(); |
| */ |
| class ZLibCodec extends Codec<List<int>, List<int>> { |
| /** |
| - * The compression level of the [ZLibCodec]. |
| + * When true, `GZip` frames will be added to the compressed data. |
| */ |
| - final int level; |
| + final bool gzip; |
| /** |
| - * Get a [Converter] for encoding to `ZLib` compressed data. |
| + * The compression-[level] can be set in the range of `-1..9`, 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 at the cost of lower compression rates. |
| */ |
| - Converter<List<int>, List<int>> get encoder => |
| - new ZLibEncoder(gzip: false, level: level); |
| + final int level; |
| + |
| + /** |
| + * Specifies how much memory should be allocated for the internal compression |
| + * state. `1` uses minimum memory but is slow and reduces compression ratio; |
| + * `9` uses maximum memory for optimal speed. The default value is `8`. |
| + * |
| + * The memory requirements for deflate are (in bytes): |
| + * (1 << (windowBits + 2)) + (1 << (memLevel + 9)) |
|
Lasse Reichstein Nielsen
2014/02/05 10:33:32
Empty line before and four-space indent to make th
vicb
2014/02/06 13:54:06
fixed
|
| + * that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values) |
| + */ |
| + final int memLevel; |
| /** |
| - * Get a [Converter] for decoding `ZLib` compressed data. |
| + * Tunes the compression algorithm. Use the value STRATEGY_DEFAULT for normal |
| + * data, STRATEGY_FILTERED for data produced by a filter (or predictor), |
| + * STRATEGY_HUFFMAN_ONLY to force Huffman encoding only (no string match), or |
| + * STRATEGY_RLE to limit match distances to one (run-length encoding). |
| + */ |
| + final int strategy; |
| + |
| + /** |
| + * Base two logarithm of the window size (the size of the history buffer). It |
| + * should be in the range 8..15. Larger values result in better compression at |
| + * the expense of memory usage. The default value is 15 |
| + */ |
| + final int windowBits; |
| + |
| + /** |
| + * When true, deflate generates raw data with no zlib header or trailer, and |
| + * will not compute an adler32 check value |
| + */ |
| + final bool raw; |
| + |
| + /** |
| + * Initial compression dictionary. |
| + * |
| + * It should consist of strings (byte sequences) that are likely to be |
| + * encountered later in the data to be compressed, with the most commonly used |
| + * strings preferably put towards the end of the dictionary. Using a dictionary |
| + * is most useful when the data to be compressed is short and can be predicted |
| + * with good accuracy; the data can then be compressed better than with the |
| + * default empty dictionary. |
| + */ |
| + final List<int> dictionary; |
| + |
| + ZLibCodec({this.level: ZLibConstant.DEFAULT_LEVEL, |
| + this.windowBits: ZLibConstant.DEFAULT_WINDOW_BITS, |
| + this.memLevel: ZLibConstant.DEFAULT_MEM_LEVEL, |
| + this.strategy: ZLibConstant.STRATEGY_DEFAULT, |
| + this.dictionary: null, |
| + this.raw: false}) { |
| + _validateZLibeLevel(level); |
| + _validateZLibMemLevel(memLevel); |
| + _validateZLibStrategy(strategy); |
| + _validateZLibWindowBits(windowBits); |
| + } |
| + |
| + const ZLibCodec._default() |
| + : level = ZLibConstant.DEFAULT_LEVEL, |
| + windowBits = ZLibConstant.DEFAULT_WINDOW_BITS, |
| + memLevel = ZLibConstant.DEFAULT_MEM_LEVEL, |
| + strategy = ZLibConstant.STRATEGY_DEFAULT, |
| + raw = false; |
| + |
| + /** |
| + * Get a [ZLibEncoder] for encoding to `ZLib` compressed data. |
| */ |
| - Converter<List<int>, List<int>> get decoder => const ZLibDecoder(); |
| + Converter<List<int>, List<int>> get encoder => |
| + new ZLibEncoder(gzip: false, level: level, windowBits: windowBits, |
| + memLevel: memLevel, strategy: strategy, |
| + dictionary: dictionary, raw: raw); |
| /** |
| - * 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. |
| + * Get a [ZLibDecoder] for decoding `ZLib` compressed data. |
| */ |
| - const ZLibCodec({this.level: 6}); |
| + Converter<List<int>, List<int>> get decoder => |
| + new ZLibDecoder(windowBits: windowBits, dictionary: dictionary, raw: raw); |
| } |
| /** |
| * An instance of the default implementation of the [GZipCodec]. |
| */ |
| -const GZipCodec GZIP = const GZipCodec(); |
| +const GZipCodec GZIP = const GZipCodec._default(); |
| /** |
| - * The [GZipCodec] encodes raw bytes to GZip compressed bytes and decodes GZip |
| + * 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. |
| + * 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]. |
| + * When true, `GZip` frames will be added to the compressed data. |
| + */ |
| + final bool gzip; |
| + |
| + /** |
| + * The compression-[level] can be set in the range of `-1..9`, 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 at the cost of lower compression rates. |
| */ |
| final int level; |
| /** |
| - * Get a [Converter] for encoding to `GZip` compressed data. |
| + * Specifies how much memory should be allocated for the internal compression |
| + * state. `1` uses minimum memory but is slow and reduces compression ratio; |
| + * `9` uses maximum memory for optimal speed. The default value is `8`. |
| + * |
| + * The memory requirements for deflate are (in bytes): |
| + * |
| + * (1 << (windowBits + 2)) + (1 << (memLevel + 9)) |
| + * that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values) |
| + */ |
| + final int memLevel; |
| + |
| + /** |
| + * Tunes the compression algorithm. Use the value |
| + * [ZlibConstant.STRATEGY_DEFAULT] for normal data, |
| + * [ZlibConstant.STRATEGY_FILTERED] for data produced by a filter |
| + * (or predictor), |
| + * [ZlibConstant.STRATEGY_HUFFMAN_ONLY] to force Huffman encoding only (no |
| + * string match), or [ZlibConstant.STRATEGY_RLE] to limit match distances to |
| + * one (run-length encoding). |
| */ |
| - Converter<List<int>, List<int>> get encoder => |
| - new ZLibEncoder(gzip: true, level: level); |
| + final int strategy; |
| + |
| + /** |
| + * Base two logarithm of the window size (the size of the history buffer). It |
| + * should be in the range 8..15. Larger values result in better compression at |
| + * the expense of memory usage. The default value is 15 |
| + */ |
| + final int windowBits; |
| + |
| + /** |
| + * Initial compression dictionary. |
| + * |
| + * It should consist of strings (byte sequences) that are likely to be |
| + * encountered later in the data to be compressed, with the most commonly used |
| + * strings preferably put towards the end of the dictionary. Using a dictionary |
| + * is most useful when the data to be compressed is short and can be predicted |
| + * with good accuracy; the data can then be compressed better than with the |
| + * default empty dictionary. |
| + */ |
| + final List<int> dictionary; |
| + |
| + /** |
| + * When true, deflate generates raw data with no zlib header or trailer, and |
| + * will not compute an adler32 check value |
| + */ |
| + final bool raw; |
| + |
| + GZipCodec({this.level: ZLibConstant.DEFAULT_LEVEL, |
| + this.windowBits: ZLibConstant.DEFAULT_WINDOW_BITS, |
| + this.memLevel: ZLibConstant.DEFAULT_MEM_LEVEL, |
| + this.strategy: ZLibConstant.STRATEGY_DEFAULT, |
| + this.dictionary: null, |
| + this.raw: false}) { |
| + _validateZLibeLevel(level); |
| + _validateZLibMemLevel(memLevel); |
| + _validateZLibStrategy(strategy); |
| + _validateZLibWindowBits(windowBits); |
| + } |
| + |
| + const GZipCodec._default() |
| + : level = ZLibConstant.DEFAULT_LEVEL, |
| + windowBits = ZLibConstant.DEFAULT_WINDOW_BITS, |
| + memLevel = ZLibConstant.DEFAULT_MEM_LEVEL, |
| + strategy = ZLibConstant.STRATEGY_DEFAULT, |
| + raw = false; |
| /** |
| - * Get a [Converter] for decoding `GZip` compressed data. |
| + * Get a [ZLibEncoder] for encoding to `GZip` compressed data. |
| */ |
| - Converter<List<int>, List<int>> get decoder => const ZLibDecoder(); |
| + Converter<List<int>, List<int>> get encoder => |
| + new ZLibEncoder(gzip: true, level: level, windowBits: windowBits, |
| + memLevel: memLevel, strategy: strategy, |
| + dictionary: dictionary, raw: raw); |
| /** |
| - * 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. |
| + * Get a [ZLibDecoder] for decoding `GZip` compressed data. |
| */ |
| - const GZipCodec({this.level: 6}); |
| + Converter<List<int>, List<int>> get decoder => |
| + new ZLibDecoder(windowBits: windowBits, dictionary: dictionary, raw: raw); |
| } |
| - |
| /** |
| - * The [ZLibEncoder] is the encoder used by [ZLibCodec] and [GZipCodec] to |
| - * compress data. |
| + * The ZLibEncoder encoder is used by [ZLibCodec] and [GZipCodec] to compress |
| + * data. |
| */ |
| class ZLibEncoder extends Converter<List<int>, List<int>> { |
| /** |
| - * If [gzip] is true, `GZip` frames will be added to the compressed data. |
| + * When true, `GZip` frames will be added to the compressed data. |
| */ |
| final bool gzip; |
| /** |
| - * The compression level used by the encoder. |
| + * The compression-[level] can be set in the range of `-1..9`, 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 at the cost of lower compression rates. |
| */ |
| 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. |
| + * Specifies how much memory should be allocated for the internal compression |
| + * state. `1` uses minimum memory but is slow and reduces compression ratio; |
| + * `9` uses maximum memory for optimal speed. The default value is `8`. |
| + * |
| + * The memory requirements for deflate are (in bytes): |
| + * |
| + * (1 << (windowBits + 2)) + (1 << (memLevel + 9)) |
| + * that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values) |
| */ |
| - const ZLibEncoder({this.gzip: false, this.level: 6}); |
| + final int memLevel; |
| + |
| + /** |
| + * Tunes the compression algorithm. Use the value |
| + * [ZlibConstant.STRATEGY_DEFAULT] for normal data, |
| + * [ZlibConstant.STRATEGY_FILTERED] for data produced by a filter |
| + * (or predictor), |
| + * [ZlibConstant.STRATEGY_HUFFMAN_ONLY] to force Huffman encoding only (no |
| + * string match), or [ZlibConstant.STRATEGY_RLE] to limit match distances to |
| + * one (run-length encoding). |
| + */ |
| + final int strategy; |
| + |
| + /** |
| + * Base two logarithm of the window size (the size of the history buffer). It |
| + * should be in the range 8..15. Larger values result in better compression at |
| + * the expense of memory usage. The default value is 15 |
| + */ |
| + final int windowBits; |
| + /** |
| + * Initial compression dictionary. |
| + * |
| + * It should consist of strings (byte sequences) that are likely to be |
| + * encountered later in the data to be compressed, with the most commonly used |
| + * strings preferably put towards the end of the dictionary. Using a dictionary |
| + * is most useful when the data to be compressed is short and can be predicted |
| + * with good accuracy; the data can then be compressed better than with the |
| + * default empty dictionary. |
| + */ |
| + final List<int> dictionary; |
| + |
| + |
| + /** |
| + * When true, deflate generates raw data with no zlib header or trailer, and |
| + * will not compute an adler32 check value |
| + */ |
| + final bool raw; |
| + |
| + ZLibEncoder({this.gzip: false, |
| + this.level: ZLibConstant.DEFAULT_LEVEL, |
| + this.windowBits: ZLibConstant.DEFAULT_WINDOW_BITS, |
| + this.memLevel: ZLibConstant.DEFAULT_MEM_LEVEL, |
| + this.strategy: ZLibConstant.STRATEGY_DEFAULT, |
| + this.dictionary: null, |
| + this.raw: false}) { |
| + _validateZLibeLevel(level); |
| + _validateZLibMemLevel(memLevel); |
| + _validateZLibStrategy(strategy); |
| + _validateZLibWindowBits(windowBits); |
| + } |
| /** |
| - * Convert a list of bytes using the options given to the [ZLibEncoder] |
| + * 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(); |
| + startChunkedConversion(sink)..add(bytes)..close(); |
| return sink.builder.takeBytes(); |
| } |
| @@ -127,21 +347,46 @@ class ZLibEncoder extends Converter<List<int>, List<int>> { |
| if (sink is! ByteConversionSink) { |
| sink = new ByteConversionSink.from(sink); |
| } |
| - return new _ZLibEncoderSink(sink, gzip, level); |
| + |
| + return new _ZLibEncoderSink(sink, gzip, level, windowBits, memLevel, |
| + strategy, dictionary, raw); |
| } |
| } |
| /** |
| - * The [ZLibDecoder] is the decoder used by [ZLibCodec] and [GZipCodec] to |
| - * decompress data. |
| + * The ZLibDecoder is used by [ZLibCodec] and [GZipCodec] to decompress data. |
| */ |
| class ZLibDecoder extends Converter<List<int>, List<int>> { |
| + /** |
| + * Base two logarithm of the window size (the size of the history buffer). It |
| + * should be in the range 8..15. Larger values result in better compression at |
| + * the expense of memory usage. The default value is 15 |
| + */ |
| + final int windowBits; |
| /** |
| - * Create a new [ZLibEncoder] converter. |
| - */ |
| - const ZLibDecoder(); |
| + * Initial compression dictionary. |
| + * |
| + * It should consist of strings (byte sequences) that are likely to be |
| + * encountered later in the data to be compressed, with the most commonly used |
| + * strings preferably put towards the end of the dictionary. Using a dictionary |
| + * is most useful when the data to be compressed is short and can be predicted |
| + * with good accuracy; the data can then be compressed better than with the |
| + * default empty dictionary. |
| + */ |
| + final List<int> dictionary; |
| + |
| + /** |
| + * When true, deflate generates raw data with no zlib header or trailer, and |
| + * will not compute an adler32 check value |
| + */ |
| + final bool raw; |
| + |
| + ZLibDecoder({this.windowBits: ZLibConstant.DEFAULT_WINDOW_BITS, |
| + this.dictionary: null, this.raw: false}) { |
| + _validateZLibWindowBits(windowBits); |
| + } |
| /** |
| * Convert a list of bytes using the options given to the [ZLibDecoder] |
| @@ -149,9 +394,7 @@ class ZLibDecoder extends Converter<List<int>, List<int>> { |
| */ |
| List<int> convert(List<int> bytes) { |
| _BufferSink sink = new _BufferSink(); |
| - startChunkedConversion(sink) |
| - ..add(bytes) |
| - ..close(); |
| + startChunkedConversion(sink)..add(bytes)..close(); |
| return sink.builder.takeBytes(); |
| } |
| @@ -165,7 +408,7 @@ class ZLibDecoder extends Converter<List<int>, List<int>> { |
| if (sink is! ByteConversionSink) { |
| sink = new ByteConversionSink.from(sink); |
| } |
| - return new _ZLibDecoderSink(sink); |
| + return new _ZLibDecoderSink(sink, windowBits, dictionary, raw); |
| } |
| } |
| @@ -191,14 +434,18 @@ class _BufferSink extends ByteConversionSink { |
| class _ZLibEncoderSink extends _FilterSink { |
| - _ZLibEncoderSink(ByteConversionSink sink, bool gzip, int level) |
| - : super(sink, _Filter.newZLibDeflateFilter(gzip, level)); |
| + _ZLibEncoderSink(ByteConversionSink sink, bool gzip, int level, |
| + int windowBits, int memLevel, int strategy, |
| + List<int> dictionary, bool raw) |
| + : super(sink, _Filter.newZLibDeflateFilter(gzip, level, windowBits, |
| + memLevel, strategy, |
| + dictionary, raw)); |
| } |
| - |
| class _ZLibDecoderSink extends _FilterSink { |
| - _ZLibDecoderSink(ByteConversionSink sink) |
| - : super(sink, _Filter.newZLibInflateFilter()); |
| + _ZLibDecoderSink(ByteConversionSink sink, int windowBits, |
| + List<int> dictionary, bool raw) |
| + : super(sink, _Filter.newZLibInflateFilter(windowBits, dictionary, raw)); |
| } |
| @@ -208,7 +455,7 @@ class _FilterSink extends ByteConversionSink { |
| bool _closed = false; |
| bool _empty = true; |
| - _FilterSink(ByteConversionSink this._sink, _Filter this._filter); |
| + _FilterSink(this._sink, this._filter); |
| void add(List<int> data) { |
| addSlice(data, 0, data.length, false); |
| @@ -258,7 +505,6 @@ class _FilterSink extends ByteConversionSink { |
| } |
| - |
| /** |
| * Private helper-class to handle native filters. |
| */ |
| @@ -274,8 +520,8 @@ abstract class _Filter { |
| * [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. |
| + * The last call to [processed] should have [end] set to [:true:]. This will |
| + * make sure an 'end' packet is written on the stream. |
| */ |
| List<int> processed({bool flush: true, bool end: false}); |
| @@ -286,6 +532,44 @@ abstract class _Filter { |
| */ |
| void end(); |
| - external static _Filter newZLibDeflateFilter(bool gzip, int level); |
| - external static _Filter newZLibInflateFilter(); |
| + external static _Filter newZLibDeflateFilter(bool gzip, int level, |
| + int windowBits, int memLevel, |
| + int strategy, |
| + List<int> dictionary, bool raw); |
| + |
| + external static _Filter newZLibInflateFilter(int windowBits, |
| + List<int> dictionary, bool raw); |
| +} |
| + |
| +void _validateZLibWindowBits(int windowBits) { |
| + if (ZLibConstant.MIN_WINDOW_BITS > windowBits || |
| + ZLibConstant.MAX_WINDOW_BITS < windowBits) { |
| + throw new RangeError.range(windowsBits, ZLibConstant.MIN_WINDOW_BITS, |
| + ZLibConstant.MAX_WINDOW_BITS); |
| + } |
| +} |
| + |
| +void _validateZLibeLevel(int level) { |
| + if (ZLibConstant.MIN_LEVEL > level || |
| + ZLibConstant.MAX_LEVEL < level) { |
| + throw new RangeError.range(level, ZLibConstant.MIN_LEVEL, |
| + ZLibConstant.MAX_LEVEL); |
| + } |
| +} |
| + |
| +void _validateZLibMemLevel(int memLevel) { |
| + if (ZLibConstant.MIN_MEM_LEVEL > memLevel || |
| + ZLibConstant.MAX_MEM_LEVEL < memLevel) { |
| + throw new RangeError(memLvel, ZLibConstant.MIN_MEM_LEVEL, |
| + ZLibConstant.MAX_MEM_LEVEL); |
| + } |
| +} |
| + |
| +void _validateZLibStrategy(int strategy) { |
| + const strategies = const <int>[ZLibConstant.STRATEGY_FILTERED, |
| + ZLibConstant.STRATEGY_HUFFMAN_ONLY, ZLibConstant.STRATEGY_RLE, |
| + ZLibConstant.STRATEGY_FIXED, ZLibConstant.STRATEGY_DEFAULT]; |
| + if (strategies.indexOf(strategy) == -1) { |
| + throw new ArgumentError("Unsupported 'strategy'"); |
| + } |
| } |