diff --git a/decompress.c b/decompress.c index 80344f0..6292ff8 100644 --- a/decompress.c +++ b/decompress.c @@ -25,6 +25,7 @@ #include "decompress.h" #include "squashfs_fs.h" +#include "swap.h" #include @@ -65,6 +66,66 @@ static sqfs_err sqfs_decompressor_xz(void *in, size_t insz, return SQFS_OK; } #define CAN_DECOMPRESS_XZ 1 + +// The following implementation was adapted from squashfs-tools +// https://github.com/plougher/squashfs-tools.git + +#define LZMA_PROPS_SIZE 5 +#define LZMA_UNCOMP_SIZE 8 +#define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + LZMA_UNCOMP_SIZE) +#define MEMLIMIT (32 * 1024 * 1024) + +static sqfs_err sqfs_decompressor_lzma(void *in, size_t insz, + void *out, size_t *outsz) { + + lzma_stream strm = LZMA_STREAM_INIT; + uint32_t uncompressed_size = 0, res; + unsigned char lzma_header[LZMA_HEADER_SIZE]; + + res = lzma_alone_decoder(&strm, MEMLIMIT); + if (res != LZMA_OK) { + lzma_end(&strm); + return SQFS_ERR; + } + + memcpy(lzma_header, in, LZMA_HEADER_SIZE); + uncompressed_size = *((uint32_t*)(lzma_header + LZMA_PROPS_SIZE)); + sqfs_swapin32(&uncompressed_size); + + if (uncompressed_size > *outsz) { + lzma_end(&strm); + return SQFS_ERR; + } + + memset(lzma_header + LZMA_PROPS_SIZE, 255, LZMA_UNCOMP_SIZE); + + strm.next_out = out; + strm.avail_out = *outsz; + strm.next_in = lzma_header; + strm.avail_in = LZMA_HEADER_SIZE; + + res = lzma_code(&strm, LZMA_RUN); + + if (res != LZMA_OK || strm.avail_in != 0) { + lzma_end(&strm); + return SQFS_ERR; + } + + strm.next_in = (uint8_t *)in + LZMA_HEADER_SIZE; + strm.avail_in = insz - LZMA_HEADER_SIZE; + + res = lzma_code(&strm, LZMA_FINISH); + lzma_end(&strm); + + if (res == LZMA_STREAM_END || (res == LZMA_OK && + strm.total_out >= uncompressed_size && strm.avail_in == 0)) { + *outsz = uncompressed_size; + return SQFS_OK; + } + + return SQFS_ERR; +} +#define CAN_DECOMPRESS_LZMA 1 #endif @@ -116,12 +177,15 @@ sqfs_decompressor sqfs_decompressor_get(sqfs_compression_type type) { #ifdef CAN_DECOMPRESS_ZLIB case ZLIB_COMPRESSION: return &sqfs_decompressor_zlib; #endif -#ifdef CAN_DECOMPRESS_XZ - case XZ_COMPRESSION: return &sqfs_decompressor_xz; +#ifdef CAN_DECOMPRESS_LZMA + case LZMA_COMPRESSION: return &sqfs_decompressor_lzma; #endif #ifdef CAN_DECOMPRESS_LZO case LZO_COMPRESSION: return &sqfs_decompressor_lzo; #endif +#ifdef CAN_DECOMPRESS_XZ + case XZ_COMPRESSION: return &sqfs_decompressor_xz; +#endif #ifdef CAN_DECOMPRESS_LZ4 case LZ4_COMPRESSION: return &sqfs_decompressor_lz4; #endif @@ -145,15 +209,18 @@ char *sqfs_compression_name(sqfs_compression_type type) { void sqfs_compression_supported(sqfs_compression_type *types) { size_t i = 0; memset(types, SQFS_COMP_UNKNOWN, SQFS_COMP_MAX * sizeof(*types)); +#ifdef CAN_DECOMPRESS_ZLIB + types[i++] = ZLIB_COMPRESSION; +#endif +#ifdef CAN_DECOMPRESS_LZMA + types[i++] = LZMA_COMPRESSION; +#endif #ifdef CAN_DECOMPRESS_LZO types[i++] = LZO_COMPRESSION; #endif #ifdef CAN_DECOMPRESS_XZ types[i++] = XZ_COMPRESSION; #endif -#ifdef CAN_DECOMPRESS_ZLIB - types[i++] = ZLIB_COMPRESSION; -#endif #ifdef CAN_DECOMPRESS_LZ4 types[i++] = LZ4_COMPRESSION; #endif