d156fae5b1408c2c7ffa5271d0c4f7ea99e54b9d
[fceu.git] / 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         {
540                 if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
541                         err=UNZ_ERRNO;
542                 else if (uMagic!=0x02014b50)
543                         err=UNZ_BADZIPFILE;
544         }
545
546         if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK)
547                 err=UNZ_ERRNO;
548
549         if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK)
550                 err=UNZ_ERRNO;
551
552         if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK)
553                 err=UNZ_ERRNO;
554
555         if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK)
556                 err=UNZ_ERRNO;
557
558         if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK)
559                 err=UNZ_ERRNO;
560
561     unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
562
563         if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK)
564                 err=UNZ_ERRNO;
565
566         if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK)
567                 err=UNZ_ERRNO;
568
569         if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK)
570                 err=UNZ_ERRNO;
571
572         if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK)
573                 err=UNZ_ERRNO;
574
575         if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK)
576                 err=UNZ_ERRNO;
577
578         if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK)
579                 err=UNZ_ERRNO;
580
581         if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK)
582                 err=UNZ_ERRNO;
583
584         if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK)
585                 err=UNZ_ERRNO;
586
587         if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK)
588                 err=UNZ_ERRNO;
589
590         if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK)
591                 err=UNZ_ERRNO;
592
593         lSeek+=file_info.size_filename;
594         if ((err==UNZ_OK) && (szFileName!=NULL))
595         {
596                 uLong uSizeRead ;
597                 if (file_info.size_filename<fileNameBufferSize)
598                 {
599                         *(szFileName+file_info.size_filename)='\0';
600                         uSizeRead = file_info.size_filename;
601                 }
602                 else
603                         uSizeRead = fileNameBufferSize;
604
605                 if ((file_info.size_filename>0) && (fileNameBufferSize>0))
606                         if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1)
607                                 err=UNZ_ERRNO;
608                 lSeek -= uSizeRead;
609         }
610
611         
612         if ((err==UNZ_OK) && (extraField!=NULL))
613         {
614                 uLong uSizeRead ;
615                 if (file_info.size_file_extra<extraFieldBufferSize)
616                         uSizeRead = file_info.size_file_extra;
617                 else
618                         uSizeRead = extraFieldBufferSize;
619
620                 if (lSeek!=0)
621                 {
622                         if (fseek(s->file,lSeek,SEEK_CUR)==0)
623                                 lSeek=0;
624                         else
625                                 err=UNZ_ERRNO;
626                 }
627                 if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
628                         if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1)
629                                 err=UNZ_ERRNO;
630                 lSeek += file_info.size_file_extra - uSizeRead;
631         }
632         else
633                 lSeek+=file_info.size_file_extra; 
634
635         
636         if ((err==UNZ_OK) && (szComment!=NULL))
637         {
638                 uLong uSizeRead ;
639                 if (file_info.size_file_comment<commentBufferSize)
640                 {
641                         *(szComment+file_info.size_file_comment)='\0';
642                         uSizeRead = file_info.size_file_comment;
643                 }
644                 else
645                         uSizeRead = commentBufferSize;
646
647                 if (lSeek!=0)
648                 {
649                         if (fseek(s->file,lSeek,SEEK_CUR)==0)
650                                 lSeek=0;
651                         else
652                                 err=UNZ_ERRNO;
653                 }
654                 if ((file_info.size_file_comment>0) && (commentBufferSize>0))
655                         if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1)
656                                 err=UNZ_ERRNO;
657                 lSeek+=file_info.size_file_comment - uSizeRead;
658         }
659         else
660                 lSeek+=file_info.size_file_comment;
661
662         if ((err==UNZ_OK) && (pfile_info!=NULL))
663                 *pfile_info=file_info;
664
665         if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
666                 *pfile_info_internal=file_info_internal;
667
668         return err;
669 }
670
671
672
673 /*
674   Write info about the ZipFile in the *pglobal_info structure.
675   No preparation of the structure is needed
676   return UNZ_OK if there is no problem.
677 */
678 extern int ZEXPORT unzGetCurrentFileInfo (file,
679                                                   pfile_info,
680                                                   szFileName, fileNameBufferSize,
681                                                   extraField, extraFieldBufferSize,
682                                                   szComment,  commentBufferSize)
683         unzFile file;
684         unz_file_info *pfile_info;
685         char *szFileName;
686         uLong fileNameBufferSize;
687         void *extraField;
688         uLong extraFieldBufferSize;
689         char *szComment;
690         uLong commentBufferSize;
691 {
692         return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL,
693                                                                                                 szFileName,fileNameBufferSize,
694                                                                                                 extraField,extraFieldBufferSize,
695                                                                                                 szComment,commentBufferSize);
696 }
697
698 /*
699   Set the current file of the zipfile to the first file.
700   return UNZ_OK if there is no problem
701 */
702 extern int ZEXPORT unzGoToFirstFile (file)
703         unzFile file;
704 {
705         int err=UNZ_OK;
706         unz_s* s;
707         if (file==NULL)
708                 return UNZ_PARAMERROR;
709         s=(unz_s*)file;
710         s->pos_in_central_dir=s->offset_central_dir;
711         s->num_file=0;
712         err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
713                                                                                          &s->cur_file_info_internal,
714                                                                                          NULL,0,NULL,0,NULL,0);
715         s->current_file_ok = (err == UNZ_OK);
716         return err;
717 }
718
719
720 /*
721   Set the current file of the zipfile to the next file.
722   return UNZ_OK if there is no problem
723   return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
724 */
725 extern int ZEXPORT unzGoToNextFile (file)
726         unzFile file;
727 {
728         unz_s* s;       
729         int err;
730
731         if (file==NULL)
732                 return UNZ_PARAMERROR;
733         s=(unz_s*)file;
734         if (!s->current_file_ok)
735                 return UNZ_END_OF_LIST_OF_FILE;
736         if (s->num_file+1==s->gi.number_entry)
737                 return UNZ_END_OF_LIST_OF_FILE;
738
739         s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
740                         s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
741         s->num_file++;
742         err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
743                                                                                            &s->cur_file_info_internal,
744                                                                                            NULL,0,NULL,0,NULL,0);
745         s->current_file_ok = (err == UNZ_OK);
746         return err;
747 }
748
749
750 /*
751   Try locate the file szFileName in the zipfile.
752   For the iCaseSensitivity signification, see unzipStringFileNameCompare
753
754   return value :
755   UNZ_OK if the file is found. It becomes the current file.
756   UNZ_END_OF_LIST_OF_FILE if the file is not found
757 */
758 extern int ZEXPORT unzLocateFile (file, szFileName, iCaseSensitivity)
759         unzFile file;
760         const char *szFileName;
761         int iCaseSensitivity;
762 {
763         unz_s* s;       
764         int err;
765
766         
767         uLong num_fileSaved;
768         uLong pos_in_central_dirSaved;
769
770
771         if (file==NULL)
772                 return UNZ_PARAMERROR;
773
774     if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
775         return UNZ_PARAMERROR;
776
777         s=(unz_s*)file;
778         if (!s->current_file_ok)
779                 return UNZ_END_OF_LIST_OF_FILE;
780
781         num_fileSaved = s->num_file;
782         pos_in_central_dirSaved = s->pos_in_central_dir;
783
784         err = unzGoToFirstFile(file);
785
786         while (err == UNZ_OK)
787         {
788                 char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
789                 unzGetCurrentFileInfo(file,NULL,
790                                                                 szCurrentFileName,sizeof(szCurrentFileName)-1,
791                                                                 NULL,0,NULL,0);
792                 if (unzStringFileNameCompare(szCurrentFileName,
793                                                                                 szFileName,iCaseSensitivity)==0)
794                         return UNZ_OK;
795                 err = unzGoToNextFile(file);
796         }
797
798         s->num_file = num_fileSaved ;
799         s->pos_in_central_dir = pos_in_central_dirSaved ;
800         return err;
801 }
802
803
804 /*
805   Read the local header of the current zipfile
806   Check the coherency of the local header and info in the end of central
807         directory about this file
808   store in *piSizeVar the size of extra info in local header
809         (filename and size of extra field data)
810 */
811 local int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar,
812                                                                                                         poffset_local_extrafield,
813                                                                                                         psize_local_extrafield)
814         unz_s* s;
815         uInt* piSizeVar;
816         uLong *poffset_local_extrafield;
817         uInt  *psize_local_extrafield;
818 {
819         uLong uMagic,uData,uFlags;
820         uLong size_filename;
821         uLong size_extra_field;
822         int err=UNZ_OK;
823
824         *piSizeVar = 0;
825         *poffset_local_extrafield = 0;
826         *psize_local_extrafield = 0;
827
828         if (fseek(s->file,s->cur_file_info_internal.offset_curfile +
829                                                                 s->byte_before_the_zipfile,SEEK_SET)!=0)
830                 return UNZ_ERRNO;
831
832
833         if (err==UNZ_OK)
834         {       
835                 if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
836                         err=UNZ_ERRNO;
837                 else if (uMagic!=0x04034b50)
838                         err=UNZ_BADZIPFILE;
839         }
840
841         if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
842                 err=UNZ_ERRNO;
843 /*
844         else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
845                 err=UNZ_BADZIPFILE;
846 */
847         if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK)
848                 err=UNZ_ERRNO;
849
850         if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
851                 err=UNZ_ERRNO;
852         else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
853                 err=UNZ_BADZIPFILE;
854
855     if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
856                          (s->cur_file_info.compression_method!=Z_DEFLATED))
857         err=UNZ_BADZIPFILE;
858
859         if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */
860                 err=UNZ_ERRNO;
861
862         if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */
863                 err=UNZ_ERRNO;
864         else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&
865                                       ((uFlags & 8)==0))
866                 err=UNZ_BADZIPFILE;
867
868         if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */
869                 err=UNZ_ERRNO;
870         else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&
871                                                           ((uFlags & 8)==0))
872                 err=UNZ_BADZIPFILE;
873
874         if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */
875                 err=UNZ_ERRNO;
876         else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && 
877                                                           ((uFlags & 8)==0))
878                 err=UNZ_BADZIPFILE;
879
880
881         if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK)
882                 err=UNZ_ERRNO;
883         else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
884                 err=UNZ_BADZIPFILE;
885
886         *piSizeVar += (uInt)size_filename;
887
888         if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK)
889                 err=UNZ_ERRNO;
890         *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
891                                                                         SIZEZIPLOCALHEADER + size_filename;
892         *psize_local_extrafield = (uInt)size_extra_field;
893
894         *piSizeVar += (uInt)size_extra_field;
895
896         return err;
897 }
898                                                                                                 
899 /*
900   Open for reading data the current file in the zipfile.
901   If there is no error and the file is opened, the return value is UNZ_OK.
902 */
903 extern int ZEXPORT unzOpenCurrentFile (file)
904         unzFile file;
905 {
906         int err=UNZ_OK;
907         int Store;
908         uInt iSizeVar;
909         unz_s* s;
910         file_in_zip_read_info_s* pfile_in_zip_read_info;
911         uLong offset_local_extrafield;  /* offset of the local extra field */
912         uInt  size_local_extrafield;    /* size of the local extra field */
913
914         if (file==NULL)
915                 return UNZ_PARAMERROR;
916         s=(unz_s*)file;
917         if (!s->current_file_ok)
918                 return UNZ_PARAMERROR;
919
920     if (s->pfile_in_zip_read != NULL)
921         unzCloseCurrentFile(file);
922
923         if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,
924                                 &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
925                 return UNZ_BADZIPFILE;
926
927         pfile_in_zip_read_info = (file_in_zip_read_info_s*)
928                                                                             ALLOC(sizeof(file_in_zip_read_info_s));
929         if (pfile_in_zip_read_info==NULL)
930                 return UNZ_INTERNALERROR;
931
932         pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
933         pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
934         pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
935         pfile_in_zip_read_info->pos_local_extrafield=0;
936
937         if (pfile_in_zip_read_info->read_buffer==NULL)
938         {
939                 TRYFREE(pfile_in_zip_read_info);
940                 return UNZ_INTERNALERROR;
941         }
942
943         pfile_in_zip_read_info->stream_initialised=0;
944         
945         if ((s->cur_file_info.compression_method!=0) &&
946         (s->cur_file_info.compression_method!=Z_DEFLATED))
947                 err=UNZ_BADZIPFILE;
948         Store = s->cur_file_info.compression_method==0;
949
950         pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
951         pfile_in_zip_read_info->crc32=0;
952         pfile_in_zip_read_info->compression_method =
953             s->cur_file_info.compression_method;
954         pfile_in_zip_read_info->file=s->file;
955         pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
956
957     pfile_in_zip_read_info->stream.total_out = 0;
958
959         if (!Store)
960         {
961           pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
962           pfile_in_zip_read_info->stream.zfree = (free_func)0;
963           pfile_in_zip_read_info->stream.opaque = (voidpf)0; 
964       
965           err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
966           if (err == Z_OK)
967             pfile_in_zip_read_info->stream_initialised=1;
968         /* windowBits is passed < 0 to tell that there is no zlib header.
969          * Note that in this case inflate *requires* an extra "dummy" byte
970          * after the compressed stream in order to complete decompression and
971          * return Z_STREAM_END. 
972          * In unzip, i don't wait absolutely Z_STREAM_END because I known the 
973          * size of both compressed and uncompressed data
974          */
975         }
976         pfile_in_zip_read_info->rest_read_compressed = 
977             s->cur_file_info.compressed_size ;
978         pfile_in_zip_read_info->rest_read_uncompressed = 
979             s->cur_file_info.uncompressed_size ;
980
981         
982         pfile_in_zip_read_info->pos_in_zipfile = 
983             s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + 
984                           iSizeVar;
985         
986         pfile_in_zip_read_info->stream.avail_in = (uInt)0;
987
988
989         s->pfile_in_zip_read = pfile_in_zip_read_info;
990     return UNZ_OK;
991 }
992
993
994 /*
995   Read bytes from the current file.
996   buf contain buffer where data must be copied
997   len the size of buf.
998
999   return the number of byte copied if somes bytes are copied
1000   return 0 if the end of file was reached
1001   return <0 with error code if there is an error
1002     (UNZ_ERRNO for IO error, or zLib error for uncompress error)
1003 */
1004 extern int ZEXPORT unzReadCurrentFile  (file, buf, len)
1005         unzFile file;
1006         voidp buf;
1007         unsigned len;
1008 {
1009         int err=UNZ_OK;
1010         uInt iRead = 0;
1011         unz_s* s;
1012         file_in_zip_read_info_s* pfile_in_zip_read_info;
1013         if (file==NULL)
1014                 return UNZ_PARAMERROR;
1015         s=(unz_s*)file;
1016     pfile_in_zip_read_info=s->pfile_in_zip_read;
1017
1018         if (pfile_in_zip_read_info==NULL)
1019                 return UNZ_PARAMERROR;
1020
1021
1022         if ((pfile_in_zip_read_info->read_buffer == NULL))
1023                 return UNZ_END_OF_LIST_OF_FILE;
1024         if (len==0)
1025                 return 0;
1026
1027         pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
1028
1029         pfile_in_zip_read_info->stream.avail_out = (uInt)len;
1030         
1031         if (len>pfile_in_zip_read_info->rest_read_uncompressed)
1032                 pfile_in_zip_read_info->stream.avail_out = 
1033                   (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
1034
1035         while (pfile_in_zip_read_info->stream.avail_out>0)
1036         {
1037                 if ((pfile_in_zip_read_info->stream.avail_in==0) &&
1038             (pfile_in_zip_read_info->rest_read_compressed>0))
1039                 {
1040                         uInt uReadThis = UNZ_BUFSIZE;
1041                         if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
1042                                 uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
1043                         if (uReadThis == 0)
1044                                 return UNZ_EOF;
1045                         if (fseek(pfile_in_zip_read_info->file,
1046                       pfile_in_zip_read_info->pos_in_zipfile + 
1047                          pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0)
1048                                 return UNZ_ERRNO;
1049                         if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1,
1050                          pfile_in_zip_read_info->file)!=1)
1051                                 return UNZ_ERRNO;
1052                         pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
1053
1054                         pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
1055                         
1056                         pfile_in_zip_read_info->stream.next_in = 
1057                 (Bytef*)pfile_in_zip_read_info->read_buffer;
1058                         pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
1059                 }
1060
1061                 if (pfile_in_zip_read_info->compression_method==0)
1062                 {
1063                         uInt uDoCopy,i ;
1064                         if (pfile_in_zip_read_info->stream.avail_out < 
1065                             pfile_in_zip_read_info->stream.avail_in)
1066                                 uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
1067                         else
1068                                 uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
1069                                 
1070                         for (i=0;i<uDoCopy;i++)
1071                                 *(pfile_in_zip_read_info->stream.next_out+i) =
1072                         *(pfile_in_zip_read_info->stream.next_in+i);
1073                                         
1074                         pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
1075                                                                 pfile_in_zip_read_info->stream.next_out,
1076                                                                 uDoCopy);
1077                         pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
1078                         pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
1079                         pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
1080                         pfile_in_zip_read_info->stream.next_out += uDoCopy;
1081                         pfile_in_zip_read_info->stream.next_in += uDoCopy;
1082             pfile_in_zip_read_info->stream.total_out += uDoCopy;
1083                         iRead += uDoCopy;
1084                 }
1085                 else
1086                 {
1087                         uLong uTotalOutBefore,uTotalOutAfter;
1088                         const Bytef *bufBefore;
1089                         uLong uOutThis;
1090                         int flush=Z_SYNC_FLUSH;
1091
1092                         uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
1093                         bufBefore = pfile_in_zip_read_info->stream.next_out;
1094
1095                         /*
1096                         if ((pfile_in_zip_read_info->rest_read_uncompressed ==
1097                                  pfile_in_zip_read_info->stream.avail_out) &&
1098                                 (pfile_in_zip_read_info->rest_read_compressed == 0))
1099                                 flush = Z_FINISH;
1100                         */
1101                         err=inflate(&pfile_in_zip_read_info->stream,flush);
1102
1103                         uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
1104                         uOutThis = uTotalOutAfter-uTotalOutBefore;
1105                         
1106                         pfile_in_zip_read_info->crc32 = 
1107                 crc32(pfile_in_zip_read_info->crc32,bufBefore,
1108                         (uInt)(uOutThis));
1109
1110                         pfile_in_zip_read_info->rest_read_uncompressed -=
1111                 uOutThis;
1112
1113                         iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
1114             
1115                         if (err==Z_STREAM_END)
1116                                 return (iRead==0) ? UNZ_EOF : iRead;
1117                         if (err!=Z_OK) 
1118                                 break;
1119                 }
1120         }
1121
1122         if (err==Z_OK)
1123                 return iRead;
1124         return err;
1125 }
1126
1127
1128 /*
1129   Give the current position in uncompressed data
1130 */
1131 extern z_off_t ZEXPORT unztell (file)
1132         unzFile file;
1133 {
1134         unz_s* s;
1135         file_in_zip_read_info_s* pfile_in_zip_read_info;
1136         if (file==NULL)
1137                 return UNZ_PARAMERROR;
1138         s=(unz_s*)file;
1139     pfile_in_zip_read_info=s->pfile_in_zip_read;
1140
1141         if (pfile_in_zip_read_info==NULL)
1142                 return UNZ_PARAMERROR;
1143
1144         return (z_off_t)pfile_in_zip_read_info->stream.total_out;
1145 }
1146
1147
1148 /*
1149   return 1 if the end of file was reached, 0 elsewhere 
1150 */
1151 extern int ZEXPORT unzeof (file)
1152         unzFile file;
1153 {
1154         unz_s* s;
1155         file_in_zip_read_info_s* pfile_in_zip_read_info;
1156         if (file==NULL)
1157                 return UNZ_PARAMERROR;
1158         s=(unz_s*)file;
1159     pfile_in_zip_read_info=s->pfile_in_zip_read;
1160
1161         if (pfile_in_zip_read_info==NULL)
1162                 return UNZ_PARAMERROR;
1163         
1164         if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
1165                 return 1;
1166         else
1167                 return 0;
1168 }
1169
1170
1171
1172 /*
1173   Read extra field from the current file (opened by unzOpenCurrentFile)
1174   This is the local-header version of the extra field (sometimes, there is
1175     more info in the local-header version than in the central-header)
1176
1177   if buf==NULL, it return the size of the local extra field that can be read
1178
1179   if buf!=NULL, len is the size of the buffer, the extra header is copied in
1180         buf.
1181   the return value is the number of bytes copied in buf, or (if <0) 
1182         the error code
1183 */
1184 extern int ZEXPORT unzGetLocalExtrafield (file,buf,len)
1185         unzFile file;
1186         voidp buf;
1187         unsigned len;
1188 {
1189         unz_s* s;
1190         file_in_zip_read_info_s* pfile_in_zip_read_info;
1191         uInt read_now;
1192         uLong size_to_read;
1193
1194         if (file==NULL)
1195                 return UNZ_PARAMERROR;
1196         s=(unz_s*)file;
1197     pfile_in_zip_read_info=s->pfile_in_zip_read;
1198
1199         if (pfile_in_zip_read_info==NULL)
1200                 return UNZ_PARAMERROR;
1201
1202         size_to_read = (pfile_in_zip_read_info->size_local_extrafield - 
1203                                 pfile_in_zip_read_info->pos_local_extrafield);
1204
1205         if (buf==NULL)
1206                 return (int)size_to_read;
1207         
1208         if (len>size_to_read)
1209                 read_now = (uInt)size_to_read;
1210         else
1211                 read_now = (uInt)len ;
1212
1213         if (read_now==0)
1214                 return 0;
1215         
1216         if (fseek(pfile_in_zip_read_info->file,
1217               pfile_in_zip_read_info->offset_local_extrafield + 
1218                           pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0)
1219                 return UNZ_ERRNO;
1220
1221         if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1)
1222                 return UNZ_ERRNO;
1223
1224         return (int)read_now;
1225 }
1226
1227 /*
1228   Close the file in zip opened with unzipOpenCurrentFile
1229   Return UNZ_CRCERROR if all the file was read but the CRC is not good
1230 */
1231 extern int ZEXPORT unzCloseCurrentFile (file)
1232         unzFile file;
1233 {
1234         int err=UNZ_OK;
1235
1236         unz_s* s;
1237         file_in_zip_read_info_s* pfile_in_zip_read_info;
1238         if (file==NULL)
1239                 return UNZ_PARAMERROR;
1240         s=(unz_s*)file;
1241     pfile_in_zip_read_info=s->pfile_in_zip_read;
1242
1243         if (pfile_in_zip_read_info==NULL)
1244                 return UNZ_PARAMERROR;
1245
1246
1247         if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
1248         {
1249                 if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
1250                         err=UNZ_CRCERROR;
1251         }
1252
1253
1254         TRYFREE(pfile_in_zip_read_info->read_buffer);
1255         pfile_in_zip_read_info->read_buffer = NULL;
1256         if (pfile_in_zip_read_info->stream_initialised)
1257                 inflateEnd(&pfile_in_zip_read_info->stream);
1258
1259         pfile_in_zip_read_info->stream_initialised = 0;
1260         TRYFREE(pfile_in_zip_read_info);
1261
1262     s->pfile_in_zip_read=NULL;
1263
1264         return err;
1265 }
1266
1267
1268 /*
1269   Get the global comment string of the ZipFile, in the szComment buffer.
1270   uSizeBuf is the size of the szComment buffer.
1271   return the number of byte copied or an error code <0
1272 */
1273 extern int ZEXPORT unzGetGlobalComment (file, szComment, uSizeBuf)
1274         unzFile file;
1275         char *szComment;
1276         uLong uSizeBuf;
1277 {
1278         unz_s* s;
1279         uLong uReadThis ;
1280         if (file==NULL)
1281                 return UNZ_PARAMERROR;
1282         s=(unz_s*)file;
1283
1284         uReadThis = uSizeBuf;
1285         if (uReadThis>s->gi.size_comment)
1286                 uReadThis = s->gi.size_comment;
1287
1288         if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0)
1289                 return UNZ_ERRNO;
1290
1291         if (uReadThis>0)
1292     {
1293       *szComment='\0';
1294           if (fread(szComment,(uInt)uReadThis,1,s->file)!=1)
1295                 return UNZ_ERRNO;
1296     }
1297
1298         if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
1299                 *(szComment+s->gi.size_comment)='\0';
1300         return (int)uReadThis;
1301 }