1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2009 by Maurus Cuelenaere
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
28 #include "chinachip.h"
30 #define tr(x) x /* Qt translation support */
32 /* From http://www.rockbox.org/wiki/ChinaChip */
35 uint32_t signature
; /* WADF */
37 int8_t timestamp
[12]; /* 200805081100 */
41 int8_t identifier
[32]; /* Chinachip PMP firmware V1.0 */
42 } __attribute__ ((packed
));
44 static inline void int2le(unsigned char* addr
, unsigned int val
)
47 addr
[1] = (val
>> 8) & 0xff;
48 addr
[2] = (val
>> 16) & 0xff;
49 addr
[3] = (val
>> 24) & 0xff;
52 static inline unsigned int le2int(unsigned char* buf
)
54 return (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
57 static long int filesize(FILE* fd
)
60 fseek(fd
, 0, SEEK_END
);
62 fseek(fd
, 0, SEEK_SET
);
67 #define ERR(fmt, ...) err(userdata, "[ERR] "fmt"\n", ##__VA_ARGS__)
68 #define INFO(fmt, ...) info(userdata, "[INFO] "fmt"\n", ##__VA_ARGS__)
71 #define ERR(fmt, ...) err(userdata, fmt, ##__VA_ARGS__)
72 #define INFO(fmt, ...) info(userdata, fmt, ##__VA_ARGS__)
74 #define FCLOSE(fd) fclose(fd); fd = NULL;
75 #define CCPMPBIN_HEADER_SIZE (sizeof(uint32_t)*2 + sizeof(uint8_t) + 9)
76 #define TOTAL_SIZE (fsize + CCPMPBIN_HEADER_SIZE + bsize)
77 int chinachip_patch(const char* firmware
, const char* bootloader
,
78 const char* output
, const char* ccpmp_backup
,
79 void (*info
)(void*, char*, ...),
80 void (*err
)(void*, char*, ...),
86 unsigned char* buf
= NULL
;
87 FILE *fd
= NULL
, *bd
= NULL
, *od
= NULL
;
88 unsigned int ccpmp_size
= 0, i
, fsize
, bsize
;
89 signed int checksum
= 0, ccpmp_pos
;
91 fd
= fopen(firmware
, "rb");
94 ERR(tr("Can't open file %s!"), firmware
);
97 bd
= fopen(bootloader
, "rb");
100 ERR(tr("Can't open file %s!"), bootloader
);
104 bsize
= filesize(bd
);
105 INFO(tr("Bootloader size is %d bytes"), bsize
);
108 fsize
= filesize(fd
);
109 INFO(tr("Firmware size is %d bytes"), fsize
);
111 buf
= malloc(TOTAL_SIZE
);
114 ERR(tr("Can't allocate %d bytes!"), fsize
);
117 memset(buf
, 0, TOTAL_SIZE
);
119 INFO(tr("Reading %s into memory..."), firmware
);
120 if(fread(buf
, fsize
, 1, fd
) != 1)
122 ERR(tr("Can't read file %s to memory!"), firmware
);
127 if(memcmp(buf
, "WADF", 4))
129 ERR(tr("File %s isn't a valid ChinaChip firmware!"), firmware
);
133 ccpmp_pos
= -1, i
= 0x40;
136 int filenamesize
= le2int(&buf
[i
]);
137 i
+= sizeof(uint32_t);
139 if(!strncmp((char*) &buf
[i
], "ccpmp.bin", 9))
142 ccpmp_size
= le2int(&buf
[i
+ sizeof(uint8_t) + filenamesize
]);
145 i
+= filenamesize
+ le2int(&buf
[i
+ sizeof(uint8_t) + filenamesize
])
146 + sizeof(uint32_t) + sizeof(uint8_t);
147 } while(ccpmp_pos
< 0 && i
< fsize
);
151 ERR(tr("Couldn't find ccpmp.bin in %s!"), firmware
);
154 INFO(tr("Found ccpmp.bin at %d bytes"), ccpmp_pos
);
158 int ccpmp_data_pos
= ccpmp_pos
+ 9;
159 bd
= fopen(ccpmp_backup
, "wb");
162 ERR(tr("Can't open file %s!"), ccpmp_backup
);
166 INFO(tr("Writing %d bytes to %s..."), ccpmp_size
, ccpmp_backup
);
167 if(fwrite(&buf
[ccpmp_data_pos
], ccpmp_size
, 1, bd
) != 1)
169 ERR(tr("Can't write to file %s!"), ccpmp_backup
);
175 INFO(tr("Renaming it to ccpmp.old..."));
176 buf
[ccpmp_pos
+ 6] = 'o';
177 buf
[ccpmp_pos
+ 7] = 'l';
178 buf
[ccpmp_pos
+ 8] = 'd';
180 bd
= fopen(bootloader
, "rb");
183 ERR(tr("Can't open file %s!"), bootloader
);
187 /* Also include path size */
188 ccpmp_pos
-= sizeof(uint32_t);
190 INFO(tr("Making place for ccpmp.bin..."));
191 memmove(&buf
[ccpmp_pos
+ bsize
+ CCPMPBIN_HEADER_SIZE
],
192 &buf
[ccpmp_pos
], fsize
- ccpmp_pos
);
194 INFO(tr("Reading %s into memory..."), bootloader
);
195 if(fread(&buf
[ccpmp_pos
+ CCPMPBIN_HEADER_SIZE
],
198 ERR(tr("Can't read file %s to memory!"), bootloader
);
203 INFO(tr("Adding header to %s..."), bootloader
);
204 int2le(&buf
[ccpmp_pos
], 9); /* Pathname Size */
205 memcpy(&buf
[ccpmp_pos
+ 4 ], "ccpmp.bin", 9); /* Pathname */
206 memset(&buf
[ccpmp_pos
+ 4 + 9 ], 0x20, sizeof(uint8_t)); /* File Type */
207 int2le(&buf
[ccpmp_pos
+ 4 + 9 + 1], bsize
); /* File Size */
210 time_info
= localtime(&cur_time
);
211 if(time_info
== NULL
)
213 ERR(tr("Can't obtain current time!"));
217 snprintf(header_time
, 13, "%04d%02d%02d%02d%02d", time_info
->tm_year
+ 1900,
223 INFO(tr("Computing checksum..."));
224 for(i
= sizeof(struct header
); i
< TOTAL_SIZE
; i
+=4)
225 checksum
+= le2int(&buf
[i
]);
227 INFO(tr("Updating main header..."));
228 memcpy(&buf
[offsetof(struct header
, timestamp
)], header_time
, 12);
229 int2le(&buf
[offsetof(struct header
, size
) ], TOTAL_SIZE
);
230 int2le(&buf
[offsetof(struct header
, checksum
) ], checksum
);
232 od
= fopen(output
, "wb");
235 ERR(tr("Can't open file %s!"), output
);
239 INFO(tr("Writing output to %s..."), output
);
240 if(fwrite(buf
, TOTAL_SIZE
, 1, od
) != 1)
242 ERR(tr("Can't write to file %s!"), output
);
266 #define VERSION "0.1"
267 #define PRINT(fmt, ...) fprintf(stderr, fmt"\n", ##__VA_ARGS__)
269 static void info(void* userdata
, char* fmt
, ...)
274 vfprintf(stderr
, fmt
, args
);
278 static void err(void* userdata
, char* fmt
, ...)
283 vfprintf(stderr
, fmt
, args
);
287 void usage(char* name
)
290 PRINT(" %s <firmware> <bootloader> <firmware_output> [backup]", name
);
292 PRINT(" %s VX747.HXF bootloader.bin output.HXF ccpmp.bak", name
);
293 PRINT(" This will copy ccpmp.bin in VX747.HXF as ccpmp.old and replace it"
294 " with bootloader.bin, the output will get written to output.HXF."
295 " The old ccpmp.bin will get written to ccpmp.bak.");
298 int main(int argc
, char* argv
[])
300 PRINT("ChinaChipPatcher v" VERSION
" - (C) Maurus Cuelenaere 2009");
301 PRINT("This is free software; see the source for copying conditions. There is NO");
302 PRINT("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
310 return chinachip_patch(argv
[1], argv
[2], argv
[3], argc
> 4 ? argv
[4] : NULL
,