2 lzma2eva - convert lzma-compressed file to AVM EVA bootloader format
3 Copyright (C) 2007 Enrik Berkhan <Enrik.Berkhan@inka.de>
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.
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.
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
23 #include <zlib.h> /* crc32 */
26 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
28 #define checksum_add32(csum, data) \
30 csum += (((data) >> 0) & 0x000000FF); \
31 csum += (((data) >> 8) & 0x000000FF); \
32 csum += (((data) >> 16) & 0x000000FF); \
33 csum += (((data) >> 24) & 0x000000FF); \
39 fprintf(stderr, "usage: lzma2eva <loadadddr> <entry> <lzmafile> <evafile>\n");
44 pexit(const char *msg)
50 /* Read an 8bit value */
51 static int fread_8(uint8_t *buf, FILE *fd)
53 return (fread(buf, sizeof(*buf), 1, fd) == 1) ? 0 : -1;
56 /* Read a 32bit little endian value and convert to host endianness. */
57 static int fread_le32(uint32_t *buf, FILE *fd)
63 if (fread(tmp, sizeof(tmp), 1, fd) != 1)
66 for (i = 0; i < ARRAY_SIZE(tmp); i++)
67 *buf |= (uint32_t)(tmp[i]) << (i * 8);
72 /* Read a 64bit little endian value and convert to host endianness. */
73 static int fread_le64(uint64_t *buf, FILE *fd)
79 if (fread(tmp, sizeof(tmp), 1, fd) != 1)
82 for (i = 0; i < ARRAY_SIZE(tmp); i++)
83 *buf |= (uint64_t)(tmp[i]) << (i * 8);
88 /* Write an 8bit value */
89 static int fwrite_8(uint8_t buf, FILE *fd)
91 return (fwrite(&buf, sizeof(buf), 1, fd) == 1) ? 0 : -1;
94 /* Convert to little endian and write a 32bit value */
95 static int fwrite_le32(uint32_t buf, FILE *fd)
101 for (i = 0; i < ARRAY_SIZE(tmp); i++)
102 tmp[i] = buf >> (i * 8);
103 if (fwrite(tmp, sizeof(tmp), 1, fd) != 1)
110 main(int argc, char *argv[])
112 const char *infile, *outfile;
114 static const uint8_t buf[4096];
121 uint32_t magic = 0xfeed1281L;
122 uint32_t reclength = 0;
124 uint32_t loadaddress = 0;
125 uint32_t type = 0x075a0201L; /* might be 7Z 2.1? */
126 uint32_t checksum = 0;
128 uint32_t compsize = 0;
130 uint32_t datasize32 = 0;
131 uint32_t datacrc32 = crc32(0, 0, 0);
138 /* "parse" command line */
139 loadaddress = strtoul(argv[1], 0, 0);
140 entry = strtoul(argv[2], 0, 0);
144 in = fopen(infile, "rb");
147 out = fopen(outfile, "w+b");
151 /* read LZMA header */
152 if (fread_8(&properties, in))
154 if (fread_le32(&dictsize, in))
156 if (fread_le64(&datasize, in))
159 /* write EVA header */
160 if (fwrite_le32(magic, out))
162 if (fgetpos(out, &reclengthpos))
164 if (fwrite_le32(reclength, out))
166 if (fwrite_le32(loadaddress, out))
168 if (fwrite_le32(type, out))
171 /* write EVA LZMA header */
172 if (fgetpos(out, &compsizepos))
174 if (fwrite_le32(compsize, out))
176 /* XXX check length */
177 datasize32 = (uint32_t)datasize;
178 if (fwrite_le32(datasize32, out))
180 if (fwrite_le32(datacrc32, out))
183 /* write modified LZMA header */
184 if (fwrite_8(properties, out))
186 if (fwrite_le32(dictsize, out))
188 if (fwrite_le32(0, out))
191 /* copy compressed data, calculate crc32 */
192 while (0 < (elems = fread(&buf, sizeof buf[0], sizeof buf, in))) {
194 if (elems != fwrite(&buf, sizeof buf[0], elems, out))
196 datacrc32 = crc32(datacrc32, buf, elems);
202 /* re-write record length */
203 reclength = compsize + 24;
204 if (fsetpos(out, &reclengthpos))
206 if (fwrite_le32(reclength, out))
209 /* re-write EVA LZMA header including size and data crc */
210 if (fsetpos(out, &compsizepos))
212 if (fwrite_le32(compsize, out))
214 if (fwrite_le32(datasize32, out))
216 if (fwrite_le32(datacrc32, out))
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))
228 while (0 < (elems = fread(&buf, sizeof buf[0], sizeof buf, out))) {
230 for (i = 0; i < elems; ++i)
235 if (fseek(out, 0, SEEK_CUR))
238 checksum = ~checksum + 1;
239 if (fwrite_le32(checksum, out))
242 /* write entry record */
243 if (fwrite_le32(0, out))
245 if (fwrite_le32(entry, out))