C200: Also flip the function of the volume buttons when display flip is enabled....
[kugel-rb.git] / tools / scramble.c
blob5dff4f408627f986d19a39716cf717e55d9ae588
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)\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], "9200")) /* Philips SA9200 */
279 modelnum = 26;
280 else if(!strcmp(&argv[1][5], "1630")) /* Philips HDD1630 */
281 modelnum = 31;
282 else {
283 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
284 return 2;
286 /* we store a 4-letter model name too, for humans */
287 strcpy(modelname, &argv[1][5]);
288 chksum = modelnum; /* start checksum calcs with this */
291 else if(!strcmp(argv[1], "-iriver")) {
292 /* iRiver code dealt with in the iriver.c code */
293 iname = argv[2];
294 oname = argv[3];
295 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
297 else if(!strcmp(argv[1], "-gigabeat")) {
298 /* iRiver code dealt with in the iriver.c code */
299 iname = argv[2];
300 oname = argv[3];
301 gigabeat_code(iname, oname);
302 return 0;
304 else if(!strcmp(argv[1], "-gigabeats")) {
305 iname = argv[2];
306 oname = argv[3];
307 gigabeat_s_code(iname, oname);
308 return 0;
310 else if(!strcmp(argv[1], "-iaudiox5")) {
311 iname = argv[2];
312 oname = argv[3];
313 return iaudio_encode(iname, oname, "COWON_X5_FW");
315 else if(!strcmp(argv[1], "-iaudiox5v")) {
316 iname = argv[2];
317 oname = argv[3];
318 return iaudio_encode(iname, oname, "COWON_X5V_FW");
320 else if(!strcmp(argv[1], "-iaudiom5")) {
321 iname = argv[2];
322 oname = argv[3];
323 return iaudio_encode(iname, oname, "COWON_M5_FW");
325 else if(!strcmp(argv[1], "-iaudiom3")) {
326 iname = argv[2];
327 oname = argv[3];
328 return iaudio_encode(iname, oname, "COWON_M3_FW");
330 else if(!strcmp(argv[1], "-ipod3g")) {
331 iname = argv[2];
332 oname = argv[3];
333 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
335 else if(!strcmp(argv[1], "-ipod4g")) {
336 iname = argv[2];
337 oname = argv[3];
338 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
340 else if(!strcmp(argv[1], "-ipod5g")) {
341 iname = argv[2];
342 oname = argv[3];
343 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
345 else if(!strncmp(argv[1], "-creative=", 10))
347 if(!strcmp(argv[2], "-no-ciff"))
349 creative_enable_ciff = false;
350 iname = argv[3];
351 oname = argv[4];
353 else
355 creative_enable_ciff = true;
356 iname = argv[2];
357 oname = argv[3];
359 if(!strcmp(&argv[1][10], "zvm"))
360 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
361 else if(!strcmp(&argv[1][10], "zvm60"))
362 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
363 else if(!strcmp(&argv[1][10], "zenvision"))
364 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
365 else if(!strcmp(&argv[1][10], "zenv"))
366 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
367 else if(!strcmp(&argv[1][10], "zen"))
368 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
369 else
371 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
372 return 2;
375 else if(!strncmp(argv[1], "-mi4", 4)) {
376 int mi4magic;
377 char model[4] = "";
378 char type[4] = "";
380 if(!strcmp(&argv[1][4], "v2")) {
381 mi4magic = MI4_MAGIC_DEFAULT;
382 version = 0x00010201;
384 else if(!strcmp(&argv[1][4], "v3")) {
385 mi4magic = MI4_MAGIC_DEFAULT;
386 version = 0x00010301;
388 else if(!strcmp(&argv[1][4], "r")) {
389 mi4magic = MI4_MAGIC_R;
390 version = 0x00010301;
392 else {
393 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
394 return -1;
397 iname = argv[2];
398 oname = argv[3];
400 if(!strncmp(argv[2], "-model=", 7)) {
401 iname = argv[3];
402 oname = argv[4];
403 strncpy(model, &argv[2][7], 4);
405 if(!strncmp(argv[3], "-type=", 6)) {
406 iname = argv[4];
407 oname = argv[5];
408 strncpy(type, &argv[3][6], 4);
412 return mi4_encode(iname, oname, version, mi4magic, model, type);
415 /* open file */
416 file = fopen(iname,"rb");
417 if (!file) {
418 perror(iname);
419 return -1;
421 fseek(file,0,SEEK_END);
422 length = ftell(file);
423 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
425 if ((method == scramble) &&
426 ((length + headerlen) >= size_limit[model_id])) {
427 printf("error: firmware image is %ld bytes while max size is %u!\n",
428 length + headerlen,
429 size_limit[model_id]);
430 fclose(file);
431 return -1;
434 fseek(file,0,SEEK_SET);
435 inbuf = malloc(length);
436 if (method == xor)
437 outbuf = malloc(length*2);
438 else if(method == add)
439 outbuf = malloc(length + 8);
440 else
441 outbuf = malloc(length);
442 if ( !inbuf || !outbuf ) {
443 printf("out of memory!\n");
444 return -1;
446 if(length> 4) {
447 /* zero-fill the last 4 bytes to make sure there's no rubbish there
448 when we write the size-aligned file later */
449 memset(outbuf+length-4, 0, 4);
452 /* read file */
453 i=fread(inbuf,1,length,file);
454 if ( !i ) {
455 perror(iname);
456 return -1;
458 fclose(file);
460 switch (method)
462 case add:
463 for (i = 0; i < length; i++) {
464 /* add 8 unsigned bits but keep a 32 bit sum */
465 chksum += inbuf[i];
467 break;
468 case scramble:
469 slen = length/4;
470 for (i = 0; i < length; i++) {
471 unsigned long addr = (i >> 2) + ((i % 4) * slen);
472 unsigned char data = inbuf[i];
473 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
474 outbuf[addr] = data;
476 break;
478 case xor:
479 /* "compress" */
480 slen = 0;
481 for (i=0; i<length; i++) {
482 if (!(i&7))
483 outbuf[slen++] = 0xff; /* all data is uncompressed */
484 outbuf[slen++] = inbuf[i];
486 break;
487 case none:
488 default:
489 /* dummy case just to silence picky compilers */
490 break;
493 if((method == none) || (method == scramble) || (method == xor)) {
494 /* calculate checksum */
495 for (i=0;i<length;i++)
496 crc += inbuf[i];
499 memset(header, 0, sizeof header);
500 switch (method)
502 case add:
504 int2be(chksum, header); /* checksum, big-endian */
505 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
506 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
507 headerlen = 8;
509 break;
511 case tcc_sum:
512 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
513 telechips_encode_sum(outbuf, length);
514 break;
516 case tcc_crc:
517 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
518 telechips_encode_crc(outbuf, length);
519 break;
521 case scramble:
522 if (headerlen == 6) {
523 int2be(length, header);
524 header[4] = (crc >> 8) & 0xff;
525 header[5] = crc & 0xff;
527 else {
528 header[0] =
529 header[1] =
530 header[2] =
531 header[3] = 0xff; /* ??? */
533 header[6] = (crc >> 8) & 0xff;
534 header[7] = crc & 0xff;
536 header[11] = version;
538 header[15] = headerlen; /* really? */
540 int2be(length, &header[20]);
542 break;
544 case xor:
546 int xorlen = strlen(xorstring);
548 /* xor data */
549 for (i=0; i<slen; i++)
550 outbuf[i] ^= xorstring[i & (xorlen-1)];
552 /* calculate checksum */
553 for (i=0; i<slen; i++)
554 crc += outbuf[i];
556 header[0] = header[2] = 'Z';
557 header[1] = header[3] = version;
558 int2le(length, &header[4]);
559 int2le(slen, &header[8]);
560 int2le(crc, &header[12]);
561 length = slen;
562 break;
565 #define MY_FIRMWARE_TYPE "Rockbox"
566 #define MY_HEADER_VERSION 1
567 default:
568 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
569 header[9]='\0'; /*shouldn't have to, but to be SURE */
570 header[10]=MY_HEADER_VERSION&0xFF;
571 header[11]=(crc>>8)&0xFF;
572 header[12]=crc&0xFF;
573 int2be(sizeof(header), &header[12]);
574 break;
577 /* write file */
578 file = fopen(oname,"wb");
579 if ( !file ) {
580 perror(oname);
581 return -1;
583 if (headerlen > 0) {
584 if ( !fwrite(header,headerlen,1,file) ) {
585 perror(oname);
586 return -1;
589 if ( !fwrite(outbuf,length,1,file) ) {
590 perror(oname);
591 return -1;
593 fclose(file);
595 free(inbuf);
596 free(outbuf);
598 return 0;
601 int iaudio_encode(char *iname, char *oname, char *idstring)
603 size_t len;
604 int length;
605 FILE *file;
606 unsigned char *outbuf;
607 int i;
608 unsigned char sum = 0;
610 file = fopen(iname, "rb");
611 if (!file) {
612 perror(iname);
613 return -1;
615 fseek(file,0,SEEK_END);
616 length = ftell(file);
618 fseek(file,0,SEEK_SET);
619 outbuf = malloc(length+0x1030);
621 if ( !outbuf ) {
622 printf("out of memory!\n");
623 return -1;
626 len = fread(outbuf+0x1030, 1, length, file);
627 if(len < (size_t) length) {
628 perror(iname);
629 return -2;
632 memset(outbuf, 0, 0x1030);
633 strcpy((char *)outbuf, idstring);
634 memcpy(outbuf+0x20, iaudio_bl_flash,
635 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
636 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
637 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
638 outbuf[0x19] = 2;
640 for(i = 0; i < length;i++)
641 sum += outbuf[0x1030 + i];
643 int2be(length, &outbuf[0x1024]);
644 outbuf[0x102b] = sum;
646 fclose(file);
648 file = fopen(oname, "wb");
649 if (!file) {
650 perror(oname);
651 return -3;
654 len = fwrite(outbuf, 1, length+0x1030, file);
655 if(len < (size_t)length) {
656 perror(oname);
657 return -4;
660 fclose(file);
661 return 0;
665 /* Create an ipod firmware partition image
667 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
669 This function doesn't yet handle the Broadcom resource image for the 5g,
670 so the resulting images won't be usable.
672 This has also only been tested on an ipod Photo
675 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
677 static const char *apple_stop_sign = "{{~~ /-----\\ "\
678 "{{~~ / \\ "\
679 "{{~~| | "\
680 "{{~~| S T O P | "\
681 "{{~~| | "\
682 "{{~~ \\ / "\
683 "{{~~ \\-----/ "\
684 "Copyright(C) 200"\
685 "1 Apple Computer"\
686 ", Inc.----------"\
687 "----------------"\
688 "----------------"\
689 "----------------"\
690 "----------------"\
691 "----------------"\
692 "---------------";
693 size_t len;
694 int length;
695 int rsrclength;
696 int rsrcoffset;
697 FILE *file;
698 unsigned int sum = 0;
699 unsigned int rsrcsum = 0;
700 unsigned char *outbuf;
701 int bufsize;
702 int i;
704 file = fopen(iname, "rb");
705 if (!file) {
706 perror(iname);
707 return -1;
709 fseek(file,0,SEEK_END);
710 length = ftell(file);
712 fseek(file,0,SEEK_SET);
714 bufsize=(length+0x4600);
715 if (fake_rsrc) {
716 bufsize = (bufsize + 0x400) & ~0x200;
719 outbuf = malloc(bufsize);
721 if ( !outbuf ) {
722 printf("out of memory!\n");
723 return -1;
726 len = fread(outbuf+0x4600, 1, length, file);
727 if(len < (size_t)length) {
728 perror(iname);
729 return -2;
731 fclose(file);
733 /* Calculate checksum for later use in header */
734 for(i = 0x4600; i < 0x4600+length;i++)
735 sum += outbuf[i];
737 /* Clear the header area to zero */
738 memset(outbuf, 0, 0x4600);
740 /* APPLE STOP SIGN */
741 strcpy((char *)outbuf, apple_stop_sign);
743 /* VOLUME HEADER */
744 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
745 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
746 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
747 short2le(fw_ver, &outbuf[0x10a]);
749 /* Firmware Directory - "osos" entry */
750 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
751 int2le(0, &outbuf[0x4208]); /* id */
752 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
753 int2le(length, &outbuf[0x4210]); /* Length of firmware */
754 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
755 int2le(0, &outbuf[0x4218]); /* Entry Offset */
756 int2le(sum, &outbuf[0x421c]); /* Checksum */
757 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
758 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
760 /* "rsrc" entry (if applicable) */
761 if (fake_rsrc) {
762 rsrcoffset=(length+0x4600+0x200) & ~0x200;
763 rsrclength=0x200;
764 rsrcsum=0;
766 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
767 int2le(0, &outbuf[0x4230]); /* id */
768 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
769 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
770 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
771 int2le(0, &outbuf[0x4240]); /* Entry Offset */
772 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
773 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
774 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
777 file = fopen(oname, "wb");
778 if (!file) {
779 perror(oname);
780 return -3;
783 len = fwrite(outbuf, 1, length+0x4600, file);
784 if(len < (size_t)length) {
785 perror(oname);
786 return -4;
789 fclose(file);
791 return 0;