1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
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 ****************************************************************************/
26 #include "gigabeats.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
);
34 ARCHOS_PLAYER
, /* and V1 recorder */
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
)
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];
63 void int2le(unsigned int val
, unsigned char* addr
)
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;
81 printf("usage: scramble [options] <input file> <output file> [xor string]\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"
109 "\nNo option results in Archos standard player/recorder format.\n");
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];
127 unsigned long modelnum
;
130 enum { none
, scramble
, xor, add
} method
= scramble
;
132 model_id
= ARCHOS_PLAYER
;
138 if(!strcmp(argv
[1], "-fm")) {
143 model_id
= ARCHOS_FMRECORDER
;
146 else if(!strcmp(argv
[1], "-v2")) {
151 model_id
= ARCHOS_V2RECORDER
;
154 else if(!strcmp(argv
[1], "-ofm")) {
159 model_id
= ARCHOS_ONDIO_FM
;
162 else if(!strcmp(argv
[1], "-osp")) {
167 model_id
= ARCHOS_ONDIO_SP
;
170 else if(!strcmp(argv
[1], "-neo")) {
176 else if(!strncmp(argv
[1], "-mm=", 4)) {
181 version
= argv
[1][4];
185 printf("Multimedia needs an xor string\n");
189 else if(!strncmp(argv
[1], "-add=", 5)) {
194 if(!strcmp(&argv
[1][5], "h120"))
196 else if(!strcmp(&argv
[1][5], "h140"))
197 modelnum
= 0; /* the same as the h120 */
198 else if(!strcmp(&argv
[1][5], "h100"))
200 else if(!strcmp(&argv
[1][5], "h300"))
202 else if(!strcmp(&argv
[1][5], "ipco"))
204 else if(!strcmp(&argv
[1][5], "nano"))
206 else if(!strcmp(&argv
[1][5], "ipvd"))
208 else if(!strcmp(&argv
[1][5], "fp7x"))
210 else if(!strcmp(&argv
[1][5], "ip3g"))
212 else if(!strcmp(&argv
[1][5], "ip4g"))
214 else if(!strcmp(&argv
[1][5], "mini"))
216 else if(!strcmp(&argv
[1][5], "iax5"))
218 else if(!strcmp(&argv
[1][5], "mn2g"))
220 else if(!strcmp(&argv
[1][5], "h10"))
222 else if(!strcmp(&argv
[1][5], "h10_5gb"))
224 else if(!strcmp(&argv
[1][5], "tpj2"))
226 else if(!strcmp(&argv
[1][5], "e200"))
228 else if(!strcmp(&argv
[1][5], "iam5"))
230 else if(!strcmp(&argv
[1][5], "giga"))
232 else if(!strcmp(&argv
[1][5], "1g2g"))
234 else if(!strcmp(&argv
[1][5], "c200"))
236 else if(!strcmp(&argv
[1][5], "gigs"))
239 fprintf(stderr
, "unsupported model: %s\n", &argv
[1][5]);
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 */
251 iriver_encode(iname
, oname
, FALSE
);
254 else if(!strcmp(argv
[1], "-gigabeat")) {
255 /* iRiver code dealt with in the iriver.c code */
258 gigabeat_code(iname
, oname
);
261 else if(!strcmp(argv
[1], "-gigabeats")) {
264 gigabeat_s_code(iname
, oname
);
267 else if(!strcmp(argv
[1], "-iaudiox5")) {
270 return iaudio_encode(iname
, oname
, "COWON_X5_FW");
272 else if(!strcmp(argv
[1], "-iaudiox5v")) {
275 return iaudio_encode(iname
, oname
, "COWON_X5V_FW");
277 else if(!strcmp(argv
[1], "-iaudiom5")) {
280 return iaudio_encode(iname
, oname
, "COWON_M5_FW");
282 else if(!strcmp(argv
[1], "-ipod3g")) {
285 return ipod_encode(iname
, oname
, 2, false); /* Firmware image v2 */
287 else if(!strcmp(argv
[1], "-ipod4g")) {
290 return ipod_encode(iname
, oname
, 3, false); /* Firmware image v3 */
292 else if(!strcmp(argv
[1], "-ipod5g")) {
295 return ipod_encode(iname
, oname
, 3, true); /* Firmware image v3 */
297 else if(!strncmp(argv
[1], "-mi4", 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;
316 printf( "Invalid mi4 version: %s\n", &argv
[1][4]);
323 if(!strncmp(argv
[2], "-model=", 7)) {
326 strncpy(model
, &argv
[2][7], 4);
328 if(!strncmp(argv
[3], "-type=", 6)) {
331 strncpy(type
, &argv
[3][6], 4);
335 return mi4_encode(iname
, oname
, version
, mi4magic
, model
, type
);
339 file
= fopen(iname
,"rb");
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",
352 size_limit
[model_id
]);
357 fseek(file
,0,SEEK_SET
);
358 inbuf
= malloc(length
);
360 outbuf
= malloc(length
*2);
361 else if(method
== add
)
362 outbuf
= malloc(length
+ 8);
364 outbuf
= malloc(length
);
365 if ( !inbuf
|| !outbuf
) {
366 printf("out of memory!\n");
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);
376 i
=fread(inbuf
,1,length
,file
);
386 for (i
= 0; i
< length
; i
++) {
387 /* add 8 unsigned bits but keep a 32 bit sum */
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 */
404 for (i
=0; i
<length
; i
++) {
406 outbuf
[slen
++] = 0xff; /* all data is uncompressed */
407 outbuf
[slen
++] = inbuf
[i
];
413 /* calculate checksum */
414 for (i
=0;i
<length
;i
++)
418 memset(header
, 0, sizeof header
);
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*/
430 if (headerlen
== 6) {
431 int2be(length
, header
);
432 header
[4] = (crc
>> 8) & 0xff;
433 header
[5] = crc
& 0xff;
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]);
454 int xorlen
= strlen(xorstring
);
457 for (i
=0; i
<slen
; i
++)
458 outbuf
[i
] ^= xorstring
[i
& (xorlen
-1)];
460 /* calculate checksum */
461 for (i
=0; i
<slen
; 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]);
473 #define MY_FIRMWARE_TYPE "Rockbox"
474 #define MY_HEADER_VERSION 1
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;
481 int2be(sizeof(header
), &header
[12]);
486 file
= fopen(oname
,"wb");
491 if ( !fwrite(header
,headerlen
,1,file
) ) {
495 if ( !fwrite(outbuf
,length
,1,file
) ) {
507 int iaudio_encode(char *iname
, char *oname
, char *idstring
)
512 unsigned char *outbuf
;
514 unsigned char sum
= 0;
516 file
= fopen(iname
, "rb");
521 fseek(file
,0,SEEK_END
);
522 length
= ftell(file
);
524 fseek(file
,0,SEEK_SET
);
525 outbuf
= malloc(length
+0x1030);
528 printf("out of memory!\n");
532 len
= fread(outbuf
+0x1030, 1, length
, file
);
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
;
549 file
= fopen(oname
, "wb");
555 len
= fwrite(outbuf
, 1, length
+0x1030, 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
= "{{~~ /-----\\ "\
598 unsigned int sum
= 0;
599 unsigned int rsrcsum
= 0;
600 unsigned char *outbuf
;
604 file
= fopen(iname
, "rb");
609 fseek(file
,0,SEEK_END
);
610 length
= ftell(file
);
612 fseek(file
,0,SEEK_SET
);
614 bufsize
=(length
+0x4600);
616 bufsize
= (bufsize
+ 0x400) & ~0x200;
619 outbuf
= malloc(bufsize
);
622 printf("out of memory!\n");
626 len
= fread(outbuf
+0x4600, 1, length
, file
);
633 /* Calculate checksum for later use in header */
634 for(i
= 0x4600; i
< 0x4600+length
;i
++)
637 /* Clear the header area to zero */
638 memset(outbuf
, 0, 0x4600);
640 /* APPLE STOP SIGN */
641 strcpy((char *)outbuf
, apple_stop_sign
);
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) */
662 rsrcoffset
=(length
+0x4600+0x200) & ~0x200;
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");
683 len
= fwrite(outbuf
, 1, length
+0x4600, file
);