lzma2eva: Endianness fixes.
[openwrt/svn-archive/archive.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 }