diff --git a/src/xz/coder.c b/src/xz/coder.c index 2ee0c704..8d882d26 100644 --- a/src/xz/coder.c +++ b/src/xz/coder.c @@ -168,7 +168,7 @@ coder_set_compression_settings(void) "with the .xz format")); // Print the selected filter chain. - message_filters(V_DEBUG, filters); + message_filters_show(V_DEBUG, filters); // If using --format=raw, we can be decoding. The memusage function // also validates the filter chain and the options used for the diff --git a/src/xz/message.c b/src/xz/message.c index f24e98e9..94140132 100644 --- a/src/xz/message.c +++ b/src/xz/message.c @@ -876,16 +876,37 @@ message_mem_needed(enum message_verbosity v, uint64_t memusage) } -extern void -message_filters(enum message_verbosity v, const lzma_filter *filters) +/// \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) { - if (v > verbosity) - return; + static char buf[16]; - fprintf(stderr, _("%s: Filter chain:"), progname); + 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 const char * +message_filters_get(const lzma_filter *filters, bool all_known) +{ + static char buf[512]; + + char *pos = buf; + size_t left = sizeof(buf); for (size_t i = 0; filters[i].id != LZMA_VLI_UNKNOWN; ++i) { - fprintf(stderr, " --"); + // 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: @@ -894,96 +915,128 @@ message_filters(enum message_verbosity v, const lzma_filter *filters) const char *mode; const char *mf; - switch (opt->mode) { - case LZMA_MODE_FAST: - mode = "fast"; - break; + if (all_known) { + switch (opt->mode) { + case LZMA_MODE_FAST: + mode = "fast"; + break; - case LZMA_MODE_NORMAL: - mode = "normal"; - break; + case LZMA_MODE_NORMAL: + mode = "normal"; + break; - default: - mode = "UNKNOWN"; - 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; + } } - switch (opt->mf) { - case LZMA_MF_HC3: - mf = "hc3"; - 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)); - case LZMA_MF_HC4: - mf = "hc4"; - break; + // 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); - 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; - } - - fprintf(stderr, "lzma%c=dict=%" PRIu32 + // 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, - filters[i].id == LZMA_FILTER_LZMA2 - ? '2' : '1', - opt->dict_size, opt->lc, opt->lp, opt->pb, mode, opt->nice_len, mf, opt->depth); break; } case LZMA_FILTER_X86: - fprintf(stderr, "x86"); - break; - case LZMA_FILTER_POWERPC: - fprintf(stderr, "powerpc"); - break; - case LZMA_FILTER_IA64: - fprintf(stderr, "ia64"); - break; - case LZMA_FILTER_ARM: - fprintf(stderr, "arm"); - break; - case LZMA_FILTER_ARMTHUMB: - fprintf(stderr, "armthumb"); - break; + 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); - case LZMA_FILTER_SPARC: - fprintf(stderr, "sparc"); break; + } case LZMA_FILTER_DELTA: { const lzma_options_delta *opt = filters[i].options; - fprintf(stderr, "delta=dist=%" PRIu32, opt->dist); + my_snprintf(&pos, &left, "delta=dist=%" PRIu32, + opt->dist); break; } default: - fprintf(stderr, "UNKNOWN"); + // This should be possible only if liblzma is + // newer than the xz tool. + my_snprintf(&pos, &left, "UNKNOWN"); break; } } - fputc('\n', stderr); + return buf; +} + + +extern void +message_filters_show(enum message_verbosity v, const lzma_filter *filters) +{ + if (v > verbosity) + return; + + fprintf(stderr, _("%s: Filter chain: %s\n"), progname, + message_filters_get(filters, true)); return; } diff --git a/src/xz/message.h b/src/xz/message.h index 7d637dfe..8f011874 100644 --- a/src/xz/message.h +++ b/src/xz/message.h @@ -86,8 +86,20 @@ extern const char *message_strm(lzma_ret code); extern void message_mem_needed(enum message_verbosity v, uint64_t memusage); +/// \brief Get the filter chain as a string +/// +/// \param filters Pointer to the filter chain +/// \param all_known If true, all filter options are printed. +/// If false, only the options that get stored +/// into .xz headers are printed. +/// +/// \return Pointer to a statically allocated buffer. +extern const char *message_filters_get( + const lzma_filter *filters, bool all_known); + + /// Print the filter chain. -extern void message_filters( +extern void message_filters_show( enum message_verbosity v, const lzma_filter *filters);