A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita
audio
rust
zig
deno
mpris
rockbox
mpd
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 - 2007 by Björn Stenberg
11 *
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.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21
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"
33#include "rkw.h"
34
35static int iaudio_encode(char *iname, char *oname, char *idstring);
36static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc);
37static int ccpmp_encode(char *iname, char *oname);
38
39void short2le(unsigned short val, unsigned char* addr)
40{
41 addr[0] = val & 0xFF;
42 addr[1] = (val >> 8) & 0xff;
43}
44
45unsigned int le2int(unsigned char* buf)
46{
47 unsigned int res = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
48
49 return res;
50}
51
52void int2le(unsigned int val, unsigned char* addr)
53{
54 addr[0] = val & 0xFF;
55 addr[1] = (val >> 8) & 0xff;
56 addr[2] = (val >> 16) & 0xff;
57 addr[3] = (val >> 24) & 0xff;
58}
59
60void int2be(unsigned int val, unsigned char* addr)
61{
62 addr[0] = (val >> 24) & 0xff;
63 addr[1] = (val >> 16) & 0xff;
64 addr[2] = (val >> 8) & 0xff;
65 addr[3] = val & 0xFF;
66}
67
68void short2be(unsigned short val, unsigned char* addr)
69{
70 addr[0] = (val >> 8) & 0xff;
71 addr[1] = val & 0xFF;
72}
73
74void usage(void)
75{
76 printf("usage: scramble [options] <input file> <output file>\n");
77 printf("options:\n"
78 "\t-neo SSI Neo format\n"
79 "\t-iriver iRiver format\n"
80 "\t-iaudiox5 iAudio X5 format\n"
81 "\t-iaudiox5v iAudio X5V format\n"
82 "\t-iaudiom5 iAudio M5 format\n"
83 "\t-iaudiom3 iAudio M3 format\n");
84 printf("\t-ipod3g ipod firmware partition format (3rd Gen)\n"
85 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
86 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
87 "\t-creative=X [-no-ciff] Creative firmware structure format\n"
88 "\t (X values: zvm, zvm60, zenvision, zenv, zen,\n"
89 "\t zenxfi, zenmozaic)\n");
90 printf("\t-gigabeat Toshiba Gigabeat F/X format\n"
91 "\t-gigabeats Toshiba Gigabeat S format\n"
92 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
93 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
94 "\t-mi4r Sandisk Rhapsody .mi4 format\n"
95 "\t All mi4 options take two optional arguments:\n");
96 printf("\t -model=XXXX where XXXX is the model id string\n"
97 "\t -type=XXXX where XXXX is a string indicating the \n"
98 "\t type of binary, eg. RBOS, RBBL\n"
99 "\t-tcc=X Telechips generic firmware format (X values: sum, crc)\n"
100 "\t-rkw Rockchip RKW format\n"
101 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
102 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd, mn2g\n"
103 "\t ip3g, ip4g, mini, iax5, iam5, iam3, h10, h10_5gb,\n");
104 printf("\t tpj2, c200, e200, giga, gigs, m100, m500, d2,\n"
105 "\t 9200, 1630, 6330, ldax, m200, c100, clip, e2v2,\n"
106 "\t m2v4, fuze, c2v2, clv2, y820, y920, y925, x747,\n"
107 "\t 747p, x777, nn2g, m244, cli+, fuz2, hd20, hd30,\n"
108 "\t ip6g, rk27, clzp, zxf2, zxf3, fuz+, e370, e360,\n"
109 "\t zxfi, zmoz, zen, zenv, zxfs, e450, e460,\n"
110 "\t e470, e580, a10, a20, a860, s750, e350, xdx3,\n"
111 "\t nn3g, nn4g)\n");
112 printf("\nNo option results in nothing being done.\n");
113
114 exit(1);
115}
116
117int main (int argc, char** argv)
118{
119 unsigned long length,i;
120 unsigned char *inbuf,*outbuf;
121 unsigned short crc=0;
122 unsigned long chksum=0; /* 32 bit checksum */
123 unsigned char header[24];
124 char *iname = argv[1];
125 char *oname = argv[2];
126 int headerlen = 6;
127 FILE* file;
128 int version=0;
129 unsigned long modelnum;
130 char modelname[5];
131 enum { none, tcc_sum, tcc_crc, rkw, add } method = none;
132 bool creative_enable_ciff;
133
134 if (argc < 3) {
135 usage();
136 }
137
138 else if(!strcmp(argv[1], "-neo")) {
139 headerlen = 17;
140 iname = argv[2];
141 oname = argv[3];
142 method = none;
143 }
144 else if(!strncmp(argv[1], "-tcc=", 4)) {
145 headerlen = 0;
146 iname = argv[2];
147 oname = argv[3];
148
149 if(!strcmp(&argv[1][5], "sum"))
150 method = tcc_sum;
151 else if(!strcmp(&argv[1][5], "crc"))
152 method = tcc_crc;
153 else {
154 fprintf(stderr, "unsupported TCC method: %s\n", &argv[1][5]);
155 return 2;
156 }
157 }
158 else if(!strncmp(argv[1], "-rkw", 4)) {
159 iname = argv[3];
160 oname = argv[4];
161 modelnum = 0;
162
163 if(!strncmp(argv[2], "-modelnum=", 10)) {
164 modelnum = atoi(&argv[2][10]);
165 }
166
167 if (!modelnum)
168 {
169 modelnum = 73; /* rk27generic */
170 fprintf(stderr, "modelnum not supplied."
171 " using default value for rk27generic target\n");
172 }
173
174 return (rkw_encode(iname, oname, modelnum) != 0) ? -1 : 0;
175 }
176 else if(!strncmp(argv[1], "-add=", 5)) {
177 iname = argv[2];
178 oname = argv[3];
179 method = add;
180
181 if(!strcmp(&argv[1][5], "h120"))
182 modelnum = 0;
183 else if(!strcmp(&argv[1][5], "h140"))
184 modelnum = 0; /* the same as the h120 */
185 else if(!strcmp(&argv[1][5], "h100"))
186 modelnum = 1;
187 else if(!strcmp(&argv[1][5], "h300"))
188 modelnum = 2;
189 else if(!strcmp(&argv[1][5], "ipco"))
190 modelnum = 3;
191 else if(!strcmp(&argv[1][5], "nano"))
192 modelnum = 4;
193 else if(!strcmp(&argv[1][5], "ipvd"))
194 modelnum = 5;
195 else if(!strcmp(&argv[1][5], "fp7x"))
196 modelnum = 6;
197 else if(!strcmp(&argv[1][5], "ip3g"))
198 modelnum = 7;
199 else if(!strcmp(&argv[1][5], "ip4g"))
200 modelnum = 8;
201 else if(!strcmp(&argv[1][5], "mini"))
202 modelnum = 9;
203 else if(!strcmp(&argv[1][5], "iax5"))
204 modelnum = 10;
205 else if(!strcmp(&argv[1][5], "mn2g"))
206 modelnum = 11;
207 else if(!strcmp(&argv[1][5], "h10"))
208 modelnum = 13;
209 else if(!strcmp(&argv[1][5], "h10_5gb"))
210 modelnum = 14;
211 else if(!strcmp(&argv[1][5], "tpj2"))
212 modelnum = 15;
213 else if(!strcmp(&argv[1][5], "e200"))
214 modelnum = 16;
215 else if(!strcmp(&argv[1][5], "iam5"))
216 modelnum = 17;
217 else if(!strcmp(&argv[1][5], "giga"))
218 modelnum = 18;
219 else if(!strcmp(&argv[1][5], "1g2g"))
220 modelnum = 19;
221 else if(!strcmp(&argv[1][5], "c200"))
222 modelnum = 20;
223 else if(!strcmp(&argv[1][5], "gigs"))
224 modelnum = 21;
225 else if(!strcmp(&argv[1][5], "m500"))
226 modelnum = 22;
227 else if(!strcmp(&argv[1][5], "m100"))
228 modelnum = 23;
229 else if(!strcmp(&argv[1][5], "d2"))
230 modelnum = 24;
231 else if(!strcmp(&argv[1][5], "iam3"))
232 modelnum = 25;
233 else if (!strcmp(&argv[1][5], "m200"))
234 modelnum = 29;
235 else if(!strcmp(&argv[1][5], "c100"))
236 modelnum = 30;
237 else if(!strcmp(&argv[1][5], "1630")) /* Philips HDD1630 */
238 modelnum = 31;
239 else if (!strcmp(&argv[1][5], "i7"))
240 modelnum = 32;
241 else if (!strcmp(&argv[1][5], "ldax"))
242 modelnum = 33;
243 else if(!strcmp(&argv[1][5], "9200")) /* Philips SA9200 */
244 modelnum = 34;
245 else if (!strcmp(&argv[1][5], "clip"))
246 modelnum = 40;
247 else if (!strcmp(&argv[1][5], "e2v2"))
248 modelnum = 41;
249 else if (!strcmp(&argv[1][5], "m2v4"))
250 modelnum = 42;
251 else if (!strcmp(&argv[1][5], "fuze"))
252 modelnum = 43;
253 else if (!strcmp(&argv[1][5], "c2v2"))
254 modelnum = 44;
255 else if (!strcmp(&argv[1][5], "x747"))
256 modelnum = 45;
257 else if (!strcmp(&argv[1][5], "747p"))
258 modelnum = 54;
259 else if (!strcmp(&argv[1][5], "y820")) /* Samsung YH-820 */
260 modelnum = 57;
261 else if (!strcmp(&argv[1][5], "y920")) /* Samsung YH-920 */
262 modelnum = 58;
263 else if (!strcmp(&argv[1][5], "y925")) /* Samsung YH-925 */
264 modelnum = 59;
265 else if (!strcmp(&argv[1][5], "clv2")) /* Sansa Clipv2 */
266 modelnum = 60;
267 else if (!strcmp(&argv[1][5], "x777"))
268 modelnum = 61;
269 else if (!strcmp(&argv[1][5], "nn2g")) /* iPod Nano 2nd Gen */
270 modelnum = 62;
271 else if (!strcmp(&argv[1][5], "x767"))
272 modelnum = 64;
273 else if (!strcmp(&argv[1][5], "6330")) /* Philips HDD6330 */
274 modelnum = 65;
275 else if (!strcmp(&argv[1][5], "cli+")) /* Sansa Clip+ */
276 modelnum = 66;
277 else if (!strcmp(&argv[1][5], "v500")) /* Packard Bell Vibe 500 */
278 modelnum = 67;
279 else if (!strcmp(&argv[1][5], "fuz2")) /* Sansa Fuze v2 */
280 modelnum = 68;
281 else if (!strcmp(&argv[1][5], "m244"))
282 modelnum = 131;
283 else if (!strcmp(&argv[1][5], "hd20")) /* MPIO HD200 */
284 modelnum = 69;
285 else if (!strcmp(&argv[1][5], "hd30")) /* MPIO HD300 */
286 modelnum = 70;
287 else if (!strcmp(&argv[1][5], "ip6g")) /* iPod Classic/6G */
288 modelnum = 71;
289 else if (!strcmp(&argv[1][5], "fuz+")) /* Sansa Fuze+ */
290 modelnum = 72;
291 else if (!strcmp(&argv[1][5], "clzp")) /* Sansa Clip Zip */
292 modelnum = 79;
293 else if (!strcmp(&argv[1][5], "conn")) /* Sansa Connect */
294 modelnum = 81;
295 else if (!strcmp(&argv[1][5], "zxf2")) /* Creative Zen X-Fi2 */
296 modelnum = 82;
297 else if (!strcmp(&argv[1][5], "zxf3")) /* Creative Zen X-Fi3 */
298 modelnum = 83;
299 else if (!strcmp(&argv[1][5], "zenv")) /* Creative Zen V */
300 modelnum = 85;
301 else if (!strcmp(&argv[1][5], "zxfi")) /* Creative ZEN X-Fi */
302 modelnum = 86;
303 else if (!strcmp(&argv[1][5], "zmoz")) /* Creative ZEN Mozaic*/
304 modelnum = 87;
305 else if (!strcmp(&argv[1][5], "e370")) /* Sony NWZ-E370 series */
306 modelnum = 88;
307 else if (!strcmp(&argv[1][5], "e360")) /* Sony NWZ-E360 series */
308 modelnum = 89;
309 else if (!strcmp(&argv[1][5], "zen")) /* Creative ZEN */
310 modelnum = 90;
311 else if (!strcmp(&argv[1][5], "zxfs")) /* Creative ZEN X-Fi Style */
312 modelnum = 94;
313 else if (!strcmp(&argv[1][5], "xdx3")) /* xDuoo X3 */
314 modelnum = 96;
315 else if (!strcmp(&argv[1][5], "e450")) /* Sony NWZ-E450 series */
316 modelnum = 100;
317 else if (!strcmp(&argv[1][5], "e460")) /* Sony NWZ-E460 series */
318 modelnum = 101;
319 else if (!strcmp(&argv[1][5], "e580")) /* Sony NWZ-E580 series */
320 modelnum = 102;
321 else if (!strcmp(&argv[1][5], "e470")) /* Sony NWZ-E470 series */
322 modelnum = 103;
323 else if (!strcmp(&argv[1][5], "a10")) /* Sony NWZ-A10 series */
324 modelnum = 104;
325 else if (!strcmp(&argv[1][5], "a20")) /* Sony NW-A20 series */
326 modelnum = 106;
327 else if (!strcmp(&argv[1][5], "a860")) /* Sony NWZ-A860 series */
328 modelnum = 107;
329 else if (!strcmp(&argv[1][5], "s750")) /* Sony NWZ-S750 series */
330 modelnum = 108;
331 else if (!strcmp(&argv[1][5], "e350")) /* Sony NWZ-E350 series */
332 modelnum = 109;
333 else if (!strcmp(&argv[1][5], "fiiom3k")) /* FiiO M3K */
334 modelnum = 114;
335 else if (!strcmp(&argv[1][5], "shq1")) /* Shanling Q1 */
336 modelnum = 115;
337 else if (!strcmp(&argv[1][5], "erosqnative")) /* Aigo Eros Q Native */
338 modelnum = 116;
339 else if (!strcmp(&argv[1][5], "nn3g")) /* iPod Nano 3rd Gen */
340 modelnum = 117;
341 else if (!strcmp(&argv[1][5], "nn4g")) /* iPod Nano 4th Gen */
342 modelnum = 118;
343 else {
344 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
345 return 2;
346 }
347 /* we store a 4-letter model name too, for humans */
348 strncpy(modelname, &argv[1][5],4);
349 modelname[4] = '\0'; /* to be sure we are null terminated */
350 chksum = modelnum; /* start checksum calcs with this */
351 }
352
353 else if(!strcmp(argv[1], "-iriver")) {
354 /* iRiver code dealt with in the iriver.c code */
355 iname = argv[2];
356 oname = argv[3];
357 return (iriver_encode(iname, oname, FALSE) != 0) ? -1 : 0;
358 }
359 else if(!strcmp(argv[1], "-gigabeat")) {
360 /* iRiver code dealt with in the iriver.c code */
361 iname = argv[2];
362 oname = argv[3];
363 gigabeat_code(iname, oname);
364 return 0;
365 }
366 else if(!strcmp(argv[1], "-gigabeats")) {
367 iname = argv[2];
368 oname = argv[3];
369 return gigabeat_s_code(iname, oname);
370 }
371 else if(!strcmp(argv[1], "-iaudiox5")) {
372 iname = argv[2];
373 oname = argv[3];
374 return iaudio_encode(iname, oname, "COWON_X5_FW");
375 }
376 else if(!strcmp(argv[1], "-iaudiox5v")) {
377 iname = argv[2];
378 oname = argv[3];
379 return iaudio_encode(iname, oname, "COWON_X5V_FW");
380 }
381 else if(!strcmp(argv[1], "-iaudiom5")) {
382 iname = argv[2];
383 oname = argv[3];
384 return iaudio_encode(iname, oname, "COWON_M5_FW");
385 }
386 else if(!strcmp(argv[1], "-iaudiom3")) {
387 iname = argv[2];
388 oname = argv[3];
389 return iaudio_encode(iname, oname, "COWON_M3_FW");
390 }
391 else if(!strcmp(argv[1], "-ipod3g")) {
392 iname = argv[2];
393 oname = argv[3];
394 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
395 }
396 else if(!strcmp(argv[1], "-ipod4g")) {
397 iname = argv[2];
398 oname = argv[3];
399 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
400 }
401 else if(!strcmp(argv[1], "-ipod5g")) {
402 iname = argv[2];
403 oname = argv[3];
404 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
405 }
406 else if(!strncmp(argv[1], "-creative=", 10)) {
407 if(!strcmp(argv[2], "-no-ciff"))
408 {
409 creative_enable_ciff = false;
410 iname = argv[3];
411 oname = argv[4];
412 }
413 else
414 {
415 creative_enable_ciff = true;
416 iname = argv[2];
417 oname = argv[3];
418 }
419 if(!strcmp(&argv[1][10], "zvm"))
420 return zvm_encode(iname, oname, ZENVISIONM, creative_enable_ciff);
421 else if(!strcmp(&argv[1][10], "zvm60"))
422 return zvm_encode(iname, oname, ZENVISIONM60, creative_enable_ciff);
423 else if(!strcmp(&argv[1][10], "zenvision"))
424 return zvm_encode(iname, oname, ZENVISION, creative_enable_ciff);
425 else if(!strcmp(&argv[1][10], "zenv"))
426 return zvm_encode(iname, oname, ZENV, creative_enable_ciff);
427 else if(!strcmp(&argv[1][10], "zen"))
428 return zvm_encode(iname, oname, ZEN, creative_enable_ciff);
429 else if(!strcmp(&argv[1][10], "zenxfi"))
430 return zvm_encode(iname, oname, ZENXFI, creative_enable_ciff);
431 else if(!strcmp(&argv[1][10], "zenmozaic"))
432 return zvm_encode(iname, oname, ZENMOZAIC, creative_enable_ciff);
433 else
434 {
435 fprintf(stderr, "unsupported Creative device: %s\n", &argv[1][10]);
436 return 2;
437 }
438 }
439 else if(!strcmp(argv[1], "-ccpmp")) {
440 iname = argv[2];
441 oname = argv[3];
442 return ccpmp_encode(iname, oname);
443 }
444 else if(!strncmp(argv[1], "-mi4", 4)) {
445 int mi4magic;
446 char model[4] = "";
447 char type[4] = "";
448
449 if(!strcmp(&argv[1][4], "v2")) {
450 mi4magic = MI4_MAGIC_DEFAULT;
451 version = 0x00010201;
452 }
453 else if(!strcmp(&argv[1][4], "v3")) {
454 mi4magic = MI4_MAGIC_DEFAULT;
455 version = 0x00010301;
456 }
457 else if(!strcmp(&argv[1][4], "r")) {
458 mi4magic = MI4_MAGIC_R;
459 version = 0x00010301;
460 }
461 else {
462 printf( "Invalid mi4 version: %s\n", &argv[1][4]);
463 return -1;
464 }
465
466 iname = argv[2];
467 oname = argv[3];
468
469 if(!strncmp(argv[2], "-model=", 7)) {
470 iname = argv[3];
471 oname = argv[4];
472 strncpy(model, &argv[2][7], 4);
473
474 if(!strncmp(argv[3], "-type=", 6)) {
475 iname = argv[4];
476 oname = argv[5];
477 strncpy(type, &argv[3][6], 4);
478 }
479 }
480
481 return mi4_encode(iname, oname, version, mi4magic, model, type);
482 }
483
484 /* open file */
485 file = fopen(iname,"rb");
486 if (!file) {
487 perror(iname);
488 return -1;
489 }
490 fseek(file,0,SEEK_END);
491 length = ftell(file);
492 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
493
494
495 fseek(file,0,SEEK_SET);
496 inbuf = malloc(length);
497 if(method == add)
498 outbuf = malloc(length + 8);
499 else
500 outbuf = malloc(length);
501 if ( !inbuf || !outbuf ) {
502 printf("out of memory!\n");
503 return -1;
504 }
505 if(length> 4) {
506 /* zero-fill the last 4 bytes to make sure there's no rubbish there
507 when we write the size-aligned file later */
508 memset(outbuf+length-4, 0, 4);
509 }
510
511 /* read file */
512 i=fread(inbuf,1,length,file);
513 if ( !i ) {
514 perror(iname);
515 return -1;
516 }
517 fclose(file);
518
519 switch (method)
520 {
521 case add:
522 for (i = 0; i < length; i++) {
523 /* add 8 unsigned bits but keep a 32 bit sum */
524 chksum += inbuf[i];
525 }
526 break;
527 case none:
528 default:
529 /* dummy case just to silence picky compilers */
530 break;
531 }
532
533 if(method == none) {
534 /* calculate checksum */
535 for (i=0;i<length;i++)
536 crc += inbuf[i];
537 }
538
539 memset(header, 0, sizeof header);
540 switch (method)
541 {
542 case add:
543 {
544 int2be(chksum, header); /* checksum, big-endian */
545 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
546 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
547 headerlen = 8;
548 }
549 break;
550
551 case tcc_sum:
552 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
553 telechips_encode_sum(outbuf, length);
554 break;
555
556 case tcc_crc:
557 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
558 telechips_encode_crc(outbuf, length);
559 break;
560
561#define MY_FIRMWARE_TYPE "Rockbox"
562#define MY_HEADER_VERSION 1
563 default:
564 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
565 header[9]='\0'; /*shouldn't have to, but to be SURE */
566 header[10]=MY_HEADER_VERSION&0xFF;
567 header[11]=(crc>>8)&0xFF;
568 header[12]=crc&0xFF;
569 int2be(sizeof(header), &header[12]);
570 break;
571 }
572
573 /* write file */
574 file = fopen(oname,"wb");
575 if ( !file ) {
576 perror(oname);
577 return -1;
578 }
579 if (headerlen > 0) {
580 if ( !fwrite(header,headerlen,1,file) ) {
581 perror(oname);
582 return -1;
583 }
584 }
585 if ( !fwrite(outbuf,length,1,file) ) {
586 perror(oname);
587 return -1;
588 }
589 fclose(file);
590
591 free(inbuf);
592 free(outbuf);
593
594 return 0;
595}
596
597static int iaudio_encode(char *iname, char *oname, char *idstring)
598{
599 size_t len;
600 int length;
601 FILE *file;
602 unsigned char *outbuf;
603 int i;
604 unsigned char sum = 0;
605
606 file = fopen(iname, "rb");
607 if (!file) {
608 perror(iname);
609 return -1;
610 }
611 fseek(file,0,SEEK_END);
612 length = ftell(file);
613
614 fseek(file,0,SEEK_SET);
615 outbuf = malloc(length+0x1030);
616
617 if ( !outbuf ) {
618 printf("out of memory!\n");
619 return -1;
620 }
621
622 len = fread(outbuf+0x1030, 1, length, file);
623 if(len < (size_t) length) {
624 perror(iname);
625 return -2;
626 }
627
628 memset(outbuf, 0, 0x1030);
629 strcpy((char *)outbuf, idstring);
630 memcpy(outbuf+0x20, iaudio_bl_flash,
631 BMPWIDTH_iaudio_bl_flash * (BMPHEIGHT_iaudio_bl_flash/8) * 2);
632 short2be(BMPWIDTH_iaudio_bl_flash, &outbuf[0x10]);
633 short2be((BMPHEIGHT_iaudio_bl_flash/8), &outbuf[0x12]);
634 outbuf[0x19] = 2;
635
636 for(i = 0; i < length;i++)
637 sum += outbuf[0x1030 + i];
638
639 int2be(length, &outbuf[0x1024]);
640 outbuf[0x102b] = sum;
641
642 fclose(file);
643
644 file = fopen(oname, "wb");
645 if (!file) {
646 perror(oname);
647 return -3;
648 }
649
650 len = fwrite(outbuf, 1, length+0x1030, file);
651 if(len < (size_t)length) {
652 perror(oname);
653 return -4;
654 }
655
656 fclose(file);
657 return 0;
658}
659
660
661/* Create an ipod firmware partition image
662
663 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
664
665 This function doesn't yet handle the Broadcom resource image for the 5g,
666 so the resulting images won't be usable.
667
668 This has also only been tested on an ipod Photo
669*/
670
671static int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
672{
673 static const char apple_stop_sign[] = "{{~~ /-----\\ "\
674 "{{~~ / \\ "\
675 "{{~~| | "\
676 "{{~~| S T O P | "\
677 "{{~~| | "\
678 "{{~~ \\ / "\
679 "{{~~ \\-----/ "\
680 "Copyright(C) 200"\
681 "1 Apple Computer"\
682 ", Inc.----------"\
683 "----------------"\
684 "----------------"\
685 "----------------"\
686 "----------------"\
687 "----------------"\
688 "---------------";
689 size_t len;
690 int length;
691 int rsrclength;
692 int rsrcoffset;
693 FILE *file;
694 unsigned int sum = 0;
695 unsigned int rsrcsum = 0;
696 unsigned char *outbuf;
697 int bufsize;
698 int i;
699
700 file = fopen(iname, "rb");
701 if (!file) {
702 perror(iname);
703 return -1;
704 }
705 fseek(file,0,SEEK_END);
706 length = ftell(file);
707
708 fseek(file,0,SEEK_SET);
709
710 bufsize=(length+0x4600);
711 if (fake_rsrc) {
712 bufsize = (bufsize + 0x400) & ~0x200;
713 }
714
715 outbuf = malloc(bufsize);
716
717 if ( !outbuf ) {
718 printf("out of memory!\n");
719 return -1;
720 }
721
722 len = fread(outbuf+0x4600, 1, length, file);
723 if(len < (size_t)length) {
724 perror(iname);
725 return -2;
726 }
727 fclose(file);
728
729 /* Calculate checksum for later use in header */
730 for(i = 0x4600; i < 0x4600+length;i++)
731 sum += outbuf[i];
732
733 /* Clear the header area to zero */
734 memset(outbuf, 0, 0x4600);
735
736 /* APPLE STOP SIGN */
737 strcpy((char *)outbuf, apple_stop_sign);
738
739 /* VOLUME HEADER */
740 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
741 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
742 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
743 short2le(fw_ver, &outbuf[0x10a]);
744
745 /* Firmware Directory - "osos" entry */
746 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
747 int2le(0, &outbuf[0x4208]); /* id */
748 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
749 int2le(length, &outbuf[0x4210]); /* Length of firmware */
750 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
751 int2le(0, &outbuf[0x4218]); /* Entry Offset */
752 int2le(sum, &outbuf[0x421c]); /* Checksum */
753 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
754 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
755
756 /* "rsrc" entry (if applicable) */
757 if (fake_rsrc) {
758 rsrcoffset=(length+0x4600+0x200) & ~0x200;
759 rsrclength=0x200;
760 rsrcsum=0;
761
762 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
763 int2le(0, &outbuf[0x4230]); /* id */
764 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
765 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
766 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
767 int2le(0, &outbuf[0x4240]); /* Entry Offset */
768 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
769 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
770 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
771 }
772
773 file = fopen(oname, "wb");
774 if (!file) {
775 perror(oname);
776 return -3;
777 }
778
779 len = fwrite(outbuf, 1, length+0x4600, file);
780 if(len < (size_t)length) {
781 perror(oname);
782 return -4;
783 }
784
785 fclose(file);
786
787 return 0;
788}
789
790#define CCPMP_SIZE 0x500000
791static int ccpmp_encode(char *iname, char *oname)
792{
793 size_t len;
794 int length;
795 FILE *file;
796 unsigned char *outbuf;
797
798 file = fopen(iname, "rb");
799 if (!file) {
800 perror(iname);
801 return -1;
802 }
803 fseek(file,0,SEEK_END);
804 length = ftell(file);
805
806 fseek(file,0,SEEK_SET);
807
808 outbuf = malloc(CCPMP_SIZE);
809
810 if ( !outbuf ) {
811 printf("out of memory!\n");
812 return -1;
813 }
814
815 len = fread(outbuf, 1, length, file);
816 if(len < (size_t)length) {
817 perror(iname);
818 return -2;
819 }
820 fclose(file);
821
822 /* Clear the tail area to 0xFF */
823 memset(&outbuf[length], 0xFF, CCPMP_SIZE - length);
824
825 /* Header */
826 int2le(length, &outbuf[0x4]);
827
828 file = fopen(oname, "wb");
829 if (!file) {
830 perror(oname);
831 return -3;
832 }
833
834 len = fwrite(outbuf, 1, CCPMP_SIZE, file);
835 if(len < (size_t)length) {
836 perror(oname);
837 return -4;
838 }
839
840 fclose(file);
841
842 return 0;
843}
844