as3525v2: fix volume setting (can now go very low)
[kugel-rb.git] / tools / scramble.c
blob7d33e4b203b60bbbc8e9a2dd2983474a60e63759
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)\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 if (!strcmp(&argv[1][5], "hd20")) /* MPIO HD200 */
332 modelnum = 69;
333 else {
334 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
335 return 2;
337 /* we store a 4-letter model name too, for humans */
338 strncpy(modelname, &argv[1][5],4);
339 modelname[4] = '\0'; /* to be sure we are null terminated */
340 chksum = modelnum; /* start checksum calcs with this */
343 else if(!strcmp(argv[1], "-iriver")) {
344 /* iRiver code dealt with in the iriver.c code */
345 iname = argv[2];
346 oname = argv[3];
347 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
349 else if(!strcmp(argv[1], "-gigabeat")) {
350 /* iRiver code dealt with in the iriver.c code */
351 iname = argv[2];
352 oname = argv[3];
353 gigabeat_code(iname, oname);
354 return 0;
356 else if(!strcmp(argv[1], "-gigabeats")) {
357 iname = argv[2];
358 oname = argv[3];
359 return gigabeat_s_code(iname, oname);
361 else if(!strcmp(argv[1], "-iaudiox5")) {
362 iname = argv[2];
363 oname = argv[3];
364 return iaudio_encode(iname, oname, "COWON_X5_FW");
366 else if(!strcmp(argv[1], "-iaudiox5v")) {
367 iname = argv[2];
368 oname = argv[3];
369 return iaudio_encode(iname, oname, "COWON_X5V_FW");
371 else if(!strcmp(argv[1], "-iaudiom5")) {
372 iname = argv[2];
373 oname = argv[3];
374 return iaudio_encode(iname, oname, "COWON_M5_FW");
376 else if(!strcmp(argv[1], "-iaudiom3")) {
377 iname = argv[2];
378 oname = argv[3];
379 return iaudio_encode(iname, oname, "COWON_M3_FW");
381 else if(!strcmp(argv[1], "-ipod3g")) {
382 iname = argv[2];
383 oname = argv[3];
384 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
386 else if(!strcmp(argv[1], "-ipod4g")) {
387 iname = argv[2];
388 oname = argv[3];
389 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
391 else if(!strcmp(argv[1], "-ipod5g")) {
392 iname = argv[2];
393 oname = argv[3];
394 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
396 else if(!strncmp(argv[1], "-creative=", 10)) {
397 if(!strcmp(argv[2], "-no-ciff"))
399 creative_enable_ciff = false;
400 iname = argv[3];
401 oname = argv[4];
403 else
405 creative_enable_ciff = true;
406 iname = argv[2];
407 oname = argv[3];
409 if(!strcmp(&argv[1][10], "zvm"))
410 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
411 else if(!strcmp(&argv[1][10], "zvm60"))
412 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
413 else if(!strcmp(&argv[1][10], "zenvision"))
414 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
415 else if(!strcmp(&argv[1][10], "zenv"))
416 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
417 else if(!strcmp(&argv[1][10], "zen"))
418 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
419 else
421 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
422 return 2;
425 else if(!strcmp(argv[1], "-ccpmp")) {
426 iname = argv[2];
427 oname = argv[3];
428 return ccpmp_encode(iname, oname);
430 else if(!strncmp(argv[1], "-mi4", 4)) {
431 int mi4magic;
432 char model[4] = "";
433 char type[4] = "";
435 if(!strcmp(&argv[1][4], "v2")) {
436 mi4magic = MI4_MAGIC_DEFAULT;
437 version = 0x00010201;
439 else if(!strcmp(&argv[1][4], "v3")) {
440 mi4magic = MI4_MAGIC_DEFAULT;
441 version = 0x00010301;
443 else if(!strcmp(&argv[1][4], "r")) {
444 mi4magic = MI4_MAGIC_R;
445 version = 0x00010301;
447 else {
448 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
449 return -1;
452 iname = argv[2];
453 oname = argv[3];
455 if(!strncmp(argv[2], "-model=", 7)) {
456 iname = argv[3];
457 oname = argv[4];
458 strncpy(model, &argv[2][7], 4);
460 if(!strncmp(argv[3], "-type=", 6)) {
461 iname = argv[4];
462 oname = argv[5];
463 strncpy(type, &argv[3][6], 4);
467 return mi4_encode(iname, oname, version, mi4magic, model, type);
470 /* open file */
471 file = fopen(iname,"rb");
472 if (!file) {
473 perror(iname);
474 return -1;
476 fseek(file,0,SEEK_END);
477 length = ftell(file);
478 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
480 if ((method == scramble) &&
481 ((length + headerlen) >= size_limit[model_id])) {
482 printf("error: firmware image is %ld bytes while max size is %u!\n",
483 length + headerlen,
484 size_limit[model_id]);
485 fclose(file);
486 return -1;
489 fseek(file,0,SEEK_SET);
490 inbuf = malloc(length);
491 if (method == xor)
492 outbuf = malloc(length*2);
493 else if(method == add)
494 outbuf = malloc(length + 8);
495 else
496 outbuf = malloc(length);
497 if ( !inbuf || !outbuf ) {
498 printf("out of memory!\n");
499 return -1;
501 if(length> 4) {
502 /* zero-fill the last 4 bytes to make sure there's no rubbish there
503 when we write the size-aligned file later */
504 memset(outbuf+length-4, 0, 4);
507 /* read file */
508 i=fread(inbuf,1,length,file);
509 if ( !i ) {
510 perror(iname);
511 return -1;
513 fclose(file);
515 switch (method)
517 case add:
518 for (i = 0; i < length; i++) {
519 /* add 8 unsigned bits but keep a 32 bit sum */
520 chksum += inbuf[i];
522 break;
523 case scramble:
524 slen = length/4;
525 for (i = 0; i < length; i++) {
526 unsigned long addr = (i >> 2) + ((i % 4) * slen);
527 unsigned char data = inbuf[i];
528 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
529 outbuf[addr] = data;
531 break;
533 case xor:
534 /* "compress" */
535 slen = 0;
536 for (i=0; i<length; i++) {
537 if (!(i&7))
538 outbuf[slen++] = 0xff; /* all data is uncompressed */
539 outbuf[slen++] = inbuf[i];
541 break;
542 case none:
543 default:
544 /* dummy case just to silence picky compilers */
545 break;
548 if((method == none) || (method == scramble) || (method == xor)) {
549 /* calculate checksum */
550 for (i=0;i<length;i++)
551 crc += inbuf[i];
554 memset(header, 0, sizeof header);
555 switch (method)
557 case add:
559 int2be(chksum, header); /* checksum, big-endian */
560 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
561 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
562 headerlen = 8;
564 break;
566 case tcc_sum:
567 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
568 telechips_encode_sum(outbuf, length);
569 break;
571 case tcc_crc:
572 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
573 telechips_encode_crc(outbuf, length);
574 break;
576 case scramble:
577 if (headerlen == 6) {
578 int2be(length, header);
579 header[4] = (crc >> 8) & 0xff;
580 header[5] = crc & 0xff;
582 else {
583 header[0] =
584 header[1] =
585 header[2] =
586 header[3] = 0xff; /* ??? */
588 header[6] = (crc >> 8) & 0xff;
589 header[7] = crc & 0xff;
591 header[11] = version;
593 header[15] = headerlen; /* really? */
595 int2be(length, &header[20]);
597 break;
599 case xor:
601 int xorlen = strlen(xorstring);
603 /* xor data */
604 for (i=0; i<slen; i++)
605 outbuf[i] ^= xorstring[i & (xorlen-1)];
607 /* calculate checksum */
608 for (i=0; i<slen; i++)
609 crc += outbuf[i];
611 header[0] = header[2] = 'Z';
612 header[1] = header[3] = version;
613 int2le(length, &header[4]);
614 int2le(slen, &header[8]);
615 int2le(crc, &header[12]);
616 length = slen;
617 break;
620 #define MY_FIRMWARE_TYPE "Rockbox"
621 #define MY_HEADER_VERSION 1
622 default:
623 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
624 header[9]='\0'; /*shouldn't have to, but to be SURE */
625 header[10]=MY_HEADER_VERSION&0xFF;
626 header[11]=(crc>>8)&0xFF;
627 header[12]=crc&0xFF;
628 int2be(sizeof(header), &header[12]);
629 break;
632 /* write file */
633 file = fopen(oname,"wb");
634 if ( !file ) {
635 perror(oname);
636 return -1;
638 if (headerlen > 0) {
639 if ( !fwrite(header,headerlen,1,file) ) {
640 perror(oname);
641 return -1;
644 if ( !fwrite(outbuf,length,1,file) ) {
645 perror(oname);
646 return -1;
648 fclose(file);
650 free(inbuf);
651 free(outbuf);
653 return 0;
656 static int iaudio_encode(char *iname, char *oname, char *idstring)
658 size_t len;
659 int length;
660 FILE *file;
661 unsigned char *outbuf;
662 int i;
663 unsigned char sum = 0;
665 file = fopen(iname, "rb");
666 if (!file) {
667 perror(iname);
668 return -1;
670 fseek(file,0,SEEK_END);
671 length = ftell(file);
673 fseek(file,0,SEEK_SET);
674 outbuf = malloc(length+0x1030);
676 if ( !outbuf ) {
677 printf("out of memory!\n");
678 return -1;
681 len = fread(outbuf+0x1030, 1, length, file);
682 if(len < (size_t) length) {
683 perror(iname);
684 return -2;
687 memset(outbuf, 0, 0x1030);
688 strcpy((char *)outbuf, idstring);
689 memcpy(outbuf+0x20, iaudio_bl_flash,
690 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
691 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
692 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
693 outbuf[0x19] = 2;
695 for(i = 0; i < length;i++)
696 sum += outbuf[0x1030 + i];
698 int2be(length, &outbuf[0x1024]);
699 outbuf[0x102b] = sum;
701 fclose(file);
703 file = fopen(oname, "wb");
704 if (!file) {
705 perror(oname);
706 return -3;
709 len = fwrite(outbuf, 1, length+0x1030, file);
710 if(len < (size_t)length) {
711 perror(oname);
712 return -4;
715 fclose(file);
716 return 0;
720 /* Create an ipod firmware partition image
722 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
724 This function doesn't yet handle the Broadcom resource image for the 5g,
725 so the resulting images won't be usable.
727 This has also only been tested on an ipod Photo
730 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
732 static const char *apple_stop_sign = "{{~~ /-----\\ "\
733 "{{~~ / \\ "\
734 "{{~~| | "\
735 "{{~~| S T O P | "\
736 "{{~~| | "\
737 "{{~~ \\ / "\
738 "{{~~ \\-----/ "\
739 "Copyright(C) 200"\
740 "1 Apple Computer"\
741 ", Inc.----------"\
742 "----------------"\
743 "----------------"\
744 "----------------"\
745 "----------------"\
746 "----------------"\
747 "---------------";
748 size_t len;
749 int length;
750 int rsrclength;
751 int rsrcoffset;
752 FILE *file;
753 unsigned int sum = 0;
754 unsigned int rsrcsum = 0;
755 unsigned char *outbuf;
756 int bufsize;
757 int i;
759 file = fopen(iname, "rb");
760 if (!file) {
761 perror(iname);
762 return -1;
764 fseek(file,0,SEEK_END);
765 length = ftell(file);
767 fseek(file,0,SEEK_SET);
769 bufsize=(length+0x4600);
770 if (fake_rsrc) {
771 bufsize = (bufsize + 0x400) & ~0x200;
774 outbuf = malloc(bufsize);
776 if ( !outbuf ) {
777 printf("out of memory!\n");
778 return -1;
781 len = fread(outbuf+0x4600, 1, length, file);
782 if(len < (size_t)length) {
783 perror(iname);
784 return -2;
786 fclose(file);
788 /* Calculate checksum for later use in header */
789 for(i = 0x4600; i < 0x4600+length;i++)
790 sum += outbuf[i];
792 /* Clear the header area to zero */
793 memset(outbuf, 0, 0x4600);
795 /* APPLE STOP SIGN */
796 strcpy((char *)outbuf, apple_stop_sign);
798 /* VOLUME HEADER */
799 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
800 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
801 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
802 short2le(fw_ver, &outbuf[0x10a]);
804 /* Firmware Directory - "osos" entry */
805 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
806 int2le(0, &outbuf[0x4208]); /* id */
807 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
808 int2le(length, &outbuf[0x4210]); /* Length of firmware */
809 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
810 int2le(0, &outbuf[0x4218]); /* Entry Offset */
811 int2le(sum, &outbuf[0x421c]); /* Checksum */
812 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
813 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
815 /* "rsrc" entry (if applicable) */
816 if (fake_rsrc) {
817 rsrcoffset=(length+0x4600+0x200) & ~0x200;
818 rsrclength=0x200;
819 rsrcsum=0;
821 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
822 int2le(0, &outbuf[0x4230]); /* id */
823 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
824 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
825 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
826 int2le(0, &outbuf[0x4240]); /* Entry Offset */
827 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
828 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
829 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
832 file = fopen(oname, "wb");
833 if (!file) {
834 perror(oname);
835 return -3;
838 len = fwrite(outbuf, 1, length+0x4600, file);
839 if(len < (size_t)length) {
840 perror(oname);
841 return -4;
844 fclose(file);
846 return 0;
849 #define CCPMP_SIZE 0x500000
850 static int ccpmp_encode(char *iname, char *oname)
852 size_t len;
853 int length;
854 FILE *file;
855 unsigned char *outbuf;
857 file = fopen(iname, "rb");
858 if (!file) {
859 perror(iname);
860 return -1;
862 fseek(file,0,SEEK_END);
863 length = ftell(file);
865 fseek(file,0,SEEK_SET);
867 outbuf = malloc(CCPMP_SIZE);
869 if ( !outbuf ) {
870 printf("out of memory!\n");
871 return -1;
874 len = fread(outbuf, 1, length, file);
875 if(len < (size_t)length) {
876 perror(iname);
877 return -2;
879 fclose(file);
881 /* Clear the tail area to 0xFF */
882 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
884 /* Header */
885 int2le(length, &outbuf[0x4]);
887 file = fopen(oname, "wb");
888 if (!file) {
889 perror(oname);
890 return -3;
893 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
894 if(len < (size_t)length) {
895 perror(oname);
896 return -4;
899 fclose(file);
901 return 0;