1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2002 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 void int2le(unsigned int val
, unsigned char* addr
)
58 addr
[1] = (val
>> 8) & 0xff;
59 addr
[2] = (val
>> 16) & 0xff;
60 addr
[3] = (val
>> 24) & 0xff;
63 void int2be(unsigned int val
, unsigned char* addr
)
65 addr
[0] = (val
>> 24) & 0xff;
66 addr
[1] = (val
>> 16) & 0xff;
67 addr
[2] = (val
>> 8) & 0xff;
73 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
75 "\t-fm Archos FM recorder format\n"
76 "\t-v2 Archos V2 recorder format\n"
77 "\t-ofm Archos Ondio FM recorder format\n"
78 "\t-osp Archos Ondio SP format\n"
79 "\t-neo SSI Neo format\n"
80 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
81 "\t-iriver iRiver format\n"
82 "\t-iaudiox5 iAudio X5 format\n"
83 "\t-iaudiox5v iAudio X5V format\n"
84 "\t-ipod3g ipod firmware partition format (3rd Gen)\n"
85 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
86 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
87 "\t-gigabeat Toshiba Gigabeat format\n"
88 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
89 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
90 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
91 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd\n"
92 "\t ip3g, ip4g, mini, x5, h10, h10_5gb)\n"
93 "\nNo option results in Archos standard player/recorder format.\n");
98 int main (int argc
, char** argv
)
100 unsigned long length
,i
,slen
;
101 unsigned char *inbuf
,*outbuf
;
102 unsigned short crc
=0;
103 unsigned long chksum
=0; /* 32 bit checksum */
104 unsigned char header
[24];
105 char *iname
= argv
[1];
106 char *oname
= argv
[2];
111 unsigned long modelnum
;
114 enum { none
, scramble
, xor, add
} method
= scramble
;
116 model_id
= ARCHOS_PLAYER
;
122 if(!strcmp(argv
[1], "-fm")) {
127 model_id
= ARCHOS_FMRECORDER
;
130 else if(!strcmp(argv
[1], "-v2")) {
135 model_id
= ARCHOS_V2RECORDER
;
138 else if(!strcmp(argv
[1], "-ofm")) {
143 model_id
= ARCHOS_ONDIO_FM
;
146 else if(!strcmp(argv
[1], "-osp")) {
151 model_id
= ARCHOS_ONDIO_SP
;
154 else if(!strcmp(argv
[1], "-neo")) {
160 else if(!strncmp(argv
[1], "-mm=", 4)) {
165 version
= argv
[1][4];
169 printf("Multimedia needs an xor string\n");
173 else if(!strncmp(argv
[1], "-add=", 5)) {
178 if(!strcmp(&argv
[1][5], "h120"))
180 else if(!strcmp(&argv
[1][5], "h140"))
181 modelnum
= 0; /* the same as the h120 */
182 else if(!strcmp(&argv
[1][5], "h100"))
184 else if(!strcmp(&argv
[1][5], "h300"))
186 else if(!strcmp(&argv
[1][5], "ipco"))
188 else if(!strcmp(&argv
[1][5], "nano"))
190 else if(!strcmp(&argv
[1][5], "ipvd"))
192 else if(!strcmp(&argv
[1][5], "fp7x"))
194 else if(!strcmp(&argv
[1][5], "ip3g"))
196 else if(!strcmp(&argv
[1][5], "ip4g"))
198 else if(!strcmp(&argv
[1][5], "mini"))
200 else if(!strcmp(&argv
[1][5], "iax5"))
202 else if(!strcmp(&argv
[1][5], "mn2g"))
204 else if(!strcmp(&argv
[1][5], "h10"))
206 else if(!strcmp(&argv
[1][5], "h10_5gb"))
208 else if(!strcmp(&argv
[1][5], "tpj2"))
211 fprintf(stderr
, "unsupported model: %s\n", &argv
[1][5]);
214 /* we store a 4-letter model name too, for humans */
215 strcpy(modelname
, &argv
[1][5]);
216 chksum
= modelnum
; /* start checksum calcs with this */
219 else if(!strcmp(argv
[1], "-iriver")) {
220 /* iRiver code dealt with in the iriver.c code */
223 iriver_encode(iname
, oname
, FALSE
);
226 else if(!strcmp(argv
[1], "-gigabeat")) {
227 /* iRiver code dealt with in the iriver.c code */
230 gigabeat_code(iname
, oname
);
233 else if(!strcmp(argv
[1], "-iaudiox5")) {
236 return iaudio_encode(iname
, oname
, "COWON_X5_FW");
238 else if(!strcmp(argv
[1], "-iaudiox5v")) {
241 return iaudio_encode(iname
, oname
, "COWON_X5V_FW");
243 else if(!strcmp(argv
[1], "-ipod3g")) {
246 return ipod_encode(iname
, oname
, 2, false); /* Firmware image v2 */
248 else if(!strcmp(argv
[1], "-ipod4g")) {
251 return ipod_encode(iname
, oname
, 3, false); /* Firmware image v3 */
253 else if(!strcmp(argv
[1], "-ipod5g")) {
256 return ipod_encode(iname
, oname
, 3, true); /* Firmware image v3 */
258 else if(!strcmp(argv
[1], "-mi4v2")) {
261 return mi4_encode(iname
, oname
, 0x00010201);
263 else if(!strcmp(argv
[1], "-mi4v3")) {
266 return mi4_encode(iname
, oname
, 0x00010301);
270 file
= fopen(iname
,"rb");
275 fseek(file
,0,SEEK_END
);
276 length
= ftell(file
);
277 length
= (length
+ 3) & ~3; /* Round up to nearest 4 byte boundary */
279 if ((method
== scramble
) &&
280 ((length
+ headerlen
) >= size_limit
[model_id
])) {
281 printf("error: firmware image is %d bytes while max size is %d!\n",
283 size_limit
[model_id
]);
288 fseek(file
,0,SEEK_SET
);
289 inbuf
= malloc(length
);
291 outbuf
= malloc(length
*2);
292 else if(method
== add
)
293 outbuf
= malloc(length
+ 8);
295 outbuf
= malloc(length
);
296 if ( !inbuf
|| !outbuf
) {
297 printf("out of memory!\n");
301 /* zero-fill the last 4 bytes to make sure there's no rubbish there
302 when we write the size-aligned file later */
303 memset(outbuf
+length
-4, 0, 4);
307 i
=fread(inbuf
,1,length
,file
);
317 for (i
= 0; i
< length
; i
++) {
318 /* add 8 unsigned bits but keep a 32 bit sum */
324 for (i
= 0; i
< length
; i
++) {
325 unsigned long addr
= (i
>> 2) + ((i
% 4) * slen
);
326 unsigned char data
= inbuf
[i
];
327 data
= ~((data
<< 1) | ((data
>> 7) & 1)); /* poor man's ROL */
335 for (i
=0; i
<length
; i
++) {
337 outbuf
[slen
++] = 0xff; /* all data is uncompressed */
338 outbuf
[slen
++] = inbuf
[i
];
344 /* calculate checksum */
345 for (i
=0;i
<length
;i
++)
349 memset(header
, 0, sizeof header
);
354 int2be(chksum
, header
); /* checksum, big-endian */
355 memcpy(&header
[4], modelname
, 4); /* 4 bytes model name */
356 memcpy(outbuf
, inbuf
, length
); /* the input buffer to output*/
361 if (headerlen
== 6) {
362 int2be(length
, header
);
363 header
[4] = (crc
>> 8) & 0xff;
364 header
[5] = crc
& 0xff;
370 header
[3] = 0xff; /* ??? */
372 header
[6] = (crc
>> 8) & 0xff;
373 header
[7] = crc
& 0xff;
375 header
[11] = version
;
377 header
[15] = headerlen
; /* really? */
379 int2be(length
, &header
[20]);
385 int xorlen
= strlen(xorstring
);
388 for (i
=0; i
<slen
; i
++)
389 outbuf
[i
] ^= xorstring
[i
& (xorlen
-1)];
391 /* calculate checksum */
392 for (i
=0; i
<slen
; i
++)
395 header
[0] = header
[2] = 'Z';
396 header
[1] = header
[3] = version
;
397 int2le(length
, &header
[4]);
398 int2le(slen
, &header
[8]);
399 int2le(crc
, &header
[12]);
404 #define MY_FIRMWARE_TYPE "Rockbox"
405 #define MY_HEADER_VERSION 1
407 strncpy((char *)header
, MY_FIRMWARE_TYPE
,9);
408 header
[9]='\0'; /*shouldn't have to, but to be SURE */
409 header
[10]=MY_HEADER_VERSION
&0xFF;
410 header
[11]=(crc
>>8)&0xFF;
412 int2be(sizeof(header
), &header
[12]);
417 file
= fopen(oname
,"wb");
422 if ( !fwrite(header
,headerlen
,1,file
) ) {
426 if ( !fwrite(outbuf
,length
,1,file
) ) {
438 int iaudio_encode(char *iname
, char *oname
, char *idstring
)
443 unsigned char *outbuf
;
445 unsigned char sum
= 0;
447 file
= fopen(iname
, "rb");
452 fseek(file
,0,SEEK_END
);
453 length
= ftell(file
);
455 fseek(file
,0,SEEK_SET
);
456 outbuf
= malloc(length
+0x1030);
459 printf("out of memory!\n");
463 len
= fread(outbuf
+0x1030, 1, length
, file
);
469 memset(outbuf
, 0, 0x1030);
470 strcpy((char *)outbuf
, idstring
);
472 for(i
= 0; i
< length
;i
++)
473 sum
+= outbuf
[0x1030 + i
];
475 int2be(length
, &outbuf
[0x1024]);
476 outbuf
[0x102b] = sum
;
480 file
= fopen(oname
, "wb");
486 len
= fwrite(outbuf
, 1, length
+0x1030, file
);
496 /* Create an ipod firmware partition image
498 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
500 This function doesn't yet handle the Broadcom resource image for the 5g,
501 so the resulting images won't be usable.
503 This has also only been tested on an ipod Photo
506 int ipod_encode(char *iname
, char *oname
, int fw_ver
, bool fake_rsrc
)
508 static const char *apple_stop_sign
= "{{~~ /-----\\ "\
529 unsigned int sum
= 0;
530 unsigned int rsrcsum
= 0;
531 unsigned char *outbuf
;
535 file
= fopen(iname
, "rb");
540 fseek(file
,0,SEEK_END
);
541 length
= ftell(file
);
543 fseek(file
,0,SEEK_SET
);
545 bufsize
=(length
+0x4600);
547 bufsize
= (bufsize
+ 0x400) & ~0x200;
550 outbuf
= malloc(bufsize
);
553 printf("out of memory!\n");
557 len
= fread(outbuf
+0x4600, 1, length
, file
);
564 /* Calculate checksum for later use in header */
565 for(i
= 0x4600; i
< 0x4600+length
;i
++)
568 /* Clear the header area to zero */
569 memset(outbuf
, 0, 0x4600);
571 /* APPLE STOP SIGN */
572 strcpy((char *)outbuf
, apple_stop_sign
);
575 memcpy(&outbuf
[0x100],"]ih[",4); /* Magic */
576 int2le(0x4000, &outbuf
[0x104]); /* Firmware offset relative to 0x200 */
577 short2le(0x10c, &outbuf
[0x108]); /* Location of extended header */
578 short2le(fw_ver
, &outbuf
[0x10a]);
580 /* Firmware Directory - "osos" entry */
581 memcpy(&outbuf
[0x4200],"!ATAsoso",8); /* dev and type */
582 int2le(0, &outbuf
[0x4208]); /* id */
583 int2le(0x4400, &outbuf
[0x420c]); /* devOffset */
584 int2le(length
, &outbuf
[0x4210]); /* Length of firmware */
585 int2le(0x10000000, &outbuf
[0x4214]); /* Addr */
586 int2le(0, &outbuf
[0x4218]); /* Entry Offset */
587 int2le(sum
, &outbuf
[0x421c]); /* Checksum */
588 int2le(0x00006012, &outbuf
[0x4220]); /* vers - 0x6012 is a guess */
589 int2le(0xffffffff, &outbuf
[0x4224]); /* LoadAddr - for flash images */
591 /* "rsrc" entry (if applicable) */
593 rsrcoffset
=(length
+0x4600+0x200) & ~0x200;
597 memcpy(&outbuf
[0x4228],"!ATAcrsr",8); /* dev and type */
598 int2le(0, &outbuf
[0x4230]); /* id */
599 int2le(rsrcoffset
, &outbuf
[0x4234]); /* devOffset */
600 int2le(rsrclength
, &outbuf
[0x4238]); /* Length of firmware */
601 int2le(0x10000000, &outbuf
[0x423c]); /* Addr */
602 int2le(0, &outbuf
[0x4240]); /* Entry Offset */
603 int2le(rsrcsum
, &outbuf
[0x4244]); /* Checksum */
604 int2le(0x0000b000, &outbuf
[0x4248]); /* vers */
605 int2le(0xffffffff, &outbuf
[0x424c]); /* LoadAddr - for flash images */
608 file
= fopen(oname
, "wb");
614 len
= fwrite(outbuf
, 1, length
+0x4600, file
);