7fe4ba6f692f86811b63327dd3bd1d39a5d0b300
[openwrt/svn-archive/archive.git] / package / utils / otrx / src / otrx.c
1 /*
2 * otrx
3 *
4 * Copyright (C) 2015 Rafał Miłecki <zajec5@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 */
11
12 #include <byteswap.h>
13 #include <errno.h>
14 #include <stdint.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18
19 #if __BYTE_ORDER == __BIG_ENDIAN
20 #define cpu_to_le32(x) bswap_32(x)
21 #define le32_to_cpu(x) bswap_32(x)
22 #elif __BYTE_ORDER == __LITTLE_ENDIAN
23 #define cpu_to_le32(x) (x)
24 #define le32_to_cpu(x) (x)
25 #else
26 #error "Unsupported endianness"
27 #endif
28
29 #define TRX_MAGIC 0x30524448
30 #define TRX_FLAGS_OFFSET 12
31 #define TRX_MAX_PARTS 3
32
33 struct trx_header {
34 uint32_t magic;
35 uint32_t length;
36 uint32_t crc32;
37 uint16_t flags;
38 uint16_t version;
39 uint32_t offset[3];
40 };
41
42 enum mode {
43 MODE_UNKNOWN,
44 MODE_CHECK,
45 MODE_EXTRACT,
46 };
47
48 enum mode mode = MODE_UNKNOWN;
49
50 char *trx_path;
51 size_t trx_offset = 0;
52 char *partition[TRX_MAX_PARTS] = {};
53
54 /**************************************************
55 * CRC32
56 **************************************************/
57
58 uint32_t otrx_crc32(uint8_t *buf, size_t len) {
59 static const uint32_t t[] = {
60 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
61 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
62 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
63 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
64 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
65 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
66 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
67 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
68 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
69 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
70 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
71 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
72 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
73 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
74 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
75 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
76 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
77 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
78 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
79 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
80 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
81 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
82 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
83 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
84 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
85 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
86 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
87 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
88 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
89 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
90 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
91 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
92 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
93 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
94 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
95 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
96 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
97 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
98 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
99 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
100 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
101 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
102 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
103 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
104 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
105 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
106 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
107 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
108 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
109 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
110 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
111 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
112 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
113 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
114 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
115 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
116 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
117 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
118 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
119 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
120 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
121 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
122 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
123 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
124 };
125 uint32_t crc = 0xffffffff;
126
127 while (len) {
128 crc = t[(crc ^ *buf) & 0xff] ^ (crc >> 8);
129 buf++;
130 len--;
131 }
132
133 return crc;
134 }
135
136 /**************************************************
137 * Check
138 **************************************************/
139
140 static int otrx_check() {
141 FILE *trx;
142 struct trx_header hdr;
143 size_t bytes, length;
144 uint8_t *buf;
145 uint32_t crc32;
146 int err = 0;
147
148 trx = fopen(trx_path, "r");
149 if (!trx) {
150 fprintf(stderr, "Couldn't open %s\n", trx_path);
151 err = -EACCES;
152 goto out;
153 }
154
155 fseek(trx, trx_offset, SEEK_SET);
156 bytes = fread(&hdr, 1, sizeof(hdr), trx);
157 if (bytes != sizeof(hdr)) {
158 fprintf(stderr, "Couldn't read %s header\n", trx_path);
159 err = -EIO;
160 goto err_close;
161 }
162
163 if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
164 fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
165 err = -EINVAL;
166 goto err_close;
167 }
168
169 length = le32_to_cpu(hdr.length);
170 if (length < sizeof(hdr)) {
171 fprintf(stderr, "Length read from TRX too low (%zu B)\n", length);
172 err = -EINVAL;
173 goto err_close;
174 }
175
176 buf = malloc(length);
177 if (!buf) {
178 fprintf(stderr, "Couldn't alloc %d B buffer\n", length);
179 err = -ENOMEM;
180 goto err_close;
181 }
182
183 fseek(trx, trx_offset, SEEK_SET);
184 bytes = fread(buf, 1, length, trx);
185 if (bytes != length) {
186 fprintf(stderr, "Couldn't read %d B of data from %s\n", length, trx_path);
187 err = -ENOMEM;
188 goto err_free_buf;
189 }
190
191 crc32 = otrx_crc32(buf + TRX_FLAGS_OFFSET, length - TRX_FLAGS_OFFSET);
192 if (crc32 != le32_to_cpu(hdr.crc32)) {
193 fprintf(stderr, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32, le32_to_cpu(hdr.crc32));
194 err = -EINVAL;
195 goto err_free_buf;
196 }
197
198 printf("Found a valid TRX version %d\n", le32_to_cpu(hdr.version));
199
200 err_free_buf:
201 free(buf);
202 err_close:
203 fclose(trx);
204 out:
205 return err;
206 }
207
208 /**************************************************
209 * Extract
210 **************************************************/
211
212 static int otrx_extract_copy(FILE *trx, size_t offset, size_t length, char *out_path) {
213 FILE *out;
214 size_t bytes;
215 uint8_t *buf;
216 int err = 0;
217
218 out = fopen(out_path, "w");
219 if (!out) {
220 fprintf(stderr, "Couldn't open %s\n", out_path);
221 err = -EACCES;
222 goto out;
223 }
224
225 buf = malloc(length);
226 if (!buf) {
227 fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
228 err = -ENOMEM;
229 goto err_close;
230 }
231
232 fseek(trx, offset, SEEK_SET);
233 bytes = fread(buf, 1, length, trx);
234 if (bytes != length) {
235 fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
236 err = -ENOMEM;
237 goto err_free_buf;
238 };
239
240 bytes = fwrite(buf, 1, length, out);
241 if (bytes != length) {
242 fprintf(stderr, "Couldn't write %zu B to %s\n", length, out_path);
243 err = -ENOMEM;
244 goto err_free_buf;
245 }
246
247 printf("Extracted 0x%zx bytes into %s\n", length, out_path);
248
249 err_free_buf:
250 free(buf);
251 err_close:
252 fclose(out);
253 out:
254 return err;
255 }
256
257 static int otrx_extract() {
258 FILE *trx;
259 struct trx_header hdr;
260 size_t bytes;
261 int i;
262 int err = 0;
263
264 trx = fopen(trx_path, "r");
265 if (!trx) {
266 fprintf(stderr, "Couldn't open %s\n", trx_path);
267 err = -EACCES;
268 goto out;
269 }
270
271 fseek(trx, trx_offset, SEEK_SET);
272 bytes = fread(&hdr, 1, sizeof(hdr), trx);
273 if (bytes != sizeof(hdr)) {
274 fprintf(stderr, "Couldn't read %s header\n", trx_path);
275 err = -EIO;
276 goto err_close;
277 }
278
279 if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
280 fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
281 err = -EINVAL;
282 goto err_close;
283 }
284
285 for (i = 0; i < TRX_MAX_PARTS; i++) {
286 size_t length;
287
288 if (!partition[i])
289 continue;
290 if (!hdr.offset[i]) {
291 printf("TRX doesn't contain partition %d, can't extract %s\n", i + 1, partition[i]);
292 continue;
293 }
294
295 if (i + 1 >= TRX_MAX_PARTS || !hdr.offset[i + 1])
296 length = le32_to_cpu(hdr.length) - le32_to_cpu(hdr.offset[i]);
297 else
298 length = le32_to_cpu(hdr.offset[i + 1]) - le32_to_cpu(hdr.offset[i]);
299
300 otrx_extract_copy(trx, trx_offset + le32_to_cpu(hdr.offset[i]), length, partition[i]);
301 }
302
303 err_close:
304 fclose(trx);
305 out:
306 return err;
307 }
308
309 /**************************************************
310 * Start
311 **************************************************/
312
313 static void parse_options(int argc, char **argv) {
314 int c;
315
316 while ((c = getopt(argc, argv, "c:e:o:1:2:3:")) != -1) {
317 switch (c) {
318 case 'c':
319 mode = MODE_CHECK;
320 trx_path = optarg;
321 break;
322 case 'e':
323 mode = MODE_EXTRACT;
324 trx_path = optarg;
325 break;
326 case 'o':
327 trx_offset = atoi(optarg);
328 break;
329 case '1':
330 partition[0] = optarg;
331 break;
332 case '2':
333 partition[1] = optarg;
334 break;
335 case '3':
336 partition[2] = optarg;
337 break;
338 }
339 }
340 }
341
342 static void usage() {
343 printf("Usage:\n");
344 printf("\n");
345 printf("Checking TRX file:\n");
346 printf("\t-c file\t\tcheck if file is a valid TRX\n");
347 printf("\t-o offset\toffset of TRX data in file (default: 0)\n");
348 printf("\n");
349 printf("Extracting from TRX file:\n");
350 printf("\t-e file\t\tfile with TRX to extract from\n");
351 printf("\t-o offset\toffset of TRX data in file (default: 0)\n");
352 printf("\t-1 file\t\tfile to extract 1st partition to (optional)\n");
353 printf("\t-2 file\t\tfile to extract 2nd partition to (optional)\n");
354 printf("\t-3 file\t\tfile to extract 3rd partition to (optional)\n");
355 }
356
357 int main(int argc, char **argv) {
358 parse_options(argc, argv);
359
360 switch (mode) {
361 case MODE_CHECK:
362 return otrx_check();
363 case MODE_EXTRACT:
364 return otrx_extract();
365 default:
366 usage();
367 }
368
369 return 0;
370 }