Don't use the same completion_event for both directions. This could cause problems...
[kugel-rb.git] / tools / scramble.c
blobc9b6d15dd4b37fa558a19b5c9e83a48443c74a70
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 static int iaudio_encode(char *iname, char *oname, char *idstring);
35 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc);
36 static int ccpmp_encode(char *iname, char *oname);
38 enum
40 ARCHOS_PLAYER, /* and V1 recorder */
41 ARCHOS_V2RECORDER,
42 ARCHOS_FMRECORDER,
43 ARCHOS_ONDIO_SP,
44 ARCHOS_ONDIO_FM
47 static unsigned int size_limit[] =
49 0x32000, /* ARCHOS_PLAYER */
50 0x64000, /* ARCHOS_V2RECORDER */
51 0x64000, /* ARCHOS_FMRECORDER */
52 0x64000, /* ARCHOS_ONDIO_SP */
53 0x64000 /* ARCHOS_ONDIO_FM */
56 void short2le(unsigned short val, unsigned char* addr)
58 addr[0] = val & 0xFF;
59 addr[1] = (val >> 8) & 0xff;
62 unsigned int le2int(unsigned char* buf)
64 unsigned int res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
66 return res;
69 void int2le(unsigned int val, unsigned char* addr)
71 addr[0] = val & 0xFF;
72 addr[1] = (val >> 8) & 0xff;
73 addr[2] = (val >> 16) & 0xff;
74 addr[3] = (val >> 24) & 0xff;
77 void int2be(unsigned int val, unsigned char* addr)
79 addr[0] = (val >> 24) & 0xff;
80 addr[1] = (val >> 16) & 0xff;
81 addr[2] = (val >> 8) & 0xff;
82 addr[3] = val & 0xFF;
85 void short2be(unsigned short val, unsigned char* addr)
87 addr[0] = (val >> 8) & 0xff;
88 addr[1] = val & 0xFF;
91 void usage(void)
93 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
94 printf("options:\n"
95 "\t-fm Archos FM recorder format\n"
96 "\t-v2 Archos V2 recorder format\n"
97 "\t-ofm Archos Ondio FM recorder format\n"
98 "\t-osp Archos Ondio SP format\n"
99 "\t-neo SSI Neo format\n"
100 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
101 "\t-iriver iRiver format\n"
102 "\t-iaudiox5 iAudio X5 format\n"
103 "\t-iaudiox5v iAudio X5V format\n"
104 "\t-iaudiom5 iAudio M5 format\n"
105 "\t-iaudiom3 iAudio M3 format\n");
106 printf("\t-ipod3g ipod firmware partition format (3rd Gen)\n"
107 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
108 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
109 "\t-creative=X Creative firmware structure format\n"
110 "\t (X values: zvm, zvm60, zenvision\n"
111 "\t zenv, zen\n");
112 printf("\t-gigabeat Toshiba Gigabeat F/X format\n"
113 "\t-gigabeats Toshiba Gigabeat S format\n"
114 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
115 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
116 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
117 "\t All mi4 options take two optional arguments:\n");
118 printf("\t -model=XXXX where XXXX is the model id string\n"
119 "\t -type=XXXX where XXXX is a string indicating the \n"
120 "\t type of binary, eg. RBOS, RBBL\n"
121 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
122 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
123 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
124 "\t ip3g, ip4g, mini, iax5, iam5, iam3, h10, h10_5gb,\n"
125 "\t tpj2, c200, e200, giga, gigs, m100, m500, d2,\n");
126 printf("\t 9200, 1630, ldax, m200, c100, clip, e2v2, m2v4,\n"
127 "\t fuze, c2v2, clv2, y820, y920, y925, x747, 747p, \n"
128 "\t x777, nn2g, m244)\n");
129 printf("\nNo option results in Archos standard player/recorder format.\n");
131 exit(1);
134 int main (int argc, char** argv)
136 unsigned long length,i,slen=0;
137 unsigned char *inbuf,*outbuf;
138 unsigned short crc=0;
139 unsigned long chksum=0; /* 32 bit checksum */
140 unsigned char header[24];
141 char *iname = argv[1];
142 char *oname = argv[2];
143 char *xorstring=NULL;
144 int headerlen = 6;
145 FILE* file;
146 int version=0;
147 unsigned long modelnum;
148 char modelname[5];
149 int model_id;
150 enum { none, scramble, xor, tcc_sum, tcc_crc, add } method = scramble;
151 bool creative_enable_ciff;
153 model_id = ARCHOS_PLAYER;
155 if (argc < 3) {
156 usage();
159 if(!strcmp(argv[1], "-fm")) {
160 headerlen = 24;
161 iname = argv[2];
162 oname = argv[3];
163 version = 4;
164 model_id = ARCHOS_FMRECORDER;
167 else if(!strcmp(argv[1], "-v2")) {
168 headerlen = 24;
169 iname = argv[2];
170 oname = argv[3];
171 version = 2;
172 model_id = ARCHOS_V2RECORDER;
175 else if(!strcmp(argv[1], "-ofm")) {
176 headerlen = 24;
177 iname = argv[2];
178 oname = argv[3];
179 version = 8;
180 model_id = ARCHOS_ONDIO_FM;
183 else if(!strcmp(argv[1], "-osp")) {
184 headerlen = 24;
185 iname = argv[2];
186 oname = argv[3];
187 version = 16;
188 model_id = ARCHOS_ONDIO_SP;
191 else if(!strcmp(argv[1], "-neo")) {
192 headerlen = 17;
193 iname = argv[2];
194 oname = argv[3];
195 method = none;
197 else if(!strncmp(argv[1], "-mm=", 4)) {
198 headerlen = 16;
199 iname = argv[2];
200 oname = argv[3];
201 method = xor;
202 version = argv[1][4];
203 if (argc > 4)
204 xorstring = argv[4];
205 else {
206 printf("Multimedia needs an xor string\n");
207 return -1;
210 else if(!strncmp(argv[1], "-tcc=", 4)) {
211 headerlen = 0;
212 iname = argv[2];
213 oname = argv[3];
215 if(!strcmp(&argv[1][5], "sum"))
216 method = tcc_sum;
217 else if(!strcmp(&argv[1][5], "crc"))
218 method = tcc_crc;
219 else {
220 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
221 return 2;
224 else if(!strncmp(argv[1], "-add=", 5)) {
225 iname = argv[2];
226 oname = argv[3];
227 method = add;
229 if(!strcmp(&argv[1][5], "h120"))
230 modelnum = 0;
231 else if(!strcmp(&argv[1][5], "h140"))
232 modelnum = 0; /* the same as the h120 */
233 else if(!strcmp(&argv[1][5], "h100"))
234 modelnum = 1;
235 else if(!strcmp(&argv[1][5], "h300"))
236 modelnum = 2;
237 else if(!strcmp(&argv[1][5], "ipco"))
238 modelnum = 3;
239 else if(!strcmp(&argv[1][5], "nano"))
240 modelnum = 4;
241 else if(!strcmp(&argv[1][5], "ipvd"))
242 modelnum = 5;
243 else if(!strcmp(&argv[1][5], "fp7x"))
244 modelnum = 6;
245 else if(!strcmp(&argv[1][5], "ip3g"))
246 modelnum = 7;
247 else if(!strcmp(&argv[1][5], "ip4g"))
248 modelnum = 8;
249 else if(!strcmp(&argv[1][5], "mini"))
250 modelnum = 9;
251 else if(!strcmp(&argv[1][5], "iax5"))
252 modelnum = 10;
253 else if(!strcmp(&argv[1][5], "mn2g"))
254 modelnum = 11;
255 else if(!strcmp(&argv[1][5], "h10"))
256 modelnum = 13;
257 else if(!strcmp(&argv[1][5], "h10_5gb"))
258 modelnum = 14;
259 else if(!strcmp(&argv[1][5], "tpj2"))
260 modelnum = 15;
261 else if(!strcmp(&argv[1][5], "e200"))
262 modelnum = 16;
263 else if(!strcmp(&argv[1][5], "iam5"))
264 modelnum = 17;
265 else if(!strcmp(&argv[1][5], "giga"))
266 modelnum = 18;
267 else if(!strcmp(&argv[1][5], "1g2g"))
268 modelnum = 19;
269 else if(!strcmp(&argv[1][5], "c200"))
270 modelnum = 20;
271 else if(!strcmp(&argv[1][5], "gigs"))
272 modelnum = 21;
273 else if(!strcmp(&argv[1][5], "m500"))
274 modelnum = 22;
275 else if(!strcmp(&argv[1][5], "m100"))
276 modelnum = 23;
277 else if(!strcmp(&argv[1][5], "d2"))
278 modelnum = 24;
279 else if(!strcmp(&argv[1][5], "iam3"))
280 modelnum = 25;
281 else if (!strcmp(&argv[1][5], "m200"))
282 modelnum = 29;
283 else if(!strcmp(&argv[1][5], "c100"))
284 modelnum = 30;
285 else if(!strcmp(&argv[1][5], "1630")) /* Philips HDD1630 */
286 modelnum = 31;
287 else if (!strcmp(&argv[1][5], "i7"))
288 modelnum = 32;
289 else if (!strcmp(&argv[1][5], "ldax"))
290 modelnum = 33;
291 else if(!strcmp(&argv[1][5], "9200")) /* Philips SA9200 */
292 modelnum = 34;
293 else if (!strcmp(&argv[1][5], "clip"))
294 modelnum = 40;
295 else if (!strcmp(&argv[1][5], "e2v2"))
296 modelnum = 41;
297 else if (!strcmp(&argv[1][5], "m2v4"))
298 modelnum = 42;
299 else if (!strcmp(&argv[1][5], "fuze"))
300 modelnum = 43;
301 else if (!strcmp(&argv[1][5], "c2v2"))
302 modelnum = 44;
303 else if (!strcmp(&argv[1][5], "x747"))
304 modelnum = 45;
305 else if (!strcmp(&argv[1][5], "747p"))
306 modelnum = 54;
307 else if (!strcmp(&argv[1][5], "y820")) /* Samsung YH-820 */
308 modelnum = 57;
309 else if (!strcmp(&argv[1][5], "y920")) /* Samsung YH-920 */
310 modelnum = 58;
311 else if (!strcmp(&argv[1][5], "y925")) /* Samsung YH-925 */
312 modelnum = 59;
313 else if (!strcmp(&argv[1][5], "clv2")) /* Sansa Clipv2 */
314 modelnum = 60;
315 else if (!strcmp(&argv[1][5], "x777"))
316 modelnum = 61;
317 else if (!strcmp(&argv[1][5], "nn2g")) /* iPod Nano 2nd Gen */
318 modelnum = 62;
319 else if (!strcmp(&argv[1][5], "x767"))
320 modelnum = 64;
321 else if (!strcmp(&argv[1][5], "m244"))
322 modelnum = 131;
323 else {
324 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
325 return 2;
327 /* we store a 4-letter model name too, for humans */
328 strcpy(modelname, &argv[1][5]);
329 chksum = modelnum; /* start checksum calcs with this */
332 else if(!strcmp(argv[1], "-iriver")) {
333 /* iRiver code dealt with in the iriver.c code */
334 iname = argv[2];
335 oname = argv[3];
336 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
338 else if(!strcmp(argv[1], "-gigabeat")) {
339 /* iRiver code dealt with in the iriver.c code */
340 iname = argv[2];
341 oname = argv[3];
342 gigabeat_code(iname, oname);
343 return 0;
345 else if(!strcmp(argv[1], "-gigabeats")) {
346 iname = argv[2];
347 oname = argv[3];
348 return gigabeat_s_code(iname, oname);
350 else if(!strcmp(argv[1], "-iaudiox5")) {
351 iname = argv[2];
352 oname = argv[3];
353 return iaudio_encode(iname, oname, "COWON_X5_FW");
355 else if(!strcmp(argv[1], "-iaudiox5v")) {
356 iname = argv[2];
357 oname = argv[3];
358 return iaudio_encode(iname, oname, "COWON_X5V_FW");
360 else if(!strcmp(argv[1], "-iaudiom5")) {
361 iname = argv[2];
362 oname = argv[3];
363 return iaudio_encode(iname, oname, "COWON_M5_FW");
365 else if(!strcmp(argv[1], "-iaudiom3")) {
366 iname = argv[2];
367 oname = argv[3];
368 return iaudio_encode(iname, oname, "COWON_M3_FW");
370 else if(!strcmp(argv[1], "-ipod3g")) {
371 iname = argv[2];
372 oname = argv[3];
373 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
375 else if(!strcmp(argv[1], "-ipod4g")) {
376 iname = argv[2];
377 oname = argv[3];
378 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
380 else if(!strcmp(argv[1], "-ipod5g")) {
381 iname = argv[2];
382 oname = argv[3];
383 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
385 else if(!strncmp(argv[1], "-creative=", 10)) {
386 if(!strcmp(argv[2], "-no-ciff"))
388 creative_enable_ciff = false;
389 iname = argv[3];
390 oname = argv[4];
392 else
394 creative_enable_ciff = true;
395 iname = argv[2];
396 oname = argv[3];
398 if(!strcmp(&argv[1][10], "zvm"))
399 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
400 else if(!strcmp(&argv[1][10], "zvm60"))
401 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
402 else if(!strcmp(&argv[1][10], "zenvision"))
403 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
404 else if(!strcmp(&argv[1][10], "zenv"))
405 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
406 else if(!strcmp(&argv[1][10], "zen"))
407 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
408 else
410 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
411 return 2;
414 else if(!strcmp(argv[1], "-ccpmp")) {
415 iname = argv[2];
416 oname = argv[3];
417 return ccpmp_encode(iname, oname);
419 else if(!strncmp(argv[1], "-mi4", 4)) {
420 int mi4magic;
421 char model[4] = "";
422 char type[4] = "";
424 if(!strcmp(&argv[1][4], "v2")) {
425 mi4magic = MI4_MAGIC_DEFAULT;
426 version = 0x00010201;
428 else if(!strcmp(&argv[1][4], "v3")) {
429 mi4magic = MI4_MAGIC_DEFAULT;
430 version = 0x00010301;
432 else if(!strcmp(&argv[1][4], "r")) {
433 mi4magic = MI4_MAGIC_R;
434 version = 0x00010301;
436 else {
437 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
438 return -1;
441 iname = argv[2];
442 oname = argv[3];
444 if(!strncmp(argv[2], "-model=", 7)) {
445 iname = argv[3];
446 oname = argv[4];
447 strncpy(model, &argv[2][7], 4);
449 if(!strncmp(argv[3], "-type=", 6)) {
450 iname = argv[4];
451 oname = argv[5];
452 strncpy(type, &argv[3][6], 4);
456 return mi4_encode(iname, oname, version, mi4magic, model, type);
459 /* open file */
460 file = fopen(iname,"rb");
461 if (!file) {
462 perror(iname);
463 return -1;
465 fseek(file,0,SEEK_END);
466 length = ftell(file);
467 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
469 if ((method == scramble) &&
470 ((length + headerlen) >= size_limit[model_id])) {
471 printf("error: firmware image is %ld bytes while max size is %u!\n",
472 length + headerlen,
473 size_limit[model_id]);
474 fclose(file);
475 return -1;
478 fseek(file,0,SEEK_SET);
479 inbuf = malloc(length);
480 if (method == xor)
481 outbuf = malloc(length*2);
482 else if(method == add)
483 outbuf = malloc(length + 8);
484 else
485 outbuf = malloc(length);
486 if ( !inbuf || !outbuf ) {
487 printf("out of memory!\n");
488 return -1;
490 if(length> 4) {
491 /* zero-fill the last 4 bytes to make sure there's no rubbish there
492 when we write the size-aligned file later */
493 memset(outbuf+length-4, 0, 4);
496 /* read file */
497 i=fread(inbuf,1,length,file);
498 if ( !i ) {
499 perror(iname);
500 return -1;
502 fclose(file);
504 switch (method)
506 case add:
507 for (i = 0; i < length; i++) {
508 /* add 8 unsigned bits but keep a 32 bit sum */
509 chksum += inbuf[i];
511 break;
512 case scramble:
513 slen = length/4;
514 for (i = 0; i < length; i++) {
515 unsigned long addr = (i >> 2) + ((i % 4) * slen);
516 unsigned char data = inbuf[i];
517 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
518 outbuf[addr] = data;
520 break;
522 case xor:
523 /* "compress" */
524 slen = 0;
525 for (i=0; i<length; i++) {
526 if (!(i&7))
527 outbuf[slen++] = 0xff; /* all data is uncompressed */
528 outbuf[slen++] = inbuf[i];
530 break;
531 case none:
532 default:
533 /* dummy case just to silence picky compilers */
534 break;
537 if((method == none) || (method == scramble) || (method == xor)) {
538 /* calculate checksum */
539 for (i=0;i<length;i++)
540 crc += inbuf[i];
543 memset(header, 0, sizeof header);
544 switch (method)
546 case add:
548 int2be(chksum, header); /* checksum, big-endian */
549 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
550 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
551 headerlen = 8;
553 break;
555 case tcc_sum:
556 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
557 telechips_encode_sum(outbuf, length);
558 break;
560 case tcc_crc:
561 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
562 telechips_encode_crc(outbuf, length);
563 break;
565 case scramble:
566 if (headerlen == 6) {
567 int2be(length, header);
568 header[4] = (crc >> 8) & 0xff;
569 header[5] = crc & 0xff;
571 else {
572 header[0] =
573 header[1] =
574 header[2] =
575 header[3] = 0xff; /* ??? */
577 header[6] = (crc >> 8) & 0xff;
578 header[7] = crc & 0xff;
580 header[11] = version;
582 header[15] = headerlen; /* really? */
584 int2be(length, &header[20]);
586 break;
588 case xor:
590 int xorlen = strlen(xorstring);
592 /* xor data */
593 for (i=0; i<slen; i++)
594 outbuf[i] ^= xorstring[i & (xorlen-1)];
596 /* calculate checksum */
597 for (i=0; i<slen; i++)
598 crc += outbuf[i];
600 header[0] = header[2] = 'Z';
601 header[1] = header[3] = version;
602 int2le(length, &header[4]);
603 int2le(slen, &header[8]);
604 int2le(crc, &header[12]);
605 length = slen;
606 break;
609 #define MY_FIRMWARE_TYPE "Rockbox"
610 #define MY_HEADER_VERSION 1
611 default:
612 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
613 header[9]='\0'; /*shouldn't have to, but to be SURE */
614 header[10]=MY_HEADER_VERSION&0xFF;
615 header[11]=(crc>>8)&0xFF;
616 header[12]=crc&0xFF;
617 int2be(sizeof(header), &header[12]);
618 break;
621 /* write file */
622 file = fopen(oname,"wb");
623 if ( !file ) {
624 perror(oname);
625 return -1;
627 if (headerlen > 0) {
628 if ( !fwrite(header,headerlen,1,file) ) {
629 perror(oname);
630 return -1;
633 if ( !fwrite(outbuf,length,1,file) ) {
634 perror(oname);
635 return -1;
637 fclose(file);
639 free(inbuf);
640 free(outbuf);
642 return 0;
645 static int iaudio_encode(char *iname, char *oname, char *idstring)
647 size_t len;
648 int length;
649 FILE *file;
650 unsigned char *outbuf;
651 int i;
652 unsigned char sum = 0;
654 file = fopen(iname, "rb");
655 if (!file) {
656 perror(iname);
657 return -1;
659 fseek(file,0,SEEK_END);
660 length = ftell(file);
662 fseek(file,0,SEEK_SET);
663 outbuf = malloc(length+0x1030);
665 if ( !outbuf ) {
666 printf("out of memory!\n");
667 return -1;
670 len = fread(outbuf+0x1030, 1, length, file);
671 if(len < (size_t) length) {
672 perror(iname);
673 return -2;
676 memset(outbuf, 0, 0x1030);
677 strcpy((char *)outbuf, idstring);
678 memcpy(outbuf+0x20, iaudio_bl_flash,
679 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
680 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
681 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
682 outbuf[0x19] = 2;
684 for(i = 0; i < length;i++)
685 sum += outbuf[0x1030 + i];
687 int2be(length, &outbuf[0x1024]);
688 outbuf[0x102b] = sum;
690 fclose(file);
692 file = fopen(oname, "wb");
693 if (!file) {
694 perror(oname);
695 return -3;
698 len = fwrite(outbuf, 1, length+0x1030, file);
699 if(len < (size_t)length) {
700 perror(oname);
701 return -4;
704 fclose(file);
705 return 0;
709 /* Create an ipod firmware partition image
711 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
713 This function doesn't yet handle the Broadcom resource image for the 5g,
714 so the resulting images won't be usable.
716 This has also only been tested on an ipod Photo
719 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
721 static const char *apple_stop_sign = "{{~~ /-----\\ "\
722 "{{~~ / \\ "\
723 "{{~~| | "\
724 "{{~~| S T O P | "\
725 "{{~~| | "\
726 "{{~~ \\ / "\
727 "{{~~ \\-----/ "\
728 "Copyright(C) 200"\
729 "1 Apple Computer"\
730 ", Inc.----------"\
731 "----------------"\
732 "----------------"\
733 "----------------"\
734 "----------------"\
735 "----------------"\
736 "---------------";
737 size_t len;
738 int length;
739 int rsrclength;
740 int rsrcoffset;
741 FILE *file;
742 unsigned int sum = 0;
743 unsigned int rsrcsum = 0;
744 unsigned char *outbuf;
745 int bufsize;
746 int i;
748 file = fopen(iname, "rb");
749 if (!file) {
750 perror(iname);
751 return -1;
753 fseek(file,0,SEEK_END);
754 length = ftell(file);
756 fseek(file,0,SEEK_SET);
758 bufsize=(length+0x4600);
759 if (fake_rsrc) {
760 bufsize = (bufsize + 0x400) & ~0x200;
763 outbuf = malloc(bufsize);
765 if ( !outbuf ) {
766 printf("out of memory!\n");
767 return -1;
770 len = fread(outbuf+0x4600, 1, length, file);
771 if(len < (size_t)length) {
772 perror(iname);
773 return -2;
775 fclose(file);
777 /* Calculate checksum for later use in header */
778 for(i = 0x4600; i < 0x4600+length;i++)
779 sum += outbuf[i];
781 /* Clear the header area to zero */
782 memset(outbuf, 0, 0x4600);
784 /* APPLE STOP SIGN */
785 strcpy((char *)outbuf, apple_stop_sign);
787 /* VOLUME HEADER */
788 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
789 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
790 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
791 short2le(fw_ver, &outbuf[0x10a]);
793 /* Firmware Directory - "osos" entry */
794 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
795 int2le(0, &outbuf[0x4208]); /* id */
796 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
797 int2le(length, &outbuf[0x4210]); /* Length of firmware */
798 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
799 int2le(0, &outbuf[0x4218]); /* Entry Offset */
800 int2le(sum, &outbuf[0x421c]); /* Checksum */
801 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
802 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
804 /* "rsrc" entry (if applicable) */
805 if (fake_rsrc) {
806 rsrcoffset=(length+0x4600+0x200) & ~0x200;
807 rsrclength=0x200;
808 rsrcsum=0;
810 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
811 int2le(0, &outbuf[0x4230]); /* id */
812 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
813 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
814 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
815 int2le(0, &outbuf[0x4240]); /* Entry Offset */
816 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
817 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
818 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
821 file = fopen(oname, "wb");
822 if (!file) {
823 perror(oname);
824 return -3;
827 len = fwrite(outbuf, 1, length+0x4600, file);
828 if(len < (size_t)length) {
829 perror(oname);
830 return -4;
833 fclose(file);
835 return 0;
838 #define CCPMP_SIZE 0x500000
839 static int ccpmp_encode(char *iname, char *oname)
841 size_t len;
842 int length;
843 FILE *file;
844 unsigned char *outbuf;
846 file = fopen(iname, "rb");
847 if (!file) {
848 perror(iname);
849 return -1;
851 fseek(file,0,SEEK_END);
852 length = ftell(file);
854 fseek(file,0,SEEK_SET);
856 outbuf = malloc(CCPMP_SIZE);
858 if ( !outbuf ) {
859 printf("out of memory!\n");
860 return -1;
863 len = fread(outbuf, 1, length, file);
864 if(len < (size_t)length) {
865 perror(iname);
866 return -2;
868 fclose(file);
870 /* Clear the tail area to 0xFF */
871 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
873 /* Header */
874 int2le(length, &outbuf[0x4]);
876 file = fopen(oname, "wb");
877 if (!file) {
878 perror(oname);
879 return -3;
882 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
883 if(len < (size_t)length) {
884 perror(oname);
885 return -4;
888 fclose(file);
890 return 0;