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