1 /* example.c -- usage example of the zlib compression library
2  * Copyright (C) 1995-2006, 2011, 2016 Jean-loup Gailly
3  * For conditions of distribution and use, see copyright notice in zlib.h
4  */
5 
6 /* @(#) $Id$ */
7 
8 #include "zlib.h"
9 #include <stdio.h>
10 
11 #ifdef STDC
12 #  include <string.h>
13 #  include <stdlib.h>
14 #endif
15 
16 #if defined(VMS) || defined(RISCOS)
17 #  define TESTFILE "foo-gz"
18 #else
19 #  define TESTFILE "foo.gz"
20 #endif
21 
22 #define CHECK_ERR(err, msg) { \
23     if (err != Z_OK) { \
24         fprintf(stderr, "%s error: %d\n", msg, err); \
25         exit(1); \
26     } \
27 }
28 
29 static z_const char hello[] = "hello, hello!";
30 /* "hello world" would be more standard, but the repeated "hello"
31  * stresses the compression code better, sorry...
32  */
33 
34 static const char dictionary[] = "hello";
35 static uLong dictId;    /* Adler32 value of the dictionary */
36 
37 #ifdef Z_SOLO
38 
myalloc(void *q, unsigned n, unsigned m)39 static void *myalloc(void *q, unsigned n, unsigned m)
40 {
41     (void)q;
42     return calloc(n, m);
43 }
44 
myfree(void *q, void *p)45 static void myfree(void *q, void *p)
46 {
47     (void)q;
48     free(p);
49 }
50 
51 static alloc_func zalloc = myalloc;
52 static free_func zfree = myfree;
53 
54 #else /* !Z_SOLO */
55 
56 static alloc_func zalloc = (alloc_func)0;
57 static free_func zfree = (free_func)0;
58 
59 /* ===========================================================================
60  * Test compress() and uncompress()
61  */
test_compress(Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)62 static void test_compress(Byte *compr, uLong comprLen, Byte *uncompr,
63                    uLong uncomprLen)
64 {
65     int err;
66     uLong len = (uLong)strlen(hello)+1;
67 
68     err = compress(compr, &comprLen, (const Bytef*)hello, len);
69     CHECK_ERR(err, "compress");
70 
71     strcpy((char*)uncompr, "garbage");
72 
73     err = uncompress(uncompr, &uncomprLen, compr, comprLen);
74     CHECK_ERR(err, "uncompress");
75 
76     if (strcmp((char*)uncompr, hello)) {
77         fprintf(stderr, "bad uncompress\n");
78         exit(1);
79     } else {
80         printf("uncompress(): %s\n", (char *)uncompr);
81     }
82 }
83 
84 /* ===========================================================================
85  * Test read/write of .gz files
86  */
test_gzio(const char *fname, Byte *uncompr, uLong uncomprLen)87 static void test_gzio(const char *fname, Byte *uncompr, uLong uncomprLen)
88 {
89 #ifdef NO_GZCOMPRESS
90     fprintf(stderr, "NO_GZCOMPRESS -- gz* functions cannot compress\n");
91 #else
92     int err;
93     int len = (int)strlen(hello)+1;
94     gzFile file;
95     z_off_t pos;
96 
97     file = gzopen(fname, "wb");
98     if (file == NULL) {
99         fprintf(stderr, "gzopen error\n");
100         exit(1);
101     }
102     gzputc(file, 'h');
103     if (gzputs(file, "ello") != 4) {
104         fprintf(stderr, "gzputs err: %s\n", gzerror(file, &err));
105         exit(1);
106     }
107     if (gzprintf(file, ", %s!", "hello") != 8) {
108         fprintf(stderr, "gzprintf err: %s\n", gzerror(file, &err));
109         exit(1);
110     }
111     gzseek(file, 1L, SEEK_CUR); /* add one zero byte */
112     gzclose(file);
113 
114     file = gzopen(fname, "rb");
115     if (file == NULL) {
116         fprintf(stderr, "gzopen error\n");
117         exit(1);
118     }
119     strcpy((char*)uncompr, "garbage");
120 
121     if (gzread(file, uncompr, (unsigned)uncomprLen) != len) {
122         fprintf(stderr, "gzread err: %s\n", gzerror(file, &err));
123         exit(1);
124     }
125     if (strcmp((char*)uncompr, hello)) {
126         fprintf(stderr, "bad gzread: %s\n", (char*)uncompr);
127         exit(1);
128     } else {
129         printf("gzread(): %s\n", (char*)uncompr);
130     }
131 
132     pos = gzseek(file, -8L, SEEK_CUR);
133     if (pos != 6 || gztell(file) != pos) {
134         fprintf(stderr, "gzseek error, pos=%ld, gztell=%ld\n",
135                 (long)pos, (long)gztell(file));
136         exit(1);
137     }
138 
139     if (gzgetc(file) != ' ') {
140         fprintf(stderr, "gzgetc error\n");
141         exit(1);
142     }
143 
144     if (gzungetc(' ', file) != ' ') {
145         fprintf(stderr, "gzungetc error\n");
146         exit(1);
147     }
148 
149     gzgets(file, (char*)uncompr, (int)uncomprLen);
150     if (strlen((char*)uncompr) != 7) { /* " hello!" */
151         fprintf(stderr, "gzgets err after gzseek: %s\n", gzerror(file, &err));
152         exit(1);
153     }
154     if (strcmp((char*)uncompr, hello + 6)) {
155         fprintf(stderr, "bad gzgets after gzseek\n");
156         exit(1);
157     } else {
158         printf("gzgets() after gzseek: %s\n", (char*)uncompr);
159     }
160 
161     gzclose(file);
162 #endif
163 }
164 
165 #endif /* Z_SOLO */
166 
167 /* ===========================================================================
168  * Test deflate() with small buffers
169  */
test_deflate(Byte *compr, uLong comprLen)170 static void test_deflate(Byte *compr, uLong comprLen)
171 {
172     z_stream c_stream; /* compression stream */
173     int err;
174     uLong len = (uLong)strlen(hello)+1;
175 
176     c_stream.zalloc = zalloc;
177     c_stream.zfree = zfree;
178     c_stream.opaque = (voidpf)0;
179 
180     err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
181     CHECK_ERR(err, "deflateInit");
182 
183     c_stream.next_in  = (z_const unsigned char *)hello;
184     c_stream.next_out = compr;
185 
186     while (c_stream.total_in != len && c_stream.total_out < comprLen) {
187         c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */
188         err = deflate(&c_stream, Z_NO_FLUSH);
189         CHECK_ERR(err, "deflate");
190     }
191     /* Finish the stream, still forcing small buffers: */
192     for (;;) {
193         c_stream.avail_out = 1;
194         err = deflate(&c_stream, Z_FINISH);
195         if (err == Z_STREAM_END)
196         {
197             break;
198         }
199         CHECK_ERR(err, "deflate");
200     }
201 
202     err = deflateEnd(&c_stream);
203     CHECK_ERR(err, "deflateEnd");
204 }
205 
206 /* ===========================================================================
207  * Test inflate() with small buffers
208  */
test_inflate(Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)209 static void test_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
210                   uLong uncomprLen)
211 {
212     int err;
213     z_stream d_stream; /* decompression stream */
214 
215     strcpy((char*)uncompr, "garbage");
216 
217     d_stream.zalloc = zalloc;
218     d_stream.zfree = zfree;
219     d_stream.opaque = (voidpf)0;
220 
221     d_stream.next_in  = compr;
222     d_stream.avail_in = 0;
223     d_stream.next_out = uncompr;
224 
225     err = inflateInit(&d_stream);
226     CHECK_ERR(err, "inflateInit");
227 
228     while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) {
229         d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */
230         err = inflate(&d_stream, Z_NO_FLUSH);
231         if (err == Z_STREAM_END)
232         {
233             break;
234         }
235         CHECK_ERR(err, "inflate");
236     }
237 
238     err = inflateEnd(&d_stream);
239     CHECK_ERR(err, "inflateEnd");
240 
241     if (strcmp((char*)uncompr, hello)) {
242         fprintf(stderr, "bad inflate\n");
243         exit(1);
244     } else {
245         printf("inflate(): %s\n", (char *)uncompr);
246     }
247 }
248 
249 /* ===========================================================================
250  * Test deflate() with large buffers and dynamic change of compression level
251  */
test_large_deflate(Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)252 static void test_large_deflate(Byte *compr, uLong comprLen, Byte *uncompr,
253                         uLong uncomprLen)
254 {
255     z_stream c_stream; /* compression stream */
256     int err;
257 
258     c_stream.zalloc = zalloc;
259     c_stream.zfree = zfree;
260     c_stream.opaque = (voidpf)0;
261 
262     err = deflateInit(&c_stream, Z_BEST_SPEED);
263     CHECK_ERR(err, "deflateInit");
264 
265     c_stream.next_out = compr;
266     c_stream.avail_out = (uInt)comprLen;
267 
268     /* At this point, uncompr is still mostly zeroes, so it should compress
269      * very well:
270      */
271     c_stream.next_in = uncompr;
272     c_stream.avail_in = (uInt)uncomprLen;
273     err = deflate(&c_stream, Z_NO_FLUSH);
274     CHECK_ERR(err, "deflate");
275     if (c_stream.avail_in != 0) {
276         fprintf(stderr, "deflate not greedy\n");
277         exit(1);
278     }
279 
280     /* Feed in already compressed data and switch to no compression: */
281     deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY);
282     c_stream.next_in = compr;
283     c_stream.avail_in = (uInt)uncomprLen/2;
284     err = deflate(&c_stream, Z_NO_FLUSH);
285     CHECK_ERR(err, "deflate");
286 
287     /* Switch back to compressing mode: */
288     deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED);
289     c_stream.next_in = uncompr;
290     c_stream.avail_in = (uInt)uncomprLen;
291     err = deflate(&c_stream, Z_NO_FLUSH);
292     CHECK_ERR(err, "deflate");
293 
294     err = deflate(&c_stream, Z_FINISH);
295     if (err != Z_STREAM_END) {
296         fprintf(stderr, "deflate should report Z_STREAM_END\n");
297         exit(1);
298     }
299     err = deflateEnd(&c_stream);
300     CHECK_ERR(err, "deflateEnd");
301 }
302 
303 /* ===========================================================================
304  * Test inflate() with large buffers
305  */
test_large_inflate(Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)306 static void test_large_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
307                         uLong uncomprLen)
308 {
309     int err;
310     z_stream d_stream; /* decompression stream */
311 
312     strcpy((char*)uncompr, "garbage");
313 
314     d_stream.zalloc = zalloc;
315     d_stream.zfree = zfree;
316     d_stream.opaque = (voidpf)0;
317 
318     d_stream.next_in  = compr;
319     d_stream.avail_in = (uInt)comprLen;
320 
321     err = inflateInit(&d_stream);
322     CHECK_ERR(err, "inflateInit");
323 
324     for (;;) {
325         d_stream.next_out = uncompr;            /* discard the output */
326         d_stream.avail_out = (uInt)uncomprLen;
327         err = inflate(&d_stream, Z_NO_FLUSH);
328         if (err == Z_STREAM_END)
329         {
330             break;
331         }
332         CHECK_ERR(err, "large inflate");
333     }
334 
335     err = inflateEnd(&d_stream);
336     CHECK_ERR(err, "inflateEnd");
337 
338     if (d_stream.total_out != 2*uncomprLen + uncomprLen/2) {
339         fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out);
340         exit(1);
341     } else {
342         printf("large_inflate(): OK\n");
343     }
344 }
345 
346 /* ===========================================================================
347  * Test deflate() with full flush
348  */
test_flush(Byte *compr, uLong *comprLen)349 static void test_flush(Byte *compr, uLong *comprLen)
350 {
351     z_stream c_stream; /* compression stream */
352     int err;
353     uInt len = (uInt)strlen(hello)+1;
354 
355     c_stream.zalloc = zalloc;
356     c_stream.zfree = zfree;
357     c_stream.opaque = (voidpf)0;
358 
359     err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
360     CHECK_ERR(err, "deflateInit");
361 
362     c_stream.next_in  = (z_const unsigned char *)hello;
363     c_stream.next_out = compr;
364     c_stream.avail_in = 3;
365     c_stream.avail_out = (uInt)*comprLen;
366     err = deflate(&c_stream, Z_FULL_FLUSH);
367     CHECK_ERR(err, "deflate");
368 
369     compr[3]++; /* force an error in first compressed block */
370     c_stream.avail_in = len - 3;
371 
372     err = deflate(&c_stream, Z_FINISH);
373     if (err != Z_STREAM_END) {
374         CHECK_ERR(err, "deflate");
375     }
376     err = deflateEnd(&c_stream);
377     CHECK_ERR(err, "deflateEnd");
378 
379     *comprLen = c_stream.total_out;
380 }
381 
382 /* ===========================================================================
383  * Test inflateSync()
384  */
test_sync(Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)385 static void test_sync(Byte *compr, uLong comprLen, Byte *uncompr,
386                       uLong uncomprLen)
387 {
388     int err;
389     z_stream d_stream; /* decompression stream */
390 
391     strcpy((char*)uncompr, "garbage");
392 
393     d_stream.zalloc = zalloc;
394     d_stream.zfree = zfree;
395     d_stream.opaque = (voidpf)0;
396 
397     d_stream.next_in  = compr;
398     d_stream.avail_in = 2; /* just read the zlib header */
399 
400     err = inflateInit(&d_stream);
401     CHECK_ERR(err, "inflateInit");
402 
403     d_stream.next_out = uncompr;
404     d_stream.avail_out = (uInt)uncomprLen;
405 
406     err = inflate(&d_stream, Z_NO_FLUSH);
407     CHECK_ERR(err, "inflate");
408 
409     d_stream.avail_in = (uInt)comprLen-2;   /* read all compressed data */
410     err = inflateSync(&d_stream);           /* but skip the damaged part */
411     CHECK_ERR(err, "inflateSync");
412 
413     err = inflate(&d_stream, Z_FINISH);
414     if (err != Z_STREAM_END) {
415         fprintf(stderr, "inflate should report Z_STREAM_END\n");
416         exit(1);
417     }
418     err = inflateEnd(&d_stream);
419     CHECK_ERR(err, "inflateEnd");
420 
421     printf("after inflateSync(): hel%s\n", (char *)uncompr);
422 }
423 
424 /* ===========================================================================
425  * Test deflate() with preset dictionary
426  */
test_dict_deflate(Byte *compr, uLong comprLen)427 static void test_dict_deflate(Byte *compr, uLong comprLen)
428 {
429     z_stream c_stream; /* compression stream */
430     int err;
431 
432     c_stream.zalloc = zalloc;
433     c_stream.zfree = zfree;
434     c_stream.opaque = (voidpf)0;
435 
436     err = deflateInit(&c_stream, Z_BEST_COMPRESSION);
437     CHECK_ERR(err, "deflateInit");
438 
439     err = deflateSetDictionary(&c_stream,
440                 (const Bytef*)dictionary, (int)sizeof(dictionary));
441     CHECK_ERR(err, "deflateSetDictionary");
442 
443     dictId = c_stream.adler;
444     c_stream.next_out = compr;
445     c_stream.avail_out = (uInt)comprLen;
446 
447     c_stream.next_in = (z_const unsigned char *)hello;
448     c_stream.avail_in = (uInt)strlen(hello)+1;
449 
450     err = deflate(&c_stream, Z_FINISH);
451     if (err != Z_STREAM_END) {
452         fprintf(stderr, "deflate should report Z_STREAM_END\n");
453         exit(1);
454     }
455     err = deflateEnd(&c_stream);
456     CHECK_ERR(err, "deflateEnd");
457 }
458 
459 /* ===========================================================================
460  * Test inflate() with a preset dictionary
461  */
test_dict_inflate(Byte *compr, uLong comprLen, Byte *uncompr, uLong uncomprLen)462 static void test_dict_inflate(Byte *compr, uLong comprLen, Byte *uncompr,
463                        uLong uncomprLen)
464 {
465     int err;
466     z_stream d_stream; /* decompression stream */
467 
468     strcpy((char*)uncompr, "garbage");
469 
470     d_stream.zalloc = zalloc;
471     d_stream.zfree = zfree;
472     d_stream.opaque = (voidpf)0;
473 
474     d_stream.next_in  = compr;
475     d_stream.avail_in = (uInt)comprLen;
476 
477     err = inflateInit(&d_stream);
478     CHECK_ERR(err, "inflateInit");
479 
480     d_stream.next_out = uncompr;
481     d_stream.avail_out = (uInt)uncomprLen;
482 
483     for (;;) {
484         err = inflate(&d_stream, Z_NO_FLUSH);
485         if (err == Z_STREAM_END)
486         {
487             break;
488         }
489         if (err == Z_NEED_DICT) {
490             if (d_stream.adler != dictId) {
491                 fprintf(stderr, "unexpected dictionary");
492                 exit(1);
493             }
494             err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary,
495                                        (int)sizeof(dictionary));
496         }
497         CHECK_ERR(err, "inflate with dict");
498     }
499 
500     err = inflateEnd(&d_stream);
501     CHECK_ERR(err, "inflateEnd");
502 
503     if (strcmp((char*)uncompr, hello)) {
504         fprintf(stderr, "bad inflate with dict\n");
505         exit(1);
506     } else {
507         printf("inflate with dictionary: %s\n", (char *)uncompr);
508     }
509 }
510 
511 /* ===========================================================================
512  * Usage:  example [output.gz  [input.gz]]
513  */
514 #define THREE 3
main(int argc, char *argv[])515 int main(int argc, char *argv[])
516 {
517     Byte *compr, *uncompr;
518     uLong uncomprLen = 20000;
519     uLong comprLen = 3 * uncomprLen;
520     static const char* myVersion = ZLIB_VERSION;
521 
522     if (zlibVersion()[0] != myVersion[0]) {
523         fprintf(stderr, "incompatible zlib version\n");
524         exit(1);
525 
526     } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) {
527         fprintf(stderr, "warning: different zlib version linked: %s\n",
528                 zlibVersion());
529     }
530 
531     printf("zlib version %s = 0x%04x, compile flags = 0x%lx\n",
532             ZLIB_VERSION, ZLIB_VERNUM, zlibCompileFlags());
533 
534     compr    = (Byte*)calloc((uInt)comprLen, 1);
535     uncompr  = (Byte*)calloc((uInt)uncomprLen, 1);
536     /* compr and uncompr are cleared to avoid reading uninitialized
537      * data and to ensure that uncompr compresses well.
538      */
539     if (compr == Z_NULL || uncompr == Z_NULL) {
540         printf("out of memory\n");
541         exit(1);
542     }
543 
544 #ifdef Z_SOLO
545     (void)argc;
546     (void)argv;
547 #else
548     test_compress(compr, comprLen, uncompr, uncomprLen);
549 
550     test_gzio((argc > 1 ? argv[1] : TESTFILE),
551               uncompr, uncomprLen);
552 #endif
553 
554     test_deflate(compr, comprLen);
555     test_inflate(compr, comprLen, uncompr, uncomprLen);
556 
557     test_large_deflate(compr, comprLen, uncompr, uncomprLen);
558     test_large_inflate(compr, comprLen, uncompr, uncomprLen);
559 
560     test_flush(compr, &comprLen);
561     test_sync(compr, comprLen, uncompr, uncomprLen);
562     comprLen = THREE * uncomprLen;
563 
564     test_dict_deflate(compr, comprLen);
565     test_dict_inflate(compr, comprLen, uncompr, uncomprLen);
566 
567     free(compr);
568     free(uncompr);
569 
570     return 0;
571 }
572