]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - contrib/pk3man/zlib/unzip.c
ff71a474da12c0358092616e47f2bcb7facbe3d3
[xonotic/netradiant.git] / contrib / pk3man / zlib / unzip.c
1 /* unzip.c -- IO on .zip files using zlib 
2    Version 0.15 beta, Mar 19th, 1998,
3
4    Read unzip.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 "unzip.h"
13
14 #ifdef STDC
15 #  include <stddef.h>
16 #  include <string.h>
17 #  include <stdlib.h>
18 #endif
19 #ifdef NO_ERRNO_H
20     extern int errno;
21 #else
22 #   include <errno.h>
23 #endif
24
25
26 #ifndef local
27 #  define local static
28 #endif
29 /* compile with -Dlocal if your debugger can't find static symbols */
30
31
32
33 #if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \
34                       !defined(CASESENSITIVITYDEFAULT_NO)
35 #define CASESENSITIVITYDEFAULT_NO
36 #endif
37
38
39 #ifndef UNZ_BUFSIZE
40 #define UNZ_BUFSIZE (16384)
41 #endif
42
43 #ifndef UNZ_MAXFILENAMEINZIP
44 #define UNZ_MAXFILENAMEINZIP (256)
45 #endif
46
47 #ifndef ALLOC
48 # define ALLOC(size) (malloc(size))
49 #endif
50 #ifndef TRYFREE
51 # define TRYFREE(p) {if (p) free(p);}
52 #endif
53
54 #define SIZECENTRALDIRITEM (0x2e)
55 #define SIZEZIPLOCALHEADER (0x1e)
56
57
58 /* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
59
60 #ifndef SEEK_CUR
61 #define SEEK_CUR    1
62 #endif
63
64 #ifndef SEEK_END
65 #define SEEK_END    2
66 #endif
67
68 #ifndef SEEK_SET
69 #define SEEK_SET    0
70 #endif
71
72 const char unz_copyright[] =
73    " unzip 0.15 Copyright 1998 Gilles Vollant ";
74
75 /* unz_file_info_interntal contain internal info about a file in zipfile*/
76 typedef struct unz_file_info_internal_s
77 {
78     uLong offset_curfile;/* relative offset of local header 4 bytes */
79 } unz_file_info_internal;
80
81
82 /* file_in_zip_read_info_s contain internal information about a file in zipfile,
83     when reading and decompress it */
84 typedef struct
85 {
86         char  *read_buffer;         /* internal buffer for compressed data */
87         z_stream stream;            /* zLib stream structure for inflate */
88
89         uLong pos_in_zipfile;       /* position in byte on the zipfile, for fseek*/
90         uLong stream_initialised;   /* flag set if stream structure is initialised*/
91
92         uLong offset_local_extrafield;/* offset of the local extra field */
93         uInt  size_local_extrafield;/* size of the local extra field */
94         uLong pos_local_extrafield;   /* position in the local extra field in read*/
95
96         uLong crc32;                /* crc32 of all data uncompressed */
97         uLong crc32_wait;           /* crc32 we must obtain after decompress all */
98         uLong rest_read_compressed; /* number of byte to be decompressed */
99         uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/
100         FILE* file;                 /* io structore of the zipfile */
101         uLong compression_method;   /* compression method (0==store) */
102         uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
103 } file_in_zip_read_info_s;
104
105
106 /* unz_s contain internal information about the zipfile
107 */
108 typedef struct
109 {
110         FILE* file;                 /* io structore of the zipfile */
111         unz_global_info gi;       /* public global information */
112         uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
113         uLong num_file;             /* number of the current file in the zipfile*/
114         uLong pos_in_central_dir;   /* pos of the current file in the central dir*/
115         uLong current_file_ok;      /* flag about the usability of the current file*/
116         uLong central_pos;          /* position of the beginning of the central dir*/
117
118         uLong size_central_dir;     /* size of the central directory  */
119         uLong offset_central_dir;   /* offset of start of central directory with
120                                                                    respect to the starting disk number */
121
122         unz_file_info cur_file_info; /* public info about the current file in zip*/
123         unz_file_info_internal cur_file_info_internal; /* private info about it*/
124     file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current
125                                             file if we are decompressing it */
126 } unz_s;
127
128
129 /* ===========================================================================
130      Read a byte from a gz_stream; update next_in and avail_in. Return EOF
131    for end of file.
132    IN assertion: the stream s has been sucessfully opened for reading.
133 */
134
135
136 local int unzlocal_getByte(fin,pi)
137         FILE *fin;
138         int *pi;
139 {
140     unsigned char c;
141         int err = fread(&c, 1, 1, fin);
142     if (err==1)
143     {
144         *pi = (int)c;
145         return UNZ_OK;
146     }
147     else
148     {
149         if (ferror(fin)) 
150             return UNZ_ERRNO;
151         else
152             return UNZ_EOF;
153     }
154 }
155
156
157 /* ===========================================================================
158    Reads a long in LSB order from the given gz_stream. Sets 
159 */
160 local int unzlocal_getShort (fin,pX)
161         FILE* fin;
162     uLong *pX;
163 {
164     uLong x ;
165     int i;
166     int err;
167
168     err = unzlocal_getByte(fin,&i);
169     x = (uLong)i;
170     
171     if (err==UNZ_OK)
172         err = unzlocal_getByte(fin,&i);
173     x += ((uLong)i)<<8;
174    
175     if (err==UNZ_OK)
176         *pX = x;
177     else
178         *pX = 0;
179     return err;
180 }
181
182 local int unzlocal_getLong (fin,pX)
183         FILE* fin;
184     uLong *pX;
185 {
186     uLong x ;
187     int i;
188     int err;
189
190     err = unzlocal_getByte(fin,&i);
191     x = (uLong)i;
192     
193     if (err==UNZ_OK)
194         err = unzlocal_getByte(fin,&i);
195     x += ((uLong)i)<<8;
196
197     if (err==UNZ_OK)
198         err = unzlocal_getByte(fin,&i);
199     x += ((uLong)i)<<16;
200
201     if (err==UNZ_OK)
202         err = unzlocal_getByte(fin,&i);
203     x += ((uLong)i)<<24;
204    
205     if (err==UNZ_OK)
206         *pX = x;
207     else
208         *pX = 0;
209     return err;
210 }
211
212
213 /* My own strcmpi / strcasecmp */
214 local int strcmpcasenosensitive_internal (fileName1,fileName2)
215         const char* fileName1;
216         const char* fileName2;
217 {
218         for (;;)
219         {
220                 char c1=*(fileName1++);
221                 char c2=*(fileName2++);
222                 if ((c1>='a') && (c1<='z'))
223                         c1 -= 0x20;
224                 if ((c2>='a') && (c2<='z'))
225                         c2 -= 0x20;
226                 if (c1=='\0')
227                         return ((c2=='\0') ? 0 : -1);
228                 if (c2=='\0')
229                         return 1;
230                 if (c1<c2)
231                         return -1;
232                 if (c1>c2)
233                         return 1;
234         }
235 }
236
237
238 #ifdef  CASESENSITIVITYDEFAULT_NO
239 #define CASESENSITIVITYDEFAULTVALUE 2
240 #else
241 #define CASESENSITIVITYDEFAULTVALUE 1
242 #endif
243
244 #ifndef STRCMPCASENOSENTIVEFUNCTION
245 #define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
246 #endif
247
248 /* 
249    Compare two filename (fileName1,fileName2).
250    If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
251    If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
252                                                                 or strcasecmp)
253    If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
254         (like 1 on Unix, 2 on Windows)
255
256 */
257 extern int ZEXPORT unzStringFileNameCompare (fileName1,fileName2,iCaseSensitivity)
258         const char* fileName1;
259         const char* fileName2;
260         int iCaseSensitivity;
261 {
262         if (iCaseSensitivity==0)
263                 iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
264
265         if (iCaseSensitivity==1)
266                 return strcmp(fileName1,fileName2);
267
268         return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
269
270
271 #define BUFREADCOMMENT (0x400)
272
273 /*
274   Locate the Central directory of a zipfile (at the end, just before
275     the global comment)
276 */
277 local uLong unzlocal_SearchCentralDir(fin)
278         FILE *fin;
279 {
280         unsigned char* buf;
281         uLong uSizeFile;
282         uLong uBackRead;
283         uLong uMaxBack=0xffff; /* maximum size of global comment */
284         uLong uPosFound=0;
285         
286         if (fseek(fin,0,SEEK_END) != 0)
287                 return 0;
288
289
290         uSizeFile = ftell( fin );
291         
292         if (uMaxBack>uSizeFile)
293                 uMaxBack = uSizeFile;
294
295         buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
296         if (buf==NULL)
297                 return 0;
298
299         uBackRead = 4;
300         while (uBackRead<uMaxBack)
301         {
302                 uLong uReadSize,uReadPos ;
303                 int i;
304                 if (uBackRead+BUFREADCOMMENT>uMaxBack) 
305                         uBackRead = uMaxBack;
306                 else
307                         uBackRead+=BUFREADCOMMENT;
308                 uReadPos = uSizeFile-uBackRead ;
309                 
310                 uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? 
311                      (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
312                 if (fseek(fin,uReadPos,SEEK_SET)!=0)
313                         break;
314
315                 if (fread(buf,(uInt)uReadSize,1,fin)!=1)
316                         break;
317
318                 for (i=(int)uReadSize-3; (i--)>0;)
319                         if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && 
320                                 ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
321                         {
322                                 uPosFound = uReadPos+i;
323                                 break;
324                         }
325
326                 if (uPosFound!=0)
327                         break;
328         }
329         TRYFREE(buf);
330         return uPosFound;
331 }
332
333 /*
334   Open a Zip file. path contain the full pathname (by example,
335      on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer
336          "zlib/zlib109.zip".
337          If the zipfile cannot be opened (file don't exist or in not valid), the
338            return value is NULL.
339      Else, the return value is a unzFile Handle, usable with other function
340            of this unzip package.
341 */
342 extern unzFile ZEXPORT unzOpen (path)
343         const char *path;
344 {
345         unz_s us;
346         unz_s *s;
347         uLong central_pos,uL;
348         FILE * fin ;
349
350         uLong number_disk;          /* number of the current dist, used for 
351                                                                    spaning ZIP, unsupported, always 0*/
352         uLong number_disk_with_CD;  /* number the the disk with central dir, used
353                                                                    for spaning ZIP, unsupported, always 0*/
354         uLong number_entry_CD;      /* total number of entries in
355                                        the central dir 
356                                        (same than number_entry on nospan) */
357
358         int err=UNZ_OK;
359
360     if (unz_copyright[0]!=' ')
361         return NULL;
362
363     fin=fopen(path,"rb");
364         if (fin==NULL)
365                 return NULL;
366
367         central_pos = unzlocal_SearchCentralDir(fin);
368         if (central_pos==0)
369                 err=UNZ_ERRNO;
370
371         if (fseek(fin,central_pos,SEEK_SET)!=0)
372                 err=UNZ_ERRNO;
373
374         /* the signature, already checked */
375         if (unzlocal_getLong(fin,&uL)!=UNZ_OK)
376                 err=UNZ_ERRNO;
377
378         /* number of this disk */
379         if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK)
380                 err=UNZ_ERRNO;
381
382         /* number of the disk with the start of the central directory */
383         if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK)
384                 err=UNZ_ERRNO;
385
386         /* total number of entries in the central dir on this disk */
387         if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK)
388                 err=UNZ_ERRNO;
389
390         /* total number of entries in the central dir */
391         if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK)
392                 err=UNZ_ERRNO;
393
394         if ((number_entry_CD!=us.gi.number_entry) ||
395                 (number_disk_with_CD!=0) ||
396                 (number_disk!=0))
397                 err=UNZ_BADZIPFILE;
398
399         /* size of the central directory */
400         if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK)
401                 err=UNZ_ERRNO;
402
403         /* offset of start of central directory with respect to the 
404               starting disk number */
405         if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK)
406                 err=UNZ_ERRNO;
407
408         /* zipfile comment length */
409         if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK)
410                 err=UNZ_ERRNO;
411
412         if ((central_pos<us.offset_central_dir+us.size_central_dir) && 
413                 (err==UNZ_OK))
414                 err=UNZ_BADZIPFILE;
415
416         if (err!=UNZ_OK)
417         {
418                 fclose(fin);
419                 return NULL;
420         }
421
422         us.file=fin;
423         us.byte_before_the_zipfile = central_pos -
424                                     (us.offset_central_dir+us.size_central_dir);
425         us.central_pos = central_pos;
426     us.pfile_in_zip_read = NULL;
427         
428
429         s=(unz_s*)ALLOC(sizeof(unz_s));
430         *s=us;
431         unzGoToFirstFile((unzFile)s);   
432         return (unzFile)s;      
433 }
434
435
436 /*
437   Close a ZipFile opened with unzipOpen.
438   If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
439     these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
440   return UNZ_OK if there is no problem. */
441 extern int ZEXPORT unzClose (file)
442         unzFile file;
443 {
444         unz_s* s;
445         if (file==NULL)
446                 return UNZ_PARAMERROR;
447         s=(unz_s*)file;
448
449     if (s->pfile_in_zip_read!=NULL)
450         unzCloseCurrentFile(file);
451
452         fclose(s->file);
453         TRYFREE(s);
454         return UNZ_OK;
455 }
456
457
458 /*
459   Write info about the ZipFile in the *pglobal_info structure.
460   No preparation of the structure is needed
461   return UNZ_OK if there is no problem. */
462 extern int ZEXPORT unzGetGlobalInfo (file,pglobal_info)
463         unzFile file;
464         unz_global_info *pglobal_info;
465 {
466         unz_s* s;
467         if (file==NULL)
468                 return UNZ_PARAMERROR;
469         s=(unz_s*)file;
470         *pglobal_info=s->gi;
471         return UNZ_OK;
472 }
473
474
475 /*
476    Translate date/time from Dos format to tm_unz (readable more easilty)
477 */
478 local void unzlocal_DosDateToTmuDate (ulDosDate, ptm)
479     uLong ulDosDate;
480     tm_unz* ptm;
481 {
482     uLong uDate;
483     uDate = (uLong)(ulDosDate>>16);
484     ptm->tm_mday = (uInt)(uDate&0x1f) ;
485     ptm->tm_mon =  (uInt)((((uDate)&0x1E0)/0x20)-1) ;
486     ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;
487
488     ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
489     ptm->tm_min =  (uInt) ((ulDosDate&0x7E0)/0x20) ;
490     ptm->tm_sec =  (uInt) (2*(ulDosDate&0x1f)) ;
491 }
492
493 /*
494   Get Info about the current file in the zipfile, with internal only info
495 */
496 local int unzlocal_GetCurrentFileInfoInternal OF((unzFile file,
497                                                   unz_file_info *pfile_info,
498                                                   unz_file_info_internal 
499                                                   *pfile_info_internal,
500                                                   char *szFileName,
501                                                                                                   uLong fileNameBufferSize,
502                                                   void *extraField,
503                                                                                                   uLong extraFieldBufferSize,
504                                                   char *szComment,
505                                                                                                   uLong commentBufferSize));
506
507 local int unzlocal_GetCurrentFileInfoInternal (file,
508                                               pfile_info,
509                                               pfile_info_internal,
510                                               szFileName, fileNameBufferSize,
511                                               extraField, extraFieldBufferSize,
512                                               szComment,  commentBufferSize)
513         unzFile file;
514         unz_file_info *pfile_info;
515         unz_file_info_internal *pfile_info_internal;
516         char *szFileName;
517         uLong fileNameBufferSize;
518         void *extraField;
519         uLong extraFieldBufferSize;
520         char *szComment;
521         uLong commentBufferSize;
522 {
523         unz_s* s;
524         unz_file_info file_info;
525         unz_file_info_internal file_info_internal;
526         int err=UNZ_OK;
527         uLong uMagic;
528         long lSeek=0;
529
530         if (file==NULL)
531                 return UNZ_PARAMERROR;
532         s=(unz_s*)file;
533         if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0)
534                 err=UNZ_ERRNO;
535
536
537         /* we check the magic */
538         if (err==UNZ_OK)
539                 if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
540                         err=UNZ_ERRNO;
541                 else if (uMagic!=0x02014b50)
542                         err=UNZ_BADZIPFILE;
543
544         if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK)
545                 err=UNZ_ERRNO;
546
547         if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK)
548                 err=UNZ_ERRNO;
549
550         if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK)
551                 err=UNZ_ERRNO;
552
553         if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK)
554                 err=UNZ_ERRNO;
555
556         if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK)
557                 err=UNZ_ERRNO;
558
559     unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
560
561         if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK)
562                 err=UNZ_ERRNO;
563
564         if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK)
565                 err=UNZ_ERRNO;
566
567         if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK)
568                 err=UNZ_ERRNO;
569
570         if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK)
571                 err=UNZ_ERRNO;
572
573         if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK)
574                 err=UNZ_ERRNO;
575
576         if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK)
577                 err=UNZ_ERRNO;
578
579         if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK)
580                 err=UNZ_ERRNO;
581
582         if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK)
583                 err=UNZ_ERRNO;
584
585         if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK)
586                 err=UNZ_ERRNO;
587
588         if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK)
589                 err=UNZ_ERRNO;
590
591         lSeek+=file_info.size_filename;
592         if ((err==UNZ_OK) && (szFileName!=NULL))
593         {
594                 uLong uSizeRead ;
595                 if (file_info.size_filename<fileNameBufferSize)
596                 {
597                         *(szFileName+file_info.size_filename)='\0';
598                         uSizeRead = file_info.size_filename;
599                 }
600                 else
601                         uSizeRead = fileNameBufferSize;
602
603                 if ((file_info.size_filename>0) && (fileNameBufferSize>0))
604                         if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1)
605                                 err=UNZ_ERRNO;
606                 lSeek -= uSizeRead;
607         }
608
609         
610         if ((err==UNZ_OK) && (extraField!=NULL))
611         {
612                 uLong uSizeRead ;
613                 if (file_info.size_file_extra<extraFieldBufferSize)
614                         uSizeRead = file_info.size_file_extra;
615                 else
616                         uSizeRead = extraFieldBufferSize;
617
618                 if (lSeek!=0)
619                         if (fseek(s->file,lSeek,SEEK_CUR)==0)
620                                 lSeek=0;
621                         else
622                                 err=UNZ_ERRNO;
623                 if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
624                         if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1)
625                                 err=UNZ_ERRNO;
626                 lSeek += file_info.size_file_extra - uSizeRead;
627         }
628         else
629                 lSeek+=file_info.size_file_extra; 
630
631         
632         if ((err==UNZ_OK) && (szComment!=NULL))
633         {
634                 uLong uSizeRead ;
635                 if (file_info.size_file_comment<commentBufferSize)
636                 {
637                         *(szComment+file_info.size_file_comment)='\0';
638                         uSizeRead = file_info.size_file_comment;
639                 }
640                 else
641                         uSizeRead = commentBufferSize;
642
643                 if (lSeek!=0)
644                         if (fseek(s->file,lSeek,SEEK_CUR)==0)
645                                 lSeek=0;
646                         else
647                                 err=UNZ_ERRNO;
648                 if ((file_info.size_file_comment>0) && (commentBufferSize>0))
649                         if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1)
650                                 err=UNZ_ERRNO;
651                 lSeek+=file_info.size_file_comment - uSizeRead;
652         }
653         else
654                 lSeek+=file_info.size_file_comment;
655
656         if ((err==UNZ_OK) && (pfile_info!=NULL))
657                 *pfile_info=file_info;
658
659         if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
660                 *pfile_info_internal=file_info_internal;
661
662         return err;
663 }
664
665
666
667 /*
668   Write info about the ZipFile in the *pglobal_info structure.
669   No preparation of the structure is needed
670   return UNZ_OK if there is no problem.
671 */
672 extern int ZEXPORT unzGetCurrentFileInfo (file,
673                                                   pfile_info,
674                                                   szFileName, fileNameBufferSize,
675                                                   extraField, extraFieldBufferSize,
676                                                   szComment,  commentBufferSize)
677         unzFile file;
678         unz_file_info *pfile_info;
679         char *szFileName;
680         uLong fileNameBufferSize;
681         void *extraField;
682         uLong extraFieldBufferSize;
683         char *szComment;
684         uLong commentBufferSize;
685 {
686         return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,
687                                                                                                 szFileName,fileNameBufferSize,
688                                                                                                 extraField,extraFieldBufferSize,
689                                                                                                 szComment,commentBufferSize);
690 }
691
692 /*
693   Set the current file of the zipfile to the first file.
694   return UNZ_OK if there is no problem
695 */
696 extern int ZEXPORT unzGoToFirstFile (file)
697         unzFile file;
698 {
699         int err=UNZ_OK;
700         unz_s* s;
701         if (file==NULL)
702                 return UNZ_PARAMERROR;
703         s=(unz_s*)file;
704         s->pos_in_central_dir=s->offset_central_dir;
705         s->num_file=0;
706         err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
707                                                                                          &s->cur_file_info_internal,
708                                                                                          NULL,0,NULL,0,NULL,0);
709         s->current_file_ok = (err == UNZ_OK);
710         return err;
711 }
712
713
714 /*
715   Set the current file of the zipfile to the next file.
716   return UNZ_OK if there is no problem
717   return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
718 */
719 extern int ZEXPORT unzGoToNextFile (file)
720         unzFile file;
721 {
722         unz_s* s;       
723         int err;
724
725         if (file==NULL)
726                 return UNZ_PARAMERROR;
727         s=(unz_s*)file;
728         if (!s->current_file_ok)
729                 return UNZ_END_OF_LIST_OF_FILE;
730         if (s->num_file+1==s->gi.number_entry)
731                 return UNZ_END_OF_LIST_OF_FILE;
732
733         s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
734                         s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
735         s->num_file++;
736         err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
737                                                                                            &s->cur_file_info_internal,
738                                                                                            NULL,0,NULL,0,NULL,0);
739         s->current_file_ok = (err == UNZ_OK);
740         return err;
741 }
742
743
744 /*
745   Try locate the file szFileName in the zipfile.
746   For the iCaseSensitivity signification, see unzipStringFileNameCompare
747
748   return value :
749   UNZ_OK if the file is found. It becomes the current file.
750   UNZ_END_OF_LIST_OF_FILE if the file is not found
751 */
752 extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity)
753         unzFile file;
754         const char *szFileName;
755         int iCaseSensitivity;
756 {
757         unz_s* s;       
758         int err;
759
760         
761         uLong num_fileSaved;
762         uLong pos_in_central_dirSaved;
763
764
765         if (file==NULL)
766                 return UNZ_PARAMERROR;
767
768     if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
769         return UNZ_PARAMERROR;
770
771         s=(unz_s*)file;
772         if (!s->current_file_ok)
773                 return UNZ_END_OF_LIST_OF_FILE;
774
775         num_fileSaved = s->num_file;
776         pos_in_central_dirSaved = s->pos_in_central_dir;
777
778         err = unzGoToFirstFile(file);
779
780         while (err == UNZ_OK)
781         {
782                 char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
783                 unzGetCurrentFileInfo(file,NULL,
784                                                                 szCurrentFileName,sizeof(szCurrentFileName)-1,
785                                                                 NULL,0,NULL,0);
786                 if (unzStringFileNameCompare(szCurrentFileName,
787                                                                                 szFileName,iCaseSensitivity)==0)
788                         return UNZ_OK;
789                 err = unzGoToNextFile(file);
790         }
791
792         s->num_file = num_fileSaved ;
793         s->pos_in_central_dir = pos_in_central_dirSaved ;
794         return err;
795 }
796
797
798 /*
799   Read the local header of the current zipfile
800   Check the coherency of the local header and info in the end of central
801         directory about this file
802   store in *piSizeVar the size of extra info in local header
803         (filename and size of extra field data)
804 */
805 local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar,
806                                                                                                         poffset_local_extrafield,
807                                                                                                         psize_local_extrafield)
808         unz_s* s;
809         uInt* piSizeVar;
810         uLong *poffset_local_extrafield;
811         uInt  *psize_local_extrafield;
812 {
813         uLong uMagic,uData,uFlags;
814         uLong size_filename;
815         uLong size_extra_field;
816         int err=UNZ_OK;
817
818         *piSizeVar = 0;
819         *poffset_local_extrafield = 0;
820         *psize_local_extrafield = 0;
821
822         if (fseek(s->file,s->cur_file_info_internal.offset_curfile +
823                                                                 s->byte_before_the_zipfile,SEEK_SET)!=0)
824                 return UNZ_ERRNO;
825
826
827         if (err==UNZ_OK)
828                 if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
829                         err=UNZ_ERRNO;
830                 else if (uMagic!=0x04034b50)
831                         err=UNZ_BADZIPFILE;
832
833         if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
834                 err=UNZ_ERRNO;
835 /*
836         else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
837                 err=UNZ_BADZIPFILE;
838 */
839         if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK)
840                 err=UNZ_ERRNO;
841
842         if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
843                 err=UNZ_ERRNO;
844         else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
845                 err=UNZ_BADZIPFILE;
846
847     if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
848                          (s->cur_file_info.compression_method!=Z_DEFLATED))
849         err=UNZ_BADZIPFILE;
850
851         if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */
852                 err=UNZ_ERRNO;
853
854         if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */
855                 err=UNZ_ERRNO;
856         else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&
857                                       ((uFlags & 8)==0))
858                 err=UNZ_BADZIPFILE;
859
860         if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */
861                 err=UNZ_ERRNO;
862         else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&
863                                                           ((uFlags & 8)==0))
864                 err=UNZ_BADZIPFILE;
865
866         if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */
867                 err=UNZ_ERRNO;
868         else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && 
869                                                           ((uFlags & 8)==0))
870                 err=UNZ_BADZIPFILE;
871
872
873         if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK)
874                 err=UNZ_ERRNO;
875         else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
876                 err=UNZ_BADZIPFILE;
877
878         *piSizeVar += (uInt)size_filename;
879
880         if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK)
881                 err=UNZ_ERRNO;
882         *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
883                                                                         SIZEZIPLOCALHEADER + size_filename;
884         *psize_local_extrafield = (uInt)size_extra_field;
885
886         *piSizeVar += (uInt)size_extra_field;
887
888         return err;
889 }
890                                                                                                 
891 /*
892   Open for reading data the current file in the zipfile.
893   If there is no error and the file is opened, the return value is UNZ_OK.
894 */
895 extern int ZEXPORT unzOpenCurrentFile (file)
896         unzFile file;
897 {
898         int err=UNZ_OK;
899         int Store;
900         uInt iSizeVar;
901         unz_s* s;
902         file_in_zip_read_info_s* pfile_in_zip_read_info;
903         uLong offset_local_extrafield;  /* offset of the local extra field */
904         uInt  size_local_extrafield;    /* size of the local extra field */
905
906         if (file==NULL)
907                 return UNZ_PARAMERROR;
908         s=(unz_s*)file;
909         if (!s->current_file_ok)
910                 return UNZ_PARAMERROR;
911
912     if (s->pfile_in_zip_read != NULL)
913         unzCloseCurrentFile(file);
914
915         if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,
916                                 &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
917                 return UNZ_BADZIPFILE;
918
919         pfile_in_zip_read_info = (file_in_zip_read_info_s*)
920                                                                             ALLOC(sizeof(file_in_zip_read_info_s));
921         if (pfile_in_zip_read_info==NULL)
922                 return UNZ_INTERNALERROR;
923
924         pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
925         pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
926         pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
927         pfile_in_zip_read_info->pos_local_extrafield=0;
928
929         if (pfile_in_zip_read_info->read_buffer==NULL)
930         {
931                 TRYFREE(pfile_in_zip_read_info);
932                 return UNZ_INTERNALERROR;
933         }
934
935         pfile_in_zip_read_info->stream_initialised=0;
936         
937         if ((s->cur_file_info.compression_method!=0) &&
938         (s->cur_file_info.compression_method!=Z_DEFLATED))
939                 err=UNZ_BADZIPFILE;
940         Store = s->cur_file_info.compression_method==0;
941
942         pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
943         pfile_in_zip_read_info->crc32=0;
944         pfile_in_zip_read_info->compression_method =
945             s->cur_file_info.compression_method;
946         pfile_in_zip_read_info->file=s->file;
947         pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
948
949     pfile_in_zip_read_info->stream.total_out = 0;
950
951         if (!Store)
952         {
953           pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
954           pfile_in_zip_read_info->stream.zfree = (free_func)0;
955           pfile_in_zip_read_info->stream.opaque = (voidpf)0; 
956       
957           err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
958           if (err == Z_OK)
959             pfile_in_zip_read_info->stream_initialised=1;
960         /* windowBits is passed < 0 to tell that there is no zlib header.
961          * Note that in this case inflate *requires* an extra "dummy" byte
962          * after the compressed stream in order to complete decompression and
963          * return Z_STREAM_END. 
964          * In unzip, i don't wait absolutely Z_STREAM_END because I known the 
965          * size of both compressed and uncompressed data
966          */
967         }
968         pfile_in_zip_read_info->rest_read_compressed = 
969             s->cur_file_info.compressed_size ;
970         pfile_in_zip_read_info->rest_read_uncompressed = 
971             s->cur_file_info.uncompressed_size ;
972
973         
974         pfile_in_zip_read_info->pos_in_zipfile = 
975             s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + 
976                           iSizeVar;
977         
978         pfile_in_zip_read_info->stream.avail_in = (uInt)0;
979
980
981         s->pfile_in_zip_read = pfile_in_zip_read_info;
982     return UNZ_OK;
983 }
984
985
986 /*
987   Read bytes from the current file.
988   buf contain buffer where data must be copied
989   len the size of buf.
990
991   return the number of byte copied if somes bytes are copied
992   return 0 if the end of file was reached
993   return <0 with error code if there is an error
994     (UNZ_ERRNO for IO error, or zLib error for uncompress error)
995 */
996 extern int ZEXPORT unzReadCurrentFile  (file, buf, len)
997         unzFile file;
998         voidp buf;
999         unsigned len;
1000 {
1001         int err=UNZ_OK;
1002         uInt iRead = 0;
1003         unz_s* s;
1004         file_in_zip_read_info_s* pfile_in_zip_read_info;
1005         if (file==NULL)
1006                 return UNZ_PARAMERROR;
1007         s=(unz_s*)file;
1008     pfile_in_zip_read_info=s->pfile_in_zip_read;
1009
1010         if (pfile_in_zip_read_info==NULL)
1011                 return UNZ_PARAMERROR;
1012
1013
1014         if ((pfile_in_zip_read_info->read_buffer == NULL))
1015                 return UNZ_END_OF_LIST_OF_FILE;
1016         if (len==0)
1017                 return 0;
1018
1019         pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
1020
1021         pfile_in_zip_read_info->stream.avail_out = (uInt)len;
1022         
1023         if (len>pfile_in_zip_read_info->rest_read_uncompressed)
1024                 pfile_in_zip_read_info->stream.avail_out = 
1025                   (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
1026
1027         while (pfile_in_zip_read_info->stream.avail_out>0)
1028         {
1029                 if ((pfile_in_zip_read_info->stream.avail_in==0) &&
1030             (pfile_in_zip_read_info->rest_read_compressed>0))
1031                 {
1032                         uInt uReadThis = UNZ_BUFSIZE;
1033                         if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
1034                                 uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
1035                         if (uReadThis == 0)
1036                                 return UNZ_EOF;
1037                         if (fseek(pfile_in_zip_read_info->file,
1038                       pfile_in_zip_read_info->pos_in_zipfile + 
1039                          pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0)
1040                                 return UNZ_ERRNO;
1041                         if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1,
1042                          pfile_in_zip_read_info->file)!=1)
1043                                 return UNZ_ERRNO;
1044                         pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
1045
1046                         pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
1047                         
1048                         pfile_in_zip_read_info->stream.next_in = 
1049                 (Bytef*)pfile_in_zip_read_info->read_buffer;
1050                         pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
1051                 }
1052
1053                 if (pfile_in_zip_read_info->compression_method==0)
1054                 {
1055                         uInt uDoCopy,i ;
1056                         if (pfile_in_zip_read_info->stream.avail_out < 
1057                             pfile_in_zip_read_info->stream.avail_in)
1058                                 uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
1059                         else
1060                                 uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
1061                                 
1062                         for (i=0;i<uDoCopy;i++)
1063                                 *(pfile_in_zip_read_info->stream.next_out+i) =
1064                         *(pfile_in_zip_read_info->stream.next_in+i);
1065                                         
1066                         pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
1067                                                                 pfile_in_zip_read_info->stream.next_out,
1068                                                                 uDoCopy);
1069                         pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
1070                         pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
1071                         pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
1072                         pfile_in_zip_read_info->stream.next_out += uDoCopy;
1073                         pfile_in_zip_read_info->stream.next_in += uDoCopy;
1074             pfile_in_zip_read_info->stream.total_out += uDoCopy;
1075                         iRead += uDoCopy;
1076                 }
1077                 else
1078                 {
1079                         uLong uTotalOutBefore,uTotalOutAfter;
1080                         const Bytef *bufBefore;
1081                         uLong uOutThis;
1082                         int flush=Z_SYNC_FLUSH;
1083
1084                         uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
1085                         bufBefore = pfile_in_zip_read_info->stream.next_out;
1086
1087                         /*
1088                         if ((pfile_in_zip_read_info->rest_read_uncompressed ==
1089                                  pfile_in_zip_read_info->stream.avail_out) &&
1090                                 (pfile_in_zip_read_info->rest_read_compressed == 0))
1091                                 flush = Z_FINISH;
1092                         */
1093                         err=inflate(&pfile_in_zip_read_info->stream,flush);
1094
1095                         uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
1096                         uOutThis = uTotalOutAfter-uTotalOutBefore;
1097                         
1098                         pfile_in_zip_read_info->crc32 = 
1099                 crc32(pfile_in_zip_read_info->crc32,bufBefore,
1100                         (uInt)(uOutThis));
1101
1102                         pfile_in_zip_read_info->rest_read_uncompressed -=
1103                 uOutThis;
1104
1105                         iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
1106             
1107                         if (err==Z_STREAM_END)
1108                                 return (iRead==0) ? UNZ_EOF : iRead;
1109                         if (err!=Z_OK) 
1110                                 break;
1111                 }
1112         }
1113
1114         if (err==Z_OK)
1115                 return iRead;
1116         return err;
1117 }
1118
1119
1120 /*
1121   Give the current position in uncompressed data
1122 */
1123 extern z_off_t ZEXPORT unztell (file)
1124         unzFile file;
1125 {
1126         unz_s* s;
1127         file_in_zip_read_info_s* pfile_in_zip_read_info;
1128         if (file==NULL)
1129                 return UNZ_PARAMERROR;
1130         s=(unz_s*)file;
1131     pfile_in_zip_read_info=s->pfile_in_zip_read;
1132
1133         if (pfile_in_zip_read_info==NULL)
1134                 return UNZ_PARAMERROR;
1135
1136         return (z_off_t)pfile_in_zip_read_info->stream.total_out;
1137 }
1138
1139
1140 /*
1141   return 1 if the end of file was reached, 0 elsewhere 
1142 */
1143 extern int ZEXPORT unzeof (file)
1144         unzFile file;
1145 {
1146         unz_s* s;
1147         file_in_zip_read_info_s* pfile_in_zip_read_info;
1148         if (file==NULL)
1149                 return UNZ_PARAMERROR;
1150         s=(unz_s*)file;
1151     pfile_in_zip_read_info=s->pfile_in_zip_read;
1152
1153         if (pfile_in_zip_read_info==NULL)
1154                 return UNZ_PARAMERROR;
1155         
1156         if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
1157                 return 1;
1158         else
1159                 return 0;
1160 }
1161
1162
1163
1164 /*
1165   Read extra field from the current file (opened by unzOpenCurrentFile)
1166   This is the local-header version of the extra field (sometimes, there is
1167     more info in the local-header version than in the central-header)
1168
1169   if buf==NULL, it return the size of the local extra field that can be read
1170
1171   if buf!=NULL, len is the size of the buffer, the extra header is copied in
1172         buf.
1173   the return value is the number of bytes copied in buf, or (if <0) 
1174         the error code
1175 */
1176 extern int ZEXPORT unzGetLocalExtrafield (file,buf,len)
1177         unzFile file;
1178         voidp buf;
1179         unsigned len;
1180 {
1181         unz_s* s;
1182         file_in_zip_read_info_s* pfile_in_zip_read_info;
1183         uInt read_now;
1184         uLong size_to_read;
1185
1186         if (file==NULL)
1187                 return UNZ_PARAMERROR;
1188         s=(unz_s*)file;
1189     pfile_in_zip_read_info=s->pfile_in_zip_read;
1190
1191         if (pfile_in_zip_read_info==NULL)
1192                 return UNZ_PARAMERROR;
1193
1194         size_to_read = (pfile_in_zip_read_info->size_local_extrafield - 
1195                                 pfile_in_zip_read_info->pos_local_extrafield);
1196
1197         if (buf==NULL)
1198                 return (int)size_to_read;
1199         
1200         if (len>size_to_read)
1201                 read_now = (uInt)size_to_read;
1202         else
1203                 read_now = (uInt)len ;
1204
1205         if (read_now==0)
1206                 return 0;
1207         
1208         if (fseek(pfile_in_zip_read_info->file,
1209               pfile_in_zip_read_info->offset_local_extrafield + 
1210                           pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0)
1211                 return UNZ_ERRNO;
1212
1213         if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1)
1214                 return UNZ_ERRNO;
1215
1216         return (int)read_now;
1217 }
1218
1219 /*
1220   Close the file in zip opened with unzipOpenCurrentFile
1221   Return UNZ_CRCERROR if all the file was read but the CRC is not good
1222 */
1223 extern int ZEXPORT unzCloseCurrentFile (file)
1224         unzFile file;
1225 {
1226         int err=UNZ_OK;
1227
1228         unz_s* s;
1229         file_in_zip_read_info_s* pfile_in_zip_read_info;
1230         if (file==NULL)
1231                 return UNZ_PARAMERROR;
1232         s=(unz_s*)file;
1233     pfile_in_zip_read_info=s->pfile_in_zip_read;
1234
1235         if (pfile_in_zip_read_info==NULL)
1236                 return UNZ_PARAMERROR;
1237
1238
1239         if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
1240         {
1241                 if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
1242                         err=UNZ_CRCERROR;
1243         }
1244
1245
1246         TRYFREE(pfile_in_zip_read_info->read_buffer);
1247         pfile_in_zip_read_info->read_buffer = NULL;
1248         if (pfile_in_zip_read_info->stream_initialised)
1249                 inflateEnd(&pfile_in_zip_read_info->stream);
1250
1251         pfile_in_zip_read_info->stream_initialised = 0;
1252         TRYFREE(pfile_in_zip_read_info);
1253
1254     s->pfile_in_zip_read=NULL;
1255
1256         return err;
1257 }
1258
1259
1260 /*
1261   Get the global comment string of the ZipFile, in the szComment buffer.
1262   uSizeBuf is the size of the szComment buffer.
1263   return the number of byte copied or an error code <0
1264 */
1265 extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf)
1266         unzFile file;
1267         char *szComment;
1268         uLong uSizeBuf;
1269 {
1270         int err=UNZ_OK;
1271         unz_s* s;
1272         uLong uReadThis ;
1273         if (file==NULL)
1274                 return UNZ_PARAMERROR;
1275         s=(unz_s*)file;
1276
1277         uReadThis = uSizeBuf;
1278         if (uReadThis>s->gi.size_comment)
1279                 uReadThis = s->gi.size_comment;
1280
1281         if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0)
1282                 return UNZ_ERRNO;
1283
1284         if (uReadThis>0)
1285     {
1286       *szComment='\0';
1287           if (fread(szComment,(uInt)uReadThis,1,s->file)!=1)
1288                 return UNZ_ERRNO;
1289     }
1290
1291         if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
1292                 *(szComment+s->gi.size_comment)='\0';
1293         return (int)uReadThis;
1294 }