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 static inline size_t otrx_min(size_t x, size_t y) {
51 /**************************************************
53 **************************************************/
55 static const uint32_t crc32_tbl[] = {
56 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
57 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
58 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
59 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
60 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
61 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
62 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
63 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
64 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
65 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
66 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
67 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
68 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
69 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
70 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
71 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
72 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
73 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
74 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
75 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
76 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
77 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
78 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
79 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
80 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
81 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
82 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
83 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
84 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
85 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
86 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
87 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
88 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
89 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
90 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
91 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
92 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
93 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
94 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
95 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
96 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
97 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
98 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
99 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
100 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
101 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
102 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
103 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
104 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
105 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
106 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
107 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
108 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
109 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
110 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
111 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
112 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
113 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
114 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
115 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
116 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
117 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
118 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
119 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
122 uint32_t otrx_crc32(uint8_t *buf, size_t len) {
123 uint32_t crc = 0xffffffff;
126 crc = crc32_tbl[(crc ^ *buf) & 0xff] ^ (crc >> 8);
134 /**************************************************
136 **************************************************/
138 static void otrx_check_parse_options(int argc, char **argv) {
141 while ((c = getopt(argc, argv, "o:")) != -1) {
144 trx_offset = atoi(optarg);
150 static int otrx_check(int argc, char **argv) {
152 struct trx_header hdr;
153 size_t bytes, length;
160 fprintf(stderr, "No TRX file passed\n");
167 otrx_check_parse_options(argc, argv);
169 trx = fopen(trx_path, "r");
171 fprintf(stderr, "Couldn't open %s\n", trx_path);
176 fseek(trx, trx_offset, SEEK_SET);
177 bytes = fread(&hdr, 1, sizeof(hdr), trx);
178 if (bytes != sizeof(hdr)) {
179 fprintf(stderr, "Couldn't read %s header\n", trx_path);
184 if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
185 fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
190 length = le32_to_cpu(hdr.length);
191 if (length < sizeof(hdr)) {
192 fprintf(stderr, "Length read from TRX too low (%zu B)\n", length);
198 fseek(trx, trx_offset + TRX_FLAGS_OFFSET, SEEK_SET);
199 length -= TRX_FLAGS_OFFSET;
200 while ((bytes = fread(buf, 1, otrx_min(sizeof(buf), length), trx)) > 0) {
201 for (i = 0; i < bytes; i++)
202 crc32 = crc32_tbl[(crc32 ^ buf[i]) & 0xff] ^ (crc32 >> 8);
207 fprintf(stderr, "Couldn't read last %zd B of data from %s\n", length, trx_path);
212 if (crc32 != le32_to_cpu(hdr.crc32)) {
213 fprintf(stderr, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32, le32_to_cpu(hdr.crc32));
218 printf("Found a valid TRX version %d\n", le32_to_cpu(hdr.version));
226 /**************************************************
228 **************************************************/
230 static void otrx_create_parse_options(int argc, char **argv) {
233 static ssize_t otrx_create_append_file(FILE *trx, const char *in_path) {
239 in = fopen(in_path, "r");
241 fprintf(stderr, "Couldn't open %s\n", in_path);
245 while ((bytes = fread(buf, 1, sizeof(buf), in)) > 0) {
246 if (fwrite(buf, 1, bytes, trx) != bytes) {
247 fprintf(stderr, "Couldn't write %zu B to %s\n", bytes, trx_path);
259 static ssize_t otrx_create_append_zeros(FILE *trx, size_t length) {
262 buf = malloc(length);
265 memset(buf, 0, length);
267 if (fwrite(buf, 1, length, trx) != length) {
268 fprintf(stderr, "Couldn't write %zu B to %s\n", length, trx_path);
275 static ssize_t otrx_create_align(FILE *trx, size_t curr_offset, size_t alignment) {
276 if (curr_offset & (alignment - 1)) {
277 size_t length = alignment - (curr_offset % alignment);
278 return otrx_create_append_zeros(trx, length);
284 static int otrx_create_write_hdr(FILE *trx, struct trx_header *hdr) {
285 size_t bytes, length;
289 hdr->magic = cpu_to_le32(TRX_MAGIC);
292 fseek(trx, 0, SEEK_SET);
293 bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx);
294 if (bytes != sizeof(struct trx_header)) {
295 fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path);
299 length = le32_to_cpu(hdr->length);
301 buf = malloc(length);
303 fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
307 fseek(trx, 0, SEEK_SET);
308 bytes = fread(buf, 1, length, trx);
309 if (bytes != length) {
310 fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
314 crc32 = otrx_crc32(buf + TRX_FLAGS_OFFSET, length - TRX_FLAGS_OFFSET);
315 hdr->crc32 = cpu_to_le32(crc32);
317 fseek(trx, 0, SEEK_SET);
318 bytes = fwrite(hdr, 1, sizeof(struct trx_header), trx);
319 if (bytes != sizeof(struct trx_header)) {
320 fprintf(stderr, "Couldn't write TRX header to %s\n", trx_path);
327 static int otrx_create(int argc, char **argv) {
329 struct trx_header hdr = {};
332 size_t curr_offset = sizeof(hdr);
337 fprintf(stderr, "No TRX file passed\n");
344 otrx_create_parse_options(argc, argv);
346 trx = fopen(trx_path, "w+");
348 fprintf(stderr, "Couldn't open %s\n", trx_path);
352 fseek(trx, curr_offset, SEEK_SET);
355 while ((c = getopt(argc, argv, "f:b:")) != -1) {
358 if (curr_idx >= TRX_MAX_PARTS) {
360 fprintf(stderr, "Reached TRX partitions limit, no place for %s\n", optarg);
364 sbytes = otrx_create_append_file(trx, optarg);
366 fprintf(stderr, "Failed to append file %s\n", optarg);
368 hdr.offset[curr_idx++] = curr_offset;
369 curr_offset += sbytes;
372 sbytes = otrx_create_align(trx, curr_offset, 4);
374 fprintf(stderr, "Failed to append zeros\n");
376 curr_offset += sbytes;
380 sbytes = strtol(optarg, NULL, 0) - curr_offset;
382 fprintf(stderr, "Current TRX length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset, strtol(optarg, NULL, 0));
384 sbytes = otrx_create_append_zeros(trx, sbytes);
386 fprintf(stderr, "Failed to append zeros\n");
388 curr_offset += sbytes;
396 hdr.length = curr_offset;
397 otrx_create_write_hdr(trx, &hdr);
404 /**************************************************
406 **************************************************/
408 static void otrx_extract_parse_options(int argc, char **argv) {
411 while ((c = getopt(argc, argv, "c:e:o:1:2:3:")) != -1) {
414 trx_offset = atoi(optarg);
417 partition[0] = optarg;
420 partition[1] = optarg;
423 partition[2] = optarg;
429 static int otrx_extract_copy(FILE *trx, size_t offset, size_t length, char *out_path) {
435 out = fopen(out_path, "w");
437 fprintf(stderr, "Couldn't open %s\n", out_path);
442 buf = malloc(length);
444 fprintf(stderr, "Couldn't alloc %zu B buffer\n", length);
449 fseek(trx, offset, SEEK_SET);
450 bytes = fread(buf, 1, length, trx);
451 if (bytes != length) {
452 fprintf(stderr, "Couldn't read %zu B of data from %s\n", length, trx_path);
457 bytes = fwrite(buf, 1, length, out);
458 if (bytes != length) {
459 fprintf(stderr, "Couldn't write %zu B to %s\n", length, out_path);
464 printf("Extracted 0x%zx bytes into %s\n", length, out_path);
474 static int otrx_extract(int argc, char **argv) {
476 struct trx_header hdr;
482 fprintf(stderr, "No TRX file passed\n");
489 otrx_extract_parse_options(argc, argv);
491 trx = fopen(trx_path, "r");
493 fprintf(stderr, "Couldn't open %s\n", trx_path);
498 fseek(trx, trx_offset, SEEK_SET);
499 bytes = fread(&hdr, 1, sizeof(hdr), trx);
500 if (bytes != sizeof(hdr)) {
501 fprintf(stderr, "Couldn't read %s header\n", trx_path);
506 if (le32_to_cpu(hdr.magic) != TRX_MAGIC) {
507 fprintf(stderr, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr.magic));
512 for (i = 0; i < TRX_MAX_PARTS; i++) {
517 if (!hdr.offset[i]) {
518 printf("TRX doesn't contain partition %d, can't extract %s\n", i + 1, partition[i]);
522 if (i + 1 >= TRX_MAX_PARTS || !hdr.offset[i + 1])
523 length = le32_to_cpu(hdr.length) - le32_to_cpu(hdr.offset[i]);
525 length = le32_to_cpu(hdr.offset[i + 1]) - le32_to_cpu(hdr.offset[i]);
527 otrx_extract_copy(trx, trx_offset + le32_to_cpu(hdr.offset[i]), length, partition[i]);
536 /**************************************************
538 **************************************************/
540 static void usage() {
543 printf("Checking TRX file:\n");
544 printf("\totrx check <file> [options]\tcheck if file is a valid TRX\n");
545 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
547 printf("Creating new TRX file:\n");
548 printf("\totrx create <file> [options] [partitions]\n");
549 printf("\t-f file\t\t\t\t[partition] start new partition with content copied from file\n");
550 printf("\t-b offset\t\t\t[partition] append zeros to partition till reaching absolute offset\n");
552 printf("Extracting from TRX file:\n");
553 printf("\totrx extract <file> [options]\textract partitions from TRX file\n");
554 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
555 printf("\t-1 file\t\t\t\tfile to extract 1st partition to (optional)\n");
556 printf("\t-2 file\t\t\t\tfile to extract 2nd partition to (optional)\n");
557 printf("\t-3 file\t\t\t\tfile to extract 3rd partition to (optional)\n");
560 int main(int argc, char **argv) {
562 if (!strcmp(argv[1], "check"))
563 return otrx_check(argc, argv);
564 else if (!strcmp(argv[1], "create"))
565 return otrx_create(argc, argv);
566 else if (!strcmp(argv[1], "extract"))
567 return otrx_extract(argc, argv);