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.
This commit is contained in:
Jia Tan 2023-01-06 00:02:29 +08:00
parent 2c189bb00a
commit 9ded880a02
3 changed files with 58 additions and 4 deletions

View File

@ -136,7 +136,8 @@ static void
parse_real(args_info *args, int argc, char **argv) parse_real(args_info *args, int argc, char **argv)
{ {
enum { enum {
OPT_X86 = INT_MIN, OPT_FILTERS = INT_MIN,
OPT_X86,
OPT_POWERPC, OPT_POWERPC,
OPT_IA64, OPT_IA64,
OPT_ARM, OPT_ARM,
@ -206,6 +207,7 @@ parse_real(args_info *args, int argc, char **argv)
{ "best", no_argument, NULL, '9' }, { "best", no_argument, NULL, '9' },
// Filters // Filters
{ "filters", optional_argument, NULL, OPT_FILTERS},
{ "lzma1", optional_argument, NULL, OPT_LZMA1 }, { "lzma1", optional_argument, NULL, OPT_LZMA1 },
{ "lzma2", optional_argument, NULL, OPT_LZMA2 }, { "lzma2", optional_argument, NULL, OPT_LZMA2 },
{ "x86", optional_argument, NULL, OPT_X86 }, { "x86", optional_argument, NULL, OPT_X86 },
@ -372,7 +374,10 @@ parse_real(args_info *args, int argc, char **argv)
opt_mode = MODE_COMPRESS; opt_mode = MODE_COMPRESS;
break; break;
// Filter setup // --filters
case OPT_FILTERS:
coder_add_filters_from_str(optarg);
break;
case OPT_X86: case OPT_X86:
coder_add_filter(LZMA_FILTER_X86, coder_add_filter(LZMA_FILTER_X86,

View File

@ -45,6 +45,11 @@ static uint32_t filters_count = 0;
/// Number of the preset (0-9) /// Number of the preset (0-9)
static uint32_t preset_number = LZMA_PRESET_DEFAULT; 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 /// Integrity check type
static lzma_check check; static lzma_check check;
@ -77,14 +82,15 @@ coder_set_check(lzma_check new_check)
static void static void
forget_filter_chain(void) forget_filter_chain(void)
{ {
// Setting a preset makes us forget a possibly defined custom // Setting a preset or using --filters makes us forget
// filter chain. // the earlier custom filter chain (if any).
while (filters_count > 0) { while (filters_count > 0) {
--filters_count; --filters_count;
free(filters[filters_count].options); free(filters[filters_count].options);
filters[filters_count].options = NULL; filters[filters_count].options = NULL;
} }
string_to_filter_used = false;
return; return;
} }
@ -114,6 +120,9 @@ coder_add_filter(lzma_vli id, void *options)
if (filters_count == LZMA_FILTERS_MAX) if (filters_count == LZMA_FILTERS_MAX)
message_fatal(_("Maximum number of filters is four")); message_fatal(_("Maximum number of filters is four"));
if (string_to_filter_used)
forget_filter_chain();
filters[filters_count].id = id; filters[filters_count].id = id;
filters[filters_count].options = options; filters[filters_count].options = options;
++filters_count; ++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__)) static void lzma_attribute((__noreturn__))
memlimit_too_small(uint64_t memory_usage) memlimit_too_small(uint64_t memory_usage)
{ {

View File

@ -77,3 +77,6 @@ extern void coder_run(const char *filename);
/// Free the memory allocated for the coder and kill the worker threads. /// Free the memory allocated for the coder and kill the worker threads.
extern void coder_free(void); extern void coder_free(void);
#endif #endif
/// Create filter chain from string
extern void coder_add_filters_from_str(const char *filter_str);