Better cacao_create_directoryList code and only add *.class files to the
[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     }
737   } while (unzGoToNextFile(file) == UNZ_OK);
738 }
739
740
741 /*
742   Try locate the file szFileName in the zipfile.
743   For the iCaseSensitivity signification, see unzipStringFileNameCompare
744
745   return value :
746   UNZ_OK if the file is found. It becomes the current file.
747   UNZ_END_OF_LIST_OF_FILE if the file is not found
748 */
749  int  unzLocateFile (file, szFileName, iCaseSensitivity)
750         unzFile file;
751         const char *szFileName;
752         int iCaseSensitivity;
753 {
754         unz_s* s;       
755         int err;
756
757         
758         uLong num_fileSaved;
759         uLong pos_in_central_dirSaved;
760
761         printf("Starting lookup\n");
762         fflush(stdout);
763
764         if (file==NULL)
765                 return UNZ_PARAMERROR;
766
767     if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
768         return UNZ_PARAMERROR;
769
770         s=(unz_s*)file;
771         if (!s->current_file_ok)
772                 return UNZ_END_OF_LIST_OF_FILE;
773
774         num_fileSaved = s->num_file;
775         pos_in_central_dirSaved = s->pos_in_central_dir;
776
777         err = unzGoToFirstFile(file);
778
779         while (err == UNZ_OK)
780         {
781                 char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
782                 unzGetCurrentFileInfo(file,NULL,
783                                                                 szCurrentFileName,sizeof(szCurrentFileName)-1,
784                                                                 NULL,0,NULL,0);
785                 if (unzStringFileNameCompare(szCurrentFileName,
786                                                                                 szFileName,iCaseSensitivity)==0) {
787                 printf("class found in zip directory\n");
788                 fflush(stdout);
789
790                         return UNZ_OK;
791                 }
792                 err = unzGoToNextFile(file);
793         }
794
795         s->num_file = num_fileSaved ;
796         s->pos_in_central_dir = pos_in_central_dirSaved ;
797         return err;
798 }
799
800 int cacao_locate(unzFile file, utf* filename)
801 {
802   unz_s         *s;
803   cacao_entry_s *ent;
804
805   s = (unz_s *) file;
806
807   for (ent = s->cacao_dir_list; ent; ent = ent->next) {
808     /*
809     printf("searching: ");utf_display(filename);
810     printf(" current: ");utf_display(ent->name);
811     printf("\n");
812     */
813     if (ent->name == filename) {
814       s->pos_in_central_dir = ent->pos;
815       return unzlocal_GetCurrentFileInfoInternal(file, &s->cur_file_info,
816                                                  &s->cur_file_info_internal,
817                                                  NULL, 0, NULL, 0, NULL, 0);
818     }
819   }
820
821   return UNZ_END_OF_LIST_OF_FILE;
822   /*return 0;*/
823 }
824
825
826 /*
827   Read the local header of the current zipfile
828   Check the coherency of the local header and info in the end of central
829         directory about this file
830   store in *piSizeVar the size of extra info in local header
831         (filename and size of extra field data)
832 */
833  int unzlocal_CheckCurrentFileCoherencyHeader (s,piSizeVar,
834                                                                                                         poffset_local_extrafield,
835                                                                                                         psize_local_extrafield)
836         unz_s* s;
837         uInt* piSizeVar;
838         uLong *poffset_local_extrafield;
839         uInt  *psize_local_extrafield;
840 {
841         uLong uMagic,uData,uFlags;
842         uLong size_filename;
843         uLong size_extra_field;
844         int err=UNZ_OK;
845
846         *piSizeVar = 0;
847         *poffset_local_extrafield = 0;
848         *psize_local_extrafield = 0;
849
850         if (fseek(s->file,s->cur_file_info_internal.offset_curfile +
851                                                                 s->byte_before_the_zipfile,SEEK_SET)!=0)
852                 return UNZ_ERRNO;
853
854
855         if (err==UNZ_OK) {
856                 if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK)
857                         err=UNZ_ERRNO;
858                 else if (uMagic!=0x04034b50)
859                         err=UNZ_BADZIPFILE;
860         }
861
862         if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
863                 err=UNZ_ERRNO;
864 /*
865         else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
866                 err=UNZ_BADZIPFILE;
867 */
868         if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK)
869                 err=UNZ_ERRNO;
870
871         if (unzlocal_getShort(s->file,&uData) != UNZ_OK)
872                 err=UNZ_ERRNO;
873         else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
874                 err=UNZ_BADZIPFILE;
875
876     if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
877                          (s->cur_file_info.compression_method!=Z_DEFLATED))
878         err=UNZ_BADZIPFILE;
879
880         if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */
881                 err=UNZ_ERRNO;
882
883         if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */
884                 err=UNZ_ERRNO;
885         else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&
886                                       ((uFlags & 8)==0))
887                 err=UNZ_BADZIPFILE;
888
889         if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */
890                 err=UNZ_ERRNO;
891         else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&
892                                                           ((uFlags & 8)==0))
893                 err=UNZ_BADZIPFILE;
894
895         if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */
896                 err=UNZ_ERRNO;
897         else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && 
898                                                           ((uFlags & 8)==0))
899                 err=UNZ_BADZIPFILE;
900
901
902         if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK)
903                 err=UNZ_ERRNO;
904         else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
905                 err=UNZ_BADZIPFILE;
906
907         *piSizeVar += (uInt)size_filename;
908
909         if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK)
910                 err=UNZ_ERRNO;
911         *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
912                                                                         SIZEZIPLOCALHEADER + size_filename;
913         *psize_local_extrafield = (uInt)size_extra_field;
914
915         *piSizeVar += (uInt)size_extra_field;
916
917         return err;
918 }
919                                                                                                 
920 /*
921   Open for reading data the current file in the zipfile.
922   If there is no error and the file is opened, the return value is UNZ_OK.
923 */
924  int  unzOpenCurrentFile (file)
925         unzFile file;
926 {
927         int err=UNZ_OK;
928         int Store;
929         uInt iSizeVar;
930         unz_s* s;
931         file_in_zip_read_info_s* pfile_in_zip_read_info;
932         uLong offset_local_extrafield;  /* offset of the local extra field */
933         uInt  size_local_extrafield;    /* size of the local extra field */
934
935         if (file==NULL)
936                 return UNZ_PARAMERROR;
937         s=(unz_s*)file;
938         if (!s->current_file_ok)
939                 return UNZ_PARAMERROR;
940
941     if (s->pfile_in_zip_read != NULL)
942         unzCloseCurrentFile(file);
943
944         if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,
945                                 &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
946                 return UNZ_BADZIPFILE;
947
948         pfile_in_zip_read_info = (file_in_zip_read_info_s*)
949                                                                             ALLOC(sizeof(file_in_zip_read_info_s));
950         if (pfile_in_zip_read_info==NULL)
951                 return UNZ_INTERNALERROR;
952
953         pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
954         pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
955         pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
956         pfile_in_zip_read_info->pos_local_extrafield=0;
957
958         if (pfile_in_zip_read_info->read_buffer==NULL)
959         {
960                 TRYFREE(pfile_in_zip_read_info);
961                 return UNZ_INTERNALERROR;
962         }
963
964         pfile_in_zip_read_info->stream_initialised=0;
965         
966         if ((s->cur_file_info.compression_method!=0) &&
967         (s->cur_file_info.compression_method!=Z_DEFLATED))
968                 err=UNZ_BADZIPFILE;
969         Store = s->cur_file_info.compression_method==0;
970
971         pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
972         pfile_in_zip_read_info->crc32=0;
973         pfile_in_zip_read_info->compression_method =
974             s->cur_file_info.compression_method;
975         pfile_in_zip_read_info->file=s->file;
976         pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
977
978     pfile_in_zip_read_info->stream.total_out = 0;
979
980         if (!Store)
981         {
982           pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
983           pfile_in_zip_read_info->stream.zfree = (free_func)0;
984           pfile_in_zip_read_info->stream.opaque = (voidpf)0; 
985       
986           err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
987           if (err == Z_OK)
988             pfile_in_zip_read_info->stream_initialised=1;
989         /* windowBits is passed < 0 to tell that there is no zlib header.
990          * Note that in this case inflate *requires* an extra "dummy" byte
991          * after the compressed stream in order to complete decompression and
992          * return Z_STREAM_END. 
993          * In unzip, i don't wait absolutely Z_STREAM_END because I known the 
994          * size of both compressed and uncompressed data
995          */
996         }
997         pfile_in_zip_read_info->rest_read_compressed = 
998             s->cur_file_info.compressed_size ;
999         pfile_in_zip_read_info->rest_read_uncompressed = 
1000             s->cur_file_info.uncompressed_size ;
1001
1002         
1003         pfile_in_zip_read_info->pos_in_zipfile = 
1004             s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + 
1005                           iSizeVar;
1006         
1007         pfile_in_zip_read_info->stream.avail_in = (uInt)0;
1008
1009
1010         s->pfile_in_zip_read = pfile_in_zip_read_info;
1011
1012     return UNZ_OK;
1013 }
1014
1015
1016 /*
1017   Read bytes from the current file.
1018   buf contain buffer where data must be copied
1019   len the size of buf.
1020
1021   return the number of byte copied if somes bytes are copied
1022   return 0 if the end of file was reached
1023   return <0 with error code if there is an error
1024     (UNZ_ERRNO for IO error, or zLib error for uncompress error)
1025 */
1026  int  unzReadCurrentFile  (file, buf, len)
1027         unzFile file;
1028         voidp buf;
1029         unsigned len;
1030 {
1031         int err=UNZ_OK;
1032         uInt iRead = 0;
1033         unz_s* s;
1034         file_in_zip_read_info_s* pfile_in_zip_read_info;
1035         if (file==NULL)
1036                 return UNZ_PARAMERROR;
1037         s=(unz_s*)file;
1038     pfile_in_zip_read_info=s->pfile_in_zip_read;
1039
1040         if (pfile_in_zip_read_info==NULL)
1041                 return UNZ_PARAMERROR;
1042
1043
1044         if ((pfile_in_zip_read_info->read_buffer == NULL))
1045                 return UNZ_END_OF_LIST_OF_FILE;
1046         if (len==0)
1047                 return 0;
1048
1049         pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
1050
1051         pfile_in_zip_read_info->stream.avail_out = (uInt)len;
1052         
1053         if (len>pfile_in_zip_read_info->rest_read_uncompressed)
1054                 pfile_in_zip_read_info->stream.avail_out = 
1055                   (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
1056
1057         while (pfile_in_zip_read_info->stream.avail_out>0)
1058         {
1059                 if ((pfile_in_zip_read_info->stream.avail_in==0) &&
1060             (pfile_in_zip_read_info->rest_read_compressed>0))
1061                 {
1062                         uInt uReadThis = UNZ_BUFSIZE;
1063                         if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
1064                                 uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
1065                         if (uReadThis == 0)
1066                                 return UNZ_EOF;
1067                         if (fseek(pfile_in_zip_read_info->file,
1068                       pfile_in_zip_read_info->pos_in_zipfile + 
1069                          pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0)
1070                                 return UNZ_ERRNO;
1071                         if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1,
1072                          pfile_in_zip_read_info->file)!=1)
1073                                 return UNZ_ERRNO;
1074                         pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
1075
1076                         pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
1077                         
1078                         pfile_in_zip_read_info->stream.next_in = 
1079                 (Bytef*)pfile_in_zip_read_info->read_buffer;
1080                         pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
1081                 }
1082
1083                 if (pfile_in_zip_read_info->compression_method==0)
1084                 {
1085                         uInt uDoCopy,i ;
1086                         if (pfile_in_zip_read_info->stream.avail_out < 
1087                             pfile_in_zip_read_info->stream.avail_in)
1088                                 uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
1089                         else
1090                                 uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
1091                                 
1092                         for (i=0;i<uDoCopy;i++)
1093                                 *(pfile_in_zip_read_info->stream.next_out+i) =
1094                         *(pfile_in_zip_read_info->stream.next_in+i);
1095                                         
1096                         pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
1097                                                                 pfile_in_zip_read_info->stream.next_out,
1098                                                                 uDoCopy);
1099                         pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
1100                         pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
1101                         pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
1102                         pfile_in_zip_read_info->stream.next_out += uDoCopy;
1103                         pfile_in_zip_read_info->stream.next_in += uDoCopy;
1104             pfile_in_zip_read_info->stream.total_out += uDoCopy;
1105                         iRead += uDoCopy;
1106                 }
1107                 else
1108                 {
1109                         uLong uTotalOutBefore,uTotalOutAfter;
1110                         const Bytef *bufBefore;
1111                         uLong uOutThis;
1112                         int flush=Z_SYNC_FLUSH;
1113
1114                         uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
1115                         bufBefore = pfile_in_zip_read_info->stream.next_out;
1116
1117                         /*
1118                         if ((pfile_in_zip_read_info->rest_read_uncompressed ==
1119                                  pfile_in_zip_read_info->stream.avail_out) &&
1120                                 (pfile_in_zip_read_info->rest_read_compressed == 0))
1121                                 flush = Z_FINISH;
1122                         */
1123                         err=inflate(&pfile_in_zip_read_info->stream,flush);
1124
1125                         uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
1126                         uOutThis = uTotalOutAfter-uTotalOutBefore;
1127                         
1128                         pfile_in_zip_read_info->crc32 = 
1129                 crc32(pfile_in_zip_read_info->crc32,bufBefore,
1130                         (uInt)(uOutThis));
1131
1132                         pfile_in_zip_read_info->rest_read_uncompressed -=
1133                 uOutThis;
1134
1135                         iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
1136             
1137                         if (err==Z_STREAM_END)
1138                                 return (iRead==0) ? UNZ_EOF : iRead;
1139                         if (err!=Z_OK) 
1140                                 break;
1141                 }
1142         }
1143
1144         if (err==Z_OK)
1145                 return iRead;
1146         return err;
1147 }
1148
1149
1150 /*
1151   Give the current position in uncompressed data
1152 */
1153  z_off_t  unztell (file)
1154         unzFile file;
1155 {
1156         unz_s* s;
1157         file_in_zip_read_info_s* pfile_in_zip_read_info;
1158         if (file==NULL)
1159                 return UNZ_PARAMERROR;
1160         s=(unz_s*)file;
1161     pfile_in_zip_read_info=s->pfile_in_zip_read;
1162
1163         if (pfile_in_zip_read_info==NULL)
1164                 return UNZ_PARAMERROR;
1165
1166         return (z_off_t)pfile_in_zip_read_info->stream.total_out;
1167 }
1168
1169
1170 /*
1171   return 1 if the end of file was reached, 0 elsewhere 
1172 */
1173  int  unzeof (file)
1174         unzFile file;
1175 {
1176         unz_s* s;
1177         file_in_zip_read_info_s* pfile_in_zip_read_info;
1178         if (file==NULL)
1179                 return UNZ_PARAMERROR;
1180         s=(unz_s*)file;
1181     pfile_in_zip_read_info=s->pfile_in_zip_read;
1182
1183         if (pfile_in_zip_read_info==NULL)
1184                 return UNZ_PARAMERROR;
1185         
1186         if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
1187                 return 1;
1188         else
1189                 return 0;
1190 }
1191
1192
1193
1194 /*
1195   Read extra field from the current file (opened by unzOpenCurrentFile)
1196   This is the local-header version of the extra field (sometimes, there is
1197     more info in the local-header version than in the central-header)
1198
1199   if buf==NULL, it return the size of the local extra field that can be read
1200
1201   if buf!=NULL, len is the size of the buffer, the extra header is copied in
1202         buf.
1203   the return value is the number of bytes copied in buf, or (if <0) 
1204         the error code
1205 */
1206  int  unzGetLocalExtrafield (file,buf,len)
1207         unzFile file;
1208         voidp buf;
1209         unsigned len;
1210 {
1211         unz_s* s;
1212         file_in_zip_read_info_s* pfile_in_zip_read_info;
1213         uInt read_now;
1214         uLong size_to_read;
1215
1216         if (file==NULL)
1217                 return UNZ_PARAMERROR;
1218         s=(unz_s*)file;
1219     pfile_in_zip_read_info=s->pfile_in_zip_read;
1220
1221         if (pfile_in_zip_read_info==NULL)
1222                 return UNZ_PARAMERROR;
1223
1224         size_to_read = (pfile_in_zip_read_info->size_local_extrafield - 
1225                                 pfile_in_zip_read_info->pos_local_extrafield);
1226
1227         if (buf==NULL)
1228                 return (int)size_to_read;
1229         
1230         if (len>size_to_read)
1231                 read_now = (uInt)size_to_read;
1232         else
1233                 read_now = (uInt)len ;
1234
1235         if (read_now==0)
1236                 return 0;
1237         
1238         if (fseek(pfile_in_zip_read_info->file,
1239               pfile_in_zip_read_info->offset_local_extrafield + 
1240                           pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0)
1241                 return UNZ_ERRNO;
1242
1243         if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1)
1244                 return UNZ_ERRNO;
1245
1246         return (int)read_now;
1247 }
1248
1249 /*
1250   Close the file in zip opened with unzipOpenCurrentFile
1251   Return UNZ_CRCERROR if all the file was read but the CRC is not good
1252 */
1253  int  unzCloseCurrentFile (file)
1254         unzFile file;
1255 {
1256         int err=UNZ_OK;
1257
1258         unz_s* s;
1259         file_in_zip_read_info_s* pfile_in_zip_read_info;
1260         if (file==NULL)
1261                 return UNZ_PARAMERROR;
1262         s=(unz_s*)file;
1263     pfile_in_zip_read_info=s->pfile_in_zip_read;
1264
1265         if (pfile_in_zip_read_info==NULL)
1266                 return UNZ_PARAMERROR;
1267
1268
1269         if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
1270         {
1271                 if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
1272                         err=UNZ_CRCERROR;
1273         }
1274
1275
1276         TRYFREE(pfile_in_zip_read_info->read_buffer);
1277         pfile_in_zip_read_info->read_buffer = NULL;
1278         if (pfile_in_zip_read_info->stream_initialised)
1279                 inflateEnd(&pfile_in_zip_read_info->stream);
1280
1281         pfile_in_zip_read_info->stream_initialised = 0;
1282         TRYFREE(pfile_in_zip_read_info);
1283
1284     s->pfile_in_zip_read=NULL;
1285
1286         return err;
1287 }
1288
1289
1290 /*
1291   Get the global comment string of the ZipFile, in the szComment buffer.
1292   uSizeBuf is the size of the szComment buffer.
1293   return the number of byte copied or an error code <0
1294 */
1295  int  unzGetGlobalComment (file, szComment, uSizeBuf)
1296         unzFile file;
1297         char *szComment;
1298         uLong uSizeBuf;
1299 {
1300   /* int err=UNZ_OK; */
1301         unz_s* s;
1302         uLong uReadThis ;
1303         if (file==NULL)
1304                 return UNZ_PARAMERROR;
1305         s=(unz_s*)file;
1306
1307         uReadThis = uSizeBuf;
1308         if (uReadThis>s->gi.size_comment)
1309                 uReadThis = s->gi.size_comment;
1310
1311         if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0)
1312                 return UNZ_ERRNO;
1313
1314         if (uReadThis>0)
1315     {
1316       *szComment='\0';
1317           if (fread(szComment,(uInt)uReadThis,1,s->file)!=1)
1318                 return UNZ_ERRNO;
1319     }
1320
1321         if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
1322                 *(szComment+s->gi.size_comment)='\0';
1323         return (int)uReadThis;
1324 }
1325
1326 #endif