]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - contrib/xz/src/lzmainfo/lzmainfo.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / contrib / xz / src / lzmainfo / lzmainfo.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       lzmainfo.c
4 /// \brief      lzmainfo tool for compatibility with LZMA Utils
5 //
6 //  Author:     Lasse Collin
7 //
8 //  This file has been put into the public domain.
9 //  You can do whatever you want with this file.
10 //
11 ///////////////////////////////////////////////////////////////////////////////
12
13 #include "sysdefs.h"
14 #include <stdio.h>
15 #include <errno.h>
16
17 #include "lzma.h"
18 #include "getopt.h"
19 #include "tuklib_gettext.h"
20 #include "tuklib_progname.h"
21 #include "tuklib_exit.h"
22
23
24 static void lzma_attribute((noreturn))
25 help(void)
26 {
27         printf(
28 _("Usage: %s [--help] [--version] [FILE]...\n"
29 "Show information stored in the .lzma file header"), progname);
30
31         printf(_(
32 "\nWith no FILE, or when FILE is -, read standard input.\n"));
33         printf("\n");
34
35         printf(_("Report bugs to <%s> (in English or Finnish).\n"),
36                         PACKAGE_BUGREPORT);
37         printf(_("%s home page: <%s>\n"), PACKAGE_NAME, PACKAGE_URL);
38
39         tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, true);
40 }
41
42
43 static void lzma_attribute((noreturn))
44 version(void)
45 {
46         puts("lzmainfo (" PACKAGE_NAME ") " PACKAGE_VERSION);
47         tuklib_exit(EXIT_SUCCESS, EXIT_FAILURE, true);
48 }
49
50
51 /// Parse command line options.
52 static void
53 parse_args(int argc, char **argv)
54 {
55         enum {
56                 OPT_HELP,
57                 OPT_VERSION,
58         };
59
60         static const struct option long_opts[] = {
61                 { "help",    no_argument, NULL, OPT_HELP },
62                 { "version", no_argument, NULL, OPT_VERSION },
63                 { NULL,      0,           NULL, 0 }
64         };
65
66         int c;
67         while ((c = getopt_long(argc, argv, "", long_opts, NULL)) != -1) {
68                 switch (c) {
69                 case OPT_HELP:
70                         help();
71
72                 case OPT_VERSION:
73                         version();
74
75                 default:
76                         exit(EXIT_FAILURE);
77                 }
78         }
79
80         return;
81 }
82
83
84 /// Primitive base-2 logarithm for integers
85 static uint32_t
86 my_log2(uint32_t n)
87 {
88         uint32_t e;
89         for (e = 0; n > 1; ++e, n /= 2) ;
90         return e;
91 }
92
93
94 /// Parse the .lzma header and display information about it.
95 static bool
96 lzmainfo(const char *name, FILE *f)
97 {
98         uint8_t buf[13];
99         const size_t size = fread(buf, 1, sizeof(buf), f);
100         if (size != 13) {
101                 fprintf(stderr, "%s: %s: %s\n", progname, name,
102                                 ferror(f) ? strerror(errno)
103                                 : _("File is too small to be a .lzma file"));
104                 return true;
105         }
106
107         lzma_filter filter = { .id = LZMA_FILTER_LZMA1 };
108
109         // Parse the first five bytes.
110         switch (lzma_properties_decode(&filter, NULL, buf, 5)) {
111         case LZMA_OK:
112                 break;
113
114         case LZMA_OPTIONS_ERROR:
115                 fprintf(stderr, "%s: %s: %s\n", progname, name,
116                                 _("Not a .lzma file"));
117                 return true;
118
119         case LZMA_MEM_ERROR:
120                 fprintf(stderr, "%s: %s\n", progname, strerror(ENOMEM));
121                 exit(EXIT_FAILURE);
122
123         default:
124                 fprintf(stderr, "%s: %s\n", progname,
125                                 _("Internal error (bug)"));
126                 exit(EXIT_FAILURE);
127         }
128
129         // Uncompressed size
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);
133
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.
138         if (f != stdin)
139                 printf("%s\n", name);
140
141         printf("Uncompressed size:             ");
142         if (uncompressed_size == UINT64_MAX)
143                 printf("Unknown");
144         else
145                 printf("%" PRIu64 " MB (%" PRIu64 " bytes)",
146                                 (uncompressed_size + 512 * 1024)
147                                         / (1024 * 1024),
148                                 uncompressed_size);
149
150         lzma_options_lzma *opt = filter.options;
151
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);
159
160         free(opt);
161
162         return false;
163 }
164
165
166 extern int
167 main(int argc, char **argv)
168 {
169         tuklib_progname_init(argv);
170         tuklib_gettext_init(PACKAGE, LOCALEDIR);
171
172         parse_args(argc, argv);
173
174         int ret = EXIT_SUCCESS;
175
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))
181                         ret = EXIT_FAILURE;
182         } else {
183                 printf("\n");
184
185                 do {
186                         if (strcmp(argv[optind], "-") == 0) {
187                                 if (lzmainfo("(stdin)", stdin))
188                                         ret = EXIT_FAILURE;
189                         } else {
190                                 FILE *f = fopen(argv[optind], "r");
191                                 if (f == NULL) {
192                                         ret = EXIT_FAILURE;
193                                         fprintf(stderr, "%s: %s: %s\n",
194                                                         progname,
195                                                         argv[optind],
196                                                         strerror(errno));
197                                         continue;
198                                 }
199
200                                 if (lzmainfo(argv[optind], f))
201                                         ret = EXIT_FAILURE;
202
203                                 printf("\n");
204                                 fclose(f);
205                         }
206                 } while (++optind < argc);
207         }
208
209         tuklib_exit(ret, EXIT_FAILURE, true);
210 }