Windows: Embed an application manifest in the EXE files
[xz/debian.git] / doc / examples / 11_file_info.c
blobcaadd98072fbf0ced7e27869a6f32dd90b45d71f
1 // SPDX-License-Identifier: 0BSD
3 ///////////////////////////////////////////////////////////////////////////////
4 //
5 /// \file 11_file_info.c
6 /// \brief Get uncompressed size of .xz file(s)
7 ///
8 /// Usage: ./11_file_info INFILE1.xz [INFILEn.xz]...
9 ///
10 /// Example: ./11_file_info foo.xz
12 // Author: Lasse Collin
14 ///////////////////////////////////////////////////////////////////////////////
16 #include <stdbool.h>
17 #include <inttypes.h>
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <lzma.h>
25 static bool
26 print_file_size(lzma_stream *strm, FILE *infile, const char *filename)
28 // Get the file size. In standard C it can be done by seeking to
29 // the end of the file and then getting the file position.
30 // In POSIX one can use fstat() and then st_size from struct stat.
31 // Also note that fseek() and ftell() use long and thus don't support
32 // large files on 32-bit systems (POSIX versions fseeko() and
33 // ftello() can support large files).
34 if (fseek(infile, 0, SEEK_END)) {
35 fprintf(stderr, "Error seeking the file '%s': %s\n",
36 filename, strerror(errno));
37 return false;
40 const long file_size = ftell(infile);
42 // The decoder wants to start from the beginning of the .xz file.
43 rewind(infile);
45 // Initialize the decoder.
46 lzma_index *i;
47 lzma_ret ret = lzma_file_info_decoder(strm, &i, UINT64_MAX,
48 (uint64_t)file_size);
49 switch (ret) {
50 case LZMA_OK:
51 // Initialization succeeded.
52 break;
54 case LZMA_MEM_ERROR:
55 fprintf(stderr, "Out of memory when initializing "
56 "the .xz file info decoder\n");
57 return false;
59 case LZMA_PROG_ERROR:
60 default:
61 fprintf(stderr, "Unknown error, possibly a bug\n");
62 return false;
65 // This example program reuses the same lzma_stream structure
66 // for multiple files, so we need to reset this when starting
67 // a new file.
68 strm->avail_in = 0;
70 // Buffer for input data.
71 uint8_t inbuf[BUFSIZ];
73 // Pass data to the decoder and seek when needed.
74 while (true) {
75 if (strm->avail_in == 0) {
76 strm->next_in = inbuf;
77 strm->avail_in = fread(inbuf, 1, sizeof(inbuf),
78 infile);
80 if (ferror(infile)) {
81 fprintf(stderr,
82 "Error reading from '%s': %s\n",
83 filename, strerror(errno));
84 return false;
87 // We don't need to care about hitting the end of
88 // the file so no need to check for feof().
91 ret = lzma_code(strm, LZMA_RUN);
93 switch (ret) {
94 case LZMA_OK:
95 break;
97 case LZMA_SEEK_NEEDED:
98 // The cast is safe because liblzma won't ask us to
99 // seek past the known size of the input file which
100 // did fit into a long.
102 // NOTE: Remember to change these to off_t if you
103 // switch fseeko() or lseek().
104 if (fseek(infile, (long)(strm->seek_pos), SEEK_SET)) {
105 fprintf(stderr, "Error seeking the "
106 "file '%s': %s\n",
107 filename, strerror(errno));
108 return false;
111 // The old data in the inbuf is useless now. Set
112 // avail_in to zero so that we will read new input
113 // from the new file position on the next iteration
114 // of this loop.
115 strm->avail_in = 0;
116 break;
118 case LZMA_STREAM_END:
119 // File information was successfully decoded.
120 // See <lzma/index.h> for functions that can be
121 // used on it. In this example we just print
122 // the uncompressed size (in bytes) of
123 // the .xz file followed by its file name.
124 printf("%10" PRIu64 " %s\n",
125 lzma_index_uncompressed_size(i),
126 filename);
128 // Free the memory of the lzma_index structure.
129 lzma_index_end(i, NULL);
131 return true;
133 case LZMA_FORMAT_ERROR:
134 // .xz magic bytes weren't found.
135 fprintf(stderr, "The file '%s' is not "
136 "in the .xz format\n", filename);
137 return false;
139 case LZMA_OPTIONS_ERROR:
140 fprintf(stderr, "The file '%s' has .xz headers that "
141 "are not supported by this liblzma "
142 "version\n", filename);
143 return false;
145 case LZMA_DATA_ERROR:
146 fprintf(stderr, "The file '%s' is corrupt\n",
147 filename);
148 return false;
150 case LZMA_MEM_ERROR:
151 fprintf(stderr, "Memory allocation failed when "
152 "decoding the file '%s'\n", filename);
153 return false;
155 // LZMA_MEMLIMIT_ERROR shouldn't happen because we used
156 // UINT64_MAX as the limit.
158 // LZMA_BUF_ERROR shouldn't happen because we always provide
159 // new input when the input buffer is empty. The decoder
160 // knows the input file size and thus won't try to read past
161 // the end of the file.
162 case LZMA_MEMLIMIT_ERROR:
163 case LZMA_BUF_ERROR:
164 case LZMA_PROG_ERROR:
165 default:
166 fprintf(stderr, "Unknown error, possibly a bug\n");
167 return false;
171 // This line is never reached.
175 extern int
176 main(int argc, char **argv)
178 bool success = true;
179 lzma_stream strm = LZMA_STREAM_INIT;
181 for (int i = 1; i < argc; ++i) {
182 FILE *infile = fopen(argv[i], "rb");
184 if (infile == NULL) {
185 fprintf(stderr, "Cannot open the file '%s': %s\n",
186 argv[i], strerror(errno));
187 success = false;
190 success &= print_file_size(&strm, infile, argv[i]);
192 (void)fclose(infile);
195 lzma_end(&strm);
197 // Close stdout to catch possible write errors that can occur
198 // when pending data is flushed from the stdio buffers.
199 if (fclose(stdout)) {
200 fprintf(stderr, "Write error: %s\n", strerror(errno));
201 success = false;
204 return success ? EXIT_SUCCESS : EXIT_FAILURE;