Reload the current playlist after reboot even if it has ended. (FS#11644)
[kugel-rb.git] / tools / scramble.c
blob683973321c689e5eb2fd20eab1481a113cb287f5
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)\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 {
343 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
344 return 2;
346 /* we store a 4-letter model name too, for humans */
347 strncpy(modelname, &argv[1][5],4);
348 modelname[4] = '\0'; /* to be sure we are null terminated */
349 chksum = modelnum; /* start checksum calcs with this */
352 else if(!strcmp(argv[1], "-iriver")) {
353 /* iRiver code dealt with in the iriver.c code */
354 iname = argv[2];
355 oname = argv[3];
356 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
358 else if(!strcmp(argv[1], "-gigabeat")) {
359 /* iRiver code dealt with in the iriver.c code */
360 iname = argv[2];
361 oname = argv[3];
362 gigabeat_code(iname, oname);
363 return 0;
365 else if(!strcmp(argv[1], "-gigabeats")) {
366 iname = argv[2];
367 oname = argv[3];
368 return gigabeat_s_code(iname, oname);
370 else if(!strcmp(argv[1], "-iaudiox5")) {
371 iname = argv[2];
372 oname = argv[3];
373 return iaudio_encode(iname, oname, "COWON_X5_FW");
375 else if(!strcmp(argv[1], "-iaudiox5v")) {
376 iname = argv[2];
377 oname = argv[3];
378 return iaudio_encode(iname, oname, "COWON_X5V_FW");
380 else if(!strcmp(argv[1], "-iaudiom5")) {
381 iname = argv[2];
382 oname = argv[3];
383 return iaudio_encode(iname, oname, "COWON_M5_FW");
385 else if(!strcmp(argv[1], "-iaudiom3")) {
386 iname = argv[2];
387 oname = argv[3];
388 return iaudio_encode(iname, oname, "COWON_M3_FW");
390 else if(!strcmp(argv[1], "-ipod3g")) {
391 iname = argv[2];
392 oname = argv[3];
393 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
395 else if(!strcmp(argv[1], "-ipod4g")) {
396 iname = argv[2];
397 oname = argv[3];
398 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
400 else if(!strcmp(argv[1], "-ipod5g")) {
401 iname = argv[2];
402 oname = argv[3];
403 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
405 else if(!strncmp(argv[1], "-creative=", 10)) {
406 if(!strcmp(argv[2], "-no-ciff"))
408 creative_enable_ciff = false;
409 iname = argv[3];
410 oname = argv[4];
412 else
414 creative_enable_ciff = true;
415 iname = argv[2];
416 oname = argv[3];
418 if(!strcmp(&argv[1][10], "zvm"))
419 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
420 else if(!strcmp(&argv[1][10], "zvm60"))
421 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
422 else if(!strcmp(&argv[1][10], "zenvision"))
423 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
424 else if(!strcmp(&argv[1][10], "zenv"))
425 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
426 else if(!strcmp(&argv[1][10], "zen"))
427 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
428 else
430 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
431 return 2;
434 else if(!strcmp(argv[1], "-ccpmp")) {
435 iname = argv[2];
436 oname = argv[3];
437 return ccpmp_encode(iname, oname);
439 else if(!strncmp(argv[1], "-mi4", 4)) {
440 int mi4magic;
441 char model[4] = "";
442 char type[4] = "";
444 if(!strcmp(&argv[1][4], "v2")) {
445 mi4magic = MI4_MAGIC_DEFAULT;
446 version = 0x00010201;
448 else if(!strcmp(&argv[1][4], "v3")) {
449 mi4magic = MI4_MAGIC_DEFAULT;
450 version = 0x00010301;
452 else if(!strcmp(&argv[1][4], "r")) {
453 mi4magic = MI4_MAGIC_R;
454 version = 0x00010301;
456 else {
457 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
458 return -1;
461 iname = argv[2];
462 oname = argv[3];
464 if(!strncmp(argv[2], "-model=", 7)) {
465 iname = argv[3];
466 oname = argv[4];
467 strncpy(model, &argv[2][7], 4);
469 if(!strncmp(argv[3], "-type=", 6)) {
470 iname = argv[4];
471 oname = argv[5];
472 strncpy(type, &argv[3][6], 4);
476 return mi4_encode(iname, oname, version, mi4magic, model, type);
479 /* open file */
480 file = fopen(iname,"rb");
481 if (!file) {
482 perror(iname);
483 return -1;
485 fseek(file,0,SEEK_END);
486 length = ftell(file);
487 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
489 if ((method == scramble) &&
490 ((length + headerlen) >= size_limit[model_id])) {
491 printf("error: firmware image is %ld bytes while max size is %u!\n",
492 length + headerlen,
493 size_limit[model_id]);
494 fclose(file);
495 return -1;
498 fseek(file,0,SEEK_SET);
499 inbuf = malloc(length);
500 if (method == xor)
501 outbuf = malloc(length*2);
502 else if(method == add)
503 outbuf = malloc(length + 8);
504 else
505 outbuf = malloc(length);
506 if ( !inbuf || !outbuf ) {
507 printf("out of memory!\n");
508 return -1;
510 if(length> 4) {
511 /* zero-fill the last 4 bytes to make sure there's no rubbish there
512 when we write the size-aligned file later */
513 memset(outbuf+length-4, 0, 4);
516 /* read file */
517 i=fread(inbuf,1,length,file);
518 if ( !i ) {
519 perror(iname);
520 return -1;
522 fclose(file);
524 switch (method)
526 case add:
527 for (i = 0; i < length; i++) {
528 /* add 8 unsigned bits but keep a 32 bit sum */
529 chksum += inbuf[i];
531 break;
532 case scramble:
533 slen = length/4;
534 for (i = 0; i < length; i++) {
535 unsigned long addr = (i >> 2) + ((i % 4) * slen);
536 unsigned char data = inbuf[i];
537 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
538 outbuf[addr] = data;
540 break;
542 case xor:
543 /* "compress" */
544 slen = 0;
545 for (i=0; i<length; i++) {
546 if (!(i&7))
547 outbuf[slen++] = 0xff; /* all data is uncompressed */
548 outbuf[slen++] = inbuf[i];
550 break;
551 case none:
552 default:
553 /* dummy case just to silence picky compilers */
554 break;
557 if((method == none) || (method == scramble) || (method == xor)) {
558 /* calculate checksum */
559 for (i=0;i<length;i++)
560 crc += inbuf[i];
563 memset(header, 0, sizeof header);
564 switch (method)
566 case add:
568 int2be(chksum, header); /* checksum, big-endian */
569 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
570 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
571 headerlen = 8;
573 break;
575 case tcc_sum:
576 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
577 telechips_encode_sum(outbuf, length);
578 break;
580 case tcc_crc:
581 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
582 telechips_encode_crc(outbuf, length);
583 break;
585 case scramble:
586 if (headerlen == 6) {
587 int2be(length, header);
588 header[4] = (crc >> 8) & 0xff;
589 header[5] = crc & 0xff;
591 else {
592 header[0] =
593 header[1] =
594 header[2] =
595 header[3] = 0xff; /* ??? */
597 header[6] = (crc >> 8) & 0xff;
598 header[7] = crc & 0xff;
600 header[11] = version;
602 header[15] = headerlen; /* really? */
604 int2be(length, &header[20]);
606 break;
608 case xor:
610 int xorlen = strlen(xorstring);
612 /* xor data */
613 for (i=0; i<slen; i++)
614 outbuf[i] ^= xorstring[i & (xorlen-1)];
616 /* calculate checksum */
617 for (i=0; i<slen; i++)
618 crc += outbuf[i];
620 header[0] = header[2] = 'Z';
621 header[1] = header[3] = version;
622 int2le(length, &header[4]);
623 int2le(slen, &header[8]);
624 int2le(crc, &header[12]);
625 length = slen;
626 break;
629 #define MY_FIRMWARE_TYPE "Rockbox"
630 #define MY_HEADER_VERSION 1
631 default:
632 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
633 header[9]='\0'; /*shouldn't have to, but to be SURE */
634 header[10]=MY_HEADER_VERSION&0xFF;
635 header[11]=(crc>>8)&0xFF;
636 header[12]=crc&0xFF;
637 int2be(sizeof(header), &header[12]);
638 break;
641 /* write file */
642 file = fopen(oname,"wb");
643 if ( !file ) {
644 perror(oname);
645 return -1;
647 if (headerlen > 0) {
648 if ( !fwrite(header,headerlen,1,file) ) {
649 perror(oname);
650 return -1;
653 if ( !fwrite(outbuf,length,1,file) ) {
654 perror(oname);
655 return -1;
657 fclose(file);
659 free(inbuf);
660 free(outbuf);
662 return 0;
665 static int iaudio_encode(char *iname, char *oname, char *idstring)
667 size_t len;
668 int length;
669 FILE *file;
670 unsigned char *outbuf;
671 int i;
672 unsigned char sum = 0;
674 file = fopen(iname, "rb");
675 if (!file) {
676 perror(iname);
677 return -1;
679 fseek(file,0,SEEK_END);
680 length = ftell(file);
682 fseek(file,0,SEEK_SET);
683 outbuf = malloc(length+0x1030);
685 if ( !outbuf ) {
686 printf("out of memory!\n");
687 return -1;
690 len = fread(outbuf+0x1030, 1, length, file);
691 if(len < (size_t) length) {
692 perror(iname);
693 return -2;
696 memset(outbuf, 0, 0x1030);
697 strcpy((char *)outbuf, idstring);
698 memcpy(outbuf+0x20, iaudio_bl_flash,
699 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
700 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
701 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
702 outbuf[0x19] = 2;
704 for(i = 0; i < length;i++)
705 sum += outbuf[0x1030 + i];
707 int2be(length, &outbuf[0x1024]);
708 outbuf[0x102b] = sum;
710 fclose(file);
712 file = fopen(oname, "wb");
713 if (!file) {
714 perror(oname);
715 return -3;
718 len = fwrite(outbuf, 1, length+0x1030, file);
719 if(len < (size_t)length) {
720 perror(oname);
721 return -4;
724 fclose(file);
725 return 0;
729 /* Create an ipod firmware partition image
731 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
733 This function doesn't yet handle the Broadcom resource image for the 5g,
734 so the resulting images won't be usable.
736 This has also only been tested on an ipod Photo
739 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
741 static const char *apple_stop_sign = "{{~~ /-----\\ "\
742 "{{~~ / \\ "\
743 "{{~~| | "\
744 "{{~~| S T O P | "\
745 "{{~~| | "\
746 "{{~~ \\ / "\
747 "{{~~ \\-----/ "\
748 "Copyright(C) 200"\
749 "1 Apple Computer"\
750 ", Inc.----------"\
751 "----------------"\
752 "----------------"\
753 "----------------"\
754 "----------------"\
755 "----------------"\
756 "---------------";
757 size_t len;
758 int length;
759 int rsrclength;
760 int rsrcoffset;
761 FILE *file;
762 unsigned int sum = 0;
763 unsigned int rsrcsum = 0;
764 unsigned char *outbuf;
765 int bufsize;
766 int i;
768 file = fopen(iname, "rb");
769 if (!file) {
770 perror(iname);
771 return -1;
773 fseek(file,0,SEEK_END);
774 length = ftell(file);
776 fseek(file,0,SEEK_SET);
778 bufsize=(length+0x4600);
779 if (fake_rsrc) {
780 bufsize = (bufsize + 0x400) & ~0x200;
783 outbuf = malloc(bufsize);
785 if ( !outbuf ) {
786 printf("out of memory!\n");
787 return -1;
790 len = fread(outbuf+0x4600, 1, length, file);
791 if(len < (size_t)length) {
792 perror(iname);
793 return -2;
795 fclose(file);
797 /* Calculate checksum for later use in header */
798 for(i = 0x4600; i < 0x4600+length;i++)
799 sum += outbuf[i];
801 /* Clear the header area to zero */
802 memset(outbuf, 0, 0x4600);
804 /* APPLE STOP SIGN */
805 strcpy((char *)outbuf, apple_stop_sign);
807 /* VOLUME HEADER */
808 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
809 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
810 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
811 short2le(fw_ver, &outbuf[0x10a]);
813 /* Firmware Directory - "osos" entry */
814 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
815 int2le(0, &outbuf[0x4208]); /* id */
816 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
817 int2le(length, &outbuf[0x4210]); /* Length of firmware */
818 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
819 int2le(0, &outbuf[0x4218]); /* Entry Offset */
820 int2le(sum, &outbuf[0x421c]); /* Checksum */
821 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
822 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
824 /* "rsrc" entry (if applicable) */
825 if (fake_rsrc) {
826 rsrcoffset=(length+0x4600+0x200) & ~0x200;
827 rsrclength=0x200;
828 rsrcsum=0;
830 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
831 int2le(0, &outbuf[0x4230]); /* id */
832 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
833 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
834 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
835 int2le(0, &outbuf[0x4240]); /* Entry Offset */
836 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
837 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
838 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
841 file = fopen(oname, "wb");
842 if (!file) {
843 perror(oname);
844 return -3;
847 len = fwrite(outbuf, 1, length+0x4600, file);
848 if(len < (size_t)length) {
849 perror(oname);
850 return -4;
853 fclose(file);
855 return 0;
858 #define CCPMP_SIZE 0x500000
859 static int ccpmp_encode(char *iname, char *oname)
861 size_t len;
862 int length;
863 FILE *file;
864 unsigned char *outbuf;
866 file = fopen(iname, "rb");
867 if (!file) {
868 perror(iname);
869 return -1;
871 fseek(file,0,SEEK_END);
872 length = ftell(file);
874 fseek(file,0,SEEK_SET);
876 outbuf = malloc(CCPMP_SIZE);
878 if ( !outbuf ) {
879 printf("out of memory!\n");
880 return -1;
883 len = fread(outbuf, 1, length, file);
884 if(len < (size_t)length) {
885 perror(iname);
886 return -2;
888 fclose(file);
890 /* Clear the tail area to 0xFF */
891 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
893 /* Header */
894 int2le(length, &outbuf[0x4]);
896 file = fopen(oname, "wb");
897 if (!file) {
898 perror(oname);
899 return -3;
902 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
903 if(len < (size_t)length) {
904 perror(oname);
905 return -4;
908 fclose(file);
910 return 0;