mirror of
https://github.com/SimoneN64/Kaizen.git
synced 2025-04-02 10:41:53 -04:00
540 lines
19 KiB
C
540 lines
19 KiB
C
/* Copyright 2015 the unarr project authors (see AUTHORS file).
|
|
License: LGPLv3 */
|
|
|
|
#include "zip.h"
|
|
|
|
#define ERR_UNCOMP UINT32_MAX
|
|
|
|
static bool zip_fill_input_buffer(ar_archive_zip *zip)
|
|
{
|
|
struct ar_archive_zip_uncomp *uncomp = &zip->uncomp;
|
|
size_t count;
|
|
|
|
if (uncomp->input.offset) {
|
|
memmove(&uncomp->input.data[0], &uncomp->input.data[uncomp->input.offset], uncomp->input.bytes_left);
|
|
uncomp->input.offset = 0;
|
|
}
|
|
count = sizeof(uncomp->input.data) - uncomp->input.bytes_left;
|
|
if (count > zip->progress.data_left)
|
|
count = zip->progress.data_left;
|
|
if (ar_read(zip->super.stream, &uncomp->input.data[uncomp->input.bytes_left], count) != count) {
|
|
warn("Unexpected EOF during decompression (invalid data size?)");
|
|
return false;
|
|
}
|
|
zip->progress.data_left -= count;
|
|
uncomp->input.bytes_left += (uint16_t)count;
|
|
uncomp->input.at_eof = !zip->progress.data_left;
|
|
|
|
return true;
|
|
}
|
|
|
|
/***** Deflate compression *****/
|
|
|
|
#ifdef HAVE_ZLIB
|
|
static void *gZlib_Alloc(void *opaque, uInt count, uInt size) { (void)opaque; return calloc(count, size); }
|
|
static void gZlib_Free(void *opaque, void *ptr) { (void)opaque; free(ptr); }
|
|
|
|
static bool zip_init_uncompress_deflate(struct ar_archive_zip_uncomp *uncomp)
|
|
{
|
|
int err;
|
|
|
|
uncomp->state.zstream.zalloc = gZlib_Alloc;
|
|
uncomp->state.zstream.zfree = gZlib_Free;
|
|
uncomp->state.zstream.opaque = NULL;
|
|
|
|
err = inflateInit2(&uncomp->state.zstream, -15);
|
|
return err == Z_OK;
|
|
}
|
|
|
|
static uint32_t zip_uncompress_data_deflate(struct ar_archive_zip_uncomp *uncomp, void *buffer, uint32_t buffer_size, bool is_last_chunk)
|
|
{
|
|
int err;
|
|
|
|
uncomp->state.zstream.next_in = &uncomp->input.data[uncomp->input.offset];
|
|
uncomp->state.zstream.avail_in = uncomp->input.bytes_left;
|
|
uncomp->state.zstream.next_out = buffer;
|
|
uncomp->state.zstream.avail_out = buffer_size;
|
|
|
|
err = inflate(&uncomp->state.zstream, Z_SYNC_FLUSH);
|
|
|
|
uncomp->input.offset += uncomp->input.bytes_left - (uint16_t)uncomp->state.zstream.avail_in;
|
|
uncomp->input.bytes_left = (uint16_t)uncomp->state.zstream.avail_in;
|
|
|
|
if (err != Z_OK && err != Z_STREAM_END) {
|
|
warn("Unexpected ZLIB error %d", err);
|
|
return ERR_UNCOMP;
|
|
}
|
|
if (err == Z_STREAM_END && (!is_last_chunk || uncomp->state.zstream.avail_out)) {
|
|
warn("Premature EOS in Deflate stream");
|
|
return ERR_UNCOMP;
|
|
}
|
|
|
|
return buffer_size - uncomp->state.zstream.avail_out;
|
|
}
|
|
|
|
static void zip_clear_uncompress_deflate(struct ar_archive_zip_uncomp *uncomp)
|
|
{
|
|
inflateEnd(&uncomp->state.zstream);
|
|
}
|
|
#endif
|
|
|
|
/***** Deflate(64) compression *****/
|
|
|
|
static bool zip_init_uncompress_deflate64(struct ar_archive_zip_uncomp *uncomp, bool deflate64)
|
|
{
|
|
uncomp->state.inflate = inflate_create(deflate64);
|
|
|
|
return uncomp->state.inflate != NULL;
|
|
}
|
|
|
|
static uint32_t zip_uncompress_data_deflate64(struct ar_archive_zip_uncomp *uncomp, void *buffer, uint32_t buffer_size, bool is_last_chunk)
|
|
{
|
|
size_t avail_in = uncomp->input.bytes_left;
|
|
size_t avail_out = buffer_size;
|
|
|
|
int result = inflate_process(uncomp->state.inflate, &uncomp->input.data[uncomp->input.offset], &avail_in, buffer, &avail_out);
|
|
|
|
uncomp->input.offset += uncomp->input.bytes_left - (uint16_t)avail_in;
|
|
uncomp->input.bytes_left = (uint16_t)avail_in;
|
|
|
|
if (result && result != EOF) {
|
|
warn("Unexpected Inflate error %d", result);
|
|
return ERR_UNCOMP;
|
|
}
|
|
if (result == EOF && (!is_last_chunk || avail_out)) {
|
|
warn("Premature EOS in Deflate stream");
|
|
return ERR_UNCOMP;
|
|
}
|
|
|
|
return buffer_size - (uint32_t)avail_out;
|
|
}
|
|
|
|
static void zip_clear_uncompress_deflate64(struct ar_archive_zip_uncomp *uncomp)
|
|
{
|
|
inflate_free(uncomp->state.inflate);
|
|
}
|
|
|
|
/***** BZIP2 compression *****/
|
|
|
|
#ifdef HAVE_BZIP2
|
|
static void *gBzip2_Alloc(void *opaque, int count, int size) { (void)opaque; return calloc(count, size); }
|
|
static void gBzip2_Free(void *opaque, void *ptr) { (void)opaque; free(ptr); }
|
|
|
|
static bool zip_init_uncompress_bzip2(struct ar_archive_zip_uncomp *uncomp)
|
|
{
|
|
int err;
|
|
|
|
uncomp->state.bstream.bzalloc = gBzip2_Alloc;
|
|
uncomp->state.bstream.bzfree = gBzip2_Free;
|
|
uncomp->state.bstream.opaque = NULL;
|
|
|
|
err = BZ2_bzDecompressInit(&uncomp->state.bstream, 0, 0);
|
|
return err == BZ_OK;
|
|
}
|
|
|
|
static uint32_t zip_uncompress_data_bzip2(struct ar_archive_zip_uncomp *uncomp, void *buffer, uint32_t buffer_size, bool is_last_chunk)
|
|
{
|
|
int err;
|
|
|
|
uncomp->state.bstream.next_in = (char *)&uncomp->input.data[uncomp->input.offset];
|
|
uncomp->state.bstream.avail_in = uncomp->input.bytes_left;
|
|
uncomp->state.bstream.next_out = (char *)buffer;
|
|
uncomp->state.bstream.avail_out = buffer_size;
|
|
|
|
err = BZ2_bzDecompress(&uncomp->state.bstream);
|
|
|
|
uncomp->input.offset += uncomp->input.bytes_left - (uint16_t)uncomp->state.bstream.avail_in;
|
|
uncomp->input.bytes_left = (uint16_t)uncomp->state.bstream.avail_in;
|
|
|
|
if (err != BZ_OK && err != BZ_STREAM_END) {
|
|
warn("Unexpected BZIP2 error %d", err);
|
|
return ERR_UNCOMP;
|
|
}
|
|
if (err == BZ_STREAM_END && (!is_last_chunk || uncomp->state.bstream.avail_out)) {
|
|
warn("Premature EOS in BZIP2 stream");
|
|
return ERR_UNCOMP;
|
|
}
|
|
|
|
return buffer_size - uncomp->state.bstream.avail_out;
|
|
}
|
|
|
|
static void zip_clear_uncompress_bzip2(struct ar_archive_zip_uncomp *uncomp)
|
|
{
|
|
BZ2_bzDecompressEnd(&uncomp->state.bstream);
|
|
}
|
|
#endif
|
|
|
|
/***** LZMA compression *****/
|
|
|
|
#ifdef HAVE_LIBLZMA
|
|
|
|
static void *gLzma_Alloc(void *opaque, size_t nmemb, size_t size)
|
|
{ (void)opaque; (void) nmemb; return malloc(size); }
|
|
static void gLzma_Free(void *opaque, void *ptr)
|
|
{ (void)opaque; free(ptr); }
|
|
|
|
static bool zip_init_uncompress_lzma(struct ar_archive_zip_uncomp *uncomp)
|
|
{
|
|
lzma_stream strm = LZMA_STREAM_INIT;
|
|
uncomp->state.lzmastream = strm;
|
|
#if LZMA_VERSION_MAJOR > 5 || (LZMA_VERSION_MAJOR == 5 && LZMA_VERSION_MINOR >= 2)
|
|
static const lzma_allocator allocator = { gLzma_Alloc, gLzma_Free, NULL };
|
|
#else
|
|
static lzma_allocator allocator = { gLzma_Alloc, gLzma_Free, NULL };
|
|
#endif
|
|
uncomp->state.lzmastream.allocator = &allocator;
|
|
return true;
|
|
}
|
|
|
|
static uint32_t zip_uncompress_data_lzma1(struct ar_archive_zip_uncomp *uncomp, void *buffer, uint32_t buffer_size, bool is_last_chunk)
|
|
{
|
|
int err;
|
|
|
|
if (uncomp->state.lzmastream.internal == NULL) {
|
|
uint8_t propsize;
|
|
propsize = uncomp->input.data[uncomp->input.offset + 2];
|
|
|
|
lzma_filter filters[2] = {{.id=LZMA_FILTER_LZMA1, .options=NULL},
|
|
{.id=LZMA_VLI_UNKNOWN, .options=NULL}};
|
|
|
|
err = lzma_properties_decode(
|
|
&filters[0], NULL,
|
|
&uncomp->input.data[uncomp->input.offset + 4], propsize);
|
|
|
|
if (err != LZMA_OK) {
|
|
warn("Properties error %d", err);
|
|
return ERR_UNCOMP;
|
|
}
|
|
|
|
err = lzma_raw_decoder(&uncomp->state.lzmastream, filters);
|
|
free(filters[0].options);
|
|
if (err != LZMA_OK) {
|
|
warn("Decoder init error %d", err);
|
|
return ERR_UNCOMP;
|
|
}
|
|
uncomp->input.offset += 4 + propsize;
|
|
uncomp->input.bytes_left -= 4 + propsize;
|
|
}
|
|
|
|
uncomp->state.lzmastream.next_in = &uncomp->input.data[uncomp->input.offset];
|
|
uncomp->state.lzmastream.avail_in = uncomp->input.bytes_left;
|
|
uncomp->state.lzmastream.next_out = buffer;
|
|
uncomp->state.lzmastream.avail_out = buffer_size;
|
|
|
|
err = lzma_code(&uncomp->state.lzmastream, LZMA_RUN);
|
|
|
|
uncomp->input.offset += (uint16_t)uncomp->input.bytes_left - (uint16_t)uncomp->state.lzmastream.avail_in;
|
|
uncomp->input.bytes_left = (uint16_t)uncomp->state.lzmastream.avail_in;
|
|
|
|
if (err != LZMA_OK && err != LZMA_STREAM_END) {
|
|
warn("Unexpected LZMA error %d", err);
|
|
warn("%d", buffer_size - uncomp->state.lzmastream.avail_out);
|
|
return ERR_UNCOMP;
|
|
}
|
|
if (err == LZMA_STREAM_END && (!is_last_chunk || uncomp->state.lzmastream.avail_out)) {
|
|
warn("Premature EOS in LZMA stream");
|
|
return ERR_UNCOMP;
|
|
}
|
|
return buffer_size - uncomp->state.lzmastream.avail_out;
|
|
}
|
|
|
|
static uint32_t zip_uncompress_data_xz(struct ar_archive_zip_uncomp *uncomp, void *buffer, uint32_t buffer_size, bool is_last_chunk)
|
|
{
|
|
int err;
|
|
|
|
if (uncomp->state.lzmastream.internal == NULL) {
|
|
/* restrict decoder memory usage to 100 MB */
|
|
err = lzma_stream_decoder(&uncomp->state.lzmastream, 100 << 20, 0);
|
|
if (err != LZMA_OK) {
|
|
warn("Unexpected LZMA Decoder init error %d", err);
|
|
return ERR_UNCOMP;
|
|
}
|
|
}
|
|
|
|
uncomp->state.lzmastream.next_in = &uncomp->input.data[uncomp->input.offset];
|
|
uncomp->state.lzmastream.avail_in = uncomp->input.bytes_left;
|
|
uncomp->state.lzmastream.next_out = buffer;
|
|
uncomp->state.lzmastream.avail_out = buffer_size;
|
|
|
|
err = lzma_code(&uncomp->state.lzmastream, LZMA_RUN);
|
|
|
|
uncomp->input.offset += (uint16_t)uncomp->input.bytes_left - (uint16_t)uncomp->state.lzmastream.avail_in;
|
|
uncomp->input.bytes_left = (uint16_t)uncomp->state.lzmastream.avail_in;
|
|
|
|
if (err != LZMA_OK && err != LZMA_STREAM_END) {
|
|
warn("Unexpected XZ error %d", err);
|
|
warn("%d", buffer_size - uncomp->state.lzmastream.avail_out);
|
|
return ERR_UNCOMP;
|
|
}
|
|
if (err == LZMA_STREAM_END && (!is_last_chunk || uncomp->state.lzmastream.avail_out)) {
|
|
warn("Premature EOS in XZ stream");
|
|
return ERR_UNCOMP;
|
|
}
|
|
return buffer_size - uncomp->state.lzmastream.avail_out;
|
|
}
|
|
|
|
|
|
static void zip_clear_uncompress_lzma(struct ar_archive_zip_uncomp *uncomp)
|
|
{
|
|
lzma_end(&uncomp->state.lzmastream);
|
|
}
|
|
|
|
#else //HAVE_LIBLZMA
|
|
|
|
static void *gLzma_Alloc(ISzAllocPtr self, size_t size) { (void)self; return malloc(size); }
|
|
static void gLzma_Free(ISzAllocPtr self, void *ptr) { (void)self; free(ptr); }
|
|
|
|
static bool zip_init_uncompress_lzma(struct ar_archive_zip_uncomp *uncomp, uint16_t flags)
|
|
{
|
|
uncomp->state.lzma.alloc.Alloc = gLzma_Alloc;
|
|
uncomp->state.lzma.alloc.Free = gLzma_Free;
|
|
uncomp->state.lzma.finish = (flags & (1 << 1)) ? LZMA_FINISH_END : LZMA_FINISH_ANY;
|
|
LzmaDec_Construct(&uncomp->state.lzma.dec);
|
|
return true;
|
|
}
|
|
|
|
static uint32_t zip_uncompress_data_lzma(struct ar_archive_zip_uncomp *uncomp, void *buffer, uint32_t buffer_size, bool is_last_chunk)
|
|
{
|
|
SizeT srclen, dstlen;
|
|
ELzmaStatus status;
|
|
ELzmaFinishMode finish;
|
|
SRes res;
|
|
|
|
if (!uncomp->state.lzma.dec.dic) {
|
|
uint8_t propsize;
|
|
if (uncomp->input.bytes_left < 9) {
|
|
warn("Insufficient data in compressed stream");
|
|
return ERR_UNCOMP;
|
|
}
|
|
propsize = uncomp->input.data[uncomp->input.offset + 2];
|
|
if (uncomp->input.data[uncomp->input.offset + 3] != 0 || uncomp->input.bytes_left < 4 + propsize) {
|
|
warn("Insufficient data in compressed stream");
|
|
return ERR_UNCOMP;
|
|
}
|
|
res = LzmaDec_Allocate(&uncomp->state.lzma.dec, &uncomp->input.data[uncomp->input.offset + 4], propsize, &uncomp->state.lzma.alloc);
|
|
uncomp->input.offset += 4 + propsize;
|
|
uncomp->input.bytes_left -= 4 + propsize;
|
|
if (res != SZ_OK)
|
|
return ERR_UNCOMP;
|
|
LzmaDec_Init(&uncomp->state.lzma.dec);
|
|
}
|
|
|
|
srclen = uncomp->input.bytes_left;
|
|
dstlen = buffer_size;
|
|
finish = uncomp->input.at_eof && is_last_chunk ? uncomp->state.lzma.finish : LZMA_FINISH_ANY;
|
|
res = LzmaDec_DecodeToBuf(&uncomp->state.lzma.dec, buffer, &dstlen, &uncomp->input.data[uncomp->input.offset], &srclen, finish, &status);
|
|
|
|
uncomp->input.offset += (uint16_t)srclen;
|
|
uncomp->input.bytes_left -= (uint16_t)srclen;
|
|
|
|
if (res != SZ_OK || (srclen == 0 && dstlen == 0)) {
|
|
warn("Unexpected LZMA error %d", res);
|
|
return ERR_UNCOMP;
|
|
}
|
|
if (status == LZMA_STATUS_FINISHED_WITH_MARK && (!is_last_chunk || dstlen != buffer_size)) {
|
|
warn("Premature EOS in LZMA stream");
|
|
return ERR_UNCOMP;
|
|
}
|
|
|
|
return (uint32_t)dstlen;
|
|
}
|
|
|
|
static void zip_clear_uncompress_lzma(struct ar_archive_zip_uncomp *uncomp)
|
|
{
|
|
LzmaDec_Free(&uncomp->state.lzma.dec, &uncomp->state.lzma.alloc);
|
|
}
|
|
|
|
#endif //HAVE_LIBLZMA
|
|
|
|
/***** PPMd compression *****/
|
|
|
|
static void *gPpmd_Alloc(ISzAllocPtr self, size_t size) { (void)self; return malloc(size); }
|
|
static void gPpmd_Free(ISzAllocPtr self, void *ptr) { (void)self; free(ptr); }
|
|
|
|
static Byte gPpmd_ByteIn_Read(const IByteIn *p)
|
|
{
|
|
struct ByteReader *self = (struct ByteReader *) p;
|
|
if (!self->input->bytes_left && (!self->zip->progress.data_left || !zip_fill_input_buffer(self->zip)))
|
|
return 0xFF;
|
|
self->input->bytes_left--;
|
|
return self->input->data[self->input->offset++];
|
|
}
|
|
|
|
static bool zip_init_uncompress_ppmd(ar_archive_zip *zip)
|
|
{
|
|
struct ar_archive_zip_uncomp *uncomp = &zip->uncomp;
|
|
uncomp->state.ppmd8.alloc.Alloc = gPpmd_Alloc;
|
|
uncomp->state.ppmd8.alloc.Free = gPpmd_Free;
|
|
uncomp->state.ppmd8.bytein.super.Read = gPpmd_ByteIn_Read;
|
|
uncomp->state.ppmd8.bytein.input = &uncomp->input;
|
|
uncomp->state.ppmd8.bytein.zip = zip;
|
|
uncomp->state.ppmd8.ctx.Stream.In = &uncomp->state.ppmd8.bytein.super;
|
|
Ppmd8_Construct(&uncomp->state.ppmd8.ctx);
|
|
return true;
|
|
}
|
|
|
|
static uint32_t zip_uncompress_data_ppmd(struct ar_archive_zip_uncomp *uncomp, void *buffer, uint32_t buffer_size, bool is_last_chunk)
|
|
{
|
|
uint32_t bytes_done = 0;
|
|
|
|
if (!uncomp->state.ppmd8.ctx.Base) {
|
|
uint8_t order, size, method;
|
|
if (uncomp->input.bytes_left < 2) {
|
|
warn("Insufficient data in compressed stream");
|
|
return ERR_UNCOMP;
|
|
}
|
|
order = (uncomp->input.data[uncomp->input.offset] & 0x0F) + 1;
|
|
size = ((uncomp->input.data[uncomp->input.offset] >> 4) | ((uncomp->input.data[uncomp->input.offset + 1] << 4) & 0xFF));
|
|
method = uncomp->input.data[uncomp->input.offset + 1] >> 4;
|
|
uncomp->input.bytes_left -= 2;
|
|
uncomp->input.offset += 2;
|
|
if (order < 2 || method > 2) {
|
|
warn("Invalid PPMd data stream");
|
|
return ERR_UNCOMP;
|
|
}
|
|
#ifndef PPMD8_FREEZE_SUPPORT
|
|
if (order == 2) {
|
|
warn("PPMd freeze method isn't supported");
|
|
return ERR_UNCOMP;
|
|
}
|
|
#endif
|
|
if (!Ppmd8_Alloc(&uncomp->state.ppmd8.ctx, (size + 1) << 20, &uncomp->state.ppmd8.alloc))
|
|
return ERR_UNCOMP;
|
|
if (!Ppmd8_Init_RangeDec(&uncomp->state.ppmd8.ctx))
|
|
return ERR_UNCOMP;
|
|
Ppmd8_Init(&uncomp->state.ppmd8.ctx, order, method);
|
|
}
|
|
|
|
while (bytes_done < buffer_size) {
|
|
int symbol = Ppmd8_DecodeSymbol(&uncomp->state.ppmd8.ctx);
|
|
if (symbol < 0) {
|
|
warn("Invalid PPMd data stream");
|
|
return ERR_UNCOMP;
|
|
}
|
|
((uint8_t *)buffer)[bytes_done++] = (uint8_t)symbol;
|
|
}
|
|
|
|
if (is_last_chunk) {
|
|
int symbol = Ppmd8_DecodeSymbol(&uncomp->state.ppmd8.ctx);
|
|
if (symbol != -1 || !Ppmd8_RangeDec_IsFinishedOK(&uncomp->state.ppmd8.ctx)) {
|
|
warn("Invalid PPMd data stream");
|
|
return ERR_UNCOMP;
|
|
}
|
|
}
|
|
|
|
return bytes_done;
|
|
}
|
|
|
|
static void zip_clear_uncompress_ppmd(struct ar_archive_zip_uncomp *uncomp)
|
|
{
|
|
Ppmd8_Free(&uncomp->state.ppmd8.ctx, &uncomp->state.ppmd8.alloc);
|
|
}
|
|
|
|
/***** common decompression handling *****/
|
|
|
|
static bool zip_init_uncompress(ar_archive_zip *zip)
|
|
{
|
|
struct ar_archive_zip_uncomp *uncomp = &zip->uncomp;
|
|
if (uncomp->initialized)
|
|
return true;
|
|
memset(uncomp, 0, sizeof(*uncomp));
|
|
if (zip->entry.method == METHOD_DEFLATE) {
|
|
#ifdef HAVE_ZLIB
|
|
if (zip_init_uncompress_deflate(uncomp)) {
|
|
uncomp->uncompress_data = zip_uncompress_data_deflate;
|
|
uncomp->clear_state = zip_clear_uncompress_deflate;
|
|
}
|
|
#else
|
|
if (zip_init_uncompress_deflate64(uncomp, false)) {
|
|
uncomp->uncompress_data = zip_uncompress_data_deflate64;
|
|
uncomp->clear_state = zip_clear_uncompress_deflate64;
|
|
}
|
|
#endif
|
|
}
|
|
else if (zip->entry.method == METHOD_DEFLATE64) {
|
|
if (zip_init_uncompress_deflate64(uncomp, true)) {
|
|
uncomp->uncompress_data = zip_uncompress_data_deflate64;
|
|
uncomp->clear_state = zip_clear_uncompress_deflate64;
|
|
}
|
|
}
|
|
else if (zip->entry.method == METHOD_BZIP2) {
|
|
#ifdef HAVE_BZIP2
|
|
if (zip_init_uncompress_bzip2(uncomp)) {
|
|
uncomp->uncompress_data = zip_uncompress_data_bzip2;
|
|
uncomp->clear_state = zip_clear_uncompress_bzip2;
|
|
}
|
|
#else
|
|
warn("BZIP2 support requires BZIP2 (define HAVE_BZIP2)");
|
|
#endif
|
|
}
|
|
#ifdef HAVE_LIBLZMA
|
|
else if (zip->entry.method == METHOD_LZMA) {
|
|
if (zip_init_uncompress_lzma(uncomp)) {
|
|
uncomp->uncompress_data = zip_uncompress_data_lzma1;
|
|
uncomp->clear_state = zip_clear_uncompress_lzma;
|
|
}
|
|
}
|
|
else if (zip->entry.method == METHOD_XZ) {
|
|
if (zip_init_uncompress_lzma(uncomp)) {
|
|
uncomp->uncompress_data = zip_uncompress_data_xz;
|
|
uncomp->clear_state = zip_clear_uncompress_lzma;
|
|
}
|
|
}
|
|
#else
|
|
else if (zip->entry.method == METHOD_LZMA) {
|
|
if (zip_init_uncompress_lzma(uncomp, zip->entry.flags)) {
|
|
uncomp->uncompress_data = zip_uncompress_data_lzma;
|
|
uncomp->clear_state = zip_clear_uncompress_lzma;
|
|
}
|
|
}
|
|
#endif // HAVE_LIBLZMA
|
|
else if (zip->entry.method == METHOD_PPMD) {
|
|
if (zip_init_uncompress_ppmd(zip)) {
|
|
uncomp->uncompress_data = zip_uncompress_data_ppmd;
|
|
uncomp->clear_state = zip_clear_uncompress_ppmd;
|
|
}
|
|
}
|
|
else
|
|
warn("Unsupported compression method %d", zip->entry.method);
|
|
uncomp->initialized = uncomp->uncompress_data != NULL && uncomp->clear_state != NULL;
|
|
return uncomp->initialized;
|
|
}
|
|
|
|
void zip_clear_uncompress(struct ar_archive_zip_uncomp *uncomp)
|
|
{
|
|
if (!uncomp->initialized)
|
|
return;
|
|
uncomp->clear_state(uncomp);
|
|
uncomp->initialized = false;
|
|
}
|
|
|
|
bool zip_uncompress_part(ar_archive_zip *zip, void *buffer, size_t buffer_size)
|
|
{
|
|
struct ar_archive_zip_uncomp *uncomp = &zip->uncomp;
|
|
uint32_t count;
|
|
|
|
if (!zip_init_uncompress(zip))
|
|
return false;
|
|
|
|
for (;;) {
|
|
if (buffer_size == 0)
|
|
return true;
|
|
|
|
if (uncomp->input.bytes_left < sizeof(uncomp->input.data) / 2 && zip->progress.data_left) {
|
|
if (!zip_fill_input_buffer(zip))
|
|
return false;
|
|
}
|
|
|
|
count = buffer_size >= UINT32_MAX ? UINT32_MAX - 1 : (uint32_t)buffer_size;
|
|
count = uncomp->uncompress_data(uncomp, buffer, count, zip->progress.bytes_done + count == zip->super.entry_size_uncompressed);
|
|
if (count == ERR_UNCOMP)
|
|
return false;
|
|
if (count == 0 && !zip->progress.data_left) {
|
|
warn("Insufficient data in compressed stream");
|
|
return false;
|
|
}
|
|
zip->progress.bytes_done += count;
|
|
buffer = (uint8_t *)buffer + count;
|
|
buffer_size -= count;
|
|
}
|
|
}
|