OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.io; | 5 part of dart.io; |
6 | 6 |
| 7 /** |
| 8 * Exposes ZLib options for input parameters. |
| 9 * |
| 10 * See http://www.zlib.net/manual.html for more documentation. |
| 11 */ |
| 12 abstract class ZLibOption { |
| 13 /// Minimal value for [ZLibCodec.windowBits], [ZLibEncoder.windowBits] |
| 14 /// and [ZLibDecoder.windowBits]. |
| 15 static const int MIN_WINDOW_BITS = 8; |
| 16 /// Maximal value for [ZLibCodec.windowBits], [ZLibEncoder.windowBits] |
| 17 /// and [ZLibDecoder.windowBits]. |
| 18 static const int MAX_WINDOW_BITS = 15; |
| 19 /// Default value for [ZLibCodec.windowBits], [ZLibEncoder.windowBits] |
| 20 /// and [ZLibDecoder.windowBits]. |
| 21 static const int DEFAULT_WINDOW_BITS = 15; |
| 22 |
| 23 /// Minimal value for [ZLibCodec.level], [ZLibEncoder.level] |
| 24 /// and [ZLibDecoder.level]. |
| 25 static const int MIN_LEVEL = -1; |
| 26 /// Maximal value for [ZLibCodec.level], [ZLibEncoder.level] |
| 27 /// and [ZLibDecoder.level]. |
| 28 static const int MAX_LEVEL = 9; |
| 29 /// Default value for [ZLibCodec.level], [ZLibEncoder.level] |
| 30 /// and [ZLibDecoder.level]. |
| 31 static const int DEFAULT_LEVEL = 6; |
| 32 |
| 33 /// Minimal value for [ZLibCodec.memLevel], [ZLibEncoder.memLevel] |
| 34 /// and [ZLibDecoder.memLevel]. |
| 35 static const int MIN_MEM_LEVEL = 1; |
| 36 /// Maximal value for [ZLibCodec.memLevel], [ZLibEncoder.memLevel] |
| 37 /// and [ZLibDecoder.memLevel]. |
| 38 static const int MAX_MEM_LEVEL = 9; |
| 39 /// Default value for [ZLibCodec.memLevel], [ZLibEncoder.memLevel] |
| 40 /// and [ZLibDecoder.memLevel]. |
| 41 static const int DEFAULT_MEM_LEVEL = 8; |
| 42 |
| 43 |
| 44 /// Recommended strategy for data produced by a filter (or predictor) |
| 45 static const int STRATEGY_FILTERED = 1; |
| 46 /// Use this strategy to force Huffman encoding only (no string match) |
| 47 static const int STRATEGY_HUFFMAN_ONLY = 2; |
| 48 /// Use this strategy to limit match distances to one (run-length encoding) |
| 49 static const int STRATEGY_RLE = 3; |
| 50 /// This strategy prevents the use of dynamic Huffman codes, allowing for a |
| 51 /// simpler decoder |
| 52 static const int STRATEGY_FIXED = 4; |
| 53 /// Recommended strategy for normal data |
| 54 static const int STRATEGY_DEFAULT = 0; |
| 55 } |
7 | 56 |
8 /** | 57 /** |
9 * An instance of the default implementation of the [ZLibCodec]. | 58 * An instance of the default implementation of the [ZLibCodec]. |
10 */ | 59 */ |
11 const ZLibCodec ZLIB = const ZLibCodec(); | 60 const ZLibCodec ZLIB = const ZLibCodec._default(); |
12 | |
13 | 61 |
14 /** | 62 /** |
15 * The [ZLibCodec] encodes raw bytes to ZLib compressed bytes and decodes ZLib | 63 * The [ZLibCodec] encodes raw bytes to ZLib compressed bytes and decodes ZLib |
16 * compressed bytes to raw bytes. | 64 * compressed bytes to raw bytes. |
17 */ | 65 */ |
18 class ZLibCodec extends Codec<List<int>, List<int>> { | 66 class ZLibCodec extends Codec<List<int>, List<int>> { |
19 /** | 67 /** |
20 * The compression level of the [ZLibCodec]. | 68 * When true, `GZip` frames will be added to the compressed data. |
| 69 */ |
| 70 final bool gzip; |
| 71 |
| 72 /** |
| 73 * The compression-[level] can be set in the range of `-1..9`, with `6` being |
| 74 * the default compression level. Levels above `6` will have higher |
| 75 * compression rates at the cost of more CPU and memory usage. Levels below |
| 76 * `6` will use less CPU and memory at the cost of lower compression rates. |
21 */ | 77 */ |
22 final int level; | 78 final int level; |
23 | 79 |
24 /** | 80 /** |
25 * Get a [Converter] for encoding to `ZLib` compressed data. | 81 * Specifies how much memory should be allocated for the internal compression |
| 82 * state. `1` uses minimum memory but is slow and reduces compression ratio; |
| 83 * `9` uses maximum memory for optimal speed. The default value is `8`. |
| 84 * |
| 85 * The memory requirements for deflate are (in bytes): |
| 86 * |
| 87 * (1 << (windowBits + 2)) + (1 << (memLevel + 9)) |
| 88 * that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values) |
| 89 */ |
| 90 final int memLevel; |
| 91 |
| 92 /** |
| 93 * Tunes the compression algorithm. Use the value STRATEGY_DEFAULT for normal |
| 94 * data, STRATEGY_FILTERED for data produced by a filter (or predictor), |
| 95 * STRATEGY_HUFFMAN_ONLY to force Huffman encoding only (no string match), or |
| 96 * STRATEGY_RLE to limit match distances to one (run-length encoding). |
| 97 */ |
| 98 final int strategy; |
| 99 |
| 100 /** |
| 101 * Base two logarithm of the window size (the size of the history buffer). It |
| 102 * should be in the range 8..15. Larger values result in better compression at |
| 103 * the expense of memory usage. The default value is 15 |
| 104 */ |
| 105 final int windowBits; |
| 106 |
| 107 /** |
| 108 * When true, deflate generates raw data with no zlib header or trailer, and |
| 109 * will not compute an adler32 check value |
| 110 */ |
| 111 final bool raw; |
| 112 |
| 113 /** |
| 114 * Initial compression dictionary. |
| 115 * |
| 116 * It should consist of strings (byte sequences) that are likely to be |
| 117 * encountered later in the data to be compressed, with the most commonly used |
| 118 * strings preferably put towards the end of the dictionary. Using a |
| 119 * dictionary is most useful when the data to be compressed is short and can |
| 120 * be predicted with good accuracy; the data can then be compressed better |
| 121 * than with the default empty dictionary. |
| 122 */ |
| 123 final List<int> dictionary; |
| 124 |
| 125 ZLibCodec({this.level: ZLibOption.DEFAULT_LEVEL, |
| 126 this.windowBits: ZLibOption.DEFAULT_WINDOW_BITS, |
| 127 this.memLevel: ZLibOption.DEFAULT_MEM_LEVEL, |
| 128 this.strategy: ZLibOption.STRATEGY_DEFAULT, |
| 129 this.dictionary: null, |
| 130 this.raw: false}) { |
| 131 _validateZLibeLevel(level); |
| 132 _validateZLibMemLevel(memLevel); |
| 133 _validateZLibStrategy(strategy); |
| 134 _validateZLibWindowBits(windowBits); |
| 135 } |
| 136 |
| 137 const ZLibCodec._default() |
| 138 : level = ZLibOption.DEFAULT_LEVEL, |
| 139 windowBits = ZLibOption.DEFAULT_WINDOW_BITS, |
| 140 memLevel = ZLibOption.DEFAULT_MEM_LEVEL, |
| 141 strategy = ZLibOption.STRATEGY_DEFAULT, |
| 142 raw = false; |
| 143 |
| 144 /** |
| 145 * Get a [ZLibEncoder] for encoding to `ZLib` compressed data. |
26 */ | 146 */ |
27 Converter<List<int>, List<int>> get encoder => | 147 Converter<List<int>, List<int>> get encoder => |
28 new ZLibEncoder(gzip: false, level: level); | 148 new ZLibEncoder(gzip: false, level: level, windowBits: windowBits, |
| 149 memLevel: memLevel, strategy: strategy, |
| 150 dictionary: dictionary, raw: raw); |
29 | 151 |
30 /** | 152 /** |
31 * Get a [Converter] for decoding `ZLib` compressed data. | 153 * Get a [ZLibDecoder] for decoding `ZLib` compressed data. |
32 */ | 154 */ |
33 Converter<List<int>, List<int>> get decoder => const ZLibDecoder(); | 155 Converter<List<int>, List<int>> get decoder => |
34 | 156 new ZLibDecoder(windowBits: windowBits, dictionary: dictionary, raw: raw); |
35 /** | |
36 * The compression-[level] can be set in the range of `1..10`, with `6` being | |
37 * the default compression level. Levels above 6 will have higher compression | |
38 * rates at the cost of more CPU and memory usage. Levels below 6 will use | |
39 * less CPU and memory, but at the cost of lower compression rates. | |
40 */ | |
41 const ZLibCodec({this.level: 6}); | |
42 } | 157 } |
43 | 158 |
44 | 159 |
45 /** | 160 /** |
46 * An instance of the default implementation of the [GZipCodec]. | 161 * An instance of the default implementation of the [GZipCodec]. |
47 */ | 162 */ |
48 const GZipCodec GZIP = const GZipCodec(); | 163 const GZipCodec GZIP = const GZipCodec._default(); |
49 | 164 |
50 | 165 |
51 /** | 166 /** |
52 * The [GZipCodec] encodes raw bytes to GZip compressed bytes and decodes GZip | 167 * The [GZipCodec] encodes raw bytes to GZip compressed bytes and decodes GZip |
53 * compressed bytes to raw bytes. | 168 * compressed bytes to raw bytes. |
54 * | 169 * |
55 * The difference between [ZLibCodec] and [GZipCodec] is that the [GZipCodec] | 170 * The difference between [ZLibCodec] and [GZipCodec] is that the [GZipCodec] |
56 * wraps the `ZLib` compressed bytes in `GZip` frames. | 171 * wraps the `ZLib` compressed bytes in `GZip` frames. |
57 */ | 172 */ |
58 class GZipCodec extends Codec<List<int>, List<int>> { | 173 class GZipCodec extends Codec<List<int>, List<int>> { |
59 /** | 174 /** |
60 * The compression level of the [ZLibCodec]. | 175 * When true, `GZip` frames will be added to the compressed data. |
| 176 */ |
| 177 final bool gzip; |
| 178 |
| 179 /** |
| 180 * The compression-[level] can be set in the range of `-1..9`, with `6` being |
| 181 * the default compression level. Levels above `6` will have higher |
| 182 * compression rates at the cost of more CPU and memory usage. Levels below |
| 183 * `6` will use less CPU and memory at the cost of lower compression rates. |
61 */ | 184 */ |
62 final int level; | 185 final int level; |
63 | 186 |
64 /** | 187 /** |
65 * Get a [Converter] for encoding to `GZip` compressed data. | 188 * Specifies how much memory should be allocated for the internal compression |
| 189 * state. `1` uses minimum memory but is slow and reduces compression ratio; |
| 190 * `9` uses maximum memory for optimal speed. The default value is `8`. |
| 191 * |
| 192 * The memory requirements for deflate are (in bytes): |
| 193 * |
| 194 * (1 << (windowBits + 2)) + (1 << (memLevel + 9)) |
| 195 * that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values) |
| 196 */ |
| 197 final int memLevel; |
| 198 |
| 199 /** |
| 200 * Tunes the compression algorithm. Use the value |
| 201 * [ZlibConstant.STRATEGY_DEFAULT] for normal data, |
| 202 * [ZlibConstant.STRATEGY_FILTERED] for data produced by a filter |
| 203 * (or predictor), |
| 204 * [ZlibConstant.STRATEGY_HUFFMAN_ONLY] to force Huffman encoding only (no |
| 205 * string match), or [ZlibConstant.STRATEGY_RLE] to limit match distances to |
| 206 * one (run-length encoding). |
| 207 */ |
| 208 final int strategy; |
| 209 |
| 210 /** |
| 211 * Base two logarithm of the window size (the size of the history buffer). It |
| 212 * should be in the range 8..15. Larger values result in better compression at |
| 213 * the expense of memory usage. The default value is 15 |
| 214 */ |
| 215 final int windowBits; |
| 216 |
| 217 /** |
| 218 * Initial compression dictionary. |
| 219 * |
| 220 * It should consist of strings (byte sequences) that are likely to be |
| 221 * encountered later in the data to be compressed, with the most commonly used |
| 222 * strings preferably put towards the end of the dictionary. Using a |
| 223 * dictionary is most useful when the data to be compressed is short and can |
| 224 * be predicted with good accuracy; the data can then be compressed better |
| 225 * than with the default empty dictionary. |
| 226 */ |
| 227 final List<int> dictionary; |
| 228 |
| 229 /** |
| 230 * When true, deflate generates raw data with no zlib header or trailer, and |
| 231 * will not compute an adler32 check value |
| 232 */ |
| 233 final bool raw; |
| 234 |
| 235 GZipCodec({this.level: ZLibOption.DEFAULT_LEVEL, |
| 236 this.windowBits: ZLibOption.DEFAULT_WINDOW_BITS, |
| 237 this.memLevel: ZLibOption.DEFAULT_MEM_LEVEL, |
| 238 this.strategy: ZLibOption.STRATEGY_DEFAULT, |
| 239 this.dictionary: null, |
| 240 this.raw: false}) { |
| 241 _validateZLibeLevel(level); |
| 242 _validateZLibMemLevel(memLevel); |
| 243 _validateZLibStrategy(strategy); |
| 244 _validateZLibWindowBits(windowBits); |
| 245 } |
| 246 |
| 247 const GZipCodec._default() |
| 248 : level = ZLibOption.DEFAULT_LEVEL, |
| 249 windowBits = ZLibOption.DEFAULT_WINDOW_BITS, |
| 250 memLevel = ZLibOption.DEFAULT_MEM_LEVEL, |
| 251 strategy = ZLibOption.STRATEGY_DEFAULT, |
| 252 raw = false; |
| 253 |
| 254 /** |
| 255 * Get a [ZLibEncoder] for encoding to `GZip` compressed data. |
66 */ | 256 */ |
67 Converter<List<int>, List<int>> get encoder => | 257 Converter<List<int>, List<int>> get encoder => |
68 new ZLibEncoder(gzip: true, level: level); | 258 new ZLibEncoder(gzip: true, level: level, windowBits: windowBits, |
| 259 memLevel: memLevel, strategy: strategy, |
| 260 dictionary: dictionary, raw: raw); |
69 | 261 |
70 /** | 262 /** |
71 * Get a [Converter] for decoding `GZip` compressed data. | 263 * Get a [ZLibDecoder] for decoding `GZip` compressed data. |
72 */ | 264 */ |
73 Converter<List<int>, List<int>> get decoder => const ZLibDecoder(); | 265 Converter<List<int>, List<int>> get decoder => |
74 | 266 new ZLibDecoder(windowBits: windowBits, dictionary: dictionary, raw: raw); |
75 /** | |
76 * The compression-[level] can be set in the range of `1..10`, with `6` being | |
77 * the default compression level. Levels above 6 will have higher compression | |
78 * rates at the cost of more CPU and memory usage. Levels below 6 will use | |
79 * less CPU and memory, but at the cost of lower compression rates. | |
80 */ | |
81 const GZipCodec({this.level: 6}); | |
82 } | 267 } |
83 | 268 |
84 | |
85 /** | 269 /** |
86 * The [ZLibEncoder] is the encoder used by [ZLibCodec] and [GZipCodec] to | 270 * The [ZLibEncoder] encoder is used by [ZLibCodec] and [GZipCodec] to compress |
87 * compress data. | 271 * data. |
88 */ | 272 */ |
89 class ZLibEncoder extends Converter<List<int>, List<int>> { | 273 class ZLibEncoder extends Converter<List<int>, List<int>> { |
90 /** | 274 /** |
91 * If [gzip] is true, `GZip` frames will be added to the compressed data. | 275 * When true, `GZip` frames will be added to the compressed data. |
92 */ | 276 */ |
93 final bool gzip; | 277 final bool gzip; |
94 | 278 |
95 /** | 279 /** |
96 * The compression level used by the encoder. | 280 * The compression-[level] can be set in the range of `-1..9`, with `6` being |
| 281 * the default compression level. Levels above `6` will have higher |
| 282 * compression rates at the cost of more CPU and memory usage. Levels below |
| 283 * `6` will use less CPU and memory at the cost of lower compression rates. |
97 */ | 284 */ |
98 final int level; | 285 final int level; |
99 | 286 |
100 /** | 287 /** |
101 * Create a new [ZLibEncoder] converter. If the [gzip] flag is set, the | 288 * Specifies how much memory should be allocated for the internal compression |
102 * encoder will wrap the encoded ZLib data in GZip frames. | 289 * state. `1` uses minimum memory but is slow and reduces compression ratio; |
| 290 * `9` uses maximum memory for optimal speed. The default value is `8`. |
| 291 * |
| 292 * The memory requirements for deflate are (in bytes): |
| 293 * |
| 294 * (1 << (windowBits + 2)) + (1 << (memLevel + 9)) |
| 295 * that is: 128K for windowBits = 15 + 128K for memLevel = 8 (default values) |
103 */ | 296 */ |
104 const ZLibEncoder({this.gzip: false, this.level: 6}); | 297 final int memLevel; |
| 298 |
| 299 /** |
| 300 * Tunes the compression algorithm. Use the value |
| 301 * [ZlibConstant.STRATEGY_DEFAULT] for normal data, |
| 302 * [ZlibConstant.STRATEGY_FILTERED] for data produced by a filter |
| 303 * (or predictor), |
| 304 * [ZlibConstant.STRATEGY_HUFFMAN_ONLY] to force Huffman encoding only (no |
| 305 * string match), or [ZlibConstant.STRATEGY_RLE] to limit match distances to |
| 306 * one (run-length encoding). |
| 307 */ |
| 308 final int strategy; |
| 309 |
| 310 /** |
| 311 * Base two logarithm of the window size (the size of the history buffer). It |
| 312 * should be in the range 8..15. Larger values result in better compression at |
| 313 * the expense of memory usage. The default value is 15 |
| 314 */ |
| 315 final int windowBits; |
| 316 |
| 317 /** |
| 318 * Initial compression dictionary. |
| 319 * |
| 320 * It should consist of strings (byte sequences) that are likely to be |
| 321 * encountered later in the data to be compressed, with the most commonly used |
| 322 * strings preferably put towards the end of the dictionary. Using a |
| 323 * dictionary is most useful when the data to be compressed is short and can |
| 324 * be predicted with good accuracy; the data can then be compressed better |
| 325 * than with the default empty dictionary. |
| 326 */ |
| 327 final List<int> dictionary; |
105 | 328 |
106 | 329 |
107 /** | 330 /** |
108 * Convert a list of bytes using the options given to the [ZLibEncoder] | 331 * When true, deflate generates raw data with no zlib header or trailer, and |
| 332 * will not compute an adler32 check value |
| 333 */ |
| 334 final bool raw; |
| 335 |
| 336 ZLibEncoder({this.gzip: false, |
| 337 this.level: ZLibOption.DEFAULT_LEVEL, |
| 338 this.windowBits: ZLibOption.DEFAULT_WINDOW_BITS, |
| 339 this.memLevel: ZLibOption.DEFAULT_MEM_LEVEL, |
| 340 this.strategy: ZLibOption.STRATEGY_DEFAULT, |
| 341 this.dictionary: null, |
| 342 this.raw: false}) { |
| 343 _validateZLibeLevel(level); |
| 344 _validateZLibMemLevel(memLevel); |
| 345 _validateZLibStrategy(strategy); |
| 346 _validateZLibWindowBits(windowBits); |
| 347 } |
| 348 |
| 349 /** |
| 350 * Convert a list of bytes using the options given to the ZLibEncoder |
109 * constructor. | 351 * constructor. |
110 */ | 352 */ |
111 List<int> convert(List<int> bytes) { | 353 List<int> convert(List<int> bytes) { |
112 _BufferSink sink = new _BufferSink(); | 354 _BufferSink sink = new _BufferSink(); |
113 startChunkedConversion(sink) | 355 startChunkedConversion(sink)..add(bytes)..close(); |
114 ..add(bytes) | |
115 ..close(); | |
116 return sink.builder.takeBytes(); | 356 return sink.builder.takeBytes(); |
117 } | 357 } |
118 | 358 |
119 /** | 359 /** |
120 * Start a chunked conversion using the options given to the [ZLibEncoder] | 360 * Start a chunked conversion using the options given to the [ZLibEncoder] |
121 * constructor. While it accepts any [ChunkedConversionSink] taking | 361 * constructor. While it accepts any [ChunkedConversionSink] taking |
122 * [List<int>]'s, the optimal sink to be passed as [sink] is a | 362 * [List<int>]'s, the optimal sink to be passed as [sink] is a |
123 * [ByteConversionSink]. | 363 * [ByteConversionSink]. |
124 */ | 364 */ |
125 ByteConversionSink startChunkedConversion( | 365 ByteConversionSink startChunkedConversion( |
126 ChunkedConversionSink<List<int>> sink) { | 366 ChunkedConversionSink<List<int>> sink) { |
127 if (sink is! ByteConversionSink) { | 367 if (sink is! ByteConversionSink) { |
128 sink = new ByteConversionSink.from(sink); | 368 sink = new ByteConversionSink.from(sink); |
129 } | 369 } |
130 return new _ZLibEncoderSink(sink, gzip, level); | 370 |
| 371 return new _ZLibEncoderSink(sink, gzip, level, windowBits, memLevel, |
| 372 strategy, dictionary, raw); |
131 } | 373 } |
132 } | 374 } |
133 | 375 |
134 | 376 |
135 /** | 377 /** |
136 * The [ZLibDecoder] is the decoder used by [ZLibCodec] and [GZipCodec] to | 378 * The [ZLibDecoder] is used by [ZLibCodec] and [GZipCodec] to decompress data. |
137 * decompress data. | |
138 */ | 379 */ |
139 class ZLibDecoder extends Converter<List<int>, List<int>> { | 380 class ZLibDecoder extends Converter<List<int>, List<int>> { |
| 381 /** |
| 382 * Base two logarithm of the window size (the size of the history buffer). It |
| 383 * should be in the range 8..15. Larger values result in better compression at |
| 384 * the expense of memory usage. The default value is 15 |
| 385 */ |
| 386 final int windowBits; |
140 | 387 |
141 /** | 388 /** |
142 * Create a new [ZLibEncoder] converter. | 389 * Initial compression dictionary. |
| 390 * |
| 391 * It should consist of strings (byte sequences) that are likely to be |
| 392 * encountered later in the data to be compressed, with the most commonly used |
| 393 * strings preferably put towards the end of the dictionary. Using a |
| 394 * dictionary is most useful when the data to be compressed is short and can |
| 395 * be predicted with good accuracy; the data can then be compressed better |
| 396 * than with the default empty dictionary. |
143 */ | 397 */ |
144 const ZLibDecoder(); | 398 final List<int> dictionary; |
| 399 |
| 400 /** |
| 401 * When true, deflate generates raw data with no zlib header or trailer, and |
| 402 * will not compute an adler32 check value |
| 403 */ |
| 404 final bool raw; |
| 405 |
| 406 ZLibDecoder({this.windowBits: ZLibOption.DEFAULT_WINDOW_BITS, |
| 407 this.dictionary: null, this.raw: false}) { |
| 408 _validateZLibWindowBits(windowBits); |
| 409 } |
145 | 410 |
146 /** | 411 /** |
147 * Convert a list of bytes using the options given to the [ZLibDecoder] | 412 * Convert a list of bytes using the options given to the [ZLibDecoder] |
148 * constructor. | 413 * constructor. |
149 */ | 414 */ |
150 List<int> convert(List<int> bytes) { | 415 List<int> convert(List<int> bytes) { |
151 _BufferSink sink = new _BufferSink(); | 416 _BufferSink sink = new _BufferSink(); |
152 startChunkedConversion(sink) | 417 startChunkedConversion(sink)..add(bytes)..close(); |
153 ..add(bytes) | |
154 ..close(); | |
155 return sink.builder.takeBytes(); | 418 return sink.builder.takeBytes(); |
156 } | 419 } |
157 | 420 |
158 /** | 421 /** |
159 * Start a chunked conversion. While it accepts any [ChunkedConversionSink] | 422 * Start a chunked conversion. While it accepts any [ChunkedConversionSink] |
160 * taking [List<int>]'s, the optimal sink to be passed as [sink] is a | 423 * taking [List<int>]'s, the optimal sink to be passed as [sink] is a |
161 * [ByteConversionSink]. | 424 * [ByteConversionSink]. |
162 */ | 425 */ |
163 ByteConversionSink startChunkedConversion( | 426 ByteConversionSink startChunkedConversion( |
164 ChunkedConversionSink<List<int>> sink) { | 427 ChunkedConversionSink<List<int>> sink) { |
165 if (sink is! ByteConversionSink) { | 428 if (sink is! ByteConversionSink) { |
166 sink = new ByteConversionSink.from(sink); | 429 sink = new ByteConversionSink.from(sink); |
167 } | 430 } |
168 return new _ZLibDecoderSink(sink); | 431 return new _ZLibDecoderSink(sink, windowBits, dictionary, raw); |
169 } | 432 } |
170 } | 433 } |
171 | 434 |
172 | 435 |
173 class _BufferSink extends ByteConversionSink { | 436 class _BufferSink extends ByteConversionSink { |
174 final BytesBuilder builder = new BytesBuilder(); | 437 final BytesBuilder builder = new BytesBuilder(); |
175 | 438 |
176 void add(List<int> chunk) { | 439 void add(List<int> chunk) { |
177 builder.add(chunk); | 440 builder.add(chunk); |
178 } | 441 } |
179 | 442 |
180 void addSlice(List<int> chunk, int start, int end, bool isLast) { | 443 void addSlice(List<int> chunk, int start, int end, bool isLast) { |
181 if (chunk is Uint8List) { | 444 if (chunk is Uint8List) { |
182 Uint8List list = chunk; | 445 Uint8List list = chunk; |
183 builder.add(new Uint8List.view(list.buffer, start, end - start)); | 446 builder.add(new Uint8List.view(list.buffer, start, end - start)); |
184 } else { | 447 } else { |
185 builder.add(chunk.sublist(start, end)); | 448 builder.add(chunk.sublist(start, end)); |
186 } | 449 } |
187 } | 450 } |
188 | 451 |
189 void close() {} | 452 void close() {} |
190 } | 453 } |
191 | 454 |
192 | 455 |
193 class _ZLibEncoderSink extends _FilterSink { | 456 class _ZLibEncoderSink extends _FilterSink { |
194 _ZLibEncoderSink(ByteConversionSink sink, bool gzip, int level) | 457 _ZLibEncoderSink(ByteConversionSink sink, bool gzip, int level, |
195 : super(sink, _Filter.newZLibDeflateFilter(gzip, level)); | 458 int windowBits, int memLevel, int strategy, |
| 459 List<int> dictionary, bool raw) |
| 460 : super(sink, _Filter.newZLibDeflateFilter(gzip, level, windowBits, |
| 461 memLevel, strategy, |
| 462 dictionary, raw)); |
| 463 } |
| 464 |
| 465 class _ZLibDecoderSink extends _FilterSink { |
| 466 _ZLibDecoderSink(ByteConversionSink sink, int windowBits, |
| 467 List<int> dictionary, bool raw) |
| 468 : super(sink, _Filter.newZLibInflateFilter(windowBits, dictionary, raw)); |
196 } | 469 } |
197 | 470 |
198 | 471 |
199 class _ZLibDecoderSink extends _FilterSink { | |
200 _ZLibDecoderSink(ByteConversionSink sink) | |
201 : super(sink, _Filter.newZLibInflateFilter()); | |
202 } | |
203 | |
204 | |
205 class _FilterSink extends ByteConversionSink { | 472 class _FilterSink extends ByteConversionSink { |
206 final _Filter _filter; | 473 final _Filter _filter; |
207 final ByteConversionSink _sink; | 474 final ByteConversionSink _sink; |
208 bool _closed = false; | 475 bool _closed = false; |
209 bool _empty = true; | 476 bool _empty = true; |
210 | 477 |
211 _FilterSink(ByteConversionSink this._sink, _Filter this._filter); | 478 _FilterSink(this._sink, this._filter); |
212 | 479 |
213 void add(List<int> data) { | 480 void add(List<int> data) { |
214 addSlice(data, 0, data.length, false); | 481 addSlice(data, 0, data.length, false); |
215 } | 482 } |
216 | 483 |
217 void addSlice(List<int> data, int start, int end, bool isLast) { | 484 void addSlice(List<int> data, int start, int end, bool isLast) { |
218 if (_closed) return; | 485 if (_closed) return; |
219 if (start < 0 || start > data.length) { | 486 if (start < 0 || start > data.length) { |
220 throw new ArgumentError("Invalid start position"); | 487 throw new ArgumentError("Invalid start position"); |
221 } | 488 } |
(...skipping 29 matching lines...) Expand all Loading... |
251 _closed = true; | 518 _closed = true; |
252 throw e; | 519 throw e; |
253 } | 520 } |
254 if (!_closed) _filter.end(); | 521 if (!_closed) _filter.end(); |
255 _closed = true; | 522 _closed = true; |
256 _sink.close(); | 523 _sink.close(); |
257 } | 524 } |
258 } | 525 } |
259 | 526 |
260 | 527 |
261 | |
262 /** | 528 /** |
263 * Private helper-class to handle native filters. | 529 * Private helper-class to handle native filters. |
264 */ | 530 */ |
265 abstract class _Filter { | 531 abstract class _Filter { |
266 /** | 532 /** |
267 * Call to process a chunk of data. A call to [process] should only be made | 533 * Call to process a chunk of data. A call to [process] should only be made |
268 * when [processed] returns [:null:]. | 534 * when [processed] returns [:null:]. |
269 */ | 535 */ |
270 void process(List<int> data, int start, int end); | 536 void process(List<int> data, int start, int end); |
271 | 537 |
272 /** | 538 /** |
273 * Get a chunk of processed data. When there are no more data available, | 539 * Get a chunk of processed data. When there are no more data available, |
274 * [processed] will return [:null:]. Set [flush] to [:false:] for non-final | 540 * [processed] will return [:null:]. Set [flush] to [:false:] for non-final |
275 * calls to improve performance of some filters. | 541 * calls to improve performance of some filters. |
276 * | 542 * |
277 * The last call to [processed] should have [end] set to [:true:]. This will m
ake | 543 * The last call to [processed] should have [end] set to [:true:]. This will |
278 * sure a 'end' packet is written on the stream. | 544 * make sure an 'end' packet is written on the stream. |
279 */ | 545 */ |
280 List<int> processed({bool flush: true, bool end: false}); | 546 List<int> processed({bool flush: true, bool end: false}); |
281 | 547 |
282 /** | 548 /** |
283 * Mark the filter as closed. Always call this method for any filter created | 549 * Mark the filter as closed. Always call this method for any filter created |
284 * to avoid leaking resources. [end] can be called at any time, but any | 550 * to avoid leaking resources. [end] can be called at any time, but any |
285 * successive calls to [process] or [processed] will fail. | 551 * successive calls to [process] or [processed] will fail. |
286 */ | 552 */ |
287 void end(); | 553 void end(); |
288 | 554 |
289 external static _Filter newZLibDeflateFilter(bool gzip, int level); | 555 external static _Filter newZLibDeflateFilter(bool gzip, int level, |
290 external static _Filter newZLibInflateFilter(); | 556 int windowBits, int memLevel, |
| 557 int strategy, |
| 558 List<int> dictionary, bool raw); |
| 559 |
| 560 external static _Filter newZLibInflateFilter(int windowBits, |
| 561 List<int> dictionary, bool raw); |
291 } | 562 } |
| 563 |
| 564 void _validateZLibWindowBits(int windowBits) { |
| 565 if (ZLibOption.MIN_WINDOW_BITS > windowBits || |
| 566 ZLibOption.MAX_WINDOW_BITS < windowBits) { |
| 567 throw new RangeError.range(windowsBits, ZLibOption.MIN_WINDOW_BITS, |
| 568 ZLibOption.MAX_WINDOW_BITS); |
| 569 } |
| 570 } |
| 571 |
| 572 void _validateZLibeLevel(int level) { |
| 573 if (ZLibOption.MIN_LEVEL > level || |
| 574 ZLibOption.MAX_LEVEL < level) { |
| 575 throw new RangeError.range(level, ZLibOption.MIN_LEVEL, |
| 576 ZLibOption.MAX_LEVEL); |
| 577 } |
| 578 } |
| 579 |
| 580 void _validateZLibMemLevel(int memLevel) { |
| 581 if (ZLibOption.MIN_MEM_LEVEL > memLevel || |
| 582 ZLibOption.MAX_MEM_LEVEL < memLevel) { |
| 583 throw new RangeError(memLvel, ZLibOption.MIN_MEM_LEVEL, |
| 584 ZLibOption.MAX_MEM_LEVEL); |
| 585 } |
| 586 } |
| 587 |
| 588 void _validateZLibStrategy(int strategy) { |
| 589 const strategies = const <int>[ZLibOption.STRATEGY_FILTERED, |
| 590 ZLibOption.STRATEGY_HUFFMAN_ONLY, ZLibOption.STRATEGY_RLE, |
| 591 ZLibOption.STRATEGY_FIXED, ZLibOption.STRATEGY_DEFAULT]; |
| 592 if (strategies.indexOf(strategy) == -1) { |
| 593 throw new ArgumentError("Unsupported 'strategy'"); |
| 594 } |
| 595 } |
OLD | NEW |