Check selection before trying to create talk files.
[maemo-rb.git] / tools / scramble.c
blobc243d78b64960b9213fa367eb56191766001ab2a
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, zxf2, zxf3)\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 if (!strcmp(&argv[1][5], "zxf2")) /* Creative Zen X-Fi2 */
365 modelnum = 82;
366 else if (!strcmp(&argv[1][5], "zxf3")) /* Creative Zen X-Fi3 */
367 modelnum = 83;
368 else {
369 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
370 return 2;
372 /* we store a 4-letter model name too, for humans */
373 strncpy(modelname, &argv[1][5],4);
374 modelname[4] = '\0'; /* to be sure we are null terminated */
375 chksum = modelnum; /* start checksum calcs with this */
378 else if(!strcmp(argv[1], "-iriver")) {
379 /* iRiver code dealt with in the iriver.c code */
380 iname = argv[2];
381 oname = argv[3];
382 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
384 else if(!strcmp(argv[1], "-gigabeat")) {
385 /* iRiver code dealt with in the iriver.c code */
386 iname = argv[2];
387 oname = argv[3];
388 gigabeat_code(iname, oname);
389 return 0;
391 else if(!strcmp(argv[1], "-gigabeats")) {
392 iname = argv[2];
393 oname = argv[3];
394 return gigabeat_s_code(iname, oname);
396 else if(!strcmp(argv[1], "-iaudiox5")) {
397 iname = argv[2];
398 oname = argv[3];
399 return iaudio_encode(iname, oname, "COWON_X5_FW");
401 else if(!strcmp(argv[1], "-iaudiox5v")) {
402 iname = argv[2];
403 oname = argv[3];
404 return iaudio_encode(iname, oname, "COWON_X5V_FW");
406 else if(!strcmp(argv[1], "-iaudiom5")) {
407 iname = argv[2];
408 oname = argv[3];
409 return iaudio_encode(iname, oname, "COWON_M5_FW");
411 else if(!strcmp(argv[1], "-iaudiom3")) {
412 iname = argv[2];
413 oname = argv[3];
414 return iaudio_encode(iname, oname, "COWON_M3_FW");
416 else if(!strcmp(argv[1], "-ipod3g")) {
417 iname = argv[2];
418 oname = argv[3];
419 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
421 else if(!strcmp(argv[1], "-ipod4g")) {
422 iname = argv[2];
423 oname = argv[3];
424 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
426 else if(!strcmp(argv[1], "-ipod5g")) {
427 iname = argv[2];
428 oname = argv[3];
429 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
431 else if(!strncmp(argv[1], "-creative=", 10)) {
432 if(!strcmp(argv[2], "-no-ciff"))
434 creative_enable_ciff = false;
435 iname = argv[3];
436 oname = argv[4];
438 else
440 creative_enable_ciff = true;
441 iname = argv[2];
442 oname = argv[3];
444 if(!strcmp(&argv[1][10], "zvm"))
445 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
446 else if(!strcmp(&argv[1][10], "zvm60"))
447 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
448 else if(!strcmp(&argv[1][10], "zenvision"))
449 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
450 else if(!strcmp(&argv[1][10], "zenv"))
451 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
452 else if(!strcmp(&argv[1][10], "zen"))
453 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
454 else
456 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
457 return 2;
460 else if(!strcmp(argv[1], "-ccpmp")) {
461 iname = argv[2];
462 oname = argv[3];
463 return ccpmp_encode(iname, oname);
465 else if(!strncmp(argv[1], "-mi4", 4)) {
466 int mi4magic;
467 char model[4] = "";
468 char type[4] = "";
470 if(!strcmp(&argv[1][4], "v2")) {
471 mi4magic = MI4_MAGIC_DEFAULT;
472 version = 0x00010201;
474 else if(!strcmp(&argv[1][4], "v3")) {
475 mi4magic = MI4_MAGIC_DEFAULT;
476 version = 0x00010301;
478 else if(!strcmp(&argv[1][4], "r")) {
479 mi4magic = MI4_MAGIC_R;
480 version = 0x00010301;
482 else {
483 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
484 return -1;
487 iname = argv[2];
488 oname = argv[3];
490 if(!strncmp(argv[2], "-model=", 7)) {
491 iname = argv[3];
492 oname = argv[4];
493 strncpy(model, &argv[2][7], 4);
495 if(!strncmp(argv[3], "-type=", 6)) {
496 iname = argv[4];
497 oname = argv[5];
498 strncpy(type, &argv[3][6], 4);
502 return mi4_encode(iname, oname, version, mi4magic, model, type);
505 /* open file */
506 file = fopen(iname,"rb");
507 if (!file) {
508 perror(iname);
509 return -1;
511 fseek(file,0,SEEK_END);
512 length = ftell(file);
513 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
515 if ((method == scramble) &&
516 ((length + headerlen) >= size_limit[model_id])) {
517 printf("error: firmware image is %ld bytes while max size is %u!\n",
518 length + headerlen,
519 size_limit[model_id]);
520 fclose(file);
521 return -1;
524 fseek(file,0,SEEK_SET);
525 inbuf = malloc(length);
526 if (method == xor)
527 outbuf = malloc(length*2);
528 else if(method == add)
529 outbuf = malloc(length + 8);
530 else
531 outbuf = malloc(length);
532 if ( !inbuf || !outbuf ) {
533 printf("out of memory!\n");
534 return -1;
536 if(length> 4) {
537 /* zero-fill the last 4 bytes to make sure there's no rubbish there
538 when we write the size-aligned file later */
539 memset(outbuf+length-4, 0, 4);
542 /* read file */
543 i=fread(inbuf,1,length,file);
544 if ( !i ) {
545 perror(iname);
546 return -1;
548 fclose(file);
550 switch (method)
552 case add:
553 for (i = 0; i < length; i++) {
554 /* add 8 unsigned bits but keep a 32 bit sum */
555 chksum += inbuf[i];
557 break;
558 case scramble:
559 slen = length/4;
560 for (i = 0; i < length; i++) {
561 unsigned long addr = (i >> 2) + ((i % 4) * slen);
562 unsigned char data = inbuf[i];
563 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
564 outbuf[addr] = data;
566 break;
568 case xor:
569 /* "compress" */
570 slen = 0;
571 for (i=0; i<length; i++) {
572 if (!(i&7))
573 outbuf[slen++] = 0xff; /* all data is uncompressed */
574 outbuf[slen++] = inbuf[i];
576 break;
577 case none:
578 default:
579 /* dummy case just to silence picky compilers */
580 break;
583 if((method == none) || (method == scramble) || (method == xor)) {
584 /* calculate checksum */
585 for (i=0;i<length;i++)
586 crc += inbuf[i];
589 memset(header, 0, sizeof header);
590 switch (method)
592 case add:
594 int2be(chksum, header); /* checksum, big-endian */
595 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
596 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
597 headerlen = 8;
599 break;
601 case tcc_sum:
602 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
603 telechips_encode_sum(outbuf, length);
604 break;
606 case tcc_crc:
607 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
608 telechips_encode_crc(outbuf, length);
609 break;
611 case scramble:
612 if (headerlen == 6) {
613 int2be(length, header);
614 header[4] = (crc >> 8) & 0xff;
615 header[5] = crc & 0xff;
617 else {
618 header[0] =
619 header[1] =
620 header[2] =
621 header[3] = 0xff; /* ??? */
623 header[6] = (crc >> 8) & 0xff;
624 header[7] = crc & 0xff;
626 header[11] = version;
628 header[15] = headerlen; /* really? */
630 int2be(length, &header[20]);
632 break;
634 case xor:
636 int xorlen = strlen(xorstring);
638 /* xor data */
639 for (i=0; i<slen; i++)
640 outbuf[i] ^= xorstring[i & (xorlen-1)];
642 /* calculate checksum */
643 for (i=0; i<slen; i++)
644 crc += outbuf[i];
646 header[0] = header[2] = 'Z';
647 header[1] = header[3] = version;
648 int2le(length, &header[4]);
649 int2le(slen, &header[8]);
650 int2le(crc, &header[12]);
651 length = slen;
652 break;
655 #define MY_FIRMWARE_TYPE "Rockbox"
656 #define MY_HEADER_VERSION 1
657 default:
658 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
659 header[9]='\0'; /*shouldn't have to, but to be SURE */
660 header[10]=MY_HEADER_VERSION&0xFF;
661 header[11]=(crc>>8)&0xFF;
662 header[12]=crc&0xFF;
663 int2be(sizeof(header), &header[12]);
664 break;
667 /* write file */
668 file = fopen(oname,"wb");
669 if ( !file ) {
670 perror(oname);
671 return -1;
673 if (headerlen > 0) {
674 if ( !fwrite(header,headerlen,1,file) ) {
675 perror(oname);
676 return -1;
679 if ( !fwrite(outbuf,length,1,file) ) {
680 perror(oname);
681 return -1;
683 fclose(file);
685 free(inbuf);
686 free(outbuf);
688 return 0;
691 static int iaudio_encode(char *iname, char *oname, char *idstring)
693 size_t len;
694 int length;
695 FILE *file;
696 unsigned char *outbuf;
697 int i;
698 unsigned char sum = 0;
700 file = fopen(iname, "rb");
701 if (!file) {
702 perror(iname);
703 return -1;
705 fseek(file,0,SEEK_END);
706 length = ftell(file);
708 fseek(file,0,SEEK_SET);
709 outbuf = malloc(length+0x1030);
711 if ( !outbuf ) {
712 printf("out of memory!\n");
713 return -1;
716 len = fread(outbuf+0x1030, 1, length, file);
717 if(len < (size_t) length) {
718 perror(iname);
719 return -2;
722 memset(outbuf, 0, 0x1030);
723 strcpy((char *)outbuf, idstring);
724 memcpy(outbuf+0x20, iaudio_bl_flash,
725 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
726 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
727 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
728 outbuf[0x19] = 2;
730 for(i = 0; i < length;i++)
731 sum += outbuf[0x1030 + i];
733 int2be(length, &outbuf[0x1024]);
734 outbuf[0x102b] = sum;
736 fclose(file);
738 file = fopen(oname, "wb");
739 if (!file) {
740 perror(oname);
741 return -3;
744 len = fwrite(outbuf, 1, length+0x1030, file);
745 if(len < (size_t)length) {
746 perror(oname);
747 return -4;
750 fclose(file);
751 return 0;
755 /* Create an ipod firmware partition image
757 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
759 This function doesn't yet handle the Broadcom resource image for the 5g,
760 so the resulting images won't be usable.
762 This has also only been tested on an ipod Photo
765 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
767 static const char *apple_stop_sign = "{{~~ /-----\\ "\
768 "{{~~ / \\ "\
769 "{{~~| | "\
770 "{{~~| S T O P | "\
771 "{{~~| | "\
772 "{{~~ \\ / "\
773 "{{~~ \\-----/ "\
774 "Copyright(C) 200"\
775 "1 Apple Computer"\
776 ", Inc.----------"\
777 "----------------"\
778 "----------------"\
779 "----------------"\
780 "----------------"\
781 "----------------"\
782 "---------------";
783 size_t len;
784 int length;
785 int rsrclength;
786 int rsrcoffset;
787 FILE *file;
788 unsigned int sum = 0;
789 unsigned int rsrcsum = 0;
790 unsigned char *outbuf;
791 int bufsize;
792 int i;
794 file = fopen(iname, "rb");
795 if (!file) {
796 perror(iname);
797 return -1;
799 fseek(file,0,SEEK_END);
800 length = ftell(file);
802 fseek(file,0,SEEK_SET);
804 bufsize=(length+0x4600);
805 if (fake_rsrc) {
806 bufsize = (bufsize + 0x400) & ~0x200;
809 outbuf = malloc(bufsize);
811 if ( !outbuf ) {
812 printf("out of memory!\n");
813 return -1;
816 len = fread(outbuf+0x4600, 1, length, file);
817 if(len < (size_t)length) {
818 perror(iname);
819 return -2;
821 fclose(file);
823 /* Calculate checksum for later use in header */
824 for(i = 0x4600; i < 0x4600+length;i++)
825 sum += outbuf[i];
827 /* Clear the header area to zero */
828 memset(outbuf, 0, 0x4600);
830 /* APPLE STOP SIGN */
831 strcpy((char *)outbuf, apple_stop_sign);
833 /* VOLUME HEADER */
834 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
835 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
836 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
837 short2le(fw_ver, &outbuf[0x10a]);
839 /* Firmware Directory - "osos" entry */
840 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
841 int2le(0, &outbuf[0x4208]); /* id */
842 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
843 int2le(length, &outbuf[0x4210]); /* Length of firmware */
844 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
845 int2le(0, &outbuf[0x4218]); /* Entry Offset */
846 int2le(sum, &outbuf[0x421c]); /* Checksum */
847 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
848 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
850 /* "rsrc" entry (if applicable) */
851 if (fake_rsrc) {
852 rsrcoffset=(length+0x4600+0x200) & ~0x200;
853 rsrclength=0x200;
854 rsrcsum=0;
856 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
857 int2le(0, &outbuf[0x4230]); /* id */
858 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
859 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
860 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
861 int2le(0, &outbuf[0x4240]); /* Entry Offset */
862 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
863 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
864 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
867 file = fopen(oname, "wb");
868 if (!file) {
869 perror(oname);
870 return -3;
873 len = fwrite(outbuf, 1, length+0x4600, file);
874 if(len < (size_t)length) {
875 perror(oname);
876 return -4;
879 fclose(file);
881 return 0;
884 #define CCPMP_SIZE 0x500000
885 static int ccpmp_encode(char *iname, char *oname)
887 size_t len;
888 int length;
889 FILE *file;
890 unsigned char *outbuf;
892 file = fopen(iname, "rb");
893 if (!file) {
894 perror(iname);
895 return -1;
897 fseek(file,0,SEEK_END);
898 length = ftell(file);
900 fseek(file,0,SEEK_SET);
902 outbuf = malloc(CCPMP_SIZE);
904 if ( !outbuf ) {
905 printf("out of memory!\n");
906 return -1;
909 len = fread(outbuf, 1, length, file);
910 if(len < (size_t)length) {
911 perror(iname);
912 return -2;
914 fclose(file);
916 /* Clear the tail area to 0xFF */
917 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
919 /* Header */
920 int2le(length, &outbuf[0x4]);
922 file = fopen(oname, "wb");
923 if (!file) {
924 perror(oname);
925 return -3;
928 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
929 if(len < (size_t)length) {
930 perror(oname);
931 return -4;
934 fclose(file);
936 return 0;