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