Update Turkish translation
[kugel-rb.git] / tools / scramble.c
blob7d981ae23d25bb840c7068576a7a274b26b1956d
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], "v500")) /* Packard Bell Vibe 500 */
326 modelnum = 67;
327 else if (!strcmp(&argv[1][5], "m244"))
328 modelnum = 131;
329 else {
330 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
331 return 2;
333 /* we store a 4-letter model name too, for humans */
334 strcpy(modelname, &argv[1][5]);
335 chksum = modelnum; /* start checksum calcs with this */
338 else if(!strcmp(argv[1], "-iriver")) {
339 /* iRiver code dealt with in the iriver.c code */
340 iname = argv[2];
341 oname = argv[3];
342 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
344 else if(!strcmp(argv[1], "-gigabeat")) {
345 /* iRiver code dealt with in the iriver.c code */
346 iname = argv[2];
347 oname = argv[3];
348 gigabeat_code(iname, oname);
349 return 0;
351 else if(!strcmp(argv[1], "-gigabeats")) {
352 iname = argv[2];
353 oname = argv[3];
354 return gigabeat_s_code(iname, oname);
356 else if(!strcmp(argv[1], "-iaudiox5")) {
357 iname = argv[2];
358 oname = argv[3];
359 return iaudio_encode(iname, oname, "COWON_X5_FW");
361 else if(!strcmp(argv[1], "-iaudiox5v")) {
362 iname = argv[2];
363 oname = argv[3];
364 return iaudio_encode(iname, oname, "COWON_X5V_FW");
366 else if(!strcmp(argv[1], "-iaudiom5")) {
367 iname = argv[2];
368 oname = argv[3];
369 return iaudio_encode(iname, oname, "COWON_M5_FW");
371 else if(!strcmp(argv[1], "-iaudiom3")) {
372 iname = argv[2];
373 oname = argv[3];
374 return iaudio_encode(iname, oname, "COWON_M3_FW");
376 else if(!strcmp(argv[1], "-ipod3g")) {
377 iname = argv[2];
378 oname = argv[3];
379 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
381 else if(!strcmp(argv[1], "-ipod4g")) {
382 iname = argv[2];
383 oname = argv[3];
384 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
386 else if(!strcmp(argv[1], "-ipod5g")) {
387 iname = argv[2];
388 oname = argv[3];
389 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
391 else if(!strncmp(argv[1], "-creative=", 10)) {
392 if(!strcmp(argv[2], "-no-ciff"))
394 creative_enable_ciff = false;
395 iname = argv[3];
396 oname = argv[4];
398 else
400 creative_enable_ciff = true;
401 iname = argv[2];
402 oname = argv[3];
404 if(!strcmp(&argv[1][10], "zvm"))
405 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
406 else if(!strcmp(&argv[1][10], "zvm60"))
407 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
408 else if(!strcmp(&argv[1][10], "zenvision"))
409 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
410 else if(!strcmp(&argv[1][10], "zenv"))
411 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
412 else if(!strcmp(&argv[1][10], "zen"))
413 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
414 else
416 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
417 return 2;
420 else if(!strcmp(argv[1], "-ccpmp")) {
421 iname = argv[2];
422 oname = argv[3];
423 return ccpmp_encode(iname, oname);
425 else if(!strncmp(argv[1], "-mi4", 4)) {
426 int mi4magic;
427 char model[4] = "";
428 char type[4] = "";
430 if(!strcmp(&argv[1][4], "v2")) {
431 mi4magic = MI4_MAGIC_DEFAULT;
432 version = 0x00010201;
434 else if(!strcmp(&argv[1][4], "v3")) {
435 mi4magic = MI4_MAGIC_DEFAULT;
436 version = 0x00010301;
438 else if(!strcmp(&argv[1][4], "r")) {
439 mi4magic = MI4_MAGIC_R;
440 version = 0x00010301;
442 else {
443 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
444 return -1;
447 iname = argv[2];
448 oname = argv[3];
450 if(!strncmp(argv[2], "-model=", 7)) {
451 iname = argv[3];
452 oname = argv[4];
453 strncpy(model, &argv[2][7], 4);
455 if(!strncmp(argv[3], "-type=", 6)) {
456 iname = argv[4];
457 oname = argv[5];
458 strncpy(type, &argv[3][6], 4);
462 return mi4_encode(iname, oname, version, mi4magic, model, type);
465 /* open file */
466 file = fopen(iname,"rb");
467 if (!file) {
468 perror(iname);
469 return -1;
471 fseek(file,0,SEEK_END);
472 length = ftell(file);
473 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
475 if ((method == scramble) &&
476 ((length + headerlen) >= size_limit[model_id])) {
477 printf("error: firmware image is %ld bytes while max size is %u!\n",
478 length + headerlen,
479 size_limit[model_id]);
480 fclose(file);
481 return -1;
484 fseek(file,0,SEEK_SET);
485 inbuf = malloc(length);
486 if (method == xor)
487 outbuf = malloc(length*2);
488 else if(method == add)
489 outbuf = malloc(length + 8);
490 else
491 outbuf = malloc(length);
492 if ( !inbuf || !outbuf ) {
493 printf("out of memory!\n");
494 return -1;
496 if(length> 4) {
497 /* zero-fill the last 4 bytes to make sure there's no rubbish there
498 when we write the size-aligned file later */
499 memset(outbuf+length-4, 0, 4);
502 /* read file */
503 i=fread(inbuf,1,length,file);
504 if ( !i ) {
505 perror(iname);
506 return -1;
508 fclose(file);
510 switch (method)
512 case add:
513 for (i = 0; i < length; i++) {
514 /* add 8 unsigned bits but keep a 32 bit sum */
515 chksum += inbuf[i];
517 break;
518 case scramble:
519 slen = length/4;
520 for (i = 0; i < length; i++) {
521 unsigned long addr = (i >> 2) + ((i % 4) * slen);
522 unsigned char data = inbuf[i];
523 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
524 outbuf[addr] = data;
526 break;
528 case xor:
529 /* "compress" */
530 slen = 0;
531 for (i=0; i<length; i++) {
532 if (!(i&7))
533 outbuf[slen++] = 0xff; /* all data is uncompressed */
534 outbuf[slen++] = inbuf[i];
536 break;
537 case none:
538 default:
539 /* dummy case just to silence picky compilers */
540 break;
543 if((method == none) || (method == scramble) || (method == xor)) {
544 /* calculate checksum */
545 for (i=0;i<length;i++)
546 crc += inbuf[i];
549 memset(header, 0, sizeof header);
550 switch (method)
552 case add:
554 int2be(chksum, header); /* checksum, big-endian */
555 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
556 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
557 headerlen = 8;
559 break;
561 case tcc_sum:
562 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
563 telechips_encode_sum(outbuf, length);
564 break;
566 case tcc_crc:
567 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
568 telechips_encode_crc(outbuf, length);
569 break;
571 case scramble:
572 if (headerlen == 6) {
573 int2be(length, header);
574 header[4] = (crc >> 8) & 0xff;
575 header[5] = crc & 0xff;
577 else {
578 header[0] =
579 header[1] =
580 header[2] =
581 header[3] = 0xff; /* ??? */
583 header[6] = (crc >> 8) & 0xff;
584 header[7] = crc & 0xff;
586 header[11] = version;
588 header[15] = headerlen; /* really? */
590 int2be(length, &header[20]);
592 break;
594 case xor:
596 int xorlen = strlen(xorstring);
598 /* xor data */
599 for (i=0; i<slen; i++)
600 outbuf[i] ^= xorstring[i & (xorlen-1)];
602 /* calculate checksum */
603 for (i=0; i<slen; i++)
604 crc += outbuf[i];
606 header[0] = header[2] = 'Z';
607 header[1] = header[3] = version;
608 int2le(length, &header[4]);
609 int2le(slen, &header[8]);
610 int2le(crc, &header[12]);
611 length = slen;
612 break;
615 #define MY_FIRMWARE_TYPE "Rockbox"
616 #define MY_HEADER_VERSION 1
617 default:
618 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
619 header[9]='\0'; /*shouldn't have to, but to be SURE */
620 header[10]=MY_HEADER_VERSION&0xFF;
621 header[11]=(crc>>8)&0xFF;
622 header[12]=crc&0xFF;
623 int2be(sizeof(header), &header[12]);
624 break;
627 /* write file */
628 file = fopen(oname,"wb");
629 if ( !file ) {
630 perror(oname);
631 return -1;
633 if (headerlen > 0) {
634 if ( !fwrite(header,headerlen,1,file) ) {
635 perror(oname);
636 return -1;
639 if ( !fwrite(outbuf,length,1,file) ) {
640 perror(oname);
641 return -1;
643 fclose(file);
645 free(inbuf);
646 free(outbuf);
648 return 0;
651 static int iaudio_encode(char *iname, char *oname, char *idstring)
653 size_t len;
654 int length;
655 FILE *file;
656 unsigned char *outbuf;
657 int i;
658 unsigned char sum = 0;
660 file = fopen(iname, "rb");
661 if (!file) {
662 perror(iname);
663 return -1;
665 fseek(file,0,SEEK_END);
666 length = ftell(file);
668 fseek(file,0,SEEK_SET);
669 outbuf = malloc(length+0x1030);
671 if ( !outbuf ) {
672 printf("out of memory!\n");
673 return -1;
676 len = fread(outbuf+0x1030, 1, length, file);
677 if(len < (size_t) length) {
678 perror(iname);
679 return -2;
682 memset(outbuf, 0, 0x1030);
683 strcpy((char *)outbuf, idstring);
684 memcpy(outbuf+0x20, iaudio_bl_flash,
685 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
686 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
687 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
688 outbuf[0x19] = 2;
690 for(i = 0; i < length;i++)
691 sum += outbuf[0x1030 + i];
693 int2be(length, &outbuf[0x1024]);
694 outbuf[0x102b] = sum;
696 fclose(file);
698 file = fopen(oname, "wb");
699 if (!file) {
700 perror(oname);
701 return -3;
704 len = fwrite(outbuf, 1, length+0x1030, file);
705 if(len < (size_t)length) {
706 perror(oname);
707 return -4;
710 fclose(file);
711 return 0;
715 /* Create an ipod firmware partition image
717 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
719 This function doesn't yet handle the Broadcom resource image for the 5g,
720 so the resulting images won't be usable.
722 This has also only been tested on an ipod Photo
725 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
727 static const char *apple_stop_sign = "{{~~ /-----\\ "\
728 "{{~~ / \\ "\
729 "{{~~| | "\
730 "{{~~| S T O P | "\
731 "{{~~| | "\
732 "{{~~ \\ / "\
733 "{{~~ \\-----/ "\
734 "Copyright(C) 200"\
735 "1 Apple Computer"\
736 ", Inc.----------"\
737 "----------------"\
738 "----------------"\
739 "----------------"\
740 "----------------"\
741 "----------------"\
742 "---------------";
743 size_t len;
744 int length;
745 int rsrclength;
746 int rsrcoffset;
747 FILE *file;
748 unsigned int sum = 0;
749 unsigned int rsrcsum = 0;
750 unsigned char *outbuf;
751 int bufsize;
752 int i;
754 file = fopen(iname, "rb");
755 if (!file) {
756 perror(iname);
757 return -1;
759 fseek(file,0,SEEK_END);
760 length = ftell(file);
762 fseek(file,0,SEEK_SET);
764 bufsize=(length+0x4600);
765 if (fake_rsrc) {
766 bufsize = (bufsize + 0x400) & ~0x200;
769 outbuf = malloc(bufsize);
771 if ( !outbuf ) {
772 printf("out of memory!\n");
773 return -1;
776 len = fread(outbuf+0x4600, 1, length, file);
777 if(len < (size_t)length) {
778 perror(iname);
779 return -2;
781 fclose(file);
783 /* Calculate checksum for later use in header */
784 for(i = 0x4600; i < 0x4600+length;i++)
785 sum += outbuf[i];
787 /* Clear the header area to zero */
788 memset(outbuf, 0, 0x4600);
790 /* APPLE STOP SIGN */
791 strcpy((char *)outbuf, apple_stop_sign);
793 /* VOLUME HEADER */
794 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
795 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
796 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
797 short2le(fw_ver, &outbuf[0x10a]);
799 /* Firmware Directory - "osos" entry */
800 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
801 int2le(0, &outbuf[0x4208]); /* id */
802 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
803 int2le(length, &outbuf[0x4210]); /* Length of firmware */
804 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
805 int2le(0, &outbuf[0x4218]); /* Entry Offset */
806 int2le(sum, &outbuf[0x421c]); /* Checksum */
807 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
808 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
810 /* "rsrc" entry (if applicable) */
811 if (fake_rsrc) {
812 rsrcoffset=(length+0x4600+0x200) & ~0x200;
813 rsrclength=0x200;
814 rsrcsum=0;
816 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
817 int2le(0, &outbuf[0x4230]); /* id */
818 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
819 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
820 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
821 int2le(0, &outbuf[0x4240]); /* Entry Offset */
822 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
823 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
824 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
827 file = fopen(oname, "wb");
828 if (!file) {
829 perror(oname);
830 return -3;
833 len = fwrite(outbuf, 1, length+0x4600, file);
834 if(len < (size_t)length) {
835 perror(oname);
836 return -4;
839 fclose(file);
841 return 0;
844 #define CCPMP_SIZE 0x500000
845 static int ccpmp_encode(char *iname, char *oname)
847 size_t len;
848 int length;
849 FILE *file;
850 unsigned char *outbuf;
852 file = fopen(iname, "rb");
853 if (!file) {
854 perror(iname);
855 return -1;
857 fseek(file,0,SEEK_END);
858 length = ftell(file);
860 fseek(file,0,SEEK_SET);
862 outbuf = malloc(CCPMP_SIZE);
864 if ( !outbuf ) {
865 printf("out of memory!\n");
866 return -1;
869 len = fread(outbuf, 1, length, file);
870 if(len < (size_t)length) {
871 perror(iname);
872 return -2;
874 fclose(file);
876 /* Clear the tail area to 0xFF */
877 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
879 /* Header */
880 int2le(length, &outbuf[0x4]);
882 file = fopen(oname, "wb");
883 if (!file) {
884 perror(oname);
885 return -3;
888 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
889 if(len < (size_t)length) {
890 perror(oname);
891 return -4;
894 fclose(file);
896 return 0;