Add D2 option to scramble
[kugel-rb.git] / tools / scramble.c
blobee731cfd0d7f75a58da2c61b5f5044bf58b13e02
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"
30 int iaudio_encode(char *iname, char *oname, char *idstring);
31 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc);
33 enum
35 ARCHOS_PLAYER, /* and V1 recorder */
36 ARCHOS_V2RECORDER,
37 ARCHOS_FMRECORDER,
38 ARCHOS_ONDIO_SP,
39 ARCHOS_ONDIO_FM
42 int size_limit[] =
44 0x32000, /* ARCHOS_PLAYER */
45 0x64000, /* ARCHOS_V2RECORDER */
46 0x64000, /* ARCHOS_FMRECORDER */
47 0x64000, /* ARCHOS_ONDIO_SP */
48 0x64000 /* ARCHOS_ONDIO_FM */
51 void short2le(unsigned short val, unsigned char* addr)
53 addr[0] = val & 0xFF;
54 addr[1] = (val >> 8) & 0xff;
57 unsigned int le2int(unsigned char* buf)
59 unsigned int res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
61 return res;
64 void int2le(unsigned int val, unsigned char* addr)
66 addr[0] = val & 0xFF;
67 addr[1] = (val >> 8) & 0xff;
68 addr[2] = (val >> 16) & 0xff;
69 addr[3] = (val >> 24) & 0xff;
72 void int2be(unsigned int val, unsigned char* addr)
74 addr[0] = (val >> 24) & 0xff;
75 addr[1] = (val >> 16) & 0xff;
76 addr[2] = (val >> 8) & 0xff;
77 addr[3] = val & 0xFF;
80 void usage(void)
82 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
83 printf("options:\n"
84 "\t-fm Archos FM recorder format\n"
85 "\t-v2 Archos V2 recorder format\n"
86 "\t-ofm Archos Ondio FM recorder format\n"
87 "\t-osp Archos Ondio SP format\n"
88 "\t-neo SSI Neo format\n"
89 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
90 "\t-iriver iRiver format\n"
91 "\t-iaudiox5 iAudio X5 format\n"
92 "\t-iaudiox5v iAudio X5V format\n"
93 "\t-iaudiom5 iAudio M5 format\n"
94 "\t-ipod3g ipod firmware partition format (3rd Gen)\n"
95 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
96 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
97 "\t-zvm Zen Vision:M FRESCUE structure format\n"
98 "\t-gigabeat Toshiba Gigabeat F/X format\n"
99 "\t-gigabeats Toshiba Gigabeat S format\n"
100 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
101 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
102 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
103 "\t All mi4 options take two optional arguments:\n"
104 "\t -model=XXXX where XXXX is the model id string\n"
105 "\t -type=XXXX where XXXX is a string indicating the \n"
106 "\t type of binary, eg. RBOS, RBBL\n"
107 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
108 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
109 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
110 "\t ip3g, ip4g, mini, iax5, h10, h10_5gb, tpj2,\n"
111 "\t c200, e200, giga, gigs, m100, m500, d2)\n"
112 "\nNo option results in Archos standard player/recorder format.\n");
114 exit(1);
117 int main (int argc, char** argv)
119 unsigned long length,i,slen;
120 unsigned char *inbuf,*outbuf;
121 unsigned short crc=0;
122 unsigned long chksum=0; /* 32 bit checksum */
123 unsigned char header[24];
124 char *iname = argv[1];
125 char *oname = argv[2];
126 char *xorstring;
127 int headerlen = 6;
128 FILE* file;
129 int version;
130 unsigned long modelnum;
131 char modelname[5];
132 int model_id;
133 enum { none, scramble, xor, tcc_sum, tcc_crc, add } method = scramble;
135 model_id = ARCHOS_PLAYER;
137 if (argc < 3) {
138 usage();
141 if(!strcmp(argv[1], "-fm")) {
142 headerlen = 24;
143 iname = argv[2];
144 oname = argv[3];
145 version = 4;
146 model_id = ARCHOS_FMRECORDER;
149 else if(!strcmp(argv[1], "-v2")) {
150 headerlen = 24;
151 iname = argv[2];
152 oname = argv[3];
153 version = 2;
154 model_id = ARCHOS_V2RECORDER;
157 else if(!strcmp(argv[1], "-ofm")) {
158 headerlen = 24;
159 iname = argv[2];
160 oname = argv[3];
161 version = 8;
162 model_id = ARCHOS_ONDIO_FM;
165 else if(!strcmp(argv[1], "-osp")) {
166 headerlen = 24;
167 iname = argv[2];
168 oname = argv[3];
169 version = 16;
170 model_id = ARCHOS_ONDIO_SP;
173 else if(!strcmp(argv[1], "-neo")) {
174 headerlen = 17;
175 iname = argv[2];
176 oname = argv[3];
177 method = none;
179 else if(!strncmp(argv[1], "-mm=", 4)) {
180 headerlen = 16;
181 iname = argv[2];
182 oname = argv[3];
183 method = xor;
184 version = argv[1][4];
185 if (argc > 4)
186 xorstring = argv[4];
187 else {
188 printf("Multimedia needs an xor string\n");
189 return -1;
192 else if(!strncmp(argv[1], "-tcc=", 4)) {
193 headerlen = 0;
194 iname = argv[2];
195 oname = argv[3];
197 if(!strcmp(&argv[1][5], "sum"))
198 method = tcc_sum;
199 else if(!strcmp(&argv[1][5], "crc"))
200 method = tcc_crc;
201 else {
202 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
203 return 2;
206 else if(!strncmp(argv[1], "-add=", 5)) {
207 iname = argv[2];
208 oname = argv[3];
209 method = add;
211 if(!strcmp(&argv[1][5], "h120"))
212 modelnum = 0;
213 else if(!strcmp(&argv[1][5], "h140"))
214 modelnum = 0; /* the same as the h120 */
215 else if(!strcmp(&argv[1][5], "h100"))
216 modelnum = 1;
217 else if(!strcmp(&argv[1][5], "h300"))
218 modelnum = 2;
219 else if(!strcmp(&argv[1][5], "ipco"))
220 modelnum = 3;
221 else if(!strcmp(&argv[1][5], "nano"))
222 modelnum = 4;
223 else if(!strcmp(&argv[1][5], "ipvd"))
224 modelnum = 5;
225 else if(!strcmp(&argv[1][5], "fp7x"))
226 modelnum = 6;
227 else if(!strcmp(&argv[1][5], "ip3g"))
228 modelnum = 7;
229 else if(!strcmp(&argv[1][5], "ip4g"))
230 modelnum = 8;
231 else if(!strcmp(&argv[1][5], "mini"))
232 modelnum = 9;
233 else if(!strcmp(&argv[1][5], "iax5"))
234 modelnum = 10;
235 else if(!strcmp(&argv[1][5], "mn2g"))
236 modelnum = 11;
237 else if(!strcmp(&argv[1][5], "h10"))
238 modelnum = 13;
239 else if(!strcmp(&argv[1][5], "h10_5gb"))
240 modelnum = 14;
241 else if(!strcmp(&argv[1][5], "tpj2"))
242 modelnum = 15;
243 else if(!strcmp(&argv[1][5], "e200"))
244 modelnum = 16;
245 else if(!strcmp(&argv[1][5], "iam5"))
246 modelnum = 17;
247 else if(!strcmp(&argv[1][5], "giga"))
248 modelnum = 18;
249 else if(!strcmp(&argv[1][5], "1g2g"))
250 modelnum = 19;
251 else if(!strcmp(&argv[1][5], "c200"))
252 modelnum = 20;
253 else if(!strcmp(&argv[1][5], "gigs"))
254 modelnum = 21;
255 else if(!strcmp(&argv[1][5], "m500"))
256 modelnum = 22;
257 else if(!strcmp(&argv[1][5], "m100"))
258 modelnum = 23;
259 else if(!strcmp(&argv[1][5], "d2"))
260 modelnum = 24;
261 else {
262 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
263 return 2;
265 /* we store a 4-letter model name too, for humans */
266 strcpy(modelname, &argv[1][5]);
267 chksum = modelnum; /* start checksum calcs with this */
270 else if(!strcmp(argv[1], "-iriver")) {
271 /* iRiver code dealt with in the iriver.c code */
272 iname = argv[2];
273 oname = argv[3];
274 iriver_encode(iname, oname, FALSE);
275 return 0;
277 else if(!strcmp(argv[1], "-gigabeat")) {
278 /* iRiver code dealt with in the iriver.c code */
279 iname = argv[2];
280 oname = argv[3];
281 gigabeat_code(iname, oname);
282 return 0;
284 else if(!strcmp(argv[1], "-gigabeats")) {
285 iname = argv[2];
286 oname = argv[3];
287 gigabeat_s_code(iname, oname);
288 return 0;
290 else if(!strcmp(argv[1], "-iaudiox5")) {
291 iname = argv[2];
292 oname = argv[3];
293 return iaudio_encode(iname, oname, "COWON_X5_FW");
295 else if(!strcmp(argv[1], "-iaudiox5v")) {
296 iname = argv[2];
297 oname = argv[3];
298 return iaudio_encode(iname, oname, "COWON_X5V_FW");
300 else if(!strcmp(argv[1], "-iaudiom5")) {
301 iname = argv[2];
302 oname = argv[3];
303 return iaudio_encode(iname, oname, "COWON_M5_FW");
305 else if(!strcmp(argv[1], "-ipod3g")) {
306 iname = argv[2];
307 oname = argv[3];
308 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
310 else if(!strcmp(argv[1], "-ipod4g")) {
311 iname = argv[2];
312 oname = argv[3];
313 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
315 else if(!strcmp(argv[1], "-ipod5g")) {
316 iname = argv[2];
317 oname = argv[3];
318 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
320 else if(!strcmp(argv[1], "-zvm")) {
321 iname = argv[2];
322 oname = argv[3];
323 return zvm_encode(iname, oname);
325 else if(!strncmp(argv[1], "-mi4", 4)) {
326 int mi4magic;
327 int version;
328 char model[4] = "";
329 char type[4] = "";
331 if(!strcmp(&argv[1][4], "v2")) {
332 mi4magic = MI4_MAGIC_DEFAULT;
333 version = 0x00010201;
335 else if(!strcmp(&argv[1][4], "v3")) {
336 mi4magic = MI4_MAGIC_DEFAULT;
337 version = 0x00010301;
339 else if(!strcmp(&argv[1][4], "r")) {
340 mi4magic = MI4_MAGIC_R;
341 version = 0x00010301;
343 else {
344 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
345 return -1;
348 iname = argv[2];
349 oname = argv[3];
351 if(!strncmp(argv[2], "-model=", 7)) {
352 iname = argv[3];
353 oname = argv[4];
354 strncpy(model, &argv[2][7], 4);
356 if(!strncmp(argv[3], "-type=", 6)) {
357 iname = argv[4];
358 oname = argv[5];
359 strncpy(type, &argv[3][6], 4);
363 return mi4_encode(iname, oname, version, mi4magic, model, type);
366 /* open file */
367 file = fopen(iname,"rb");
368 if (!file) {
369 perror(iname);
370 return -1;
372 fseek(file,0,SEEK_END);
373 length = ftell(file);
374 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
376 if ((method == scramble) &&
377 ((length + headerlen) >= size_limit[model_id])) {
378 printf("error: firmware image is %d bytes while max size is %d!\n",
379 length + headerlen,
380 size_limit[model_id]);
381 fclose(file);
382 return -1;
385 fseek(file,0,SEEK_SET);
386 inbuf = malloc(length);
387 if (method == xor)
388 outbuf = malloc(length*2);
389 else if(method == add)
390 outbuf = malloc(length + 8);
391 else
392 outbuf = malloc(length);
393 if ( !inbuf || !outbuf ) {
394 printf("out of memory!\n");
395 return -1;
397 if(length> 4) {
398 /* zero-fill the last 4 bytes to make sure there's no rubbish there
399 when we write the size-aligned file later */
400 memset(outbuf+length-4, 0, 4);
403 /* read file */
404 i=fread(inbuf,1,length,file);
405 if ( !i ) {
406 perror(iname);
407 return -1;
409 fclose(file);
411 switch (method)
413 case add:
414 for (i = 0; i < length; i++) {
415 /* add 8 unsigned bits but keep a 32 bit sum */
416 chksum += inbuf[i];
418 break;
419 case scramble:
420 slen = length/4;
421 for (i = 0; i < length; i++) {
422 unsigned long addr = (i >> 2) + ((i % 4) * slen);
423 unsigned char data = inbuf[i];
424 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
425 outbuf[addr] = data;
427 break;
429 case xor:
430 /* "compress" */
431 slen = 0;
432 for (i=0; i<length; i++) {
433 if (!(i&7))
434 outbuf[slen++] = 0xff; /* all data is uncompressed */
435 outbuf[slen++] = inbuf[i];
437 break;
440 if((method == none) || (method == scramble) || (method == xor)) {
441 /* calculate checksum */
442 for (i=0;i<length;i++)
443 crc += inbuf[i];
446 memset(header, 0, sizeof header);
447 switch (method)
449 case add:
451 int2be(chksum, header); /* checksum, big-endian */
452 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
453 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
454 headerlen = 8;
456 break;
458 case tcc_sum:
459 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
460 telechips_encode_sum(outbuf, length);
461 break;
463 case tcc_crc:
464 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
465 telechips_encode_crc(outbuf, length);
466 break;
468 case scramble:
469 if (headerlen == 6) {
470 int2be(length, header);
471 header[4] = (crc >> 8) & 0xff;
472 header[5] = crc & 0xff;
474 else {
475 header[0] =
476 header[1] =
477 header[2] =
478 header[3] = 0xff; /* ??? */
480 header[6] = (crc >> 8) & 0xff;
481 header[7] = crc & 0xff;
483 header[11] = version;
485 header[15] = headerlen; /* really? */
487 int2be(length, &header[20]);
489 break;
491 case xor:
493 int xorlen = strlen(xorstring);
495 /* xor data */
496 for (i=0; i<slen; i++)
497 outbuf[i] ^= xorstring[i & (xorlen-1)];
499 /* calculate checksum */
500 for (i=0; i<slen; i++)
501 crc += outbuf[i];
503 header[0] = header[2] = 'Z';
504 header[1] = header[3] = version;
505 int2le(length, &header[4]);
506 int2le(slen, &header[8]);
507 int2le(crc, &header[12]);
508 length = slen;
509 break;
512 #define MY_FIRMWARE_TYPE "Rockbox"
513 #define MY_HEADER_VERSION 1
514 default:
515 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
516 header[9]='\0'; /*shouldn't have to, but to be SURE */
517 header[10]=MY_HEADER_VERSION&0xFF;
518 header[11]=(crc>>8)&0xFF;
519 header[12]=crc&0xFF;
520 int2be(sizeof(header), &header[12]);
521 break;
524 /* write file */
525 file = fopen(oname,"wb");
526 if ( !file ) {
527 perror(oname);
528 return -1;
530 if (headerlen > 0) {
531 if ( !fwrite(header,headerlen,1,file) ) {
532 perror(oname);
533 return -1;
536 if ( !fwrite(outbuf,length,1,file) ) {
537 perror(oname);
538 return -1;
540 fclose(file);
542 free(inbuf);
543 free(outbuf);
545 return 0;
548 int iaudio_encode(char *iname, char *oname, char *idstring)
550 size_t len;
551 int length;
552 FILE *file;
553 unsigned char *outbuf;
554 int i;
555 unsigned char sum = 0;
557 file = fopen(iname, "rb");
558 if (!file) {
559 perror(iname);
560 return -1;
562 fseek(file,0,SEEK_END);
563 length = ftell(file);
565 fseek(file,0,SEEK_SET);
566 outbuf = malloc(length+0x1030);
568 if ( !outbuf ) {
569 printf("out of memory!\n");
570 return -1;
573 len = fread(outbuf+0x1030, 1, length, file);
574 if(len < length) {
575 perror(iname);
576 return -2;
579 memset(outbuf, 0, 0x1030);
580 strcpy((char *)outbuf, idstring);
582 for(i = 0; i < length;i++)
583 sum += outbuf[0x1030 + i];
585 int2be(length, &outbuf[0x1024]);
586 outbuf[0x102b] = sum;
588 fclose(file);
590 file = fopen(oname, "wb");
591 if (!file) {
592 perror(oname);
593 return -3;
596 len = fwrite(outbuf, 1, length+0x1030, file);
597 if(len < length) {
598 perror(oname);
599 return -4;
602 fclose(file);
606 /* Create an ipod firmware partition image
608 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
610 This function doesn't yet handle the Broadcom resource image for the 5g,
611 so the resulting images won't be usable.
613 This has also only been tested on an ipod Photo
616 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
618 static const char *apple_stop_sign = "{{~~ /-----\\ "\
619 "{{~~ / \\ "\
620 "{{~~| | "\
621 "{{~~| S T O P | "\
622 "{{~~| | "\
623 "{{~~ \\ / "\
624 "{{~~ \\-----/ "\
625 "Copyright(C) 200"\
626 "1 Apple Computer"\
627 ", Inc.----------"\
628 "----------------"\
629 "----------------"\
630 "----------------"\
631 "----------------"\
632 "----------------"\
633 "---------------";
634 size_t len;
635 int length;
636 int rsrclength;
637 int rsrcoffset;
638 FILE *file;
639 unsigned int sum = 0;
640 unsigned int rsrcsum = 0;
641 unsigned char *outbuf;
642 int bufsize;
643 int i;
645 file = fopen(iname, "rb");
646 if (!file) {
647 perror(iname);
648 return -1;
650 fseek(file,0,SEEK_END);
651 length = ftell(file);
653 fseek(file,0,SEEK_SET);
655 bufsize=(length+0x4600);
656 if (fake_rsrc) {
657 bufsize = (bufsize + 0x400) & ~0x200;
660 outbuf = malloc(bufsize);
662 if ( !outbuf ) {
663 printf("out of memory!\n");
664 return -1;
667 len = fread(outbuf+0x4600, 1, length, file);
668 if(len < length) {
669 perror(iname);
670 return -2;
672 fclose(file);
674 /* Calculate checksum for later use in header */
675 for(i = 0x4600; i < 0x4600+length;i++)
676 sum += outbuf[i];
678 /* Clear the header area to zero */
679 memset(outbuf, 0, 0x4600);
681 /* APPLE STOP SIGN */
682 strcpy((char *)outbuf, apple_stop_sign);
684 /* VOLUME HEADER */
685 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
686 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
687 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
688 short2le(fw_ver, &outbuf[0x10a]);
690 /* Firmware Directory - "osos" entry */
691 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
692 int2le(0, &outbuf[0x4208]); /* id */
693 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
694 int2le(length, &outbuf[0x4210]); /* Length of firmware */
695 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
696 int2le(0, &outbuf[0x4218]); /* Entry Offset */
697 int2le(sum, &outbuf[0x421c]); /* Checksum */
698 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
699 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
701 /* "rsrc" entry (if applicable) */
702 if (fake_rsrc) {
703 rsrcoffset=(length+0x4600+0x200) & ~0x200;
704 rsrclength=0x200;
705 rsrcsum=0;
707 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
708 int2le(0, &outbuf[0x4230]); /* id */
709 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
710 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
711 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
712 int2le(0, &outbuf[0x4240]); /* Entry Offset */
713 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
714 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
715 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
718 file = fopen(oname, "wb");
719 if (!file) {
720 perror(oname);
721 return -3;
724 len = fwrite(outbuf, 1, length+0x4600, file);
725 if(len < length) {
726 perror(oname);
727 return -4;
730 fclose(file);
732 return 0;
736 /* Create an Zen Vision:M FRESCUE structure file
739 int zvm_encode(char *iname, char *oname)
741 size_t len;
742 int length;
743 FILE *file;
744 unsigned int sum = 0;
745 unsigned char *outbuf;
746 int i;
748 file = fopen(iname, "rb");
749 if (!file) {
750 perror(iname);
751 return -1;
753 fseek(file,0,SEEK_END);
754 length = ftell(file);
756 fseek(file,0,SEEK_SET);
758 outbuf = malloc(length+0x18+0x10);
760 if ( !outbuf ) {
761 printf("out of memory!\n");
762 return -1;
765 len = fread(outbuf+0x18, 1, length, file);
766 if(len < length) {
767 perror(iname);
768 return -2;
770 fclose(file);
772 /* Calculate checksum for later use in header */
773 for(i=0; i<length; i+= 4)
774 sum += le2int(&outbuf[0x18+i]) + (le2int(&outbuf[0x18+i])>>16);
776 /* Clear the header area to zero */
777 memset(outbuf, 0, 0x18);
779 /* Header (EDOC) */
780 memcpy((char*)outbuf, "EDOC", 4);
781 /* Total Size */
782 int2le(length+0x20, &outbuf[0x4]);
783 /* 4 bytes of zero */
785 /* Address = 0x900000 */
786 int2le(0x900000, &outbuf[0xC]);
787 /* Size */
788 int2le(length, &outbuf[0x10]);
789 /* Checksum */
790 int2le(sum, &outbuf[0x14]);
791 outbuf[0x16] = 0;
792 outbuf[0x17] = 0;
793 /* Data starts here... */
795 /* Second block starts here ... */
796 /* Address = 0x0 */
797 /* Size */
798 int2le(0x4, &outbuf[0x18+length+0x4]);
799 /* Checksum */
800 outbuf[0x18+length+0x8] = 0xB7;
801 outbuf[0x18+length+0x9] = 0xD5;
802 /* Data: LDR PC, =0x900000 */
803 outbuf[0x18+length+0xC] = 0x18;
804 outbuf[0x18+length+0xD] = 0xF0;
805 outbuf[0x18+length+0xE] = 0x9F;
806 outbuf[0x18+length+0xF] = 0xE5;
809 file = fopen(oname, "wb");
810 if (!file) {
811 perror(oname);
812 return -3;
815 len = fwrite(outbuf, 1, length+0x28, file);
816 if(len < length+0x18) {
817 perror(oname);
818 return -4;
821 free(outbuf);
823 fclose(file);
825 return 0;