summary refs log tree commit diff stats
path: root/libs/cocos2d/Support/ZipUtils.m
diff options
context:
space:
mode:
Diffstat (limited to 'libs/cocos2d/Support/ZipUtils.m')
-rwxr-xr-xlibs/cocos2d/Support/ZipUtils.m251
1 files changed, 251 insertions, 0 deletions
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 @@
1/* cocos2d for iPhone
2 *
3 * http://www.cocos2d-iphone.org
4 *
5 *
6 * Inflates either zlib or gzip deflated memory. The inflated memory is
7 * expected to be freed by the caller.
8 *
9 * inflateMemory_ based on zlib example code
10 * http://www.zlib.net
11 *
12 * Some ideas were taken from:
13 * http://themanaworld.org/
14 * from the mapreader.cpp file
15 */
16
17#import <Availability.h>
18
19#import <zlib.h>
20#import <stdlib.h>
21#import <assert.h>
22#import <stdio.h>
23
24#import "ZipUtils.h"
25#import "CCFileUtils.h"
26#import "../ccMacros.h"
27
28// memory in iPhone is precious
29// Should buffer factor be 1.5 instead of 2 ?
30#define BUFFER_INC_FACTOR (2)
31
32static int inflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int *outLength, unsigned int outLenghtHint )
33{
34 /* ret value */
35 int err = Z_OK;
36
37 int bufferSize = outLenghtHint;
38 *out = (unsigned char*) malloc(bufferSize);
39
40 z_stream d_stream; /* decompression stream */
41 d_stream.zalloc = (alloc_func)0;
42 d_stream.zfree = (free_func)0;
43 d_stream.opaque = (voidpf)0;
44
45 d_stream.next_in = in;
46 d_stream.avail_in = inLength;
47 d_stream.next_out = *out;
48 d_stream.avail_out = bufferSize;
49
50 /* window size to hold 256k */
51 if( (err = inflateInit2(&d_stream, 15 + 32)) != Z_OK )
52 return err;
53
54 for (;;) {
55 err = inflate(&d_stream, Z_NO_FLUSH);
56
57 if (err == Z_STREAM_END)
58 break;
59
60 switch (err) {
61 case Z_NEED_DICT:
62 err = Z_DATA_ERROR;
63 case Z_DATA_ERROR:
64 case Z_MEM_ERROR:
65 inflateEnd(&d_stream);
66 return err;
67 }
68
69 // not enough memory ?
70 if (err != Z_STREAM_END) {
71
72 unsigned char *tmp = realloc(*out, bufferSize * BUFFER_INC_FACTOR);
73
74 /* not enough memory, ouch */
75 if (! tmp ) {
76 CCLOG(@"cocos2d: ZipUtils: realloc failed");
77 inflateEnd(&d_stream);
78 return Z_MEM_ERROR;
79 }
80 /* only assign to *out if tmp is valid. it's not guaranteed that realloc will reuse the memory */
81 *out = tmp;
82
83 d_stream.next_out = *out + bufferSize;
84 d_stream.avail_out = bufferSize;
85 bufferSize *= BUFFER_INC_FACTOR;
86 }
87 }
88
89
90 *outLength = bufferSize - d_stream.avail_out;
91 err = inflateEnd(&d_stream);
92 return err;
93}
94
95int ccInflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int outLengthHint )
96{
97 unsigned int outLength = 0;
98 int err = inflateMemoryWithHint(in, inLength, out, &outLength, outLengthHint );
99
100 if (err != Z_OK || *out == NULL) {
101 if (err == Z_MEM_ERROR)
102 CCLOG(@"cocos2d: ZipUtils: Out of memory while decompressing map data!");
103
104 else if (err == Z_VERSION_ERROR)
105 CCLOG(@"cocos2d: ZipUtils: Incompatible zlib version!");
106
107 else if (err == Z_DATA_ERROR)
108 CCLOG(@"cocos2d: ZipUtils: Incorrect zlib compressed data!");
109
110 else
111 CCLOG(@"cocos2d: ZipUtils: Unknown error while decompressing map data!");
112
113 free(*out);
114 *out = NULL;
115 outLength = 0;
116 }
117
118 return outLength;
119}
120
121int ccInflateMemory(unsigned char *in, unsigned int inLength, unsigned char **out)
122{
123 // 256k for hint
124 return ccInflateMemoryWithHint(in, inLength, out, 256 * 1024 );
125}
126
127int ccInflateGZipFile(const char *path, unsigned char **out)
128{
129 int len;
130 unsigned int offset = 0;
131
132 NSCAssert( out, @"ccInflateGZipFile: invalid 'out' parameter");
133 NSCAssert( &*out, @"ccInflateGZipFile: invalid 'out' parameter");
134
135 gzFile inFile = gzopen(path, "rb");
136 if( inFile == NULL ) {
137 CCLOG(@"cocos2d: ZipUtils: error open gzip file: %s", path);
138 return -1;
139 }
140
141 /* 512k initial decompress buffer */
142 int bufferSize = 512 * 1024;
143 unsigned int totalBufferSize = bufferSize;
144
145 *out = malloc( bufferSize );
146 if( ! out ) {
147 CCLOG(@"cocos2d: ZipUtils: out of memory");
148 return -1;
149 }
150
151 for (;;) {
152 len = gzread(inFile, *out + offset, bufferSize);
153 if (len < 0) {
154 CCLOG(@"cocos2d: ZipUtils: error in gzread");
155 free( *out );
156 *out = NULL;
157 return -1;
158 }
159 if (len == 0)
160 break;
161
162 offset += len;
163
164 // finish reading the file
165 if( len < bufferSize )
166 break;
167
168 bufferSize *= BUFFER_INC_FACTOR;
169 totalBufferSize += bufferSize;
170 unsigned char *tmp = realloc(*out, totalBufferSize );
171
172 if( ! tmp ) {
173 CCLOG(@"cocos2d: ZipUtils: out of memory");
174 free( *out );
175 *out = NULL;
176 return -1;
177 }
178
179 *out = tmp;
180 }
181
182 if (gzclose(inFile) != Z_OK)
183 CCLOG(@"cocos2d: ZipUtils: gzclose failed");
184
185 return offset;
186}
187
188int ccInflateCCZFile(const char *path, unsigned char **out)
189{
190 NSCAssert( out, @"ccInflateCCZFile: invalid 'out' parameter");
191 NSCAssert( &*out, @"ccInflateCCZFile: invalid 'out' parameter");
192
193 // load file into memory
194 unsigned char *compressed = NULL;
195 NSInteger fileLen = ccLoadFileIntoMemory( path, &compressed );
196 if( fileLen < 0 ) {
197 CCLOG(@"cocos2d: Error loading CCZ compressed file");
198 }
199
200 struct CCZHeader *header = (struct CCZHeader*) compressed;
201
202 // verify header
203 if( header->sig[0] != 'C' || header->sig[1] != 'C' || header->sig[2] != 'Z' || header->sig[3] != '!' ) {
204 CCLOG(@"cocos2d: Invalid CCZ file");
205 free(compressed);
206 return -1;
207 }
208
209 // verify header version
210 uint16_t version = CFSwapInt16BigToHost( header->version );
211 if( version > 2 ) {
212 CCLOG(@"cocos2d: Unsupported CCZ header format");
213 free(compressed);
214 return -1;
215 }
216
217 // verify compression format
218 if( CFSwapInt16BigToHost(header->compression_type) != CCZ_COMPRESSION_ZLIB ) {
219 CCLOG(@"cocos2d: CCZ Unsupported compression method");
220 free(compressed);
221 return -1;
222 }
223
224 uint32_t len = CFSwapInt32BigToHost( header->len );
225
226 *out = malloc( len );
227 if(! *out )
228 {
229 CCLOG(@"cocos2d: CCZ: Failed to allocate memory for texture");
230 free(compressed);
231 return -1;
232 }
233
234
235 uLongf destlen = len;
236 uLongf source = (uLongf) compressed + sizeof(*header);
237 int ret = uncompress(*out, &destlen, (Bytef*)source, fileLen - sizeof(*header) );
238
239 free( compressed );
240
241 if( ret != Z_OK )
242 {
243 CCLOG(@"cocos2d: CCZ: Failed to uncompress data");
244 free( *out );
245 *out = NULL;
246 return -1;
247 }
248
249
250 return len;
251}