ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

unzip.cpp

Go to the documentation of this file.
00001 /* ScummVM - Graphic Adventure Engine
00002  *
00003  * ScummVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 /* unzip.c -- IO on .zip files using zlib
00024    Version 0.15 beta, Mar 19th, 1998,
00025 
00026    Read unzip.h for more info
00027 */
00028 
00029 /* unzip.h -- IO for uncompress .zip files using zlib
00030    Version 0.15 beta, Mar 19th, 1998,
00031 
00032    Copyright (C) 1998 Gilles Vollant
00033 
00034    This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g
00035      WinZip, InfoZip tools and compatible.
00036    Encryption and multi volume ZipFile (span) are not supported.
00037    Old compressions used by old PKZip 1.x are not supported
00038 
00039    THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE
00040    CAN CHANGE IN FUTURE VERSION !!
00041    I WAIT FEEDBACK at mail info@winimage.com
00042    Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution
00043 
00044    Condition of use and distribution are the same than zlib :
00045 
00046   This software is provided 'as-is', without any express or implied
00047   warranty.  In no event will the authors be held liable for any damages
00048   arising from the use of this software.
00049 
00050   Permission is granted to anyone to use this software for any purpose,
00051   including commercial applications, and to alter it and redistribute it
00052   freely, subject to the following restrictions:
00053 
00054   1. The origin of this software must not be misrepresented; you must not
00055      claim that you wrote the original software. If you use this software
00056      in a product, an acknowledgment in the product documentation would be
00057      appreciated but is not required.
00058   2. Altered source versions must be plainly marked as such, and must not be
00059      misrepresented as being the original software.
00060   3. This notice may not be removed or altered from any source distribution.
00061 
00062 
00063 */
00064 /* for more info about .ZIP format, see
00065       ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip
00066    PkWare has also a specification at :
00067       ftp://ftp.pkware.com/probdesc.zip */
00068 
00069 // Disable symbol overrides so that we can use zlib.h
00070 #define FORBIDDEN_SYMBOL_ALLOW_ALL
00071 
00072 #include "common/scummsys.h"
00073 
00074 #ifdef USE_ZLIB
00075 
00076 #ifdef __SYMBIAN32__
00077 #include <zlib\zlib.h>
00078 #else
00079 #include <zlib.h>
00080 #endif
00081 
00082 #else  // !USE_ZLIB
00083 
00084 // Even when zlib is not linked in, we can still open ZIP archives and read
00085 // uncompressed files from them.  Attempted decompression of compressed files
00086 // will result in an error.
00087 //
00088 // Define the constants and types used by zlib.
00089 #define Z_ERRNO -1
00090 #define Z_OK 0
00091 #define Z_DEFLATED 8
00092 typedef void *voidp;
00093 typedef unsigned int uInt;
00094 typedef unsigned long uLong;
00095 typedef long z_off_t;
00096 typedef unsigned char Byte;
00097 typedef Byte Bytef;
00098 typedef struct {
00099     Bytef    *next_in, *next_out;
00100     uInt     avail_in, avail_out;
00101     uLong    total_out;
00102 } z_stream;
00103 
00104 #endif  // !USE_ZLIB
00105 
00106 #include "common/fs.h"
00107 #include "common/unzip.h"
00108 #include "common/memstream.h"
00109 
00110 #include "common/hashmap.h"
00111 #include "common/hash-str.h"
00112 
00113 #if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
00114 /* like the STRICT of WIN32, we define a pointer that cannot be converted
00115     from (void *) without cast */
00116 typedef struct TagunzFile__ { int unused; } unzFile__;
00117 typedef unzFile__ *unzFile;
00118 #else
00119 typedef voidp unzFile;
00120 #endif
00121 
00122 #define UNZ_OK                                  (0)
00123 #define UNZ_END_OF_LIST_OF_FILE (-100)
00124 #define UNZ_ERRNO               (Z_ERRNO)
00125 #define UNZ_EOF                 (0)
00126 #define UNZ_PARAMERROR                  (-102)
00127 #define UNZ_BADZIPFILE                  (-103)
00128 #define UNZ_INTERNALERROR               (-104)
00129 #define UNZ_CRCERROR                    (-105)
00130 
00131 /* tm_unz contain date/time info */
00132 typedef struct {
00133     uInt tm_sec;            /* seconds after the minute - [0,59] */
00134     uInt tm_min;            /* minutes after the hour - [0,59] */
00135     uInt tm_hour;           /* hours since midnight - [0,23] */
00136     uInt tm_mday;           /* day of the month - [1,31] */
00137     uInt tm_mon;            /* months since January - [0,11] */
00138     uInt tm_year;           /* years - [1980..2044] */
00139 } tm_unz;
00140 
00141 /* unz_global_info structure contain global data about the ZIPfile
00142    These data comes from the end of central dir */
00143 typedef struct {
00144     uLong number_entry;         /* total number of entries in
00145                        the central dir on this disk */
00146     uLong size_comment;         /* size of the global comment of the zipfile */
00147 } unz_global_info;
00148 
00149 
00150 /* unz_file_info contain information about a file in the zipfile */
00151 typedef struct {
00152     uLong version;              /* version made by                 2 bytes */
00153     uLong version_needed;       /* version needed to extract       2 bytes */
00154     uLong flag;                 /* general purpose bit flag        2 bytes */
00155     uLong compression_method;   /* compression method              2 bytes */
00156     uLong dosDate;              /* last mod file date in Dos fmt   4 bytes */
00157     uLong crc;                  /* crc-32                          4 bytes */
00158     uLong compressed_size;      /* compressed size                 4 bytes */
00159     uLong uncompressed_size;    /* uncompressed size               4 bytes */
00160     uLong size_filename;        /* filename length                 2 bytes */
00161     uLong size_file_extra;      /* extra field length              2 bytes */
00162     uLong size_file_comment;    /* file comment length             2 bytes */
00163 
00164     uLong disk_num_start;       /* disk number start               2 bytes */
00165     uLong internal_fa;          /* internal file attributes        2 bytes */
00166     uLong external_fa;          /* external file attributes        4 bytes */
00167 
00168     tm_unz tmu_date;
00169 } unz_file_info;
00170 
00171 int unzStringFileNameCompare(const char* fileName1,
00172                                                  const char* fileName2,
00173                                                  int iCaseSensitivity);
00174 /*
00175    Compare two filename (fileName1,fileName2).
00176    If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
00177    If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
00178                                 or strcasecmp)
00179    If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
00180     (like 1 on Unix, 2 on Windows)
00181 */
00182 
00183 
00184 /*
00185   Open a Zip file. path contain the full pathname (by example,
00186      on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer
00187      "zlib/zlib111.zip".
00188      If the zipfile cannot be opened (file don't exist or in not valid), the
00189        return value is NULL.
00190      Else, the return value is a unzFile Handle, usable with other function
00191        of this unzip package.
00192 */
00193 
00194 int unzClose(unzFile file);
00195 /*
00196   Close a ZipFile opened with unzipOpen.
00197   If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
00198     these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
00199   return UNZ_OK if there is no problem. */
00200 
00201 int unzGetGlobalInfo(unzFile file,
00202                     unz_global_info *pglobal_info);
00203 /*
00204   Write info about the ZipFile in the *pglobal_info structure.
00205   No preparation of the structure is needed
00206   return UNZ_OK if there is no problem. */
00207 
00208 
00209 int unzGetGlobalComment(unzFile file, char *szComment, uLong uSizeBuf);
00210 /*
00211   Get the global comment string of the ZipFile, in the szComment buffer.
00212   uSizeBuf is the size of the szComment buffer.
00213   return the number of byte copied or an error code <0
00214 */
00215 
00216 
00217 /***************************************************************************/
00218 /* Unzip package allow you browse the directory of the zipfile */
00219 
00220 int unzGoToFirstFile(unzFile file);
00221 /*
00222   Set the current file of the zipfile to the first file.
00223   return UNZ_OK if there is no problem
00224 */
00225 
00226 int unzGoToNextFile(unzFile file);
00227 /*
00228   Set the current file of the zipfile to the next file.
00229   return UNZ_OK if there is no problem
00230   return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
00231 */
00232 
00233 int unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity);
00234 /*
00235   Try locate the file szFileName in the zipfile.
00236   For the iCaseSensitivity signification, see unzStringFileNameCompare
00237 
00238   return value :
00239   UNZ_OK if the file is found. It becomes the current file.
00240   UNZ_END_OF_LIST_OF_FILE if the file is not found
00241 */
00242 
00243 
00244 int unzGetCurrentFileInfo(unzFile file,
00245                          unz_file_info *pfile_info,
00246                          char *szFileName,
00247                          uLong fileNameBufferSize,
00248                          void *extraField,
00249                          uLong extraFieldBufferSize,
00250                          char *szComment,
00251                          uLong commentBufferSize);
00252 /*
00253   Get Info about the current file
00254   if pfile_info!=NULL, the *pfile_info structure will contain somes info about
00255         the current file
00256   if szFileName!=NULL, the filemane string will be copied in szFileName
00257             (fileNameBufferSize is the size of the buffer)
00258   if extraField!=NULL, the extra field information will be copied in extraField
00259             (extraFieldBufferSize is the size of the buffer).
00260             This is the Central-header version of the extra field
00261   if szComment!=NULL, the comment string of the file will be copied in szComment
00262             (commentBufferSize is the size of the buffer)
00263 */
00264 
00265 /***************************************************************************/
00266 /* for reading the content of the current zipfile, you can open it, read data
00267    from it, and close it (you can close it before reading all the file)
00268    */
00269 
00270 int unzOpenCurrentFile(unzFile file);
00271 /*
00272   Open for reading data the current file in the zipfile.
00273   If there is no error, the return value is UNZ_OK.
00274 */
00275 
00276 int unzCloseCurrentFile(unzFile file);
00277 /*
00278   Close the file in zip opened with unzOpenCurrentFile
00279   Return UNZ_CRCERROR if all the file was read but the CRC is not good
00280 */
00281 
00282 
00283 int unzReadCurrentFile(unzFile file, voidp buf, unsigned len);
00284 /*
00285   Read bytes from the current file (opened by unzOpenCurrentFile)
00286   buf contain buffer where data must be copied
00287   len the size of buf.
00288 
00289   return the number of byte copied if somes bytes are copied
00290   return 0 if the end of file was reached
00291   return <0 with error code if there is an error
00292     (UNZ_ERRNO for IO error, or zLib error for uncompress error)
00293 */
00294 
00295 z_off_t unztell(unzFile file);
00296 /*
00297   Give the current position in uncompressed data
00298 */
00299 
00300 int unzeof(unzFile file);
00301 /*
00302   return 1 if the end of file was reached, 0 elsewhere
00303 */
00304 
00305 int unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len);
00306 /*
00307   Read extra field from the current file (opened by unzOpenCurrentFile)
00308   This is the local-header version of the extra field (sometimes, there is
00309     more info in the local-header version than in the central-header)
00310 
00311   if buf==NULL, it return the size of the local extra field
00312 
00313   if buf!=NULL, len is the size of the buffer, the extra header is copied in
00314     buf.
00315   the return value is the number of bytes copied in buf, or (if <0)
00316     the error code
00317 */
00318 
00319 #if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \
00320                       !defined(CASESENSITIVITYDEFAULT_NO)
00321 #define CASESENSITIVITYDEFAULT_NO
00322 #endif
00323 
00324 
00325 #ifndef UNZ_BUFSIZE
00326 #define UNZ_BUFSIZE (16384)
00327 #endif
00328 
00329 #ifndef UNZ_MAXFILENAMEINZIP
00330 #define UNZ_MAXFILENAMEINZIP (256)
00331 #endif
00332 
00333 #define SIZECENTRALDIRITEM (0x2e)
00334 #define SIZEZIPLOCALHEADER (0x1e)
00335 
00336 
00337 #if 0
00338 const char unz_copyright[] =
00339    " unzip 0.15 Copyright 1998 Gilles Vollant ";
00340 #endif
00341 
00342 /* unz_file_info_interntal contain internal info about a file in zipfile*/
00343 typedef struct {
00344     uLong offset_curfile;/* relative offset of local header 4 bytes */
00345 } unz_file_info_internal;
00346 
00347 
00348 /* file_in_zip_read_info_s contain internal information about a file in zipfile,
00349     when reading and decompress it */
00350 typedef struct {
00351     char  *read_buffer;         /* internal buffer for compressed data */
00352     z_stream stream;            /* zLib stream structure for inflate */
00353 
00354     uLong pos_in_zipfile;       /* position in byte on the zipfile, for fseek*/
00355     uLong stream_initialized;   /* flag set if stream structure is initialized*/
00356 
00357     uLong offset_local_extrafield;/* offset of the local extra field */
00358     uInt  size_local_extrafield;/* size of the local extra field */
00359     uLong pos_local_extrafield;   /* position in the local extra field in read*/
00360 
00361     uLong crc32_data;                /* crc32 of all data uncompressed */
00362     uLong crc32_wait;           /* crc32 we must obtain after decompress all */
00363     uLong rest_read_compressed; /* number of byte to be decompressed */
00364     uLong rest_read_uncompressed;/*number of byte to be obtained after decomp*/
00365     Common::SeekableReadStream *_stream;                 /* io structore of the zipfile */
00366     uLong compression_method;   /* compression method (0==store) */
00367     uLong byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
00368 } file_in_zip_read_info_s;
00369 
00370 typedef struct {
00371     uLong num_file;                 /* number of the current file in the zipfile*/
00372     uLong pos_in_central_dir;       /* pos of the current file in the central dir*/
00373     uLong current_file_ok;          /* flag about the usability of the current file*/
00374     unz_file_info cur_file_info;                    /* public info about the current file in zip*/
00375     unz_file_info_internal cur_file_info_internal;  /* private info about it*/
00376 } cached_file_in_zip;
00377 
00378 typedef Common::HashMap<Common::String, cached_file_in_zip, Common::IgnoreCase_Hash,
00379     Common::IgnoreCase_EqualTo> ZipHash;
00380 
00381 /* unz_s contain internal information about the zipfile
00382 */
00383 typedef struct {
00384     Common::SeekableReadStream *_stream;                /* io structore of the zipfile */
00385     unz_global_info gi;             /* public global information */
00386     uLong byte_before_the_zipfile;  /* byte before the zipfile, (>0 for sfx)*/
00387     uLong num_file;                 /* number of the current file in the zipfile*/
00388     uLong pos_in_central_dir;       /* pos of the current file in the central dir*/
00389     uLong current_file_ok;          /* flag about the usability of the current file*/
00390     uLong central_pos;              /* position of the beginning of the central dir*/
00391 
00392     uLong size_central_dir;         /* size of the central directory  */
00393     uLong offset_central_dir;       /* offset of start of central directory with
00394                                     respect to the starting disk number */
00395 
00396     unz_file_info cur_file_info;                    /* public info about the current file in zip*/
00397     unz_file_info_internal cur_file_info_internal;  /* private info about it*/
00398     file_in_zip_read_info_s* pfile_in_zip_read;     /* structure about the current
00399                                                     file if we are decompressing it */
00400     ZipHash _hash;
00401 } unz_s;
00402 
00403 /* ===========================================================================
00404      Read a byte from a gz_stream; update next_in and avail_in. Return EOF
00405    for end of file.
00406    IN assertion: the stream s has been successfully opened for reading.
00407 */
00408 
00409 
00410 /*static int unzlocal_getByte(Common::SeekableReadStream &fin, int *pi) {
00411     unsigned char c = fin.readByte();
00412       *pi = (int)c;
00413         return UNZ_OK;
00414     } else {
00415         if (fin.err())
00416             return UNZ_ERRNO;
00417         else
00418             return UNZ_EOF;
00419     }
00420 }*/
00421 
00422 
00423 /* ===========================================================================
00424    Reads a long in LSB order from the given gz_stream. Sets
00425 */
00426 static int unzlocal_getShort(Common::SeekableReadStream *fin, uLong *pX) {
00427     *pX = fin->readUint16LE();
00428     return (fin->err() || fin->eos()) ? UNZ_ERRNO : UNZ_OK;
00429 }
00430 
00431 static int unzlocal_getLong(Common::SeekableReadStream *fin, uLong *pX) {
00432     *pX = fin->readUint32LE();
00433     return (fin->err() || fin->eos()) ? UNZ_ERRNO : UNZ_OK;
00434 }
00435 
00436 
00437 #ifdef  CASESENSITIVITYDEFAULT_NO
00438 #define CASESENSITIVITYDEFAULTVALUE 2
00439 #else
00440 #define CASESENSITIVITYDEFAULTVALUE 1
00441 #endif
00442 
00443 /*
00444    Compare two filename (fileName1,fileName2).
00445    If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
00446    If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
00447                                                                 or strcasecmp)
00448    If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
00449         (like 1 on Unix, 2 on Windows)
00450 
00451 */
00452 int unzStringFileNameCompare(const char* fileName1, const char* fileName2, int iCaseSensitivity) {
00453     if (iCaseSensitivity==0)
00454         iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
00455 
00456     if (iCaseSensitivity==1)
00457         return strcmp(fileName1,fileName2);
00458 
00459     return scumm_stricmp(fileName1,fileName2);
00460 }
00461 
00462 #define BUFREADCOMMENT (0x400)
00463 
00464 /*
00465   Locate the Central directory of a zipfile (at the end, just before
00466     the global comment)
00467 */
00468 static uLong unzlocal_SearchCentralDir(Common::SeekableReadStream &fin) {
00469     unsigned char* buf;
00470     uLong uSizeFile;
00471     uLong uBackRead;
00472     uLong uMaxBack=0xffff; /* maximum size of global comment */
00473     uLong uPosFound=0;
00474 
00475     uSizeFile = fin.size();
00476     if (fin.err())
00477         return 0;
00478 
00479     if (uMaxBack>uSizeFile)
00480         uMaxBack = uSizeFile;
00481 
00482     buf = (unsigned char*)malloc(BUFREADCOMMENT+4);
00483     if (buf==nullptr)
00484         return 0;
00485 
00486     uBackRead = 4;
00487     while (uBackRead<uMaxBack) {
00488         uLong uReadSize,uReadPos;
00489         int i;
00490         if (uBackRead+BUFREADCOMMENT>uMaxBack)
00491             uBackRead = uMaxBack;
00492         else
00493             uBackRead+=BUFREADCOMMENT;
00494         uReadPos = uSizeFile-uBackRead;
00495 
00496         uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
00497                      (BUFREADCOMMENT+4) : (uSizeFile-uReadPos);
00498         fin.seek(uReadPos, SEEK_SET);
00499         if (fin.err())
00500             break;
00501 
00502         if (fin.read(buf,(uInt)uReadSize)!=uReadSize)
00503             break;
00504 
00505                 for (i=(int)uReadSize-3; (i--)>0;)
00506             if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
00507                 ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
00508             {
00509                 uPosFound = uReadPos+i;
00510                 break;
00511             }
00512 
00513         if (uPosFound!=0)
00514             break;
00515     }
00516     free(buf);
00517     return uPosFound;
00518 }
00519 
00520 /*
00521   Open a Zip file. path contain the full pathname (by example,
00522      on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer
00523      "zlib/zlib109.zip".
00524      If the zipfile cannot be opened (file don't exist or in not valid), the
00525        return value is NULL.
00526      Else, the return value is a unzFile Handle, usable with other function
00527        of this unzip package.
00528 */
00529 unzFile unzOpen(Common::SeekableReadStream *stream) {
00530     if (!stream)
00531         return nullptr;
00532 
00533     unz_s *us = new unz_s;
00534     uLong central_pos,uL;
00535 
00536     uLong number_disk;          /* number of the current dist, used for
00537                                    spaning ZIP, unsupported, always 0*/
00538     uLong number_disk_with_CD;  /* number the the disk with central dir, used
00539                                    for spaning ZIP, unsupported, always 0*/
00540     uLong number_entry_CD;      /* total number of entries in
00541                                    the central dir
00542                                    (same than number_entry on nospan) */
00543 
00544     int err=UNZ_OK;
00545 
00546     us->_stream = stream;
00547 
00548     central_pos = unzlocal_SearchCentralDir(*us->_stream);
00549     if (central_pos==0)
00550         err=UNZ_ERRNO;
00551 
00552     us->_stream->seek(central_pos, SEEK_SET);
00553     if (us->_stream->err())
00554         err=UNZ_ERRNO;
00555 
00556     /* the signature, already checked */
00557     if (unzlocal_getLong(us->_stream,&uL)!=UNZ_OK)
00558         err=UNZ_ERRNO;
00559 
00560     /* number of this disk */
00561     if (unzlocal_getShort(us->_stream,&number_disk)!=UNZ_OK)
00562         err=UNZ_ERRNO;
00563 
00564     /* number of the disk with the start of the central directory */
00565     if (unzlocal_getShort(us->_stream,&number_disk_with_CD)!=UNZ_OK)
00566         err=UNZ_ERRNO;
00567 
00568     /* total number of entries in the central dir on this disk */
00569     if (unzlocal_getShort(us->_stream,&us->gi.number_entry)!=UNZ_OK)
00570         err=UNZ_ERRNO;
00571 
00572     /* total number of entries in the central dir */
00573     if (unzlocal_getShort(us->_stream,&number_entry_CD)!=UNZ_OK)
00574         err=UNZ_ERRNO;
00575 
00576     if ((number_entry_CD!=us->gi.number_entry) ||
00577         (number_disk_with_CD!=0) ||
00578         (number_disk!=0))
00579         err=UNZ_BADZIPFILE;
00580 
00581     /* size of the central directory */
00582     if (unzlocal_getLong(us->_stream,&us->size_central_dir)!=UNZ_OK)
00583         err=UNZ_ERRNO;
00584 
00585     /* offset of start of central directory with respect to the
00586           starting disk number */
00587     if (unzlocal_getLong(us->_stream,&us->offset_central_dir)!=UNZ_OK)
00588         err=UNZ_ERRNO;
00589 
00590     /* zipfile comment length */
00591     if (unzlocal_getShort(us->_stream,&us->gi.size_comment)!=UNZ_OK)
00592         err=UNZ_ERRNO;
00593 
00594     if ((central_pos<us->offset_central_dir+us->size_central_dir) && (err==UNZ_OK))
00595         err=UNZ_BADZIPFILE;
00596 
00597     if (err != UNZ_OK) {
00598         delete us->_stream;
00599         delete us;
00600         return nullptr;
00601     }
00602 
00603     us->byte_before_the_zipfile = central_pos -
00604                             (us->offset_central_dir+us->size_central_dir);
00605     us->central_pos = central_pos;
00606     us->pfile_in_zip_read = nullptr;
00607 
00608     err = unzGoToFirstFile((unzFile)us);
00609 
00610     while (err == UNZ_OK) {
00611         // Get the file details
00612         char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
00613         unzGetCurrentFileInfo(us, nullptr, szCurrentFileName, sizeof(szCurrentFileName) - 1,
00614                             nullptr, 0, nullptr, 0);
00615 
00616         // Save details into the hash
00617         cached_file_in_zip fe;
00618         fe.num_file = us->num_file;
00619         fe.pos_in_central_dir = us->pos_in_central_dir;
00620         fe.current_file_ok = us->current_file_ok;
00621         fe.cur_file_info = us->cur_file_info;
00622         fe.cur_file_info_internal = us->cur_file_info_internal;
00623 
00624         us->_hash[Common::String(szCurrentFileName)] = fe;
00625 
00626         // Move to the next file
00627         err = unzGoToNextFile((unzFile)us);
00628     }
00629     return (unzFile)us;
00630 }
00631 
00632 
00633 /*
00634   Close a ZipFile opened with unzipOpen.
00635   If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
00636     these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
00637   return UNZ_OK if there is no problem. */
00638 int unzClose(unzFile file) {
00639     unz_s *s;
00640     if (file == nullptr)
00641         return UNZ_PARAMERROR;
00642     s = (unz_s *)file;
00643 
00644     if (s->pfile_in_zip_read != nullptr)
00645         unzCloseCurrentFile(file);
00646 
00647     delete s->_stream;
00648     delete s;
00649     return UNZ_OK;
00650 }
00651 
00652 
00653 /*
00654   Write info about the ZipFile in the *pglobal_info structure.
00655   No preparation of the structure is needed
00656   return UNZ_OK if there is no problem. */
00657 int unzGetGlobalInfo(unzFile file, unz_global_info *pglobal_info) {
00658     unz_s *s;
00659     if (file == nullptr)
00660         return UNZ_PARAMERROR;
00661     s = (unz_s *)file;
00662     *pglobal_info = s->gi;
00663     return UNZ_OK;
00664 }
00665 
00666 
00667 /*
00668    Translate date/time from Dos format to tm_unz (readable more easilty)
00669 */
00670 static void unzlocal_DosDateToTmuDate(uLong ulDosDate, tm_unz* ptm) {
00671     uLong uDate;
00672     uDate = (uLong)(ulDosDate>>16);
00673     ptm->tm_mday = (uInt)(uDate&0x1f);
00674     ptm->tm_mon =  (uInt)((((uDate)&0x1E0)/0x20)-1);
00675     ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980);
00676 
00677     ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
00678     ptm->tm_min =  (uInt) ((ulDosDate&0x7E0)/0x20);
00679     ptm->tm_sec =  (uInt) (2*(ulDosDate&0x1f));
00680 }
00681 
00682 /*
00683   Get Info about the current file in the zipfile, with internal only info
00684 */
00685 static int unzlocal_GetCurrentFileInfoInternal(unzFile file,
00686                                                   unz_file_info *pfile_info,
00687                                                   unz_file_info_internal
00688                                                   *pfile_info_internal,
00689                                                   char *szFileName,
00690                                                   uLong fileNameBufferSize,
00691                                                   void *extraField,
00692                                                   uLong extraFieldBufferSize,
00693                                                   char *szComment,
00694                                                   uLong commentBufferSize);
00695 
00696 static int unzlocal_GetCurrentFileInfoInternal(unzFile file,
00697                                               unz_file_info *pfile_info,
00698                                               unz_file_info_internal *pfile_info_internal,
00699                                               char *szFileName, uLong fileNameBufferSize,
00700                                               void *extraField, uLong extraFieldBufferSize,
00701                                               char *szComment,  uLong commentBufferSize)
00702 {
00703     unz_s* s;
00704     unz_file_info file_info;
00705     unz_file_info_internal file_info_internal;
00706     int err=UNZ_OK;
00707     uLong uMagic;
00708     long lSeek=0;
00709 
00710     if (file==nullptr)
00711         return UNZ_PARAMERROR;
00712     s=(unz_s*)file;
00713     s->_stream->seek(s->pos_in_central_dir+s->byte_before_the_zipfile, SEEK_SET);
00714     if (s->_stream->err())
00715         err=UNZ_ERRNO;
00716 
00717 
00718     /* we check the magic */
00719     if (err==UNZ_OK) {
00720         if (unzlocal_getLong(s->_stream,&uMagic) != UNZ_OK)
00721             err=UNZ_ERRNO;
00722         else if (uMagic!=0x02014b50)
00723             err=UNZ_BADZIPFILE;
00724     }
00725 
00726     if (unzlocal_getShort(s->_stream,&file_info.version) != UNZ_OK)
00727         err=UNZ_ERRNO;
00728 
00729     if (unzlocal_getShort(s->_stream,&file_info.version_needed) != UNZ_OK)
00730         err=UNZ_ERRNO;
00731 
00732     if (unzlocal_getShort(s->_stream,&file_info.flag) != UNZ_OK)
00733         err=UNZ_ERRNO;
00734 
00735     if (unzlocal_getShort(s->_stream,&file_info.compression_method) != UNZ_OK)
00736         err=UNZ_ERRNO;
00737 
00738     if (unzlocal_getLong(s->_stream,&file_info.dosDate) != UNZ_OK)
00739         err=UNZ_ERRNO;
00740 
00741     unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
00742 
00743     if (unzlocal_getLong(s->_stream,&file_info.crc) != UNZ_OK)
00744         err=UNZ_ERRNO;
00745 
00746     if (unzlocal_getLong(s->_stream,&file_info.compressed_size) != UNZ_OK)
00747         err=UNZ_ERRNO;
00748 
00749     if (unzlocal_getLong(s->_stream,&file_info.uncompressed_size) != UNZ_OK)
00750         err=UNZ_ERRNO;
00751 
00752     if (unzlocal_getShort(s->_stream,&file_info.size_filename) != UNZ_OK)
00753         err=UNZ_ERRNO;
00754 
00755     if (unzlocal_getShort(s->_stream,&file_info.size_file_extra) != UNZ_OK)
00756         err=UNZ_ERRNO;
00757 
00758     if (unzlocal_getShort(s->_stream,&file_info.size_file_comment) != UNZ_OK)
00759         err=UNZ_ERRNO;
00760 
00761     if (unzlocal_getShort(s->_stream,&file_info.disk_num_start) != UNZ_OK)
00762         err=UNZ_ERRNO;
00763 
00764     if (unzlocal_getShort(s->_stream,&file_info.internal_fa) != UNZ_OK)
00765         err=UNZ_ERRNO;
00766 
00767     if (unzlocal_getLong(s->_stream,&file_info.external_fa) != UNZ_OK)
00768         err=UNZ_ERRNO;
00769 
00770     if (unzlocal_getLong(s->_stream,&file_info_internal.offset_curfile) != UNZ_OK)
00771         err=UNZ_ERRNO;
00772 
00773     lSeek+=file_info.size_filename;
00774     if ((err==UNZ_OK) && (szFileName!=nullptr)) {
00775         uLong uSizeRead;
00776         if (file_info.size_filename<fileNameBufferSize) {
00777             *(szFileName+file_info.size_filename)='\0';
00778             uSizeRead = file_info.size_filename;
00779         } else
00780             uSizeRead = fileNameBufferSize;
00781 
00782         if ((file_info.size_filename>0) && (fileNameBufferSize>0))
00783             if (s->_stream->read(szFileName,(uInt)uSizeRead)!=uSizeRead)
00784                 err=UNZ_ERRNO;
00785         lSeek -= uSizeRead;
00786     }
00787 
00788 
00789     if ((err==UNZ_OK) && (extraField!=nullptr)) {
00790         uLong uSizeRead;
00791         if (file_info.size_file_extra<extraFieldBufferSize)
00792             uSizeRead = file_info.size_file_extra;
00793         else
00794             uSizeRead = extraFieldBufferSize;
00795 
00796         if (lSeek!=0) {
00797             s->_stream->seek(lSeek, SEEK_CUR);
00798             if (s->_stream->err())
00799                 lSeek=0;
00800             else
00801                 err=UNZ_ERRNO;
00802         }
00803         if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
00804             if (s->_stream->read(extraField,(uInt)uSizeRead)!=uSizeRead)
00805                 err=UNZ_ERRNO;
00806         lSeek += file_info.size_file_extra - uSizeRead;
00807     }
00808     else
00809         lSeek+=file_info.size_file_extra;
00810 
00811 
00812     if ((err==UNZ_OK) && (szComment!=nullptr)) {
00813         uLong uSizeRead;
00814         if (file_info.size_file_comment<commentBufferSize) {
00815             *(szComment+file_info.size_file_comment)='\0';
00816             uSizeRead = file_info.size_file_comment;
00817         } else
00818             uSizeRead = commentBufferSize;
00819 
00820         if (lSeek!=0) {
00821             s->_stream->seek(lSeek, SEEK_CUR);
00822             if (s->_stream->err())
00823                 lSeek=0;
00824             else
00825                 err=UNZ_ERRNO;
00826         }
00827         if ((file_info.size_file_comment>0) && (commentBufferSize>0))
00828             if (s->_stream->read(szComment,(uInt)uSizeRead)!=uSizeRead)
00829                 err=UNZ_ERRNO;
00830         lSeek+=file_info.size_file_comment - uSizeRead;
00831     } else
00832         lSeek+=file_info.size_file_comment;
00833 
00834     if ((err==UNZ_OK) && (pfile_info!=nullptr))
00835         *pfile_info=file_info;
00836 
00837     if ((err==UNZ_OK) && (pfile_info_internal!=nullptr))
00838         *pfile_info_internal=file_info_internal;
00839 
00840     return err;
00841 }
00842 
00843 
00844 
00845 /*
00846   Write info about the ZipFile in the *pglobal_info structure.
00847   No preparation of the structure is needed
00848   return UNZ_OK if there is no problem.
00849 */
00850 int unzGetCurrentFileInfo(unzFile file,
00851                                                   unz_file_info *pfile_info,
00852                                                   char *szFileName, uLong fileNameBufferSize,
00853                                                   void *extraField, uLong extraFieldBufferSize,
00854                                                   char *szComment,  uLong commentBufferSize)
00855 {
00856     return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,nullptr,
00857                                                 szFileName,fileNameBufferSize,
00858                                                 extraField,extraFieldBufferSize,
00859                                                 szComment,commentBufferSize);
00860 }
00861 
00862 /*
00863   Set the current file of the zipfile to the first file.
00864   return UNZ_OK if there is no problem
00865 */
00866 int unzGoToFirstFile(unzFile file) {
00867     int err=UNZ_OK;
00868     unz_s* s;
00869     if (file==nullptr)
00870         return UNZ_PARAMERROR;
00871     s=(unz_s*)file;
00872     s->pos_in_central_dir=s->offset_central_dir;
00873     s->num_file=0;
00874     err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
00875                                              &s->cur_file_info_internal,
00876                                              nullptr,0,nullptr,0,nullptr,0);
00877     s->current_file_ok = (err == UNZ_OK);
00878     return err;
00879 }
00880 
00881 
00882 /*
00883   Set the current file of the zipfile to the next file.
00884   return UNZ_OK if there is no problem
00885   return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
00886 */
00887 int unzGoToNextFile(unzFile file) {
00888     unz_s* s;
00889     int err;
00890 
00891     if (file==nullptr)
00892         return UNZ_PARAMERROR;
00893     s=(unz_s*)file;
00894     if (!s->current_file_ok)
00895         return UNZ_END_OF_LIST_OF_FILE;
00896     if (s->num_file+1==s->gi.number_entry)
00897         return UNZ_END_OF_LIST_OF_FILE;
00898 
00899     s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
00900             s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment;
00901     s->num_file++;
00902     err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info,
00903                                                &s->cur_file_info_internal,
00904                                                nullptr,0,nullptr,0,nullptr,0);
00905     s->current_file_ok = (err == UNZ_OK);
00906     return err;
00907 }
00908 
00909 /*
00910   Try locate the file szFileName in the zipfile.
00911   For the iCaseSensitivity signification, see unzipStringFileNameCompare
00912 
00913   return value :
00914   UNZ_OK if the file is found. It becomes the current file.
00915   UNZ_END_OF_LIST_OF_FILE if the file is not found
00916 */
00917 int unzLocateFile(unzFile file, const char *szFileName, int iCaseSensitivity) {
00918     unz_s* s;
00919 
00920     if (file==nullptr)
00921         return UNZ_PARAMERROR;
00922 
00923     if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
00924         return UNZ_PARAMERROR;
00925 
00926     s=(unz_s*)file;
00927     if (!s->current_file_ok)
00928         return UNZ_END_OF_LIST_OF_FILE;
00929 
00930     // Check to see if the entry exists
00931     ZipHash::iterator i = s->_hash.find(Common::String(szFileName));
00932     if (i == s->_hash.end())
00933         return UNZ_END_OF_LIST_OF_FILE;
00934 
00935     // Found it, so reset the details in the main structure
00936     cached_file_in_zip &fe = i->_value;
00937     s->num_file = fe.num_file;
00938     s->pos_in_central_dir = fe.pos_in_central_dir;
00939     s->current_file_ok = fe.current_file_ok;
00940     s->cur_file_info = fe.cur_file_info;
00941     s->cur_file_info_internal = fe.cur_file_info_internal;
00942 
00943     return UNZ_OK;
00944 }
00945 
00946 
00947 /*
00948   Read the local header of the current zipfile
00949   Check the coherency of the local header and info in the end of central
00950         directory about this file
00951   store in *piSizeVar the size of extra info in local header
00952         (filename and size of extra field data)
00953 */
00954 static int unzlocal_CheckCurrentFileCoherencyHeader(unz_s* s, uInt* piSizeVar,
00955                                                     uLong *poffset_local_extrafield,
00956                                                     uInt  *psize_local_extrafield) {
00957     uLong uMagic,uData,uFlags;
00958     uLong size_filename;
00959     uLong size_extra_field;
00960     int err=UNZ_OK;
00961 
00962     *piSizeVar = 0;
00963     *poffset_local_extrafield = 0;
00964     *psize_local_extrafield = 0;
00965 
00966     s->_stream->seek(s->cur_file_info_internal.offset_curfile +
00967                                 s->byte_before_the_zipfile, SEEK_SET);
00968     if (s->_stream->err())
00969         return UNZ_ERRNO;
00970 
00971 
00972     if (err==UNZ_OK) {
00973         if (unzlocal_getLong(s->_stream,&uMagic) != UNZ_OK)
00974             err=UNZ_ERRNO;
00975         else if (uMagic!=0x04034b50)
00976             err=UNZ_BADZIPFILE;
00977     }
00978 
00979     if (unzlocal_getShort(s->_stream,&uData) != UNZ_OK)
00980         err=UNZ_ERRNO;
00981 /*
00982     else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
00983         err=UNZ_BADZIPFILE;
00984 */
00985     if (unzlocal_getShort(s->_stream,&uFlags) != UNZ_OK)
00986         err=UNZ_ERRNO;
00987 
00988     if (unzlocal_getShort(s->_stream,&uData) != UNZ_OK)
00989         err=UNZ_ERRNO;
00990     else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
00991         err=UNZ_BADZIPFILE;
00992 
00993     if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
00994                          (s->cur_file_info.compression_method!=Z_DEFLATED))
00995         err=UNZ_BADZIPFILE;
00996 
00997     if (unzlocal_getLong(s->_stream,&uData) != UNZ_OK) /* date/time */
00998         err=UNZ_ERRNO;
00999 
01000     if (unzlocal_getLong(s->_stream,&uData) != UNZ_OK) /* crc */
01001         err=UNZ_ERRNO;
01002     else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) &&
01003                               ((uFlags & 8)==0))
01004         err=UNZ_BADZIPFILE;
01005 
01006     if (unzlocal_getLong(s->_stream,&uData) != UNZ_OK) /* size compr */
01007         err=UNZ_ERRNO;
01008     else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) &&
01009                               ((uFlags & 8)==0))
01010         err=UNZ_BADZIPFILE;
01011 
01012     if (unzlocal_getLong(s->_stream,&uData) != UNZ_OK) /* size uncompr */
01013         err=UNZ_ERRNO;
01014     else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) &&
01015                               ((uFlags & 8)==0))
01016         err=UNZ_BADZIPFILE;
01017 
01018 
01019     if (unzlocal_getShort(s->_stream,&size_filename) != UNZ_OK)
01020         err=UNZ_ERRNO;
01021     else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
01022         err=UNZ_BADZIPFILE;
01023 
01024     *piSizeVar += (uInt)size_filename;
01025 
01026     if (unzlocal_getShort(s->_stream,&size_extra_field) != UNZ_OK)
01027         err=UNZ_ERRNO;
01028     *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
01029                                     SIZEZIPLOCALHEADER + size_filename;
01030     *psize_local_extrafield = (uInt)size_extra_field;
01031 
01032     *piSizeVar += (uInt)size_extra_field;
01033 
01034     return err;
01035 }
01036 
01037 /*
01038   Open for reading data the current file in the zipfile.
01039   If there is no error and the file is opened, the return value is UNZ_OK.
01040 */
01041 int unzOpenCurrentFile (unzFile file) {
01042     int err=UNZ_OK;
01043     int Store;
01044     uInt iSizeVar;
01045     unz_s* s;
01046     file_in_zip_read_info_s* pfile_in_zip_read_info;
01047     uLong offset_local_extrafield;  /* offset of the local extra field */
01048     uInt  size_local_extrafield;    /* size of the local extra field */
01049 
01050     if (file==nullptr)
01051         return UNZ_PARAMERROR;
01052     s=(unz_s*)file;
01053     if (!s->current_file_ok)
01054         return UNZ_PARAMERROR;
01055 
01056     if (s->pfile_in_zip_read != nullptr)
01057         unzCloseCurrentFile(file);
01058 
01059     if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar,
01060                 &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
01061         return UNZ_BADZIPFILE;
01062 
01063     pfile_in_zip_read_info = (file_in_zip_read_info_s*) malloc(sizeof(file_in_zip_read_info_s));
01064 
01065     if (pfile_in_zip_read_info==nullptr)
01066         return UNZ_INTERNALERROR;
01067 
01068     pfile_in_zip_read_info->read_buffer=(char *)malloc(UNZ_BUFSIZE);
01069     pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
01070     pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
01071     pfile_in_zip_read_info->pos_local_extrafield=0;
01072 
01073     if (pfile_in_zip_read_info->read_buffer==nullptr)
01074     {
01075         free(pfile_in_zip_read_info);
01076         return UNZ_INTERNALERROR;
01077     }
01078 
01079     pfile_in_zip_read_info->stream_initialized=0;
01080 
01081     if ((s->cur_file_info.compression_method!=0) &&
01082         (s->cur_file_info.compression_method!=Z_DEFLATED))
01083         err=UNZ_BADZIPFILE;
01084     Store = s->cur_file_info.compression_method==0;
01085 
01086     pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
01087     pfile_in_zip_read_info->crc32_data=0;
01088     pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method;
01089     pfile_in_zip_read_info->_stream=s->_stream;
01090     pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
01091 
01092     pfile_in_zip_read_info->stream.total_out = 0;
01093 
01094     if (!Store) {
01095 #ifdef USE_ZLIB
01096         pfile_in_zip_read_info->stream.zalloc = (alloc_func)nullptr;
01097         pfile_in_zip_read_info->stream.zfree = (free_func)nullptr;
01098         pfile_in_zip_read_info->stream.opaque = (voidpf)nullptr;
01099 
01100         err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
01101         if (err == Z_OK)
01102             pfile_in_zip_read_info->stream_initialized = 1;
01103     /* windowBits is passed < 0 to tell that there is no zlib header.
01104      * Note that in this case inflate *requires* an extra "dummy" byte
01105      * after the compressed stream in order to complete decompression and
01106      * return Z_STREAM_END.
01107      * In unzip, i don't wait absolutely Z_STREAM_END because I known the
01108      * size of both compressed and uncompressed data
01109      */
01110 #else
01111         err=UNZ_BADZIPFILE;
01112 #endif
01113     }
01114     pfile_in_zip_read_info->rest_read_compressed = s->cur_file_info.compressed_size;
01115     pfile_in_zip_read_info->rest_read_uncompressed = s->cur_file_info.uncompressed_size;
01116 
01117 
01118     pfile_in_zip_read_info->pos_in_zipfile =
01119         s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + iSizeVar;
01120 
01121     pfile_in_zip_read_info->stream.avail_in = (uInt)0;
01122 
01123     s->pfile_in_zip_read = pfile_in_zip_read_info;
01124     return err;
01125 }
01126 
01127 
01128 /*
01129   Read bytes from the current file.
01130   buf contain buffer where data must be copied
01131   len the size of buf.
01132 
01133   return the number of byte copied if somes bytes are copied
01134   return 0 if the end of file was reached
01135   return <0 with error code if there is an error
01136     (UNZ_ERRNO for IO error, or zLib error for uncompress error)
01137 */
01138 int unzReadCurrentFile(unzFile file, voidp buf, unsigned len) {
01139     int err=UNZ_OK;
01140     uInt iRead = 0;
01141     unz_s* s;
01142     file_in_zip_read_info_s* pfile_in_zip_read_info;
01143     if (file==nullptr)
01144         return UNZ_PARAMERROR;
01145     s=(unz_s*)file;
01146     pfile_in_zip_read_info=s->pfile_in_zip_read;
01147 
01148     if (pfile_in_zip_read_info==nullptr)
01149         return UNZ_PARAMERROR;
01150 
01151 
01152     if (pfile_in_zip_read_info->read_buffer == nullptr)
01153         return UNZ_END_OF_LIST_OF_FILE;
01154     if (len==0)
01155         return 0;
01156 
01157     pfile_in_zip_read_info->stream.next_out = (Bytef *)buf;
01158 
01159     pfile_in_zip_read_info->stream.avail_out = (uInt)len;
01160 
01161     if (len>pfile_in_zip_read_info->rest_read_uncompressed)
01162         pfile_in_zip_read_info->stream.avail_out =
01163           (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
01164 
01165     while (pfile_in_zip_read_info->stream.avail_out>0) {
01166         if ((pfile_in_zip_read_info->stream.avail_in==0) &&
01167             (pfile_in_zip_read_info->rest_read_compressed>0)) {
01168             uInt uReadThis = UNZ_BUFSIZE;
01169             if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
01170                 uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
01171             if (uReadThis == 0)
01172                 return UNZ_EOF;
01173             pfile_in_zip_read_info->_stream->seek(pfile_in_zip_read_info->pos_in_zipfile +
01174                 pfile_in_zip_read_info->byte_before_the_zipfile, SEEK_SET);
01175             if (pfile_in_zip_read_info->_stream->err())
01176                 return UNZ_ERRNO;
01177             if (pfile_in_zip_read_info->_stream->read(pfile_in_zip_read_info->read_buffer,uReadThis)!=uReadThis)
01178                 return UNZ_ERRNO;
01179             pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
01180 
01181             pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
01182 
01183             pfile_in_zip_read_info->stream.next_in = (Bytef *)pfile_in_zip_read_info->read_buffer;
01184             pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
01185         }
01186 
01187         if (pfile_in_zip_read_info->compression_method==0) {
01188             uInt uDoCopy,i;
01189             if (pfile_in_zip_read_info->stream.avail_out < pfile_in_zip_read_info->stream.avail_in)
01190                 uDoCopy = pfile_in_zip_read_info->stream.avail_out;
01191             else
01192                 uDoCopy = pfile_in_zip_read_info->stream.avail_in;
01193 
01194             for (i=0;i<uDoCopy;i++)
01195                 *(pfile_in_zip_read_info->stream.next_out+i) = *(pfile_in_zip_read_info->stream.next_in+i);
01196 
01197 #ifdef USE_ZLIB
01198             pfile_in_zip_read_info->crc32_data = crc32(pfile_in_zip_read_info->crc32_data,
01199                                 pfile_in_zip_read_info->stream.next_out,
01200                                 uDoCopy);
01201 #endif  // otherwise leave crc32_data as is and it won't be verified at the end
01202             pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
01203             pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
01204             pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
01205             pfile_in_zip_read_info->stream.next_out += uDoCopy;
01206             pfile_in_zip_read_info->stream.next_in += uDoCopy;
01207             pfile_in_zip_read_info->stream.total_out += uDoCopy;
01208             iRead += uDoCopy;
01209         } else {
01210 #ifdef USE_ZLIB
01211             uLong uTotalOutBefore,uTotalOutAfter;
01212             const Bytef *bufBefore;
01213             uLong uOutThis;
01214             int flush = Z_SYNC_FLUSH;
01215 
01216             uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
01217             bufBefore = pfile_in_zip_read_info->stream.next_out;
01218 
01219             /*
01220             if ((pfile_in_zip_read_info->rest_read_uncompressed ==
01221                      pfile_in_zip_read_info->stream.avail_out) &&
01222                 (pfile_in_zip_read_info->rest_read_compressed == 0))
01223                 flush = Z_FINISH;
01224             */
01225             err=inflate(&pfile_in_zip_read_info->stream,flush);
01226 
01227             uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
01228             uOutThis = uTotalOutAfter-uTotalOutBefore;
01229 
01230             pfile_in_zip_read_info->crc32_data =
01231                 crc32(pfile_in_zip_read_info->crc32_data,bufBefore, (uInt)(uOutThis));
01232 
01233             pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis;
01234 
01235             iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
01236 
01237             if (err==Z_STREAM_END)
01238                 return (iRead==0) ? UNZ_EOF : iRead;
01239             if (err!=Z_OK)
01240                 break;
01241 #else
01242             // Cannot decompress the file without zlib.
01243             err = UNZ_BADZIPFILE;
01244             break;
01245 #endif
01246         }
01247     }
01248 
01249     if (err==Z_OK)
01250         return iRead;
01251     return err;
01252 }
01253 
01254 
01255 /*
01256   Give the current position in uncompressed data
01257 */
01258 z_off_t unztell(unzFile file) {
01259     unz_s* s;
01260     file_in_zip_read_info_s* pfile_in_zip_read_info;
01261     if (file==nullptr)
01262         return UNZ_PARAMERROR;
01263     s=(unz_s*)file;
01264     pfile_in_zip_read_info=s->pfile_in_zip_read;
01265 
01266     if (pfile_in_zip_read_info==nullptr)
01267         return UNZ_PARAMERROR;
01268 
01269     return (z_off_t)pfile_in_zip_read_info->stream.total_out;
01270 }
01271 
01272 
01273 /*
01274   return 1 if the end of file was reached, 0 elsewhere
01275 */
01276 int unzeof(unzFile file) {
01277     unz_s* s;
01278     file_in_zip_read_info_s* pfile_in_zip_read_info;
01279     if (file==nullptr)
01280         return UNZ_PARAMERROR;
01281     s=(unz_s*)file;
01282     pfile_in_zip_read_info=s->pfile_in_zip_read;
01283 
01284     if (pfile_in_zip_read_info==nullptr)
01285         return UNZ_PARAMERROR;
01286 
01287     if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
01288         return 1;
01289     else
01290         return 0;
01291 }
01292 
01293 
01294 
01295 /*
01296   Read extra field from the current file (opened by unzOpenCurrentFile)
01297   This is the local-header version of the extra field (sometimes, there is
01298     more info in the local-header version than in the central-header)
01299 
01300   if buf==NULL, it return the size of the local extra field that can be read
01301 
01302   if buf!=NULL, len is the size of the buffer, the extra header is copied in
01303     buf.
01304   the return value is the number of bytes copied in buf, or (if <0)
01305     the error code
01306 */
01307 int unzGetLocalExtrafield(unzFile file, voidp buf, unsigned len) {
01308     unz_s* s;
01309     file_in_zip_read_info_s* pfile_in_zip_read_info;
01310     uInt read_now;
01311     uLong size_to_read;
01312 
01313     if (file==nullptr)
01314         return UNZ_PARAMERROR;
01315     s=(unz_s*)file;
01316     pfile_in_zip_read_info=s->pfile_in_zip_read;
01317 
01318     if (pfile_in_zip_read_info==nullptr)
01319         return UNZ_PARAMERROR;
01320 
01321     size_to_read = (pfile_in_zip_read_info->size_local_extrafield -
01322                 pfile_in_zip_read_info->pos_local_extrafield);
01323 
01324     if (buf==nullptr)
01325         return (int)size_to_read;
01326 
01327     if (len>size_to_read)
01328         read_now = (uInt)size_to_read;
01329     else
01330         read_now = (uInt)len;
01331 
01332     if (read_now==0)
01333         return 0;
01334 
01335     pfile_in_zip_read_info->_stream->seek(pfile_in_zip_read_info->offset_local_extrafield +
01336               pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET);
01337     if (pfile_in_zip_read_info->_stream->err())
01338         return UNZ_ERRNO;
01339 
01340     if (pfile_in_zip_read_info->_stream->read(buf,(uInt)size_to_read)!=size_to_read)
01341         return UNZ_ERRNO;
01342 
01343     return (int)read_now;
01344 }
01345 
01346 /*
01347   Close the file in zip opened with unzipOpenCurrentFile
01348   Return UNZ_CRCERROR if all the file was read but the CRC is not good
01349 */
01350 int unzCloseCurrentFile(unzFile file) {
01351     int err=UNZ_OK;
01352 
01353     unz_s* s;
01354     file_in_zip_read_info_s* pfile_in_zip_read_info;
01355     if (file == nullptr)
01356         return UNZ_PARAMERROR;
01357     s = (unz_s*)file;
01358     pfile_in_zip_read_info = s->pfile_in_zip_read;
01359 
01360     if (pfile_in_zip_read_info == nullptr)
01361         return UNZ_PARAMERROR;
01362 
01363 
01364 #ifdef USE_ZLIB
01365     // Only verify crc32_data when zlib is linked in, because otherwise crc32() is
01366     // not defined.
01367     if (pfile_in_zip_read_info->rest_read_uncompressed == 0) {
01368         if (pfile_in_zip_read_info->crc32_data != pfile_in_zip_read_info->crc32_wait)
01369             err=UNZ_CRCERROR;
01370     }
01371     if (pfile_in_zip_read_info->stream_initialized)
01372         inflateEnd(&pfile_in_zip_read_info->stream);
01373 #endif
01374 
01375 
01376     free(pfile_in_zip_read_info->read_buffer);
01377     pfile_in_zip_read_info->read_buffer = nullptr;
01378 
01379     pfile_in_zip_read_info->stream_initialized = 0;
01380     free(pfile_in_zip_read_info);
01381 
01382     s->pfile_in_zip_read=nullptr;
01383 
01384     return err;
01385 }
01386 
01387 
01388 /*
01389   Get the global comment string of the ZipFile, in the szComment buffer.
01390   uSizeBuf is the size of the szComment buffer.
01391   return the number of byte copied or an error code <0
01392 */
01393 int unzGetGlobalComment(unzFile file, char *szComment, uLong uSizeBuf) {
01394     unz_s* s;
01395     uLong uReadThis;
01396     if (file==nullptr)
01397         return UNZ_PARAMERROR;
01398     s=(unz_s*)file;
01399 
01400     uReadThis = uSizeBuf;
01401     if (uReadThis>s->gi.size_comment)
01402         uReadThis = s->gi.size_comment;
01403 
01404     s->_stream->seek(s->central_pos+22, SEEK_SET);
01405     if (s->_stream->err())
01406         return UNZ_ERRNO;
01407 
01408     if (uReadThis>0) {
01409         *szComment='\0';
01410         if (s->_stream->read(szComment,(uInt)uReadThis)!=uReadThis)
01411             return UNZ_ERRNO;
01412     }
01413 
01414     if ((szComment != nullptr) && (uSizeBuf > s->gi.size_comment))
01415         *(szComment+s->gi.size_comment)='\0';
01416     return (int)uReadThis;
01417 }
01418 
01419 
01420 namespace Common {
01421 
01422 
01423 class ZipArchive : public Archive {
01424     unzFile _zipFile;
01425 
01426 public:
01427     ZipArchive(unzFile zipFile);
01428 
01429 
01430     ~ZipArchive();
01431 
01432     virtual bool hasFile(const String &name) const;
01433     virtual int listMembers(ArchiveMemberList &list) const;
01434     virtual const ArchiveMemberPtr getMember(const String &name) const;
01435     virtual SeekableReadStream *createReadStreamForMember(const String &name) const;
01436 };
01437 
01438 /*
01439 class ZipArchiveMember : public ArchiveMember {
01440     unzFile _zipFile;
01441 
01442 public:
01443     ZipArchiveMember(FSNode &node) : _node(node) {
01444     }
01445 
01446     String getName() const {
01447         ...
01448     }
01449 
01450     SeekableReadStream *open() {
01451         ...
01452     }
01453 };
01454 */
01455 
01456 ZipArchive::ZipArchive(unzFile zipFile) : _zipFile(zipFile) {
01457     assert(_zipFile);
01458 }
01459 
01460 ZipArchive::~ZipArchive() {
01461     unzClose(_zipFile);
01462 }
01463 
01464 bool ZipArchive::hasFile(const String &name) const {
01465     return (unzLocateFile(_zipFile, name.c_str(), 2) == UNZ_OK);
01466 }
01467 
01468 int ZipArchive::listMembers(ArchiveMemberList &list) const {
01469     int members = 0;
01470 
01471     const unz_s *const archive = (const unz_s *)_zipFile;
01472     for (ZipHash::const_iterator i = archive->_hash.begin(), end = archive->_hash.end();
01473          i != end; ++i) {
01474         list.push_back(ArchiveMemberList::value_type(new GenericArchiveMember(i->_key, this)));
01475         ++members;
01476     }
01477 
01478     return members;
01479 }
01480 
01481 const ArchiveMemberPtr ZipArchive::getMember(const String &name) const {
01482     if (!hasFile(name))
01483         return ArchiveMemberPtr();
01484 
01485     return ArchiveMemberPtr(new GenericArchiveMember(name, this));
01486 }
01487 
01488 SeekableReadStream *ZipArchive::createReadStreamForMember(const String &name) const {
01489     if (unzLocateFile(_zipFile, name.c_str(), 2) != UNZ_OK)
01490         return nullptr;
01491 
01492     unz_file_info fileInfo;
01493     if (unzOpenCurrentFile(_zipFile) != UNZ_OK)
01494         return nullptr;
01495 
01496     if (unzGetCurrentFileInfo(_zipFile, &fileInfo, nullptr, 0, nullptr, 0, nullptr, 0) != UNZ_OK)
01497         return nullptr;
01498 
01499     byte *buffer = (byte *)malloc(fileInfo.uncompressed_size);
01500     assert(buffer);
01501 
01502     if (unzReadCurrentFile(_zipFile, buffer, fileInfo.uncompressed_size) != (int)fileInfo.uncompressed_size) {
01503         free(buffer);
01504         return nullptr;
01505     }
01506 
01507     if (unzCloseCurrentFile(_zipFile) != UNZ_OK) {
01508         free(buffer);
01509         return nullptr;
01510     }
01511 
01512     return new MemoryReadStream(buffer, fileInfo.uncompressed_size, DisposeAfterUse::YES);
01513 
01514     // FIXME: instead of reading all into a memory stream, we could
01515     // instead create a new ZipStream class. But then we have to be
01516     // careful to handle the case where the client code opens multiple
01517     // files in the archive and tries to use them independently.
01518 }
01519 
01520 Archive *makeZipArchive(const String &name) {
01521     return makeZipArchive(SearchMan.createReadStreamForMember(name));
01522 }
01523 
01524 Archive *makeZipArchive(const FSNode &node) {
01525     return makeZipArchive(node.createReadStream());
01526 }
01527 
01528 Archive *makeZipArchive(SeekableReadStream *stream) {
01529     if (!stream)
01530         return nullptr;
01531     unzFile zipFile = unzOpen(stream);
01532     if (!zipFile) {
01533         // stream gets deleted by unzOpen() call if something
01534         // goes wrong.
01535         return nullptr;
01536     }
01537     return new ZipArchive(zipFile);
01538 }
01539 
01540 } // End of namespace Common


Generated on Sat Jul 20 2019 05:00:48 for ResidualVM by doxygen 1.7.1
curved edge   curved edge