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