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 uint32_t otrx_crc32(uint8_t *buf, size_t len) {
52 static const uint32_t t[] = {
53 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
54 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
55 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
56 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
57 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
58 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
59 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
60 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
61 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
62 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
63 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
64 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
65 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
66 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
67 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
68 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
69 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
70 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
71 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
72 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
73 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
74 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
75 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
76 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
77 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
78 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
79 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
80 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
81 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
82 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
83 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
84 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
85 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
86 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
87 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
88 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
89 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
90 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
91 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
92 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
93 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
94 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
95 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
96 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
97 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
98 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
99 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
100 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
101 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
102 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
103 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
104 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
105 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
106 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
107 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
108 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
109 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
110 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
111 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
112 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
113 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
114 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
115 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
116 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
118 uint32_t crc = 0xffffffff;
121 crc = t[(crc ^ *buf) & 0xff] ^ (crc >> 8);
129 /**************************************************
131 **************************************************/
133 static void otrx_check_parse_options(int argc, char **argv) {
136 while ((c = getopt(argc, argv, "o:")) != -1) {
139 trx_offset = atoi(optarg);
145 static int otrx_check(int argc, char **argv) {
147 struct trx_header hdr;
148 size_t bytes, length;
154 fprintf(stderr, "No TRX file passed\n");
161 otrx_check_parse_options(argc, argv);
163 trx = fopen(trx_path, "r");
165 fprintf(stderr, "Couldn't open %s\n", trx_path);
170 fseek(trx, trx_offset, SEEK_SET);
171 bytes = fread(&hdr, 1, sizeof(hdr), trx);
172 if (bytes != sizeof(hdr)) {
173 fprintf(stderr, "Couldn't read %s header\n", trx_path);
178 if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
179 fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
184 length = le32_to_cpu(hdr.length);
185 if (length < sizeof(hdr)) {
186 fprintf(stderr, "Length read from TRX too low (%zu B)\n", length);
191 buf = malloc(length);
193 fprintf(stderr, "Couldn't alloc %zd B buffer\n", length);
198 fseek(trx, trx_offset, SEEK_SET);
199 bytes = fread(buf, 1, length, trx);
200 if (bytes != length) {
201 fprintf(stderr, "Couldn't read %zd B of data from %s\n", length, trx_path);
206 crc32 = otrx_crc32(buf + TRX_FLAGS_OFFSET, length - TRX_FLAGS_OFFSET);
207 if (crc32 != le32_to_cpu(hdr.crc32)) {
208 fprintf(stderr, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32, le32_to_cpu(hdr.crc32));
213 printf("Found a valid TRX version %d\n", le32_to_cpu(hdr.version));
223 /**************************************************
225 **************************************************/
227 static void otrx_create_parse_options(int argc, char **argv) {
230 static ssize_t otrx_create_append_file(FILE *trx, const char *in_path) {
236 in = fopen(in_path, "r");
238 fprintf(stderr, "Couldn't open %s\n", in_path);
242 while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
243 if (fwrite(buf, 1, bytes, trx) != bytes) {
244 fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, trx_path);
256 static ssize_t otrx_create_append_zeros(FILE *trx, size_t length) {
259 buf = malloc(length);
262 memset(buf, 0, length);
264 if (fwrite(buf, 1, length, trx) != length) {
265 fprintf(stderr, "Couldn't write %zu B to %s\n", length, trx_path);
272 static ssize_t otrx_create_align(FILE *trx, size_t curr_offset, size_t alignment) {
273 if (curr_offset & (alignment - 1)) {
274 size_t length = alignment - (curr_offset % alignment);
275 return otrx_create_append_zeros(trx, length);
281 static int otrx_create_write_hdr(FILE *trx, struct trx_header *hdr) {
282 size_t bytes, length;
286 hdr->magic = cpu_to_le32(TRX_MAGIC);
289 fseek(trx, 0, SEEK_SET);
290 bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx);
291 if (bytes != sizeof(struct trx_header)) {
292 fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path);
296 length = le32_to_cpu(hdr->length);
298 buf = malloc(length);
300 fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
304 fseek(trx, 0, SEEK_SET);
305 bytes = fread(buf, 1, length, trx);
306 if (bytes != length) {
307 fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
311 crc32 = otrx_crc32(buf + TRX_FLAGS_OFFSET, length - TRX_FLAGS_OFFSET);
312 hdr->crc32 = cpu_to_le32(crc32);
314 fseek(trx, 0, SEEK_SET);
315 bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx);
316 if (bytes != sizeof(struct trx_header)) {
317 fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path);
324 static int otrx_create(int argc, char **argv) {
326 struct trx_header hdr = {};
329 size_t curr_offset = sizeof(hdr);
334 fprintf(stderr, "No TRX file passed\n");
341 otrx_create_parse_options(argc, argv);
343 trx = fopen(trx_path, "w+");
345 fprintf(stderr, "Couldn't open %s\n", trx_path);
349 fseek(trx, curr_offset, SEEK_SET);
352 while ((c = getopt(argc, argv, "f:b:")) != -1) {
355 if (curr_idx >= TRX_MAX_PARTS) {
357 fprintf(stderr, "Reached TRX partitions limit, no place for %s\n", optarg);
361 sbytes = otrx_create_append_file(trx, optarg);
363 fprintf(stderr, "Failed to append file %s\n", optarg);
365 hdr.offset[curr_idx++] = curr_offset;
366 curr_offset += sbytes;
369 sbytes = otrx_create_align(trx, curr_offset, 4);
371 fprintf(stderr, "Failed to append zeros\n");
373 curr_offset += sbytes;
377 sbytes = strtol(optarg, NULL, 0) - curr_offset;
379 fprintf(stderr, "Current TRX length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset, strtol(optarg, NULL, 0));
381 sbytes = otrx_create_append_zeros(trx, sbytes);
383 fprintf(stderr, "Failed to append zeros\n");
385 curr_offset += sbytes;
393 hdr.length = curr_offset;
394 otrx_create_write_hdr(trx, &hdr);
401 /**************************************************
403 **************************************************/
405 static void otrx_extract_parse_options(int argc, char **argv) {
408 while ((c = getopt(argc, argv, "c:e:o:1:2:3:")) != -1) {
411 trx_offset = atoi(optarg);
414 partition[0] = optarg;
417 partition[1] = optarg;
420 partition[2] = optarg;
426 static int otrx_extract_copy(FILE *trx, size_t offset, size_t length, char *out_path) {
432 out = fopen(out_path, "w");
434 fprintf(stderr, "Couldn't open %s\n", out_path);
439 buf = malloc(length);
441 fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
446 fseek(trx, offset, SEEK_SET);
447 bytes = fread(buf, 1, length, trx);
448 if (bytes != length) {
449 fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
454 bytes = fwrite(buf, 1, length, out);
455 if (bytes != length) {
456 fprintf(stderr, "Couldn't write %zu B to %s\n", length, out_path);
461 printf("Extracted 0x%zx bytes into %s\n", length, out_path);
471 static int otrx_extract(int argc, char **argv) {
473 struct trx_header hdr;
479 fprintf(stderr, "No TRX file passed\n");
486 otrx_extract_parse_options(argc, argv);
488 trx = fopen(trx_path, "r");
490 fprintf(stderr, "Couldn't open %s\n", trx_path);
495 fseek(trx, trx_offset, SEEK_SET);
496 bytes = fread(&hdr, 1, sizeof(hdr), trx);
497 if (bytes != sizeof(hdr)) {
498 fprintf(stderr, "Couldn't read %s header\n", trx_path);
503 if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
504 fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
509 for (i = 0; i < TRX_MAX_PARTS; i++) {
514 if (!hdr.offset[i]) {
515 printf("TRX doesn't contain partition %d, can't extract %s\n", i + 1, partition[i]);
519 if (i + 1 >= TRX_MAX_PARTS || !hdr.offset[i + 1])
520 length = le32_to_cpu(hdr.length) - le32_to_cpu(hdr.offset[i]);
522 length = le32_to_cpu(hdr.offset[i + 1]) - le32_to_cpu(hdr.offset[i]);
524 otrx_extract_copy(trx, trx_offset + le32_to_cpu(hdr.offset[i]), length, partition[i]);
533 /**************************************************
535 **************************************************/
537 static void usage() {
540 printf("Checking TRX file:\n");
541 printf("\totrx check <file> [options]\tcheck if file is a valid TRX\n");
542 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
544 printf("Creating new TRX file:\n");
545 printf("\totrx create <file> [options] [partitions]\n");
546 printf("\t-f file\t\t\t\t[partition] start new partition with content copied from file\n");
547 printf("\t-b offset\t\t\t[partition] append zeros to partition till reaching absolute offset\n");
549 printf("Extracting from TRX file:\n");
550 printf("\totrx extract <file> [options]\textract partitions from TRX file\n");
551 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
552 printf("\t-1 file\t\t\t\tfile to extract 1st partition to (optional)\n");
553 printf("\t-2 file\t\t\t\tfile to extract 2nd partition to (optional)\n");
554 printf("\t-3 file\t\t\t\tfile to extract 3rd partition to (optional)\n");
557 int main(int argc, char **argv) {
559 if (!strcmp(argv[1], "check"))
560 return otrx_check(argc, argv);
561 else if (!strcmp(argv[1], "create"))
562 return otrx_create(argc, argv);
563 else if (!strcmp(argv[1], "extract"))
564 return otrx_extract(argc, argv);