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