mpegplayer:
[kugel-rb.git] / tools / scramble.c
blob3ee8b26aa4a46dd6ce387734821b951258b91b8c
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, 6330, ldax, m200, c100, clip, e2v2,\n"
127 "\t m2v4, fuze, c2v2, clv2, y820, y920, y925, x747,\n"
128 "\t 747p, x777, nn2g, m244, cli+)\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], "6330")) /* Philips HDD6330 */
322 modelnum = 65;
323 else if (!strcmp(&argv[1][5], "cli+")) /* Sansa Clip+ */
324 modelnum = 66;
325 else if (!strcmp(&argv[1][5], "m244"))
326 modelnum = 131;
327 else {
328 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
329 return 2;
331 /* we store a 4-letter model name too, for humans */
332 strcpy(modelname, &argv[1][5]);
333 chksum = modelnum; /* start checksum calcs with this */
336 else if(!strcmp(argv[1], "-iriver")) {
337 /* iRiver code dealt with in the iriver.c code */
338 iname = argv[2];
339 oname = argv[3];
340 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
342 else if(!strcmp(argv[1], "-gigabeat")) {
343 /* iRiver code dealt with in the iriver.c code */
344 iname = argv[2];
345 oname = argv[3];
346 gigabeat_code(iname, oname);
347 return 0;
349 else if(!strcmp(argv[1], "-gigabeats")) {
350 iname = argv[2];
351 oname = argv[3];
352 return gigabeat_s_code(iname, oname);
354 else if(!strcmp(argv[1], "-iaudiox5")) {
355 iname = argv[2];
356 oname = argv[3];
357 return iaudio_encode(iname, oname, "COWON_X5_FW");
359 else if(!strcmp(argv[1], "-iaudiox5v")) {
360 iname = argv[2];
361 oname = argv[3];
362 return iaudio_encode(iname, oname, "COWON_X5V_FW");
364 else if(!strcmp(argv[1], "-iaudiom5")) {
365 iname = argv[2];
366 oname = argv[3];
367 return iaudio_encode(iname, oname, "COWON_M5_FW");
369 else if(!strcmp(argv[1], "-iaudiom3")) {
370 iname = argv[2];
371 oname = argv[3];
372 return iaudio_encode(iname, oname, "COWON_M3_FW");
374 else if(!strcmp(argv[1], "-ipod3g")) {
375 iname = argv[2];
376 oname = argv[3];
377 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
379 else if(!strcmp(argv[1], "-ipod4g")) {
380 iname = argv[2];
381 oname = argv[3];
382 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
384 else if(!strcmp(argv[1], "-ipod5g")) {
385 iname = argv[2];
386 oname = argv[3];
387 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
389 else if(!strncmp(argv[1], "-creative=", 10)) {
390 if(!strcmp(argv[2], "-no-ciff"))
392 creative_enable_ciff = false;
393 iname = argv[3];
394 oname = argv[4];
396 else
398 creative_enable_ciff = true;
399 iname = argv[2];
400 oname = argv[3];
402 if(!strcmp(&argv[1][10], "zvm"))
403 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
404 else if(!strcmp(&argv[1][10], "zvm60"))
405 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
406 else if(!strcmp(&argv[1][10], "zenvision"))
407 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
408 else if(!strcmp(&argv[1][10], "zenv"))
409 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
410 else if(!strcmp(&argv[1][10], "zen"))
411 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
412 else
414 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
415 return 2;
418 else if(!strcmp(argv[1], "-ccpmp")) {
419 iname = argv[2];
420 oname = argv[3];
421 return ccpmp_encode(iname, oname);
423 else if(!strncmp(argv[1], "-mi4", 4)) {
424 int mi4magic;
425 char model[4] = "";
426 char type[4] = "";
428 if(!strcmp(&argv[1][4], "v2")) {
429 mi4magic = MI4_MAGIC_DEFAULT;
430 version = 0x00010201;
432 else if(!strcmp(&argv[1][4], "v3")) {
433 mi4magic = MI4_MAGIC_DEFAULT;
434 version = 0x00010301;
436 else if(!strcmp(&argv[1][4], "r")) {
437 mi4magic = MI4_MAGIC_R;
438 version = 0x00010301;
440 else {
441 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
442 return -1;
445 iname = argv[2];
446 oname = argv[3];
448 if(!strncmp(argv[2], "-model=", 7)) {
449 iname = argv[3];
450 oname = argv[4];
451 strncpy(model, &argv[2][7], 4);
453 if(!strncmp(argv[3], "-type=", 6)) {
454 iname = argv[4];
455 oname = argv[5];
456 strncpy(type, &argv[3][6], 4);
460 return mi4_encode(iname, oname, version, mi4magic, model, type);
463 /* open file */
464 file = fopen(iname,"rb");
465 if (!file) {
466 perror(iname);
467 return -1;
469 fseek(file,0,SEEK_END);
470 length = ftell(file);
471 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
473 if ((method == scramble) &&
474 ((length + headerlen) >= size_limit[model_id])) {
475 printf("error: firmware image is %ld bytes while max size is %u!\n",
476 length + headerlen,
477 size_limit[model_id]);
478 fclose(file);
479 return -1;
482 fseek(file,0,SEEK_SET);
483 inbuf = malloc(length);
484 if (method == xor)
485 outbuf = malloc(length*2);
486 else if(method == add)
487 outbuf = malloc(length + 8);
488 else
489 outbuf = malloc(length);
490 if ( !inbuf || !outbuf ) {
491 printf("out of memory!\n");
492 return -1;
494 if(length> 4) {
495 /* zero-fill the last 4 bytes to make sure there's no rubbish there
496 when we write the size-aligned file later */
497 memset(outbuf+length-4, 0, 4);
500 /* read file */
501 i=fread(inbuf,1,length,file);
502 if ( !i ) {
503 perror(iname);
504 return -1;
506 fclose(file);
508 switch (method)
510 case add:
511 for (i = 0; i < length; i++) {
512 /* add 8 unsigned bits but keep a 32 bit sum */
513 chksum += inbuf[i];
515 break;
516 case scramble:
517 slen = length/4;
518 for (i = 0; i < length; i++) {
519 unsigned long addr = (i >> 2) + ((i % 4) * slen);
520 unsigned char data = inbuf[i];
521 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
522 outbuf[addr] = data;
524 break;
526 case xor:
527 /* "compress" */
528 slen = 0;
529 for (i=0; i<length; i++) {
530 if (!(i&7))
531 outbuf[slen++] = 0xff; /* all data is uncompressed */
532 outbuf[slen++] = inbuf[i];
534 break;
535 case none:
536 default:
537 /* dummy case just to silence picky compilers */
538 break;
541 if((method == none) || (method == scramble) || (method == xor)) {
542 /* calculate checksum */
543 for (i=0;i<length;i++)
544 crc += inbuf[i];
547 memset(header, 0, sizeof header);
548 switch (method)
550 case add:
552 int2be(chksum, header); /* checksum, big-endian */
553 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
554 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
555 headerlen = 8;
557 break;
559 case tcc_sum:
560 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
561 telechips_encode_sum(outbuf, length);
562 break;
564 case tcc_crc:
565 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
566 telechips_encode_crc(outbuf, length);
567 break;
569 case scramble:
570 if (headerlen == 6) {
571 int2be(length, header);
572 header[4] = (crc >> 8) & 0xff;
573 header[5] = crc & 0xff;
575 else {
576 header[0] =
577 header[1] =
578 header[2] =
579 header[3] = 0xff; /* ??? */
581 header[6] = (crc >> 8) & 0xff;
582 header[7] = crc & 0xff;
584 header[11] = version;
586 header[15] = headerlen; /* really? */
588 int2be(length, &header[20]);
590 break;
592 case xor:
594 int xorlen = strlen(xorstring);
596 /* xor data */
597 for (i=0; i<slen; i++)
598 outbuf[i] ^= xorstring[i & (xorlen-1)];
600 /* calculate checksum */
601 for (i=0; i<slen; i++)
602 crc += outbuf[i];
604 header[0] = header[2] = 'Z';
605 header[1] = header[3] = version;
606 int2le(length, &header[4]);
607 int2le(slen, &header[8]);
608 int2le(crc, &header[12]);
609 length = slen;
610 break;
613 #define MY_FIRMWARE_TYPE "Rockbox"
614 #define MY_HEADER_VERSION 1
615 default:
616 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
617 header[9]='\0'; /*shouldn't have to, but to be SURE */
618 header[10]=MY_HEADER_VERSION&0xFF;
619 header[11]=(crc>>8)&0xFF;
620 header[12]=crc&0xFF;
621 int2be(sizeof(header), &header[12]);
622 break;
625 /* write file */
626 file = fopen(oname,"wb");
627 if ( !file ) {
628 perror(oname);
629 return -1;
631 if (headerlen > 0) {
632 if ( !fwrite(header,headerlen,1,file) ) {
633 perror(oname);
634 return -1;
637 if ( !fwrite(outbuf,length,1,file) ) {
638 perror(oname);
639 return -1;
641 fclose(file);
643 free(inbuf);
644 free(outbuf);
646 return 0;
649 static int iaudio_encode(char *iname, char *oname, char *idstring)
651 size_t len;
652 int length;
653 FILE *file;
654 unsigned char *outbuf;
655 int i;
656 unsigned char sum = 0;
658 file = fopen(iname, "rb");
659 if (!file) {
660 perror(iname);
661 return -1;
663 fseek(file,0,SEEK_END);
664 length = ftell(file);
666 fseek(file,0,SEEK_SET);
667 outbuf = malloc(length+0x1030);
669 if ( !outbuf ) {
670 printf("out of memory!\n");
671 return -1;
674 len = fread(outbuf+0x1030, 1, length, file);
675 if(len < (size_t) length) {
676 perror(iname);
677 return -2;
680 memset(outbuf, 0, 0x1030);
681 strcpy((char *)outbuf, idstring);
682 memcpy(outbuf+0x20, iaudio_bl_flash,
683 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
684 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
685 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
686 outbuf[0x19] = 2;
688 for(i = 0; i < length;i++)
689 sum += outbuf[0x1030 + i];
691 int2be(length, &outbuf[0x1024]);
692 outbuf[0x102b] = sum;
694 fclose(file);
696 file = fopen(oname, "wb");
697 if (!file) {
698 perror(oname);
699 return -3;
702 len = fwrite(outbuf, 1, length+0x1030, file);
703 if(len < (size_t)length) {
704 perror(oname);
705 return -4;
708 fclose(file);
709 return 0;
713 /* Create an ipod firmware partition image
715 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
717 This function doesn't yet handle the Broadcom resource image for the 5g,
718 so the resulting images won't be usable.
720 This has also only been tested on an ipod Photo
723 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
725 static const char *apple_stop_sign = "{{~~ /-----\\ "\
726 "{{~~ / \\ "\
727 "{{~~| | "\
728 "{{~~| S T O P | "\
729 "{{~~| | "\
730 "{{~~ \\ / "\
731 "{{~~ \\-----/ "\
732 "Copyright(C) 200"\
733 "1 Apple Computer"\
734 ", Inc.----------"\
735 "----------------"\
736 "----------------"\
737 "----------------"\
738 "----------------"\
739 "----------------"\
740 "---------------";
741 size_t len;
742 int length;
743 int rsrclength;
744 int rsrcoffset;
745 FILE *file;
746 unsigned int sum = 0;
747 unsigned int rsrcsum = 0;
748 unsigned char *outbuf;
749 int bufsize;
750 int i;
752 file = fopen(iname, "rb");
753 if (!file) {
754 perror(iname);
755 return -1;
757 fseek(file,0,SEEK_END);
758 length = ftell(file);
760 fseek(file,0,SEEK_SET);
762 bufsize=(length+0x4600);
763 if (fake_rsrc) {
764 bufsize = (bufsize + 0x400) & ~0x200;
767 outbuf = malloc(bufsize);
769 if ( !outbuf ) {
770 printf("out of memory!\n");
771 return -1;
774 len = fread(outbuf+0x4600, 1, length, file);
775 if(len < (size_t)length) {
776 perror(iname);
777 return -2;
779 fclose(file);
781 /* Calculate checksum for later use in header */
782 for(i = 0x4600; i < 0x4600+length;i++)
783 sum += outbuf[i];
785 /* Clear the header area to zero */
786 memset(outbuf, 0, 0x4600);
788 /* APPLE STOP SIGN */
789 strcpy((char *)outbuf, apple_stop_sign);
791 /* VOLUME HEADER */
792 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
793 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
794 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
795 short2le(fw_ver, &outbuf[0x10a]);
797 /* Firmware Directory - "osos" entry */
798 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
799 int2le(0, &outbuf[0x4208]); /* id */
800 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
801 int2le(length, &outbuf[0x4210]); /* Length of firmware */
802 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
803 int2le(0, &outbuf[0x4218]); /* Entry Offset */
804 int2le(sum, &outbuf[0x421c]); /* Checksum */
805 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
806 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
808 /* "rsrc" entry (if applicable) */
809 if (fake_rsrc) {
810 rsrcoffset=(length+0x4600+0x200) & ~0x200;
811 rsrclength=0x200;
812 rsrcsum=0;
814 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
815 int2le(0, &outbuf[0x4230]); /* id */
816 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
817 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
818 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
819 int2le(0, &outbuf[0x4240]); /* Entry Offset */
820 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
821 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
822 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
825 file = fopen(oname, "wb");
826 if (!file) {
827 perror(oname);
828 return -3;
831 len = fwrite(outbuf, 1, length+0x4600, file);
832 if(len < (size_t)length) {
833 perror(oname);
834 return -4;
837 fclose(file);
839 return 0;
842 #define CCPMP_SIZE 0x500000
843 static int ccpmp_encode(char *iname, char *oname)
845 size_t len;
846 int length;
847 FILE *file;
848 unsigned char *outbuf;
850 file = fopen(iname, "rb");
851 if (!file) {
852 perror(iname);
853 return -1;
855 fseek(file,0,SEEK_END);
856 length = ftell(file);
858 fseek(file,0,SEEK_SET);
860 outbuf = malloc(CCPMP_SIZE);
862 if ( !outbuf ) {
863 printf("out of memory!\n");
864 return -1;
867 len = fread(outbuf, 1, length, file);
868 if(len < (size_t)length) {
869 perror(iname);
870 return -2;
872 fclose(file);
874 /* Clear the tail area to 0xFF */
875 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
877 /* Header */
878 int2le(length, &outbuf[0x4]);
880 file = fopen(oname, "wb");
881 if (!file) {
882 perror(oname);
883 return -3;
886 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
887 if(len < (size_t)length) {
888 perror(oname);
889 return -4;
892 fclose(file);
894 return 0;