Alright, revert r21229 for now. Stupid me forgetting about the inclusion sequence :(
[kugel-rb.git] / tools / scramble.c
blob8bf8d3d03480288164c6803b296956afe0c14901
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)\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], "c100"))
282 modelnum = 30;
283 else if(!strcmp(&argv[1][5], "1630")) /* Philips HDD1630 */
284 modelnum = 31;
285 else if (!strcmp(&argv[1][5], "i7"))
286 modelnum = 32;
287 else if (!strcmp(&argv[1][5], "ldax"))
288 modelnum = 33;
289 else if(!strcmp(&argv[1][5], "9200")) /* Philips SA9200 */
290 modelnum = 34;
291 else if (!strcmp(&argv[1][5], "clip"))
292 modelnum = 40;
293 else if (!strcmp(&argv[1][5], "e2v2"))
294 modelnum = 41;
295 else if (!strcmp(&argv[1][5], "m2v4"))
296 modelnum = 42;
297 else if (!strcmp(&argv[1][5], "fuze"))
298 modelnum = 43;
299 else if (!strcmp(&argv[1][5], "c2v2"))
300 modelnum = 44;
301 else if (!strcmp(&argv[1][5], "x747"))
302 modelnum = 45;
303 else if (!strcmp(&argv[1][5], "y820")) /* Samsung YH-820 */
304 modelnum = 57;
305 else if (!strcmp(&argv[1][5], "y920")) /* Samsung YH-920 */
306 modelnum = 58;
307 else if (!strcmp(&argv[1][5], "y925")) /* Samsung YH-925 */
308 modelnum = 59;
309 else if (!strcmp(&argv[1][5], "clv2")) /* Sansa Clipv2 */
310 modelnum = 60;
311 else {
312 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
313 return 2;
315 /* we store a 4-letter model name too, for humans */
316 strcpy(modelname, &argv[1][5]);
317 chksum = modelnum; /* start checksum calcs with this */
320 else if(!strcmp(argv[1], "-iriver")) {
321 /* iRiver code dealt with in the iriver.c code */
322 iname = argv[2];
323 oname = argv[3];
324 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
326 else if(!strcmp(argv[1], "-gigabeat")) {
327 /* iRiver code dealt with in the iriver.c code */
328 iname = argv[2];
329 oname = argv[3];
330 gigabeat_code(iname, oname);
331 return 0;
333 else if(!strcmp(argv[1], "-gigabeats")) {
334 iname = argv[2];
335 oname = argv[3];
336 return gigabeat_s_code(iname, oname);
338 else if(!strcmp(argv[1], "-iaudiox5")) {
339 iname = argv[2];
340 oname = argv[3];
341 return iaudio_encode(iname, oname, "COWON_X5_FW");
343 else if(!strcmp(argv[1], "-iaudiox5v")) {
344 iname = argv[2];
345 oname = argv[3];
346 return iaudio_encode(iname, oname, "COWON_X5V_FW");
348 else if(!strcmp(argv[1], "-iaudiom5")) {
349 iname = argv[2];
350 oname = argv[3];
351 return iaudio_encode(iname, oname, "COWON_M5_FW");
353 else if(!strcmp(argv[1], "-iaudiom3")) {
354 iname = argv[2];
355 oname = argv[3];
356 return iaudio_encode(iname, oname, "COWON_M3_FW");
358 else if(!strcmp(argv[1], "-ipod3g")) {
359 iname = argv[2];
360 oname = argv[3];
361 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
363 else if(!strcmp(argv[1], "-ipod4g")) {
364 iname = argv[2];
365 oname = argv[3];
366 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
368 else if(!strcmp(argv[1], "-ipod5g")) {
369 iname = argv[2];
370 oname = argv[3];
371 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
373 else if(!strncmp(argv[1], "-creative=", 10))
375 if(!strcmp(argv[2], "-no-ciff"))
377 creative_enable_ciff = false;
378 iname = argv[3];
379 oname = argv[4];
381 else
383 creative_enable_ciff = true;
384 iname = argv[2];
385 oname = argv[3];
387 if(!strcmp(&argv[1][10], "zvm"))
388 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
389 else if(!strcmp(&argv[1][10], "zvm60"))
390 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
391 else if(!strcmp(&argv[1][10], "zenvision"))
392 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
393 else if(!strcmp(&argv[1][10], "zenv"))
394 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
395 else if(!strcmp(&argv[1][10], "zen"))
396 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
397 else
399 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
400 return 2;
403 else if(!strncmp(argv[1], "-mi4", 4)) {
404 int mi4magic;
405 char model[4] = "";
406 char type[4] = "";
408 if(!strcmp(&argv[1][4], "v2")) {
409 mi4magic = MI4_MAGIC_DEFAULT;
410 version = 0x00010201;
412 else if(!strcmp(&argv[1][4], "v3")) {
413 mi4magic = MI4_MAGIC_DEFAULT;
414 version = 0x00010301;
416 else if(!strcmp(&argv[1][4], "r")) {
417 mi4magic = MI4_MAGIC_R;
418 version = 0x00010301;
420 else {
421 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
422 return -1;
425 iname = argv[2];
426 oname = argv[3];
428 if(!strncmp(argv[2], "-model=", 7)) {
429 iname = argv[3];
430 oname = argv[4];
431 strncpy(model, &argv[2][7], 4);
433 if(!strncmp(argv[3], "-type=", 6)) {
434 iname = argv[4];
435 oname = argv[5];
436 strncpy(type, &argv[3][6], 4);
440 return mi4_encode(iname, oname, version, mi4magic, model, type);
443 /* open file */
444 file = fopen(iname,"rb");
445 if (!file) {
446 perror(iname);
447 return -1;
449 fseek(file,0,SEEK_END);
450 length = ftell(file);
451 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
453 if ((method == scramble) &&
454 ((length + headerlen) >= size_limit[model_id])) {
455 printf("error: firmware image is %ld bytes while max size is %u!\n",
456 length + headerlen,
457 size_limit[model_id]);
458 fclose(file);
459 return -1;
462 fseek(file,0,SEEK_SET);
463 inbuf = malloc(length);
464 if (method == xor)
465 outbuf = malloc(length*2);
466 else if(method == add)
467 outbuf = malloc(length + 8);
468 else
469 outbuf = malloc(length);
470 if ( !inbuf || !outbuf ) {
471 printf("out of memory!\n");
472 return -1;
474 if(length> 4) {
475 /* zero-fill the last 4 bytes to make sure there's no rubbish there
476 when we write the size-aligned file later */
477 memset(outbuf+length-4, 0, 4);
480 /* read file */
481 i=fread(inbuf,1,length,file);
482 if ( !i ) {
483 perror(iname);
484 return -1;
486 fclose(file);
488 switch (method)
490 case add:
491 for (i = 0; i < length; i++) {
492 /* add 8 unsigned bits but keep a 32 bit sum */
493 chksum += inbuf[i];
495 break;
496 case scramble:
497 slen = length/4;
498 for (i = 0; i < length; i++) {
499 unsigned long addr = (i >> 2) + ((i % 4) * slen);
500 unsigned char data = inbuf[i];
501 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
502 outbuf[addr] = data;
504 break;
506 case xor:
507 /* "compress" */
508 slen = 0;
509 for (i=0; i<length; i++) {
510 if (!(i&7))
511 outbuf[slen++] = 0xff; /* all data is uncompressed */
512 outbuf[slen++] = inbuf[i];
514 break;
515 case none:
516 default:
517 /* dummy case just to silence picky compilers */
518 break;
521 if((method == none) || (method == scramble) || (method == xor)) {
522 /* calculate checksum */
523 for (i=0;i<length;i++)
524 crc += inbuf[i];
527 memset(header, 0, sizeof header);
528 switch (method)
530 case add:
532 int2be(chksum, header); /* checksum, big-endian */
533 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
534 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
535 headerlen = 8;
537 break;
539 case tcc_sum:
540 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
541 telechips_encode_sum(outbuf, length);
542 break;
544 case tcc_crc:
545 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
546 telechips_encode_crc(outbuf, length);
547 break;
549 case scramble:
550 if (headerlen == 6) {
551 int2be(length, header);
552 header[4] = (crc >> 8) & 0xff;
553 header[5] = crc & 0xff;
555 else {
556 header[0] =
557 header[1] =
558 header[2] =
559 header[3] = 0xff; /* ??? */
561 header[6] = (crc >> 8) & 0xff;
562 header[7] = crc & 0xff;
564 header[11] = version;
566 header[15] = headerlen; /* really? */
568 int2be(length, &header[20]);
570 break;
572 case xor:
574 int xorlen = strlen(xorstring);
576 /* xor data */
577 for (i=0; i<slen; i++)
578 outbuf[i] ^= xorstring[i & (xorlen-1)];
580 /* calculate checksum */
581 for (i=0; i<slen; i++)
582 crc += outbuf[i];
584 header[0] = header[2] = 'Z';
585 header[1] = header[3] = version;
586 int2le(length, &header[4]);
587 int2le(slen, &header[8]);
588 int2le(crc, &header[12]);
589 length = slen;
590 break;
593 #define MY_FIRMWARE_TYPE "Rockbox"
594 #define MY_HEADER_VERSION 1
595 default:
596 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
597 header[9]='\0'; /*shouldn't have to, but to be SURE */
598 header[10]=MY_HEADER_VERSION&0xFF;
599 header[11]=(crc>>8)&0xFF;
600 header[12]=crc&0xFF;
601 int2be(sizeof(header), &header[12]);
602 break;
605 /* write file */
606 file = fopen(oname,"wb");
607 if ( !file ) {
608 perror(oname);
609 return -1;
611 if (headerlen > 0) {
612 if ( !fwrite(header,headerlen,1,file) ) {
613 perror(oname);
614 return -1;
617 if ( !fwrite(outbuf,length,1,file) ) {
618 perror(oname);
619 return -1;
621 fclose(file);
623 free(inbuf);
624 free(outbuf);
626 return 0;
629 int iaudio_encode(char *iname, char *oname, char *idstring)
631 size_t len;
632 int length;
633 FILE *file;
634 unsigned char *outbuf;
635 int i;
636 unsigned char sum = 0;
638 file = fopen(iname, "rb");
639 if (!file) {
640 perror(iname);
641 return -1;
643 fseek(file,0,SEEK_END);
644 length = ftell(file);
646 fseek(file,0,SEEK_SET);
647 outbuf = malloc(length+0x1030);
649 if ( !outbuf ) {
650 printf("out of memory!\n");
651 return -1;
654 len = fread(outbuf+0x1030, 1, length, file);
655 if(len < (size_t) length) {
656 perror(iname);
657 return -2;
660 memset(outbuf, 0, 0x1030);
661 strcpy((char *)outbuf, idstring);
662 memcpy(outbuf+0x20, iaudio_bl_flash,
663 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
664 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
665 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
666 outbuf[0x19] = 2;
668 for(i = 0; i < length;i++)
669 sum += outbuf[0x1030 + i];
671 int2be(length, &outbuf[0x1024]);
672 outbuf[0x102b] = sum;
674 fclose(file);
676 file = fopen(oname, "wb");
677 if (!file) {
678 perror(oname);
679 return -3;
682 len = fwrite(outbuf, 1, length+0x1030, file);
683 if(len < (size_t)length) {
684 perror(oname);
685 return -4;
688 fclose(file);
689 return 0;
693 /* Create an ipod firmware partition image
695 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
697 This function doesn't yet handle the Broadcom resource image for the 5g,
698 so the resulting images won't be usable.
700 This has also only been tested on an ipod Photo
703 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
705 static const char *apple_stop_sign = "{{~~ /-----\\ "\
706 "{{~~ / \\ "\
707 "{{~~| | "\
708 "{{~~| S T O P | "\
709 "{{~~| | "\
710 "{{~~ \\ / "\
711 "{{~~ \\-----/ "\
712 "Copyright(C) 200"\
713 "1 Apple Computer"\
714 ", Inc.----------"\
715 "----------------"\
716 "----------------"\
717 "----------------"\
718 "----------------"\
719 "----------------"\
720 "---------------";
721 size_t len;
722 int length;
723 int rsrclength;
724 int rsrcoffset;
725 FILE *file;
726 unsigned int sum = 0;
727 unsigned int rsrcsum = 0;
728 unsigned char *outbuf;
729 int bufsize;
730 int i;
732 file = fopen(iname, "rb");
733 if (!file) {
734 perror(iname);
735 return -1;
737 fseek(file,0,SEEK_END);
738 length = ftell(file);
740 fseek(file,0,SEEK_SET);
742 bufsize=(length+0x4600);
743 if (fake_rsrc) {
744 bufsize = (bufsize + 0x400) & ~0x200;
747 outbuf = malloc(bufsize);
749 if ( !outbuf ) {
750 printf("out of memory!\n");
751 return -1;
754 len = fread(outbuf+0x4600, 1, length, file);
755 if(len < (size_t)length) {
756 perror(iname);
757 return -2;
759 fclose(file);
761 /* Calculate checksum for later use in header */
762 for(i = 0x4600; i < 0x4600+length;i++)
763 sum += outbuf[i];
765 /* Clear the header area to zero */
766 memset(outbuf, 0, 0x4600);
768 /* APPLE STOP SIGN */
769 strcpy((char *)outbuf, apple_stop_sign);
771 /* VOLUME HEADER */
772 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
773 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
774 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
775 short2le(fw_ver, &outbuf[0x10a]);
777 /* Firmware Directory - "osos" entry */
778 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
779 int2le(0, &outbuf[0x4208]); /* id */
780 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
781 int2le(length, &outbuf[0x4210]); /* Length of firmware */
782 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
783 int2le(0, &outbuf[0x4218]); /* Entry Offset */
784 int2le(sum, &outbuf[0x421c]); /* Checksum */
785 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
786 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
788 /* "rsrc" entry (if applicable) */
789 if (fake_rsrc) {
790 rsrcoffset=(length+0x4600+0x200) & ~0x200;
791 rsrclength=0x200;
792 rsrcsum=0;
794 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
795 int2le(0, &outbuf[0x4230]); /* id */
796 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
797 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
798 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
799 int2le(0, &outbuf[0x4240]); /* Entry Offset */
800 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
801 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
802 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
805 file = fopen(oname, "wb");
806 if (!file) {
807 perror(oname);
808 return -3;
811 len = fwrite(outbuf, 1, length+0x4600, file);
812 if(len < (size_t)length) {
813 perror(oname);
814 return -4;
817 fclose(file);
819 return 0;