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