aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/sqfs/compressor.h11
-rw-r--r--lib/common/comp_opt.c8
-rw-r--r--lib/sqfs/comp/compressor.c1
-rw-r--r--lib/sqfs/comp/lzma.c49
4 files changed, 58 insertions, 11 deletions
diff --git a/include/sqfs/compressor.h b/include/sqfs/compressor.h
index bdb942e..a257c3a 100644
--- a/include/sqfs/compressor.h
+++ b/include/sqfs/compressor.h
@@ -262,6 +262,17 @@ typedef enum {
SQFS_COMP_FLAG_LZ4_ALL = 0x0001,
/**
+ * @brief Tell the LZMAv1 compressor to try the "extreme" option.
+ *
+ * The "extreme" option means that the compressor should try some
+ * strategies that it normally wouldn't, that may drastically increase
+ * compression time, but will not increase the decompressors memory
+ * consumption.
+ */
+ SQFS_COMP_FLAG_LZMA_EXTREME = 0x0001,
+ SQFS_COMP_FLAG_LZMA_ALL = 0x0001,
+
+ /**
* @brief For XZ, set this to select the x86 BCJ filter.
*/
SQFS_COMP_FLAG_XZ_X86 = 0x0001,
diff --git a/lib/common/comp_opt.c b/lib/common/comp_opt.c
index 323fa4f..c279f1e 100644
--- a/lib/common/comp_opt.c
+++ b/lib/common/comp_opt.c
@@ -34,6 +34,10 @@ static const flag_t xz_flags[] = {
{ "extreme", SQFS_COMP_FLAG_XZ_EXTREME },
};
+static const flag_t lzma_flags[] = {
+ { "extreme", SQFS_COMP_FLAG_LZMA_EXTREME },
+};
+
static const flag_t lz4_flags[] = {
{ "hc", SQFS_COMP_FLAG_LZ4_HC },
};
@@ -131,6 +135,10 @@ int compressor_cfg_init_options(sqfs_compressor_config_t *cfg,
flags = xz_flags;
num_flags = sizeof(xz_flags) / sizeof(xz_flags[0]);
break;
+ case SQFS_COMP_LZMA:
+ flags = lzma_flags;
+ num_flags = sizeof(lzma_flags) / sizeof(lzma_flags[0]);
+ break;
case SQFS_COMP_LZ4:
flags = lz4_flags;
num_flags = sizeof(lz4_flags) / sizeof(lz4_flags[0]);
diff --git a/lib/sqfs/comp/compressor.c b/lib/sqfs/comp/compressor.c
index ea53339..2a0cebb 100644
--- a/lib/sqfs/comp/compressor.c
+++ b/lib/sqfs/comp/compressor.c
@@ -171,6 +171,7 @@ int sqfs_compressor_config_init(sqfs_compressor_config_t *cfg,
cfg->opt.xz.pb = SQFS_XZ_DEFAULT_PB;
break;
case SQFS_COMP_LZMA:
+ flag_mask |= SQFS_COMP_FLAG_LZMA_ALL;
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 2a6cd1f..8db018d 100644
--- a/lib/sqfs/comp/lzma.c
+++ b/lib/sqfs/comp/lzma.c
@@ -24,6 +24,7 @@
typedef struct {
sqfs_compressor_t base;
size_t block_size;
+ sqfs_u32 flags;
} lzma_compressor_t;
static int lzma_write_options(sqfs_compressor_t *base, sqfs_file_t *file)
@@ -39,18 +40,15 @@ static int lzma_read_options(sqfs_compressor_t *base, sqfs_file_t *file)
return SQFS_ERROR_UNSUPPORTED;
}
-static sqfs_s32 lzma_comp_block(sqfs_compressor_t *base, const sqfs_u8 *in,
- sqfs_u32 size, sqfs_u8 *out, sqfs_u32 outsize)
+static sqfs_s32 try_compress(lzma_compressor_t *lzma, sqfs_u32 preset,
+ const sqfs_u8 *in, size_t size,
+ sqfs_u8 *out, size_t outsize)
{
- lzma_compressor_t *lzma = (lzma_compressor_t *)base;
lzma_stream strm = LZMA_STREAM_INIT;
lzma_options_lzma opt;
int ret;
- if (outsize < LZMA_HEADER_SIZE || size >= 0x7FFFFFFF)
- return SQFS_ERROR_ARG_INVALID;
-
- lzma_lzma_preset(&opt, LZMA_DEFAULT_LEVEL);
+ lzma_lzma_preset(&opt, preset);
opt.dict_size = lzma->block_size;
if (lzma_alone_encoder(&strm, &opt) != LZMA_OK) {
@@ -83,6 +81,33 @@ static sqfs_s32 lzma_comp_block(sqfs_compressor_t *base, const sqfs_u8 *in,
return strm.total_out;
}
+static sqfs_s32 lzma_comp_block(sqfs_compressor_t *base, const sqfs_u8 *in,
+ sqfs_u32 size, sqfs_u8 *out, sqfs_u32 outsize)
+{
+ lzma_compressor_t *lzma = (lzma_compressor_t *)base;
+ sqfs_s32 ret, smallest;
+ sqfs_u32 preset;
+
+ if (outsize < LZMA_HEADER_SIZE || size >= 0x7FFFFFFF)
+ return SQFS_ERROR_ARG_INVALID;
+
+ preset = LZMA_DEFAULT_LEVEL;
+ ret = try_compress(lzma, preset, in, size, out, outsize);
+ if (ret < 0 || !(lzma->flags & SQFS_COMP_FLAG_LZMA_EXTREME))
+ return ret;
+
+ preset |= LZMA_PRESET_EXTREME;
+ smallest = ret;
+
+ ret = try_compress(lzma, preset, in, size, out, outsize);
+ if (ret < 0 || (ret > 0 && (smallest == 0 || ret < smallest)))
+ return ret;
+
+ preset &= ~LZMA_PRESET_EXTREME;
+ return smallest == 0 ? 0 :
+ try_compress(lzma, preset, in, size, out, outsize);
+}
+
static sqfs_s32 lzma_uncomp_block(sqfs_compressor_t *base, const sqfs_u8 *in,
sqfs_u32 size, sqfs_u8 *out, sqfs_u32 outsize)
{
@@ -151,9 +176,7 @@ static void lzma_get_configuration(const sqfs_compressor_t *base,
memset(cfg, 0, sizeof(*cfg));
cfg->id = SQFS_COMP_LZMA;
cfg->block_size = lzma->block_size;
-
- if (base->do_block == lzma_uncomp_block)
- cfg->flags |= SQFS_COMP_FLAG_UNCOMPRESS;
+ cfg->flags = lzma->flags;
}
static sqfs_object_t *lzma_create_copy(const sqfs_object_t *cmp)
@@ -176,8 +199,11 @@ int lzma_compressor_create(const sqfs_compressor_config_t *cfg,
{
sqfs_compressor_t *base;
lzma_compressor_t *lzma;
+ sqfs_u32 mask;
+
+ mask = SQFS_COMP_FLAG_GENERIC_ALL | SQFS_COMP_FLAG_LZMA_ALL;
- if (cfg->flags & ~SQFS_COMP_FLAG_GENERIC_ALL)
+ if (cfg->flags & ~mask)
return SQFS_ERROR_UNSUPPORTED;
lzma = calloc(1, sizeof(*lzma));
@@ -186,6 +212,7 @@ int lzma_compressor_create(const sqfs_compressor_config_t *cfg,
return SQFS_ERROR_ALLOC;
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;