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