fix building on w32.
[Rockbox.git] / tools / scramble.c
blob8fd4ca98f43ec1341af7c674d0c648a598da1e15
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
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 ****************************************************************************/
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdbool.h>
23 #include <string.h>
24 #include "iriver.h"
25 #include "gigabeat.h"
26 #include "gigabeats.h"
27 #include "mi4.h"
28 #include "telechips.h"
29 #include "creative.h"
30 #include "iaudio_bl_flash.h"
32 int iaudio_encode(char *iname, char *oname, char *idstring);
33 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc);
35 enum
37 ARCHOS_PLAYER, /* and V1 recorder */
38 ARCHOS_V2RECORDER,
39 ARCHOS_FMRECORDER,
40 ARCHOS_ONDIO_SP,
41 ARCHOS_ONDIO_FM
44 static unsigned int size_limit[] =
46 0x32000, /* ARCHOS_PLAYER */
47 0x64000, /* ARCHOS_V2RECORDER */
48 0x64000, /* ARCHOS_FMRECORDER */
49 0x64000, /* ARCHOS_ONDIO_SP */
50 0x64000 /* ARCHOS_ONDIO_FM */
53 void short2le(unsigned short val, unsigned char* addr)
55 addr[0] = val & 0xFF;
56 addr[1] = (val >> 8) & 0xff;
59 unsigned int le2int(unsigned char* buf)
61 unsigned int res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
63 return res;
66 void int2le(unsigned int val, unsigned char* addr)
68 addr[0] = val & 0xFF;
69 addr[1] = (val >> 8) & 0xff;
70 addr[2] = (val >> 16) & 0xff;
71 addr[3] = (val >> 24) & 0xff;
74 void int2be(unsigned int val, unsigned char* addr)
76 addr[0] = (val >> 24) & 0xff;
77 addr[1] = (val >> 16) & 0xff;
78 addr[2] = (val >> 8) & 0xff;
79 addr[3] = val & 0xFF;
82 void short2be(unsigned short val, unsigned char* addr)
84 addr[0] = (val >> 8) & 0xff;
85 addr[1] = val & 0xFF;
88 void usage(void)
90 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
91 printf("options:\n"
92 "\t-fm Archos FM recorder format\n"
93 "\t-v2 Archos V2 recorder format\n"
94 "\t-ofm Archos Ondio FM recorder format\n"
95 "\t-osp Archos Ondio SP format\n"
96 "\t-neo SSI Neo format\n"
97 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
98 "\t-iriver iRiver format\n"
99 "\t-iaudiox5 iAudio X5 format\n"
100 "\t-iaudiox5v iAudio X5V format\n"
101 "\t-iaudiom5 iAudio M5 format\n"
102 "\t-iaudiom3 iAudio M3 format\n");
103 printf("\t-ipod3g ipod firmware partition format (3rd Gen)\n"
104 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
105 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
106 "\t-creative=X Creative firmware structure format\n"
107 "\t (X values: zvm, zvm60, zenvision\n"
108 "\t zenv, zen\n");
109 printf("\t-gigabeat Toshiba Gigabeat F/X format\n"
110 "\t-gigabeats Toshiba Gigabeat S format\n"
111 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
112 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
113 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
114 "\t All mi4 options take two optional arguments:\n");
115 printf("\t -model=XXXX where XXXX is the model id string\n"
116 "\t -type=XXXX where XXXX is a string indicating the \n"
117 "\t type of binary, eg. RBOS, RBBL\n"
118 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
119 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
120 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
121 "\t ip3g, ip4g, mini, iax5, iam5, iam3, h10, h10_5gb,\n"
122 "\t tpj2, c200, e200, giga, gigs, m100, m500, d2,\n");
123 printf("\t 9200, 1630)\n");
124 printf("\nNo option results in Archos standard player/recorder format.\n");
126 exit(1);
129 int main (int argc, char** argv)
131 unsigned long length,i,slen=0;
132 unsigned char *inbuf,*outbuf;
133 unsigned short crc=0;
134 unsigned long chksum=0; /* 32 bit checksum */
135 unsigned char header[24];
136 char *iname = argv[1];
137 char *oname = argv[2];
138 char *xorstring=NULL;
139 int headerlen = 6;
140 FILE* file;
141 int version=0;
142 unsigned long modelnum;
143 char modelname[5];
144 int model_id;
145 enum { none, scramble, xor, tcc_sum, tcc_crc, add } method = scramble;
147 model_id = ARCHOS_PLAYER;
149 if (argc < 3) {
150 usage();
153 if(!strcmp(argv[1], "-fm")) {
154 headerlen = 24;
155 iname = argv[2];
156 oname = argv[3];
157 version = 4;
158 model_id = ARCHOS_FMRECORDER;
161 else if(!strcmp(argv[1], "-v2")) {
162 headerlen = 24;
163 iname = argv[2];
164 oname = argv[3];
165 version = 2;
166 model_id = ARCHOS_V2RECORDER;
169 else if(!strcmp(argv[1], "-ofm")) {
170 headerlen = 24;
171 iname = argv[2];
172 oname = argv[3];
173 version = 8;
174 model_id = ARCHOS_ONDIO_FM;
177 else if(!strcmp(argv[1], "-osp")) {
178 headerlen = 24;
179 iname = argv[2];
180 oname = argv[3];
181 version = 16;
182 model_id = ARCHOS_ONDIO_SP;
185 else if(!strcmp(argv[1], "-neo")) {
186 headerlen = 17;
187 iname = argv[2];
188 oname = argv[3];
189 method = none;
191 else if(!strncmp(argv[1], "-mm=", 4)) {
192 headerlen = 16;
193 iname = argv[2];
194 oname = argv[3];
195 method = xor;
196 version = argv[1][4];
197 if (argc > 4)
198 xorstring = argv[4];
199 else {
200 printf("Multimedia needs an xor string\n");
201 return -1;
204 else if(!strncmp(argv[1], "-tcc=", 4)) {
205 headerlen = 0;
206 iname = argv[2];
207 oname = argv[3];
209 if(!strcmp(&argv[1][5], "sum"))
210 method = tcc_sum;
211 else if(!strcmp(&argv[1][5], "crc"))
212 method = tcc_crc;
213 else {
214 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
215 return 2;
218 else if(!strncmp(argv[1], "-add=", 5)) {
219 iname = argv[2];
220 oname = argv[3];
221 method = add;
223 if(!strcmp(&argv[1][5], "h120"))
224 modelnum = 0;
225 else if(!strcmp(&argv[1][5], "h140"))
226 modelnum = 0; /* the same as the h120 */
227 else if(!strcmp(&argv[1][5], "h100"))
228 modelnum = 1;
229 else if(!strcmp(&argv[1][5], "h300"))
230 modelnum = 2;
231 else if(!strcmp(&argv[1][5], "ipco"))
232 modelnum = 3;
233 else if(!strcmp(&argv[1][5], "nano"))
234 modelnum = 4;
235 else if(!strcmp(&argv[1][5], "ipvd"))
236 modelnum = 5;
237 else if(!strcmp(&argv[1][5], "fp7x"))
238 modelnum = 6;
239 else if(!strcmp(&argv[1][5], "ip3g"))
240 modelnum = 7;
241 else if(!strcmp(&argv[1][5], "ip4g"))
242 modelnum = 8;
243 else if(!strcmp(&argv[1][5], "mini"))
244 modelnum = 9;
245 else if(!strcmp(&argv[1][5], "iax5"))
246 modelnum = 10;
247 else if(!strcmp(&argv[1][5], "mn2g"))
248 modelnum = 11;
249 else if(!strcmp(&argv[1][5], "h10"))
250 modelnum = 13;
251 else if(!strcmp(&argv[1][5], "h10_5gb"))
252 modelnum = 14;
253 else if(!strcmp(&argv[1][5], "tpj2"))
254 modelnum = 15;
255 else if(!strcmp(&argv[1][5], "e200"))
256 modelnum = 16;
257 else if(!strcmp(&argv[1][5], "iam5"))
258 modelnum = 17;
259 else if(!strcmp(&argv[1][5], "giga"))
260 modelnum = 18;
261 else if(!strcmp(&argv[1][5], "1g2g"))
262 modelnum = 19;
263 else if(!strcmp(&argv[1][5], "c200"))
264 modelnum = 20;
265 else if(!strcmp(&argv[1][5], "gigs"))
266 modelnum = 21;
267 else if(!strcmp(&argv[1][5], "m500"))
268 modelnum = 22;
269 else if(!strcmp(&argv[1][5], "m100"))
270 modelnum = 23;
271 else if(!strcmp(&argv[1][5], "d2"))
272 modelnum = 24;
273 else if(!strcmp(&argv[1][5], "iam3"))
274 modelnum = 25;
275 else if(!strcmp(&argv[1][5], "9200")) /* Philips SA9200 */
276 modelnum = 26;
277 else if(!strcmp(&argv[1][5], "1630")) /* Philips HDD1630 */
278 modelnum = 31;
279 else {
280 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
281 return 2;
283 /* we store a 4-letter model name too, for humans */
284 strcpy(modelname, &argv[1][5]);
285 chksum = modelnum; /* start checksum calcs with this */
288 else if(!strcmp(argv[1], "-iriver")) {
289 /* iRiver code dealt with in the iriver.c code */
290 iname = argv[2];
291 oname = argv[3];
292 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
294 else if(!strcmp(argv[1], "-gigabeat")) {
295 /* iRiver code dealt with in the iriver.c code */
296 iname = argv[2];
297 oname = argv[3];
298 gigabeat_code(iname, oname);
299 return 0;
301 else if(!strcmp(argv[1], "-gigabeats")) {
302 iname = argv[2];
303 oname = argv[3];
304 gigabeat_s_code(iname, oname);
305 return 0;
307 else if(!strcmp(argv[1], "-iaudiox5")) {
308 iname = argv[2];
309 oname = argv[3];
310 return iaudio_encode(iname, oname, "COWON_X5_FW");
312 else if(!strcmp(argv[1], "-iaudiox5v")) {
313 iname = argv[2];
314 oname = argv[3];
315 return iaudio_encode(iname, oname, "COWON_X5V_FW");
317 else if(!strcmp(argv[1], "-iaudiom5")) {
318 iname = argv[2];
319 oname = argv[3];
320 return iaudio_encode(iname, oname, "COWON_M5_FW");
322 else if(!strcmp(argv[1], "-iaudiom3")) {
323 iname = argv[2];
324 oname = argv[3];
325 return iaudio_encode(iname, oname, "COWON_M3_FW");
327 else if(!strcmp(argv[1], "-ipod3g")) {
328 iname = argv[2];
329 oname = argv[3];
330 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
332 else if(!strcmp(argv[1], "-ipod4g")) {
333 iname = argv[2];
334 oname = argv[3];
335 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
337 else if(!strcmp(argv[1], "-ipod5g")) {
338 iname = argv[2];
339 oname = argv[3];
340 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
342 else if(!strncmp(argv[1], "-creative=", 10)) {
343 iname = argv[2];
344 oname = argv[3];
345 if(!strcmp(&argv[1][10], "zvm"))
346 return zvm_encode(iname, oname, ZENVISIONM);
347 else if(!strcmp(&argv[1][10], "zvm60"))
348 return zvm_encode(iname, oname, ZENVISIONM60);
349 else if(!strcmp(&argv[1][10], "zenvision"))
350 return zvm_encode(iname, oname, ZENVISION);
351 else if(!strcmp(&argv[1][10], "zenv"))
352 return zvm_encode(iname, oname, ZENV);
353 else if(!strcmp(&argv[1][10], "zen"))
354 return zvm_encode(iname, oname, ZEN);
355 else {
356 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
357 return 2;
360 else if(!strncmp(argv[1], "-mi4", 4)) {
361 int mi4magic;
362 char model[4] = "";
363 char type[4] = "";
365 if(!strcmp(&argv[1][4], "v2")) {
366 mi4magic = MI4_MAGIC_DEFAULT;
367 version = 0x00010201;
369 else if(!strcmp(&argv[1][4], "v3")) {
370 mi4magic = MI4_MAGIC_DEFAULT;
371 version = 0x00010301;
373 else if(!strcmp(&argv[1][4], "r")) {
374 mi4magic = MI4_MAGIC_R;
375 version = 0x00010301;
377 else {
378 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
379 return -1;
382 iname = argv[2];
383 oname = argv[3];
385 if(!strncmp(argv[2], "-model=", 7)) {
386 iname = argv[3];
387 oname = argv[4];
388 strncpy(model, &argv[2][7], 4);
390 if(!strncmp(argv[3], "-type=", 6)) {
391 iname = argv[4];
392 oname = argv[5];
393 strncpy(type, &argv[3][6], 4);
397 return mi4_encode(iname, oname, version, mi4magic, model, type);
400 /* open file */
401 file = fopen(iname,"rb");
402 if (!file) {
403 perror(iname);
404 return -1;
406 fseek(file,0,SEEK_END);
407 length = ftell(file);
408 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
410 if ((method == scramble) &&
411 ((length + headerlen) >= size_limit[model_id])) {
412 printf("error: firmware image is %ld bytes while max size is %u!\n",
413 length + headerlen,
414 size_limit[model_id]);
415 fclose(file);
416 return -1;
419 fseek(file,0,SEEK_SET);
420 inbuf = malloc(length);
421 if (method == xor)
422 outbuf = malloc(length*2);
423 else if(method == add)
424 outbuf = malloc(length + 8);
425 else
426 outbuf = malloc(length);
427 if ( !inbuf || !outbuf ) {
428 printf("out of memory!\n");
429 return -1;
431 if(length> 4) {
432 /* zero-fill the last 4 bytes to make sure there's no rubbish there
433 when we write the size-aligned file later */
434 memset(outbuf+length-4, 0, 4);
437 /* read file */
438 i=fread(inbuf,1,length,file);
439 if ( !i ) {
440 perror(iname);
441 return -1;
443 fclose(file);
445 switch (method)
447 case add:
448 for (i = 0; i < length; i++) {
449 /* add 8 unsigned bits but keep a 32 bit sum */
450 chksum += inbuf[i];
452 break;
453 case scramble:
454 slen = length/4;
455 for (i = 0; i < length; i++) {
456 unsigned long addr = (i >> 2) + ((i % 4) * slen);
457 unsigned char data = inbuf[i];
458 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
459 outbuf[addr] = data;
461 break;
463 case xor:
464 /* "compress" */
465 slen = 0;
466 for (i=0; i<length; i++) {
467 if (!(i&7))
468 outbuf[slen++] = 0xff; /* all data is uncompressed */
469 outbuf[slen++] = inbuf[i];
471 break;
472 case none:
473 default:
474 /* dummy case just to silence picky compilers */
475 break;
478 if((method == none) || (method == scramble) || (method == xor)) {
479 /* calculate checksum */
480 for (i=0;i<length;i++)
481 crc += inbuf[i];
484 memset(header, 0, sizeof header);
485 switch (method)
487 case add:
489 int2be(chksum, header); /* checksum, big-endian */
490 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
491 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
492 headerlen = 8;
494 break;
496 case tcc_sum:
497 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
498 telechips_encode_sum(outbuf, length);
499 break;
501 case tcc_crc:
502 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
503 telechips_encode_crc(outbuf, length);
504 break;
506 case scramble:
507 if (headerlen == 6) {
508 int2be(length, header);
509 header[4] = (crc >> 8) & 0xff;
510 header[5] = crc & 0xff;
512 else {
513 header[0] =
514 header[1] =
515 header[2] =
516 header[3] = 0xff; /* ??? */
518 header[6] = (crc >> 8) & 0xff;
519 header[7] = crc & 0xff;
521 header[11] = version;
523 header[15] = headerlen; /* really? */
525 int2be(length, &header[20]);
527 break;
529 case xor:
531 int xorlen = strlen(xorstring);
533 /* xor data */
534 for (i=0; i<slen; i++)
535 outbuf[i] ^= xorstring[i & (xorlen-1)];
537 /* calculate checksum */
538 for (i=0; i<slen; i++)
539 crc += outbuf[i];
541 header[0] = header[2] = 'Z';
542 header[1] = header[3] = version;
543 int2le(length, &header[4]);
544 int2le(slen, &header[8]);
545 int2le(crc, &header[12]);
546 length = slen;
547 break;
550 #define MY_FIRMWARE_TYPE "Rockbox"
551 #define MY_HEADER_VERSION 1
552 default:
553 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
554 header[9]='\0'; /*shouldn't have to, but to be SURE */
555 header[10]=MY_HEADER_VERSION&0xFF;
556 header[11]=(crc>>8)&0xFF;
557 header[12]=crc&0xFF;
558 int2be(sizeof(header), &header[12]);
559 break;
562 /* write file */
563 file = fopen(oname,"wb");
564 if ( !file ) {
565 perror(oname);
566 return -1;
568 if (headerlen > 0) {
569 if ( !fwrite(header,headerlen,1,file) ) {
570 perror(oname);
571 return -1;
574 if ( !fwrite(outbuf,length,1,file) ) {
575 perror(oname);
576 return -1;
578 fclose(file);
580 free(inbuf);
581 free(outbuf);
583 return 0;
586 int iaudio_encode(char *iname, char *oname, char *idstring)
588 size_t len;
589 int length;
590 FILE *file;
591 unsigned char *outbuf;
592 int i;
593 unsigned char sum = 0;
595 file = fopen(iname, "rb");
596 if (!file) {
597 perror(iname);
598 return -1;
600 fseek(file,0,SEEK_END);
601 length = ftell(file);
603 fseek(file,0,SEEK_SET);
604 outbuf = malloc(length+0x1030);
606 if ( !outbuf ) {
607 printf("out of memory!\n");
608 return -1;
611 len = fread(outbuf+0x1030, 1, length, file);
612 if(len < (size_t) length) {
613 perror(iname);
614 return -2;
617 memset(outbuf, 0, 0x1030);
618 strcpy((char *)outbuf, idstring);
619 memcpy(outbuf+0x20, iaudio_bl_flash,
620 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
621 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
622 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
623 outbuf[0x19] = 2;
625 for(i = 0; i < length;i++)
626 sum += outbuf[0x1030 + i];
628 int2be(length, &outbuf[0x1024]);
629 outbuf[0x102b] = sum;
631 fclose(file);
633 file = fopen(oname, "wb");
634 if (!file) {
635 perror(oname);
636 return -3;
639 len = fwrite(outbuf, 1, length+0x1030, file);
640 if(len < (size_t)length) {
641 perror(oname);
642 return -4;
645 fclose(file);
646 return 0;
650 /* Create an ipod firmware partition image
652 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
654 This function doesn't yet handle the Broadcom resource image for the 5g,
655 so the resulting images won't be usable.
657 This has also only been tested on an ipod Photo
660 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
662 static const char *apple_stop_sign = "{{~~ /-----\\ "\
663 "{{~~ / \\ "\
664 "{{~~| | "\
665 "{{~~| S T O P | "\
666 "{{~~| | "\
667 "{{~~ \\ / "\
668 "{{~~ \\-----/ "\
669 "Copyright(C) 200"\
670 "1 Apple Computer"\
671 ", Inc.----------"\
672 "----------------"\
673 "----------------"\
674 "----------------"\
675 "----------------"\
676 "----------------"\
677 "---------------";
678 size_t len;
679 int length;
680 int rsrclength;
681 int rsrcoffset;
682 FILE *file;
683 unsigned int sum = 0;
684 unsigned int rsrcsum = 0;
685 unsigned char *outbuf;
686 int bufsize;
687 int i;
689 file = fopen(iname, "rb");
690 if (!file) {
691 perror(iname);
692 return -1;
694 fseek(file,0,SEEK_END);
695 length = ftell(file);
697 fseek(file,0,SEEK_SET);
699 bufsize=(length+0x4600);
700 if (fake_rsrc) {
701 bufsize = (bufsize + 0x400) & ~0x200;
704 outbuf = malloc(bufsize);
706 if ( !outbuf ) {
707 printf("out of memory!\n");
708 return -1;
711 len = fread(outbuf+0x4600, 1, length, file);
712 if(len < (size_t)length) {
713 perror(iname);
714 return -2;
716 fclose(file);
718 /* Calculate checksum for later use in header */
719 for(i = 0x4600; i < 0x4600+length;i++)
720 sum += outbuf[i];
722 /* Clear the header area to zero */
723 memset(outbuf, 0, 0x4600);
725 /* APPLE STOP SIGN */
726 strcpy((char *)outbuf, apple_stop_sign);
728 /* VOLUME HEADER */
729 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
730 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
731 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
732 short2le(fw_ver, &outbuf[0x10a]);
734 /* Firmware Directory - "osos" entry */
735 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
736 int2le(0, &outbuf[0x4208]); /* id */
737 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
738 int2le(length, &outbuf[0x4210]); /* Length of firmware */
739 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
740 int2le(0, &outbuf[0x4218]); /* Entry Offset */
741 int2le(sum, &outbuf[0x421c]); /* Checksum */
742 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
743 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
745 /* "rsrc" entry (if applicable) */
746 if (fake_rsrc) {
747 rsrcoffset=(length+0x4600+0x200) & ~0x200;
748 rsrclength=0x200;
749 rsrcsum=0;
751 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
752 int2le(0, &outbuf[0x4230]); /* id */
753 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
754 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
755 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
756 int2le(0, &outbuf[0x4240]); /* Entry Offset */
757 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
758 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
759 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
762 file = fopen(oname, "wb");
763 if (!file) {
764 perror(oname);
765 return -3;
768 len = fwrite(outbuf, 1, length+0x4600, file);
769 if(len < (size_t)length) {
770 perror(oname);
771 return -4;
774 fclose(file);
776 return 0;