mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 21:40:07 +00:00
590 lines
20 KiB
Dart
590 lines
20 KiB
Dart
// 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;
|
|
|
|
/**
|
|
* 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._default();
|
|
|
|
/**
|
|
* 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>> {
|
|
/**
|
|
* 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;
|
|
|
|
/**
|
|
* 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 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,
|
|
this.gzip: 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,
|
|
gzip = false,
|
|
dictionary = null;
|
|
|
|
/**
|
|
* Get a [ZLibEncoder] for encoding to `ZLib` compressed data.
|
|
*/
|
|
ZLibEncoder get encoder =>
|
|
new ZLibEncoder(gzip: false, level: level, windowBits: windowBits,
|
|
memLevel: memLevel, strategy: strategy,
|
|
dictionary: dictionary, raw: raw);
|
|
|
|
/**
|
|
* Get a [ZLibDecoder] for decoding `ZLib` compressed data.
|
|
*/
|
|
ZLibDecoder get decoder =>
|
|
new ZLibDecoder(windowBits: windowBits, dictionary: dictionary, raw: raw);
|
|
}
|
|
|
|
|
|
/**
|
|
* An instance of the default implementation of the [GZipCodec].
|
|
*/
|
|
const GZipCodec GZIP = const GZipCodec._default();
|
|
|
|
|
|
/**
|
|
* 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>> {
|
|
/**
|
|
* 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;
|
|
|
|
/**
|
|
* 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
|
|
* [ZLibOption.STRATEGY_DEFAULT] for normal data,
|
|
* [ZLibOption.STRATEGY_FILTERED] for data produced by a filter
|
|
* (or predictor), [ZLibOption.STRATEGY_HUFFMAN_ONLY] to force Huffman
|
|
* encoding only (no string match), or [ZLibOption.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;
|
|
|
|
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,
|
|
this.gzip: true}) {
|
|
_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,
|
|
gzip = true,
|
|
dictionary = null;
|
|
|
|
/**
|
|
* Get a [ZLibEncoder] for encoding to `GZip` compressed data.
|
|
*/
|
|
ZLibEncoder 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.
|
|
*/
|
|
ZLibDecoder get decoder =>
|
|
new ZLibDecoder(windowBits: windowBits, dictionary: dictionary, raw: raw);
|
|
}
|
|
|
|
/**
|
|
* The [ZLibEncoder] encoder is used by [ZLibCodec] and [GZipCodec] to compress
|
|
* data.
|
|
*/
|
|
class ZLibEncoder extends Converter<List<int>, List<int>>
|
|
implements ChunkedConverter<List<int>, List<int>, List<int>, List<int>> {
|
|
|
|
/**
|
|
* 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;
|
|
|
|
/**
|
|
* 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
|
|
* [ZLibOption.STRATEGY_DEFAULT] for normal data,
|
|
* [ZLibOption.STRATEGY_FILTERED] for data produced by a filter
|
|
* (or predictor), [ZLibOption.STRATEGY_HUFFMAN_ONLY] to force Huffman
|
|
* encoding only (no string match), or [ZLibOption.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: 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();
|
|
return sink.builder.takeBytes();
|
|
}
|
|
|
|
/**
|
|
* Start a chunked conversion using the options given to the [ZLibEncoder]
|
|
* constructor. While it accepts any [Sink] taking [List<int>]'s,
|
|
* the optimal sink to be passed as [sink] is a [ByteConversionSink].
|
|
*/
|
|
ByteConversionSink startChunkedConversion(Sink<List<int>> sink) {
|
|
if (sink is! ByteConversionSink) {
|
|
sink = new ByteConversionSink.from(sink);
|
|
}
|
|
return new _ZLibEncoderSink(sink, gzip, level, windowBits, memLevel,
|
|
strategy, dictionary, raw);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 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;
|
|
|
|
/**
|
|
* 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: ZLibOption.DEFAULT_WINDOW_BITS,
|
|
this.dictionary: null, this.raw: false}) {
|
|
_validateZLibWindowBits(windowBits);
|
|
}
|
|
|
|
/**
|
|
* 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 [Sink]
|
|
* taking [List<int>]'s, the optimal sink to be passed as [sink] is a
|
|
* [ByteConversionSink].
|
|
*/
|
|
ByteConversionSink startChunkedConversion(Sink<List<int>> sink) {
|
|
if (sink is! ByteConversionSink) {
|
|
sink = new ByteConversionSink.from(sink);
|
|
}
|
|
return new _ZLibDecoderSink(sink, windowBits, dictionary, raw);
|
|
}
|
|
}
|
|
|
|
|
|
class _BufferSink extends ByteConversionSink {
|
|
final BytesBuilder builder = new BytesBuilder(copy: false);
|
|
|
|
void add(List<int> chunk) {
|
|
builder.add(chunk);
|
|
}
|
|
|
|
void addSlice(List<int> chunk, int start, int end, bool isLast) {
|
|
if (chunk is Uint8List) {
|
|
Uint8List list = chunk;
|
|
builder.add(new Uint8List.view(list.buffer, start, end - start));
|
|
} else {
|
|
builder.add(chunk.sublist(start, end));
|
|
}
|
|
}
|
|
|
|
void close() {}
|
|
}
|
|
|
|
|
|
class _ZLibEncoderSink extends _FilterSink {
|
|
_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, int windowBits,
|
|
List<int> dictionary, bool raw)
|
|
: super(sink, _Filter._newZLibInflateFilter(windowBits, dictionary, raw));
|
|
}
|
|
|
|
|
|
class _FilterSink extends ByteConversionSink {
|
|
final _Filter _filter;
|
|
final ByteConversionSink _sink;
|
|
bool _closed = false;
|
|
bool _empty = true;
|
|
|
|
_FilterSink(this._sink, this._filter);
|
|
|
|
void add(List<int> data) {
|
|
addSlice(data, 0, data.length, false);
|
|
}
|
|
|
|
void addSlice(List<int> data, int start, int end, bool isLast) {
|
|
if (_closed) return;
|
|
if (end == null) throw new ArgumentError.notNull("end");
|
|
RangeError.checkValidRange(start, end, data.length);
|
|
try {
|
|
_empty = false;
|
|
_BufferAndStart bufferAndStart =
|
|
_ensureFastAndSerializableByteData(data, start, end);
|
|
_filter.process(bufferAndStart.buffer,
|
|
bufferAndStart.start,
|
|
end - (start - bufferAndStart.start));
|
|
List<int> out;
|
|
while ((out = _filter.processed(flush: false)) != null) {
|
|
_sink.add(out);
|
|
}
|
|
} catch (e) {
|
|
_closed = true;
|
|
rethrow;
|
|
}
|
|
|
|
if (isLast) close();
|
|
}
|
|
|
|
void close() {
|
|
if (_closed) return;
|
|
// 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 {
|
|
List<int> out;
|
|
while ((out = _filter.processed(end: true)) != null) {
|
|
_sink.add(out);
|
|
}
|
|
} catch (e) {
|
|
_closed = true;
|
|
throw e;
|
|
}
|
|
_closed = true;
|
|
_sink.close();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Private helper-class to handle native filters.
|
|
*/
|
|
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 an 'end' packet is written on the stream.
|
|
*/
|
|
List<int> processed({bool flush: true, bool end: false});
|
|
|
|
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(windowBits, 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.range(memLevel, 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'");
|
|
}
|
|
}
|