When applying the system proxy values really use the values.
[Rockbox.git] / tools / scramble.c
blob6d69f9175e28bfdd78a6b201d2d07ccf0f0f0ddd
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)\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 {
260 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
261 return 2;
263 /* we store a 4-letter model name too, for humans */
264 strcpy(modelname, &argv[1][5]);
265 chksum = modelnum; /* start checksum calcs with this */
268 else if(!strcmp(argv[1], "-iriver")) {
269 /* iRiver code dealt with in the iriver.c code */
270 iname = argv[2];
271 oname = argv[3];
272 iriver_encode(iname, oname, FALSE);
273 return 0;
275 else if(!strcmp(argv[1], "-gigabeat")) {
276 /* iRiver code dealt with in the iriver.c code */
277 iname = argv[2];
278 oname = argv[3];
279 gigabeat_code(iname, oname);
280 return 0;
282 else if(!strcmp(argv[1], "-gigabeats")) {
283 iname = argv[2];
284 oname = argv[3];
285 gigabeat_s_code(iname, oname);
286 return 0;
288 else if(!strcmp(argv[1], "-iaudiox5")) {
289 iname = argv[2];
290 oname = argv[3];
291 return iaudio_encode(iname, oname, "COWON_X5_FW");
293 else if(!strcmp(argv[1], "-iaudiox5v")) {
294 iname = argv[2];
295 oname = argv[3];
296 return iaudio_encode(iname, oname, "COWON_X5V_FW");
298 else if(!strcmp(argv[1], "-iaudiom5")) {
299 iname = argv[2];
300 oname = argv[3];
301 return iaudio_encode(iname, oname, "COWON_M5_FW");
303 else if(!strcmp(argv[1], "-ipod3g")) {
304 iname = argv[2];
305 oname = argv[3];
306 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
308 else if(!strcmp(argv[1], "-ipod4g")) {
309 iname = argv[2];
310 oname = argv[3];
311 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
313 else if(!strcmp(argv[1], "-ipod5g")) {
314 iname = argv[2];
315 oname = argv[3];
316 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
318 else if(!strcmp(argv[1], "-zvm")) {
319 iname = argv[2];
320 oname = argv[3];
321 return zvm_encode(iname, oname);
323 else if(!strncmp(argv[1], "-mi4", 4)) {
324 int mi4magic;
325 int version;
326 char model[4] = "";
327 char type[4] = "";
329 if(!strcmp(&argv[1][4], "v2")) {
330 mi4magic = MI4_MAGIC_DEFAULT;
331 version = 0x00010201;
333 else if(!strcmp(&argv[1][4], "v3")) {
334 mi4magic = MI4_MAGIC_DEFAULT;
335 version = 0x00010301;
337 else if(!strcmp(&argv[1][4], "r")) {
338 mi4magic = MI4_MAGIC_R;
339 version = 0x00010301;
341 else {
342 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
343 return -1;
346 iname = argv[2];
347 oname = argv[3];
349 if(!strncmp(argv[2], "-model=", 7)) {
350 iname = argv[3];
351 oname = argv[4];
352 strncpy(model, &argv[2][7], 4);
354 if(!strncmp(argv[3], "-type=", 6)) {
355 iname = argv[4];
356 oname = argv[5];
357 strncpy(type, &argv[3][6], 4);
361 return mi4_encode(iname, oname, version, mi4magic, model, type);
364 /* open file */
365 file = fopen(iname,"rb");
366 if (!file) {
367 perror(iname);
368 return -1;
370 fseek(file,0,SEEK_END);
371 length = ftell(file);
372 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
374 if ((method == scramble) &&
375 ((length + headerlen) >= size_limit[model_id])) {
376 printf("error: firmware image is %d bytes while max size is %d!\n",
377 length + headerlen,
378 size_limit[model_id]);
379 fclose(file);
380 return -1;
383 fseek(file,0,SEEK_SET);
384 inbuf = malloc(length);
385 if (method == xor)
386 outbuf = malloc(length*2);
387 else if(method == add)
388 outbuf = malloc(length + 8);
389 else
390 outbuf = malloc(length);
391 if ( !inbuf || !outbuf ) {
392 printf("out of memory!\n");
393 return -1;
395 if(length> 4) {
396 /* zero-fill the last 4 bytes to make sure there's no rubbish there
397 when we write the size-aligned file later */
398 memset(outbuf+length-4, 0, 4);
401 /* read file */
402 i=fread(inbuf,1,length,file);
403 if ( !i ) {
404 perror(iname);
405 return -1;
407 fclose(file);
409 switch (method)
411 case add:
412 for (i = 0; i < length; i++) {
413 /* add 8 unsigned bits but keep a 32 bit sum */
414 chksum += inbuf[i];
416 break;
417 case scramble:
418 slen = length/4;
419 for (i = 0; i < length; i++) {
420 unsigned long addr = (i >> 2) + ((i % 4) * slen);
421 unsigned char data = inbuf[i];
422 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
423 outbuf[addr] = data;
425 break;
427 case xor:
428 /* "compress" */
429 slen = 0;
430 for (i=0; i<length; i++) {
431 if (!(i&7))
432 outbuf[slen++] = 0xff; /* all data is uncompressed */
433 outbuf[slen++] = inbuf[i];
435 break;
438 if((method == none) || (method == scramble) || (method == xor)) {
439 /* calculate checksum */
440 for (i=0;i<length;i++)
441 crc += inbuf[i];
444 memset(header, 0, sizeof header);
445 switch (method)
447 case add:
449 int2be(chksum, header); /* checksum, big-endian */
450 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
451 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
452 headerlen = 8;
454 break;
456 case tcc_sum:
457 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
458 telechips_encode_sum(outbuf, length);
459 break;
461 case tcc_crc:
462 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
463 telechips_encode_crc(outbuf, length);
464 break;
466 case scramble:
467 if (headerlen == 6) {
468 int2be(length, header);
469 header[4] = (crc >> 8) & 0xff;
470 header[5] = crc & 0xff;
472 else {
473 header[0] =
474 header[1] =
475 header[2] =
476 header[3] = 0xff; /* ??? */
478 header[6] = (crc >> 8) & 0xff;
479 header[7] = crc & 0xff;
481 header[11] = version;
483 header[15] = headerlen; /* really? */
485 int2be(length, &header[20]);
487 break;
489 case xor:
491 int xorlen = strlen(xorstring);
493 /* xor data */
494 for (i=0; i<slen; i++)
495 outbuf[i] ^= xorstring[i & (xorlen-1)];
497 /* calculate checksum */
498 for (i=0; i<slen; i++)
499 crc += outbuf[i];
501 header[0] = header[2] = 'Z';
502 header[1] = header[3] = version;
503 int2le(length, &header[4]);
504 int2le(slen, &header[8]);
505 int2le(crc, &header[12]);
506 length = slen;
507 break;
510 #define MY_FIRMWARE_TYPE "Rockbox"
511 #define MY_HEADER_VERSION 1
512 default:
513 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
514 header[9]='\0'; /*shouldn't have to, but to be SURE */
515 header[10]=MY_HEADER_VERSION&0xFF;
516 header[11]=(crc>>8)&0xFF;
517 header[12]=crc&0xFF;
518 int2be(sizeof(header), &header[12]);
519 break;
522 /* write file */
523 file = fopen(oname,"wb");
524 if ( !file ) {
525 perror(oname);
526 return -1;
528 if (headerlen > 0) {
529 if ( !fwrite(header,headerlen,1,file) ) {
530 perror(oname);
531 return -1;
534 if ( !fwrite(outbuf,length,1,file) ) {
535 perror(oname);
536 return -1;
538 fclose(file);
540 free(inbuf);
541 free(outbuf);
543 return 0;
546 int iaudio_encode(char *iname, char *oname, char *idstring)
548 size_t len;
549 int length;
550 FILE *file;
551 unsigned char *outbuf;
552 int i;
553 unsigned char sum = 0;
555 file = fopen(iname, "rb");
556 if (!file) {
557 perror(iname);
558 return -1;
560 fseek(file,0,SEEK_END);
561 length = ftell(file);
563 fseek(file,0,SEEK_SET);
564 outbuf = malloc(length+0x1030);
566 if ( !outbuf ) {
567 printf("out of memory!\n");
568 return -1;
571 len = fread(outbuf+0x1030, 1, length, file);
572 if(len < length) {
573 perror(iname);
574 return -2;
577 memset(outbuf, 0, 0x1030);
578 strcpy((char *)outbuf, idstring);
580 for(i = 0; i < length;i++)
581 sum += outbuf[0x1030 + i];
583 int2be(length, &outbuf[0x1024]);
584 outbuf[0x102b] = sum;
586 fclose(file);
588 file = fopen(oname, "wb");
589 if (!file) {
590 perror(oname);
591 return -3;
594 len = fwrite(outbuf, 1, length+0x1030, file);
595 if(len < length) {
596 perror(oname);
597 return -4;
600 fclose(file);
604 /* Create an ipod firmware partition image
606 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
608 This function doesn't yet handle the Broadcom resource image for the 5g,
609 so the resulting images won't be usable.
611 This has also only been tested on an ipod Photo
614 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
616 static const char *apple_stop_sign = "{{~~ /-----\\ "\
617 "{{~~ / \\ "\
618 "{{~~| | "\
619 "{{~~| S T O P | "\
620 "{{~~| | "\
621 "{{~~ \\ / "\
622 "{{~~ \\-----/ "\
623 "Copyright(C) 200"\
624 "1 Apple Computer"\
625 ", Inc.----------"\
626 "----------------"\
627 "----------------"\
628 "----------------"\
629 "----------------"\
630 "----------------"\
631 "---------------";
632 size_t len;
633 int length;
634 int rsrclength;
635 int rsrcoffset;
636 FILE *file;
637 unsigned int sum = 0;
638 unsigned int rsrcsum = 0;
639 unsigned char *outbuf;
640 int bufsize;
641 int i;
643 file = fopen(iname, "rb");
644 if (!file) {
645 perror(iname);
646 return -1;
648 fseek(file,0,SEEK_END);
649 length = ftell(file);
651 fseek(file,0,SEEK_SET);
653 bufsize=(length+0x4600);
654 if (fake_rsrc) {
655 bufsize = (bufsize + 0x400) & ~0x200;
658 outbuf = malloc(bufsize);
660 if ( !outbuf ) {
661 printf("out of memory!\n");
662 return -1;
665 len = fread(outbuf+0x4600, 1, length, file);
666 if(len < length) {
667 perror(iname);
668 return -2;
670 fclose(file);
672 /* Calculate checksum for later use in header */
673 for(i = 0x4600; i < 0x4600+length;i++)
674 sum += outbuf[i];
676 /* Clear the header area to zero */
677 memset(outbuf, 0, 0x4600);
679 /* APPLE STOP SIGN */
680 strcpy((char *)outbuf, apple_stop_sign);
682 /* VOLUME HEADER */
683 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
684 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
685 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
686 short2le(fw_ver, &outbuf[0x10a]);
688 /* Firmware Directory - "osos" entry */
689 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
690 int2le(0, &outbuf[0x4208]); /* id */
691 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
692 int2le(length, &outbuf[0x4210]); /* Length of firmware */
693 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
694 int2le(0, &outbuf[0x4218]); /* Entry Offset */
695 int2le(sum, &outbuf[0x421c]); /* Checksum */
696 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
697 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
699 /* "rsrc" entry (if applicable) */
700 if (fake_rsrc) {
701 rsrcoffset=(length+0x4600+0x200) & ~0x200;
702 rsrclength=0x200;
703 rsrcsum=0;
705 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
706 int2le(0, &outbuf[0x4230]); /* id */
707 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
708 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
709 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
710 int2le(0, &outbuf[0x4240]); /* Entry Offset */
711 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
712 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
713 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
716 file = fopen(oname, "wb");
717 if (!file) {
718 perror(oname);
719 return -3;
722 len = fwrite(outbuf, 1, length+0x4600, file);
723 if(len < length) {
724 perror(oname);
725 return -4;
728 fclose(file);
730 return 0;
734 /* Create an Zen Vision:M FRESCUE structure file
737 int zvm_encode(char *iname, char *oname)
739 size_t len;
740 int length;
741 FILE *file;
742 unsigned int sum = 0;
743 unsigned char *outbuf;
744 int i;
746 file = fopen(iname, "rb");
747 if (!file) {
748 perror(iname);
749 return -1;
751 fseek(file,0,SEEK_END);
752 length = ftell(file);
754 fseek(file,0,SEEK_SET);
756 outbuf = malloc(length+0x18+0x10);
758 if ( !outbuf ) {
759 printf("out of memory!\n");
760 return -1;
763 len = fread(outbuf+0x18, 1, length, file);
764 if(len < length) {
765 perror(iname);
766 return -2;
768 fclose(file);
770 /* Calculate checksum for later use in header */
771 for(i=0; i<length; i+= 4)
772 sum += le2int(&outbuf[0x18+i]) + (le2int(&outbuf[0x18+i])>>16);
774 /* Clear the header area to zero */
775 memset(outbuf, 0, 0x18);
777 /* Header (EDOC) */
778 memcpy((char*)outbuf, "EDOC", 4);
779 /* Total Size */
780 int2le(length+0x20, &outbuf[0x4]);
781 /* 4 bytes of zero */
783 /* Address = 0x900000 */
784 int2le(0x900000, &outbuf[0xC]);
785 /* Size */
786 int2le(length, &outbuf[0x10]);
787 /* Checksum */
788 int2le(sum, &outbuf[0x14]);
789 outbuf[0x16] = 0;
790 outbuf[0x17] = 0;
791 /* Data starts here... */
793 /* Second block starts here ... */
794 /* Address = 0x0 */
795 /* Size */
796 int2le(0x4, &outbuf[0x18+length+0x4]);
797 /* Checksum */
798 outbuf[0x18+length+0x8] = 0xB7;
799 outbuf[0x18+length+0x9] = 0xD5;
800 /* Data: LDR PC, =0x900000 */
801 outbuf[0x18+length+0xC] = 0x18;
802 outbuf[0x18+length+0xD] = 0xF0;
803 outbuf[0x18+length+0xE] = 0x9F;
804 outbuf[0x18+length+0xF] = 0xE5;
807 file = fopen(oname, "wb");
808 if (!file) {
809 perror(oname);
810 return -3;
813 len = fwrite(outbuf, 1, length+0x28, file);
814 if(len < length+0x18) {
815 perror(oname);
816 return -4;
819 free(outbuf);
821 fclose(file);
823 return 0;