Fix a typo in the comment and add a (somewhat vague) description of the values returned.
[kugel-rb/myfork.git] / tools / scramble.c
blob0efb8e26319d295c6eca78c6c36cf6af630942df
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 printf("\nNo option results in Archos standard player/recorder format.\n");
128 exit(1);
131 int main (int argc, char** argv)
133 unsigned long length,i,slen=0;
134 unsigned char *inbuf,*outbuf;
135 unsigned short crc=0;
136 unsigned long chksum=0; /* 32 bit checksum */
137 unsigned char header[24];
138 char *iname = argv[1];
139 char *oname = argv[2];
140 char *xorstring=NULL;
141 int headerlen = 6;
142 FILE* file;
143 int version=0;
144 unsigned long modelnum;
145 char modelname[5];
146 int model_id;
147 enum { none, scramble, xor, tcc_sum, tcc_crc, add } method = scramble;
148 bool creative_enable_ciff;
150 model_id = ARCHOS_PLAYER;
152 if (argc < 3) {
153 usage();
156 if(!strcmp(argv[1], "-fm")) {
157 headerlen = 24;
158 iname = argv[2];
159 oname = argv[3];
160 version = 4;
161 model_id = ARCHOS_FMRECORDER;
164 else if(!strcmp(argv[1], "-v2")) {
165 headerlen = 24;
166 iname = argv[2];
167 oname = argv[3];
168 version = 2;
169 model_id = ARCHOS_V2RECORDER;
172 else if(!strcmp(argv[1], "-ofm")) {
173 headerlen = 24;
174 iname = argv[2];
175 oname = argv[3];
176 version = 8;
177 model_id = ARCHOS_ONDIO_FM;
180 else if(!strcmp(argv[1], "-osp")) {
181 headerlen = 24;
182 iname = argv[2];
183 oname = argv[3];
184 version = 16;
185 model_id = ARCHOS_ONDIO_SP;
188 else if(!strcmp(argv[1], "-neo")) {
189 headerlen = 17;
190 iname = argv[2];
191 oname = argv[3];
192 method = none;
194 else if(!strncmp(argv[1], "-mm=", 4)) {
195 headerlen = 16;
196 iname = argv[2];
197 oname = argv[3];
198 method = xor;
199 version = argv[1][4];
200 if (argc > 4)
201 xorstring = argv[4];
202 else {
203 printf("Multimedia needs an xor string\n");
204 return -1;
207 else if(!strncmp(argv[1], "-tcc=", 4)) {
208 headerlen = 0;
209 iname = argv[2];
210 oname = argv[3];
212 if(!strcmp(&argv[1][5], "sum"))
213 method = tcc_sum;
214 else if(!strcmp(&argv[1][5], "crc"))
215 method = tcc_crc;
216 else {
217 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
218 return 2;
221 else if(!strncmp(argv[1], "-add=", 5)) {
222 iname = argv[2];
223 oname = argv[3];
224 method = add;
226 if(!strcmp(&argv[1][5], "h120"))
227 modelnum = 0;
228 else if(!strcmp(&argv[1][5], "h140"))
229 modelnum = 0; /* the same as the h120 */
230 else if(!strcmp(&argv[1][5], "h100"))
231 modelnum = 1;
232 else if(!strcmp(&argv[1][5], "h300"))
233 modelnum = 2;
234 else if(!strcmp(&argv[1][5], "ipco"))
235 modelnum = 3;
236 else if(!strcmp(&argv[1][5], "nano"))
237 modelnum = 4;
238 else if(!strcmp(&argv[1][5], "ipvd"))
239 modelnum = 5;
240 else if(!strcmp(&argv[1][5], "fp7x"))
241 modelnum = 6;
242 else if(!strcmp(&argv[1][5], "ip3g"))
243 modelnum = 7;
244 else if(!strcmp(&argv[1][5], "ip4g"))
245 modelnum = 8;
246 else if(!strcmp(&argv[1][5], "mini"))
247 modelnum = 9;
248 else if(!strcmp(&argv[1][5], "iax5"))
249 modelnum = 10;
250 else if(!strcmp(&argv[1][5], "mn2g"))
251 modelnum = 11;
252 else if(!strcmp(&argv[1][5], "h10"))
253 modelnum = 13;
254 else if(!strcmp(&argv[1][5], "h10_5gb"))
255 modelnum = 14;
256 else if(!strcmp(&argv[1][5], "tpj2"))
257 modelnum = 15;
258 else if(!strcmp(&argv[1][5], "e200"))
259 modelnum = 16;
260 else if(!strcmp(&argv[1][5], "iam5"))
261 modelnum = 17;
262 else if(!strcmp(&argv[1][5], "giga"))
263 modelnum = 18;
264 else if(!strcmp(&argv[1][5], "1g2g"))
265 modelnum = 19;
266 else if(!strcmp(&argv[1][5], "c200"))
267 modelnum = 20;
268 else if(!strcmp(&argv[1][5], "gigs"))
269 modelnum = 21;
270 else if(!strcmp(&argv[1][5], "m500"))
271 modelnum = 22;
272 else if(!strcmp(&argv[1][5], "m100"))
273 modelnum = 23;
274 else if(!strcmp(&argv[1][5], "d2"))
275 modelnum = 24;
276 else if(!strcmp(&argv[1][5], "iam3"))
277 modelnum = 25;
278 else if (!strcmp(&argv[1][5], "m200"))
279 modelnum = 29;
280 else if(!strcmp(&argv[1][5], "1630")) /* Philips HDD1630 */
281 modelnum = 31;
282 else if (!strcmp(&argv[1][5], "i7"))
283 modelnum = 32;
284 else if (!strcmp(&argv[1][5], "ldax"))
285 modelnum = 33;
286 else if(!strcmp(&argv[1][5], "9200")) /* Philips SA9200 */
287 modelnum = 34;
288 else if (!strcmp(&argv[1][5], "clip"))
289 modelnum = 40;
290 else if (!strcmp(&argv[1][5], "e2v2"))
291 modelnum = 41;
292 else if (!strcmp(&argv[1][5], "m2v4"))
293 modelnum = 42;
294 else if (!strcmp(&argv[1][5], "fuze"))
295 modelnum = 43;
296 else if (!strcmp(&argv[1][5], "c2v2"))
297 modelnum = 44;
298 else if (!strcmp(&argv[1][5], "x747"))
299 modelnum = 45;
300 else {
301 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
302 return 2;
304 /* we store a 4-letter model name too, for humans */
305 strcpy(modelname, &argv[1][5]);
306 chksum = modelnum; /* start checksum calcs with this */
309 else if(!strcmp(argv[1], "-iriver")) {
310 /* iRiver code dealt with in the iriver.c code */
311 iname = argv[2];
312 oname = argv[3];
313 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
315 else if(!strcmp(argv[1], "-gigabeat")) {
316 /* iRiver code dealt with in the iriver.c code */
317 iname = argv[2];
318 oname = argv[3];
319 gigabeat_code(iname, oname);
320 return 0;
322 else if(!strcmp(argv[1], "-gigabeats")) {
323 iname = argv[2];
324 oname = argv[3];
325 gigabeat_s_code(iname, oname);
326 return 0;
328 else if(!strcmp(argv[1], "-iaudiox5")) {
329 iname = argv[2];
330 oname = argv[3];
331 return iaudio_encode(iname, oname, "COWON_X5_FW");
333 else if(!strcmp(argv[1], "-iaudiox5v")) {
334 iname = argv[2];
335 oname = argv[3];
336 return iaudio_encode(iname, oname, "COWON_X5V_FW");
338 else if(!strcmp(argv[1], "-iaudiom5")) {
339 iname = argv[2];
340 oname = argv[3];
341 return iaudio_encode(iname, oname, "COWON_M5_FW");
343 else if(!strcmp(argv[1], "-iaudiom3")) {
344 iname = argv[2];
345 oname = argv[3];
346 return iaudio_encode(iname, oname, "COWON_M3_FW");
348 else if(!strcmp(argv[1], "-ipod3g")) {
349 iname = argv[2];
350 oname = argv[3];
351 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
353 else if(!strcmp(argv[1], "-ipod4g")) {
354 iname = argv[2];
355 oname = argv[3];
356 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
358 else if(!strcmp(argv[1], "-ipod5g")) {
359 iname = argv[2];
360 oname = argv[3];
361 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
363 else if(!strncmp(argv[1], "-creative=", 10))
365 if(!strcmp(argv[2], "-no-ciff"))
367 creative_enable_ciff = false;
368 iname = argv[3];
369 oname = argv[4];
371 else
373 creative_enable_ciff = true;
374 iname = argv[2];
375 oname = argv[3];
377 if(!strcmp(&argv[1][10], "zvm"))
378 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
379 else if(!strcmp(&argv[1][10], "zvm60"))
380 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
381 else if(!strcmp(&argv[1][10], "zenvision"))
382 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
383 else if(!strcmp(&argv[1][10], "zenv"))
384 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
385 else if(!strcmp(&argv[1][10], "zen"))
386 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
387 else
389 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
390 return 2;
393 else if(!strncmp(argv[1], "-mi4", 4)) {
394 int mi4magic;
395 char model[4] = "";
396 char type[4] = "";
398 if(!strcmp(&argv[1][4], "v2")) {
399 mi4magic = MI4_MAGIC_DEFAULT;
400 version = 0x00010201;
402 else if(!strcmp(&argv[1][4], "v3")) {
403 mi4magic = MI4_MAGIC_DEFAULT;
404 version = 0x00010301;
406 else if(!strcmp(&argv[1][4], "r")) {
407 mi4magic = MI4_MAGIC_R;
408 version = 0x00010301;
410 else {
411 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
412 return -1;
415 iname = argv[2];
416 oname = argv[3];
418 if(!strncmp(argv[2], "-model=", 7)) {
419 iname = argv[3];
420 oname = argv[4];
421 strncpy(model, &argv[2][7], 4);
423 if(!strncmp(argv[3], "-type=", 6)) {
424 iname = argv[4];
425 oname = argv[5];
426 strncpy(type, &argv[3][6], 4);
430 return mi4_encode(iname, oname, version, mi4magic, model, type);
433 /* open file */
434 file = fopen(iname,"rb");
435 if (!file) {
436 perror(iname);
437 return -1;
439 fseek(file,0,SEEK_END);
440 length = ftell(file);
441 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
443 if ((method == scramble) &&
444 ((length + headerlen) >= size_limit[model_id])) {
445 printf("error: firmware image is %ld bytes while max size is %u!\n",
446 length + headerlen,
447 size_limit[model_id]);
448 fclose(file);
449 return -1;
452 fseek(file,0,SEEK_SET);
453 inbuf = malloc(length);
454 if (method == xor)
455 outbuf = malloc(length*2);
456 else if(method == add)
457 outbuf = malloc(length + 8);
458 else
459 outbuf = malloc(length);
460 if ( !inbuf || !outbuf ) {
461 printf("out of memory!\n");
462 return -1;
464 if(length> 4) {
465 /* zero-fill the last 4 bytes to make sure there's no rubbish there
466 when we write the size-aligned file later */
467 memset(outbuf+length-4, 0, 4);
470 /* read file */
471 i=fread(inbuf,1,length,file);
472 if ( !i ) {
473 perror(iname);
474 return -1;
476 fclose(file);
478 switch (method)
480 case add:
481 for (i = 0; i < length; i++) {
482 /* add 8 unsigned bits but keep a 32 bit sum */
483 chksum += inbuf[i];
485 break;
486 case scramble:
487 slen = length/4;
488 for (i = 0; i < length; i++) {
489 unsigned long addr = (i >> 2) + ((i % 4) * slen);
490 unsigned char data = inbuf[i];
491 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
492 outbuf[addr] = data;
494 break;
496 case xor:
497 /* "compress" */
498 slen = 0;
499 for (i=0; i<length; i++) {
500 if (!(i&7))
501 outbuf[slen++] = 0xff; /* all data is uncompressed */
502 outbuf[slen++] = inbuf[i];
504 break;
505 case none:
506 default:
507 /* dummy case just to silence picky compilers */
508 break;
511 if((method == none) || (method == scramble) || (method == xor)) {
512 /* calculate checksum */
513 for (i=0;i<length;i++)
514 crc += inbuf[i];
517 memset(header, 0, sizeof header);
518 switch (method)
520 case add:
522 int2be(chksum, header); /* checksum, big-endian */
523 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
524 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
525 headerlen = 8;
527 break;
529 case tcc_sum:
530 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
531 telechips_encode_sum(outbuf, length);
532 break;
534 case tcc_crc:
535 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
536 telechips_encode_crc(outbuf, length);
537 break;
539 case scramble:
540 if (headerlen == 6) {
541 int2be(length, header);
542 header[4] = (crc >> 8) & 0xff;
543 header[5] = crc & 0xff;
545 else {
546 header[0] =
547 header[1] =
548 header[2] =
549 header[3] = 0xff; /* ??? */
551 header[6] = (crc >> 8) & 0xff;
552 header[7] = crc & 0xff;
554 header[11] = version;
556 header[15] = headerlen; /* really? */
558 int2be(length, &header[20]);
560 break;
562 case xor:
564 int xorlen = strlen(xorstring);
566 /* xor data */
567 for (i=0; i<slen; i++)
568 outbuf[i] ^= xorstring[i & (xorlen-1)];
570 /* calculate checksum */
571 for (i=0; i<slen; i++)
572 crc += outbuf[i];
574 header[0] = header[2] = 'Z';
575 header[1] = header[3] = version;
576 int2le(length, &header[4]);
577 int2le(slen, &header[8]);
578 int2le(crc, &header[12]);
579 length = slen;
580 break;
583 #define MY_FIRMWARE_TYPE "Rockbox"
584 #define MY_HEADER_VERSION 1
585 default:
586 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
587 header[9]='\0'; /*shouldn't have to, but to be SURE */
588 header[10]=MY_HEADER_VERSION&0xFF;
589 header[11]=(crc>>8)&0xFF;
590 header[12]=crc&0xFF;
591 int2be(sizeof(header), &header[12]);
592 break;
595 /* write file */
596 file = fopen(oname,"wb");
597 if ( !file ) {
598 perror(oname);
599 return -1;
601 if (headerlen > 0) {
602 if ( !fwrite(header,headerlen,1,file) ) {
603 perror(oname);
604 return -1;
607 if ( !fwrite(outbuf,length,1,file) ) {
608 perror(oname);
609 return -1;
611 fclose(file);
613 free(inbuf);
614 free(outbuf);
616 return 0;
619 int iaudio_encode(char *iname, char *oname, char *idstring)
621 size_t len;
622 int length;
623 FILE *file;
624 unsigned char *outbuf;
625 int i;
626 unsigned char sum = 0;
628 file = fopen(iname, "rb");
629 if (!file) {
630 perror(iname);
631 return -1;
633 fseek(file,0,SEEK_END);
634 length = ftell(file);
636 fseek(file,0,SEEK_SET);
637 outbuf = malloc(length+0x1030);
639 if ( !outbuf ) {
640 printf("out of memory!\n");
641 return -1;
644 len = fread(outbuf+0x1030, 1, length, file);
645 if(len < (size_t) length) {
646 perror(iname);
647 return -2;
650 memset(outbuf, 0, 0x1030);
651 strcpy((char *)outbuf, idstring);
652 memcpy(outbuf+0x20, iaudio_bl_flash,
653 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
654 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
655 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
656 outbuf[0x19] = 2;
658 for(i = 0; i < length;i++)
659 sum += outbuf[0x1030 + i];
661 int2be(length, &outbuf[0x1024]);
662 outbuf[0x102b] = sum;
664 fclose(file);
666 file = fopen(oname, "wb");
667 if (!file) {
668 perror(oname);
669 return -3;
672 len = fwrite(outbuf, 1, length+0x1030, file);
673 if(len < (size_t)length) {
674 perror(oname);
675 return -4;
678 fclose(file);
679 return 0;
683 /* Create an ipod firmware partition image
685 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
687 This function doesn't yet handle the Broadcom resource image for the 5g,
688 so the resulting images won't be usable.
690 This has also only been tested on an ipod Photo
693 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
695 static const char *apple_stop_sign = "{{~~ /-----\\ "\
696 "{{~~ / \\ "\
697 "{{~~| | "\
698 "{{~~| S T O P | "\
699 "{{~~| | "\
700 "{{~~ \\ / "\
701 "{{~~ \\-----/ "\
702 "Copyright(C) 200"\
703 "1 Apple Computer"\
704 ", Inc.----------"\
705 "----------------"\
706 "----------------"\
707 "----------------"\
708 "----------------"\
709 "----------------"\
710 "---------------";
711 size_t len;
712 int length;
713 int rsrclength;
714 int rsrcoffset;
715 FILE *file;
716 unsigned int sum = 0;
717 unsigned int rsrcsum = 0;
718 unsigned char *outbuf;
719 int bufsize;
720 int i;
722 file = fopen(iname, "rb");
723 if (!file) {
724 perror(iname);
725 return -1;
727 fseek(file,0,SEEK_END);
728 length = ftell(file);
730 fseek(file,0,SEEK_SET);
732 bufsize=(length+0x4600);
733 if (fake_rsrc) {
734 bufsize = (bufsize + 0x400) & ~0x200;
737 outbuf = malloc(bufsize);
739 if ( !outbuf ) {
740 printf("out of memory!\n");
741 return -1;
744 len = fread(outbuf+0x4600, 1, length, file);
745 if(len < (size_t)length) {
746 perror(iname);
747 return -2;
749 fclose(file);
751 /* Calculate checksum for later use in header */
752 for(i = 0x4600; i < 0x4600+length;i++)
753 sum += outbuf[i];
755 /* Clear the header area to zero */
756 memset(outbuf, 0, 0x4600);
758 /* APPLE STOP SIGN */
759 strcpy((char *)outbuf, apple_stop_sign);
761 /* VOLUME HEADER */
762 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
763 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
764 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
765 short2le(fw_ver, &outbuf[0x10a]);
767 /* Firmware Directory - "osos" entry */
768 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
769 int2le(0, &outbuf[0x4208]); /* id */
770 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
771 int2le(length, &outbuf[0x4210]); /* Length of firmware */
772 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
773 int2le(0, &outbuf[0x4218]); /* Entry Offset */
774 int2le(sum, &outbuf[0x421c]); /* Checksum */
775 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
776 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
778 /* "rsrc" entry (if applicable) */
779 if (fake_rsrc) {
780 rsrcoffset=(length+0x4600+0x200) & ~0x200;
781 rsrclength=0x200;
782 rsrcsum=0;
784 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
785 int2le(0, &outbuf[0x4230]); /* id */
786 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
787 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
788 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
789 int2le(0, &outbuf[0x4240]); /* Entry Offset */
790 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
791 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
792 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
795 file = fopen(oname, "wb");
796 if (!file) {
797 perror(oname);
798 return -3;
801 len = fwrite(outbuf, 1, length+0x4600, file);
802 if(len < (size_t)length) {
803 perror(oname);
804 return -4;
807 fclose(file);
809 return 0;