6424dde1d2c462dccc0f763affa13fb5f547edcc
[openwrt-10.03/.git] / tools / firmware-utils / src / lzma2eva.c
1 /*
2     lzma2eva - convert lzma-compressed file to AVM EVA bootloader format
3     Copyright (C) 2007  Enrik Berkhan <Enrik.Berkhan@inka.de>
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18 */
19
20 #include <stdint.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <zlib.h> /* crc32 */
24
25
26 #define ARRAY_SIZE(x)   (sizeof(x) / sizeof((x)[0]))
27
28 #define checksum_add32(csum, data) \
29   do { \
30     csum += (((data) >> 0)  & 0x000000FF); \
31     csum += (((data) >> 8)  & 0x000000FF); \
32     csum += (((data) >> 16) & 0x000000FF); \
33     csum += (((data) >> 24) & 0x000000FF); \
34   } while (0)
35
36 void
37 usage(void)
38 {
39   fprintf(stderr, "usage: lzma2eva <loadadddr> <entry> <lzmafile> <evafile>\n");
40   exit(1);
41 }
42
43 void
44 pexit(const char *msg)
45 {
46   perror(msg);
47   exit(1);
48 }
49
50 /* Read an 8bit value */
51 static int fread_8(uint8_t *buf, FILE *fd)
52 {
53   return (fread(buf, sizeof(*buf), 1, fd) == 1) ? 0 : -1;
54 }
55
56 /* Read a 32bit little endian value and convert to host endianness. */
57 static int fread_le32(uint32_t *buf, FILE *fd)
58 {
59   size_t count;
60   uint8_t tmp[4];
61   unsigned int i;
62
63   if (fread(tmp, sizeof(tmp), 1, fd) != 1)
64     return -1;
65   *buf = 0;
66   for (i = 0; i < ARRAY_SIZE(tmp); i++)
67     *buf |= (uint32_t)(tmp[i]) << (i * 8);
68
69   return 0;
70 }
71
72 /* Read a 64bit little endian value and convert to host endianness. */
73 static int fread_le64(uint64_t *buf, FILE *fd)
74 {
75   size_t count;
76   uint8_t tmp[8];
77   unsigned int i;
78
79   if (fread(tmp, sizeof(tmp), 1, fd) != 1)
80     return -1;
81   *buf = 0;
82   for (i = 0; i < ARRAY_SIZE(tmp); i++)
83     *buf |= (uint64_t)(tmp[i]) << (i * 8);
84
85   return 0;
86 }
87
88 /* Write an 8bit value */
89 static int fwrite_8(uint8_t buf, FILE *fd)
90 {
91   return (fwrite(&buf, sizeof(buf), 1, fd) == 1) ? 0 : -1;
92 }
93
94 /* Convert to little endian and write a 32bit value */
95 static int fwrite_le32(uint32_t buf, FILE *fd)
96 {
97   size_t count;
98   uint8_t tmp[4];
99   unsigned int i;
100
101   for (i = 0; i < ARRAY_SIZE(tmp); i++)
102     tmp[i] = buf >> (i * 8);
103   if (fwrite(tmp, sizeof(tmp), 1, fd) != 1)
104     return -1;
105
106   return 0;
107 }
108
109 int
110 main(int argc, char *argv[])
111 {
112   const char *infile, *outfile;
113   FILE *in, *out;
114   static const uint8_t buf[4096];
115   size_t elems;
116
117   uint8_t properties;
118   uint32_t dictsize;
119   uint64_t datasize;
120
121   uint32_t magic = 0xfeed1281L;
122   uint32_t reclength = 0;
123   fpos_t reclengthpos;
124   uint32_t loadaddress = 0;
125   uint32_t type = 0x075a0201L; /* might be 7Z 2.1? */
126   uint32_t checksum = 0;
127
128   uint32_t compsize = 0;
129   fpos_t compsizepos;
130   uint32_t datasize32 = 0;
131   uint32_t datacrc32 = crc32(0, 0, 0);
132
133   uint32_t entry = 0;
134
135   if (argc != 5)
136     usage();
137
138   /* "parse" command line */
139   loadaddress = strtoul(argv[1], 0, 0);
140   entry = strtoul(argv[2], 0, 0);
141   infile = argv[3];
142   outfile = argv[4];
143
144   in = fopen(infile, "rb");
145   if (!in)
146     pexit("fopen");
147   out = fopen(outfile, "w+b");
148   if (!out)
149     pexit("fopen");
150
151   /* read LZMA header */
152   if (fread_8(&properties, in))
153     pexit("fread");
154   if (fread_le32(&dictsize, in))
155     pexit("fread");
156   if (fread_le64(&datasize, in))
157     pexit("fread");
158
159   /* write EVA header */
160   if (fwrite_le32(magic, out))
161     pexit("fwrite");
162   if (fgetpos(out, &reclengthpos))
163     pexit("fgetpos");
164   if (fwrite_le32(reclength, out))
165     pexit("fwrite");
166   if (fwrite_le32(loadaddress, out))
167     pexit("fwrite");
168   if (fwrite_le32(type, out))
169     pexit("fwrite");
170
171   /* write EVA LZMA header */
172   if (fgetpos(out, &compsizepos))
173     pexit("fgetpos");
174   if (fwrite_le32(compsize, out))
175     pexit("fwrite");
176   /* XXX check length */
177   datasize32 = (uint32_t)datasize;
178   if (fwrite_le32(datasize32, out))
179     pexit("fwrite");
180   if (fwrite_le32(datacrc32, out))
181     pexit("fwrite");
182
183   /* write modified LZMA header */
184   if (fwrite_8(properties, out))
185     pexit("fwrite");
186   if (fwrite_le32(dictsize, out))
187     pexit("fwrite");
188   if (fwrite_le32(0, out))
189     pexit("fwrite");
190
191   /* copy compressed data, calculate crc32 */
192   while (0 < (elems = fread(&buf, sizeof buf[0], sizeof buf, in))) {
193     compsize += elems;
194     if (elems != fwrite(&buf, sizeof buf[0], elems, out))
195       pexit("fwrite");
196     datacrc32 = crc32(datacrc32, buf, elems);
197   }
198   if (ferror(in))
199     pexit("fread");
200   fclose(in);
201
202   /* re-write record length */
203   reclength = compsize + 24;
204   if (fsetpos(out, &reclengthpos))
205     pexit("fsetpos");
206   if (fwrite_le32(reclength, out))
207     pexit("fwrite");
208
209   /* re-write EVA LZMA header including size and data crc */
210   if (fsetpos(out, &compsizepos))
211     pexit("fsetpos");
212   if (fwrite_le32(compsize, out))
213     pexit("fwrite");
214   if (fwrite_le32(datasize32, out))
215     pexit("fwrite");
216   if (fwrite_le32(datacrc32, out))
217     pexit("fwrite");
218
219   /* calculate record checksum */
220   checksum += reclength;
221   checksum += loadaddress;
222   checksum_add32(checksum, type);
223   checksum_add32(checksum, compsize);
224   checksum_add32(checksum, datasize32);
225   checksum_add32(checksum, datacrc32);
226   if (fseek(out, 0, SEEK_CUR))
227     pexit("fseek");
228   while (0 < (elems = fread(&buf, sizeof buf[0], sizeof buf, out))) {
229     size_t i;
230     for (i = 0; i < elems; ++i)
231       checksum += buf[i];
232   }
233   if (ferror(out))
234     pexit("fread");
235   if (fseek(out, 0, SEEK_CUR))
236     pexit("fseek");
237
238   checksum = ~checksum + 1;
239   if (fwrite_le32(checksum, out))
240     pexit("fwrite");
241
242   /* write entry record */
243   if (fwrite_le32(0, out))
244     pexit("fwrite");
245   if (fwrite_le32(entry, out))
246     pexit("fwrite");
247
248   if (fclose(out))
249     pexit("fclose");
250
251   return 0;
252 }