Bump codec's API version. This is related to r29388 which changed the mp3entry struct.
[maemo-rb.git] / tools / scramble.c
blobc18631a2f5a848753008d3fbf57c7954565726e8
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 "\t ip6g)\n");
130 printf("\nNo option results in Archos standard player/recorder format.\n");
132 exit(1);
135 int main (int argc, char** argv)
137 unsigned long length,i,slen=0;
138 unsigned char *inbuf,*outbuf;
139 unsigned short crc=0;
140 unsigned long chksum=0; /* 32 bit checksum */
141 unsigned char header[24];
142 char *iname = argv[1];
143 char *oname = argv[2];
144 char *xorstring=NULL;
145 int headerlen = 6;
146 FILE* file;
147 int version=0;
148 unsigned long modelnum;
149 char modelname[5];
150 int model_id;
151 enum { none, scramble, xor, tcc_sum, tcc_crc, add } method = scramble;
152 bool creative_enable_ciff;
154 model_id = ARCHOS_PLAYER;
156 if (argc < 3) {
157 usage();
160 if(!strcmp(argv[1], "-fm")) {
161 headerlen = 24;
162 iname = argv[2];
163 oname = argv[3];
164 version = 4;
165 model_id = ARCHOS_FMRECORDER;
168 else if(!strcmp(argv[1], "-v2")) {
169 headerlen = 24;
170 iname = argv[2];
171 oname = argv[3];
172 version = 2;
173 model_id = ARCHOS_V2RECORDER;
176 else if(!strcmp(argv[1], "-ofm")) {
177 headerlen = 24;
178 iname = argv[2];
179 oname = argv[3];
180 version = 8;
181 model_id = ARCHOS_ONDIO_FM;
184 else if(!strcmp(argv[1], "-osp")) {
185 headerlen = 24;
186 iname = argv[2];
187 oname = argv[3];
188 version = 16;
189 model_id = ARCHOS_ONDIO_SP;
192 else if(!strcmp(argv[1], "-neo")) {
193 headerlen = 17;
194 iname = argv[2];
195 oname = argv[3];
196 method = none;
198 else if(!strncmp(argv[1], "-mm=", 4)) {
199 headerlen = 16;
200 iname = argv[2];
201 oname = argv[3];
202 method = xor;
203 version = argv[1][4];
204 if (argc > 4)
205 xorstring = argv[4];
206 else {
207 printf("Multimedia needs an xor string\n");
208 return -1;
211 else if(!strncmp(argv[1], "-tcc=", 4)) {
212 headerlen = 0;
213 iname = argv[2];
214 oname = argv[3];
216 if(!strcmp(&argv[1][5], "sum"))
217 method = tcc_sum;
218 else if(!strcmp(&argv[1][5], "crc"))
219 method = tcc_crc;
220 else {
221 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
222 return 2;
225 else if(!strncmp(argv[1], "-add=", 5)) {
226 iname = argv[2];
227 oname = argv[3];
228 method = add;
230 if(!strcmp(&argv[1][5], "h120"))
231 modelnum = 0;
232 else if(!strcmp(&argv[1][5], "h140"))
233 modelnum = 0; /* the same as the h120 */
234 else if(!strcmp(&argv[1][5], "h100"))
235 modelnum = 1;
236 else if(!strcmp(&argv[1][5], "h300"))
237 modelnum = 2;
238 else if(!strcmp(&argv[1][5], "ipco"))
239 modelnum = 3;
240 else if(!strcmp(&argv[1][5], "nano"))
241 modelnum = 4;
242 else if(!strcmp(&argv[1][5], "ipvd"))
243 modelnum = 5;
244 else if(!strcmp(&argv[1][5], "fp7x"))
245 modelnum = 6;
246 else if(!strcmp(&argv[1][5], "ip3g"))
247 modelnum = 7;
248 else if(!strcmp(&argv[1][5], "ip4g"))
249 modelnum = 8;
250 else if(!strcmp(&argv[1][5], "mini"))
251 modelnum = 9;
252 else if(!strcmp(&argv[1][5], "iax5"))
253 modelnum = 10;
254 else if(!strcmp(&argv[1][5], "mn2g"))
255 modelnum = 11;
256 else if(!strcmp(&argv[1][5], "h10"))
257 modelnum = 13;
258 else if(!strcmp(&argv[1][5], "h10_5gb"))
259 modelnum = 14;
260 else if(!strcmp(&argv[1][5], "tpj2"))
261 modelnum = 15;
262 else if(!strcmp(&argv[1][5], "e200"))
263 modelnum = 16;
264 else if(!strcmp(&argv[1][5], "iam5"))
265 modelnum = 17;
266 else if(!strcmp(&argv[1][5], "giga"))
267 modelnum = 18;
268 else if(!strcmp(&argv[1][5], "1g2g"))
269 modelnum = 19;
270 else if(!strcmp(&argv[1][5], "c200"))
271 modelnum = 20;
272 else if(!strcmp(&argv[1][5], "gigs"))
273 modelnum = 21;
274 else if(!strcmp(&argv[1][5], "m500"))
275 modelnum = 22;
276 else if(!strcmp(&argv[1][5], "m100"))
277 modelnum = 23;
278 else if(!strcmp(&argv[1][5], "d2"))
279 modelnum = 24;
280 else if(!strcmp(&argv[1][5], "iam3"))
281 modelnum = 25;
282 else if (!strcmp(&argv[1][5], "m200"))
283 modelnum = 29;
284 else if(!strcmp(&argv[1][5], "c100"))
285 modelnum = 30;
286 else if(!strcmp(&argv[1][5], "1630")) /* Philips HDD1630 */
287 modelnum = 31;
288 else if (!strcmp(&argv[1][5], "i7"))
289 modelnum = 32;
290 else if (!strcmp(&argv[1][5], "ldax"))
291 modelnum = 33;
292 else if(!strcmp(&argv[1][5], "9200")) /* Philips SA9200 */
293 modelnum = 34;
294 else if (!strcmp(&argv[1][5], "clip"))
295 modelnum = 40;
296 else if (!strcmp(&argv[1][5], "e2v2"))
297 modelnum = 41;
298 else if (!strcmp(&argv[1][5], "m2v4"))
299 modelnum = 42;
300 else if (!strcmp(&argv[1][5], "fuze"))
301 modelnum = 43;
302 else if (!strcmp(&argv[1][5], "c2v2"))
303 modelnum = 44;
304 else if (!strcmp(&argv[1][5], "x747"))
305 modelnum = 45;
306 else if (!strcmp(&argv[1][5], "747p"))
307 modelnum = 54;
308 else if (!strcmp(&argv[1][5], "y820")) /* Samsung YH-820 */
309 modelnum = 57;
310 else if (!strcmp(&argv[1][5], "y920")) /* Samsung YH-920 */
311 modelnum = 58;
312 else if (!strcmp(&argv[1][5], "y925")) /* Samsung YH-925 */
313 modelnum = 59;
314 else if (!strcmp(&argv[1][5], "clv2")) /* Sansa Clipv2 */
315 modelnum = 60;
316 else if (!strcmp(&argv[1][5], "x777"))
317 modelnum = 61;
318 else if (!strcmp(&argv[1][5], "nn2g")) /* iPod Nano 2nd Gen */
319 modelnum = 62;
320 else if (!strcmp(&argv[1][5], "x767"))
321 modelnum = 64;
322 else if (!strcmp(&argv[1][5], "6330")) /* Philips HDD6330 */
323 modelnum = 65;
324 else if (!strcmp(&argv[1][5], "cli+")) /* Sansa Clip+ */
325 modelnum = 66;
326 else if (!strcmp(&argv[1][5], "v500")) /* Packard Bell Vibe 500 */
327 modelnum = 67;
328 else if (!strcmp(&argv[1][5], "fuz2")) /* Sansa Fuze v2 */
329 modelnum = 68;
330 else if (!strcmp(&argv[1][5], "m244"))
331 modelnum = 131;
332 else if (!strcmp(&argv[1][5], "hd20")) /* MPIO HD200 */
333 modelnum = 69;
334 else if (!strcmp(&argv[1][5], "hd30")) /* MPIO HD300 */
335 modelnum = 70;
336 else if (!strcmp(&argv[1][5], "ip6g")) /* iPod Classic/6G */
337 modelnum = 71;
338 else {
339 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
340 return 2;
342 /* we store a 4-letter model name too, for humans */
343 strncpy(modelname, &argv[1][5],4);
344 modelname[4] = '\0'; /* to be sure we are null terminated */
345 chksum = modelnum; /* start checksum calcs with this */
348 else if(!strcmp(argv[1], "-iriver")) {
349 /* iRiver code dealt with in the iriver.c code */
350 iname = argv[2];
351 oname = argv[3];
352 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
354 else if(!strcmp(argv[1], "-gigabeat")) {
355 /* iRiver code dealt with in the iriver.c code */
356 iname = argv[2];
357 oname = argv[3];
358 gigabeat_code(iname, oname);
359 return 0;
361 else if(!strcmp(argv[1], "-gigabeats")) {
362 iname = argv[2];
363 oname = argv[3];
364 return gigabeat_s_code(iname, oname);
366 else if(!strcmp(argv[1], "-iaudiox5")) {
367 iname = argv[2];
368 oname = argv[3];
369 return iaudio_encode(iname, oname, "COWON_X5_FW");
371 else if(!strcmp(argv[1], "-iaudiox5v")) {
372 iname = argv[2];
373 oname = argv[3];
374 return iaudio_encode(iname, oname, "COWON_X5V_FW");
376 else if(!strcmp(argv[1], "-iaudiom5")) {
377 iname = argv[2];
378 oname = argv[3];
379 return iaudio_encode(iname, oname, "COWON_M5_FW");
381 else if(!strcmp(argv[1], "-iaudiom3")) {
382 iname = argv[2];
383 oname = argv[3];
384 return iaudio_encode(iname, oname, "COWON_M3_FW");
386 else if(!strcmp(argv[1], "-ipod3g")) {
387 iname = argv[2];
388 oname = argv[3];
389 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
391 else if(!strcmp(argv[1], "-ipod4g")) {
392 iname = argv[2];
393 oname = argv[3];
394 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
396 else if(!strcmp(argv[1], "-ipod5g")) {
397 iname = argv[2];
398 oname = argv[3];
399 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
401 else if(!strncmp(argv[1], "-creative=", 10)) {
402 if(!strcmp(argv[2], "-no-ciff"))
404 creative_enable_ciff = false;
405 iname = argv[3];
406 oname = argv[4];
408 else
410 creative_enable_ciff = true;
411 iname = argv[2];
412 oname = argv[3];
414 if(!strcmp(&argv[1][10], "zvm"))
415 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
416 else if(!strcmp(&argv[1][10], "zvm60"))
417 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
418 else if(!strcmp(&argv[1][10], "zenvision"))
419 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
420 else if(!strcmp(&argv[1][10], "zenv"))
421 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
422 else if(!strcmp(&argv[1][10], "zen"))
423 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
424 else
426 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
427 return 2;
430 else if(!strcmp(argv[1], "-ccpmp")) {
431 iname = argv[2];
432 oname = argv[3];
433 return ccpmp_encode(iname, oname);
435 else if(!strncmp(argv[1], "-mi4", 4)) {
436 int mi4magic;
437 char model[4] = "";
438 char type[4] = "";
440 if(!strcmp(&argv[1][4], "v2")) {
441 mi4magic = MI4_MAGIC_DEFAULT;
442 version = 0x00010201;
444 else if(!strcmp(&argv[1][4], "v3")) {
445 mi4magic = MI4_MAGIC_DEFAULT;
446 version = 0x00010301;
448 else if(!strcmp(&argv[1][4], "r")) {
449 mi4magic = MI4_MAGIC_R;
450 version = 0x00010301;
452 else {
453 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
454 return -1;
457 iname = argv[2];
458 oname = argv[3];
460 if(!strncmp(argv[2], "-model=", 7)) {
461 iname = argv[3];
462 oname = argv[4];
463 strncpy(model, &argv[2][7], 4);
465 if(!strncmp(argv[3], "-type=", 6)) {
466 iname = argv[4];
467 oname = argv[5];
468 strncpy(type, &argv[3][6], 4);
472 return mi4_encode(iname, oname, version, mi4magic, model, type);
475 /* open file */
476 file = fopen(iname,"rb");
477 if (!file) {
478 perror(iname);
479 return -1;
481 fseek(file,0,SEEK_END);
482 length = ftell(file);
483 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
485 if ((method == scramble) &&
486 ((length + headerlen) >= size_limit[model_id])) {
487 printf("error: firmware image is %ld bytes while max size is %u!\n",
488 length + headerlen,
489 size_limit[model_id]);
490 fclose(file);
491 return -1;
494 fseek(file,0,SEEK_SET);
495 inbuf = malloc(length);
496 if (method == xor)
497 outbuf = malloc(length*2);
498 else if(method == add)
499 outbuf = malloc(length + 8);
500 else
501 outbuf = malloc(length);
502 if ( !inbuf || !outbuf ) {
503 printf("out of memory!\n");
504 return -1;
506 if(length> 4) {
507 /* zero-fill the last 4 bytes to make sure there's no rubbish there
508 when we write the size-aligned file later */
509 memset(outbuf+length-4, 0, 4);
512 /* read file */
513 i=fread(inbuf,1,length,file);
514 if ( !i ) {
515 perror(iname);
516 return -1;
518 fclose(file);
520 switch (method)
522 case add:
523 for (i = 0; i < length; i++) {
524 /* add 8 unsigned bits but keep a 32 bit sum */
525 chksum += inbuf[i];
527 break;
528 case scramble:
529 slen = length/4;
530 for (i = 0; i < length; i++) {
531 unsigned long addr = (i >> 2) + ((i % 4) * slen);
532 unsigned char data = inbuf[i];
533 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
534 outbuf[addr] = data;
536 break;
538 case xor:
539 /* "compress" */
540 slen = 0;
541 for (i=0; i<length; i++) {
542 if (!(i&7))
543 outbuf[slen++] = 0xff; /* all data is uncompressed */
544 outbuf[slen++] = inbuf[i];
546 break;
547 case none:
548 default:
549 /* dummy case just to silence picky compilers */
550 break;
553 if((method == none) || (method == scramble) || (method == xor)) {
554 /* calculate checksum */
555 for (i=0;i<length;i++)
556 crc += inbuf[i];
559 memset(header, 0, sizeof header);
560 switch (method)
562 case add:
564 int2be(chksum, header); /* checksum, big-endian */
565 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
566 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
567 headerlen = 8;
569 break;
571 case tcc_sum:
572 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
573 telechips_encode_sum(outbuf, length);
574 break;
576 case tcc_crc:
577 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
578 telechips_encode_crc(outbuf, length);
579 break;
581 case scramble:
582 if (headerlen == 6) {
583 int2be(length, header);
584 header[4] = (crc >> 8) & 0xff;
585 header[5] = crc & 0xff;
587 else {
588 header[0] =
589 header[1] =
590 header[2] =
591 header[3] = 0xff; /* ??? */
593 header[6] = (crc >> 8) & 0xff;
594 header[7] = crc & 0xff;
596 header[11] = version;
598 header[15] = headerlen; /* really? */
600 int2be(length, &header[20]);
602 break;
604 case xor:
606 int xorlen = strlen(xorstring);
608 /* xor data */
609 for (i=0; i<slen; i++)
610 outbuf[i] ^= xorstring[i & (xorlen-1)];
612 /* calculate checksum */
613 for (i=0; i<slen; i++)
614 crc += outbuf[i];
616 header[0] = header[2] = 'Z';
617 header[1] = header[3] = version;
618 int2le(length, &header[4]);
619 int2le(slen, &header[8]);
620 int2le(crc, &header[12]);
621 length = slen;
622 break;
625 #define MY_FIRMWARE_TYPE "Rockbox"
626 #define MY_HEADER_VERSION 1
627 default:
628 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
629 header[9]='\0'; /*shouldn't have to, but to be SURE */
630 header[10]=MY_HEADER_VERSION&0xFF;
631 header[11]=(crc>>8)&0xFF;
632 header[12]=crc&0xFF;
633 int2be(sizeof(header), &header[12]);
634 break;
637 /* write file */
638 file = fopen(oname,"wb");
639 if ( !file ) {
640 perror(oname);
641 return -1;
643 if (headerlen > 0) {
644 if ( !fwrite(header,headerlen,1,file) ) {
645 perror(oname);
646 return -1;
649 if ( !fwrite(outbuf,length,1,file) ) {
650 perror(oname);
651 return -1;
653 fclose(file);
655 free(inbuf);
656 free(outbuf);
658 return 0;
661 static int iaudio_encode(char *iname, char *oname, char *idstring)
663 size_t len;
664 int length;
665 FILE *file;
666 unsigned char *outbuf;
667 int i;
668 unsigned char sum = 0;
670 file = fopen(iname, "rb");
671 if (!file) {
672 perror(iname);
673 return -1;
675 fseek(file,0,SEEK_END);
676 length = ftell(file);
678 fseek(file,0,SEEK_SET);
679 outbuf = malloc(length+0x1030);
681 if ( !outbuf ) {
682 printf("out of memory!\n");
683 return -1;
686 len = fread(outbuf+0x1030, 1, length, file);
687 if(len < (size_t) length) {
688 perror(iname);
689 return -2;
692 memset(outbuf, 0, 0x1030);
693 strcpy((char *)outbuf, idstring);
694 memcpy(outbuf+0x20, iaudio_bl_flash,
695 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
696 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
697 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
698 outbuf[0x19] = 2;
700 for(i = 0; i < length;i++)
701 sum += outbuf[0x1030 + i];
703 int2be(length, &outbuf[0x1024]);
704 outbuf[0x102b] = sum;
706 fclose(file);
708 file = fopen(oname, "wb");
709 if (!file) {
710 perror(oname);
711 return -3;
714 len = fwrite(outbuf, 1, length+0x1030, file);
715 if(len < (size_t)length) {
716 perror(oname);
717 return -4;
720 fclose(file);
721 return 0;
725 /* Create an ipod firmware partition image
727 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
729 This function doesn't yet handle the Broadcom resource image for the 5g,
730 so the resulting images won't be usable.
732 This has also only been tested on an ipod Photo
735 static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
737 static const char *apple_stop_sign = "{{~~ /-----\\ "\
738 "{{~~ / \\ "\
739 "{{~~| | "\
740 "{{~~| S T O P | "\
741 "{{~~| | "\
742 "{{~~ \\ / "\
743 "{{~~ \\-----/ "\
744 "Copyright(C) 200"\
745 "1 Apple Computer"\
746 ", Inc.----------"\
747 "----------------"\
748 "----------------"\
749 "----------------"\
750 "----------------"\
751 "----------------"\
752 "---------------";
753 size_t len;
754 int length;
755 int rsrclength;
756 int rsrcoffset;
757 FILE *file;
758 unsigned int sum = 0;
759 unsigned int rsrcsum = 0;
760 unsigned char *outbuf;
761 int bufsize;
762 int i;
764 file = fopen(iname, "rb");
765 if (!file) {
766 perror(iname);
767 return -1;
769 fseek(file,0,SEEK_END);
770 length = ftell(file);
772 fseek(file,0,SEEK_SET);
774 bufsize=(length+0x4600);
775 if (fake_rsrc) {
776 bufsize = (bufsize + 0x400) & ~0x200;
779 outbuf = malloc(bufsize);
781 if ( !outbuf ) {
782 printf("out of memory!\n");
783 return -1;
786 len = fread(outbuf+0x4600, 1, length, file);
787 if(len < (size_t)length) {
788 perror(iname);
789 return -2;
791 fclose(file);
793 /* Calculate checksum for later use in header */
794 for(i = 0x4600; i < 0x4600+length;i++)
795 sum += outbuf[i];
797 /* Clear the header area to zero */
798 memset(outbuf, 0, 0x4600);
800 /* APPLE STOP SIGN */
801 strcpy((char *)outbuf, apple_stop_sign);
803 /* VOLUME HEADER */
804 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
805 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
806 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
807 short2le(fw_ver, &outbuf[0x10a]);
809 /* Firmware Directory - "osos" entry */
810 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
811 int2le(0, &outbuf[0x4208]); /* id */
812 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
813 int2le(length, &outbuf[0x4210]); /* Length of firmware */
814 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
815 int2le(0, &outbuf[0x4218]); /* Entry Offset */
816 int2le(sum, &outbuf[0x421c]); /* Checksum */
817 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
818 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
820 /* "rsrc" entry (if applicable) */
821 if (fake_rsrc) {
822 rsrcoffset=(length+0x4600+0x200) & ~0x200;
823 rsrclength=0x200;
824 rsrcsum=0;
826 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
827 int2le(0, &outbuf[0x4230]); /* id */
828 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
829 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
830 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
831 int2le(0, &outbuf[0x4240]); /* Entry Offset */
832 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
833 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
834 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
837 file = fopen(oname, "wb");
838 if (!file) {
839 perror(oname);
840 return -3;
843 len = fwrite(outbuf, 1, length+0x4600, file);
844 if(len < (size_t)length) {
845 perror(oname);
846 return -4;
849 fclose(file);
851 return 0;
854 #define CCPMP_SIZE 0x500000
855 static int ccpmp_encode(char *iname, char *oname)
857 size_t len;
858 int length;
859 FILE *file;
860 unsigned char *outbuf;
862 file = fopen(iname, "rb");
863 if (!file) {
864 perror(iname);
865 return -1;
867 fseek(file,0,SEEK_END);
868 length = ftell(file);
870 fseek(file,0,SEEK_SET);
872 outbuf = malloc(CCPMP_SIZE);
874 if ( !outbuf ) {
875 printf("out of memory!\n");
876 return -1;
879 len = fread(outbuf, 1, length, file);
880 if(len < (size_t)length) {
881 perror(iname);
882 return -2;
884 fclose(file);
886 /* Clear the tail area to 0xFF */
887 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
889 /* Header */
890 int2le(length, &outbuf[0x4]);
892 file = fopen(oname, "wb");
893 if (!file) {
894 perror(oname);
895 return -3;
898 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
899 if(len < (size_t)length) {
900 perror(oname);
901 return -4;
904 fclose(file);
906 return 0;