From 9cd57b731ab1c666d4a1cb725538fdc137763d12 Mon Sep 17 00:00:00 2001 From: Starla Insigna Date: Sat, 30 Jul 2011 11:19:14 -0400 Subject: Initial commit (version 0.2.1) --- libs/cocos2d/Support/ZipUtils.m | 251 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100755 libs/cocos2d/Support/ZipUtils.m (limited to 'libs/cocos2d/Support/ZipUtils.m') diff --git a/libs/cocos2d/Support/ZipUtils.m b/libs/cocos2d/Support/ZipUtils.m new file mode 100755 index 0000000..ccd8bbc --- /dev/null +++ b/libs/cocos2d/Support/ZipUtils.m @@ -0,0 +1,251 @@ +/* cocos2d for iPhone + * + * http://www.cocos2d-iphone.org + * + * + * Inflates either zlib or gzip deflated memory. The inflated memory is + * expected to be freed by the caller. + * + * inflateMemory_ based on zlib example code + * http://www.zlib.net + * + * Some ideas were taken from: + * http://themanaworld.org/ + * from the mapreader.cpp file + */ + +#import + +#import +#import +#import +#import + +#import "ZipUtils.h" +#import "CCFileUtils.h" +#import "../ccMacros.h" + +// memory in iPhone is precious +// Should buffer factor be 1.5 instead of 2 ? +#define BUFFER_INC_FACTOR (2) + +static int inflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int *outLength, unsigned int outLenghtHint ) +{ + /* ret value */ + int err = Z_OK; + + int bufferSize = outLenghtHint; + *out = (unsigned char*) malloc(bufferSize); + + z_stream d_stream; /* decompression stream */ + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + d_stream.next_in = in; + d_stream.avail_in = inLength; + d_stream.next_out = *out; + d_stream.avail_out = bufferSize; + + /* window size to hold 256k */ + if( (err = inflateInit2(&d_stream, 15 + 32)) != Z_OK ) + return err; + + for (;;) { + err = inflate(&d_stream, Z_NO_FLUSH); + + if (err == Z_STREAM_END) + break; + + switch (err) { + case Z_NEED_DICT: + err = Z_DATA_ERROR; + case Z_DATA_ERROR: + case Z_MEM_ERROR: + inflateEnd(&d_stream); + return err; + } + + // not enough memory ? + if (err != Z_STREAM_END) { + + unsigned char *tmp = realloc(*out, bufferSize * BUFFER_INC_FACTOR); + + /* not enough memory, ouch */ + if (! tmp ) { + CCLOG(@"cocos2d: ZipUtils: realloc failed"); + inflateEnd(&d_stream); + return Z_MEM_ERROR; + } + /* only assign to *out if tmp is valid. it's not guaranteed that realloc will reuse the memory */ + *out = tmp; + + d_stream.next_out = *out + bufferSize; + d_stream.avail_out = bufferSize; + bufferSize *= BUFFER_INC_FACTOR; + } + } + + + *outLength = bufferSize - d_stream.avail_out; + err = inflateEnd(&d_stream); + return err; +} + +int ccInflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int outLengthHint ) +{ + unsigned int outLength = 0; + int err = inflateMemoryWithHint(in, inLength, out, &outLength, outLengthHint ); + + if (err != Z_OK || *out == NULL) { + if (err == Z_MEM_ERROR) + CCLOG(@"cocos2d: ZipUtils: Out of memory while decompressing map data!"); + + 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!"); + + free(*out); + *out = NULL; + outLength = 0; + } + + return outLength; +} + +int ccInflateMemory(unsigned char *in, unsigned int inLength, unsigned char **out) +{ + // 256k for hint + return ccInflateMemoryWithHint(in, inLength, out, 256 * 1024 ); +} + +int ccInflateGZipFile(const char *path, unsigned char **out) +{ + int len; + unsigned int offset = 0; + + NSCAssert( out, @"ccInflateGZipFile: invalid 'out' parameter"); + NSCAssert( &*out, @"ccInflateGZipFile: invalid 'out' parameter"); + + gzFile inFile = gzopen(path, "rb"); + if( inFile == NULL ) { + CCLOG(@"cocos2d: ZipUtils: error open gzip file: %s", path); + return -1; + } + + /* 512k initial decompress buffer */ + int bufferSize = 512 * 1024; + unsigned int totalBufferSize = bufferSize; + + *out = malloc( bufferSize ); + if( ! out ) { + CCLOG(@"cocos2d: ZipUtils: out of memory"); + return -1; + } + + for (;;) { + len = gzread(inFile, *out + offset, bufferSize); + if (len < 0) { + CCLOG(@"cocos2d: ZipUtils: error in gzread"); + free( *out ); + *out = NULL; + return -1; + } + if (len == 0) + break; + + offset += len; + + // finish reading the file + if( len < bufferSize ) + break; + + bufferSize *= BUFFER_INC_FACTOR; + totalBufferSize += bufferSize; + unsigned char *tmp = realloc(*out, totalBufferSize ); + + if( ! tmp ) { + CCLOG(@"cocos2d: ZipUtils: out of memory"); + free( *out ); + *out = NULL; + return -1; + } + + *out = tmp; + } + + if (gzclose(inFile) != Z_OK) + CCLOG(@"cocos2d: ZipUtils: gzclose failed"); + + return offset; +} + +int ccInflateCCZFile(const char *path, unsigned char **out) +{ + NSCAssert( out, @"ccInflateCCZFile: invalid 'out' parameter"); + NSCAssert( &*out, @"ccInflateCCZFile: invalid 'out' parameter"); + + // load file into memory + unsigned char *compressed = NULL; + NSInteger fileLen = ccLoadFileIntoMemory( path, &compressed ); + if( fileLen < 0 ) { + CCLOG(@"cocos2d: Error loading CCZ compressed file"); + } + + struct CCZHeader *header = (struct CCZHeader*) compressed; + + // verify header + if( header->sig[0] != 'C' || header->sig[1] != 'C' || header->sig[2] != 'Z' || header->sig[3] != '!' ) { + CCLOG(@"cocos2d: Invalid CCZ file"); + free(compressed); + return -1; + } + + // verify header version + uint16_t version = CFSwapInt16BigToHost( header->version ); + if( version > 2 ) { + CCLOG(@"cocos2d: Unsupported CCZ header format"); + free(compressed); + return -1; + } + + // verify compression format + if( CFSwapInt16BigToHost(header->compression_type) != CCZ_COMPRESSION_ZLIB ) { + CCLOG(@"cocos2d: CCZ Unsupported compression method"); + free(compressed); + return -1; + } + + uint32_t len = CFSwapInt32BigToHost( header->len ); + + *out = malloc( len ); + if(! *out ) + { + CCLOG(@"cocos2d: CCZ: Failed to allocate memory for texture"); + free(compressed); + return -1; + } + + + uLongf destlen = len; + uLongf source = (uLongf) compressed + sizeof(*header); + int ret = uncompress(*out, &destlen, (Bytef*)source, fileLen - sizeof(*header) ); + + free( compressed ); + + if( ret != Z_OK ) + { + CCLOG(@"cocos2d: CCZ: Failed to uncompress data"); + free( *out ); + *out = NULL; + return -1; + } + + + return len; +} -- cgit 1.4.1