Line data Source code
1 : /* SPDX-License-Identifier: LGPL-2.1+ */
2 :
3 : #include "import-compress.h"
4 : #include "string-table.h"
5 : #include "util.h"
6 :
7 0 : void import_compress_free(ImportCompress *c) {
8 0 : assert(c);
9 :
10 0 : if (c->type == IMPORT_COMPRESS_XZ)
11 0 : lzma_end(&c->xz);
12 0 : else if (c->type == IMPORT_COMPRESS_GZIP) {
13 0 : if (c->encoding)
14 0 : deflateEnd(&c->gzip);
15 : else
16 0 : inflateEnd(&c->gzip);
17 : #if HAVE_BZIP2
18 0 : } else if (c->type == IMPORT_COMPRESS_BZIP2) {
19 0 : if (c->encoding)
20 0 : BZ2_bzCompressEnd(&c->bzip2);
21 : else
22 0 : BZ2_bzDecompressEnd(&c->bzip2);
23 : #endif
24 : }
25 :
26 0 : c->type = IMPORT_COMPRESS_UNKNOWN;
27 0 : }
28 :
29 0 : int import_uncompress_detect(ImportCompress *c, const void *data, size_t size) {
30 : static const uint8_t xz_signature[] = {
31 : 0xfd, '7', 'z', 'X', 'Z', 0x00
32 : };
33 : static const uint8_t gzip_signature[] = {
34 : 0x1f, 0x8b
35 : };
36 : static const uint8_t bzip2_signature[] = {
37 : 'B', 'Z', 'h'
38 : };
39 :
40 : int r;
41 :
42 0 : assert(c);
43 :
44 0 : if (c->type != IMPORT_COMPRESS_UNKNOWN)
45 0 : return 1;
46 :
47 0 : if (size < MAX3(sizeof(xz_signature),
48 : sizeof(gzip_signature),
49 : sizeof(bzip2_signature)))
50 0 : return 0;
51 :
52 0 : assert(data);
53 :
54 0 : if (memcmp(data, xz_signature, sizeof(xz_signature)) == 0) {
55 : lzma_ret xzr;
56 :
57 0 : xzr = lzma_stream_decoder(&c->xz, UINT64_MAX, LZMA_TELL_UNSUPPORTED_CHECK | LZMA_CONCATENATED);
58 0 : if (xzr != LZMA_OK)
59 0 : return -EIO;
60 :
61 0 : c->type = IMPORT_COMPRESS_XZ;
62 :
63 0 : } else if (memcmp(data, gzip_signature, sizeof(gzip_signature)) == 0) {
64 0 : r = inflateInit2(&c->gzip, 15+16);
65 0 : if (r != Z_OK)
66 0 : return -EIO;
67 :
68 0 : c->type = IMPORT_COMPRESS_GZIP;
69 :
70 : #if HAVE_BZIP2
71 0 : } else if (memcmp(data, bzip2_signature, sizeof(bzip2_signature)) == 0) {
72 0 : r = BZ2_bzDecompressInit(&c->bzip2, 0, 0);
73 0 : if (r != BZ_OK)
74 0 : return -EIO;
75 :
76 0 : c->type = IMPORT_COMPRESS_BZIP2;
77 : #endif
78 : } else
79 0 : c->type = IMPORT_COMPRESS_UNCOMPRESSED;
80 :
81 0 : c->encoding = false;
82 :
83 0 : return 1;
84 : }
85 :
86 0 : int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCompressCallback callback, void *userdata) {
87 : int r;
88 :
89 0 : assert(c);
90 0 : assert(callback);
91 :
92 0 : r = import_uncompress_detect(c, data, size);
93 0 : if (r <= 0)
94 0 : return r;
95 :
96 0 : if (c->encoding)
97 0 : return -EINVAL;
98 :
99 0 : if (size <= 0)
100 0 : return 1;
101 :
102 0 : assert(data);
103 :
104 0 : switch (c->type) {
105 :
106 0 : case IMPORT_COMPRESS_UNCOMPRESSED:
107 0 : r = callback(data, size, userdata);
108 0 : if (r < 0)
109 0 : return r;
110 :
111 0 : break;
112 :
113 0 : case IMPORT_COMPRESS_XZ:
114 0 : c->xz.next_in = data;
115 0 : c->xz.avail_in = size;
116 :
117 0 : while (c->xz.avail_in > 0) {
118 : uint8_t buffer[16 * 1024];
119 : lzma_ret lzr;
120 :
121 0 : c->xz.next_out = buffer;
122 0 : c->xz.avail_out = sizeof(buffer);
123 :
124 0 : lzr = lzma_code(&c->xz, LZMA_RUN);
125 0 : if (!IN_SET(lzr, LZMA_OK, LZMA_STREAM_END))
126 0 : return -EIO;
127 :
128 0 : r = callback(buffer, sizeof(buffer) - c->xz.avail_out, userdata);
129 0 : if (r < 0)
130 0 : return r;
131 : }
132 :
133 0 : break;
134 :
135 0 : case IMPORT_COMPRESS_GZIP:
136 0 : c->gzip.next_in = (void*) data;
137 0 : c->gzip.avail_in = size;
138 :
139 0 : while (c->gzip.avail_in > 0) {
140 : uint8_t buffer[16 * 1024];
141 :
142 0 : c->gzip.next_out = buffer;
143 0 : c->gzip.avail_out = sizeof(buffer);
144 :
145 0 : r = inflate(&c->gzip, Z_NO_FLUSH);
146 0 : if (!IN_SET(r, Z_OK, Z_STREAM_END))
147 0 : return -EIO;
148 :
149 0 : r = callback(buffer, sizeof(buffer) - c->gzip.avail_out, userdata);
150 0 : if (r < 0)
151 0 : return r;
152 : }
153 :
154 0 : break;
155 :
156 : #if HAVE_BZIP2
157 0 : case IMPORT_COMPRESS_BZIP2:
158 0 : c->bzip2.next_in = (void*) data;
159 0 : c->bzip2.avail_in = size;
160 :
161 0 : while (c->bzip2.avail_in > 0) {
162 : uint8_t buffer[16 * 1024];
163 :
164 0 : c->bzip2.next_out = (char*) buffer;
165 0 : c->bzip2.avail_out = sizeof(buffer);
166 :
167 0 : r = BZ2_bzDecompress(&c->bzip2);
168 0 : if (!IN_SET(r, BZ_OK, BZ_STREAM_END))
169 0 : return -EIO;
170 :
171 0 : r = callback(buffer, sizeof(buffer) - c->bzip2.avail_out, userdata);
172 0 : if (r < 0)
173 0 : return r;
174 : }
175 :
176 0 : break;
177 : #endif
178 :
179 0 : default:
180 0 : assert_not_reached("Unknown compression");
181 : }
182 :
183 0 : return 1;
184 : }
185 :
186 0 : int import_compress_init(ImportCompress *c, ImportCompressType t) {
187 : int r;
188 :
189 0 : assert(c);
190 :
191 0 : switch (t) {
192 :
193 0 : case IMPORT_COMPRESS_XZ: {
194 : lzma_ret xzr;
195 :
196 0 : xzr = lzma_easy_encoder(&c->xz, LZMA_PRESET_DEFAULT, LZMA_CHECK_CRC64);
197 0 : if (xzr != LZMA_OK)
198 0 : return -EIO;
199 :
200 0 : c->type = IMPORT_COMPRESS_XZ;
201 0 : break;
202 : }
203 :
204 0 : case IMPORT_COMPRESS_GZIP:
205 0 : r = deflateInit2(&c->gzip, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY);
206 0 : if (r != Z_OK)
207 0 : return -EIO;
208 :
209 0 : c->type = IMPORT_COMPRESS_GZIP;
210 0 : break;
211 :
212 : #if HAVE_BZIP2
213 0 : case IMPORT_COMPRESS_BZIP2:
214 0 : r = BZ2_bzCompressInit(&c->bzip2, 9, 0, 0);
215 0 : if (r != BZ_OK)
216 0 : return -EIO;
217 :
218 0 : c->type = IMPORT_COMPRESS_BZIP2;
219 0 : break;
220 : #endif
221 :
222 0 : case IMPORT_COMPRESS_UNCOMPRESSED:
223 0 : c->type = IMPORT_COMPRESS_UNCOMPRESSED;
224 0 : break;
225 :
226 0 : default:
227 0 : return -EOPNOTSUPP;
228 : }
229 :
230 0 : c->encoding = true;
231 0 : return 0;
232 : }
233 :
234 0 : static int enlarge_buffer(void **buffer, size_t *buffer_size, size_t *buffer_allocated) {
235 : size_t l;
236 : void *p;
237 :
238 0 : if (*buffer_allocated > *buffer_size)
239 0 : return 0;
240 :
241 0 : l = MAX(16*1024U, (*buffer_size * 2));
242 0 : p = realloc(*buffer, l);
243 0 : if (!p)
244 0 : return -ENOMEM;
245 :
246 0 : *buffer = p;
247 0 : *buffer_allocated = l;
248 :
249 0 : return 1;
250 : }
251 :
252 0 : int import_compress(ImportCompress *c, const void *data, size_t size, void **buffer, size_t *buffer_size, size_t *buffer_allocated) {
253 : int r;
254 :
255 0 : assert(c);
256 0 : assert(buffer);
257 0 : assert(buffer_size);
258 0 : assert(buffer_allocated);
259 :
260 0 : if (!c->encoding)
261 0 : return -EINVAL;
262 :
263 0 : if (size <= 0)
264 0 : return 0;
265 :
266 0 : assert(data);
267 :
268 0 : *buffer_size = 0;
269 :
270 0 : switch (c->type) {
271 :
272 0 : case IMPORT_COMPRESS_XZ:
273 :
274 0 : c->xz.next_in = data;
275 0 : c->xz.avail_in = size;
276 :
277 0 : while (c->xz.avail_in > 0) {
278 : lzma_ret lzr;
279 :
280 0 : r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
281 0 : if (r < 0)
282 0 : return r;
283 :
284 0 : c->xz.next_out = (uint8_t*) *buffer + *buffer_size;
285 0 : c->xz.avail_out = *buffer_allocated - *buffer_size;
286 :
287 0 : lzr = lzma_code(&c->xz, LZMA_RUN);
288 0 : if (lzr != LZMA_OK)
289 0 : return -EIO;
290 :
291 0 : *buffer_size += (*buffer_allocated - *buffer_size) - c->xz.avail_out;
292 : }
293 :
294 0 : break;
295 :
296 0 : case IMPORT_COMPRESS_GZIP:
297 :
298 0 : c->gzip.next_in = (void*) data;
299 0 : c->gzip.avail_in = size;
300 :
301 0 : while (c->gzip.avail_in > 0) {
302 0 : r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
303 0 : if (r < 0)
304 0 : return r;
305 :
306 0 : c->gzip.next_out = (uint8_t*) *buffer + *buffer_size;
307 0 : c->gzip.avail_out = *buffer_allocated - *buffer_size;
308 :
309 0 : r = deflate(&c->gzip, Z_NO_FLUSH);
310 0 : if (r != Z_OK)
311 0 : return -EIO;
312 :
313 0 : *buffer_size += (*buffer_allocated - *buffer_size) - c->gzip.avail_out;
314 : }
315 :
316 0 : break;
317 :
318 : #if HAVE_BZIP2
319 0 : case IMPORT_COMPRESS_BZIP2:
320 :
321 0 : c->bzip2.next_in = (void*) data;
322 0 : c->bzip2.avail_in = size;
323 :
324 0 : while (c->bzip2.avail_in > 0) {
325 0 : r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
326 0 : if (r < 0)
327 0 : return r;
328 :
329 0 : c->bzip2.next_out = (void*) ((uint8_t*) *buffer + *buffer_size);
330 0 : c->bzip2.avail_out = *buffer_allocated - *buffer_size;
331 :
332 0 : r = BZ2_bzCompress(&c->bzip2, BZ_RUN);
333 0 : if (r != BZ_RUN_OK)
334 0 : return -EIO;
335 :
336 0 : *buffer_size += (*buffer_allocated - *buffer_size) - c->bzip2.avail_out;
337 : }
338 :
339 0 : break;
340 : #endif
341 :
342 0 : case IMPORT_COMPRESS_UNCOMPRESSED:
343 :
344 0 : if (*buffer_allocated < size) {
345 : void *p;
346 :
347 0 : p = realloc(*buffer, size);
348 0 : if (!p)
349 0 : return -ENOMEM;
350 :
351 0 : *buffer = p;
352 0 : *buffer_allocated = size;
353 : }
354 :
355 0 : memcpy(*buffer, data, size);
356 0 : *buffer_size = size;
357 0 : break;
358 :
359 0 : default:
360 0 : return -EOPNOTSUPP;
361 : }
362 :
363 0 : return 0;
364 : }
365 :
366 0 : int import_compress_finish(ImportCompress *c, void **buffer, size_t *buffer_size, size_t *buffer_allocated) {
367 : int r;
368 :
369 0 : assert(c);
370 0 : assert(buffer);
371 0 : assert(buffer_size);
372 0 : assert(buffer_allocated);
373 :
374 0 : if (!c->encoding)
375 0 : return -EINVAL;
376 :
377 0 : *buffer_size = 0;
378 :
379 0 : switch (c->type) {
380 :
381 0 : case IMPORT_COMPRESS_XZ: {
382 : lzma_ret lzr;
383 :
384 0 : c->xz.avail_in = 0;
385 :
386 : do {
387 0 : r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
388 0 : if (r < 0)
389 0 : return r;
390 :
391 0 : c->xz.next_out = (uint8_t*) *buffer + *buffer_size;
392 0 : c->xz.avail_out = *buffer_allocated - *buffer_size;
393 :
394 0 : lzr = lzma_code(&c->xz, LZMA_FINISH);
395 0 : if (!IN_SET(lzr, LZMA_OK, LZMA_STREAM_END))
396 0 : return -EIO;
397 :
398 0 : *buffer_size += (*buffer_allocated - *buffer_size) - c->xz.avail_out;
399 0 : } while (lzr != LZMA_STREAM_END);
400 :
401 0 : break;
402 : }
403 :
404 0 : case IMPORT_COMPRESS_GZIP:
405 0 : c->gzip.avail_in = 0;
406 :
407 : do {
408 0 : r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
409 0 : if (r < 0)
410 0 : return r;
411 :
412 0 : c->gzip.next_out = (uint8_t*) *buffer + *buffer_size;
413 0 : c->gzip.avail_out = *buffer_allocated - *buffer_size;
414 :
415 0 : r = deflate(&c->gzip, Z_FINISH);
416 0 : if (!IN_SET(r, Z_OK, Z_STREAM_END))
417 0 : return -EIO;
418 :
419 0 : *buffer_size += (*buffer_allocated - *buffer_size) - c->gzip.avail_out;
420 0 : } while (r != Z_STREAM_END);
421 :
422 0 : break;
423 :
424 : #if HAVE_BZIP2
425 0 : case IMPORT_COMPRESS_BZIP2:
426 0 : c->bzip2.avail_in = 0;
427 :
428 : do {
429 0 : r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
430 0 : if (r < 0)
431 0 : return r;
432 :
433 0 : c->bzip2.next_out = (void*) ((uint8_t*) *buffer + *buffer_size);
434 0 : c->bzip2.avail_out = *buffer_allocated - *buffer_size;
435 :
436 0 : r = BZ2_bzCompress(&c->bzip2, BZ_FINISH);
437 0 : if (!IN_SET(r, BZ_FINISH_OK, BZ_STREAM_END))
438 0 : return -EIO;
439 :
440 0 : *buffer_size += (*buffer_allocated - *buffer_size) - c->bzip2.avail_out;
441 0 : } while (r != BZ_STREAM_END);
442 :
443 0 : break;
444 : #endif
445 :
446 0 : case IMPORT_COMPRESS_UNCOMPRESSED:
447 0 : break;
448 :
449 0 : default:
450 0 : return -EOPNOTSUPP;
451 : }
452 :
453 0 : return 0;
454 : }
455 :
456 : static const char* const import_compress_type_table[_IMPORT_COMPRESS_TYPE_MAX] = {
457 : [IMPORT_COMPRESS_UNKNOWN] = "unknown",
458 : [IMPORT_COMPRESS_UNCOMPRESSED] = "uncompressed",
459 : [IMPORT_COMPRESS_XZ] = "xz",
460 : [IMPORT_COMPRESS_GZIP] = "gzip",
461 : #if HAVE_BZIP2
462 : [IMPORT_COMPRESS_BZIP2] = "bzip2",
463 : #endif
464 : };
465 :
466 0 : DEFINE_STRING_TABLE_LOOKUP(import_compress_type, ImportCompressType);
|