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)
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 void otrx_create_parse_options(int argc
, char **argv
) {
234 static ssize_t
otrx_create_append_file(FILE *trx
, const char *in_path
) {
240 in
= fopen(in_path
, "r");
242 fprintf(stderr
, "Couldn't open %s\n", in_path
);
246 while ((bytes
= fread(buf
, 1, sizeof(buf
), in
)) > 0) {
247 if (fwrite(buf
, 1, bytes
, trx
) != bytes
) {
248 fprintf(stderr
, "Couldn't write %zu B to %s\n", bytes
, trx_path
);
260 static ssize_t
otrx_create_append_zeros(FILE *trx
, size_t length
) {
263 buf
= malloc(length
);
266 memset(buf
, 0, length
);
268 if (fwrite(buf
, 1, length
, trx
) != length
) {
269 fprintf(stderr
, "Couldn't write %zu B to %s\n", length
, trx_path
);
276 static ssize_t
otrx_create_align(FILE *trx
, size_t curr_offset
, size_t alignment
) {
277 if (curr_offset
& (alignment
- 1)) {
278 size_t length
= alignment
- (curr_offset
% alignment
);
279 return otrx_create_append_zeros(trx
, length
);
285 static int otrx_create_write_hdr(FILE *trx
, struct trx_header
*hdr
) {
286 size_t bytes
, length
;
290 hdr
->magic
= cpu_to_le32(TRX_MAGIC
);
293 fseek(trx
, 0, SEEK_SET
);
294 bytes
= fwrite(hdr
, 1, sizeof(struct trx_header
), trx
);
295 if (bytes
!= sizeof(struct trx_header
)) {
296 fprintf(stderr
, "Couldn't write TRX header to %s\n", trx_path
);
300 length
= le32_to_cpu(hdr
->length
);
303 fseek(trx
, TRX_FLAGS_OFFSET
, SEEK_SET
);
304 length
-= TRX_FLAGS_OFFSET
;
305 while ((bytes
= fread(buf
, 1, otrx_min(sizeof(buf
), length
), trx
)) > 0) {
306 crc32
= otrx_crc32(crc32
, buf
, bytes
);
309 hdr
->crc32
= cpu_to_le32(crc32
);
311 fseek(trx
, 0, SEEK_SET
);
312 bytes
= fwrite(hdr
, 1, sizeof(struct trx_header
), trx
);
313 if (bytes
!= sizeof(struct trx_header
)) {
314 fprintf(stderr
, "Couldn't write TRX header to %s\n", trx_path
);
321 static int otrx_create(int argc
, char **argv
) {
323 struct trx_header hdr
= {};
326 size_t curr_offset
= sizeof(hdr
);
331 fprintf(stderr
, "No TRX file passed\n");
338 otrx_create_parse_options(argc
, argv
);
340 trx
= fopen(trx_path
, "w+");
342 fprintf(stderr
, "Couldn't open %s\n", trx_path
);
346 fseek(trx
, curr_offset
, SEEK_SET
);
349 while ((c
= getopt(argc
, argv
, "f:b:")) != -1) {
352 if (curr_idx
>= TRX_MAX_PARTS
) {
354 fprintf(stderr
, "Reached TRX partitions limit, no place for %s\n", optarg
);
358 sbytes
= otrx_create_append_file(trx
, optarg
);
360 fprintf(stderr
, "Failed to append file %s\n", optarg
);
362 hdr
.offset
[curr_idx
++] = curr_offset
;
363 curr_offset
+= sbytes
;
366 sbytes
= otrx_create_align(trx
, curr_offset
, 4);
368 fprintf(stderr
, "Failed to append zeros\n");
370 curr_offset
+= sbytes
;
374 sbytes
= strtol(optarg
, NULL
, 0) - curr_offset
;
376 fprintf(stderr
, "Current TRX length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset
, strtol(optarg
, NULL
, 0));
378 sbytes
= otrx_create_append_zeros(trx
, sbytes
);
380 fprintf(stderr
, "Failed to append zeros\n");
382 curr_offset
+= sbytes
;
390 hdr
.length
= curr_offset
;
391 otrx_create_write_hdr(trx
, &hdr
);
398 /**************************************************
400 **************************************************/
402 static void otrx_extract_parse_options(int argc
, char **argv
) {
405 while ((c
= getopt(argc
, argv
, "c:e:o:1:2:3:")) != -1) {
408 trx_offset
= atoi(optarg
);
411 partition
[0] = optarg
;
414 partition
[1] = optarg
;
417 partition
[2] = optarg
;
423 static int otrx_extract_copy(FILE *trx
, size_t offset
, size_t length
, char *out_path
) {
429 out
= fopen(out_path
, "w");
431 fprintf(stderr
, "Couldn't open %s\n", out_path
);
436 buf
= malloc(length
);
438 fprintf(stderr
, "Couldn't alloc %zu B buffer\n", length
);
443 fseek(trx
, offset
, SEEK_SET
);
444 bytes
= fread(buf
, 1, length
, trx
);
445 if (bytes
!= length
) {
446 fprintf(stderr
, "Couldn't read %zu B of data from %s\n", length
, trx_path
);
451 bytes
= fwrite(buf
, 1, length
, out
);
452 if (bytes
!= length
) {
453 fprintf(stderr
, "Couldn't write %zu B to %s\n", length
, out_path
);
458 printf("Extracted 0x%zx bytes into %s\n", length
, out_path
);
468 static int otrx_extract(int argc
, char **argv
) {
470 struct trx_header hdr
;
476 fprintf(stderr
, "No TRX file passed\n");
483 otrx_extract_parse_options(argc
, argv
);
485 trx
= fopen(trx_path
, "r");
487 fprintf(stderr
, "Couldn't open %s\n", trx_path
);
492 fseek(trx
, trx_offset
, SEEK_SET
);
493 bytes
= fread(&hdr
, 1, sizeof(hdr
), trx
);
494 if (bytes
!= sizeof(hdr
)) {
495 fprintf(stderr
, "Couldn't read %s header\n", trx_path
);
500 if (le32_to_cpu(hdr
.magic
) != TRX_MAGIC
) {
501 fprintf(stderr
, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr
.magic
));
506 for (i
= 0; i
< TRX_MAX_PARTS
; i
++) {
511 if (!hdr
.offset
[i
]) {
512 printf("TRX doesn't contain partition %d, can't extract %s\n", i
+ 1, partition
[i
]);
516 if (i
+ 1 >= TRX_MAX_PARTS
|| !hdr
.offset
[i
+ 1])
517 length
= le32_to_cpu(hdr
.length
) - le32_to_cpu(hdr
.offset
[i
]);
519 length
= le32_to_cpu(hdr
.offset
[i
+ 1]) - le32_to_cpu(hdr
.offset
[i
]);
521 otrx_extract_copy(trx
, trx_offset
+ le32_to_cpu(hdr
.offset
[i
]), length
, partition
[i
]);
530 /**************************************************
532 **************************************************/
534 static void usage() {
537 printf("Checking TRX file:\n");
538 printf("\totrx check <file> [options]\tcheck if file is a valid TRX\n");
539 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
541 printf("Creating new TRX file:\n");
542 printf("\totrx create <file> [options] [partitions]\n");
543 printf("\t-f file\t\t\t\t[partition] start new partition with content copied from file\n");
544 printf("\t-b offset\t\t\t[partition] append zeros to partition till reaching absolute offset\n");
546 printf("Extracting from TRX file:\n");
547 printf("\totrx extract <file> [options]\textract partitions from TRX file\n");
548 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
549 printf("\t-1 file\t\t\t\tfile to extract 1st partition to (optional)\n");
550 printf("\t-2 file\t\t\t\tfile to extract 2nd partition to (optional)\n");
551 printf("\t-3 file\t\t\t\tfile to extract 3rd partition to (optional)\n");
554 int main(int argc
, char **argv
) {
556 if (!strcmp(argv
[1], "check"))
557 return otrx_check(argc
, argv
);
558 else if (!strcmp(argv
[1], "create"))
559 return otrx_create(argc
, argv
);
560 else if (!strcmp(argv
[1], "extract"))
561 return otrx_extract(argc
, argv
);