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"))
229 else if(!strcmp(&argv
[1][5], "1g2g"))
232 fprintf(stderr
, "unsupported model: %s\n", &argv
[1][5]);
235 /* we store a 4-letter model name too, for humans */
236 strcpy(modelname
, &argv
[1][5]);
237 chksum
= modelnum
; /* start checksum calcs with this */
240 else if(!strcmp(argv
[1], "-iriver")) {
241 /* iRiver code dealt with in the iriver.c code */
244 iriver_encode(iname
, oname
, FALSE
);
247 else if(!strcmp(argv
[1], "-gigabeat")) {
248 /* iRiver code dealt with in the iriver.c code */
251 gigabeat_code(iname
, oname
);
254 else if(!strcmp(argv
[1], "-iaudiox5")) {
257 return iaudio_encode(iname
, oname
, "COWON_X5_FW");
259 else if(!strcmp(argv
[1], "-iaudiox5v")) {
262 return iaudio_encode(iname
, oname
, "COWON_X5V_FW");
264 else if(!strcmp(argv
[1], "-iaudiom5")) {
267 return iaudio_encode(iname
, oname
, "COWON_M5_FW");
269 else if(!strcmp(argv
[1], "-ipod3g")) {
272 return ipod_encode(iname
, oname
, 2, false); /* Firmware image v2 */
274 else if(!strcmp(argv
[1], "-ipod4g")) {
277 return ipod_encode(iname
, oname
, 3, false); /* Firmware image v3 */
279 else if(!strcmp(argv
[1], "-ipod5g")) {
282 return ipod_encode(iname
, oname
, 3, true); /* Firmware image v3 */
284 else if(!strncmp(argv
[1], "-mi4", 4)) {
290 if(!strcmp(&argv
[1][4], "v2")) {
291 mi4magic
= MI4_MAGIC_DEFAULT
;
292 version
= 0x00010201;
294 else if(!strcmp(&argv
[1][4], "v3")) {
295 mi4magic
= MI4_MAGIC_DEFAULT
;
296 version
= 0x00010301;
298 else if(!strcmp(&argv
[1][4], "r")) {
299 mi4magic
= MI4_MAGIC_R
;
300 version
= 0x00010301;
303 printf( "Invalid mi4 version: %s\n", &argv
[1][4]);
310 if(!strncmp(argv
[2], "-model=", 7)) {
313 strncpy(model
, &argv
[2][7], 4);
315 if(!strncmp(argv
[3], "-type=", 6)) {
318 strncpy(type
, &argv
[3][6], 4);
322 return mi4_encode(iname
, oname
, version
, mi4magic
, model
, type
);
326 file
= fopen(iname
,"rb");
331 fseek(file
,0,SEEK_END
);
332 length
= ftell(file
);
333 length
= (length
+ 3) & ~3; /* Round up to nearest 4 byte boundary */
335 if ((method
== scramble
) &&
336 ((length
+ headerlen
) >= size_limit
[model_id
])) {
337 printf("error: firmware image is %d bytes while max size is %d!\n",
339 size_limit
[model_id
]);
344 fseek(file
,0,SEEK_SET
);
345 inbuf
= malloc(length
);
347 outbuf
= malloc(length
*2);
348 else if(method
== add
)
349 outbuf
= malloc(length
+ 8);
351 outbuf
= malloc(length
);
352 if ( !inbuf
|| !outbuf
) {
353 printf("out of memory!\n");
357 /* zero-fill the last 4 bytes to make sure there's no rubbish there
358 when we write the size-aligned file later */
359 memset(outbuf
+length
-4, 0, 4);
363 i
=fread(inbuf
,1,length
,file
);
373 for (i
= 0; i
< length
; i
++) {
374 /* add 8 unsigned bits but keep a 32 bit sum */
380 for (i
= 0; i
< length
; i
++) {
381 unsigned long addr
= (i
>> 2) + ((i
% 4) * slen
);
382 unsigned char data
= inbuf
[i
];
383 data
= ~((data
<< 1) | ((data
>> 7) & 1)); /* poor man's ROL */
391 for (i
=0; i
<length
; i
++) {
393 outbuf
[slen
++] = 0xff; /* all data is uncompressed */
394 outbuf
[slen
++] = inbuf
[i
];
400 /* calculate checksum */
401 for (i
=0;i
<length
;i
++)
405 memset(header
, 0, sizeof header
);
410 int2be(chksum
, header
); /* checksum, big-endian */
411 memcpy(&header
[4], modelname
, 4); /* 4 bytes model name */
412 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
417 if (headerlen
== 6) {
418 int2be(length
, header
);
419 header
[4] = (crc
>> 8) & 0xff;
420 header
[5] = crc
& 0xff;
426 header
[3] = 0xff; /* ??? */
428 header
[6] = (crc
>> 8) & 0xff;
429 header
[7] = crc
& 0xff;
431 header
[11] = version
;
433 header
[15] = headerlen
; /* really? */
435 int2be(length
, &header
[20]);
441 int xorlen
= strlen(xorstring
);
444 for (i
=0; i
<slen
; i
++)
445 outbuf
[i
] ^= xorstring
[i
& (xorlen
-1)];
447 /* calculate checksum */
448 for (i
=0; i
<slen
; i
++)
451 header
[0] = header
[2] = 'Z';
452 header
[1] = header
[3] = version
;
453 int2le(length
, &header
[4]);
454 int2le(slen
, &header
[8]);
455 int2le(crc
, &header
[12]);
460 #define MY_FIRMWARE_TYPE "Rockbox"
461 #define MY_HEADER_VERSION 1
463 strncpy((char *)header
, MY_FIRMWARE_TYPE
,9);
464 header
[9]='\0'; /*shouldn't have to, but to be SURE */
465 header
[10]=MY_HEADER_VERSION
&0xFF;
466 header
[11]=(crc
>>8)&0xFF;
468 int2be(sizeof(header
), &header
[12]);
473 file
= fopen(oname
,"wb");
478 if ( !fwrite(header
,headerlen
,1,file
) ) {
482 if ( !fwrite(outbuf
,length
,1,file
) ) {
494 int iaudio_encode(char *iname
, char *oname
, char *idstring
)
499 unsigned char *outbuf
;
501 unsigned char sum
= 0;
503 file
= fopen(iname
, "rb");
508 fseek(file
,0,SEEK_END
);
509 length
= ftell(file
);
511 fseek(file
,0,SEEK_SET
);
512 outbuf
= malloc(length
+0x1030);
515 printf("out of memory!\n");
519 len
= fread(outbuf
+0x1030, 1, length
, file
);
525 memset(outbuf
, 0, 0x1030);
526 strcpy((char *)outbuf
, idstring
);
528 for(i
= 0; i
< length
;i
++)
529 sum
+= outbuf
[0x1030 + i
];
531 int2be(length
, &outbuf
[0x1024]);
532 outbuf
[0x102b] = sum
;
536 file
= fopen(oname
, "wb");
542 len
= fwrite(outbuf
, 1, length
+0x1030, file
);
552 /* Create an ipod firmware partition image
554 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
556 This function doesn't yet handle the Broadcom resource image for the 5g,
557 so the resulting images won't be usable.
559 This has also only been tested on an ipod Photo
562 int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
)
564 static const char *apple_stop_sign
= "{{~~ /-----\\ "\
585 unsigned int sum
= 0;
586 unsigned int rsrcsum
= 0;
587 unsigned char *outbuf
;
591 file
= fopen(iname
, "rb");
596 fseek(file
,0,SEEK_END
);
597 length
= ftell(file
);
599 fseek(file
,0,SEEK_SET
);
601 bufsize
=(length
+0x4600);
603 bufsize
= (bufsize
+ 0x400) & ~0x200;
606 outbuf
= malloc(bufsize
);
609 printf("out of memory!\n");
613 len
= fread(outbuf
+0x4600, 1, length
, file
);
620 /* Calculate checksum for later use in header */
621 for(i
= 0x4600; i
< 0x4600+length
;i
++)
624 /* Clear the header area to zero */
625 memset(outbuf
, 0, 0x4600);
627 /* APPLE STOP SIGN */
628 strcpy((char *)outbuf
, apple_stop_sign
);
631 memcpy(&outbuf
[0x100],"]ih[",4); /* Magic */
632 int2le(0x4000, &outbuf
[0x104]); /* Firmware offset relative to 0x200 */
633 short2le(0x10c, &outbuf
[0x108]); /* Location of extended header */
634 short2le(fw_ver
, &outbuf
[0x10a]);
636 /* Firmware Directory - "osos" entry */
637 memcpy(&outbuf
[0x4200],"!ATAsoso",8); /* dev and type */
638 int2le(0, &outbuf
[0x4208]); /* id */
639 int2le(0x4400, &outbuf
[0x420c]); /* devOffset */
640 int2le(length
, &outbuf
[0x4210]); /* Length of firmware */
641 int2le(0x10000000, &outbuf
[0x4214]); /* Addr */
642 int2le(0, &outbuf
[0x4218]); /* Entry Offset */
643 int2le(sum
, &outbuf
[0x421c]); /* Checksum */
644 int2le(0x00006012, &outbuf
[0x4220]); /* vers - 0x6012 is a guess */
645 int2le(0xffffffff, &outbuf
[0x4224]); /* LoadAddr - for flash images */
647 /* "rsrc" entry (if applicable) */
649 rsrcoffset
=(length
+0x4600+0x200) & ~0x200;
653 memcpy(&outbuf
[0x4228],"!ATAcrsr",8); /* dev and type */
654 int2le(0, &outbuf
[0x4230]); /* id */
655 int2le(rsrcoffset
, &outbuf
[0x4234]); /* devOffset */
656 int2le(rsrclength
, &outbuf
[0x4238]); /* Length of firmware */
657 int2le(0x10000000, &outbuf
[0x423c]); /* Addr */
658 int2le(0, &outbuf
[0x4240]); /* Entry Offset */
659 int2le(rsrcsum
, &outbuf
[0x4244]); /* Checksum */
660 int2le(0x0000b000, &outbuf
[0x4248]); /* vers */
661 int2le(0xffffffff, &outbuf
[0x424c]); /* LoadAddr - for flash images */
664 file
= fopen(oname
, "wb");
670 len
= fwrite(outbuf
, 1, length
+0x4600, file
);