Code police, no functional changes (yet)
[maemo-rb.git] / tools / scramble.c
blobba0eda338af8992d4090399fdd63ba3d655808b0
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, 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 {
257 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
258 return 2;
260 /* we store a 4-letter model name too, for humans */
261 strcpy(modelname, &argv[1][5]);
262 chksum = modelnum; /* start checksum calcs with this */
265 else if(!strcmp(argv[1], "-iriver")) {
266 /* iRiver code dealt with in the iriver.c code */
267 iname = argv[2];
268 oname = argv[3];
269 iriver_encode(iname, oname, FALSE);
270 return 0;
272 else if(!strcmp(argv[1], "-gigabeat")) {
273 /* iRiver code dealt with in the iriver.c code */
274 iname = argv[2];
275 oname = argv[3];
276 gigabeat_code(iname, oname);
277 return 0;
279 else if(!strcmp(argv[1], "-gigabeats")) {
280 iname = argv[2];
281 oname = argv[3];
282 gigabeat_s_code(iname, oname);
283 return 0;
285 else if(!strcmp(argv[1], "-iaudiox5")) {
286 iname = argv[2];
287 oname = argv[3];
288 return iaudio_encode(iname, oname, "COWON_X5_FW");
290 else if(!strcmp(argv[1], "-iaudiox5v")) {
291 iname = argv[2];
292 oname = argv[3];
293 return iaudio_encode(iname, oname, "COWON_X5V_FW");
295 else if(!strcmp(argv[1], "-iaudiom5")) {
296 iname = argv[2];
297 oname = argv[3];
298 return iaudio_encode(iname, oname, "COWON_M5_FW");
300 else if(!strcmp(argv[1], "-ipod3g")) {
301 iname = argv[2];
302 oname = argv[3];
303 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
305 else if(!strcmp(argv[1], "-ipod4g")) {
306 iname = argv[2];
307 oname = argv[3];
308 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
310 else if(!strcmp(argv[1], "-ipod5g")) {
311 iname = argv[2];
312 oname = argv[3];
313 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
315 else if(!strncmp(argv[1], "-mi4", 4)) {
316 int mi4magic;
317 int version;
318 char model[4] = "";
319 char type[4] = "";
321 if(!strcmp(&argv[1][4], "v2")) {
322 mi4magic = MI4_MAGIC_DEFAULT;
323 version = 0x00010201;
325 else if(!strcmp(&argv[1][4], "v3")) {
326 mi4magic = MI4_MAGIC_DEFAULT;
327 version = 0x00010301;
329 else if(!strcmp(&argv[1][4], "r")) {
330 mi4magic = MI4_MAGIC_R;
331 version = 0x00010301;
333 else {
334 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
335 return -1;
338 iname = argv[2];
339 oname = argv[3];
341 if(!strncmp(argv[2], "-model=", 7)) {
342 iname = argv[3];
343 oname = argv[4];
344 strncpy(model, &argv[2][7], 4);
346 if(!strncmp(argv[3], "-type=", 6)) {
347 iname = argv[4];
348 oname = argv[5];
349 strncpy(type, &argv[3][6], 4);
353 return mi4_encode(iname, oname, version, mi4magic, model, type);
356 /* open file */
357 file = fopen(iname,"rb");
358 if (!file) {
359 perror(iname);
360 return -1;
362 fseek(file,0,SEEK_END);
363 length = ftell(file);
364 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
366 if ((method == scramble) &&
367 ((length + headerlen) >= size_limit[model_id])) {
368 printf("error: firmware image is %d bytes while max size is %d!\n",
369 length + headerlen,
370 size_limit[model_id]);
371 fclose(file);
372 return -1;
375 fseek(file,0,SEEK_SET);
376 inbuf = malloc(length);
377 if (method == xor)
378 outbuf = malloc(length*2);
379 else if(method == add)
380 outbuf = malloc(length + 8);
381 else
382 outbuf = malloc(length);
383 if ( !inbuf || !outbuf ) {
384 printf("out of memory!\n");
385 return -1;
387 if(length> 4) {
388 /* zero-fill the last 4 bytes to make sure there's no rubbish there
389 when we write the size-aligned file later */
390 memset(outbuf+length-4, 0, 4);
393 /* read file */
394 i=fread(inbuf,1,length,file);
395 if ( !i ) {
396 perror(iname);
397 return -1;
399 fclose(file);
401 switch (method)
403 case add:
404 for (i = 0; i < length; i++) {
405 /* add 8 unsigned bits but keep a 32 bit sum */
406 chksum += inbuf[i];
408 break;
409 case scramble:
410 slen = length/4;
411 for (i = 0; i < length; i++) {
412 unsigned long addr = (i >> 2) + ((i % 4) * slen);
413 unsigned char data = inbuf[i];
414 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
415 outbuf[addr] = data;
417 break;
419 case xor:
420 /* "compress" */
421 slen = 0;
422 for (i=0; i<length; i++) {
423 if (!(i&7))
424 outbuf[slen++] = 0xff; /* all data is uncompressed */
425 outbuf[slen++] = inbuf[i];
427 break;
430 if((method == none) || (method == scramble) || (method == xor)) {
431 /* calculate checksum */
432 for (i=0;i<length;i++)
433 crc += inbuf[i];
436 memset(header, 0, sizeof header);
437 switch (method)
439 case add:
441 int2be(chksum, header); /* checksum, big-endian */
442 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
443 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
444 headerlen = 8;
446 break;
448 case tcc_sum:
449 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
450 telechips_encode_sum(outbuf, length);
451 break;
453 case tcc_crc:
454 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
455 telechips_encode_crc(outbuf, length);
456 break;
458 case scramble:
459 if (headerlen == 6) {
460 int2be(length, header);
461 header[4] = (crc >> 8) & 0xff;
462 header[5] = crc & 0xff;
464 else {
465 header[0] =
466 header[1] =
467 header[2] =
468 header[3] = 0xff; /* ??? */
470 header[6] = (crc >> 8) & 0xff;
471 header[7] = crc & 0xff;
473 header[11] = version;
475 header[15] = headerlen; /* really? */
477 int2be(length, &header[20]);
479 break;
481 case xor:
483 int xorlen = strlen(xorstring);
485 /* xor data */
486 for (i=0; i<slen; i++)
487 outbuf[i] ^= xorstring[i & (xorlen-1)];
489 /* calculate checksum */
490 for (i=0; i<slen; i++)
491 crc += outbuf[i];
493 header[0] = header[2] = 'Z';
494 header[1] = header[3] = version;
495 int2le(length, &header[4]);
496 int2le(slen, &header[8]);
497 int2le(crc, &header[12]);
498 length = slen;
499 break;
502 #define MY_FIRMWARE_TYPE "Rockbox"
503 #define MY_HEADER_VERSION 1
504 default:
505 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
506 header[9]='\0'; /*shouldn't have to, but to be SURE */
507 header[10]=MY_HEADER_VERSION&0xFF;
508 header[11]=(crc>>8)&0xFF;
509 header[12]=crc&0xFF;
510 int2be(sizeof(header), &header[12]);
511 break;
514 /* write file */
515 file = fopen(oname,"wb");
516 if ( !file ) {
517 perror(oname);
518 return -1;
520 if (headerlen > 0) {
521 if ( !fwrite(header,headerlen,1,file) ) {
522 perror(oname);
523 return -1;
526 if ( !fwrite(outbuf,length,1,file) ) {
527 perror(oname);
528 return -1;
530 fclose(file);
532 free(inbuf);
533 free(outbuf);
535 return 0;
538 int iaudio_encode(char *iname, char *oname, char *idstring)
540 size_t len;
541 int length;
542 FILE *file;
543 unsigned char *outbuf;
544 int i;
545 unsigned char sum = 0;
547 file = fopen(iname, "rb");
548 if (!file) {
549 perror(iname);
550 return -1;
552 fseek(file,0,SEEK_END);
553 length = ftell(file);
555 fseek(file,0,SEEK_SET);
556 outbuf = malloc(length+0x1030);
558 if ( !outbuf ) {
559 printf("out of memory!\n");
560 return -1;
563 len = fread(outbuf+0x1030, 1, length, file);
564 if(len < length) {
565 perror(iname);
566 return -2;
569 memset(outbuf, 0, 0x1030);
570 strcpy((char *)outbuf, idstring);
572 for(i = 0; i < length;i++)
573 sum += outbuf[0x1030 + i];
575 int2be(length, &outbuf[0x1024]);
576 outbuf[0x102b] = sum;
578 fclose(file);
580 file = fopen(oname, "wb");
581 if (!file) {
582 perror(oname);
583 return -3;
586 len = fwrite(outbuf, 1, length+0x1030, file);
587 if(len < length) {
588 perror(oname);
589 return -4;
592 fclose(file);
596 /* Create an ipod firmware partition image
598 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
600 This function doesn't yet handle the Broadcom resource image for the 5g,
601 so the resulting images won't be usable.
603 This has also only been tested on an ipod Photo
606 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
608 static const char *apple_stop_sign = "{{~~ /-----\\ "\
609 "{{~~ / \\ "\
610 "{{~~| | "\
611 "{{~~| S T O P | "\
612 "{{~~| | "\
613 "{{~~ \\ / "\
614 "{{~~ \\-----/ "\
615 "Copyright(C) 200"\
616 "1 Apple Computer"\
617 ", Inc.----------"\
618 "----------------"\
619 "----------------"\
620 "----------------"\
621 "----------------"\
622 "----------------"\
623 "---------------";
624 size_t len;
625 int length;
626 int rsrclength;
627 int rsrcoffset;
628 FILE *file;
629 unsigned int sum = 0;
630 unsigned int rsrcsum = 0;
631 unsigned char *outbuf;
632 int bufsize;
633 int i;
635 file = fopen(iname, "rb");
636 if (!file) {
637 perror(iname);
638 return -1;
640 fseek(file,0,SEEK_END);
641 length = ftell(file);
643 fseek(file,0,SEEK_SET);
645 bufsize=(length+0x4600);
646 if (fake_rsrc) {
647 bufsize = (bufsize + 0x400) & ~0x200;
650 outbuf = malloc(bufsize);
652 if ( !outbuf ) {
653 printf("out of memory!\n");
654 return -1;
657 len = fread(outbuf+0x4600, 1, length, file);
658 if(len < length) {
659 perror(iname);
660 return -2;
662 fclose(file);
664 /* Calculate checksum for later use in header */
665 for(i = 0x4600; i < 0x4600+length;i++)
666 sum += outbuf[i];
668 /* Clear the header area to zero */
669 memset(outbuf, 0, 0x4600);
671 /* APPLE STOP SIGN */
672 strcpy((char *)outbuf, apple_stop_sign);
674 /* VOLUME HEADER */
675 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
676 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
677 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
678 short2le(fw_ver, &outbuf[0x10a]);
680 /* Firmware Directory - "osos" entry */
681 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
682 int2le(0, &outbuf[0x4208]); /* id */
683 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
684 int2le(length, &outbuf[0x4210]); /* Length of firmware */
685 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
686 int2le(0, &outbuf[0x4218]); /* Entry Offset */
687 int2le(sum, &outbuf[0x421c]); /* Checksum */
688 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
689 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
691 /* "rsrc" entry (if applicable) */
692 if (fake_rsrc) {
693 rsrcoffset=(length+0x4600+0x200) & ~0x200;
694 rsrclength=0x200;
695 rsrcsum=0;
697 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
698 int2le(0, &outbuf[0x4230]); /* id */
699 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
700 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
701 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
702 int2le(0, &outbuf[0x4240]); /* Entry Offset */
703 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
704 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
705 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
708 file = fopen(oname, "wb");
709 if (!file) {
710 perror(oname);
711 return -3;
714 len = fwrite(outbuf, 1, length+0x4600, file);
715 if(len < length) {
716 perror(oname);
717 return -4;
720 fclose(file);
722 return 0;