make colours look right
[kugel-rb.git] / tools / scramble.c
blob649af6e4085c0c2ad0992a2d9b5548988cd3dda9
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)\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 {
289 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
290 return 2;
292 /* we store a 4-letter model name too, for humans */
293 strcpy(modelname, &argv[1][5]);
294 chksum = modelnum; /* start checksum calcs with this */
297 else if(!strcmp(argv[1], "-iriver")) {
298 /* iRiver code dealt with in the iriver.c code */
299 iname = argv[2];
300 oname = argv[3];
301 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
303 else if(!strcmp(argv[1], "-gigabeat")) {
304 /* iRiver code dealt with in the iriver.c code */
305 iname = argv[2];
306 oname = argv[3];
307 gigabeat_code(iname, oname);
308 return 0;
310 else if(!strcmp(argv[1], "-gigabeats")) {
311 iname = argv[2];
312 oname = argv[3];
313 gigabeat_s_code(iname, oname);
314 return 0;
316 else if(!strcmp(argv[1], "-iaudiox5")) {
317 iname = argv[2];
318 oname = argv[3];
319 return iaudio_encode(iname, oname, "COWON_X5_FW");
321 else if(!strcmp(argv[1], "-iaudiox5v")) {
322 iname = argv[2];
323 oname = argv[3];
324 return iaudio_encode(iname, oname, "COWON_X5V_FW");
326 else if(!strcmp(argv[1], "-iaudiom5")) {
327 iname = argv[2];
328 oname = argv[3];
329 return iaudio_encode(iname, oname, "COWON_M5_FW");
331 else if(!strcmp(argv[1], "-iaudiom3")) {
332 iname = argv[2];
333 oname = argv[3];
334 return iaudio_encode(iname, oname, "COWON_M3_FW");
336 else if(!strcmp(argv[1], "-ipod3g")) {
337 iname = argv[2];
338 oname = argv[3];
339 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
341 else if(!strcmp(argv[1], "-ipod4g")) {
342 iname = argv[2];
343 oname = argv[3];
344 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
346 else if(!strcmp(argv[1], "-ipod5g")) {
347 iname = argv[2];
348 oname = argv[3];
349 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
351 else if(!strncmp(argv[1], "-creative=", 10))
353 if(!strcmp(argv[2], "-no-ciff"))
355 creative_enable_ciff = false;
356 iname = argv[3];
357 oname = argv[4];
359 else
361 creative_enable_ciff = true;
362 iname = argv[2];
363 oname = argv[3];
365 if(!strcmp(&argv[1][10], "zvm"))
366 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
367 else if(!strcmp(&argv[1][10], "zvm60"))
368 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
369 else if(!strcmp(&argv[1][10], "zenvision"))
370 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
371 else if(!strcmp(&argv[1][10], "zenv"))
372 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
373 else if(!strcmp(&argv[1][10], "zen"))
374 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
375 else
377 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
378 return 2;
381 else if(!strncmp(argv[1], "-mi4", 4)) {
382 int mi4magic;
383 char model[4] = "";
384 char type[4] = "";
386 if(!strcmp(&argv[1][4], "v2")) {
387 mi4magic = MI4_MAGIC_DEFAULT;
388 version = 0x00010201;
390 else if(!strcmp(&argv[1][4], "v3")) {
391 mi4magic = MI4_MAGIC_DEFAULT;
392 version = 0x00010301;
394 else if(!strcmp(&argv[1][4], "r")) {
395 mi4magic = MI4_MAGIC_R;
396 version = 0x00010301;
398 else {
399 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
400 return -1;
403 iname = argv[2];
404 oname = argv[3];
406 if(!strncmp(argv[2], "-model=", 7)) {
407 iname = argv[3];
408 oname = argv[4];
409 strncpy(model, &argv[2][7], 4);
411 if(!strncmp(argv[3], "-type=", 6)) {
412 iname = argv[4];
413 oname = argv[5];
414 strncpy(type, &argv[3][6], 4);
418 return mi4_encode(iname, oname, version, mi4magic, model, type);
421 /* open file */
422 file = fopen(iname,"rb");
423 if (!file) {
424 perror(iname);
425 return -1;
427 fseek(file,0,SEEK_END);
428 length = ftell(file);
429 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
431 if ((method == scramble) &&
432 ((length + headerlen) >= size_limit[model_id])) {
433 printf("error: firmware image is %ld bytes while max size is %u!\n",
434 length + headerlen,
435 size_limit[model_id]);
436 fclose(file);
437 return -1;
440 fseek(file,0,SEEK_SET);
441 inbuf = malloc(length);
442 if (method == xor)
443 outbuf = malloc(length*2);
444 else if(method == add)
445 outbuf = malloc(length + 8);
446 else
447 outbuf = malloc(length);
448 if ( !inbuf || !outbuf ) {
449 printf("out of memory!\n");
450 return -1;
452 if(length> 4) {
453 /* zero-fill the last 4 bytes to make sure there's no rubbish there
454 when we write the size-aligned file later */
455 memset(outbuf+length-4, 0, 4);
458 /* read file */
459 i=fread(inbuf,1,length,file);
460 if ( !i ) {
461 perror(iname);
462 return -1;
464 fclose(file);
466 switch (method)
468 case add:
469 for (i = 0; i < length; i++) {
470 /* add 8 unsigned bits but keep a 32 bit sum */
471 chksum += inbuf[i];
473 break;
474 case scramble:
475 slen = length/4;
476 for (i = 0; i < length; i++) {
477 unsigned long addr = (i >> 2) + ((i % 4) * slen);
478 unsigned char data = inbuf[i];
479 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
480 outbuf[addr] = data;
482 break;
484 case xor:
485 /* "compress" */
486 slen = 0;
487 for (i=0; i<length; i++) {
488 if (!(i&7))
489 outbuf[slen++] = 0xff; /* all data is uncompressed */
490 outbuf[slen++] = inbuf[i];
492 break;
493 case none:
494 default:
495 /* dummy case just to silence picky compilers */
496 break;
499 if((method == none) || (method == scramble) || (method == xor)) {
500 /* calculate checksum */
501 for (i=0;i<length;i++)
502 crc += inbuf[i];
505 memset(header, 0, sizeof header);
506 switch (method)
508 case add:
510 int2be(chksum, header); /* checksum, big-endian */
511 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
512 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
513 headerlen = 8;
515 break;
517 case tcc_sum:
518 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
519 telechips_encode_sum(outbuf, length);
520 break;
522 case tcc_crc:
523 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
524 telechips_encode_crc(outbuf, length);
525 break;
527 case scramble:
528 if (headerlen == 6) {
529 int2be(length, header);
530 header[4] = (crc >> 8) & 0xff;
531 header[5] = crc & 0xff;
533 else {
534 header[0] =
535 header[1] =
536 header[2] =
537 header[3] = 0xff; /* ??? */
539 header[6] = (crc >> 8) & 0xff;
540 header[7] = crc & 0xff;
542 header[11] = version;
544 header[15] = headerlen; /* really? */
546 int2be(length, &header[20]);
548 break;
550 case xor:
552 int xorlen = strlen(xorstring);
554 /* xor data */
555 for (i=0; i<slen; i++)
556 outbuf[i] ^= xorstring[i & (xorlen-1)];
558 /* calculate checksum */
559 for (i=0; i<slen; i++)
560 crc += outbuf[i];
562 header[0] = header[2] = 'Z';
563 header[1] = header[3] = version;
564 int2le(length, &header[4]);
565 int2le(slen, &header[8]);
566 int2le(crc, &header[12]);
567 length = slen;
568 break;
571 #define MY_FIRMWARE_TYPE "Rockbox"
572 #define MY_HEADER_VERSION 1
573 default:
574 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
575 header[9]='\0'; /*shouldn't have to, but to be SURE */
576 header[10]=MY_HEADER_VERSION&0xFF;
577 header[11]=(crc>>8)&0xFF;
578 header[12]=crc&0xFF;
579 int2be(sizeof(header), &header[12]);
580 break;
583 /* write file */
584 file = fopen(oname,"wb");
585 if ( !file ) {
586 perror(oname);
587 return -1;
589 if (headerlen > 0) {
590 if ( !fwrite(header,headerlen,1,file) ) {
591 perror(oname);
592 return -1;
595 if ( !fwrite(outbuf,length,1,file) ) {
596 perror(oname);
597 return -1;
599 fclose(file);
601 free(inbuf);
602 free(outbuf);
604 return 0;
607 int iaudio_encode(char *iname, char *oname, char *idstring)
609 size_t len;
610 int length;
611 FILE *file;
612 unsigned char *outbuf;
613 int i;
614 unsigned char sum = 0;
616 file = fopen(iname, "rb");
617 if (!file) {
618 perror(iname);
619 return -1;
621 fseek(file,0,SEEK_END);
622 length = ftell(file);
624 fseek(file,0,SEEK_SET);
625 outbuf = malloc(length+0x1030);
627 if ( !outbuf ) {
628 printf("out of memory!\n");
629 return -1;
632 len = fread(outbuf+0x1030, 1, length, file);
633 if(len < (size_t) length) {
634 perror(iname);
635 return -2;
638 memset(outbuf, 0, 0x1030);
639 strcpy((char *)outbuf, idstring);
640 memcpy(outbuf+0x20, iaudio_bl_flash,
641 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
642 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
643 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
644 outbuf[0x19] = 2;
646 for(i = 0; i < length;i++)
647 sum += outbuf[0x1030 + i];
649 int2be(length, &outbuf[0x1024]);
650 outbuf[0x102b] = sum;
652 fclose(file);
654 file = fopen(oname, "wb");
655 if (!file) {
656 perror(oname);
657 return -3;
660 len = fwrite(outbuf, 1, length+0x1030, file);
661 if(len < (size_t)length) {
662 perror(oname);
663 return -4;
666 fclose(file);
667 return 0;
671 /* Create an ipod firmware partition image
673 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
675 This function doesn't yet handle the Broadcom resource image for the 5g,
676 so the resulting images won't be usable.
678 This has also only been tested on an ipod Photo
681 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
683 static const char *apple_stop_sign = "{{~~ /-----\\ "\
684 "{{~~ / \\ "\
685 "{{~~| | "\
686 "{{~~| S T O P | "\
687 "{{~~| | "\
688 "{{~~ \\ / "\
689 "{{~~ \\-----/ "\
690 "Copyright(C) 200"\
691 "1 Apple Computer"\
692 ", Inc.----------"\
693 "----------------"\
694 "----------------"\
695 "----------------"\
696 "----------------"\
697 "----------------"\
698 "---------------";
699 size_t len;
700 int length;
701 int rsrclength;
702 int rsrcoffset;
703 FILE *file;
704 unsigned int sum = 0;
705 unsigned int rsrcsum = 0;
706 unsigned char *outbuf;
707 int bufsize;
708 int i;
710 file = fopen(iname, "rb");
711 if (!file) {
712 perror(iname);
713 return -1;
715 fseek(file,0,SEEK_END);
716 length = ftell(file);
718 fseek(file,0,SEEK_SET);
720 bufsize=(length+0x4600);
721 if (fake_rsrc) {
722 bufsize = (bufsize + 0x400) & ~0x200;
725 outbuf = malloc(bufsize);
727 if ( !outbuf ) {
728 printf("out of memory!\n");
729 return -1;
732 len = fread(outbuf+0x4600, 1, length, file);
733 if(len < (size_t)length) {
734 perror(iname);
735 return -2;
737 fclose(file);
739 /* Calculate checksum for later use in header */
740 for(i = 0x4600; i < 0x4600+length;i++)
741 sum += outbuf[i];
743 /* Clear the header area to zero */
744 memset(outbuf, 0, 0x4600);
746 /* APPLE STOP SIGN */
747 strcpy((char *)outbuf, apple_stop_sign);
749 /* VOLUME HEADER */
750 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
751 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
752 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
753 short2le(fw_ver, &outbuf[0x10a]);
755 /* Firmware Directory - "osos" entry */
756 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
757 int2le(0, &outbuf[0x4208]); /* id */
758 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
759 int2le(length, &outbuf[0x4210]); /* Length of firmware */
760 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
761 int2le(0, &outbuf[0x4218]); /* Entry Offset */
762 int2le(sum, &outbuf[0x421c]); /* Checksum */
763 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
764 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
766 /* "rsrc" entry (if applicable) */
767 if (fake_rsrc) {
768 rsrcoffset=(length+0x4600+0x200) & ~0x200;
769 rsrclength=0x200;
770 rsrcsum=0;
772 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
773 int2le(0, &outbuf[0x4230]); /* id */
774 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
775 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
776 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
777 int2le(0, &outbuf[0x4240]); /* Entry Offset */
778 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
779 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
780 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
783 file = fopen(oname, "wb");
784 if (!file) {
785 perror(oname);
786 return -3;
789 len = fwrite(outbuf, 1, length+0x4600, file);
790 if(len < (size_t)length) {
791 perror(oname);
792 return -4;
795 fclose(file);
797 return 0;