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