mirror of https://git.tukaani.org/xz.git
Some xz command line tool improvements.
This commit is contained in:
parent
e33194e79d
commit
4820f10d0f
|
@ -53,7 +53,7 @@ parse_real(args_info *args, int argc, char **argv)
|
||||||
OPT_FILES0,
|
OPT_FILES0,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char short_opts[] = "cC:dfF:hHlLkM:p:qrS:tT:vVz123456789";
|
static const char short_opts[] = "cC:defF:hHlkM:qrS:tT:vVz0123456789";
|
||||||
|
|
||||||
static const struct option long_opts[] = {
|
static const struct option long_opts[] = {
|
||||||
// Operation mode
|
// Operation mode
|
||||||
|
@ -77,11 +77,11 @@ parse_real(args_info *args, int argc, char **argv)
|
||||||
// Basic compression settings
|
// Basic compression settings
|
||||||
{ "format", required_argument, NULL, 'F' },
|
{ "format", required_argument, NULL, 'F' },
|
||||||
{ "check", required_argument, NULL, 'C' },
|
{ "check", required_argument, NULL, 'C' },
|
||||||
{ "preset", required_argument, NULL, 'p' },
|
|
||||||
{ "memory", required_argument, NULL, 'M' },
|
{ "memory", required_argument, NULL, 'M' },
|
||||||
{ "threads", required_argument, NULL, 'T' },
|
{ "threads", required_argument, NULL, 'T' },
|
||||||
|
|
||||||
{ "fast", no_argument, NULL, '1' },
|
{ "extreme", no_argument, NULL, 'e' },
|
||||||
|
{ "fast", no_argument, NULL, '0' },
|
||||||
{ "best", no_argument, NULL, '9' },
|
{ "best", no_argument, NULL, '9' },
|
||||||
|
|
||||||
// Filters
|
// Filters
|
||||||
|
@ -114,20 +114,12 @@ parse_real(args_info *args, int argc, char **argv)
|
||||||
while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL))
|
while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL))
|
||||||
!= -1) {
|
!= -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
// gzip-like options
|
// Compression preset (also for decompression if --format=raw)
|
||||||
|
case '0': case '1': case '2': case '3': case '4':
|
||||||
case '1': case '2': case '3': case '4':
|
|
||||||
case '5': case '6': case '7': case '8': case '9':
|
case '5': case '6': case '7': case '8': case '9':
|
||||||
coder_set_preset(c - '0');
|
coder_set_preset(c - '0');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'p': {
|
|
||||||
const uint64_t preset = str_to_uint64(
|
|
||||||
"preset", optarg, 1, 9);
|
|
||||||
coder_set_preset(preset);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// --memory
|
// --memory
|
||||||
case 'M':
|
case 'M':
|
||||||
// On 32-bit systems, SIZE_MAX would make more sense
|
// On 32-bit systems, SIZE_MAX would make more sense
|
||||||
|
@ -162,6 +154,11 @@ parse_real(args_info *args, int argc, char **argv)
|
||||||
opt_mode = MODE_DECOMPRESS;
|
opt_mode = MODE_DECOMPRESS;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// --extreme
|
||||||
|
case 'e':
|
||||||
|
coder_set_extreme();
|
||||||
|
break;
|
||||||
|
|
||||||
// --force
|
// --force
|
||||||
case 'f':
|
case 'f':
|
||||||
opt_force = true;
|
opt_force = true;
|
||||||
|
|
|
@ -891,8 +891,8 @@ message_help(bool long_help)
|
||||||
}
|
}
|
||||||
|
|
||||||
puts(_(
|
puts(_(
|
||||||
" -p, --preset=NUM compression preset: 1-2 fast compression, 3-6 good\n"
|
" -0 .. -9 compression preset; 0-2 fast compression, 3-5 good\n"
|
||||||
" compression, 7-9 excellent compression; default is 7"));
|
" compression, 6-9 excellent compression; default is 6"));
|
||||||
|
|
||||||
puts(_(
|
puts(_(
|
||||||
" -M, --memory=NUM use roughly NUM bytes of memory at maximum; 0 indicates\n"
|
" -M, --memory=NUM use roughly NUM bytes of memory at maximum; 0 indicates\n"
|
||||||
|
|
|
@ -315,7 +315,7 @@ options_lzma(const char *str)
|
||||||
};
|
};
|
||||||
|
|
||||||
static const option_map opts[] = {
|
static const option_map opts[] = {
|
||||||
{ "preset", NULL, 1, 9 },
|
{ "preset", NULL, 0, 9 },
|
||||||
{ "dict", NULL, LZMA_DICT_SIZE_MIN,
|
{ "dict", NULL, LZMA_DICT_SIZE_MIN,
|
||||||
(UINT32_C(1) << 30) + (UINT32_C(1) << 29) },
|
(UINT32_C(1) << 30) + (UINT32_C(1) << 29) },
|
||||||
{ "lc", NULL, LZMA_LCLP_MIN, LZMA_LCLP_MAX },
|
{ "lc", NULL, LZMA_LCLP_MIN, LZMA_LCLP_MAX },
|
||||||
|
|
129
src/xz/process.c
129
src/xz/process.c
|
@ -34,14 +34,22 @@ static lzma_filter filters[LZMA_FILTERS_MAX + 1];
|
||||||
/// Number of filters. Zero indicates that we are using a preset.
|
/// Number of filters. Zero indicates that we are using a preset.
|
||||||
static size_t filters_count = 0;
|
static size_t filters_count = 0;
|
||||||
|
|
||||||
/// Number of the preset (1-9)
|
/// Number of the preset (0-9)
|
||||||
static size_t preset_number = 7;
|
static size_t preset_number = 6;
|
||||||
|
|
||||||
/// Indicate if no preset has been given. In that case, we will auto-adjust
|
/// True if we should auto-adjust the compression settings to use less memory
|
||||||
/// the compression preset so that it doesn't use too much RAM.
|
/// if memory usage limit is too low for the original settings.
|
||||||
// FIXME
|
static bool auto_adjust = true;
|
||||||
|
|
||||||
|
/// Indicate if no preset has been explicitly given. In that case, if we need
|
||||||
|
/// to auto-adjust for lower memory usage, we won't print a warning.
|
||||||
static bool preset_default = true;
|
static bool preset_default = true;
|
||||||
|
|
||||||
|
/// If a preset is used (no custom filter chain) and preset_extreme is true,
|
||||||
|
/// a significantly slower compression is used to achieve slightly better
|
||||||
|
/// compression ratio.
|
||||||
|
static bool preset_extreme = false;
|
||||||
|
|
||||||
/// Integrity check type
|
/// Integrity check type
|
||||||
static lzma_check check = LZMA_CHECK_CRC64;
|
static lzma_check check = LZMA_CHECK_CRC64;
|
||||||
|
|
||||||
|
@ -63,6 +71,14 @@ coder_set_preset(size_t new_preset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extern void
|
||||||
|
coder_set_extreme(void)
|
||||||
|
{
|
||||||
|
preset_extreme = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
coder_add_filter(lzma_vli id, void *options)
|
coder_add_filter(lzma_vli id, void *options)
|
||||||
{
|
{
|
||||||
|
@ -77,6 +93,15 @@ coder_add_filter(lzma_vli id, void *options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void lzma_attribute((noreturn))
|
||||||
|
memlimit_too_small(uint64_t memory_usage, uint64_t memory_limit)
|
||||||
|
{
|
||||||
|
message_fatal(_("Memory usage limit (%" PRIu64 " MiB) is too small "
|
||||||
|
"for the given filter setup (%" PRIu64 " MiB)"),
|
||||||
|
memory_limit >> 20, memory_usage >> 20);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
extern void
|
extern void
|
||||||
coder_set_compression_settings(void)
|
coder_set_compression_settings(void)
|
||||||
{
|
{
|
||||||
|
@ -99,6 +124,9 @@ coder_set_compression_settings(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the preset for LZMA1 or LZMA2.
|
// Get the preset for LZMA1 or LZMA2.
|
||||||
|
if (preset_extreme)
|
||||||
|
preset_number |= LZMA_PRESET_EXTREME;
|
||||||
|
|
||||||
if (lzma_lzma_preset(&opt_lzma, preset_number))
|
if (lzma_lzma_preset(&opt_lzma, preset_number))
|
||||||
message_bug();
|
message_bug();
|
||||||
|
|
||||||
|
@ -107,6 +135,8 @@ coder_set_compression_settings(void)
|
||||||
? LZMA_FILTER_LZMA1 : LZMA_FILTER_LZMA2;
|
? LZMA_FILTER_LZMA1 : LZMA_FILTER_LZMA2;
|
||||||
filters[0].options = &opt_lzma;
|
filters[0].options = &opt_lzma;
|
||||||
filters_count = 1;
|
filters_count = 1;
|
||||||
|
} else {
|
||||||
|
preset_default = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Terminate the filter options array.
|
// Terminate the filter options array.
|
||||||
|
@ -139,30 +169,77 @@ coder_set_compression_settings(void)
|
||||||
message_fatal("Unsupported filter chain or filter options");
|
message_fatal("Unsupported filter chain or filter options");
|
||||||
|
|
||||||
// Print memory usage info.
|
// Print memory usage info.
|
||||||
message(V_DEBUG, _("%" PRIu64 " MiB of memory is required per thread, "
|
message(V_DEBUG, _("%'" PRIu64 " MiB (%'" PRIu64 " B) of memory is "
|
||||||
"limit is %" PRIu64 " MiB"),
|
"required per thread, "
|
||||||
memory_usage / (1024 * 1024),
|
"limit is %'" PRIu64 " MiB (%'" PRIu64 " B)"),
|
||||||
memory_limit / (1024 * 1024));
|
memory_usage >> 20, memory_usage,
|
||||||
|
memory_limit >> 20, memory_limit);
|
||||||
|
|
||||||
if (preset_default) {
|
if (memory_usage > memory_limit) {
|
||||||
// When no preset was explicitly requested, we use the default
|
// If --no-auto-adjust was used or we didn't find LZMA1 or
|
||||||
// preset only if the memory usage limit allows. Otherwise we
|
// LZMA2 as the last filter, give an error immediatelly.
|
||||||
// select a lower preset automatically.
|
// --format=raw implies --no-auto-adjust.
|
||||||
while (memory_usage > memory_limit) {
|
if (!auto_adjust || opt_format == FORMAT_RAW)
|
||||||
if (preset_number == 1)
|
memlimit_too_small(memory_usage, memory_limit);
|
||||||
message_fatal(_("Memory usage limit is too "
|
|
||||||
"small for any internal "
|
|
||||||
"filter preset"));
|
|
||||||
|
|
||||||
if (lzma_lzma_preset(&opt_lzma, --preset_number))
|
assert(opt_mode == MODE_COMPRESS);
|
||||||
message_bug();
|
|
||||||
|
// Look for the last filter if it is LZMA2 or LZMA1, so
|
||||||
|
// we can make it use less RAM. With other filters we don't
|
||||||
|
// know what to do.
|
||||||
|
size_t i = 0;
|
||||||
|
while (filters[i].id != LZMA_FILTER_LZMA2
|
||||||
|
&& filters[i].id != LZMA_FILTER_LZMA1) {
|
||||||
|
if (filters[i].id == LZMA_VLI_UNKNOWN)
|
||||||
|
memlimit_too_small(memory_usage, memory_limit);
|
||||||
|
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrease the dictionary size until we meet the memory
|
||||||
|
// usage limit. First round down to full mebibytes.
|
||||||
|
lzma_options_lzma *opt = filters[i].options;
|
||||||
|
const uint32_t orig_dict_size = opt->dict_size;
|
||||||
|
opt->dict_size &= ~((UINT32_C(1) << 20) - 1);
|
||||||
|
while (true) {
|
||||||
|
// If it is below 1 MiB, auto-adjusting failed. We
|
||||||
|
// could be more sophisticated and scale it down even
|
||||||
|
// more, but let's see if many complain about this
|
||||||
|
// version.
|
||||||
|
//
|
||||||
|
// FIXME: Displays the scaled memory usage instead
|
||||||
|
// of the original.
|
||||||
|
if (opt->dict_size < (UINT32_C(1) << 20))
|
||||||
|
memlimit_too_small(memory_usage, memory_limit);
|
||||||
|
|
||||||
memory_usage = lzma_memusage_encoder(filters);
|
memory_usage = lzma_memusage_encoder(filters);
|
||||||
|
if (memory_usage == UINT64_MAX)
|
||||||
|
message_bug();
|
||||||
|
|
||||||
|
// Accept it if it is low enough.
|
||||||
|
if (memory_usage <= memory_limit)
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Otherwise 1 MiB down and try again. I hope this
|
||||||
|
// isn't too slow method for cases where the original
|
||||||
|
// dict_size is very big.
|
||||||
|
opt->dict_size -= UINT32_C(1) << 20;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if (memory_usage > memory_limit)
|
// Tell the user that we decreased the dictionary size.
|
||||||
message_fatal(_("Memory usage limit is too small "
|
// However, omit the message if no preset or custom chain
|
||||||
"for the given filter setup"));
|
// was given. FIXME: Always warn?
|
||||||
|
if (!preset_default)
|
||||||
|
message(V_WARNING, "Adjusted LZMA%c dictionary size "
|
||||||
|
"from %'" PRIu32 " MiB to "
|
||||||
|
"%'" PRIu32 " MiB to not exceed "
|
||||||
|
"the memory usage limit of "
|
||||||
|
"%'" PRIu64 " MiB",
|
||||||
|
filters[i].id == LZMA_FILTER_LZMA2
|
||||||
|
? '2' : '1',
|
||||||
|
orig_dict_size >> 20,
|
||||||
|
opt->dict_size >> 20,
|
||||||
|
memory_limit >> 20);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Limit the number of worker threads so that memory usage
|
// Limit the number of worker threads so that memory usage
|
||||||
|
@ -224,8 +301,8 @@ coder_init(void)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case FORMAT_RAW:
|
case FORMAT_RAW:
|
||||||
// Memory usage has already been checked in args.c.
|
// Memory usage has already been checked in
|
||||||
// FIXME Comment
|
// coder_set_compression_settings().
|
||||||
ret = lzma_raw_decoder(&strm, filters);
|
ret = lzma_raw_decoder(&strm, filters);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,9 @@ extern void coder_set_check(lzma_check check);
|
||||||
/// Set preset number
|
/// Set preset number
|
||||||
extern void coder_set_preset(size_t new_preset);
|
extern void coder_set_preset(size_t new_preset);
|
||||||
|
|
||||||
|
/// Enable extreme mode
|
||||||
|
extern void coder_set_extreme(void);
|
||||||
|
|
||||||
/// Add a filter to the custom filter chain
|
/// Add a filter to the custom filter chain
|
||||||
extern void coder_add_filter(lzma_vli id, void *options);
|
extern void coder_add_filter(lzma_vli id, void *options);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue