fix out-of-bounds array access
[kugel-rb.git] / tools / scramble.c
blobffcde9328bc608130c4bbbcf43251a630358a8ba
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 if (!strcmp(&argv[1][5], "i7"))
283 modelnum = 32;
284 else {
285 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
286 return 2;
288 /* we store a 4-letter model name too, for humans */
289 strcpy(modelname, &argv[1][5]);
290 chksum = modelnum; /* start checksum calcs with this */
293 else if(!strcmp(argv[1], "-iriver")) {
294 /* iRiver code dealt with in the iriver.c code */
295 iname = argv[2];
296 oname = argv[3];
297 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
299 else if(!strcmp(argv[1], "-gigabeat")) {
300 /* iRiver code dealt with in the iriver.c code */
301 iname = argv[2];
302 oname = argv[3];
303 gigabeat_code(iname, oname);
304 return 0;
306 else if(!strcmp(argv[1], "-gigabeats")) {
307 iname = argv[2];
308 oname = argv[3];
309 gigabeat_s_code(iname, oname);
310 return 0;
312 else if(!strcmp(argv[1], "-iaudiox5")) {
313 iname = argv[2];
314 oname = argv[3];
315 return iaudio_encode(iname, oname, "COWON_X5_FW");
317 else if(!strcmp(argv[1], "-iaudiox5v")) {
318 iname = argv[2];
319 oname = argv[3];
320 return iaudio_encode(iname, oname, "COWON_X5V_FW");
322 else if(!strcmp(argv[1], "-iaudiom5")) {
323 iname = argv[2];
324 oname = argv[3];
325 return iaudio_encode(iname, oname, "COWON_M5_FW");
327 else if(!strcmp(argv[1], "-iaudiom3")) {
328 iname = argv[2];
329 oname = argv[3];
330 return iaudio_encode(iname, oname, "COWON_M3_FW");
332 else if(!strcmp(argv[1], "-ipod3g")) {
333 iname = argv[2];
334 oname = argv[3];
335 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
337 else if(!strcmp(argv[1], "-ipod4g")) {
338 iname = argv[2];
339 oname = argv[3];
340 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
342 else if(!strcmp(argv[1], "-ipod5g")) {
343 iname = argv[2];
344 oname = argv[3];
345 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
347 else if(!strncmp(argv[1], "-creative=", 10))
349 if(!strcmp(argv[2], "-no-ciff"))
351 creative_enable_ciff = false;
352 iname = argv[3];
353 oname = argv[4];
355 else
357 creative_enable_ciff = true;
358 iname = argv[2];
359 oname = argv[3];
361 if(!strcmp(&argv[1][10], "zvm"))
362 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
363 else if(!strcmp(&argv[1][10], "zvm60"))
364 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
365 else if(!strcmp(&argv[1][10], "zenvision"))
366 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
367 else if(!strcmp(&argv[1][10], "zenv"))
368 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
369 else if(!strcmp(&argv[1][10], "zen"))
370 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
371 else
373 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
374 return 2;
377 else if(!strncmp(argv[1], "-mi4", 4)) {
378 int mi4magic;
379 char model[4] = "";
380 char type[4] = "";
382 if(!strcmp(&argv[1][4], "v2")) {
383 mi4magic = MI4_MAGIC_DEFAULT;
384 version = 0x00010201;
386 else if(!strcmp(&argv[1][4], "v3")) {
387 mi4magic = MI4_MAGIC_DEFAULT;
388 version = 0x00010301;
390 else if(!strcmp(&argv[1][4], "r")) {
391 mi4magic = MI4_MAGIC_R;
392 version = 0x00010301;
394 else {
395 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
396 return -1;
399 iname = argv[2];
400 oname = argv[3];
402 if(!strncmp(argv[2], "-model=", 7)) {
403 iname = argv[3];
404 oname = argv[4];
405 strncpy(model, &argv[2][7], 4);
407 if(!strncmp(argv[3], "-type=", 6)) {
408 iname = argv[4];
409 oname = argv[5];
410 strncpy(type, &argv[3][6], 4);
414 return mi4_encode(iname, oname, version, mi4magic, model, type);
417 /* open file */
418 file = fopen(iname,"rb");
419 if (!file) {
420 perror(iname);
421 return -1;
423 fseek(file,0,SEEK_END);
424 length = ftell(file);
425 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
427 if ((method == scramble) &&
428 ((length + headerlen) >= size_limit[model_id])) {
429 printf("error: firmware image is %ld bytes while max size is %u!\n",
430 length + headerlen,
431 size_limit[model_id]);
432 fclose(file);
433 return -1;
436 fseek(file,0,SEEK_SET);
437 inbuf = malloc(length);
438 if (method == xor)
439 outbuf = malloc(length*2);
440 else if(method == add)
441 outbuf = malloc(length + 8);
442 else
443 outbuf = malloc(length);
444 if ( !inbuf || !outbuf ) {
445 printf("out of memory!\n");
446 return -1;
448 if(length> 4) {
449 /* zero-fill the last 4 bytes to make sure there's no rubbish there
450 when we write the size-aligned file later */
451 memset(outbuf+length-4, 0, 4);
454 /* read file */
455 i=fread(inbuf,1,length,file);
456 if ( !i ) {
457 perror(iname);
458 return -1;
460 fclose(file);
462 switch (method)
464 case add:
465 for (i = 0; i < length; i++) {
466 /* add 8 unsigned bits but keep a 32 bit sum */
467 chksum += inbuf[i];
469 break;
470 case scramble:
471 slen = length/4;
472 for (i = 0; i < length; i++) {
473 unsigned long addr = (i >> 2) + ((i % 4) * slen);
474 unsigned char data = inbuf[i];
475 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
476 outbuf[addr] = data;
478 break;
480 case xor:
481 /* "compress" */
482 slen = 0;
483 for (i=0; i<length; i++) {
484 if (!(i&7))
485 outbuf[slen++] = 0xff; /* all data is uncompressed */
486 outbuf[slen++] = inbuf[i];
488 break;
489 case none:
490 default:
491 /* dummy case just to silence picky compilers */
492 break;
495 if((method == none) || (method == scramble) || (method == xor)) {
496 /* calculate checksum */
497 for (i=0;i<length;i++)
498 crc += inbuf[i];
501 memset(header, 0, sizeof header);
502 switch (method)
504 case add:
506 int2be(chksum, header); /* checksum, big-endian */
507 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
508 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
509 headerlen = 8;
511 break;
513 case tcc_sum:
514 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
515 telechips_encode_sum(outbuf, length);
516 break;
518 case tcc_crc:
519 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
520 telechips_encode_crc(outbuf, length);
521 break;
523 case scramble:
524 if (headerlen == 6) {
525 int2be(length, header);
526 header[4] = (crc >> 8) & 0xff;
527 header[5] = crc & 0xff;
529 else {
530 header[0] =
531 header[1] =
532 header[2] =
533 header[3] = 0xff; /* ??? */
535 header[6] = (crc >> 8) & 0xff;
536 header[7] = crc & 0xff;
538 header[11] = version;
540 header[15] = headerlen; /* really? */
542 int2be(length, &header[20]);
544 break;
546 case xor:
548 int xorlen = strlen(xorstring);
550 /* xor data */
551 for (i=0; i<slen; i++)
552 outbuf[i] ^= xorstring[i & (xorlen-1)];
554 /* calculate checksum */
555 for (i=0; i<slen; i++)
556 crc += outbuf[i];
558 header[0] = header[2] = 'Z';
559 header[1] = header[3] = version;
560 int2le(length, &header[4]);
561 int2le(slen, &header[8]);
562 int2le(crc, &header[12]);
563 length = slen;
564 break;
567 #define MY_FIRMWARE_TYPE "Rockbox"
568 #define MY_HEADER_VERSION 1
569 default:
570 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
571 header[9]='\0'; /*shouldn't have to, but to be SURE */
572 header[10]=MY_HEADER_VERSION&0xFF;
573 header[11]=(crc>>8)&0xFF;
574 header[12]=crc&0xFF;
575 int2be(sizeof(header), &header[12]);
576 break;
579 /* write file */
580 file = fopen(oname,"wb");
581 if ( !file ) {
582 perror(oname);
583 return -1;
585 if (headerlen > 0) {
586 if ( !fwrite(header,headerlen,1,file) ) {
587 perror(oname);
588 return -1;
591 if ( !fwrite(outbuf,length,1,file) ) {
592 perror(oname);
593 return -1;
595 fclose(file);
597 free(inbuf);
598 free(outbuf);
600 return 0;
603 int iaudio_encode(char *iname, char *oname, char *idstring)
605 size_t len;
606 int length;
607 FILE *file;
608 unsigned char *outbuf;
609 int i;
610 unsigned char sum = 0;
612 file = fopen(iname, "rb");
613 if (!file) {
614 perror(iname);
615 return -1;
617 fseek(file,0,SEEK_END);
618 length = ftell(file);
620 fseek(file,0,SEEK_SET);
621 outbuf = malloc(length+0x1030);
623 if ( !outbuf ) {
624 printf("out of memory!\n");
625 return -1;
628 len = fread(outbuf+0x1030, 1, length, file);
629 if(len < (size_t) length) {
630 perror(iname);
631 return -2;
634 memset(outbuf, 0, 0x1030);
635 strcpy((char *)outbuf, idstring);
636 memcpy(outbuf+0x20, iaudio_bl_flash,
637 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
638 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
639 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
640 outbuf[0x19] = 2;
642 for(i = 0; i < length;i++)
643 sum += outbuf[0x1030 + i];
645 int2be(length, &outbuf[0x1024]);
646 outbuf[0x102b] = sum;
648 fclose(file);
650 file = fopen(oname, "wb");
651 if (!file) {
652 perror(oname);
653 return -3;
656 len = fwrite(outbuf, 1, length+0x1030, file);
657 if(len < (size_t)length) {
658 perror(oname);
659 return -4;
662 fclose(file);
663 return 0;
667 /* Create an ipod firmware partition image
669 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
671 This function doesn't yet handle the Broadcom resource image for the 5g,
672 so the resulting images won't be usable.
674 This has also only been tested on an ipod Photo
677 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
679 static const char *apple_stop_sign = "{{~~ /-----\\ "\
680 "{{~~ / \\ "\
681 "{{~~| | "\
682 "{{~~| S T O P | "\
683 "{{~~| | "\
684 "{{~~ \\ / "\
685 "{{~~ \\-----/ "\
686 "Copyright(C) 200"\
687 "1 Apple Computer"\
688 ", Inc.----------"\
689 "----------------"\
690 "----------------"\
691 "----------------"\
692 "----------------"\
693 "----------------"\
694 "---------------";
695 size_t len;
696 int length;
697 int rsrclength;
698 int rsrcoffset;
699 FILE *file;
700 unsigned int sum = 0;
701 unsigned int rsrcsum = 0;
702 unsigned char *outbuf;
703 int bufsize;
704 int i;
706 file = fopen(iname, "rb");
707 if (!file) {
708 perror(iname);
709 return -1;
711 fseek(file,0,SEEK_END);
712 length = ftell(file);
714 fseek(file,0,SEEK_SET);
716 bufsize=(length+0x4600);
717 if (fake_rsrc) {
718 bufsize = (bufsize + 0x400) & ~0x200;
721 outbuf = malloc(bufsize);
723 if ( !outbuf ) {
724 printf("out of memory!\n");
725 return -1;
728 len = fread(outbuf+0x4600, 1, length, file);
729 if(len < (size_t)length) {
730 perror(iname);
731 return -2;
733 fclose(file);
735 /* Calculate checksum for later use in header */
736 for(i = 0x4600; i < 0x4600+length;i++)
737 sum += outbuf[i];
739 /* Clear the header area to zero */
740 memset(outbuf, 0, 0x4600);
742 /* APPLE STOP SIGN */
743 strcpy((char *)outbuf, apple_stop_sign);
745 /* VOLUME HEADER */
746 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
747 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
748 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
749 short2le(fw_ver, &outbuf[0x10a]);
751 /* Firmware Directory - "osos" entry */
752 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
753 int2le(0, &outbuf[0x4208]); /* id */
754 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
755 int2le(length, &outbuf[0x4210]); /* Length of firmware */
756 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
757 int2le(0, &outbuf[0x4218]); /* Entry Offset */
758 int2le(sum, &outbuf[0x421c]); /* Checksum */
759 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
760 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
762 /* "rsrc" entry (if applicable) */
763 if (fake_rsrc) {
764 rsrcoffset=(length+0x4600+0x200) & ~0x200;
765 rsrclength=0x200;
766 rsrcsum=0;
768 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
769 int2le(0, &outbuf[0x4230]); /* id */
770 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
771 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
772 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
773 int2le(0, &outbuf[0x4240]); /* Entry Offset */
774 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
775 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
776 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
779 file = fopen(oname, "wb");
780 if (!file) {
781 perror(oname);
782 return -3;
785 len = fwrite(outbuf, 1, length+0x4600, file);
786 if(len < (size_t)length) {
787 perror(oname);
788 return -4;
791 fclose(file);
793 return 0;