diff options
Diffstat (limited to 'lib/common/comp_lzo.c')
-rw-r--r-- | lib/common/comp_lzo.c | 42 |
1 files changed, 35 insertions, 7 deletions
diff --git a/lib/common/comp_lzo.c b/lib/common/comp_lzo.c index cf5a362..f371fb6 100644 --- a/lib/common/comp_lzo.c +++ b/lib/common/comp_lzo.c @@ -13,6 +13,8 @@ #include <lzo/lzo1x.h> +#define LZO_MAX_SIZE(size) (size + (size / 16) + 64 + 3) + #define LZO_NUM_ALGS (sizeof(lzo_algs) / sizeof(lzo_algs[0])) typedef int (*lzo_cb_t)(const lzo_bytep src, lzo_uint src_len, lzo_bytep dst, @@ -49,6 +51,9 @@ typedef struct { int algorithm; int level; + size_t buf_size; + size_t work_size; + sqfs_u8 buffer[]; } lzo_compressor_t; @@ -128,27 +133,33 @@ static sqfs_s32 lzo_comp_block(sqfs_compressor_t *base, const sqfs_u8 *in, sqfs_u32 size, sqfs_u8 *out, sqfs_u32 outsize) { lzo_compressor_t *lzo = (lzo_compressor_t *)base; - lzo_uint len = outsize; + void *scratch; + lzo_uint len; int ret; if (size >= 0x7FFFFFFF) return 0; + scratch = lzo->buffer + lzo->work_size; + len = lzo->buf_size - lzo->work_size; + if (lzo->algorithm == SQFS_LZO1X_999 && lzo->level != SQFS_LZO_DEFAULT_LEVEL) { - ret = lzo1x_999_compress_level(in, size, out, &len, + ret = lzo1x_999_compress_level(in, size, scratch, &len, lzo->buffer, NULL, 0, 0, lzo->level); } else { - ret = lzo_algs[lzo->algorithm].compress(in, size, out, + ret = lzo_algs[lzo->algorithm].compress(in, size, scratch, &len, lzo->buffer); } if (ret != LZO_E_OK) return SQFS_ERROR_COMPRESSOR; - if (len < size) + if (len < size && len <= outsize) { + memcpy(out, scratch, len); return len; + } return 0; } @@ -176,7 +187,7 @@ static sqfs_compressor_t *lzo_create_copy(sqfs_compressor_t *cmp) lzo_compressor_t *other = (lzo_compressor_t *)cmp; lzo_compressor_t *lzo; - lzo = calloc(1, sizeof(*lzo) + lzo_algs[other->algorithm].bufsize); + lzo = calloc(1, sizeof(*lzo) + other->buf_size); if (lzo == NULL) return NULL; @@ -193,6 +204,7 @@ sqfs_compressor_t *lzo_compressor_create(const sqfs_compressor_config_t *cfg) { sqfs_compressor_t *base; lzo_compressor_t *lzo; + size_t scratch_size; if (cfg->flags & ~SQFS_COMP_FLAG_GENERIC_ALL) return NULL; @@ -209,8 +221,22 @@ sqfs_compressor_t *lzo_compressor_create(const sqfs_compressor_config_t *cfg) return NULL; } - lzo = calloc(1, - sizeof(*lzo) + lzo_algs[cfg->opt.lzo.algorithm].bufsize); + /* XXX: liblzo does not do bounds checking internally, + we need our own internal scratch buffer at worst case size... */ + if (cfg->flags & SQFS_COMP_FLAG_UNCOMPRESS) { + scratch_size = 0; + } else { + scratch_size = cfg->block_size; + if (scratch_size < SQFS_META_BLOCK_SIZE) + scratch_size = SQFS_META_BLOCK_SIZE; + + scratch_size = LZO_MAX_SIZE(scratch_size); + } + + /* ...in addition to the LZO work space buffer of course */ + scratch_size += lzo_algs[cfg->opt.lzo.algorithm].bufsize; + + lzo = calloc(1, sizeof(*lzo) + scratch_size); base = (sqfs_compressor_t *)lzo; if (lzo == NULL) @@ -218,6 +244,8 @@ sqfs_compressor_t *lzo_compressor_create(const sqfs_compressor_config_t *cfg) lzo->algorithm = cfg->opt.lzo.algorithm; lzo->level = cfg->opt.lzo.level; + lzo->buf_size = scratch_size; + lzo->work_size = lzo_algs[cfg->opt.lzo.algorithm].bufsize; base->destroy = lzo_destroy; base->do_block = (cfg->flags & SQFS_COMP_FLAG_UNCOMPRESS) ? |