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 ****************************************************************************/
28 int iaudio_encode(char *iname
, char *oname
, char *idstring
);
29 int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
);
33 ARCHOS_PLAYER
, /* and V1 recorder */
42 0x32000, /* ARCHOS_PLAYER */
43 0x64000, /* ARCHOS_V2RECORDER */
44 0x64000, /* ARCHOS_FMRECORDER */
45 0x64000, /* ARCHOS_ONDIO_SP */
46 0x64000 /* ARCHOS_ONDIO_FM */
49 void short2le(unsigned short val
, unsigned char* addr
)
52 addr
[1] = (val
>> 8) & 0xff;
55 unsigned int le2int(unsigned char* buf
)
57 unsigned int res
= (buf
[3] << 24) | (buf
[2] << 16) | (buf
[1] << 8) | buf
[0];
62 void int2le(unsigned int val
, unsigned char* addr
)
65 addr
[1] = (val
>> 8) & 0xff;
66 addr
[2] = (val
>> 16) & 0xff;
67 addr
[3] = (val
>> 24) & 0xff;
70 void int2be(unsigned int val
, unsigned char* addr
)
72 addr
[0] = (val
>> 24) & 0xff;
73 addr
[1] = (val
>> 16) & 0xff;
74 addr
[2] = (val
>> 8) & 0xff;
80 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
82 "\t-fm Archos FM recorder format\n"
83 "\t-v2 Archos V2 recorder format\n"
84 "\t-ofm Archos Ondio FM recorder format\n"
85 "\t-osp Archos Ondio SP format\n"
86 "\t-neo SSI Neo format\n"
87 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
88 "\t-iriver iRiver format\n"
89 "\t-iaudiox5 iAudio X5 format\n"
90 "\t-iaudiox5v iAudio X5V format\n"
91 "\t-iaudiom5 iAudio M5 format\n"
92 "\t-ipod3g ipod firmware partition format (3rd Gen)\n"
93 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
94 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
95 "\t-gigabeat Toshiba Gigabeat format\n"
96 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
97 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
98 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
99 "\t All mi4 options take two optional arguments:\n"
100 "\t -model=XXXX where XXXX is the model id string\n"
101 "\t -type=XXXX where XXXX is a string indicating the \n"
102 "\t type of binary, eg. RBOS, RBBL\n"
103 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
104 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
105 "\t ip3g, ip4g, mini, iax5, h10, h10_5gb, tpj2, e200)\n"
106 "\nNo option results in Archos standard player/recorder format.\n");
111 int main (int argc
, char** argv
)
113 unsigned long length
,i
,slen
;
114 unsigned char *inbuf
,*outbuf
;
115 unsigned short crc
=0;
116 unsigned long chksum
=0; /* 32 bit checksum */
117 unsigned char header
[24];
118 char *iname
= argv
[1];
119 char *oname
= argv
[2];
124 unsigned long modelnum
;
127 enum { none
, scramble
, xor, add
} method
= scramble
;
129 model_id
= ARCHOS_PLAYER
;
135 if(!strcmp(argv
[1], "-fm")) {
140 model_id
= ARCHOS_FMRECORDER
;
143 else if(!strcmp(argv
[1], "-v2")) {
148 model_id
= ARCHOS_V2RECORDER
;
151 else if(!strcmp(argv
[1], "-ofm")) {
156 model_id
= ARCHOS_ONDIO_FM
;
159 else if(!strcmp(argv
[1], "-osp")) {
164 model_id
= ARCHOS_ONDIO_SP
;
167 else if(!strcmp(argv
[1], "-neo")) {
173 else if(!strncmp(argv
[1], "-mm=", 4)) {
178 version
= argv
[1][4];
182 printf("Multimedia needs an xor string\n");
186 else if(!strncmp(argv
[1], "-add=", 5)) {
191 if(!strcmp(&argv
[1][5], "h120"))
193 else if(!strcmp(&argv
[1][5], "h140"))
194 modelnum
= 0; /* the same as the h120 */
195 else if(!strcmp(&argv
[1][5], "h100"))
197 else if(!strcmp(&argv
[1][5], "h300"))
199 else if(!strcmp(&argv
[1][5], "ipco"))
201 else if(!strcmp(&argv
[1][5], "nano"))
203 else if(!strcmp(&argv
[1][5], "ipvd"))
205 else if(!strcmp(&argv
[1][5], "fp7x"))
207 else if(!strcmp(&argv
[1][5], "ip3g"))
209 else if(!strcmp(&argv
[1][5], "ip4g"))
211 else if(!strcmp(&argv
[1][5], "mini"))
213 else if(!strcmp(&argv
[1][5], "iax5"))
215 else if(!strcmp(&argv
[1][5], "mn2g"))
217 else if(!strcmp(&argv
[1][5], "h10"))
219 else if(!strcmp(&argv
[1][5], "h10_5gb"))
221 else if(!strcmp(&argv
[1][5], "tpj2"))
223 else if(!strcmp(&argv
[1][5], "e200"))
225 else if(!strcmp(&argv
[1][5], "iam5"))
227 else if(!strcmp(&argv
[1][5], "giga"))
230 fprintf(stderr
, "unsupported model: %s\n", &argv
[1][5]);
233 /* we store a 4-letter model name too, for humans */
234 strcpy(modelname
, &argv
[1][5]);
235 chksum
= modelnum
; /* start checksum calcs with this */
238 else if(!strcmp(argv
[1], "-iriver")) {
239 /* iRiver code dealt with in the iriver.c code */
242 iriver_encode(iname
, oname
, FALSE
);
245 else if(!strcmp(argv
[1], "-gigabeat")) {
246 /* iRiver code dealt with in the iriver.c code */
249 gigabeat_code(iname
, oname
);
252 else if(!strcmp(argv
[1], "-iaudiox5")) {
255 return iaudio_encode(iname
, oname
, "COWON_X5_FW");
257 else if(!strcmp(argv
[1], "-iaudiox5v")) {
260 return iaudio_encode(iname
, oname
, "COWON_X5V_FW");
262 else if(!strcmp(argv
[1], "-iaudiom5")) {
265 return iaudio_encode(iname
, oname
, "COWON_M5_FW");
267 else if(!strcmp(argv
[1], "-ipod3g")) {
270 return ipod_encode(iname
, oname
, 2, false); /* Firmware image v2 */
272 else if(!strcmp(argv
[1], "-ipod4g")) {
275 return ipod_encode(iname
, oname
, 3, false); /* Firmware image v3 */
277 else if(!strcmp(argv
[1], "-ipod5g")) {
280 return ipod_encode(iname
, oname
, 3, true); /* Firmware image v3 */
282 else if(!strncmp(argv
[1], "-mi4", 4)) {
288 if(!strcmp(&argv
[1][4], "v2")) {
289 mi4magic
= MI4_MAGIC_DEFAULT
;
290 version
= 0x00010201;
292 else if(!strcmp(&argv
[1][4], "v3")) {
293 mi4magic
= MI4_MAGIC_DEFAULT
;
294 version
= 0x00010301;
296 else if(!strcmp(&argv
[1][4], "r")) {
297 mi4magic
= MI4_MAGIC_R
;
298 version
= 0x00010301;
301 printf( "Invalid mi4 version: %s\n", &argv
[1][4]);
308 if(!strncmp(argv
[2], "-model=", 7)) {
311 strncpy(model
, &argv
[2][7], 4);
313 if(!strncmp(argv
[3], "-type=", 6)) {
316 strncpy(type
, &argv
[3][6], 4);
320 return mi4_encode(iname
, oname
, version
, mi4magic
, model
, type
);
324 file
= fopen(iname
,"rb");
329 fseek(file
,0,SEEK_END
);
330 length
= ftell(file
);
331 length
= (length
+ 3) & ~3; /* Round up to nearest 4 byte boundary */
333 if ((method
== scramble
) &&
334 ((length
+ headerlen
) >= size_limit
[model_id
])) {
335 printf("error: firmware image is %d bytes while max size is %d!\n",
337 size_limit
[model_id
]);
342 fseek(file
,0,SEEK_SET
);
343 inbuf
= malloc(length
);
345 outbuf
= malloc(length
*2);
346 else if(method
== add
)
347 outbuf
= malloc(length
+ 8);
349 outbuf
= malloc(length
);
350 if ( !inbuf
|| !outbuf
) {
351 printf("out of memory!\n");
355 /* zero-fill the last 4 bytes to make sure there's no rubbish there
356 when we write the size-aligned file later */
357 memset(outbuf
+length
-4, 0, 4);
361 i
=fread(inbuf
,1,length
,file
);
371 for (i
= 0; i
< length
; i
++) {
372 /* add 8 unsigned bits but keep a 32 bit sum */
378 for (i
= 0; i
< length
; i
++) {
379 unsigned long addr
= (i
>> 2) + ((i
% 4) * slen
);
380 unsigned char data
= inbuf
[i
];
381 data
= ~((data
<< 1) | ((data
>> 7) & 1)); /* poor man's ROL */
389 for (i
=0; i
<length
; i
++) {
391 outbuf
[slen
++] = 0xff; /* all data is uncompressed */
392 outbuf
[slen
++] = inbuf
[i
];
398 /* calculate checksum */
399 for (i
=0;i
<length
;i
++)
403 memset(header
, 0, sizeof header
);
408 int2be(chksum
, header
); /* checksum, big-endian */
409 memcpy(&header
[4], modelname
, 4); /* 4 bytes model name */
410 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
415 if (headerlen
== 6) {
416 int2be(length
, header
);
417 header
[4] = (crc
>> 8) & 0xff;
418 header
[5] = crc
& 0xff;
424 header
[3] = 0xff; /* ??? */
426 header
[6] = (crc
>> 8) & 0xff;
427 header
[7] = crc
& 0xff;
429 header
[11] = version
;
431 header
[15] = headerlen
; /* really? */
433 int2be(length
, &header
[20]);
439 int xorlen
= strlen(xorstring
);
442 for (i
=0; i
<slen
; i
++)
443 outbuf
[i
] ^= xorstring
[i
& (xorlen
-1)];
445 /* calculate checksum */
446 for (i
=0; i
<slen
; i
++)
449 header
[0] = header
[2] = 'Z';
450 header
[1] = header
[3] = version
;
451 int2le(length
, &header
[4]);
452 int2le(slen
, &header
[8]);
453 int2le(crc
, &header
[12]);
458 #define MY_FIRMWARE_TYPE "Rockbox"
459 #define MY_HEADER_VERSION 1
461 strncpy((char *)header
, MY_FIRMWARE_TYPE
,9);
462 header
[9]='\0'; /*shouldn't have to, but to be SURE */
463 header
[10]=MY_HEADER_VERSION
&0xFF;
464 header
[11]=(crc
>>8)&0xFF;
466 int2be(sizeof(header
), &header
[12]);
471 file
= fopen(oname
,"wb");
476 if ( !fwrite(header
,headerlen
,1,file
) ) {
480 if ( !fwrite(outbuf
,length
,1,file
) ) {
492 int iaudio_encode(char *iname
, char *oname
, char *idstring
)
497 unsigned char *outbuf
;
499 unsigned char sum
= 0;
501 file
= fopen(iname
, "rb");
506 fseek(file
,0,SEEK_END
);
507 length
= ftell(file
);
509 fseek(file
,0,SEEK_SET
);
510 outbuf
= malloc(length
+0x1030);
513 printf("out of memory!\n");
517 len
= fread(outbuf
+0x1030, 1, length
, file
);
523 memset(outbuf
, 0, 0x1030);
524 strcpy((char *)outbuf
, idstring
);
526 for(i
= 0; i
< length
;i
++)
527 sum
+= outbuf
[0x1030 + i
];
529 int2be(length
, &outbuf
[0x1024]);
530 outbuf
[0x102b] = sum
;
534 file
= fopen(oname
, "wb");
540 len
= fwrite(outbuf
, 1, length
+0x1030, file
);
550 /* Create an ipod firmware partition image
552 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
554 This function doesn't yet handle the Broadcom resource image for the 5g,
555 so the resulting images won't be usable.
557 This has also only been tested on an ipod Photo
560 int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
)
562 static const char *apple_stop_sign
= "{{~~ /-----\\ "\
583 unsigned int sum
= 0;
584 unsigned int rsrcsum
= 0;
585 unsigned char *outbuf
;
589 file
= fopen(iname
, "rb");
594 fseek(file
,0,SEEK_END
);
595 length
= ftell(file
);
597 fseek(file
,0,SEEK_SET
);
599 bufsize
=(length
+0x4600);
601 bufsize
= (bufsize
+ 0x400) & ~0x200;
604 outbuf
= malloc(bufsize
);
607 printf("out of memory!\n");
611 len
= fread(outbuf
+0x4600, 1, length
, file
);
618 /* Calculate checksum for later use in header */
619 for(i
= 0x4600; i
< 0x4600+length
;i
++)
622 /* Clear the header area to zero */
623 memset(outbuf
, 0, 0x4600);
625 /* APPLE STOP SIGN */
626 strcpy((char *)outbuf
, apple_stop_sign
);
629 memcpy(&outbuf
[0x100],"]ih[",4); /* Magic */
630 int2le(0x4000, &outbuf
[0x104]); /* Firmware offset relative to 0x200 */
631 short2le(0x10c, &outbuf
[0x108]); /* Location of extended header */
632 short2le(fw_ver
, &outbuf
[0x10a]);
634 /* Firmware Directory - "osos" entry */
635 memcpy(&outbuf
[0x4200],"!ATAsoso",8); /* dev and type */
636 int2le(0, &outbuf
[0x4208]); /* id */
637 int2le(0x4400, &outbuf
[0x420c]); /* devOffset */
638 int2le(length
, &outbuf
[0x4210]); /* Length of firmware */
639 int2le(0x10000000, &outbuf
[0x4214]); /* Addr */
640 int2le(0, &outbuf
[0x4218]); /* Entry Offset */
641 int2le(sum
, &outbuf
[0x421c]); /* Checksum */
642 int2le(0x00006012, &outbuf
[0x4220]); /* vers - 0x6012 is a guess */
643 int2le(0xffffffff, &outbuf
[0x4224]); /* LoadAddr - for flash images */
645 /* "rsrc" entry (if applicable) */
647 rsrcoffset
=(length
+0x4600+0x200) & ~0x200;
651 memcpy(&outbuf
[0x4228],"!ATAcrsr",8); /* dev and type */
652 int2le(0, &outbuf
[0x4230]); /* id */
653 int2le(rsrcoffset
, &outbuf
[0x4234]); /* devOffset */
654 int2le(rsrclength
, &outbuf
[0x4238]); /* Length of firmware */
655 int2le(0x10000000, &outbuf
[0x423c]); /* Addr */
656 int2le(0, &outbuf
[0x4240]); /* Entry Offset */
657 int2le(rsrcsum
, &outbuf
[0x4244]); /* Checksum */
658 int2le(0x0000b000, &outbuf
[0x4248]); /* vers */
659 int2le(0xffffffff, &outbuf
[0x424c]); /* LoadAddr - for flash images */
662 file
= fopen(oname
, "wb");
668 len
= fwrite(outbuf
, 1, length
+0x4600, file
);