2012-04-19 14:35:52 +08:00
/****************************************************************************
2014-01-07 11:25:07 +08:00
Copyright ( c ) 2010 - 2012 cocos2d - x . org
Copyright ( c ) 2013 - 2014 Chukong Technologies Inc .
2013-04-26 01:40:49 +08:00
http : //www.cocos2d-x.org
Permission is hereby granted , free of charge , to any person obtaining a copy
of this software and associated documentation files ( the " Software " ) , to deal
in the Software without restriction , including without limitation the rights
to use , copy , modify , merge , publish , distribute , sublicense , and / or sell
copies of the Software , and to permit persons to whom the Software is
furnished to do so , subject to the following conditions :
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software .
THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-10-11 09:21:15 +08:00
// FIXME: hack, must be included before ziputils
2014-11-17 03:41:37 +08:00
# ifdef MINIZIP_FROM_SYSTEM
# include <minizip/unzip.h>
# else // from our embedded sources
2014-10-11 09:21:15 +08:00
# include "unzip.h"
2014-11-17 03:41:37 +08:00
# endif
2014-10-11 09:21:15 +08:00
# include "base/ZipUtils.h"
2012-04-19 14:35:52 +08:00
# include <zlib.h>
# include <assert.h>
# include <stdlib.h>
2014-04-27 01:35:57 +08:00
# include "base/CCData.h"
2014-04-30 08:37:36 +08:00
# include "base/ccMacros.h"
2014-05-17 05:36:00 +08:00
# include "platform/CCFileUtils.h"
2012-11-08 19:46:53 +08:00
# include <map>
2012-04-19 14:35:52 +08:00
2014-10-11 11:39:42 +08:00
// FIXME: Other platforms should use upstream minizip like mingw-w64
2014-11-17 03:41:37 +08:00
# ifdef MINIZIP_FROM_SYSTEM
2014-10-11 11:39:42 +08:00
# define unzGoToFirstFile64(A,B,C,D) unzGoToFirstFile2(A,B,C,D, NULL, 0, NULL, 0)
# define unzGoToNextFile64(A,B,C,D) unzGoToNextFile2(A,B,C,D, NULL, 0, NULL, 0)
# endif
2012-06-19 16:31:26 +08:00
NS_CC_BEGIN
2013-05-06 22:04:45 +08:00
unsigned int ZipUtils : : s_uEncryptedPvrKeyParts [ 4 ] = { 0 , 0 , 0 , 0 } ;
unsigned int ZipUtils : : s_uEncryptionKey [ 1024 ] ;
bool ZipUtils : : s_bEncryptionKeyIsValid = false ;
2013-04-26 01:40:49 +08:00
2013-05-06 22:04:45 +08:00
// --------------------- ZipUtils ---------------------
2013-04-26 01:40:49 +08:00
2013-12-06 16:32:06 +08:00
inline void ZipUtils : : decodeEncodedPvr ( unsigned int * data , ssize_t len )
2013-04-26 01:40:49 +08:00
{
const int enclen = 1024 ;
const int securelen = 512 ;
const int distance = 64 ;
// check if key was set
// make sure to call caw_setkey_part() for all 4 key parts
2013-11-12 10:09:47 +08:00
CCASSERT ( s_uEncryptedPvrKeyParts [ 0 ] ! = 0 , " Cocos2D: CCZ file is encrypted but key part 0 is not set. Did you call ZipUtils::setPvrEncryptionKeyPart(...)? " ) ;
CCASSERT ( s_uEncryptedPvrKeyParts [ 1 ] ! = 0 , " Cocos2D: CCZ file is encrypted but key part 1 is not set. Did you call ZipUtils::setPvrEncryptionKeyPart(...)? " ) ;
CCASSERT ( s_uEncryptedPvrKeyParts [ 2 ] ! = 0 , " Cocos2D: CCZ file is encrypted but key part 2 is not set. Did you call ZipUtils::setPvrEncryptionKeyPart(...)? " ) ;
CCASSERT ( s_uEncryptedPvrKeyParts [ 3 ] ! = 0 , " Cocos2D: CCZ file is encrypted but key part 3 is not set. Did you call ZipUtils::setPvrEncryptionKeyPart(...)? " ) ;
2013-04-26 01:40:49 +08:00
// create long key
2013-05-06 22:04:45 +08:00
if ( ! s_bEncryptionKeyIsValid )
2013-04-26 01:40:49 +08:00
{
unsigned int y , p , e ;
unsigned int rounds = 6 ;
unsigned int sum = 0 ;
2013-05-06 22:04:45 +08:00
unsigned int z = s_uEncryptionKey [ enclen - 1 ] ;
2013-04-26 01:40:49 +08:00
do
{
# define DELTA 0x9e3779b9
2013-05-06 22:04:45 +08:00
# define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (s_uEncryptedPvrKeyParts[(p&3)^e] ^ z)))
2013-04-26 01:40:49 +08:00
sum + = DELTA ;
e = ( sum > > 2 ) & 3 ;
for ( p = 0 ; p < enclen - 1 ; p + + )
{
2013-05-06 22:04:45 +08:00
y = s_uEncryptionKey [ p + 1 ] ;
z = s_uEncryptionKey [ p ] + = MX ;
2013-04-26 01:40:49 +08:00
}
2013-05-06 22:04:45 +08:00
y = s_uEncryptionKey [ 0 ] ;
z = s_uEncryptionKey [ enclen - 1 ] + = MX ;
2013-04-26 01:40:49 +08:00
} while ( - - rounds ) ;
2013-05-06 22:04:45 +08:00
s_bEncryptionKeyIsValid = true ;
2013-04-26 01:40:49 +08:00
}
int b = 0 ;
int i = 0 ;
// encrypt first part completely
for ( ; i < len & & i < securelen ; i + + )
{
2013-05-06 22:04:45 +08:00
data [ i ] ^ = s_uEncryptionKey [ b + + ] ;
2013-04-26 01:40:49 +08:00
if ( b > = enclen )
{
b = 0 ;
}
}
// encrypt second section partially
for ( ; i < len ; i + = distance )
{
2013-05-06 22:04:45 +08:00
data [ i ] ^ = s_uEncryptionKey [ b + + ] ;
2013-04-26 01:40:49 +08:00
if ( b > = enclen )
{
b = 0 ;
}
}
}
2013-12-06 16:32:06 +08:00
inline unsigned int ZipUtils : : checksumPvr ( const unsigned int * data , ssize_t len )
2013-04-26 01:40:49 +08:00
{
unsigned int cs = 0 ;
const int cslen = 128 ;
len = ( len < cslen ) ? len : cslen ;
for ( int i = 0 ; i < len ; i + + )
{
cs = cs ^ data [ i ] ;
}
return cs ;
}
2012-06-19 16:31:26 +08:00
// memory in iPhone is precious
// Should buffer factor be 1.5 instead of 2 ?
# define BUFFER_INC_FACTOR (2)
2013-12-06 16:32:06 +08:00
int ZipUtils : : inflateMemoryWithHint ( unsigned char * in , ssize_t inLength , unsigned char * * out , ssize_t * outLength , ssize_t outLenghtHint )
2012-04-19 14:35:52 +08:00
{
2012-06-19 16:31:26 +08:00
/* ret value */
int err = Z_OK ;
2013-04-26 01:40:49 +08:00
2013-12-06 16:32:06 +08:00
ssize_t bufferSize = outLenghtHint ;
2013-11-12 10:09:47 +08:00
* out = ( unsigned char * ) malloc ( bufferSize ) ;
2013-04-26 01:40:49 +08:00
z_stream d_stream ; /* decompression stream */
2012-06-19 16:31:26 +08:00
d_stream . zalloc = ( alloc_func ) 0 ;
d_stream . zfree = ( free_func ) 0 ;
d_stream . opaque = ( voidpf ) 0 ;
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
d_stream . next_in = in ;
2013-12-06 16:32:06 +08:00
d_stream . avail_in = static_cast < unsigned int > ( inLength ) ;
2012-06-19 16:31:26 +08:00
d_stream . next_out = * out ;
2013-12-06 16:32:06 +08:00
d_stream . avail_out = static_cast < unsigned int > ( bufferSize ) ;
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
/* window size to hold 256k */
if ( ( err = inflateInit2 ( & d_stream , 15 + 32 ) ) ! = Z_OK )
return err ;
2013-04-26 01:40:49 +08:00
for ( ; ; )
2012-06-19 16:31:26 +08:00
{
err = inflate ( & d_stream , Z_NO_FLUSH ) ;
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
if ( err = = Z_STREAM_END )
2012-04-19 14:35:52 +08:00
{
2012-06-19 16:31:26 +08:00
break ;
}
2013-04-26 01:40:49 +08:00
switch ( err )
2012-06-19 16:31:26 +08:00
{
2013-04-26 01:40:49 +08:00
case Z_NEED_DICT :
err = Z_DATA_ERROR ;
case Z_DATA_ERROR :
case Z_MEM_ERROR :
inflateEnd ( & d_stream ) ;
return err ;
2012-06-19 16:31:26 +08:00
}
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
// not enough memory ?
2013-04-26 01:40:49 +08:00
if ( err ! = Z_STREAM_END )
2012-06-19 16:31:26 +08:00
{
2013-09-16 16:22:52 +08:00
* out = ( unsigned char * ) realloc ( * out , bufferSize * BUFFER_INC_FACTOR ) ;
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
/* not enough memory, ouch */
2013-04-26 01:40:49 +08:00
if ( ! * out )
2012-04-19 14:35:52 +08:00
{
2012-06-19 16:31:26 +08:00
CCLOG ( " cocos2d: ZipUtils: realloc failed " ) ;
2012-04-19 14:35:52 +08:00
inflateEnd ( & d_stream ) ;
2012-06-19 16:31:26 +08:00
return Z_MEM_ERROR ;
2012-04-19 14:35:52 +08:00
}
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
d_stream . next_out = * out + bufferSize ;
2013-12-06 16:32:06 +08:00
d_stream . avail_out = static_cast < unsigned int > ( bufferSize ) ;
2012-06-19 16:31:26 +08:00
bufferSize * = BUFFER_INC_FACTOR ;
2012-04-19 14:35:52 +08:00
}
}
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
* outLength = bufferSize - d_stream . avail_out ;
err = inflateEnd ( & d_stream ) ;
return err ;
}
2012-04-19 14:35:52 +08:00
2013-12-06 16:32:06 +08:00
ssize_t ZipUtils : : inflateMemoryWithHint ( unsigned char * in , ssize_t inLength , unsigned char * * out , ssize_t outLengthHint )
2012-06-19 16:31:26 +08:00
{
2013-12-06 16:32:06 +08:00
ssize_t outLength = 0 ;
2013-11-12 10:09:47 +08:00
int err = inflateMemoryWithHint ( in , inLength , out , & outLength , outLengthHint ) ;
2013-04-26 01:40:49 +08:00
2013-12-18 17:47:20 +08:00
if ( err ! = Z_OK | | * out = = nullptr ) {
2012-06-19 16:31:26 +08:00
if ( err = = Z_MEM_ERROR )
{
CCLOG ( " cocos2d: ZipUtils: Out of memory while decompressing map data! " ) ;
2013-04-26 01:40:49 +08:00
} else
if ( err = = Z_VERSION_ERROR )
{
CCLOG ( " cocos2d: ZipUtils: Incompatible zlib version! " ) ;
} else
if ( err = = Z_DATA_ERROR )
{
CCLOG ( " cocos2d: ZipUtils: Incorrect zlib compressed data! " ) ;
}
else
{
CCLOG ( " cocos2d: ZipUtils: Unknown error while decompressing map data! " ) ;
}
2013-11-12 10:09:47 +08:00
if ( * out ) {
free ( * out ) ;
2013-12-18 17:47:20 +08:00
* out = nullptr ;
2013-11-12 10:09:47 +08:00
}
2012-06-19 16:31:26 +08:00
outLength = 0 ;
2012-04-19 14:35:52 +08:00
}
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
return outLength ;
}
2013-12-06 16:32:06 +08:00
ssize_t ZipUtils : : inflateMemory ( unsigned char * in , ssize_t inLength , unsigned char * * out )
2012-06-19 16:31:26 +08:00
{
// 256k for hint
2013-11-12 10:09:47 +08:00
return inflateMemoryWithHint ( in , inLength , out , 256 * 1024 ) ;
2012-06-19 16:31:26 +08:00
}
2013-11-12 10:09:47 +08:00
int ZipUtils : : inflateGZipFile ( const char * path , unsigned char * * out )
2012-06-19 16:31:26 +08:00
{
int len ;
unsigned int offset = 0 ;
2013-04-26 01:40:49 +08:00
2015-07-14 15:28:36 +08:00
CCASSERT ( out , " out can't be nullptr. " ) ;
CCASSERT ( & * out , " &*out can't be nullptr. " ) ;
2013-04-26 01:40:49 +08:00
2015-09-18 04:30:32 +08:00
gzFile inFile = gzopen ( FileUtils : : getInstance ( ) - > getSuitableFOpen ( path ) . c_str ( ) , " rb " ) ;
2013-12-18 17:47:20 +08:00
if ( inFile = = nullptr ) {
2012-06-19 16:31:26 +08:00
CCLOG ( " cocos2d: ZipUtils: error open gzip file: %s " , path ) ;
return - 1 ;
2012-04-19 14:35:52 +08:00
}
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
/* 512k initial decompress buffer */
unsigned int bufferSize = 512 * 1024 ;
unsigned int totalBufferSize = bufferSize ;
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
* out = ( unsigned char * ) malloc ( bufferSize ) ;
2013-04-26 01:40:49 +08:00
if ( ! out )
2012-06-19 16:31:26 +08:00
{
CCLOG ( " cocos2d: ZipUtils: out of memory " ) ;
return - 1 ;
}
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
for ( ; ; ) {
len = gzread ( inFile , * out + offset , bufferSize ) ;
2013-04-26 01:40:49 +08:00
if ( len < 0 )
2012-06-19 16:31:26 +08:00
{
CCLOG ( " cocos2d: ZipUtils: error in gzread " ) ;
free ( * out ) ;
2013-12-18 17:47:20 +08:00
* out = nullptr ;
2012-04-19 14:35:52 +08:00
return - 1 ;
}
2012-06-19 16:31:26 +08:00
if ( len = = 0 )
{
break ;
}
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
offset + = len ;
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
// finish reading the file
if ( ( unsigned int ) len < bufferSize )
{
break ;
}
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
bufferSize * = BUFFER_INC_FACTOR ;
totalBufferSize + = bufferSize ;
unsigned char * tmp = ( unsigned char * ) realloc ( * out , totalBufferSize ) ;
2013-04-26 01:40:49 +08:00
if ( ! tmp )
2012-04-19 14:35:52 +08:00
{
CCLOG ( " cocos2d: ZipUtils: out of memory " ) ;
2012-06-19 16:31:26 +08:00
free ( * out ) ;
2013-12-18 17:47:20 +08:00
* out = nullptr ;
2012-04-19 14:35:52 +08:00
return - 1 ;
}
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
* out = tmp ;
}
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
if ( gzclose ( inFile ) ! = Z_OK )
{
CCLOG ( " cocos2d: ZipUtils: gzclose failed " ) ;
}
2013-04-26 01:40:49 +08:00
2012-06-19 16:31:26 +08:00
return offset ;
}
2012-04-19 14:35:52 +08:00
2013-11-12 10:09:47 +08:00
bool ZipUtils : : isCCZFile ( const char * path )
2012-06-19 16:31:26 +08:00
{
2013-04-26 01:40:49 +08:00
// load file into memory
2013-12-18 14:58:17 +08:00
Data compressedData = FileUtils : : getInstance ( ) - > getDataFromFile ( path ) ;
2013-07-25 21:35:00 +08:00
2013-12-18 14:58:17 +08:00
if ( compressedData . isNull ( ) )
2013-04-26 01:40:49 +08:00
{
2013-07-25 21:35:00 +08:00
CCLOG ( " cocos2d: ZipUtils: loading file failed " ) ;
return false ;
}
2013-12-18 14:58:17 +08:00
return isCCZBuffer ( compressedData . getBytes ( ) , compressedData . getSize ( ) ) ;
2013-07-25 21:35:00 +08:00
}
2013-12-10 21:20:52 +08:00
bool ZipUtils : : isCCZBuffer ( const unsigned char * buffer , ssize_t len )
2013-07-25 21:35:00 +08:00
{
2013-11-13 11:22:34 +08:00
if ( static_cast < size_t > ( len ) < sizeof ( struct CCZHeader ) )
2013-07-25 21:35:00 +08:00
{
return false ;
2013-04-26 01:40:49 +08:00
}
2013-07-25 21:35:00 +08:00
struct CCZHeader * header = ( struct CCZHeader * ) buffer ;
return header - > sig [ 0 ] = = ' C ' & & header - > sig [ 1 ] = = ' C ' & & header - > sig [ 2 ] = = ' Z ' & & ( header - > sig [ 3 ] = = ' ! ' | | header - > sig [ 3 ] = = ' p ' ) ;
}
2013-11-12 10:09:47 +08:00
bool ZipUtils : : isGZipFile ( const char * path )
2013-07-25 21:35:00 +08:00
{
// load file into memory
2013-12-18 14:58:17 +08:00
Data compressedData = FileUtils : : getInstance ( ) - > getDataFromFile ( path ) ;
2013-07-25 21:35:00 +08:00
2013-12-18 14:58:17 +08:00
if ( compressedData . isNull ( ) )
2013-07-25 21:35:00 +08:00
{
CCLOG ( " cocos2d: ZipUtils: loading file failed " ) ;
return false ;
}
2013-12-18 14:58:17 +08:00
return isGZipBuffer ( compressedData . getBytes ( ) , compressedData . getSize ( ) ) ;
2013-07-25 21:35:00 +08:00
}
2013-12-10 21:20:52 +08:00
bool ZipUtils : : isGZipBuffer ( const unsigned char * buffer , ssize_t len )
2013-07-25 21:35:00 +08:00
{
if ( len < 2 )
{
return false ;
}
return buffer [ 0 ] = = 0x1F & & buffer [ 1 ] = = 0x8B ;
}
2013-12-06 16:32:06 +08:00
int ZipUtils : : inflateCCZBuffer ( const unsigned char * buffer , ssize_t bufferLen , unsigned char * * out )
2013-07-25 21:35:00 +08:00
{
struct CCZHeader * header = ( struct CCZHeader * ) buffer ;
2013-04-26 01:40:49 +08:00
// verify header
if ( header - > sig [ 0 ] = = ' C ' & & header - > sig [ 1 ] = = ' C ' & & header - > sig [ 2 ] = = ' Z ' & & header - > sig [ 3 ] = = ' ! ' )
{
// verify header version
unsigned int version = CC_SWAP_INT16_BIG_TO_HOST ( header - > version ) ;
if ( version > 2 )
{
CCLOG ( " cocos2d: Unsupported CCZ header format " ) ;
return - 1 ;
}
2013-07-25 21:35:00 +08:00
2013-04-26 01:40:49 +08:00
// verify compression format
if ( CC_SWAP_INT16_BIG_TO_HOST ( header - > compression_type ) ! = CCZ_COMPRESSION_ZLIB )
{
CCLOG ( " cocos2d: CCZ Unsupported compression method " ) ;
return - 1 ;
}
}
else if ( header - > sig [ 0 ] = = ' C ' & & header - > sig [ 1 ] = = ' C ' & & header - > sig [ 2 ] = = ' Z ' & & header - > sig [ 3 ] = = ' p ' )
{
// encrypted ccz file
2013-07-25 21:35:00 +08:00
header = ( struct CCZHeader * ) buffer ;
2013-04-26 01:40:49 +08:00
// verify header version
unsigned int version = CC_SWAP_INT16_BIG_TO_HOST ( header - > version ) ;
if ( version > 0 )
{
CCLOG ( " cocos2d: Unsupported CCZ header format " ) ;
return - 1 ;
}
2013-07-25 21:35:00 +08:00
2013-04-26 01:40:49 +08:00
// verify compression format
if ( CC_SWAP_INT16_BIG_TO_HOST ( header - > compression_type ) ! = CCZ_COMPRESSION_ZLIB )
{
CCLOG ( " cocos2d: CCZ Unsupported compression method " ) ;
return - 1 ;
}
2013-07-25 21:35:00 +08:00
2013-04-26 01:40:49 +08:00
// decrypt
2013-07-25 21:35:00 +08:00
unsigned int * ints = ( unsigned int * ) ( buffer + 12 ) ;
2013-12-06 16:32:06 +08:00
ssize_t enclen = ( bufferLen - 12 ) / 4 ;
2013-07-25 21:35:00 +08:00
2013-11-12 10:09:47 +08:00
decodeEncodedPvr ( ints , enclen ) ;
2013-07-25 21:35:00 +08:00
2013-04-26 01:40:49 +08:00
# if COCOS2D_DEBUG > 0
// verify checksum in debug mode
2013-11-12 10:09:47 +08:00
unsigned int calculated = checksumPvr ( ints , enclen ) ;
2013-04-26 01:40:49 +08:00
unsigned int required = CC_SWAP_INT32_BIG_TO_HOST ( header - > reserved ) ;
2013-07-25 21:35:00 +08:00
2013-04-26 01:40:49 +08:00
if ( calculated ! = required )
{
2013-05-06 22:04:45 +08:00
CCLOG ( " cocos2d: Can't decrypt image file. Is the decryption key valid? " ) ;
2013-04-26 01:40:49 +08:00
return - 1 ;
}
# endif
}
else
{
CCLOG ( " cocos2d: Invalid CCZ file " ) ;
return - 1 ;
}
2013-07-25 21:35:00 +08:00
2013-04-26 01:40:49 +08:00
unsigned int len = CC_SWAP_INT32_BIG_TO_HOST ( header - > len ) ;
2013-07-25 21:35:00 +08:00
2013-04-26 01:40:49 +08:00
* out = ( unsigned char * ) malloc ( len ) ;
if ( ! * out )
{
CCLOG ( " cocos2d: CCZ: Failed to allocate memory for texture " ) ;
return - 1 ;
}
2013-07-25 21:35:00 +08:00
2013-04-26 01:40:49 +08:00
unsigned long destlen = len ;
2013-12-05 11:37:27 +08:00
size_t source = ( size_t ) buffer + sizeof ( * header ) ;
2013-07-25 21:35:00 +08:00
int ret = uncompress ( * out , & destlen , ( Bytef * ) source , bufferLen - sizeof ( * header ) ) ;
2013-04-26 01:40:49 +08:00
if ( ret ! = Z_OK )
{
CCLOG ( " cocos2d: CCZ: Failed to uncompress data " ) ;
free ( * out ) ;
2013-12-18 17:47:20 +08:00
* out = nullptr ;
2013-04-26 01:40:49 +08:00
return - 1 ;
}
2013-07-25 21:35:00 +08:00
2013-04-26 01:40:49 +08:00
return len ;
2012-06-19 16:31:26 +08:00
}
2012-04-19 14:35:52 +08:00
2013-11-12 10:09:47 +08:00
int ZipUtils : : inflateCCZFile ( const char * path , unsigned char * * out )
2013-07-25 21:35:00 +08:00
{
2013-12-18 14:58:17 +08:00
CCASSERT ( out , " Invalid pointer for buffer! " ) ;
2013-07-25 21:35:00 +08:00
// load file into memory
2013-12-18 14:58:17 +08:00
Data compressedData = FileUtils : : getInstance ( ) - > getDataFromFile ( path ) ;
2013-07-25 21:35:00 +08:00
2013-12-18 14:58:17 +08:00
if ( compressedData . isNull ( ) )
2013-07-25 21:35:00 +08:00
{
CCLOG ( " cocos2d: Error loading CCZ compressed file " ) ;
return - 1 ;
}
2013-12-18 14:58:17 +08:00
return inflateCCZBuffer ( compressedData . getBytes ( ) , compressedData . getSize ( ) , out ) ;
2013-07-25 21:35:00 +08:00
}
2013-11-12 10:09:47 +08:00
void ZipUtils : : setPvrEncryptionKeyPart ( int index , unsigned int value )
2013-05-06 22:04:45 +08:00
{
2013-07-20 13:01:27 +08:00
CCASSERT ( index > = 0 , " Cocos2d: key part index cannot be less than 0 " ) ;
CCASSERT ( index < = 3 , " Cocos2d: key part index cannot be greater than 3 " ) ;
2013-05-06 22:04:45 +08:00
if ( s_uEncryptedPvrKeyParts [ index ] ! = value )
{
s_uEncryptedPvrKeyParts [ index ] = value ;
s_bEncryptionKeyIsValid = false ;
}
}
2013-11-12 10:09:47 +08:00
void ZipUtils : : setPvrEncryptionKey ( unsigned int keyPart1 , unsigned int keyPart2 , unsigned int keyPart3 , unsigned int keyPart4 )
2013-05-07 22:14:38 +08:00
{
2013-11-12 10:09:47 +08:00
setPvrEncryptionKeyPart ( 0 , keyPart1 ) ;
setPvrEncryptionKeyPart ( 1 , keyPart2 ) ;
setPvrEncryptionKeyPart ( 2 , keyPart3 ) ;
setPvrEncryptionKeyPart ( 3 , keyPart4 ) ;
2013-05-07 22:14:38 +08:00
}
2012-11-08 19:46:53 +08:00
// --------------------- ZipFile ---------------------
// from unzip.cpp
# define UNZ_MAXFILENAMEINZIP 256
2014-10-08 17:30:14 +08:00
static const std : : string emptyFilename ( " " ) ;
2012-11-09 15:53:40 +08:00
struct ZipEntryInfo
{
unz_file_pos pos ;
uLong uncompressed_size ;
} ;
2012-11-08 19:46:53 +08:00
class ZipFilePrivate
{
public :
unzFile zipFile ;
2013-04-26 01:40:49 +08:00
2012-11-08 19:46:53 +08:00
// std::unordered_map is faster if available on the platform
2013-11-22 05:43:59 +08:00
typedef std : : unordered_map < std : : string , struct ZipEntryInfo > FileListContainer ;
2012-11-08 19:46:53 +08:00
FileListContainer fileList ;
} ;
2014-10-08 17:30:14 +08:00
ZipFile * ZipFile : : createWithBuffer ( const void * buffer , uLong size )
{
2015-12-16 14:02:55 +08:00
ZipFile * zip = new ( std : : nothrow ) ZipFile ( ) ;
2014-10-08 17:30:14 +08:00
if ( zip & & zip - > initWithBuffer ( buffer , size ) ) {
return zip ;
} else {
if ( zip ) delete zip ;
return nullptr ;
}
}
ZipFile : : ZipFile ( )
: _data ( new ZipFilePrivate )
{
_data - > zipFile = nullptr ;
}
2012-11-08 19:46:53 +08:00
ZipFile : : ZipFile ( const std : : string & zipFile , const std : : string & filter )
2013-06-15 14:03:30 +08:00
: _data ( new ZipFilePrivate )
2012-11-08 19:46:53 +08:00
{
2015-09-18 04:30:32 +08:00
_data - > zipFile = unzOpen ( FileUtils : : getInstance ( ) - > getSuitableFOpen ( zipFile ) . c_str ( ) ) ;
2013-06-26 16:42:11 +08:00
setFilter ( filter ) ;
2012-11-08 19:46:53 +08:00
}
ZipFile : : ~ ZipFile ( )
{
2013-06-15 14:03:30 +08:00
if ( _data & & _data - > zipFile )
2012-11-08 19:46:53 +08:00
{
2013-06-15 14:03:30 +08:00
unzClose ( _data - > zipFile ) ;
2012-11-08 19:46:53 +08:00
}
2013-06-26 16:42:11 +08:00
2013-06-15 14:03:30 +08:00
CC_SAFE_DELETE ( _data ) ;
2012-11-08 19:46:53 +08:00
}
2013-06-26 16:42:11 +08:00
bool ZipFile : : setFilter ( const std : : string & filter )
2012-11-08 19:46:53 +08:00
{
bool ret = false ;
do
{
2013-06-26 16:42:11 +08:00
CC_BREAK_IF ( ! _data ) ;
CC_BREAK_IF ( ! _data - > zipFile ) ;
2013-04-26 01:40:49 +08:00
2012-11-08 19:46:53 +08:00
// clear existing file list
2013-06-26 16:42:11 +08:00
_data - > fileList . clear ( ) ;
2013-04-26 01:40:49 +08:00
2012-11-11 21:04:41 +08:00
// UNZ_MAXFILENAMEINZIP + 1 - it is done so in unzLocateFile
char szCurrentFileName [ UNZ_MAXFILENAMEINZIP + 1 ] ;
unz_file_info64 fileInfo ;
2013-04-26 01:40:49 +08:00
2012-11-08 19:46:53 +08:00
// go through all files and store position information about the required files
2013-06-26 16:42:11 +08:00
int err = unzGoToFirstFile64 ( _data - > zipFile , & fileInfo ,
2013-04-26 01:40:49 +08:00
szCurrentFileName , sizeof ( szCurrentFileName ) - 1 ) ;
2012-11-08 19:46:53 +08:00
while ( err = = UNZ_OK )
{
unz_file_pos posInfo ;
2013-06-26 16:42:11 +08:00
int posErr = unzGetFilePos ( _data - > zipFile , & posInfo ) ;
2012-11-08 19:46:53 +08:00
if ( posErr = = UNZ_OK )
{
std : : string currentFileName = szCurrentFileName ;
2012-11-11 21:04:41 +08:00
// cache info about filtered files only (like 'assets/')
if ( filter . empty ( )
| | currentFileName . substr ( 0 , filter . length ( ) ) = = filter )
2012-11-08 19:46:53 +08:00
{
2012-11-11 21:04:41 +08:00
ZipEntryInfo entry ;
entry . pos = posInfo ;
entry . uncompressed_size = ( uLong ) fileInfo . uncompressed_size ;
2013-06-26 16:42:11 +08:00
_data - > fileList [ currentFileName ] = entry ;
2012-11-08 19:46:53 +08:00
}
}
2012-11-11 21:04:41 +08:00
// next file - also get the information about it
2013-06-26 16:42:11 +08:00
err = unzGoToNextFile64 ( _data - > zipFile , & fileInfo ,
2013-04-26 01:40:49 +08:00
szCurrentFileName , sizeof ( szCurrentFileName ) - 1 ) ;
2012-11-08 19:46:53 +08:00
}
ret = true ;
2013-04-26 01:40:49 +08:00
2012-11-08 19:46:53 +08:00
} while ( false ) ;
2013-04-26 01:40:49 +08:00
2012-11-08 19:46:53 +08:00
return ret ;
}
bool ZipFile : : fileExists ( const std : : string & fileName ) const
{
bool ret = false ;
do
{
2013-06-15 14:03:30 +08:00
CC_BREAK_IF ( ! _data ) ;
2013-04-26 01:40:49 +08:00
2013-06-15 14:03:30 +08:00
ret = _data - > fileList . find ( fileName ) ! = _data - > fileList . end ( ) ;
2012-11-08 19:46:53 +08:00
} while ( false ) ;
2013-04-26 01:40:49 +08:00
2012-11-08 19:46:53 +08:00
return ret ;
}
2013-12-05 17:19:01 +08:00
unsigned char * ZipFile : : getFileData ( const std : : string & fileName , ssize_t * size )
2012-11-08 19:46:53 +08:00
{
2013-12-18 17:47:20 +08:00
unsigned char * buffer = nullptr ;
2013-11-12 10:09:47 +08:00
if ( size )
* size = 0 ;
2012-11-08 19:46:53 +08:00
do
{
2013-06-26 16:42:11 +08:00
CC_BREAK_IF ( ! _data - > zipFile ) ;
2012-11-08 19:46:53 +08:00
CC_BREAK_IF ( fileName . empty ( ) ) ;
2013-04-26 01:40:49 +08:00
2013-06-26 16:42:11 +08:00
ZipFilePrivate : : FileListContainer : : const_iterator it = _data - > fileList . find ( fileName ) ;
CC_BREAK_IF ( it = = _data - > fileList . end ( ) ) ;
2013-04-26 01:40:49 +08:00
2012-11-09 15:53:40 +08:00
ZipEntryInfo fileInfo = it - > second ;
2013-04-26 01:40:49 +08:00
2013-06-26 16:42:11 +08:00
int nRet = unzGoToFilePos ( _data - > zipFile , & fileInfo . pos ) ;
2012-11-08 19:46:53 +08:00
CC_BREAK_IF ( UNZ_OK ! = nRet ) ;
2013-04-26 01:40:49 +08:00
2013-06-26 16:42:11 +08:00
nRet = unzOpenCurrentFile ( _data - > zipFile ) ;
2012-11-08 19:46:53 +08:00
CC_BREAK_IF ( UNZ_OK ! = nRet ) ;
2013-04-26 01:40:49 +08:00
2013-11-12 10:09:47 +08:00
buffer = ( unsigned char * ) malloc ( fileInfo . uncompressed_size ) ;
2013-12-06 16:32:06 +08:00
int CC_UNUSED nSize = unzReadCurrentFile ( _data - > zipFile , buffer , static_cast < unsigned int > ( fileInfo . uncompressed_size ) ) ;
2013-07-20 13:01:27 +08:00
CCASSERT ( nSize = = 0 | | nSize = = ( int ) fileInfo . uncompressed_size , " the file size is wrong " ) ;
2013-04-26 01:40:49 +08:00
2013-11-12 10:09:47 +08:00
if ( size )
2012-11-08 19:46:53 +08:00
{
2013-11-12 10:09:47 +08:00
* size = fileInfo . uncompressed_size ;
2012-11-08 19:46:53 +08:00
}
2013-06-26 16:42:11 +08:00
unzCloseCurrentFile ( _data - > zipFile ) ;
2012-11-08 19:46:53 +08:00
} while ( 0 ) ;
2013-04-26 01:40:49 +08:00
2013-11-12 10:09:47 +08:00
return buffer ;
2012-11-08 19:46:53 +08:00
}
2016-05-04 09:21:35 +08:00
bool ZipFile : : getFileData ( const std : : string & fileName , ResizableBuffer * buffer )
{
bool res = false ;
do
{
CC_BREAK_IF ( ! _data - > zipFile ) ;
CC_BREAK_IF ( fileName . empty ( ) ) ;
ZipFilePrivate : : FileListContainer : : const_iterator it = _data - > fileList . find ( fileName ) ;
CC_BREAK_IF ( it = = _data - > fileList . end ( ) ) ;
ZipEntryInfo fileInfo = it - > second ;
int nRet = unzGoToFilePos ( _data - > zipFile , & fileInfo . pos ) ;
CC_BREAK_IF ( UNZ_OK ! = nRet ) ;
nRet = unzOpenCurrentFile ( _data - > zipFile ) ;
CC_BREAK_IF ( UNZ_OK ! = nRet ) ;
buffer - > resize ( fileInfo . uncompressed_size ) ;
int CC_UNUSED nSize = unzReadCurrentFile ( _data - > zipFile , buffer - > buffer ( ) , static_cast < unsigned int > ( fileInfo . uncompressed_size ) ) ;
CCASSERT ( nSize = = 0 | | nSize = = ( int ) fileInfo . uncompressed_size , " the file size is wrong " ) ;
unzCloseCurrentFile ( _data - > zipFile ) ;
res = true ;
} while ( 0 ) ;
return res ;
}
2014-10-08 17:30:14 +08:00
std : : string ZipFile : : getFirstFilename ( )
{
if ( unzGoToFirstFile ( _data - > zipFile ) ! = UNZ_OK ) return emptyFilename ;
std : : string path ;
unz_file_info info ;
getCurrentFileInfo ( & path , & info ) ;
return path ;
}
std : : string ZipFile : : getNextFilename ( )
{
if ( unzGoToNextFile ( _data - > zipFile ) ! = UNZ_OK ) return emptyFilename ;
std : : string path ;
unz_file_info info ;
2014-10-11 09:28:05 +08:00
getCurrentFileInfo ( & path , & info ) ;
2014-10-08 17:30:14 +08:00
return path ;
}
int ZipFile : : getCurrentFileInfo ( std : : string * filename , unz_file_info * info )
{
char path [ FILENAME_MAX + 1 ] ;
int ret = unzGetCurrentFileInfo ( _data - > zipFile , info , path , sizeof ( path ) , nullptr , 0 , nullptr , 0 ) ;
if ( ret ! = UNZ_OK ) {
* filename = emptyFilename ;
} else {
filename - > assign ( path ) ;
}
return ret ;
}
bool ZipFile : : initWithBuffer ( const void * buffer , uLong size )
{
if ( ! buffer | | size = = 0 ) return false ;
_data - > zipFile = unzOpenBuffer ( buffer , size ) ;
if ( ! _data - > zipFile ) return false ;
setFilter ( emptyFilename ) ;
return true ;
}
2012-06-19 16:31:26 +08:00
NS_CC_END