OLD | NEW |
| (Empty) |
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | |
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. | |
4 | |
5 library reader; | |
6 | |
7 import 'input_stream.dart'; | |
8 import 'options.dart'; | |
9 import 'read_request.dart'; | |
10 import 'utils.dart'; | |
11 | |
12 /** | |
13 * A class for extracting and decompressing an archive. | |
14 * | |
15 * Each instance of this class represents a specific set of options for | |
16 * extracting an archive. These options can be used to create multiple input | |
17 * streams using the [reader.ArchiveReader.openFilename] and | |
18 * [reader.ArchiveReader.openMemory] methods. | |
19 * | |
20 * Before opening an archive, this needs to be configured. [filter] should be | |
21 * used to enable specific decompression algorithms, and [format] should be used | |
22 * to enable specific archive formats. | |
23 */ | |
24 class ArchiveReader { | |
25 /** | |
26 * The configuration for the filter(s) to use when decompressing the contents | |
27 * of an archive. The precise compression used is auto-detected from among all | |
28 * enabled options. | |
29 */ | |
30 final Filter filter; | |
31 | |
32 /** | |
33 * The configuration for the archive format(s) to look for when extracting the | |
34 * contents of an archive. The format used is auto-detected from among all | |
35 * enabled options. | |
36 */ | |
37 final Format format; | |
38 | |
39 /** | |
40 * Options for both [filter] and [format]. See [the libarchive | |
41 * documentation][wiki] for a list of available options. | |
42 * | |
43 * [wiki]: https://github.com/libarchive/libarchive/wiki/ManPageArchiveReadSet
Options3 | |
44 */ | |
45 final ArchiveOptions options; | |
46 | |
47 /** Creates a new, unconfigured archive reader. */ | |
48 ArchiveReader() : filter = new Filter._(), | |
49 format = new Format._(), | |
50 options = new ArchiveOptions(); | |
51 | |
52 /** | |
53 * Begins extracting from [file]. | |
54 * | |
55 * [block_size] only needs to be specified for reading from devices that | |
56 * require strict I/O blocking. | |
57 */ | |
58 Future<ArchiveInputStream> openFilename(String file, [int block_size=16384]) { | |
59 var id; | |
60 return _createArchive().then((_id) { | |
61 id = _id; | |
62 return call(OPEN_FILENAME, id, [file, block_size]); | |
63 }).then((_) => new ArchiveInputStream(id)); | |
64 } | |
65 | |
66 /** Begins extracting from [data], which should be a list of bytes. */ | |
67 Future<ArchiveInputStream> openData(List<int> data) { | |
68 var id; | |
69 return _createArchive().then((_id) { | |
70 id = _id; | |
71 return call(OPEN_MEMORY, id, [bytesForC(data)]); | |
72 }).then((_) => new ArchiveInputStream(id)); | |
73 } | |
74 | |
75 /** | |
76 * Creates an archive struct, applies all the configuration options to it, and | |
77 * returns its id. | |
78 */ | |
79 Future<int> _createArchive() { | |
80 return call(NEW).then((id) { | |
81 if (id == 0 || id == null) { | |
82 throw new ArchiveException("Archive is invalid or closed."); | |
83 } | |
84 return _pushConfiguration(id).then((_) => id); | |
85 }); | |
86 } | |
87 | |
88 /** | |
89 * Applies all configuration in this archive to the archive identified by | |
90 * [id]. Returns a future that completes once all the configuration is | |
91 * applied. | |
92 */ | |
93 Future _pushConfiguration(int id) { | |
94 var pending = <Future>[]; | |
95 if (filter.program != null) { | |
96 if (filter.programSignature != null) { | |
97 var signature = bytesForC(filter.programSignature); | |
98 pending.add(call(SUPPORT_FILTER_PROGRAM_SIGNATURE, id, | |
99 [filter.program, signature])); | |
100 } else { | |
101 pending.add(call(SUPPORT_FILTER_PROGRAM, id, [filter.program])); | |
102 } | |
103 } else if (filter.all) { | |
104 pending.add(call(SUPPORT_FILTER_ALL, id)); | |
105 } else { | |
106 if (filter.bzip2) pending.add(call(SUPPORT_FILTER_BZIP2, id)); | |
107 if (filter.compress) { | |
108 pending.add(call(SUPPORT_FILTER_COMPRESS, id)); | |
109 } | |
110 if (filter.gzip) pending.add(call(SUPPORT_FILTER_GZIP, id)); | |
111 if (filter.lzma) pending.add(call(SUPPORT_FILTER_LZMA, id)); | |
112 if (filter.xz) pending.add(call(SUPPORT_FILTER_XZ, id)); | |
113 } | |
114 | |
115 if (format.all) { | |
116 pending.add(call(SUPPORT_FORMAT_ALL, id)); | |
117 } else { | |
118 if (format.ar) pending.add(call(SUPPORT_FORMAT_AR, id)); | |
119 if (format.cpio) pending.add(call(SUPPORT_FORMAT_CPIO, id)); | |
120 if (format.empty) pending.add(call(SUPPORT_FORMAT_EMPTY, id)); | |
121 if (format.iso9660) pending.add(call(SUPPORT_FORMAT_ISO9660, id)); | |
122 if (format.mtree) pending.add(call(SUPPORT_FORMAT_MTREE, id)); | |
123 if (format.raw) pending.add(call(SUPPORT_FORMAT_RAW, id)); | |
124 if (format.tar) pending.add(call(SUPPORT_FORMAT_TAR, id)); | |
125 if (format.zip) pending.add(call(SUPPORT_FORMAT_ZIP, id)); | |
126 } | |
127 | |
128 void addOption(request, option) { | |
129 var value; | |
130 if (option.value == false || option.value == null) { | |
131 value = null; | |
132 } else if (option.value == true) { | |
133 value = '1'; | |
134 } else { | |
135 value = option.value.toString(); | |
136 } | |
137 | |
138 pending.add(CALL(request, id, [module, option.name, value])); | |
139 }; | |
140 | |
141 for (var option in filter.options.all) { | |
142 addOption(SET_FILTER_OPTION, option); | |
143 } | |
144 | |
145 for (var option in format.options.all) { | |
146 addOption(SET_FORMAT_OPTION, option); | |
147 } | |
148 | |
149 for (var option in options.all) { | |
150 addOption(SET_OPTION, option); | |
151 } | |
152 | |
153 return Future.wait(pending); | |
154 } | |
155 } | |
156 | |
157 /** | |
158 * The configuration for the filter(s) to use when decompressing the contents | |
159 * of an archive. The precise compression used is auto-detected from among all | |
160 * enabled options. | |
161 */ | |
162 class Filter { | |
163 /** | |
164 * Auto-detect among all possible filters. If this is set, all other filter | |
165 * flags are ignored. [program] takes precedence over this. | |
166 */ | |
167 bool all = false; | |
168 | |
169 /** | |
170 * Enable [bzip2][wp] compression. | |
171 * | |
172 * [wp]: http://en.wikipedia.org/wiki/Bzip2 | |
173 */ | |
174 bool bzip2 = false; | |
175 | |
176 /** | |
177 * Enable the compression used by [the `compress` utility][wp]. | |
178 * | |
179 * [wp]: http://en.wikipedia.org/wiki/Compress | |
180 */ | |
181 bool compress = false; | |
182 | |
183 /** | |
184 * Enable [gzip][wp] compression. | |
185 * | |
186 * [wp]: http://en.wikipedia.org/wiki/Gzip | |
187 */ | |
188 bool gzip = false; | |
189 | |
190 /** | |
191 * Enable [lzma][wp] compression. | |
192 * | |
193 * [wp]: http://en.wikipedia.org/wiki/Lzma | |
194 */ | |
195 bool lzma = false; | |
196 | |
197 /** | |
198 * Enable [xz][wp] compression. | |
199 * | |
200 * [wp]: http://en.wikipedia.org/wiki/Xz | |
201 */ | |
202 bool xz = false; | |
203 | |
204 /** | |
205 * Compress using the command-line program `program`. If this is specified and | |
206 * [programSignature] is not, all other filter flags are ignored. This takes | |
207 * precedence over [all]. | |
208 */ | |
209 String program; | |
210 | |
211 // TODO(nweiz): allow multiple programs with signatures to be specified. | |
212 /** | |
213 * If set, `program` will be applied only to files whose initial bytes match | |
214 * [programSignature]. | |
215 */ | |
216 List<int> programSignature; | |
217 | |
218 /** | |
219 * Options for individual filters. See [the libarchive documentation][wiki] | |
220 * for a list of available options. | |
221 * | |
222 * [wiki]: https://github.com/libarchive/libarchive/wiki/ManPageArchiveReadSet
Options3 | |
223 */ | |
224 final ArchiveOptions options; | |
225 | |
226 Filter._() : options = new ArchiveOptions(); | |
227 } | |
228 | |
229 /** | |
230 * The configuration for the archive format(s) to look for when extracting the | |
231 * contents of an archive. The format used is auto-detected from among all | |
232 * enabled options. | |
233 */ | |
234 class Format { | |
235 /** | |
236 * Auto-detect among all possible formats. If this is set, all other format | |
237 * flags are ignored. | |
238 */ | |
239 bool all = false; | |
240 | |
241 /** | |
242 * Enable the [ar][wp] format. | |
243 * | |
244 * [wp]: http://en.wikipedia.org/wiki/Ar_(Unix) | |
245 */ | |
246 bool ar = false; | |
247 | |
248 /** | |
249 * Enable the [cpio][wp] format. | |
250 * | |
251 * [wp]: http://en.wikipedia.org/wiki/Cpio | |
252 */ | |
253 bool cpio = false; | |
254 | |
255 /** Enable treating empty files as archives with no entries. */ | |
256 bool empty = false; | |
257 | |
258 /** | |
259 * Enable the [ISO 9660][wp] format. | |
260 * | |
261 * [wp]: http://en.wikipedia.org/wiki/ISO_9660 | |
262 */ | |
263 bool iso9660 = false; | |
264 | |
265 /** | |
266 * Enable the [mtree][wiki] format. | |
267 * | |
268 * [wiki]: https://github.com/libarchive/libarchive/wiki/ManPageMtree5 | |
269 */ | |
270 bool mtree = false; | |
271 | |
272 /** Enable treating unknown files as archives containing a single file. */ | |
273 bool raw = false; | |
274 | |
275 /** | |
276 * Enable the [tar][wp] format. | |
277 * | |
278 * [wp]: http://en.wikipedia.org/wiki/Tar_(file_format) | |
279 */ | |
280 bool tar = false; | |
281 | |
282 /** | |
283 * Enable the [zip][wp] format. | |
284 * | |
285 * [wp]: http://en.wikipedia.org/wiki/ZIP_(file_format) | |
286 */ | |
287 bool zip = false; | |
288 | |
289 | |
290 /** | |
291 * Options for individual formats. See [the libarchive documentation][wiki] | |
292 * for a list of available options. | |
293 * | |
294 * [wiki]: https://github.com/libarchive/libarchive/wiki/ManPageArchiveReadSet
Options3 | |
295 */ | |
296 final ArchiveOptions options; | |
297 | |
298 Format._() : options = new ArchiveOptions(); | |
299 } | |
OLD | NEW |