Merge everything up to v3.10 branch point
[maemo-rb.git] / tools / scramble.c
blob126fa7baa72109391dbbebd125b42e6c30f78abe
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 {
345 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
346 return 2;
348 /* we store a 4-letter model name too, for humans */
349 strncpy(modelname, &argv[1][5],4);
350 modelname[4] = '\0'; /* to be sure we are null terminated */
351 chksum = modelnum; /* start checksum calcs with this */
354 else if(!strcmp(argv[1], "-iriver")) {
355 /* iRiver code dealt with in the iriver.c code */
356 iname = argv[2];
357 oname = argv[3];
358 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
360 else if(!strcmp(argv[1], "-gigabeat")) {
361 /* iRiver code dealt with in the iriver.c code */
362 iname = argv[2];
363 oname = argv[3];
364 gigabeat_code(iname, oname);
365 return 0;
367 else if(!strcmp(argv[1], "-gigabeats")) {
368 iname = argv[2];
369 oname = argv[3];
370 return gigabeat_s_code(iname, oname);
372 else if(!strcmp(argv[1], "-iaudiox5")) {
373 iname = argv[2];
374 oname = argv[3];
375 return iaudio_encode(iname, oname, "COWON_X5_FW");
377 else if(!strcmp(argv[1], "-iaudiox5v")) {
378 iname = argv[2];
379 oname = argv[3];
380 return iaudio_encode(iname, oname, "COWON_X5V_FW");
382 else if(!strcmp(argv[1], "-iaudiom5")) {
383 iname = argv[2];
384 oname = argv[3];
385 return iaudio_encode(iname, oname, "COWON_M5_FW");
387 else if(!strcmp(argv[1], "-iaudiom3")) {
388 iname = argv[2];
389 oname = argv[3];
390 return iaudio_encode(iname, oname, "COWON_M3_FW");
392 else if(!strcmp(argv[1], "-ipod3g")) {
393 iname = argv[2];
394 oname = argv[3];
395 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
397 else if(!strcmp(argv[1], "-ipod4g")) {
398 iname = argv[2];
399 oname = argv[3];
400 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
402 else if(!strcmp(argv[1], "-ipod5g")) {
403 iname = argv[2];
404 oname = argv[3];
405 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
407 else if(!strncmp(argv[1], "-creative=", 10)) {
408 if(!strcmp(argv[2], "-no-ciff"))
410 creative_enable_ciff = false;
411 iname = argv[3];
412 oname = argv[4];
414 else
416 creative_enable_ciff = true;
417 iname = argv[2];
418 oname = argv[3];
420 if(!strcmp(&argv[1][10], "zvm"))
421 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
422 else if(!strcmp(&argv[1][10], "zvm60"))
423 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
424 else if(!strcmp(&argv[1][10], "zenvision"))
425 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
426 else if(!strcmp(&argv[1][10], "zenv"))
427 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
428 else if(!strcmp(&argv[1][10], "zen"))
429 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
430 else
432 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
433 return 2;
436 else if(!strcmp(argv[1], "-ccpmp")) {
437 iname = argv[2];
438 oname = argv[3];
439 return ccpmp_encode(iname, oname);
441 else if(!strncmp(argv[1], "-mi4", 4)) {
442 int mi4magic;
443 char model[4] = "";
444 char type[4] = "";
446 if(!strcmp(&argv[1][4], "v2")) {
447 mi4magic = MI4_MAGIC_DEFAULT;
448 version = 0x00010201;
450 else if(!strcmp(&argv[1][4], "v3")) {
451 mi4magic = MI4_MAGIC_DEFAULT;
452 version = 0x00010301;
454 else if(!strcmp(&argv[1][4], "r")) {
455 mi4magic = MI4_MAGIC_R;
456 version = 0x00010301;
458 else {
459 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
460 return -1;
463 iname = argv[2];
464 oname = argv[3];
466 if(!strncmp(argv[2], "-model=", 7)) {
467 iname = argv[3];
468 oname = argv[4];
469 strncpy(model, &argv[2][7], 4);
471 if(!strncmp(argv[3], "-type=", 6)) {
472 iname = argv[4];
473 oname = argv[5];
474 strncpy(type, &argv[3][6], 4);
478 return mi4_encode(iname, oname, version, mi4magic, model, type);
481 /* open file */
482 file = fopen(iname,"rb");
483 if (!file) {
484 perror(iname);
485 return -1;
487 fseek(file,0,SEEK_END);
488 length = ftell(file);
489 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
491 if ((method == scramble) &&
492 ((length + headerlen) >= size_limit[model_id])) {
493 printf("error: firmware image is %ld bytes while max size is %u!\n",
494 length + headerlen,
495 size_limit[model_id]);
496 fclose(file);
497 return -1;
500 fseek(file,0,SEEK_SET);
501 inbuf = malloc(length);
502 if (method == xor)
503 outbuf = malloc(length*2);
504 else if(method == add)
505 outbuf = malloc(length + 8);
506 else
507 outbuf = malloc(length);
508 if ( !inbuf || !outbuf ) {
509 printf("out of memory!\n");
510 return -1;
512 if(length> 4) {
513 /* zero-fill the last 4 bytes to make sure there's no rubbish there
514 when we write the size-aligned file later */
515 memset(outbuf+length-4, 0, 4);
518 /* read file */
519 i=fread(inbuf,1,length,file);
520 if ( !i ) {
521 perror(iname);
522 return -1;
524 fclose(file);
526 switch (method)
528 case add:
529 for (i = 0; i < length; i++) {
530 /* add 8 unsigned bits but keep a 32 bit sum */
531 chksum += inbuf[i];
533 break;
534 case scramble:
535 slen = length/4;
536 for (i = 0; i < length; i++) {
537 unsigned long addr = (i >> 2) + ((i % 4) * slen);
538 unsigned char data = inbuf[i];
539 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
540 outbuf[addr] = data;
542 break;
544 case xor:
545 /* "compress" */
546 slen = 0;
547 for (i=0; i<length; i++) {
548 if (!(i&7))
549 outbuf[slen++] = 0xff; /* all data is uncompressed */
550 outbuf[slen++] = inbuf[i];
552 break;
553 case none:
554 default:
555 /* dummy case just to silence picky compilers */
556 break;
559 if((method == none) || (method == scramble) || (method == xor)) {
560 /* calculate checksum */
561 for (i=0;i<length;i++)
562 crc += inbuf[i];
565 memset(header, 0, sizeof header);
566 switch (method)
568 case add:
570 int2be(chksum, header); /* checksum, big-endian */
571 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
572 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
573 headerlen = 8;
575 break;
577 case tcc_sum:
578 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
579 telechips_encode_sum(outbuf, length);
580 break;
582 case tcc_crc:
583 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
584 telechips_encode_crc(outbuf, length);
585 break;
587 case scramble:
588 if (headerlen == 6) {
589 int2be(length, header);
590 header[4] = (crc >> 8) & 0xff;
591 header[5] = crc & 0xff;
593 else {
594 header[0] =
595 header[1] =
596 header[2] =
597 header[3] = 0xff; /* ??? */
599 header[6] = (crc >> 8) & 0xff;
600 header[7] = crc & 0xff;
602 header[11] = version;
604 header[15] = headerlen; /* really? */
606 int2be(length, &header[20]);
608 break;
610 case xor:
612 int xorlen = strlen(xorstring);
614 /* xor data */
615 for (i=0; i<slen; i++)
616 outbuf[i] ^= xorstring[i & (xorlen-1)];
618 /* calculate checksum */
619 for (i=0; i<slen; i++)
620 crc += outbuf[i];
622 header[0] = header[2] = 'Z';
623 header[1] = header[3] = version;
624 int2le(length, &header[4]);
625 int2le(slen, &header[8]);
626 int2le(crc, &header[12]);
627 length = slen;
628 break;
631 #define MY_FIRMWARE_TYPE "Rockbox"
632 #define MY_HEADER_VERSION 1
633 default:
634 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
635 header[9]='\0'; /*shouldn't have to, but to be SURE */
636 header[10]=MY_HEADER_VERSION&0xFF;
637 header[11]=(crc>>8)&0xFF;
638 header[12]=crc&0xFF;
639 int2be(sizeof(header), &header[12]);
640 break;
643 /* write file */
644 file = fopen(oname,"wb");
645 if ( !file ) {
646 perror(oname);
647 return -1;
649 if (headerlen > 0) {
650 if ( !fwrite(header,headerlen,1,file) ) {
651 perror(oname);
652 return -1;
655 if ( !fwrite(outbuf,length,1,file) ) {
656 perror(oname);
657 return -1;
659 fclose(file);
661 free(inbuf);
662 free(outbuf);
664 return 0;
667 static int iaudio_encode(char *iname, char *oname, char *idstring)
669 size_t len;
670 int length;
671 FILE *file;
672 unsigned char *outbuf;
673 int i;
674 unsigned char sum = 0;
676 file = fopen(iname, "rb");
677 if (!file) {
678 perror(iname);
679 return -1;
681 fseek(file,0,SEEK_END);
682 length = ftell(file);
684 fseek(file,0,SEEK_SET);
685 outbuf = malloc(length+0x1030);
687 if ( !outbuf ) {
688 printf("out of memory!\n");
689 return -1;
692 len = fread(outbuf+0x1030, 1, length, file);
693 if(len < (size_t) length) {
694 perror(iname);
695 return -2;
698 memset(outbuf, 0, 0x1030);
699 strcpy((char *)outbuf, idstring);
700 memcpy(outbuf+0x20, iaudio_bl_flash,
701 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
702 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
703 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
704 outbuf[0x19] = 2;
706 for(i = 0; i < length;i++)
707 sum += outbuf[0x1030 + i];
709 int2be(length, &outbuf[0x1024]);
710 outbuf[0x102b] = sum;
712 fclose(file);
714 file = fopen(oname, "wb");
715 if (!file) {
716 perror(oname);
717 return -3;
720 len = fwrite(outbuf, 1, length+0x1030, file);
721 if(len < (size_t)length) {
722 perror(oname);
723 return -4;
726 fclose(file);
727 return 0;
731 /* Create an ipod firmware partition image
733 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
735 This function doesn't yet handle the Broadcom resource image for the 5g,
736 so the resulting images won't be usable.
738 This has also only been tested on an ipod Photo
741 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
743 static const char *apple_stop_sign = "{{~~ /-----\\ "\
744 "{{~~ / \\ "\
745 "{{~~| | "\
746 "{{~~| S T O P | "\
747 "{{~~| | "\
748 "{{~~ \\ / "\
749 "{{~~ \\-----/ "\
750 "Copyright(C) 200"\
751 "1 Apple Computer"\
752 ", Inc.----------"\
753 "----------------"\
754 "----------------"\
755 "----------------"\
756 "----------------"\
757 "----------------"\
758 "---------------";
759 size_t len;
760 int length;
761 int rsrclength;
762 int rsrcoffset;
763 FILE *file;
764 unsigned int sum = 0;
765 unsigned int rsrcsum = 0;
766 unsigned char *outbuf;
767 int bufsize;
768 int i;
770 file = fopen(iname, "rb");
771 if (!file) {
772 perror(iname);
773 return -1;
775 fseek(file,0,SEEK_END);
776 length = ftell(file);
778 fseek(file,0,SEEK_SET);
780 bufsize=(length+0x4600);
781 if (fake_rsrc) {
782 bufsize = (bufsize + 0x400) & ~0x200;
785 outbuf = malloc(bufsize);
787 if ( !outbuf ) {
788 printf("out of memory!\n");
789 return -1;
792 len = fread(outbuf+0x4600, 1, length, file);
793 if(len < (size_t)length) {
794 perror(iname);
795 return -2;
797 fclose(file);
799 /* Calculate checksum for later use in header */
800 for(i = 0x4600; i < 0x4600+length;i++)
801 sum += outbuf[i];
803 /* Clear the header area to zero */
804 memset(outbuf, 0, 0x4600);
806 /* APPLE STOP SIGN */
807 strcpy((char *)outbuf, apple_stop_sign);
809 /* VOLUME HEADER */
810 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
811 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
812 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
813 short2le(fw_ver, &outbuf[0x10a]);
815 /* Firmware Directory - "osos" entry */
816 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
817 int2le(0, &outbuf[0x4208]); /* id */
818 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
819 int2le(length, &outbuf[0x4210]); /* Length of firmware */
820 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
821 int2le(0, &outbuf[0x4218]); /* Entry Offset */
822 int2le(sum, &outbuf[0x421c]); /* Checksum */
823 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
824 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
826 /* "rsrc" entry (if applicable) */
827 if (fake_rsrc) {
828 rsrcoffset=(length+0x4600+0x200) & ~0x200;
829 rsrclength=0x200;
830 rsrcsum=0;
832 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
833 int2le(0, &outbuf[0x4230]); /* id */
834 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
835 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
836 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
837 int2le(0, &outbuf[0x4240]); /* Entry Offset */
838 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
839 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
840 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
843 file = fopen(oname, "wb");
844 if (!file) {
845 perror(oname);
846 return -3;
849 len = fwrite(outbuf, 1, length+0x4600, file);
850 if(len < (size_t)length) {
851 perror(oname);
852 return -4;
855 fclose(file);
857 return 0;
860 #define CCPMP_SIZE 0x500000
861 static int ccpmp_encode(char *iname, char *oname)
863 size_t len;
864 int length;
865 FILE *file;
866 unsigned char *outbuf;
868 file = fopen(iname, "rb");
869 if (!file) {
870 perror(iname);
871 return -1;
873 fseek(file,0,SEEK_END);
874 length = ftell(file);
876 fseek(file,0,SEEK_SET);
878 outbuf = malloc(CCPMP_SIZE);
880 if ( !outbuf ) {
881 printf("out of memory!\n");
882 return -1;
885 len = fread(outbuf, 1, length, file);
886 if(len < (size_t)length) {
887 perror(iname);
888 return -2;
890 fclose(file);
892 /* Clear the tail area to 0xFF */
893 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
895 /* Header */
896 int2le(length, &outbuf[0x4]);
898 file = fopen(oname, "wb");
899 if (!file) {
900 perror(oname);
901 return -3;
904 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
905 if(len < (size_t)length) {
906 perror(oname);
907 return -4;
910 fclose(file);
912 return 0;