2 * compressfile.c - compression 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 compress a file.
31 * This program does *not* have anything to do with WIM files other than the
32 * fact that this makes use of compression formats that are used in WIM files.
33 * This is purely an example of using the compression API.
37 * $ gcc compressfile.c -o compressfile -lwim
41 * $ ./compressfile INFILE OUTFILE [LZX | XPRESS | LZMS] [chunk size]
44 * Use the decompressfile.c program to decompress the file.
48 * $ ./compressfile book.txt book.txt.lzms LZMS 1048576
50 * $ ./decompressfile book.txt.lzms book.txt
52 * The compressed file format created here is simply a series of compressed
53 * chunks. A real format would need to have checksums and other metadata.
56 #define _FILE_OFFSET_BITS 64
58 #if defined(_MSC_VER) && _MSC_VER < 1800 /* VS pre-2013? */
59 # define PRIu64 "I64u"
62 # define __STDC_FORMAT_MACROS 1
63 # include <inttypes.h>
80 * Windows compatibility defines for string encoding. Applications using wimlib
81 * that need to run on both UNIX and Windows will need to do something similar
82 * to this, whereas applications that only need to run on one or the other can
83 * just use their platform's convention directly.
87 typedef wchar_t tchar;
88 # define _T(text) L##text
89 # define T(text) _T(text)
92 # define tstrcmp wcscmp
93 # define tstrtol wcstol
100 # define tstrcmp strcmp
101 # define tstrtol strtol
105 fatal_error(int err, const char *format, ...)
109 va_start(va, format);
110 vfprintf(stderr, format, va);
112 fprintf(stderr, ": %s\n", strerror(err));
120 do_compress(int in_fd, const tchar *in_filename,
121 int out_fd, const tchar *out_filename,
122 uint32_t chunk_size, struct wimlib_compressor *compressor)
124 char *ubuf = (char *)malloc(chunk_size);
125 char *cbuf = (char *)malloc(chunk_size - 1);
128 for (chunk_num = 1; ; chunk_num++) {
135 /* Read next chunk of data to compress. */
136 bytes_read = read(in_fd, ubuf, chunk_size);
137 if (bytes_read <= 0) {
140 fatal_error(errno, "Error reading \"%" TS"\"",
144 /* Compress the chunk. */
147 csize = wimlib_compress(ubuf, usize, cbuf, usize - 1, compressor);
149 /* Chunk was compressed; use the compressed data. */
153 /* Chunk did not compress to less than original size;
154 * use the uncompressed data. */
159 printf("Chunk %" PRIu64": %" PRIu32" => %" PRIu32" bytes\n",
160 chunk_num, usize, out_size);
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, &usize, sizeof(uint32_t)) != sizeof(uint32_t) ||
166 write(out_fd, &out_size, sizeof(uint32_t)) != sizeof(uint32_t) ||
167 write(out_fd, out_buf, out_size) != (int32_t)out_size)
169 fatal_error(errno, "Error writing to \"%" TS"\"",
177 int main(int argc, tchar **argv)
179 const tchar *in_filename;
180 const tchar *out_filename;
183 struct wimlib_compressor *compressor;
184 enum wimlib_compression_type ctype = WIMLIB_COMPRESSION_TYPE_LZX;
186 uint32_t chunk_size = 32768;
189 if (argc < 3 || argc > 5) {
190 fprintf(stderr, "Usage: %" TS" INFILE OUTFILE "
191 "[LZX | XPRESS | LZMS] [chunk size]\n", argv[0]);
195 in_filename = argv[1];
196 out_filename = argv[2];
198 /* Parse compression type (optional) */
200 if (!tstrcmp(argv[3], T("LZX")))
201 ctype = WIMLIB_COMPRESSION_TYPE_LZX;
202 else if (!tstrcmp(argv[3], T("XPRESS")))
203 ctype = WIMLIB_COMPRESSION_TYPE_XPRESS;
204 else if (!tstrcmp(argv[3], T("LZMS")))
205 ctype = WIMLIB_COMPRESSION_TYPE_LZMS;
208 "Unrecognized compression type \"%" TS"\"",
211 /* Parse chunk size (optional). */
213 chunk_size = tstrtol(argv[4], NULL, 10);
215 /* Open input file and output file. */
216 in_fd = topen(in_filename, O_RDONLY | O_BINARY);
218 fatal_error(errno, "Failed to open \"%" TS"\"", in_filename);
219 out_fd = topen(out_filename, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY,
222 fatal_error(errno, "Failed to open \"%" TS"s\"", out_filename);
224 /* Create a compressor for the compression type and chunk size with the
225 * default parameters. */
226 ret = wimlib_create_compressor(ctype, chunk_size, 0, &compressor);
228 fatal_error(0, "Failed to create compressor: %" TS,
229 wimlib_get_error_string((enum wimlib_error_code)ret));
231 ctype32 = (uint32_t)ctype;
232 /* Write compression type and chunk size to the file. */
233 if (write(out_fd, &ctype32, sizeof(uint32_t)) != sizeof(uint32_t) ||
234 write(out_fd, &chunk_size, sizeof(uint32_t)) != sizeof(uint32_t))
236 fatal_error(errno, "Error writing to \"%" TS"\"", out_filename);
239 /* Compress and write the data. */
240 do_compress(in_fd, in_filename,
241 out_fd, out_filename,
242 chunk_size, compressor);
244 /* Cleanup and return. */
246 fatal_error(errno, "Error closing \"%" TS"\"", out_filename);
247 wimlib_free_compressor(compressor);