aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJia Tan <jiat0218@gmail.com>2023-01-06 00:02:29 +0800
committerJia Tan <jiat0218@gmail.com>2023-07-17 23:34:55 +0800
commit9ded880a0221f4d1256845fc4ab957ffd377c760 (patch)
tree29c2b360d4cd4156ef73d40dcbab00dc5a76a32b
parentTests: Improve feature testing for skipping. (diff)
downloadxz-9ded880a0221f4d1256845fc4ab957ffd377c760.tar.xz
xz: Add --filters option to CLI.
The --filters option uses the new lzma_str_to_filters() function to convert a string into a full filter chain. Using this option will reset all previous filters set by --preset, --[filter], or --filters.
-rw-r--r--src/xz/args.c9
-rw-r--r--src/xz/coder.c50
-rw-r--r--src/xz/coder.h3
3 files changed, 58 insertions, 4 deletions
diff --git a/src/xz/args.c b/src/xz/args.c
index b831946f..e21aee93 100644
--- a/src/xz/args.c
+++ b/src/xz/args.c
@@ -136,7 +136,8 @@ static void
parse_real(args_info *args, int argc, char **argv)
{
enum {
- OPT_X86 = INT_MIN,
+ OPT_FILTERS = INT_MIN,
+ OPT_X86,
OPT_POWERPC,
OPT_IA64,
OPT_ARM,
@@ -206,6 +207,7 @@ parse_real(args_info *args, int argc, char **argv)
{ "best", no_argument, NULL, '9' },
// Filters
+ { "filters", optional_argument, NULL, OPT_FILTERS},
{ "lzma1", optional_argument, NULL, OPT_LZMA1 },
{ "lzma2", optional_argument, NULL, OPT_LZMA2 },
{ "x86", optional_argument, NULL, OPT_X86 },
@@ -372,7 +374,10 @@ parse_real(args_info *args, int argc, char **argv)
opt_mode = MODE_COMPRESS;
break;
- // Filter setup
+ // --filters
+ case OPT_FILTERS:
+ coder_add_filters_from_str(optarg);
+ break;
case OPT_X86:
coder_add_filter(LZMA_FILTER_X86,
diff --git a/src/xz/coder.c b/src/xz/coder.c
index 05f22888..b998cb2b 100644
--- a/src/xz/coder.c
+++ b/src/xz/coder.c
@@ -45,6 +45,11 @@ static uint32_t filters_count = 0;
/// Number of the preset (0-9)
static uint32_t preset_number = LZMA_PRESET_DEFAULT;
+/// True if the current filter chain was set using the --filters option.
+/// The filter chain is reset if a preset option (like -9) or an old-style
+/// filter option (like --lzma2) is used after a --filters option.
+static bool string_to_filter_used = false;
+
/// Integrity check type
static lzma_check check;
@@ -77,14 +82,15 @@ coder_set_check(lzma_check new_check)
static void
forget_filter_chain(void)
{
- // Setting a preset makes us forget a possibly defined custom
- // filter chain.
+ // Setting a preset or using --filters makes us forget
+ // the earlier custom filter chain (if any).
while (filters_count > 0) {
--filters_count;
free(filters[filters_count].options);
filters[filters_count].options = NULL;
}
+ string_to_filter_used = false;
return;
}
@@ -114,6 +120,9 @@ coder_add_filter(lzma_vli id, void *options)
if (filters_count == LZMA_FILTERS_MAX)
message_fatal(_("Maximum number of filters is four"));
+ if (string_to_filter_used)
+ forget_filter_chain();
+
filters[filters_count].id = id;
filters[filters_count].options = options;
++filters_count;
@@ -128,6 +137,43 @@ coder_add_filter(lzma_vli id, void *options)
}
+extern void
+coder_add_filters_from_str(const char *filter_str)
+{
+ // Forget presets and previously defined filter chain. See
+ // coder_add_filter() above for why preset_number must be reset too.
+ forget_filter_chain();
+ preset_number = LZMA_PRESET_DEFAULT;
+
+ string_to_filter_used = true;
+
+ // Include LZMA_STR_ALL_FILTERS so this can be used with --format=raw.
+ int error_pos;
+ const char *err = lzma_str_to_filters(filter_str, &error_pos,
+ filters, LZMA_STR_ALL_FILTERS, NULL);
+
+ if (err != NULL) {
+ // FIXME? The message in err isn't translated.
+ // Including the translations in the xz translations is
+ // slightly ugly but possible. Creating a new domain for
+ // liblzma might not be worth it especially since on some
+ // OSes it adds extra dependencies to translation libraries.
+ message(V_ERROR, _("Error in --filters=FILTERS option:"));
+ message(V_ERROR, "%s", filter_str);
+ message(V_ERROR, "%*s^", error_pos, "");
+ message_fatal("%s", err);
+ }
+
+ // Set the filters_count to be the number of filters converted from
+ // the string.
+ for (filters_count = 0; filters[filters_count].id != LZMA_VLI_UNKNOWN;
+ ++filters_count) ;
+
+ assert(filters_count > 0);
+ return;
+}
+
+
static void lzma_attribute((__noreturn__))
memlimit_too_small(uint64_t memory_usage)
{
diff --git a/src/xz/coder.h b/src/xz/coder.h
index b4f43a2b..997d2586 100644
--- a/src/xz/coder.h
+++ b/src/xz/coder.h
@@ -77,3 +77,6 @@ extern void coder_run(const char *filename);
/// Free the memory allocated for the coder and kill the worker threads.
extern void coder_free(void);
#endif
+
+/// Create filter chain from string
+extern void coder_add_filters_from_str(const char *filter_str);