Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 1 | /*************************************************************************** |
| 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 Chapman | 3ba16cb | 2006-07-22 13:21:50 +0000 | [diff] [blame] | 22 | #include <stdbool.h> |
Daniel Stenberg | 362259a | 2005-11-14 18:58:30 +0000 | [diff] [blame] | 23 | #include <string.h> |
Daniel Stenberg | adaae24 | 2005-01-24 09:01:48 +0000 | [diff] [blame] | 24 | #include "iriver.h" |
Dave Chapman | 530f31d | 2006-08-30 23:17:04 +0000 | [diff] [blame^] | 25 | #include "mi4.h" |
Daniel Stenberg | adaae24 | 2005-01-24 09:01:48 +0000 | [diff] [blame] | 26 | |
Linus Nielsen Feltzing | d569727 | 2006-03-27 08:31:34 +0000 | [diff] [blame] | 27 | int iaudio_encode(char *iname, char *oname, char *idstring); |
Dave Chapman | 3ba16cb | 2006-07-22 13:21:50 +0000 | [diff] [blame] | 28 | int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc); |
Linus Nielsen Feltzing | 074999d | 2005-12-27 23:14:49 +0000 | [diff] [blame] | 29 | |
Linus Nielsen Feltzing | 7b86bad | 2005-09-14 07:48:45 +0000 | [diff] [blame] | 30 | enum |
| 31 | { |
Linus Nielsen Feltzing | 56fa2da | 2005-09-14 11:15:59 +0000 | [diff] [blame] | 32 | ARCHOS_PLAYER, /* and V1 recorder */ |
Linus Nielsen Feltzing | 7b86bad | 2005-09-14 07:48:45 +0000 | [diff] [blame] | 33 | ARCHOS_V2RECORDER, |
| 34 | ARCHOS_FMRECORDER, |
| 35 | ARCHOS_ONDIO_SP, |
| 36 | ARCHOS_ONDIO_FM |
| 37 | }; |
| 38 | |
| 39 | int size_limit[] = |
| 40 | { |
| 41 | 0x32000, /* ARCHOS_PLAYER */ |
Linus Nielsen Feltzing | 7b86bad | 2005-09-14 07:48:45 +0000 | [diff] [blame] | 42 | 0x64000, /* ARCHOS_V2RECORDER */ |
| 43 | 0x64000, /* ARCHOS_FMRECORDER */ |
| 44 | 0x64000, /* ARCHOS_ONDIO_SP */ |
| 45 | 0x64000 /* ARCHOS_ONDIO_FM */ |
| 46 | }; |
| 47 | |
Dave Chapman | c52ae7a | 2006-07-21 16:16:48 +0000 | [diff] [blame] | 48 | void short2le(unsigned short val, unsigned char* addr) |
| 49 | { |
| 50 | addr[0] = val & 0xFF; |
| 51 | addr[1] = (val >> 8) & 0xff; |
| 52 | } |
| 53 | |
Björn Stenberg | 123ae83 | 2004-01-08 21:34:52 +0000 | [diff] [blame] | 54 | void 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 | |
| 62 | void 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 Stenberg | adaae24 | 2005-01-24 09:01:48 +0000 | [diff] [blame] | 70 | void 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 Feltzing | d569727 | 2006-03-27 08:31:34 +0000 | [diff] [blame] | 81 | "\t-iaudiox5 iAudio X5 format\n" |
| 82 | "\t-iaudiox5v iAudio X5V format\n" |
Dave Chapman | 3ba16cb | 2006-07-22 13:21:50 +0000 | [diff] [blame] | 83 | "\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 Chapman | 530f31d | 2006-08-30 23:17:04 +0000 | [diff] [blame^] | 86 | "\t-mi4v2 PortalPlayer .mi4 format (revision 010201)\n" |
| 87 | "\t-mi4v3 PortalPlayer .mi4 format (revision 010301)\n" |
Dave Chapman | 33cc6de | 2005-11-07 22:20:55 +0000 | [diff] [blame] | 88 | "\t-add=X Rockbox generic \"add-up\" checksum format\n" |
Dave Chapman | 0d10031 | 2006-02-05 18:30:50 +0000 | [diff] [blame] | 89 | "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd\n" |
Barry Wardell | 1920df3 | 2006-08-28 08:11:32 +0000 | [diff] [blame] | 90 | "\t ip3g, ip4g, mini, x5, h10, h10_5gb)\n" |
Daniel Stenberg | adaae24 | 2005-01-24 09:01:48 +0000 | [diff] [blame] | 91 | "\nNo option results in Archos standard player/recorder format.\n"); |
| 92 | |
| 93 | exit(1); |
| 94 | } |
| 95 | |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 96 | int main (int argc, char** argv) |
| 97 | { |
| 98 | unsigned long length,i,slen; |
| 99 | unsigned char *inbuf,*outbuf; |
| 100 | unsigned short crc=0; |
Linus Nielsen Feltzing | ddd1551 | 2005-01-28 10:28:34 +0000 | [diff] [blame] | 101 | unsigned long chksum=0; /* 32 bit checksum */ |
Björn Stenberg | 323f297 | 2002-12-19 15:00:40 +0000 | [diff] [blame] | 102 | unsigned char header[24]; |
Daniel Stenberg | 362259a | 2005-11-14 18:58:30 +0000 | [diff] [blame] | 103 | char *iname = argv[1]; |
| 104 | char *oname = argv[2]; |
| 105 | char *xorstring; |
Björn Stenberg | 323f297 | 2002-12-19 15:00:40 +0000 | [diff] [blame] | 106 | int headerlen = 6; |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 107 | FILE* file; |
Linus Nielsen Feltzing | ed11bd3 | 2003-10-27 18:04:28 +0000 | [diff] [blame] | 108 | int version; |
Dave Chapman | 33cc6de | 2005-11-07 22:20:55 +0000 | [diff] [blame] | 109 | unsigned long modelnum; |
| 110 | char modelname[5]; |
Linus Nielsen Feltzing | 7b86bad | 2005-09-14 07:48:45 +0000 | [diff] [blame] | 111 | int model_id; |
Daniel Stenberg | bf355b7 | 2005-01-24 13:14:14 +0000 | [diff] [blame] | 112 | enum { none, scramble, xor, add } method = scramble; |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 113 | |
Linus Nielsen Feltzing | 7b86bad | 2005-09-14 07:48:45 +0000 | [diff] [blame] | 114 | model_id = ARCHOS_PLAYER; |
| 115 | |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 116 | if (argc < 3) { |
Daniel Stenberg | adaae24 | 2005-01-24 09:01:48 +0000 | [diff] [blame] | 117 | usage(); |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 118 | } |
Björn Stenberg | 323f297 | 2002-12-19 15:00:40 +0000 | [diff] [blame] | 119 | |
Linus Nielsen Feltzing | ed11bd3 | 2003-10-27 18:04:28 +0000 | [diff] [blame] | 120 | if(!strcmp(argv[1], "-fm")) { |
Björn Stenberg | 323f297 | 2002-12-19 15:00:40 +0000 | [diff] [blame] | 121 | headerlen = 24; |
| 122 | iname = argv[2]; |
| 123 | oname = argv[3]; |
Linus Nielsen Feltzing | ed11bd3 | 2003-10-27 18:04:28 +0000 | [diff] [blame] | 124 | version = 4; |
Linus Nielsen Feltzing | 7b86bad | 2005-09-14 07:48:45 +0000 | [diff] [blame] | 125 | model_id = ARCHOS_FMRECORDER; |
Linus Nielsen Feltzing | ed11bd3 | 2003-10-27 18:04:28 +0000 | [diff] [blame] | 126 | } |
| 127 | |
Daniel Stenberg | 0115af2 | 2003-12-12 14:07:28 +0000 | [diff] [blame] | 128 | else if(!strcmp(argv[1], "-v2")) { |
Linus Nielsen Feltzing | ed11bd3 | 2003-10-27 18:04:28 +0000 | [diff] [blame] | 129 | headerlen = 24; |
| 130 | iname = argv[2]; |
| 131 | oname = argv[3]; |
| 132 | version = 2; |
Linus Nielsen Feltzing | 7b86bad | 2005-09-14 07:48:45 +0000 | [diff] [blame] | 133 | model_id = ARCHOS_V2RECORDER; |
Björn Stenberg | 323f297 | 2002-12-19 15:00:40 +0000 | [diff] [blame] | 134 | } |
Daniel Stenberg | 0115af2 | 2003-12-12 14:07:28 +0000 | [diff] [blame] | 135 | |
Jörg Hohensohn | 4f52bf4 | 2004-09-08 21:21:22 +0000 | [diff] [blame] | 136 | else if(!strcmp(argv[1], "-ofm")) { |
| 137 | headerlen = 24; |
| 138 | iname = argv[2]; |
| 139 | oname = argv[3]; |
| 140 | version = 8; |
Linus Nielsen Feltzing | 7b86bad | 2005-09-14 07:48:45 +0000 | [diff] [blame] | 141 | model_id = ARCHOS_ONDIO_FM; |
Jörg Hohensohn | 4f52bf4 | 2004-09-08 21:21:22 +0000 | [diff] [blame] | 142 | } |
| 143 | |
| 144 | else if(!strcmp(argv[1], "-osp")) { |
| 145 | headerlen = 24; |
| 146 | iname = argv[2]; |
| 147 | oname = argv[3]; |
| 148 | version = 16; |
Linus Nielsen Feltzing | 7b86bad | 2005-09-14 07:48:45 +0000 | [diff] [blame] | 149 | model_id = ARCHOS_ONDIO_SP; |
Jörg Hohensohn | 4f52bf4 | 2004-09-08 21:21:22 +0000 | [diff] [blame] | 150 | } |
| 151 | |
Daniel Stenberg | 0115af2 | 2003-12-12 14:07:28 +0000 | [diff] [blame] | 152 | else if(!strcmp(argv[1], "-neo")) { |
| 153 | headerlen = 17; |
| 154 | iname = argv[2]; |
| 155 | oname = argv[3]; |
Björn Stenberg | 123ae83 | 2004-01-08 21:34:52 +0000 | [diff] [blame] | 156 | 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 Stenberg | 0115af2 | 2003-12-12 14:07:28 +0000 | [diff] [blame] | 170 | } |
Daniel Stenberg | bf355b7 | 2005-01-24 13:14:14 +0000 | [diff] [blame] | 171 | 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 Chapman | 33cc6de | 2005-11-07 22:20:55 +0000 | [diff] [blame] | 177 | modelnum = 0; |
Daniel Stenberg | bf355b7 | 2005-01-24 13:14:14 +0000 | [diff] [blame] | 178 | else if(!strcmp(&argv[1][5], "h140")) |
Dave Chapman | 33cc6de | 2005-11-07 22:20:55 +0000 | [diff] [blame] | 179 | modelnum = 0; /* the same as the h120 */ |
Daniel Stenberg | bf355b7 | 2005-01-24 13:14:14 +0000 | [diff] [blame] | 180 | else if(!strcmp(&argv[1][5], "h100")) |
Dave Chapman | 33cc6de | 2005-11-07 22:20:55 +0000 | [diff] [blame] | 181 | modelnum = 1; |
Daniel Stenberg | bf355b7 | 2005-01-24 13:14:14 +0000 | [diff] [blame] | 182 | else if(!strcmp(&argv[1][5], "h300")) |
Dave Chapman | 33cc6de | 2005-11-07 22:20:55 +0000 | [diff] [blame] | 183 | 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 Chapman | 2a7bd9f | 2005-12-18 13:04:00 +0000 | [diff] [blame] | 188 | else if(!strcmp(&argv[1][5], "ipvd")) |
| 189 | modelnum = 5; |
Dave Chapman | d83e929 | 2006-01-12 00:35:50 +0000 | [diff] [blame] | 190 | else if(!strcmp(&argv[1][5], "fp7x")) |
| 191 | modelnum = 6; |
Dave Chapman | 0d10031 | 2006-02-05 18:30:50 +0000 | [diff] [blame] | 192 | else if(!strcmp(&argv[1][5], "ip3g")) |
| 193 | modelnum = 7; |
| 194 | else if(!strcmp(&argv[1][5], "ip4g")) |
| 195 | modelnum = 8; |
Dave Chapman | 8b1297a | 2006-02-21 15:01:25 +0000 | [diff] [blame] | 196 | else if(!strcmp(&argv[1][5], "mini")) |
| 197 | modelnum = 9; |
Linus Nielsen Feltzing | 1c1915c | 2006-03-21 14:40:07 +0000 | [diff] [blame] | 198 | else if(!strcmp(&argv[1][5], "iax5")) |
| 199 | modelnum = 10; |
Jens Arnold | d3feb78 | 2006-03-30 17:29:21 +0000 | [diff] [blame] | 200 | else if(!strcmp(&argv[1][5], "mn2g")) |
| 201 | modelnum = 11; |
Barry Wardell | 1920df3 | 2006-08-28 08:11:32 +0000 | [diff] [blame] | 202 | else if(!strcmp(&argv[1][5], "h10")) |
| 203 | modelnum = 13; |
| 204 | else if(!strcmp(&argv[1][5], "h10_5gb")) |
| 205 | modelnum = 14; |
Daniel Stenberg | bf355b7 | 2005-01-24 13:14:14 +0000 | [diff] [blame] | 206 | 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 Chapman | 33cc6de | 2005-11-07 22:20:55 +0000 | [diff] [blame] | 211 | strcpy(modelname, &argv[1][5]); |
| 212 | chksum = modelnum; /* start checksum calcs with this */ |
Daniel Stenberg | bf355b7 | 2005-01-24 13:14:14 +0000 | [diff] [blame] | 213 | } |
Daniel Stenberg | 0115af2 | 2003-12-12 14:07:28 +0000 | [diff] [blame] | 214 | |
Daniel Stenberg | adaae24 | 2005-01-24 09:01:48 +0000 | [diff] [blame] | 215 | 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 Feltzing | d569727 | 2006-03-27 08:31:34 +0000 | [diff] [blame] | 222 | else if(!strcmp(argv[1], "-iaudiox5")) { |
Linus Nielsen Feltzing | 074999d | 2005-12-27 23:14:49 +0000 | [diff] [blame] | 223 | iname = argv[2]; |
| 224 | oname = argv[3]; |
Linus Nielsen Feltzing | d569727 | 2006-03-27 08:31:34 +0000 | [diff] [blame] | 225 | 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 Feltzing | 074999d | 2005-12-27 23:14:49 +0000 | [diff] [blame] | 231 | } |
Dave Chapman | 3ba16cb | 2006-07-22 13:21:50 +0000 | [diff] [blame] | 232 | else if(!strcmp(argv[1], "-ipod3g")) { |
Dave Chapman | c52ae7a | 2006-07-21 16:16:48 +0000 | [diff] [blame] | 233 | iname = argv[2]; |
| 234 | oname = argv[3]; |
Dave Chapman | 3ba16cb | 2006-07-22 13:21:50 +0000 | [diff] [blame] | 235 | 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 Chapman | c52ae7a | 2006-07-21 16:16:48 +0000 | [diff] [blame] | 246 | } |
Dave Chapman | 530f31d | 2006-08-30 23:17:04 +0000 | [diff] [blame^] | 247 | 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 Stenberg | adaae24 | 2005-01-24 09:01:48 +0000 | [diff] [blame] | 257 | |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 258 | /* open file */ |
Björn Stenberg | 323f297 | 2002-12-19 15:00:40 +0000 | [diff] [blame] | 259 | file = fopen(iname,"rb"); |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 260 | if (!file) { |
Björn Stenberg | 323f297 | 2002-12-19 15:00:40 +0000 | [diff] [blame] | 261 | perror(iname); |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 262 | return -1; |
| 263 | } |
| 264 | fseek(file,0,SEEK_END); |
| 265 | length = ftell(file); |
Linus Nielsen Feltzing | 1326f66 | 2003-04-12 21:17:47 +0000 | [diff] [blame] | 266 | length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */ |
| 267 | |
Linus Nielsen Feltzing | 7b86bad | 2005-09-14 07:48:45 +0000 | [diff] [blame] | 268 | if ((method == scramble) && |
| 269 | ((length + headerlen) >= size_limit[model_id])) { |
Daniel Stenberg | 637ab47 | 2005-12-06 13:44:01 +0000 | [diff] [blame] | 270 | printf("error: firmware image is %d bytes while max size is %d!\n", |
| 271 | length + headerlen, |
| 272 | size_limit[model_id]); |
Linus Nielsen Feltzing | 6a42997 | 2003-04-14 09:59:47 +0000 | [diff] [blame] | 273 | fclose(file); |
| 274 | return -1; |
| 275 | } |
Linus Nielsen Feltzing | 7b86bad | 2005-09-14 07:48:45 +0000 | [diff] [blame] | 276 | |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 277 | fseek(file,0,SEEK_SET); |
| 278 | inbuf = malloc(length); |
Björn Stenberg | 123ae83 | 2004-01-08 21:34:52 +0000 | [diff] [blame] | 279 | if (method == xor) |
| 280 | outbuf = malloc(length*2); |
Daniel Stenberg | bf355b7 | 2005-01-24 13:14:14 +0000 | [diff] [blame] | 281 | else if(method == add) |
| 282 | outbuf = malloc(length + 8); |
Björn Stenberg | 123ae83 | 2004-01-08 21:34:52 +0000 | [diff] [blame] | 283 | else |
| 284 | outbuf = malloc(length); |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 285 | if ( !inbuf || !outbuf ) { |
| 286 | printf("out of memory!\n"); |
| 287 | return -1; |
| 288 | } |
Daniel Stenberg | bf355b7 | 2005-01-24 13:14:14 +0000 | [diff] [blame] | 289 | 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 Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 294 | |
| 295 | /* read file */ |
| 296 | i=fread(inbuf,1,length,file); |
| 297 | if ( !i ) { |
Björn Stenberg | 323f297 | 2002-12-19 15:00:40 +0000 | [diff] [blame] | 298 | perror(iname); |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 299 | return -1; |
| 300 | } |
| 301 | fclose(file); |
| 302 | |
Björn Stenberg | 123ae83 | 2004-01-08 21:34:52 +0000 | [diff] [blame] | 303 | switch (method) |
| 304 | { |
Daniel Stenberg | bf355b7 | 2005-01-24 13:14:14 +0000 | [diff] [blame] | 305 | case add: |
Linus Nielsen Feltzing | 599b0ff | 2005-01-28 12:20:20 +0000 | [diff] [blame] | 306 | for (i = 0; i < length; i++) { |
| 307 | /* add 8 unsigned bits but keep a 32 bit sum */ |
| 308 | chksum += inbuf[i]; |
Daniel Stenberg | bf355b7 | 2005-01-24 13:14:14 +0000 | [diff] [blame] | 309 | } |
| 310 | break; |
Björn Stenberg | 123ae83 | 2004-01-08 21:34:52 +0000 | [diff] [blame] | 311 | 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 Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 330 | } |
Daniel Stenberg | bf355b7 | 2005-01-24 13:14:14 +0000 | [diff] [blame] | 331 | |
| 332 | if(method != add) { |
| 333 | /* calculate checksum */ |
| 334 | for (i=0;i<length;i++) |
| 335 | crc += inbuf[i]; |
| 336 | } |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 337 | |
Björn Stenberg | 323f297 | 2002-12-19 15:00:40 +0000 | [diff] [blame] | 338 | memset(header, 0, sizeof header); |
Björn Stenberg | 123ae83 | 2004-01-08 21:34:52 +0000 | [diff] [blame] | 339 | switch (method) |
| 340 | { |
Daniel Stenberg | bf355b7 | 2005-01-24 13:14:14 +0000 | [diff] [blame] | 341 | case add: |
| 342 | { |
Linus Nielsen Feltzing | ddd1551 | 2005-01-28 10:28:34 +0000 | [diff] [blame] | 343 | int2be(chksum, header); /* checksum, big-endian */ |
Dave Chapman | 33cc6de | 2005-11-07 22:20:55 +0000 | [diff] [blame] | 344 | memcpy(&header[4], modelname, 4); /* 4 bytes model name */ |
Daniel Stenberg | bf355b7 | 2005-01-24 13:14:14 +0000 | [diff] [blame] | 345 | memcpy(outbuf, inbuf, length); /* the input buffer to output*/ |
| 346 | headerlen = 8; |
| 347 | } |
| 348 | break; |
Björn Stenberg | 123ae83 | 2004-01-08 21:34:52 +0000 | [diff] [blame] | 349 | 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 Stenberg | 123ae83 | 2004-01-08 21:34:52 +0000 | [diff] [blame] | 376 | /* xor data */ |
| 377 | for (i=0; i<slen; i++) |
| 378 | outbuf[i] ^= xorstring[i & (xorlen-1)]; |
Daniel Stenberg | 0115af2 | 2003-12-12 14:07:28 +0000 | [diff] [blame] | 379 | |
Björn Stenberg | 452702d | 2004-03-17 23:43:42 +0000 | [diff] [blame] | 380 | /* calculate checksum */ |
| 381 | for (i=0; i<slen; i++) |
| 382 | crc += outbuf[i]; |
| 383 | |
Björn Stenberg | 123ae83 | 2004-01-08 21:34:52 +0000 | [diff] [blame] | 384 | 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 Stenberg | 0115af2 | 2003-12-12 14:07:28 +0000 | [diff] [blame] | 391 | } |
Björn Stenberg | 123ae83 | 2004-01-08 21:34:52 +0000 | [diff] [blame] | 392 | |
Daniel Stenberg | 0115af2 | 2003-12-12 14:07:28 +0000 | [diff] [blame] | 393 | #define MY_FIRMWARE_TYPE "Rockbox" |
| 394 | #define MY_HEADER_VERSION 1 |
Björn Stenberg | 123ae83 | 2004-01-08 21:34:52 +0000 | [diff] [blame] | 395 | default: |
Daniel Stenberg | 362259a | 2005-11-14 18:58:30 +0000 | [diff] [blame] | 396 | strncpy((char *)header, MY_FIRMWARE_TYPE,9); |
Björn Stenberg | 123ae83 | 2004-01-08 21:34:52 +0000 | [diff] [blame] | 397 | 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 Stenberg | 323f297 | 2002-12-19 15:00:40 +0000 | [diff] [blame] | 403 | } |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 404 | |
| 405 | /* write file */ |
Björn Stenberg | 323f297 | 2002-12-19 15:00:40 +0000 | [diff] [blame] | 406 | file = fopen(oname,"wb"); |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 407 | if ( !file ) { |
Björn Stenberg | 323f297 | 2002-12-19 15:00:40 +0000 | [diff] [blame] | 408 | perror(oname); |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 409 | return -1; |
| 410 | } |
Björn Stenberg | 323f297 | 2002-12-19 15:00:40 +0000 | [diff] [blame] | 411 | if ( !fwrite(header,headerlen,1,file) ) { |
| 412 | perror(oname); |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 413 | return -1; |
| 414 | } |
| 415 | if ( !fwrite(outbuf,length,1,file) ) { |
Björn Stenberg | 323f297 | 2002-12-19 15:00:40 +0000 | [diff] [blame] | 416 | perror(oname); |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 417 | return -1; |
| 418 | } |
| 419 | fclose(file); |
| 420 | |
| 421 | free(inbuf); |
| 422 | free(outbuf); |
| 423 | |
Linus Nielsen Feltzing | 6a42997 | 2003-04-14 09:59:47 +0000 | [diff] [blame] | 424 | return 0; |
Björn Stenberg | e1715c2 | 2002-03-28 14:34:13 +0000 | [diff] [blame] | 425 | } |
Linus Nielsen Feltzing | 074999d | 2005-12-27 23:14:49 +0000 | [diff] [blame] | 426 | |
Linus Nielsen Feltzing | d569727 | 2006-03-27 08:31:34 +0000 | [diff] [blame] | 427 | int iaudio_encode(char *iname, char *oname, char *idstring) |
Linus Nielsen Feltzing | 074999d | 2005-12-27 23:14:49 +0000 | [diff] [blame] | 428 | { |
| 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 Feltzing | d569727 | 2006-03-27 08:31:34 +0000 | [diff] [blame] | 459 | strcpy((char *)outbuf, idstring); |
Linus Nielsen Feltzing | 074999d | 2005-12-27 23:14:49 +0000 | [diff] [blame] | 460 | |
| 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 Chapman | c52ae7a | 2006-07-21 16:16:48 +0000 | [diff] [blame] | 483 | |
| 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 Chapman | 3ba16cb | 2006-07-22 13:21:50 +0000 | [diff] [blame] | 495 | int ipod_encode(char *iname, char *oname, int fw_ver, bool fake_rsrc) |
Dave Chapman | c52ae7a | 2006-07-21 16:16:48 +0000 | [diff] [blame] | 496 | { |
| 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 Chapman | 3ba16cb | 2006-07-22 13:21:50 +0000 | [diff] [blame] | 515 | int rsrclength; |
| 516 | int rsrcoffset; |
Dave Chapman | c52ae7a | 2006-07-21 16:16:48 +0000 | [diff] [blame] | 517 | FILE *file; |
Dave Chapman | c52ae7a | 2006-07-21 16:16:48 +0000 | [diff] [blame] | 518 | unsigned int sum = 0; |
Dave Chapman | 3ba16cb | 2006-07-22 13:21:50 +0000 | [diff] [blame] | 519 | unsigned int rsrcsum = 0; |
| 520 | unsigned char *outbuf; |
| 521 | int bufsize; |
| 522 | int i; |
| 523 | |
Dave Chapman | c52ae7a | 2006-07-21 16:16:48 +0000 | [diff] [blame] | 524 | 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 Chapman | 3ba16cb | 2006-07-22 13:21:50 +0000 | [diff] [blame] | 532 | 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 Chapman | c52ae7a | 2006-07-21 16:16:48 +0000 | [diff] [blame] | 540 | |
| 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 Chapman | 3ba16cb | 2006-07-22 13:21:50 +0000 | [diff] [blame] | 580 | /* "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 Chapman | c52ae7a | 2006-07-21 16:16:48 +0000 | [diff] [blame] | 597 | 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 | } |