summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sqfs/compressor.h26
-rw-r--r--lib/common/comp_opt.c47
-rw-r--r--lib/sqfs/comp/compressor.c9
-rw-r--r--lib/sqfs/comp/lzma.c60
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=<value> 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=<value> Compression level. Value from %d to %d.\n"
-" Defaults to %d.\n"
+" For XZ, defaults to %d, for LZMA defaults to %d.\n"
" lc=<value> 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) ?