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