example.pas 15 KB

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