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