Accept expressions in CACHE_OVERLAP() macro
[kugel-rb.git] / tools / scramble.c
blobca3fd3bb352783e38be9b647c6f888f39b585847
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 - 2007 by Björn Stenberg
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include "iriver.h"
27 #include "gigabeat.h"
28 #include "gigabeats.h"
29 #include "mi4.h"
30 #include "telechips.h"
31 #include "creative.h"
32 #include "iaudio_bl_flash.h"
34 static int iaudio_encode(char *iname, char *oname, char *idstring);
35 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc);
36 static int ccpmp_encode(char *iname, char *oname);
38 enum
40 ARCHOS_PLAYER, /* and V1 recorder */
41 ARCHOS_V2RECORDER,
42 ARCHOS_FMRECORDER,
43 ARCHOS_ONDIO_SP,
44 ARCHOS_ONDIO_FM
47 static unsigned int size_limit[] =
49 0x32000, /* ARCHOS_PLAYER */
50 0x64000, /* ARCHOS_V2RECORDER */
51 0x64000, /* ARCHOS_FMRECORDER */
52 0x64000, /* ARCHOS_ONDIO_SP */
53 0x64000 /* ARCHOS_ONDIO_FM */
56 void short2le(unsigned short val, unsigned char* addr)
58 addr[0] = val & 0xFF;
59 addr[1] = (val >> 8) & 0xff;
62 unsigned int le2int(unsigned char* buf)
64 unsigned int res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
66 return res;
69 void int2le(unsigned int val, unsigned char* addr)
71 addr[0] = val & 0xFF;
72 addr[1] = (val >> 8) & 0xff;
73 addr[2] = (val >> 16) & 0xff;
74 addr[3] = (val >> 24) & 0xff;
77 void int2be(unsigned int val, unsigned char* addr)
79 addr[0] = (val >> 24) & 0xff;
80 addr[1] = (val >> 16) & 0xff;
81 addr[2] = (val >> 8) & 0xff;
82 addr[3] = val & 0xFF;
85 void short2be(unsigned short val, unsigned char* addr)
87 addr[0] = (val >> 8) & 0xff;
88 addr[1] = val & 0xFF;
91 void usage(void)
93 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
94 printf("options:\n"
95 "\t-fm Archos FM recorder format\n"
96 "\t-v2 Archos V2 recorder format\n"
97 "\t-ofm Archos Ondio FM recorder format\n"
98 "\t-osp Archos Ondio SP format\n"
99 "\t-neo SSI Neo format\n"
100 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
101 "\t-iriver iRiver format\n"
102 "\t-iaudiox5 iAudio X5 format\n"
103 "\t-iaudiox5v iAudio X5V format\n"
104 "\t-iaudiom5 iAudio M5 format\n"
105 "\t-iaudiom3 iAudio M3 format\n");
106 printf("\t-ipod3g ipod firmware partition format (3rd Gen)\n"
107 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
108 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
109 "\t-creative=X Creative firmware structure format\n"
110 "\t (X values: zvm, zvm60, zenvision\n"
111 "\t zenv, zen\n");
112 printf("\t-gigabeat Toshiba Gigabeat F/X format\n"
113 "\t-gigabeats Toshiba Gigabeat S format\n"
114 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
115 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
116 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
117 "\t All mi4 options take two optional arguments:\n");
118 printf("\t -model=XXXX where XXXX is the model id string\n"
119 "\t -type=XXXX where XXXX is a string indicating the \n"
120 "\t type of binary, eg. RBOS, RBBL\n"
121 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
122 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
123 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
124 "\t ip3g, ip4g, mini, iax5, iam5, iam3, h10, h10_5gb,\n"
125 "\t tpj2, c200, e200, giga, gigs, m100, m500, d2,\n");
126 printf("\t 9200, 1630, 6330, ldax, m200, c100, clip, e2v2,\n"
127 "\t m2v4, fuze, c2v2, clv2, y820, y920, y925, x747,\n"
128 "\t 747p, x777, nn2g, m244, cli+, fuz2)\n");
129 printf("\nNo option results in Archos standard player/recorder format.\n");
131 exit(1);
134 int main (int argc, char** argv)
136 unsigned long length,i,slen=0;
137 unsigned char *inbuf,*outbuf;
138 unsigned short crc=0;
139 unsigned long chksum=0; /* 32 bit checksum */
140 unsigned char header[24];
141 char *iname = argv[1];
142 char *oname = argv[2];
143 char *xorstring=NULL;
144 int headerlen = 6;
145 FILE* file;
146 int version=0;
147 unsigned long modelnum;
148 char modelname[5];
149 int model_id;
150 enum { none, scramble, xor, tcc_sum, tcc_crc, add } method = scramble;
151 bool creative_enable_ciff;
153 model_id = ARCHOS_PLAYER;
155 if (argc < 3) {
156 usage();
159 if(!strcmp(argv[1], "-fm")) {
160 headerlen = 24;
161 iname = argv[2];
162 oname = argv[3];
163 version = 4;
164 model_id = ARCHOS_FMRECORDER;
167 else if(!strcmp(argv[1], "-v2")) {
168 headerlen = 24;
169 iname = argv[2];
170 oname = argv[3];
171 version = 2;
172 model_id = ARCHOS_V2RECORDER;
175 else if(!strcmp(argv[1], "-ofm")) {
176 headerlen = 24;
177 iname = argv[2];
178 oname = argv[3];
179 version = 8;
180 model_id = ARCHOS_ONDIO_FM;
183 else if(!strcmp(argv[1], "-osp")) {
184 headerlen = 24;
185 iname = argv[2];
186 oname = argv[3];
187 version = 16;
188 model_id = ARCHOS_ONDIO_SP;
191 else if(!strcmp(argv[1], "-neo")) {
192 headerlen = 17;
193 iname = argv[2];
194 oname = argv[3];
195 method = none;
197 else if(!strncmp(argv[1], "-mm=", 4)) {
198 headerlen = 16;
199 iname = argv[2];
200 oname = argv[3];
201 method = xor;
202 version = argv[1][4];
203 if (argc > 4)
204 xorstring = argv[4];
205 else {
206 printf("Multimedia needs an xor string\n");
207 return -1;
210 else if(!strncmp(argv[1], "-tcc=", 4)) {
211 headerlen = 0;
212 iname = argv[2];
213 oname = argv[3];
215 if(!strcmp(&argv[1][5], "sum"))
216 method = tcc_sum;
217 else if(!strcmp(&argv[1][5], "crc"))
218 method = tcc_crc;
219 else {
220 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
221 return 2;
224 else if(!strncmp(argv[1], "-add=", 5)) {
225 iname = argv[2];
226 oname = argv[3];
227 method = add;
229 if(!strcmp(&argv[1][5], "h120"))
230 modelnum = 0;
231 else if(!strcmp(&argv[1][5], "h140"))
232 modelnum = 0; /* the same as the h120 */
233 else if(!strcmp(&argv[1][5], "h100"))
234 modelnum = 1;
235 else if(!strcmp(&argv[1][5], "h300"))
236 modelnum = 2;
237 else if(!strcmp(&argv[1][5], "ipco"))
238 modelnum = 3;
239 else if(!strcmp(&argv[1][5], "nano"))
240 modelnum = 4;
241 else if(!strcmp(&argv[1][5], "ipvd"))
242 modelnum = 5;
243 else if(!strcmp(&argv[1][5], "fp7x"))
244 modelnum = 6;
245 else if(!strcmp(&argv[1][5], "ip3g"))
246 modelnum = 7;
247 else if(!strcmp(&argv[1][5], "ip4g"))
248 modelnum = 8;
249 else if(!strcmp(&argv[1][5], "mini"))
250 modelnum = 9;
251 else if(!strcmp(&argv[1][5], "iax5"))
252 modelnum = 10;
253 else if(!strcmp(&argv[1][5], "mn2g"))
254 modelnum = 11;
255 else if(!strcmp(&argv[1][5], "h10"))
256 modelnum = 13;
257 else if(!strcmp(&argv[1][5], "h10_5gb"))
258 modelnum = 14;
259 else if(!strcmp(&argv[1][5], "tpj2"))
260 modelnum = 15;
261 else if(!strcmp(&argv[1][5], "e200"))
262 modelnum = 16;
263 else if(!strcmp(&argv[1][5], "iam5"))
264 modelnum = 17;
265 else if(!strcmp(&argv[1][5], "giga"))
266 modelnum = 18;
267 else if(!strcmp(&argv[1][5], "1g2g"))
268 modelnum = 19;
269 else if(!strcmp(&argv[1][5], "c200"))
270 modelnum = 20;
271 else if(!strcmp(&argv[1][5], "gigs"))
272 modelnum = 21;
273 else if(!strcmp(&argv[1][5], "m500"))
274 modelnum = 22;
275 else if(!strcmp(&argv[1][5], "m100"))
276 modelnum = 23;
277 else if(!strcmp(&argv[1][5], "d2"))
278 modelnum = 24;
279 else if(!strcmp(&argv[1][5], "iam3"))
280 modelnum = 25;
281 else if (!strcmp(&argv[1][5], "m200"))
282 modelnum = 29;
283 else if(!strcmp(&argv[1][5], "c100"))
284 modelnum = 30;
285 else if(!strcmp(&argv[1][5], "1630")) /* Philips HDD1630 */
286 modelnum = 31;
287 else if (!strcmp(&argv[1][5], "i7"))
288 modelnum = 32;
289 else if (!strcmp(&argv[1][5], "ldax"))
290 modelnum = 33;
291 else if(!strcmp(&argv[1][5], "9200")) /* Philips SA9200 */
292 modelnum = 34;
293 else if (!strcmp(&argv[1][5], "clip"))
294 modelnum = 40;
295 else if (!strcmp(&argv[1][5], "e2v2"))
296 modelnum = 41;
297 else if (!strcmp(&argv[1][5], "m2v4"))
298 modelnum = 42;
299 else if (!strcmp(&argv[1][5], "fuze"))
300 modelnum = 43;
301 else if (!strcmp(&argv[1][5], "c2v2"))
302 modelnum = 44;
303 else if (!strcmp(&argv[1][5], "x747"))
304 modelnum = 45;
305 else if (!strcmp(&argv[1][5], "747p"))
306 modelnum = 54;
307 else if (!strcmp(&argv[1][5], "y820")) /* Samsung YH-820 */
308 modelnum = 57;
309 else if (!strcmp(&argv[1][5], "y920")) /* Samsung YH-920 */
310 modelnum = 58;
311 else if (!strcmp(&argv[1][5], "y925")) /* Samsung YH-925 */
312 modelnum = 59;
313 else if (!strcmp(&argv[1][5], "clv2")) /* Sansa Clipv2 */
314 modelnum = 60;
315 else if (!strcmp(&argv[1][5], "x777"))
316 modelnum = 61;
317 else if (!strcmp(&argv[1][5], "nn2g")) /* iPod Nano 2nd Gen */
318 modelnum = 62;
319 else if (!strcmp(&argv[1][5], "x767"))
320 modelnum = 64;
321 else if (!strcmp(&argv[1][5], "6330")) /* Philips HDD6330 */
322 modelnum = 65;
323 else if (!strcmp(&argv[1][5], "cli+")) /* Sansa Clip+ */
324 modelnum = 66;
325 else if (!strcmp(&argv[1][5], "v500")) /* Packard Bell Vibe 500 */
326 modelnum = 67;
327 else if (!strcmp(&argv[1][5], "fuz2")) /* Sansa Fuze v2 */
328 modelnum = 68;
329 else if (!strcmp(&argv[1][5], "m244"))
330 modelnum = 131;
331 else {
332 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
333 return 2;
335 /* we store a 4-letter model name too, for humans */
336 strcpy(modelname, &argv[1][5]);
337 chksum = modelnum; /* start checksum calcs with this */
340 else if(!strcmp(argv[1], "-iriver")) {
341 /* iRiver code dealt with in the iriver.c code */
342 iname = argv[2];
343 oname = argv[3];
344 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
346 else if(!strcmp(argv[1], "-gigabeat")) {
347 /* iRiver code dealt with in the iriver.c code */
348 iname = argv[2];
349 oname = argv[3];
350 gigabeat_code(iname, oname);
351 return 0;
353 else if(!strcmp(argv[1], "-gigabeats")) {
354 iname = argv[2];
355 oname = argv[3];
356 return gigabeat_s_code(iname, oname);
358 else if(!strcmp(argv[1], "-iaudiox5")) {
359 iname = argv[2];
360 oname = argv[3];
361 return iaudio_encode(iname, oname, "COWON_X5_FW");
363 else if(!strcmp(argv[1], "-iaudiox5v")) {
364 iname = argv[2];
365 oname = argv[3];
366 return iaudio_encode(iname, oname, "COWON_X5V_FW");
368 else if(!strcmp(argv[1], "-iaudiom5")) {
369 iname = argv[2];
370 oname = argv[3];
371 return iaudio_encode(iname, oname, "COWON_M5_FW");
373 else if(!strcmp(argv[1], "-iaudiom3")) {
374 iname = argv[2];
375 oname = argv[3];
376 return iaudio_encode(iname, oname, "COWON_M3_FW");
378 else if(!strcmp(argv[1], "-ipod3g")) {
379 iname = argv[2];
380 oname = argv[3];
381 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
383 else if(!strcmp(argv[1], "-ipod4g")) {
384 iname = argv[2];
385 oname = argv[3];
386 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
388 else if(!strcmp(argv[1], "-ipod5g")) {
389 iname = argv[2];
390 oname = argv[3];
391 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
393 else if(!strncmp(argv[1], "-creative=", 10)) {
394 if(!strcmp(argv[2], "-no-ciff"))
396 creative_enable_ciff = false;
397 iname = argv[3];
398 oname = argv[4];
400 else
402 creative_enable_ciff = true;
403 iname = argv[2];
404 oname = argv[3];
406 if(!strcmp(&argv[1][10], "zvm"))
407 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
408 else if(!strcmp(&argv[1][10], "zvm60"))
409 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
410 else if(!strcmp(&argv[1][10], "zenvision"))
411 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
412 else if(!strcmp(&argv[1][10], "zenv"))
413 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
414 else if(!strcmp(&argv[1][10], "zen"))
415 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
416 else
418 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
419 return 2;
422 else if(!strcmp(argv[1], "-ccpmp")) {
423 iname = argv[2];
424 oname = argv[3];
425 return ccpmp_encode(iname, oname);
427 else if(!strncmp(argv[1], "-mi4", 4)) {
428 int mi4magic;
429 char model[4] = "";
430 char type[4] = "";
432 if(!strcmp(&argv[1][4], "v2")) {
433 mi4magic = MI4_MAGIC_DEFAULT;
434 version = 0x00010201;
436 else if(!strcmp(&argv[1][4], "v3")) {
437 mi4magic = MI4_MAGIC_DEFAULT;
438 version = 0x00010301;
440 else if(!strcmp(&argv[1][4], "r")) {
441 mi4magic = MI4_MAGIC_R;
442 version = 0x00010301;
444 else {
445 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
446 return -1;
449 iname = argv[2];
450 oname = argv[3];
452 if(!strncmp(argv[2], "-model=", 7)) {
453 iname = argv[3];
454 oname = argv[4];
455 strncpy(model, &argv[2][7], 4);
457 if(!strncmp(argv[3], "-type=", 6)) {
458 iname = argv[4];
459 oname = argv[5];
460 strncpy(type, &argv[3][6], 4);
464 return mi4_encode(iname, oname, version, mi4magic, model, type);
467 /* open file */
468 file = fopen(iname,"rb");
469 if (!file) {
470 perror(iname);
471 return -1;
473 fseek(file,0,SEEK_END);
474 length = ftell(file);
475 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
477 if ((method == scramble) &&
478 ((length + headerlen) >= size_limit[model_id])) {
479 printf("error: firmware image is %ld bytes while max size is %u!\n",
480 length + headerlen,
481 size_limit[model_id]);
482 fclose(file);
483 return -1;
486 fseek(file,0,SEEK_SET);
487 inbuf = malloc(length);
488 if (method == xor)
489 outbuf = malloc(length*2);
490 else if(method == add)
491 outbuf = malloc(length + 8);
492 else
493 outbuf = malloc(length);
494 if ( !inbuf || !outbuf ) {
495 printf("out of memory!\n");
496 return -1;
498 if(length> 4) {
499 /* zero-fill the last 4 bytes to make sure there's no rubbish there
500 when we write the size-aligned file later */
501 memset(outbuf+length-4, 0, 4);
504 /* read file */
505 i=fread(inbuf,1,length,file);
506 if ( !i ) {
507 perror(iname);
508 return -1;
510 fclose(file);
512 switch (method)
514 case add:
515 for (i = 0; i < length; i++) {
516 /* add 8 unsigned bits but keep a 32 bit sum */
517 chksum += inbuf[i];
519 break;
520 case scramble:
521 slen = length/4;
522 for (i = 0; i < length; i++) {
523 unsigned long addr = (i >> 2) + ((i % 4) * slen);
524 unsigned char data = inbuf[i];
525 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
526 outbuf[addr] = data;
528 break;
530 case xor:
531 /* "compress" */
532 slen = 0;
533 for (i=0; i<length; i++) {
534 if (!(i&7))
535 outbuf[slen++] = 0xff; /* all data is uncompressed */
536 outbuf[slen++] = inbuf[i];
538 break;
539 case none:
540 default:
541 /* dummy case just to silence picky compilers */
542 break;
545 if((method == none) || (method == scramble) || (method == xor)) {
546 /* calculate checksum */
547 for (i=0;i<length;i++)
548 crc += inbuf[i];
551 memset(header, 0, sizeof header);
552 switch (method)
554 case add:
556 int2be(chksum, header); /* checksum, big-endian */
557 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
558 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
559 headerlen = 8;
561 break;
563 case tcc_sum:
564 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
565 telechips_encode_sum(outbuf, length);
566 break;
568 case tcc_crc:
569 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
570 telechips_encode_crc(outbuf, length);
571 break;
573 case scramble:
574 if (headerlen == 6) {
575 int2be(length, header);
576 header[4] = (crc >> 8) & 0xff;
577 header[5] = crc & 0xff;
579 else {
580 header[0] =
581 header[1] =
582 header[2] =
583 header[3] = 0xff; /* ??? */
585 header[6] = (crc >> 8) & 0xff;
586 header[7] = crc & 0xff;
588 header[11] = version;
590 header[15] = headerlen; /* really? */
592 int2be(length, &header[20]);
594 break;
596 case xor:
598 int xorlen = strlen(xorstring);
600 /* xor data */
601 for (i=0; i<slen; i++)
602 outbuf[i] ^= xorstring[i & (xorlen-1)];
604 /* calculate checksum */
605 for (i=0; i<slen; i++)
606 crc += outbuf[i];
608 header[0] = header[2] = 'Z';
609 header[1] = header[3] = version;
610 int2le(length, &header[4]);
611 int2le(slen, &header[8]);
612 int2le(crc, &header[12]);
613 length = slen;
614 break;
617 #define MY_FIRMWARE_TYPE "Rockbox"
618 #define MY_HEADER_VERSION 1
619 default:
620 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
621 header[9]='\0'; /*shouldn't have to, but to be SURE */
622 header[10]=MY_HEADER_VERSION&0xFF;
623 header[11]=(crc>>8)&0xFF;
624 header[12]=crc&0xFF;
625 int2be(sizeof(header), &header[12]);
626 break;
629 /* write file */
630 file = fopen(oname,"wb");
631 if ( !file ) {
632 perror(oname);
633 return -1;
635 if (headerlen > 0) {
636 if ( !fwrite(header,headerlen,1,file) ) {
637 perror(oname);
638 return -1;
641 if ( !fwrite(outbuf,length,1,file) ) {
642 perror(oname);
643 return -1;
645 fclose(file);
647 free(inbuf);
648 free(outbuf);
650 return 0;
653 static int iaudio_encode(char *iname, char *oname, char *idstring)
655 size_t len;
656 int length;
657 FILE *file;
658 unsigned char *outbuf;
659 int i;
660 unsigned char sum = 0;
662 file = fopen(iname, "rb");
663 if (!file) {
664 perror(iname);
665 return -1;
667 fseek(file,0,SEEK_END);
668 length = ftell(file);
670 fseek(file,0,SEEK_SET);
671 outbuf = malloc(length+0x1030);
673 if ( !outbuf ) {
674 printf("out of memory!\n");
675 return -1;
678 len = fread(outbuf+0x1030, 1, length, file);
679 if(len < (size_t) length) {
680 perror(iname);
681 return -2;
684 memset(outbuf, 0, 0x1030);
685 strcpy((char *)outbuf, idstring);
686 memcpy(outbuf+0x20, iaudio_bl_flash,
687 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
688 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
689 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
690 outbuf[0x19] = 2;
692 for(i = 0; i < length;i++)
693 sum += outbuf[0x1030 + i];
695 int2be(length, &outbuf[0x1024]);
696 outbuf[0x102b] = sum;
698 fclose(file);
700 file = fopen(oname, "wb");
701 if (!file) {
702 perror(oname);
703 return -3;
706 len = fwrite(outbuf, 1, length+0x1030, file);
707 if(len < (size_t)length) {
708 perror(oname);
709 return -4;
712 fclose(file);
713 return 0;
717 /* Create an ipod firmware partition image
719 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
721 This function doesn't yet handle the Broadcom resource image for the 5g,
722 so the resulting images won't be usable.
724 This has also only been tested on an ipod Photo
727 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
729 static const char *apple_stop_sign = "{{~~ /-----\\ "\
730 "{{~~ / \\ "\
731 "{{~~| | "\
732 "{{~~| S T O P | "\
733 "{{~~| | "\
734 "{{~~ \\ / "\
735 "{{~~ \\-----/ "\
736 "Copyright(C) 200"\
737 "1 Apple Computer"\
738 ", Inc.----------"\
739 "----------------"\
740 "----------------"\
741 "----------------"\
742 "----------------"\
743 "----------------"\
744 "---------------";
745 size_t len;
746 int length;
747 int rsrclength;
748 int rsrcoffset;
749 FILE *file;
750 unsigned int sum = 0;
751 unsigned int rsrcsum = 0;
752 unsigned char *outbuf;
753 int bufsize;
754 int i;
756 file = fopen(iname, "rb");
757 if (!file) {
758 perror(iname);
759 return -1;
761 fseek(file,0,SEEK_END);
762 length = ftell(file);
764 fseek(file,0,SEEK_SET);
766 bufsize=(length+0x4600);
767 if (fake_rsrc) {
768 bufsize = (bufsize + 0x400) & ~0x200;
771 outbuf = malloc(bufsize);
773 if ( !outbuf ) {
774 printf("out of memory!\n");
775 return -1;
778 len = fread(outbuf+0x4600, 1, length, file);
779 if(len < (size_t)length) {
780 perror(iname);
781 return -2;
783 fclose(file);
785 /* Calculate checksum for later use in header */
786 for(i = 0x4600; i < 0x4600+length;i++)
787 sum += outbuf[i];
789 /* Clear the header area to zero */
790 memset(outbuf, 0, 0x4600);
792 /* APPLE STOP SIGN */
793 strcpy((char *)outbuf, apple_stop_sign);
795 /* VOLUME HEADER */
796 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
797 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
798 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
799 short2le(fw_ver, &outbuf[0x10a]);
801 /* Firmware Directory - "osos" entry */
802 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
803 int2le(0, &outbuf[0x4208]); /* id */
804 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
805 int2le(length, &outbuf[0x4210]); /* Length of firmware */
806 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
807 int2le(0, &outbuf[0x4218]); /* Entry Offset */
808 int2le(sum, &outbuf[0x421c]); /* Checksum */
809 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
810 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
812 /* "rsrc" entry (if applicable) */
813 if (fake_rsrc) {
814 rsrcoffset=(length+0x4600+0x200) & ~0x200;
815 rsrclength=0x200;
816 rsrcsum=0;
818 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
819 int2le(0, &outbuf[0x4230]); /* id */
820 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
821 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
822 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
823 int2le(0, &outbuf[0x4240]); /* Entry Offset */
824 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
825 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
826 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
829 file = fopen(oname, "wb");
830 if (!file) {
831 perror(oname);
832 return -3;
835 len = fwrite(outbuf, 1, length+0x4600, file);
836 if(len < (size_t)length) {
837 perror(oname);
838 return -4;
841 fclose(file);
843 return 0;
846 #define CCPMP_SIZE 0x500000
847 static int ccpmp_encode(char *iname, char *oname)
849 size_t len;
850 int length;
851 FILE *file;
852 unsigned char *outbuf;
854 file = fopen(iname, "rb");
855 if (!file) {
856 perror(iname);
857 return -1;
859 fseek(file,0,SEEK_END);
860 length = ftell(file);
862 fseek(file,0,SEEK_SET);
864 outbuf = malloc(CCPMP_SIZE);
866 if ( !outbuf ) {
867 printf("out of memory!\n");
868 return -1;
871 len = fread(outbuf, 1, length, file);
872 if(len < (size_t)length) {
873 perror(iname);
874 return -2;
876 fclose(file);
878 /* Clear the tail area to 0xFF */
879 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
881 /* Header */
882 int2le(length, &outbuf[0x4]);
884 file = fopen(oname, "wb");
885 if (!file) {
886 perror(oname);
887 return -3;
890 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
891 if(len < (size_t)length) {
892 perror(oname);
893 return -4;
896 fclose(file);
898 return 0;