Factor out scramble / mkboot functions to allow easier reuse (for rbutil).
[Rockbox.git] / tools / scramble.c
blob5263809e417ae40a9a78730870f728ef07178693
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)\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 {
278 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
279 return 2;
281 /* we store a 4-letter model name too, for humans */
282 strcpy(modelname, &argv[1][5]);
283 chksum = modelnum; /* start checksum calcs with this */
286 else if(!strcmp(argv[1], "-iriver")) {
287 /* iRiver code dealt with in the iriver.c code */
288 iname = argv[2];
289 oname = argv[3];
290 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
292 else if(!strcmp(argv[1], "-gigabeat")) {
293 /* iRiver code dealt with in the iriver.c code */
294 iname = argv[2];
295 oname = argv[3];
296 gigabeat_code(iname, oname);
297 return 0;
299 else if(!strcmp(argv[1], "-gigabeats")) {
300 iname = argv[2];
301 oname = argv[3];
302 gigabeat_s_code(iname, oname);
303 return 0;
305 else if(!strcmp(argv[1], "-iaudiox5")) {
306 iname = argv[2];
307 oname = argv[3];
308 return iaudio_encode(iname, oname, "COWON_X5_FW");
310 else if(!strcmp(argv[1], "-iaudiox5v")) {
311 iname = argv[2];
312 oname = argv[3];
313 return iaudio_encode(iname, oname, "COWON_X5V_FW");
315 else if(!strcmp(argv[1], "-iaudiom5")) {
316 iname = argv[2];
317 oname = argv[3];
318 return iaudio_encode(iname, oname, "COWON_M5_FW");
320 else if(!strcmp(argv[1], "-iaudiom3")) {
321 iname = argv[2];
322 oname = argv[3];
323 return iaudio_encode(iname, oname, "COWON_M3_FW");
325 else if(!strcmp(argv[1], "-ipod3g")) {
326 iname = argv[2];
327 oname = argv[3];
328 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
330 else if(!strcmp(argv[1], "-ipod4g")) {
331 iname = argv[2];
332 oname = argv[3];
333 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
335 else if(!strcmp(argv[1], "-ipod5g")) {
336 iname = argv[2];
337 oname = argv[3];
338 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
340 else if(!strncmp(argv[1], "-creative=", 10)) {
341 iname = argv[2];
342 oname = argv[3];
343 if(!strcmp(&argv[1][10], "zvm"))
344 return zvm_encode(iname, oname, ZENVISIONM);
345 else if(!strcmp(&argv[1][10], "zvm60"))
346 return zvm_encode(iname, oname, ZENVISIONM60);
347 else if(!strcmp(&argv[1][10], "zenvision"))
348 return zvm_encode(iname, oname, ZENVISION);
349 else if(!strcmp(&argv[1][10], "zenv"))
350 return zvm_encode(iname, oname, ZENV);
351 else if(!strcmp(&argv[1][10], "zen"))
352 return zvm_encode(iname, oname, ZEN);
353 else {
354 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
355 return 2;
358 else if(!strncmp(argv[1], "-mi4", 4)) {
359 int mi4magic;
360 char model[4] = "";
361 char type[4] = "";
363 if(!strcmp(&argv[1][4], "v2")) {
364 mi4magic = MI4_MAGIC_DEFAULT;
365 version = 0x00010201;
367 else if(!strcmp(&argv[1][4], "v3")) {
368 mi4magic = MI4_MAGIC_DEFAULT;
369 version = 0x00010301;
371 else if(!strcmp(&argv[1][4], "r")) {
372 mi4magic = MI4_MAGIC_R;
373 version = 0x00010301;
375 else {
376 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
377 return -1;
380 iname = argv[2];
381 oname = argv[3];
383 if(!strncmp(argv[2], "-model=", 7)) {
384 iname = argv[3];
385 oname = argv[4];
386 strncpy(model, &argv[2][7], 4);
388 if(!strncmp(argv[3], "-type=", 6)) {
389 iname = argv[4];
390 oname = argv[5];
391 strncpy(type, &argv[3][6], 4);
395 return mi4_encode(iname, oname, version, mi4magic, model, type);
398 /* open file */
399 file = fopen(iname,"rb");
400 if (!file) {
401 perror(iname);
402 return -1;
404 fseek(file,0,SEEK_END);
405 length = ftell(file);
406 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
408 if ((method == scramble) &&
409 ((length + headerlen) >= size_limit[model_id])) {
410 printf("error: firmware image is %ld bytes while max size is %u!\n",
411 length + headerlen,
412 size_limit[model_id]);
413 fclose(file);
414 return -1;
417 fseek(file,0,SEEK_SET);
418 inbuf = malloc(length);
419 if (method == xor)
420 outbuf = malloc(length*2);
421 else if(method == add)
422 outbuf = malloc(length + 8);
423 else
424 outbuf = malloc(length);
425 if ( !inbuf || !outbuf ) {
426 printf("out of memory!\n");
427 return -1;
429 if(length> 4) {
430 /* zero-fill the last 4 bytes to make sure there's no rubbish there
431 when we write the size-aligned file later */
432 memset(outbuf+length-4, 0, 4);
435 /* read file */
436 i=fread(inbuf,1,length,file);
437 if ( !i ) {
438 perror(iname);
439 return -1;
441 fclose(file);
443 switch (method)
445 case add:
446 for (i = 0; i < length; i++) {
447 /* add 8 unsigned bits but keep a 32 bit sum */
448 chksum += inbuf[i];
450 break;
451 case scramble:
452 slen = length/4;
453 for (i = 0; i < length; i++) {
454 unsigned long addr = (i >> 2) + ((i % 4) * slen);
455 unsigned char data = inbuf[i];
456 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
457 outbuf[addr] = data;
459 break;
461 case xor:
462 /* "compress" */
463 slen = 0;
464 for (i=0; i<length; i++) {
465 if (!(i&7))
466 outbuf[slen++] = 0xff; /* all data is uncompressed */
467 outbuf[slen++] = inbuf[i];
469 break;
470 case none:
471 default:
472 /* dummy case just to silence picky compilers */
473 break;
476 if((method == none) || (method == scramble) || (method == xor)) {
477 /* calculate checksum */
478 for (i=0;i<length;i++)
479 crc += inbuf[i];
482 memset(header, 0, sizeof header);
483 switch (method)
485 case add:
487 int2be(chksum, header); /* checksum, big-endian */
488 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
489 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
490 headerlen = 8;
492 break;
494 case tcc_sum:
495 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
496 telechips_encode_sum(outbuf, length);
497 break;
499 case tcc_crc:
500 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
501 telechips_encode_crc(outbuf, length);
502 break;
504 case scramble:
505 if (headerlen == 6) {
506 int2be(length, header);
507 header[4] = (crc >> 8) & 0xff;
508 header[5] = crc & 0xff;
510 else {
511 header[0] =
512 header[1] =
513 header[2] =
514 header[3] = 0xff; /* ??? */
516 header[6] = (crc >> 8) & 0xff;
517 header[7] = crc & 0xff;
519 header[11] = version;
521 header[15] = headerlen; /* really? */
523 int2be(length, &header[20]);
525 break;
527 case xor:
529 int xorlen = strlen(xorstring);
531 /* xor data */
532 for (i=0; i<slen; i++)
533 outbuf[i] ^= xorstring[i & (xorlen-1)];
535 /* calculate checksum */
536 for (i=0; i<slen; i++)
537 crc += outbuf[i];
539 header[0] = header[2] = 'Z';
540 header[1] = header[3] = version;
541 int2le(length, &header[4]);
542 int2le(slen, &header[8]);
543 int2le(crc, &header[12]);
544 length = slen;
545 break;
548 #define MY_FIRMWARE_TYPE "Rockbox"
549 #define MY_HEADER_VERSION 1
550 default:
551 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
552 header[9]='\0'; /*shouldn't have to, but to be SURE */
553 header[10]=MY_HEADER_VERSION&0xFF;
554 header[11]=(crc>>8)&0xFF;
555 header[12]=crc&0xFF;
556 int2be(sizeof(header), &header[12]);
557 break;
560 /* write file */
561 file = fopen(oname,"wb");
562 if ( !file ) {
563 perror(oname);
564 return -1;
566 if (headerlen > 0) {
567 if ( !fwrite(header,headerlen,1,file) ) {
568 perror(oname);
569 return -1;
572 if ( !fwrite(outbuf,length,1,file) ) {
573 perror(oname);
574 return -1;
576 fclose(file);
578 free(inbuf);
579 free(outbuf);
581 return 0;
584 int iaudio_encode(char *iname, char *oname, char *idstring)
586 size_t len;
587 int length;
588 FILE *file;
589 unsigned char *outbuf;
590 int i;
591 unsigned char sum = 0;
593 file = fopen(iname, "rb");
594 if (!file) {
595 perror(iname);
596 return -1;
598 fseek(file,0,SEEK_END);
599 length = ftell(file);
601 fseek(file,0,SEEK_SET);
602 outbuf = malloc(length+0x1030);
604 if ( !outbuf ) {
605 printf("out of memory!\n");
606 return -1;
609 len = fread(outbuf+0x1030, 1, length, file);
610 if(len < (size_t) length) {
611 perror(iname);
612 return -2;
615 memset(outbuf, 0, 0x1030);
616 strcpy((char *)outbuf, idstring);
617 memcpy(outbuf+0x20, iaudio_bl_flash,
618 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
619 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
620 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
621 outbuf[0x19] = 2;
623 for(i = 0; i < length;i++)
624 sum += outbuf[0x1030 + i];
626 int2be(length, &outbuf[0x1024]);
627 outbuf[0x102b] = sum;
629 fclose(file);
631 file = fopen(oname, "wb");
632 if (!file) {
633 perror(oname);
634 return -3;
637 len = fwrite(outbuf, 1, length+0x1030, file);
638 if(len < (size_t)length) {
639 perror(oname);
640 return -4;
643 fclose(file);
644 return 0;
648 /* Create an ipod firmware partition image
650 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
652 This function doesn't yet handle the Broadcom resource image for the 5g,
653 so the resulting images won't be usable.
655 This has also only been tested on an ipod Photo
658 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
660 static const char *apple_stop_sign = "{{~~ /-----\\ "\
661 "{{~~ / \\ "\
662 "{{~~| | "\
663 "{{~~| S T O P | "\
664 "{{~~| | "\
665 "{{~~ \\ / "\
666 "{{~~ \\-----/ "\
667 "Copyright(C) 200"\
668 "1 Apple Computer"\
669 ", Inc.----------"\
670 "----------------"\
671 "----------------"\
672 "----------------"\
673 "----------------"\
674 "----------------"\
675 "---------------";
676 size_t len;
677 int length;
678 int rsrclength;
679 int rsrcoffset;
680 FILE *file;
681 unsigned int sum = 0;
682 unsigned int rsrcsum = 0;
683 unsigned char *outbuf;
684 int bufsize;
685 int i;
687 file = fopen(iname, "rb");
688 if (!file) {
689 perror(iname);
690 return -1;
692 fseek(file,0,SEEK_END);
693 length = ftell(file);
695 fseek(file,0,SEEK_SET);
697 bufsize=(length+0x4600);
698 if (fake_rsrc) {
699 bufsize = (bufsize + 0x400) & ~0x200;
702 outbuf = malloc(bufsize);
704 if ( !outbuf ) {
705 printf("out of memory!\n");
706 return -1;
709 len = fread(outbuf+0x4600, 1, length, file);
710 if(len < (size_t)length) {
711 perror(iname);
712 return -2;
714 fclose(file);
716 /* Calculate checksum for later use in header */
717 for(i = 0x4600; i < 0x4600+length;i++)
718 sum += outbuf[i];
720 /* Clear the header area to zero */
721 memset(outbuf, 0, 0x4600);
723 /* APPLE STOP SIGN */
724 strcpy((char *)outbuf, apple_stop_sign);
726 /* VOLUME HEADER */
727 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
728 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
729 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
730 short2le(fw_ver, &outbuf[0x10a]);
732 /* Firmware Directory - "osos" entry */
733 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
734 int2le(0, &outbuf[0x4208]); /* id */
735 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
736 int2le(length, &outbuf[0x4210]); /* Length of firmware */
737 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
738 int2le(0, &outbuf[0x4218]); /* Entry Offset */
739 int2le(sum, &outbuf[0x421c]); /* Checksum */
740 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
741 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
743 /* "rsrc" entry (if applicable) */
744 if (fake_rsrc) {
745 rsrcoffset=(length+0x4600+0x200) & ~0x200;
746 rsrclength=0x200;
747 rsrcsum=0;
749 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
750 int2le(0, &outbuf[0x4230]); /* id */
751 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
752 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
753 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
754 int2le(0, &outbuf[0x4240]); /* Entry Offset */
755 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
756 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
757 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
760 file = fopen(oname, "wb");
761 if (!file) {
762 perror(oname);
763 return -3;
766 len = fwrite(outbuf, 1, length+0x4600, file);
767 if(len < (size_t)length) {
768 perror(oname);
769 return -4;
772 fclose(file);
774 return 0;