From 7484744af6cbabe81e92af7d9e061dfd597fff7b Mon Sep 17 00:00:00 2001 From: Lasse Collin Date: Mon, 28 Nov 2022 21:57:47 +0200 Subject: [PATCH] xz: Use lzma_str_from_filters(). Two uses: Displaying encoder filter chain when compressing with -vv, and displaying the decoder filter chain in --list -vv. --- src/xz/list.c | 28 ++++++-- src/xz/message.c | 175 ++--------------------------------------------- 2 files changed, 28 insertions(+), 175 deletions(-) diff --git a/src/xz/list.c b/src/xz/list.c index b532a25b..ee61aeb9 100644 --- a/src/xz/list.c +++ b/src/xz/list.c @@ -52,10 +52,13 @@ typedef struct { uint64_t memusage; /// The filter chain of this Block in human-readable form - char filter_chain[FILTERS_STR_SIZE]; + char *filter_chain; } block_header_info; +#define BLOCK_HEADER_INFO_INIT { .filter_chain = NULL } +#define block_header_info_end(bhi) free((bhi)->filter_chain) + /// Strings ending in a colon. These are used for lines like /// " Foo: 123 MiB". These are grouped because translated strings @@ -566,10 +569,19 @@ parse_block_header(file_pair *pair, const lzma_index_iter *iter, } // Convert the filter chain to human readable form. - message_filters_to_str(bhi->filter_chain, filters, false); + const lzma_ret str_ret = lzma_str_from_filters( + &bhi->filter_chain, filters, + LZMA_STR_DECODER | LZMA_STR_GETOPT_LONG, NULL); // Free the memory allocated by lzma_block_header_decode(). lzma_filters_free(filters, NULL); + + // Check if the stringification succeeded. + if (str_ret != LZMA_OK) { + message_error("%s: %s", pair->src_name, message_strm(str_ret)); + return true; + } + return false; data_error: @@ -864,9 +876,6 @@ print_info_adv(xz_file_info *xfi, file_pair *pair) // Cache the verbosity level to a local variable. const bool detailed = message_verbosity_get() >= V_DEBUG; - // Information collected from Block Headers - block_header_info bhi; - // Print information about the Blocks but only if there is // at least one Block. if (lzma_index_block_count(xfi->idx) > 0) { @@ -916,8 +925,11 @@ print_info_adv(xz_file_info *xfi, file_pair *pair) // Iterate over the Blocks. while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) { + // If in detailed mode, collect the information from + // Block Header before starting to print the next line. + block_header_info bhi = BLOCK_HEADER_INFO_INIT; if (detailed && parse_details(pair, &iter, &bhi, xfi)) - return true; + return true; const char *cols1[4] = { uint64_to_str(iter.stream.number, 0), @@ -1001,6 +1013,7 @@ print_info_adv(xz_file_info *xfi, file_pair *pair) } putchar('\n'); + block_header_info_end(&bhi); } } @@ -1058,9 +1071,9 @@ print_info_robot(xz_file_info *xfi, file_pair *pair) iter.stream.padding); lzma_index_iter_rewind(&iter); - block_header_info bhi; while (!lzma_index_iter_next(&iter, LZMA_INDEX_ITER_BLOCK)) { + block_header_info bhi = BLOCK_HEADER_INFO_INIT; if (message_verbosity_get() >= V_DEBUG && parse_details( pair, &iter, &bhi, xfi)) @@ -1091,6 +1104,7 @@ print_info_robot(xz_file_info *xfi, file_pair *pair) bhi.filter_chain); putchar('\n'); + block_header_info_end(&bhi); } } diff --git a/src/xz/message.c b/src/xz/message.c index d4883709..4b577656 100644 --- a/src/xz/message.c +++ b/src/xz/message.c @@ -900,181 +900,20 @@ message_mem_needed(enum message_verbosity v, uint64_t memusage) } -/// \brief Convert uint32_t to a nice string for --lzma[12]=dict=SIZE -/// -/// The idea is to use KiB or MiB suffix when possible. -static const char * -uint32_to_optstr(uint32_t num) -{ - static char buf[16]; - - if ((num & ((UINT32_C(1) << 20) - 1)) == 0) - snprintf(buf, sizeof(buf), "%" PRIu32 "MiB", num >> 20); - else if ((num & ((UINT32_C(1) << 10) - 1)) == 0) - snprintf(buf, sizeof(buf), "%" PRIu32 "KiB", num >> 10); - else - snprintf(buf, sizeof(buf), "%" PRIu32, num); - - return buf; -} - - -extern void -message_filters_to_str(char buf[FILTERS_STR_SIZE], - const lzma_filter *filters, bool all_known) -{ - char *pos = buf; - size_t left = FILTERS_STR_SIZE; - - for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) { - // Add the dashes for the filter option. A space is - // needed after the first and later filters. - my_snprintf(&pos, &left, "%s", i == 0 ? "--" : " --"); - - switch (filters[i].id) { - case LZMA_FILTER_LZMA1: - case LZMA_FILTER_LZMA2: { - const lzma_options_lzma *opt = filters[i].options; - const char *mode = NULL; - const char *mf = NULL; - - if (all_known) { - switch (opt->mode) { - case LZMA_MODE_FAST: - mode = "fast"; - break; - - case LZMA_MODE_NORMAL: - mode = "normal"; - break; - - default: - mode = "UNKNOWN"; - break; - } - - switch (opt->mf) { - case LZMA_MF_HC3: - mf = "hc3"; - break; - - case LZMA_MF_HC4: - mf = "hc4"; - break; - - case LZMA_MF_BT2: - mf = "bt2"; - break; - - case LZMA_MF_BT3: - mf = "bt3"; - break; - - case LZMA_MF_BT4: - mf = "bt4"; - break; - - default: - mf = "UNKNOWN"; - break; - } - } - - // Add the filter name and dictionary size, which - // is always known. - my_snprintf(&pos, &left, "lzma%c=dict=%s", - filters[i].id == LZMA_FILTER_LZMA2 - ? '2' : '1', - uint32_to_optstr(opt->dict_size)); - - // With LZMA1 also lc/lp/pb are known when - // decompressing, but this function is never - // used to print information about .lzma headers. - assert(filters[i].id == LZMA_FILTER_LZMA2 - || all_known); - - // Print the rest of the options, which are known - // only when compressing. - if (all_known) - my_snprintf(&pos, &left, - ",lc=%" PRIu32 ",lp=%" PRIu32 - ",pb=%" PRIu32 - ",mode=%s,nice=%" PRIu32 ",mf=%s" - ",depth=%" PRIu32, - opt->lc, opt->lp, opt->pb, - mode, opt->nice_len, mf, opt->depth); - break; - } - - case LZMA_FILTER_X86: - case LZMA_FILTER_POWERPC: - case LZMA_FILTER_IA64: - case LZMA_FILTER_ARM: - case LZMA_FILTER_ARMTHUMB: - case LZMA_FILTER_SPARC: { - static const char bcj_names[][9] = { - "x86", - "powerpc", - "ia64", - "arm", - "armthumb", - "sparc", - }; - - const lzma_options_bcj *opt = filters[i].options; - my_snprintf(&pos, &left, "%s", bcj_names[filters[i].id - - LZMA_FILTER_X86]); - - // Show the start offset only when really needed. - if (opt != NULL && opt->start_offset != 0) - my_snprintf(&pos, &left, "=start=%" PRIu32, - opt->start_offset); - - break; - } - - case LZMA_FILTER_ARM64: { - // FIXME TODO: Merge with the above generic BCJ list - // once the Filter ID is changed to the final value. - const lzma_options_bcj *opt = filters[i].options; - my_snprintf(&pos, &left, "arm64"); - - // Show the start offset only when really needed. - if (opt != NULL && opt->start_offset != 0) - my_snprintf(&pos, &left, "=start=%" PRIu32, - opt->start_offset); - - break; - } - - case LZMA_FILTER_DELTA: { - const lzma_options_delta *opt = filters[i].options; - my_snprintf(&pos, &left, "delta=dist=%" PRIu32, - opt->dist); - break; - } - - default: - // This should be possible only if liblzma is - // newer than the xz tool. - my_snprintf(&pos, &left, "UNKNOWN"); - break; - } - } - - return; -} - - extern void message_filters_show(enum message_verbosity v, const lzma_filter *filters) { if (v > verbosity) return; - char buf[FILTERS_STR_SIZE]; - message_filters_to_str(buf, filters, true); + char *buf; + const lzma_ret ret = lzma_str_from_filters(&buf, filters, + LZMA_STR_ENCODER | LZMA_STR_GETOPT_LONG, NULL); + if (ret != LZMA_OK) + message_fatal("%s", message_strm(ret)); + fprintf(stderr, _("%s: Filter chain: %s\n"), progname, buf); + free(buf); return; }