Introduce Rockbox Utility to the manual as automated installation option. Only rather...
[Rockbox.git] / tools / scramble.c
blob8534d418324be7a5541b2e6f6603b725b78d6b00
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"
29 int iaudio_encode(char *iname, char *oname, char *idstring);
30 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc);
32 enum
34 ARCHOS_PLAYER, /* and V1 recorder */
35 ARCHOS_V2RECORDER,
36 ARCHOS_FMRECORDER,
37 ARCHOS_ONDIO_SP,
38 ARCHOS_ONDIO_FM
41 int size_limit[] =
43 0x32000, /* ARCHOS_PLAYER */
44 0x64000, /* ARCHOS_V2RECORDER */
45 0x64000, /* ARCHOS_FMRECORDER */
46 0x64000, /* ARCHOS_ONDIO_SP */
47 0x64000 /* ARCHOS_ONDIO_FM */
50 void short2le(unsigned short val, unsigned char* addr)
52 addr[0] = val & 0xFF;
53 addr[1] = (val >> 8) & 0xff;
56 unsigned int le2int(unsigned char* buf)
58 unsigned int res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
60 return res;
63 void int2le(unsigned int val, unsigned char* addr)
65 addr[0] = val & 0xFF;
66 addr[1] = (val >> 8) & 0xff;
67 addr[2] = (val >> 16) & 0xff;
68 addr[3] = (val >> 24) & 0xff;
71 void int2be(unsigned int val, unsigned char* addr)
73 addr[0] = (val >> 24) & 0xff;
74 addr[1] = (val >> 16) & 0xff;
75 addr[2] = (val >> 8) & 0xff;
76 addr[3] = val & 0xFF;
79 void usage(void)
81 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
82 printf("options:\n"
83 "\t-fm Archos FM recorder format\n"
84 "\t-v2 Archos V2 recorder format\n"
85 "\t-ofm Archos Ondio FM recorder format\n"
86 "\t-osp Archos Ondio SP format\n"
87 "\t-neo SSI Neo format\n"
88 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
89 "\t-iriver iRiver format\n"
90 "\t-iaudiox5 iAudio X5 format\n"
91 "\t-iaudiox5v iAudio X5V format\n"
92 "\t-iaudiom5 iAudio M5 format\n"
93 "\t-ipod3g ipod firmware partition format (3rd Gen)\n"
94 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
95 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
96 "\t-gigabeat Toshiba Gigabeat F/X format\n"
97 "\t-gigabeats Toshiba Gigabeat S format\n"
98 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
99 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
100 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
101 "\t All mi4 options take two optional arguments:\n"
102 "\t -model=XXXX where XXXX is the model id string\n"
103 "\t -type=XXXX where XXXX is a string indicating the \n"
104 "\t type of binary, eg. RBOS, RBBL\n"
105 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
106 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
107 "\t ip3g, ip4g, mini, iax5, h10, h10_5gb, tpj2,\n"
108 "\t c200, e200)\n"
109 "\nNo option results in Archos standard player/recorder format.\n");
111 exit(1);
114 int main (int argc, char** argv)
116 unsigned long length,i,slen;
117 unsigned char *inbuf,*outbuf;
118 unsigned short crc=0;
119 unsigned long chksum=0; /* 32 bit checksum */
120 unsigned char header[24];
121 char *iname = argv[1];
122 char *oname = argv[2];
123 char *xorstring;
124 int headerlen = 6;
125 FILE* file;
126 int version;
127 unsigned long modelnum;
128 char modelname[5];
129 int model_id;
130 enum { none, scramble, xor, add } method = scramble;
132 model_id = ARCHOS_PLAYER;
134 if (argc < 3) {
135 usage();
138 if(!strcmp(argv[1], "-fm")) {
139 headerlen = 24;
140 iname = argv[2];
141 oname = argv[3];
142 version = 4;
143 model_id = ARCHOS_FMRECORDER;
146 else if(!strcmp(argv[1], "-v2")) {
147 headerlen = 24;
148 iname = argv[2];
149 oname = argv[3];
150 version = 2;
151 model_id = ARCHOS_V2RECORDER;
154 else if(!strcmp(argv[1], "-ofm")) {
155 headerlen = 24;
156 iname = argv[2];
157 oname = argv[3];
158 version = 8;
159 model_id = ARCHOS_ONDIO_FM;
162 else if(!strcmp(argv[1], "-osp")) {
163 headerlen = 24;
164 iname = argv[2];
165 oname = argv[3];
166 version = 16;
167 model_id = ARCHOS_ONDIO_SP;
170 else if(!strcmp(argv[1], "-neo")) {
171 headerlen = 17;
172 iname = argv[2];
173 oname = argv[3];
174 method = none;
176 else if(!strncmp(argv[1], "-mm=", 4)) {
177 headerlen = 16;
178 iname = argv[2];
179 oname = argv[3];
180 method = xor;
181 version = argv[1][4];
182 if (argc > 4)
183 xorstring = argv[4];
184 else {
185 printf("Multimedia needs an xor string\n");
186 return -1;
189 else if(!strncmp(argv[1], "-add=", 5)) {
190 iname = argv[2];
191 oname = argv[3];
192 method = add;
194 if(!strcmp(&argv[1][5], "h120"))
195 modelnum = 0;
196 else if(!strcmp(&argv[1][5], "h140"))
197 modelnum = 0; /* the same as the h120 */
198 else if(!strcmp(&argv[1][5], "h100"))
199 modelnum = 1;
200 else if(!strcmp(&argv[1][5], "h300"))
201 modelnum = 2;
202 else if(!strcmp(&argv[1][5], "ipco"))
203 modelnum = 3;
204 else if(!strcmp(&argv[1][5], "nano"))
205 modelnum = 4;
206 else if(!strcmp(&argv[1][5], "ipvd"))
207 modelnum = 5;
208 else if(!strcmp(&argv[1][5], "fp7x"))
209 modelnum = 6;
210 else if(!strcmp(&argv[1][5], "ip3g"))
211 modelnum = 7;
212 else if(!strcmp(&argv[1][5], "ip4g"))
213 modelnum = 8;
214 else if(!strcmp(&argv[1][5], "mini"))
215 modelnum = 9;
216 else if(!strcmp(&argv[1][5], "iax5"))
217 modelnum = 10;
218 else if(!strcmp(&argv[1][5], "mn2g"))
219 modelnum = 11;
220 else if(!strcmp(&argv[1][5], "h10"))
221 modelnum = 13;
222 else if(!strcmp(&argv[1][5], "h10_5gb"))
223 modelnum = 14;
224 else if(!strcmp(&argv[1][5], "tpj2"))
225 modelnum = 15;
226 else if(!strcmp(&argv[1][5], "e200"))
227 modelnum = 16;
228 else if(!strcmp(&argv[1][5], "iam5"))
229 modelnum = 17;
230 else if(!strcmp(&argv[1][5], "giga"))
231 modelnum = 18;
232 else if(!strcmp(&argv[1][5], "1g2g"))
233 modelnum = 19;
234 else if(!strcmp(&argv[1][5], "c200"))
235 modelnum = 20;
236 else if(!strcmp(&argv[1][5], "gigs"))
237 modelnum = 21;
238 else {
239 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
240 return 2;
242 /* we store a 4-letter model name too, for humans */
243 strcpy(modelname, &argv[1][5]);
244 chksum = modelnum; /* start checksum calcs with this */
247 else if(!strcmp(argv[1], "-iriver")) {
248 /* iRiver code dealt with in the iriver.c code */
249 iname = argv[2];
250 oname = argv[3];
251 iriver_encode(iname, oname, FALSE);
252 return 0;
254 else if(!strcmp(argv[1], "-gigabeat")) {
255 /* iRiver code dealt with in the iriver.c code */
256 iname = argv[2];
257 oname = argv[3];
258 gigabeat_code(iname, oname);
259 return 0;
261 else if(!strcmp(argv[1], "-gigabeats")) {
262 iname = argv[2];
263 oname = argv[3];
264 gigabeat_s_code(iname, oname);
265 return 0;
267 else if(!strcmp(argv[1], "-iaudiox5")) {
268 iname = argv[2];
269 oname = argv[3];
270 return iaudio_encode(iname, oname, "COWON_X5_FW");
272 else if(!strcmp(argv[1], "-iaudiox5v")) {
273 iname = argv[2];
274 oname = argv[3];
275 return iaudio_encode(iname, oname, "COWON_X5V_FW");
277 else if(!strcmp(argv[1], "-iaudiom5")) {
278 iname = argv[2];
279 oname = argv[3];
280 return iaudio_encode(iname, oname, "COWON_M5_FW");
282 else if(!strcmp(argv[1], "-ipod3g")) {
283 iname = argv[2];
284 oname = argv[3];
285 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
287 else if(!strcmp(argv[1], "-ipod4g")) {
288 iname = argv[2];
289 oname = argv[3];
290 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
292 else if(!strcmp(argv[1], "-ipod5g")) {
293 iname = argv[2];
294 oname = argv[3];
295 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
297 else if(!strncmp(argv[1], "-mi4", 4)) {
298 int mi4magic;
299 int version;
300 char model[4] = "";
301 char type[4] = "";
303 if(!strcmp(&argv[1][4], "v2")) {
304 mi4magic = MI4_MAGIC_DEFAULT;
305 version = 0x00010201;
307 else if(!strcmp(&argv[1][4], "v3")) {
308 mi4magic = MI4_MAGIC_DEFAULT;
309 version = 0x00010301;
311 else if(!strcmp(&argv[1][4], "r")) {
312 mi4magic = MI4_MAGIC_R;
313 version = 0x00010301;
315 else {
316 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
317 return -1;
320 iname = argv[2];
321 oname = argv[3];
323 if(!strncmp(argv[2], "-model=", 7)) {
324 iname = argv[3];
325 oname = argv[4];
326 strncpy(model, &argv[2][7], 4);
328 if(!strncmp(argv[3], "-type=", 6)) {
329 iname = argv[4];
330 oname = argv[5];
331 strncpy(type, &argv[3][6], 4);
335 return mi4_encode(iname, oname, version, mi4magic, model, type);
338 /* open file */
339 file = fopen(iname,"rb");
340 if (!file) {
341 perror(iname);
342 return -1;
344 fseek(file,0,SEEK_END);
345 length = ftell(file);
346 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
348 if ((method == scramble) &&
349 ((length + headerlen) >= size_limit[model_id])) {
350 printf("error: firmware image is %d bytes while max size is %d!\n",
351 length + headerlen,
352 size_limit[model_id]);
353 fclose(file);
354 return -1;
357 fseek(file,0,SEEK_SET);
358 inbuf = malloc(length);
359 if (method == xor)
360 outbuf = malloc(length*2);
361 else if(method == add)
362 outbuf = malloc(length + 8);
363 else
364 outbuf = malloc(length);
365 if ( !inbuf || !outbuf ) {
366 printf("out of memory!\n");
367 return -1;
369 if(length> 4) {
370 /* zero-fill the last 4 bytes to make sure there's no rubbish there
371 when we write the size-aligned file later */
372 memset(outbuf+length-4, 0, 4);
375 /* read file */
376 i=fread(inbuf,1,length,file);
377 if ( !i ) {
378 perror(iname);
379 return -1;
381 fclose(file);
383 switch (method)
385 case add:
386 for (i = 0; i < length; i++) {
387 /* add 8 unsigned bits but keep a 32 bit sum */
388 chksum += inbuf[i];
390 break;
391 case scramble:
392 slen = length/4;
393 for (i = 0; i < length; i++) {
394 unsigned long addr = (i >> 2) + ((i % 4) * slen);
395 unsigned char data = inbuf[i];
396 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
397 outbuf[addr] = data;
399 break;
401 case xor:
402 /* "compress" */
403 slen = 0;
404 for (i=0; i<length; i++) {
405 if (!(i&7))
406 outbuf[slen++] = 0xff; /* all data is uncompressed */
407 outbuf[slen++] = inbuf[i];
409 break;
412 if(method != add) {
413 /* calculate checksum */
414 for (i=0;i<length;i++)
415 crc += inbuf[i];
418 memset(header, 0, sizeof header);
419 switch (method)
421 case add:
423 int2be(chksum, header); /* checksum, big-endian */
424 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
425 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
426 headerlen = 8;
428 break;
429 case scramble:
430 if (headerlen == 6) {
431 int2be(length, header);
432 header[4] = (crc >> 8) & 0xff;
433 header[5] = crc & 0xff;
435 else {
436 header[0] =
437 header[1] =
438 header[2] =
439 header[3] = 0xff; /* ??? */
441 header[6] = (crc >> 8) & 0xff;
442 header[7] = crc & 0xff;
444 header[11] = version;
446 header[15] = headerlen; /* really? */
448 int2be(length, &header[20]);
450 break;
452 case xor:
454 int xorlen = strlen(xorstring);
456 /* xor data */
457 for (i=0; i<slen; i++)
458 outbuf[i] ^= xorstring[i & (xorlen-1)];
460 /* calculate checksum */
461 for (i=0; i<slen; i++)
462 crc += outbuf[i];
464 header[0] = header[2] = 'Z';
465 header[1] = header[3] = version;
466 int2le(length, &header[4]);
467 int2le(slen, &header[8]);
468 int2le(crc, &header[12]);
469 length = slen;
470 break;
473 #define MY_FIRMWARE_TYPE "Rockbox"
474 #define MY_HEADER_VERSION 1
475 default:
476 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
477 header[9]='\0'; /*shouldn't have to, but to be SURE */
478 header[10]=MY_HEADER_VERSION&0xFF;
479 header[11]=(crc>>8)&0xFF;
480 header[12]=crc&0xFF;
481 int2be(sizeof(header), &header[12]);
482 break;
485 /* write file */
486 file = fopen(oname,"wb");
487 if ( !file ) {
488 perror(oname);
489 return -1;
491 if ( !fwrite(header,headerlen,1,file) ) {
492 perror(oname);
493 return -1;
495 if ( !fwrite(outbuf,length,1,file) ) {
496 perror(oname);
497 return -1;
499 fclose(file);
501 free(inbuf);
502 free(outbuf);
504 return 0;
507 int iaudio_encode(char *iname, char *oname, char *idstring)
509 size_t len;
510 int length;
511 FILE *file;
512 unsigned char *outbuf;
513 int i;
514 unsigned char sum = 0;
516 file = fopen(iname, "rb");
517 if (!file) {
518 perror(iname);
519 return -1;
521 fseek(file,0,SEEK_END);
522 length = ftell(file);
524 fseek(file,0,SEEK_SET);
525 outbuf = malloc(length+0x1030);
527 if ( !outbuf ) {
528 printf("out of memory!\n");
529 return -1;
532 len = fread(outbuf+0x1030, 1, length, file);
533 if(len < length) {
534 perror(iname);
535 return -2;
538 memset(outbuf, 0, 0x1030);
539 strcpy((char *)outbuf, idstring);
541 for(i = 0; i < length;i++)
542 sum += outbuf[0x1030 + i];
544 int2be(length, &outbuf[0x1024]);
545 outbuf[0x102b] = sum;
547 fclose(file);
549 file = fopen(oname, "wb");
550 if (!file) {
551 perror(oname);
552 return -3;
555 len = fwrite(outbuf, 1, length+0x1030, file);
556 if(len < length) {
557 perror(oname);
558 return -4;
561 fclose(file);
565 /* Create an ipod firmware partition image
567 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
569 This function doesn't yet handle the Broadcom resource image for the 5g,
570 so the resulting images won't be usable.
572 This has also only been tested on an ipod Photo
575 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
577 static const char *apple_stop_sign = "{{~~ /-----\\ "\
578 "{{~~ / \\ "\
579 "{{~~| | "\
580 "{{~~| S T O P | "\
581 "{{~~| | "\
582 "{{~~ \\ / "\
583 "{{~~ \\-----/ "\
584 "Copyright(C) 200"\
585 "1 Apple Computer"\
586 ", Inc.----------"\
587 "----------------"\
588 "----------------"\
589 "----------------"\
590 "----------------"\
591 "----------------"\
592 "---------------";
593 size_t len;
594 int length;
595 int rsrclength;
596 int rsrcoffset;
597 FILE *file;
598 unsigned int sum = 0;
599 unsigned int rsrcsum = 0;
600 unsigned char *outbuf;
601 int bufsize;
602 int i;
604 file = fopen(iname, "rb");
605 if (!file) {
606 perror(iname);
607 return -1;
609 fseek(file,0,SEEK_END);
610 length = ftell(file);
612 fseek(file,0,SEEK_SET);
614 bufsize=(length+0x4600);
615 if (fake_rsrc) {
616 bufsize = (bufsize + 0x400) & ~0x200;
619 outbuf = malloc(bufsize);
621 if ( !outbuf ) {
622 printf("out of memory!\n");
623 return -1;
626 len = fread(outbuf+0x4600, 1, length, file);
627 if(len < length) {
628 perror(iname);
629 return -2;
631 fclose(file);
633 /* Calculate checksum for later use in header */
634 for(i = 0x4600; i < 0x4600+length;i++)
635 sum += outbuf[i];
637 /* Clear the header area to zero */
638 memset(outbuf, 0, 0x4600);
640 /* APPLE STOP SIGN */
641 strcpy((char *)outbuf, apple_stop_sign);
643 /* VOLUME HEADER */
644 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
645 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
646 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
647 short2le(fw_ver, &outbuf[0x10a]);
649 /* Firmware Directory - "osos" entry */
650 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
651 int2le(0, &outbuf[0x4208]); /* id */
652 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
653 int2le(length, &outbuf[0x4210]); /* Length of firmware */
654 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
655 int2le(0, &outbuf[0x4218]); /* Entry Offset */
656 int2le(sum, &outbuf[0x421c]); /* Checksum */
657 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
658 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
660 /* "rsrc" entry (if applicable) */
661 if (fake_rsrc) {
662 rsrcoffset=(length+0x4600+0x200) & ~0x200;
663 rsrclength=0x200;
664 rsrcsum=0;
666 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
667 int2le(0, &outbuf[0x4230]); /* id */
668 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
669 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
670 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
671 int2le(0, &outbuf[0x4240]); /* Entry Offset */
672 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
673 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
674 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
677 file = fopen(oname, "wb");
678 if (!file) {
679 perror(oname);
680 return -3;
683 len = fwrite(outbuf, 1, length+0x4600, file);
684 if(len < length) {
685 perror(oname);
686 return -4;
689 fclose(file);
691 return 0;