/*************************************************************************** * __________ __ ___. * Open \______ \ ____ ____ | | _\_ |__ _______ ___ * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ * \/ \/ \/ \/ \/ * $Id$ * * Copyright (C) 2002 by Björn Stenberg * * All files in this archive are subject to the GNU General Public License. * See the file COPYING in the source tree root for full license agreement. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * ****************************************************************************/ #include #include #include #include "iriver.h" int iaudio_encode(char *iname, char *oname); enum { ARCHOS_PLAYER, /* and V1 recorder */ ARCHOS_V2RECORDER, ARCHOS_FMRECORDER, ARCHOS_ONDIO_SP, ARCHOS_ONDIO_FM }; int size_limit[] = { 0x32000, /* ARCHOS_PLAYER */ 0x64000, /* ARCHOS_V2RECORDER */ 0x64000, /* ARCHOS_FMRECORDER */ 0x64000, /* ARCHOS_ONDIO_SP */ 0x64000 /* ARCHOS_ONDIO_FM */ }; void int2le(unsigned int val, unsigned char* addr) { addr[0] = val & 0xFF; addr[1] = (val >> 8) & 0xff; addr[2] = (val >> 16) & 0xff; addr[3] = (val >> 24) & 0xff; } void int2be(unsigned int val, unsigned char* addr) { addr[0] = (val >> 24) & 0xff; addr[1] = (val >> 16) & 0xff; addr[2] = (val >> 8) & 0xff; addr[3] = val & 0xFF; } void usage(void) { printf("usage: scramble [options] [xor string]\n"); printf("options:\n" "\t-fm Archos FM recorder format\n" "\t-v2 Archos V2 recorder format\n" "\t-ofm Archos Ondio FM recorder format\n" "\t-osp Archos Ondio SP format\n" "\t-neo SSI Neo format\n" "\t-mm=X Archos Multimedia format (X values: A=JBMM, B=AV1xx, C=AV3xx)\n" "\t-iriver iRiver format\n" "\t-iaudio iAudio format\n" "\t-add=X Rockbox generic \"add-up\" checksum format\n" "\t (X values: h100, h120, h140, h300, ipco, nano, ipvd\n" "\t ip3g, ip4g, mini)\n" "\nNo option results in Archos standard player/recorder format.\n"); exit(1); } int main (int argc, char** argv) { unsigned long length,i,slen; unsigned char *inbuf,*outbuf; unsigned short crc=0; unsigned long chksum=0; /* 32 bit checksum */ unsigned char header[24]; char *iname = argv[1]; char *oname = argv[2]; char *xorstring; int headerlen = 6; FILE* file; int version; unsigned long modelnum; char modelname[5]; int model_id; enum { none, scramble, xor, add } method = scramble; model_id = ARCHOS_PLAYER; if (argc < 3) { usage(); } if(!strcmp(argv[1], "-fm")) { headerlen = 24; iname = argv[2]; oname = argv[3]; version = 4; model_id = ARCHOS_FMRECORDER; } else if(!strcmp(argv[1], "-v2")) { headerlen = 24; iname = argv[2]; oname = argv[3]; version = 2; model_id = ARCHOS_V2RECORDER; } else if(!strcmp(argv[1], "-ofm")) { headerlen = 24; iname = argv[2]; oname = argv[3]; version = 8; model_id = ARCHOS_ONDIO_FM; } else if(!strcmp(argv[1], "-osp")) { headerlen = 24; iname = argv[2]; oname = argv[3]; version = 16; model_id = ARCHOS_ONDIO_SP; } else if(!strcmp(argv[1], "-neo")) { headerlen = 17; iname = argv[2]; oname = argv[3]; method = none; } else if(!strncmp(argv[1], "-mm=", 4)) { headerlen = 16; iname = argv[2]; oname = argv[3]; method = xor; version = argv[1][4]; if (argc > 4) xorstring = argv[4]; else { printf("Multimedia needs an xor string\n"); return -1; } } else if(!strncmp(argv[1], "-add=", 5)) { iname = argv[2]; oname = argv[3]; method = add; if(!strcmp(&argv[1][5], "h120")) modelnum = 0; else if(!strcmp(&argv[1][5], "h140")) modelnum = 0; /* the same as the h120 */ else if(!strcmp(&argv[1][5], "h100")) modelnum = 1; else if(!strcmp(&argv[1][5], "h300")) modelnum = 2; else if(!strcmp(&argv[1][5], "ipco")) modelnum = 3; else if(!strcmp(&argv[1][5], "nano")) modelnum = 4; else if(!strcmp(&argv[1][5], "ipvd")) modelnum = 5; else if(!strcmp(&argv[1][5], "fp7x")) modelnum = 6; else if(!strcmp(&argv[1][5], "ip3g")) modelnum = 7; else if(!strcmp(&argv[1][5], "ip4g")) modelnum = 8; else if(!strcmp(&argv[1][5], "mini")) modelnum = 9; else { fprintf(stderr, "unsupported model: %s\n", &argv[1][5]); return 2; } /* we store a 4-letter model name too, for humans */ strcpy(modelname, &argv[1][5]); chksum = modelnum; /* start checksum calcs with this */ } else if(!strcmp(argv[1], "-iriver")) { /* iRiver code dealt with in the iriver.c code */ iname = argv[2]; oname = argv[3]; iriver_encode(iname, oname, FALSE); return 0; } else if(!strcmp(argv[1], "-iaudio")) { iname = argv[2]; oname = argv[3]; return iaudio_encode(iname, oname); } /* open file */ file = fopen(iname,"rb"); if (!file) { perror(iname); return -1; } fseek(file,0,SEEK_END); length = ftell(file); length = (length + 3) & ~3; /* Round up to nearest 4 byte boundary */ if ((method == scramble) && ((length + headerlen) >= size_limit[model_id])) { printf("error: firmware image is %d bytes while max size is %d!\n", length + headerlen, size_limit[model_id]); fclose(file); return -1; } fseek(file,0,SEEK_SET); inbuf = malloc(length); if (method == xor) outbuf = malloc(length*2); else if(method == add) outbuf = malloc(length + 8); else outbuf = malloc(length); if ( !inbuf || !outbuf ) { printf("out of memory!\n"); return -1; } if(length> 4) { /* zero-fill the last 4 bytes to make sure there's no rubbish there when we write the size-aligned file later */ memset(outbuf+length-4, 0, 4); } /* read file */ i=fread(inbuf,1,length,file); if ( !i ) { perror(iname); return -1; } fclose(file); switch (method) { case add: for (i = 0; i < length; i++) { /* add 8 unsigned bits but keep a 32 bit sum */ chksum += inbuf[i]; } break; case scramble: slen = length/4; for (i = 0; i < length; i++) { unsigned long addr = (i >> 2) + ((i % 4) * slen); unsigned char data = inbuf[i]; data = ~((data << 1) | ((data >> 7) & 1)); /* poor man's ROL */ outbuf[addr] = data; } break; case xor: /* "compress" */ slen = 0; for (i=0; i> 8) & 0xff; header[5] = crc & 0xff; } else { header[0] = header[1] = header[2] = header[3] = 0xff; /* ??? */ header[6] = (crc >> 8) & 0xff; header[7] = crc & 0xff; header[11] = version; header[15] = headerlen; /* really? */ int2be(length, &header[20]); } break; case xor: { int xorlen = strlen(xorstring); /* xor data */ for (i=0; i>8)&0xFF; header[12]=crc&0xFF; int2be(sizeof(header), &header[12]); break; } /* write file */ file = fopen(oname,"wb"); if ( !file ) { perror(oname); return -1; } if ( !fwrite(header,headerlen,1,file) ) { perror(oname); return -1; } if ( !fwrite(outbuf,length,1,file) ) { perror(oname); return -1; } fclose(file); free(inbuf); free(outbuf); return 0; } int iaudio_encode(char *iname, char *oname) { size_t len; int length; FILE *file; unsigned char *outbuf; int i; unsigned char sum = 0; file = fopen(iname, "rb"); if (!file) { perror(iname); return -1; } fseek(file,0,SEEK_END); length = ftell(file); fseek(file,0,SEEK_SET); outbuf = malloc(length+0x1030); if ( !outbuf ) { printf("out of memory!\n"); return -1; } len = fread(outbuf+0x1030, 1, length, file); if(len < length) { perror(iname); return -2; } memset(outbuf, 0, 0x1030); strcpy((char *)outbuf, "COWON_X5_FW"); for(i = 0; i < length;i++) sum += outbuf[0x1030 + i]; int2be(length, &outbuf[0x1024]); outbuf[0x102b] = sum; fclose(file); file = fopen(oname, "wb"); if (!file) { perror(oname); return -3; } len = fwrite(outbuf, 1, length+0x1030, file); if(len < length) { perror(oname); return -4; } fclose(file); }