Fix typo in the comment
[maemo-rb.git] / tools / scramble.c
blobce06523db5c394bf3daa48a9f416947df9e907b6
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], "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], "x767"))
318 modelnum = 64;
319 else {
320 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
321 return 2;
323 /* we store a 4-letter model name too, for humans */
324 strcpy(modelname, &argv[1][5]);
325 chksum = modelnum; /* start checksum calcs with this */
328 else if(!strcmp(argv[1], "-iriver")) {
329 /* iRiver code dealt with in the iriver.c code */
330 iname = argv[2];
331 oname = argv[3];
332 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
334 else if(!strcmp(argv[1], "-gigabeat")) {
335 /* iRiver code dealt with in the iriver.c code */
336 iname = argv[2];
337 oname = argv[3];
338 gigabeat_code(iname, oname);
339 return 0;
341 else if(!strcmp(argv[1], "-gigabeats")) {
342 iname = argv[2];
343 oname = argv[3];
344 return gigabeat_s_code(iname, oname);
346 else if(!strcmp(argv[1], "-iaudiox5")) {
347 iname = argv[2];
348 oname = argv[3];
349 return iaudio_encode(iname, oname, "COWON_X5_FW");
351 else if(!strcmp(argv[1], "-iaudiox5v")) {
352 iname = argv[2];
353 oname = argv[3];
354 return iaudio_encode(iname, oname, "COWON_X5V_FW");
356 else if(!strcmp(argv[1], "-iaudiom5")) {
357 iname = argv[2];
358 oname = argv[3];
359 return iaudio_encode(iname, oname, "COWON_M5_FW");
361 else if(!strcmp(argv[1], "-iaudiom3")) {
362 iname = argv[2];
363 oname = argv[3];
364 return iaudio_encode(iname, oname, "COWON_M3_FW");
366 else if(!strcmp(argv[1], "-ipod3g")) {
367 iname = argv[2];
368 oname = argv[3];
369 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
371 else if(!strcmp(argv[1], "-ipod4g")) {
372 iname = argv[2];
373 oname = argv[3];
374 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
376 else if(!strcmp(argv[1], "-ipod5g")) {
377 iname = argv[2];
378 oname = argv[3];
379 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
381 else if(!strncmp(argv[1], "-creative=", 10)) {
382 if(!strcmp(argv[2], "-no-ciff"))
384 creative_enable_ciff = false;
385 iname = argv[3];
386 oname = argv[4];
388 else
390 creative_enable_ciff = true;
391 iname = argv[2];
392 oname = argv[3];
394 if(!strcmp(&argv[1][10], "zvm"))
395 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
396 else if(!strcmp(&argv[1][10], "zvm60"))
397 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
398 else if(!strcmp(&argv[1][10], "zenvision"))
399 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
400 else if(!strcmp(&argv[1][10], "zenv"))
401 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
402 else if(!strcmp(&argv[1][10], "zen"))
403 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
404 else
406 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
407 return 2;
410 else if(!strcmp(argv[1], "-ccpmp")) {
411 iname = argv[2];
412 oname = argv[3];
413 return ccpmp_encode(iname, oname);
415 else if(!strncmp(argv[1], "-mi4", 4)) {
416 int mi4magic;
417 char model[4] = "";
418 char type[4] = "";
420 if(!strcmp(&argv[1][4], "v2")) {
421 mi4magic = MI4_MAGIC_DEFAULT;
422 version = 0x00010201;
424 else if(!strcmp(&argv[1][4], "v3")) {
425 mi4magic = MI4_MAGIC_DEFAULT;
426 version = 0x00010301;
428 else if(!strcmp(&argv[1][4], "r")) {
429 mi4magic = MI4_MAGIC_R;
430 version = 0x00010301;
432 else {
433 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
434 return -1;
437 iname = argv[2];
438 oname = argv[3];
440 if(!strncmp(argv[2], "-model=", 7)) {
441 iname = argv[3];
442 oname = argv[4];
443 strncpy(model, &argv[2][7], 4);
445 if(!strncmp(argv[3], "-type=", 6)) {
446 iname = argv[4];
447 oname = argv[5];
448 strncpy(type, &argv[3][6], 4);
452 return mi4_encode(iname, oname, version, mi4magic, model, type);
455 /* open file */
456 file = fopen(iname,"rb");
457 if (!file) {
458 perror(iname);
459 return -1;
461 fseek(file,0,SEEK_END);
462 length = ftell(file);
463 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
465 if ((method == scramble) &&
466 ((length + headerlen) >= size_limit[model_id])) {
467 printf("error: firmware image is %ld bytes while max size is %u!\n",
468 length + headerlen,
469 size_limit[model_id]);
470 fclose(file);
471 return -1;
474 fseek(file,0,SEEK_SET);
475 inbuf = malloc(length);
476 if (method == xor)
477 outbuf = malloc(length*2);
478 else if(method == add)
479 outbuf = malloc(length + 8);
480 else
481 outbuf = malloc(length);
482 if ( !inbuf || !outbuf ) {
483 printf("out of memory!\n");
484 return -1;
486 if(length> 4) {
487 /* zero-fill the last 4 bytes to make sure there's no rubbish there
488 when we write the size-aligned file later */
489 memset(outbuf+length-4, 0, 4);
492 /* read file */
493 i=fread(inbuf,1,length,file);
494 if ( !i ) {
495 perror(iname);
496 return -1;
498 fclose(file);
500 switch (method)
502 case add:
503 for (i = 0; i < length; i++) {
504 /* add 8 unsigned bits but keep a 32 bit sum */
505 chksum += inbuf[i];
507 break;
508 case scramble:
509 slen = length/4;
510 for (i = 0; i < length; i++) {
511 unsigned long addr = (i >> 2) + ((i % 4) * slen);
512 unsigned char data = inbuf[i];
513 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
514 outbuf[addr] = data;
516 break;
518 case xor:
519 /* "compress" */
520 slen = 0;
521 for (i=0; i<length; i++) {
522 if (!(i&7))
523 outbuf[slen++] = 0xff; /* all data is uncompressed */
524 outbuf[slen++] = inbuf[i];
526 break;
527 case none:
528 default:
529 /* dummy case just to silence picky compilers */
530 break;
533 if((method == none) || (method == scramble) || (method == xor)) {
534 /* calculate checksum */
535 for (i=0;i<length;i++)
536 crc += inbuf[i];
539 memset(header, 0, sizeof header);
540 switch (method)
542 case add:
544 int2be(chksum, header); /* checksum, big-endian */
545 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
546 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
547 headerlen = 8;
549 break;
551 case tcc_sum:
552 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
553 telechips_encode_sum(outbuf, length);
554 break;
556 case tcc_crc:
557 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
558 telechips_encode_crc(outbuf, length);
559 break;
561 case scramble:
562 if (headerlen == 6) {
563 int2be(length, header);
564 header[4] = (crc >> 8) & 0xff;
565 header[5] = crc & 0xff;
567 else {
568 header[0] =
569 header[1] =
570 header[2] =
571 header[3] = 0xff; /* ??? */
573 header[6] = (crc >> 8) & 0xff;
574 header[7] = crc & 0xff;
576 header[11] = version;
578 header[15] = headerlen; /* really? */
580 int2be(length, &header[20]);
582 break;
584 case xor:
586 int xorlen = strlen(xorstring);
588 /* xor data */
589 for (i=0; i<slen; i++)
590 outbuf[i] ^= xorstring[i & (xorlen-1)];
592 /* calculate checksum */
593 for (i=0; i<slen; i++)
594 crc += outbuf[i];
596 header[0] = header[2] = 'Z';
597 header[1] = header[3] = version;
598 int2le(length, &header[4]);
599 int2le(slen, &header[8]);
600 int2le(crc, &header[12]);
601 length = slen;
602 break;
605 #define MY_FIRMWARE_TYPE "Rockbox"
606 #define MY_HEADER_VERSION 1
607 default:
608 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
609 header[9]='\0'; /*shouldn't have to, but to be SURE */
610 header[10]=MY_HEADER_VERSION&0xFF;
611 header[11]=(crc>>8)&0xFF;
612 header[12]=crc&0xFF;
613 int2be(sizeof(header), &header[12]);
614 break;
617 /* write file */
618 file = fopen(oname,"wb");
619 if ( !file ) {
620 perror(oname);
621 return -1;
623 if (headerlen > 0) {
624 if ( !fwrite(header,headerlen,1,file) ) {
625 perror(oname);
626 return -1;
629 if ( !fwrite(outbuf,length,1,file) ) {
630 perror(oname);
631 return -1;
633 fclose(file);
635 free(inbuf);
636 free(outbuf);
638 return 0;
641 int iaudio_encode(char *iname, char *oname, char *idstring)
643 size_t len;
644 int length;
645 FILE *file;
646 unsigned char *outbuf;
647 int i;
648 unsigned char sum = 0;
650 file = fopen(iname, "rb");
651 if (!file) {
652 perror(iname);
653 return -1;
655 fseek(file,0,SEEK_END);
656 length = ftell(file);
658 fseek(file,0,SEEK_SET);
659 outbuf = malloc(length+0x1030);
661 if ( !outbuf ) {
662 printf("out of memory!\n");
663 return -1;
666 len = fread(outbuf+0x1030, 1, length, file);
667 if(len < (size_t) length) {
668 perror(iname);
669 return -2;
672 memset(outbuf, 0, 0x1030);
673 strcpy((char *)outbuf, idstring);
674 memcpy(outbuf+0x20, iaudio_bl_flash,
675 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
676 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
677 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
678 outbuf[0x19] = 2;
680 for(i = 0; i < length;i++)
681 sum += outbuf[0x1030 + i];
683 int2be(length, &outbuf[0x1024]);
684 outbuf[0x102b] = sum;
686 fclose(file);
688 file = fopen(oname, "wb");
689 if (!file) {
690 perror(oname);
691 return -3;
694 len = fwrite(outbuf, 1, length+0x1030, file);
695 if(len < (size_t)length) {
696 perror(oname);
697 return -4;
700 fclose(file);
701 return 0;
705 /* Create an ipod firmware partition image
707 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
709 This function doesn't yet handle the Broadcom resource image for the 5g,
710 so the resulting images won't be usable.
712 This has also only been tested on an ipod Photo
715 int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
717 static const char *apple_stop_sign = "{{~~ /-----\\ "\
718 "{{~~ / \\ "\
719 "{{~~| | "\
720 "{{~~| S T O P | "\
721 "{{~~| | "\
722 "{{~~ \\ / "\
723 "{{~~ \\-----/ "\
724 "Copyright(C) 200"\
725 "1 Apple Computer"\
726 ", Inc.----------"\
727 "----------------"\
728 "----------------"\
729 "----------------"\
730 "----------------"\
731 "----------------"\
732 "---------------";
733 size_t len;
734 int length;
735 int rsrclength;
736 int rsrcoffset;
737 FILE *file;
738 unsigned int sum = 0;
739 unsigned int rsrcsum = 0;
740 unsigned char *outbuf;
741 int bufsize;
742 int i;
744 file = fopen(iname, "rb");
745 if (!file) {
746 perror(iname);
747 return -1;
749 fseek(file,0,SEEK_END);
750 length = ftell(file);
752 fseek(file,0,SEEK_SET);
754 bufsize=(length+0x4600);
755 if (fake_rsrc) {
756 bufsize = (bufsize + 0x400) & ~0x200;
759 outbuf = malloc(bufsize);
761 if ( !outbuf ) {
762 printf("out of memory!\n");
763 return -1;
766 len = fread(outbuf+0x4600, 1, length, file);
767 if(len < (size_t)length) {
768 perror(iname);
769 return -2;
771 fclose(file);
773 /* Calculate checksum for later use in header */
774 for(i = 0x4600; i < 0x4600+length;i++)
775 sum += outbuf[i];
777 /* Clear the header area to zero */
778 memset(outbuf, 0, 0x4600);
780 /* APPLE STOP SIGN */
781 strcpy((char *)outbuf, apple_stop_sign);
783 /* VOLUME HEADER */
784 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
785 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
786 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
787 short2le(fw_ver, &outbuf[0x10a]);
789 /* Firmware Directory - "osos" entry */
790 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
791 int2le(0, &outbuf[0x4208]); /* id */
792 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
793 int2le(length, &outbuf[0x4210]); /* Length of firmware */
794 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
795 int2le(0, &outbuf[0x4218]); /* Entry Offset */
796 int2le(sum, &outbuf[0x421c]); /* Checksum */
797 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
798 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
800 /* "rsrc" entry (if applicable) */
801 if (fake_rsrc) {
802 rsrcoffset=(length+0x4600+0x200) & ~0x200;
803 rsrclength=0x200;
804 rsrcsum=0;
806 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
807 int2le(0, &outbuf[0x4230]); /* id */
808 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
809 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
810 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
811 int2le(0, &outbuf[0x4240]); /* Entry Offset */
812 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
813 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
814 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
817 file = fopen(oname, "wb");
818 if (!file) {
819 perror(oname);
820 return -3;
823 len = fwrite(outbuf, 1, length+0x4600, file);
824 if(len < (size_t)length) {
825 perror(oname);
826 return -4;
829 fclose(file);
831 return 0;
834 #define CCPMP_SIZE 0x500000
835 int ccpmp_encode(char *iname, char *oname)
837 size_t len;
838 int length;
839 FILE *file;
840 unsigned char *outbuf;
842 file = fopen(iname, "rb");
843 if (!file) {
844 perror(iname);
845 return -1;
847 fseek(file,0,SEEK_END);
848 length = ftell(file);
850 fseek(file,0,SEEK_SET);
852 outbuf = malloc(CCPMP_SIZE);
854 if ( !outbuf ) {
855 printf("out of memory!\n");
856 return -1;
859 len = fread(outbuf, 1, length, file);
860 if(len < (size_t)length) {
861 perror(iname);
862 return -2;
864 fclose(file);
866 /* Clear the tail area to 0xFF */
867 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
869 /* Header */
870 int2le(length, &outbuf[0x4]);
872 file = fopen(oname, "wb");
873 if (!file) {
874 perror(oname);
875 return -3;
878 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
879 if(len < (size_t)length) {
880 perror(oname);
881 return -4;
884 fclose(file);
886 return 0;