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

Side by Side Diff: sdk/lib/io/data_transformer.dart

Issue 22867033: Update ZLib/GZip in dart:io to be a Codec/Converter from dart:convert. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Add documentation and convert impl. Created 7 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/bin/io_natives.cc ('k') | sdk/lib/io/http_impl.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 /**
9 * An instance of the default implementation of the [ZLibCodec].
10 */
11 const ZLIB = const ZLibCodec();
12
13
14 /**
15 * The [ZLibCodec] encodes raw bytes to ZLib compressed bytes and decodes ZLib
16 * compressed bytes to raw bytes.
17 */
18 class ZLibCodec extends Codec<List<int>, List<int>> {
19 /**
20 * The compression level of the [ZLibCodec].
21 */
22 final int level;
23
24 /**
25 * Get a [Converter] for encoding to `ZLib` compressed data.
26 */
27 Converter<List<int>, List<int>> get encoder =>
28 const ZLibEncoder(gzip: false, level: level);
29
30 /**
31 * Get a [Converter] for decoding `ZLib` compressed data.
32 */
33 Converter<List<int>, List<int>> get decoder => const ZLibDecoder();
34
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 }
43
44
45 /**
46 * An instance of the default implementation of the [GZipCodec].
47 */
48 const GZIP = const GZipCodec();
49
50
51 /**
52 * The [GZipCodec] encodes raw bytes to GZip compressed bytes and decodes GZip
53 * compressed bytes to raw bytes.
54 *
55 * The difference between [ZLibCodec] and [GZipCodec] is that the [GZipCodec]
56 * wraps the `ZLib` compressed bytes in `GZip` frames.
57 */
58 class GZipCodec extends Codec<List<int>, List<int>> {
59 /**
60 * The compression level of the [ZLibCodec].
61 */
62 final int level;
63
64 /**
65 * Get a [Converter] for encoding to `GZip` compressed data.
66 */
67 final Converter<List<int>, List<int>> encoder =
68 const ZLibEncoder(gzip: true, level: level);
69
70 /**
71 * Get a [Converter] for decoding `GZip` compressed data.
72 */
73 final Converter<List<int>, List<int>> decoder = const ZLibDecoder();
74
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 }
83
84
85 /**
86 * The [ZLibEncoder] is the encoder used by [ZLibCodec] and [GZipCodec] to
87 * compress data.
88 */
89 class ZLibEncoder extends Converter<List<int>, List<int>> {
Søren Gjesse 2013/08/22 16:07:26 We could consider making this and ZLibDecoder priv
Anders Johnsen 2013/08/23 07:11:53 Exposing both codecs and converters is in sync wit
90 /**
91 * If [gzip] is true, `GZip` frames will be added to the compressed data.
92 */
93 final bool gzip;
94
95 /**
96 * The compression level used by the encoder.
97 */
98 final int level;
99
100 /**
101 * Create a new [ZLibEncoder] converter. If the [gzip] flag is set, the
102 * encoder will wrap the encoded ZLib data in GZip frames.
103 */
104 const ZLibEncoder({this.gzip: false, this.level: 6});
105
106
107 /**
108 * Convert a list of bytes using the options given to the [ZLibEncoder]
109 * constructor.
110 */
111 List<int> convert(List<int> bytes) {
112 _BufferSink sink = new _BufferSink();
113 startChunkedConversion(sink)
114 ..add(bytes)
115 ..close();
116 return sink.builder.takeBytes();
117 }
118
119 /**
120 * Start a chunked conversion using the options given to the [ZLibEncoder]
121 * constructor. While it accepts any [ChunkedConversionSink] taking
122 * [List<int>]'s, the optimal sink to be passed as [sink] is a
123 * [ByteConversionSink].
124 */
125 ByteConversionSink startChunkedConversion(
126 ChunkedConversionSink<List<int>> sink) {
127 if (sink is! ByteConversionSink) {
128 sink = new ByteConversionSink.from(sink);
129 }
130 return new _ZLibEncoderSink(sink, gzip, level);
131 }
132 }
133
134
135 /**
136 * The [ZLibDecoder] is the decoder used by [ZLibCodec] and [GZipCodec] to
137 * decompress data.
138 */
139 class ZLibDecoder extends Converter<List<int>, List<int>> {
140
141 /**
142 * Create a new [ZLibEncoder] converter.
143 */
144 const ZLibDecoder();
145
146 /**
147 * Convert a list of bytes using the options given to the [ZLibDecoder]
148 * constructor.
149 */
150 List<int> convert(List<int> bytes) {
151 _BufferSink sink = new _BufferSink();
152 startChunkedConversion(sink)
153 ..add(bytes)
154 ..close();
155 return sink.builder.takeBytes();
156 }
157
158 /**
159 * Start a chunked conversion. While it accepts any [ChunkedConversionSink]
160 * taking [List<int>]'s, the optimal sink to be passed as [sink] is a
161 * [ByteConversionSink].
162 */
163 ByteConversionSink startChunkedConversion(
164 ChunkedConversionSink<List<int>> sink) {
165 if (sink is! ByteConversionSink) {
166 sink = new ByteConversionSink.from(sink);
167 }
168 return new _ZLibDecoderSink(sink);
169 }
170 }
171
172
173 class _BufferSink extends ByteConversionSink {
174 final BytesBuilder builder = new BytesBuilder();
175
176 void add(List<int> chunk) {
177 builder.add(chunk);
178 }
179
180 void addSlice(List<int> chunk, int start, int end, bool isLast) {
181 if (chunk is Uint8List) {
182 builder.add(Uint8List.view(chunk, start, end - start));
183 } else {
184 buidler.add(chunk.sublist(start, end));
185 }
186 }
187
188 void close() {}
189 }
190
191
192 class _ZLibEncoderSink extends _FilterSink {
193 _ZLibEncoderSink(ByteConversionSink sink, bool gzip, int level)
194 : super(sink, _Filter.newZLibDeflateFilter(gzip, level));
195 }
196
197
198 class _ZLibDecoderSink extends _FilterSink {
199 _ZLibDecoderSink(ByteConversionSink sink)
200 : super(sink, _Filter.newZLibInflateFilter());
201 }
202
203
204 class _FilterSink extends ByteConversionSink {
205 final _Filter _filter;
206 final ByteConversionSink _sink;
207 bool _closed = false;
208 bool _empty = true;
209
210 _FilterSink(ByteConversionSink this._sink, _Filter this._filter);
211
212 void add(List<int> data) {
213 addSlice(data, 0, data.length, false);
214 }
215
216 void addSlice(List<int> data, int start, int end, bool isLast) {
217 if (_closed) return;
218 if (start < 0 || start > data.length) {
219 throw ArgumentError("Invalid start position");
220 }
221 if (end < 0 || end > data.length || end < start) {
222 throw ArgumentError("Invalid end position");
223 }
224 try {
225 _empty = false;
226 _filter.process(data, start, end);
227 var out;
228 while ((out = _filter.processed(flush: false)) != null) {
229 _sink.add(out);
230 }
231 } catch (e) {
232 _closed = true;
233 throw e;
234 }
235
236 if (isLast) close();
237 }
238
239 void close() {
240 if (_closed) return;
241 // Be sure to send process an empty chunk of data. Without this, the empty
242 // message would not have a GZip frame (if compressed with GZip).
243 if (_empty) _filter.process(const [], 0, 0);
244 try {
245 var out;
246 while ((out = _filter.processed(end: true)) != null) {
247 _sink.add(out);
248 }
249 } catch (e) {
250 _closed = true;
251 throw e;
252 }
253 if (!_closed) _filter.end();
254 _closed = true;
255 _sink.close();
256 }
257 }
258
259
260
7 /** 261 /**
8 * Private helper-class to handle native filters. 262 * Private helper-class to handle native filters.
9 */ 263 */
10 abstract class _Filter { 264 abstract class _Filter {
11 /** 265 /**
12 * Call to process a chunk of data. A call to [process] should only be made 266 * Call to process a chunk of data. A call to [process] should only be made
13 * when [processed] returns [null]. 267 * when [processed] returns [null].
14 */ 268 */
15 void process(List<int> data); 269 void process(List<int> data, int start, int end);
16 270
17 /** 271 /**
18 * Get a chunk of processed data. When there are no more data available, 272 * Get a chunk of processed data. When there are no more data available,
19 * [processed] will return [null]. Set [flush] to [false] for non-final 273 * [processed] will return [null]. Set [flush] to [false] for non-final
20 * calls to improve performance of some filters. 274 * calls to improve performance of some filters.
21 * 275 *
22 * The last call to [processed] should have [end] set to [true]. This will mak e 276 * The last call to [processed] should have [end] set to [true]. This will mak e
23 * sure a 'end' packet is written on the stream. 277 * sure a 'end' packet is written on the stream.
24 */ 278 */
25 List<int> processed({bool flush: true, bool end: false}); 279 List<int> processed({bool flush: true, bool end: false});
26 280
27 /** 281 /**
28 * Mark the filter as closed. Always call this method for any filter created 282 * Mark the filter as closed. Always call this method for any filter created
29 * to avoid leaking resources. [end] can be called at any time, but any 283 * to avoid leaking resources. [end] can be called at any time, but any
30 * successive calls to [process] or [processed] will fail. 284 * successive calls to [process] or [processed] will fail.
31 */ 285 */
32 void end(); 286 void end();
33 287
34 external static _Filter newZLibDeflateFilter(bool gzip, int level); 288 external static _Filter newZLibDeflateFilter(bool gzip, int level);
35 external static _Filter newZLibInflateFilter(); 289 external static _Filter newZLibInflateFilter();
36 } 290 }
37
38
39 class _FilterTransformer extends StreamEventTransformer<List<int>, List<int>> {
40 final _Filter _filter;
41 bool _closed = false;
42 bool _empty = true;
43
44 _FilterTransformer(_Filter this._filter);
45
46 void handleData(List<int> data, EventSink<List<int>> sink) {
47 if (_closed) return;
48 try {
49 _empty = false;
50 _filter.process(data);
51 var out;
52 while ((out = _filter.processed(flush: false)) != null) {
53 sink.add(out);
54 }
55 } catch (e, s) {
56 _closed = true;
57 // TODO(floitsch): we are losing the stack trace.
58 sink.addError(e);
59 sink.close();
60 }
61 }
62
63 void handleDone(EventSink<List<int>> sink) {
64 if (_closed) return;
65 if (_empty) _filter.process(const []);
66 try {
67 var out;
68 while ((out = _filter.processed(end: true)) != null) {
69 sink.add(out);
70 }
71 } catch (e, s) {
72 // TODO(floitsch): we are losing the stack trace.
73 sink.addError(e);
74 _closed = true;
75 }
76 if (!_closed) _filter.end();
77 _closed = true;
78 sink.close();
79 }
80 }
81
82
83 /**
84 * ZLibDeflater class used to deflate a stream of bytes, using zlib.
85 */
86 class ZLibDeflater extends _FilterTransformer {
87 ZLibDeflater({bool gzip: true, int level: 6})
88 : super(_Filter.newZLibDeflateFilter(gzip, level));
89 }
90
91
92 /**
93 * ZLibInflater class used to inflate a stream of bytes, using zlib.
94 */
95 class ZLibInflater extends _FilterTransformer {
96 ZLibInflater() : super(_Filter.newZLibInflateFilter());
97 }
98
OLDNEW
« no previous file with comments | « runtime/bin/io_natives.cc ('k') | sdk/lib/io/http_impl.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698