Remove svn:executable from these files.
[kugel-rb/myfork.git] / tools / scramble.c
blobcabe15f48d0a2fe3074fe7b2025f497a7f49343f
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, c100, clip, e2v2, m2v4,\n"
126 "\t fuze, c2v2, clv2, y820, y920, y925, x747, 747p, \n"
127 "\t x777)\n");
128 printf("\nNo option results in Archos standard player/recorder format.\n");
130 exit(1);
133 int main (int argc, char** argv)
135 unsigned long length,i,slen=0;
136 unsigned char *inbuf,*outbuf;
137 unsigned short crc=0;
138 unsigned long chksum=0; /* 32 bit checksum */
139 unsigned char header[24];
140 char *iname = argv[1];
141 char *oname = argv[2];
142 char *xorstring=NULL;
143 int headerlen = 6;
144 FILE* file;
145 int version=0;
146 unsigned long modelnum;
147 char modelname[5];
148 int model_id;
149 enum { none, scramble, xor, tcc_sum, tcc_crc, add } method = scramble;
150 bool creative_enable_ciff;
152 model_id = ARCHOS_PLAYER;
154 if (argc < 3) {
155 usage();
158 if(!strcmp(argv[1], "-fm")) {
159 headerlen = 24;
160 iname = argv[2];
161 oname = argv[3];
162 version = 4;
163 model_id = ARCHOS_FMRECORDER;
166 else if(!strcmp(argv[1], "-v2")) {
167 headerlen = 24;
168 iname = argv[2];
169 oname = argv[3];
170 version = 2;
171 model_id = ARCHOS_V2RECORDER;
174 else if(!strcmp(argv[1], "-ofm")) {
175 headerlen = 24;
176 iname = argv[2];
177 oname = argv[3];
178 version = 8;
179 model_id = ARCHOS_ONDIO_FM;
182 else if(!strcmp(argv[1], "-osp")) {
183 headerlen = 24;
184 iname = argv[2];
185 oname = argv[3];
186 version = 16;
187 model_id = ARCHOS_ONDIO_SP;
190 else if(!strcmp(argv[1], "-neo")) {
191 headerlen = 17;
192 iname = argv[2];
193 oname = argv[3];
194 method = none;
196 else if(!strncmp(argv[1], "-mm=", 4)) {
197 headerlen = 16;
198 iname = argv[2];
199 oname = argv[3];
200 method = xor;
201 version = argv[1][4];
202 if (argc > 4)
203 xorstring = argv[4];
204 else {
205 printf("Multimedia needs an xor string\n");
206 return -1;
209 else if(!strncmp(argv[1], "-tcc=", 4)) {
210 headerlen = 0;
211 iname = argv[2];
212 oname = argv[3];
214 if(!strcmp(&argv[1][5], "sum"))
215 method = tcc_sum;
216 else if(!strcmp(&argv[1][5], "crc"))
217 method = tcc_crc;
218 else {
219 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
220 return 2;
223 else if(!strncmp(argv[1], "-add=", 5)) {
224 iname = argv[2];
225 oname = argv[3];
226 method = add;
228 if(!strcmp(&argv[1][5], "h120"))
229 modelnum = 0;
230 else if(!strcmp(&argv[1][5], "h140"))
231 modelnum = 0; /* the same as the h120 */
232 else if(!strcmp(&argv[1][5], "h100"))
233 modelnum = 1;
234 else if(!strcmp(&argv[1][5], "h300"))
235 modelnum = 2;
236 else if(!strcmp(&argv[1][5], "ipco"))
237 modelnum = 3;
238 else if(!strcmp(&argv[1][5], "nano"))
239 modelnum = 4;
240 else if(!strcmp(&argv[1][5], "ipvd"))
241 modelnum = 5;
242 else if(!strcmp(&argv[1][5], "fp7x"))
243 modelnum = 6;
244 else if(!strcmp(&argv[1][5], "ip3g"))
245 modelnum = 7;
246 else if(!strcmp(&argv[1][5], "ip4g"))
247 modelnum = 8;
248 else if(!strcmp(&argv[1][5], "mini"))
249 modelnum = 9;
250 else if(!strcmp(&argv[1][5], "iax5"))
251 modelnum = 10;
252 else if(!strcmp(&argv[1][5], "mn2g"))
253 modelnum = 11;
254 else if(!strcmp(&argv[1][5], "h10"))
255 modelnum = 13;
256 else if(!strcmp(&argv[1][5], "h10_5gb"))
257 modelnum = 14;
258 else if(!strcmp(&argv[1][5], "tpj2"))
259 modelnum = 15;
260 else if(!strcmp(&argv[1][5], "e200"))
261 modelnum = 16;
262 else if(!strcmp(&argv[1][5], "iam5"))
263 modelnum = 17;
264 else if(!strcmp(&argv[1][5], "giga"))
265 modelnum = 18;
266 else if(!strcmp(&argv[1][5], "1g2g"))
267 modelnum = 19;
268 else if(!strcmp(&argv[1][5], "c200"))
269 modelnum = 20;
270 else if(!strcmp(&argv[1][5], "gigs"))
271 modelnum = 21;
272 else if(!strcmp(&argv[1][5], "m500"))
273 modelnum = 22;
274 else if(!strcmp(&argv[1][5], "m100"))
275 modelnum = 23;
276 else if(!strcmp(&argv[1][5], "d2"))
277 modelnum = 24;
278 else if(!strcmp(&argv[1][5], "iam3"))
279 modelnum = 25;
280 else if (!strcmp(&argv[1][5], "m200"))
281 modelnum = 29;
282 else if(!strcmp(&argv[1][5], "c100"))
283 modelnum = 30;
284 else if(!strcmp(&argv[1][5], "1630")) /* Philips HDD1630 */
285 modelnum = 31;
286 else if (!strcmp(&argv[1][5], "i7"))
287 modelnum = 32;
288 else if (!strcmp(&argv[1][5], "ldax"))
289 modelnum = 33;
290 else if(!strcmp(&argv[1][5], "9200")) /* Philips SA9200 */
291 modelnum = 34;
292 else if (!strcmp(&argv[1][5], "clip"))
293 modelnum = 40;
294 else if (!strcmp(&argv[1][5], "e2v2"))
295 modelnum = 41;
296 else if (!strcmp(&argv[1][5], "m2v4"))
297 modelnum = 42;
298 else if (!strcmp(&argv[1][5], "fuze"))
299 modelnum = 43;
300 else if (!strcmp(&argv[1][5], "c2v2"))
301 modelnum = 44;
302 else if (!strcmp(&argv[1][5], "x747"))
303 modelnum = 45;
304 else if (!strcmp(&argv[1][5], "747p"))
305 modelnum = 54;
306 else if (!strcmp(&argv[1][5], "x777"))
307 modelnum = 61;
308 else if (!strcmp(&argv[1][5], "y820")) /* Samsung YH-820 */
309 modelnum = 57;
310 else if (!strcmp(&argv[1][5], "y920")) /* Samsung YH-920 */
311 modelnum = 58;
312 else if (!strcmp(&argv[1][5], "y925")) /* Samsung YH-925 */
313 modelnum = 59;
314 else if (!strcmp(&argv[1][5], "clv2")) /* Sansa Clipv2 */
315 modelnum = 60;
316 else {
317 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
318 return 2;
320 /* we store a 4-letter model name too, for humans */
321 strcpy(modelname, &argv[1][5]);
322 chksum = modelnum; /* start checksum calcs with this */
325 else if(!strcmp(argv[1], "-iriver")) {
326 /* iRiver code dealt with in the iriver.c code */
327 iname = argv[2];
328 oname = argv[3];
329 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
331 else if(!strcmp(argv[1], "-gigabeat")) {
332 /* iRiver code dealt with in the iriver.c code */
333 iname = argv[2];
334 oname = argv[3];
335 gigabeat_code(iname, oname);
336 return 0;
338 else if(!strcmp(argv[1], "-gigabeats")) {
339 iname = argv[2];
340 oname = argv[3];
341 return gigabeat_s_code(iname, oname);
343 else if(!strcmp(argv[1], "-iaudiox5")) {
344 iname = argv[2];
345 oname = argv[3];
346 return iaudio_encode(iname, oname, "COWON_X5_FW");
348 else if(!strcmp(argv[1], "-iaudiox5v")) {
349 iname = argv[2];
350 oname = argv[3];
351 return iaudio_encode(iname, oname, "COWON_X5V_FW");
353 else if(!strcmp(argv[1], "-iaudiom5")) {
354 iname = argv[2];
355 oname = argv[3];
356 return iaudio_encode(iname, oname, "COWON_M5_FW");
358 else if(!strcmp(argv[1], "-iaudiom3")) {
359 iname = argv[2];
360 oname = argv[3];
361 return iaudio_encode(iname, oname, "COWON_M3_FW");
363 else if(!strcmp(argv[1], "-ipod3g")) {
364 iname = argv[2];
365 oname = argv[3];
366 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
368 else if(!strcmp(argv[1], "-ipod4g")) {
369 iname = argv[2];
370 oname = argv[3];
371 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
373 else if(!strcmp(argv[1], "-ipod5g")) {
374 iname = argv[2];
375 oname = argv[3];
376 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
378 else if(!strncmp(argv[1], "-creative=", 10))
380 if(!strcmp(argv[2], "-no-ciff"))
382 creative_enable_ciff = false;
383 iname = argv[3];
384 oname = argv[4];
386 else
388 creative_enable_ciff = true;
389 iname = argv[2];
390 oname = argv[3];
392 if(!strcmp(&argv[1][10], "zvm"))
393 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
394 else if(!strcmp(&argv[1][10], "zvm60"))
395 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
396 else if(!strcmp(&argv[1][10], "zenvision"))
397 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
398 else if(!strcmp(&argv[1][10], "zenv"))
399 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
400 else if(!strcmp(&argv[1][10], "zen"))
401 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
402 else
404 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
405 return 2;
408 else if(!strncmp(argv[1], "-mi4", 4)) {
409 int mi4magic;
410 char model[4] = "";
411 char type[4] = "";
413 if(!strcmp(&argv[1][4], "v2")) {
414 mi4magic = MI4_MAGIC_DEFAULT;
415 version = 0x00010201;
417 else if(!strcmp(&argv[1][4], "v3")) {
418 mi4magic = MI4_MAGIC_DEFAULT;
419 version = 0x00010301;
421 else if(!strcmp(&argv[1][4], "r")) {
422 mi4magic = MI4_MAGIC_R;
423 version = 0x00010301;
425 else {
426 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
427 return -1;
430 iname = argv[2];
431 oname = argv[3];
433 if(!strncmp(argv[2], "-model=", 7)) {
434 iname = argv[3];
435 oname = argv[4];
436 strncpy(model, &argv[2][7], 4);
438 if(!strncmp(argv[3], "-type=", 6)) {
439 iname = argv[4];
440 oname = argv[5];
441 strncpy(type, &argv[3][6], 4);
445 return mi4_encode(iname, oname, version, mi4magic, model, type);
448 /* open file */
449 file = fopen(iname,"rb");
450 if (!file) {
451 perror(iname);
452 return -1;
454 fseek(file,0,SEEK_END);
455 length = ftell(file);
456 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
458 if ((method == scramble) &&
459 ((length + headerlen) >= size_limit[model_id])) {
460 printf("error: firmware image is %ld bytes while max size is %u!\n",
461 length + headerlen,
462 size_limit[model_id]);
463 fclose(file);
464 return -1;
467 fseek(file,0,SEEK_SET);
468 inbuf = malloc(length);
469 if (method == xor)
470 outbuf = malloc(length*2);
471 else if(method == add)
472 outbuf = malloc(length + 8);
473 else
474 outbuf = malloc(length);
475 if ( !inbuf || !outbuf ) {
476 printf("out of memory!\n");
477 return -1;
479 if(length> 4) {
480 /* zero-fill the last 4 bytes to make sure there's no rubbish there
481 when we write the size-aligned file later */
482 memset(outbuf+length-4, 0, 4);
485 /* read file */
486 i=fread(inbuf,1,length,file);
487 if ( !i ) {
488 perror(iname);
489 return -1;
491 fclose(file);
493 switch (method)
495 case add:
496 for (i = 0; i < length; i++) {
497 /* add 8 unsigned bits but keep a 32 bit sum */
498 chksum += inbuf[i];
500 break;
501 case scramble:
502 slen = length/4;
503 for (i = 0; i < length; i++) {
504 unsigned long addr = (i >> 2) + ((i % 4) * slen);
505 unsigned char data = inbuf[i];
506 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
507 outbuf[addr] = data;
509 break;
511 case xor:
512 /* "compress" */
513 slen = 0;
514 for (i=0; i<length; i++) {
515 if (!(i&7))
516 outbuf[slen++] = 0xff; /* all data is uncompressed */
517 outbuf[slen++] = inbuf[i];
519 break;
520 case none:
521 default:
522 /* dummy case just to silence picky compilers */
523 break;
526 if((method == none) || (method == scramble) || (method == xor)) {
527 /* calculate checksum */
528 for (i=0;i<length;i++)
529 crc += inbuf[i];
532 memset(header, 0, sizeof header);
533 switch (method)
535 case add:
537 int2be(chksum, header); /* checksum, big-endian */
538 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
539 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
540 headerlen = 8;
542 break;
544 case tcc_sum:
545 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
546 telechips_encode_sum(outbuf, length);
547 break;
549 case tcc_crc:
550 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
551 telechips_encode_crc(outbuf, length);
552 break;
554 case scramble:
555 if (headerlen == 6) {
556 int2be(length, header);
557 header[4] = (crc >> 8) & 0xff;
558 header[5] = crc & 0xff;
560 else {
561 header[0] =
562 header[1] =
563 header[2] =
564 header[3] = 0xff; /* ??? */
566 header[6] = (crc >> 8) & 0xff;
567 header[7] = crc & 0xff;
569 header[11] = version;
571 header[15] = headerlen; /* really? */
573 int2be(length, &header[20]);
575 break;
577 case xor:
579 int xorlen = strlen(xorstring);
581 /* xor data */
582 for (i=0; i<slen; i++)
583 outbuf[i] ^= xorstring[i & (xorlen-1)];
585 /* calculate checksum */
586 for (i=0; i<slen; i++)
587 crc += outbuf[i];
589 header[0] = header[2] = 'Z';
590 header[1] = header[3] = version;
591 int2le(length, &header[4]);
592 int2le(slen, &header[8]);
593 int2le(crc, &header[12]);
594 length = slen;
595 break;
598 #define MY_FIRMWARE_TYPE "Rockbox"
599 #define MY_HEADER_VERSION 1
600 default:
601 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
602 header[9]='\0'; /*shouldn't have to, but to be SURE */
603 header[10]=MY_HEADER_VERSION&0xFF;
604 header[11]=(crc>>8)&0xFF;
605 header[12]=crc&0xFF;
606 int2be(sizeof(header), &header[12]);
607 break;
610 /* write file */
611 file = fopen(oname,"wb");
612 if ( !file ) {
613 perror(oname);
614 return -1;
616 if (headerlen > 0) {
617 if ( !fwrite(header,headerlen,1,file) ) {
618 perror(oname);
619 return -1;
622 if ( !fwrite(outbuf,length,1,file) ) {
623 perror(oname);
624 return -1;
626 fclose(file);
628 free(inbuf);
629 free(outbuf);
631 return 0;
634 int iaudio_encode(char *iname, char *oname, char *idstring)
636 size_t len;
637 int length;
638 FILE *file;
639 unsigned char *outbuf;
640 int i;
641 unsigned char sum = 0;
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);
652 outbuf = malloc(length+0x1030);
654 if ( !outbuf ) {
655 printf("out of memory!\n");
656 return -1;
659 len = fread(outbuf+0x1030, 1, length, file);
660 if(len < (size_t) length) {
661 perror(iname);
662 return -2;
665 memset(outbuf, 0, 0x1030);
666 strcpy((char *)outbuf, idstring);
667 memcpy(outbuf+0x20, iaudio_bl_flash,
668 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
669 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
670 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
671 outbuf[0x19] = 2;
673 for(i = 0; i < length;i++)
674 sum += outbuf[0x1030 + i];
676 int2be(length, &outbuf[0x1024]);
677 outbuf[0x102b] = sum;
679 fclose(file);
681 file = fopen(oname, "wb");
682 if (!file) {
683 perror(oname);
684 return -3;
687 len = fwrite(outbuf, 1, length+0x1030, file);
688 if(len < (size_t)length) {
689 perror(oname);
690 return -4;
693 fclose(file);
694 return 0;
698 /* Create an ipod firmware partition image
700 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
702 This function doesn't yet handle the Broadcom resource image for the 5g,
703 so the resulting images won't be usable.
705 This has also only been tested on an ipod Photo
708 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
710 static const char *apple_stop_sign = "{{~~ /-----\\ "\
711 "{{~~ / \\ "\
712 "{{~~| | "\
713 "{{~~| S T O P | "\
714 "{{~~| | "\
715 "{{~~ \\ / "\
716 "{{~~ \\-----/ "\
717 "Copyright(C) 200"\
718 "1 Apple Computer"\
719 ", Inc.----------"\
720 "----------------"\
721 "----------------"\
722 "----------------"\
723 "----------------"\
724 "----------------"\
725 "---------------";
726 size_t len;
727 int length;
728 int rsrclength;
729 int rsrcoffset;
730 FILE *file;
731 unsigned int sum = 0;
732 unsigned int rsrcsum = 0;
733 unsigned char *outbuf;
734 int bufsize;
735 int i;
737 file = fopen(iname, "rb");
738 if (!file) {
739 perror(iname);
740 return -1;
742 fseek(file,0,SEEK_END);
743 length = ftell(file);
745 fseek(file,0,SEEK_SET);
747 bufsize=(length+0x4600);
748 if (fake_rsrc) {
749 bufsize = (bufsize + 0x400) & ~0x200;
752 outbuf = malloc(bufsize);
754 if ( !outbuf ) {
755 printf("out of memory!\n");
756 return -1;
759 len = fread(outbuf+0x4600, 1, length, file);
760 if(len < (size_t)length) {
761 perror(iname);
762 return -2;
764 fclose(file);
766 /* Calculate checksum for later use in header */
767 for(i = 0x4600; i < 0x4600+length;i++)
768 sum += outbuf[i];
770 /* Clear the header area to zero */
771 memset(outbuf, 0, 0x4600);
773 /* APPLE STOP SIGN */
774 strcpy((char *)outbuf, apple_stop_sign);
776 /* VOLUME HEADER */
777 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
778 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
779 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
780 short2le(fw_ver, &outbuf[0x10a]);
782 /* Firmware Directory - "osos" entry */
783 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
784 int2le(0, &outbuf[0x4208]); /* id */
785 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
786 int2le(length, &outbuf[0x4210]); /* Length of firmware */
787 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
788 int2le(0, &outbuf[0x4218]); /* Entry Offset */
789 int2le(sum, &outbuf[0x421c]); /* Checksum */
790 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
791 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
793 /* "rsrc" entry (if applicable) */
794 if (fake_rsrc) {
795 rsrcoffset=(length+0x4600+0x200) & ~0x200;
796 rsrclength=0x200;
797 rsrcsum=0;
799 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
800 int2le(0, &outbuf[0x4230]); /* id */
801 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
802 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
803 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
804 int2le(0, &outbuf[0x4240]); /* Entry Offset */
805 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
806 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
807 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
810 file = fopen(oname, "wb");
811 if (!file) {
812 perror(oname);
813 return -3;
816 len = fwrite(outbuf, 1, length+0x4600, file);
817 if(len < (size_t)length) {
818 perror(oname);
819 return -4;
822 fclose(file);
824 return 0;