1 // example3.c - Demonstrates how to use miniz.c's deflate() and inflate() functions for simple file compression.
2 // Public domain, May 15 2011, Rich Geldreich, richgel99@gmail.com. See "unlicense" statement at the end of tinfl.c.
3 // For simplicity, this example is limited to files smaller than 4GB, but this is not a limitation of miniz.c.
4 #include <stdio.h>
5 #include <limits.h>
6 #include "miniz.h"
7 
8 typedef unsigned char uint8;
9 typedef unsigned short uint16;
10 typedef unsigned int uint;
11 
12 #define my_max(a,b) (((a) > (b)) ? (a) : (b))
13 #define my_min(a,b) (((a) < (b)) ? (a) : (b))
14 
15 #define BUF_SIZE (1024 * 1024)
16 static uint8 s_inbuf[BUF_SIZE];
17 static uint8 s_outbuf[BUF_SIZE];
18 
main(int argc,char * argv[])19 int main(int argc, char *argv[])
20 {
21   const char *pMode;
22   FILE *pInfile, *pOutfile;
23   uint infile_size;
24   int level = Z_BEST_COMPRESSION;
25   z_stream stream;
26   int p = 1;
27   const char *pSrc_filename;
28   const char *pDst_filename;
29   long file_loc;
30 
31   printf("miniz.c version: %s\n", MZ_VERSION);
32 
33   if (argc < 4)
34   {
35     printf("Usage: example3 [options] [mode:c or d] infile outfile\n");
36     printf("\nModes:\n");
37     printf("c - Compresses file infile to a zlib stream in file outfile\n");
38     printf("d - Decompress zlib stream in file infile to file outfile\n");
39     printf("\nOptions:\n");
40     printf("-l[0-10] - Compression level, higher values are slower.\n");
41     return EXIT_FAILURE;
42   }
43 
44   while ((p < argc) && (argv[p][0] == '-'))
45   {
46     switch (argv[p][1])
47     {
48       case 'l':
49       {
50         level = atoi(&argv[1][2]);
51         if ((level < 0) || (level > 10))
52         {
53           printf("Invalid level!\n");
54           return EXIT_FAILURE;
55         }
56         break;
57       }
58       default:
59       {
60         printf("Invalid option: %s\n", argv[p]);
61         return EXIT_FAILURE;
62       }
63     }
64     p++;
65   }
66 
67   if ((argc - p) < 3)
68   {
69     printf("Must specify mode, input filename, and output filename after options!\n");
70     return EXIT_FAILURE;
71   }
72   else if ((argc - p) > 3)
73   {
74     printf("Too many filenames!\n");
75     return EXIT_FAILURE;
76   }
77 
78   pMode = argv[p++];
79   if (!strchr("cCdD", pMode[0]))
80   {
81     printf("Invalid mode!\n");
82     return EXIT_FAILURE;
83   }
84 
85   pSrc_filename = argv[p++];
86   pDst_filename = argv[p++];
87 
88   printf("Mode: %c, Level: %u\nInput File: \"%s\"\nOutput File: \"%s\"\n", pMode[0], level, pSrc_filename, pDst_filename);
89 
90   // Open input file.
91   pInfile = fopen(pSrc_filename, "rb");
92   if (!pInfile)
93   {
94     printf("Failed opening input file!\n");
95     return EXIT_FAILURE;
96   }
97 
98   // Determine input file's size.
99   fseek(pInfile, 0, SEEK_END);
100   file_loc = ftell(pInfile);
101   fseek(pInfile, 0, SEEK_SET);
102 
103   if ((file_loc < 0) || (file_loc > INT_MAX))
104   {
105      // This is not a limitation of miniz or tinfl, but this example.
106      printf("File is too large to be processed by this example.\n");
107      return EXIT_FAILURE;
108   }
109 
110   infile_size = (uint)file_loc;
111 
112   // Open output file.
113   pOutfile = fopen(pDst_filename, "wb");
114   if (!pOutfile)
115   {
116     printf("Failed opening output file!\n");
117     return EXIT_FAILURE;
118   }
119 
120   printf("Input file size: %u\n", infile_size);
121 
122   // Init the z_stream
123   memset(&stream, 0, sizeof(stream));
124   stream.next_in = s_inbuf;
125   stream.avail_in = 0;
126   stream.next_out = s_outbuf;
127   stream.avail_out = BUF_SIZE;
128 
129   if ((pMode[0] == 'c') || (pMode[0] == 'C'))
130   {
131     // Compression.
132     uint infile_remaining = infile_size;
133 
134     if (deflateInit(&stream, level) != Z_OK)
135     {
136       printf("deflateInit() failed!\n");
137       return EXIT_FAILURE;
138     }
139 
140     for ( ; ; )
141     {
142       int status;
143       if (!stream.avail_in)
144       {
145         // Input buffer is empty, so read more bytes from input file.
146         uint n = my_min(BUF_SIZE, infile_remaining);
147 
148         if (fread(s_inbuf, 1, n, pInfile) != n)
149         {
150           printf("Failed reading from input file!\n");
151           return EXIT_FAILURE;
152         }
153 
154         stream.next_in = s_inbuf;
155         stream.avail_in = n;
156 
157         infile_remaining -= n;
158         //printf("Input bytes remaining: %u\n", infile_remaining);
159       }
160 
161       status = deflate(&stream, infile_remaining ? Z_NO_FLUSH : Z_FINISH);
162 
163       if ((status == Z_STREAM_END) || (!stream.avail_out))
164       {
165         // Output buffer is full, or compression is done, so write buffer to output file.
166         uint n = BUF_SIZE - stream.avail_out;
167         if (fwrite(s_outbuf, 1, n, pOutfile) != n)
168         {
169           printf("Failed writing to output file!\n");
170           return EXIT_FAILURE;
171         }
172         stream.next_out = s_outbuf;
173         stream.avail_out = BUF_SIZE;
174       }
175 
176       if (status == Z_STREAM_END)
177         break;
178       else if (status != Z_OK)
179       {
180         printf("deflate() failed with status %i!\n", status);
181         return EXIT_FAILURE;
182       }
183     }
184 
185     if (deflateEnd(&stream) != Z_OK)
186     {
187       printf("deflateEnd() failed!\n");
188       return EXIT_FAILURE;
189     }
190   }
191   else if ((pMode[0] == 'd') || (pMode[0] == 'D'))
192   {
193     // Decompression.
194     uint infile_remaining = infile_size;
195 
196     if (inflateInit(&stream))
197     {
198       printf("inflateInit() failed!\n");
199       return EXIT_FAILURE;
200     }
201 
202     for ( ; ; )
203     {
204       int status;
205       if (!stream.avail_in)
206       {
207         // Input buffer is empty, so read more bytes from input file.
208         uint n = my_min(BUF_SIZE, infile_remaining);
209 
210         if (fread(s_inbuf, 1, n, pInfile) != n)
211         {
212           printf("Failed reading from input file!\n");
213           return EXIT_FAILURE;
214         }
215 
216         stream.next_in = s_inbuf;
217         stream.avail_in = n;
218 
219         infile_remaining -= n;
220       }
221 
222       status = inflate(&stream, Z_SYNC_FLUSH);
223 
224       if ((status == Z_STREAM_END) || (!stream.avail_out))
225       {
226         // Output buffer is full, or decompression is done, so write buffer to output file.
227         uint n = BUF_SIZE - stream.avail_out;
228         if (fwrite(s_outbuf, 1, n, pOutfile) != n)
229         {
230           printf("Failed writing to output file!\n");
231           return EXIT_FAILURE;
232         }
233         stream.next_out = s_outbuf;
234         stream.avail_out = BUF_SIZE;
235       }
236 
237       if (status == Z_STREAM_END)
238         break;
239       else if (status != Z_OK)
240       {
241         printf("inflate() failed with status %i!\n", status);
242         return EXIT_FAILURE;
243       }
244     }
245 
246     if (inflateEnd(&stream) != Z_OK)
247     {
248       printf("inflateEnd() failed!\n");
249       return EXIT_FAILURE;
250     }
251   }
252   else
253   {
254     printf("Invalid mode!\n");
255     return EXIT_FAILURE;
256   }
257 
258   fclose(pInfile);
259   if (EOF == fclose(pOutfile))
260   {
261     printf("Failed writing to output file!\n");
262     return EXIT_FAILURE;
263   }
264 
265   printf("Total input bytes: %u\n", (mz_uint32)stream.total_in);
266   printf("Total output bytes: %u\n", (mz_uint32)stream.total_out);
267   printf("Success.\n");
268   return EXIT_SUCCESS;
269 }
270