diff --git a/src/xz/list.c b/src/xz/list.c index 98307eb2..e71fbe20 100644 --- a/src/xz/list.c +++ b/src/xz/list.c @@ -29,9 +29,12 @@ typedef struct { /// Uncompressed Size fields bool all_have_sizes; + /// Oldest XZ Utils version that will decompress the file + uint32_t min_version; + } xz_file_info; -#define XZ_FILE_INFO_INIT { NULL, 0, 0, true } +#define XZ_FILE_INFO_INIT { NULL, 0, 0, true, 50000002 } /// Information about a .xz Block @@ -104,8 +107,32 @@ static struct { uint64_t stream_padding; uint64_t memusage_max; uint32_t checks; + uint32_t min_version; bool all_have_sizes; -} totals = { 0, 0, 0, 0, 0, 0, 0, 0, true }; +} totals = { 0, 0, 0, 0, 0, 0, 0, 0, 0, true }; + + +/// Convert XZ Utils version number to a string. +static const char * +xz_ver_to_str(uint32_t ver) +{ + static char buf[32]; + + unsigned int major = ver / 10000000U; + ver -= major * 10000000U; + + unsigned int minor = ver / 10000U; + ver -= minor * 10000U; + + unsigned int patch = ver / 10U; + ver -= patch * 10U; + + const char *stability = ver == 0 ? "alpha" : ver == 1 ? "beta" : ""; + + snprintf(buf, sizeof(buf), "%u.%u.%u%s", + major, minor, patch, stability); + return buf; +} /// \brief Parse the Index(es) from the given .xz file @@ -452,6 +479,21 @@ parse_block_header(file_pair *pair, const lzma_index_iter *iter, if (xfi->memusage_max < bhi->memusage) xfi->memusage_max = bhi->memusage; + // Determine the minimum XZ Utils version that supports this Block. + // + // Currently the only thing that 5.0.0 doesn't support is empty + // LZMA2 Block. This bug was fixed in 5.0.3. + { + size_t i = 0; + while (filters[i + 1].id != LZMA_VLI_UNKNOWN) + ++i; + + if (filters[i].id == LZMA_FILTER_LZMA2 + && iter->block.uncompressed_size == 0 + && xfi->min_version < 50000032U) + xfi->min_version = 50000032U; + } + // Convert the filter chain to human readable form. message_filters_to_str(bhi->filter_chain, filters, false); @@ -830,6 +872,8 @@ print_info_adv(xz_file_info *xfi, file_pair *pair) round_up_to_mib(xfi->memusage_max), 0)); printf(_(" Sizes in headers: %s\n"), xfi->all_have_sizes ? _("Yes") : _("No")); + printf(_(" Minimum XZ Utils version: %s\n"), + xz_ver_to_str(xfi->min_version)); } return false; @@ -912,9 +956,10 @@ print_info_robot(xz_file_info *xfi, file_pair *pair) } if (message_verbosity_get() >= V_DEBUG) - printf("summary\t%" PRIu64 "\t%s\n", + printf("summary\t%" PRIu64 "\t%s\t%" PRIu32 "\n", xfi->memusage_max, - xfi->all_have_sizes ? "yes" : "no"); + xfi->all_have_sizes ? "yes" : "no", + xfi->min_version); return false; } @@ -935,6 +980,9 @@ update_totals(const xz_file_info *xfi) if (totals.memusage_max < xfi->memusage_max) totals.memusage_max = xfi->memusage_max; + if (totals.min_version < xfi->min_version) + totals.min_version = xfi->min_version; + totals.all_have_sizes &= xfi->all_have_sizes; return; @@ -999,6 +1047,8 @@ print_totals_adv(void) round_up_to_mib(totals.memusage_max), 0)); printf(_(" Sizes in headers: %s\n"), totals.all_have_sizes ? _("Yes") : _("No")); + printf(_(" Minimum XZ Utils version: %s\n"), + xz_ver_to_str(totals.min_version)); } return; @@ -1024,9 +1074,10 @@ print_totals_robot(void) totals.files); if (message_verbosity_get() >= V_DEBUG) - printf("\t%" PRIu64 "\t%s", + printf("\t%" PRIu64 "\t%s\t%" PRIu32, totals.memusage_max, - totals.all_have_sizes ? "yes" : "no"); + totals.all_have_sizes ? "yes" : "no", + totals.min_version); putchar('\n');