summaryrefslogtreecommitdiff
path: root/tools/mi4.c
blob: cf052be6eb038717e0fbc98010036aaf88b107b4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/***************************************************************************
 *             __________               __   ___.
 *   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;
}