]> git.ipfire.org Git - thirdparty/xz.git/commitdiff
xz: Add --filters option to CLI.
authorJia Tan <jiat0218@gmail.com>
Thu, 5 Jan 2023 16:02:29 +0000 (00:02 +0800)
committerJia Tan <jiat0218@gmail.com>
Mon, 17 Jul 2023 15:34:55 +0000 (23:34 +0800)
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.

src/xz/args.c
src/xz/coder.c
src/xz/coder.h

index b831946f78b587425c939d7a29fd4e300e561b45..e21aee93278ab0c3b27925d8baea35ee602a5aac 100644 (file)
@@ -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,
index 05f228882b735af547c3637c34b845ffe989e611..b998cb2bfdb4239be1eccb5cb51d06456d41f3e4 100644 (file)
@@ -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)
 {
index b4f43a2bf21c34992574158fa0dcfe591a59d597..997d2586776e743e33b8fe063870668d7ad366a7 100644 (file)
@@ -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);