diff options
Diffstat (limited to 'depends/lzma/wrapper/decompress.c')
-rw-r--r-- | depends/lzma/wrapper/decompress.c | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/depends/lzma/wrapper/decompress.c b/depends/lzma/wrapper/decompress.c new file mode 100644 index 00000000..65ff9119 --- /dev/null +++ b/depends/lzma/wrapper/decompress.c @@ -0,0 +1,263 @@ +/* + * Written in 2009 by Lloyd Hilaiel + * + * License + * + * All the cruft you find here is public domain. You don't have to credit + * anyone to use this code, but my personal request is that you mention + * Igor Pavlov for his hard, high quality work. + */ + +#include "include/decompress.h" +#include "pavlov/LzmaDec.h" +#include "pavlov/7zCrc.h" +#include "common_internal.h" +#include "lzma_header.h" +#include "lzip_header.h" + +#include <string.h> +#include <assert.h> + +#define ELZMA_DECOMPRESS_INPUT_BUFSIZE (1024 * 64) +#define ELZMA_DECOMPRESS_OUTPUT_BUFSIZE (1024 * 256) + +/** an opaque handle to an lzma decompressor */ +struct _elzma_decompress_handle +{ + char inbuf[ELZMA_DECOMPRESS_INPUT_BUFSIZE]; + char outbuf[ELZMA_DECOMPRESS_OUTPUT_BUFSIZE]; + struct elzma_alloc_struct allocStruct; +}; + +elzma_decompress_handle elzma_decompress_alloc() +{ + elzma_decompress_handle hand = malloc(sizeof(struct _elzma_decompress_handle)); + memset((void *)hand, 0, sizeof(struct _elzma_decompress_handle)); + init_alloc_struct(&(hand->allocStruct), NULL, NULL, NULL, NULL); + return hand; +} + +void elzma_decompress_set_allocation_callbacks(elzma_decompress_handle hand, + elzma_malloc mallocFunc, void *mallocFuncContext, + elzma_free freeFunc, void *freeFuncContext) +{ + if (hand) + { + init_alloc_struct(&(hand->allocStruct), mallocFunc, mallocFuncContext, freeFunc, + freeFuncContext); + } +} + +void elzma_decompress_free(elzma_decompress_handle *hand) +{ + if (*hand) + free(*hand); + *hand = NULL; +} + +int elzma_decompress_run(elzma_decompress_handle hand, elzma_read_callback inputStream, + void *inputContext, elzma_write_callback outputStream, + void *outputContext, elzma_file_format format) +{ + unsigned long long int totalRead = 0; /* total amount read from stream */ + unsigned int crc32 = CRC_INIT_VAL; /* running crc32 (lzip case) */ + CLzmaDec dec; + unsigned int errorCode = ELZMA_E_OK; + struct elzma_format_handler formatHandler; + struct elzma_file_header h; + struct elzma_file_footer f; + + /* switch between supported formats */ + if (format == ELZMA_lzma) + { + initializeLZMAFormatHandler(&formatHandler); + } + else if (format == ELZMA_lzip) + { + CrcGenerateTable(); + initializeLZIPFormatHandler(&formatHandler); + } + else + { + return ELZMA_E_BAD_PARAMS; + } + + /* initialize footer */ + f.crc32 = 0; + f.uncompressedSize = 0; + + /* initialize decoder memory */ + memset((void *)&dec, 0, sizeof(dec)); + LzmaDec_Init(&dec); + + /* decode the header. */ + { + unsigned char *hdr = + hand->allocStruct.Alloc(&(hand->allocStruct), formatHandler.header_size); + + size_t sz = formatHandler.header_size; + + formatHandler.init_header(&h); + + if (inputStream(inputContext, hdr, &sz) != 0 || sz != formatHandler.header_size) + { + hand->allocStruct.Free(&(hand->allocStruct), hdr); + return ELZMA_E_INPUT_ERROR; + } + + if (0 != formatHandler.parse_header(hdr, &h)) + { + hand->allocStruct.Free(&(hand->allocStruct), hdr); + return ELZMA_E_CORRUPT_HEADER; + } + + /* the LzmaDec_Allocate call requires 5 bytes which have + * compression properties encoded in them. In the case of + * lzip, the header format does not already contain what + * LzmaDec_Allocate expects, so we must craft it, silly */ + { + unsigned char propsBuf[13]; + const unsigned char *propsPtr = hdr; + + if (format == ELZMA_lzip) + { + struct elzma_format_handler lzmaHand; + initializeLZMAFormatHandler(&lzmaHand); + lzmaHand.serialize_header(propsBuf, &h); + propsPtr = propsBuf; + } + + /* now we're ready to allocate the decoder */ + LzmaDec_Allocate(&dec, propsPtr, 5); + } + + hand->allocStruct.Free(&(hand->allocStruct), hdr); + } + + /* perform the decoding */ + for (;;) + { + size_t dstLen = ELZMA_DECOMPRESS_OUTPUT_BUFSIZE; + size_t srcLen = ELZMA_DECOMPRESS_INPUT_BUFSIZE; + size_t amt = 0; + size_t bufOff = 0; + ELzmaStatus stat; + + if (0 != inputStream(inputContext, hand->inbuf, &srcLen)) + { + errorCode = ELZMA_E_INPUT_ERROR; + goto decompressEnd; + } + + /* handle the case where the input prematurely finishes */ + if (srcLen == 0) + { + errorCode = ELZMA_E_INSUFFICIENT_INPUT; + goto decompressEnd; + } + + amt = srcLen; + + /* handle the case where a single read buffer of compressed bytes + * will translate into multiple buffers of uncompressed bytes, + * with this inner loop */ + stat = LZMA_STATUS_NOT_SPECIFIED; + + while (bufOff < srcLen) + { + SRes r = LzmaDec_DecodeToBuf(&dec, (uint8_t *)hand->outbuf, &dstLen, + ((uint8_t *)hand->inbuf + bufOff), &amt, + LZMA_FINISH_ANY, &stat); + + /* XXX deal with result code more granularly*/ + if (r != SZ_OK) + { + errorCode = ELZMA_E_DECOMPRESS_ERROR; + goto decompressEnd; + } + + /* write what we've read */ + { + size_t wt; + + /* if decoding lzip, update our crc32 value */ + if (format == ELZMA_lzip && dstLen > 0) + { + crc32 = CrcUpdate(crc32, hand->outbuf, dstLen); + } + totalRead += dstLen; + + wt = outputStream(outputContext, hand->outbuf, dstLen); + if (wt != dstLen) + { + errorCode = ELZMA_E_OUTPUT_ERROR; + goto decompressEnd; + } + } + + /* do we have more data on the input buffer? */ + bufOff += amt; + assert(bufOff <= srcLen); + if (bufOff >= srcLen) + break; + amt = srcLen - bufOff; + + /* with lzip, we will have the footer left on the buffer! */ + if (stat == LZMA_STATUS_FINISHED_WITH_MARK) + { + break; + } + } + + /* now check status */ + if (stat == LZMA_STATUS_FINISHED_WITH_MARK) + { + /* read a footer if one is expected and + * present */ + if (formatHandler.footer_size > 0 && amt >= formatHandler.footer_size && + formatHandler.parse_footer != NULL) + { + formatHandler.parse_footer((unsigned char *)hand->inbuf + bufOff, &f); + } + + break; + } + /* for LZMA utils, we don't always have a finished mark */ + if (!h.isStreamed && totalRead >= h.uncompressedSize) + { + break; + } + } + + /* finish the calculated crc32 */ + crc32 ^= 0xFFFFFFFF; + + /* if we have a footer, check that the calculated crc32 matches + * the encoded crc32, and that the sizes match */ + if (formatHandler.footer_size) + { + if (f.crc32 != crc32) + { + errorCode = ELZMA_E_CRC32_MISMATCH; + } + else if (f.uncompressedSize != totalRead) + { + errorCode = ELZMA_E_SIZE_MISMATCH; + } + } + else if (!h.isStreamed) + { + /* if the format does not support a footer and has an uncompressed + * size in the header, let's compare that with how much we actually + * read */ + if (h.uncompressedSize != totalRead) + { + errorCode = ELZMA_E_SIZE_MISMATCH; + } + } + +decompressEnd: + LzmaDec_Free(&dec); + + return errorCode; +} |