12940b44dSPeter Avalos ///////////////////////////////////////////////////////////////////////////////
22940b44dSPeter Avalos //
32940b44dSPeter Avalos /// \file lzmainfo.c
42940b44dSPeter Avalos /// \brief lzmainfo tool for compatibility with LZMA Utils
52940b44dSPeter Avalos //
62940b44dSPeter Avalos // Author: Lasse Collin
72940b44dSPeter Avalos //
82940b44dSPeter Avalos // This file has been put into the public domain.
92940b44dSPeter Avalos // You can do whatever you want with this file.
102940b44dSPeter Avalos //
112940b44dSPeter Avalos ///////////////////////////////////////////////////////////////////////////////
122940b44dSPeter Avalos
132940b44dSPeter Avalos #include "sysdefs.h"
142940b44dSPeter Avalos #include <stdio.h>
152940b44dSPeter Avalos #include <errno.h>
162940b44dSPeter Avalos
172940b44dSPeter Avalos #include "lzma.h"
182940b44dSPeter Avalos #include "getopt.h"
192940b44dSPeter Avalos #include "tuklib_gettext.h"
202940b44dSPeter Avalos #include "tuklib_progname.h"
212940b44dSPeter Avalos #include "tuklib_exit.h"
222940b44dSPeter Avalos
232940b44dSPeter Avalos #ifdef TUKLIB_DOSLIKE
242940b44dSPeter Avalos # include <fcntl.h>
252940b44dSPeter Avalos # include <io.h>
262940b44dSPeter Avalos #endif
272940b44dSPeter Avalos
282940b44dSPeter Avalos
29*114db65bSPeter Avalos static void lzma_attribute((__noreturn__))
help(void)302940b44dSPeter Avalos help(void)
312940b44dSPeter Avalos {
322940b44dSPeter Avalos printf(
332940b44dSPeter Avalos _("Usage: %s [--help] [--version] [FILE]...\n"
342940b44dSPeter Avalos "Show information stored in the .lzma file header"), progname);
352940b44dSPeter Avalos
362940b44dSPeter Avalos printf(_(
372940b44dSPeter Avalos "\nWith no FILE, or when FILE is -, read standard input.\n"));
382940b44dSPeter Avalos printf("\n");
392940b44dSPeter Avalos
402940b44dSPeter Avalos printf(_("Report bugs to <%s> (in English or Finnish).\n"),
412940b44dSPeter Avalos PACKAGE_BUGREPORT);
422940b44dSPeter Avalos printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
432940b44dSPeter Avalos
442940b44dSPeter Avalos tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, true);
452940b44dSPeter Avalos }
462940b44dSPeter Avalos
472940b44dSPeter Avalos
48*114db65bSPeter Avalos static void lzma_attribute((__noreturn__))
version(void)492940b44dSPeter Avalos version(void)
502940b44dSPeter Avalos {
512940b44dSPeter Avalos puts("lzmainfo (" PACKAGE_NAME ") " LZMA_VERSION_STRING);
522940b44dSPeter Avalos tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, true);
532940b44dSPeter Avalos }
542940b44dSPeter Avalos
552940b44dSPeter Avalos
562940b44dSPeter Avalos /// Parse command line options.
572940b44dSPeter Avalos static void
parse_args(int argc,char ** argv)582940b44dSPeter Avalos parse_args(int argc, char **argv)
592940b44dSPeter Avalos {
602940b44dSPeter Avalos enum {
612940b44dSPeter Avalos OPT_HELP,
622940b44dSPeter Avalos OPT_VERSION,
632940b44dSPeter Avalos };
642940b44dSPeter Avalos
652940b44dSPeter Avalos static const struct option long_opts[] = {
662940b44dSPeter Avalos { "help", no_argument, NULL, OPT_HELP },
672940b44dSPeter Avalos { "version", no_argument, NULL, OPT_VERSION },
682940b44dSPeter Avalos { NULL, 0, NULL, 0 }
692940b44dSPeter Avalos };
702940b44dSPeter Avalos
712940b44dSPeter Avalos int c;
722940b44dSPeter Avalos while ((c = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
732940b44dSPeter Avalos switch (c) {
742940b44dSPeter Avalos case OPT_HELP:
752940b44dSPeter Avalos help();
762940b44dSPeter Avalos
772940b44dSPeter Avalos case OPT_VERSION:
782940b44dSPeter Avalos version();
792940b44dSPeter Avalos
802940b44dSPeter Avalos default:
812940b44dSPeter Avalos exit(EXIT_FAILURE);
822940b44dSPeter Avalos }
832940b44dSPeter Avalos }
842940b44dSPeter Avalos
852940b44dSPeter Avalos return;
862940b44dSPeter Avalos }
872940b44dSPeter Avalos
882940b44dSPeter Avalos
892940b44dSPeter Avalos /// Primitive base-2 logarithm for integers
902940b44dSPeter Avalos static uint32_t
my_log2(uint32_t n)912940b44dSPeter Avalos my_log2(uint32_t n)
922940b44dSPeter Avalos {
932940b44dSPeter Avalos uint32_t e;
942940b44dSPeter Avalos for (e = 0; n > 1; ++e, n /= 2) ;
952940b44dSPeter Avalos return e;
962940b44dSPeter Avalos }
972940b44dSPeter Avalos
982940b44dSPeter Avalos
992940b44dSPeter Avalos /// Parse the .lzma header and display information about it.
1002940b44dSPeter Avalos static bool
lzmainfo(const char * name,FILE * f)1012940b44dSPeter Avalos lzmainfo(const char *name, FILE *f)
1022940b44dSPeter Avalos {
1032940b44dSPeter Avalos uint8_t buf[13];
1042940b44dSPeter Avalos const size_t size = fread(buf, 1, sizeof(buf), f);
1052940b44dSPeter Avalos if (size != 13) {
1062940b44dSPeter Avalos fprintf(stderr, "%s: %s: %s\n", progname, name,
1072940b44dSPeter Avalos ferror(f) ? strerror(errno)
1082940b44dSPeter Avalos : _("File is too small to be a .lzma file"));
1092940b44dSPeter Avalos return true;
1102940b44dSPeter Avalos }
1112940b44dSPeter Avalos
1122940b44dSPeter Avalos lzma_filter filter = { .id = LZMA_FILTER_LZMA1 };
1132940b44dSPeter Avalos
1142940b44dSPeter Avalos // Parse the first five bytes.
1152940b44dSPeter Avalos switch (lzma_properties_decode(&filter, NULL, buf, 5)) {
1162940b44dSPeter Avalos case LZMA_OK:
1172940b44dSPeter Avalos break;
1182940b44dSPeter Avalos
1192940b44dSPeter Avalos case LZMA_OPTIONS_ERROR:
1202940b44dSPeter Avalos fprintf(stderr, "%s: %s: %s\n", progname, name,
1212940b44dSPeter Avalos _("Not a .lzma file"));
1222940b44dSPeter Avalos return true;
1232940b44dSPeter Avalos
1242940b44dSPeter Avalos case LZMA_MEM_ERROR:
1252940b44dSPeter Avalos fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM));
1262940b44dSPeter Avalos exit(EXIT_FAILURE);
1272940b44dSPeter Avalos
1282940b44dSPeter Avalos default:
1292940b44dSPeter Avalos fprintf(stderr, "%s: %s\n", progname,
1302940b44dSPeter Avalos _("Internal error (bug)"));
1312940b44dSPeter Avalos exit(EXIT_FAILURE);
1322940b44dSPeter Avalos }
1332940b44dSPeter Avalos
1342940b44dSPeter Avalos // Uncompressed size
1352940b44dSPeter Avalos uint64_t uncompressed_size = 0;
1362940b44dSPeter Avalos for (size_t i = 0; i < 8; ++i)
1372940b44dSPeter Avalos uncompressed_size |= (uint64_t)(buf[5 + i]) << (i * 8);
1382940b44dSPeter Avalos
1392940b44dSPeter Avalos // Display the results. We don't want to translate these and also
1402940b44dSPeter Avalos // will use MB instead of MiB, because someone could be parsing
1412940b44dSPeter Avalos // this output and we don't want to break that when people move
1422940b44dSPeter Avalos // from LZMA Utils to XZ Utils.
1432940b44dSPeter Avalos if (f != stdin)
1442940b44dSPeter Avalos printf("%s\n", name);
1452940b44dSPeter Avalos
1462940b44dSPeter Avalos printf("Uncompressed size: ");
1472940b44dSPeter Avalos if (uncompressed_size == UINT64_MAX)
1482940b44dSPeter Avalos printf("Unknown");
1492940b44dSPeter Avalos else
1502940b44dSPeter Avalos printf("%" PRIu64 " MB (%" PRIu64 " bytes)",
1512940b44dSPeter Avalos (uncompressed_size + 512 * 1024)
1522940b44dSPeter Avalos / (1024 * 1024),
1532940b44dSPeter Avalos uncompressed_size);
1542940b44dSPeter Avalos
1552940b44dSPeter Avalos lzma_options_lzma *opt = filter.options;
1562940b44dSPeter Avalos
1572940b44dSPeter Avalos printf("\nDictionary size: "
1582940b44dSPeter Avalos "%" PRIu32 " MB (2^%" PRIu32 " bytes)\n"
1592940b44dSPeter Avalos "Literal context bits (lc): %" PRIu32 "\n"
1602940b44dSPeter Avalos "Literal pos bits (lp): %" PRIu32 "\n"
1612940b44dSPeter Avalos "Number of pos bits (pb): %" PRIu32 "\n",
1622940b44dSPeter Avalos (opt->dict_size + 512 * 1024) / (1024 * 1024),
1632940b44dSPeter Avalos my_log2(opt->dict_size), opt->lc, opt->lp, opt->pb);
1642940b44dSPeter Avalos
1652940b44dSPeter Avalos free(opt);
1662940b44dSPeter Avalos
1672940b44dSPeter Avalos return false;
1682940b44dSPeter Avalos }
1692940b44dSPeter Avalos
1702940b44dSPeter Avalos
1712940b44dSPeter Avalos extern int
main(int argc,char ** argv)1722940b44dSPeter Avalos main(int argc, char **argv)
1732940b44dSPeter Avalos {
1742940b44dSPeter Avalos tuklib_progname_init(argv);
1752940b44dSPeter Avalos tuklib_gettext_init(PACKAGE, LOCALEDIR);
1762940b44dSPeter Avalos
1772940b44dSPeter Avalos parse_args(argc, argv);
1782940b44dSPeter Avalos
1792940b44dSPeter Avalos #ifdef TUKLIB_DOSLIKE
1802940b44dSPeter Avalos setmode(fileno(stdin), O_BINARY);
1812940b44dSPeter Avalos #endif
1822940b44dSPeter Avalos
1832940b44dSPeter Avalos int ret = EXIT_SUCCESS;
1842940b44dSPeter Avalos
1852940b44dSPeter Avalos // We print empty lines around the output only when reading from
1862940b44dSPeter Avalos // files specified on the command line. This is due to how
1872940b44dSPeter Avalos // LZMA Utils did it.
1882940b44dSPeter Avalos if (optind == argc) {
1892940b44dSPeter Avalos if (lzmainfo("(stdin)", stdin))
1902940b44dSPeter Avalos ret = EXIT_FAILURE;
1912940b44dSPeter Avalos } else {
1922940b44dSPeter Avalos printf("\n");
1932940b44dSPeter Avalos
1942940b44dSPeter Avalos do {
1952940b44dSPeter Avalos if (strcmp(argv[optind], "-") == 0) {
1962940b44dSPeter Avalos if (lzmainfo("(stdin)", stdin))
1972940b44dSPeter Avalos ret = EXIT_FAILURE;
1982940b44dSPeter Avalos } else {
1992940b44dSPeter Avalos FILE *f = fopen(argv[optind], "r");
2002940b44dSPeter Avalos if (f == NULL) {
2012940b44dSPeter Avalos ret = EXIT_FAILURE;
2022940b44dSPeter Avalos fprintf(stderr, "%s: %s: %s\n",
2032940b44dSPeter Avalos progname,
2042940b44dSPeter Avalos argv[optind],
2052940b44dSPeter Avalos strerror(errno));
2062940b44dSPeter Avalos continue;
2072940b44dSPeter Avalos }
2082940b44dSPeter Avalos
2092940b44dSPeter Avalos if (lzmainfo(argv[optind], f))
2102940b44dSPeter Avalos ret = EXIT_FAILURE;
2112940b44dSPeter Avalos
2122940b44dSPeter Avalos printf("\n");
2132940b44dSPeter Avalos fclose(f);
2142940b44dSPeter Avalos }
2152940b44dSPeter Avalos } while (++optind < argc);
2162940b44dSPeter Avalos }
2172940b44dSPeter Avalos
2182940b44dSPeter Avalos tuklib_exit(ret, EXIT_FAILURE, true);
2192940b44dSPeter Avalos }
220