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..6413b53dc445549a8c309612635c8da0e50d64e2 100644 |
--- a/sdk/lib/io/data_transformer.dart |
+++ b/sdk/lib/io/data_transformer.dart |
@@ -4,12 +4,60 @@ |
part of dart.io; |
+/** |
+ * Exposes ZLib options for input parameters. |
+ * |
+ * See http://www.zlib.net/manual.html for more documentation. |
+ */ |
+abstract class ZLibOption { |
+ /// Minimal value for [ZLibCodec.windowBits], [ZLibEncoder.windowBits] |
+ /// and [ZLibDecoder.windowBits]. |
+ static const int MIN_WINDOW_BITS = 8; |
+ /// Maximal value for [ZLibCodec.windowBits], [ZLibEncoder.windowBits] |
+ /// and [ZLibDecoder.windowBits]. |
+ static const int MAX_WINDOW_BITS = 15; |
+ /// Default value for [ZLibCodec.windowBits], [ZLibEncoder.windowBits] |
+ /// and [ZLibDecoder.windowBits]. |
+ static const int DEFAULT_WINDOW_BITS = 15; |
+ |
+ /// Minimal value for [ZLibCodec.level], [ZLibEncoder.level] |
+ /// and [ZLibDecoder.level]. |
+ static const int MIN_LEVEL = -1; |
+ /// Maximal value for [ZLibCodec.level], [ZLibEncoder.level] |
+ /// and [ZLibDecoder.level]. |
+ static const int MAX_LEVEL = 9; |
+ /// Default value for [ZLibCodec.level], [ZLibEncoder.level] |
+ /// and [ZLibDecoder.level]. |
+ static const int DEFAULT_LEVEL = 6; |
+ |
+ /// Minimal value for [ZLibCodec.memLevel], [ZLibEncoder.memLevel] |
+ /// and [ZLibDecoder.memLevel]. |
+ static const int MIN_MEM_LEVEL = 1; |
+ /// Maximal value for [ZLibCodec.memLevel], [ZLibEncoder.memLevel] |
+ /// and [ZLibDecoder.memLevel]. |
+ static const int MAX_MEM_LEVEL = 9; |
+ /// Default value for [ZLibCodec.memLevel], [ZLibEncoder.memLevel] |
+ /// and [ZLibDecoder.memLevel]. |
+ static const int DEFAULT_MEM_LEVEL = 8; |
+ |
+ |
+ /// Recommended strategy for data produced by a filter (or predictor) |
+ static const int STRATEGY_FILTERED = 1; |
+ /// Use this strategy to force Huffman encoding only (no string match) |
+ static const int STRATEGY_HUFFMAN_ONLY = 2; |
+ /// Use this strategy to limit match distances to one (run-length encoding) |
+ static const int STRATEGY_RLE = 3; |
+ /// This strategy prevents the use of dynamic Huffman codes, allowing for a |
+ /// simpler decoder |
+ static const int STRATEGY_FIXED = 4; |
+ /// Recommended strategy for normal data |
+ 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,35 +65,102 @@ 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 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 `ZLib` 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) |
*/ |
- Converter<List<int>, List<int>> get encoder => |
- new ZLibEncoder(gzip: false, level: level); |
+ final int memLevel; |
+ |
+ /** |
+ * 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: ZLibOption.DEFAULT_LEVEL, |
+ this.windowBits: ZLibOption.DEFAULT_WINDOW_BITS, |
+ this.memLevel: ZLibOption.DEFAULT_MEM_LEVEL, |
+ this.strategy: ZLibOption.STRATEGY_DEFAULT, |
+ this.dictionary: null, |
+ this.raw: false}) { |
+ _validateZLibeLevel(level); |
+ _validateZLibMemLevel(memLevel); |
+ _validateZLibStrategy(strategy); |
+ _validateZLibWindowBits(windowBits); |
+ } |
+ |
+ const ZLibCodec._default() |
+ : level = ZLibOption.DEFAULT_LEVEL, |
+ windowBits = ZLibOption.DEFAULT_WINDOW_BITS, |
+ memLevel = ZLibOption.DEFAULT_MEM_LEVEL, |
+ strategy = ZLibOption.STRATEGY_DEFAULT, |
+ raw = false; |
/** |
- * Get a [Converter] for decoding `ZLib` compressed data. |
+ * 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(); |
/** |
@@ -57,62 +172,187 @@ const GZipCodec GZIP = const GZipCodec(); |
*/ |
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) |
*/ |
- Converter<List<int>, List<int>> get encoder => |
- new ZLibEncoder(gzip: true, level: level); |
+ final int memLevel; |
/** |
- * Get a [Converter] for decoding `GZip` compressed data. |
+ * 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 decoder => const ZLibDecoder(); |
+ final int strategy; |
/** |
- * 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. |
+ * 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 |
*/ |
- const GZipCodec({this.level: 6}); |
-} |
+ 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: ZLibOption.DEFAULT_LEVEL, |
+ this.windowBits: ZLibOption.DEFAULT_WINDOW_BITS, |
+ this.memLevel: ZLibOption.DEFAULT_MEM_LEVEL, |
+ this.strategy: ZLibOption.STRATEGY_DEFAULT, |
+ this.dictionary: null, |
+ this.raw: false}) { |
+ _validateZLibeLevel(level); |
+ _validateZLibMemLevel(memLevel); |
+ _validateZLibStrategy(strategy); |
+ _validateZLibWindowBits(windowBits); |
+ } |
+ |
+ const GZipCodec._default() |
+ : level = ZLibOption.DEFAULT_LEVEL, |
+ windowBits = ZLibOption.DEFAULT_WINDOW_BITS, |
+ memLevel = ZLibOption.DEFAULT_MEM_LEVEL, |
+ strategy = ZLibOption.STRATEGY_DEFAULT, |
+ raw = false; |
+ |
+ /** |
+ * Get a [ZLibEncoder] for encoding to `GZip` compressed data. |
+ */ |
+ Converter<List<int>, List<int>> get encoder => |
+ new ZLibEncoder(gzip: true, level: level, windowBits: windowBits, |
+ memLevel: memLevel, strategy: strategy, |
+ dictionary: dictionary, raw: raw); |
+ /** |
+ * Get a [ZLibDecoder] for decoding `GZip` compressed data. |
+ */ |
+ 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; |
/** |
- * Convert a list of bytes using the options given to the [ZLibEncoder] |
+ * 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: ZLibOption.DEFAULT_LEVEL, |
+ this.windowBits: ZLibOption.DEFAULT_WINDOW_BITS, |
+ this.memLevel: ZLibOption.DEFAULT_MEM_LEVEL, |
+ this.strategy: ZLibOption.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 |
* 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 +367,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; |
+ |
+ /** |
+ * 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; |
/** |
- * Create a new [ZLibEncoder] converter. |
+ * When true, deflate generates raw data with no zlib header or trailer, and |
+ * will not compute an adler32 check value |
*/ |
- const ZLibDecoder(); |
+ final bool raw; |
+ |
+ ZLibDecoder({this.windowBits: ZLibOption.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 +414,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 +428,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 +454,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 +475,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 +525,6 @@ class _FilterSink extends ByteConversionSink { |
} |
- |
/** |
* Private helper-class to handle native filters. |
*/ |
@@ -274,8 +540,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 +552,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 (ZLibOption.MIN_WINDOW_BITS > windowBits || |
+ ZLibOption.MAX_WINDOW_BITS < windowBits) { |
+ throw new RangeError.range(windowsBits, ZLibOption.MIN_WINDOW_BITS, |
+ ZLibOption.MAX_WINDOW_BITS); |
+ } |
+} |
+ |
+void _validateZLibeLevel(int level) { |
+ if (ZLibOption.MIN_LEVEL > level || |
+ ZLibOption.MAX_LEVEL < level) { |
+ throw new RangeError.range(level, ZLibOption.MIN_LEVEL, |
+ ZLibOption.MAX_LEVEL); |
+ } |
+} |
+ |
+void _validateZLibMemLevel(int memLevel) { |
+ if (ZLibOption.MIN_MEM_LEVEL > memLevel || |
+ ZLibOption.MAX_MEM_LEVEL < memLevel) { |
+ throw new RangeError(memLvel, ZLibOption.MIN_MEM_LEVEL, |
+ ZLibOption.MAX_MEM_LEVEL); |
+ } |
+} |
+ |
+void _validateZLibStrategy(int strategy) { |
+ const strategies = const <int>[ZLibOption.STRATEGY_FILTERED, |
+ ZLibOption.STRATEGY_HUFFMAN_ONLY, ZLibOption.STRATEGY_RLE, |
+ ZLibOption.STRATEGY_FIXED, ZLibOption.STRATEGY_DEFAULT]; |
+ if (strategies.indexOf(strategy) == -1) { |
+ throw new ArgumentError("Unsupported 'strategy'"); |
+ } |
} |