]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - contrib/pk3man/zlib/zip.c
* added pk3man and fixed it to compile for latest radiant
[xonotic/netradiant.git] / contrib / pk3man / zlib / zip.c
1 /* zip.c -- IO on .zip files using zlib 
2    Version 0.15 beta, Mar 19th, 1998,
3
4    Read zip.h for more info
5 */
6
7
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include "zlib.h"
12 #include "zip.h"
13
14 #  define DEF_MEM_LEVEL 8
15
16 #ifdef STDC
17 #  include <stddef.h>
18 #  include <string.h>
19 #  include <stdlib.h>
20 #endif
21 #ifdef NO_ERRNO_H
22     extern int errno;
23 #else
24 #   include <errno.h>
25 #endif
26
27
28 #ifndef local
29 #  define local static
30 #endif
31 /* compile with -Dlocal if your debugger can't find static symbols */
32
33 #ifndef VERSIONMADEBY
34 # define VERSIONMADEBY   (0x0) /* platform depedent */
35 #endif
36
37 #ifndef Z_BUFSIZE
38 #define Z_BUFSIZE (16384)
39 #endif
40
41 #ifndef Z_MAXFILENAMEINZIP
42 #define Z_MAXFILENAMEINZIP (256)
43 #endif
44
45 #ifndef ALLOC
46 # define ALLOC(size) (malloc(size))
47 #endif
48 #ifndef TRYFREE
49 # define TRYFREE(p) {if (p) free(p);}
50 #endif
51
52 /*
53 #define SIZECENTRALDIRITEM (0x2e)
54 #define SIZEZIPLOCALHEADER (0x1e)
55 */
56
57 /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
58
59 #ifndef SEEK_CUR
60 #define SEEK_CUR    1
61 #endif
62
63 #ifndef SEEK_END
64 #define SEEK_END    2
65 #endif
66
67 #ifndef SEEK_SET
68 #define SEEK_SET    0
69 #endif
70
71 const char zip_copyright[] =
72    " zip 0.15 Copyright 1998 Gilles Vollant ";
73
74
75 #define SIZEDATA_INDATABLOCK (4096-(4*4))
76
77 #define LOCALHEADERMAGIC    (0x04034b50)
78 #define CENTRALHEADERMAGIC  (0x02014b50)
79 #define ENDHEADERMAGIC      (0x06054b50)
80
81 #define FLAG_LOCALHEADER_OFFSET (0x06)
82 #define CRC_LOCALHEADER_OFFSET  (0x0e)
83
84 #define SIZECENTRALHEADER (0x2e) /* 46 */
85
86 typedef struct linkedlist_datablock_internal_s
87 {
88   struct linkedlist_datablock_internal_s* next_datablock;
89   uLong  avail_in_this_block;
90   uLong  filled_in_this_block;
91   uLong  unused; /* for future use and alignement */
92   unsigned char data[SIZEDATA_INDATABLOCK];
93 } linkedlist_datablock_internal;
94
95 typedef struct linkedlist_data_s
96 {
97     linkedlist_datablock_internal* first_block;
98     linkedlist_datablock_internal* last_block;
99 } linkedlist_data;
100
101
102 typedef struct
103 {
104         z_stream stream;            /* zLib stream structure for inflate */
105     int  stream_initialised;    /* 1 is stream is initialised */
106     uInt pos_in_buffered_data;  /* last written byte in buffered_data */
107
108     uLong pos_local_header;     /* offset of the local header of the file 
109                                      currenty writing */
110     char* central_header;       /* central header data for the current file */
111     uLong size_centralheader;   /* size of the central header for cur file */
112     uLong flag;                 /* flag of the file currently writing */
113
114     int  method;                /* compression method of file currenty wr.*/
115     Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/
116     uLong dosDate;
117     uLong crc32;
118 } curfile_info;
119
120 typedef struct
121 {
122     FILE * filezip;
123     linkedlist_data central_dir;/* datablock with central dir in construction*/
124     int  in_opened_file_inzip;  /* 1 if a file in the zip is currently writ.*/
125     curfile_info ci;            /* info on the file curretly writing */
126
127     uLong begin_pos;            /* position of the beginning of the zipfile */
128     uLong number_entry;
129 } zip_internal;
130
131 local linkedlist_datablock_internal* allocate_new_datablock()
132 {
133     linkedlist_datablock_internal* ldi;
134     ldi = (linkedlist_datablock_internal*)
135                  ALLOC(sizeof(linkedlist_datablock_internal));
136     if (ldi!=NULL)
137     {
138         ldi->next_datablock = NULL ;
139         ldi->filled_in_this_block = 0 ;
140         ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ;
141     }
142     return ldi;
143 }
144
145 local void free_datablock(ldi)
146     linkedlist_datablock_internal* ldi;
147 {
148     while (ldi!=NULL)
149     {
150         linkedlist_datablock_internal* ldinext = ldi->next_datablock;
151         TRYFREE(ldi);
152         ldi = ldinext;
153     }
154 }
155
156 local void init_linkedlist(ll)
157     linkedlist_data* ll;
158 {
159     ll->first_block = ll->last_block = NULL;
160 }
161
162 local void free_linkedlist(ll)
163     linkedlist_data* ll;
164 {
165     free_datablock(ll->first_block);
166     ll->first_block = ll->last_block = NULL;
167 }
168
169
170 local int add_data_in_datablock(ll,buf,len)
171     linkedlist_data* ll;    
172     const void* buf;
173     uLong len;
174 {
175     linkedlist_datablock_internal* ldi;
176     const unsigned char* from_copy;
177
178     if (ll==NULL)
179         return ZIP_INTERNALERROR;
180
181     if (ll->last_block == NULL)
182     {
183         ll->first_block = ll->last_block = allocate_new_datablock();
184         if (ll->first_block == NULL)
185             return ZIP_INTERNALERROR;
186     }
187
188     ldi = ll->last_block;
189     from_copy = (unsigned char*)buf;
190
191     while (len>0)
192     {
193         uInt copy_this;
194         uInt i;
195         unsigned char* to_copy;
196
197         if (ldi->avail_in_this_block==0)
198         {
199             ldi->next_datablock = allocate_new_datablock();
200             if (ldi->next_datablock == NULL)
201                 return ZIP_INTERNALERROR;
202             ldi = ldi->next_datablock ;
203             ll->last_block = ldi;
204         }
205
206         if (ldi->avail_in_this_block < len)
207             copy_this = (uInt)ldi->avail_in_this_block;
208         else
209             copy_this = (uInt)len;
210
211         to_copy = &(ldi->data[ldi->filled_in_this_block]);
212
213         for (i=0;i<copy_this;i++)
214             *(to_copy+i)=*(from_copy+i);
215
216         ldi->filled_in_this_block += copy_this;
217         ldi->avail_in_this_block -= copy_this;
218         from_copy += copy_this ;
219         len -= copy_this;
220     }
221     return ZIP_OK;
222 }
223
224
225 local int write_datablock(fout,ll)
226     FILE * fout;
227     linkedlist_data* ll;    
228 {
229     linkedlist_datablock_internal* ldi;
230     ldi = ll->first_block;
231     while (ldi!=NULL)
232     {
233         if (ldi->filled_in_this_block > 0)
234             if (fwrite(ldi->data,(uInt)ldi->filled_in_this_block,1,fout)!=1)
235                 return ZIP_ERRNO;
236         ldi = ldi->next_datablock;
237     }
238     return ZIP_OK;
239 }
240
241 /****************************************************************************/
242
243 /* ===========================================================================
244    Outputs a long in LSB order to the given file
245    nbByte == 1, 2 or 4 (byte, short or long)
246 */
247
248 local int ziplocal_putValue OF((FILE *file, uLong x, int nbByte));
249 local int ziplocal_putValue (file, x, nbByte)
250     FILE *file;
251     uLong x;
252     int nbByte;
253 {
254     unsigned char buf[4];
255     int n;
256     for (n = 0; n < nbByte; n++) {
257         buf[n] = (unsigned char)(x & 0xff);
258         x >>= 8;
259     }
260     if (fwrite(buf,nbByte,1,file)!=1)
261         return ZIP_ERRNO;
262     else
263         return ZIP_OK;
264 }
265
266 local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte));
267 local void ziplocal_putValue_inmemory (dest, x, nbByte)
268     void* dest;
269     uLong x;
270     int nbByte;
271 {
272     unsigned char* buf=(unsigned char*)dest;
273     int n;
274     for (n = 0; n < nbByte; n++) {
275         buf[n] = (unsigned char)(x & 0xff);
276         x >>= 8;
277     }
278 }
279 /****************************************************************************/
280
281
282 local uLong ziplocal_TmzDateToDosDate(ptm,dosDate)
283     tm_zip* ptm;
284     uLong dosDate;
285 {
286     uLong year = (uLong)ptm->tm_year;
287     if (year>1980)
288         year-=1980;
289     else if (year>80)
290         year-=80;
291     return
292       (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) |
293         ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour));
294 }
295
296
297 /****************************************************************************/
298
299 extern zipFile ZEXPORT zipOpen (pathname, append)
300     const char *pathname;
301     int append;
302 {
303     zip_internal ziinit;
304     zip_internal* zi;
305
306     ziinit.filezip = fopen(pathname,(append == 0) ? "wb" : "ab");
307     if (ziinit.filezip == NULL)
308         return NULL;
309     ziinit.begin_pos = ftell(ziinit.filezip);
310     ziinit.in_opened_file_inzip = 0;
311     ziinit.ci.stream_initialised = 0;
312     ziinit.number_entry = 0;
313     init_linkedlist(&(ziinit.central_dir));
314
315
316     zi = (zip_internal*)ALLOC(sizeof(zip_internal));
317     if (zi==NULL)
318     {
319         fclose(ziinit.filezip);
320         return NULL;
321     }
322
323     *zi = ziinit;
324     return (zipFile)zi;
325 }
326
327 extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi, 
328                                         extrafield_local, size_extrafield_local,
329                                         extrafield_global, size_extrafield_global,
330                                         comment, method, level)
331     zipFile file;
332     const char* filename;
333     const zip_fileinfo* zipfi;
334     const void* extrafield_local;
335     uInt size_extrafield_local;
336     const void* extrafield_global;
337     uInt size_extrafield_global;
338     const char* comment;
339     int method;
340     int level;
341 {
342     zip_internal* zi;
343     uInt size_filename;
344     uInt size_comment;
345     uInt i;
346     int err = ZIP_OK;
347
348     if (file == NULL)
349         return ZIP_PARAMERROR;
350     if ((method!=0) && (method!=Z_DEFLATED))
351         return ZIP_PARAMERROR;
352
353     zi = (zip_internal*)file;
354
355     if (zi->in_opened_file_inzip == 1)
356     {
357         err = zipCloseFileInZip (file);
358         if (err != ZIP_OK)
359             return err;
360     }
361
362
363     if (filename==NULL)
364         filename="-";
365
366     if (comment==NULL)
367         size_comment = 0;
368     else
369         size_comment = strlen(comment);
370
371     size_filename = strlen(filename);
372
373     if (zipfi == NULL)
374         zi->ci.dosDate = 0;
375     else
376     {
377         if (zipfi->dosDate != 0)
378             zi->ci.dosDate = zipfi->dosDate;
379         else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate);
380     }
381
382     zi->ci.flag = 0;
383     if ((level==8) || (level==9))
384       zi->ci.flag |= 2;
385     if ((level==2))
386       zi->ci.flag |= 4;
387     if ((level==1))
388       zi->ci.flag |= 6;
389
390     zi->ci.crc32 = 0;
391     zi->ci.method = method;
392     zi->ci.stream_initialised = 0;
393     zi->ci.pos_in_buffered_data = 0;
394     zi->ci.pos_local_header = ftell(zi->filezip);
395     zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + 
396                                       size_extrafield_global + size_comment;
397     zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader);
398
399     ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4);
400     /* version info */
401     ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2);
402     ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2);
403     ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2);
404     ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2);
405     ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4);
406     ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/
407     ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/
408     ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/
409     ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2);
410     ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2);
411     ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2);
412     ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/
413
414     if (zipfi==NULL)
415         ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); 
416     else
417         ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); 
418
419     if (zipfi==NULL)
420         ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); 
421     else
422         ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4);
423
424     ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header,4);
425
426     for (i=0;i<size_filename;i++)
427         *(zi->ci.central_header+SIZECENTRALHEADER+i) = *(filename+i);
428
429     for (i=0;i<size_extrafield_global;i++)
430         *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+i) =
431               *(((const char*)extrafield_global)+i);
432
433     for (i=0;i<size_comment;i++)
434         *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+
435               size_extrafield_global+i) = *(filename+i);
436     if (zi->ci.central_header == NULL)
437         return ZIP_INTERNALERROR;
438
439     /* write the local header */
440     err = ziplocal_putValue(zi->filezip,(uLong)LOCALHEADERMAGIC,4);
441
442     if (err==ZIP_OK)
443         err = ziplocal_putValue(zi->filezip,(uLong)20,2);/* version needed to extract */
444     if (err==ZIP_OK)
445         err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.flag,2);
446
447     if (err==ZIP_OK)
448         err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.method,2);
449
450     if (err==ZIP_OK)
451         err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.dosDate,4);
452
453     if (err==ZIP_OK)
454         err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* crc 32, unknown */
455     if (err==ZIP_OK)
456         err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* compressed size, unknown */
457     if (err==ZIP_OK)
458         err = ziplocal_putValue(zi->filezip,(uLong)0,4); /* uncompressed size, unknown */
459
460     if (err==ZIP_OK)
461         err = ziplocal_putValue(zi->filezip,(uLong)size_filename,2);
462
463     if (err==ZIP_OK)
464         err = ziplocal_putValue(zi->filezip,(uLong)size_extrafield_local,2);
465
466     if ((err==ZIP_OK) && (size_filename>0))
467         if (fwrite(filename,(uInt)size_filename,1,zi->filezip)!=1)
468                 err = ZIP_ERRNO;
469
470     if ((err==ZIP_OK) && (size_extrafield_local>0))
471         if (fwrite(extrafield_local,(uInt)size_extrafield_local,1,zi->filezip)
472                                                                            !=1)
473                 err = ZIP_ERRNO;
474
475     zi->ci.stream.avail_in = (uInt)0;
476     zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
477     zi->ci.stream.next_out = zi->ci.buffered_data;
478     zi->ci.stream.total_in = 0;
479     zi->ci.stream.total_out = 0;
480
481     if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED))
482     {
483         zi->ci.stream.zalloc = (alloc_func)0;
484         zi->ci.stream.zfree = (free_func)0;
485         zi->ci.stream.opaque = (voidpf)0;
486
487         err = deflateInit2(&zi->ci.stream, level,
488                Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0);
489
490         if (err==Z_OK)
491             zi->ci.stream_initialised = 1;
492     }
493
494
495     if (err==Z_OK)
496         zi->in_opened_file_inzip = 1;
497     return err;
498 }
499
500 extern int ZEXPORT zipWriteInFileInZip (file, buf, len)
501     zipFile file;
502     const voidp buf;
503     unsigned len;
504 {
505     zip_internal* zi;
506     int err=ZIP_OK;
507
508     if (file == NULL)
509         return ZIP_PARAMERROR;
510     zi = (zip_internal*)file;
511
512     if (zi->in_opened_file_inzip == 0)
513         return ZIP_PARAMERROR;
514
515     zi->ci.stream.next_in = buf;
516     zi->ci.stream.avail_in = len;
517     zi->ci.crc32 = crc32(zi->ci.crc32,buf,len);
518
519     while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
520     {
521         if (zi->ci.stream.avail_out == 0)
522         {
523             if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip)
524                                                                            !=1)
525                 err = ZIP_ERRNO;
526             zi->ci.pos_in_buffered_data = 0;
527             zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
528             zi->ci.stream.next_out = zi->ci.buffered_data;
529         }
530
531         if (zi->ci.method == Z_DEFLATED)
532         {
533             uLong uTotalOutBefore = zi->ci.stream.total_out;
534             err=deflate(&zi->ci.stream,  Z_NO_FLUSH);
535             zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
536
537         }
538         else
539         {
540             uInt copy_this,i;
541             if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
542                 copy_this = zi->ci.stream.avail_in;
543             else
544                 copy_this = zi->ci.stream.avail_out;
545             for (i=0;i<copy_this;i++)
546                 *(((char*)zi->ci.stream.next_out)+i) =
547                     *(((const char*)zi->ci.stream.next_in)+i);
548             {
549                 zi->ci.stream.avail_in -= copy_this;
550                 zi->ci.stream.avail_out-= copy_this;
551                 zi->ci.stream.next_in+= copy_this;
552                 zi->ci.stream.next_out+= copy_this;
553                 zi->ci.stream.total_in+= copy_this;
554                 zi->ci.stream.total_out+= copy_this;
555                 zi->ci.pos_in_buffered_data += copy_this;
556             }
557         }
558     }
559
560     return 0;
561 }
562
563 extern int ZEXPORT zipCloseFileInZip (file)
564     zipFile file;
565 {
566     zip_internal* zi;
567     int err=ZIP_OK;
568
569     if (file == NULL)
570         return ZIP_PARAMERROR;
571     zi = (zip_internal*)file;
572
573     if (zi->in_opened_file_inzip == 0)    
574         return ZIP_PARAMERROR;
575     zi->ci.stream.avail_in = 0;
576     
577     if (zi->ci.method == Z_DEFLATED)
578         while (err==ZIP_OK)
579     {
580         uLong uTotalOutBefore;
581         if (zi->ci.stream.avail_out == 0)
582         {
583             if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip)
584                                                                            !=1)
585                 err = ZIP_ERRNO;
586             zi->ci.pos_in_buffered_data = 0;
587             zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
588             zi->ci.stream.next_out = zi->ci.buffered_data;
589         }
590         uTotalOutBefore = zi->ci.stream.total_out;
591         err=deflate(&zi->ci.stream,  Z_FINISH);
592         zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
593     }
594
595     if (err==Z_STREAM_END)
596         err=ZIP_OK; /* this is normal */
597
598     if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK))
599         if (fwrite(zi->ci.buffered_data,(uInt)zi->ci.pos_in_buffered_data,1,zi->filezip)
600                                                                        !=1)
601             err = ZIP_ERRNO;
602
603     if ((zi->ci.method == Z_DEFLATED) && (err==ZIP_OK))
604     {
605         err=deflateEnd(&zi->ci.stream);
606         zi->ci.stream_initialised = 0;
607     }
608
609     ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)zi->ci.crc32,4); /*crc*/
610     ziplocal_putValue_inmemory(zi->ci.central_header+20,
611                                 (uLong)zi->ci.stream.total_out,4); /*compr size*/
612     ziplocal_putValue_inmemory(zi->ci.central_header+24,
613                                 (uLong)zi->ci.stream.total_in,4); /*uncompr size*/
614
615     if (err==ZIP_OK)
616         err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header,
617                                        (uLong)zi->ci.size_centralheader);
618     free(zi->ci.central_header);
619
620     if (err==ZIP_OK)
621     {
622         long cur_pos_inzip = ftell(zi->filezip);
623             if (fseek(zi->filezip,
624                   zi->ci.pos_local_header + 14,SEEK_SET)!=0)
625                     err = ZIP_ERRNO;
626
627         if (err==ZIP_OK)
628             err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.crc32,4); /* crc 32, unknown */
629
630         if (err==ZIP_OK) /* compressed size, unknown */
631             err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.stream.total_out,4); 
632
633         if (err==ZIP_OK) /* uncompressed size, unknown */
634             err = ziplocal_putValue(zi->filezip,(uLong)zi->ci.stream.total_in,4);
635
636             if (fseek(zi->filezip,
637                   cur_pos_inzip,SEEK_SET)!=0)
638                     err = ZIP_ERRNO;
639     }
640
641     zi->number_entry ++;
642     zi->in_opened_file_inzip = 0;
643
644     return err;
645 }
646
647 extern int ZEXPORT zipClose (file, global_comment)
648     zipFile file;
649     const char* global_comment;
650 {
651     zip_internal* zi;
652     int err = 0;
653     uLong size_centraldir = 0;
654     uLong centraldir_pos_inzip ;
655     uInt size_global_comment;
656     if (file == NULL)
657         return ZIP_PARAMERROR;
658     zi = (zip_internal*)file;
659
660     if (zi->in_opened_file_inzip == 1)
661     {
662         err = zipCloseFileInZip (file);
663     }
664
665     if (global_comment==NULL)
666         size_global_comment = 0;
667     else
668         size_global_comment = strlen(global_comment);
669
670
671     centraldir_pos_inzip = ftell(zi->filezip);
672     if (err==ZIP_OK)
673     {
674         linkedlist_datablock_internal* ldi = zi->central_dir.first_block ;
675         while (ldi!=NULL)
676         {
677             if ((err==ZIP_OK) && (ldi->filled_in_this_block>0))
678                 if (fwrite(ldi->data,(uInt)ldi->filled_in_this_block,
679                                         1,zi->filezip) !=1 )
680                     err = ZIP_ERRNO;
681
682             size_centraldir += ldi->filled_in_this_block;
683             ldi = ldi->next_datablock;
684         }
685     }
686     free_datablock(zi->central_dir.first_block);
687
688     if (err==ZIP_OK) /* Magic End */
689         err = ziplocal_putValue(zi->filezip,(uLong)ENDHEADERMAGIC,4);
690
691     if (err==ZIP_OK) /* number of this disk */
692         err = ziplocal_putValue(zi->filezip,(uLong)0,2);
693
694     if (err==ZIP_OK) /* number of the disk with the start of the central directory */
695         err = ziplocal_putValue(zi->filezip,(uLong)0,2);
696
697     if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
698         err = ziplocal_putValue(zi->filezip,(uLong)zi->number_entry,2);
699
700     if (err==ZIP_OK) /* total number of entries in the central dir */
701         err = ziplocal_putValue(zi->filezip,(uLong)zi->number_entry,2);
702
703     if (err==ZIP_OK) /* size of the central directory */
704         err = ziplocal_putValue(zi->filezip,(uLong)size_centraldir,4);
705
706     if (err==ZIP_OK) /* offset of start of central directory with respect to the 
707                                 starting disk number */
708         err = ziplocal_putValue(zi->filezip,(uLong)centraldir_pos_inzip ,4);
709
710     if (err==ZIP_OK) /* zipfile comment length */
711         err = ziplocal_putValue(zi->filezip,(uLong)size_global_comment,2);
712
713     if ((err==ZIP_OK) && (size_global_comment>0))
714         if (fwrite(global_comment,(uInt)size_global_comment,1,zi->filezip) !=1 )
715                 err = ZIP_ERRNO;
716     fclose(zi->filezip);
717     TRYFREE(zi);
718
719     return err;
720 }