1 ///////////////////////////////////////////////////////////////////////////////
4 /// \brief lzmainfo tool for compatibility with LZMA Utils
6 // Author: Lasse Collin
8 // This file has been put into the public domain.
9 // You can do whatever you want with this file.
11 ///////////////////////////////////////////////////////////////////////////////
19 #include "tuklib_gettext.h"
20 #include "tuklib_progname.h"
21 #include "tuklib_exit.h"
24 static void lzma_attribute((noreturn))
28 _("Usage: %s [--help] [--version] [FILE]...\n"
29 "Show information stored in the .lzma file header"), progname);
32 "\nWith no FILE, or when FILE is -, read standard input.\n"));
35 printf(_("Report bugs to <%s> (in English or Finnish).\n"),
37 printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
39 tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, true);
43 static void lzma_attribute((noreturn))
46 puts("lzmainfo (" PACKAGE_NAME ") " PACKAGE_VERSION);
47 tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, true);
51 /// Parse command line options.
53 parse_args(int argc, char **argv)
60 static const struct option long_opts[] = {
61 { "help", no_argument, NULL, OPT_HELP },
62 { "version", no_argument, NULL, OPT_VERSION },
67 while ((c = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
84 /// Primitive base-2 logarithm for integers
89 for (e = 0; n > 1; ++e, n /= 2) ;
94 /// Parse the .lzma header and display information about it.
96 lzmainfo(const char *name, FILE *f)
99 const size_t size = fread(buf, 1, sizeof(buf), f);
101 fprintf(stderr, "%s: %s: %s\n", progname, name,
102 ferror(f) ? strerror(errno)
103 : _("File is too small to be a .lzma file"));
107 lzma_filter filter = { .id = LZMA_FILTER_LZMA1 };
109 // Parse the first five bytes.
110 switch (lzma_properties_decode(&filter, NULL, buf, 5)) {
114 case LZMA_OPTIONS_ERROR:
115 fprintf(stderr, "%s: %s: %s\n", progname, name,
116 _("Not a .lzma file"));
120 fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM));
124 fprintf(stderr, "%s: %s\n", progname,
125 _("Internal error (bug)"));
130 uint64_t uncompressed_size = 0;
131 for (size_t i = 0; i < 8; ++i)
132 uncompressed_size |= (uint64_t)(buf[5 + i]) << (i * 8);
134 // Display the results. We don't want to translate these and also
135 // will use MB instead of MiB, because someone could be parsing
136 // this output and we don't want to break that when people move
137 // from LZMA Utils to XZ Utils.
139 printf("%s\n", name);
141 printf("Uncompressed size: ");
142 if (uncompressed_size == UINT64_MAX)
145 printf("%" PRIu64 " MB (%" PRIu64 " bytes)",
146 (uncompressed_size + 512 * 1024)
150 lzma_options_lzma *opt = filter.options;
152 printf("\nDictionary size: "
153 "%u MB (2^%u bytes)\n"
154 "Literal context bits (lc): %" PRIu32 "\n"
155 "Literal pos bits (lp): %" PRIu32 "\n"
156 "Number of pos bits (pb): %" PRIu32 "\n",
157 (opt->dict_size + 512 * 1024) / (1024 * 1024),
158 my_log2(opt->dict_size), opt->lc, opt->lp, opt->pb);
167 main(int argc, char **argv)
169 tuklib_progname_init(argv);
170 tuklib_gettext_init(PACKAGE, LOCALEDIR);
172 parse_args(argc, argv);
174 int ret = EXIT_SUCCESS;
176 // We print empty lines around the output only when reading from
177 // files specified on the command line. This is due to how
178 // LZMA Utils did it.
179 if (optind == argc) {
180 if (lzmainfo("(stdin)", stdin))
186 if (strcmp(argv[optind], "-") == 0) {
187 if (lzmainfo("(stdin)", stdin))
190 FILE *f = fopen(argv[optind], "r");
193 fprintf(stderr, "%s: %s: %s\n",
200 if (lzmainfo(argv[optind], f))
206 } while (++optind < argc);
209 tuklib_exit(ret, EXIT_FAILURE, true);