Sansa Fuze+: initial commit (bootloader only, LCD basically working)
[kugel-rb.git] / tools / scramble.c
blobdbf41fde44d632873323b4911e016cddc91a4bf6
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, hd20, hd30,\n"
129 "\t ip6g)\n");
130 printf("\nNo option results in Archos standard player/recorder format.\n");
132 exit(1);
135 int main (int argc, char** argv)
137 unsigned long length,i,slen=0;
138 unsigned char *inbuf,*outbuf;
139 unsigned short crc=0;
140 unsigned long chksum=0; /* 32 bit checksum */
141 unsigned char header[24];
142 char *iname = argv[1];
143 char *oname = argv[2];
144 char *xorstring=NULL;
145 int headerlen = 6;
146 FILE* file;
147 int version=0;
148 unsigned long modelnum;
149 char modelname[5];
150 int model_id;
151 enum { none, scramble, xor, tcc_sum, tcc_crc, add } method = scramble;
152 bool creative_enable_ciff;
154 model_id = ARCHOS_PLAYER;
156 if (argc < 3) {
157 usage();
160 if(!strcmp(argv[1], "-fm")) {
161 headerlen = 24;
162 iname = argv[2];
163 oname = argv[3];
164 version = 4;
165 model_id = ARCHOS_FMRECORDER;
168 else if(!strcmp(argv[1], "-v2")) {
169 headerlen = 24;
170 iname = argv[2];
171 oname = argv[3];
172 version = 2;
173 model_id = ARCHOS_V2RECORDER;
176 else if(!strcmp(argv[1], "-ofm")) {
177 headerlen = 24;
178 iname = argv[2];
179 oname = argv[3];
180 version = 8;
181 model_id = ARCHOS_ONDIO_FM;
184 else if(!strcmp(argv[1], "-osp")) {
185 headerlen = 24;
186 iname = argv[2];
187 oname = argv[3];
188 version = 16;
189 model_id = ARCHOS_ONDIO_SP;
192 else if(!strcmp(argv[1], "-neo")) {
193 headerlen = 17;
194 iname = argv[2];
195 oname = argv[3];
196 method = none;
198 else if(!strncmp(argv[1], "-mm=", 4)) {
199 headerlen = 16;
200 iname = argv[2];
201 oname = argv[3];
202 method = xor;
203 version = argv[1][4];
204 if (argc > 4)
205 xorstring = argv[4];
206 else {
207 printf("Multimedia needs an xor string\n");
208 return -1;
211 else if(!strncmp(argv[1], "-tcc=", 4)) {
212 headerlen = 0;
213 iname = argv[2];
214 oname = argv[3];
216 if(!strcmp(&argv[1][5], "sum"))
217 method = tcc_sum;
218 else if(!strcmp(&argv[1][5], "crc"))
219 method = tcc_crc;
220 else {
221 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
222 return 2;
225 else if(!strncmp(argv[1], "-add=", 5)) {
226 iname = argv[2];
227 oname = argv[3];
228 method = add;
230 if(!strcmp(&argv[1][5], "h120"))
231 modelnum = 0;
232 else if(!strcmp(&argv[1][5], "h140"))
233 modelnum = 0; /* the same as the h120 */
234 else if(!strcmp(&argv[1][5], "h100"))
235 modelnum = 1;
236 else if(!strcmp(&argv[1][5], "h300"))
237 modelnum = 2;
238 else if(!strcmp(&argv[1][5], "ipco"))
239 modelnum = 3;
240 else if(!strcmp(&argv[1][5], "nano"))
241 modelnum = 4;
242 else if(!strcmp(&argv[1][5], "ipvd"))
243 modelnum = 5;
244 else if(!strcmp(&argv[1][5], "fp7x"))
245 modelnum = 6;
246 else if(!strcmp(&argv[1][5], "ip3g"))
247 modelnum = 7;
248 else if(!strcmp(&argv[1][5], "ip4g"))
249 modelnum = 8;
250 else if(!strcmp(&argv[1][5], "mini"))
251 modelnum = 9;
252 else if(!strcmp(&argv[1][5], "iax5"))
253 modelnum = 10;
254 else if(!strcmp(&argv[1][5], "mn2g"))
255 modelnum = 11;
256 else if(!strcmp(&argv[1][5], "h10"))
257 modelnum = 13;
258 else if(!strcmp(&argv[1][5], "h10_5gb"))
259 modelnum = 14;
260 else if(!strcmp(&argv[1][5], "tpj2"))
261 modelnum = 15;
262 else if(!strcmp(&argv[1][5], "e200"))
263 modelnum = 16;
264 else if(!strcmp(&argv[1][5], "iam5"))
265 modelnum = 17;
266 else if(!strcmp(&argv[1][5], "giga"))
267 modelnum = 18;
268 else if(!strcmp(&argv[1][5], "1g2g"))
269 modelnum = 19;
270 else if(!strcmp(&argv[1][5], "c200"))
271 modelnum = 20;
272 else if(!strcmp(&argv[1][5], "gigs"))
273 modelnum = 21;
274 else if(!strcmp(&argv[1][5], "m500"))
275 modelnum = 22;
276 else if(!strcmp(&argv[1][5], "m100"))
277 modelnum = 23;
278 else if(!strcmp(&argv[1][5], "d2"))
279 modelnum = 24;
280 else if(!strcmp(&argv[1][5], "iam3"))
281 modelnum = 25;
282 else if (!strcmp(&argv[1][5], "m200"))
283 modelnum = 29;
284 else if(!strcmp(&argv[1][5], "c100"))
285 modelnum = 30;
286 else if(!strcmp(&argv[1][5], "1630")) /* Philips HDD1630 */
287 modelnum = 31;
288 else if (!strcmp(&argv[1][5], "i7"))
289 modelnum = 32;
290 else if (!strcmp(&argv[1][5], "ldax"))
291 modelnum = 33;
292 else if(!strcmp(&argv[1][5], "9200")) /* Philips SA9200 */
293 modelnum = 34;
294 else if (!strcmp(&argv[1][5], "clip"))
295 modelnum = 40;
296 else if (!strcmp(&argv[1][5], "e2v2"))
297 modelnum = 41;
298 else if (!strcmp(&argv[1][5], "m2v4"))
299 modelnum = 42;
300 else if (!strcmp(&argv[1][5], "fuze"))
301 modelnum = 43;
302 else if (!strcmp(&argv[1][5], "c2v2"))
303 modelnum = 44;
304 else if (!strcmp(&argv[1][5], "x747"))
305 modelnum = 45;
306 else if (!strcmp(&argv[1][5], "747p"))
307 modelnum = 54;
308 else if (!strcmp(&argv[1][5], "y820")) /* Samsung YH-820 */
309 modelnum = 57;
310 else if (!strcmp(&argv[1][5], "y920")) /* Samsung YH-920 */
311 modelnum = 58;
312 else if (!strcmp(&argv[1][5], "y925")) /* Samsung YH-925 */
313 modelnum = 59;
314 else if (!strcmp(&argv[1][5], "clv2")) /* Sansa Clipv2 */
315 modelnum = 60;
316 else if (!strcmp(&argv[1][5], "x777"))
317 modelnum = 61;
318 else if (!strcmp(&argv[1][5], "nn2g")) /* iPod Nano 2nd Gen */
319 modelnum = 62;
320 else if (!strcmp(&argv[1][5], "x767"))
321 modelnum = 64;
322 else if (!strcmp(&argv[1][5], "6330")) /* Philips HDD6330 */
323 modelnum = 65;
324 else if (!strcmp(&argv[1][5], "cli+")) /* Sansa Clip+ */
325 modelnum = 66;
326 else if (!strcmp(&argv[1][5], "v500")) /* Packard Bell Vibe 500 */
327 modelnum = 67;
328 else if (!strcmp(&argv[1][5], "fuz2")) /* Sansa Fuze v2 */
329 modelnum = 68;
330 else if (!strcmp(&argv[1][5], "m244"))
331 modelnum = 131;
332 else if (!strcmp(&argv[1][5], "hd20")) /* MPIO HD200 */
333 modelnum = 69;
334 else if (!strcmp(&argv[1][5], "hd30")) /* MPIO HD300 */
335 modelnum = 70;
336 else if (!strcmp(&argv[1][5], "ip6g")) /* iPod Classic/6G */
337 modelnum = 71;
338 else if (!strcmp(&argv[1][5], "fuz+")) /* Sansa Fuze+ */
339 modelnum = 72;
340 else {
341 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
342 return 2;
344 /* we store a 4-letter model name too, for humans */
345 strncpy(modelname, &argv[1][5],4);
346 modelname[4] = '\0'; /* to be sure we are null terminated */
347 chksum = modelnum; /* start checksum calcs with this */
350 else if(!strcmp(argv[1], "-iriver")) {
351 /* iRiver code dealt with in the iriver.c code */
352 iname = argv[2];
353 oname = argv[3];
354 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
356 else if(!strcmp(argv[1], "-gigabeat")) {
357 /* iRiver code dealt with in the iriver.c code */
358 iname = argv[2];
359 oname = argv[3];
360 gigabeat_code(iname, oname);
361 return 0;
363 else if(!strcmp(argv[1], "-gigabeats")) {
364 iname = argv[2];
365 oname = argv[3];
366 return gigabeat_s_code(iname, oname);
368 else if(!strcmp(argv[1], "-iaudiox5")) {
369 iname = argv[2];
370 oname = argv[3];
371 return iaudio_encode(iname, oname, "COWON_X5_FW");
373 else if(!strcmp(argv[1], "-iaudiox5v")) {
374 iname = argv[2];
375 oname = argv[3];
376 return iaudio_encode(iname, oname, "COWON_X5V_FW");
378 else if(!strcmp(argv[1], "-iaudiom5")) {
379 iname = argv[2];
380 oname = argv[3];
381 return iaudio_encode(iname, oname, "COWON_M5_FW");
383 else if(!strcmp(argv[1], "-iaudiom3")) {
384 iname = argv[2];
385 oname = argv[3];
386 return iaudio_encode(iname, oname, "COWON_M3_FW");
388 else if(!strcmp(argv[1], "-ipod3g")) {
389 iname = argv[2];
390 oname = argv[3];
391 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
393 else if(!strcmp(argv[1], "-ipod4g")) {
394 iname = argv[2];
395 oname = argv[3];
396 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
398 else if(!strcmp(argv[1], "-ipod5g")) {
399 iname = argv[2];
400 oname = argv[3];
401 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
403 else if(!strncmp(argv[1], "-creative=", 10)) {
404 if(!strcmp(argv[2], "-no-ciff"))
406 creative_enable_ciff = false;
407 iname = argv[3];
408 oname = argv[4];
410 else
412 creative_enable_ciff = true;
413 iname = argv[2];
414 oname = argv[3];
416 if(!strcmp(&argv[1][10], "zvm"))
417 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
418 else if(!strcmp(&argv[1][10], "zvm60"))
419 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
420 else if(!strcmp(&argv[1][10], "zenvision"))
421 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
422 else if(!strcmp(&argv[1][10], "zenv"))
423 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
424 else if(!strcmp(&argv[1][10], "zen"))
425 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
426 else
428 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
429 return 2;
432 else if(!strcmp(argv[1], "-ccpmp")) {
433 iname = argv[2];
434 oname = argv[3];
435 return ccpmp_encode(iname, oname);
437 else if(!strncmp(argv[1], "-mi4", 4)) {
438 int mi4magic;
439 char model[4] = "";
440 char type[4] = "";
442 if(!strcmp(&argv[1][4], "v2")) {
443 mi4magic = MI4_MAGIC_DEFAULT;
444 version = 0x00010201;
446 else if(!strcmp(&argv[1][4], "v3")) {
447 mi4magic = MI4_MAGIC_DEFAULT;
448 version = 0x00010301;
450 else if(!strcmp(&argv[1][4], "r")) {
451 mi4magic = MI4_MAGIC_R;
452 version = 0x00010301;
454 else {
455 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
456 return -1;
459 iname = argv[2];
460 oname = argv[3];
462 if(!strncmp(argv[2], "-model=", 7)) {
463 iname = argv[3];
464 oname = argv[4];
465 strncpy(model, &argv[2][7], 4);
467 if(!strncmp(argv[3], "-type=", 6)) {
468 iname = argv[4];
469 oname = argv[5];
470 strncpy(type, &argv[3][6], 4);
474 return mi4_encode(iname, oname, version, mi4magic, model, type);
477 /* open file */
478 file = fopen(iname,"rb");
479 if (!file) {
480 perror(iname);
481 return -1;
483 fseek(file,0,SEEK_END);
484 length = ftell(file);
485 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
487 if ((method == scramble) &&
488 ((length + headerlen) >= size_limit[model_id])) {
489 printf("error: firmware image is %ld bytes while max size is %u!\n",
490 length + headerlen,
491 size_limit[model_id]);
492 fclose(file);
493 return -1;
496 fseek(file,0,SEEK_SET);
497 inbuf = malloc(length);
498 if (method == xor)
499 outbuf = malloc(length*2);
500 else if(method == add)
501 outbuf = malloc(length + 8);
502 else
503 outbuf = malloc(length);
504 if ( !inbuf || !outbuf ) {
505 printf("out of memory!\n");
506 return -1;
508 if(length> 4) {
509 /* zero-fill the last 4 bytes to make sure there's no rubbish there
510 when we write the size-aligned file later */
511 memset(outbuf+length-4, 0, 4);
514 /* read file */
515 i=fread(inbuf,1,length,file);
516 if ( !i ) {
517 perror(iname);
518 return -1;
520 fclose(file);
522 switch (method)
524 case add:
525 for (i = 0; i < length; i++) {
526 /* add 8 unsigned bits but keep a 32 bit sum */
527 chksum += inbuf[i];
529 break;
530 case scramble:
531 slen = length/4;
532 for (i = 0; i < length; i++) {
533 unsigned long addr = (i >> 2) + ((i % 4) * slen);
534 unsigned char data = inbuf[i];
535 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
536 outbuf[addr] = data;
538 break;
540 case xor:
541 /* "compress" */
542 slen = 0;
543 for (i=0; i<length; i++) {
544 if (!(i&7))
545 outbuf[slen++] = 0xff; /* all data is uncompressed */
546 outbuf[slen++] = inbuf[i];
548 break;
549 case none:
550 default:
551 /* dummy case just to silence picky compilers */
552 break;
555 if((method == none) || (method == scramble) || (method == xor)) {
556 /* calculate checksum */
557 for (i=0;i<length;i++)
558 crc += inbuf[i];
561 memset(header, 0, sizeof header);
562 switch (method)
564 case add:
566 int2be(chksum, header); /* checksum, big-endian */
567 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
568 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
569 headerlen = 8;
571 break;
573 case tcc_sum:
574 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
575 telechips_encode_sum(outbuf, length);
576 break;
578 case tcc_crc:
579 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
580 telechips_encode_crc(outbuf, length);
581 break;
583 case scramble:
584 if (headerlen == 6) {
585 int2be(length, header);
586 header[4] = (crc >> 8) & 0xff;
587 header[5] = crc & 0xff;
589 else {
590 header[0] =
591 header[1] =
592 header[2] =
593 header[3] = 0xff; /* ??? */
595 header[6] = (crc >> 8) & 0xff;
596 header[7] = crc & 0xff;
598 header[11] = version;
600 header[15] = headerlen; /* really? */
602 int2be(length, &header[20]);
604 break;
606 case xor:
608 int xorlen = strlen(xorstring);
610 /* xor data */
611 for (i=0; i<slen; i++)
612 outbuf[i] ^= xorstring[i & (xorlen-1)];
614 /* calculate checksum */
615 for (i=0; i<slen; i++)
616 crc += outbuf[i];
618 header[0] = header[2] = 'Z';
619 header[1] = header[3] = version;
620 int2le(length, &header[4]);
621 int2le(slen, &header[8]);
622 int2le(crc, &header[12]);
623 length = slen;
624 break;
627 #define MY_FIRMWARE_TYPE "Rockbox"
628 #define MY_HEADER_VERSION 1
629 default:
630 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
631 header[9]='\0'; /*shouldn't have to, but to be SURE */
632 header[10]=MY_HEADER_VERSION&0xFF;
633 header[11]=(crc>>8)&0xFF;
634 header[12]=crc&0xFF;
635 int2be(sizeof(header), &header[12]);
636 break;
639 /* write file */
640 file = fopen(oname,"wb");
641 if ( !file ) {
642 perror(oname);
643 return -1;
645 if (headerlen > 0) {
646 if ( !fwrite(header,headerlen,1,file) ) {
647 perror(oname);
648 return -1;
651 if ( !fwrite(outbuf,length,1,file) ) {
652 perror(oname);
653 return -1;
655 fclose(file);
657 free(inbuf);
658 free(outbuf);
660 return 0;
663 static int iaudio_encode(char *iname, char *oname, char *idstring)
665 size_t len;
666 int length;
667 FILE *file;
668 unsigned char *outbuf;
669 int i;
670 unsigned char sum = 0;
672 file = fopen(iname, "rb");
673 if (!file) {
674 perror(iname);
675 return -1;
677 fseek(file,0,SEEK_END);
678 length = ftell(file);
680 fseek(file,0,SEEK_SET);
681 outbuf = malloc(length+0x1030);
683 if ( !outbuf ) {
684 printf("out of memory!\n");
685 return -1;
688 len = fread(outbuf+0x1030, 1, length, file);
689 if(len < (size_t) length) {
690 perror(iname);
691 return -2;
694 memset(outbuf, 0, 0x1030);
695 strcpy((char *)outbuf, idstring);
696 memcpy(outbuf+0x20, iaudio_bl_flash,
697 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
698 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
699 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
700 outbuf[0x19] = 2;
702 for(i = 0; i < length;i++)
703 sum += outbuf[0x1030 + i];
705 int2be(length, &outbuf[0x1024]);
706 outbuf[0x102b] = sum;
708 fclose(file);
710 file = fopen(oname, "wb");
711 if (!file) {
712 perror(oname);
713 return -3;
716 len = fwrite(outbuf, 1, length+0x1030, file);
717 if(len < (size_t)length) {
718 perror(oname);
719 return -4;
722 fclose(file);
723 return 0;
727 /* Create an ipod firmware partition image
729 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
731 This function doesn't yet handle the Broadcom resource image for the 5g,
732 so the resulting images won't be usable.
734 This has also only been tested on an ipod Photo
737 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
739 static const char *apple_stop_sign = "{{~~ /-----\\ "\
740 "{{~~ / \\ "\
741 "{{~~| | "\
742 "{{~~| S T O P | "\
743 "{{~~| | "\
744 "{{~~ \\ / "\
745 "{{~~ \\-----/ "\
746 "Copyright(C) 200"\
747 "1 Apple Computer"\
748 ", Inc.----------"\
749 "----------------"\
750 "----------------"\
751 "----------------"\
752 "----------------"\
753 "----------------"\
754 "---------------";
755 size_t len;
756 int length;
757 int rsrclength;
758 int rsrcoffset;
759 FILE *file;
760 unsigned int sum = 0;
761 unsigned int rsrcsum = 0;
762 unsigned char *outbuf;
763 int bufsize;
764 int i;
766 file = fopen(iname, "rb");
767 if (!file) {
768 perror(iname);
769 return -1;
771 fseek(file,0,SEEK_END);
772 length = ftell(file);
774 fseek(file,0,SEEK_SET);
776 bufsize=(length+0x4600);
777 if (fake_rsrc) {
778 bufsize = (bufsize + 0x400) & ~0x200;
781 outbuf = malloc(bufsize);
783 if ( !outbuf ) {
784 printf("out of memory!\n");
785 return -1;
788 len = fread(outbuf+0x4600, 1, length, file);
789 if(len < (size_t)length) {
790 perror(iname);
791 return -2;
793 fclose(file);
795 /* Calculate checksum for later use in header */
796 for(i = 0x4600; i < 0x4600+length;i++)
797 sum += outbuf[i];
799 /* Clear the header area to zero */
800 memset(outbuf, 0, 0x4600);
802 /* APPLE STOP SIGN */
803 strcpy((char *)outbuf, apple_stop_sign);
805 /* VOLUME HEADER */
806 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
807 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
808 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
809 short2le(fw_ver, &outbuf[0x10a]);
811 /* Firmware Directory - "osos" entry */
812 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
813 int2le(0, &outbuf[0x4208]); /* id */
814 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
815 int2le(length, &outbuf[0x4210]); /* Length of firmware */
816 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
817 int2le(0, &outbuf[0x4218]); /* Entry Offset */
818 int2le(sum, &outbuf[0x421c]); /* Checksum */
819 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
820 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
822 /* "rsrc" entry (if applicable) */
823 if (fake_rsrc) {
824 rsrcoffset=(length+0x4600+0x200) & ~0x200;
825 rsrclength=0x200;
826 rsrcsum=0;
828 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
829 int2le(0, &outbuf[0x4230]); /* id */
830 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
831 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
832 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
833 int2le(0, &outbuf[0x4240]); /* Entry Offset */
834 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
835 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
836 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
839 file = fopen(oname, "wb");
840 if (!file) {
841 perror(oname);
842 return -3;
845 len = fwrite(outbuf, 1, length+0x4600, file);
846 if(len < (size_t)length) {
847 perror(oname);
848 return -4;
851 fclose(file);
853 return 0;
856 #define CCPMP_SIZE 0x500000
857 static int ccpmp_encode(char *iname, char *oname)
859 size_t len;
860 int length;
861 FILE *file;
862 unsigned char *outbuf;
864 file = fopen(iname, "rb");
865 if (!file) {
866 perror(iname);
867 return -1;
869 fseek(file,0,SEEK_END);
870 length = ftell(file);
872 fseek(file,0,SEEK_SET);
874 outbuf = malloc(CCPMP_SIZE);
876 if ( !outbuf ) {
877 printf("out of memory!\n");
878 return -1;
881 len = fread(outbuf, 1, length, file);
882 if(len < (size_t)length) {
883 perror(iname);
884 return -2;
886 fclose(file);
888 /* Clear the tail area to 0xFF */
889 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
891 /* Header */
892 int2le(length, &outbuf[0x4]);
894 file = fopen(oname, "wb");
895 if (!file) {
896 perror(oname);
897 return -3;
900 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
901 if(len < (size_t)length) {
902 perror(oname);
903 return -4;
906 fclose(file);
908 return 0;