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