(Hopefully) fix overlay plugins.
[maemo-rb.git] / tools / scramble.c
blobc3b200c01e7ca69c438e3eab18c8e70d5db22cc5
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"
33 #include "rkw.h"
35 static int iaudio_encode(char *iname, char *oname, char *idstring);
36 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc);
37 static int ccpmp_encode(char *iname, char *oname);
39 enum
41 ARCHOS_PLAYER, /* and V1 recorder */
42 ARCHOS_V2RECORDER,
43 ARCHOS_FMRECORDER,
44 ARCHOS_ONDIO_SP,
45 ARCHOS_ONDIO_FM
48 static unsigned int size_limit[] =
50 0x32000, /* ARCHOS_PLAYER */
51 0x64000, /* ARCHOS_V2RECORDER */
52 0x64000, /* ARCHOS_FMRECORDER */
53 0x64000, /* ARCHOS_ONDIO_SP */
54 0x64000 /* ARCHOS_ONDIO_FM */
57 void short2le(unsigned short val, unsigned char* addr)
59 addr[0] = val & 0xFF;
60 addr[1] = (val >> 8) & 0xff;
63 unsigned int le2int(unsigned char* buf)
65 unsigned int res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
67 return res;
70 void int2le(unsigned int val, unsigned char* addr)
72 addr[0] = val & 0xFF;
73 addr[1] = (val >> 8) & 0xff;
74 addr[2] = (val >> 16) & 0xff;
75 addr[3] = (val >> 24) & 0xff;
78 void int2be(unsigned int val, unsigned char* addr)
80 addr[0] = (val >> 24) & 0xff;
81 addr[1] = (val >> 16) & 0xff;
82 addr[2] = (val >> 8) & 0xff;
83 addr[3] = val & 0xFF;
86 void short2be(unsigned short val, unsigned char* addr)
88 addr[0] = (val >> 8) & 0xff;
89 addr[1] = val & 0xFF;
92 void usage(void)
94 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
95 printf("options:\n"
96 "\t-fm Archos FM recorder format\n"
97 "\t-v2 Archos V2 recorder format\n"
98 "\t-ofm Archos Ondio FM recorder format\n"
99 "\t-osp Archos Ondio SP format\n"
100 "\t-neo SSI Neo format\n"
101 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
102 "\t-iriver iRiver format\n"
103 "\t-iaudiox5 iAudio X5 format\n"
104 "\t-iaudiox5v iAudio X5V format\n"
105 "\t-iaudiom5 iAudio M5 format\n"
106 "\t-iaudiom3 iAudio M3 format\n");
107 printf("\t-ipod3g ipod firmware partition format (3rd Gen)\n"
108 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
109 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
110 "\t-creative=X Creative firmware structure format\n"
111 "\t (X values: zvm, zvm60, zenvision\n"
112 "\t zenv, zen\n");
113 printf("\t-gigabeat Toshiba Gigabeat F/X format\n"
114 "\t-gigabeats Toshiba Gigabeat S format\n"
115 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
116 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
117 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
118 "\t All mi4 options take two optional arguments:\n");
119 printf("\t -model=XXXX where XXXX is the model id string\n"
120 "\t -type=XXXX where XXXX is a string indicating the \n"
121 "\t type of binary, eg. RBOS, RBBL\n"
122 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
123 "\t-rkw Rockchip RKW format\n"
124 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
125 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
126 "\t ip3g, ip4g, mini, iax5, iam5, iam3, h10, h10_5gb,\n");
127 printf("\t tpj2, c200, e200, giga, gigs, m100, m500, d2,\n"
128 "\t 9200, 1630, 6330, ldax, m200, c100, clip, e2v2,\n"
129 "\t m2v4, fuze, c2v2, clv2, y820, y920, y925, x747,\n"
130 "\t 747p, x777, nn2g, m244, cli+, fuz2, hd20, hd30,\n"
131 "\t ip6g, rk27, clzp)\n");
132 printf("\nNo option results in Archos standard player/recorder format.\n");
134 exit(1);
137 int main (int argc, char** argv)
139 unsigned long length,i,slen=0;
140 unsigned char *inbuf,*outbuf;
141 unsigned short crc=0;
142 unsigned long chksum=0; /* 32 bit checksum */
143 unsigned char header[24];
144 char *iname = argv[1];
145 char *oname = argv[2];
146 char *xorstring=NULL;
147 int headerlen = 6;
148 FILE* file;
149 int version=0;
150 unsigned long modelnum;
151 char modelname[5];
152 int model_id;
153 enum { none, scramble, xor, tcc_sum, tcc_crc, rkw, add } method = scramble;
154 bool creative_enable_ciff;
156 model_id = ARCHOS_PLAYER;
158 if (argc < 3) {
159 usage();
162 if(!strcmp(argv[1], "-fm")) {
163 headerlen = 24;
164 iname = argv[2];
165 oname = argv[3];
166 version = 4;
167 model_id = ARCHOS_FMRECORDER;
170 else if(!strcmp(argv[1], "-v2")) {
171 headerlen = 24;
172 iname = argv[2];
173 oname = argv[3];
174 version = 2;
175 model_id = ARCHOS_V2RECORDER;
178 else if(!strcmp(argv[1], "-ofm")) {
179 headerlen = 24;
180 iname = argv[2];
181 oname = argv[3];
182 version = 8;
183 model_id = ARCHOS_ONDIO_FM;
186 else if(!strcmp(argv[1], "-osp")) {
187 headerlen = 24;
188 iname = argv[2];
189 oname = argv[3];
190 version = 16;
191 model_id = ARCHOS_ONDIO_SP;
194 else if(!strcmp(argv[1], "-neo")) {
195 headerlen = 17;
196 iname = argv[2];
197 oname = argv[3];
198 method = none;
200 else if(!strncmp(argv[1], "-mm=", 4)) {
201 headerlen = 16;
202 iname = argv[2];
203 oname = argv[3];
204 method = xor;
205 version = argv[1][4];
206 if (argc > 4)
207 xorstring = argv[4];
208 else {
209 printf("Multimedia needs an xor string\n");
210 return -1;
213 else if(!strncmp(argv[1], "-tcc=", 4)) {
214 headerlen = 0;
215 iname = argv[2];
216 oname = argv[3];
218 if(!strcmp(&argv[1][5], "sum"))
219 method = tcc_sum;
220 else if(!strcmp(&argv[1][5], "crc"))
221 method = tcc_crc;
222 else {
223 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
224 return 2;
227 else if(!strncmp(argv[1], "-rkw", 4)) {
228 iname = argv[3];
229 oname = argv[4];
230 modelnum = 0;
232 if(!strncmp(argv[2], "-modelnum=", 10)) {
233 modelnum = atoi(&argv[2][10]);
236 if (!modelnum)
238 modelnum = 73; /* rk27generic */
239 fprintf(stderr, "modelnum not supplied."
240 " using default value for rk27generic target\n");
243 return (rkw_encode(iname, oname, modelnum) != 0) ? -1 : 0;
245 else if(!strncmp(argv[1], "-add=", 5)) {
246 iname = argv[2];
247 oname = argv[3];
248 method = add;
250 if(!strcmp(&argv[1][5], "h120"))
251 modelnum = 0;
252 else if(!strcmp(&argv[1][5], "h140"))
253 modelnum = 0; /* the same as the h120 */
254 else if(!strcmp(&argv[1][5], "h100"))
255 modelnum = 1;
256 else if(!strcmp(&argv[1][5], "h300"))
257 modelnum = 2;
258 else if(!strcmp(&argv[1][5], "ipco"))
259 modelnum = 3;
260 else if(!strcmp(&argv[1][5], "nano"))
261 modelnum = 4;
262 else if(!strcmp(&argv[1][5], "ipvd"))
263 modelnum = 5;
264 else if(!strcmp(&argv[1][5], "fp7x"))
265 modelnum = 6;
266 else if(!strcmp(&argv[1][5], "ip3g"))
267 modelnum = 7;
268 else if(!strcmp(&argv[1][5], "ip4g"))
269 modelnum = 8;
270 else if(!strcmp(&argv[1][5], "mini"))
271 modelnum = 9;
272 else if(!strcmp(&argv[1][5], "iax5"))
273 modelnum = 10;
274 else if(!strcmp(&argv[1][5], "mn2g"))
275 modelnum = 11;
276 else if(!strcmp(&argv[1][5], "h10"))
277 modelnum = 13;
278 else if(!strcmp(&argv[1][5], "h10_5gb"))
279 modelnum = 14;
280 else if(!strcmp(&argv[1][5], "tpj2"))
281 modelnum = 15;
282 else if(!strcmp(&argv[1][5], "e200"))
283 modelnum = 16;
284 else if(!strcmp(&argv[1][5], "iam5"))
285 modelnum = 17;
286 else if(!strcmp(&argv[1][5], "giga"))
287 modelnum = 18;
288 else if(!strcmp(&argv[1][5], "1g2g"))
289 modelnum = 19;
290 else if(!strcmp(&argv[1][5], "c200"))
291 modelnum = 20;
292 else if(!strcmp(&argv[1][5], "gigs"))
293 modelnum = 21;
294 else if(!strcmp(&argv[1][5], "m500"))
295 modelnum = 22;
296 else if(!strcmp(&argv[1][5], "m100"))
297 modelnum = 23;
298 else if(!strcmp(&argv[1][5], "d2"))
299 modelnum = 24;
300 else if(!strcmp(&argv[1][5], "iam3"))
301 modelnum = 25;
302 else if (!strcmp(&argv[1][5], "m200"))
303 modelnum = 29;
304 else if(!strcmp(&argv[1][5], "c100"))
305 modelnum = 30;
306 else if(!strcmp(&argv[1][5], "1630")) /* Philips HDD1630 */
307 modelnum = 31;
308 else if (!strcmp(&argv[1][5], "i7"))
309 modelnum = 32;
310 else if (!strcmp(&argv[1][5], "ldax"))
311 modelnum = 33;
312 else if(!strcmp(&argv[1][5], "9200")) /* Philips SA9200 */
313 modelnum = 34;
314 else if (!strcmp(&argv[1][5], "clip"))
315 modelnum = 40;
316 else if (!strcmp(&argv[1][5], "e2v2"))
317 modelnum = 41;
318 else if (!strcmp(&argv[1][5], "m2v4"))
319 modelnum = 42;
320 else if (!strcmp(&argv[1][5], "fuze"))
321 modelnum = 43;
322 else if (!strcmp(&argv[1][5], "c2v2"))
323 modelnum = 44;
324 else if (!strcmp(&argv[1][5], "x747"))
325 modelnum = 45;
326 else if (!strcmp(&argv[1][5], "747p"))
327 modelnum = 54;
328 else if (!strcmp(&argv[1][5], "y820")) /* Samsung YH-820 */
329 modelnum = 57;
330 else if (!strcmp(&argv[1][5], "y920")) /* Samsung YH-920 */
331 modelnum = 58;
332 else if (!strcmp(&argv[1][5], "y925")) /* Samsung YH-925 */
333 modelnum = 59;
334 else if (!strcmp(&argv[1][5], "clv2")) /* Sansa Clipv2 */
335 modelnum = 60;
336 else if (!strcmp(&argv[1][5], "x777"))
337 modelnum = 61;
338 else if (!strcmp(&argv[1][5], "nn2g")) /* iPod Nano 2nd Gen */
339 modelnum = 62;
340 else if (!strcmp(&argv[1][5], "x767"))
341 modelnum = 64;
342 else if (!strcmp(&argv[1][5], "6330")) /* Philips HDD6330 */
343 modelnum = 65;
344 else if (!strcmp(&argv[1][5], "cli+")) /* Sansa Clip+ */
345 modelnum = 66;
346 else if (!strcmp(&argv[1][5], "v500")) /* Packard Bell Vibe 500 */
347 modelnum = 67;
348 else if (!strcmp(&argv[1][5], "fuz2")) /* Sansa Fuze v2 */
349 modelnum = 68;
350 else if (!strcmp(&argv[1][5], "m244"))
351 modelnum = 131;
352 else if (!strcmp(&argv[1][5], "hd20")) /* MPIO HD200 */
353 modelnum = 69;
354 else if (!strcmp(&argv[1][5], "hd30")) /* MPIO HD300 */
355 modelnum = 70;
356 else if (!strcmp(&argv[1][5], "ip6g")) /* iPod Classic/6G */
357 modelnum = 71;
358 else if (!strcmp(&argv[1][5], "fuz+")) /* Sansa Fuze+ */
359 modelnum = 72;
360 else if (!strcmp(&argv[1][5], "clzp")) /* Sansa Clip Zip */
361 modelnum = 79;
362 else if (!strcmp(&argv[1][5], "conn")) /* Sansa Connect */
363 modelnum = 81;
364 else {
365 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
366 return 2;
368 /* we store a 4-letter model name too, for humans */
369 strncpy(modelname, &argv[1][5],4);
370 modelname[4] = '\0'; /* to be sure we are null terminated */
371 chksum = modelnum; /* start checksum calcs with this */
374 else if(!strcmp(argv[1], "-iriver")) {
375 /* iRiver code dealt with in the iriver.c code */
376 iname = argv[2];
377 oname = argv[3];
378 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
380 else if(!strcmp(argv[1], "-gigabeat")) {
381 /* iRiver code dealt with in the iriver.c code */
382 iname = argv[2];
383 oname = argv[3];
384 gigabeat_code(iname, oname);
385 return 0;
387 else if(!strcmp(argv[1], "-gigabeats")) {
388 iname = argv[2];
389 oname = argv[3];
390 return gigabeat_s_code(iname, oname);
392 else if(!strcmp(argv[1], "-iaudiox5")) {
393 iname = argv[2];
394 oname = argv[3];
395 return iaudio_encode(iname, oname, "COWON_X5_FW");
397 else if(!strcmp(argv[1], "-iaudiox5v")) {
398 iname = argv[2];
399 oname = argv[3];
400 return iaudio_encode(iname, oname, "COWON_X5V_FW");
402 else if(!strcmp(argv[1], "-iaudiom5")) {
403 iname = argv[2];
404 oname = argv[3];
405 return iaudio_encode(iname, oname, "COWON_M5_FW");
407 else if(!strcmp(argv[1], "-iaudiom3")) {
408 iname = argv[2];
409 oname = argv[3];
410 return iaudio_encode(iname, oname, "COWON_M3_FW");
412 else if(!strcmp(argv[1], "-ipod3g")) {
413 iname = argv[2];
414 oname = argv[3];
415 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
417 else if(!strcmp(argv[1], "-ipod4g")) {
418 iname = argv[2];
419 oname = argv[3];
420 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
422 else if(!strcmp(argv[1], "-ipod5g")) {
423 iname = argv[2];
424 oname = argv[3];
425 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
427 else if(!strncmp(argv[1], "-creative=", 10)) {
428 if(!strcmp(argv[2], "-no-ciff"))
430 creative_enable_ciff = false;
431 iname = argv[3];
432 oname = argv[4];
434 else
436 creative_enable_ciff = true;
437 iname = argv[2];
438 oname = argv[3];
440 if(!strcmp(&argv[1][10], "zvm"))
441 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
442 else if(!strcmp(&argv[1][10], "zvm60"))
443 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
444 else if(!strcmp(&argv[1][10], "zenvision"))
445 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
446 else if(!strcmp(&argv[1][10], "zenv"))
447 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
448 else if(!strcmp(&argv[1][10], "zen"))
449 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
450 else
452 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
453 return 2;
456 else if(!strcmp(argv[1], "-ccpmp")) {
457 iname = argv[2];
458 oname = argv[3];
459 return ccpmp_encode(iname, oname);
461 else if(!strncmp(argv[1], "-mi4", 4)) {
462 int mi4magic;
463 char model[4] = "";
464 char type[4] = "";
466 if(!strcmp(&argv[1][4], "v2")) {
467 mi4magic = MI4_MAGIC_DEFAULT;
468 version = 0x00010201;
470 else if(!strcmp(&argv[1][4], "v3")) {
471 mi4magic = MI4_MAGIC_DEFAULT;
472 version = 0x00010301;
474 else if(!strcmp(&argv[1][4], "r")) {
475 mi4magic = MI4_MAGIC_R;
476 version = 0x00010301;
478 else {
479 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
480 return -1;
483 iname = argv[2];
484 oname = argv[3];
486 if(!strncmp(argv[2], "-model=", 7)) {
487 iname = argv[3];
488 oname = argv[4];
489 strncpy(model, &argv[2][7], 4);
491 if(!strncmp(argv[3], "-type=", 6)) {
492 iname = argv[4];
493 oname = argv[5];
494 strncpy(type, &argv[3][6], 4);
498 return mi4_encode(iname, oname, version, mi4magic, model, type);
501 /* open file */
502 file = fopen(iname,"rb");
503 if (!file) {
504 perror(iname);
505 return -1;
507 fseek(file,0,SEEK_END);
508 length = ftell(file);
509 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
511 if ((method == scramble) &&
512 ((length + headerlen) >= size_limit[model_id])) {
513 printf("error: firmware image is %ld bytes while max size is %u!\n",
514 length + headerlen,
515 size_limit[model_id]);
516 fclose(file);
517 return -1;
520 fseek(file,0,SEEK_SET);
521 inbuf = malloc(length);
522 if (method == xor)
523 outbuf = malloc(length*2);
524 else if(method == add)
525 outbuf = malloc(length + 8);
526 else
527 outbuf = malloc(length);
528 if ( !inbuf || !outbuf ) {
529 printf("out of memory!\n");
530 return -1;
532 if(length> 4) {
533 /* zero-fill the last 4 bytes to make sure there's no rubbish there
534 when we write the size-aligned file later */
535 memset(outbuf+length-4, 0, 4);
538 /* read file */
539 i=fread(inbuf,1,length,file);
540 if ( !i ) {
541 perror(iname);
542 return -1;
544 fclose(file);
546 switch (method)
548 case add:
549 for (i = 0; i < length; i++) {
550 /* add 8 unsigned bits but keep a 32 bit sum */
551 chksum += inbuf[i];
553 break;
554 case scramble:
555 slen = length/4;
556 for (i = 0; i < length; i++) {
557 unsigned long addr = (i >> 2) + ((i % 4) * slen);
558 unsigned char data = inbuf[i];
559 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
560 outbuf[addr] = data;
562 break;
564 case xor:
565 /* "compress" */
566 slen = 0;
567 for (i=0; i<length; i++) {
568 if (!(i&7))
569 outbuf[slen++] = 0xff; /* all data is uncompressed */
570 outbuf[slen++] = inbuf[i];
572 break;
573 case none:
574 default:
575 /* dummy case just to silence picky compilers */
576 break;
579 if((method == none) || (method == scramble) || (method == xor)) {
580 /* calculate checksum */
581 for (i=0;i<length;i++)
582 crc += inbuf[i];
585 memset(header, 0, sizeof header);
586 switch (method)
588 case add:
590 int2be(chksum, header); /* checksum, big-endian */
591 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
592 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
593 headerlen = 8;
595 break;
597 case tcc_sum:
598 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
599 telechips_encode_sum(outbuf, length);
600 break;
602 case tcc_crc:
603 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
604 telechips_encode_crc(outbuf, length);
605 break;
607 case scramble:
608 if (headerlen == 6) {
609 int2be(length, header);
610 header[4] = (crc >> 8) & 0xff;
611 header[5] = crc & 0xff;
613 else {
614 header[0] =
615 header[1] =
616 header[2] =
617 header[3] = 0xff; /* ??? */
619 header[6] = (crc >> 8) & 0xff;
620 header[7] = crc & 0xff;
622 header[11] = version;
624 header[15] = headerlen; /* really? */
626 int2be(length, &header[20]);
628 break;
630 case xor:
632 int xorlen = strlen(xorstring);
634 /* xor data */
635 for (i=0; i<slen; i++)
636 outbuf[i] ^= xorstring[i & (xorlen-1)];
638 /* calculate checksum */
639 for (i=0; i<slen; i++)
640 crc += outbuf[i];
642 header[0] = header[2] = 'Z';
643 header[1] = header[3] = version;
644 int2le(length, &header[4]);
645 int2le(slen, &header[8]);
646 int2le(crc, &header[12]);
647 length = slen;
648 break;
651 #define MY_FIRMWARE_TYPE "Rockbox"
652 #define MY_HEADER_VERSION 1
653 default:
654 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
655 header[9]='\0'; /*shouldn't have to, but to be SURE */
656 header[10]=MY_HEADER_VERSION&0xFF;
657 header[11]=(crc>>8)&0xFF;
658 header[12]=crc&0xFF;
659 int2be(sizeof(header), &header[12]);
660 break;
663 /* write file */
664 file = fopen(oname,"wb");
665 if ( !file ) {
666 perror(oname);
667 return -1;
669 if (headerlen > 0) {
670 if ( !fwrite(header,headerlen,1,file) ) {
671 perror(oname);
672 return -1;
675 if ( !fwrite(outbuf,length,1,file) ) {
676 perror(oname);
677 return -1;
679 fclose(file);
681 free(inbuf);
682 free(outbuf);
684 return 0;
687 static int iaudio_encode(char *iname, char *oname, char *idstring)
689 size_t len;
690 int length;
691 FILE *file;
692 unsigned char *outbuf;
693 int i;
694 unsigned char sum = 0;
696 file = fopen(iname, "rb");
697 if (!file) {
698 perror(iname);
699 return -1;
701 fseek(file,0,SEEK_END);
702 length = ftell(file);
704 fseek(file,0,SEEK_SET);
705 outbuf = malloc(length+0x1030);
707 if ( !outbuf ) {
708 printf("out of memory!\n");
709 return -1;
712 len = fread(outbuf+0x1030, 1, length, file);
713 if(len < (size_t) length) {
714 perror(iname);
715 return -2;
718 memset(outbuf, 0, 0x1030);
719 strcpy((char *)outbuf, idstring);
720 memcpy(outbuf+0x20, iaudio_bl_flash,
721 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
722 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
723 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
724 outbuf[0x19] = 2;
726 for(i = 0; i < length;i++)
727 sum += outbuf[0x1030 + i];
729 int2be(length, &outbuf[0x1024]);
730 outbuf[0x102b] = sum;
732 fclose(file);
734 file = fopen(oname, "wb");
735 if (!file) {
736 perror(oname);
737 return -3;
740 len = fwrite(outbuf, 1, length+0x1030, file);
741 if(len < (size_t)length) {
742 perror(oname);
743 return -4;
746 fclose(file);
747 return 0;
751 /* Create an ipod firmware partition image
753 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
755 This function doesn't yet handle the Broadcom resource image for the 5g,
756 so the resulting images won't be usable.
758 This has also only been tested on an ipod Photo
761 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
763 static const char *apple_stop_sign = "{{~~ /-----\\ "\
764 "{{~~ / \\ "\
765 "{{~~| | "\
766 "{{~~| S T O P | "\
767 "{{~~| | "\
768 "{{~~ \\ / "\
769 "{{~~ \\-----/ "\
770 "Copyright(C) 200"\
771 "1 Apple Computer"\
772 ", Inc.----------"\
773 "----------------"\
774 "----------------"\
775 "----------------"\
776 "----------------"\
777 "----------------"\
778 "---------------";
779 size_t len;
780 int length;
781 int rsrclength;
782 int rsrcoffset;
783 FILE *file;
784 unsigned int sum = 0;
785 unsigned int rsrcsum = 0;
786 unsigned char *outbuf;
787 int bufsize;
788 int i;
790 file = fopen(iname, "rb");
791 if (!file) {
792 perror(iname);
793 return -1;
795 fseek(file,0,SEEK_END);
796 length = ftell(file);
798 fseek(file,0,SEEK_SET);
800 bufsize=(length+0x4600);
801 if (fake_rsrc) {
802 bufsize = (bufsize + 0x400) & ~0x200;
805 outbuf = malloc(bufsize);
807 if ( !outbuf ) {
808 printf("out of memory!\n");
809 return -1;
812 len = fread(outbuf+0x4600, 1, length, file);
813 if(len < (size_t)length) {
814 perror(iname);
815 return -2;
817 fclose(file);
819 /* Calculate checksum for later use in header */
820 for(i = 0x4600; i < 0x4600+length;i++)
821 sum += outbuf[i];
823 /* Clear the header area to zero */
824 memset(outbuf, 0, 0x4600);
826 /* APPLE STOP SIGN */
827 strcpy((char *)outbuf, apple_stop_sign);
829 /* VOLUME HEADER */
830 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
831 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
832 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
833 short2le(fw_ver, &outbuf[0x10a]);
835 /* Firmware Directory - "osos" entry */
836 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
837 int2le(0, &outbuf[0x4208]); /* id */
838 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
839 int2le(length, &outbuf[0x4210]); /* Length of firmware */
840 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
841 int2le(0, &outbuf[0x4218]); /* Entry Offset */
842 int2le(sum, &outbuf[0x421c]); /* Checksum */
843 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
844 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
846 /* "rsrc" entry (if applicable) */
847 if (fake_rsrc) {
848 rsrcoffset=(length+0x4600+0x200) & ~0x200;
849 rsrclength=0x200;
850 rsrcsum=0;
852 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
853 int2le(0, &outbuf[0x4230]); /* id */
854 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
855 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
856 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
857 int2le(0, &outbuf[0x4240]); /* Entry Offset */
858 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
859 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
860 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
863 file = fopen(oname, "wb");
864 if (!file) {
865 perror(oname);
866 return -3;
869 len = fwrite(outbuf, 1, length+0x4600, file);
870 if(len < (size_t)length) {
871 perror(oname);
872 return -4;
875 fclose(file);
877 return 0;
880 #define CCPMP_SIZE 0x500000
881 static int ccpmp_encode(char *iname, char *oname)
883 size_t len;
884 int length;
885 FILE *file;
886 unsigned char *outbuf;
888 file = fopen(iname, "rb");
889 if (!file) {
890 perror(iname);
891 return -1;
893 fseek(file,0,SEEK_END);
894 length = ftell(file);
896 fseek(file,0,SEEK_SET);
898 outbuf = malloc(CCPMP_SIZE);
900 if ( !outbuf ) {
901 printf("out of memory!\n");
902 return -1;
905 len = fread(outbuf, 1, length, file);
906 if(len < (size_t)length) {
907 perror(iname);
908 return -2;
910 fclose(file);
912 /* Clear the tail area to 0xFF */
913 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
915 /* Header */
916 int2le(length, &outbuf[0x4]);
918 file = fopen(oname, "wb");
919 if (!file) {
920 perror(oname);
921 return -3;
924 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
925 if(len < (size_t)length) {
926 perror(oname);
927 return -4;
930 fclose(file);
932 return 0;