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