blob: d1e3d1d3412fcbb706871a96e35c92902f9317b9 [file] [log] [blame]
Björn Stenberge1715c22002-03-28 14:34:13 +00001/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2002 by Björn Stenberg
11 *
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
14 *
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
17 *
18 ****************************************************************************/
19
20#include <stdio.h>
21#include <stdlib.h>
Dave Chapman3ba16cb2006-07-22 13:21:50 +000022#include <stdbool.h>
Daniel Stenberg362259a2005-11-14 18:58:30 +000023#include <string.h>
Daniel Stenbergadaae242005-01-24 09:01:48 +000024#include "iriver.h"
Dave Chapman530f31d2006-08-30 23:17:04 +000025#include "mi4.h"
Daniel Stenbergadaae242005-01-24 09:01:48 +000026
Linus Nielsen Feltzingd5697272006-03-27 08:31:34 +000027int iaudio_encode(char *iname, char *oname, char *idstring);
Dave Chapman3ba16cb2006-07-22 13:21:50 +000028int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc);
Linus Nielsen Feltzing074999d2005-12-27 23:14:49 +000029
Linus Nielsen Feltzing7b86bad2005-09-14 07:48:45 +000030enum
31{
Linus Nielsen Feltzing56fa2da2005-09-14 11:15:59 +000032 ARCHOS_PLAYER, /* and V1 recorder */
Linus Nielsen Feltzing7b86bad2005-09-14 07:48:45 +000033 ARCHOS_V2RECORDER,
34 ARCHOS_FMRECORDER,
35 ARCHOS_ONDIO_SP,
36 ARCHOS_ONDIO_FM
37};
38
39int size_limit[] =
40{
41 0x32000, /* ARCHOS_PLAYER */
Linus Nielsen Feltzing7b86bad2005-09-14 07:48:45 +000042 0x64000, /* ARCHOS_V2RECORDER */
43 0x64000, /* ARCHOS_FMRECORDER */
44 0x64000, /* ARCHOS_ONDIO_SP */
45 0x64000 /* ARCHOS_ONDIO_FM */
46};
47
Dave Chapmanc52ae7a2006-07-21 16:16:48 +000048void short2le(unsigned short val, unsigned char* addr)
49{
50 addr[0] = val & 0xFF;
51 addr[1] = (val >> 8) & 0xff;
52}
53
Björn Stenberg123ae832004-01-08 21:34:52 +000054void int2le(unsigned int val, unsigned char* addr)
55{
56 addr[0] = val & 0xFF;
57 addr[1] = (val >> 8) & 0xff;
58 addr[2] = (val >> 16) & 0xff;
59 addr[3] = (val >> 24) & 0xff;
60}
61
62void int2be(unsigned int val, unsigned char* addr)
63{
64 addr[0] = (val >> 24) & 0xff;
65 addr[1] = (val >> 16) & 0xff;
66 addr[2] = (val >> 8) & 0xff;
67 addr[3] = val & 0xFF;
68}
69
Daniel Stenbergadaae242005-01-24 09:01:48 +000070void usage(void)
71{
72 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
73 printf("options:\n"
74 "\t-fm Archos FM recorder format\n"
75 "\t-v2 Archos V2 recorder format\n"
76 "\t-ofm Archos Ondio FM recorder format\n"
77 "\t-osp Archos Ondio SP format\n"
78 "\t-neo SSI Neo format\n"
79 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
80 "\t-iriver iRiver format\n"
Linus Nielsen Feltzingd5697272006-03-27 08:31:34 +000081 "\t-iaudiox5 iAudio X5 format\n"
82 "\t-iaudiox5v iAudio X5V format\n"
Dave Chapman3ba16cb2006-07-22 13:21:50 +000083 "\t-ipod3g ipod firmware partition format (3rd Gen)\n"
84 "\t-ipod4g ipod firmware partition format (4th Gen, Mini, Nano, Photo/Color)\n"
85 "\t-ipod5g ipod firmware partition format (5th Gen - aka Video)\n"
Dave Chapman530f31d2006-08-30 23:17:04 +000086 "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n"
87 "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n"
Dave Chapman33cc6de2005-11-07 22:20:55 +000088 "\t-add=X Rockbox generic \"add-up\" checksum format\n"
Dave Chapman0d100312006-02-05 18:30:50 +000089 "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd\n"
Barry Wardell1920df32006-08-28 08:11:32 +000090 "\t ip3g, ip4g, mini, x5, h10, h10_5gb)\n"
Daniel Stenbergadaae242005-01-24 09:01:48 +000091 "\nNo option results in Archos standard player/recorder format.\n");
92
93 exit(1);
94}
95
Björn Stenberge1715c22002-03-28 14:34:13 +000096int main (int argc, char** argv)
97{
98 unsigned long length,i,slen;
99 unsigned char *inbuf,*outbuf;
100 unsigned short crc=0;
Linus Nielsen Feltzingddd15512005-01-28 10:28:34 +0000101 unsigned long chksum=0; /* 32 bit checksum */
Björn Stenberg323f2972002-12-19 15:00:40 +0000102 unsigned char header[24];
Daniel Stenberg362259a2005-11-14 18:58:30 +0000103 char *iname = argv[1];
104 char *oname = argv[2];
105 char *xorstring;
Björn Stenberg323f2972002-12-19 15:00:40 +0000106 int headerlen = 6;
Björn Stenberge1715c22002-03-28 14:34:13 +0000107 FILE* file;
Linus Nielsen Feltzinged11bd32003-10-27 18:04:28 +0000108 int version;
Dave Chapman33cc6de2005-11-07 22:20:55 +0000109 unsigned long modelnum;
110 char modelname[5];
Linus Nielsen Feltzing7b86bad2005-09-14 07:48:45 +0000111 int model_id;
Daniel Stenbergbf355b72005-01-24 13:14:14 +0000112 enum { none, scramble, xor, add } method = scramble;
Björn Stenberge1715c22002-03-28 14:34:13 +0000113
Linus Nielsen Feltzing7b86bad2005-09-14 07:48:45 +0000114 model_id = ARCHOS_PLAYER;
115
Björn Stenberge1715c22002-03-28 14:34:13 +0000116 if (argc < 3) {
Daniel Stenbergadaae242005-01-24 09:01:48 +0000117 usage();
Björn Stenberge1715c22002-03-28 14:34:13 +0000118 }
Björn Stenberg323f2972002-12-19 15:00:40 +0000119
Linus Nielsen Feltzinged11bd32003-10-27 18:04:28 +0000120 if(!strcmp(argv[1], "-fm")) {
Björn Stenberg323f2972002-12-19 15:00:40 +0000121 headerlen = 24;
122 iname = argv[2];
123 oname = argv[3];
Linus Nielsen Feltzinged11bd32003-10-27 18:04:28 +0000124 version = 4;
Linus Nielsen Feltzing7b86bad2005-09-14 07:48:45 +0000125 model_id = ARCHOS_FMRECORDER;
Linus Nielsen Feltzinged11bd32003-10-27 18:04:28 +0000126 }
127
Daniel Stenberg0115af22003-12-12 14:07:28 +0000128 else if(!strcmp(argv[1], "-v2")) {
Linus Nielsen Feltzinged11bd32003-10-27 18:04:28 +0000129 headerlen = 24;
130 iname = argv[2];
131 oname = argv[3];
132 version = 2;
Linus Nielsen Feltzing7b86bad2005-09-14 07:48:45 +0000133 model_id = ARCHOS_V2RECORDER;
Björn Stenberg323f2972002-12-19 15:00:40 +0000134 }
Daniel Stenberg0115af22003-12-12 14:07:28 +0000135
Jörg Hohensohn4f52bf42004-09-08 21:21:22 +0000136 else if(!strcmp(argv[1], "-ofm")) {
137 headerlen = 24;
138 iname = argv[2];
139 oname = argv[3];
140 version = 8;
Linus Nielsen Feltzing7b86bad2005-09-14 07:48:45 +0000141 model_id = ARCHOS_ONDIO_FM;
Jörg Hohensohn4f52bf42004-09-08 21:21:22 +0000142 }
143
144 else if(!strcmp(argv[1], "-osp")) {
145 headerlen = 24;
146 iname = argv[2];
147 oname = argv[3];
148 version = 16;
Linus Nielsen Feltzing7b86bad2005-09-14 07:48:45 +0000149 model_id = ARCHOS_ONDIO_SP;
Jörg Hohensohn4f52bf42004-09-08 21:21:22 +0000150 }
151
Daniel Stenberg0115af22003-12-12 14:07:28 +0000152 else if(!strcmp(argv[1], "-neo")) {
153 headerlen = 17;
154 iname = argv[2];
155 oname = argv[3];
Björn Stenberg123ae832004-01-08 21:34:52 +0000156 method = none;
157 }
158 else if(!strncmp(argv[1], "-mm=", 4)) {
159 headerlen = 16;
160 iname = argv[2];
161 oname = argv[3];
162 method = xor;
163 version = argv[1][4];
164 if (argc > 4)
165 xorstring = argv[4];
166 else {
167 printf("Multimedia needs an xor string\n");
168 return -1;
169 }
Daniel Stenberg0115af22003-12-12 14:07:28 +0000170 }
Daniel Stenbergbf355b72005-01-24 13:14:14 +0000171 else if(!strncmp(argv[1], "-add=", 5)) {
172 iname = argv[2];
173 oname = argv[3];
174 method = add;
175
176 if(!strcmp(&argv[1][5], "h120"))
Dave Chapman33cc6de2005-11-07 22:20:55 +0000177 modelnum = 0;
Daniel Stenbergbf355b72005-01-24 13:14:14 +0000178 else if(!strcmp(&argv[1][5], "h140"))
Dave Chapman33cc6de2005-11-07 22:20:55 +0000179 modelnum = 0; /* the same as the h120 */
Daniel Stenbergbf355b72005-01-24 13:14:14 +0000180 else if(!strcmp(&argv[1][5], "h100"))
Dave Chapman33cc6de2005-11-07 22:20:55 +0000181 modelnum = 1;
Daniel Stenbergbf355b72005-01-24 13:14:14 +0000182 else if(!strcmp(&argv[1][5], "h300"))
Dave Chapman33cc6de2005-11-07 22:20:55 +0000183 modelnum = 2;
184 else if(!strcmp(&argv[1][5], "ipco"))
185 modelnum = 3;
186 else if(!strcmp(&argv[1][5], "nano"))
187 modelnum = 4;
Dave Chapman2a7bd9f2005-12-18 13:04:00 +0000188 else if(!strcmp(&argv[1][5], "ipvd"))
189 modelnum = 5;
Dave Chapmand83e9292006-01-12 00:35:50 +0000190 else if(!strcmp(&argv[1][5], "fp7x"))
191 modelnum = 6;
Dave Chapman0d100312006-02-05 18:30:50 +0000192 else if(!strcmp(&argv[1][5], "ip3g"))
193 modelnum = 7;
194 else if(!strcmp(&argv[1][5], "ip4g"))
195 modelnum = 8;
Dave Chapman8b1297a2006-02-21 15:01:25 +0000196 else if(!strcmp(&argv[1][5], "mini"))
197 modelnum = 9;
Linus Nielsen Feltzing1c1915c2006-03-21 14:40:07 +0000198 else if(!strcmp(&argv[1][5], "iax5"))
199 modelnum = 10;
Jens Arnoldd3feb782006-03-30 17:29:21 +0000200 else if(!strcmp(&argv[1][5], "mn2g"))
201 modelnum = 11;
Barry Wardell1920df32006-08-28 08:11:32 +0000202 else if(!strcmp(&argv[1][5], "h10"))
203 modelnum = 13;
204 else if(!strcmp(&argv[1][5], "h10_5gb"))
205 modelnum = 14;
Daniel Stenbergbf355b72005-01-24 13:14:14 +0000206 else {
207 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
208 return 2;
209 }
210 /* we store a 4-letter model name too, for humans */
Dave Chapman33cc6de2005-11-07 22:20:55 +0000211 strcpy(modelname, &argv[1][5]);
212 chksum = modelnum; /* start checksum calcs with this */
Daniel Stenbergbf355b72005-01-24 13:14:14 +0000213 }
Daniel Stenberg0115af22003-12-12 14:07:28 +0000214
Daniel Stenbergadaae242005-01-24 09:01:48 +0000215 else if(!strcmp(argv[1], "-iriver")) {
216 /* iRiver code dealt with in the iriver.c code */
217 iname = argv[2];
218 oname = argv[3];
219 iriver_encode(iname, oname, FALSE);
220 return 0;
221 }
Linus Nielsen Feltzingd5697272006-03-27 08:31:34 +0000222 else if(!strcmp(argv[1], "-iaudiox5")) {
Linus Nielsen Feltzing074999d2005-12-27 23:14:49 +0000223 iname = argv[2];
224 oname = argv[3];
Linus Nielsen Feltzingd5697272006-03-27 08:31:34 +0000225 return iaudio_encode(iname, oname, "COWON_X5_FW");
226 }
227 else if(!strcmp(argv[1], "-iaudiox5v")) {
228 iname = argv[2];
229 oname = argv[3];
230 return iaudio_encode(iname, oname, "COWON_X5V_FW");
Linus Nielsen Feltzing074999d2005-12-27 23:14:49 +0000231 }
Dave Chapman3ba16cb2006-07-22 13:21:50 +0000232 else if(!strcmp(argv[1], "-ipod3g")) {
Dave Chapmanc52ae7a2006-07-21 16:16:48 +0000233 iname = argv[2];
234 oname = argv[3];
Dave Chapman3ba16cb2006-07-22 13:21:50 +0000235 return ipod_encode(iname, oname, 2, false); /* Firmware image v2 */
236 }
237 else if(!strcmp(argv[1], "-ipod4g")) {
238 iname = argv[2];
239 oname = argv[3];
240 return ipod_encode(iname, oname, 3, false); /* Firmware image v3 */
241 }
242 else if(!strcmp(argv[1], "-ipod5g")) {
243 iname = argv[2];
244 oname = argv[3];
245 return ipod_encode(iname, oname, 3, true); /* Firmware image v3 */
Dave Chapmanc52ae7a2006-07-21 16:16:48 +0000246 }
Dave Chapman530f31d2006-08-30 23:17:04 +0000247 else if(!strcmp(argv[1], "-mi4v2")) {
248 iname = argv[2];
249 oname = argv[3];
250 return mi4_encode(iname, oname, 0x00010201);
251 }
252 else if(!strcmp(argv[1], "-mi4v3")) {
253 iname = argv[2];
254 oname = argv[3];
255 return mi4_encode(iname, oname, 0x00010301);
256 }
Daniel Stenbergadaae242005-01-24 09:01:48 +0000257
Björn Stenberge1715c22002-03-28 14:34:13 +0000258 /* open file */
Björn Stenberg323f2972002-12-19 15:00:40 +0000259 file = fopen(iname,"rb");
Björn Stenberge1715c22002-03-28 14:34:13 +0000260 if (!file) {
Björn Stenberg323f2972002-12-19 15:00:40 +0000261 perror(iname);
Björn Stenberge1715c22002-03-28 14:34:13 +0000262 return -1;
263 }
264 fseek(file,0,SEEK_END);
265 length = ftell(file);
Linus Nielsen Feltzing1326f662003-04-12 21:17:47 +0000266 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
267
Linus Nielsen Feltzing7b86bad2005-09-14 07:48:45 +0000268 if ((method == scramble) &&
269 ((length + headerlen) >= size_limit[model_id])) {
Daniel Stenberg637ab472005-12-06 13:44:01 +0000270 printf("error: firmware image is %d bytes while max size is %d!\n",
271 length + headerlen,
272 size_limit[model_id]);
Linus Nielsen Feltzing6a429972003-04-14 09:59:47 +0000273 fclose(file);
274 return -1;
275 }
Linus Nielsen Feltzing7b86bad2005-09-14 07:48:45 +0000276
Björn Stenberge1715c22002-03-28 14:34:13 +0000277 fseek(file,0,SEEK_SET);
278 inbuf = malloc(length);
Björn Stenberg123ae832004-01-08 21:34:52 +0000279 if (method == xor)
280 outbuf = malloc(length*2);
Daniel Stenbergbf355b72005-01-24 13:14:14 +0000281 else if(method == add)
282 outbuf = malloc(length + 8);
Björn Stenberg123ae832004-01-08 21:34:52 +0000283 else
284 outbuf = malloc(length);
Björn Stenberge1715c22002-03-28 14:34:13 +0000285 if ( !inbuf || !outbuf ) {
286 printf("out of memory!\n");
287 return -1;
288 }
Daniel Stenbergbf355b72005-01-24 13:14:14 +0000289 if(length> 4) {
290 /* zero-fill the last 4 bytes to make sure there's no rubbish there
291 when we write the size-aligned file later */
292 memset(outbuf+length-4, 0, 4);
293 }
Björn Stenberge1715c22002-03-28 14:34:13 +0000294
295 /* read file */
296 i=fread(inbuf,1,length,file);
297 if ( !i ) {
Björn Stenberg323f2972002-12-19 15:00:40 +0000298 perror(iname);
Björn Stenberge1715c22002-03-28 14:34:13 +0000299 return -1;
300 }
301 fclose(file);
302
Björn Stenberg123ae832004-01-08 21:34:52 +0000303 switch (method)
304 {
Daniel Stenbergbf355b72005-01-24 13:14:14 +0000305 case add:
Linus Nielsen Feltzing599b0ff2005-01-28 12:20:20 +0000306 for (i = 0; i < length; i++) {
307 /* add 8 unsigned bits but keep a 32 bit sum */
308 chksum += inbuf[i];
Daniel Stenbergbf355b72005-01-24 13:14:14 +0000309 }
310 break;
Björn Stenberg123ae832004-01-08 21:34:52 +0000311 case scramble:
312 slen = length/4;
313 for (i = 0; i < length; i++) {
314 unsigned long addr = (i >> 2) + ((i % 4) * slen);
315 unsigned char data = inbuf[i];
316 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
317 outbuf[addr] = data;
318 }
319 break;
320
321 case xor:
322 /* "compress" */
323 slen = 0;
324 for (i=0; i<length; i++) {
325 if (!(i&7))
326 outbuf[slen++] = 0xff; /* all data is uncompressed */
327 outbuf[slen++] = inbuf[i];
328 }
329 break;
Björn Stenberge1715c22002-03-28 14:34:13 +0000330 }
Daniel Stenbergbf355b72005-01-24 13:14:14 +0000331
332 if(method != add) {
333 /* calculate checksum */
334 for (i=0;i<length;i++)
335 crc += inbuf[i];
336 }
Björn Stenberge1715c22002-03-28 14:34:13 +0000337
Björn Stenberg323f2972002-12-19 15:00:40 +0000338 memset(header, 0, sizeof header);
Björn Stenberg123ae832004-01-08 21:34:52 +0000339 switch (method)
340 {
Daniel Stenbergbf355b72005-01-24 13:14:14 +0000341 case add:
342 {
Linus Nielsen Feltzingddd15512005-01-28 10:28:34 +0000343 int2be(chksum, header); /* checksum, big-endian */
Dave Chapman33cc6de2005-11-07 22:20:55 +0000344 memcpy(&header[4], modelname, 4); /* 4 bytes model name */
Daniel Stenbergbf355b72005-01-24 13:14:14 +0000345 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
346 headerlen = 8;
347 }
348 break;
Björn Stenberg123ae832004-01-08 21:34:52 +0000349 case scramble:
350 if (headerlen == 6) {
351 int2be(length, header);
352 header[4] = (crc >> 8) & 0xff;
353 header[5] = crc & 0xff;
354 }
355 else {
356 header[0] =
357 header[1] =
358 header[2] =
359 header[3] = 0xff; /* ??? */
360
361 header[6] = (crc >> 8) & 0xff;
362 header[7] = crc & 0xff;
363
364 header[11] = version;
365
366 header[15] = headerlen; /* really? */
367
368 int2be(length, &header[20]);
369 }
370 break;
371
372 case xor:
373 {
374 int xorlen = strlen(xorstring);
375
Björn Stenberg123ae832004-01-08 21:34:52 +0000376 /* xor data */
377 for (i=0; i<slen; i++)
378 outbuf[i] ^= xorstring[i & (xorlen-1)];
Daniel Stenberg0115af22003-12-12 14:07:28 +0000379
Björn Stenberg452702d2004-03-17 23:43:42 +0000380 /* calculate checksum */
381 for (i=0; i<slen; i++)
382 crc += outbuf[i];
383
Björn Stenberg123ae832004-01-08 21:34:52 +0000384 header[0] = header[2] = 'Z';
385 header[1] = header[3] = version;
386 int2le(length, &header[4]);
387 int2le(slen, &header[8]);
388 int2le(crc, &header[12]);
389 length = slen;
390 break;
Daniel Stenberg0115af22003-12-12 14:07:28 +0000391 }
Björn Stenberg123ae832004-01-08 21:34:52 +0000392
Daniel Stenberg0115af22003-12-12 14:07:28 +0000393#define MY_FIRMWARE_TYPE "Rockbox"
394#define MY_HEADER_VERSION 1
Björn Stenberg123ae832004-01-08 21:34:52 +0000395 default:
Daniel Stenberg362259a2005-11-14 18:58:30 +0000396 strncpy((char *)header, MY_FIRMWARE_TYPE,9);
Björn Stenberg123ae832004-01-08 21:34:52 +0000397 header[9]='\0'; /*shouldn't have to, but to be SURE */
398 header[10]=MY_HEADER_VERSION&0xFF;
399 header[11]=(crc>>8)&0xFF;
400 header[12]=crc&0xFF;
401 int2be(sizeof(header), &header[12]);
402 break;
Björn Stenberg323f2972002-12-19 15:00:40 +0000403 }
Björn Stenberge1715c22002-03-28 14:34:13 +0000404
405 /* write file */
Björn Stenberg323f2972002-12-19 15:00:40 +0000406 file = fopen(oname,"wb");
Björn Stenberge1715c22002-03-28 14:34:13 +0000407 if ( !file ) {
Björn Stenberg323f2972002-12-19 15:00:40 +0000408 perror(oname);
Björn Stenberge1715c22002-03-28 14:34:13 +0000409 return -1;
410 }
Björn Stenberg323f2972002-12-19 15:00:40 +0000411 if ( !fwrite(header,headerlen,1,file) ) {
412 perror(oname);
Björn Stenberge1715c22002-03-28 14:34:13 +0000413 return -1;
414 }
415 if ( !fwrite(outbuf,length,1,file) ) {
Björn Stenberg323f2972002-12-19 15:00:40 +0000416 perror(oname);
Björn Stenberge1715c22002-03-28 14:34:13 +0000417 return -1;
418 }
419 fclose(file);
420
421 free(inbuf);
422 free(outbuf);
423
Linus Nielsen Feltzing6a429972003-04-14 09:59:47 +0000424 return 0;
Björn Stenberge1715c22002-03-28 14:34:13 +0000425}
Linus Nielsen Feltzing074999d2005-12-27 23:14:49 +0000426
Linus Nielsen Feltzingd5697272006-03-27 08:31:34 +0000427int iaudio_encode(char *iname, char *oname, char *idstring)
Linus Nielsen Feltzing074999d2005-12-27 23:14:49 +0000428{
429 size_t len;
430 int length;
431 FILE *file;
432 unsigned char *outbuf;
433 int i;
434 unsigned char sum = 0;
435
436 file = fopen(iname, "rb");
437 if (!file) {
438 perror(iname);
439 return -1;
440 }
441 fseek(file,0,SEEK_END);
442 length = ftell(file);
443
444 fseek(file,0,SEEK_SET);
445 outbuf = malloc(length+0x1030);
446
447 if ( !outbuf ) {
448 printf("out of memory!\n");
449 return -1;
450 }
451
452 len = fread(outbuf+0x1030, 1, length, file);
453 if(len < length) {
454 perror(iname);
455 return -2;
456 }
457
458 memset(outbuf, 0, 0x1030);
Linus Nielsen Feltzingd5697272006-03-27 08:31:34 +0000459 strcpy((char *)outbuf, idstring);
Linus Nielsen Feltzing074999d2005-12-27 23:14:49 +0000460
461 for(i = 0; i < length;i++)
462 sum += outbuf[0x1030 + i];
463
464 int2be(length, &outbuf[0x1024]);
465 outbuf[0x102b] = sum;
466
467 fclose(file);
468
469 file = fopen(oname, "wb");
470 if (!file) {
471 perror(oname);
472 return -3;
473 }
474
475 len = fwrite(outbuf, 1, length+0x1030, file);
476 if(len < length) {
477 perror(oname);
478 return -4;
479 }
480
481 fclose(file);
482}
Dave Chapmanc52ae7a2006-07-21 16:16:48 +0000483
484
485/* Create an ipod firmware partition image
486
487 fw_ver = 2 for 3rd Gen ipods, 3 for all later ipods including 5g.
488
489 This function doesn't yet handle the Broadcom resource image for the 5g,
490 so the resulting images won't be usable.
491
492 This has also only been tested on an ipod Photo
493*/
494
Dave Chapman3ba16cb2006-07-22 13:21:50 +0000495int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc)
Dave Chapmanc52ae7a2006-07-21 16:16:48 +0000496{
497 static const char *apple_stop_sign = "{{~~ /-----\\ "\
498 "{{~~ / \\ "\
499 "{{~~| | "\
500 "{{~~| S T O P | "\
501 "{{~~| | "\
502 "{{~~ \\ / "\
503 "{{~~ \\-----/ "\
504 "Copyright(C) 200"\
505 "1 Apple Computer"\
506 ", Inc.----------"\
507 "----------------"\
508 "----------------"\
509 "----------------"\
510 "----------------"\
511 "----------------"\
512 "---------------";
513 size_t len;
514 int length;
Dave Chapman3ba16cb2006-07-22 13:21:50 +0000515 int rsrclength;
516 int rsrcoffset;
Dave Chapmanc52ae7a2006-07-21 16:16:48 +0000517 FILE *file;
Dave Chapmanc52ae7a2006-07-21 16:16:48 +0000518 unsigned int sum = 0;
Dave Chapman3ba16cb2006-07-22 13:21:50 +0000519 unsigned int rsrcsum = 0;
520 unsigned char *outbuf;
521 int bufsize;
522 int i;
523
Dave Chapmanc52ae7a2006-07-21 16:16:48 +0000524 file = fopen(iname, "rb");
525 if (!file) {
526 perror(iname);
527 return -1;
528 }
529 fseek(file,0,SEEK_END);
530 length = ftell(file);
531
Dave Chapman3ba16cb2006-07-22 13:21:50 +0000532 fseek(file,0,SEEK_SET);
533
534 bufsize=(length+0x4600);
535 if (fake_rsrc) {
536 bufsize = (bufsize + 0x400) & ~0x200;
537 }
538
539 outbuf = malloc(bufsize);
Dave Chapmanc52ae7a2006-07-21 16:16:48 +0000540
541 if ( !outbuf ) {
542 printf("out of memory!\n");
543 return -1;
544 }
545
546 len = fread(outbuf+0x4600, 1, length, file);
547 if(len < length) {
548 perror(iname);
549 return -2;
550 }
551 fclose(file);
552
553 /* Calculate checksum for later use in header */
554 for(i = 0x4600; i < 0x4600+length;i++)
555 sum += outbuf[i];
556
557 /* Clear the header area to zero */
558 memset(outbuf, 0, 0x4600);
559
560 /* APPLE STOP SIGN */
561 strcpy((char *)outbuf, apple_stop_sign);
562
563 /* VOLUME HEADER */
564 memcpy(&outbuf[0x100],"]ih[",4); /* Magic */
565 int2le(0x4000, &outbuf[0x104]); /* Firmware offset relative to 0x200 */
566 short2le(0x10c, &outbuf[0x108]); /* Location of extended header */
567 short2le(fw_ver, &outbuf[0x10a]);
568
569 /* Firmware Directory - "osos" entry */
570 memcpy(&outbuf[0x4200],"!ATAsoso",8); /* dev and type */
571 int2le(0, &outbuf[0x4208]); /* id */
572 int2le(0x4400, &outbuf[0x420c]); /* devOffset */
573 int2le(length, &outbuf[0x4210]); /* Length of firmware */
574 int2le(0x10000000, &outbuf[0x4214]); /* Addr */
575 int2le(0, &outbuf[0x4218]); /* Entry Offset */
576 int2le(sum, &outbuf[0x421c]); /* Checksum */
577 int2le(0x00006012, &outbuf[0x4220]); /* vers - 0x6012 is a guess */
578 int2le(0xffffffff, &outbuf[0x4224]); /* LoadAddr - for flash images */
579
Dave Chapman3ba16cb2006-07-22 13:21:50 +0000580 /* "rsrc" entry (if applicable) */
581 if (fake_rsrc) {
582 rsrcoffset=(length+0x4600+0x200) & ~0x200;
583 rsrclength=0x200;
584 rsrcsum=0;
585
586 memcpy(&outbuf[0x4228],"!ATAcrsr",8); /* dev and type */
587 int2le(0, &outbuf[0x4230]); /* id */
588 int2le(rsrcoffset, &outbuf[0x4234]); /* devOffset */
589 int2le(rsrclength, &outbuf[0x4238]); /* Length of firmware */
590 int2le(0x10000000, &outbuf[0x423c]); /* Addr */
591 int2le(0, &outbuf[0x4240]); /* Entry Offset */
592 int2le(rsrcsum, &outbuf[0x4244]); /* Checksum */
593 int2le(0x0000b000, &outbuf[0x4248]); /* vers */
594 int2le(0xffffffff, &outbuf[0x424c]); /* LoadAddr - for flash images */
595 }
596
Dave Chapmanc52ae7a2006-07-21 16:16:48 +0000597 file = fopen(oname, "wb");
598 if (!file) {
599 perror(oname);
600 return -3;
601 }
602
603 len = fwrite(outbuf, 1, length+0x4600, file);
604 if(len < length) {
605 perror(oname);
606 return -4;
607 }
608
609 fclose(file);
610}