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,\n"
107 "\nNo option results in Archos standard player/recorder format.\n");
112 int main (int argc
, char** argv
)
114 unsigned long length
,i
,slen
;
115 unsigned char *inbuf
,*outbuf
;
116 unsigned short crc
=0;
117 unsigned long chksum
=0; /* 32 bit checksum */
118 unsigned char header
[24];
119 char *iname
= argv
[1];
120 char *oname
= argv
[2];
125 unsigned long modelnum
;
128 enum { none
, scramble
, xor, add
} method
= scramble
;
130 model_id
= ARCHOS_PLAYER
;
136 if(!strcmp(argv
[1], "-fm")) {
141 model_id
= ARCHOS_FMRECORDER
;
144 else if(!strcmp(argv
[1], "-v2")) {
149 model_id
= ARCHOS_V2RECORDER
;
152 else if(!strcmp(argv
[1], "-ofm")) {
157 model_id
= ARCHOS_ONDIO_FM
;
160 else if(!strcmp(argv
[1], "-osp")) {
165 model_id
= ARCHOS_ONDIO_SP
;
168 else if(!strcmp(argv
[1], "-neo")) {
174 else if(!strncmp(argv
[1], "-mm=", 4)) {
179 version
= argv
[1][4];
183 printf("Multimedia needs an xor string\n");
187 else if(!strncmp(argv
[1], "-add=", 5)) {
192 if(!strcmp(&argv
[1][5], "h120"))
194 else if(!strcmp(&argv
[1][5], "h140"))
195 modelnum
= 0; /* the same as the h120 */
196 else if(!strcmp(&argv
[1][5], "h100"))
198 else if(!strcmp(&argv
[1][5], "h300"))
200 else if(!strcmp(&argv
[1][5], "ipco"))
202 else if(!strcmp(&argv
[1][5], "nano"))
204 else if(!strcmp(&argv
[1][5], "ipvd"))
206 else if(!strcmp(&argv
[1][5], "fp7x"))
208 else if(!strcmp(&argv
[1][5], "ip3g"))
210 else if(!strcmp(&argv
[1][5], "ip4g"))
212 else if(!strcmp(&argv
[1][5], "mini"))
214 else if(!strcmp(&argv
[1][5], "iax5"))
216 else if(!strcmp(&argv
[1][5], "mn2g"))
218 else if(!strcmp(&argv
[1][5], "h10"))
220 else if(!strcmp(&argv
[1][5], "h10_5gb"))
222 else if(!strcmp(&argv
[1][5], "tpj2"))
224 else if(!strcmp(&argv
[1][5], "e200"))
226 else if(!strcmp(&argv
[1][5], "iam5"))
228 else if(!strcmp(&argv
[1][5], "giga"))
230 else if(!strcmp(&argv
[1][5], "1g2g"))
232 else if(!strcmp(&argv
[1][5], "c200"))
235 fprintf(stderr
, "unsupported model: %s\n", &argv
[1][5]);
238 /* we store a 4-letter model name too, for humans */
239 strcpy(modelname
, &argv
[1][5]);
240 chksum
= modelnum
; /* start checksum calcs with this */
243 else if(!strcmp(argv
[1], "-iriver")) {
244 /* iRiver code dealt with in the iriver.c code */
247 iriver_encode(iname
, oname
, FALSE
);
250 else if(!strcmp(argv
[1], "-gigabeat")) {
251 /* iRiver code dealt with in the iriver.c code */
254 gigabeat_code(iname
, oname
);
257 else if(!strcmp(argv
[1], "-iaudiox5")) {
260 return iaudio_encode(iname
, oname
, "COWON_X5_FW");
262 else if(!strcmp(argv
[1], "-iaudiox5v")) {
265 return iaudio_encode(iname
, oname
, "COWON_X5V_FW");
267 else if(!strcmp(argv
[1], "-iaudiom5")) {
270 return iaudio_encode(iname
, oname
, "COWON_M5_FW");
272 else if(!strcmp(argv
[1], "-ipod3g")) {
275 return ipod_encode(iname
, oname
, 2, false); /* Firmware image v2 */
277 else if(!strcmp(argv
[1], "-ipod4g")) {
280 return ipod_encode(iname
, oname
, 3, false); /* Firmware image v3 */
282 else if(!strcmp(argv
[1], "-ipod5g")) {
285 return ipod_encode(iname
, oname
, 3, true); /* Firmware image v3 */
287 else if(!strncmp(argv
[1], "-mi4", 4)) {
293 if(!strcmp(&argv
[1][4], "v2")) {
294 mi4magic
= MI4_MAGIC_DEFAULT
;
295 version
= 0x00010201;
297 else if(!strcmp(&argv
[1][4], "v3")) {
298 mi4magic
= MI4_MAGIC_DEFAULT
;
299 version
= 0x00010301;
301 else if(!strcmp(&argv
[1][4], "r")) {
302 mi4magic
= MI4_MAGIC_R
;
303 version
= 0x00010301;
306 printf( "Invalid mi4 version: %s\n", &argv
[1][4]);
313 if(!strncmp(argv
[2], "-model=", 7)) {
316 strncpy(model
, &argv
[2][7], 4);
318 if(!strncmp(argv
[3], "-type=", 6)) {
321 strncpy(type
, &argv
[3][6], 4);
325 return mi4_encode(iname
, oname
, version
, mi4magic
, model
, type
);
329 file
= fopen(iname
,"rb");
334 fseek(file
,0,SEEK_END
);
335 length
= ftell(file
);
336 length
= (length
+ 3) & ~3; /* Round up to nearest 4 byte boundary */
338 if ((method
== scramble
) &&
339 ((length
+ headerlen
) >= size_limit
[model_id
])) {
340 printf("error: firmware image is %d bytes while max size is %d!\n",
342 size_limit
[model_id
]);
347 fseek(file
,0,SEEK_SET
);
348 inbuf
= malloc(length
);
350 outbuf
= malloc(length
*2);
351 else if(method
== add
)
352 outbuf
= malloc(length
+ 8);
354 outbuf
= malloc(length
);
355 if ( !inbuf
|| !outbuf
) {
356 printf("out of memory!\n");
360 /* zero-fill the last 4 bytes to make sure there's no rubbish there
361 when we write the size-aligned file later */
362 memset(outbuf
+length
-4, 0, 4);
366 i
=fread(inbuf
,1,length
,file
);
376 for (i
= 0; i
< length
; i
++) {
377 /* add 8 unsigned bits but keep a 32 bit sum */
383 for (i
= 0; i
< length
; i
++) {
384 unsigned long addr
= (i
>> 2) + ((i
% 4) * slen
);
385 unsigned char data
= inbuf
[i
];
386 data
= ~((data
<< 1) | ((data
>> 7) & 1)); /* poor man's ROL */
394 for (i
=0; i
<length
; i
++) {
396 outbuf
[slen
++] = 0xff; /* all data is uncompressed */
397 outbuf
[slen
++] = inbuf
[i
];
403 /* calculate checksum */
404 for (i
=0;i
<length
;i
++)
408 memset(header
, 0, sizeof header
);
413 int2be(chksum
, header
); /* checksum, big-endian */
414 memcpy(&header
[4], modelname
, 4); /* 4 bytes model name */
415 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
420 if (headerlen
== 6) {
421 int2be(length
, header
);
422 header
[4] = (crc
>> 8) & 0xff;
423 header
[5] = crc
& 0xff;
429 header
[3] = 0xff; /* ??? */
431 header
[6] = (crc
>> 8) & 0xff;
432 header
[7] = crc
& 0xff;
434 header
[11] = version
;
436 header
[15] = headerlen
; /* really? */
438 int2be(length
, &header
[20]);
444 int xorlen
= strlen(xorstring
);
447 for (i
=0; i
<slen
; i
++)
448 outbuf
[i
] ^= xorstring
[i
& (xorlen
-1)];
450 /* calculate checksum */
451 for (i
=0; i
<slen
; i
++)
454 header
[0] = header
[2] = 'Z';
455 header
[1] = header
[3] = version
;
456 int2le(length
, &header
[4]);
457 int2le(slen
, &header
[8]);
458 int2le(crc
, &header
[12]);
463 #define MY_FIRMWARE_TYPE "Rockbox"
464 #define MY_HEADER_VERSION 1
466 strncpy((char *)header
, MY_FIRMWARE_TYPE
,9);
467 header
[9]='\0'; /*shouldn't have to, but to be SURE */
468 header
[10]=MY_HEADER_VERSION
&0xFF;
469 header
[11]=(crc
>>8)&0xFF;
471 int2be(sizeof(header
), &header
[12]);
476 file
= fopen(oname
,"wb");
481 if ( !fwrite(header
,headerlen
,1,file
) ) {
485 if ( !fwrite(outbuf
,length
,1,file
) ) {
497 int iaudio_encode(char *iname
, char *oname
, char *idstring
)
502 unsigned char *outbuf
;
504 unsigned char sum
= 0;
506 file
= fopen(iname
, "rb");
511 fseek(file
,0,SEEK_END
);
512 length
= ftell(file
);
514 fseek(file
,0,SEEK_SET
);
515 outbuf
= malloc(length
+0x1030);
518 printf("out of memory!\n");
522 len
= fread(outbuf
+0x1030, 1, length
, file
);
528 memset(outbuf
, 0, 0x1030);
529 strcpy((char *)outbuf
, idstring
);
531 for(i
= 0; i
< length
;i
++)
532 sum
+= outbuf
[0x1030 + i
];
534 int2be(length
, &outbuf
[0x1024]);
535 outbuf
[0x102b] = sum
;
539 file
= fopen(oname
, "wb");
545 len
= fwrite(outbuf
, 1, length
+0x1030, file
);
555 /* Create an ipod firmware partition image
557 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
559 This function doesn't yet handle the Broadcom resource image for the 5g,
560 so the resulting images won't be usable.
562 This has also only been tested on an ipod Photo
565 int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
)
567 static const char *apple_stop_sign
= "{{~~ /-----\\ "\
588 unsigned int sum
= 0;
589 unsigned int rsrcsum
= 0;
590 unsigned char *outbuf
;
594 file
= fopen(iname
, "rb");
599 fseek(file
,0,SEEK_END
);
600 length
= ftell(file
);
602 fseek(file
,0,SEEK_SET
);
604 bufsize
=(length
+0x4600);
606 bufsize
= (bufsize
+ 0x400) & ~0x200;
609 outbuf
= malloc(bufsize
);
612 printf("out of memory!\n");
616 len
= fread(outbuf
+0x4600, 1, length
, file
);
623 /* Calculate checksum for later use in header */
624 for(i
= 0x4600; i
< 0x4600+length
;i
++)
627 /* Clear the header area to zero */
628 memset(outbuf
, 0, 0x4600);
630 /* APPLE STOP SIGN */
631 strcpy((char *)outbuf
, apple_stop_sign
);
634 memcpy(&outbuf
[0x100],"]ih[",4); /* Magic */
635 int2le(0x4000, &outbuf
[0x104]); /* Firmware offset relative to 0x200 */
636 short2le(0x10c, &outbuf
[0x108]); /* Location of extended header */
637 short2le(fw_ver
, &outbuf
[0x10a]);
639 /* Firmware Directory - "osos" entry */
640 memcpy(&outbuf
[0x4200],"!ATAsoso",8); /* dev and type */
641 int2le(0, &outbuf
[0x4208]); /* id */
642 int2le(0x4400, &outbuf
[0x420c]); /* devOffset */
643 int2le(length
, &outbuf
[0x4210]); /* Length of firmware */
644 int2le(0x10000000, &outbuf
[0x4214]); /* Addr */
645 int2le(0, &outbuf
[0x4218]); /* Entry Offset */
646 int2le(sum
, &outbuf
[0x421c]); /* Checksum */
647 int2le(0x00006012, &outbuf
[0x4220]); /* vers - 0x6012 is a guess */
648 int2le(0xffffffff, &outbuf
[0x4224]); /* LoadAddr - for flash images */
650 /* "rsrc" entry (if applicable) */
652 rsrcoffset
=(length
+0x4600+0x200) & ~0x200;
656 memcpy(&outbuf
[0x4228],"!ATAcrsr",8); /* dev and type */
657 int2le(0, &outbuf
[0x4230]); /* id */
658 int2le(rsrcoffset
, &outbuf
[0x4234]); /* devOffset */
659 int2le(rsrclength
, &outbuf
[0x4238]); /* Length of firmware */
660 int2le(0x10000000, &outbuf
[0x423c]); /* Addr */
661 int2le(0, &outbuf
[0x4240]); /* Entry Offset */
662 int2le(rsrcsum
, &outbuf
[0x4244]); /* Checksum */
663 int2le(0x0000b000, &outbuf
[0x4248]); /* vers */
664 int2le(0xffffffff, &outbuf
[0x424c]); /* LoadAddr - for flash images */
667 file
= fopen(oname
, "wb");
673 len
= fwrite(outbuf
, 1, length
+0x4600, file
);