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"
34 _("Usage: %s [--help] [--version] [FILE]...\n"
35 "Show information stored in the .lzma file header"), progname
);
38 "\nWith no FILE, or when FILE is -, read standard input.\n"));
41 printf(_("Report bugs to <%s> (in English or Finnish).\n"),
43 printf(_("%s home page: <%s>\n"), PACKAGE_NAME
, PACKAGE_URL
);
45 tuklib_exit(EXIT_SUCCESS
, EXIT_FAILURE
, true);
53 puts("lzmainfo (" PACKAGE_NAME
") " LZMA_VERSION_STRING
);
54 tuklib_exit(EXIT_SUCCESS
, EXIT_FAILURE
, true);
58 /// Parse command line options.
60 parse_args(int argc
, char **argv
)
67 static const struct option long_opts
[] = {
68 { "help", no_argument
, NULL
, OPT_HELP
},
69 { "version", no_argument
, NULL
, OPT_VERSION
},
74 while ((c
= getopt_long(argc
, argv
, "", long_opts
, NULL
)) != -1) {
91 /// Primitive base-2 logarithm for integers
96 for (e
= 0; n
> 1; ++e
, n
/= 2) ;
101 /// Parse the .lzma header and display information about it.
103 lzmainfo(const char *name
, FILE *f
)
106 const size_t size
= fread(buf
, 1, sizeof(buf
), f
);
108 fprintf(stderr
, "%s: %s: %s\n", progname
, name
,
109 ferror(f
) ? strerror(errno
)
110 : _("File is too small to be a .lzma file"));
114 lzma_filter filter
= { .id
= LZMA_FILTER_LZMA1
};
116 // Parse the first five bytes.
117 switch (lzma_properties_decode(&filter
, NULL
, buf
, 5)) {
121 case LZMA_OPTIONS_ERROR
:
122 fprintf(stderr
, "%s: %s: %s\n", progname
, name
,
123 _("Not a .lzma file"));
127 fprintf(stderr
, "%s: %s\n", progname
, strerror(ENOMEM
));
131 fprintf(stderr
, "%s: %s\n", progname
,
132 _("Internal error (bug)"));
137 uint64_t uncompressed_size
= 0;
138 for (size_t i
= 0; i
< 8; ++i
)
139 uncompressed_size
|= (uint64_t)(buf
[5 + i
]) << (i
* 8);
141 // Display the results. We don't want to translate these and also
142 // will use MB instead of MiB, because someone could be parsing
143 // this output and we don't want to break that when people move
144 // from LZMA Utils to XZ Utils.
146 printf("%s\n", name
);
148 printf("Uncompressed size: ");
149 if (uncompressed_size
== UINT64_MAX
)
152 printf("%" PRIu64
" MB (%" PRIu64
" bytes)",
153 (uncompressed_size
+ 512 * 1024)
157 lzma_options_lzma
*opt
= filter
.options
;
159 printf("\nDictionary size: "
160 "%" PRIu32
" MB (2^%" PRIu32
" bytes)\n"
161 "Literal context bits (lc): %" PRIu32
"\n"
162 "Literal pos bits (lp): %" PRIu32
"\n"
163 "Number of pos bits (pb): %" PRIu32
"\n",
164 (opt
->dict_size
+ 512 * 1024) / (1024 * 1024),
165 my_log2(opt
->dict_size
), opt
->lc
, opt
->lp
, opt
->pb
);
174 main(int argc
, char **argv
)
176 tuklib_progname_init(argv
);
177 tuklib_gettext_init(PACKAGE
, LOCALEDIR
);
179 parse_args(argc
, argv
);
181 #ifdef TUKLIB_DOSLIKE
182 setmode(fileno(stdin
), O_BINARY
);
185 int ret
= EXIT_SUCCESS
;
187 // We print empty lines around the output only when reading from
188 // files specified on the command line. This is due to how
189 // LZMA Utils did it.
190 if (optind
== argc
) {
191 if (lzmainfo("(stdin)", stdin
))
197 if (strcmp(argv
[optind
], "-") == 0) {
198 if (lzmainfo("(stdin)", stdin
))
201 FILE *f
= fopen(argv
[optind
], "r");
204 fprintf(stderr
, "%s: %s: %s\n",
211 if (lzmainfo(argv
[optind
], f
))
217 } while (++optind
< argc
);
220 tuklib_exit(ret
, EXIT_FAILURE
, true);