1 /* Copyright 2015 the unarr project authors (see AUTHORS file).
2 License: LGPLv3 */
3
4 #include "zip.h"
5
6 #define ERR_UNCOMP UINT32_MAX
7
zip_fill_input_buffer(ar_archive_zip * zip)8 static bool zip_fill_input_buffer(ar_archive_zip *zip)
9 {
10 struct ar_archive_zip_uncomp *uncomp = &zip->uncomp;
11 size_t count;
12
13 if (uncomp->input.offset) {
14 memmove(&uncomp->input.data[0], &uncomp->input.data[uncomp->input.offset], uncomp->input.bytes_left);
15 uncomp->input.offset = 0;
16 }
17 count = sizeof(uncomp->input.data) - uncomp->input.bytes_left;
18 if (count > zip->progress.data_left)
19 count = zip->progress.data_left;
20 if (ar_read(zip->super.stream, &uncomp->input.data[uncomp->input.bytes_left], count) != count) {
21 warn("Unexpected EOF during decompression (invalid data size?)");
22 return false;
23 }
24 zip->progress.data_left -= count;
25 uncomp->input.bytes_left += (uint16_t)count;
26 uncomp->input.at_eof = !zip->progress.data_left;
27
28 return true;
29 }
30
31 /***** Deflate compression *****/
32
33 #ifdef HAVE_ZLIB
gZlib_Alloc(void * opaque,uInt count,uInt size)34 static void *gZlib_Alloc(void *opaque, uInt count, uInt size) { (void)opaque; return calloc(count, size); }
gZlib_Free(void * opaque,void * ptr)35 static void gZlib_Free(void *opaque, void *ptr) { (void)opaque; free(ptr); }
36
zip_init_uncompress_deflate(struct ar_archive_zip_uncomp * uncomp)37 static bool zip_init_uncompress_deflate(struct ar_archive_zip_uncomp *uncomp)
38 {
39 int err;
40
41 uncomp->state.zstream.zalloc = gZlib_Alloc;
42 uncomp->state.zstream.zfree = gZlib_Free;
43 uncomp->state.zstream.opaque = NULL;
44
45 err = inflateInit2(&uncomp->state.zstream, -15);
46 return err == Z_OK;
47 }
48
zip_uncompress_data_deflate(struct ar_archive_zip_uncomp * uncomp,void * buffer,uint32_t buffer_size,bool is_last_chunk)49 static uint32_t zip_uncompress_data_deflate(struct ar_archive_zip_uncomp *uncomp, void *buffer, uint32_t buffer_size, bool is_last_chunk)
50 {
51 int err;
52
53 uncomp->state.zstream.next_in = &uncomp->input.data[uncomp->input.offset];
54 uncomp->state.zstream.avail_in = uncomp->input.bytes_left;
55 uncomp->state.zstream.next_out = buffer;
56 uncomp->state.zstream.avail_out = buffer_size;
57
58 err = inflate(&uncomp->state.zstream, Z_SYNC_FLUSH);
59
60 uncomp->input.offset += uncomp->input.bytes_left - (uint16_t)uncomp->state.zstream.avail_in;
61 uncomp->input.bytes_left = (uint16_t)uncomp->state.zstream.avail_in;
62
63 if (err != Z_OK && err != Z_STREAM_END) {
64 warn("Unexpected ZLIB error %d", err);
65 return ERR_UNCOMP;
66 }
67 if (err == Z_STREAM_END && (!is_last_chunk || uncomp->state.zstream.avail_out)) {
68 warn("Premature EOS in Deflate stream");
69 return ERR_UNCOMP;
70 }
71
72 return buffer_size - uncomp->state.zstream.avail_out;
73 }
74
zip_clear_uncompress_deflate(struct ar_archive_zip_uncomp * uncomp)75 static void zip_clear_uncompress_deflate(struct ar_archive_zip_uncomp *uncomp)
76 {
77 inflateEnd(&uncomp->state.zstream);
78 }
79 #endif
80
81 /***** Deflate(64) compression *****/
82
zip_init_uncompress_deflate64(struct ar_archive_zip_uncomp * uncomp,bool deflate64)83 static bool zip_init_uncompress_deflate64(struct ar_archive_zip_uncomp *uncomp, bool deflate64)
84 {
85 uncomp->state.inflate = inflate_create(deflate64);
86
87 return uncomp->state.inflate != NULL;
88 }
89
zip_uncompress_data_deflate64(struct ar_archive_zip_uncomp * uncomp,void * buffer,uint32_t buffer_size,bool is_last_chunk)90 static uint32_t zip_uncompress_data_deflate64(struct ar_archive_zip_uncomp *uncomp, void *buffer, uint32_t buffer_size, bool is_last_chunk)
91 {
92 size_t avail_in = uncomp->input.bytes_left;
93 size_t avail_out = buffer_size;
94
95 int result = inflate_process(uncomp->state.inflate, &uncomp->input.data[uncomp->input.offset], &avail_in, buffer, &avail_out);
96
97 uncomp->input.offset += uncomp->input.bytes_left - (uint16_t)avail_in;
98 uncomp->input.bytes_left = (uint16_t)avail_in;
99
100 if (result && result != EOF) {
101 warn("Unexpected Inflate error %d", result);
102 return ERR_UNCOMP;
103 }
104 if (result == EOF && (!is_last_chunk || avail_out)) {
105 warn("Premature EOS in Deflate stream");
106 return ERR_UNCOMP;
107 }
108
109 return buffer_size - (uint32_t)avail_out;
110 }
111
zip_clear_uncompress_deflate64(struct ar_archive_zip_uncomp * uncomp)112 static void zip_clear_uncompress_deflate64(struct ar_archive_zip_uncomp *uncomp)
113 {
114 inflate_free(uncomp->state.inflate);
115 }
116
117 /***** BZIP2 compression *****/
118
119 #ifdef HAVE_BZIP2
gBzip2_Alloc(void * opaque,int count,int size)120 static void *gBzip2_Alloc(void *opaque, int count, int size) { (void)opaque; return calloc(count, size); }
gBzip2_Free(void * opaque,void * ptr)121 static void gBzip2_Free(void *opaque, void *ptr) { (void)opaque; free(ptr); }
122
zip_init_uncompress_bzip2(struct ar_archive_zip_uncomp * uncomp)123 static bool zip_init_uncompress_bzip2(struct ar_archive_zip_uncomp *uncomp)
124 {
125 int err;
126
127 uncomp->state.bstream.bzalloc = gBzip2_Alloc;
128 uncomp->state.bstream.bzfree = gBzip2_Free;
129 uncomp->state.bstream.opaque = NULL;
130
131 err = BZ2_bzDecompressInit(&uncomp->state.bstream, 0, 0);
132 return err == BZ_OK;
133 }
134
zip_uncompress_data_bzip2(struct ar_archive_zip_uncomp * uncomp,void * buffer,uint32_t buffer_size,bool is_last_chunk)135 static uint32_t zip_uncompress_data_bzip2(struct ar_archive_zip_uncomp *uncomp, void *buffer, uint32_t buffer_size, bool is_last_chunk)
136 {
137 int err;
138
139 uncomp->state.bstream.next_in = (char *)&uncomp->input.data[uncomp->input.offset];
140 uncomp->state.bstream.avail_in = uncomp->input.bytes_left;
141 uncomp->state.bstream.next_out = (char *)buffer;
142 uncomp->state.bstream.avail_out = buffer_size;
143
144 err = BZ2_bzDecompress(&uncomp->state.bstream);
145
146 uncomp->input.offset += uncomp->input.bytes_left - (uint16_t)uncomp->state.bstream.avail_in;
147 uncomp->input.bytes_left = (uint16_t)uncomp->state.bstream.avail_in;
148
149 if (err != BZ_OK && err != BZ_STREAM_END) {
150 warn("Unexpected BZIP2 error %d", err);
151 return ERR_UNCOMP;
152 }
153 if (err == BZ_STREAM_END && (!is_last_chunk || uncomp->state.bstream.avail_out)) {
154 warn("Premature EOS in BZIP2 stream");
155 return ERR_UNCOMP;
156 }
157
158 return buffer_size - uncomp->state.bstream.avail_out;
159 }
160
zip_clear_uncompress_bzip2(struct ar_archive_zip_uncomp * uncomp)161 static void zip_clear_uncompress_bzip2(struct ar_archive_zip_uncomp *uncomp)
162 {
163 BZ2_bzDecompressEnd(&uncomp->state.bstream);
164 }
165 #endif
166
167 /***** LZMA compression *****/
168
169 #ifdef HAVE_LIBLZMA
170
gLzma_Alloc(void * opaque,size_t nmemb,size_t size)171 static void *gLzma_Alloc(void *opaque, size_t nmemb, size_t size)
172 { (void)opaque; (void) nmemb; return malloc(size); }
gLzma_Free(void * opaque,void * ptr)173 static void gLzma_Free(void *opaque, void *ptr)
174 { (void)opaque; free(ptr); }
175
zip_init_uncompress_lzma(struct ar_archive_zip_uncomp * uncomp)176 static bool zip_init_uncompress_lzma(struct ar_archive_zip_uncomp *uncomp)
177 {
178 lzma_stream strm = LZMA_STREAM_INIT;
179 uncomp->state.lzmastream = strm;
180 static const lzma_allocator allocator = { gLzma_Alloc, gLzma_Free, NULL };
181 uncomp->state.lzmastream.allocator = &allocator;
182 return true;
183 }
184
zip_uncompress_data_lzma1(struct ar_archive_zip_uncomp * uncomp,void * buffer,uint32_t buffer_size,bool is_last_chunk)185 static uint32_t zip_uncompress_data_lzma1(struct ar_archive_zip_uncomp *uncomp, void *buffer, uint32_t buffer_size, bool is_last_chunk)
186 {
187 int err;
188
189 if (uncomp->state.lzmastream.internal == NULL) {
190 uint8_t propsize;
191 propsize = uncomp->input.data[uncomp->input.offset + 2];
192
193 lzma_filter filters[2] = {{.id=LZMA_FILTER_LZMA1, .options=NULL},
194 {.id=LZMA_VLI_UNKNOWN, .options=NULL}};
195
196 err = lzma_properties_decode(
197 &filters[0], NULL,
198 &uncomp->input.data[uncomp->input.offset + 4], propsize);
199
200 if (err != LZMA_OK) {
201 warn("Properties error %d", err);
202 return ERR_UNCOMP;
203 }
204
205 err = lzma_raw_decoder(&uncomp->state.lzmastream, filters);
206 free(filters[0].options);
207 if (err != LZMA_OK) {
208 warn("Decoder init error %d", err);
209 return ERR_UNCOMP;
210 }
211 uncomp->input.offset += 4 + propsize;
212 uncomp->input.bytes_left -= 4 + propsize;
213 }
214
215 uncomp->state.lzmastream.next_in = &uncomp->input.data[uncomp->input.offset];
216 uncomp->state.lzmastream.avail_in = uncomp->input.bytes_left;
217 uncomp->state.lzmastream.next_out = buffer;
218 uncomp->state.lzmastream.avail_out = buffer_size;
219
220 err = lzma_code(&uncomp->state.lzmastream, LZMA_RUN);
221
222 uncomp->input.offset += (uint16_t)uncomp->input.bytes_left - (uint16_t)uncomp->state.lzmastream.avail_in;
223 uncomp->input.bytes_left = (uint16_t)uncomp->state.lzmastream.avail_in;
224
225 if (err != LZMA_OK && err != LZMA_STREAM_END) {
226 warn("Unexpected LZMA error %d", err);
227 warn("%d", buffer_size - uncomp->state.lzmastream.avail_out);
228 return ERR_UNCOMP;
229 }
230 if (err == LZMA_STREAM_END && (!is_last_chunk || uncomp->state.lzmastream.avail_out)) {
231 warn("Premature EOS in LZMA stream");
232 return ERR_UNCOMP;
233 }
234 return buffer_size - uncomp->state.lzmastream.avail_out;
235 }
236
zip_uncompress_data_xz(struct ar_archive_zip_uncomp * uncomp,void * buffer,uint32_t buffer_size,bool is_last_chunk)237 static uint32_t zip_uncompress_data_xz(struct ar_archive_zip_uncomp *uncomp, void *buffer, uint32_t buffer_size, bool is_last_chunk)
238 {
239 int err;
240
241 if (uncomp->state.lzmastream.internal == NULL) {
242 /* restrict decoder memory usage to 100 MB */
243 err = lzma_stream_decoder(&uncomp->state.lzmastream, 100 << 20, 0);
244 if (err != LZMA_OK) {
245 warn("Unexpected LZMA Decoder init error %d", err);
246 return ERR_UNCOMP;
247 }
248 }
249
250 uncomp->state.lzmastream.next_in = &uncomp->input.data[uncomp->input.offset];
251 uncomp->state.lzmastream.avail_in = uncomp->input.bytes_left;
252 uncomp->state.lzmastream.next_out = buffer;
253 uncomp->state.lzmastream.avail_out = buffer_size;
254
255 err = lzma_code(&uncomp->state.lzmastream, LZMA_RUN);
256
257 uncomp->input.offset += (uint16_t)uncomp->input.bytes_left - (uint16_t)uncomp->state.lzmastream.avail_in;
258 uncomp->input.bytes_left = (uint16_t)uncomp->state.lzmastream.avail_in;
259
260 if (err != LZMA_OK && err != LZMA_STREAM_END) {
261 warn("Unexpected XZ error %d", err);
262 warn("%d", buffer_size - uncomp->state.lzmastream.avail_out);
263 return ERR_UNCOMP;
264 }
265 if (err == LZMA_STREAM_END && (!is_last_chunk || uncomp->state.lzmastream.avail_out)) {
266 warn("Premature EOS in XZ stream");
267 return ERR_UNCOMP;
268 }
269 return buffer_size - uncomp->state.lzmastream.avail_out;
270 }
271
272
zip_clear_uncompress_lzma(struct ar_archive_zip_uncomp * uncomp)273 static void zip_clear_uncompress_lzma(struct ar_archive_zip_uncomp *uncomp)
274 {
275 lzma_end(&uncomp->state.lzmastream);
276 }
277
278 #else //HAVE_LIBLZMA
279
gLzma_Alloc(ISzAllocPtr self,size_t size)280 static void *gLzma_Alloc(ISzAllocPtr self, size_t size) { (void)self; return malloc(size); }
gLzma_Free(ISzAllocPtr self,void * ptr)281 static void gLzma_Free(ISzAllocPtr self, void *ptr) { (void)self; free(ptr); }
282
zip_init_uncompress_lzma(struct ar_archive_zip_uncomp * uncomp,uint16_t flags)283 static bool zip_init_uncompress_lzma(struct ar_archive_zip_uncomp *uncomp, uint16_t flags)
284 {
285 uncomp->state.lzma.alloc.Alloc = gLzma_Alloc;
286 uncomp->state.lzma.alloc.Free = gLzma_Free;
287 uncomp->state.lzma.finish = (flags & (1 << 1)) ? LZMA_FINISH_END : LZMA_FINISH_ANY;
288 LzmaDec_Construct(&uncomp->state.lzma.dec);
289 return true;
290 }
291
zip_uncompress_data_lzma(struct ar_archive_zip_uncomp * uncomp,void * buffer,uint32_t buffer_size,bool is_last_chunk)292 static uint32_t zip_uncompress_data_lzma(struct ar_archive_zip_uncomp *uncomp, void *buffer, uint32_t buffer_size, bool is_last_chunk)
293 {
294 SizeT srclen, dstlen;
295 ELzmaStatus status;
296 ELzmaFinishMode finish;
297 SRes res;
298
299 if (!uncomp->state.lzma.dec.dic) {
300 uint8_t propsize;
301 if (uncomp->input.bytes_left < 9) {
302 warn("Insufficient data in compressed stream");
303 return ERR_UNCOMP;
304 }
305 propsize = uncomp->input.data[uncomp->input.offset + 2];
306 if (uncomp->input.data[uncomp->input.offset + 3] != 0 || uncomp->input.bytes_left < 4 + propsize) {
307 warn("Insufficient data in compressed stream");
308 return ERR_UNCOMP;
309 }
310 res = LzmaDec_Allocate(&uncomp->state.lzma.dec, &uncomp->input.data[uncomp->input.offset + 4], propsize, &uncomp->state.lzma.alloc);
311 uncomp->input.offset += 4 + propsize;
312 uncomp->input.bytes_left -= 4 + propsize;
313 if (res != SZ_OK)
314 return ERR_UNCOMP;
315 LzmaDec_Init(&uncomp->state.lzma.dec);
316 }
317
318 srclen = uncomp->input.bytes_left;
319 dstlen = buffer_size;
320 finish = uncomp->input.at_eof && is_last_chunk ? uncomp->state.lzma.finish : LZMA_FINISH_ANY;
321 res = LzmaDec_DecodeToBuf(&uncomp->state.lzma.dec, buffer, &dstlen, &uncomp->input.data[uncomp->input.offset], &srclen, finish, &status);
322
323 uncomp->input.offset += (uint16_t)srclen;
324 uncomp->input.bytes_left -= (uint16_t)srclen;
325
326 if (res != SZ_OK || (srclen == 0 && dstlen == 0)) {
327 warn("Unexpected LZMA error %d", res);
328 return ERR_UNCOMP;
329 }
330 if (status == LZMA_STATUS_FINISHED_WITH_MARK && (!is_last_chunk || dstlen != buffer_size)) {
331 warn("Premature EOS in LZMA stream");
332 return ERR_UNCOMP;
333 }
334
335 return (uint32_t)dstlen;
336 }
337
zip_clear_uncompress_lzma(struct ar_archive_zip_uncomp * uncomp)338 static void zip_clear_uncompress_lzma(struct ar_archive_zip_uncomp *uncomp)
339 {
340 LzmaDec_Free(&uncomp->state.lzma.dec, &uncomp->state.lzma.alloc);
341 }
342
343 #endif //HAVE_LIBLZMA
344
345 /***** PPMd compression *****/
346
gPpmd_Alloc(ISzAllocPtr self,size_t size)347 static void *gPpmd_Alloc(ISzAllocPtr self, size_t size) { (void)self; return malloc(size); }
gPpmd_Free(ISzAllocPtr self,void * ptr)348 static void gPpmd_Free(ISzAllocPtr self, void *ptr) { (void)self; free(ptr); }
349
gPpmd_ByteIn_Read(const IByteIn * p)350 static Byte gPpmd_ByteIn_Read(const IByteIn *p)
351 {
352 struct ByteReader *self = (struct ByteReader *) p;
353 if (!self->input->bytes_left && (!self->zip->progress.data_left || !zip_fill_input_buffer(self->zip)))
354 return 0xFF;
355 self->input->bytes_left--;
356 return self->input->data[self->input->offset++];
357 }
358
zip_init_uncompress_ppmd(ar_archive_zip * zip)359 static bool zip_init_uncompress_ppmd(ar_archive_zip *zip)
360 {
361 struct ar_archive_zip_uncomp *uncomp = &zip->uncomp;
362 uncomp->state.ppmd8.alloc.Alloc = gPpmd_Alloc;
363 uncomp->state.ppmd8.alloc.Free = gPpmd_Free;
364 uncomp->state.ppmd8.bytein.super.Read = gPpmd_ByteIn_Read;
365 uncomp->state.ppmd8.bytein.input = &uncomp->input;
366 uncomp->state.ppmd8.bytein.zip = zip;
367 uncomp->state.ppmd8.ctx.Stream.In = &uncomp->state.ppmd8.bytein.super;
368 Ppmd8_Construct(&uncomp->state.ppmd8.ctx);
369 return true;
370 }
371
zip_uncompress_data_ppmd(struct ar_archive_zip_uncomp * uncomp,void * buffer,uint32_t buffer_size,bool is_last_chunk)372 static uint32_t zip_uncompress_data_ppmd(struct ar_archive_zip_uncomp *uncomp, void *buffer, uint32_t buffer_size, bool is_last_chunk)
373 {
374 uint32_t bytes_done = 0;
375
376 if (!uncomp->state.ppmd8.ctx.Base) {
377 uint8_t order, size, method;
378 if (uncomp->input.bytes_left < 2) {
379 warn("Insufficient data in compressed stream");
380 return ERR_UNCOMP;
381 }
382 order = (uncomp->input.data[uncomp->input.offset] & 0x0F) + 1;
383 size = ((uncomp->input.data[uncomp->input.offset] >> 4) | ((uncomp->input.data[uncomp->input.offset + 1] << 4) & 0xFF));
384 method = uncomp->input.data[uncomp->input.offset + 1] >> 4;
385 uncomp->input.bytes_left -= 2;
386 uncomp->input.offset += 2;
387 if (order < 2 || method > 2) {
388 warn("Invalid PPMd data stream");
389 return ERR_UNCOMP;
390 }
391 #ifndef PPMD8_FREEZE_SUPPORT
392 if (order == 2) {
393 warn("PPMd freeze method isn't supported");
394 return ERR_UNCOMP;
395 }
396 #endif
397 if (!Ppmd8_Alloc(&uncomp->state.ppmd8.ctx, (size + 1) << 20, &uncomp->state.ppmd8.alloc))
398 return ERR_UNCOMP;
399 if (!Ppmd8_RangeDec_Init(&uncomp->state.ppmd8.ctx))
400 return ERR_UNCOMP;
401 Ppmd8_Init(&uncomp->state.ppmd8.ctx, order, method);
402 }
403
404 while (bytes_done < buffer_size) {
405 int symbol = Ppmd8_DecodeSymbol(&uncomp->state.ppmd8.ctx);
406 if (symbol < 0) {
407 warn("Invalid PPMd data stream");
408 return ERR_UNCOMP;
409 }
410 ((uint8_t *)buffer)[bytes_done++] = (uint8_t)symbol;
411 }
412
413 if (is_last_chunk) {
414 int symbol = Ppmd8_DecodeSymbol(&uncomp->state.ppmd8.ctx);
415 if (symbol != -1 || !Ppmd8_RangeDec_IsFinishedOK(&uncomp->state.ppmd8.ctx)) {
416 warn("Invalid PPMd data stream");
417 return ERR_UNCOMP;
418 }
419 }
420
421 return bytes_done;
422 }
423
zip_clear_uncompress_ppmd(struct ar_archive_zip_uncomp * uncomp)424 static void zip_clear_uncompress_ppmd(struct ar_archive_zip_uncomp *uncomp)
425 {
426 Ppmd8_Free(&uncomp->state.ppmd8.ctx, &uncomp->state.ppmd8.alloc);
427 }
428
429 /***** common decompression handling *****/
430
zip_init_uncompress(ar_archive_zip * zip)431 static bool zip_init_uncompress(ar_archive_zip *zip)
432 {
433 struct ar_archive_zip_uncomp *uncomp = &zip->uncomp;
434 if (uncomp->initialized)
435 return true;
436 memset(uncomp, 0, sizeof(*uncomp));
437 if (zip->entry.method == METHOD_DEFLATE) {
438 #ifdef HAVE_ZLIB
439 if (zip_init_uncompress_deflate(uncomp)) {
440 uncomp->uncompress_data = zip_uncompress_data_deflate;
441 uncomp->clear_state = zip_clear_uncompress_deflate;
442 }
443 #else
444 if (zip_init_uncompress_deflate64(uncomp, false)) {
445 uncomp->uncompress_data = zip_uncompress_data_deflate64;
446 uncomp->clear_state = zip_clear_uncompress_deflate64;
447 }
448 #endif
449 }
450 else if (zip->entry.method == METHOD_DEFLATE64) {
451 if (zip_init_uncompress_deflate64(uncomp, true)) {
452 uncomp->uncompress_data = zip_uncompress_data_deflate64;
453 uncomp->clear_state = zip_clear_uncompress_deflate64;
454 }
455 }
456 else if (zip->entry.method == METHOD_BZIP2) {
457 #ifdef HAVE_BZIP2
458 if (zip_init_uncompress_bzip2(uncomp)) {
459 uncomp->uncompress_data = zip_uncompress_data_bzip2;
460 uncomp->clear_state = zip_clear_uncompress_bzip2;
461 }
462 #else
463 warn("BZIP2 support requires BZIP2 (define HAVE_BZIP2)");
464 #endif
465 }
466 #ifdef HAVE_LIBLZMA
467 else if (zip->entry.method == METHOD_LZMA) {
468 if (zip_init_uncompress_lzma(uncomp)) {
469 uncomp->uncompress_data = zip_uncompress_data_lzma1;
470 uncomp->clear_state = zip_clear_uncompress_lzma;
471 }
472 }
473 else if (zip->entry.method == METHOD_XZ) {
474 if (zip_init_uncompress_lzma(uncomp)) {
475 uncomp->uncompress_data = zip_uncompress_data_xz;
476 uncomp->clear_state = zip_clear_uncompress_lzma;
477 }
478 }
479 #else
480 else if (zip->entry.method == METHOD_LZMA) {
481 if (zip_init_uncompress_lzma(uncomp, zip->entry.flags)) {
482 uncomp->uncompress_data = zip_uncompress_data_lzma;
483 uncomp->clear_state = zip_clear_uncompress_lzma;
484 }
485 }
486 #endif // HAVE_LIBLZMA
487 else if (zip->entry.method == METHOD_PPMD) {
488 if (zip_init_uncompress_ppmd(zip)) {
489 uncomp->uncompress_data = zip_uncompress_data_ppmd;
490 uncomp->clear_state = zip_clear_uncompress_ppmd;
491 }
492 }
493 else
494 warn("Unsupported compression method %d", zip->entry.method);
495 uncomp->initialized = uncomp->uncompress_data != NULL && uncomp->clear_state != NULL;
496 return uncomp->initialized;
497 }
498
zip_clear_uncompress(struct ar_archive_zip_uncomp * uncomp)499 void zip_clear_uncompress(struct ar_archive_zip_uncomp *uncomp)
500 {
501 if (!uncomp->initialized)
502 return;
503 uncomp->clear_state(uncomp);
504 uncomp->initialized = false;
505 }
506
zip_uncompress_part(ar_archive_zip * zip,void * buffer,size_t buffer_size)507 bool zip_uncompress_part(ar_archive_zip *zip, void *buffer, size_t buffer_size)
508 {
509 struct ar_archive_zip_uncomp *uncomp = &zip->uncomp;
510 uint32_t count;
511
512 if (!zip_init_uncompress(zip))
513 return false;
514
515 for (;;) {
516 if (buffer_size == 0)
517 return true;
518
519 if (uncomp->input.bytes_left < sizeof(uncomp->input.data) / 2 && zip->progress.data_left) {
520 if (!zip_fill_input_buffer(zip))
521 return false;
522 }
523
524 count = buffer_size >= UINT32_MAX ? UINT32_MAX - 1 : (uint32_t)buffer_size;
525 count = uncomp->uncompress_data(uncomp, buffer, count, zip->progress.bytes_done + count == zip->super.entry_size_uncompressed);
526 if (count == ERR_UNCOMP)
527 return false;
528 if (count == 0 && !zip->progress.data_left) {
529 warn("Insufficient data in compressed stream");
530 return false;
531 }
532 zip->progress.bytes_done += count;
533 buffer = (uint8_t *)buffer + count;
534 buffer_size -= count;
535 }
536 }
537