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