store the 'add' checksum big-endian
[kugel-rb.git] / tools / scramble.c
blobd94dabf96f1764a3f850c3f364c56bed7174a2d2
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2002 by Björn Stenberg
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.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
20 #include <stdio.h>
21 #include <stdlib.h>
23 #include "iriver.h"
25 void int2le(unsigned int val, unsigned char* addr)
27 addr[0] = val & 0xFF;
28 addr[1] = (val >> 8) & 0xff;
29 addr[2] = (val >> 16) & 0xff;
30 addr[3] = (val >> 24) & 0xff;
33 void int2be(unsigned int val, unsigned char* addr)
35 addr[0] = (val >> 24) & 0xff;
36 addr[1] = (val >> 16) & 0xff;
37 addr[2] = (val >> 8) & 0xff;
38 addr[3] = val & 0xFF;
41 void usage(void)
43 printf("usage: scramble [options] <input file> <output file> [xor string]\n");
44 printf("options:\n"
45 "\t-fm Archos FM recorder format\n"
46 "\t-v2 Archos V2 recorder format\n"
47 "\t-ofm Archos Ondio FM recorder format\n"
48 "\t-osp Archos Ondio SP format\n"
49 "\t-neo SSI Neo format\n"
50 "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n"
51 "\t-iriver iRiver format\n"
52 "\t-add=X Rockbox iRiver \"add-up\" checksum format\n"
53 "\t (X values: h100, h120, h140, h300)\n"
54 "\nNo option results in Archos standard player/recorder format.\n");
56 exit(1);
59 int main (int argc, char** argv)
61 unsigned long length,i,slen;
62 unsigned char *inbuf,*outbuf;
63 unsigned short crc=0;
64 unsigned long crc32=0; /* 32 bit checksum */
65 unsigned char header[24];
66 unsigned char *iname = argv[1];
67 unsigned char *oname = argv[2];
68 unsigned char *xorstring;
69 int headerlen = 6;
70 FILE* file;
71 int version;
72 unsigned long irivernum;
73 char irivermodel[5];
74 enum { none, scramble, xor, add } method = scramble;
76 if (argc < 3) {
77 usage();
80 if(!strcmp(argv[1], "-fm")) {
81 headerlen = 24;
82 iname = argv[2];
83 oname = argv[3];
84 version = 4;
87 else if(!strcmp(argv[1], "-v2")) {
88 headerlen = 24;
89 iname = argv[2];
90 oname = argv[3];
91 version = 2;
94 else if(!strcmp(argv[1], "-ofm")) {
95 headerlen = 24;
96 iname = argv[2];
97 oname = argv[3];
98 version = 8;
101 else if(!strcmp(argv[1], "-osp")) {
102 headerlen = 24;
103 iname = argv[2];
104 oname = argv[3];
105 version = 16;
108 else if(!strcmp(argv[1], "-neo")) {
109 headerlen = 17;
110 iname = argv[2];
111 oname = argv[3];
112 method = none;
114 else if(!strncmp(argv[1], "-mm=", 4)) {
115 headerlen = 16;
116 iname = argv[2];
117 oname = argv[3];
118 method = xor;
119 version = argv[1][4];
120 if (argc > 4)
121 xorstring = argv[4];
122 else {
123 printf("Multimedia needs an xor string\n");
124 return -1;
127 else if(!strncmp(argv[1], "-add=", 5)) {
128 iname = argv[2];
129 oname = argv[3];
130 method = add;
132 if(!strcmp(&argv[1][5], "h120"))
133 irivernum = 0;
134 else if(!strcmp(&argv[1][5], "h140"))
135 irivernum = 0; /* the same as the h120 */
136 else if(!strcmp(&argv[1][5], "h100"))
137 irivernum = 1;
138 else if(!strcmp(&argv[1][5], "h300"))
139 irivernum = 2;
140 else {
141 fprintf(stderr, "unsupported model: %s\n", &argv[1][5]);
142 return 2;
144 /* we store a 4-letter model name too, for humans */
145 strcpy(irivermodel, &argv[1][5]);
146 crc32 = irivernum; /* start checksum calcs with this */
149 else if(!strcmp(argv[1], "-iriver")) {
150 /* iRiver code dealt with in the iriver.c code */
151 iname = argv[2];
152 oname = argv[3];
153 iriver_encode(iname, oname, FALSE);
154 return 0;
157 /* open file */
158 file = fopen(iname,"rb");
159 if (!file) {
160 perror(iname);
161 return -1;
163 fseek(file,0,SEEK_END);
164 length = ftell(file);
165 length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */
167 if ((method == scramble) && ((length + headerlen) >= 0x32000)) {
168 printf("error: max firmware size is 200KB!\n");
169 fclose(file);
170 return -1;
173 fseek(file,0,SEEK_SET);
174 inbuf = malloc(length);
175 if (method == xor)
176 outbuf = malloc(length*2);
177 else if(method == add)
178 outbuf = malloc(length + 8);
179 else
180 outbuf = malloc(length);
181 if ( !inbuf || !outbuf ) {
182 printf("out of memory!\n");
183 return -1;
185 if(length> 4) {
186 /* zero-fill the last 4 bytes to make sure there's no rubbish there
187 when we write the size-aligned file later */
188 memset(outbuf+length-4, 0, 4);
191 /* read file */
192 i=fread(inbuf,1,length,file);
193 if ( !i ) {
194 perror(iname);
195 return -1;
197 fclose(file);
199 switch (method)
201 case add:
202 for (i = 0; i < length/2; i++) {
203 unsigned short *inbuf16 = (unsigned short *)inbuf;
204 /* add 16 unsigned bits but keep a 32 bit sum */
205 crc32 += inbuf16[i];
207 break;
208 case scramble:
209 slen = length/4;
210 for (i = 0; i < length; i++) {
211 unsigned long addr = (i >> 2) + ((i % 4) * slen);
212 unsigned char data = inbuf[i];
213 data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */
214 outbuf[addr] = data;
216 break;
218 case xor:
219 /* "compress" */
220 slen = 0;
221 for (i=0; i<length; i++) {
222 if (!(i&7))
223 outbuf[slen++] = 0xff; /* all data is uncompressed */
224 outbuf[slen++] = inbuf[i];
226 break;
229 if(method != add) {
230 /* calculate checksum */
231 for (i=0;i<length;i++)
232 crc += inbuf[i];
235 memset(header, 0, sizeof header);
236 switch (method)
238 case add:
240 int2be(crc32, header); /* checksum, big-endian */
241 memcpy(&header[4], irivermodel, 4); /* 4 bytes model name */
242 memcpy(outbuf, inbuf, length); /* the input buffer to output*/
243 headerlen = 8;
245 break;
246 case scramble:
247 if (headerlen == 6) {
248 int2be(length, header);
249 header[4] = (crc >> 8) & 0xff;
250 header[5] = crc & 0xff;
252 else {
253 header[0] =
254 header[1] =
255 header[2] =
256 header[3] = 0xff; /* ??? */
258 header[6] = (crc >> 8) & 0xff;
259 header[7] = crc & 0xff;
261 header[11] = version;
263 header[15] = headerlen; /* really? */
265 int2be(length, &header[20]);
267 break;
269 case xor:
271 int xorlen = strlen(xorstring);
273 /* xor data */
274 for (i=0; i<slen; i++)
275 outbuf[i] ^= xorstring[i & (xorlen-1)];
277 /* calculate checksum */
278 for (i=0; i<slen; i++)
279 crc += outbuf[i];
281 header[0] = header[2] = 'Z';
282 header[1] = header[3] = version;
283 int2le(length, &header[4]);
284 int2le(slen, &header[8]);
285 int2le(crc, &header[12]);
286 length = slen;
287 break;
290 #define MY_FIRMWARE_TYPE "Rockbox"
291 #define MY_HEADER_VERSION 1
292 default:
293 strncpy(header,MY_FIRMWARE_TYPE,9);
294 header[9]='\0'; /*shouldn't have to, but to be SURE */
295 header[10]=MY_HEADER_VERSION&0xFF;
296 header[11]=(crc>>8)&0xFF;
297 header[12]=crc&0xFF;
298 int2be(sizeof(header), &header[12]);
299 break;
302 /* write file */
303 file = fopen(oname,"wb");
304 if ( !file ) {
305 perror(oname);
306 return -1;
308 if ( !fwrite(header,headerlen,1,file) ) {
309 perror(oname);
310 return -1;
312 if ( !fwrite(outbuf,length,1,file) ) {
313 perror(oname);
314 return -1;
316 fclose(file);
318 free(inbuf);
319 free(outbuf);
321 return 0;