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