4 * Copyright (C) 2015-2017 Rafał Miłecki <zajec5@gmail.com>
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)
21 #if !defined(__BYTE_ORDER)
22 #error "Unknown byte order"
25 #if __BYTE_ORDER == __BIG_ENDIAN
26 #define cpu_to_le32(x) bswap_32(x)
27 #define le32_to_cpu(x) bswap_32(x)
28 #elif __BYTE_ORDER == __LITTLE_ENDIAN
29 #define cpu_to_le32(x) (x)
30 #define le32_to_cpu(x) (x)
32 #error "Unsupported endianness"
35 #define TRX_MAGIC 0x30524448
36 #define TRX_FLAGS_OFFSET 12
37 #define TRX_MAX_PARTS 3
49 size_t trx_offset = 0;
50 char *partition[TRX_MAX_PARTS] = {};
52 static inline size_t otrx_min(size_t x, size_t y) {
56 /**************************************************
58 **************************************************/
60 static const uint32_t crc32_tbl[] = {
61 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
62 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
63 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
64 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
65 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
66 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
67 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
68 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
69 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
70 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
71 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
72 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
73 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
74 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
75 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
76 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
77 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
78 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
79 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
80 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
81 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
82 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
83 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
84 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
85 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
86 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
87 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
88 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
89 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
90 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
91 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
92 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
93 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
94 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
95 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
96 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
97 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
98 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
99 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
100 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
101 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
102 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
103 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
104 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
105 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
106 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
107 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
108 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
109 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
110 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
111 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
112 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
113 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
114 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
115 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
116 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
117 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
118 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
119 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
120 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
121 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
122 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
123 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
124 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
127 uint32_t otrx_crc32(uint32_t crc, uint8_t *buf, size_t len) {
129 crc = crc32_tbl[(crc ^ *buf) & 0xff] ^ (crc >> 8);
137 /**************************************************
139 **************************************************/
141 static void otrx_check_parse_options(int argc, char **argv) {
144 while ((c = getopt(argc, argv, "o:")) != -1) {
147 trx_offset = atoi(optarg);
153 static int otrx_check(int argc, char **argv) {
155 struct trx_header hdr;
156 size_t bytes, length;
162 fprintf(stderr, "No TRX file passed\n");
169 otrx_check_parse_options(argc, argv);
171 trx = fopen(trx_path, "r");
173 fprintf(stderr, "Couldn't open %s\n", trx_path);
178 fseek(trx, trx_offset, SEEK_SET);
179 bytes = fread(&hdr, 1, sizeof(hdr), trx);
180 if (bytes != sizeof(hdr)) {
181 fprintf(stderr, "Couldn't read %s header\n", trx_path);
186 if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
187 fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
192 length = le32_to_cpu(hdr.length);
193 if (length < sizeof(hdr)) {
194 fprintf(stderr, "Length read from TRX too low (%zu B)\n", length);
200 fseek(trx, trx_offset + TRX_FLAGS_OFFSET, SEEK_SET);
201 length -= TRX_FLAGS_OFFSET;
202 while ((bytes = fread(buf, 1, otrx_min(sizeof(buf), length), trx)) > 0) {
203 crc32 = otrx_crc32(crc32, buf, bytes);
208 fprintf(stderr, "Couldn't read last %zd B of data from %s\n", length, trx_path);
213 if (crc32 != le32_to_cpu(hdr.crc32)) {
214 fprintf(stderr, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32, le32_to_cpu(hdr.crc32));
219 printf("Found a valid TRX version %d\n", le32_to_cpu(hdr.version));
227 /**************************************************
229 **************************************************/
231 static ssize_t otrx_create_append_file(FILE *trx, const char *in_path) {
237 in = fopen(in_path, "r");
239 fprintf(stderr, "Couldn't open %s\n", in_path);
243 while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
244 if (fwrite(buf, 1, bytes, trx) != bytes) {
245 fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, trx_path);
257 static ssize_t otrx_create_append_zeros(FILE *trx, size_t length) {
260 buf = malloc(length);
263 memset(buf, 0, length);
265 if (fwrite(buf, 1, length, trx) != length) {
266 fprintf(stderr, "Couldn't write %zu B to %s\n", length, trx_path);
273 static ssize_t otrx_create_align(FILE *trx, size_t curr_offset, size_t alignment) {
274 if (curr_offset & (alignment - 1)) {
275 size_t length = alignment - (curr_offset % alignment);
276 return otrx_create_append_zeros(trx, length);
282 static int otrx_create_write_hdr(FILE *trx, struct trx_header *hdr) {
283 size_t bytes, length;
287 hdr->magic = cpu_to_le32(TRX_MAGIC);
290 fseek(trx, 0, SEEK_SET);
291 bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx);
292 if (bytes != sizeof(struct trx_header)) {
293 fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path);
297 length = le32_to_cpu(hdr->length);
300 fseek(trx, TRX_FLAGS_OFFSET, SEEK_SET);
301 length -= TRX_FLAGS_OFFSET;
302 while ((bytes = fread(buf, 1, otrx_min(sizeof(buf), length), trx)) > 0) {
303 crc32 = otrx_crc32(crc32, buf, bytes);
306 hdr->crc32 = cpu_to_le32(crc32);
308 fseek(trx, 0, SEEK_SET);
309 bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx);
310 if (bytes != sizeof(struct trx_header)) {
311 fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path);
318 static int otrx_create(int argc, char **argv) {
320 struct trx_header hdr = {};
323 size_t curr_offset = sizeof(hdr);
328 fprintf(stderr, "No TRX file passed\n");
334 trx = fopen(trx_path, "w+");
336 fprintf(stderr, "Couldn't open %s\n", trx_path);
340 fseek(trx, curr_offset, SEEK_SET);
343 while ((c = getopt(argc, argv, "f:A:a:b:")) != -1) {
346 if (curr_idx >= TRX_MAX_PARTS) {
348 fprintf(stderr, "Reached TRX partitions limit, no place for %s\n", optarg);
352 sbytes = otrx_create_append_file(trx, optarg);
354 fprintf(stderr, "Failed to append file %s\n", optarg);
356 hdr.offset[curr_idx++] = curr_offset;
357 curr_offset += sbytes;
360 sbytes = otrx_create_align(trx, curr_offset, 4);
362 fprintf(stderr, "Failed to append zeros\n");
364 curr_offset += sbytes;
368 sbytes = otrx_create_append_file(trx, optarg);
370 fprintf(stderr, "Failed to append file %s\n", optarg);
372 curr_offset += sbytes;
375 sbytes = otrx_create_align(trx, curr_offset, 4);
377 fprintf(stderr, "Failed to append zeros\n");
379 curr_offset += sbytes;
382 sbytes = otrx_create_align(trx, curr_offset, strtol(optarg, NULL, 0));
384 fprintf(stderr, "Failed to append zeros\n");
386 curr_offset += sbytes;
389 sbytes = strtol(optarg, NULL, 0) - curr_offset;
391 fprintf(stderr, "Current TRX length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset, strtol(optarg, NULL, 0));
393 sbytes = otrx_create_append_zeros(trx, sbytes);
395 fprintf(stderr, "Failed to append zeros\n");
397 curr_offset += sbytes;
405 sbytes = otrx_create_align(trx, curr_offset, 0x1000);
407 fprintf(stderr, "Failed to append zeros\n");
409 curr_offset += sbytes;
411 hdr.length = curr_offset;
412 otrx_create_write_hdr(trx, &hdr);
419 /**************************************************
421 **************************************************/
423 static void otrx_extract_parse_options(int argc, char **argv) {
426 while ((c = getopt(argc, argv, "c:e:o:1:2:3:")) != -1) {
429 trx_offset = atoi(optarg);
432 partition[0] = optarg;
435 partition[1] = optarg;
438 partition[2] = optarg;
444 static int otrx_extract_copy(FILE *trx, size_t offset, size_t length, char *out_path) {
450 out = fopen(out_path, "w");
452 fprintf(stderr, "Couldn't open %s\n", out_path);
457 buf = malloc(length);
459 fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
464 fseek(trx, offset, SEEK_SET);
465 bytes = fread(buf, 1, length, trx);
466 if (bytes != length) {
467 fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
472 bytes = fwrite(buf, 1, length, out);
473 if (bytes != length) {
474 fprintf(stderr, "Couldn't write %zu B to %s\n", length, out_path);
479 printf("Extracted 0x%zx bytes into %s\n", length, out_path);
489 static int otrx_extract(int argc, char **argv) {
491 struct trx_header hdr;
497 fprintf(stderr, "No TRX file passed\n");
504 otrx_extract_parse_options(argc, argv);
506 trx = fopen(trx_path, "r");
508 fprintf(stderr, "Couldn't open %s\n", trx_path);
513 fseek(trx, trx_offset, SEEK_SET);
514 bytes = fread(&hdr, 1, sizeof(hdr), trx);
515 if (bytes != sizeof(hdr)) {
516 fprintf(stderr, "Couldn't read %s header\n", trx_path);
521 if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
522 fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
527 for (i = 0; i < TRX_MAX_PARTS; i++) {
532 if (!hdr.offset[i]) {
533 printf("TRX doesn't contain partition %d, can't extract %s\n", i + 1, partition[i]);
537 if (i + 1 >= TRX_MAX_PARTS || !hdr.offset[i + 1])
538 length = le32_to_cpu(hdr.length) - le32_to_cpu(hdr.offset[i]);
540 length = le32_to_cpu(hdr.offset[i + 1]) - le32_to_cpu(hdr.offset[i]);
542 otrx_extract_copy(trx, trx_offset + le32_to_cpu(hdr.offset[i]), length, partition[i]);
551 /**************************************************
553 **************************************************/
555 static void usage() {
558 printf("Checking TRX file:\n");
559 printf("\totrx check <file> [options]\tcheck if file is a valid TRX\n");
560 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
562 printf("Creating new TRX file:\n");
563 printf("\totrx create <file> [options] [partitions]\n");
564 printf("\t-f file\t\t\t\t[partition] start new partition with content copied from file\n");
565 printf("\t-A file\t\t\t\t[partition] append current partition with content copied from file\n");
566 printf("\t-a alignment\t\t\t[partition] align current partition\n");
567 printf("\t-b offset\t\t\t[partition] append zeros to partition till reaching absolute offset\n");
569 printf("Extracting from TRX file:\n");
570 printf("\totrx extract <file> [options]\textract partitions from TRX file\n");
571 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
572 printf("\t-1 file\t\t\t\tfile to extract 1st partition to (optional)\n");
573 printf("\t-2 file\t\t\t\tfile to extract 2nd partition to (optional)\n");
574 printf("\t-3 file\t\t\t\tfile to extract 3rd partition to (optional)\n");
577 int main(int argc, char **argv) {
579 if (!strcmp(argv[1], "check"))
580 return otrx_check(argc, argv);
581 else if (!strcmp(argv[1], "create"))
582 return otrx_create(argc, argv);
583 else if (!strcmp(argv[1], "extract"))
584 return otrx_extract(argc, argv);