Changed TryPeek to handle race condition with Dequeue.
[mono.git] / support / minizip / zip.c
1 /* zip.c -- IO on .zip files using zlib
2    Version 1.01e, February 12th, 2005
3
4    27 Dec 2004 Rolf Kalbermatter
5    Modification to zipOpen2 to support globalComment retrieval.
6
7    Copyright (C) 1998-2005 Gilles Vollant
8
9    Read zip.h for more info
10 */
11
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <string.h>
16 #include <time.h>
17 #include "zlib.h"
18 #include "zip.h"
19
20 #ifdef STDC
21 #  include <stddef.h>
22 #  include <string.h>
23 #  include <stdlib.h>
24 #endif
25 #ifdef NO_ERRNO_H
26     extern int errno;
27 #else
28 #   include <errno.h>
29 #endif
30
31
32 #ifndef local
33 #  define local static
34 #endif
35 /* compile with -Dlocal if your debugger can't find static symbols */
36
37 #ifndef VERSIONMADEBY
38 # define VERSIONMADEBY   (0x0) /* platform depedent */
39 #endif
40
41 #ifndef Z_BUFSIZE
42 #define Z_BUFSIZE (16384)
43 #endif
44
45 #ifndef Z_MAXFILENAMEINZIP
46 #define Z_MAXFILENAMEINZIP (256)
47 #endif
48
49 #ifndef ALLOC
50 # define ALLOC(size) (malloc(size))
51 #endif
52 #ifndef TRYFREE
53 # define TRYFREE(p) {if (p) free(p);}
54 #endif
55
56 /*
57 #define SIZECENTRALDIRITEM (0x2e)
58 #define SIZEZIPLOCALHEADER (0x1e)
59 */
60
61 /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
62
63 #ifndef SEEK_CUR
64 #define SEEK_CUR    1
65 #endif
66
67 #ifndef SEEK_END
68 #define SEEK_END    2
69 #endif
70
71 #ifndef SEEK_SET
72 #define SEEK_SET    0
73 #endif
74
75 #ifndef DEF_MEM_LEVEL
76 #if MAX_MEM_LEVEL >= 8
77 #  define DEF_MEM_LEVEL 8
78 #else
79 #  define DEF_MEM_LEVEL  MAX_MEM_LEVEL
80 #endif
81 #endif
82 const char zip_copyright[] =
83    " zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
84
85
86 #define SIZEDATA_INDATABLOCK (4096-(4*4))
87
88 #define LOCALHEADERMAGIC    (0x04034b50)
89 #define CENTRALHEADERMAGIC  (0x02014b50)
90 #define ENDHEADERMAGIC      (0x06054b50)
91
92 #define FLAG_LOCALHEADER_OFFSET (0x06)
93 #define CRC_LOCALHEADER_OFFSET  (0x0e)
94
95 #define SIZECENTRALHEADER (0x2e) /* 46 */
96
97 typedef struct linkedlist_datablock_internal_s
98 {
99   struct linkedlist_datablock_internal_s* next_datablock;
100   uLong  avail_in_this_block;
101   uLong  filled_in_this_block;
102   uLong  unused; /* for future use and alignement */
103   unsigned char data[SIZEDATA_INDATABLOCK];
104 } linkedlist_datablock_internal;
105
106 typedef struct linkedlist_data_s
107 {
108     linkedlist_datablock_internal* first_block;
109     linkedlist_datablock_internal* last_block;
110 } linkedlist_data;
111
112
113 typedef struct
114 {
115     z_stream stream;            /* zLib stream structure for inflate */
116     int  stream_initialised;    /* 1 is stream is initialised */
117     uInt pos_in_buffered_data;  /* last written byte in buffered_data */
118
119     uLong pos_local_header;     /* offset of the local header of the file
120                                      currenty writing */
121     char* central_header;       /* central header data for the current file */
122     uLong size_centralheader;   /* size of the central header for cur file */
123     uLong flag;                 /* flag of the file currently writing */
124
125     int  method;                /* compression method of file currenty wr.*/
126     int  raw;                   /* 1 for directly writing raw data */
127     Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/
128     uLong dosDate;
129     uLong crc32;
130     int  encrypt;
131 #ifndef NOCRYPT
132     unsigned long keys[3];     /* keys defining the pseudo-random sequence */
133     const unsigned long* pcrc_32_tab;
134     int crypt_header_size;
135 #endif
136 } curfile_info;
137
138 typedef struct
139 {
140     zlib_filefunc_def z_filefunc;
141     voidpf filestream;        /* io structore of the zipfile */
142     linkedlist_data central_dir;/* datablock with central dir in construction*/
143     int  in_opened_file_inzip;  /* 1 if a file in the zip is currently writ.*/
144     curfile_info ci;            /* info on the file curretly writing */
145
146     uLong begin_pos;            /* position of the beginning of the zipfile */
147     uLong add_position_when_writting_offset;
148     uLong number_entry;
149 #ifndef NO_ADDFILEINEXISTINGZIP
150     char *globalcomment;
151 #endif
152 } zip_internal;
153
154
155
156 #ifndef NOCRYPT
157 #define INCLUDECRYPTINGCODE_IFCRYPTALLOWED
158 #include "crypt.h"
159 #endif
160
161 local linkedlist_datablock_internal* allocate_new_datablock(void)
162 {
163     linkedlist_datablock_internal* ldi;
164     ldi = (linkedlist_datablock_internal*)
165                  ALLOC(sizeof(linkedlist_datablock_internal));
166     if (ldi!=NULL)
167     {
168         ldi->next_datablock = NULL ;
169         ldi->filled_in_this_block = 0 ;
170         ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ;
171     }
172     return ldi;
173 }
174
175 local void free_datablock(linkedlist_datablock_internal *ldi)
176 {
177     while (ldi!=NULL)
178     {
179         linkedlist_datablock_internal* ldinext = ldi->next_datablock;
180         TRYFREE(ldi);
181         ldi = ldinext;
182     }
183 }
184
185 local void init_linkedlist(linkedlist_data *ll)
186 {
187     ll->first_block = ll->last_block = NULL;
188 }
189
190 local void free_linkedlist(linkedlist_data *ll)
191 {
192     free_datablock(ll->first_block);
193     ll->first_block = ll->last_block = NULL;
194 }
195
196
197 local int add_data_in_datablock(linkedlist_data *ll, const void *buf, uLong len)
198 {
199     linkedlist_datablock_internal* ldi;
200     const unsigned char* from_copy;
201
202     if (ll==NULL)
203         return ZIP_INTERNALERROR;
204
205     if (ll->last_block == NULL)
206     {
207         ll->first_block = ll->last_block = allocate_new_datablock();
208         if (ll->first_block == NULL)
209             return ZIP_INTERNALERROR;
210     }
211
212     ldi = ll->last_block;
213     from_copy = (unsigned char*)buf;
214
215     while (len>0)
216     {
217         uInt copy_this;
218         uInt i;
219         unsigned char* to_copy;
220
221         if (ldi->avail_in_this_block==0)
222         {
223             ldi->next_datablock = allocate_new_datablock();
224             if (ldi->next_datablock == NULL)
225                 return ZIP_INTERNALERROR;
226             ldi = ldi->next_datablock ;
227             ll->last_block = ldi;
228         }
229
230         if (ldi->avail_in_this_block < len)
231             copy_this = (uInt)ldi->avail_in_this_block;
232         else
233             copy_this = (uInt)len;
234
235         to_copy = &(ldi->data[ldi->filled_in_this_block]);
236
237         for (i=0;i<copy_this;i++)
238             *(to_copy+i)=*(from_copy+i);
239
240         ldi->filled_in_this_block += copy_this;
241         ldi->avail_in_this_block -= copy_this;
242         from_copy += copy_this ;
243         len -= copy_this;
244     }
245     return ZIP_OK;
246 }
247
248
249
250 /****************************************************************************/
251
252 #ifndef NO_ADDFILEINEXISTINGZIP
253 /* ===========================================================================
254    Inputs a long in LSB order to the given file
255    nbByte == 1, 2 or 4 (byte, short or long)
256 */
257
258 local int ziplocal_putValue OF((const zlib_filefunc_def* pzlib_filefunc_def,
259                                 voidpf filestream, uLong x, int nbByte));
260 local int ziplocal_putValue (pzlib_filefunc_def, filestream, x, nbByte)
261     const zlib_filefunc_def* pzlib_filefunc_def;
262     voidpf filestream;
263     uLong x;
264     int nbByte;
265 {
266     unsigned char buf[4];
267     int n;
268     for (n = 0; n < nbByte; n++)
269     {
270         buf[n] = (unsigned char)(x & 0xff);
271         x >>= 8;
272     }
273     if (x != 0)
274       {     /* data overflow - hack for ZIP64 (X Roche) */
275       for (n = 0; n < nbByte; n++)
276         {
277           buf[n] = 0xff;
278         }
279       }
280
281     if (ZWRITE(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte)
282         return ZIP_ERRNO;
283     else
284         return ZIP_OK;
285 }
286
287 local void ziplocal_putValue_inmemory OF((void* dest, uLong x, int nbByte));
288 local void ziplocal_putValue_inmemory (dest, x, nbByte)
289     void* dest;
290     uLong x;
291     int nbByte;
292 {
293     unsigned char* buf=(unsigned char*)dest;
294     int n;
295     for (n = 0; n < nbByte; n++) {
296         buf[n] = (unsigned char)(x & 0xff);
297         x >>= 8;
298     }
299
300     if (x != 0)
301     {     /* data overflow - hack for ZIP64 */
302        for (n = 0; n < nbByte; n++)
303        {
304           buf[n] = 0xff;
305        }
306     }
307 }
308
309 /****************************************************************************/
310
311
312 local uLong ziplocal_TmzDateToDosDate(const tm_zip *ptm, uLong dosDate)
313 {
314     uLong year = (uLong)ptm->tm_year;
315     if (year>1980)
316         year-=1980;
317     else if (year>80)
318         year-=80;
319     return
320       (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) |
321         ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour));
322 }
323
324
325 /****************************************************************************/
326
327 local int ziplocal_getByte OF((
328     const zlib_filefunc_def* pzlib_filefunc_def,
329     voidpf filestream,
330     int *pi));
331
332 local int ziplocal_getByte(pzlib_filefunc_def,filestream,pi)
333     const zlib_filefunc_def* pzlib_filefunc_def;
334     voidpf filestream;
335     int *pi;
336 {
337     unsigned char c;
338     int err = (int)ZREAD(*pzlib_filefunc_def,filestream,&c,1);
339     if (err==1)
340     {
341         *pi = (int)c;
342         return ZIP_OK;
343     }
344     else
345     {
346         if (ZERROR(*pzlib_filefunc_def,filestream))
347             return ZIP_ERRNO;
348         else
349             return ZIP_EOF;
350     }
351 }
352
353
354 /* ===========================================================================
355    Reads a long in LSB order from the given gz_stream. Sets
356 */
357 local int ziplocal_getShort OF((
358     const zlib_filefunc_def* pzlib_filefunc_def,
359     voidpf filestream,
360     uLong *pX));
361
362 local int ziplocal_getShort (pzlib_filefunc_def,filestream,pX)
363     const zlib_filefunc_def* pzlib_filefunc_def;
364     voidpf filestream;
365     uLong *pX;
366 {
367     uLong x ;
368     int i;
369     int err;
370
371     err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
372     x = (uLong)i;
373
374     if (err==ZIP_OK)
375         err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
376     x += ((uLong)i)<<8;
377
378     if (err==ZIP_OK)
379         *pX = x;
380     else
381         *pX = 0;
382     return err;
383 }
384
385 local int ziplocal_getLong OF((
386     const zlib_filefunc_def* pzlib_filefunc_def,
387     voidpf filestream,
388     uLong *pX));
389
390 local int ziplocal_getLong (pzlib_filefunc_def,filestream,pX)
391     const zlib_filefunc_def* pzlib_filefunc_def;
392     voidpf filestream;
393     uLong *pX;
394 {
395     uLong x ;
396     int i;
397     int err;
398
399     err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
400     x = (uLong)i;
401
402     if (err==ZIP_OK)
403         err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
404     x += ((uLong)i)<<8;
405
406     if (err==ZIP_OK)
407         err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
408     x += ((uLong)i)<<16;
409
410     if (err==ZIP_OK)
411         err = ziplocal_getByte(pzlib_filefunc_def,filestream,&i);
412     x += ((uLong)i)<<24;
413
414     if (err==ZIP_OK)
415         *pX = x;
416     else
417         *pX = 0;
418     return err;
419 }
420
421 #ifndef BUFREADCOMMENT
422 #define BUFREADCOMMENT (0x400)
423 #endif
424 /*
425   Locate the Central directory of a zipfile (at the end, just before
426     the global comment)
427 */
428 local uLong ziplocal_SearchCentralDir OF((
429     const zlib_filefunc_def* pzlib_filefunc_def,
430     voidpf filestream));
431
432 local uLong ziplocal_SearchCentralDir(pzlib_filefunc_def,filestream)
433     const zlib_filefunc_def* pzlib_filefunc_def;
434     voidpf filestream;
435 {
436     unsigned char* buf;
437     uLong uSizeFile;
438     uLong uBackRead;
439     uLong uMaxBack=0xffff; /* maximum size of global comment */
440     uLong uPosFound=0;
441
442     if (ZSEEK(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
443         return 0;
444
445
446     uSizeFile = ZTELL(*pzlib_filefunc_def,filestream);
447
448     if (uMaxBack>uSizeFile)
449         uMaxBack = uSizeFile;
450
451     buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
452     if (buf==NULL)
453         return 0;
454
455     uBackRead = 4;
456     while (uBackRead<uMaxBack)
457     {
458         uLong uReadSize,uReadPos ;
459         int i;
460         if (uBackRead+BUFREADCOMMENT>uMaxBack)
461             uBackRead = uMaxBack;
462         else
463             uBackRead+=BUFREADCOMMENT;
464         uReadPos = uSizeFile-uBackRead ;
465
466         uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
467                      (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
468         if (ZSEEK(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
469             break;
470
471         if (ZREAD(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
472             break;
473
474         for (i=(int)uReadSize-3; (i--)>0;)
475             if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
476                 ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
477             {
478                 uPosFound = uReadPos+i;
479                 break;
480             }
481
482         if (uPosFound!=0)
483             break;
484     }
485     TRYFREE(buf);
486     return uPosFound;
487 }
488 #endif /* !NO_ADDFILEINEXISTINGZIP*/
489
490 /************************************************************/
491 extern zipFile ZEXPORT zipOpen2 (pathname, append, globalcomment, pzlib_filefunc_def)
492     const char *pathname;
493     int append;
494     zipcharpc* globalcomment;
495     zlib_filefunc_def* pzlib_filefunc_def;
496 {
497     zip_internal ziinit;
498     zip_internal* zi;
499     int err=ZIP_OK;
500
501
502     if (pzlib_filefunc_def==NULL)
503         fill_fopen_filefunc(&ziinit.z_filefunc);
504     else
505         ziinit.z_filefunc = *pzlib_filefunc_def;
506
507     ziinit.filestream = (*(ziinit.z_filefunc.zopen_file))
508                  (ziinit.z_filefunc.opaque,
509                   pathname,
510                   (append == APPEND_STATUS_CREATE) ?
511                   (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) :
512                     (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING));
513
514     if (ziinit.filestream == NULL)
515         return NULL;
516     ziinit.begin_pos = ZTELL(ziinit.z_filefunc,ziinit.filestream);
517     ziinit.in_opened_file_inzip = 0;
518     ziinit.ci.stream_initialised = 0;
519     ziinit.number_entry = 0;
520     ziinit.add_position_when_writting_offset = 0;
521     init_linkedlist(&(ziinit.central_dir));
522
523
524     zi = (zip_internal*)ALLOC(sizeof(zip_internal));
525     if (zi==NULL)
526     {
527         ZCLOSE(ziinit.z_filefunc,ziinit.filestream);
528         return NULL;
529     }
530
531     /* now we add file in a zipfile */
532 #    ifndef NO_ADDFILEINEXISTINGZIP
533     ziinit.globalcomment = NULL;
534     if (append == APPEND_STATUS_ADDINZIP)
535     {
536         uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
537
538         uLong size_central_dir;     /* size of the central directory  */
539         uLong offset_central_dir;   /* offset of start of central directory */
540         uLong central_pos,uL;
541
542         uLong number_disk;          /* number of the current dist, used for
543                                     spaning ZIP, unsupported, always 0*/
544         uLong number_disk_with_CD;  /* number the the disk with central dir, used
545                                     for spaning ZIP, unsupported, always 0*/
546         uLong number_entry;
547         uLong number_entry_CD;      /* total number of entries in
548                                     the central dir
549                                     (same than number_entry on nospan) */
550         uLong size_comment;
551
552         central_pos = ziplocal_SearchCentralDir(&ziinit.z_filefunc,ziinit.filestream);
553         if (central_pos==0)
554             err=ZIP_ERRNO;
555
556         if (ZSEEK(ziinit.z_filefunc, ziinit.filestream,
557                                         central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
558             err=ZIP_ERRNO;
559
560         /* the signature, already checked */
561         if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&uL)!=ZIP_OK)
562             err=ZIP_ERRNO;
563
564         /* number of this disk */
565         if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk)!=ZIP_OK)
566             err=ZIP_ERRNO;
567
568         /* number of the disk with the start of the central directory */
569         if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_disk_with_CD)!=ZIP_OK)
570             err=ZIP_ERRNO;
571
572         /* total number of entries in the central dir on this disk */
573         if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry)!=ZIP_OK)
574             err=ZIP_ERRNO;
575
576         /* total number of entries in the central dir */
577         if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&number_entry_CD)!=ZIP_OK)
578             err=ZIP_ERRNO;
579
580         if ((number_entry_CD!=number_entry) ||
581             (number_disk_with_CD!=0) ||
582             (number_disk!=0))
583             err=ZIP_BADZIPFILE;
584
585         /* size of the central directory */
586         if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&size_central_dir)!=ZIP_OK)
587             err=ZIP_ERRNO;
588
589         /* offset of start of central directory with respect to the
590             starting disk number */
591         if (ziplocal_getLong(&ziinit.z_filefunc, ziinit.filestream,&offset_central_dir)!=ZIP_OK)
592             err=ZIP_ERRNO;
593
594         /* zipfile global comment length */
595         if (ziplocal_getShort(&ziinit.z_filefunc, ziinit.filestream,&size_comment)!=ZIP_OK)
596             err=ZIP_ERRNO;
597
598         if ((central_pos<offset_central_dir+size_central_dir) &&
599             (err==ZIP_OK))
600             err=ZIP_BADZIPFILE;
601
602         if (err!=ZIP_OK)
603         {
604             ZCLOSE(ziinit.z_filefunc, ziinit.filestream);
605             return NULL;
606         }
607
608         if (size_comment>0)
609         {
610             ziinit.globalcomment = ALLOC(size_comment+1);
611             if (ziinit.globalcomment)
612             {
613                size_comment = ZREAD(ziinit.z_filefunc, ziinit.filestream,ziinit.globalcomment,size_comment);
614                ziinit.globalcomment[size_comment]=0;
615             }
616         }
617
618         byte_before_the_zipfile = central_pos -
619                                 (offset_central_dir+size_central_dir);
620         ziinit.add_position_when_writting_offset = byte_before_the_zipfile;
621
622         {
623             uLong size_central_dir_to_read = size_central_dir;
624             size_t buf_size = SIZEDATA_INDATABLOCK;
625             void* buf_read = (void*)ALLOC(buf_size);
626             if (ZSEEK(ziinit.z_filefunc, ziinit.filestream,
627                   offset_central_dir + byte_before_the_zipfile,
628                   ZLIB_FILEFUNC_SEEK_SET) != 0)
629                   err=ZIP_ERRNO;
630
631             while ((size_central_dir_to_read>0) && (err==ZIP_OK))
632             {
633                 uLong read_this = SIZEDATA_INDATABLOCK;
634                 if (read_this > size_central_dir_to_read)
635                     read_this = size_central_dir_to_read;
636                 if (ZREAD(ziinit.z_filefunc, ziinit.filestream,buf_read,read_this) != read_this)
637                     err=ZIP_ERRNO;
638
639                 if (err==ZIP_OK)
640                     err = add_data_in_datablock(&ziinit.central_dir,buf_read,
641                                                 (uLong)read_this);
642                 size_central_dir_to_read-=read_this;
643             }
644             TRYFREE(buf_read);
645         }
646         ziinit.begin_pos = byte_before_the_zipfile;
647         ziinit.number_entry = number_entry_CD;
648
649         if (ZSEEK(ziinit.z_filefunc, ziinit.filestream,
650                   offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)
651             err=ZIP_ERRNO;
652     }
653
654     if (globalcomment)
655     {
656       *globalcomment = ziinit.globalcomment;
657     }
658 #    endif /* !NO_ADDFILEINEXISTINGZIP*/
659
660     if (err != ZIP_OK)
661     {
662 #    ifndef NO_ADDFILEINEXISTINGZIP
663         TRYFREE(ziinit.globalcomment);
664 #    endif /* !NO_ADDFILEINEXISTINGZIP*/
665         TRYFREE(zi);
666         return NULL;
667     }
668     else
669     {
670         *zi = ziinit;
671         return (zipFile)zi;
672     }
673 }
674
675 extern zipFile ZEXPORT zipOpen (pathname, append)
676     const char *pathname;
677     int append;
678 {
679     return zipOpen2(pathname,append,NULL,NULL);
680 }
681
682 extern int ZEXPORT zipOpenNewFileInZip3 (file, filename, zipfi,
683                                          extrafield_local, size_extrafield_local,
684                                          extrafield_global, size_extrafield_global,
685                                          comment, method, level, raw,
686                                          windowBits, memLevel, strategy,
687                                          password, crcForCrypting)
688     zipFile file;
689     const char* filename;
690     const zip_fileinfo* zipfi;
691     const void* extrafield_local;
692     uInt size_extrafield_local;
693     const void* extrafield_global;
694     uInt size_extrafield_global;
695     const char* comment;
696     int method;
697     int level;
698     int raw;
699     int windowBits;
700     int memLevel;
701     int strategy;
702     const char* password;
703     uLong crcForCrypting;
704 {
705     zip_internal* zi;
706     uInt size_filename;
707     uInt size_comment;
708     uInt i;
709     int err = ZIP_OK;
710
711 #    ifdef NOCRYPT
712     if (password != NULL)
713         return ZIP_PARAMERROR;
714 #    endif
715
716     if (file == NULL)
717         return ZIP_PARAMERROR;
718     if ((method!=0) && (method!=Z_DEFLATED))
719         return ZIP_PARAMERROR;
720
721     zi = (zip_internal*)file;
722
723     if (zi->in_opened_file_inzip == 1)
724     {
725         err = zipCloseFileInZip (file);
726         if (err != ZIP_OK)
727             return err;
728     }
729
730
731     if (filename==NULL)
732         filename="-";
733
734     if (comment==NULL)
735         size_comment = 0;
736     else
737         size_comment = (uInt)strlen(comment);
738
739     size_filename = (uInt)strlen(filename);
740
741     if (zipfi == NULL)
742         zi->ci.dosDate = 0;
743     else
744     {
745         if (zipfi->dosDate != 0)
746             zi->ci.dosDate = zipfi->dosDate;
747         else zi->ci.dosDate = ziplocal_TmzDateToDosDate(&zipfi->tmz_date,zipfi->dosDate);
748     }
749
750     zi->ci.flag = 0;
751     if ((level==8) || (level==9))
752       zi->ci.flag |= 2;
753     if ((level==2))
754       zi->ci.flag |= 4;
755     if ((level==1))
756       zi->ci.flag |= 6;
757     if (password != NULL)
758       zi->ci.flag |= 1;
759
760     zi->ci.crc32 = 0;
761     zi->ci.method = method;
762     zi->ci.encrypt = 0;
763     zi->ci.stream_initialised = 0;
764     zi->ci.pos_in_buffered_data = 0;
765     zi->ci.raw = raw;
766     zi->ci.pos_local_header = ZTELL(zi->z_filefunc,zi->filestream) ;
767     zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename +
768                                       size_extrafield_global + size_comment;
769     zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader);
770
771     ziplocal_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4);
772     /* version info */
773     ziplocal_putValue_inmemory(zi->ci.central_header+4,(uLong)VERSIONMADEBY,2);
774     ziplocal_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2);
775     ziplocal_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2);
776     ziplocal_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2);
777     ziplocal_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4);
778     ziplocal_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/
779     ziplocal_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/
780     ziplocal_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/
781     ziplocal_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2);
782     ziplocal_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2);
783     ziplocal_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2);
784     ziplocal_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/
785
786     if (zipfi==NULL)
787         ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2);
788     else
789         ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2);
790
791     if (zipfi==NULL)
792         ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4);
793     else
794         ziplocal_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4);
795
796     ziplocal_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header- zi->add_position_when_writting_offset,4);
797
798     for (i=0;i<size_filename;i++)
799         *(zi->ci.central_header+SIZECENTRALHEADER+i) = *(filename+i);
800
801     for (i=0;i<size_extrafield_global;i++)
802         *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+i) =
803               *(((const char*)extrafield_global)+i);
804
805     for (i=0;i<size_comment;i++)
806         *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+
807               size_extrafield_global+i) = *(comment+i);
808     if (zi->ci.central_header == NULL)
809         return ZIP_INTERNALERROR;
810
811     /* write the local header */
812     err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC,4);
813
814     if (err==ZIP_OK)
815         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */
816     if (err==ZIP_OK)
817         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2);
818
819     if (err==ZIP_OK)
820         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2);
821
822     if (err==ZIP_OK)
823         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4);
824
825     if (err==ZIP_OK)
826         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */
827     if (err==ZIP_OK)
828         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */
829     if (err==ZIP_OK)
830         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */
831
832     if (err==ZIP_OK)
833         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2);
834
835     if (err==ZIP_OK)
836         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield_local,2);
837
838     if ((err==ZIP_OK) && (size_filename>0))
839         if (ZWRITE(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename)
840                 err = ZIP_ERRNO;
841
842     if ((err==ZIP_OK) && (size_extrafield_local>0))
843         if (ZWRITE(zi->z_filefunc,zi->filestream,extrafield_local,size_extrafield_local)
844                                                                            !=size_extrafield_local)
845                 err = ZIP_ERRNO;
846
847     zi->ci.stream.avail_in = (uInt)0;
848     zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
849     zi->ci.stream.next_out = zi->ci.buffered_data;
850     zi->ci.stream.total_in = 0;
851     zi->ci.stream.total_out = 0;
852
853     if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
854     {
855         zi->ci.stream.zalloc = (alloc_func)0;
856         zi->ci.stream.zfree = (free_func)0;
857         zi->ci.stream.opaque = (voidpf)0;
858
859         if (windowBits>0)
860             windowBits = -windowBits;
861
862         err = deflateInit2(&zi->ci.stream, level,
863                Z_DEFLATED, windowBits, memLevel, strategy);
864
865         if (err==Z_OK)
866             zi->ci.stream_initialised = 1;
867     }
868 #    ifndef NOCRYPT
869     zi->ci.crypt_header_size = 0;
870     if ((err==Z_OK) && (password != NULL))
871     {
872         unsigned char bufHead[RAND_HEAD_LEN];
873         unsigned int sizeHead;
874         zi->ci.encrypt = 1;
875         zi->ci.pcrc_32_tab = get_crc_table();
876         /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/
877
878         sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting);
879         zi->ci.crypt_header_size = sizeHead;
880
881         if (ZWRITE(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead)
882                 err = ZIP_ERRNO;
883     }
884 #    endif
885
886     if (err==Z_OK)
887         zi->in_opened_file_inzip = 1;
888     return err;
889 }
890
891 extern int ZEXPORT zipOpenNewFileInZip2(file, filename, zipfi,
892                                         extrafield_local, size_extrafield_local,
893                                         extrafield_global, size_extrafield_global,
894                                         comment, method, level, raw)
895     zipFile file;
896     const char* filename;
897     const zip_fileinfo* zipfi;
898     const void* extrafield_local;
899     uInt size_extrafield_local;
900     const void* extrafield_global;
901     uInt size_extrafield_global;
902     const char* comment;
903     int method;
904     int level;
905     int raw;
906 {
907     return zipOpenNewFileInZip3 (file, filename, zipfi,
908                                  extrafield_local, size_extrafield_local,
909                                  extrafield_global, size_extrafield_global,
910                                  comment, method, level, raw,
911                                  -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
912                                  NULL, 0);
913 }
914
915 extern int ZEXPORT zipOpenNewFileInZip (file, filename, zipfi,
916                                         extrafield_local, size_extrafield_local,
917                                         extrafield_global, size_extrafield_global,
918                                         comment, method, level)
919     zipFile file;
920     const char* filename;
921     const zip_fileinfo* zipfi;
922     const void* extrafield_local;
923     uInt size_extrafield_local;
924     const void* extrafield_global;
925     uInt size_extrafield_global;
926     const char* comment;
927     int method;
928     int level;
929 {
930     return zipOpenNewFileInZip2 (file, filename, zipfi,
931                                  extrafield_local, size_extrafield_local,
932                                  extrafield_global, size_extrafield_global,
933                                  comment, method, level, 0);
934 }
935
936 local int zipFlushWriteBuffer(zip_internal *zi)
937 {
938     int err=ZIP_OK;
939
940     if (zi->ci.encrypt != 0)
941     {
942 #ifndef NOCRYPT
943         uInt i;
944         int t;
945         for (i=0;i<zi->ci.pos_in_buffered_data;i++)
946             zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab,
947                                        zi->ci.buffered_data[i],t);
948 #endif
949     }
950     if (ZWRITE(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data)
951                                                                     !=zi->ci.pos_in_buffered_data)
952       err = ZIP_ERRNO;
953     zi->ci.pos_in_buffered_data = 0;
954     return err;
955 }
956
957 extern int ZEXPORT zipWriteInFileInZip (file, buf, len)
958     zipFile file;
959     const void* buf;
960     unsigned len;
961 {
962     zip_internal* zi;
963     int err=ZIP_OK;
964
965     if (file == NULL)
966         return ZIP_PARAMERROR;
967     zi = (zip_internal*)file;
968
969     if (zi->in_opened_file_inzip == 0)
970         return ZIP_PARAMERROR;
971
972     zi->ci.stream.next_in = (void*)buf;
973     zi->ci.stream.avail_in = len;
974     zi->ci.crc32 = crc32(zi->ci.crc32,buf,len);
975
976     while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
977     {
978         if (zi->ci.stream.avail_out == 0)
979         {
980             if (zipFlushWriteBuffer(zi) == ZIP_ERRNO)
981                 err = ZIP_ERRNO;
982             zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
983             zi->ci.stream.next_out = zi->ci.buffered_data;
984         }
985
986
987         if(err != ZIP_OK)
988             break;
989
990         if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
991         {
992             uLong uTotalOutBefore = zi->ci.stream.total_out;
993             err=deflate(&zi->ci.stream,  Z_NO_FLUSH);
994             zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
995
996         }
997         else
998         {
999             uInt copy_this,i;
1000             if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
1001                 copy_this = zi->ci.stream.avail_in;
1002             else
1003                 copy_this = zi->ci.stream.avail_out;
1004             for (i=0;i<copy_this;i++)
1005                 *(((char*)zi->ci.stream.next_out)+i) =
1006                     *(((const char*)zi->ci.stream.next_in)+i);
1007             {
1008                 zi->ci.stream.avail_in -= copy_this;
1009                 zi->ci.stream.avail_out-= copy_this;
1010                 zi->ci.stream.next_in+= copy_this;
1011                 zi->ci.stream.next_out+= copy_this;
1012                 zi->ci.stream.total_in+= copy_this;
1013                 zi->ci.stream.total_out+= copy_this;
1014                 zi->ci.pos_in_buffered_data += copy_this;
1015             }
1016         }
1017     }
1018
1019     return err;
1020 }
1021
1022 extern int ZEXPORT zipCloseFileInZipRaw (file, uncompressed_size, crc32)
1023     zipFile file;
1024     uLong uncompressed_size;
1025     uLong crc32;
1026 {
1027     zip_internal* zi;
1028     uLong compressed_size;
1029     int err=ZIP_OK;
1030
1031     if (file == NULL)
1032         return ZIP_PARAMERROR;
1033     zi = (zip_internal*)file;
1034
1035     if (zi->in_opened_file_inzip == 0)
1036         return ZIP_PARAMERROR;
1037     zi->ci.stream.avail_in = 0;
1038
1039     if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
1040         while (err==ZIP_OK)
1041     {
1042         uLong uTotalOutBefore;
1043         if (zi->ci.stream.avail_out == 0)
1044         {
1045             if (zipFlushWriteBuffer(zi) == ZIP_ERRNO)
1046                 err = ZIP_ERRNO;
1047             zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
1048             zi->ci.stream.next_out = zi->ci.buffered_data;
1049         }
1050         uTotalOutBefore = zi->ci.stream.total_out;
1051         err=deflate(&zi->ci.stream,  Z_FINISH);
1052         zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
1053     }
1054
1055     if (err==Z_STREAM_END)
1056         err=ZIP_OK; /* this is normal */
1057
1058     if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK))
1059         if (zipFlushWriteBuffer(zi)==ZIP_ERRNO)
1060             err = ZIP_ERRNO;
1061
1062     if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
1063     {
1064         err=deflateEnd(&zi->ci.stream);
1065         zi->ci.stream_initialised = 0;
1066     }
1067
1068     if (!zi->ci.raw)
1069     {
1070         crc32 = (uLong)zi->ci.crc32;
1071         uncompressed_size = (uLong)zi->ci.stream.total_in;
1072     }
1073     compressed_size = (uLong)zi->ci.stream.total_out;
1074 #    ifndef NOCRYPT
1075     compressed_size += zi->ci.crypt_header_size;
1076 #    endif
1077
1078     ziplocal_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/
1079     ziplocal_putValue_inmemory(zi->ci.central_header+20,
1080                                 compressed_size,4); /*compr size*/
1081     if (zi->ci.stream.data_type == Z_ASCII)
1082         ziplocal_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2);
1083     ziplocal_putValue_inmemory(zi->ci.central_header+24,
1084                                 uncompressed_size,4); /*uncompr size*/
1085
1086     if (err==ZIP_OK)
1087         err = add_data_in_datablock(&zi->central_dir,zi->ci.central_header,
1088                                        (uLong)zi->ci.size_centralheader);
1089     free(zi->ci.central_header);
1090
1091     if (err==ZIP_OK)
1092     {
1093         long cur_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream);
1094         if (ZSEEK(zi->z_filefunc,zi->filestream,
1095                   zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0)
1096             err = ZIP_ERRNO;
1097
1098         if (err==ZIP_OK)
1099             err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */
1100
1101         if (err==ZIP_OK) /* compressed size, unknown */
1102             err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4);
1103
1104         if (err==ZIP_OK) /* uncompressed size, unknown */
1105             err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4);
1106
1107         if (ZSEEK(zi->z_filefunc,zi->filestream,
1108                   cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0)
1109             err = ZIP_ERRNO;
1110     }
1111
1112     zi->number_entry ++;
1113     zi->in_opened_file_inzip = 0;
1114
1115     return err;
1116 }
1117
1118 extern int ZEXPORT zipCloseFileInZip (file)
1119     zipFile file;
1120 {
1121     return zipCloseFileInZipRaw (file,0,0);
1122 }
1123
1124 extern int ZEXPORT zipClose (file, global_comment)
1125     zipFile file;
1126     const char* global_comment;
1127 {
1128     zip_internal* zi;
1129     int err = 0;
1130     uLong size_centraldir = 0;
1131     uLong centraldir_pos_inzip;
1132     uInt size_global_comment;
1133     if (file == NULL)
1134         return ZIP_PARAMERROR;
1135     zi = (zip_internal*)file;
1136
1137     if (zi->in_opened_file_inzip == 1)
1138     {
1139         err = zipCloseFileInZip (file);
1140     }
1141
1142 #ifndef NO_ADDFILEINEXISTINGZIP
1143     if (global_comment==NULL)
1144         global_comment = zi->globalcomment;
1145 #endif
1146     if (global_comment==NULL)
1147         size_global_comment = 0;
1148     else
1149         size_global_comment = (uInt)strlen(global_comment);
1150
1151     centraldir_pos_inzip = ZTELL(zi->z_filefunc,zi->filestream);
1152     if (err==ZIP_OK)
1153     {
1154         linkedlist_datablock_internal* ldi = zi->central_dir.first_block ;
1155         while (ldi!=NULL)
1156         {
1157             if ((err==ZIP_OK) && (ldi->filled_in_this_block>0))
1158                 if (ZWRITE(zi->z_filefunc,zi->filestream,
1159                            ldi->data,ldi->filled_in_this_block)
1160                               !=ldi->filled_in_this_block )
1161                     err = ZIP_ERRNO;
1162
1163             size_centraldir += ldi->filled_in_this_block;
1164             ldi = ldi->next_datablock;
1165         }
1166     }
1167     free_datablock(zi->central_dir.first_block);
1168
1169     if (err==ZIP_OK) /* Magic End */
1170         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4);
1171
1172     if (err==ZIP_OK) /* number of this disk */
1173         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);
1174
1175     if (err==ZIP_OK) /* number of the disk with the start of the central directory */
1176         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);
1177
1178     if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
1179         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
1180
1181     if (err==ZIP_OK) /* total number of entries in the central dir */
1182         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
1183
1184     if (err==ZIP_OK) /* size of the central directory */
1185         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4);
1186
1187     if (err==ZIP_OK) /* offset of start of central directory with respect to the
1188                             starting disk number */
1189         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,
1190                                 (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4);
1191
1192     if (err==ZIP_OK) /* zipfile comment length */
1193         err = ziplocal_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2);
1194
1195     if ((err==ZIP_OK) && (size_global_comment>0))
1196         if (ZWRITE(zi->z_filefunc,zi->filestream,
1197                    global_comment,size_global_comment) != size_global_comment)
1198                 err = ZIP_ERRNO;
1199
1200     if (ZCLOSE(zi->z_filefunc,zi->filestream) != 0)
1201         if (err == ZIP_OK)
1202             err = ZIP_ERRNO;
1203
1204 #ifndef NO_ADDFILEINEXISTINGZIP
1205     TRYFREE(zi->globalcomment);
1206 #endif
1207     TRYFREE(zi);
1208
1209     return err;
1210 }