1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 /* unzip.c -- IO on .zip files using zlib
24    Version 0.15 beta, Mar 19th, 1998,
25 
26    Read unzip.h for more info
27 */
28 
29 /* unzip.h -- IO for uncompress .zip files using zlib
30    Version 0.15 beta, Mar 19th, 1998,
31 
32    Copyright (C) 1998 Gilles Vollant
33 
34    This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
35      WinZip, InfoZip tools and compatible.
36    Encryption and multi volume ZipFile (span) are not supported.
37    Old compressions used by old PKZip 1.x are not supported
38 
39    THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE
40    CAN CHANGE IN FUTURE VERSION !!
41    I WAIT FEEDBACK at mail info@winimage.com
42    Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
43 
44    Condition of use and distribution are the same than zlib :
45 
46   This software is provided 'as-is', without any express or implied
47   warranty.  In no event will the authors be held liable for any damages
48   arising from the use of this software.
49 
50   Permission is granted to anyone to use this software for any purpose,
51   including commercial applications, and to alter it and redistribute it
52   freely, subject to the following restrictions:
53 
54   1. The origin of this software must not be misrepresented; you must not
55      claim that you wrote the original software. If you use this software
56      in a product, an acknowledgment in the product documentation would be
57      appreciated but is not required.
58   2. Altered source versions must be plainly marked as such, and must not be
59      misrepresented as being the original software.
60   3. This notice may not be removed or altered from any source distribution.
61 
62 
63 */
64 /* for more info about .ZIP format, see
65       ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
66    PkWare has also a specification at :
67       ftp://ftp.pkware.com/probdesc.zip */
68 
69 // Disable symbol overrides so that we can use zlib.h
70 #define FORBIDDEN_SYMBOL_ALLOW_ALL
71 
72 #include "common/scummsys.h"
73 
74 #ifdef USE_ZLIB
75 
76 #ifdef __SYMBIAN32__
77 #include <zlib\zlib.h>
78 #else
79 #include <zlib.h>
80 #endif
81 
82 #else  // !USE_ZLIB
83 
84 // Even when zlib is not linked in, we can still open ZIP archives and read
85 // uncompressed files from them.  Attempted decompression of compressed files
86 // will result in an error.
87 //
88 // Define the constants and types used by zlib.
89 #define Z_ERRNO -1
90 #define Z_OK 0
91 #define Z_DEFLATED 8
92 typedef void *voidp;
93 typedef unsigned int uInt;
94 typedef unsigned long uLong;
95 typedef long z_off_t;
96 typedef unsigned char Byte;
97 typedef Byte Bytef;
98 typedef struct {
99 	Bytef    *next_in, *next_out;
100 	uInt     avail_in, avail_out;
101 	uLong    total_out;
102 } z_stream;
103 
104 #endif  // !USE_ZLIB
105 
106 #include "common/fs.h"
107 #include "common/unzip.h"
108 #include "common/memstream.h"
109 
110 #include "common/hashmap.h"
111 #include "common/hash-str.h"
112 
113 #if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
114 /* like the STRICT of WIN32, we define a pointer that cannot be converted
115     from (void *) without cast */
116 typedef struct TagunzFile__ { int unused; } unzFile__;
117 typedef unzFile__ *unzFile;
118 #else
119 typedef voidp unzFile;
120 #endif
121 
122 #define UNZ_OK                                  (0)
123 #define UNZ_END_OF_LIST_OF_FILE (-100)
124 #define UNZ_ERRNO               (Z_ERRNO)
125 #define UNZ_EOF                 (0)
126 #define UNZ_PARAMERROR                  (-102)
127 #define UNZ_BADZIPFILE                  (-103)
128 #define UNZ_INTERNALERROR               (-104)
129 #define UNZ_CRCERROR                    (-105)
130 
131 /* tm_unz contain date/time info */
132 typedef struct {
133 	uInt tm_sec;            /* seconds after the minute - [0,59] */
134 	uInt tm_min;            /* minutes after the hour - [0,59] */
135 	uInt tm_hour;           /* hours since midnight - [0,23] */
136 	uInt tm_mday;           /* day of the month - [1,31] */
137 	uInt tm_mon;            /* months since January - [0,11] */
138 	uInt tm_year;           /* years - [1980..2044] */
139 } tm_unz;
140 
141 /* unz_global_info structure contain global data about the ZIPfile
142    These data comes from the end of central dir */
143 typedef struct {
144 	uLong number_entry;         /* total number of entries in
145 				       the central dir on this disk */
146 	uLong size_comment;         /* size of the global comment of the zipfile */
147 } unz_global_info;
148 
149 
150 /* unz_file_info contain information about a file in the zipfile */
151 typedef struct {
152 	uLong version;              /* version made by                 2 bytes */
153 	uLong version_needed;       /* version needed to extract       2 bytes */
154 	uLong flag;                 /* general purpose bit flag        2 bytes */
155 	uLong compression_method;   /* compression method              2 bytes */
156 	uLong dosDate;              /* last mod file date in Dos fmt   4 bytes */
157 	uLong crc;                  /* crc-32                          4 bytes */
158 	uLong compressed_size;      /* compressed size                 4 bytes */
159 	uLong uncompressed_size;    /* uncompressed size               4 bytes */
160 	uLong size_filename;        /* filename length                 2 bytes */
161 	uLong size_file_extra;      /* extra field length              2 bytes */
162 	uLong size_file_comment;    /* file comment length             2 bytes */
163 
164 	uLong disk_num_start;       /* disk number start               2 bytes */
165 	uLong internal_fa;          /* internal file attributes        2 bytes */
166 	uLong external_fa;          /* external file attributes        4 bytes */
167 
168 	tm_unz tmu_date;
169 } unz_file_info;
170 
171 int unzStringFileNameCompare(const char* fileName1,
172 												 const char* fileName2,
173 												 int iCaseSensitivity);
174 /*
175    Compare two filename (fileName1,fileName2).
176    If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
177    If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
178 								or strcasecmp)
179    If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
180 	(like 1 on Unix, 2 on Windows)
181 */
182 
183 
184 /*
185   Open a Zip file. path contain the full pathname (by example,
186 	 on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
187 	 "zlib/zlib111.zip".
188 	 If the zipfile cannot be opened (file don't exist or in not valid), the
189 	   return value is NULL.
190 	 Else, the return value is a unzFile Handle, usable with other function
191 	   of this unzip package.
192 */
193 
194 int unzClose(unzFile file);
195 /*
196   Close a ZipFile opened with unzipOpen.
197   If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
198 	these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
199   return UNZ_OK if there is no problem. */
200 
201 int unzGetGlobalInfo(unzFile file,
202 					unz_global_info *pglobal_info);
203 /*
204   Write info about the ZipFile in the *pglobal_info structure.
205   No preparation of the structure is needed
206   return UNZ_OK if there is no problem. */
207 
208 
209 int unzGetGlobalComment(unzFile file, char *szComment, uLong uSizeBuf);
210 /*
211   Get the global comment string of the ZipFile, in the szComment buffer.
212   uSizeBuf is the size of the szComment buffer.
213   return the number of byte copied or an error code <0
214 */
215 
216 
217 /***************************************************************************/
218 /* Unzip package allow you browse the directory of the zipfile */
219 
220 int unzGoToFirstFile(unzFile file);
221 /*
222   Set the current file of the zipfile to the first file.
223   return UNZ_OK if there is no problem
224 */
225 
226 int unzGoToNextFile(unzFile file);
227 /*
228   Set the current file of the zipfile to the next file.
229   return UNZ_OK if there is no problem
230   return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
231 */
232 
233 int unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity);
234 /*
235   Try locate the file szFileName in the zipfile.
236   For the iCaseSensitivity signification, see unzStringFileNameCompare
237 
238   return value :
239   UNZ_OK if the file is found. It becomes the current file.
240   UNZ_END_OF_LIST_OF_FILE if the file is not found
241 */
242 
243 
244 int unzGetCurrentFileInfo(unzFile file,
245 					     unz_file_info *pfile_info,
246 					     char *szFileName,
247 					     uLong fileNameBufferSize,
248 					     void *extraField,
249 					     uLong extraFieldBufferSize,
250 					     char *szComment,
251 					     uLong commentBufferSize);
252 /*
253   Get Info about the current file
254   if pfile_info!=NULL, the *pfile_info structure will contain somes info about
255 	    the current file
256   if szFileName!=NULL, the filemane string will be copied in szFileName
257 			(fileNameBufferSize is the size of the buffer)
258   if extraField!=NULL, the extra field information will be copied in extraField
259 			(extraFieldBufferSize is the size of the buffer).
260 			This is the Central-header version of the extra field
261   if szComment!=NULL, the comment string of the file will be copied in szComment
262 			(commentBufferSize is the size of the buffer)
263 */
264 
265 /***************************************************************************/
266 /* for reading the content of the current zipfile, you can open it, read data
267    from it, and close it (you can close it before reading all the file)
268    */
269 
270 int unzOpenCurrentFile(unzFile file);
271 /*
272   Open for reading data the current file in the zipfile.
273   If there is no error, the return value is UNZ_OK.
274 */
275 
276 int unzCloseCurrentFile(unzFile file);
277 /*
278   Close the file in zip opened with unzOpenCurrentFile
279   Return UNZ_CRCERROR if all the file was read but the CRC is not good
280 */
281 
282 
283 int unzReadCurrentFile(unzFile file, voidp buf, unsigned len);
284 /*
285   Read bytes from the current file (opened by unzOpenCurrentFile)
286   buf contain buffer where data must be copied
287   len the size of buf.
288 
289   return the number of byte copied if somes bytes are copied
290   return 0 if the end of file was reached
291   return <0 with error code if there is an error
292 	(UNZ_ERRNO for IO error, or zLib error for uncompress error)
293 */
294 
295 z_off_t unztell(unzFile file);
296 /*
297   Give the current position in uncompressed data
298 */
299 
300 int unzeof(unzFile file);
301 /*
302   return 1 if the end of file was reached, 0 elsewhere
303 */
304 
305 int unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len);
306 /*
307   Read extra field from the current file (opened by unzOpenCurrentFile)
308   This is the local-header version of the extra field (sometimes, there is
309 	more info in the local-header version than in the central-header)
310 
311   if buf==NULL, it return the size of the local extra field
312 
313   if buf!=NULL, len is the size of the buffer, the extra header is copied in
314 	buf.
315   the return value is the number of bytes copied in buf, or (if <0)
316 	the error code
317 */
318 
319 #if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \
320 					  !defined(CASESENSITIVITYDEFAULT_NO)
321 #define CASESENSITIVITYDEFAULT_NO
322 #endif
323 
324 
325 #ifndef UNZ_BUFSIZE
326 #define UNZ_BUFSIZE (16384)
327 #endif
328 
329 #ifndef UNZ_MAXFILENAMEINZIP
330 #define UNZ_MAXFILENAMEINZIP (256)
331 #endif
332 
333 #define SIZECENTRALDIRITEM (0x2e)
334 #define SIZEZIPLOCALHEADER (0x1e)
335 
336 
337 #if 0
338 const char unz_copyright[] =
339    " unzip 0.15 Copyright 1998 Gilles Vollant ";
340 #endif
341 
342 /* unz_file_info_interntal contain internal info about a file in zipfile*/
343 typedef struct {
344 	uLong offset_curfile;/* relative offset of local header 4 bytes */
345 } unz_file_info_internal;
346 
347 
348 /* file_in_zip_read_info_s contain internal information about a file in zipfile,
349 	when reading and decompress it */
350 typedef struct {
351 	char  *read_buffer;         /* internal buffer for compressed data */
352 	z_stream stream;            /* zLib stream structure for inflate */
353 
354 	uLong pos_in_zipfile;       /* position in byte on the zipfile, for fseek*/
355 	uLong stream_initialized;   /* flag set if stream structure is initialized*/
356 
357 	uLong offset_local_extrafield;/* offset of the local extra field */
358 	uInt  size_local_extrafield;/* size of the local extra field */
359 	uLong pos_local_extrafield;   /* position in the local extra field in read*/
360 
361 	uLong crc32_data;                /* crc32 of all data uncompressed */
362 	uLong crc32_wait;           /* crc32 we must obtain after decompress all */
363 	uLong rest_read_compressed; /* number of byte to be decompressed */
364 	uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/
365 	Common::SeekableReadStream *_stream;                 /* io structore of the zipfile */
366 	uLong compression_method;   /* compression method (0==store) */
367 	uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
368 } file_in_zip_read_info_s;
369 
370 typedef struct {
371 	uLong num_file;					/* number of the current file in the zipfile*/
372 	uLong pos_in_central_dir;		/* pos of the current file in the central dir*/
373 	uLong current_file_ok;			/* flag about the usability of the current file*/
374 	unz_file_info cur_file_info;					/* public info about the current file in zip*/
375 	unz_file_info_internal cur_file_info_internal;	/* private info about it*/
376 } cached_file_in_zip;
377 
378 typedef Common::HashMap<Common::String, cached_file_in_zip, Common::IgnoreCase_Hash,
379 	Common::IgnoreCase_EqualTo> ZipHash;
380 
381 /* unz_s contain internal information about the zipfile
382 */
383 typedef struct {
384 	Common::SeekableReadStream *_stream;				/* io structore of the zipfile */
385 	unz_global_info gi;				/* public global information */
386 	uLong byte_before_the_zipfile;	/* byte before the zipfile, (>0 for sfx)*/
387 	uLong num_file;					/* number of the current file in the zipfile*/
388 	uLong pos_in_central_dir;		/* pos of the current file in the central dir*/
389 	uLong current_file_ok;			/* flag about the usability of the current file*/
390 	uLong central_pos;				/* position of the beginning of the central dir*/
391 
392 	uLong size_central_dir;			/* size of the central directory  */
393 	uLong offset_central_dir;		/* offset of start of central directory with
394 									respect to the starting disk number */
395 
396 	unz_file_info cur_file_info;					/* public info about the current file in zip*/
397 	unz_file_info_internal cur_file_info_internal;	/* private info about it*/
398 	file_in_zip_read_info_s* pfile_in_zip_read;		/* structure about the current
399 													file if we are decompressing it */
400 	ZipHash _hash;
401 } unz_s;
402 
403 /* ===========================================================================
404 	 Read a byte from a gz_stream; update next_in and avail_in. Return EOF
405    for end of file.
406    IN assertion: the stream s has been successfully opened for reading.
407 */
408 
409 
410 /*static int unzlocal_getByte(Common::SeekableReadStream &fin, int *pi) {
411 	unsigned char c = fin.readByte();
412 	  *pi = (int)c;
413 		return UNZ_OK;
414 	} else {
415 		if (fin.err())
416 			return UNZ_ERRNO;
417 		else
418 			return UNZ_EOF;
419 	}
420 }*/
421 
422 
423 /* ===========================================================================
424    Reads a long in LSB order from the given gz_stream. Sets
425 */
unzlocal_getShort(Common::SeekableReadStream * fin,uLong * pX)426 static int unzlocal_getShort(Common::SeekableReadStream *fin, uLong *pX) {
427 	*pX = fin->readUint16LE();
428 	return (fin->err() || fin->eos()) ? UNZ_ERRNO : UNZ_OK;
429 }
430 
unzlocal_getLong(Common::SeekableReadStream * fin,uLong * pX)431 static int unzlocal_getLong(Common::SeekableReadStream *fin, uLong *pX) {
432 	*pX = fin->readUint32LE();
433 	return (fin->err() || fin->eos()) ? UNZ_ERRNO : UNZ_OK;
434 }
435 
436 
437 #ifdef  CASESENSITIVITYDEFAULT_NO
438 #define CASESENSITIVITYDEFAULTVALUE 2
439 #else
440 #define CASESENSITIVITYDEFAULTVALUE 1
441 #endif
442 
443 /*
444    Compare two filename (fileName1,fileName2).
445    If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
446    If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
447 																or strcasecmp)
448    If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
449 		(like 1 on Unix, 2 on Windows)
450 
451 */
unzStringFileNameCompare(const char * fileName1,const char * fileName2,int iCaseSensitivity)452 int unzStringFileNameCompare(const char* fileName1, const char* fileName2, int iCaseSensitivity) {
453 	if (iCaseSensitivity==0)
454 		iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
455 
456 	if (iCaseSensitivity==1)
457 		return strcmp(fileName1,fileName2);
458 
459 	return scumm_stricmp(fileName1,fileName2);
460 }
461 
462 #define BUFREADCOMMENT (0x400)
463 
464 /*
465   Locate the Central directory of a zipfile (at the end, just before
466 	the global comment)
467 */
unzlocal_SearchCentralDir(Common::SeekableReadStream & fin)468 static uLong unzlocal_SearchCentralDir(Common::SeekableReadStream &fin) {
469 	unsigned char* buf;
470 	uLong uSizeFile;
471 	uLong uBackRead;
472 	uLong uMaxBack=0xffff; /* maximum size of global comment */
473 	uLong uPosFound=0;
474 
475 	uSizeFile = fin.size();
476 	if (fin.err())
477 		return 0;
478 
479 	if (uMaxBack>uSizeFile)
480 		uMaxBack = uSizeFile;
481 
482 	buf = (unsigned char*)malloc(BUFREADCOMMENT+4);
483 	if (buf==nullptr)
484 		return 0;
485 
486 	uBackRead = 4;
487 	while (uBackRead<uMaxBack) {
488 		uLong uReadSize,uReadPos;
489 		int i;
490 		if (uBackRead+BUFREADCOMMENT>uMaxBack)
491 			uBackRead = uMaxBack;
492 		else
493 			uBackRead+=BUFREADCOMMENT;
494 		uReadPos = uSizeFile-uBackRead;
495 
496 		uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
497 					 (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
498 		fin.seek(uReadPos, SEEK_SET);
499 		if (fin.err())
500 			break;
501 
502 		if (fin.read(buf,(uInt)uReadSize)!=uReadSize)
503 			break;
504 
505 				for (i=(int)uReadSize-3; (i--)>0;)
506 			if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
507 				((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
508 			{
509 				uPosFound = uReadPos+i;
510 				break;
511 			}
512 
513 		if (uPosFound!=0)
514 			break;
515 	}
516 	free(buf);
517 	return uPosFound;
518 }
519 
520 /*
521   Open a Zip file. path contain the full pathname (by example,
522 	 on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer
523 	 "zlib/zlib109.zip".
524 	 If the zipfile cannot be opened (file don't exist or in not valid), the
525 	   return value is NULL.
526 	 Else, the return value is a unzFile Handle, usable with other function
527 	   of this unzip package.
528 */
unzOpen(Common::SeekableReadStream * stream)529 unzFile unzOpen(Common::SeekableReadStream *stream) {
530 	if (!stream)
531 		return nullptr;
532 
533 	unz_s *us = new unz_s;
534 	uLong central_pos,uL;
535 
536 	uLong number_disk;          /* number of the current dist, used for
537 								   spaning ZIP, unsupported, always 0*/
538 	uLong number_disk_with_CD;  /* number the the disk with central dir, used
539 								   for spaning ZIP, unsupported, always 0*/
540 	uLong number_entry_CD;      /* total number of entries in
541 	                               the central dir
542 	                               (same than number_entry on nospan) */
543 
544 	int err=UNZ_OK;
545 
546 	us->_stream = stream;
547 
548 	central_pos = unzlocal_SearchCentralDir(*us->_stream);
549 	if (central_pos==0)
550 		err=UNZ_ERRNO;
551 
552 	us->_stream->seek(central_pos, SEEK_SET);
553 	if (us->_stream->err())
554 		err=UNZ_ERRNO;
555 
556 	/* the signature, already checked */
557 	if (unzlocal_getLong(us->_stream,&uL)!=UNZ_OK)
558 		err=UNZ_ERRNO;
559 
560 	/* number of this disk */
561 	if (unzlocal_getShort(us->_stream,&number_disk)!=UNZ_OK)
562 		err=UNZ_ERRNO;
563 
564 	/* number of the disk with the start of the central directory */
565 	if (unzlocal_getShort(us->_stream,&number_disk_with_CD)!=UNZ_OK)
566 		err=UNZ_ERRNO;
567 
568 	/* total number of entries in the central dir on this disk */
569 	if (unzlocal_getShort(us->_stream,&us->gi.number_entry)!=UNZ_OK)
570 		err=UNZ_ERRNO;
571 
572 	/* total number of entries in the central dir */
573 	if (unzlocal_getShort(us->_stream,&number_entry_CD)!=UNZ_OK)
574 		err=UNZ_ERRNO;
575 
576 	if ((number_entry_CD!=us->gi.number_entry) ||
577 	    (number_disk_with_CD!=0) ||
578 	    (number_disk!=0))
579 		err=UNZ_BADZIPFILE;
580 
581 	/* size of the central directory */
582 	if (unzlocal_getLong(us->_stream,&us->size_central_dir)!=UNZ_OK)
583 		err=UNZ_ERRNO;
584 
585 	/* offset of start of central directory with respect to the
586 	      starting disk number */
587 	if (unzlocal_getLong(us->_stream,&us->offset_central_dir)!=UNZ_OK)
588 		err=UNZ_ERRNO;
589 
590 	/* zipfile comment length */
591 	if (unzlocal_getShort(us->_stream,&us->gi.size_comment)!=UNZ_OK)
592 		err=UNZ_ERRNO;
593 
594 	if ((central_pos<us->offset_central_dir+us->size_central_dir) && (err==UNZ_OK))
595 		err=UNZ_BADZIPFILE;
596 
597 	if (err != UNZ_OK) {
598 		delete us->_stream;
599 		delete us;
600 		return nullptr;
601 	}
602 
603 	us->byte_before_the_zipfile = central_pos -
604 		                    (us->offset_central_dir+us->size_central_dir);
605 	us->central_pos = central_pos;
606 	us->pfile_in_zip_read = nullptr;
607 
608 	err = unzGoToFirstFile((unzFile)us);
609 
610 	while (err == UNZ_OK) {
611 		// Get the file details
612 		char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
613 		unzGetCurrentFileInfo(us, nullptr, szCurrentFileName, sizeof(szCurrentFileName) - 1,
614 							nullptr, 0, nullptr, 0);
615 
616 		// Save details into the hash
617 		cached_file_in_zip fe;
618 		fe.num_file = us->num_file;
619 		fe.pos_in_central_dir = us->pos_in_central_dir;
620 		fe.current_file_ok = us->current_file_ok;
621 		fe.cur_file_info = us->cur_file_info;
622 		fe.cur_file_info_internal = us->cur_file_info_internal;
623 
624 		us->_hash[Common::String(szCurrentFileName)] = fe;
625 
626 		// Move to the next file
627 		err = unzGoToNextFile((unzFile)us);
628 	}
629 	return (unzFile)us;
630 }
631 
632 
633 /*
634   Close a ZipFile opened with unzipOpen.
635   If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
636 	these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
637   return UNZ_OK if there is no problem. */
unzClose(unzFile file)638 int unzClose(unzFile file) {
639 	unz_s *s;
640 	if (file == nullptr)
641 		return UNZ_PARAMERROR;
642 	s = (unz_s *)file;
643 
644 	if (s->pfile_in_zip_read != nullptr)
645 		unzCloseCurrentFile(file);
646 
647 	delete s->_stream;
648 	delete s;
649 	return UNZ_OK;
650 }
651 
652 
653 /*
654   Write info about the ZipFile in the *pglobal_info structure.
655   No preparation of the structure is needed
656   return UNZ_OK if there is no problem. */
unzGetGlobalInfo(unzFile file,unz_global_info * pglobal_info)657 int unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info) {
658 	unz_s *s;
659 	if (file == nullptr)
660 		return UNZ_PARAMERROR;
661 	s = (unz_s *)file;
662 	*pglobal_info = s->gi;
663 	return UNZ_OK;
664 }
665 
666 
667 /*
668    Translate date/time from Dos format to tm_unz (readable more easilty)
669 */
unzlocal_DosDateToTmuDate(uLong ulDosDate,tm_unz * ptm)670 static void unzlocal_DosDateToTmuDate(uLong ulDosDate, tm_unz* ptm) {
671 	uLong uDate;
672 	uDate = (uLong)(ulDosDate>>16);
673 	ptm->tm_mday = (uInt)(uDate&0x1f);
674 	ptm->tm_mon =  (uInt)((((uDate)&0x1E0)/0x20)-1);
675 	ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980);
676 
677 	ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
678 	ptm->tm_min =  (uInt) ((ulDosDate&0x7E0)/0x20);
679 	ptm->tm_sec =  (uInt) (2*(ulDosDate&0x1f));
680 }
681 
682 /*
683   Get Info about the current file in the zipfile, with internal only info
684 */
685 static int unzlocal_GetCurrentFileInfoInternal(unzFile file,
686 												  unz_file_info *pfile_info,
687 												  unz_file_info_internal
688 												  *pfile_info_internal,
689 												  char *szFileName,
690 												  uLong fileNameBufferSize,
691 												  void *extraField,
692 												  uLong extraFieldBufferSize,
693 												  char *szComment,
694 												  uLong commentBufferSize);
695 
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)696 static int unzlocal_GetCurrentFileInfoInternal(unzFile file,
697 											  unz_file_info *pfile_info,
698 											  unz_file_info_internal *pfile_info_internal,
699 											  char *szFileName, uLong fileNameBufferSize,
700 											  void *extraField, uLong extraFieldBufferSize,
701 											  char *szComment,  uLong commentBufferSize)
702 {
703 	unz_s* s;
704 	unz_file_info file_info;
705 	unz_file_info_internal file_info_internal;
706 	int err=UNZ_OK;
707 	uLong uMagic;
708 	long lSeek=0;
709 
710 	if (file==nullptr)
711 		return UNZ_PARAMERROR;
712 	s=(unz_s*)file;
713 	s->_stream->seek(s->pos_in_central_dir+s->byte_before_the_zipfile, SEEK_SET);
714 	if (s->_stream->err())
715 		err=UNZ_ERRNO;
716 
717 
718 	/* we check the magic */
719 	if (err==UNZ_OK) {
720 		if (unzlocal_getLong(s->_stream,&uMagic) != UNZ_OK)
721 			err=UNZ_ERRNO;
722 		else if (uMagic!=0x02014b50)
723 			err=UNZ_BADZIPFILE;
724 	}
725 
726 	if (unzlocal_getShort(s->_stream,&file_info.version) != UNZ_OK)
727 		err=UNZ_ERRNO;
728 
729 	if (unzlocal_getShort(s->_stream,&file_info.version_needed) != UNZ_OK)
730 		err=UNZ_ERRNO;
731 
732 	if (unzlocal_getShort(s->_stream,&file_info.flag) != UNZ_OK)
733 		err=UNZ_ERRNO;
734 
735 	if (unzlocal_getShort(s->_stream,&file_info.compression_method) != UNZ_OK)
736 		err=UNZ_ERRNO;
737 
738 	if (unzlocal_getLong(s->_stream,&file_info.dosDate) != UNZ_OK)
739 		err=UNZ_ERRNO;
740 
741 	unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
742 
743 	if (unzlocal_getLong(s->_stream,&file_info.crc) != UNZ_OK)
744 		err=UNZ_ERRNO;
745 
746 	if (unzlocal_getLong(s->_stream,&file_info.compressed_size) != UNZ_OK)
747 		err=UNZ_ERRNO;
748 
749 	if (unzlocal_getLong(s->_stream,&file_info.uncompressed_size) != UNZ_OK)
750 		err=UNZ_ERRNO;
751 
752 	if (unzlocal_getShort(s->_stream,&file_info.size_filename) != UNZ_OK)
753 		err=UNZ_ERRNO;
754 
755 	if (unzlocal_getShort(s->_stream,&file_info.size_file_extra) != UNZ_OK)
756 		err=UNZ_ERRNO;
757 
758 	if (unzlocal_getShort(s->_stream,&file_info.size_file_comment) != UNZ_OK)
759 		err=UNZ_ERRNO;
760 
761 	if (unzlocal_getShort(s->_stream,&file_info.disk_num_start) != UNZ_OK)
762 		err=UNZ_ERRNO;
763 
764 	if (unzlocal_getShort(s->_stream,&file_info.internal_fa) != UNZ_OK)
765 		err=UNZ_ERRNO;
766 
767 	if (unzlocal_getLong(s->_stream,&file_info.external_fa) != UNZ_OK)
768 		err=UNZ_ERRNO;
769 
770 	if (unzlocal_getLong(s->_stream,&file_info_internal.offset_curfile) != UNZ_OK)
771 		err=UNZ_ERRNO;
772 
773 	lSeek+=file_info.size_filename;
774 	if ((err==UNZ_OK) && (szFileName!=nullptr)) {
775 		uLong uSizeRead;
776 		if (file_info.size_filename<fileNameBufferSize) {
777 			*(szFileName+file_info.size_filename)='\0';
778 			uSizeRead = file_info.size_filename;
779 		} else
780 			uSizeRead = fileNameBufferSize;
781 
782 		if ((file_info.size_filename>0) && (fileNameBufferSize>0))
783 			if (s->_stream->read(szFileName,(uInt)uSizeRead)!=uSizeRead)
784 				err=UNZ_ERRNO;
785 		lSeek -= uSizeRead;
786 	}
787 
788 
789 	if ((err==UNZ_OK) && (extraField!=nullptr)) {
790 		uLong uSizeRead;
791 		if (file_info.size_file_extra<extraFieldBufferSize)
792 			uSizeRead = file_info.size_file_extra;
793 		else
794 			uSizeRead = extraFieldBufferSize;
795 
796 		if (lSeek!=0) {
797 			s->_stream->seek(lSeek, SEEK_CUR);
798 			if (s->_stream->err())
799 				lSeek=0;
800 			else
801 				err=UNZ_ERRNO;
802 		}
803 		if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
804 			if (s->_stream->read(extraField,(uInt)uSizeRead)!=uSizeRead)
805 				err=UNZ_ERRNO;
806 		lSeek += file_info.size_file_extra - uSizeRead;
807 	}
808 	else
809 		lSeek+=file_info.size_file_extra;
810 
811 
812 	if ((err==UNZ_OK) && (szComment!=nullptr)) {
813 		uLong uSizeRead;
814 		if (file_info.size_file_comment<commentBufferSize) {
815 			*(szComment+file_info.size_file_comment)='\0';
816 			uSizeRead = file_info.size_file_comment;
817 		} else
818 			uSizeRead = commentBufferSize;
819 
820 		if (lSeek!=0) {
821 			s->_stream->seek(lSeek, SEEK_CUR);
822 			if (s->_stream->err())
823 				lSeek=0;
824 			else
825 				err=UNZ_ERRNO;
826 		}
827 		if ((file_info.size_file_comment>0) && (commentBufferSize>0))
828 			if (s->_stream->read(szComment,(uInt)uSizeRead)!=uSizeRead)
829 				err=UNZ_ERRNO;
830 		lSeek+=file_info.size_file_comment - uSizeRead;
831 	} else
832 		lSeek+=file_info.size_file_comment;
833 
834 	if ((err==UNZ_OK) && (pfile_info!=nullptr))
835 		*pfile_info=file_info;
836 
837 	if ((err==UNZ_OK) && (pfile_info_internal!=nullptr))
838 		*pfile_info_internal=file_info_internal;
839 
840 	return err;
841 }
842 
843 
844 
845 /*
846   Write info about the ZipFile in the *pglobal_info structure.
847   No preparation of the structure is needed
848   return UNZ_OK if there is no problem.
849 */
unzGetCurrentFileInfo(unzFile file,unz_file_info * pfile_info,char * szFileName,uLong fileNameBufferSize,void * extraField,uLong extraFieldBufferSize,char * szComment,uLong commentBufferSize)850 int unzGetCurrentFileInfo(unzFile file,
851 												  unz_file_info *pfile_info,
852 												  char *szFileName, uLong fileNameBufferSize,
853 												  void *extraField, uLong extraFieldBufferSize,
854 												  char *szComment,  uLong commentBufferSize)
855 {
856 	return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,nullptr,
857 												szFileName,fileNameBufferSize,
858 												extraField,extraFieldBufferSize,
859 												szComment,commentBufferSize);
860 }
861 
862 /*
863   Set the current file of the zipfile to the first file.
864   return UNZ_OK if there is no problem
865 */
unzGoToFirstFile(unzFile file)866 int unzGoToFirstFile(unzFile file) {
867 	int err=UNZ_OK;
868 	unz_s* s;
869 	if (file==nullptr)
870 		return UNZ_PARAMERROR;
871 	s=(unz_s*)file;
872 	s->pos_in_central_dir=s->offset_central_dir;
873 	s->num_file=0;
874 	err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
875 											 &s->cur_file_info_internal,
876 											 nullptr,0,nullptr,0,nullptr,0);
877 	s->current_file_ok = (err == UNZ_OK);
878 	return err;
879 }
880 
881 
882 /*
883   Set the current file of the zipfile to the next file.
884   return UNZ_OK if there is no problem
885   return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
886 */
unzGoToNextFile(unzFile file)887 int unzGoToNextFile(unzFile file) {
888 	unz_s* s;
889 	int err;
890 
891 	if (file==nullptr)
892 		return UNZ_PARAMERROR;
893 	s=(unz_s*)file;
894 	if (!s->current_file_ok)
895 		return UNZ_END_OF_LIST_OF_FILE;
896 	if (s->num_file+1==s->gi.number_entry)
897 		return UNZ_END_OF_LIST_OF_FILE;
898 
899 	s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
900 			s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment;
901 	s->num_file++;
902 	err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
903 											   &s->cur_file_info_internal,
904 											   nullptr,0,nullptr,0,nullptr,0);
905 	s->current_file_ok = (err == UNZ_OK);
906 	return err;
907 }
908 
909 /*
910   Try locate the file szFileName in the zipfile.
911   For the iCaseSensitivity signification, see unzipStringFileNameCompare
912 
913   return value :
914   UNZ_OK if the file is found. It becomes the current file.
915   UNZ_END_OF_LIST_OF_FILE if the file is not found
916 */
unzLocateFile(unzFile file,const char * szFileName,int iCaseSensitivity)917 int unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity) {
918 	unz_s* s;
919 
920 	if (file==nullptr)
921 		return UNZ_PARAMERROR;
922 
923 	if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
924 		return UNZ_PARAMERROR;
925 
926 	s=(unz_s*)file;
927 	if (!s->current_file_ok)
928 		return UNZ_END_OF_LIST_OF_FILE;
929 
930 	// Check to see if the entry exists
931 	ZipHash::iterator i = s->_hash.find(Common::String(szFileName));
932 	if (i == s->_hash.end())
933 		return UNZ_END_OF_LIST_OF_FILE;
934 
935 	// Found it, so reset the details in the main structure
936 	cached_file_in_zip &fe = i->_value;
937 	s->num_file = fe.num_file;
938 	s->pos_in_central_dir = fe.pos_in_central_dir;
939 	s->current_file_ok = fe.current_file_ok;
940 	s->cur_file_info = fe.cur_file_info;
941 	s->cur_file_info_internal = fe.cur_file_info_internal;
942 
943 	return UNZ_OK;
944 }
945 
946 
947 /*
948   Read the local header of the current zipfile
949   Check the coherency of the local header and info in the end of central
950 		directory about this file
951   store in *piSizeVar the size of extra info in local header
952 		(filename and size of extra field data)
953 */
unzlocal_CheckCurrentFileCoherencyHeader(unz_s * s,uInt * piSizeVar,uLong * poffset_local_extrafield,uInt * psize_local_extrafield)954 static int unzlocal_CheckCurrentFileCoherencyHeader(unz_s* s, uInt* piSizeVar,
955 													uLong *poffset_local_extrafield,
956 													uInt  *psize_local_extrafield) {
957 	uLong uMagic,uData,uFlags;
958 	uLong size_filename;
959 	uLong size_extra_field;
960 	int err=UNZ_OK;
961 
962 	*piSizeVar = 0;
963 	*poffset_local_extrafield = 0;
964 	*psize_local_extrafield = 0;
965 
966 	s->_stream->seek(s->cur_file_info_internal.offset_curfile +
967 								s->byte_before_the_zipfile, SEEK_SET);
968 	if (s->_stream->err())
969 		return UNZ_ERRNO;
970 
971 
972 	if (err==UNZ_OK) {
973 		if (unzlocal_getLong(s->_stream,&uMagic) != UNZ_OK)
974 			err=UNZ_ERRNO;
975 		else if (uMagic!=0x04034b50)
976 			err=UNZ_BADZIPFILE;
977 	}
978 
979 	if (unzlocal_getShort(s->_stream,&uData) != UNZ_OK)
980 		err=UNZ_ERRNO;
981 /*
982 	else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
983 		err=UNZ_BADZIPFILE;
984 */
985 	if (unzlocal_getShort(s->_stream,&uFlags) != UNZ_OK)
986 		err=UNZ_ERRNO;
987 
988 	if (unzlocal_getShort(s->_stream,&uData) != UNZ_OK)
989 		err=UNZ_ERRNO;
990 	else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
991 		err=UNZ_BADZIPFILE;
992 
993 	if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
994 	                     (s->cur_file_info.compression_method!=Z_DEFLATED))
995 		err=UNZ_BADZIPFILE;
996 
997 	if (unzlocal_getLong(s->_stream,&uData) != UNZ_OK) /* date/time */
998 		err=UNZ_ERRNO;
999 
1000 	if (unzlocal_getLong(s->_stream,&uData) != UNZ_OK) /* crc */
1001 		err=UNZ_ERRNO;
1002 	else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&
1003 		                      ((uFlags & 8)==0))
1004 		err=UNZ_BADZIPFILE;
1005 
1006 	if (unzlocal_getLong(s->_stream,&uData) != UNZ_OK) /* size compr */
1007 		err=UNZ_ERRNO;
1008 	else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&
1009 							  ((uFlags & 8)==0))
1010 		err=UNZ_BADZIPFILE;
1011 
1012 	if (unzlocal_getLong(s->_stream,&uData) != UNZ_OK) /* size uncompr */
1013 		err=UNZ_ERRNO;
1014 	else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) &&
1015 							  ((uFlags & 8)==0))
1016 		err=UNZ_BADZIPFILE;
1017 
1018 
1019 	if (unzlocal_getShort(s->_stream,&size_filename) != UNZ_OK)
1020 		err=UNZ_ERRNO;
1021 	else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
1022 		err=UNZ_BADZIPFILE;
1023 
1024 	*piSizeVar += (uInt)size_filename;
1025 
1026 	if (unzlocal_getShort(s->_stream,&size_extra_field) != UNZ_OK)
1027 		err=UNZ_ERRNO;
1028 	*poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
1029 									SIZEZIPLOCALHEADER + size_filename;
1030 	*psize_local_extrafield = (uInt)size_extra_field;
1031 
1032 	*piSizeVar += (uInt)size_extra_field;
1033 
1034 	return err;
1035 }
1036 
1037 /*
1038   Open for reading data the current file in the zipfile.
1039   If there is no error and the file is opened, the return value is UNZ_OK.
1040 */
unzOpenCurrentFile(unzFile file)1041 int unzOpenCurrentFile (unzFile file) {
1042 	int err=UNZ_OK;
1043 	int Store;
1044 	uInt iSizeVar;
1045 	unz_s* s;
1046 	file_in_zip_read_info_s* pfile_in_zip_read_info;
1047 	uLong offset_local_extrafield;  /* offset of the local extra field */
1048 	uInt  size_local_extrafield;    /* size of the local extra field */
1049 
1050 	if (file==nullptr)
1051 		return UNZ_PARAMERROR;
1052 	s=(unz_s*)file;
1053 	if (!s->current_file_ok)
1054 		return UNZ_PARAMERROR;
1055 
1056 	if (s->pfile_in_zip_read != nullptr)
1057 		unzCloseCurrentFile(file);
1058 
1059 	if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,
1060 				&offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
1061 		return UNZ_BADZIPFILE;
1062 
1063 	pfile_in_zip_read_info = (file_in_zip_read_info_s*) malloc(sizeof(file_in_zip_read_info_s));
1064 
1065 	if (pfile_in_zip_read_info==nullptr)
1066 		return UNZ_INTERNALERROR;
1067 
1068 	pfile_in_zip_read_info->read_buffer=(char *)malloc(UNZ_BUFSIZE);
1069 	pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
1070 	pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
1071 	pfile_in_zip_read_info->pos_local_extrafield=0;
1072 
1073 	if (pfile_in_zip_read_info->read_buffer==nullptr)
1074 	{
1075 		free(pfile_in_zip_read_info);
1076 		return UNZ_INTERNALERROR;
1077 	}
1078 
1079 	pfile_in_zip_read_info->stream_initialized=0;
1080 
1081 	if ((s->cur_file_info.compression_method!=0) &&
1082 	    (s->cur_file_info.compression_method!=Z_DEFLATED))
1083 		err=UNZ_BADZIPFILE;
1084 	Store = s->cur_file_info.compression_method==0;
1085 
1086 	pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
1087 	pfile_in_zip_read_info->crc32_data=0;
1088 	pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method;
1089 	pfile_in_zip_read_info->_stream=s->_stream;
1090 	pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
1091 
1092 	pfile_in_zip_read_info->stream.total_out = 0;
1093 
1094 	if (!Store) {
1095 #ifdef USE_ZLIB
1096 		pfile_in_zip_read_info->stream.zalloc = (alloc_func)nullptr;
1097 		pfile_in_zip_read_info->stream.zfree = (free_func)nullptr;
1098 		pfile_in_zip_read_info->stream.opaque = (voidpf)nullptr;
1099 
1100 		err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
1101 		if (err == Z_OK)
1102 			pfile_in_zip_read_info->stream_initialized = 1;
1103 	/* windowBits is passed < 0 to tell that there is no zlib header.
1104 	 * Note that in this case inflate *requires* an extra "dummy" byte
1105 	 * after the compressed stream in order to complete decompression and
1106 	 * return Z_STREAM_END.
1107 	 * In unzip, i don't wait absolutely Z_STREAM_END because I known the
1108 	 * size of both compressed and uncompressed data
1109 	 */
1110 #else
1111 		err=UNZ_BADZIPFILE;
1112 #endif
1113 	}
1114 	pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size;
1115 	pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size;
1116 
1117 
1118 	pfile_in_zip_read_info->pos_in_zipfile =
1119 		s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar;
1120 
1121 	pfile_in_zip_read_info->stream.avail_in = (uInt)0;
1122 
1123 	s->pfile_in_zip_read = pfile_in_zip_read_info;
1124 	return err;
1125 }
1126 
1127 
1128 /*
1129   Read bytes from the current file.
1130   buf contain buffer where data must be copied
1131   len the size of buf.
1132 
1133   return the number of byte copied if somes bytes are copied
1134   return 0 if the end of file was reached
1135   return <0 with error code if there is an error
1136 	(UNZ_ERRNO for IO error, or zLib error for uncompress error)
1137 */
unzReadCurrentFile(unzFile file,voidp buf,unsigned len)1138 int unzReadCurrentFile(unzFile file, voidp buf, unsigned len) {
1139 	int err=UNZ_OK;
1140 	uInt iRead = 0;
1141 	unz_s* s;
1142 	file_in_zip_read_info_s* pfile_in_zip_read_info;
1143 	if (file==nullptr)
1144 		return UNZ_PARAMERROR;
1145 	s=(unz_s*)file;
1146 	pfile_in_zip_read_info=s->pfile_in_zip_read;
1147 
1148 	if (pfile_in_zip_read_info==nullptr)
1149 		return UNZ_PARAMERROR;
1150 
1151 
1152 	if (pfile_in_zip_read_info->read_buffer == nullptr)
1153 		return UNZ_END_OF_LIST_OF_FILE;
1154 	if (len==0)
1155 		return 0;
1156 
1157 	pfile_in_zip_read_info->stream.next_out = (Bytef *)buf;
1158 
1159 	pfile_in_zip_read_info->stream.avail_out = (uInt)len;
1160 
1161 	if (len>pfile_in_zip_read_info->rest_read_uncompressed)
1162 		pfile_in_zip_read_info->stream.avail_out =
1163 		  (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
1164 
1165 	while (pfile_in_zip_read_info->stream.avail_out>0) {
1166 		if ((pfile_in_zip_read_info->stream.avail_in==0) &&
1167 		    (pfile_in_zip_read_info->rest_read_compressed>0)) {
1168 			uInt uReadThis = UNZ_BUFSIZE;
1169 			if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
1170 				uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
1171 			if (uReadThis == 0)
1172 				return UNZ_EOF;
1173 			pfile_in_zip_read_info->_stream->seek(pfile_in_zip_read_info->pos_in_zipfile +
1174 				pfile_in_zip_read_info->byte_before_the_zipfile, SEEK_SET);
1175 			if (pfile_in_zip_read_info->_stream->err())
1176 				return UNZ_ERRNO;
1177 			if (pfile_in_zip_read_info->_stream->read(pfile_in_zip_read_info->read_buffer,uReadThis)!=uReadThis)
1178 				return UNZ_ERRNO;
1179 			pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
1180 
1181 			pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
1182 
1183 			pfile_in_zip_read_info->stream.next_in = (Bytef *)pfile_in_zip_read_info->read_buffer;
1184 			pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
1185 		}
1186 
1187 		if (pfile_in_zip_read_info->compression_method==0) {
1188 			uInt uDoCopy,i;
1189 			if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in)
1190 				uDoCopy = pfile_in_zip_read_info->stream.avail_out;
1191 			else
1192 				uDoCopy = pfile_in_zip_read_info->stream.avail_in;
1193 
1194 			for (i=0;i<uDoCopy;i++)
1195 				*(pfile_in_zip_read_info->stream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i);
1196 
1197 #ifdef USE_ZLIB
1198 			pfile_in_zip_read_info->crc32_data = crc32(pfile_in_zip_read_info->crc32_data,
1199 								pfile_in_zip_read_info->stream.next_out,
1200 								uDoCopy);
1201 #endif  // otherwise leave crc32_data as is and it won't be verified at the end
1202 			pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
1203 			pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
1204 			pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
1205 			pfile_in_zip_read_info->stream.next_out += uDoCopy;
1206 			pfile_in_zip_read_info->stream.next_in += uDoCopy;
1207 			pfile_in_zip_read_info->stream.total_out += uDoCopy;
1208 			iRead += uDoCopy;
1209 		} else {
1210 #ifdef USE_ZLIB
1211 			uLong uTotalOutBefore,uTotalOutAfter;
1212 			const Bytef *bufBefore;
1213 			uLong uOutThis;
1214 			int flush = Z_SYNC_FLUSH;
1215 
1216 			uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
1217 			bufBefore = pfile_in_zip_read_info->stream.next_out;
1218 
1219 			/*
1220 			if ((pfile_in_zip_read_info->rest_read_uncompressed ==
1221 			         pfile_in_zip_read_info->stream.avail_out) &&
1222 				(pfile_in_zip_read_info->rest_read_compressed == 0))
1223 				flush = Z_FINISH;
1224 			*/
1225 			err=inflate(&pfile_in_zip_read_info->stream,flush);
1226 
1227 			uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
1228 			uOutThis = uTotalOutAfter-uTotalOutBefore;
1229 
1230 			pfile_in_zip_read_info->crc32_data =
1231 				crc32(pfile_in_zip_read_info->crc32_data,bufBefore, (uInt)(uOutThis));
1232 
1233 			pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis;
1234 
1235 			iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
1236 
1237 			if (err==Z_STREAM_END)
1238 				return (iRead==0) ? UNZ_EOF : iRead;
1239 			if (err!=Z_OK)
1240 				break;
1241 #else
1242 			// Cannot decompress the file without zlib.
1243 			err = UNZ_BADZIPFILE;
1244 			break;
1245 #endif
1246 		}
1247 	}
1248 
1249 	if (err==Z_OK)
1250 		return iRead;
1251 	return err;
1252 }
1253 
1254 
1255 /*
1256   Give the current position in uncompressed data
1257 */
unztell(unzFile file)1258 z_off_t unztell(unzFile file) {
1259 	unz_s* s;
1260 	file_in_zip_read_info_s* pfile_in_zip_read_info;
1261 	if (file==nullptr)
1262 		return UNZ_PARAMERROR;
1263 	s=(unz_s*)file;
1264 	pfile_in_zip_read_info=s->pfile_in_zip_read;
1265 
1266 	if (pfile_in_zip_read_info==nullptr)
1267 		return UNZ_PARAMERROR;
1268 
1269 	return (z_off_t)pfile_in_zip_read_info->stream.total_out;
1270 }
1271 
1272 
1273 /*
1274   return 1 if the end of file was reached, 0 elsewhere
1275 */
unzeof(unzFile file)1276 int unzeof(unzFile file) {
1277 	unz_s* s;
1278 	file_in_zip_read_info_s* pfile_in_zip_read_info;
1279 	if (file==nullptr)
1280 		return UNZ_PARAMERROR;
1281 	s=(unz_s*)file;
1282 	pfile_in_zip_read_info=s->pfile_in_zip_read;
1283 
1284 	if (pfile_in_zip_read_info==nullptr)
1285 		return UNZ_PARAMERROR;
1286 
1287 	if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
1288 		return 1;
1289 	else
1290 		return 0;
1291 }
1292 
1293 
1294 
1295 /*
1296   Read extra field from the current file (opened by unzOpenCurrentFile)
1297   This is the local-header version of the extra field (sometimes, there is
1298 	more info in the local-header version than in the central-header)
1299 
1300   if buf==NULL, it return the size of the local extra field that can be read
1301 
1302   if buf!=NULL, len is the size of the buffer, the extra header is copied in
1303 	buf.
1304   the return value is the number of bytes copied in buf, or (if <0)
1305 	the error code
1306 */
unzGetLocalExtrafield(unzFile file,voidp buf,unsigned len)1307 int unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len) {
1308 	unz_s* s;
1309 	file_in_zip_read_info_s* pfile_in_zip_read_info;
1310 	uInt read_now;
1311 	uLong size_to_read;
1312 
1313 	if (file==nullptr)
1314 		return UNZ_PARAMERROR;
1315 	s=(unz_s*)file;
1316 	pfile_in_zip_read_info=s->pfile_in_zip_read;
1317 
1318 	if (pfile_in_zip_read_info==nullptr)
1319 		return UNZ_PARAMERROR;
1320 
1321 	size_to_read = (pfile_in_zip_read_info->size_local_extrafield -
1322 				pfile_in_zip_read_info->pos_local_extrafield);
1323 
1324 	if (buf==nullptr)
1325 		return (int)size_to_read;
1326 
1327 	if (len>size_to_read)
1328 		read_now = (uInt)size_to_read;
1329 	else
1330 		read_now = (uInt)len;
1331 
1332 	if (read_now==0)
1333 		return 0;
1334 
1335 	pfile_in_zip_read_info->_stream->seek(pfile_in_zip_read_info->offset_local_extrafield +
1336 			  pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET);
1337 	if (pfile_in_zip_read_info->_stream->err())
1338 		return UNZ_ERRNO;
1339 
1340 	if (pfile_in_zip_read_info->_stream->read(buf,(uInt)size_to_read)!=size_to_read)
1341 		return UNZ_ERRNO;
1342 
1343 	return (int)read_now;
1344 }
1345 
1346 /*
1347   Close the file in zip opened with unzipOpenCurrentFile
1348   Return UNZ_CRCERROR if all the file was read but the CRC is not good
1349 */
unzCloseCurrentFile(unzFile file)1350 int unzCloseCurrentFile(unzFile file) {
1351 	int err=UNZ_OK;
1352 
1353 	unz_s* s;
1354 	file_in_zip_read_info_s* pfile_in_zip_read_info;
1355 	if (file == nullptr)
1356 		return UNZ_PARAMERROR;
1357 	s = (unz_s*)file;
1358 	pfile_in_zip_read_info = s->pfile_in_zip_read;
1359 
1360 	if (pfile_in_zip_read_info == nullptr)
1361 		return UNZ_PARAMERROR;
1362 
1363 
1364 #ifdef USE_ZLIB
1365 	// Only verify crc32_data when zlib is linked in, because otherwise crc32() is
1366 	// not defined.
1367 	if (pfile_in_zip_read_info->rest_read_uncompressed == 0) {
1368 		if (pfile_in_zip_read_info->crc32_data != pfile_in_zip_read_info->crc32_wait)
1369 			err=UNZ_CRCERROR;
1370 	}
1371 	if (pfile_in_zip_read_info->stream_initialized)
1372 		inflateEnd(&pfile_in_zip_read_info->stream);
1373 #endif
1374 
1375 
1376 	free(pfile_in_zip_read_info->read_buffer);
1377 	pfile_in_zip_read_info->read_buffer = nullptr;
1378 
1379 	pfile_in_zip_read_info->stream_initialized = 0;
1380 	free(pfile_in_zip_read_info);
1381 
1382 	s->pfile_in_zip_read=nullptr;
1383 
1384 	return err;
1385 }
1386 
1387 
1388 /*
1389   Get the global comment string of the ZipFile, in the szComment buffer.
1390   uSizeBuf is the size of the szComment buffer.
1391   return the number of byte copied or an error code <0
1392 */
unzGetGlobalComment(unzFile file,char * szComment,uLong uSizeBuf)1393 int unzGetGlobalComment(unzFile file, char *szComment, uLong uSizeBuf) {
1394 	unz_s* s;
1395 	uLong uReadThis;
1396 	if (file==nullptr)
1397 		return UNZ_PARAMERROR;
1398 	s=(unz_s*)file;
1399 
1400 	uReadThis = uSizeBuf;
1401 	if (uReadThis>s->gi.size_comment)
1402 		uReadThis = s->gi.size_comment;
1403 
1404 	s->_stream->seek(s->central_pos+22, SEEK_SET);
1405 	if (s->_stream->err())
1406 		return UNZ_ERRNO;
1407 
1408 	if (uReadThis>0) {
1409 		*szComment='\0';
1410 		if (s->_stream->read(szComment,(uInt)uReadThis)!=uReadThis)
1411 			return UNZ_ERRNO;
1412 	}
1413 
1414 	if ((szComment != nullptr) && (uSizeBuf > s->gi.size_comment))
1415 		*(szComment+s->gi.size_comment)='\0';
1416 	return (int)uReadThis;
1417 }
1418 
1419 
1420 namespace Common {
1421 
1422 
1423 class ZipArchive : public Archive {
1424 	unzFile _zipFile;
1425 
1426 public:
1427 	ZipArchive(unzFile zipFile);
1428 
1429 
1430 	~ZipArchive();
1431 
1432 	virtual bool hasFile(const Path &path) const;
1433 	virtual int listMembers(ArchiveMemberList &list) const;
1434 	virtual const ArchiveMemberPtr getMember(const Path &path) const;
1435 	virtual SeekableReadStream *createReadStreamForMember(const Path &path) const;
1436 };
1437 
1438 /*
1439 class ZipArchiveMember : public ArchiveMember {
1440 	unzFile _zipFile;
1441 
1442 public:
1443 	ZipArchiveMember(FSNode &node) : _node(node) {
1444 	}
1445 
1446 	String getName() const {
1447 		...
1448 	}
1449 
1450 	SeekableReadStream *open() {
1451 		...
1452 	}
1453 };
1454 */
1455 
ZipArchive(unzFile zipFile)1456 ZipArchive::ZipArchive(unzFile zipFile) : _zipFile(zipFile) {
1457 	assert(_zipFile);
1458 }
1459 
~ZipArchive()1460 ZipArchive::~ZipArchive() {
1461 	unzClose(_zipFile);
1462 }
1463 
hasFile(const Path & path) const1464 bool ZipArchive::hasFile(const Path &path) const {
1465 	String name = path.toString();
1466 	return (unzLocateFile(_zipFile, name.c_str(), 2) == UNZ_OK);
1467 }
1468 
listMembers(ArchiveMemberList & list) const1469 int ZipArchive::listMembers(ArchiveMemberList &list) const {
1470 	int members = 0;
1471 
1472 	const unz_s *const archive = (const unz_s *)_zipFile;
1473 	for (ZipHash::const_iterator i = archive->_hash.begin(), end = archive->_hash.end();
1474 	     i != end; ++i) {
1475 		list.push_back(ArchiveMemberList::value_type(new GenericArchiveMember(i->_key, this)));
1476 		++members;
1477 	}
1478 
1479 	return members;
1480 }
1481 
getMember(const Path & path) const1482 const ArchiveMemberPtr ZipArchive::getMember(const Path &path) const {
1483 	String name = path.toString();
1484 	if (!hasFile(name))
1485 		return ArchiveMemberPtr();
1486 
1487 	return ArchiveMemberPtr(new GenericArchiveMember(name, this));
1488 }
1489 
createReadStreamForMember(const Path & path) const1490 SeekableReadStream *ZipArchive::createReadStreamForMember(const Path &path) const {
1491 	String name = path.toString();
1492 	if (unzLocateFile(_zipFile, name.c_str(), 2) != UNZ_OK)
1493 		return nullptr;
1494 
1495 	unz_file_info fileInfo;
1496 	if (unzOpenCurrentFile(_zipFile) != UNZ_OK)
1497 		return nullptr;
1498 
1499 	if (unzGetCurrentFileInfo(_zipFile, &fileInfo, nullptr, 0, nullptr, 0, nullptr, 0) != UNZ_OK)
1500 		return nullptr;
1501 
1502 	byte *buffer = (byte *)malloc(fileInfo.uncompressed_size);
1503 	assert(buffer);
1504 
1505 	if (unzReadCurrentFile(_zipFile, buffer, fileInfo.uncompressed_size) != (int)fileInfo.uncompressed_size) {
1506 		free(buffer);
1507 		return nullptr;
1508 	}
1509 
1510 	if (unzCloseCurrentFile(_zipFile) != UNZ_OK) {
1511 		free(buffer);
1512 		return nullptr;
1513 	}
1514 
1515 	return new MemoryReadStream(buffer, fileInfo.uncompressed_size, DisposeAfterUse::YES);
1516 
1517 	// FIXME: instead of reading all into a memory stream, we could
1518 	// instead create a new ZipStream class. But then we have to be
1519 	// careful to handle the case where the client code opens multiple
1520 	// files in the archive and tries to use them independently.
1521 }
1522 
makeZipArchive(const String & name)1523 Archive *makeZipArchive(const String &name) {
1524 	return makeZipArchive(SearchMan.createReadStreamForMember(name));
1525 }
1526 
makeZipArchive(const FSNode & node)1527 Archive *makeZipArchive(const FSNode &node) {
1528 	return makeZipArchive(node.createReadStream());
1529 }
1530 
makeZipArchive(SeekableReadStream * stream)1531 Archive *makeZipArchive(SeekableReadStream *stream) {
1532 	if (!stream)
1533 		return nullptr;
1534 	unzFile zipFile = unzOpen(stream);
1535 	if (!zipFile) {
1536 		// stream gets deleted by unzOpen() call if something
1537 		// goes wrong.
1538 		return nullptr;
1539 	}
1540 	return new ZipArchive(zipFile);
1541 }
1542 
1543 } // End of namespace Common
1544