1
0
mirror of https://git.tukaani.org/xz.git synced 2025-03-29 03:40:47 +00:00
xz/src/lzmainfo/lzmainfo.c
Lasse Collin d3cd7abe85 Use LZMA_VERSION_STRING instead of PACKAGE_VERSION.
Those are the same thing, and the former makes it a bit
easier to build the code with other build systems, because
one doesn't need to update the version number into custom
config.h.

This change affects only lzmainfo. Other tools were already
using LZMA_VERSION_STRING.
2010-10-08 16:53:20 +03:00

211 lines
4.6 KiB
C

///////////////////////////////////////////////////////////////////////////////
//
/// \file lzmainfo.c
/// \brief lzmainfo tool for compatibility with LZMA Utils
//
// Author: Lasse Collin
//
// This file has been put into the public domain.
// You can do whatever you want with this file.
//
///////////////////////////////////////////////////////////////////////////////
#include "sysdefs.h"
#include <stdio.h>
#include <errno.h>
#include "lzma.h"
#include "getopt.h"
#include "tuklib_gettext.h"
#include "tuklib_progname.h"
#include "tuklib_exit.h"
static void lzma_attribute((noreturn))
help(void)
{
printf(
_("Usage: %s [--help] [--version] [FILE]...\n"
"Show information stored in the .lzma file header"), progname);
printf(_(
"\nWith no FILE, or when FILE is -, read standard input.\n"));
printf("\n");
printf(_("Report bugs to <%s> (in English or Finnish).\n"),
PACKAGE_BUGREPORT);
printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, true);
}
static void lzma_attribute((noreturn))
version(void)
{
puts("lzmainfo (" PACKAGE_NAME ") " LZMA_VERSION_STRING);
tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, true);
}
/// Parse command line options.
static void
parse_args(int argc, char **argv)
{
enum {
OPT_HELP,
OPT_VERSION,
};
static const struct option long_opts[] = {
{ "help", no_argument, NULL, OPT_HELP },
{ "version", no_argument, NULL, OPT_VERSION },
{ NULL, 0, NULL, 0 }
};
int c;
while ((c = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
switch (c) {
case OPT_HELP:
help();
case OPT_VERSION:
version();
default:
exit(EXIT_FAILURE);
}
}
return;
}
/// Primitive base-2 logarithm for integers
static uint32_t
my_log2(uint32_t n)
{
uint32_t e;
for (e = 0; n > 1; ++e, n /= 2) ;
return e;
}
/// Parse the .lzma header and display information about it.
static bool
lzmainfo(const char *name, FILE *f)
{
uint8_t buf[13];
const size_t size = fread(buf, 1, sizeof(buf), f);
if (size != 13) {
fprintf(stderr, "%s: %s: %s\n", progname, name,
ferror(f) ? strerror(errno)
: _("File is too small to be a .lzma file"));
return true;
}
lzma_filter filter = { .id = LZMA_FILTER_LZMA1 };
// Parse the first five bytes.
switch (lzma_properties_decode(&filter, NULL, buf, 5)) {
case LZMA_OK:
break;
case LZMA_OPTIONS_ERROR:
fprintf(stderr, "%s: %s: %s\n", progname, name,
_("Not a .lzma file"));
return true;
case LZMA_MEM_ERROR:
fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM));
exit(EXIT_FAILURE);
default:
fprintf(stderr, "%s: %s\n", progname,
_("Internal error (bug)"));
exit(EXIT_FAILURE);
}
// Uncompressed size
uint64_t uncompressed_size = 0;
for (size_t i = 0; i < 8; ++i)
uncompressed_size |= (uint64_t)(buf[5 + i]) << (i * 8);
// Display the results. We don't want to translate these and also
// will use MB instead of MiB, because someone could be parsing
// this output and we don't want to break that when people move
// from LZMA Utils to XZ Utils.
if (f != stdin)
printf("%s\n", name);
printf("Uncompressed size: ");
if (uncompressed_size == UINT64_MAX)
printf("Unknown");
else
printf("%" PRIu64 " MB (%" PRIu64 " bytes)",
(uncompressed_size + 512 * 1024)
/ (1024 * 1024),
uncompressed_size);
lzma_options_lzma *opt = filter.options;
printf("\nDictionary size: "
"%u MB (2^%u bytes)\n"
"Literal context bits (lc): %" PRIu32 "\n"
"Literal pos bits (lp): %" PRIu32 "\n"
"Number of pos bits (pb): %" PRIu32 "\n",
(opt->dict_size + 512 * 1024) / (1024 * 1024),
my_log2(opt->dict_size), opt->lc, opt->lp, opt->pb);
free(opt);
return false;
}
extern int
main(int argc, char **argv)
{
tuklib_progname_init(argv);
tuklib_gettext_init(PACKAGE, LOCALEDIR);
parse_args(argc, argv);
int ret = EXIT_SUCCESS;
// We print empty lines around the output only when reading from
// files specified on the command line. This is due to how
// LZMA Utils did it.
if (optind == argc) {
if (lzmainfo("(stdin)", stdin))
ret = EXIT_FAILURE;
} else {
printf("\n");
do {
if (strcmp(argv[optind], "-") == 0) {
if (lzmainfo("(stdin)", stdin))
ret = EXIT_FAILURE;
} else {
FILE *f = fopen(argv[optind], "r");
if (f == NULL) {
ret = EXIT_FAILURE;
fprintf(stderr, "%s: %s: %s\n",
progname,
argv[optind],
strerror(errno));
continue;
}
if (lzmainfo(argv[optind], f))
ret = EXIT_FAILURE;
printf("\n");
fclose(f);
}
} while (++optind < argc);
}
tuklib_exit(ret, EXIT_FAILURE, true);
}