zip.pas 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792
  1. unit zip;
  2. { zip.c -- IO on .zip files using zlib
  3. zip.h -- IO for compress .zip files using zlib
  4. Version 0.15 alpha, Mar 19th, 1998,
  5. Copyright (C) 1998 Gilles Vollant
  6. This package allows to create .ZIP file, compatible with PKZip 2.04g
  7. WinZip, InfoZip tools and compatible.
  8. Encryption and multi volume ZipFile (span) are not supported.
  9. Old compressions used by old PKZip 1.x are not supported
  10. For decompression of .zip files, look at unzip.pas
  11. Pascal tranlastion
  12. Copyright (C) 2000 by Jacques Nomssi Nzali
  13. For conditions of distribution and use, see copyright notice in readme.txt }
  14. interface
  15. {$ifdef WIN32}
  16. {$define Delphi}
  17. {$endif}
  18. uses
  19. //zutil,
  20. zbase,
  21. //zLib,
  22. ziputils;
  23. const
  24. ZIP_OK = (0);
  25. ZIP_ERRNO = (Z_ERRNO);
  26. ZIP_PARAMERROR = (-102);
  27. ZIP_INTERNALERROR = (-104);
  28. Z_DEFAULT_COMPRESSION = -(1);
  29. Z_DEFLATED = 8;
  30. (*
  31. { tm_zip contain date/time info }
  32. type
  33. tm_zip = record
  34. tm_sec : integer; { seconds after the minute - [0,59] }
  35. tm_min : integer; { minutes after the hour - [0,59] }
  36. tm_hour : integer; { hours since midnight - [0,23] }
  37. tm_mday : integer; { day of the month - [1,31] }
  38. tm_mon : integer; { months since January - [0,11] }
  39. tm_year : integer; { years - [1980..2044] }
  40. end;
  41. *)
  42. type
  43. zip_fileinfo = record
  44. tmz_date: tm_zip; { date in understandable format }
  45. dosDate: longword; { if dos_date = 0, tmu_date is used }
  46. { flag : longint; }{ general purpose bit flag 2 bytes }
  47. internal_fa: longint; { internal file attributes 2 bytes }
  48. external_fa: longint; { external file attributes 4 bytes }
  49. end;
  50. zip_fileinfo_ptr = ^zip_fileinfo;
  51. function zipOpen(const pathname: PChar; append: longint): zipFile; {ZEXPORT}
  52. { Create a zipfile.
  53. pathname contain on Windows NT a filename like "c:\\zlib\\zlib111.zip" or on
  54. an Unix computer "zlib/zlib111.zip".
  55. if the file pathname exist and append=1, the zip will be created at the end
  56. of the file. (useful if the file contain a self extractor code)
  57. If the zipfile cannot be opened, the return value is NIL.
  58. Else, the return value is a zipFile Handle, usable with other function
  59. of this zip package. }
  60. function zipOpenNewFileInZip(afile: zipFile;
  61. {const} filename: PChar; const zipfi: zip_fileinfo_ptr; const extrafield_local: pointer; size_extrafield_local: integer; const extrafield_global: pointer; size_extrafield_global: integer; const comment: PChar; method: longint; level: longint): longint; {ZEXPORT}
  62. { Open a file in the ZIP for writing.
  63. filename : the filename in zip (if NIL, '-' without quote will be used
  64. zipfi^ contain supplemental information
  65. if extrafield_local<>NIL and size_extrafield_local>0, extrafield_local
  66. contains the extrafield data the the local header
  67. if extrafield_global<>NIL and size_extrafield_global>0, extrafield_global
  68. contains the extrafield data the the local header
  69. if comment <> NIL, comment contain the comment string
  70. method contain the compression method (0 for store, Z_DEFLATED for deflate)
  71. level contain the level of compression (can be Z_DEFAULT_COMPRESSION) }
  72. function zipWriteInFileInZip(afile: zipFile; const buf: pointer; len: cardinal): longint; {ZEXPORT}
  73. { Write data in the zipfile }
  74. function zipCloseFileInZip(afile: zipFile): longint; {ZEXPORT}
  75. { Close the current file in the zipfile }
  76. function zipClose(afile: zipFile; const global_comment: PChar): longint; {ZEXPORT}
  77. { Close the zipfile }
  78. implementation
  79. uses
  80. {$ifdef Delphi}
  81. SysUtils,
  82. {$else}
  83. strings,
  84. {$endif}
  85. zDeflate, crc;
  86. const
  87. VERSIONMADEBY = ($0); { platform depedent }
  88. const
  89. zip_copyright: PChar = ' zip 0.15 Copyright 1998 Gilles Vollant ';
  90. const
  91. SIZEDATA_INDATABLOCK = (4096 - (4 * 4));
  92. LOCALHEADERMAGIC = $04034b50;
  93. {CENTRALHEADERMAGIC = $02014b50;}
  94. ENDHEADERMAGIC = $06054b50;
  95. FLAG_LOCALHEADER_OFFSET = $06;
  96. CRC_LOCALHEADER_OFFSET = $0e;
  97. SIZECENTRALHEADER = $2e; { 46 }
  98. type
  99. linkedlist_datablock_internal_ptr = ^linkedlist_datablock_internal;
  100. linkedlist_datablock_internal = record
  101. next_datablock: linkedlist_datablock_internal_ptr;
  102. avail_in_this_block: longint;
  103. filled_in_this_block: longint;
  104. unused: longint; { for future use and alignement }
  105. Data: array[0..SIZEDATA_INDATABLOCK - 1] of byte;
  106. end;
  107. type
  108. linkedlist_data = record
  109. first_block: linkedlist_datablock_internal_ptr;
  110. last_block: linkedlist_datablock_internal_ptr;
  111. end;
  112. linkedlist_data_ptr = ^linkedlist_data;
  113. type
  114. curfile_info = record
  115. stream: z_stream; { zLib stream structure for inflate }
  116. stream_initialised: boolean; { TRUE is stream is initialised }
  117. pos_in_buffered_data: integer; { last written byte in buffered_data }
  118. pos_local_header: longint; { offset of the local header of the file
  119. currenty writing }
  120. central_header: PChar; { central header data for the current file }
  121. size_centralheader: longint; { size of the central header for cur file }
  122. flag: longint; { flag of the file currently writing }
  123. method: longint; { compression method of file currenty wr.}
  124. buffered_data: array[0..Z_BUFSIZE - 1] of byte;{ buffer contain compressed data to be written}
  125. dosDate: longint;
  126. crc32: longint;
  127. end;
  128. type
  129. zip_internal = record
  130. filezip: FILEptr;
  131. central_dir: linkedlist_data; { datablock with central dir in construction}
  132. in_opened_file_inzip: boolean; { TRUE if a file in the zip is currently writ.}
  133. ci: curfile_info; { info on the file curretly writing }
  134. begin_pos: longint; { position of the beginning of the zipfile }
  135. number_entry: longint;
  136. end;
  137. zip_internal_ptr = ^zip_internal;
  138. function allocate_new_datablock: linkedlist_datablock_internal_ptr;
  139. var
  140. ldi: linkedlist_datablock_internal_ptr;
  141. begin
  142. ldi := linkedlist_datablock_internal_ptr(GetMem(sizeof(linkedlist_datablock_internal)));
  143. if (ldi <> nil) then
  144. begin
  145. ldi^.next_datablock := nil;
  146. ldi^.filled_in_this_block := 0;
  147. ldi^.avail_in_this_block := SIZEDATA_INDATABLOCK;
  148. end;
  149. allocate_new_datablock := ldi;
  150. end;
  151. procedure free_datablock(ldi: linkedlist_datablock_internal_ptr);
  152. var
  153. ldinext: linkedlist_datablock_internal_ptr;
  154. begin
  155. while (ldi <> nil) do
  156. begin
  157. ldinext := ldi^.next_datablock;
  158. FreeMem(ldi);
  159. ldi := ldinext;
  160. end;
  161. end;
  162. procedure init_linkedlist(var ll: linkedlist_data);
  163. begin
  164. ll.last_block := nil;
  165. ll.first_block := nil;
  166. end;
  167. procedure free_linkedlist(var ll: linkedlist_data);
  168. begin
  169. free_datablock(ll.first_block);
  170. ll.last_block := nil;
  171. ll.first_block := nil;
  172. end;
  173. function add_data_in_datablock(ll: linkedlist_data_ptr; const buf: pointer; len: longint): longint;
  174. var
  175. ldi: linkedlist_datablock_internal_ptr;
  176. from_copy: {const} Pbyte;
  177. var
  178. copy_this: integer;
  179. i: integer;
  180. to_copy: Pbyte;
  181. begin
  182. if (ll = nil) then
  183. begin
  184. add_data_in_datablock := ZIP_INTERNALERROR;
  185. exit;
  186. end;
  187. if (ll^.last_block = nil) then
  188. begin
  189. ll^.last_block := allocate_new_datablock;
  190. ll^.first_block := ll^.last_block;
  191. if (ll^.first_block = nil) then
  192. begin
  193. add_data_in_datablock := ZIP_INTERNALERROR;
  194. exit;
  195. end;
  196. end;
  197. ldi := ll^.last_block;
  198. from_copy := Pbyte(buf);
  199. while (len > 0) do
  200. begin
  201. if (ldi^.avail_in_this_block = 0) then
  202. begin
  203. ldi^.next_datablock := allocate_new_datablock;
  204. if (ldi^.next_datablock = nil) then
  205. begin
  206. add_data_in_datablock := ZIP_INTERNALERROR;
  207. exit;
  208. end;
  209. ldi := ldi^.next_datablock;
  210. ll^.last_block := ldi;
  211. end;
  212. if (ldi^.avail_in_this_block < len) then
  213. copy_this := integer(ldi^.avail_in_this_block)
  214. else
  215. copy_this := integer(len);
  216. to_copy := @(ldi^.Data[ldi^.filled_in_this_block]);
  217. for i := 0 to copy_this - 1 do
  218. Pbytearray(to_copy)^[i] := Pbytearray(from_copy)^[i];
  219. Inc(ldi^.filled_in_this_block, copy_this);
  220. Dec(ldi^.avail_in_this_block, copy_this);
  221. Inc(from_copy, copy_this);
  222. Dec(len, copy_this);
  223. end;
  224. add_data_in_datablock := ZIP_OK;
  225. end;
  226. function write_datablock(fout: FILEptr; ll: linkedlist_data_ptr): longint;
  227. var
  228. ldi: linkedlist_datablock_internal_ptr;
  229. begin
  230. ldi := ll^.first_block;
  231. while (ldi <> nil) do
  232. begin
  233. if (ldi^.filled_in_this_block > 0) then
  234. if (fwrite(@ldi^.Data, integer(ldi^.filled_in_this_block), 1, fout) <> 1) then
  235. begin
  236. write_datablock := ZIP_ERRNO;
  237. exit;
  238. end;
  239. ldi := ldi^.next_datablock;
  240. end;
  241. write_datablock := ZIP_OK;
  242. end;
  243. {**************************************************************************}
  244. { ===========================================================================
  245. Outputs a long in LSB order to the given file
  246. nbByte = 1, 2 or 4 (byte, short or long) }
  247. function ziplocal_putValue(afile: FILEptr; x: longint; nbByte: longint): longint;
  248. var
  249. buf: array[0..4 - 1] of byte;
  250. n: longint;
  251. begin
  252. for n := 0 to nbByte - 1 do
  253. begin
  254. buf[n] := byte(x and $ff);
  255. x := x shr 8;
  256. end;
  257. if (fwrite(@buf, nbByte, 1, afile) <> 1) then
  258. ziplocal_putValue := ZIP_ERRNO
  259. else
  260. ziplocal_putValue := ZIP_OK;
  261. end;
  262. procedure ziplocal_putValue_inmemory(dest: pointer; x: longint; nbByte: longint);
  263. var
  264. buf: Pbytearray;
  265. n: longint;
  266. begin
  267. buf := Pbytearray(dest);
  268. for n := 0 to nbByte - 1 do
  269. begin
  270. buf^[n] := Byte(x and $ff);
  271. x := x shr 8;
  272. end;
  273. end;
  274. {**************************************************************************}
  275. function ziplocal_TmzDateToDosDate(var ptm: tm_zip; dosDate: longint): longint;
  276. var
  277. year: longint;
  278. begin
  279. year := longint(ptm.tm_year);
  280. if (year > 1980) then
  281. Dec(year, 1980)
  282. else
  283. if (year > 80) then
  284. Dec(year, 80);
  285. ziplocal_TmzDateToDosDate := longint(
  286. ((ptm.tm_mday) + (32 * (ptm.tm_mon + 1)) + (512 * year)) shl 16) or
  287. ((ptm.tm_sec div 2) + (32 * ptm.tm_min) + (2048 * longint(ptm.tm_hour)));
  288. end;
  289. {**************************************************************************}
  290. function zipOpen(const pathname: PChar; append: longint): zipFile; {ZEXPORT}
  291. var
  292. ziinit: zip_internal;
  293. zi: zip_internal_ptr;
  294. begin
  295. if (append = 0) then
  296. ziinit.filezip := fopen(pathname, fopenwrite)
  297. else
  298. ziinit.filezip := fopen(pathname, fappendwrite);
  299. if (ziinit.filezip = nil) then
  300. begin
  301. zipOpen := nil;
  302. exit;
  303. end;
  304. ziinit.begin_pos := ftell(ziinit.filezip);
  305. ziinit.in_opened_file_inzip := False;
  306. ziinit.ci.stream_initialised := False;
  307. ziinit.number_entry := 0;
  308. init_linkedlist(ziinit.central_dir);
  309. zi := zip_internal_ptr(AllocMem(sizeof(zip_internal)));
  310. if (zi = nil) then
  311. begin
  312. fclose(ziinit.filezip);
  313. zipOpen := nil;
  314. exit;
  315. end;
  316. zi^ := ziinit;
  317. zipOpen := zipFile(zi);
  318. end;
  319. function zipOpenNewFileInZip(afile: zipFile;
  320. {const} filename: PChar; const zipfi: zip_fileinfo_ptr; const extrafield_local: pointer; size_extrafield_local: integer; const extrafield_global: pointer; size_extrafield_global: integer; const comment: PChar; method: longint; level: longint): longint; {ZEXPORT}
  321. var
  322. zi: zip_internal_ptr;
  323. size_filename: integer;
  324. size_comment: integer;
  325. i: integer;
  326. err: longint;
  327. begin
  328. err := ZIP_OK;
  329. if (afile = nil) then
  330. begin
  331. zipOpenNewFileInZip := ZIP_PARAMERROR;
  332. exit;
  333. end;
  334. if ((method <> 0) and (method <> Z_DEFLATED)) then
  335. begin
  336. zipOpenNewFileInZip := ZIP_PARAMERROR;
  337. exit;
  338. end;
  339. zi := zip_internal_ptr(afile);
  340. if (zi^.in_opened_file_inzip = True) then
  341. begin
  342. err := zipCloseFileInZip(afile);
  343. if (err <> ZIP_OK) then
  344. begin
  345. zipOpenNewFileInZip := err;
  346. exit;
  347. end;
  348. end;
  349. if (filename = nil) then
  350. filename := '-';
  351. if (comment = nil) then
  352. size_comment := 0
  353. else
  354. size_comment := strlen(comment);
  355. size_filename := strlen(filename);
  356. if (zipfi = nil) then
  357. zi^.ci.dosDate := 0
  358. else
  359. if (zipfi^.dosDate <> 0) then
  360. zi^.ci.dosDate := zipfi^.dosDate
  361. else
  362. zi^.ci.dosDate := ziplocal_TmzDateToDosDate(zipfi^.tmz_date, zipfi^.dosDate);
  363. zi^.ci.flag := 0;
  364. if ((level = 8) or (level = 9)) then
  365. zi^.ci.flag := zi^.ci.flag or 2;
  366. if ((level = 2)) then
  367. zi^.ci.flag := zi^.ci.flag or 4;
  368. if ((level = 1)) then
  369. zi^.ci.flag := zi^.ci.flag or 6;
  370. zi^.ci.crc32 := 0;
  371. zi^.ci.method := method;
  372. zi^.ci.stream_initialised := False;
  373. zi^.ci.pos_in_buffered_data := 0;
  374. zi^.ci.pos_local_header := ftell(zi^.filezip);
  375. zi^.ci.size_centralheader := SIZECENTRALHEADER + size_filename +
  376. size_extrafield_global + size_comment;
  377. zi^.ci.central_header := PChar(AllocMem(integer(zi^.ci.size_centralheader)));
  378. ziplocal_putValue_inmemory(zi^.ci.central_header, longint(CENTRALHEADERMAGIC), 4);
  379. { version info }
  380. ziplocal_putValue_inmemory(zi^.ci.central_header + 4, longint(VERSIONMADEBY), 2);
  381. ziplocal_putValue_inmemory(zi^.ci.central_header + 6, longint(20), 2);
  382. ziplocal_putValue_inmemory(zi^.ci.central_header + 8, longint(zi^.ci.flag), 2);
  383. ziplocal_putValue_inmemory(zi^.ci.central_header + 10, longint(zi^.ci.method), 2);
  384. ziplocal_putValue_inmemory(zi^.ci.central_header + 12, longint(zi^.ci.dosDate), 4);
  385. ziplocal_putValue_inmemory(zi^.ci.central_header + 16, longint(0), 4); {crc}
  386. ziplocal_putValue_inmemory(zi^.ci.central_header + 20, longint(0), 4); {compr size}
  387. ziplocal_putValue_inmemory(zi^.ci.central_header + 24, longint(0), 4); {uncompr size}
  388. ziplocal_putValue_inmemory(zi^.ci.central_header + 28, longint(size_filename), 2);
  389. ziplocal_putValue_inmemory(zi^.ci.central_header + 30, longint(size_extrafield_global), 2);
  390. ziplocal_putValue_inmemory(zi^.ci.central_header + 32, longint(size_comment), 2);
  391. ziplocal_putValue_inmemory(zi^.ci.central_header + 34, longint(0), 2); {disk nm start}
  392. if (zipfi = nil) then
  393. ziplocal_putValue_inmemory(zi^.ci.central_header + 36, longint(0), 2)
  394. else
  395. ziplocal_putValue_inmemory(zi^.ci.central_header + 36, longint(zipfi^.internal_fa), 2);
  396. if (zipfi = nil) then
  397. ziplocal_putValue_inmemory(zi^.ci.central_header + 38, longint(0), 4)
  398. else
  399. ziplocal_putValue_inmemory(zi^.ci.central_header + 38, longint(zipfi^.external_fa), 4);
  400. ziplocal_putValue_inmemory(zi^.ci.central_header + 42, longint(zi^.ci.pos_local_header), 4);
  401. i := 0;
  402. while (i < size_filename) do
  403. begin
  404. (zi^.ci.central_header +SIZECENTRALHEADER + i)^ := (filename + i)^;
  405. Inc(i);
  406. end;
  407. i := 0;
  408. while (i < size_extrafield_global) do
  409. begin
  410. (zi^.ci.central_header +SIZECENTRALHEADER + size_filename + i)^ :=
  411. ({const} PChar(extrafield_global) + i)^;
  412. Inc(i);
  413. end;
  414. i := 0;
  415. while (i < size_comment) do
  416. begin
  417. (zi^.ci.central_header +SIZECENTRALHEADER + size_filename + size_extrafield_global + i)^ := (filename + i)^;
  418. Inc(i);
  419. end;
  420. if (zi^.ci.central_header = nil) then
  421. begin
  422. zipOpenNewFileInZip := ZIP_INTERNALERROR;
  423. exit;
  424. end;
  425. { write the local header }
  426. err := ziplocal_putValue(zi^.filezip, longint(LOCALHEADERMAGIC), 4);
  427. if (err = ZIP_OK) then
  428. err := ziplocal_putValue(zi^.filezip, longint(20), 2); { version needed to extract }
  429. if (err = ZIP_OK) then
  430. err := ziplocal_putValue(zi^.filezip, longint(zi^.ci.flag), 2);
  431. if (err = ZIP_OK) then
  432. err := ziplocal_putValue(zi^.filezip, longint(zi^.ci.method), 2);
  433. if (err = ZIP_OK) then
  434. err := ziplocal_putValue(zi^.filezip, longint(zi^.ci.dosDate), 4);
  435. if (err = ZIP_OK) then
  436. err := ziplocal_putValue(zi^.filezip, longint(0), 4); { crc 32, unknown }
  437. if (err = ZIP_OK) then
  438. err := ziplocal_putValue(zi^.filezip, longint(0), 4); { compressed size, unknown }
  439. if (err = ZIP_OK) then
  440. err := ziplocal_putValue(zi^.filezip, longint(0), 4); { uncompressed size, unknown }
  441. if (err = ZIP_OK) then
  442. err := ziplocal_putValue(zi^.filezip, longint(size_filename), 2);
  443. if (err = ZIP_OK) then
  444. err := ziplocal_putValue(zi^.filezip, longint(size_extrafield_local), 2);
  445. if ((err = ZIP_OK) and (size_filename > 0)) then
  446. if (fwrite(filename, integer(size_filename), 1, zi^.filezip) <> 1) then
  447. err := ZIP_ERRNO;
  448. if ((err = ZIP_OK) and (size_extrafield_local > 0)) then
  449. if (fwrite(extrafield_local, integer(size_extrafield_local), 1, zi^.filezip) <> 1) then
  450. err := ZIP_ERRNO;
  451. zi^.ci.stream.avail_in := integer(0);
  452. zi^.ci.stream.avail_out := integer(Z_BUFSIZE);
  453. zi^.ci.stream.next_out := Pbyte(@zi^.ci.buffered_data);
  454. zi^.ci.stream.total_in := 0;
  455. zi^.ci.stream.total_out := 0;
  456. if ((err = ZIP_OK) and (zi^.ci.method = Z_DEFLATED)) then
  457. begin
  458. err := deflateInit2(zi^.ci.stream, level,
  459. Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0);
  460. if (err = Z_OK) then
  461. zi^.ci.stream_initialised := True;
  462. end;
  463. if (err = Z_OK) then
  464. zi^.in_opened_file_inzip := True;
  465. zipOpenNewFileInZip := err;
  466. end;
  467. function zipWriteInFileInZip(afile: zipFile; const buf: pointer; len: cardinal): longint; {ZEXPORT}
  468. var
  469. zi: zip_internal_ptr;
  470. err: longint;
  471. var
  472. uTotalOutBefore: longint;
  473. var
  474. copy_this, i: integer;
  475. begin
  476. err := ZIP_OK;
  477. if (afile = nil) then
  478. begin
  479. zipWriteInFileInZip := ZIP_PARAMERROR;
  480. exit;
  481. end;
  482. zi := zip_internal_ptr(afile);
  483. if (zi^.in_opened_file_inzip = False) then
  484. begin
  485. zipWriteInFileInZip := ZIP_PARAMERROR;
  486. exit;
  487. end;
  488. zi^.ci.stream.next_in := buf;
  489. zi^.ci.stream.avail_in := len;
  490. zi^.ci.crc32 := crc32(zi^.ci.crc32, buf, len);
  491. while ((err = ZIP_OK) and (zi^.ci.stream.avail_in > 0)) do
  492. begin
  493. if (zi^.ci.stream.avail_out = 0) then
  494. begin
  495. if fwrite(@zi^.ci.buffered_data, integer(zi^.ci.pos_in_buffered_data), 1, zi^.filezip) <> 1 then
  496. err := ZIP_ERRNO;
  497. zi^.ci.pos_in_buffered_data := 0;
  498. zi^.ci.stream.avail_out := integer(Z_BUFSIZE);
  499. zi^.ci.stream.next_out := Pbyte(@zi^.ci.buffered_data);
  500. end;
  501. if (zi^.ci.method = Z_DEFLATED) then
  502. begin
  503. uTotalOutBefore := zi^.ci.stream.total_out;
  504. err := deflate(zi^.ci.stream, Z_NO_FLUSH);
  505. Inc(zi^.ci.pos_in_buffered_data, integer(zi^.ci.stream.total_out - uTotalOutBefore));
  506. end
  507. else
  508. begin
  509. if (zi^.ci.stream.avail_in < zi^.ci.stream.avail_out) then
  510. copy_this := zi^.ci.stream.avail_in
  511. else
  512. copy_this := zi^.ci.stream.avail_out;
  513. for i := 0 to copy_this - 1 do
  514. (PChar(zi^.ci.stream.next_out) +i)^ :=
  515. ( {const} PChar(zi^.ci.stream.next_in) + i)^;
  516. Dec(zi^.ci.stream.avail_in, copy_this);
  517. Dec(zi^.ci.stream.avail_out, copy_this);
  518. Inc(zi^.ci.stream.next_in, copy_this);
  519. Inc(zi^.ci.stream.next_out, copy_this);
  520. Inc(zi^.ci.stream.total_in, copy_this);
  521. Inc(zi^.ci.stream.total_out, copy_this);
  522. Inc(zi^.ci.pos_in_buffered_data, copy_this);
  523. end;
  524. end;
  525. zipWriteInFileInZip := 0;
  526. end;
  527. function zipCloseFileInZip(afile: zipFile): longint; {ZEXPORT}
  528. var
  529. zi: zip_internal_ptr;
  530. err: longint;
  531. var
  532. uTotalOutBefore: longint;
  533. var
  534. cur_pos_inzip: longint;
  535. begin
  536. err := ZIP_OK;
  537. if (afile = nil) then
  538. begin
  539. zipCloseFileInZip := ZIP_PARAMERROR;
  540. exit;
  541. end;
  542. zi := zip_internal_ptr(afile);
  543. if (zi^.in_opened_file_inzip = False) then
  544. begin
  545. zipCloseFileInZip := ZIP_PARAMERROR;
  546. exit;
  547. end;
  548. zi^.ci.stream.avail_in := 0;
  549. if (zi^.ci.method = Z_DEFLATED) then
  550. while (err = ZIP_OK) do
  551. begin
  552. if (zi^.ci.stream.avail_out = 0) then
  553. begin
  554. if fwrite(@zi^.ci.buffered_data, integer(zi^.ci.pos_in_buffered_data), 1, zi^.filezip) <> 1 then
  555. err := ZIP_ERRNO;
  556. zi^.ci.pos_in_buffered_data := 0;
  557. zi^.ci.stream.avail_out := integer(Z_BUFSIZE);
  558. zi^.ci.stream.next_out := Pbyte(@zi^.ci.buffered_data);
  559. end;
  560. uTotalOutBefore := zi^.ci.stream.total_out;
  561. err := deflate(zi^.ci.stream, Z_FINISH);
  562. Inc(zi^.ci.pos_in_buffered_data, integer(zi^.ci.stream.total_out - uTotalOutBefore));
  563. end;
  564. if (err = Z_STREAM_END) then
  565. err := ZIP_OK; { this is normal }
  566. if (zi^.ci.pos_in_buffered_data > 0) and (err = ZIP_OK) then
  567. if fwrite(@zi^.ci.buffered_data, integer(zi^.ci.pos_in_buffered_data), 1, zi^.filezip) <> 1 then
  568. err := ZIP_ERRNO;
  569. if ((zi^.ci.method = Z_DEFLATED) and (err = ZIP_OK)) then
  570. begin
  571. err := deflateEnd(zi^.ci.stream);
  572. zi^.ci.stream_initialised := False;
  573. end;
  574. ziplocal_putValue_inmemory(zi^.ci.central_header + 16, longint(zi^.ci.crc32), 4); {crc}
  575. ziplocal_putValue_inmemory(zi^.ci.central_header + 20, longint(zi^.ci.stream.total_out), 4); {compr size}
  576. ziplocal_putValue_inmemory(zi^.ci.central_header + 24, longint(zi^.ci.stream.total_in), 4); {uncompr size}
  577. if (err = ZIP_OK) then
  578. err := add_data_in_datablock(@zi^.central_dir, zi^.ci.central_header, longint(zi^.ci.size_centralheader));
  579. FreeMem(zi^.ci.central_header);
  580. if (err = ZIP_OK) then
  581. begin
  582. cur_pos_inzip := ftell(zi^.filezip);
  583. if fseek(zi^.filezip, zi^.ci.pos_local_header + 14, SEEK_SET) <> 0 then
  584. err := ZIP_ERRNO;
  585. if (err = ZIP_OK) then
  586. err := ziplocal_putValue(zi^.filezip, longint(zi^.ci.crc32), 4); { crc 32, unknown }
  587. if (err = ZIP_OK) then { compressed size, unknown }
  588. err := ziplocal_putValue(zi^.filezip, longint(zi^.ci.stream.total_out), 4);
  589. if (err = ZIP_OK) then { uncompressed size, unknown }
  590. err := ziplocal_putValue(zi^.filezip, longint(zi^.ci.stream.total_in), 4);
  591. if fseek(zi^.filezip, cur_pos_inzip, SEEK_SET) <> 0 then
  592. err := ZIP_ERRNO;
  593. end;
  594. Inc(zi^.number_entry);
  595. zi^.in_opened_file_inzip := False;
  596. zipCloseFileInZip := err;
  597. end;
  598. function zipClose(afile: zipFile; const global_comment: PChar): longint; {ZEXPORT}
  599. var
  600. zi: zip_internal_ptr;
  601. err: longint;
  602. size_centraldir: longint;
  603. centraldir_pos_inzip: longint;
  604. size_global_comment: integer;
  605. var
  606. ldi: linkedlist_datablock_internal_ptr;
  607. begin
  608. err := 0;
  609. size_centraldir := 0;
  610. if (afile = nil) then
  611. begin
  612. zipClose := ZIP_PARAMERROR;
  613. exit;
  614. end;
  615. zi := zip_internal_ptr(afile);
  616. if (zi^.in_opened_file_inzip = True) then
  617. err := zipCloseFileInZip(afile);
  618. if (global_comment = nil) then
  619. size_global_comment := 0
  620. else
  621. size_global_comment := strlen(global_comment);
  622. centraldir_pos_inzip := ftell(zi^.filezip);
  623. if (err = ZIP_OK) then
  624. begin
  625. ldi := zi^.central_dir.first_block;
  626. while (ldi <> nil) do
  627. begin
  628. if ((err = ZIP_OK) and (ldi^.filled_in_this_block > 0)) then
  629. if fwrite(@ldi^.Data, integer(ldi^.filled_in_this_block), 1, zi^.filezip) <> 1 then
  630. err := ZIP_ERRNO;
  631. Inc(size_centraldir, ldi^.filled_in_this_block);
  632. ldi := ldi^.next_datablock;
  633. end;
  634. end;
  635. free_datablock(zi^.central_dir.first_block);
  636. if (err = ZIP_OK) then { Magic End }
  637. err := ziplocal_putValue(zi^.filezip, longint(ENDHEADERMAGIC), 4);
  638. if (err = ZIP_OK) then { number of this disk }
  639. err := ziplocal_putValue(zi^.filezip, longint(0), 2);
  640. if (err = ZIP_OK) then { number of the disk with the start of the central directory }
  641. err := ziplocal_putValue(zi^.filezip, longint(0), 2);
  642. if (err = ZIP_OK) then { total number of entries in the central dir on this disk }
  643. err := ziplocal_putValue(zi^.filezip, longint(zi^.number_entry), 2);
  644. if (err = ZIP_OK) then { total number of entries in the central dir }
  645. err := ziplocal_putValue(zi^.filezip, longint(zi^.number_entry), 2);
  646. if (err = ZIP_OK) then { size of the central directory }
  647. err := ziplocal_putValue(zi^.filezip, longint(size_centraldir), 4);
  648. if (err = ZIP_OK) then { offset of start of central directory with respect to the
  649. starting disk number }
  650. err := ziplocal_putValue(zi^.filezip, longint(centraldir_pos_inzip), 4);
  651. if (err = ZIP_OK) then { zipfile comment length }
  652. err := ziplocal_putValue(zi^.filezip, longint(size_global_comment), 2);
  653. if ((err = ZIP_OK) and (size_global_comment > 0)) then
  654. if fwrite(global_comment, integer(size_global_comment), 1, zi^.filezip) <> 1 then
  655. err := ZIP_ERRNO;
  656. fclose(zi^.filezip);
  657. FreeMem(zi);
  658. zipClose := err;
  659. end;
  660. end.