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.