From 0f23f0396aede08a5d0c95d75b272f1b1787a365 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Thu, 4 Jun 2020 04:57:08 +0200 Subject: lzma compressor: support micro management options The LZMA compressor (through the xz-utils library) supports basically the same options for micro management as the XZ compressor. This commit enables support for those options in the compressor, the option parser and adds an option field to the configuration structure. Signed-off-by: David Oberhollenzer --- include/sqfs/compressor.h | 26 ++++++++++++++++---- lib/common/comp_opt.c | 47 ++++++++++++++++++++++++++---------- lib/sqfs/comp/compressor.c | 9 +++++++ lib/sqfs/comp/lzma.c | 60 +++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 119 insertions(+), 23 deletions(-) diff --git a/include/sqfs/compressor.h b/include/sqfs/compressor.h index a257c3a..c8cab02 100644 --- a/include/sqfs/compressor.h +++ b/include/sqfs/compressor.h @@ -185,13 +185,13 @@ struct sqfs_compressor_config_t { } lzo; /** - * @brief Options for the xz compressor. + * @brief Options for the LZMA and XZ (LZMA v2) compressors. */ struct { /** * @brief LZMA dictionary size. * - * This value must either be a power of two or the sumo + * This value must either be a power of two or the sum * of two consecutive powers of two. * * Default is setting this to the same as the @@ -200,7 +200,9 @@ struct sqfs_compressor_config_t { sqfs_u32 dict_size; /** - * @brief Compression level. Maximum 9, default is 6. + * @brief Compression level. Maximum 9. + * + * For LZMA, the default is 5, for XZ the default is 6. */ sqfs_u8 level; @@ -243,7 +245,7 @@ struct sqfs_compressor_config_t { sqfs_u8 pb; sqfs_u32 padd0[2]; - } xz; + } xz, lzma; sqfs_u64 padd0[2]; } opt; @@ -392,6 +394,22 @@ typedef enum { #define SQFS_XZ_MAX_PB 4 #define SQFS_XZ_DEFAULT_PB 2 +#define SQFS_LZMA_MIN_LEVEL (0) +#define SQFS_LZMA_MAX_LEVEL (9) +#define SQFS_LZMA_DEFAULT_LEVEL (5) + +#define SQFS_LZMA_MIN_LC 0 +#define SQFS_LZMA_MAX_LC 4 +#define SQFS_LZMA_DEFAULT_LC 3 + +#define SQFS_LZMA_MIN_LP 0 +#define SQFS_LZMA_MAX_LP 4 +#define SQFS_LZMA_DEFAULT_LP 0 + +#define SQFS_LZMA_MIN_PB 0 +#define SQFS_LZMA_MAX_PB 4 +#define SQFS_LZMA_DEFAULT_PB 2 + #ifdef __cplusplus extern "C" { #endif diff --git a/lib/common/comp_opt.c b/lib/common/comp_opt.c index c279f1e..8864a0e 100644 --- a/lib/common/comp_opt.c +++ b/lib/common/comp_opt.c @@ -136,6 +136,8 @@ int compressor_cfg_init_options(sqfs_compressor_config_t *cfg, num_flags = sizeof(xz_flags) / sizeof(xz_flags[0]); break; case SQFS_COMP_LZMA: + min_level = SQFS_LZMA_MIN_LEVEL; + max_level = SQFS_LZMA_MAX_LEVEL; flags = lzma_flags; num_flags = sizeof(lzma_flags) / sizeof(lzma_flags[0]); break; @@ -200,6 +202,9 @@ int compressor_cfg_init_options(sqfs_compressor_config_t *cfg, case SQFS_COMP_XZ: cfg->opt.xz.level = level; break; + case SQFS_COMP_LZMA: + cfg->opt.lzma.level = level; + break; default: goto fail_opt; } @@ -215,13 +220,15 @@ int compressor_cfg_init_options(sqfs_compressor_config_t *cfg, goto fail_lzo_alg; break; case OPT_DICT: - if (cfg->id != SQFS_COMP_XZ) + if (cfg->id != SQFS_COMP_XZ && + cfg->id != SQFS_COMP_LZMA) { goto fail_opt; + } if (value == NULL) goto fail_value; - if (parse_size("Parsing XZ dictionary size", + if (parse_size("Parsing LZMA dictionary size", &dict_size, value, cfg->block_size)) { return -1; } @@ -229,8 +236,10 @@ int compressor_cfg_init_options(sqfs_compressor_config_t *cfg, cfg->opt.xz.dict_size = dict_size; break; case OPT_LC: - if (cfg->id != SQFS_COMP_XZ) + if (cfg->id != SQFS_COMP_XZ && + cfg->id != SQFS_COMP_LZMA) { goto fail_opt; + } if (value == NULL) goto fail_value; @@ -240,8 +249,10 @@ int compressor_cfg_init_options(sqfs_compressor_config_t *cfg, goto fail_lc; break; case OPT_LP: - if (cfg->id != SQFS_COMP_XZ) + if (cfg->id != SQFS_COMP_XZ && + cfg->id != SQFS_COMP_LZMA) { goto fail_opt; + } if (value == NULL) goto fail_value; @@ -251,8 +262,10 @@ int compressor_cfg_init_options(sqfs_compressor_config_t *cfg, goto fail_lp; break; case OPT_PB: - if (cfg->id != SQFS_COMP_XZ) + if (cfg->id != SQFS_COMP_XZ && + cfg->id != SQFS_COMP_LZMA) { goto fail_opt; + } if (value == NULL) goto fail_value; @@ -268,8 +281,10 @@ int compressor_cfg_init_options(sqfs_compressor_config_t *cfg, } } - if (cfg->id == SQFS_COMP_XZ && (cfg->opt.xz.lp + cfg->opt.xz.lc) > 4) - goto fail_sum_lp_lc; + if (cfg->id == SQFS_COMP_XZ || cfg->id == SQFS_COMP_LZMA) { + if ((cfg->opt.xz.lp + cfg->opt.xz.lc) > 4) + goto fail_sum_lp_lc; + } return 0; fail_sum_lp_lc: @@ -362,12 +377,12 @@ static void lzo_print_help(void) printf("\t%s\n", lzo_algs[i]); } -static void xz_print_help(void) +static void xz_lzma_print_help(void) { size_t i; printf( -"Available options for xz compressor:\n" +"Available options for LZMA and XZ (LZMA v2) compressors:\n" "\n" " dictsize= Dictionary size. Either a value in bytes or a\n" " percentage of the block size. Defaults to 100%%.\n" @@ -375,7 +390,7 @@ static void xz_print_help(void) " can also be used for kibi and mebi bytes\n" " respecitively.\n" " level= Compression level. Value from %d to %d.\n" -" Defaults to %d.\n" +" For XZ, defaults to %d, for LZMA defaults to %d.\n" " lc= Number of literal context bits.\n" " How many of the highest bits of the previous\n" " uncompressed byte to take into account when\n" @@ -390,16 +405,21 @@ static void xz_print_help(void) " of the input data, i.e. pb=0 means single byte\n" " allignment, pb=1 means 16 bit, 2 means 32 bit.\n" " Default is %d.\n" +" extreme If this flag is set, try to crunch the data extra hard\n" +" without increasing the decompressors memory\n" +" requirements." "\n" "If values are set, the sum of lc + lp must not exceed 4.\n" "The maximum for pb is %d.\n" "\n" -"In additon to the options, one or more bcj filters can be specified.\n" +"In additon to the options, for the XZ compressor, one or more bcj filters\n" +"can be specified.\n" "If multiple filters are provided, the one yielding the best compression\n" "ratio will be used.\n" "\n" "The following filters are available:\n", - SQFS_XZ_MIN_LEVEL, SQFS_XZ_MAX_LEVEL, SQFS_XZ_DEFAULT_LEVEL, + SQFS_XZ_MIN_LEVEL, SQFS_XZ_MAX_LEVEL, + SQFS_XZ_DEFAULT_LEVEL, SQFS_LZMA_DEFAULT_LEVEL, SQFS_XZ_DEFAULT_LC, SQFS_XZ_DEFAULT_LP, SQFS_XZ_DEFAULT_PB, SQFS_XZ_MAX_PB); @@ -419,7 +439,8 @@ static void zstd_print_help(void) static const compressor_help_fun_t helpfuns[SQFS_COMP_MAX + 1] = { [SQFS_COMP_GZIP] = gzip_print_help, - [SQFS_COMP_XZ] = xz_print_help, + [SQFS_COMP_XZ] = xz_lzma_print_help, + [SQFS_COMP_LZMA] = xz_lzma_print_help, [SQFS_COMP_LZO] = lzo_print_help, [SQFS_COMP_LZ4] = lz4_print_help, [SQFS_COMP_ZSTD] = zstd_print_help, diff --git a/lib/sqfs/comp/compressor.c b/lib/sqfs/comp/compressor.c index 2a0cebb..521471d 100644 --- a/lib/sqfs/comp/compressor.c +++ b/lib/sqfs/comp/compressor.c @@ -98,6 +98,10 @@ int sqfs_compressor_create(const sqfs_compressor_config_t *cfg, ret = memcmp(cfg->opt.xz.padd0, padd0, sizeof(cfg->opt.xz.padd0)); break; + case SQFS_COMP_LZMA: + ret = memcmp(cfg->opt.lzma.padd0, padd0, + sizeof(cfg->opt.lzma.padd0)); + break; case SQFS_COMP_LZO: ret = memcmp(cfg->opt.lzo.padd0, padd0, sizeof(cfg->opt.lzo.padd0)); @@ -172,6 +176,11 @@ int sqfs_compressor_config_init(sqfs_compressor_config_t *cfg, break; case SQFS_COMP_LZMA: flag_mask |= SQFS_COMP_FLAG_LZMA_ALL; + cfg->opt.lzma.dict_size = block_size; + cfg->opt.lzma.level = SQFS_LZMA_DEFAULT_LEVEL; + cfg->opt.lzma.lc = SQFS_LZMA_DEFAULT_LC; + cfg->opt.lzma.lp = SQFS_LZMA_DEFAULT_LP; + cfg->opt.lzma.pb = SQFS_LZMA_DEFAULT_PB; break; case SQFS_COMP_LZ4: flag_mask |= SQFS_COMP_FLAG_LZ4_ALL; diff --git a/lib/sqfs/comp/lzma.c b/lib/sqfs/comp/lzma.c index 8db018d..59871b1 100644 --- a/lib/sqfs/comp/lzma.c +++ b/lib/sqfs/comp/lzma.c @@ -18,13 +18,18 @@ #define LZMA_SIZE_BYTES (8) #define LZMA_HEADER_SIZE (13) -#define LZMA_DEFAULT_LEVEL (5) -#define MEMLIMIT (32 * 1024 * 1024) +#define MEMLIMIT (64 * 1024 * 1024) typedef struct { sqfs_compressor_t base; size_t block_size; + size_t dict_size; + sqfs_u32 flags; + sqfs_u8 level; + sqfs_u8 lc; + sqfs_u8 lp; + sqfs_u8 pb; } lzma_compressor_t; static int lzma_write_options(sqfs_compressor_t *base, sqfs_file_t *file) @@ -50,6 +55,9 @@ static sqfs_s32 try_compress(lzma_compressor_t *lzma, sqfs_u32 preset, lzma_lzma_preset(&opt, preset); opt.dict_size = lzma->block_size; + opt.lc = lzma->lc; + opt.lp = lzma->lp; + opt.pb = lzma->pb; if (lzma_alone_encoder(&strm, &opt) != LZMA_OK) { lzma_end(&strm); @@ -91,7 +99,7 @@ static sqfs_s32 lzma_comp_block(sqfs_compressor_t *base, const sqfs_u8 *in, if (outsize < LZMA_HEADER_SIZE || size >= 0x7FFFFFFF) return SQFS_ERROR_ARG_INVALID; - preset = LZMA_DEFAULT_LEVEL; + preset = lzma->level; ret = try_compress(lzma, preset, in, size, out, outsize); if (ret < 0 || !(lzma->flags & SQFS_COMP_FLAG_LZMA_EXTREME)) return ret; @@ -177,6 +185,11 @@ static void lzma_get_configuration(const sqfs_compressor_t *base, cfg->id = SQFS_COMP_LZMA; cfg->block_size = lzma->block_size; cfg->flags = lzma->flags; + cfg->opt.lzma.dict_size = lzma->dict_size; + cfg->opt.lzma.level = lzma->level; + cfg->opt.lzma.lc = lzma->lc; + cfg->opt.lzma.lp = lzma->lp; + cfg->opt.lzma.pb = lzma->pb; } static sqfs_object_t *lzma_create_copy(const sqfs_object_t *cmp) @@ -206,6 +219,36 @@ int lzma_compressor_create(const sqfs_compressor_config_t *cfg, if (cfg->flags & ~mask) return SQFS_ERROR_UNSUPPORTED; + /* XXX: values are unsigned and minimum is 0 */ + if (cfg->opt.lzma.level > SQFS_LZMA_MAX_LEVEL) + return SQFS_ERROR_UNSUPPORTED; + + if (cfg->opt.lzma.lc > SQFS_LZMA_MAX_LC) + return SQFS_ERROR_UNSUPPORTED; + + if (cfg->opt.lzma.lp > SQFS_LZMA_MAX_LP) + return SQFS_ERROR_UNSUPPORTED; + + if (cfg->opt.lzma.pb > SQFS_LZMA_MAX_PB) + return SQFS_ERROR_UNSUPPORTED; + + if (cfg->opt.lzma.lc + cfg->opt.lzma.lp > 4) + return SQFS_ERROR_UNSUPPORTED; + + if (cfg->opt.lzma.dict_size == 0) + return SQFS_ERROR_UNSUPPORTED; + + mask = cfg->opt.lzma.dict_size; + mask &= mask - 1; + + if (mask != 0) { + if ((mask & (mask - 1)) != 0) + return SQFS_ERROR_UNSUPPORTED; + + if (cfg->opt.lzma.dict_size != (mask | mask >> 1)) + return SQFS_ERROR_UNSUPPORTED; + } + lzma = calloc(1, sizeof(*lzma)); base = (sqfs_compressor_t *)lzma; if (lzma == NULL) @@ -213,9 +256,14 @@ int lzma_compressor_create(const sqfs_compressor_config_t *cfg, lzma->block_size = cfg->block_size; lzma->flags = cfg->flags; - - if (lzma->block_size < SQFS_META_BLOCK_SIZE) - lzma->block_size = SQFS_META_BLOCK_SIZE; + lzma->dict_size = cfg->opt.lzma.dict_size; + lzma->level = cfg->opt.lzma.level; + lzma->lc = cfg->opt.lzma.lc; + lzma->lp = cfg->opt.lzma.lp; + lzma->pb = cfg->opt.lzma.pb; + + if (lzma->dict_size < SQFS_META_BLOCK_SIZE) + lzma->dict_size = SQFS_META_BLOCK_SIZE; base->get_configuration = lzma_get_configuration; base->do_block = (cfg->flags & SQFS_COMP_FLAG_UNCOMPRESS) ? -- cgit v1.2.3