wimlib.h: fix typo
[wimlib] / examples / decompressfile.c
1 /*
2  * decompressfile.c
3  *
4  * An example of using wimlib's compression API to decompress a file compressed
5  * with the compressfile.c program.
6  *
7  * This program does *not* have anything to do with WIM files other than the
8  * fact that this makes use of compression formats that are used in WIM files.
9  * This is purely an example of using the compression API.
10  *
11  * Compile with:
12  *
13  *    $ gcc decompressfile.c -o decompressfile -lwim
14  *
15  * Run with:
16  *
17  *    $ ./decompressfile INFILE OUTFILE
18  *
19  * For example:
20  *
21  *    $ ./compressfile book.txt book.txt.lzms LZMS 1048576
22  *    $ rm -f book.txt
23  *    $ ./decompressfile book.txt.lzms book.txt
24  *
25  * The compressed file format created here is simply a series of compressed
26  * chunks.  A real format would need to have checksums and other metadata.
27  *
28  * The author dedicates this file to the public domain.
29  * You can do whatever you want with this file.
30  */
31
32 #define _GNU_SOURCE
33 #define _FILE_OFFSET_BITS 64
34
35 #include <wimlib.h>
36
37 #include <errno.h>
38 #include <error.h>
39 #include <fcntl.h>
40 #include <inttypes.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
44
45 static void
46 do_decompress(int in_fd, const char *in_filename,
47               int out_fd, const char *out_filename,
48               uint32_t chunk_size, struct wimlib_decompressor *decompressor)
49 {
50         uint64_t chunk_num;
51
52         char *ubuf = malloc(chunk_size);
53         char *cbuf = malloc(chunk_size - 1);
54
55         for (chunk_num = 1; ; chunk_num++) {
56                 ssize_t bytes_read;
57                 uint32_t usize;
58                 uint32_t csize;
59
60                 /* Read chunk uncompressed and compressed sizes.  */
61                 bytes_read = read(in_fd, &usize, sizeof(uint32_t));
62                 if (bytes_read == 0)
63                         break;
64
65                 if (bytes_read != sizeof(uint32_t) ||
66                     read(in_fd, &csize, sizeof(uint32_t)) != sizeof(uint32_t))
67                 {
68                         error(1, errno, "Error reading \"%s\"", in_filename);
69                 }
70
71                 if (csize > usize || usize > chunk_size)
72                         error(1, 0, "The data is invalid!");
73
74                 if (usize == csize) {
75                         if (read(in_fd, ubuf, usize) != usize) {
76                                 error(1, errno, "Error reading \"%s\"",
77                                       in_filename);
78                         }
79                 } else {
80                         if (read(in_fd, cbuf, csize) != csize) {
81                                 error(1, errno, "Error reading \"%s\"",
82                                       in_filename);
83                         }
84
85                         if (wimlib_decompress(cbuf, csize, ubuf, usize,
86                                               decompressor))
87                         {
88                                 error(1, 0, "The compressed data is invalid!");
89                         }
90                 }
91
92                 printf("Chunk %"PRIu64": %"PRIu32" => %"PRIu32" bytes\n",
93                        chunk_num, csize, usize);
94
95                 /* Output the uncompressed chunk size, the compressed chunk
96                  * size, then the chunk data.  Note: a real program would need
97                  * to output the chunk sizes in consistent endianness.  */
98                 if (write(out_fd, ubuf, usize) != usize)
99                         error(1, errno, "Error writing to \"%s\"", out_filename);
100         }
101         free(ubuf);
102         free(cbuf);
103 }
104
105 int main(int argc, char **argv)
106 {
107         const char *in_filename;
108         const char *out_filename;
109         int in_fd;
110         int out_fd;
111         uint32_t ctype;
112         uint32_t chunk_size;
113         int ret;
114         struct wimlib_decompressor *decompressor;
115
116         if (argc != 3) {
117                 fprintf(stderr, "Usage: %s INFILE OUTFILE\n", argv[0]);
118                 return 2;
119         }
120
121         in_filename = argv[1];
122         out_filename = argv[2];
123
124         /* Open input file and output file.  */
125         in_fd = open(in_filename, O_RDONLY);
126         if (in_fd < 0)
127                 error(1, errno, "Failed to open \"%s\"", in_filename);
128         out_fd = open(out_filename, O_WRONLY | O_TRUNC | O_CREAT, 0644);
129         if (out_fd < 0)
130                 error(1, errno, "Failed to open \"%s\"", out_filename);
131
132         /* Get compression type and chunk size.  */
133         if (read(in_fd, &ctype, sizeof(uint32_t)) != sizeof(uint32_t) ||
134             read(in_fd, &chunk_size, sizeof(uint32_t)) != sizeof(uint32_t))
135                 error(1, errno, "Error reading from \"%s\"", in_filename);
136
137         /* Create a decompressor for the compression type and chunk size with
138          * the default parameters.  */
139         ret = wimlib_create_decompressor(ctype, chunk_size, &decompressor);
140         if (ret != 0)
141                 error(1, 0, "Failed to create decompressor: %s",
142                       wimlib_get_error_string(ret));
143
144         /* Decompress and write the data.  */
145         do_decompress(in_fd, in_filename,
146                       out_fd, out_filename,
147                       chunk_size, decompressor);
148
149         /* Cleanup and return.  */
150         if (close(out_fd))
151                 error(1, errno, "Error closing \"%s\"", out_filename);
152         wimlib_free_decompressor(decompressor);
153         return 0;
154 }