4 * Copyright (C) 2015 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)
20 #if __BYTE_ORDER == __BIG_ENDIAN
21 #define cpu_to_le32(x) bswap_32(x)
22 #define le32_to_cpu(x) bswap_32(x)
23 #elif __BYTE_ORDER == __LITTLE_ENDIAN
24 #define cpu_to_le32(x) (x)
25 #define le32_to_cpu(x) (x)
27 #error "Unsupported endianness"
30 #define TRX_MAGIC 0x30524448
31 #define TRX_FLAGS_OFFSET 12
32 #define TRX_MAX_PARTS 3
44 size_t trx_offset = 0;
45 char *partition[TRX_MAX_PARTS] = {};
47 /**************************************************
49 **************************************************/
51 static const uint32_t crc32_tbl[] = {
52 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
53 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
54 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
55 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
56 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
57 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
58 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
59 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
60 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
61 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
62 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
63 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
64 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
65 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
66 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
67 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
68 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
69 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
70 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
71 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
72 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
73 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
74 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
75 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
76 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
77 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
78 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
79 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
80 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
81 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
82 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
83 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
84 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
85 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
86 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
87 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
88 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
89 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
90 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
91 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
92 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
93 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
94 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
95 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
96 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
97 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
98 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
99 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
100 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
101 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
102 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
103 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
104 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
105 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
106 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
107 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
108 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
109 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
110 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
111 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
112 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
113 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
114 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
115 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
118 uint32_t otrx_crc32(uint8_t *buf, size_t len) {
119 uint32_t crc = 0xffffffff;
122 crc = crc32_tbl[(crc ^ *buf) & 0xff] ^ (crc >> 8);
130 /**************************************************
132 **************************************************/
134 static void otrx_check_parse_options(int argc, char **argv) {
137 while ((c = getopt(argc, argv, "o:")) != -1) {
140 trx_offset = atoi(optarg);
146 static int otrx_check(int argc, char **argv) {
148 struct trx_header hdr;
149 size_t bytes, length;
155 fprintf(stderr, "No TRX file passed\n");
162 otrx_check_parse_options(argc, argv);
164 trx = fopen(trx_path, "r");
166 fprintf(stderr, "Couldn't open %s\n", trx_path);
171 fseek(trx, trx_offset, SEEK_SET);
172 bytes = fread(&hdr, 1, sizeof(hdr), trx);
173 if (bytes != sizeof(hdr)) {
174 fprintf(stderr, "Couldn't read %s header\n", trx_path);
179 if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
180 fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
185 length = le32_to_cpu(hdr.length);
186 if (length < sizeof(hdr)) {
187 fprintf(stderr, "Length read from TRX too low (%zu B)\n", length);
192 buf = malloc(length);
194 fprintf(stderr, "Couldn't alloc %zd B buffer\n", length);
199 fseek(trx, trx_offset, SEEK_SET);
200 bytes = fread(buf, 1, length, trx);
201 if (bytes != length) {
202 fprintf(stderr, "Couldn't read %zd B of data from %s\n", length, trx_path);
207 crc32 = otrx_crc32(buf + TRX_FLAGS_OFFSET, length - TRX_FLAGS_OFFSET);
208 if (crc32 != le32_to_cpu(hdr.crc32)) {
209 fprintf(stderr, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32, le32_to_cpu(hdr.crc32));
214 printf("Found a valid TRX version %d\n", le32_to_cpu(hdr.version));
224 /**************************************************
226 **************************************************/
228 static void otrx_create_parse_options(int argc, char **argv) {
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);
299 buf = malloc(length);
301 fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
305 fseek(trx, 0, SEEK_SET);
306 bytes = fread(buf, 1, length, trx);
307 if (bytes != length) {
308 fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
312 crc32 = otrx_crc32(buf + TRX_FLAGS_OFFSET, length - TRX_FLAGS_OFFSET);
313 hdr->crc32 = cpu_to_le32(crc32);
315 fseek(trx, 0, SEEK_SET);
316 bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx);
317 if (bytes != sizeof(struct trx_header)) {
318 fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path);
325 static int otrx_create(int argc, char **argv) {
327 struct trx_header hdr = {};
330 size_t curr_offset = sizeof(hdr);
335 fprintf(stderr, "No TRX file passed\n");
342 otrx_create_parse_options(argc, argv);
344 trx = fopen(trx_path, "w+");
346 fprintf(stderr, "Couldn't open %s\n", trx_path);
350 fseek(trx, curr_offset, SEEK_SET);
353 while ((c = getopt(argc, argv, "f:b:")) != -1) {
356 if (curr_idx >= TRX_MAX_PARTS) {
358 fprintf(stderr, "Reached TRX partitions limit, no place for %s\n", optarg);
362 sbytes = otrx_create_append_file(trx, optarg);
364 fprintf(stderr, "Failed to append file %s\n", optarg);
366 hdr.offset[curr_idx++] = curr_offset;
367 curr_offset += sbytes;
370 sbytes = otrx_create_align(trx, curr_offset, 4);
372 fprintf(stderr, "Failed to append zeros\n");
374 curr_offset += sbytes;
378 sbytes = strtol(optarg, NULL, 0) - curr_offset;
380 fprintf(stderr, "Current TRX length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset, strtol(optarg, NULL, 0));
382 sbytes = otrx_create_append_zeros(trx, sbytes);
384 fprintf(stderr, "Failed to append zeros\n");
386 curr_offset += sbytes;
394 hdr.length = curr_offset;
395 otrx_create_write_hdr(trx, &hdr);
402 /**************************************************
404 **************************************************/
406 static void otrx_extract_parse_options(int argc, char **argv) {
409 while ((c = getopt(argc, argv, "c:e:o:1:2:3:")) != -1) {
412 trx_offset = atoi(optarg);
415 partition[0] = optarg;
418 partition[1] = optarg;
421 partition[2] = optarg;
427 static int otrx_extract_copy(FILE *trx, size_t offset, size_t length, char *out_path) {
433 out = fopen(out_path, "w");
435 fprintf(stderr, "Couldn't open %s\n", out_path);
440 buf = malloc(length);
442 fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
447 fseek(trx, offset, SEEK_SET);
448 bytes = fread(buf, 1, length, trx);
449 if (bytes != length) {
450 fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
455 bytes = fwrite(buf, 1, length, out);
456 if (bytes != length) {
457 fprintf(stderr, "Couldn't write %zu B to %s\n", length, out_path);
462 printf("Extracted 0x%zx bytes into %s\n", length, out_path);
472 static int otrx_extract(int argc, char **argv) {
474 struct trx_header hdr;
480 fprintf(stderr, "No TRX file passed\n");
487 otrx_extract_parse_options(argc, argv);
489 trx = fopen(trx_path, "r");
491 fprintf(stderr, "Couldn't open %s\n", trx_path);
496 fseek(trx, trx_offset, SEEK_SET);
497 bytes = fread(&hdr, 1, sizeof(hdr), trx);
498 if (bytes != sizeof(hdr)) {
499 fprintf(stderr, "Couldn't read %s header\n", trx_path);
504 if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
505 fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
510 for (i = 0; i < TRX_MAX_PARTS; i++) {
515 if (!hdr.offset[i]) {
516 printf("TRX doesn't contain partition %d, can't extract %s\n", i + 1, partition[i]);
520 if (i + 1 >= TRX_MAX_PARTS || !hdr.offset[i + 1])
521 length = le32_to_cpu(hdr.length) - le32_to_cpu(hdr.offset[i]);
523 length = le32_to_cpu(hdr.offset[i + 1]) - le32_to_cpu(hdr.offset[i]);
525 otrx_extract_copy(trx, trx_offset + le32_to_cpu(hdr.offset[i]), length, partition[i]);
534 /**************************************************
536 **************************************************/
538 static void usage() {
541 printf("Checking TRX file:\n");
542 printf("\totrx check <file> [options]\tcheck if file is a valid TRX\n");
543 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
545 printf("Creating new TRX file:\n");
546 printf("\totrx create <file> [options] [partitions]\n");
547 printf("\t-f file\t\t\t\t[partition] start new partition with content copied from file\n");
548 printf("\t-b offset\t\t\t[partition] append zeros to partition till reaching absolute offset\n");
550 printf("Extracting from TRX file:\n");
551 printf("\totrx extract <file> [options]\textract partitions from TRX file\n");
552 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
553 printf("\t-1 file\t\t\t\tfile to extract 1st partition to (optional)\n");
554 printf("\t-2 file\t\t\t\tfile to extract 2nd partition to (optional)\n");
555 printf("\t-3 file\t\t\t\tfile to extract 3rd partition to (optional)\n");
558 int main(int argc, char **argv) {
560 if (!strcmp(argv[1], "check"))
561 return otrx_check(argc, argv);
562 else if (!strcmp(argv[1], "create"))
563 return otrx_create(argc, argv);
564 else if (!strcmp(argv[1], "extract"))
565 return otrx_extract(argc, argv);