New committer!
[kugel-rb.git] / tools / scramble.c
blob5d2b12fb841de6875b684e1c1cc17d8308619de5
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);
36 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)\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], "x777"))
308 modelnum = 61;
309 else if (!strcmp(&argv[1][5], "y820")) /* Samsung YH-820 */
310 modelnum = 57;
311 else if (!strcmp(&argv[1][5], "y920")) /* Samsung YH-920 */
312 modelnum = 58;
313 else if (!strcmp(&argv[1][5], "y925")) /* Samsung YH-925 */
314 modelnum = 59;
315 else if (!strcmp(&argv[1][5], "clv2")) /* Sansa Clipv2 */
316 modelnum = 60;
317 else {
318 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
319 return 2;
321 /* we store a 4-letter model name too, for humans */
322 strcpy(modelname, &argv[1][5]);
323 chksum = modelnum; /* start checksum calcs with this */
326 else if(!strcmp(argv[1], "-iriver")) {
327 /* iRiver code dealt with in the iriver.c code */
328 iname = argv[2];
329 oname = argv[3];
330 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
332 else if(!strcmp(argv[1], "-gigabeat")) {
333 /* iRiver code dealt with in the iriver.c code */
334 iname = argv[2];
335 oname = argv[3];
336 gigabeat_code(iname, oname);
337 return 0;
339 else if(!strcmp(argv[1], "-gigabeats")) {
340 iname = argv[2];
341 oname = argv[3];
342 return gigabeat_s_code(iname, oname);
344 else if(!strcmp(argv[1], "-iaudiox5")) {
345 iname = argv[2];
346 oname = argv[3];
347 return iaudio_encode(iname, oname, "COWON_X5_FW");
349 else if(!strcmp(argv[1], "-iaudiox5v")) {
350 iname = argv[2];
351 oname = argv[3];
352 return iaudio_encode(iname, oname, "COWON_X5V_FW");
354 else if(!strcmp(argv[1], "-iaudiom5")) {
355 iname = argv[2];
356 oname = argv[3];
357 return iaudio_encode(iname, oname, "COWON_M5_FW");
359 else if(!strcmp(argv[1], "-iaudiom3")) {
360 iname = argv[2];
361 oname = argv[3];
362 return iaudio_encode(iname, oname, "COWON_M3_FW");
364 else if(!strcmp(argv[1], "-ipod3g")) {
365 iname = argv[2];
366 oname = argv[3];
367 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
369 else if(!strcmp(argv[1], "-ipod4g")) {
370 iname = argv[2];
371 oname = argv[3];
372 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
374 else if(!strcmp(argv[1], "-ipod5g")) {
375 iname = argv[2];
376 oname = argv[3];
377 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
379 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(!strcmp(argv[1], "-ccpmp")) {
409 iname = argv[2];
410 oname = argv[3];
411 return ccpmp_encode(iname, oname);
413 else if(!strncmp(argv[1], "-mi4", 4)) {
414 int mi4magic;
415 char model[4] = "";
416 char type[4] = "";
418 if(!strcmp(&argv[1][4], "v2")) {
419 mi4magic = MI4_MAGIC_DEFAULT;
420 version = 0x00010201;
422 else if(!strcmp(&argv[1][4], "v3")) {
423 mi4magic = MI4_MAGIC_DEFAULT;
424 version = 0x00010301;
426 else if(!strcmp(&argv[1][4], "r")) {
427 mi4magic = MI4_MAGIC_R;
428 version = 0x00010301;
430 else {
431 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
432 return -1;
435 iname = argv[2];
436 oname = argv[3];
438 if(!strncmp(argv[2], "-model=", 7)) {
439 iname = argv[3];
440 oname = argv[4];
441 strncpy(model, &argv[2][7], 4);
443 if(!strncmp(argv[3], "-type=", 6)) {
444 iname = argv[4];
445 oname = argv[5];
446 strncpy(type, &argv[3][6], 4);
450 return mi4_encode(iname, oname, version, mi4magic, model, type);
453 /* open file */
454 file = fopen(iname,"rb");
455 if (!file) {
456 perror(iname);
457 return -1;
459 fseek(file,0,SEEK_END);
460 length = ftell(file);
461 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
463 if ((method == scramble) &&
464 ((length + headerlen) >= size_limit[model_id])) {
465 printf("error: firmware image is %ld bytes while max size is %u!\n",
466 length + headerlen,
467 size_limit[model_id]);
468 fclose(file);
469 return -1;
472 fseek(file,0,SEEK_SET);
473 inbuf = malloc(length);
474 if (method == xor)
475 outbuf = malloc(length*2);
476 else if(method == add)
477 outbuf = malloc(length + 8);
478 else
479 outbuf = malloc(length);
480 if ( !inbuf || !outbuf ) {
481 printf("out of memory!\n");
482 return -1;
484 if(length> 4) {
485 /* zero-fill the last 4 bytes to make sure there's no rubbish there
486 when we write the size-aligned file later */
487 memset(outbuf+length-4, 0, 4);
490 /* read file */
491 i=fread(inbuf,1,length,file);
492 if ( !i ) {
493 perror(iname);
494 return -1;
496 fclose(file);
498 switch (method)
500 case add:
501 for (i = 0; i < length; i++) {
502 /* add 8 unsigned bits but keep a 32 bit sum */
503 chksum += inbuf[i];
505 break;
506 case scramble:
507 slen = length/4;
508 for (i = 0; i < length; i++) {
509 unsigned long addr = (i >> 2) + ((i % 4) * slen);
510 unsigned char data = inbuf[i];
511 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
512 outbuf[addr] = data;
514 break;
516 case xor:
517 /* "compress" */
518 slen = 0;
519 for (i=0; i<length; i++) {
520 if (!(i&7))
521 outbuf[slen++] = 0xff; /* all data is uncompressed */
522 outbuf[slen++] = inbuf[i];
524 break;
525 case none:
526 default:
527 /* dummy case just to silence picky compilers */
528 break;
531 if((method == none) || (method == scramble) || (method == xor)) {
532 /* calculate checksum */
533 for (i=0;i<length;i++)
534 crc += inbuf[i];
537 memset(header, 0, sizeof header);
538 switch (method)
540 case add:
542 int2be(chksum, header); /* checksum, big-endian */
543 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
544 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
545 headerlen = 8;
547 break;
549 case tcc_sum:
550 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
551 telechips_encode_sum(outbuf, length);
552 break;
554 case tcc_crc:
555 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
556 telechips_encode_crc(outbuf, length);
557 break;
559 case scramble:
560 if (headerlen == 6) {
561 int2be(length, header);
562 header[4] = (crc >> 8) & 0xff;
563 header[5] = crc & 0xff;
565 else {
566 header[0] =
567 header[1] =
568 header[2] =
569 header[3] = 0xff; /* ??? */
571 header[6] = (crc >> 8) & 0xff;
572 header[7] = crc & 0xff;
574 header[11] = version;
576 header[15] = headerlen; /* really? */
578 int2be(length, &header[20]);
580 break;
582 case xor:
584 int xorlen = strlen(xorstring);
586 /* xor data */
587 for (i=0; i<slen; i++)
588 outbuf[i] ^= xorstring[i & (xorlen-1)];
590 /* calculate checksum */
591 for (i=0; i<slen; i++)
592 crc += outbuf[i];
594 header[0] = header[2] = 'Z';
595 header[1] = header[3] = version;
596 int2le(length, &header[4]);
597 int2le(slen, &header[8]);
598 int2le(crc, &header[12]);
599 length = slen;
600 break;
603 #define MY_FIRMWARE_TYPE "Rockbox"
604 #define MY_HEADER_VERSION 1
605 default:
606 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
607 header[9]='\0'; /*shouldn't have to, but to be SURE */
608 header[10]=MY_HEADER_VERSION&0xFF;
609 header[11]=(crc>>8)&0xFF;
610 header[12]=crc&0xFF;
611 int2be(sizeof(header), &header[12]);
612 break;
615 /* write file */
616 file = fopen(oname,"wb");
617 if ( !file ) {
618 perror(oname);
619 return -1;
621 if (headerlen > 0) {
622 if ( !fwrite(header,headerlen,1,file) ) {
623 perror(oname);
624 return -1;
627 if ( !fwrite(outbuf,length,1,file) ) {
628 perror(oname);
629 return -1;
631 fclose(file);
633 free(inbuf);
634 free(outbuf);
636 return 0;
639 int iaudio_encode(char *iname, char *oname, char *idstring)
641 size_t len;
642 int length;
643 FILE *file;
644 unsigned char *outbuf;
645 int i;
646 unsigned char sum = 0;
648 file = fopen(iname, "rb");
649 if (!file) {
650 perror(iname);
651 return -1;
653 fseek(file,0,SEEK_END);
654 length = ftell(file);
656 fseek(file,0,SEEK_SET);
657 outbuf = malloc(length+0x1030);
659 if ( !outbuf ) {
660 printf("out of memory!\n");
661 return -1;
664 len = fread(outbuf+0x1030, 1, length, file);
665 if(len < (size_t) length) {
666 perror(iname);
667 return -2;
670 memset(outbuf, 0, 0x1030);
671 strcpy((char *)outbuf, idstring);
672 memcpy(outbuf+0x20, iaudio_bl_flash,
673 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
674 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
675 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
676 outbuf[0x19] = 2;
678 for(i = 0; i < length;i++)
679 sum += outbuf[0x1030 + i];
681 int2be(length, &outbuf[0x1024]);
682 outbuf[0x102b] = sum;
684 fclose(file);
686 file = fopen(oname, "wb");
687 if (!file) {
688 perror(oname);
689 return -3;
692 len = fwrite(outbuf, 1, length+0x1030, file);
693 if(len < (size_t)length) {
694 perror(oname);
695 return -4;
698 fclose(file);
699 return 0;
703 /* Create an ipod firmware partition image
705 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
707 This function doesn't yet handle the Broadcom resource image for the 5g,
708 so the resulting images won't be usable.
710 This has also only been tested on an ipod Photo
713 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
715 static const char *apple_stop_sign = "{{~~ /-----\\ "\
716 "{{~~ / \\ "\
717 "{{~~| | "\
718 "{{~~| S T O P | "\
719 "{{~~| | "\
720 "{{~~ \\ / "\
721 "{{~~ \\-----/ "\
722 "Copyright(C) 200"\
723 "1 Apple Computer"\
724 ", Inc.----------"\
725 "----------------"\
726 "----------------"\
727 "----------------"\
728 "----------------"\
729 "----------------"\
730 "---------------";
731 size_t len;
732 int length;
733 int rsrclength;
734 int rsrcoffset;
735 FILE *file;
736 unsigned int sum = 0;
737 unsigned int rsrcsum = 0;
738 unsigned char *outbuf;
739 int bufsize;
740 int i;
742 file = fopen(iname, "rb");
743 if (!file) {
744 perror(iname);
745 return -1;
747 fseek(file,0,SEEK_END);
748 length = ftell(file);
750 fseek(file,0,SEEK_SET);
752 bufsize=(length+0x4600);
753 if (fake_rsrc) {
754 bufsize = (bufsize + 0x400) & ~0x200;
757 outbuf = malloc(bufsize);
759 if ( !outbuf ) {
760 printf("out of memory!\n");
761 return -1;
764 len = fread(outbuf+0x4600, 1, length, file);
765 if(len < (size_t)length) {
766 perror(iname);
767 return -2;
769 fclose(file);
771 /* Calculate checksum for later use in header */
772 for(i = 0x4600; i < 0x4600+length;i++)
773 sum += outbuf[i];
775 /* Clear the header area to zero */
776 memset(outbuf, 0, 0x4600);
778 /* APPLE STOP SIGN */
779 strcpy((char *)outbuf, apple_stop_sign);
781 /* VOLUME HEADER */
782 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
783 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
784 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
785 short2le(fw_ver, &outbuf[0x10a]);
787 /* Firmware Directory - "osos" entry */
788 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
789 int2le(0, &outbuf[0x4208]); /* id */
790 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
791 int2le(length, &outbuf[0x4210]); /* Length of firmware */
792 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
793 int2le(0, &outbuf[0x4218]); /* Entry Offset */
794 int2le(sum, &outbuf[0x421c]); /* Checksum */
795 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
796 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
798 /* "rsrc" entry (if applicable) */
799 if (fake_rsrc) {
800 rsrcoffset=(length+0x4600+0x200) & ~0x200;
801 rsrclength=0x200;
802 rsrcsum=0;
804 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
805 int2le(0, &outbuf[0x4230]); /* id */
806 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
807 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
808 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
809 int2le(0, &outbuf[0x4240]); /* Entry Offset */
810 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
811 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
812 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
815 file = fopen(oname, "wb");
816 if (!file) {
817 perror(oname);
818 return -3;
821 len = fwrite(outbuf, 1, length+0x4600, file);
822 if(len < (size_t)length) {
823 perror(oname);
824 return -4;
827 fclose(file);
829 return 0;
832 #define CCPMP_SIZE 0x500000
833 int ccpmp_encode(char *iname, char *oname)
835 size_t len;
836 int length;
837 FILE *file;
838 unsigned char *outbuf;
840 file = fopen(iname, "rb");
841 if (!file) {
842 perror(iname);
843 return -1;
845 fseek(file,0,SEEK_END);
846 length = ftell(file);
848 fseek(file,0,SEEK_SET);
850 outbuf = malloc(CCPMP_SIZE);
852 if ( !outbuf ) {
853 printf("out of memory!\n");
854 return -1;
857 len = fread(outbuf, 1, length, file);
858 if(len < (size_t)length) {
859 perror(iname);
860 return -2;
862 fclose(file);
864 /* Clear the tail area to 0xFF */
865 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
867 /* Header */
868 int2le(length, &outbuf[0x4]);
870 file = fopen(oname, "wb");
871 if (!file) {
872 perror(oname);
873 return -3;
876 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
877 if(len < (size_t)length) {
878 perror(oname);
879 return -4;
882 fclose(file);
884 return 0;