Remove use of uniqbuf in PictureFlow, preventing crash on 64-bit sim and freeing...
[kugel-rb.git] / tools / scramble.c
bloba8bb9a9680da3c644458f007854fff3b31cb701d
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, ldax, m200, clip, e2v2, m2v4, fuze,\n"
126 "\t y820, y920, y925)\n");
127 printf("\nNo option results in Archos standard player/recorder format.\n");
129 exit(1);
132 int main (int argc, char** argv)
134 unsigned long length,i,slen=0;
135 unsigned char *inbuf,*outbuf;
136 unsigned short crc=0;
137 unsigned long chksum=0; /* 32 bit checksum */
138 unsigned char header[24];
139 char *iname = argv[1];
140 char *oname = argv[2];
141 char *xorstring=NULL;
142 int headerlen = 6;
143 FILE* file;
144 int version=0;
145 unsigned long modelnum;
146 char modelname[5];
147 int model_id;
148 enum { none, scramble, xor, tcc_sum, tcc_crc, add } method = scramble;
149 bool creative_enable_ciff;
151 model_id = ARCHOS_PLAYER;
153 if (argc < 3) {
154 usage();
157 if(!strcmp(argv[1], "-fm")) {
158 headerlen = 24;
159 iname = argv[2];
160 oname = argv[3];
161 version = 4;
162 model_id = ARCHOS_FMRECORDER;
165 else if(!strcmp(argv[1], "-v2")) {
166 headerlen = 24;
167 iname = argv[2];
168 oname = argv[3];
169 version = 2;
170 model_id = ARCHOS_V2RECORDER;
173 else if(!strcmp(argv[1], "-ofm")) {
174 headerlen = 24;
175 iname = argv[2];
176 oname = argv[3];
177 version = 8;
178 model_id = ARCHOS_ONDIO_FM;
181 else if(!strcmp(argv[1], "-osp")) {
182 headerlen = 24;
183 iname = argv[2];
184 oname = argv[3];
185 version = 16;
186 model_id = ARCHOS_ONDIO_SP;
189 else if(!strcmp(argv[1], "-neo")) {
190 headerlen = 17;
191 iname = argv[2];
192 oname = argv[3];
193 method = none;
195 else if(!strncmp(argv[1], "-mm=", 4)) {
196 headerlen = 16;
197 iname = argv[2];
198 oname = argv[3];
199 method = xor;
200 version = argv[1][4];
201 if (argc > 4)
202 xorstring = argv[4];
203 else {
204 printf("Multimedia needs an xor string\n");
205 return -1;
208 else if(!strncmp(argv[1], "-tcc=", 4)) {
209 headerlen = 0;
210 iname = argv[2];
211 oname = argv[3];
213 if(!strcmp(&argv[1][5], "sum"))
214 method = tcc_sum;
215 else if(!strcmp(&argv[1][5], "crc"))
216 method = tcc_crc;
217 else {
218 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
219 return 2;
222 else if(!strncmp(argv[1], "-add=", 5)) {
223 iname = argv[2];
224 oname = argv[3];
225 method = add;
227 if(!strcmp(&argv[1][5], "h120"))
228 modelnum = 0;
229 else if(!strcmp(&argv[1][5], "h140"))
230 modelnum = 0; /* the same as the h120 */
231 else if(!strcmp(&argv[1][5], "h100"))
232 modelnum = 1;
233 else if(!strcmp(&argv[1][5], "h300"))
234 modelnum = 2;
235 else if(!strcmp(&argv[1][5], "ipco"))
236 modelnum = 3;
237 else if(!strcmp(&argv[1][5], "nano"))
238 modelnum = 4;
239 else if(!strcmp(&argv[1][5], "ipvd"))
240 modelnum = 5;
241 else if(!strcmp(&argv[1][5], "fp7x"))
242 modelnum = 6;
243 else if(!strcmp(&argv[1][5], "ip3g"))
244 modelnum = 7;
245 else if(!strcmp(&argv[1][5], "ip4g"))
246 modelnum = 8;
247 else if(!strcmp(&argv[1][5], "mini"))
248 modelnum = 9;
249 else if(!strcmp(&argv[1][5], "iax5"))
250 modelnum = 10;
251 else if(!strcmp(&argv[1][5], "mn2g"))
252 modelnum = 11;
253 else if(!strcmp(&argv[1][5], "h10"))
254 modelnum = 13;
255 else if(!strcmp(&argv[1][5], "h10_5gb"))
256 modelnum = 14;
257 else if(!strcmp(&argv[1][5], "tpj2"))
258 modelnum = 15;
259 else if(!strcmp(&argv[1][5], "e200"))
260 modelnum = 16;
261 else if(!strcmp(&argv[1][5], "iam5"))
262 modelnum = 17;
263 else if(!strcmp(&argv[1][5], "giga"))
264 modelnum = 18;
265 else if(!strcmp(&argv[1][5], "1g2g"))
266 modelnum = 19;
267 else if(!strcmp(&argv[1][5], "c200"))
268 modelnum = 20;
269 else if(!strcmp(&argv[1][5], "gigs"))
270 modelnum = 21;
271 else if(!strcmp(&argv[1][5], "m500"))
272 modelnum = 22;
273 else if(!strcmp(&argv[1][5], "m100"))
274 modelnum = 23;
275 else if(!strcmp(&argv[1][5], "d2"))
276 modelnum = 24;
277 else if(!strcmp(&argv[1][5], "iam3"))
278 modelnum = 25;
279 else if (!strcmp(&argv[1][5], "m200"))
280 modelnum = 29;
281 else if(!strcmp(&argv[1][5], "1630")) /* Philips HDD1630 */
282 modelnum = 31;
283 else if (!strcmp(&argv[1][5], "i7"))
284 modelnum = 32;
285 else if (!strcmp(&argv[1][5], "ldax"))
286 modelnum = 33;
287 else if(!strcmp(&argv[1][5], "9200")) /* Philips SA9200 */
288 modelnum = 34;
289 else if (!strcmp(&argv[1][5], "clip"))
290 modelnum = 40;
291 else if (!strcmp(&argv[1][5], "e2v2"))
292 modelnum = 41;
293 else if (!strcmp(&argv[1][5], "m2v4"))
294 modelnum = 42;
295 else if (!strcmp(&argv[1][5], "fuze"))
296 modelnum = 43;
297 else if (!strcmp(&argv[1][5], "c2v2"))
298 modelnum = 44;
299 else if (!strcmp(&argv[1][5], "x747"))
300 modelnum = 45;
301 else if (!strcmp(&argv[1][5], "y820")) /* Samsung YH-820 */
302 modelnum = 57;
303 else if (!strcmp(&argv[1][5], "y920")) /* Samsung YH-920 */
304 modelnum = 58;
305 else if (!strcmp(&argv[1][5], "y925")) /* Samsung YH-925 */
306 modelnum = 59;
307 else {
308 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
309 return 2;
311 /* we store a 4-letter model name too, for humans */
312 strcpy(modelname, &argv[1][5]);
313 chksum = modelnum; /* start checksum calcs with this */
316 else if(!strcmp(argv[1], "-iriver")) {
317 /* iRiver code dealt with in the iriver.c code */
318 iname = argv[2];
319 oname = argv[3];
320 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
322 else if(!strcmp(argv[1], "-gigabeat")) {
323 /* iRiver code dealt with in the iriver.c code */
324 iname = argv[2];
325 oname = argv[3];
326 gigabeat_code(iname, oname);
327 return 0;
329 else if(!strcmp(argv[1], "-gigabeats")) {
330 iname = argv[2];
331 oname = argv[3];
332 return gigabeat_s_code(iname, oname);
334 else if(!strcmp(argv[1], "-iaudiox5")) {
335 iname = argv[2];
336 oname = argv[3];
337 return iaudio_encode(iname, oname, "COWON_X5_FW");
339 else if(!strcmp(argv[1], "-iaudiox5v")) {
340 iname = argv[2];
341 oname = argv[3];
342 return iaudio_encode(iname, oname, "COWON_X5V_FW");
344 else if(!strcmp(argv[1], "-iaudiom5")) {
345 iname = argv[2];
346 oname = argv[3];
347 return iaudio_encode(iname, oname, "COWON_M5_FW");
349 else if(!strcmp(argv[1], "-iaudiom3")) {
350 iname = argv[2];
351 oname = argv[3];
352 return iaudio_encode(iname, oname, "COWON_M3_FW");
354 else if(!strcmp(argv[1], "-ipod3g")) {
355 iname = argv[2];
356 oname = argv[3];
357 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
359 else if(!strcmp(argv[1], "-ipod4g")) {
360 iname = argv[2];
361 oname = argv[3];
362 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
364 else if(!strcmp(argv[1], "-ipod5g")) {
365 iname = argv[2];
366 oname = argv[3];
367 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
369 else if(!strncmp(argv[1], "-creative=", 10))
371 if(!strcmp(argv[2], "-no-ciff"))
373 creative_enable_ciff = false;
374 iname = argv[3];
375 oname = argv[4];
377 else
379 creative_enable_ciff = true;
380 iname = argv[2];
381 oname = argv[3];
383 if(!strcmp(&argv[1][10], "zvm"))
384 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
385 else if(!strcmp(&argv[1][10], "zvm60"))
386 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
387 else if(!strcmp(&argv[1][10], "zenvision"))
388 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
389 else if(!strcmp(&argv[1][10], "zenv"))
390 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
391 else if(!strcmp(&argv[1][10], "zen"))
392 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
393 else
395 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
396 return 2;
399 else if(!strncmp(argv[1], "-mi4", 4)) {
400 int mi4magic;
401 char model[4] = "";
402 char type[4] = "";
404 if(!strcmp(&argv[1][4], "v2")) {
405 mi4magic = MI4_MAGIC_DEFAULT;
406 version = 0x00010201;
408 else if(!strcmp(&argv[1][4], "v3")) {
409 mi4magic = MI4_MAGIC_DEFAULT;
410 version = 0x00010301;
412 else if(!strcmp(&argv[1][4], "r")) {
413 mi4magic = MI4_MAGIC_R;
414 version = 0x00010301;
416 else {
417 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
418 return -1;
421 iname = argv[2];
422 oname = argv[3];
424 if(!strncmp(argv[2], "-model=", 7)) {
425 iname = argv[3];
426 oname = argv[4];
427 strncpy(model, &argv[2][7], 4);
429 if(!strncmp(argv[3], "-type=", 6)) {
430 iname = argv[4];
431 oname = argv[5];
432 strncpy(type, &argv[3][6], 4);
436 return mi4_encode(iname, oname, version, mi4magic, model, type);
439 /* open file */
440 file = fopen(iname,"rb");
441 if (!file) {
442 perror(iname);
443 return -1;
445 fseek(file,0,SEEK_END);
446 length = ftell(file);
447 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
449 if ((method == scramble) &&
450 ((length + headerlen) >= size_limit[model_id])) {
451 printf("error: firmware image is %ld bytes while max size is %u!\n",
452 length + headerlen,
453 size_limit[model_id]);
454 fclose(file);
455 return -1;
458 fseek(file,0,SEEK_SET);
459 inbuf = malloc(length);
460 if (method == xor)
461 outbuf = malloc(length*2);
462 else if(method == add)
463 outbuf = malloc(length + 8);
464 else
465 outbuf = malloc(length);
466 if ( !inbuf || !outbuf ) {
467 printf("out of memory!\n");
468 return -1;
470 if(length> 4) {
471 /* zero-fill the last 4 bytes to make sure there's no rubbish there
472 when we write the size-aligned file later */
473 memset(outbuf+length-4, 0, 4);
476 /* read file */
477 i=fread(inbuf,1,length,file);
478 if ( !i ) {
479 perror(iname);
480 return -1;
482 fclose(file);
484 switch (method)
486 case add:
487 for (i = 0; i < length; i++) {
488 /* add 8 unsigned bits but keep a 32 bit sum */
489 chksum += inbuf[i];
491 break;
492 case scramble:
493 slen = length/4;
494 for (i = 0; i < length; i++) {
495 unsigned long addr = (i >> 2) + ((i % 4) * slen);
496 unsigned char data = inbuf[i];
497 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
498 outbuf[addr] = data;
500 break;
502 case xor:
503 /* "compress" */
504 slen = 0;
505 for (i=0; i<length; i++) {
506 if (!(i&7))
507 outbuf[slen++] = 0xff; /* all data is uncompressed */
508 outbuf[slen++] = inbuf[i];
510 break;
511 case none:
512 default:
513 /* dummy case just to silence picky compilers */
514 break;
517 if((method == none) || (method == scramble) || (method == xor)) {
518 /* calculate checksum */
519 for (i=0;i<length;i++)
520 crc += inbuf[i];
523 memset(header, 0, sizeof header);
524 switch (method)
526 case add:
528 int2be(chksum, header); /* checksum, big-endian */
529 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
530 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
531 headerlen = 8;
533 break;
535 case tcc_sum:
536 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
537 telechips_encode_sum(outbuf, length);
538 break;
540 case tcc_crc:
541 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
542 telechips_encode_crc(outbuf, length);
543 break;
545 case scramble:
546 if (headerlen == 6) {
547 int2be(length, header);
548 header[4] = (crc >> 8) & 0xff;
549 header[5] = crc & 0xff;
551 else {
552 header[0] =
553 header[1] =
554 header[2] =
555 header[3] = 0xff; /* ??? */
557 header[6] = (crc >> 8) & 0xff;
558 header[7] = crc & 0xff;
560 header[11] = version;
562 header[15] = headerlen; /* really? */
564 int2be(length, &header[20]);
566 break;
568 case xor:
570 int xorlen = strlen(xorstring);
572 /* xor data */
573 for (i=0; i<slen; i++)
574 outbuf[i] ^= xorstring[i & (xorlen-1)];
576 /* calculate checksum */
577 for (i=0; i<slen; i++)
578 crc += outbuf[i];
580 header[0] = header[2] = 'Z';
581 header[1] = header[3] = version;
582 int2le(length, &header[4]);
583 int2le(slen, &header[8]);
584 int2le(crc, &header[12]);
585 length = slen;
586 break;
589 #define MY_FIRMWARE_TYPE "Rockbox"
590 #define MY_HEADER_VERSION 1
591 default:
592 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
593 header[9]='\0'; /*shouldn't have to, but to be SURE */
594 header[10]=MY_HEADER_VERSION&0xFF;
595 header[11]=(crc>>8)&0xFF;
596 header[12]=crc&0xFF;
597 int2be(sizeof(header), &header[12]);
598 break;
601 /* write file */
602 file = fopen(oname,"wb");
603 if ( !file ) {
604 perror(oname);
605 return -1;
607 if (headerlen > 0) {
608 if ( !fwrite(header,headerlen,1,file) ) {
609 perror(oname);
610 return -1;
613 if ( !fwrite(outbuf,length,1,file) ) {
614 perror(oname);
615 return -1;
617 fclose(file);
619 free(inbuf);
620 free(outbuf);
622 return 0;
625 int iaudio_encode(char *iname, char *oname, char *idstring)
627 size_t len;
628 int length;
629 FILE *file;
630 unsigned char *outbuf;
631 int i;
632 unsigned char sum = 0;
634 file = fopen(iname, "rb");
635 if (!file) {
636 perror(iname);
637 return -1;
639 fseek(file,0,SEEK_END);
640 length = ftell(file);
642 fseek(file,0,SEEK_SET);
643 outbuf = malloc(length+0x1030);
645 if ( !outbuf ) {
646 printf("out of memory!\n");
647 return -1;
650 len = fread(outbuf+0x1030, 1, length, file);
651 if(len < (size_t) length) {
652 perror(iname);
653 return -2;
656 memset(outbuf, 0, 0x1030);
657 strcpy((char *)outbuf, idstring);
658 memcpy(outbuf+0x20, iaudio_bl_flash,
659 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
660 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
661 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
662 outbuf[0x19] = 2;
664 for(i = 0; i < length;i++)
665 sum += outbuf[0x1030 + i];
667 int2be(length, &outbuf[0x1024]);
668 outbuf[0x102b] = sum;
670 fclose(file);
672 file = fopen(oname, "wb");
673 if (!file) {
674 perror(oname);
675 return -3;
678 len = fwrite(outbuf, 1, length+0x1030, file);
679 if(len < (size_t)length) {
680 perror(oname);
681 return -4;
684 fclose(file);
685 return 0;
689 /* Create an ipod firmware partition image
691 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
693 This function doesn't yet handle the Broadcom resource image for the 5g,
694 so the resulting images won't be usable.
696 This has also only been tested on an ipod Photo
699 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
701 static const char *apple_stop_sign = "{{~~ /-----\\ "\
702 "{{~~ / \\ "\
703 "{{~~| | "\
704 "{{~~| S T O P | "\
705 "{{~~| | "\
706 "{{~~ \\ / "\
707 "{{~~ \\-----/ "\
708 "Copyright(C) 200"\
709 "1 Apple Computer"\
710 ", Inc.----------"\
711 "----------------"\
712 "----------------"\
713 "----------------"\
714 "----------------"\
715 "----------------"\
716 "---------------";
717 size_t len;
718 int length;
719 int rsrclength;
720 int rsrcoffset;
721 FILE *file;
722 unsigned int sum = 0;
723 unsigned int rsrcsum = 0;
724 unsigned char *outbuf;
725 int bufsize;
726 int i;
728 file = fopen(iname, "rb");
729 if (!file) {
730 perror(iname);
731 return -1;
733 fseek(file,0,SEEK_END);
734 length = ftell(file);
736 fseek(file,0,SEEK_SET);
738 bufsize=(length+0x4600);
739 if (fake_rsrc) {
740 bufsize = (bufsize + 0x400) & ~0x200;
743 outbuf = malloc(bufsize);
745 if ( !outbuf ) {
746 printf("out of memory!\n");
747 return -1;
750 len = fread(outbuf+0x4600, 1, length, file);
751 if(len < (size_t)length) {
752 perror(iname);
753 return -2;
755 fclose(file);
757 /* Calculate checksum for later use in header */
758 for(i = 0x4600; i < 0x4600+length;i++)
759 sum += outbuf[i];
761 /* Clear the header area to zero */
762 memset(outbuf, 0, 0x4600);
764 /* APPLE STOP SIGN */
765 strcpy((char *)outbuf, apple_stop_sign);
767 /* VOLUME HEADER */
768 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
769 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
770 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
771 short2le(fw_ver, &outbuf[0x10a]);
773 /* Firmware Directory - "osos" entry */
774 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
775 int2le(0, &outbuf[0x4208]); /* id */
776 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
777 int2le(length, &outbuf[0x4210]); /* Length of firmware */
778 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
779 int2le(0, &outbuf[0x4218]); /* Entry Offset */
780 int2le(sum, &outbuf[0x421c]); /* Checksum */
781 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
782 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
784 /* "rsrc" entry (if applicable) */
785 if (fake_rsrc) {
786 rsrcoffset=(length+0x4600+0x200) & ~0x200;
787 rsrclength=0x200;
788 rsrcsum=0;
790 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
791 int2le(0, &outbuf[0x4230]); /* id */
792 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
793 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
794 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
795 int2le(0, &outbuf[0x4240]); /* Entry Offset */
796 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
797 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
798 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
801 file = fopen(oname, "wb");
802 if (!file) {
803 perror(oname);
804 return -3;
807 len = fwrite(outbuf, 1, length+0x4600, file);
808 if(len < (size_t)length) {
809 perror(oname);
810 return -4;
813 fclose(file);
815 return 0;