Use better names for hotkey related constants; add somecomments (FS#11191)
[kugel-rb.git] / tools / scramble.c
blobed972f7768965f293895d1f30a636992dcd6c854
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 - 2007 by Björn Stenberg
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 ****************************************************************************/
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include "iriver.h"
27 #include "gigabeat.h"
28 #include "gigabeats.h"
29 #include "mi4.h"
30 #include "telechips.h"
31 #include "creative.h"
32 #include "iaudio_bl_flash.h"
34 static int iaudio_encode(char *iname, char *oname, char *idstring);
35 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc);
36 static int ccpmp_encode(char *iname, char *oname);
38 enum
40 ARCHOS_PLAYER, /* and V1 recorder */
41 ARCHOS_V2RECORDER,
42 ARCHOS_FMRECORDER,
43 ARCHOS_ONDIO_SP,
44 ARCHOS_ONDIO_FM
47 static unsigned int size_limit[] =
49 0x32000, /* ARCHOS_PLAYER */
50 0x64000, /* ARCHOS_V2RECORDER */
51 0x64000, /* ARCHOS_FMRECORDER */
52 0x64000, /* ARCHOS_ONDIO_SP */
53 0x64000 /* ARCHOS_ONDIO_FM */
56 void short2le(unsigned short val, unsigned char* addr)
58 addr[0] = val & 0xFF;
59 addr[1] = (val >> 8) & 0xff;
62 unsigned int le2int(unsigned char* buf)
64 unsigned int res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
66 return res;
69 void int2le(unsigned int val, unsigned char* addr)
71 addr[0] = val & 0xFF;
72 addr[1] = (val >> 8) & 0xff;
73 addr[2] = (val >> 16) & 0xff;
74 addr[3] = (val >> 24) & 0xff;
77 void int2be(unsigned int val, unsigned char* addr)
79 addr[0] = (val >> 24) & 0xff;
80 addr[1] = (val >> 16) & 0xff;
81 addr[2] = (val >> 8) & 0xff;
82 addr[3] = val & 0xFF;
85 void short2be(unsigned short val, unsigned char* addr)
87 addr[0] = (val >> 8) & 0xff;
88 addr[1] = val & 0xFF;
91 void usage(void)
93 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
94 printf("options:\n"
95 "\t-fm Archos FM recorder format\n"
96 "\t-v2 Archos V2 recorder format\n"
97 "\t-ofm Archos Ondio FM recorder format\n"
98 "\t-osp Archos Ondio SP format\n"
99 "\t-neo SSI Neo format\n"
100 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
101 "\t-iriver iRiver format\n"
102 "\t-iaudiox5 iAudio X5 format\n"
103 "\t-iaudiox5v iAudio X5V format\n"
104 "\t-iaudiom5 iAudio M5 format\n"
105 "\t-iaudiom3 iAudio M3 format\n");
106 printf("\t-ipod3g ipod firmware partition format (3rd Gen)\n"
107 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
108 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
109 "\t-creative=X Creative firmware structure format\n"
110 "\t (X values: zvm, zvm60, zenvision\n"
111 "\t zenv, zen\n");
112 printf("\t-gigabeat Toshiba Gigabeat F/X format\n"
113 "\t-gigabeats Toshiba Gigabeat S format\n"
114 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
115 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
116 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
117 "\t All mi4 options take two optional arguments:\n");
118 printf("\t -model=XXXX where XXXX is the model id string\n"
119 "\t -type=XXXX where XXXX is a string indicating the \n"
120 "\t type of binary, eg. RBOS, RBBL\n"
121 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
122 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
123 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
124 "\t ip3g, ip4g, mini, iax5, iam5, iam3, h10, h10_5gb,\n"
125 "\t tpj2, c200, e200, giga, gigs, m100, m500, d2,\n");
126 printf("\t 9200, 1630, 6330, ldax, m200, c100, clip, e2v2,\n"
127 "\t m2v4, fuze, c2v2, clv2, y820, y920, y925, x747,\n"
128 "\t 747p, x777, nn2g, m244, cli+, fuz2)\n");
129 printf("\nNo option results in Archos standard player/recorder format.\n");
131 exit(1);
134 int main (int argc, char** argv)
136 unsigned long length,i,slen=0;
137 unsigned char *inbuf,*outbuf;
138 unsigned short crc=0;
139 unsigned long chksum=0; /* 32 bit checksum */
140 unsigned char header[24];
141 char *iname = argv[1];
142 char *oname = argv[2];
143 char *xorstring=NULL;
144 int headerlen = 6;
145 FILE* file;
146 int version=0;
147 unsigned long modelnum;
148 char modelname[5];
149 int model_id;
150 enum { none, scramble, xor, tcc_sum, tcc_crc, add } method = scramble;
151 bool creative_enable_ciff;
153 model_id = ARCHOS_PLAYER;
155 if (argc < 3) {
156 usage();
159 if(!strcmp(argv[1], "-fm")) {
160 headerlen = 24;
161 iname = argv[2];
162 oname = argv[3];
163 version = 4;
164 model_id = ARCHOS_FMRECORDER;
167 else if(!strcmp(argv[1], "-v2")) {
168 headerlen = 24;
169 iname = argv[2];
170 oname = argv[3];
171 version = 2;
172 model_id = ARCHOS_V2RECORDER;
175 else if(!strcmp(argv[1], "-ofm")) {
176 headerlen = 24;
177 iname = argv[2];
178 oname = argv[3];
179 version = 8;
180 model_id = ARCHOS_ONDIO_FM;
183 else if(!strcmp(argv[1], "-osp")) {
184 headerlen = 24;
185 iname = argv[2];
186 oname = argv[3];
187 version = 16;
188 model_id = ARCHOS_ONDIO_SP;
191 else if(!strcmp(argv[1], "-neo")) {
192 headerlen = 17;
193 iname = argv[2];
194 oname = argv[3];
195 method = none;
197 else if(!strncmp(argv[1], "-mm=", 4)) {
198 headerlen = 16;
199 iname = argv[2];
200 oname = argv[3];
201 method = xor;
202 version = argv[1][4];
203 if (argc > 4)
204 xorstring = argv[4];
205 else {
206 printf("Multimedia needs an xor string\n");
207 return -1;
210 else if(!strncmp(argv[1], "-tcc=", 4)) {
211 headerlen = 0;
212 iname = argv[2];
213 oname = argv[3];
215 if(!strcmp(&argv[1][5], "sum"))
216 method = tcc_sum;
217 else if(!strcmp(&argv[1][5], "crc"))
218 method = tcc_crc;
219 else {
220 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
221 return 2;
224 else if(!strncmp(argv[1], "-add=", 5)) {
225 iname = argv[2];
226 oname = argv[3];
227 method = add;
229 if(!strcmp(&argv[1][5], "h120"))
230 modelnum = 0;
231 else if(!strcmp(&argv[1][5], "h140"))
232 modelnum = 0; /* the same as the h120 */
233 else if(!strcmp(&argv[1][5], "h100"))
234 modelnum = 1;
235 else if(!strcmp(&argv[1][5], "h300"))
236 modelnum = 2;
237 else if(!strcmp(&argv[1][5], "ipco"))
238 modelnum = 3;
239 else if(!strcmp(&argv[1][5], "nano"))
240 modelnum = 4;
241 else if(!strcmp(&argv[1][5], "ipvd"))
242 modelnum = 5;
243 else if(!strcmp(&argv[1][5], "fp7x"))
244 modelnum = 6;
245 else if(!strcmp(&argv[1][5], "ip3g"))
246 modelnum = 7;
247 else if(!strcmp(&argv[1][5], "ip4g"))
248 modelnum = 8;
249 else if(!strcmp(&argv[1][5], "mini"))
250 modelnum = 9;
251 else if(!strcmp(&argv[1][5], "iax5"))
252 modelnum = 10;
253 else if(!strcmp(&argv[1][5], "mn2g"))
254 modelnum = 11;
255 else if(!strcmp(&argv[1][5], "h10"))
256 modelnum = 13;
257 else if(!strcmp(&argv[1][5], "h10_5gb"))
258 modelnum = 14;
259 else if(!strcmp(&argv[1][5], "tpj2"))
260 modelnum = 15;
261 else if(!strcmp(&argv[1][5], "e200"))
262 modelnum = 16;
263 else if(!strcmp(&argv[1][5], "iam5"))
264 modelnum = 17;
265 else if(!strcmp(&argv[1][5], "giga"))
266 modelnum = 18;
267 else if(!strcmp(&argv[1][5], "1g2g"))
268 modelnum = 19;
269 else if(!strcmp(&argv[1][5], "c200"))
270 modelnum = 20;
271 else if(!strcmp(&argv[1][5], "gigs"))
272 modelnum = 21;
273 else if(!strcmp(&argv[1][5], "m500"))
274 modelnum = 22;
275 else if(!strcmp(&argv[1][5], "m100"))
276 modelnum = 23;
277 else if(!strcmp(&argv[1][5], "d2"))
278 modelnum = 24;
279 else if(!strcmp(&argv[1][5], "iam3"))
280 modelnum = 25;
281 else if (!strcmp(&argv[1][5], "m200"))
282 modelnum = 29;
283 else if(!strcmp(&argv[1][5], "c100"))
284 modelnum = 30;
285 else if(!strcmp(&argv[1][5], "1630")) /* Philips HDD1630 */
286 modelnum = 31;
287 else if (!strcmp(&argv[1][5], "i7"))
288 modelnum = 32;
289 else if (!strcmp(&argv[1][5], "ldax"))
290 modelnum = 33;
291 else if(!strcmp(&argv[1][5], "9200")) /* Philips SA9200 */
292 modelnum = 34;
293 else if (!strcmp(&argv[1][5], "clip"))
294 modelnum = 40;
295 else if (!strcmp(&argv[1][5], "e2v2"))
296 modelnum = 41;
297 else if (!strcmp(&argv[1][5], "m2v4"))
298 modelnum = 42;
299 else if (!strcmp(&argv[1][5], "fuze"))
300 modelnum = 43;
301 else if (!strcmp(&argv[1][5], "c2v2"))
302 modelnum = 44;
303 else if (!strcmp(&argv[1][5], "x747"))
304 modelnum = 45;
305 else if (!strcmp(&argv[1][5], "747p"))
306 modelnum = 54;
307 else if (!strcmp(&argv[1][5], "y820")) /* Samsung YH-820 */
308 modelnum = 57;
309 else if (!strcmp(&argv[1][5], "y920")) /* Samsung YH-920 */
310 modelnum = 58;
311 else if (!strcmp(&argv[1][5], "y925")) /* Samsung YH-925 */
312 modelnum = 59;
313 else if (!strcmp(&argv[1][5], "clv2")) /* Sansa Clipv2 */
314 modelnum = 60;
315 else if (!strcmp(&argv[1][5], "x777"))
316 modelnum = 61;
317 else if (!strcmp(&argv[1][5], "nn2g")) /* iPod Nano 2nd Gen */
318 modelnum = 62;
319 else if (!strcmp(&argv[1][5], "x767"))
320 modelnum = 64;
321 else if (!strcmp(&argv[1][5], "6330")) /* Philips HDD6330 */
322 modelnum = 65;
323 else if (!strcmp(&argv[1][5], "cli+")) /* Sansa Clip+ */
324 modelnum = 66;
325 else if (!strcmp(&argv[1][5], "v500")) /* Packard Bell Vibe 500 */
326 modelnum = 67;
327 else if (!strcmp(&argv[1][5], "fuz2")) /* Sansa Fuze v2 */
328 modelnum = 68;
329 else if (!strcmp(&argv[1][5], "m244"))
330 modelnum = 131;
331 else {
332 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
333 return 2;
335 /* we store a 4-letter model name too, for humans */
336 strncpy(modelname, &argv[1][5],4);
337 modelname[4] = '\0'; /* to be sure we are null terminated */
338 chksum = modelnum; /* start checksum calcs with this */
341 else if(!strcmp(argv[1], "-iriver")) {
342 /* iRiver code dealt with in the iriver.c code */
343 iname = argv[2];
344 oname = argv[3];
345 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
347 else if(!strcmp(argv[1], "-gigabeat")) {
348 /* iRiver code dealt with in the iriver.c code */
349 iname = argv[2];
350 oname = argv[3];
351 gigabeat_code(iname, oname);
352 return 0;
354 else if(!strcmp(argv[1], "-gigabeats")) {
355 iname = argv[2];
356 oname = argv[3];
357 return gigabeat_s_code(iname, oname);
359 else if(!strcmp(argv[1], "-iaudiox5")) {
360 iname = argv[2];
361 oname = argv[3];
362 return iaudio_encode(iname, oname, "COWON_X5_FW");
364 else if(!strcmp(argv[1], "-iaudiox5v")) {
365 iname = argv[2];
366 oname = argv[3];
367 return iaudio_encode(iname, oname, "COWON_X5V_FW");
369 else if(!strcmp(argv[1], "-iaudiom5")) {
370 iname = argv[2];
371 oname = argv[3];
372 return iaudio_encode(iname, oname, "COWON_M5_FW");
374 else if(!strcmp(argv[1], "-iaudiom3")) {
375 iname = argv[2];
376 oname = argv[3];
377 return iaudio_encode(iname, oname, "COWON_M3_FW");
379 else if(!strcmp(argv[1], "-ipod3g")) {
380 iname = argv[2];
381 oname = argv[3];
382 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
384 else if(!strcmp(argv[1], "-ipod4g")) {
385 iname = argv[2];
386 oname = argv[3];
387 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
389 else if(!strcmp(argv[1], "-ipod5g")) {
390 iname = argv[2];
391 oname = argv[3];
392 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
394 else if(!strncmp(argv[1], "-creative=", 10)) {
395 if(!strcmp(argv[2], "-no-ciff"))
397 creative_enable_ciff = false;
398 iname = argv[3];
399 oname = argv[4];
401 else
403 creative_enable_ciff = true;
404 iname = argv[2];
405 oname = argv[3];
407 if(!strcmp(&argv[1][10], "zvm"))
408 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
409 else if(!strcmp(&argv[1][10], "zvm60"))
410 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
411 else if(!strcmp(&argv[1][10], "zenvision"))
412 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
413 else if(!strcmp(&argv[1][10], "zenv"))
414 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
415 else if(!strcmp(&argv[1][10], "zen"))
416 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
417 else
419 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
420 return 2;
423 else if(!strcmp(argv[1], "-ccpmp")) {
424 iname = argv[2];
425 oname = argv[3];
426 return ccpmp_encode(iname, oname);
428 else if(!strncmp(argv[1], "-mi4", 4)) {
429 int mi4magic;
430 char model[4] = "";
431 char type[4] = "";
433 if(!strcmp(&argv[1][4], "v2")) {
434 mi4magic = MI4_MAGIC_DEFAULT;
435 version = 0x00010201;
437 else if(!strcmp(&argv[1][4], "v3")) {
438 mi4magic = MI4_MAGIC_DEFAULT;
439 version = 0x00010301;
441 else if(!strcmp(&argv[1][4], "r")) {
442 mi4magic = MI4_MAGIC_R;
443 version = 0x00010301;
445 else {
446 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
447 return -1;
450 iname = argv[2];
451 oname = argv[3];
453 if(!strncmp(argv[2], "-model=", 7)) {
454 iname = argv[3];
455 oname = argv[4];
456 strncpy(model, &argv[2][7], 4);
458 if(!strncmp(argv[3], "-type=", 6)) {
459 iname = argv[4];
460 oname = argv[5];
461 strncpy(type, &argv[3][6], 4);
465 return mi4_encode(iname, oname, version, mi4magic, model, type);
468 /* open file */
469 file = fopen(iname,"rb");
470 if (!file) {
471 perror(iname);
472 return -1;
474 fseek(file,0,SEEK_END);
475 length = ftell(file);
476 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
478 if ((method == scramble) &&
479 ((length + headerlen) >= size_limit[model_id])) {
480 printf("error: firmware image is %ld bytes while max size is %u!\n",
481 length + headerlen,
482 size_limit[model_id]);
483 fclose(file);
484 return -1;
487 fseek(file,0,SEEK_SET);
488 inbuf = malloc(length);
489 if (method == xor)
490 outbuf = malloc(length*2);
491 else if(method == add)
492 outbuf = malloc(length + 8);
493 else
494 outbuf = malloc(length);
495 if ( !inbuf || !outbuf ) {
496 printf("out of memory!\n");
497 return -1;
499 if(length> 4) {
500 /* zero-fill the last 4 bytes to make sure there's no rubbish there
501 when we write the size-aligned file later */
502 memset(outbuf+length-4, 0, 4);
505 /* read file */
506 i=fread(inbuf,1,length,file);
507 if ( !i ) {
508 perror(iname);
509 return -1;
511 fclose(file);
513 switch (method)
515 case add:
516 for (i = 0; i < length; i++) {
517 /* add 8 unsigned bits but keep a 32 bit sum */
518 chksum += inbuf[i];
520 break;
521 case scramble:
522 slen = length/4;
523 for (i = 0; i < length; i++) {
524 unsigned long addr = (i >> 2) + ((i % 4) * slen);
525 unsigned char data = inbuf[i];
526 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
527 outbuf[addr] = data;
529 break;
531 case xor:
532 /* "compress" */
533 slen = 0;
534 for (i=0; i<length; i++) {
535 if (!(i&7))
536 outbuf[slen++] = 0xff; /* all data is uncompressed */
537 outbuf[slen++] = inbuf[i];
539 break;
540 case none:
541 default:
542 /* dummy case just to silence picky compilers */
543 break;
546 if((method == none) || (method == scramble) || (method == xor)) {
547 /* calculate checksum */
548 for (i=0;i<length;i++)
549 crc += inbuf[i];
552 memset(header, 0, sizeof header);
553 switch (method)
555 case add:
557 int2be(chksum, header); /* checksum, big-endian */
558 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
559 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
560 headerlen = 8;
562 break;
564 case tcc_sum:
565 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
566 telechips_encode_sum(outbuf, length);
567 break;
569 case tcc_crc:
570 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
571 telechips_encode_crc(outbuf, length);
572 break;
574 case scramble:
575 if (headerlen == 6) {
576 int2be(length, header);
577 header[4] = (crc >> 8) & 0xff;
578 header[5] = crc & 0xff;
580 else {
581 header[0] =
582 header[1] =
583 header[2] =
584 header[3] = 0xff; /* ??? */
586 header[6] = (crc >> 8) & 0xff;
587 header[7] = crc & 0xff;
589 header[11] = version;
591 header[15] = headerlen; /* really? */
593 int2be(length, &header[20]);
595 break;
597 case xor:
599 int xorlen = strlen(xorstring);
601 /* xor data */
602 for (i=0; i<slen; i++)
603 outbuf[i] ^= xorstring[i & (xorlen-1)];
605 /* calculate checksum */
606 for (i=0; i<slen; i++)
607 crc += outbuf[i];
609 header[0] = header[2] = 'Z';
610 header[1] = header[3] = version;
611 int2le(length, &header[4]);
612 int2le(slen, &header[8]);
613 int2le(crc, &header[12]);
614 length = slen;
615 break;
618 #define MY_FIRMWARE_TYPE "Rockbox"
619 #define MY_HEADER_VERSION 1
620 default:
621 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
622 header[9]='\0'; /*shouldn't have to, but to be SURE */
623 header[10]=MY_HEADER_VERSION&0xFF;
624 header[11]=(crc>>8)&0xFF;
625 header[12]=crc&0xFF;
626 int2be(sizeof(header), &header[12]);
627 break;
630 /* write file */
631 file = fopen(oname,"wb");
632 if ( !file ) {
633 perror(oname);
634 return -1;
636 if (headerlen > 0) {
637 if ( !fwrite(header,headerlen,1,file) ) {
638 perror(oname);
639 return -1;
642 if ( !fwrite(outbuf,length,1,file) ) {
643 perror(oname);
644 return -1;
646 fclose(file);
648 free(inbuf);
649 free(outbuf);
651 return 0;
654 static int iaudio_encode(char *iname, char *oname, char *idstring)
656 size_t len;
657 int length;
658 FILE *file;
659 unsigned char *outbuf;
660 int i;
661 unsigned char sum = 0;
663 file = fopen(iname, "rb");
664 if (!file) {
665 perror(iname);
666 return -1;
668 fseek(file,0,SEEK_END);
669 length = ftell(file);
671 fseek(file,0,SEEK_SET);
672 outbuf = malloc(length+0x1030);
674 if ( !outbuf ) {
675 printf("out of memory!\n");
676 return -1;
679 len = fread(outbuf+0x1030, 1, length, file);
680 if(len < (size_t) length) {
681 perror(iname);
682 return -2;
685 memset(outbuf, 0, 0x1030);
686 strcpy((char *)outbuf, idstring);
687 memcpy(outbuf+0x20, iaudio_bl_flash,
688 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
689 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
690 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
691 outbuf[0x19] = 2;
693 for(i = 0; i < length;i++)
694 sum += outbuf[0x1030 + i];
696 int2be(length, &outbuf[0x1024]);
697 outbuf[0x102b] = sum;
699 fclose(file);
701 file = fopen(oname, "wb");
702 if (!file) {
703 perror(oname);
704 return -3;
707 len = fwrite(outbuf, 1, length+0x1030, file);
708 if(len < (size_t)length) {
709 perror(oname);
710 return -4;
713 fclose(file);
714 return 0;
718 /* Create an ipod firmware partition image
720 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
722 This function doesn't yet handle the Broadcom resource image for the 5g,
723 so the resulting images won't be usable.
725 This has also only been tested on an ipod Photo
728 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
730 static const char *apple_stop_sign = "{{~~ /-----\\ "\
731 "{{~~ / \\ "\
732 "{{~~| | "\
733 "{{~~| S T O P | "\
734 "{{~~| | "\
735 "{{~~ \\ / "\
736 "{{~~ \\-----/ "\
737 "Copyright(C) 200"\
738 "1 Apple Computer"\
739 ", Inc.----------"\
740 "----------------"\
741 "----------------"\
742 "----------------"\
743 "----------------"\
744 "----------------"\
745 "---------------";
746 size_t len;
747 int length;
748 int rsrclength;
749 int rsrcoffset;
750 FILE *file;
751 unsigned int sum = 0;
752 unsigned int rsrcsum = 0;
753 unsigned char *outbuf;
754 int bufsize;
755 int i;
757 file = fopen(iname, "rb");
758 if (!file) {
759 perror(iname);
760 return -1;
762 fseek(file,0,SEEK_END);
763 length = ftell(file);
765 fseek(file,0,SEEK_SET);
767 bufsize=(length+0x4600);
768 if (fake_rsrc) {
769 bufsize = (bufsize + 0x400) & ~0x200;
772 outbuf = malloc(bufsize);
774 if ( !outbuf ) {
775 printf("out of memory!\n");
776 return -1;
779 len = fread(outbuf+0x4600, 1, length, file);
780 if(len < (size_t)length) {
781 perror(iname);
782 return -2;
784 fclose(file);
786 /* Calculate checksum for later use in header */
787 for(i = 0x4600; i < 0x4600+length;i++)
788 sum += outbuf[i];
790 /* Clear the header area to zero */
791 memset(outbuf, 0, 0x4600);
793 /* APPLE STOP SIGN */
794 strcpy((char *)outbuf, apple_stop_sign);
796 /* VOLUME HEADER */
797 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
798 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
799 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
800 short2le(fw_ver, &outbuf[0x10a]);
802 /* Firmware Directory - "osos" entry */
803 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
804 int2le(0, &outbuf[0x4208]); /* id */
805 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
806 int2le(length, &outbuf[0x4210]); /* Length of firmware */
807 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
808 int2le(0, &outbuf[0x4218]); /* Entry Offset */
809 int2le(sum, &outbuf[0x421c]); /* Checksum */
810 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
811 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
813 /* "rsrc" entry (if applicable) */
814 if (fake_rsrc) {
815 rsrcoffset=(length+0x4600+0x200) & ~0x200;
816 rsrclength=0x200;
817 rsrcsum=0;
819 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
820 int2le(0, &outbuf[0x4230]); /* id */
821 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
822 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
823 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
824 int2le(0, &outbuf[0x4240]); /* Entry Offset */
825 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
826 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
827 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
830 file = fopen(oname, "wb");
831 if (!file) {
832 perror(oname);
833 return -3;
836 len = fwrite(outbuf, 1, length+0x4600, file);
837 if(len < (size_t)length) {
838 perror(oname);
839 return -4;
842 fclose(file);
844 return 0;
847 #define CCPMP_SIZE 0x500000
848 static int ccpmp_encode(char *iname, char *oname)
850 size_t len;
851 int length;
852 FILE *file;
853 unsigned char *outbuf;
855 file = fopen(iname, "rb");
856 if (!file) {
857 perror(iname);
858 return -1;
860 fseek(file,0,SEEK_END);
861 length = ftell(file);
863 fseek(file,0,SEEK_SET);
865 outbuf = malloc(CCPMP_SIZE);
867 if ( !outbuf ) {
868 printf("out of memory!\n");
869 return -1;
872 len = fread(outbuf, 1, length, file);
873 if(len < (size_t)length) {
874 perror(iname);
875 return -2;
877 fclose(file);
879 /* Clear the tail area to 0xFF */
880 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
882 /* Header */
883 int2le(length, &outbuf[0x4]);
885 file = fopen(oname, "wb");
886 if (!file) {
887 perror(oname);
888 return -3;
891 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
892 if(len < (size_t)length) {
893 perror(oname);
894 return -4;
897 fclose(file);
899 return 0;