Prepare new, unofficial pandora build
[maemo-rb.git] / tools / scramble.c
blob7c7a847ea1bd0d822cbdb4f9fe9034a797c43a33
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, rk27, clzp)\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 if (!strcmp(&argv[1][5], "rk27")) /* rockchip 27xx generic */
341 modelnum = 73;
342 else if (!strcmp(&argv[1][5], "clzp")) /* Sansa Clip Zip */
343 modelnum = 79;
344 else if (!strcmp(&argv[1][5], "conn")) /* Sansa Connect */
345 modelnum = 81;
346 else {
347 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
348 return 2;
350 /* we store a 4-letter model name too, for humans */
351 strncpy(modelname, &argv[1][5],4);
352 modelname[4] = '\0'; /* to be sure we are null terminated */
353 chksum = modelnum; /* start checksum calcs with this */
356 else if(!strcmp(argv[1], "-iriver")) {
357 /* iRiver code dealt with in the iriver.c code */
358 iname = argv[2];
359 oname = argv[3];
360 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
362 else if(!strcmp(argv[1], "-gigabeat")) {
363 /* iRiver code dealt with in the iriver.c code */
364 iname = argv[2];
365 oname = argv[3];
366 gigabeat_code(iname, oname);
367 return 0;
369 else if(!strcmp(argv[1], "-gigabeats")) {
370 iname = argv[2];
371 oname = argv[3];
372 return gigabeat_s_code(iname, oname);
374 else if(!strcmp(argv[1], "-iaudiox5")) {
375 iname = argv[2];
376 oname = argv[3];
377 return iaudio_encode(iname, oname, "COWON_X5_FW");
379 else if(!strcmp(argv[1], "-iaudiox5v")) {
380 iname = argv[2];
381 oname = argv[3];
382 return iaudio_encode(iname, oname, "COWON_X5V_FW");
384 else if(!strcmp(argv[1], "-iaudiom5")) {
385 iname = argv[2];
386 oname = argv[3];
387 return iaudio_encode(iname, oname, "COWON_M5_FW");
389 else if(!strcmp(argv[1], "-iaudiom3")) {
390 iname = argv[2];
391 oname = argv[3];
392 return iaudio_encode(iname, oname, "COWON_M3_FW");
394 else if(!strcmp(argv[1], "-ipod3g")) {
395 iname = argv[2];
396 oname = argv[3];
397 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
399 else if(!strcmp(argv[1], "-ipod4g")) {
400 iname = argv[2];
401 oname = argv[3];
402 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
404 else if(!strcmp(argv[1], "-ipod5g")) {
405 iname = argv[2];
406 oname = argv[3];
407 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
409 else if(!strncmp(argv[1], "-creative=", 10)) {
410 if(!strcmp(argv[2], "-no-ciff"))
412 creative_enable_ciff = false;
413 iname = argv[3];
414 oname = argv[4];
416 else
418 creative_enable_ciff = true;
419 iname = argv[2];
420 oname = argv[3];
422 if(!strcmp(&argv[1][10], "zvm"))
423 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
424 else if(!strcmp(&argv[1][10], "zvm60"))
425 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
426 else if(!strcmp(&argv[1][10], "zenvision"))
427 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
428 else if(!strcmp(&argv[1][10], "zenv"))
429 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
430 else if(!strcmp(&argv[1][10], "zen"))
431 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
432 else
434 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
435 return 2;
438 else if(!strcmp(argv[1], "-ccpmp")) {
439 iname = argv[2];
440 oname = argv[3];
441 return ccpmp_encode(iname, oname);
443 else if(!strncmp(argv[1], "-mi4", 4)) {
444 int mi4magic;
445 char model[4] = "";
446 char type[4] = "";
448 if(!strcmp(&argv[1][4], "v2")) {
449 mi4magic = MI4_MAGIC_DEFAULT;
450 version = 0x00010201;
452 else if(!strcmp(&argv[1][4], "v3")) {
453 mi4magic = MI4_MAGIC_DEFAULT;
454 version = 0x00010301;
456 else if(!strcmp(&argv[1][4], "r")) {
457 mi4magic = MI4_MAGIC_R;
458 version = 0x00010301;
460 else {
461 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
462 return -1;
465 iname = argv[2];
466 oname = argv[3];
468 if(!strncmp(argv[2], "-model=", 7)) {
469 iname = argv[3];
470 oname = argv[4];
471 strncpy(model, &argv[2][7], 4);
473 if(!strncmp(argv[3], "-type=", 6)) {
474 iname = argv[4];
475 oname = argv[5];
476 strncpy(type, &argv[3][6], 4);
480 return mi4_encode(iname, oname, version, mi4magic, model, type);
483 /* open file */
484 file = fopen(iname,"rb");
485 if (!file) {
486 perror(iname);
487 return -1;
489 fseek(file,0,SEEK_END);
490 length = ftell(file);
491 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
493 if ((method == scramble) &&
494 ((length + headerlen) >= size_limit[model_id])) {
495 printf("error: firmware image is %ld bytes while max size is %u!\n",
496 length + headerlen,
497 size_limit[model_id]);
498 fclose(file);
499 return -1;
502 fseek(file,0,SEEK_SET);
503 inbuf = malloc(length);
504 if (method == xor)
505 outbuf = malloc(length*2);
506 else if(method == add)
507 outbuf = malloc(length + 8);
508 else
509 outbuf = malloc(length);
510 if ( !inbuf || !outbuf ) {
511 printf("out of memory!\n");
512 return -1;
514 if(length> 4) {
515 /* zero-fill the last 4 bytes to make sure there's no rubbish there
516 when we write the size-aligned file later */
517 memset(outbuf+length-4, 0, 4);
520 /* read file */
521 i=fread(inbuf,1,length,file);
522 if ( !i ) {
523 perror(iname);
524 return -1;
526 fclose(file);
528 switch (method)
530 case add:
531 for (i = 0; i < length; i++) {
532 /* add 8 unsigned bits but keep a 32 bit sum */
533 chksum += inbuf[i];
535 break;
536 case scramble:
537 slen = length/4;
538 for (i = 0; i < length; i++) {
539 unsigned long addr = (i >> 2) + ((i % 4) * slen);
540 unsigned char data = inbuf[i];
541 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
542 outbuf[addr] = data;
544 break;
546 case xor:
547 /* "compress" */
548 slen = 0;
549 for (i=0; i<length; i++) {
550 if (!(i&7))
551 outbuf[slen++] = 0xff; /* all data is uncompressed */
552 outbuf[slen++] = inbuf[i];
554 break;
555 case none:
556 default:
557 /* dummy case just to silence picky compilers */
558 break;
561 if((method == none) || (method == scramble) || (method == xor)) {
562 /* calculate checksum */
563 for (i=0;i<length;i++)
564 crc += inbuf[i];
567 memset(header, 0, sizeof header);
568 switch (method)
570 case add:
572 int2be(chksum, header); /* checksum, big-endian */
573 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
574 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
575 headerlen = 8;
577 break;
579 case tcc_sum:
580 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
581 telechips_encode_sum(outbuf, length);
582 break;
584 case tcc_crc:
585 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
586 telechips_encode_crc(outbuf, length);
587 break;
589 case scramble:
590 if (headerlen == 6) {
591 int2be(length, header);
592 header[4] = (crc >> 8) & 0xff;
593 header[5] = crc & 0xff;
595 else {
596 header[0] =
597 header[1] =
598 header[2] =
599 header[3] = 0xff; /* ??? */
601 header[6] = (crc >> 8) & 0xff;
602 header[7] = crc & 0xff;
604 header[11] = version;
606 header[15] = headerlen; /* really? */
608 int2be(length, &header[20]);
610 break;
612 case xor:
614 int xorlen = strlen(xorstring);
616 /* xor data */
617 for (i=0; i<slen; i++)
618 outbuf[i] ^= xorstring[i & (xorlen-1)];
620 /* calculate checksum */
621 for (i=0; i<slen; i++)
622 crc += outbuf[i];
624 header[0] = header[2] = 'Z';
625 header[1] = header[3] = version;
626 int2le(length, &header[4]);
627 int2le(slen, &header[8]);
628 int2le(crc, &header[12]);
629 length = slen;
630 break;
633 #define MY_FIRMWARE_TYPE "Rockbox"
634 #define MY_HEADER_VERSION 1
635 default:
636 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
637 header[9]='\0'; /*shouldn't have to, but to be SURE */
638 header[10]=MY_HEADER_VERSION&0xFF;
639 header[11]=(crc>>8)&0xFF;
640 header[12]=crc&0xFF;
641 int2be(sizeof(header), &header[12]);
642 break;
645 /* write file */
646 file = fopen(oname,"wb");
647 if ( !file ) {
648 perror(oname);
649 return -1;
651 if (headerlen > 0) {
652 if ( !fwrite(header,headerlen,1,file) ) {
653 perror(oname);
654 return -1;
657 if ( !fwrite(outbuf,length,1,file) ) {
658 perror(oname);
659 return -1;
661 fclose(file);
663 free(inbuf);
664 free(outbuf);
666 return 0;
669 static int iaudio_encode(char *iname, char *oname, char *idstring)
671 size_t len;
672 int length;
673 FILE *file;
674 unsigned char *outbuf;
675 int i;
676 unsigned char sum = 0;
678 file = fopen(iname, "rb");
679 if (!file) {
680 perror(iname);
681 return -1;
683 fseek(file,0,SEEK_END);
684 length = ftell(file);
686 fseek(file,0,SEEK_SET);
687 outbuf = malloc(length+0x1030);
689 if ( !outbuf ) {
690 printf("out of memory!\n");
691 return -1;
694 len = fread(outbuf+0x1030, 1, length, file);
695 if(len < (size_t) length) {
696 perror(iname);
697 return -2;
700 memset(outbuf, 0, 0x1030);
701 strcpy((char *)outbuf, idstring);
702 memcpy(outbuf+0x20, iaudio_bl_flash,
703 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
704 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
705 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
706 outbuf[0x19] = 2;
708 for(i = 0; i < length;i++)
709 sum += outbuf[0x1030 + i];
711 int2be(length, &outbuf[0x1024]);
712 outbuf[0x102b] = sum;
714 fclose(file);
716 file = fopen(oname, "wb");
717 if (!file) {
718 perror(oname);
719 return -3;
722 len = fwrite(outbuf, 1, length+0x1030, file);
723 if(len < (size_t)length) {
724 perror(oname);
725 return -4;
728 fclose(file);
729 return 0;
733 /* Create an ipod firmware partition image
735 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
737 This function doesn't yet handle the Broadcom resource image for the 5g,
738 so the resulting images won't be usable.
740 This has also only been tested on an ipod Photo
743 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
745 static const char *apple_stop_sign = "{{~~ /-----\\ "\
746 "{{~~ / \\ "\
747 "{{~~| | "\
748 "{{~~| S T O P | "\
749 "{{~~| | "\
750 "{{~~ \\ / "\
751 "{{~~ \\-----/ "\
752 "Copyright(C) 200"\
753 "1 Apple Computer"\
754 ", Inc.----------"\
755 "----------------"\
756 "----------------"\
757 "----------------"\
758 "----------------"\
759 "----------------"\
760 "---------------";
761 size_t len;
762 int length;
763 int rsrclength;
764 int rsrcoffset;
765 FILE *file;
766 unsigned int sum = 0;
767 unsigned int rsrcsum = 0;
768 unsigned char *outbuf;
769 int bufsize;
770 int i;
772 file = fopen(iname, "rb");
773 if (!file) {
774 perror(iname);
775 return -1;
777 fseek(file,0,SEEK_END);
778 length = ftell(file);
780 fseek(file,0,SEEK_SET);
782 bufsize=(length+0x4600);
783 if (fake_rsrc) {
784 bufsize = (bufsize + 0x400) & ~0x200;
787 outbuf = malloc(bufsize);
789 if ( !outbuf ) {
790 printf("out of memory!\n");
791 return -1;
794 len = fread(outbuf+0x4600, 1, length, file);
795 if(len < (size_t)length) {
796 perror(iname);
797 return -2;
799 fclose(file);
801 /* Calculate checksum for later use in header */
802 for(i = 0x4600; i < 0x4600+length;i++)
803 sum += outbuf[i];
805 /* Clear the header area to zero */
806 memset(outbuf, 0, 0x4600);
808 /* APPLE STOP SIGN */
809 strcpy((char *)outbuf, apple_stop_sign);
811 /* VOLUME HEADER */
812 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
813 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
814 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
815 short2le(fw_ver, &outbuf[0x10a]);
817 /* Firmware Directory - "osos" entry */
818 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
819 int2le(0, &outbuf[0x4208]); /* id */
820 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
821 int2le(length, &outbuf[0x4210]); /* Length of firmware */
822 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
823 int2le(0, &outbuf[0x4218]); /* Entry Offset */
824 int2le(sum, &outbuf[0x421c]); /* Checksum */
825 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
826 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
828 /* "rsrc" entry (if applicable) */
829 if (fake_rsrc) {
830 rsrcoffset=(length+0x4600+0x200) & ~0x200;
831 rsrclength=0x200;
832 rsrcsum=0;
834 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
835 int2le(0, &outbuf[0x4230]); /* id */
836 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
837 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
838 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
839 int2le(0, &outbuf[0x4240]); /* Entry Offset */
840 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
841 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
842 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
845 file = fopen(oname, "wb");
846 if (!file) {
847 perror(oname);
848 return -3;
851 len = fwrite(outbuf, 1, length+0x4600, file);
852 if(len < (size_t)length) {
853 perror(oname);
854 return -4;
857 fclose(file);
859 return 0;
862 #define CCPMP_SIZE 0x500000
863 static int ccpmp_encode(char *iname, char *oname)
865 size_t len;
866 int length;
867 FILE *file;
868 unsigned char *outbuf;
870 file = fopen(iname, "rb");
871 if (!file) {
872 perror(iname);
873 return -1;
875 fseek(file,0,SEEK_END);
876 length = ftell(file);
878 fseek(file,0,SEEK_SET);
880 outbuf = malloc(CCPMP_SIZE);
882 if ( !outbuf ) {
883 printf("out of memory!\n");
884 return -1;
887 len = fread(outbuf, 1, length, file);
888 if(len < (size_t)length) {
889 perror(iname);
890 return -2;
892 fclose(file);
894 /* Clear the tail area to 0xFF */
895 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
897 /* Header */
898 int2le(length, &outbuf[0x4]);
900 file = fopen(oname, "wb");
901 if (!file) {
902 perror(oname);
903 return -3;
906 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
907 if(len < (size_t)length) {
908 perror(oname);
909 return -4;
912 fclose(file);
914 return 0;