2 * compressfile.c - compression API example
4 * The following copying information applies to this specific source code file:
6 * Written in 2014-2016 by Eric Biggers <ebiggers3@gmail.com>
8 * To the extent possible under law, the author(s) have dedicated all copyright
9 * and related and neighboring rights to this software to the public domain
10 * worldwide via the Creative Commons Zero 1.0 Universal Public Domain
11 * Dedication (the "CC0").
13 * This software is distributed in the hope that it will be useful, but WITHOUT
14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15 * FOR A PARTICULAR PURPOSE. See the CC0 for more details.
17 * You should have received a copy of the CC0 along with this software; if not
18 * see <http://creativecommons.org/publicdomain/zero/1.0/>.
22 * This an example of using wimlib's compression API to compress a file.
24 * This program does *not* have anything to do with WIM files other than the
25 * fact that this makes use of compression formats that are used in WIM files.
26 * This is purely an example of using the compression API.
30 * $ gcc compressfile.c -o compressfile -lwim
34 * $ ./compressfile INFILE OUTFILE [LZX | XPRESS | LZMS] [chunk size]
37 * Use the decompressfile.c program to decompress the file.
41 * $ ./compressfile book.txt book.txt.lzms LZMS 1048576
43 * $ ./decompressfile book.txt.lzms book.txt
45 * The compressed file format created here is simply a series of compressed
46 * chunks. A real format would need to have checksums and other metadata.
49 #define _FILE_OFFSET_BITS 64
51 #if defined(_MSC_VER) && _MSC_VER < 1800 /* VS pre-2013? */
52 # define PRIu64 "I64u"
55 # define __STDC_FORMAT_MACROS 1
56 # include <inttypes.h>
73 * Windows compatibility defines for string encoding. Applications using wimlib
74 * that need to run on both UNIX and Windows will need to do something similar
75 * to this, whereas applications that only need to run on one or the other can
76 * just use their platform's convention directly.
80 typedef wchar_t tchar;
81 # define _T(text) L##text
82 # define T(text) _T(text)
85 # define tstrcmp wcscmp
86 # define tstrtol wcstol
93 # define tstrcmp strcmp
94 # define tstrtol strtol
98 fatal_error(int err, const char *format, ...)
102 va_start(va, format);
103 vfprintf(stderr, format, va);
105 fprintf(stderr, ": %s\n", strerror(err));
113 do_compress(int in_fd, const tchar *in_filename,
114 int out_fd, const tchar *out_filename,
115 uint32_t chunk_size, struct wimlib_compressor *compressor)
117 char *ubuf = (char *)malloc(chunk_size);
118 char *cbuf = (char *)malloc(chunk_size - 1);
121 for (chunk_num = 1; ; chunk_num++) {
128 /* Read next chunk of data to compress. */
129 bytes_read = read(in_fd, ubuf, chunk_size);
130 if (bytes_read <= 0) {
133 fatal_error(errno, "Error reading \"%" TS"\"",
137 /* Compress the chunk. */
140 csize = wimlib_compress(ubuf, usize, cbuf, usize - 1, compressor);
142 /* Chunk was compressed; use the compressed data. */
146 /* Chunk did not compress to less than original size;
147 * use the uncompressed data. */
152 printf("Chunk %" PRIu64": %" PRIu32" => %" PRIu32" bytes\n",
153 chunk_num, usize, out_size);
155 /* Output the uncompressed chunk size, the compressed chunk
156 * size, then the chunk data. Note: a real program would need
157 * to output the chunk sizes in consistent endianness. */
158 if (write(out_fd, &usize, sizeof(uint32_t)) != sizeof(uint32_t) ||
159 write(out_fd, &out_size, sizeof(uint32_t)) != sizeof(uint32_t) ||
160 write(out_fd, out_buf, out_size) != (int32_t)out_size)
162 fatal_error(errno, "Error writing to \"%" TS"\"",
170 int main(int argc, tchar **argv)
172 const tchar *in_filename;
173 const tchar *out_filename;
176 struct wimlib_compressor *compressor;
177 enum wimlib_compression_type ctype = WIMLIB_COMPRESSION_TYPE_LZX;
179 uint32_t chunk_size = 32768;
182 if (argc < 3 || argc > 5) {
183 fprintf(stderr, "Usage: %" TS" INFILE OUTFILE "
184 "[LZX | XPRESS | LZMS] [chunk size]\n", argv[0]);
188 in_filename = argv[1];
189 out_filename = argv[2];
191 /* Parse compression type (optional) */
193 if (!tstrcmp(argv[3], T("LZX")))
194 ctype = WIMLIB_COMPRESSION_TYPE_LZX;
195 else if (!tstrcmp(argv[3], T("XPRESS")))
196 ctype = WIMLIB_COMPRESSION_TYPE_XPRESS;
197 else if (!tstrcmp(argv[3], T("LZMS")))
198 ctype = WIMLIB_COMPRESSION_TYPE_LZMS;
201 "Unrecognized compression type \"%" TS"\"",
204 /* Parse chunk size (optional). */
206 chunk_size = tstrtol(argv[4], NULL, 10);
208 /* Open input file and output file. */
209 in_fd = topen(in_filename, O_RDONLY | O_BINARY);
211 fatal_error(errno, "Failed to open \"%" TS"\"", in_filename);
212 out_fd = topen(out_filename, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY,
215 fatal_error(errno, "Failed to open \"%" TS"s\"", out_filename);
217 /* Create a compressor for the compression type and chunk size with the
218 * default parameters. */
219 ret = wimlib_create_compressor(ctype, chunk_size, 0, &compressor);
221 fatal_error(0, "Failed to create compressor: %" TS,
222 wimlib_get_error_string((enum wimlib_error_code)ret));
224 ctype32 = (uint32_t)ctype;
225 /* Write compression type and chunk size to the file. */
226 if (write(out_fd, &ctype32, sizeof(uint32_t)) != sizeof(uint32_t) ||
227 write(out_fd, &chunk_size, sizeof(uint32_t)) != sizeof(uint32_t))
229 fatal_error(errno, "Error writing to \"%" TS"\"", out_filename);
232 /* Compress and write the data. */
233 do_compress(in_fd, in_filename,
234 out_fd, out_filename,
235 chunk_size, compressor);
237 /* Cleanup and return. */
239 fatal_error(errno, "Error closing \"%" TS"\"", out_filename);
240 wimlib_free_compressor(compressor);