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#define checksum_add32(csum, data) \
26  csum += ((uint8_t *)&data)[0]; \
27  csum += ((uint8_t *)&data)[1]; \
28  csum += ((uint8_t *)&data)[2]; \
29  csum += ((uint8_t *)&data)[3];
30
31void
32usage(void)
33{
34  fprintf(stderr, "usage: lzma2eva <loadadddr> <entry> <lzmafile> <evafile>\n");
35  exit(1);
36}
37
38void
39pexit(const char *msg)
40{
41  perror(msg);
42  exit(1);
43}
44
45int
46main(int argc, char *argv[])
47{
48
49  const char *infile, *outfile;
50  FILE *in, *out;
51  static const uint8_t buf[4096];
52  size_t elems;
53
54  uint8_t properties;
55  uint32_t dictsize;
56  uint64_t datasize;
57
58  uint32_t magic = 0xfeed1281L;
59  uint32_t reclength = 0;
60  fpos_t reclengthpos;
61  uint32_t loadaddress = 0;
62  uint32_t type = 0x075a0201L; /* might be 7Z 2.1? */
63  uint32_t checksum = 0;
64
65  uint32_t compsize = 0;
66  fpos_t compsizepos;
67  uint32_t datasize32 = 0;
68  uint32_t datacrc32 = crc32(0, 0, 0);
69
70  uint32_t zero = 0;
71  uint32_t entry = 0;
72
73  if (argc != 5)
74    usage();
75
76  /* "parse" command line */
77  loadaddress = strtoul(argv[1], 0, 0);
78  entry = strtoul(argv[2], 0, 0);
79  infile = argv[3];
80  outfile = argv[4];
81
82  in = fopen(infile, "rb");
83  if (!in)
84    pexit("fopen");
85  out = fopen(outfile, "w+b");
86  if (!out)
87    pexit("fopen");
88
89  /* read LZMA header */
90  if (1 != fread(&properties, sizeof properties, 1, in))
91    pexit("fread");
92  if (1 != fread(&dictsize, sizeof dictsize, 1, in))
93    pexit("fread");
94  if (1 != fread(&datasize, sizeof datasize, 1, in))
95    pexit("fread");
96
97  /* write EVA header */
98  if (1 != fwrite(&magic, sizeof magic, 1, out))
99    pexit("fwrite");
100  if (fgetpos(out, &reclengthpos))
101    pexit("fgetpos");
102  if (1 != fwrite(&reclength, sizeof reclength, 1, out))
103    pexit("fwrite");
104  if (1 != fwrite(&loadaddress, sizeof loadaddress, 1, out))
105    pexit("fwrite");
106  if (1 != fwrite(&type, sizeof type, 1, out))
107    pexit("fwrite");
108
109  /* write EVA LZMA header */
110  if (fgetpos(out, &compsizepos))
111    pexit("fgetpos");
112  if (1 != fwrite(&compsize, sizeof compsize, 1, out))
113    pexit("fwrite");
114  /* XXX check length */
115  datasize32 = (uint32_t)datasize;
116  if (1 != fwrite(&datasize32, sizeof datasize32, 1, out))
117    pexit("fwrite");
118  if (1 != fwrite(&datacrc32, sizeof datacrc32, 1, out))
119    pexit("fwrite");
120
121  /* write modified LZMA header */
122  if (1 != fwrite(&properties, sizeof properties, 1, out))
123    pexit("fwrite");
124  if (1 != fwrite(&dictsize, sizeof dictsize, 1, out))
125    pexit("fwrite");
126  if (1 != fwrite(&zero, 3, 1, out))
127    pexit("fwrite");
128
129  /* copy compressed data, calculate crc32 */
130  while (0 < (elems = fread(&buf, sizeof buf[0], sizeof buf, in))) {
131    compsize += elems;
132    if (elems != fwrite(&buf, sizeof buf[0], elems, out))
133      pexit("fwrite");
134    datacrc32 = crc32(datacrc32, buf, elems);
135  }
136  if (ferror(in))
137    pexit("fread");
138  fclose(in);
139
140  /* re-write record length */
141  reclength = compsize + 24;
142  if (fsetpos(out, &reclengthpos))
143    pexit("fsetpos");
144  if (1 != fwrite(&reclength, sizeof reclength, 1, out))
145    pexit("fwrite");
146
147  /* re-write EVA LZMA header including size and data crc */
148  if (fsetpos(out, &compsizepos))
149    pexit("fsetpos");
150  if (1 != fwrite(&compsize, sizeof compsize, 1, out))
151    pexit("fwrite");
152  if (1 != fwrite(&datasize32, sizeof datasize32, 1, out))
153    pexit("fwrite");
154  if (1 != fwrite(&datacrc32, sizeof datacrc32, 1, out))
155    pexit("fwrite");
156
157  /* calculate record checksum */
158  checksum += reclength;
159  checksum += loadaddress;
160  checksum_add32(checksum, type);
161  checksum_add32(checksum, compsize);
162  checksum_add32(checksum, datasize32);
163  checksum_add32(checksum, datacrc32);
164  if (fseek(out, 0, SEEK_CUR))
165    pexit("fseek");
166  while (0 < (elems = fread(&buf, sizeof buf[0], sizeof buf, out))) {
167    size_t i;
168    for (i = 0; i < elems; ++i)
169      checksum += buf[i];
170  }
171  if (ferror(out))
172    pexit("fread");
173  if (fseek(out, 0, SEEK_CUR))
174    pexit("fseek");
175
176  checksum = ~checksum + 1;
177  if (1 != fwrite(&checksum, sizeof checksum, 1, out))
178    pexit("fwrite");
179
180  /* write entry record */
181  if (1 != fwrite(&zero, sizeof zero, 1, out))
182    pexit("fwrite");
183  if (1 != fwrite(&entry, sizeof entry, 1, out))
184    pexit("fwrite");
185
186  if (fclose(out))
187    pexit("fclose");
188
189  return 0;
190}
191