diff options
Diffstat (limited to 'libs/cocos2d/Support/ZipUtils.m')
-rwxr-xr-x | libs/cocos2d/Support/ZipUtils.m | 251 |
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 | |||
32 | static 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 | |||
95 | int 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 | |||
121 | int 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 | |||
127 | int 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 | |||
188 | int 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 | } | ||