Skip to content

Commit b109342

Browse files
committed
Added new ccz header support from TexturePacker
On behalf from latest TexturePacker added his code changes from website, for details on contentprotection see: https://www.codeandweb.com/texturepacker/contentprotection Original ZipUtils could not handle pvr.ccz version 2 correctly (wrong byte header), currently version 3 (pvr.ccz = pvr+zlib) works fine.
1 parent 5e7c087 commit b109342

File tree

2 files changed

+204
-29
lines changed

2 files changed

+204
-29
lines changed

cocos2d/Support/ZipUtils.h

+28-4
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,26 @@
2020
#ifdef __cplusplus
2121
extern "C" {
2222
#endif
23+
24+
/**
25+
* Set the TexturePacker encryption key
26+
*
27+
* If your key used to encrypt the pvr.ccz file is
28+
* aaaaaaaabbbbbbbbccccccccdddddddd
29+
* you have to call this function 4 times:
30+
* caw_setkey_part(0, 0xaaaaaaaa);
31+
* caw_setkey_part(1, 0xbbbbbbbb);
32+
* caw_setkey_part(2, 0xcccccccc);
33+
* caw_setkey_part(3, 0xdddddddd);
34+
*
35+
* Distribute the call accross some files but make sure
36+
* to call all of the parts *before* loading the first
37+
* spritesheet.
38+
*
39+
* @param index part of the key [0..3]
40+
* @param value value of the key part
41+
*/
42+
void caw_setkey_part(int index, uint32_t value);
2343

2444
/* XXX: pragma pack ??? */
2545
/** @struct CCZHeader
@@ -28,7 +48,7 @@ extern "C" {
2848
uint8_t sig[4]; // signature. Should be 'CCZ!' 4 bytes
2949
uint16_t compression_type; // should 0
3050
uint16_t version; // should be 2 (although version type==1 is also supported)
31-
uint32_t reserved; // Reserved for users.
51+
uint32_t reserved; // Reserverd for users.
3252
uint32_t len; // size of the uncompressed file
3353
};
3454

@@ -47,35 +67,39 @@ extern "C" {
4767
* Inflates either zlib or gzip deflated memory. The inflated memory is
4868
* expected to be freed by the caller.
4969
*
50-
* It will allocate 256k for the destination buffer. If it is not enough it will multiply the previous buffer size per 2, until there is enough memory.
70+
* It will allocate 256k for the destination buffer. If it is not enought it will multiply the previous buffer size per 2, until there is enough memory.
5171
* @returns the length of the deflated buffer
5272
*
73+
@since v0.8.1
5374
*/
5475
int ccInflateMemory(unsigned char *in, unsigned int inLength, unsigned char **out);
5576

5677
/**
5778
* Inflates either zlib or gzip deflated memory. The inflated memory is
5879
* expected to be freed by the caller.
5980
*
60-
* outlengthHint is assumed to be the needed room to allocate the inflated buffer.
81+
* outLenghtHint is assumed to be the needed room to allocate the inflated buffer.
6182
*
6283
* @returns the length of the deflated buffer
6384
*
85+
@since v1.0.0
6486
*/
65-
int ccInflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int outlengthHint );
87+
int ccInflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int outLengthHint );
6688

6789

6890
/** inflates a GZip file into memory
6991
*
7092
* @returns the length of the deflated buffer
7193
*
94+
* @since v0.99.5
7295
*/
7396
int ccInflateGZipFile(const char *filename, unsigned char **out);
7497

7598
/** inflates a CCZ file into memory
7699
*
77100
* @returns the length of the deflated buffer
78101
*
102+
* @since v0.99.5
79103
*/
80104
int ccInflateCCZFile(const char *filename, unsigned char **out);
81105

cocos2d/Support/ZipUtils.m

+176-25
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@
2727
// Should buffer factor be 1.5 instead of 2 ?
2828
#define BUFFER_INC_FACTOR (2)
2929

30-
static int inflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int *outLength, unsigned int outlengthHint )
30+
static int inflateMemoryWithHint(unsigned char *in, unsigned int inLength, unsigned char **out, unsigned int *outLength, unsigned int outLengthHint )
3131
{
3232
/* ret value */
3333
int err = Z_OK;
3434

35-
int bufferSize = outlengthHint;
35+
int bufferSize = outLengthHint;
3636
*out = (unsigned char*) malloc(bufferSize);
3737

3838
z_stream d_stream; /* decompression stream */
@@ -183,8 +183,110 @@ int ccInflateGZipFile(const char *path, unsigned char **out)
183183
return offset;
184184
}
185185

186+
typedef struct {
187+
uint8_t sig[4]; // signature. Should be 'CCZp' 4 bytes
188+
uint16_t compression_type; // should 0
189+
uint16_t version; // should be 2 (although version type==1 is also supported)
190+
uint32_t checksum; // Checksum
191+
uint32_t len; // size of the uncompressed file
192+
} CCPHeader;
193+
194+
static uint32_t caw_key[4] = {0,0,0,0};
195+
static uint32_t caw_longKey[1024];
196+
static bool caw_longKeyValid=false;
197+
198+
void caw_setkey_part(int index, uint32_t value)
199+
{
200+
assert(index >= 0);
201+
assert(index < 4);
202+
if(caw_key[index] != value)
203+
{
204+
caw_key[index] = value;
205+
caw_longKeyValid = false;
206+
}
207+
}
208+
209+
static inline void caw_encdec (uint32_t *data, int len)
210+
{
211+
const int enclen = 1024;
212+
const int securelen = 512;
213+
const int distance = 64;
214+
215+
// check if key was set
216+
// make sure to call caw_setkey_part() for all 4 key parts
217+
assert(caw_key[0] != 0);
218+
assert(caw_key[1] != 0);
219+
assert(caw_key[2] != 0);
220+
assert(caw_key[3] != 0);
221+
222+
// create long key
223+
if(!caw_longKeyValid)
224+
{
225+
uint32_t y;
226+
unsigned int p, rounds=6, e;
227+
228+
uint32_t sum = 0;
229+
uint32_t z = caw_longKey[enclen-1];
230+
do
231+
{
232+
#define DELTA 0x9e3779b9
233+
#define MX (((z>>5^y<<2) + (y>>3^z<<4)) ^ ((sum^y) + (caw_key[(p&3)^e] ^ z)))
234+
235+
sum += DELTA;
236+
e = (sum >> 2) & 3;
237+
for (p=0; p<enclen-1; p++)
238+
{
239+
y = caw_longKey[p+1];
240+
z = caw_longKey[p] += MX;
241+
}
242+
y = caw_longKey[0];
243+
z = caw_longKey[enclen-1] += MX;
244+
} while (--rounds);
245+
246+
caw_longKeyValid = true;
247+
}
248+
249+
int b=0;
250+
int i=0;
251+
252+
// encrypt first part completely
253+
for(; i<len && i<securelen; i++)
254+
{
255+
data[i] ^= caw_longKey[b++];
256+
if(b >= enclen)
257+
{
258+
b=0;
259+
}
260+
}
261+
262+
// encrypt second section partially
263+
for(; i<len; i+=distance)
264+
{
265+
data[i] ^= caw_longKey[b++];
266+
if(b >= enclen)
267+
{
268+
b=0;
269+
}
270+
}
271+
}
272+
273+
static inline uint32_t caw_checksum(const uint32_t *data, int len)
274+
{
275+
uint32_t cs=0;
276+
const int cslen=128;
277+
len = (len < cslen) ? len : cslen;
278+
for(int i=0; i<len; i++)
279+
{
280+
cs = cs ^ data[i];
281+
}
282+
return cs;
283+
}
284+
285+
186286
int ccInflateCCZFile(const char *path, unsigned char **out)
187287
{
288+
printf("inflating: %s\n", path);
289+
188290
NSCAssert( out, @"ccInflateCCZFile: invalid 'out' parameter");
189291
NSCAssert( &*out, @"ccInflateCCZFile: invalid 'out' parameter");
190292

@@ -196,31 +298,80 @@ int ccInflateCCZFile(const char *path, unsigned char **out)
196298
return -1;
197299
}
198300

199-
struct CCZHeader *header = (struct CCZHeader*) compressed;
200-
201-
// verify header
202-
if( header->sig[0] != 'C' || header->sig[1] != 'C' || header->sig[2] != 'Z' || header->sig[3] != '!' ) {
203-
CCLOG(@"cocos2d: Invalid CCZ file");
204-
free(compressed);
205-
return -1;
301+
uint32_t len = 0;
302+
uint32_t headerSize = 0;
303+
304+
if( compressed[0] == 'C' && compressed[1] == 'C' && compressed[2] == 'Z' && compressed[3] == '!' )
305+
{
306+
// standard ccz file
307+
struct CCZHeader *header = (struct CCZHeader*) compressed;
308+
309+
// verify header version
310+
uint16_t version = CFSwapInt16BigToHost( header->version );
311+
if( version > 2 ) {
312+
CCLOG(@"cocos2d: Unsupported CCZ header format");
313+
free(compressed);
314+
return -1;
315+
}
316+
317+
// verify compression format
318+
if( CFSwapInt16BigToHost(header->compression_type) != CCZ_COMPRESSION_ZLIB ) {
319+
CCLOG(@"cocos2d: CCZ Unsupported compression method");
320+
free(compressed);
321+
return -1;
322+
}
323+
324+
len = CFSwapInt32BigToHost( header->len );
325+
326+
headerSize = sizeof(struct CCZHeader);
206327
}
207-
208-
// verify header version
209-
uint16_t version = CFSwapInt16BigToHost( header->version );
210-
if( version > 2 ) {
211-
CCLOG(@"cocos2d: Unsupported CCZ header format");
212-
free(compressed);
213-
return -1;
214-
}
215-
216-
// verify compression format
217-
if( CFSwapInt16BigToHost(header->compression_type) != CCZ_COMPRESSION_ZLIB ) {
218-
CCLOG(@"cocos2d: CCZ Unsupported compression method");
328+
else if(compressed[0] == 'C' && compressed[1] == 'C' && compressed[2] == 'Z' && compressed[3] == 'p' )
329+
{
330+
// encrypted ccz file
331+
CCPHeader *header = (CCPHeader*) compressed;
332+
333+
// verify header version
334+
uint16_t version = CFSwapInt16BigToHost( header->version );
335+
if( version > 0 ) {
336+
CCLOG(@"cocos2d: Unsupported CCZ header format");
337+
free(compressed);
338+
return -1;
339+
}
340+
341+
// verify compression format
342+
if( CFSwapInt16BigToHost(header->compression_type) != 0 ) {
343+
CCLOG(@"cocos2d: CCZ Unsupported compression method");
344+
free(compressed);
345+
return -1;
346+
}
347+
348+
// decrypt
349+
headerSize = sizeof(CCPHeader);
350+
uint32_t* ints = (uint32_t*)(compressed+12);
351+
int enclen = (fileLen-12)/4;
352+
353+
caw_encdec(ints, enclen);
354+
355+
len = CFSwapInt32BigToHost( header->len );
356+
357+
#ifndef NDEBUG
358+
// verify checksum in debug mode
359+
uint32_t calculated = caw_checksum(ints, enclen);
360+
uint32_t required = CFSwapInt32BigToHost( header->checksum );
361+
if(calculated != required)
362+
{
363+
CCLOG(@"cocos2d: Can't decrypt image file: Invalid decryption key");
364+
free(compressed);
365+
return -1;
366+
}
367+
#endif
368+
}
369+
else {
370+
CCLOG(@"cocos2d: Invalid CCZ file");
219371
free(compressed);
220372
return -1;
221-
}
373+
}
222374

223-
uint32_t len = CFSwapInt32BigToHost( header->len );
224375

225376
*out = malloc( len );
226377
if(! *out )
@@ -232,8 +383,8 @@ int ccInflateCCZFile(const char *path, unsigned char **out)
232383

233384

234385
uLongf destlen = len;
235-
uLongf source = (uLongf) compressed + sizeof(*header);
236-
int ret = uncompress(*out, &destlen, (Bytef*)source, fileLen - sizeof(*header) );
386+
uLongf source = (uLongf) compressed + headerSize;
387+
int ret = uncompress(*out, &destlen, (Bytef*)source, fileLen - headerSize );
237388

238389
free( compressed );
239390

0 commit comments

Comments
 (0)