Make TTS name conversion functions static members.
[Rockbox.git] / tools / scramble.c
blob3e5a0771bc8f7bbbd9e04fd852a581712f7ff93b
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 - 2007 by Björn Stenberg
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdbool.h>
23 #include <string.h>
24 #include "iriver.h"
25 #include "gigabeat.h"
26 #include "gigabeats.h"
27 #include "mi4.h"
28 #include "telechips.h"
30 int iaudio_encode(char *iname, char *oname, char *idstring);
31 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc);
33 enum
35 ARCHOS_PLAYER, /* and V1 recorder */
36 ARCHOS_V2RECORDER,
37 ARCHOS_FMRECORDER,
38 ARCHOS_ONDIO_SP,
39 ARCHOS_ONDIO_FM
42 int size_limit[] =
44 0x32000, /* ARCHOS_PLAYER */
45 0x64000, /* ARCHOS_V2RECORDER */
46 0x64000, /* ARCHOS_FMRECORDER */
47 0x64000, /* ARCHOS_ONDIO_SP */
48 0x64000 /* ARCHOS_ONDIO_FM */
51 void short2le(unsigned short val, unsigned char* addr)
53 addr[0] = val & 0xFF;
54 addr[1] = (val >> 8) & 0xff;
57 unsigned int le2int(unsigned char* buf)
59 unsigned int res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
61 return res;
64 void int2le(unsigned int val, unsigned char* addr)
66 addr[0] = val & 0xFF;
67 addr[1] = (val >> 8) & 0xff;
68 addr[2] = (val >> 16) & 0xff;
69 addr[3] = (val >> 24) & 0xff;
72 void int2be(unsigned int val, unsigned char* addr)
74 addr[0] = (val >> 24) & 0xff;
75 addr[1] = (val >> 16) & 0xff;
76 addr[2] = (val >> 8) & 0xff;
77 addr[3] = val & 0xFF;
80 void usage(void)
82 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
83 printf("options:\n"
84 "\t-fm Archos FM recorder format\n"
85 "\t-v2 Archos V2 recorder format\n"
86 "\t-ofm Archos Ondio FM recorder format\n"
87 "\t-osp Archos Ondio SP format\n"
88 "\t-neo SSI Neo format\n"
89 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
90 "\t-iriver iRiver format\n"
91 "\t-iaudiox5 iAudio X5 format\n"
92 "\t-iaudiox5v iAudio X5V format\n"
93 "\t-iaudiom5 iAudio M5 format\n"
94 "\t-ipod3g ipod firmware partition format (3rd Gen)\n"
95 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
96 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
97 "\t-gigabeat Toshiba Gigabeat F/X format\n"
98 "\t-gigabeats Toshiba Gigabeat S format\n"
99 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
100 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
101 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
102 "\t All mi4 options take two optional arguments:\n"
103 "\t -model=XXXX where XXXX is the model id string\n"
104 "\t -type=XXXX where XXXX is a string indicating the \n"
105 "\t type of binary, eg. RBOS, RBBL\n"
106 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
107 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
108 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
109 "\t ip3g, ip4g, mini, iax5, h10, h10_5gb, tpj2,\n"
110 "\t c200, e200, giga, gigs, m100, m500)\n"
111 "\nNo option results in Archos standard player/recorder format.\n");
113 exit(1);
116 int main (int argc, char** argv)
118 unsigned long length,i,slen;
119 unsigned char *inbuf,*outbuf;
120 unsigned short crc=0;
121 unsigned long chksum=0; /* 32 bit checksum */
122 unsigned char header[24];
123 char *iname = argv[1];
124 char *oname = argv[2];
125 char *xorstring;
126 int headerlen = 6;
127 FILE* file;
128 int version;
129 unsigned long modelnum;
130 char modelname[5];
131 int model_id;
132 enum { none, scramble, xor, tcc_sum, tcc_crc, add } method = scramble;
134 model_id = ARCHOS_PLAYER;
136 if (argc < 3) {
137 usage();
140 if(!strcmp(argv[1], "-fm")) {
141 headerlen = 24;
142 iname = argv[2];
143 oname = argv[3];
144 version = 4;
145 model_id = ARCHOS_FMRECORDER;
148 else if(!strcmp(argv[1], "-v2")) {
149 headerlen = 24;
150 iname = argv[2];
151 oname = argv[3];
152 version = 2;
153 model_id = ARCHOS_V2RECORDER;
156 else if(!strcmp(argv[1], "-ofm")) {
157 headerlen = 24;
158 iname = argv[2];
159 oname = argv[3];
160 version = 8;
161 model_id = ARCHOS_ONDIO_FM;
164 else if(!strcmp(argv[1], "-osp")) {
165 headerlen = 24;
166 iname = argv[2];
167 oname = argv[3];
168 version = 16;
169 model_id = ARCHOS_ONDIO_SP;
172 else if(!strcmp(argv[1], "-neo")) {
173 headerlen = 17;
174 iname = argv[2];
175 oname = argv[3];
176 method = none;
178 else if(!strncmp(argv[1], "-mm=", 4)) {
179 headerlen = 16;
180 iname = argv[2];
181 oname = argv[3];
182 method = xor;
183 version = argv[1][4];
184 if (argc > 4)
185 xorstring = argv[4];
186 else {
187 printf("Multimedia needs an xor string\n");
188 return -1;
191 else if(!strncmp(argv[1], "-tcc=", 4)) {
192 headerlen = 0;
193 iname = argv[2];
194 oname = argv[3];
196 if(!strcmp(&argv[1][5], "sum"))
197 method = tcc_sum;
198 else if(!strcmp(&argv[1][5], "crc"))
199 method = tcc_crc;
200 else {
201 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
202 return 2;
205 else if(!strncmp(argv[1], "-add=", 5)) {
206 iname = argv[2];
207 oname = argv[3];
208 method = add;
210 if(!strcmp(&argv[1][5], "h120"))
211 modelnum = 0;
212 else if(!strcmp(&argv[1][5], "h140"))
213 modelnum = 0; /* the same as the h120 */
214 else if(!strcmp(&argv[1][5], "h100"))
215 modelnum = 1;
216 else if(!strcmp(&argv[1][5], "h300"))
217 modelnum = 2;
218 else if(!strcmp(&argv[1][5], "ipco"))
219 modelnum = 3;
220 else if(!strcmp(&argv[1][5], "nano"))
221 modelnum = 4;
222 else if(!strcmp(&argv[1][5], "ipvd"))
223 modelnum = 5;
224 else if(!strcmp(&argv[1][5], "fp7x"))
225 modelnum = 6;
226 else if(!strcmp(&argv[1][5], "ip3g"))
227 modelnum = 7;
228 else if(!strcmp(&argv[1][5], "ip4g"))
229 modelnum = 8;
230 else if(!strcmp(&argv[1][5], "mini"))
231 modelnum = 9;
232 else if(!strcmp(&argv[1][5], "iax5"))
233 modelnum = 10;
234 else if(!strcmp(&argv[1][5], "mn2g"))
235 modelnum = 11;
236 else if(!strcmp(&argv[1][5], "h10"))
237 modelnum = 13;
238 else if(!strcmp(&argv[1][5], "h10_5gb"))
239 modelnum = 14;
240 else if(!strcmp(&argv[1][5], "tpj2"))
241 modelnum = 15;
242 else if(!strcmp(&argv[1][5], "e200"))
243 modelnum = 16;
244 else if(!strcmp(&argv[1][5], "iam5"))
245 modelnum = 17;
246 else if(!strcmp(&argv[1][5], "giga"))
247 modelnum = 18;
248 else if(!strcmp(&argv[1][5], "1g2g"))
249 modelnum = 19;
250 else if(!strcmp(&argv[1][5], "c200"))
251 modelnum = 20;
252 else if(!strcmp(&argv[1][5], "gigs"))
253 modelnum = 21;
254 else if(!strcmp(&argv[1][5], "m500"))
255 modelnum = 22;
256 else if(!strcmp(&argv[1][5], "m100"))
257 modelnum = 23;
258 else {
259 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
260 return 2;
262 /* we store a 4-letter model name too, for humans */
263 strcpy(modelname, &argv[1][5]);
264 chksum = modelnum; /* start checksum calcs with this */
267 else if(!strcmp(argv[1], "-iriver")) {
268 /* iRiver code dealt with in the iriver.c code */
269 iname = argv[2];
270 oname = argv[3];
271 iriver_encode(iname, oname, FALSE);
272 return 0;
274 else if(!strcmp(argv[1], "-gigabeat")) {
275 /* iRiver code dealt with in the iriver.c code */
276 iname = argv[2];
277 oname = argv[3];
278 gigabeat_code(iname, oname);
279 return 0;
281 else if(!strcmp(argv[1], "-gigabeats")) {
282 iname = argv[2];
283 oname = argv[3];
284 gigabeat_s_code(iname, oname);
285 return 0;
287 else if(!strcmp(argv[1], "-iaudiox5")) {
288 iname = argv[2];
289 oname = argv[3];
290 return iaudio_encode(iname, oname, "COWON_X5_FW");
292 else if(!strcmp(argv[1], "-iaudiox5v")) {
293 iname = argv[2];
294 oname = argv[3];
295 return iaudio_encode(iname, oname, "COWON_X5V_FW");
297 else if(!strcmp(argv[1], "-iaudiom5")) {
298 iname = argv[2];
299 oname = argv[3];
300 return iaudio_encode(iname, oname, "COWON_M5_FW");
302 else if(!strcmp(argv[1], "-ipod3g")) {
303 iname = argv[2];
304 oname = argv[3];
305 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
307 else if(!strcmp(argv[1], "-ipod4g")) {
308 iname = argv[2];
309 oname = argv[3];
310 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
312 else if(!strcmp(argv[1], "-ipod5g")) {
313 iname = argv[2];
314 oname = argv[3];
315 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
317 else if(!strncmp(argv[1], "-mi4", 4)) {
318 int mi4magic;
319 int version;
320 char model[4] = "";
321 char type[4] = "";
323 if(!strcmp(&argv[1][4], "v2")) {
324 mi4magic = MI4_MAGIC_DEFAULT;
325 version = 0x00010201;
327 else if(!strcmp(&argv[1][4], "v3")) {
328 mi4magic = MI4_MAGIC_DEFAULT;
329 version = 0x00010301;
331 else if(!strcmp(&argv[1][4], "r")) {
332 mi4magic = MI4_MAGIC_R;
333 version = 0x00010301;
335 else {
336 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
337 return -1;
340 iname = argv[2];
341 oname = argv[3];
343 if(!strncmp(argv[2], "-model=", 7)) {
344 iname = argv[3];
345 oname = argv[4];
346 strncpy(model, &argv[2][7], 4);
348 if(!strncmp(argv[3], "-type=", 6)) {
349 iname = argv[4];
350 oname = argv[5];
351 strncpy(type, &argv[3][6], 4);
355 return mi4_encode(iname, oname, version, mi4magic, model, type);
358 /* open file */
359 file = fopen(iname,"rb");
360 if (!file) {
361 perror(iname);
362 return -1;
364 fseek(file,0,SEEK_END);
365 length = ftell(file);
366 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
368 if ((method == scramble) &&
369 ((length + headerlen) >= size_limit[model_id])) {
370 printf("error: firmware image is %d bytes while max size is %d!\n",
371 length + headerlen,
372 size_limit[model_id]);
373 fclose(file);
374 return -1;
377 fseek(file,0,SEEK_SET);
378 inbuf = malloc(length);
379 if (method == xor)
380 outbuf = malloc(length*2);
381 else if(method == add)
382 outbuf = malloc(length + 8);
383 else
384 outbuf = malloc(length);
385 if ( !inbuf || !outbuf ) {
386 printf("out of memory!\n");
387 return -1;
389 if(length> 4) {
390 /* zero-fill the last 4 bytes to make sure there's no rubbish there
391 when we write the size-aligned file later */
392 memset(outbuf+length-4, 0, 4);
395 /* read file */
396 i=fread(inbuf,1,length,file);
397 if ( !i ) {
398 perror(iname);
399 return -1;
401 fclose(file);
403 switch (method)
405 case add:
406 for (i = 0; i < length; i++) {
407 /* add 8 unsigned bits but keep a 32 bit sum */
408 chksum += inbuf[i];
410 break;
411 case scramble:
412 slen = length/4;
413 for (i = 0; i < length; i++) {
414 unsigned long addr = (i >> 2) + ((i % 4) * slen);
415 unsigned char data = inbuf[i];
416 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
417 outbuf[addr] = data;
419 break;
421 case xor:
422 /* "compress" */
423 slen = 0;
424 for (i=0; i<length; i++) {
425 if (!(i&7))
426 outbuf[slen++] = 0xff; /* all data is uncompressed */
427 outbuf[slen++] = inbuf[i];
429 break;
432 if((method == none) || (method == scramble) || (method == xor)) {
433 /* calculate checksum */
434 for (i=0;i<length;i++)
435 crc += inbuf[i];
438 memset(header, 0, sizeof header);
439 switch (method)
441 case add:
443 int2be(chksum, header); /* checksum, big-endian */
444 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
445 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
446 headerlen = 8;
448 break;
450 case tcc_sum:
451 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
452 telechips_encode_sum(outbuf, length);
453 break;
455 case tcc_crc:
456 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
457 telechips_encode_crc(outbuf, length);
458 break;
460 case scramble:
461 if (headerlen == 6) {
462 int2be(length, header);
463 header[4] = (crc >> 8) & 0xff;
464 header[5] = crc & 0xff;
466 else {
467 header[0] =
468 header[1] =
469 header[2] =
470 header[3] = 0xff; /* ??? */
472 header[6] = (crc >> 8) & 0xff;
473 header[7] = crc & 0xff;
475 header[11] = version;
477 header[15] = headerlen; /* really? */
479 int2be(length, &header[20]);
481 break;
483 case xor:
485 int xorlen = strlen(xorstring);
487 /* xor data */
488 for (i=0; i<slen; i++)
489 outbuf[i] ^= xorstring[i & (xorlen-1)];
491 /* calculate checksum */
492 for (i=0; i<slen; i++)
493 crc += outbuf[i];
495 header[0] = header[2] = 'Z';
496 header[1] = header[3] = version;
497 int2le(length, &header[4]);
498 int2le(slen, &header[8]);
499 int2le(crc, &header[12]);
500 length = slen;
501 break;
504 #define MY_FIRMWARE_TYPE "Rockbox"
505 #define MY_HEADER_VERSION 1
506 default:
507 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
508 header[9]='\0'; /*shouldn't have to, but to be SURE */
509 header[10]=MY_HEADER_VERSION&0xFF;
510 header[11]=(crc>>8)&0xFF;
511 header[12]=crc&0xFF;
512 int2be(sizeof(header), &header[12]);
513 break;
516 /* write file */
517 file = fopen(oname,"wb");
518 if ( !file ) {
519 perror(oname);
520 return -1;
522 if (headerlen > 0) {
523 if ( !fwrite(header,headerlen,1,file) ) {
524 perror(oname);
525 return -1;
528 if ( !fwrite(outbuf,length,1,file) ) {
529 perror(oname);
530 return -1;
532 fclose(file);
534 free(inbuf);
535 free(outbuf);
537 return 0;
540 int iaudio_encode(char *iname, char *oname, char *idstring)
542 size_t len;
543 int length;
544 FILE *file;
545 unsigned char *outbuf;
546 int i;
547 unsigned char sum = 0;
549 file = fopen(iname, "rb");
550 if (!file) {
551 perror(iname);
552 return -1;
554 fseek(file,0,SEEK_END);
555 length = ftell(file);
557 fseek(file,0,SEEK_SET);
558 outbuf = malloc(length+0x1030);
560 if ( !outbuf ) {
561 printf("out of memory!\n");
562 return -1;
565 len = fread(outbuf+0x1030, 1, length, file);
566 if(len < length) {
567 perror(iname);
568 return -2;
571 memset(outbuf, 0, 0x1030);
572 strcpy((char *)outbuf, idstring);
574 for(i = 0; i < length;i++)
575 sum += outbuf[0x1030 + i];
577 int2be(length, &outbuf[0x1024]);
578 outbuf[0x102b] = sum;
580 fclose(file);
582 file = fopen(oname, "wb");
583 if (!file) {
584 perror(oname);
585 return -3;
588 len = fwrite(outbuf, 1, length+0x1030, file);
589 if(len < length) {
590 perror(oname);
591 return -4;
594 fclose(file);
598 /* Create an ipod firmware partition image
600 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
602 This function doesn't yet handle the Broadcom resource image for the 5g,
603 so the resulting images won't be usable.
605 This has also only been tested on an ipod Photo
608 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
610 static const char *apple_stop_sign = "{{~~ /-----\\ "\
611 "{{~~ / \\ "\
612 "{{~~| | "\
613 "{{~~| S T O P | "\
614 "{{~~| | "\
615 "{{~~ \\ / "\
616 "{{~~ \\-----/ "\
617 "Copyright(C) 200"\
618 "1 Apple Computer"\
619 ", Inc.----------"\
620 "----------------"\
621 "----------------"\
622 "----------------"\
623 "----------------"\
624 "----------------"\
625 "---------------";
626 size_t len;
627 int length;
628 int rsrclength;
629 int rsrcoffset;
630 FILE *file;
631 unsigned int sum = 0;
632 unsigned int rsrcsum = 0;
633 unsigned char *outbuf;
634 int bufsize;
635 int i;
637 file = fopen(iname, "rb");
638 if (!file) {
639 perror(iname);
640 return -1;
642 fseek(file,0,SEEK_END);
643 length = ftell(file);
645 fseek(file,0,SEEK_SET);
647 bufsize=(length+0x4600);
648 if (fake_rsrc) {
649 bufsize = (bufsize + 0x400) & ~0x200;
652 outbuf = malloc(bufsize);
654 if ( !outbuf ) {
655 printf("out of memory!\n");
656 return -1;
659 len = fread(outbuf+0x4600, 1, length, file);
660 if(len < length) {
661 perror(iname);
662 return -2;
664 fclose(file);
666 /* Calculate checksum for later use in header */
667 for(i = 0x4600; i < 0x4600+length;i++)
668 sum += outbuf[i];
670 /* Clear the header area to zero */
671 memset(outbuf, 0, 0x4600);
673 /* APPLE STOP SIGN */
674 strcpy((char *)outbuf, apple_stop_sign);
676 /* VOLUME HEADER */
677 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
678 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
679 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
680 short2le(fw_ver, &outbuf[0x10a]);
682 /* Firmware Directory - "osos" entry */
683 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
684 int2le(0, &outbuf[0x4208]); /* id */
685 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
686 int2le(length, &outbuf[0x4210]); /* Length of firmware */
687 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
688 int2le(0, &outbuf[0x4218]); /* Entry Offset */
689 int2le(sum, &outbuf[0x421c]); /* Checksum */
690 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
691 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
693 /* "rsrc" entry (if applicable) */
694 if (fake_rsrc) {
695 rsrcoffset=(length+0x4600+0x200) & ~0x200;
696 rsrclength=0x200;
697 rsrcsum=0;
699 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
700 int2le(0, &outbuf[0x4230]); /* id */
701 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
702 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
703 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
704 int2le(0, &outbuf[0x4240]); /* Entry Offset */
705 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
706 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
707 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
710 file = fopen(oname, "wb");
711 if (!file) {
712 perror(oname);
713 return -3;
716 len = fwrite(outbuf, 1, length+0x4600, file);
717 if(len < length) {
718 perror(oname);
719 return -4;
722 fclose(file);
724 return 0;