Update Esperanto and add Slovak languages:
[kugel-rb.git] / tools / scramble.c
blob9bfdbda9057a6741abf98a168dde94dd38b2356e
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)\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], "m244"))
324 modelnum = 131;
325 else {
326 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
327 return 2;
329 /* we store a 4-letter model name too, for humans */
330 strcpy(modelname, &argv[1][5]);
331 chksum = modelnum; /* start checksum calcs with this */
334 else if(!strcmp(argv[1], "-iriver")) {
335 /* iRiver code dealt with in the iriver.c code */
336 iname = argv[2];
337 oname = argv[3];
338 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
340 else if(!strcmp(argv[1], "-gigabeat")) {
341 /* iRiver code dealt with in the iriver.c code */
342 iname = argv[2];
343 oname = argv[3];
344 gigabeat_code(iname, oname);
345 return 0;
347 else if(!strcmp(argv[1], "-gigabeats")) {
348 iname = argv[2];
349 oname = argv[3];
350 return gigabeat_s_code(iname, oname);
352 else if(!strcmp(argv[1], "-iaudiox5")) {
353 iname = argv[2];
354 oname = argv[3];
355 return iaudio_encode(iname, oname, "COWON_X5_FW");
357 else if(!strcmp(argv[1], "-iaudiox5v")) {
358 iname = argv[2];
359 oname = argv[3];
360 return iaudio_encode(iname, oname, "COWON_X5V_FW");
362 else if(!strcmp(argv[1], "-iaudiom5")) {
363 iname = argv[2];
364 oname = argv[3];
365 return iaudio_encode(iname, oname, "COWON_M5_FW");
367 else if(!strcmp(argv[1], "-iaudiom3")) {
368 iname = argv[2];
369 oname = argv[3];
370 return iaudio_encode(iname, oname, "COWON_M3_FW");
372 else if(!strcmp(argv[1], "-ipod3g")) {
373 iname = argv[2];
374 oname = argv[3];
375 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
377 else if(!strcmp(argv[1], "-ipod4g")) {
378 iname = argv[2];
379 oname = argv[3];
380 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
382 else if(!strcmp(argv[1], "-ipod5g")) {
383 iname = argv[2];
384 oname = argv[3];
385 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
387 else if(!strncmp(argv[1], "-creative=", 10)) {
388 if(!strcmp(argv[2], "-no-ciff"))
390 creative_enable_ciff = false;
391 iname = argv[3];
392 oname = argv[4];
394 else
396 creative_enable_ciff = true;
397 iname = argv[2];
398 oname = argv[3];
400 if(!strcmp(&argv[1][10], "zvm"))
401 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
402 else if(!strcmp(&argv[1][10], "zvm60"))
403 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
404 else if(!strcmp(&argv[1][10], "zenvision"))
405 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
406 else if(!strcmp(&argv[1][10], "zenv"))
407 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
408 else if(!strcmp(&argv[1][10], "zen"))
409 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
410 else
412 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
413 return 2;
416 else if(!strcmp(argv[1], "-ccpmp")) {
417 iname = argv[2];
418 oname = argv[3];
419 return ccpmp_encode(iname, oname);
421 else if(!strncmp(argv[1], "-mi4", 4)) {
422 int mi4magic;
423 char model[4] = "";
424 char type[4] = "";
426 if(!strcmp(&argv[1][4], "v2")) {
427 mi4magic = MI4_MAGIC_DEFAULT;
428 version = 0x00010201;
430 else if(!strcmp(&argv[1][4], "v3")) {
431 mi4magic = MI4_MAGIC_DEFAULT;
432 version = 0x00010301;
434 else if(!strcmp(&argv[1][4], "r")) {
435 mi4magic = MI4_MAGIC_R;
436 version = 0x00010301;
438 else {
439 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
440 return -1;
443 iname = argv[2];
444 oname = argv[3];
446 if(!strncmp(argv[2], "-model=", 7)) {
447 iname = argv[3];
448 oname = argv[4];
449 strncpy(model, &argv[2][7], 4);
451 if(!strncmp(argv[3], "-type=", 6)) {
452 iname = argv[4];
453 oname = argv[5];
454 strncpy(type, &argv[3][6], 4);
458 return mi4_encode(iname, oname, version, mi4magic, model, type);
461 /* open file */
462 file = fopen(iname,"rb");
463 if (!file) {
464 perror(iname);
465 return -1;
467 fseek(file,0,SEEK_END);
468 length = ftell(file);
469 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
471 if ((method == scramble) &&
472 ((length + headerlen) >= size_limit[model_id])) {
473 printf("error: firmware image is %ld bytes while max size is %u!\n",
474 length + headerlen,
475 size_limit[model_id]);
476 fclose(file);
477 return -1;
480 fseek(file,0,SEEK_SET);
481 inbuf = malloc(length);
482 if (method == xor)
483 outbuf = malloc(length*2);
484 else if(method == add)
485 outbuf = malloc(length + 8);
486 else
487 outbuf = malloc(length);
488 if ( !inbuf || !outbuf ) {
489 printf("out of memory!\n");
490 return -1;
492 if(length> 4) {
493 /* zero-fill the last 4 bytes to make sure there's no rubbish there
494 when we write the size-aligned file later */
495 memset(outbuf+length-4, 0, 4);
498 /* read file */
499 i=fread(inbuf,1,length,file);
500 if ( !i ) {
501 perror(iname);
502 return -1;
504 fclose(file);
506 switch (method)
508 case add:
509 for (i = 0; i < length; i++) {
510 /* add 8 unsigned bits but keep a 32 bit sum */
511 chksum += inbuf[i];
513 break;
514 case scramble:
515 slen = length/4;
516 for (i = 0; i < length; i++) {
517 unsigned long addr = (i >> 2) + ((i % 4) * slen);
518 unsigned char data = inbuf[i];
519 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
520 outbuf[addr] = data;
522 break;
524 case xor:
525 /* "compress" */
526 slen = 0;
527 for (i=0; i<length; i++) {
528 if (!(i&7))
529 outbuf[slen++] = 0xff; /* all data is uncompressed */
530 outbuf[slen++] = inbuf[i];
532 break;
533 case none:
534 default:
535 /* dummy case just to silence picky compilers */
536 break;
539 if((method == none) || (method == scramble) || (method == xor)) {
540 /* calculate checksum */
541 for (i=0;i<length;i++)
542 crc += inbuf[i];
545 memset(header, 0, sizeof header);
546 switch (method)
548 case add:
550 int2be(chksum, header); /* checksum, big-endian */
551 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
552 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
553 headerlen = 8;
555 break;
557 case tcc_sum:
558 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
559 telechips_encode_sum(outbuf, length);
560 break;
562 case tcc_crc:
563 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
564 telechips_encode_crc(outbuf, length);
565 break;
567 case scramble:
568 if (headerlen == 6) {
569 int2be(length, header);
570 header[4] = (crc >> 8) & 0xff;
571 header[5] = crc & 0xff;
573 else {
574 header[0] =
575 header[1] =
576 header[2] =
577 header[3] = 0xff; /* ??? */
579 header[6] = (crc >> 8) & 0xff;
580 header[7] = crc & 0xff;
582 header[11] = version;
584 header[15] = headerlen; /* really? */
586 int2be(length, &header[20]);
588 break;
590 case xor:
592 int xorlen = strlen(xorstring);
594 /* xor data */
595 for (i=0; i<slen; i++)
596 outbuf[i] ^= xorstring[i & (xorlen-1)];
598 /* calculate checksum */
599 for (i=0; i<slen; i++)
600 crc += outbuf[i];
602 header[0] = header[2] = 'Z';
603 header[1] = header[3] = version;
604 int2le(length, &header[4]);
605 int2le(slen, &header[8]);
606 int2le(crc, &header[12]);
607 length = slen;
608 break;
611 #define MY_FIRMWARE_TYPE "Rockbox"
612 #define MY_HEADER_VERSION 1
613 default:
614 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
615 header[9]='\0'; /*shouldn't have to, but to be SURE */
616 header[10]=MY_HEADER_VERSION&0xFF;
617 header[11]=(crc>>8)&0xFF;
618 header[12]=crc&0xFF;
619 int2be(sizeof(header), &header[12]);
620 break;
623 /* write file */
624 file = fopen(oname,"wb");
625 if ( !file ) {
626 perror(oname);
627 return -1;
629 if (headerlen > 0) {
630 if ( !fwrite(header,headerlen,1,file) ) {
631 perror(oname);
632 return -1;
635 if ( !fwrite(outbuf,length,1,file) ) {
636 perror(oname);
637 return -1;
639 fclose(file);
641 free(inbuf);
642 free(outbuf);
644 return 0;
647 static int iaudio_encode(char *iname, char *oname, char *idstring)
649 size_t len;
650 int length;
651 FILE *file;
652 unsigned char *outbuf;
653 int i;
654 unsigned char sum = 0;
656 file = fopen(iname, "rb");
657 if (!file) {
658 perror(iname);
659 return -1;
661 fseek(file,0,SEEK_END);
662 length = ftell(file);
664 fseek(file,0,SEEK_SET);
665 outbuf = malloc(length+0x1030);
667 if ( !outbuf ) {
668 printf("out of memory!\n");
669 return -1;
672 len = fread(outbuf+0x1030, 1, length, file);
673 if(len < (size_t) length) {
674 perror(iname);
675 return -2;
678 memset(outbuf, 0, 0x1030);
679 strcpy((char *)outbuf, idstring);
680 memcpy(outbuf+0x20, iaudio_bl_flash,
681 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
682 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
683 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
684 outbuf[0x19] = 2;
686 for(i = 0; i < length;i++)
687 sum += outbuf[0x1030 + i];
689 int2be(length, &outbuf[0x1024]);
690 outbuf[0x102b] = sum;
692 fclose(file);
694 file = fopen(oname, "wb");
695 if (!file) {
696 perror(oname);
697 return -3;
700 len = fwrite(outbuf, 1, length+0x1030, file);
701 if(len < (size_t)length) {
702 perror(oname);
703 return -4;
706 fclose(file);
707 return 0;
711 /* Create an ipod firmware partition image
713 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
715 This function doesn't yet handle the Broadcom resource image for the 5g,
716 so the resulting images won't be usable.
718 This has also only been tested on an ipod Photo
721 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
723 static const char *apple_stop_sign = "{{~~ /-----\\ "\
724 "{{~~ / \\ "\
725 "{{~~| | "\
726 "{{~~| S T O P | "\
727 "{{~~| | "\
728 "{{~~ \\ / "\
729 "{{~~ \\-----/ "\
730 "Copyright(C) 200"\
731 "1 Apple Computer"\
732 ", Inc.----------"\
733 "----------------"\
734 "----------------"\
735 "----------------"\
736 "----------------"\
737 "----------------"\
738 "---------------";
739 size_t len;
740 int length;
741 int rsrclength;
742 int rsrcoffset;
743 FILE *file;
744 unsigned int sum = 0;
745 unsigned int rsrcsum = 0;
746 unsigned char *outbuf;
747 int bufsize;
748 int i;
750 file = fopen(iname, "rb");
751 if (!file) {
752 perror(iname);
753 return -1;
755 fseek(file,0,SEEK_END);
756 length = ftell(file);
758 fseek(file,0,SEEK_SET);
760 bufsize=(length+0x4600);
761 if (fake_rsrc) {
762 bufsize = (bufsize + 0x400) & ~0x200;
765 outbuf = malloc(bufsize);
767 if ( !outbuf ) {
768 printf("out of memory!\n");
769 return -1;
772 len = fread(outbuf+0x4600, 1, length, file);
773 if(len < (size_t)length) {
774 perror(iname);
775 return -2;
777 fclose(file);
779 /* Calculate checksum for later use in header */
780 for(i = 0x4600; i < 0x4600+length;i++)
781 sum += outbuf[i];
783 /* Clear the header area to zero */
784 memset(outbuf, 0, 0x4600);
786 /* APPLE STOP SIGN */
787 strcpy((char *)outbuf, apple_stop_sign);
789 /* VOLUME HEADER */
790 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
791 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
792 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
793 short2le(fw_ver, &outbuf[0x10a]);
795 /* Firmware Directory - "osos" entry */
796 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
797 int2le(0, &outbuf[0x4208]); /* id */
798 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
799 int2le(length, &outbuf[0x4210]); /* Length of firmware */
800 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
801 int2le(0, &outbuf[0x4218]); /* Entry Offset */
802 int2le(sum, &outbuf[0x421c]); /* Checksum */
803 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
804 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
806 /* "rsrc" entry (if applicable) */
807 if (fake_rsrc) {
808 rsrcoffset=(length+0x4600+0x200) & ~0x200;
809 rsrclength=0x200;
810 rsrcsum=0;
812 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
813 int2le(0, &outbuf[0x4230]); /* id */
814 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
815 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
816 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
817 int2le(0, &outbuf[0x4240]); /* Entry Offset */
818 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
819 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
820 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
823 file = fopen(oname, "wb");
824 if (!file) {
825 perror(oname);
826 return -3;
829 len = fwrite(outbuf, 1, length+0x4600, file);
830 if(len < (size_t)length) {
831 perror(oname);
832 return -4;
835 fclose(file);
837 return 0;
840 #define CCPMP_SIZE 0x500000
841 static int ccpmp_encode(char *iname, char *oname)
843 size_t len;
844 int length;
845 FILE *file;
846 unsigned char *outbuf;
848 file = fopen(iname, "rb");
849 if (!file) {
850 perror(iname);
851 return -1;
853 fseek(file,0,SEEK_END);
854 length = ftell(file);
856 fseek(file,0,SEEK_SET);
858 outbuf = malloc(CCPMP_SIZE);
860 if ( !outbuf ) {
861 printf("out of memory!\n");
862 return -1;
865 len = fread(outbuf, 1, length, file);
866 if(len < (size_t)length) {
867 perror(iname);
868 return -2;
870 fclose(file);
872 /* Clear the tail area to 0xFF */
873 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
875 /* Header */
876 int2le(length, &outbuf[0x4]);
878 file = fopen(oname, "wb");
879 if (!file) {
880 perror(oname);
881 return -3;
884 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
885 if(len < (size_t)length) {
886 perror(oname);
887 return -4;
890 fclose(file);
892 return 0;