Inform the console when an unsupported WMA flavor is played.
[kugel-rb.git] / tools / scramble.c
blob7aad4bfa92e85e3ff4189277d898e88ade0f46e1
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-gigabeat Toshiba Gigabeat F/X format\n"
108 "\t-gigabeats Toshiba Gigabeat S format\n"
109 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
110 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
111 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
112 "\t All mi4 options take two optional arguments:\n");
113 printf("\t -model=XXXX where XXXX is the model id string\n"
114 "\t -type=XXXX where XXXX is a string indicating the \n"
115 "\t type of binary, eg. RBOS, RBBL\n"
116 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
117 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
118 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
119 "\t ip3g, ip4g, mini, iax5, iam5, iam3, h10, h10_5gb,\n"
120 "\t tpj2, c200, e200, giga, gigs, m100, m500, d2)\n");
121 printf("\nNo option results in Archos standard player/recorder format.\n");
123 exit(1);
126 int main (int argc, char** argv)
128 unsigned long length,i,slen=0;
129 unsigned char *inbuf,*outbuf;
130 unsigned short crc=0;
131 unsigned long chksum=0; /* 32 bit checksum */
132 unsigned char header[24];
133 char *iname = argv[1];
134 char *oname = argv[2];
135 char *xorstring=NULL;
136 int headerlen = 6;
137 FILE* file;
138 int version=0;
139 unsigned long modelnum;
140 char modelname[5];
141 int model_id;
142 enum { none, scramble, xor, tcc_sum, tcc_crc, add } method = scramble;
144 model_id = ARCHOS_PLAYER;
146 if (argc < 3) {
147 usage();
150 if(!strcmp(argv[1], "-fm")) {
151 headerlen = 24;
152 iname = argv[2];
153 oname = argv[3];
154 version = 4;
155 model_id = ARCHOS_FMRECORDER;
158 else if(!strcmp(argv[1], "-v2")) {
159 headerlen = 24;
160 iname = argv[2];
161 oname = argv[3];
162 version = 2;
163 model_id = ARCHOS_V2RECORDER;
166 else if(!strcmp(argv[1], "-ofm")) {
167 headerlen = 24;
168 iname = argv[2];
169 oname = argv[3];
170 version = 8;
171 model_id = ARCHOS_ONDIO_FM;
174 else if(!strcmp(argv[1], "-osp")) {
175 headerlen = 24;
176 iname = argv[2];
177 oname = argv[3];
178 version = 16;
179 model_id = ARCHOS_ONDIO_SP;
182 else if(!strcmp(argv[1], "-neo")) {
183 headerlen = 17;
184 iname = argv[2];
185 oname = argv[3];
186 method = none;
188 else if(!strncmp(argv[1], "-mm=", 4)) {
189 headerlen = 16;
190 iname = argv[2];
191 oname = argv[3];
192 method = xor;
193 version = argv[1][4];
194 if (argc > 4)
195 xorstring = argv[4];
196 else {
197 printf("Multimedia needs an xor string\n");
198 return -1;
201 else if(!strncmp(argv[1], "-tcc=", 4)) {
202 headerlen = 0;
203 iname = argv[2];
204 oname = argv[3];
206 if(!strcmp(&argv[1][5], "sum"))
207 method = tcc_sum;
208 else if(!strcmp(&argv[1][5], "crc"))
209 method = tcc_crc;
210 else {
211 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
212 return 2;
215 else if(!strncmp(argv[1], "-add=", 5)) {
216 iname = argv[2];
217 oname = argv[3];
218 method = add;
220 if(!strcmp(&argv[1][5], "h120"))
221 modelnum = 0;
222 else if(!strcmp(&argv[1][5], "h140"))
223 modelnum = 0; /* the same as the h120 */
224 else if(!strcmp(&argv[1][5], "h100"))
225 modelnum = 1;
226 else if(!strcmp(&argv[1][5], "h300"))
227 modelnum = 2;
228 else if(!strcmp(&argv[1][5], "ipco"))
229 modelnum = 3;
230 else if(!strcmp(&argv[1][5], "nano"))
231 modelnum = 4;
232 else if(!strcmp(&argv[1][5], "ipvd"))
233 modelnum = 5;
234 else if(!strcmp(&argv[1][5], "fp7x"))
235 modelnum = 6;
236 else if(!strcmp(&argv[1][5], "ip3g"))
237 modelnum = 7;
238 else if(!strcmp(&argv[1][5], "ip4g"))
239 modelnum = 8;
240 else if(!strcmp(&argv[1][5], "mini"))
241 modelnum = 9;
242 else if(!strcmp(&argv[1][5], "iax5"))
243 modelnum = 10;
244 else if(!strcmp(&argv[1][5], "mn2g"))
245 modelnum = 11;
246 else if(!strcmp(&argv[1][5], "h10"))
247 modelnum = 13;
248 else if(!strcmp(&argv[1][5], "h10_5gb"))
249 modelnum = 14;
250 else if(!strcmp(&argv[1][5], "tpj2"))
251 modelnum = 15;
252 else if(!strcmp(&argv[1][5], "e200"))
253 modelnum = 16;
254 else if(!strcmp(&argv[1][5], "iam5"))
255 modelnum = 17;
256 else if(!strcmp(&argv[1][5], "giga"))
257 modelnum = 18;
258 else if(!strcmp(&argv[1][5], "1g2g"))
259 modelnum = 19;
260 else if(!strcmp(&argv[1][5], "c200"))
261 modelnum = 20;
262 else if(!strcmp(&argv[1][5], "gigs"))
263 modelnum = 21;
264 else if(!strcmp(&argv[1][5], "m500"))
265 modelnum = 22;
266 else if(!strcmp(&argv[1][5], "m100"))
267 modelnum = 23;
268 else if(!strcmp(&argv[1][5], "d2"))
269 modelnum = 24;
270 else if(!strcmp(&argv[1][5], "iam3"))
271 modelnum = 25;
272 else {
273 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
274 return 2;
276 /* we store a 4-letter model name too, for humans */
277 strcpy(modelname, &argv[1][5]);
278 chksum = modelnum; /* start checksum calcs with this */
281 else if(!strcmp(argv[1], "-iriver")) {
282 /* iRiver code dealt with in the iriver.c code */
283 iname = argv[2];
284 oname = argv[3];
285 iriver_encode(iname, oname, FALSE);
286 return 0;
288 else if(!strcmp(argv[1], "-gigabeat")) {
289 /* iRiver code dealt with in the iriver.c code */
290 iname = argv[2];
291 oname = argv[3];
292 gigabeat_code(iname, oname);
293 return 0;
295 else if(!strcmp(argv[1], "-gigabeats")) {
296 iname = argv[2];
297 oname = argv[3];
298 gigabeat_s_code(iname, oname);
299 return 0;
301 else if(!strcmp(argv[1], "-iaudiox5")) {
302 iname = argv[2];
303 oname = argv[3];
304 return iaudio_encode(iname, oname, "COWON_X5_FW");
306 else if(!strcmp(argv[1], "-iaudiox5v")) {
307 iname = argv[2];
308 oname = argv[3];
309 return iaudio_encode(iname, oname, "COWON_X5V_FW");
311 else if(!strcmp(argv[1], "-iaudiom5")) {
312 iname = argv[2];
313 oname = argv[3];
314 return iaudio_encode(iname, oname, "COWON_M5_FW");
316 else if(!strcmp(argv[1], "-iaudiom3")) {
317 iname = argv[2];
318 oname = argv[3];
319 return iaudio_encode(iname, oname, "COWON_M3_FW");
321 else if(!strcmp(argv[1], "-ipod3g")) {
322 iname = argv[2];
323 oname = argv[3];
324 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
326 else if(!strcmp(argv[1], "-ipod4g")) {
327 iname = argv[2];
328 oname = argv[3];
329 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
331 else if(!strcmp(argv[1], "-ipod5g")) {
332 iname = argv[2];
333 oname = argv[3];
334 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
336 else if(!strncmp(argv[1], "-creative=", 10)) {
337 iname = argv[2];
338 oname = argv[3];
339 if(!strcmp(&argv[1][10], "zvm"))
340 return zvm_encode(iname, oname, ZENVISIONM);
341 else if(!strcmp(&argv[1][10], "zvm60"))
342 return zvm_encode(iname, oname, ZENVISIONM60);
343 else if(!strcmp(&argv[1][10], "zenvision"))
344 return zvm_encode(iname, oname, ZENVISION);
345 else if(!strcmp(&argv[1][10], "zenv"))
346 return zvm_encode(iname, oname, ZENV);
347 else {
348 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
349 return 2;
352 else if(!strncmp(argv[1], "-mi4", 4)) {
353 int mi4magic;
354 char model[4] = "";
355 char type[4] = "";
357 if(!strcmp(&argv[1][4], "v2")) {
358 mi4magic = MI4_MAGIC_DEFAULT;
359 version = 0x00010201;
361 else if(!strcmp(&argv[1][4], "v3")) {
362 mi4magic = MI4_MAGIC_DEFAULT;
363 version = 0x00010301;
365 else if(!strcmp(&argv[1][4], "r")) {
366 mi4magic = MI4_MAGIC_R;
367 version = 0x00010301;
369 else {
370 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
371 return -1;
374 iname = argv[2];
375 oname = argv[3];
377 if(!strncmp(argv[2], "-model=", 7)) {
378 iname = argv[3];
379 oname = argv[4];
380 strncpy(model, &argv[2][7], 4);
382 if(!strncmp(argv[3], "-type=", 6)) {
383 iname = argv[4];
384 oname = argv[5];
385 strncpy(type, &argv[3][6], 4);
389 return mi4_encode(iname, oname, version, mi4magic, model, type);
392 /* open file */
393 file = fopen(iname,"rb");
394 if (!file) {
395 perror(iname);
396 return -1;
398 fseek(file,0,SEEK_END);
399 length = ftell(file);
400 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
402 if ((method == scramble) &&
403 ((length + headerlen) >= size_limit[model_id])) {
404 printf("error: firmware image is %ld bytes while max size is %u!\n",
405 length + headerlen,
406 size_limit[model_id]);
407 fclose(file);
408 return -1;
411 fseek(file,0,SEEK_SET);
412 inbuf = malloc(length);
413 if (method == xor)
414 outbuf = malloc(length*2);
415 else if(method == add)
416 outbuf = malloc(length + 8);
417 else
418 outbuf = malloc(length);
419 if ( !inbuf || !outbuf ) {
420 printf("out of memory!\n");
421 return -1;
423 if(length> 4) {
424 /* zero-fill the last 4 bytes to make sure there's no rubbish there
425 when we write the size-aligned file later */
426 memset(outbuf+length-4, 0, 4);
429 /* read file */
430 i=fread(inbuf,1,length,file);
431 if ( !i ) {
432 perror(iname);
433 return -1;
435 fclose(file);
437 switch (method)
439 case add:
440 for (i = 0; i < length; i++) {
441 /* add 8 unsigned bits but keep a 32 bit sum */
442 chksum += inbuf[i];
444 break;
445 case scramble:
446 slen = length/4;
447 for (i = 0; i < length; i++) {
448 unsigned long addr = (i >> 2) + ((i % 4) * slen);
449 unsigned char data = inbuf[i];
450 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
451 outbuf[addr] = data;
453 break;
455 case xor:
456 /* "compress" */
457 slen = 0;
458 for (i=0; i<length; i++) {
459 if (!(i&7))
460 outbuf[slen++] = 0xff; /* all data is uncompressed */
461 outbuf[slen++] = inbuf[i];
463 break;
464 case none:
465 default:
466 /* dummy case just to silence picky compilers */
467 break;
470 if((method == none) || (method == scramble) || (method == xor)) {
471 /* calculate checksum */
472 for (i=0;i<length;i++)
473 crc += inbuf[i];
476 memset(header, 0, sizeof header);
477 switch (method)
479 case add:
481 int2be(chksum, header); /* checksum, big-endian */
482 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
483 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
484 headerlen = 8;
486 break;
488 case tcc_sum:
489 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
490 telechips_encode_sum(outbuf, length);
491 break;
493 case tcc_crc:
494 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
495 telechips_encode_crc(outbuf, length);
496 break;
498 case scramble:
499 if (headerlen == 6) {
500 int2be(length, header);
501 header[4] = (crc >> 8) & 0xff;
502 header[5] = crc & 0xff;
504 else {
505 header[0] =
506 header[1] =
507 header[2] =
508 header[3] = 0xff; /* ??? */
510 header[6] = (crc >> 8) & 0xff;
511 header[7] = crc & 0xff;
513 header[11] = version;
515 header[15] = headerlen; /* really? */
517 int2be(length, &header[20]);
519 break;
521 case xor:
523 int xorlen = strlen(xorstring);
525 /* xor data */
526 for (i=0; i<slen; i++)
527 outbuf[i] ^= xorstring[i & (xorlen-1)];
529 /* calculate checksum */
530 for (i=0; i<slen; i++)
531 crc += outbuf[i];
533 header[0] = header[2] = 'Z';
534 header[1] = header[3] = version;
535 int2le(length, &header[4]);
536 int2le(slen, &header[8]);
537 int2le(crc, &header[12]);
538 length = slen;
539 break;
542 #define MY_FIRMWARE_TYPE "Rockbox"
543 #define MY_HEADER_VERSION 1
544 default:
545 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
546 header[9]='\0'; /*shouldn't have to, but to be SURE */
547 header[10]=MY_HEADER_VERSION&0xFF;
548 header[11]=(crc>>8)&0xFF;
549 header[12]=crc&0xFF;
550 int2be(sizeof(header), &header[12]);
551 break;
554 /* write file */
555 file = fopen(oname,"wb");
556 if ( !file ) {
557 perror(oname);
558 return -1;
560 if (headerlen > 0) {
561 if ( !fwrite(header,headerlen,1,file) ) {
562 perror(oname);
563 return -1;
566 if ( !fwrite(outbuf,length,1,file) ) {
567 perror(oname);
568 return -1;
570 fclose(file);
572 free(inbuf);
573 free(outbuf);
575 return 0;
578 int iaudio_encode(char *iname, char *oname, char *idstring)
580 size_t len;
581 int length;
582 FILE *file;
583 unsigned char *outbuf;
584 int i;
585 unsigned char sum = 0;
587 file = fopen(iname, "rb");
588 if (!file) {
589 perror(iname);
590 return -1;
592 fseek(file,0,SEEK_END);
593 length = ftell(file);
595 fseek(file,0,SEEK_SET);
596 outbuf = malloc(length+0x1030);
598 if ( !outbuf ) {
599 printf("out of memory!\n");
600 return -1;
603 len = fread(outbuf+0x1030, 1, length, file);
604 if(len < (size_t) length) {
605 perror(iname);
606 return -2;
609 memset(outbuf, 0, 0x1030);
610 strcpy((char *)outbuf, idstring);
611 memcpy(outbuf+0x20, iaudio_bl_flash,
612 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
613 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
614 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
615 outbuf[0x19] = 2;
617 for(i = 0; i < length;i++)
618 sum += outbuf[0x1030 + i];
620 int2be(length, &outbuf[0x1024]);
621 outbuf[0x102b] = sum;
623 fclose(file);
625 file = fopen(oname, "wb");
626 if (!file) {
627 perror(oname);
628 return -3;
631 len = fwrite(outbuf, 1, length+0x1030, file);
632 if(len < (size_t)length) {
633 perror(oname);
634 return -4;
637 fclose(file);
638 return 0;
642 /* Create an ipod firmware partition image
644 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
646 This function doesn't yet handle the Broadcom resource image for the 5g,
647 so the resulting images won't be usable.
649 This has also only been tested on an ipod Photo
652 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
654 static const char *apple_stop_sign = "{{~~ /-----\\ "\
655 "{{~~ / \\ "\
656 "{{~~| | "\
657 "{{~~| S T O P | "\
658 "{{~~| | "\
659 "{{~~ \\ / "\
660 "{{~~ \\-----/ "\
661 "Copyright(C) 200"\
662 "1 Apple Computer"\
663 ", Inc.----------"\
664 "----------------"\
665 "----------------"\
666 "----------------"\
667 "----------------"\
668 "----------------"\
669 "---------------";
670 size_t len;
671 int length;
672 int rsrclength;
673 int rsrcoffset;
674 FILE *file;
675 unsigned int sum = 0;
676 unsigned int rsrcsum = 0;
677 unsigned char *outbuf;
678 int bufsize;
679 int i;
681 file = fopen(iname, "rb");
682 if (!file) {
683 perror(iname);
684 return -1;
686 fseek(file,0,SEEK_END);
687 length = ftell(file);
689 fseek(file,0,SEEK_SET);
691 bufsize=(length+0x4600);
692 if (fake_rsrc) {
693 bufsize = (bufsize + 0x400) & ~0x200;
696 outbuf = malloc(bufsize);
698 if ( !outbuf ) {
699 printf("out of memory!\n");
700 return -1;
703 len = fread(outbuf+0x4600, 1, length, file);
704 if(len < (size_t)length) {
705 perror(iname);
706 return -2;
708 fclose(file);
710 /* Calculate checksum for later use in header */
711 for(i = 0x4600; i < 0x4600+length;i++)
712 sum += outbuf[i];
714 /* Clear the header area to zero */
715 memset(outbuf, 0, 0x4600);
717 /* APPLE STOP SIGN */
718 strcpy((char *)outbuf, apple_stop_sign);
720 /* VOLUME HEADER */
721 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
722 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
723 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
724 short2le(fw_ver, &outbuf[0x10a]);
726 /* Firmware Directory - "osos" entry */
727 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
728 int2le(0, &outbuf[0x4208]); /* id */
729 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
730 int2le(length, &outbuf[0x4210]); /* Length of firmware */
731 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
732 int2le(0, &outbuf[0x4218]); /* Entry Offset */
733 int2le(sum, &outbuf[0x421c]); /* Checksum */
734 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
735 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
737 /* "rsrc" entry (if applicable) */
738 if (fake_rsrc) {
739 rsrcoffset=(length+0x4600+0x200) & ~0x200;
740 rsrclength=0x200;
741 rsrcsum=0;
743 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
744 int2le(0, &outbuf[0x4230]); /* id */
745 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
746 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
747 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
748 int2le(0, &outbuf[0x4240]); /* Entry Offset */
749 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
750 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
751 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
754 file = fopen(oname, "wb");
755 if (!file) {
756 perror(oname);
757 return -3;
760 len = fwrite(outbuf, 1, length+0x4600, file);
761 if(len < (size_t)length) {
762 perror(oname);
763 return -4;
766 fclose(file);
768 return 0;