Better menu verbiage for test_codec
[kugel-rb.git] / tools / scramble.c
blob51f672bcd01af6977de36dcb5300f90ddf146c7c
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, nn2g)\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 {
322 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
323 return 2;
325 /* we store a 4-letter model name too, for humans */
326 strcpy(modelname, &argv[1][5]);
327 chksum = modelnum; /* start checksum calcs with this */
330 else if(!strcmp(argv[1], "-iriver")) {
331 /* iRiver code dealt with in the iriver.c code */
332 iname = argv[2];
333 oname = argv[3];
334 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
336 else if(!strcmp(argv[1], "-gigabeat")) {
337 /* iRiver code dealt with in the iriver.c code */
338 iname = argv[2];
339 oname = argv[3];
340 gigabeat_code(iname, oname);
341 return 0;
343 else if(!strcmp(argv[1], "-gigabeats")) {
344 iname = argv[2];
345 oname = argv[3];
346 return gigabeat_s_code(iname, oname);
348 else if(!strcmp(argv[1], "-iaudiox5")) {
349 iname = argv[2];
350 oname = argv[3];
351 return iaudio_encode(iname, oname, "COWON_X5_FW");
353 else if(!strcmp(argv[1], "-iaudiox5v")) {
354 iname = argv[2];
355 oname = argv[3];
356 return iaudio_encode(iname, oname, "COWON_X5V_FW");
358 else if(!strcmp(argv[1], "-iaudiom5")) {
359 iname = argv[2];
360 oname = argv[3];
361 return iaudio_encode(iname, oname, "COWON_M5_FW");
363 else if(!strcmp(argv[1], "-iaudiom3")) {
364 iname = argv[2];
365 oname = argv[3];
366 return iaudio_encode(iname, oname, "COWON_M3_FW");
368 else if(!strcmp(argv[1], "-ipod3g")) {
369 iname = argv[2];
370 oname = argv[3];
371 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
373 else if(!strcmp(argv[1], "-ipod4g")) {
374 iname = argv[2];
375 oname = argv[3];
376 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
378 else if(!strcmp(argv[1], "-ipod5g")) {
379 iname = argv[2];
380 oname = argv[3];
381 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
383 else if(!strncmp(argv[1], "-creative=", 10)) {
384 if(!strcmp(argv[2], "-no-ciff"))
386 creative_enable_ciff = false;
387 iname = argv[3];
388 oname = argv[4];
390 else
392 creative_enable_ciff = true;
393 iname = argv[2];
394 oname = argv[3];
396 if(!strcmp(&argv[1][10], "zvm"))
397 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
398 else if(!strcmp(&argv[1][10], "zvm60"))
399 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
400 else if(!strcmp(&argv[1][10], "zenvision"))
401 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
402 else if(!strcmp(&argv[1][10], "zenv"))
403 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
404 else if(!strcmp(&argv[1][10], "zen"))
405 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
406 else
408 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
409 return 2;
412 else if(!strcmp(argv[1], "-ccpmp")) {
413 iname = argv[2];
414 oname = argv[3];
415 return ccpmp_encode(iname, oname);
417 else if(!strncmp(argv[1], "-mi4", 4)) {
418 int mi4magic;
419 char model[4] = "";
420 char type[4] = "";
422 if(!strcmp(&argv[1][4], "v2")) {
423 mi4magic = MI4_MAGIC_DEFAULT;
424 version = 0x00010201;
426 else if(!strcmp(&argv[1][4], "v3")) {
427 mi4magic = MI4_MAGIC_DEFAULT;
428 version = 0x00010301;
430 else if(!strcmp(&argv[1][4], "r")) {
431 mi4magic = MI4_MAGIC_R;
432 version = 0x00010301;
434 else {
435 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
436 return -1;
439 iname = argv[2];
440 oname = argv[3];
442 if(!strncmp(argv[2], "-model=", 7)) {
443 iname = argv[3];
444 oname = argv[4];
445 strncpy(model, &argv[2][7], 4);
447 if(!strncmp(argv[3], "-type=", 6)) {
448 iname = argv[4];
449 oname = argv[5];
450 strncpy(type, &argv[3][6], 4);
454 return mi4_encode(iname, oname, version, mi4magic, model, type);
457 /* open file */
458 file = fopen(iname,"rb");
459 if (!file) {
460 perror(iname);
461 return -1;
463 fseek(file,0,SEEK_END);
464 length = ftell(file);
465 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
467 if ((method == scramble) &&
468 ((length + headerlen) >= size_limit[model_id])) {
469 printf("error: firmware image is %ld bytes while max size is %u!\n",
470 length + headerlen,
471 size_limit[model_id]);
472 fclose(file);
473 return -1;
476 fseek(file,0,SEEK_SET);
477 inbuf = malloc(length);
478 if (method == xor)
479 outbuf = malloc(length*2);
480 else if(method == add)
481 outbuf = malloc(length + 8);
482 else
483 outbuf = malloc(length);
484 if ( !inbuf || !outbuf ) {
485 printf("out of memory!\n");
486 return -1;
488 if(length> 4) {
489 /* zero-fill the last 4 bytes to make sure there's no rubbish there
490 when we write the size-aligned file later */
491 memset(outbuf+length-4, 0, 4);
494 /* read file */
495 i=fread(inbuf,1,length,file);
496 if ( !i ) {
497 perror(iname);
498 return -1;
500 fclose(file);
502 switch (method)
504 case add:
505 for (i = 0; i < length; i++) {
506 /* add 8 unsigned bits but keep a 32 bit sum */
507 chksum += inbuf[i];
509 break;
510 case scramble:
511 slen = length/4;
512 for (i = 0; i < length; i++) {
513 unsigned long addr = (i >> 2) + ((i % 4) * slen);
514 unsigned char data = inbuf[i];
515 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
516 outbuf[addr] = data;
518 break;
520 case xor:
521 /* "compress" */
522 slen = 0;
523 for (i=0; i<length; i++) {
524 if (!(i&7))
525 outbuf[slen++] = 0xff; /* all data is uncompressed */
526 outbuf[slen++] = inbuf[i];
528 break;
529 case none:
530 default:
531 /* dummy case just to silence picky compilers */
532 break;
535 if((method == none) || (method == scramble) || (method == xor)) {
536 /* calculate checksum */
537 for (i=0;i<length;i++)
538 crc += inbuf[i];
541 memset(header, 0, sizeof header);
542 switch (method)
544 case add:
546 int2be(chksum, header); /* checksum, big-endian */
547 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
548 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
549 headerlen = 8;
551 break;
553 case tcc_sum:
554 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
555 telechips_encode_sum(outbuf, length);
556 break;
558 case tcc_crc:
559 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
560 telechips_encode_crc(outbuf, length);
561 break;
563 case scramble:
564 if (headerlen == 6) {
565 int2be(length, header);
566 header[4] = (crc >> 8) & 0xff;
567 header[5] = crc & 0xff;
569 else {
570 header[0] =
571 header[1] =
572 header[2] =
573 header[3] = 0xff; /* ??? */
575 header[6] = (crc >> 8) & 0xff;
576 header[7] = crc & 0xff;
578 header[11] = version;
580 header[15] = headerlen; /* really? */
582 int2be(length, &header[20]);
584 break;
586 case xor:
588 int xorlen = strlen(xorstring);
590 /* xor data */
591 for (i=0; i<slen; i++)
592 outbuf[i] ^= xorstring[i & (xorlen-1)];
594 /* calculate checksum */
595 for (i=0; i<slen; i++)
596 crc += outbuf[i];
598 header[0] = header[2] = 'Z';
599 header[1] = header[3] = version;
600 int2le(length, &header[4]);
601 int2le(slen, &header[8]);
602 int2le(crc, &header[12]);
603 length = slen;
604 break;
607 #define MY_FIRMWARE_TYPE "Rockbox"
608 #define MY_HEADER_VERSION 1
609 default:
610 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
611 header[9]='\0'; /*shouldn't have to, but to be SURE */
612 header[10]=MY_HEADER_VERSION&0xFF;
613 header[11]=(crc>>8)&0xFF;
614 header[12]=crc&0xFF;
615 int2be(sizeof(header), &header[12]);
616 break;
619 /* write file */
620 file = fopen(oname,"wb");
621 if ( !file ) {
622 perror(oname);
623 return -1;
625 if (headerlen > 0) {
626 if ( !fwrite(header,headerlen,1,file) ) {
627 perror(oname);
628 return -1;
631 if ( !fwrite(outbuf,length,1,file) ) {
632 perror(oname);
633 return -1;
635 fclose(file);
637 free(inbuf);
638 free(outbuf);
640 return 0;
643 int iaudio_encode(char *iname, char *oname, char *idstring)
645 size_t len;
646 int length;
647 FILE *file;
648 unsigned char *outbuf;
649 int i;
650 unsigned char sum = 0;
652 file = fopen(iname, "rb");
653 if (!file) {
654 perror(iname);
655 return -1;
657 fseek(file,0,SEEK_END);
658 length = ftell(file);
660 fseek(file,0,SEEK_SET);
661 outbuf = malloc(length+0x1030);
663 if ( !outbuf ) {
664 printf("out of memory!\n");
665 return -1;
668 len = fread(outbuf+0x1030, 1, length, file);
669 if(len < (size_t) length) {
670 perror(iname);
671 return -2;
674 memset(outbuf, 0, 0x1030);
675 strcpy((char *)outbuf, idstring);
676 memcpy(outbuf+0x20, iaudio_bl_flash,
677 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
678 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
679 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
680 outbuf[0x19] = 2;
682 for(i = 0; i < length;i++)
683 sum += outbuf[0x1030 + i];
685 int2be(length, &outbuf[0x1024]);
686 outbuf[0x102b] = sum;
688 fclose(file);
690 file = fopen(oname, "wb");
691 if (!file) {
692 perror(oname);
693 return -3;
696 len = fwrite(outbuf, 1, length+0x1030, file);
697 if(len < (size_t)length) {
698 perror(oname);
699 return -4;
702 fclose(file);
703 return 0;
707 /* Create an ipod firmware partition image
709 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
711 This function doesn't yet handle the Broadcom resource image for the 5g,
712 so the resulting images won't be usable.
714 This has also only been tested on an ipod Photo
717 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
719 static const char *apple_stop_sign = "{{~~ /-----\\ "\
720 "{{~~ / \\ "\
721 "{{~~| | "\
722 "{{~~| S T O P | "\
723 "{{~~| | "\
724 "{{~~ \\ / "\
725 "{{~~ \\-----/ "\
726 "Copyright(C) 200"\
727 "1 Apple Computer"\
728 ", Inc.----------"\
729 "----------------"\
730 "----------------"\
731 "----------------"\
732 "----------------"\
733 "----------------"\
734 "---------------";
735 size_t len;
736 int length;
737 int rsrclength;
738 int rsrcoffset;
739 FILE *file;
740 unsigned int sum = 0;
741 unsigned int rsrcsum = 0;
742 unsigned char *outbuf;
743 int bufsize;
744 int i;
746 file = fopen(iname, "rb");
747 if (!file) {
748 perror(iname);
749 return -1;
751 fseek(file,0,SEEK_END);
752 length = ftell(file);
754 fseek(file,0,SEEK_SET);
756 bufsize=(length+0x4600);
757 if (fake_rsrc) {
758 bufsize = (bufsize + 0x400) & ~0x200;
761 outbuf = malloc(bufsize);
763 if ( !outbuf ) {
764 printf("out of memory!\n");
765 return -1;
768 len = fread(outbuf+0x4600, 1, length, file);
769 if(len < (size_t)length) {
770 perror(iname);
771 return -2;
773 fclose(file);
775 /* Calculate checksum for later use in header */
776 for(i = 0x4600; i < 0x4600+length;i++)
777 sum += outbuf[i];
779 /* Clear the header area to zero */
780 memset(outbuf, 0, 0x4600);
782 /* APPLE STOP SIGN */
783 strcpy((char *)outbuf, apple_stop_sign);
785 /* VOLUME HEADER */
786 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
787 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
788 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
789 short2le(fw_ver, &outbuf[0x10a]);
791 /* Firmware Directory - "osos" entry */
792 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
793 int2le(0, &outbuf[0x4208]); /* id */
794 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
795 int2le(length, &outbuf[0x4210]); /* Length of firmware */
796 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
797 int2le(0, &outbuf[0x4218]); /* Entry Offset */
798 int2le(sum, &outbuf[0x421c]); /* Checksum */
799 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
800 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
802 /* "rsrc" entry (if applicable) */
803 if (fake_rsrc) {
804 rsrcoffset=(length+0x4600+0x200) & ~0x200;
805 rsrclength=0x200;
806 rsrcsum=0;
808 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
809 int2le(0, &outbuf[0x4230]); /* id */
810 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
811 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
812 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
813 int2le(0, &outbuf[0x4240]); /* Entry Offset */
814 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
815 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
816 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
819 file = fopen(oname, "wb");
820 if (!file) {
821 perror(oname);
822 return -3;
825 len = fwrite(outbuf, 1, length+0x4600, file);
826 if(len < (size_t)length) {
827 perror(oname);
828 return -4;
831 fclose(file);
833 return 0;
836 #define CCPMP_SIZE 0x500000
837 int ccpmp_encode(char *iname, char *oname)
839 size_t len;
840 int length;
841 FILE *file;
842 unsigned char *outbuf;
844 file = fopen(iname, "rb");
845 if (!file) {
846 perror(iname);
847 return -1;
849 fseek(file,0,SEEK_END);
850 length = ftell(file);
852 fseek(file,0,SEEK_SET);
854 outbuf = malloc(CCPMP_SIZE);
856 if ( !outbuf ) {
857 printf("out of memory!\n");
858 return -1;
861 len = fread(outbuf, 1, length, file);
862 if(len < (size_t)length) {
863 perror(iname);
864 return -2;
866 fclose(file);
868 /* Clear the tail area to 0xFF */
869 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
871 /* Header */
872 int2le(length, &outbuf[0x4]);
874 file = fopen(oname, "wb");
875 if (!file) {
876 perror(oname);
877 return -3;
880 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
881 if(len < (size_t)length) {
882 perror(oname);
883 return -4;
886 fclose(file);
888 return 0;