Save some binsize in LCD driver of iPod nano 2G. No impact to speed.
[maemo-rb.git] / tools / scramble.c
blobb460d51c5e9a1b3aec333138f9a3fd5a89628d4c
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+, fuz2, hd20, hd30)\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], "fuz2")) /* Sansa Fuze v2 */
328 modelnum = 68;
329 else if (!strcmp(&argv[1][5], "m244"))
330 modelnum = 131;
331 else if (!strcmp(&argv[1][5], "hd20")) /* MPIO HD200 */
332 modelnum = 69;
333 else if (!strcmp(&argv[1][5], "hd30")) /* MPIO HD300 */
334 modelnum = 70;
335 else {
336 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
337 return 2;
339 /* we store a 4-letter model name too, for humans */
340 strncpy(modelname, &argv[1][5],4);
341 modelname[4] = '\0'; /* to be sure we are null terminated */
342 chksum = modelnum; /* start checksum calcs with this */
345 else if(!strcmp(argv[1], "-iriver")) {
346 /* iRiver code dealt with in the iriver.c code */
347 iname = argv[2];
348 oname = argv[3];
349 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
351 else if(!strcmp(argv[1], "-gigabeat")) {
352 /* iRiver code dealt with in the iriver.c code */
353 iname = argv[2];
354 oname = argv[3];
355 gigabeat_code(iname, oname);
356 return 0;
358 else if(!strcmp(argv[1], "-gigabeats")) {
359 iname = argv[2];
360 oname = argv[3];
361 return gigabeat_s_code(iname, oname);
363 else if(!strcmp(argv[1], "-iaudiox5")) {
364 iname = argv[2];
365 oname = argv[3];
366 return iaudio_encode(iname, oname, "COWON_X5_FW");
368 else if(!strcmp(argv[1], "-iaudiox5v")) {
369 iname = argv[2];
370 oname = argv[3];
371 return iaudio_encode(iname, oname, "COWON_X5V_FW");
373 else if(!strcmp(argv[1], "-iaudiom5")) {
374 iname = argv[2];
375 oname = argv[3];
376 return iaudio_encode(iname, oname, "COWON_M5_FW");
378 else if(!strcmp(argv[1], "-iaudiom3")) {
379 iname = argv[2];
380 oname = argv[3];
381 return iaudio_encode(iname, oname, "COWON_M3_FW");
383 else if(!strcmp(argv[1], "-ipod3g")) {
384 iname = argv[2];
385 oname = argv[3];
386 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
388 else if(!strcmp(argv[1], "-ipod4g")) {
389 iname = argv[2];
390 oname = argv[3];
391 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
393 else if(!strcmp(argv[1], "-ipod5g")) {
394 iname = argv[2];
395 oname = argv[3];
396 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
398 else if(!strncmp(argv[1], "-creative=", 10)) {
399 if(!strcmp(argv[2], "-no-ciff"))
401 creative_enable_ciff = false;
402 iname = argv[3];
403 oname = argv[4];
405 else
407 creative_enable_ciff = true;
408 iname = argv[2];
409 oname = argv[3];
411 if(!strcmp(&argv[1][10], "zvm"))
412 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
413 else if(!strcmp(&argv[1][10], "zvm60"))
414 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
415 else if(!strcmp(&argv[1][10], "zenvision"))
416 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
417 else if(!strcmp(&argv[1][10], "zenv"))
418 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
419 else if(!strcmp(&argv[1][10], "zen"))
420 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
421 else
423 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
424 return 2;
427 else if(!strcmp(argv[1], "-ccpmp")) {
428 iname = argv[2];
429 oname = argv[3];
430 return ccpmp_encode(iname, oname);
432 else if(!strncmp(argv[1], "-mi4", 4)) {
433 int mi4magic;
434 char model[4] = "";
435 char type[4] = "";
437 if(!strcmp(&argv[1][4], "v2")) {
438 mi4magic = MI4_MAGIC_DEFAULT;
439 version = 0x00010201;
441 else if(!strcmp(&argv[1][4], "v3")) {
442 mi4magic = MI4_MAGIC_DEFAULT;
443 version = 0x00010301;
445 else if(!strcmp(&argv[1][4], "r")) {
446 mi4magic = MI4_MAGIC_R;
447 version = 0x00010301;
449 else {
450 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
451 return -1;
454 iname = argv[2];
455 oname = argv[3];
457 if(!strncmp(argv[2], "-model=", 7)) {
458 iname = argv[3];
459 oname = argv[4];
460 strncpy(model, &argv[2][7], 4);
462 if(!strncmp(argv[3], "-type=", 6)) {
463 iname = argv[4];
464 oname = argv[5];
465 strncpy(type, &argv[3][6], 4);
469 return mi4_encode(iname, oname, version, mi4magic, model, type);
472 /* open file */
473 file = fopen(iname,"rb");
474 if (!file) {
475 perror(iname);
476 return -1;
478 fseek(file,0,SEEK_END);
479 length = ftell(file);
480 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
482 if ((method == scramble) &&
483 ((length + headerlen) >= size_limit[model_id])) {
484 printf("error: firmware image is %ld bytes while max size is %u!\n",
485 length + headerlen,
486 size_limit[model_id]);
487 fclose(file);
488 return -1;
491 fseek(file,0,SEEK_SET);
492 inbuf = malloc(length);
493 if (method == xor)
494 outbuf = malloc(length*2);
495 else if(method == add)
496 outbuf = malloc(length + 8);
497 else
498 outbuf = malloc(length);
499 if ( !inbuf || !outbuf ) {
500 printf("out of memory!\n");
501 return -1;
503 if(length> 4) {
504 /* zero-fill the last 4 bytes to make sure there's no rubbish there
505 when we write the size-aligned file later */
506 memset(outbuf+length-4, 0, 4);
509 /* read file */
510 i=fread(inbuf,1,length,file);
511 if ( !i ) {
512 perror(iname);
513 return -1;
515 fclose(file);
517 switch (method)
519 case add:
520 for (i = 0; i < length; i++) {
521 /* add 8 unsigned bits but keep a 32 bit sum */
522 chksum += inbuf[i];
524 break;
525 case scramble:
526 slen = length/4;
527 for (i = 0; i < length; i++) {
528 unsigned long addr = (i >> 2) + ((i % 4) * slen);
529 unsigned char data = inbuf[i];
530 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
531 outbuf[addr] = data;
533 break;
535 case xor:
536 /* "compress" */
537 slen = 0;
538 for (i=0; i<length; i++) {
539 if (!(i&7))
540 outbuf[slen++] = 0xff; /* all data is uncompressed */
541 outbuf[slen++] = inbuf[i];
543 break;
544 case none:
545 default:
546 /* dummy case just to silence picky compilers */
547 break;
550 if((method == none) || (method == scramble) || (method == xor)) {
551 /* calculate checksum */
552 for (i=0;i<length;i++)
553 crc += inbuf[i];
556 memset(header, 0, sizeof header);
557 switch (method)
559 case add:
561 int2be(chksum, header); /* checksum, big-endian */
562 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
563 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
564 headerlen = 8;
566 break;
568 case tcc_sum:
569 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
570 telechips_encode_sum(outbuf, length);
571 break;
573 case tcc_crc:
574 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
575 telechips_encode_crc(outbuf, length);
576 break;
578 case scramble:
579 if (headerlen == 6) {
580 int2be(length, header);
581 header[4] = (crc >> 8) & 0xff;
582 header[5] = crc & 0xff;
584 else {
585 header[0] =
586 header[1] =
587 header[2] =
588 header[3] = 0xff; /* ??? */
590 header[6] = (crc >> 8) & 0xff;
591 header[7] = crc & 0xff;
593 header[11] = version;
595 header[15] = headerlen; /* really? */
597 int2be(length, &header[20]);
599 break;
601 case xor:
603 int xorlen = strlen(xorstring);
605 /* xor data */
606 for (i=0; i<slen; i++)
607 outbuf[i] ^= xorstring[i & (xorlen-1)];
609 /* calculate checksum */
610 for (i=0; i<slen; i++)
611 crc += outbuf[i];
613 header[0] = header[2] = 'Z';
614 header[1] = header[3] = version;
615 int2le(length, &header[4]);
616 int2le(slen, &header[8]);
617 int2le(crc, &header[12]);
618 length = slen;
619 break;
622 #define MY_FIRMWARE_TYPE "Rockbox"
623 #define MY_HEADER_VERSION 1
624 default:
625 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
626 header[9]='\0'; /*shouldn't have to, but to be SURE */
627 header[10]=MY_HEADER_VERSION&0xFF;
628 header[11]=(crc>>8)&0xFF;
629 header[12]=crc&0xFF;
630 int2be(sizeof(header), &header[12]);
631 break;
634 /* write file */
635 file = fopen(oname,"wb");
636 if ( !file ) {
637 perror(oname);
638 return -1;
640 if (headerlen > 0) {
641 if ( !fwrite(header,headerlen,1,file) ) {
642 perror(oname);
643 return -1;
646 if ( !fwrite(outbuf,length,1,file) ) {
647 perror(oname);
648 return -1;
650 fclose(file);
652 free(inbuf);
653 free(outbuf);
655 return 0;
658 static int iaudio_encode(char *iname, char *oname, char *idstring)
660 size_t len;
661 int length;
662 FILE *file;
663 unsigned char *outbuf;
664 int i;
665 unsigned char sum = 0;
667 file = fopen(iname, "rb");
668 if (!file) {
669 perror(iname);
670 return -1;
672 fseek(file,0,SEEK_END);
673 length = ftell(file);
675 fseek(file,0,SEEK_SET);
676 outbuf = malloc(length+0x1030);
678 if ( !outbuf ) {
679 printf("out of memory!\n");
680 return -1;
683 len = fread(outbuf+0x1030, 1, length, file);
684 if(len < (size_t) length) {
685 perror(iname);
686 return -2;
689 memset(outbuf, 0, 0x1030);
690 strcpy((char *)outbuf, idstring);
691 memcpy(outbuf+0x20, iaudio_bl_flash,
692 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
693 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
694 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
695 outbuf[0x19] = 2;
697 for(i = 0; i < length;i++)
698 sum += outbuf[0x1030 + i];
700 int2be(length, &outbuf[0x1024]);
701 outbuf[0x102b] = sum;
703 fclose(file);
705 file = fopen(oname, "wb");
706 if (!file) {
707 perror(oname);
708 return -3;
711 len = fwrite(outbuf, 1, length+0x1030, file);
712 if(len < (size_t)length) {
713 perror(oname);
714 return -4;
717 fclose(file);
718 return 0;
722 /* Create an ipod firmware partition image
724 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
726 This function doesn't yet handle the Broadcom resource image for the 5g,
727 so the resulting images won't be usable.
729 This has also only been tested on an ipod Photo
732 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
734 static const char *apple_stop_sign = "{{~~ /-----\\ "\
735 "{{~~ / \\ "\
736 "{{~~| | "\
737 "{{~~| S T O P | "\
738 "{{~~| | "\
739 "{{~~ \\ / "\
740 "{{~~ \\-----/ "\
741 "Copyright(C) 200"\
742 "1 Apple Computer"\
743 ", Inc.----------"\
744 "----------------"\
745 "----------------"\
746 "----------------"\
747 "----------------"\
748 "----------------"\
749 "---------------";
750 size_t len;
751 int length;
752 int rsrclength;
753 int rsrcoffset;
754 FILE *file;
755 unsigned int sum = 0;
756 unsigned int rsrcsum = 0;
757 unsigned char *outbuf;
758 int bufsize;
759 int i;
761 file = fopen(iname, "rb");
762 if (!file) {
763 perror(iname);
764 return -1;
766 fseek(file,0,SEEK_END);
767 length = ftell(file);
769 fseek(file,0,SEEK_SET);
771 bufsize=(length+0x4600);
772 if (fake_rsrc) {
773 bufsize = (bufsize + 0x400) & ~0x200;
776 outbuf = malloc(bufsize);
778 if ( !outbuf ) {
779 printf("out of memory!\n");
780 return -1;
783 len = fread(outbuf+0x4600, 1, length, file);
784 if(len < (size_t)length) {
785 perror(iname);
786 return -2;
788 fclose(file);
790 /* Calculate checksum for later use in header */
791 for(i = 0x4600; i < 0x4600+length;i++)
792 sum += outbuf[i];
794 /* Clear the header area to zero */
795 memset(outbuf, 0, 0x4600);
797 /* APPLE STOP SIGN */
798 strcpy((char *)outbuf, apple_stop_sign);
800 /* VOLUME HEADER */
801 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
802 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
803 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
804 short2le(fw_ver, &outbuf[0x10a]);
806 /* Firmware Directory - "osos" entry */
807 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
808 int2le(0, &outbuf[0x4208]); /* id */
809 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
810 int2le(length, &outbuf[0x4210]); /* Length of firmware */
811 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
812 int2le(0, &outbuf[0x4218]); /* Entry Offset */
813 int2le(sum, &outbuf[0x421c]); /* Checksum */
814 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
815 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
817 /* "rsrc" entry (if applicable) */
818 if (fake_rsrc) {
819 rsrcoffset=(length+0x4600+0x200) & ~0x200;
820 rsrclength=0x200;
821 rsrcsum=0;
823 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
824 int2le(0, &outbuf[0x4230]); /* id */
825 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
826 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
827 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
828 int2le(0, &outbuf[0x4240]); /* Entry Offset */
829 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
830 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
831 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
834 file = fopen(oname, "wb");
835 if (!file) {
836 perror(oname);
837 return -3;
840 len = fwrite(outbuf, 1, length+0x4600, file);
841 if(len < (size_t)length) {
842 perror(oname);
843 return -4;
846 fclose(file);
848 return 0;
851 #define CCPMP_SIZE 0x500000
852 static int ccpmp_encode(char *iname, char *oname)
854 size_t len;
855 int length;
856 FILE *file;
857 unsigned char *outbuf;
859 file = fopen(iname, "rb");
860 if (!file) {
861 perror(iname);
862 return -1;
864 fseek(file,0,SEEK_END);
865 length = ftell(file);
867 fseek(file,0,SEEK_SET);
869 outbuf = malloc(CCPMP_SIZE);
871 if ( !outbuf ) {
872 printf("out of memory!\n");
873 return -1;
876 len = fread(outbuf, 1, length, file);
877 if(len < (size_t)length) {
878 perror(iname);
879 return -2;
881 fclose(file);
883 /* Clear the tail area to 0xFF */
884 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
886 /* Header */
887 int2le(length, &outbuf[0x4]);
889 file = fopen(oname, "wb");
890 if (!file) {
891 perror(oname);
892 return -3;
895 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
896 if(len < (size_t)length) {
897 perror(oname);
898 return -4;
901 fclose(file);
903 return 0;