2 * decompressfile.c - decompression API example
4 * Copyright 2022 Eric Biggers
6 * Permission is hereby granted, free of charge, to any person
7 * obtaining a copy of this software and associated documentation
8 * files (the "Software"), to deal in the Software without
9 * restriction, including without limitation the rights to use,
10 * copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following
15 * The above copyright notice and this permission notice shall be
16 * included in all copies or substantial portions of the Software.
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
20 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
24 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25 * OTHER DEALINGS IN THE SOFTWARE.
29 * This an example of using wimlib's compression API to decompress a file
30 * compressed with the compressfile.c program.
32 * This program does *not* have anything to do with WIM files other than the
33 * fact that this makes use of compression formats that are used in WIM files.
34 * This is purely an example of using the compression API.
38 * $ gcc decompressfile.c -o decompressfile -lwim
42 * $ ./decompressfile INFILE OUTFILE
46 * $ ./compressfile book.txt book.txt.lzms LZMS 1048576
48 * $ ./decompressfile book.txt.lzms book.txt
50 * The compressed file format created here is simply a series of compressed
51 * chunks. A real format would need to have checksums and other metadata.
54 #define _FILE_OFFSET_BITS 64
56 #if defined(_MSC_VER) && _MSC_VER < 1800 /* VS pre-2013? */
57 # define PRIu64 "I64u"
60 # define __STDC_FORMAT_MACROS 1
61 # include <inttypes.h>
78 * Windows compatibility defines for string encoding. Applications using wimlib
79 * that need to run on both UNIX and Windows will need to do something similar
80 * to this, whereas applications that only need to run on one or the other can
81 * just use their platform's convention directly.
85 typedef wchar_t tchar;
96 fatal_error(int err, const char *format, ...)
100 va_start(va, format);
101 vfprintf(stderr, format, va);
103 fprintf(stderr, ": %s\n", strerror(err));
111 do_decompress(int in_fd, const tchar *in_filename,
112 int out_fd, const tchar *out_filename,
113 uint32_t chunk_size, struct wimlib_decompressor *decompressor)
117 char *ubuf = (char *)malloc(chunk_size);
118 char *cbuf = (char *)malloc(chunk_size - 1);
120 for (chunk_num = 1; ; chunk_num++) {
125 /* Read chunk uncompressed and compressed sizes. */
126 bytes_read = read(in_fd, &usize, sizeof(uint32_t));
130 if (bytes_read != sizeof(uint32_t) ||
131 read(in_fd, &csize, sizeof(uint32_t)) != sizeof(uint32_t))
133 fatal_error(errno, "Error reading \"%" TS"\"",
137 if (csize > usize || usize > chunk_size)
138 fatal_error(0, "The data is invalid!");
140 if (usize == csize) {
141 if (read(in_fd, ubuf, usize) != (int32_t)usize) {
142 fatal_error(errno, "Error reading \"%" TS"\"",
146 if (read(in_fd, cbuf, csize) != (int32_t)csize) {
147 fatal_error(errno, "Error reading \"%" TS"\"",
151 if (wimlib_decompress(cbuf, csize, ubuf, usize,
155 "The compressed data is invalid!");
159 printf("Chunk %" PRIu64": %" PRIu32" => %" PRIu32" bytes\n",
160 chunk_num, csize, usize);
162 /* Output the uncompressed chunk size, the compressed chunk
163 * size, then the chunk data. Note: a real program would need
164 * to output the chunk sizes in consistent endianness. */
165 if (write(out_fd, ubuf, usize) != (int32_t)usize) {
166 fatal_error(errno, "Error writing to \"%" TS"\"",
174 int main(int argc, tchar **argv)
176 const tchar *in_filename;
177 const tchar *out_filename;
181 enum wimlib_compression_type ctype;
184 struct wimlib_decompressor *decompressor;
187 fprintf(stderr, "Usage: %" TS" INFILE OUTFILE\n", argv[0]);
191 in_filename = argv[1];
192 out_filename = argv[2];
194 /* Open input file and output file. */
195 in_fd = topen(in_filename, O_RDONLY | O_BINARY);
197 fatal_error(errno, "Failed to open \"%" TS"\"", in_filename);
198 out_fd = topen(out_filename, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY,
201 fatal_error(errno, "Failed to open \"%" TS"\"", out_filename);
203 /* Get compression type and chunk size. */
204 if (read(in_fd, &ctype32, sizeof(uint32_t)) != sizeof(uint32_t) ||
205 read(in_fd, &chunk_size, sizeof(uint32_t)) != sizeof(uint32_t))
206 fatal_error(errno, "Error reading from \"%" TS"\"", in_filename);
207 ctype = (enum wimlib_compression_type)ctype32;
209 /* Create a decompressor for the compression type and chunk size with
210 * the default parameters. */
211 ret = wimlib_create_decompressor(ctype, chunk_size, &decompressor);
213 fatal_error(0, "Failed to create decompressor: %" TS,
214 wimlib_get_error_string((enum wimlib_error_code)ret));
216 /* Decompress and write the data. */
217 do_decompress(in_fd, in_filename,
218 out_fd, out_filename,
219 chunk_size, decompressor);
221 /* Cleanup and return. */
223 fatal_error(errno, "Error closing \"%" TS"\"", out_filename);
224 wimlib_free_decompressor(decompressor);