Commit FS#10260 by Marko Pahlke: Clip SVG for the manual (used to add a pdf and updat...
[kugel-rb.git] / tools / scramble.c
blobffb568b75e740e317c470378e5ec2256c735dc81
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 c2v2, clv2, 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 if (!strcmp(&argv[1][5], "clv2")) /* Sansa Clipv2 */
308 modelnum = 60;
309 else {
310 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
311 return 2;
313 /* we store a 4-letter model name too, for humans */
314 strcpy(modelname, &argv[1][5]);
315 chksum = modelnum; /* start checksum calcs with this */
318 else if(!strcmp(argv[1], "-iriver")) {
319 /* iRiver code dealt with in the iriver.c code */
320 iname = argv[2];
321 oname = argv[3];
322 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
324 else if(!strcmp(argv[1], "-gigabeat")) {
325 /* iRiver code dealt with in the iriver.c code */
326 iname = argv[2];
327 oname = argv[3];
328 gigabeat_code(iname, oname);
329 return 0;
331 else if(!strcmp(argv[1], "-gigabeats")) {
332 iname = argv[2];
333 oname = argv[3];
334 return gigabeat_s_code(iname, oname);
336 else if(!strcmp(argv[1], "-iaudiox5")) {
337 iname = argv[2];
338 oname = argv[3];
339 return iaudio_encode(iname, oname, "COWON_X5_FW");
341 else if(!strcmp(argv[1], "-iaudiox5v")) {
342 iname = argv[2];
343 oname = argv[3];
344 return iaudio_encode(iname, oname, "COWON_X5V_FW");
346 else if(!strcmp(argv[1], "-iaudiom5")) {
347 iname = argv[2];
348 oname = argv[3];
349 return iaudio_encode(iname, oname, "COWON_M5_FW");
351 else if(!strcmp(argv[1], "-iaudiom3")) {
352 iname = argv[2];
353 oname = argv[3];
354 return iaudio_encode(iname, oname, "COWON_M3_FW");
356 else if(!strcmp(argv[1], "-ipod3g")) {
357 iname = argv[2];
358 oname = argv[3];
359 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
361 else if(!strcmp(argv[1], "-ipod4g")) {
362 iname = argv[2];
363 oname = argv[3];
364 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
366 else if(!strcmp(argv[1], "-ipod5g")) {
367 iname = argv[2];
368 oname = argv[3];
369 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
371 else if(!strncmp(argv[1], "-creative=", 10))
373 if(!strcmp(argv[2], "-no-ciff"))
375 creative_enable_ciff = false;
376 iname = argv[3];
377 oname = argv[4];
379 else
381 creative_enable_ciff = true;
382 iname = argv[2];
383 oname = argv[3];
385 if(!strcmp(&argv[1][10], "zvm"))
386 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
387 else if(!strcmp(&argv[1][10], "zvm60"))
388 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
389 else if(!strcmp(&argv[1][10], "zenvision"))
390 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
391 else if(!strcmp(&argv[1][10], "zenv"))
392 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
393 else if(!strcmp(&argv[1][10], "zen"))
394 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
395 else
397 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
398 return 2;
401 else if(!strncmp(argv[1], "-mi4", 4)) {
402 int mi4magic;
403 char model[4] = "";
404 char type[4] = "";
406 if(!strcmp(&argv[1][4], "v2")) {
407 mi4magic = MI4_MAGIC_DEFAULT;
408 version = 0x00010201;
410 else if(!strcmp(&argv[1][4], "v3")) {
411 mi4magic = MI4_MAGIC_DEFAULT;
412 version = 0x00010301;
414 else if(!strcmp(&argv[1][4], "r")) {
415 mi4magic = MI4_MAGIC_R;
416 version = 0x00010301;
418 else {
419 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
420 return -1;
423 iname = argv[2];
424 oname = argv[3];
426 if(!strncmp(argv[2], "-model=", 7)) {
427 iname = argv[3];
428 oname = argv[4];
429 strncpy(model, &argv[2][7], 4);
431 if(!strncmp(argv[3], "-type=", 6)) {
432 iname = argv[4];
433 oname = argv[5];
434 strncpy(type, &argv[3][6], 4);
438 return mi4_encode(iname, oname, version, mi4magic, model, type);
441 /* open file */
442 file = fopen(iname,"rb");
443 if (!file) {
444 perror(iname);
445 return -1;
447 fseek(file,0,SEEK_END);
448 length = ftell(file);
449 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
451 if ((method == scramble) &&
452 ((length + headerlen) >= size_limit[model_id])) {
453 printf("error: firmware image is %ld bytes while max size is %u!\n",
454 length + headerlen,
455 size_limit[model_id]);
456 fclose(file);
457 return -1;
460 fseek(file,0,SEEK_SET);
461 inbuf = malloc(length);
462 if (method == xor)
463 outbuf = malloc(length*2);
464 else if(method == add)
465 outbuf = malloc(length + 8);
466 else
467 outbuf = malloc(length);
468 if ( !inbuf || !outbuf ) {
469 printf("out of memory!\n");
470 return -1;
472 if(length> 4) {
473 /* zero-fill the last 4 bytes to make sure there's no rubbish there
474 when we write the size-aligned file later */
475 memset(outbuf+length-4, 0, 4);
478 /* read file */
479 i=fread(inbuf,1,length,file);
480 if ( !i ) {
481 perror(iname);
482 return -1;
484 fclose(file);
486 switch (method)
488 case add:
489 for (i = 0; i < length; i++) {
490 /* add 8 unsigned bits but keep a 32 bit sum */
491 chksum += inbuf[i];
493 break;
494 case scramble:
495 slen = length/4;
496 for (i = 0; i < length; i++) {
497 unsigned long addr = (i >> 2) + ((i % 4) * slen);
498 unsigned char data = inbuf[i];
499 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
500 outbuf[addr] = data;
502 break;
504 case xor:
505 /* "compress" */
506 slen = 0;
507 for (i=0; i<length; i++) {
508 if (!(i&7))
509 outbuf[slen++] = 0xff; /* all data is uncompressed */
510 outbuf[slen++] = inbuf[i];
512 break;
513 case none:
514 default:
515 /* dummy case just to silence picky compilers */
516 break;
519 if((method == none) || (method == scramble) || (method == xor)) {
520 /* calculate checksum */
521 for (i=0;i<length;i++)
522 crc += inbuf[i];
525 memset(header, 0, sizeof header);
526 switch (method)
528 case add:
530 int2be(chksum, header); /* checksum, big-endian */
531 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
532 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
533 headerlen = 8;
535 break;
537 case tcc_sum:
538 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
539 telechips_encode_sum(outbuf, length);
540 break;
542 case tcc_crc:
543 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
544 telechips_encode_crc(outbuf, length);
545 break;
547 case scramble:
548 if (headerlen == 6) {
549 int2be(length, header);
550 header[4] = (crc >> 8) & 0xff;
551 header[5] = crc & 0xff;
553 else {
554 header[0] =
555 header[1] =
556 header[2] =
557 header[3] = 0xff; /* ??? */
559 header[6] = (crc >> 8) & 0xff;
560 header[7] = crc & 0xff;
562 header[11] = version;
564 header[15] = headerlen; /* really? */
566 int2be(length, &header[20]);
568 break;
570 case xor:
572 int xorlen = strlen(xorstring);
574 /* xor data */
575 for (i=0; i<slen; i++)
576 outbuf[i] ^= xorstring[i & (xorlen-1)];
578 /* calculate checksum */
579 for (i=0; i<slen; i++)
580 crc += outbuf[i];
582 header[0] = header[2] = 'Z';
583 header[1] = header[3] = version;
584 int2le(length, &header[4]);
585 int2le(slen, &header[8]);
586 int2le(crc, &header[12]);
587 length = slen;
588 break;
591 #define MY_FIRMWARE_TYPE "Rockbox"
592 #define MY_HEADER_VERSION 1
593 default:
594 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
595 header[9]='\0'; /*shouldn't have to, but to be SURE */
596 header[10]=MY_HEADER_VERSION&0xFF;
597 header[11]=(crc>>8)&0xFF;
598 header[12]=crc&0xFF;
599 int2be(sizeof(header), &header[12]);
600 break;
603 /* write file */
604 file = fopen(oname,"wb");
605 if ( !file ) {
606 perror(oname);
607 return -1;
609 if (headerlen > 0) {
610 if ( !fwrite(header,headerlen,1,file) ) {
611 perror(oname);
612 return -1;
615 if ( !fwrite(outbuf,length,1,file) ) {
616 perror(oname);
617 return -1;
619 fclose(file);
621 free(inbuf);
622 free(outbuf);
624 return 0;
627 int iaudio_encode(char *iname, char *oname, char *idstring)
629 size_t len;
630 int length;
631 FILE *file;
632 unsigned char *outbuf;
633 int i;
634 unsigned char sum = 0;
636 file = fopen(iname, "rb");
637 if (!file) {
638 perror(iname);
639 return -1;
641 fseek(file,0,SEEK_END);
642 length = ftell(file);
644 fseek(file,0,SEEK_SET);
645 outbuf = malloc(length+0x1030);
647 if ( !outbuf ) {
648 printf("out of memory!\n");
649 return -1;
652 len = fread(outbuf+0x1030, 1, length, file);
653 if(len < (size_t) length) {
654 perror(iname);
655 return -2;
658 memset(outbuf, 0, 0x1030);
659 strcpy((char *)outbuf, idstring);
660 memcpy(outbuf+0x20, iaudio_bl_flash,
661 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
662 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
663 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
664 outbuf[0x19] = 2;
666 for(i = 0; i < length;i++)
667 sum += outbuf[0x1030 + i];
669 int2be(length, &outbuf[0x1024]);
670 outbuf[0x102b] = sum;
672 fclose(file);
674 file = fopen(oname, "wb");
675 if (!file) {
676 perror(oname);
677 return -3;
680 len = fwrite(outbuf, 1, length+0x1030, file);
681 if(len < (size_t)length) {
682 perror(oname);
683 return -4;
686 fclose(file);
687 return 0;
691 /* Create an ipod firmware partition image
693 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
695 This function doesn't yet handle the Broadcom resource image for the 5g,
696 so the resulting images won't be usable.
698 This has also only been tested on an ipod Photo
701 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
703 static const char *apple_stop_sign = "{{~~ /-----\\ "\
704 "{{~~ / \\ "\
705 "{{~~| | "\
706 "{{~~| S T O P | "\
707 "{{~~| | "\
708 "{{~~ \\ / "\
709 "{{~~ \\-----/ "\
710 "Copyright(C) 200"\
711 "1 Apple Computer"\
712 ", Inc.----------"\
713 "----------------"\
714 "----------------"\
715 "----------------"\
716 "----------------"\
717 "----------------"\
718 "---------------";
719 size_t len;
720 int length;
721 int rsrclength;
722 int rsrcoffset;
723 FILE *file;
724 unsigned int sum = 0;
725 unsigned int rsrcsum = 0;
726 unsigned char *outbuf;
727 int bufsize;
728 int i;
730 file = fopen(iname, "rb");
731 if (!file) {
732 perror(iname);
733 return -1;
735 fseek(file,0,SEEK_END);
736 length = ftell(file);
738 fseek(file,0,SEEK_SET);
740 bufsize=(length+0x4600);
741 if (fake_rsrc) {
742 bufsize = (bufsize + 0x400) & ~0x200;
745 outbuf = malloc(bufsize);
747 if ( !outbuf ) {
748 printf("out of memory!\n");
749 return -1;
752 len = fread(outbuf+0x4600, 1, length, file);
753 if(len < (size_t)length) {
754 perror(iname);
755 return -2;
757 fclose(file);
759 /* Calculate checksum for later use in header */
760 for(i = 0x4600; i < 0x4600+length;i++)
761 sum += outbuf[i];
763 /* Clear the header area to zero */
764 memset(outbuf, 0, 0x4600);
766 /* APPLE STOP SIGN */
767 strcpy((char *)outbuf, apple_stop_sign);
769 /* VOLUME HEADER */
770 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
771 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
772 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
773 short2le(fw_ver, &outbuf[0x10a]);
775 /* Firmware Directory - "osos" entry */
776 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
777 int2le(0, &outbuf[0x4208]); /* id */
778 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
779 int2le(length, &outbuf[0x4210]); /* Length of firmware */
780 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
781 int2le(0, &outbuf[0x4218]); /* Entry Offset */
782 int2le(sum, &outbuf[0x421c]); /* Checksum */
783 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
784 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
786 /* "rsrc" entry (if applicable) */
787 if (fake_rsrc) {
788 rsrcoffset=(length+0x4600+0x200) & ~0x200;
789 rsrclength=0x200;
790 rsrcsum=0;
792 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
793 int2le(0, &outbuf[0x4230]); /* id */
794 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
795 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
796 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
797 int2le(0, &outbuf[0x4240]); /* Entry Offset */
798 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
799 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
800 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
803 file = fopen(oname, "wb");
804 if (!file) {
805 perror(oname);
806 return -3;
809 len = fwrite(outbuf, 1, length+0x4600, file);
810 if(len < (size_t)length) {
811 perror(oname);
812 return -4;
815 fclose(file);
817 return 0;