rockbox/tools/mi4.c

192 lines
5.1 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 2006 Dave Chapman
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
* CRC32 implementation taken from:
*
* efone - Distributed internet phone system.
*
* (c) 1999,2000 Krzysztof Dabrowski
* (c) 1999,2000 ElysiuM deeZine
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
*/
/* based on implementation by Finn Yannick Jacobs */
/* crc_tab[] -- this crcTable is being build by chksum_crc32GenTab().
* so make sure, you call it before using the other
* functions!
*/
static unsigned int crc_tab[256];
/* chksum_crc() -- to a given block, this one calculates the
* crc32-checksum until the length is
* reached. the crc32-checksum will be
* the result.
*/
static unsigned int chksum_crc32 (unsigned char *block, unsigned int length)
{
register unsigned long crc;
unsigned long i;
crc = 0;
for (i = 0; i < length; i++)
{
crc = ((crc >> 8) & 0x00FFFFFF) ^ crc_tab[(crc ^ *block++) & 0xFF];
}
return (crc);
}
/* chksum_crc32gentab() -- to a global crc_tab[256], this one will
* calculate the crcTable for crc32-checksums.
* it is generated to the polynom [..]
*/
static void chksum_crc32gentab (void)
{
unsigned long crc, poly;
int i, j;
poly = 0xEDB88320L;
for (i = 0; i < 256; i++)
{
crc = i;
for (j = 8; j > 0; j--)
{
if (crc & 1)
{
crc = (crc >> 1) ^ poly;
}
else
{
crc >>= 1;
}
}
crc_tab[i] = crc;
}
}
static 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;
}
int mi4_encode(char *iname, char *oname, int version, int magic,
char *model, char *type)
{
size_t len;
int length;
int mi4length;
FILE *file;
unsigned int crc = 0;
unsigned char *outbuf;
file = fopen(iname, "rb");
if (!file) {
perror(iname);
return -1;
}
fseek(file,0,SEEK_END);
length = ftell(file);
fseek(file,0,SEEK_SET);
/* Add 4 bytes to length (for magic), the 0x200 byte header and
then round to an even 0x400 bytes
*/
mi4length = (length+4+0x200+0x3ff)&~0x3ff;
outbuf = malloc(mi4length);
if ( !outbuf ) {
printf("out of memory!\n");
return -1;
}
/* Clear the buffer to zero */
memset(outbuf, 0, mi4length);
len = fread(outbuf+0x200, 1, length, file);
if(len < (size_t)length) {
perror(iname);
return -2;
}
fclose(file);
/* We need to write some data into the actual image - before calculating
the CRC. */
int2le(0x00000100, &outbuf[0x2e0]); /* magic */
int2le(magic, &outbuf[0x2e4]); /* magic */
int2le(length+4, &outbuf[0x2e8]); /* length plus 0xaa55aa55 */
int2le(0xaa55aa55, &outbuf[0x200+length]); /* More Magic */
strncpy((char *)outbuf+0x1f8, type, 4); /* type of binary (RBBL, RBOS) */
strncpy((char *)outbuf+0x1fc, model, 4); /* 4 character model id */
/* Calculate CRC32 checksum */
chksum_crc32gentab ();
crc = chksum_crc32 (outbuf+0x200,mi4length-0x200);
memcpy(outbuf, "PPOS", 4); /* Magic */
int2le(version, &outbuf[0x04]); /* .mi4 version */
int2le(length+4, &outbuf[0x08]); /* Length of firmware plus magic */
int2le(crc, &outbuf[0x0c]); /* CRC32 of mi4 file */
int2le(0x00000002, &outbuf[0x10]); /* Encryption type: 2 = TEA */
int2le(mi4length, &outbuf[0x14]); /* Total .mi4 length */
int2le(mi4length-0x200, &outbuf[0x18]); /* Length of plaintext part */
/* v3 files require a dummy DSA signature */
if (version == 0x00010301) {
outbuf[0x2f]=0x01;
}
file = fopen(oname, "wb");
if (!file) {
perror(oname);
return -3;
}
len = fwrite(outbuf, 1, mi4length, file);
if(len < (size_t)length) {
perror(oname);
return -4;
}
fclose(file);
fprintf(stderr, "File encoded successfully\n" );
return 0;
}