Remove .a files before running ar, to avoid problems with renamed files remaining...
[kugel-rb.git] / tools / scramble.c
blob8c4b435c0245fa5fd451dea43e26b98f9458ffd8
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 - 2007 by Björn Stenberg
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdbool.h>
25 #include <string.h>
26 #include "iriver.h"
27 #include "gigabeat.h"
28 #include "gigabeats.h"
29 #include "mi4.h"
30 #include "telechips.h"
31 #include "creative.h"
32 #include "iaudio_bl_flash.h"
34 int iaudio_encode(char *iname, char *oname, char *idstring);
35 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc);
37 enum
39 ARCHOS_PLAYER, /* and V1 recorder */
40 ARCHOS_V2RECORDER,
41 ARCHOS_FMRECORDER,
42 ARCHOS_ONDIO_SP,
43 ARCHOS_ONDIO_FM
46 static unsigned int size_limit[] =
48 0x32000, /* ARCHOS_PLAYER */
49 0x64000, /* ARCHOS_V2RECORDER */
50 0x64000, /* ARCHOS_FMRECORDER */
51 0x64000, /* ARCHOS_ONDIO_SP */
52 0x64000 /* ARCHOS_ONDIO_FM */
55 void short2le(unsigned short val, unsigned char* addr)
57 addr[0] = val & 0xFF;
58 addr[1] = (val >> 8) & 0xff;
61 unsigned int le2int(unsigned char* buf)
63 unsigned int res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
65 return res;
68 void int2le(unsigned int val, unsigned char* addr)
70 addr[0] = val & 0xFF;
71 addr[1] = (val >> 8) & 0xff;
72 addr[2] = (val >> 16) & 0xff;
73 addr[3] = (val >> 24) & 0xff;
76 void int2be(unsigned int val, unsigned char* addr)
78 addr[0] = (val >> 24) & 0xff;
79 addr[1] = (val >> 16) & 0xff;
80 addr[2] = (val >> 8) & 0xff;
81 addr[3] = val & 0xFF;
84 void short2be(unsigned short val, unsigned char* addr)
86 addr[0] = (val >> 8) & 0xff;
87 addr[1] = val & 0xFF;
90 void usage(void)
92 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
93 printf("options:\n"
94 "\t-fm Archos FM recorder format\n"
95 "\t-v2 Archos V2 recorder format\n"
96 "\t-ofm Archos Ondio FM recorder format\n"
97 "\t-osp Archos Ondio SP format\n"
98 "\t-neo SSI Neo format\n"
99 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
100 "\t-iriver iRiver format\n"
101 "\t-iaudiox5 iAudio X5 format\n"
102 "\t-iaudiox5v iAudio X5V format\n"
103 "\t-iaudiom5 iAudio M5 format\n"
104 "\t-iaudiom3 iAudio M3 format\n");
105 printf("\t-ipod3g ipod firmware partition format (3rd Gen)\n"
106 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
107 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
108 "\t-creative=X Creative firmware structure format\n"
109 "\t (X values: zvm, zvm60, zenvision\n"
110 "\t zenv, zen\n");
111 printf("\t-gigabeat Toshiba Gigabeat F/X format\n"
112 "\t-gigabeats Toshiba Gigabeat S format\n"
113 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
114 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
115 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
116 "\t All mi4 options take two optional arguments:\n");
117 printf("\t -model=XXXX where XXXX is the model id string\n"
118 "\t -type=XXXX where XXXX is a string indicating the \n"
119 "\t type of binary, eg. RBOS, RBBL\n"
120 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
121 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
122 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
123 "\t ip3g, ip4g, mini, iax5, iam5, iam3, h10, h10_5gb,\n"
124 "\t tpj2, c200, e200, giga, gigs, m100, m500, d2,\n");
125 printf("\t 9200, 1630, ldax, m200, clip, e2v2, m2v4, fuze)\n");
126 printf("\nNo option results in Archos standard player/recorder format.\n");
128 exit(1);
131 int main (int argc, char** argv)
133 unsigned long length,i,slen=0;
134 unsigned char *inbuf,*outbuf;
135 unsigned short crc=0;
136 unsigned long chksum=0; /* 32 bit checksum */
137 unsigned char header[24];
138 char *iname = argv[1];
139 char *oname = argv[2];
140 char *xorstring=NULL;
141 int headerlen = 6;
142 FILE* file;
143 int version=0;
144 unsigned long modelnum;
145 char modelname[5];
146 int model_id;
147 enum { none, scramble, xor, tcc_sum, tcc_crc, add } method = scramble;
148 bool creative_enable_ciff;
150 model_id = ARCHOS_PLAYER;
152 if (argc < 3) {
153 usage();
156 if(!strcmp(argv[1], "-fm")) {
157 headerlen = 24;
158 iname = argv[2];
159 oname = argv[3];
160 version = 4;
161 model_id = ARCHOS_FMRECORDER;
164 else if(!strcmp(argv[1], "-v2")) {
165 headerlen = 24;
166 iname = argv[2];
167 oname = argv[3];
168 version = 2;
169 model_id = ARCHOS_V2RECORDER;
172 else if(!strcmp(argv[1], "-ofm")) {
173 headerlen = 24;
174 iname = argv[2];
175 oname = argv[3];
176 version = 8;
177 model_id = ARCHOS_ONDIO_FM;
180 else if(!strcmp(argv[1], "-osp")) {
181 headerlen = 24;
182 iname = argv[2];
183 oname = argv[3];
184 version = 16;
185 model_id = ARCHOS_ONDIO_SP;
188 else if(!strcmp(argv[1], "-neo")) {
189 headerlen = 17;
190 iname = argv[2];
191 oname = argv[3];
192 method = none;
194 else if(!strncmp(argv[1], "-mm=", 4)) {
195 headerlen = 16;
196 iname = argv[2];
197 oname = argv[3];
198 method = xor;
199 version = argv[1][4];
200 if (argc > 4)
201 xorstring = argv[4];
202 else {
203 printf("Multimedia needs an xor string\n");
204 return -1;
207 else if(!strncmp(argv[1], "-tcc=", 4)) {
208 headerlen = 0;
209 iname = argv[2];
210 oname = argv[3];
212 if(!strcmp(&argv[1][5], "sum"))
213 method = tcc_sum;
214 else if(!strcmp(&argv[1][5], "crc"))
215 method = tcc_crc;
216 else {
217 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
218 return 2;
221 else if(!strncmp(argv[1], "-add=", 5)) {
222 iname = argv[2];
223 oname = argv[3];
224 method = add;
226 if(!strcmp(&argv[1][5], "h120"))
227 modelnum = 0;
228 else if(!strcmp(&argv[1][5], "h140"))
229 modelnum = 0; /* the same as the h120 */
230 else if(!strcmp(&argv[1][5], "h100"))
231 modelnum = 1;
232 else if(!strcmp(&argv[1][5], "h300"))
233 modelnum = 2;
234 else if(!strcmp(&argv[1][5], "ipco"))
235 modelnum = 3;
236 else if(!strcmp(&argv[1][5], "nano"))
237 modelnum = 4;
238 else if(!strcmp(&argv[1][5], "ipvd"))
239 modelnum = 5;
240 else if(!strcmp(&argv[1][5], "fp7x"))
241 modelnum = 6;
242 else if(!strcmp(&argv[1][5], "ip3g"))
243 modelnum = 7;
244 else if(!strcmp(&argv[1][5], "ip4g"))
245 modelnum = 8;
246 else if(!strcmp(&argv[1][5], "mini"))
247 modelnum = 9;
248 else if(!strcmp(&argv[1][5], "iax5"))
249 modelnum = 10;
250 else if(!strcmp(&argv[1][5], "mn2g"))
251 modelnum = 11;
252 else if(!strcmp(&argv[1][5], "h10"))
253 modelnum = 13;
254 else if(!strcmp(&argv[1][5], "h10_5gb"))
255 modelnum = 14;
256 else if(!strcmp(&argv[1][5], "tpj2"))
257 modelnum = 15;
258 else if(!strcmp(&argv[1][5], "e200"))
259 modelnum = 16;
260 else if(!strcmp(&argv[1][5], "iam5"))
261 modelnum = 17;
262 else if(!strcmp(&argv[1][5], "giga"))
263 modelnum = 18;
264 else if(!strcmp(&argv[1][5], "1g2g"))
265 modelnum = 19;
266 else if(!strcmp(&argv[1][5], "c200"))
267 modelnum = 20;
268 else if(!strcmp(&argv[1][5], "gigs"))
269 modelnum = 21;
270 else if(!strcmp(&argv[1][5], "m500"))
271 modelnum = 22;
272 else if(!strcmp(&argv[1][5], "m100"))
273 modelnum = 23;
274 else if(!strcmp(&argv[1][5], "d2"))
275 modelnum = 24;
276 else if(!strcmp(&argv[1][5], "iam3"))
277 modelnum = 25;
278 else if (!strcmp(&argv[1][5], "m200"))
279 modelnum = 29;
280 else if(!strcmp(&argv[1][5], "1630")) /* Philips HDD1630 */
281 modelnum = 31;
282 else if (!strcmp(&argv[1][5], "i7"))
283 modelnum = 32;
284 else if (!strcmp(&argv[1][5], "ldax"))
285 modelnum = 33;
286 else if(!strcmp(&argv[1][5], "9200")) /* Philips SA9200 */
287 modelnum = 34;
288 else if (!strcmp(&argv[1][5], "clip"))
289 modelnum = 40;
290 else if (!strcmp(&argv[1][5], "e2v2"))
291 modelnum = 41;
292 else if (!strcmp(&argv[1][5], "m2v4"))
293 modelnum = 42;
294 else if (!strcmp(&argv[1][5], "fuze"))
295 modelnum = 43;
296 else {
297 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
298 return 2;
300 /* we store a 4-letter model name too, for humans */
301 strcpy(modelname, &argv[1][5]);
302 chksum = modelnum; /* start checksum calcs with this */
305 else if(!strcmp(argv[1], "-iriver")) {
306 /* iRiver code dealt with in the iriver.c code */
307 iname = argv[2];
308 oname = argv[3];
309 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
311 else if(!strcmp(argv[1], "-gigabeat")) {
312 /* iRiver code dealt with in the iriver.c code */
313 iname = argv[2];
314 oname = argv[3];
315 gigabeat_code(iname, oname);
316 return 0;
318 else if(!strcmp(argv[1], "-gigabeats")) {
319 iname = argv[2];
320 oname = argv[3];
321 gigabeat_s_code(iname, oname);
322 return 0;
324 else if(!strcmp(argv[1], "-iaudiox5")) {
325 iname = argv[2];
326 oname = argv[3];
327 return iaudio_encode(iname, oname, "COWON_X5_FW");
329 else if(!strcmp(argv[1], "-iaudiox5v")) {
330 iname = argv[2];
331 oname = argv[3];
332 return iaudio_encode(iname, oname, "COWON_X5V_FW");
334 else if(!strcmp(argv[1], "-iaudiom5")) {
335 iname = argv[2];
336 oname = argv[3];
337 return iaudio_encode(iname, oname, "COWON_M5_FW");
339 else if(!strcmp(argv[1], "-iaudiom3")) {
340 iname = argv[2];
341 oname = argv[3];
342 return iaudio_encode(iname, oname, "COWON_M3_FW");
344 else if(!strcmp(argv[1], "-ipod3g")) {
345 iname = argv[2];
346 oname = argv[3];
347 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
349 else if(!strcmp(argv[1], "-ipod4g")) {
350 iname = argv[2];
351 oname = argv[3];
352 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
354 else if(!strcmp(argv[1], "-ipod5g")) {
355 iname = argv[2];
356 oname = argv[3];
357 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
359 else if(!strncmp(argv[1], "-creative=", 10))
361 if(!strcmp(argv[2], "-no-ciff"))
363 creative_enable_ciff = false;
364 iname = argv[3];
365 oname = argv[4];
367 else
369 creative_enable_ciff = true;
370 iname = argv[2];
371 oname = argv[3];
373 if(!strcmp(&argv[1][10], "zvm"))
374 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
375 else if(!strcmp(&argv[1][10], "zvm60"))
376 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
377 else if(!strcmp(&argv[1][10], "zenvision"))
378 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
379 else if(!strcmp(&argv[1][10], "zenv"))
380 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
381 else if(!strcmp(&argv[1][10], "zen"))
382 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
383 else
385 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
386 return 2;
389 else if(!strncmp(argv[1], "-mi4", 4)) {
390 int mi4magic;
391 char model[4] = "";
392 char type[4] = "";
394 if(!strcmp(&argv[1][4], "v2")) {
395 mi4magic = MI4_MAGIC_DEFAULT;
396 version = 0x00010201;
398 else if(!strcmp(&argv[1][4], "v3")) {
399 mi4magic = MI4_MAGIC_DEFAULT;
400 version = 0x00010301;
402 else if(!strcmp(&argv[1][4], "r")) {
403 mi4magic = MI4_MAGIC_R;
404 version = 0x00010301;
406 else {
407 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
408 return -1;
411 iname = argv[2];
412 oname = argv[3];
414 if(!strncmp(argv[2], "-model=", 7)) {
415 iname = argv[3];
416 oname = argv[4];
417 strncpy(model, &argv[2][7], 4);
419 if(!strncmp(argv[3], "-type=", 6)) {
420 iname = argv[4];
421 oname = argv[5];
422 strncpy(type, &argv[3][6], 4);
426 return mi4_encode(iname, oname, version, mi4magic, model, type);
429 /* open file */
430 file = fopen(iname,"rb");
431 if (!file) {
432 perror(iname);
433 return -1;
435 fseek(file,0,SEEK_END);
436 length = ftell(file);
437 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
439 if ((method == scramble) &&
440 ((length + headerlen) >= size_limit[model_id])) {
441 printf("error: firmware image is %ld bytes while max size is %u!\n",
442 length + headerlen,
443 size_limit[model_id]);
444 fclose(file);
445 return -1;
448 fseek(file,0,SEEK_SET);
449 inbuf = malloc(length);
450 if (method == xor)
451 outbuf = malloc(length*2);
452 else if(method == add)
453 outbuf = malloc(length + 8);
454 else
455 outbuf = malloc(length);
456 if ( !inbuf || !outbuf ) {
457 printf("out of memory!\n");
458 return -1;
460 if(length> 4) {
461 /* zero-fill the last 4 bytes to make sure there's no rubbish there
462 when we write the size-aligned file later */
463 memset(outbuf+length-4, 0, 4);
466 /* read file */
467 i=fread(inbuf,1,length,file);
468 if ( !i ) {
469 perror(iname);
470 return -1;
472 fclose(file);
474 switch (method)
476 case add:
477 for (i = 0; i < length; i++) {
478 /* add 8 unsigned bits but keep a 32 bit sum */
479 chksum += inbuf[i];
481 break;
482 case scramble:
483 slen = length/4;
484 for (i = 0; i < length; i++) {
485 unsigned long addr = (i >> 2) + ((i % 4) * slen);
486 unsigned char data = inbuf[i];
487 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
488 outbuf[addr] = data;
490 break;
492 case xor:
493 /* "compress" */
494 slen = 0;
495 for (i=0; i<length; i++) {
496 if (!(i&7))
497 outbuf[slen++] = 0xff; /* all data is uncompressed */
498 outbuf[slen++] = inbuf[i];
500 break;
501 case none:
502 default:
503 /* dummy case just to silence picky compilers */
504 break;
507 if((method == none) || (method == scramble) || (method == xor)) {
508 /* calculate checksum */
509 for (i=0;i<length;i++)
510 crc += inbuf[i];
513 memset(header, 0, sizeof header);
514 switch (method)
516 case add:
518 int2be(chksum, header); /* checksum, big-endian */
519 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
520 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
521 headerlen = 8;
523 break;
525 case tcc_sum:
526 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
527 telechips_encode_sum(outbuf, length);
528 break;
530 case tcc_crc:
531 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
532 telechips_encode_crc(outbuf, length);
533 break;
535 case scramble:
536 if (headerlen == 6) {
537 int2be(length, header);
538 header[4] = (crc >> 8) & 0xff;
539 header[5] = crc & 0xff;
541 else {
542 header[0] =
543 header[1] =
544 header[2] =
545 header[3] = 0xff; /* ??? */
547 header[6] = (crc >> 8) & 0xff;
548 header[7] = crc & 0xff;
550 header[11] = version;
552 header[15] = headerlen; /* really? */
554 int2be(length, &header[20]);
556 break;
558 case xor:
560 int xorlen = strlen(xorstring);
562 /* xor data */
563 for (i=0; i<slen; i++)
564 outbuf[i] ^= xorstring[i & (xorlen-1)];
566 /* calculate checksum */
567 for (i=0; i<slen; i++)
568 crc += outbuf[i];
570 header[0] = header[2] = 'Z';
571 header[1] = header[3] = version;
572 int2le(length, &header[4]);
573 int2le(slen, &header[8]);
574 int2le(crc, &header[12]);
575 length = slen;
576 break;
579 #define MY_FIRMWARE_TYPE "Rockbox"
580 #define MY_HEADER_VERSION 1
581 default:
582 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
583 header[9]='\0'; /*shouldn't have to, but to be SURE */
584 header[10]=MY_HEADER_VERSION&0xFF;
585 header[11]=(crc>>8)&0xFF;
586 header[12]=crc&0xFF;
587 int2be(sizeof(header), &header[12]);
588 break;
591 /* write file */
592 file = fopen(oname,"wb");
593 if ( !file ) {
594 perror(oname);
595 return -1;
597 if (headerlen > 0) {
598 if ( !fwrite(header,headerlen,1,file) ) {
599 perror(oname);
600 return -1;
603 if ( !fwrite(outbuf,length,1,file) ) {
604 perror(oname);
605 return -1;
607 fclose(file);
609 free(inbuf);
610 free(outbuf);
612 return 0;
615 int iaudio_encode(char *iname, char *oname, char *idstring)
617 size_t len;
618 int length;
619 FILE *file;
620 unsigned char *outbuf;
621 int i;
622 unsigned char sum = 0;
624 file = fopen(iname, "rb");
625 if (!file) {
626 perror(iname);
627 return -1;
629 fseek(file,0,SEEK_END);
630 length = ftell(file);
632 fseek(file,0,SEEK_SET);
633 outbuf = malloc(length+0x1030);
635 if ( !outbuf ) {
636 printf("out of memory!\n");
637 return -1;
640 len = fread(outbuf+0x1030, 1, length, file);
641 if(len < (size_t) length) {
642 perror(iname);
643 return -2;
646 memset(outbuf, 0, 0x1030);
647 strcpy((char *)outbuf, idstring);
648 memcpy(outbuf+0x20, iaudio_bl_flash,
649 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
650 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
651 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
652 outbuf[0x19] = 2;
654 for(i = 0; i < length;i++)
655 sum += outbuf[0x1030 + i];
657 int2be(length, &outbuf[0x1024]);
658 outbuf[0x102b] = sum;
660 fclose(file);
662 file = fopen(oname, "wb");
663 if (!file) {
664 perror(oname);
665 return -3;
668 len = fwrite(outbuf, 1, length+0x1030, file);
669 if(len < (size_t)length) {
670 perror(oname);
671 return -4;
674 fclose(file);
675 return 0;
679 /* Create an ipod firmware partition image
681 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
683 This function doesn't yet handle the Broadcom resource image for the 5g,
684 so the resulting images won't be usable.
686 This has also only been tested on an ipod Photo
689 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
691 static const char *apple_stop_sign = "{{~~ /-----\\ "\
692 "{{~~ / \\ "\
693 "{{~~| | "\
694 "{{~~| S T O P | "\
695 "{{~~| | "\
696 "{{~~ \\ / "\
697 "{{~~ \\-----/ "\
698 "Copyright(C) 200"\
699 "1 Apple Computer"\
700 ", Inc.----------"\
701 "----------------"\
702 "----------------"\
703 "----------------"\
704 "----------------"\
705 "----------------"\
706 "---------------";
707 size_t len;
708 int length;
709 int rsrclength;
710 int rsrcoffset;
711 FILE *file;
712 unsigned int sum = 0;
713 unsigned int rsrcsum = 0;
714 unsigned char *outbuf;
715 int bufsize;
716 int i;
718 file = fopen(iname, "rb");
719 if (!file) {
720 perror(iname);
721 return -1;
723 fseek(file,0,SEEK_END);
724 length = ftell(file);
726 fseek(file,0,SEEK_SET);
728 bufsize=(length+0x4600);
729 if (fake_rsrc) {
730 bufsize = (bufsize + 0x400) & ~0x200;
733 outbuf = malloc(bufsize);
735 if ( !outbuf ) {
736 printf("out of memory!\n");
737 return -1;
740 len = fread(outbuf+0x4600, 1, length, file);
741 if(len < (size_t)length) {
742 perror(iname);
743 return -2;
745 fclose(file);
747 /* Calculate checksum for later use in header */
748 for(i = 0x4600; i < 0x4600+length;i++)
749 sum += outbuf[i];
751 /* Clear the header area to zero */
752 memset(outbuf, 0, 0x4600);
754 /* APPLE STOP SIGN */
755 strcpy((char *)outbuf, apple_stop_sign);
757 /* VOLUME HEADER */
758 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
759 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
760 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
761 short2le(fw_ver, &outbuf[0x10a]);
763 /* Firmware Directory - "osos" entry */
764 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
765 int2le(0, &outbuf[0x4208]); /* id */
766 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
767 int2le(length, &outbuf[0x4210]); /* Length of firmware */
768 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
769 int2le(0, &outbuf[0x4218]); /* Entry Offset */
770 int2le(sum, &outbuf[0x421c]); /* Checksum */
771 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
772 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
774 /* "rsrc" entry (if applicable) */
775 if (fake_rsrc) {
776 rsrcoffset=(length+0x4600+0x200) & ~0x200;
777 rsrclength=0x200;
778 rsrcsum=0;
780 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
781 int2le(0, &outbuf[0x4230]); /* id */
782 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
783 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
784 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
785 int2le(0, &outbuf[0x4240]); /* Entry Offset */
786 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
787 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
788 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
791 file = fopen(oname, "wb");
792 if (!file) {
793 perror(oname);
794 return -3;
797 len = fwrite(outbuf, 1, length+0x4600, file);
798 if(len < (size_t)length) {
799 perror(oname);
800 return -4;
803 fclose(file);
805 return 0;