From d6af7f347077b22403133239592e478931307759 Mon Sep 17 00:00:00 2001 From: Jia Tan Date: Tue, 18 Apr 2023 20:29:09 +0800 Subject: xz: Create command line options for filters[1-9]. The new command line options are meant to be combined with --block-list. They work as an optional extension to --block-list to specify a custom filter chain for each block listed. The new options allow the creation of up to 9 reusable filter chains. For instance: xz --block-list=1:10MiB,3:5MiB,,2:5MiB,1:0 --filters1=delta--lzma2 \ --filters2=x86--lzma2 --filters3=arm64--lzma2 Will create the following blocks: 1. A block of size 10 MiB with filter chain delta, lzma2. 2. A block of size 5 MiB with filter chain arm64, lzma2. 3. A block of size 5 MiB with filter chain arm64, lzma2. 4. A block of size 5 MiB with filter chain x86, lzma2. 5. A block containing the rest of the file contents with filter chain delta, lzma2. --- src/xz/args.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 75 insertions(+), 7 deletions(-) (limited to 'src/xz/args.c') diff --git a/src/xz/args.c b/src/xz/args.c index e21aee93..b2eee193 100644 --- a/src/xz/args.c +++ b/src/xz/args.c @@ -83,14 +83,14 @@ parse_block_list(const char *str_const) ++count; // Prevent an unlikely integer overflow. - if (count > SIZE_MAX / sizeof(uint64_t) - 1) + if (count > SIZE_MAX / sizeof(block_list_entry) - 1) message_fatal(_("%s: Too many arguments to --block-list"), str); // Allocate memory to hold all the sizes specified. // If --block-list was specified already, its value is forgotten. free(opt_block_list); - opt_block_list = xmalloc((count + 1) * sizeof(uint64_t)); + opt_block_list = xmalloc((count + 1) * sizeof(block_list_entry)); for (size_t i = 0; i < count; ++i) { // Locate the next comma and replace it with \0. @@ -98,6 +98,40 @@ parse_block_list(const char *str_const) if (p != NULL) *p = '\0'; + // Use the default filter chain unless overridden. + opt_block_list[i].filters_index = 0; + + // To specify a filter chain, the block list entry may be + // prepended with "[filter-chain-number]:". The size is + // still required for every block. + // For instance: + // --block-list=2:10MiB,1:5MiB,,8MiB,0:0 + // + // Translates to: + // 1. Block of 10 MiB using filter chain 2 + // 2. Block of 5 MiB using filter chain 1 + // 3. Block of 5 MiB using filter chain 1 + // 4. Block of 8 MiB using the default filter chain + // 5. The last block uses the default filter chain + // + // The block list: + // --block-list=2:MiB,1:,0 + // + // Is not allowed because the second block does not specify + // the block size, only the filter chain. + if (str[0] >= '0' && str[0] <= '9' && str[1] == ':') { + if (str[2] == '\0') + message_fatal(_("In --block-list, block " + "size is missing after " + "filter chain number `%c:'"), + str[0]); + + int filter_num = str[0] - '0'; + opt_block_list[i].filters_index = + (uint32_t)filter_num; + str += 2; + } + if (str[0] == '\0') { // There is no string, that is, a comma follows // another comma. Use the previous value. @@ -107,17 +141,17 @@ parse_block_list(const char *str_const) assert(i > 0); opt_block_list[i] = opt_block_list[i - 1]; } else { - opt_block_list[i] = str_to_uint64("block-list", str, - 0, UINT64_MAX); + opt_block_list[i].size = str_to_uint64("block-list", + str, 0, UINT64_MAX); // Zero indicates no more new Blocks. - if (opt_block_list[i] == 0) { + if (opt_block_list[i].size == 0) { if (i + 1 != count) message_fatal(_("0 can only be used " "as the last element " "in --block-list")); - opt_block_list[i] = UINT64_MAX; + opt_block_list[i].size = UINT64_MAX; } } @@ -125,7 +159,7 @@ parse_block_list(const char *str_const) } // Terminate the array. - opt_block_list[count] = 0; + opt_block_list[count].size = 0; free(str_start); return; @@ -137,6 +171,16 @@ parse_real(args_info *args, int argc, char **argv) { enum { OPT_FILTERS = INT_MIN, + OPT_FILTERS1, + OPT_FILTERS2, + OPT_FILTERS3, + OPT_FILTERS4, + OPT_FILTERS5, + OPT_FILTERS6, + OPT_FILTERS7, + OPT_FILTERS8, + OPT_FILTERS9, + OPT_X86, OPT_POWERPC, OPT_IA64, @@ -208,6 +252,16 @@ parse_real(args_info *args, int argc, char **argv) // Filters { "filters", optional_argument, NULL, OPT_FILTERS}, + { "filters1", optional_argument, NULL, OPT_FILTERS1}, + { "filters2", optional_argument, NULL, OPT_FILTERS2}, + { "filters3", optional_argument, NULL, OPT_FILTERS3}, + { "filters4", optional_argument, NULL, OPT_FILTERS4}, + { "filters5", optional_argument, NULL, OPT_FILTERS5}, + { "filters6", optional_argument, NULL, OPT_FILTERS6}, + { "filters7", optional_argument, NULL, OPT_FILTERS7}, + { "filters8", optional_argument, NULL, OPT_FILTERS8}, + { "filters9", optional_argument, NULL, OPT_FILTERS9}, + { "lzma1", optional_argument, NULL, OPT_LZMA1 }, { "lzma2", optional_argument, NULL, OPT_LZMA2 }, { "x86", optional_argument, NULL, OPT_X86 }, @@ -379,6 +433,20 @@ parse_real(args_info *args, int argc, char **argv) coder_add_filters_from_str(optarg); break; + // --filters1...--filters9 + case OPT_FILTERS1: + case OPT_FILTERS2: + case OPT_FILTERS3: + case OPT_FILTERS4: + case OPT_FILTERS5: + case OPT_FILTERS6: + case OPT_FILTERS7: + case OPT_FILTERS8: + case OPT_FILTERS9: + coder_add_block_filters(optarg, + (size_t)(c - OPT_FILTERS)); + break; + case OPT_X86: coder_add_filter(LZMA_FILTER_X86, options_bcj(optarg)); -- cgit v1.2.3