| (* example.c -- usage example of the zlib compression library |
| * Copyright (C) 1995-2003 Jean-loup Gailly. |
| * For conditions of distribution and use, see copyright notice in zlib.h |
| * |
| * Pascal translation |
| * Copyright (C) 1998 by Jacques Nomssi Nzali. |
| * For conditions of distribution and use, see copyright notice in readme.txt |
| * |
| * Adaptation to the zlibpas interface |
| * Copyright (C) 2003 by Cosmin Truta. |
| * For conditions of distribution and use, see copyright notice in readme.txt |
| *) |
| |
| program example; |
| |
| {$DEFINE TEST_COMPRESS} |
| {DO NOT $DEFINE TEST_GZIO} |
| {$DEFINE TEST_DEFLATE} |
| {$DEFINE TEST_INFLATE} |
| {$DEFINE TEST_FLUSH} |
| {$DEFINE TEST_SYNC} |
| {$DEFINE TEST_DICT} |
| |
| uses SysUtils, zlibpas; |
| |
| const TESTFILE = 'foo.gz'; |
| |
| (* "hello world" would be more standard, but the repeated "hello" |
| * stresses the compression code better, sorry... |
| *) |
| const hello: PChar = 'hello, hello!'; |
| |
| const dictionary: PChar = 'hello'; |
| |
| var dictId: LongInt; (* Adler32 value of the dictionary *) |
| |
| procedure CHECK_ERR(err: Integer; msg: String); |
| begin |
| if err <> Z_OK then |
| begin |
| WriteLn(msg, ' error: ', err); |
| Halt(1); |
| end; |
| end; |
| |
| procedure EXIT_ERR(const msg: String); |
| begin |
| WriteLn('Error: ', msg); |
| Halt(1); |
| end; |
| |
| (* =========================================================================== |
| * Test compress and uncompress |
| *) |
| {$IFDEF TEST_COMPRESS} |
| procedure test_compress(compr: Pointer; comprLen: LongInt; |
| uncompr: Pointer; uncomprLen: LongInt); |
| var err: Integer; |
| len: LongInt; |
| begin |
| len := StrLen(hello)+1; |
| |
| err := compress(compr, comprLen, hello, len); |
| CHECK_ERR(err, 'compress'); |
| |
| StrCopy(PChar(uncompr), 'garbage'); |
| |
| err := uncompress(uncompr, uncomprLen, compr, comprLen); |
| CHECK_ERR(err, 'uncompress'); |
| |
| if StrComp(PChar(uncompr), hello) <> 0 then |
| EXIT_ERR('bad uncompress') |
| else |
| WriteLn('uncompress(): ', PChar(uncompr)); |
| end; |
| {$ENDIF} |
| |
| (* =========================================================================== |
| * Test read/write of .gz files |
| *) |
| {$IFDEF TEST_GZIO} |
| procedure test_gzio(const fname: PChar; (* compressed file name *) |
| uncompr: Pointer; |
| uncomprLen: LongInt); |
| var err: Integer; |
| len: Integer; |
| zfile: gzFile; |
| pos: LongInt; |
| begin |
| len := StrLen(hello)+1; |
| |
| zfile := gzopen(fname, 'wb'); |
| if zfile = NIL then |
| begin |
| WriteLn('gzopen error'); |
| Halt(1); |
| end; |
| gzputc(zfile, 'h'); |
| if gzputs(zfile, 'ello') <> 4 then |
| begin |
| WriteLn('gzputs err: ', gzerror(zfile, err)); |
| Halt(1); |
| end; |
| {$IFDEF GZ_FORMAT_STRING} |
| if gzprintf(zfile, ', %s!', 'hello') <> 8 then |
| begin |
| WriteLn('gzprintf err: ', gzerror(zfile, err)); |
| Halt(1); |
| end; |
| {$ELSE} |
| if gzputs(zfile, ', hello!') <> 8 then |
| begin |
| WriteLn('gzputs err: ', gzerror(zfile, err)); |
| Halt(1); |
| end; |
| {$ENDIF} |
| gzseek(zfile, 1, SEEK_CUR); (* add one zero byte *) |
| gzclose(zfile); |
| |
| zfile := gzopen(fname, 'rb'); |
| if zfile = NIL then |
| begin |
| WriteLn('gzopen error'); |
| Halt(1); |
| end; |
| |
| StrCopy(PChar(uncompr), 'garbage'); |
| |
| if gzread(zfile, uncompr, uncomprLen) <> len then |
| begin |
| WriteLn('gzread err: ', gzerror(zfile, err)); |
| Halt(1); |
| end; |
| if StrComp(PChar(uncompr), hello) <> 0 then |
| begin |
| WriteLn('bad gzread: ', PChar(uncompr)); |
| Halt(1); |
| end |
| else |
| WriteLn('gzread(): ', PChar(uncompr)); |
| |
| pos := gzseek(zfile, -8, SEEK_CUR); |
| if (pos <> 6) or (gztell(zfile) <> pos) then |
| begin |
| WriteLn('gzseek error, pos=', pos, ', gztell=', gztell(zfile)); |
| Halt(1); |
| end; |
| |
| if gzgetc(zfile) <> ' ' then |
| begin |
| WriteLn('gzgetc error'); |
| Halt(1); |
| end; |
| |
| if gzungetc(' ', zfile) <> ' ' then |
| begin |
| WriteLn('gzungetc error'); |
| Halt(1); |
| end; |
| |
| gzgets(zfile, PChar(uncompr), uncomprLen); |
| uncomprLen := StrLen(PChar(uncompr)); |
| if uncomprLen <> 7 then (* " hello!" *) |
| begin |
| WriteLn('gzgets err after gzseek: ', gzerror(zfile, err)); |
| Halt(1); |
| end; |
| if StrComp(PChar(uncompr), hello + 6) <> 0 then |
| begin |
| WriteLn('bad gzgets after gzseek'); |
| Halt(1); |
| end |
| else |
| WriteLn('gzgets() after gzseek: ', PChar(uncompr)); |
| |
| gzclose(zfile); |
| end; |
| {$ENDIF} |
| |
| (* =========================================================================== |
| * Test deflate with small buffers |
| *) |
| {$IFDEF TEST_DEFLATE} |
| procedure test_deflate(compr: Pointer; comprLen: LongInt); |
| var c_stream: z_stream; (* compression stream *) |
| err: Integer; |
| len: LongInt; |
| begin |
| len := StrLen(hello)+1; |
| |
| c_stream.zalloc := NIL; |
| c_stream.zfree := NIL; |
| c_stream.opaque := NIL; |
| |
| err := deflateInit(c_stream, Z_DEFAULT_COMPRESSION); |
| CHECK_ERR(err, 'deflateInit'); |
| |
| c_stream.next_in := hello; |
| c_stream.next_out := compr; |
| |
| while (c_stream.total_in <> len) and |
| (c_stream.total_out < comprLen) do |
| begin |
| c_stream.avail_out := 1; { force small buffers } |
| c_stream.avail_in := 1; |
| err := deflate(c_stream, Z_NO_FLUSH); |
| CHECK_ERR(err, 'deflate'); |
| end; |
| |
| (* Finish the stream, still forcing small buffers: *) |
| while TRUE do |
| begin |
| c_stream.avail_out := 1; |
| err := deflate(c_stream, Z_FINISH); |
| if err = Z_STREAM_END then |
| break; |
| CHECK_ERR(err, 'deflate'); |
| end; |
| |
| err := deflateEnd(c_stream); |
| CHECK_ERR(err, 'deflateEnd'); |
| end; |
| {$ENDIF} |
| |
| (* =========================================================================== |
| * Test inflate with small buffers |
| *) |
| {$IFDEF TEST_INFLATE} |
| procedure test_inflate(compr: Pointer; comprLen : LongInt; |
| uncompr: Pointer; uncomprLen : LongInt); |
| var err: Integer; |
| d_stream: z_stream; (* decompression stream *) |
| begin |
| StrCopy(PChar(uncompr), 'garbage'); |
| |
| d_stream.zalloc := NIL; |
| d_stream.zfree := NIL; |
| d_stream.opaque := NIL; |
| |
| d_stream.next_in := compr; |
| d_stream.avail_in := 0; |
| d_stream.next_out := uncompr; |
| |
| err := inflateInit(d_stream); |
| CHECK_ERR(err, 'inflateInit'); |
| |
| while (d_stream.total_out < uncomprLen) and |
| (d_stream.total_in < comprLen) do |
| begin |
| d_stream.avail_out := 1; (* force small buffers *) |
| d_stream.avail_in := 1; |
| err := inflate(d_stream, Z_NO_FLUSH); |
| if err = Z_STREAM_END then |
| break; |
| CHECK_ERR(err, 'inflate'); |
| end; |
| |
| err := inflateEnd(d_stream); |
| CHECK_ERR(err, 'inflateEnd'); |
| |
| if StrComp(PChar(uncompr), hello) <> 0 then |
| EXIT_ERR('bad inflate') |
| else |
| WriteLn('inflate(): ', PChar(uncompr)); |
| end; |
| {$ENDIF} |
| |
| (* =========================================================================== |
| * Test deflate with large buffers and dynamic change of compression level |
| *) |
| {$IFDEF TEST_DEFLATE} |
| procedure test_large_deflate(compr: Pointer; comprLen: LongInt; |
| uncompr: Pointer; uncomprLen: LongInt); |
| var c_stream: z_stream; (* compression stream *) |
| err: Integer; |
| begin |
| c_stream.zalloc := NIL; |
| c_stream.zfree := NIL; |
| c_stream.opaque := NIL; |
| |
| err := deflateInit(c_stream, Z_BEST_SPEED); |
| CHECK_ERR(err, 'deflateInit'); |
| |
| c_stream.next_out := compr; |
| c_stream.avail_out := Integer(comprLen); |
| |
| (* At this point, uncompr is still mostly zeroes, so it should compress |
| * very well: |
| *) |
| c_stream.next_in := uncompr; |
| c_stream.avail_in := Integer(uncomprLen); |
| err := deflate(c_stream, Z_NO_FLUSH); |
| CHECK_ERR(err, 'deflate'); |
| if c_stream.avail_in <> 0 then |
| EXIT_ERR('deflate not greedy'); |
| |
| (* Feed in already compressed data and switch to no compression: *) |
| deflateParams(c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); |
| c_stream.next_in := compr; |
| c_stream.avail_in := Integer(comprLen div 2); |
| err := deflate(c_stream, Z_NO_FLUSH); |
| CHECK_ERR(err, 'deflate'); |
| |
| (* Switch back to compressing mode: *) |
| deflateParams(c_stream, Z_BEST_COMPRESSION, Z_FILTERED); |
| c_stream.next_in := uncompr; |
| c_stream.avail_in := Integer(uncomprLen); |
| err := deflate(c_stream, Z_NO_FLUSH); |
| CHECK_ERR(err, 'deflate'); |
| |
| err := deflate(c_stream, Z_FINISH); |
| if err <> Z_STREAM_END then |
| EXIT_ERR('deflate should report Z_STREAM_END'); |
| |
| err := deflateEnd(c_stream); |
| CHECK_ERR(err, 'deflateEnd'); |
| end; |
| {$ENDIF} |
| |
| (* =========================================================================== |
| * Test inflate with large buffers |
| *) |
| {$IFDEF TEST_INFLATE} |
| procedure test_large_inflate(compr: Pointer; comprLen: LongInt; |
| uncompr: Pointer; uncomprLen: LongInt); |
| var err: Integer; |
| d_stream: z_stream; (* decompression stream *) |
| begin |
| StrCopy(PChar(uncompr), 'garbage'); |
| |
| d_stream.zalloc := NIL; |
| d_stream.zfree := NIL; |
| d_stream.opaque := NIL; |
| |
| d_stream.next_in := compr; |
| d_stream.avail_in := Integer(comprLen); |
| |
| err := inflateInit(d_stream); |
| CHECK_ERR(err, 'inflateInit'); |
| |
| while TRUE do |
| begin |
| d_stream.next_out := uncompr; (* discard the output *) |
| d_stream.avail_out := Integer(uncomprLen); |
| err := inflate(d_stream, Z_NO_FLUSH); |
| if err = Z_STREAM_END then |
| break; |
| CHECK_ERR(err, 'large inflate'); |
| end; |
| |
| err := inflateEnd(d_stream); |
| CHECK_ERR(err, 'inflateEnd'); |
| |
| if d_stream.total_out <> 2 * uncomprLen + comprLen div 2 then |
| begin |
| WriteLn('bad large inflate: ', d_stream.total_out); |
| Halt(1); |
| end |
| else |
| WriteLn('large_inflate(): OK'); |
| end; |
| {$ENDIF} |
| |
| (* =========================================================================== |
| * Test deflate with full flush |
| *) |
| {$IFDEF TEST_FLUSH} |
| procedure test_flush(compr: Pointer; var comprLen : LongInt); |
| var c_stream: z_stream; (* compression stream *) |
| err: Integer; |
| len: Integer; |
| begin |
| len := StrLen(hello)+1; |
| |
| c_stream.zalloc := NIL; |
| c_stream.zfree := NIL; |
| c_stream.opaque := NIL; |
| |
| err := deflateInit(c_stream, Z_DEFAULT_COMPRESSION); |
| CHECK_ERR(err, 'deflateInit'); |
| |
| c_stream.next_in := hello; |
| c_stream.next_out := compr; |
| c_stream.avail_in := 3; |
| c_stream.avail_out := Integer(comprLen); |
| err := deflate(c_stream, Z_FULL_FLUSH); |
| CHECK_ERR(err, 'deflate'); |
| |
| Inc(PByteArray(compr)^[3]); (* force an error in first compressed block *) |
| c_stream.avail_in := len - 3; |
| |
| err := deflate(c_stream, Z_FINISH); |
| if err <> Z_STREAM_END then |
| CHECK_ERR(err, 'deflate'); |
| |
| err := deflateEnd(c_stream); |
| CHECK_ERR(err, 'deflateEnd'); |
| |
| comprLen := c_stream.total_out; |
| end; |
| {$ENDIF} |
| |
| (* =========================================================================== |
| * Test inflateSync() |
| *) |
| {$IFDEF TEST_SYNC} |
| procedure test_sync(compr: Pointer; comprLen: LongInt; |
| uncompr: Pointer; uncomprLen : LongInt); |
| var err: Integer; |
| d_stream: z_stream; (* decompression stream *) |
| begin |
| StrCopy(PChar(uncompr), 'garbage'); |
| |
| d_stream.zalloc := NIL; |
| d_stream.zfree := NIL; |
| d_stream.opaque := NIL; |
| |
| d_stream.next_in := compr; |
| d_stream.avail_in := 2; (* just read the zlib header *) |
| |
| err := inflateInit(d_stream); |
| CHECK_ERR(err, 'inflateInit'); |
| |
| d_stream.next_out := uncompr; |
| d_stream.avail_out := Integer(uncomprLen); |
| |
| inflate(d_stream, Z_NO_FLUSH); |
| CHECK_ERR(err, 'inflate'); |
| |
| d_stream.avail_in := Integer(comprLen-2); (* read all compressed data *) |
| err := inflateSync(d_stream); (* but skip the damaged part *) |
| CHECK_ERR(err, 'inflateSync'); |
| |
| err := inflate(d_stream, Z_FINISH); |
| if err <> Z_DATA_ERROR then |
| EXIT_ERR('inflate should report DATA_ERROR'); |
| (* Because of incorrect adler32 *) |
| |
| err := inflateEnd(d_stream); |
| CHECK_ERR(err, 'inflateEnd'); |
| |
| WriteLn('after inflateSync(): hel', PChar(uncompr)); |
| end; |
| {$ENDIF} |
| |
| (* =========================================================================== |
| * Test deflate with preset dictionary |
| *) |
| {$IFDEF TEST_DICT} |
| procedure test_dict_deflate(compr: Pointer; comprLen: LongInt); |
| var c_stream: z_stream; (* compression stream *) |
| err: Integer; |
| begin |
| c_stream.zalloc := NIL; |
| c_stream.zfree := NIL; |
| c_stream.opaque := NIL; |
| |
| err := deflateInit(c_stream, Z_BEST_COMPRESSION); |
| CHECK_ERR(err, 'deflateInit'); |
| |
| err := deflateSetDictionary(c_stream, dictionary, StrLen(dictionary)); |
| CHECK_ERR(err, 'deflateSetDictionary'); |
| |
| dictId := c_stream.adler; |
| c_stream.next_out := compr; |
| c_stream.avail_out := Integer(comprLen); |
| |
| c_stream.next_in := hello; |
| c_stream.avail_in := StrLen(hello)+1; |
| |
| err := deflate(c_stream, Z_FINISH); |
| if err <> Z_STREAM_END then |
| EXIT_ERR('deflate should report Z_STREAM_END'); |
| |
| err := deflateEnd(c_stream); |
| CHECK_ERR(err, 'deflateEnd'); |
| end; |
| {$ENDIF} |
| |
| (* =========================================================================== |
| * Test inflate with a preset dictionary |
| *) |
| {$IFDEF TEST_DICT} |
| procedure test_dict_inflate(compr: Pointer; comprLen: LongInt; |
| uncompr: Pointer; uncomprLen: LongInt); |
| var err: Integer; |
| d_stream: z_stream; (* decompression stream *) |
| begin |
| StrCopy(PChar(uncompr), 'garbage'); |
| |
| d_stream.zalloc := NIL; |
| d_stream.zfree := NIL; |
| d_stream.opaque := NIL; |
| |
| d_stream.next_in := compr; |
| d_stream.avail_in := Integer(comprLen); |
| |
| err := inflateInit(d_stream); |
| CHECK_ERR(err, 'inflateInit'); |
| |
| d_stream.next_out := uncompr; |
| d_stream.avail_out := Integer(uncomprLen); |
| |
| while TRUE do |
| begin |
| err := inflate(d_stream, Z_NO_FLUSH); |
| if err = Z_STREAM_END then |
| break; |
| if err = Z_NEED_DICT then |
| begin |
| if d_stream.adler <> dictId then |
| EXIT_ERR('unexpected dictionary'); |
| err := inflateSetDictionary(d_stream, dictionary, StrLen(dictionary)); |
| end; |
| CHECK_ERR(err, 'inflate with dict'); |
| end; |
| |
| err := inflateEnd(d_stream); |
| CHECK_ERR(err, 'inflateEnd'); |
| |
| if StrComp(PChar(uncompr), hello) <> 0 then |
| EXIT_ERR('bad inflate with dict') |
| else |
| WriteLn('inflate with dictionary: ', PChar(uncompr)); |
| end; |
| {$ENDIF} |
| |
| var compr, uncompr: Pointer; |
| comprLen, uncomprLen: LongInt; |
| |
| begin |
| if zlibVersion^ <> ZLIB_VERSION[1] then |
| EXIT_ERR('Incompatible zlib version'); |
| |
| WriteLn('zlib version: ', zlibVersion); |
| WriteLn('zlib compile flags: ', Format('0x%x', [zlibCompileFlags])); |
| |
| comprLen := 10000 * SizeOf(Integer); (* don't overflow on MSDOS *) |
| uncomprLen := comprLen; |
| GetMem(compr, comprLen); |
| GetMem(uncompr, uncomprLen); |
| if (compr = NIL) or (uncompr = NIL) then |
| EXIT_ERR('Out of memory'); |
| (* compr and uncompr are cleared to avoid reading uninitialized |
| * data and to ensure that uncompr compresses well. |
| *) |
| FillChar(compr^, comprLen, 0); |
| FillChar(uncompr^, uncomprLen, 0); |
| |
| {$IFDEF TEST_COMPRESS} |
| WriteLn('** Testing compress'); |
| test_compress(compr, comprLen, uncompr, uncomprLen); |
| {$ENDIF} |
| |
| {$IFDEF TEST_GZIO} |
| WriteLn('** Testing gzio'); |
| if ParamCount >= 1 then |
| test_gzio(ParamStr(1), uncompr, uncomprLen) |
| else |
| test_gzio(TESTFILE, uncompr, uncomprLen); |
| {$ENDIF} |
| |
| {$IFDEF TEST_DEFLATE} |
| WriteLn('** Testing deflate with small buffers'); |
| test_deflate(compr, comprLen); |
| {$ENDIF} |
| {$IFDEF TEST_INFLATE} |
| WriteLn('** Testing inflate with small buffers'); |
| test_inflate(compr, comprLen, uncompr, uncomprLen); |
| {$ENDIF} |
| |
| {$IFDEF TEST_DEFLATE} |
| WriteLn('** Testing deflate with large buffers'); |
| test_large_deflate(compr, comprLen, uncompr, uncomprLen); |
| {$ENDIF} |
| {$IFDEF TEST_INFLATE} |
| WriteLn('** Testing inflate with large buffers'); |
| test_large_inflate(compr, comprLen, uncompr, uncomprLen); |
| {$ENDIF} |
| |
| {$IFDEF TEST_FLUSH} |
| WriteLn('** Testing deflate with full flush'); |
| test_flush(compr, comprLen); |
| {$ENDIF} |
| {$IFDEF TEST_SYNC} |
| WriteLn('** Testing inflateSync'); |
| test_sync(compr, comprLen, uncompr, uncomprLen); |
| {$ENDIF} |
| comprLen := uncomprLen; |
| |
| {$IFDEF TEST_DICT} |
| WriteLn('** Testing deflate and inflate with preset dictionary'); |
| test_dict_deflate(compr, comprLen); |
| test_dict_inflate(compr, comprLen, uncompr, uncomprLen); |
| {$ENDIF} |
| |
| FreeMem(compr, comprLen); |
| FreeMem(uncompr, uncomprLen); |
| end. |