1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (C) 2015-2017 Rafał Miłecki <zajec5@gmail.com>
17 #if !defined(__BYTE_ORDER)
18 #error "Unknown byte order"
21 #if __BYTE_ORDER == __BIG_ENDIAN
22 #define cpu_to_le32(x) bswap_32(x)
23 #define le32_to_cpu(x) bswap_32(x)
24 #elif __BYTE_ORDER == __LITTLE_ENDIAN
25 #define cpu_to_le32(x) (x)
26 #define le32_to_cpu(x) (x)
28 #error "Unsupported endianness"
31 #define TRX_MAGIC 0x30524448
32 #define TRX_FLAGS_OFFSET 12
33 #define TRX_MAX_PARTS 3
45 size_t trx_offset
= 0;
46 char *partition
[TRX_MAX_PARTS
] = {};
48 static inline size_t otrx_min(size_t x
, size_t y
) {
52 /**************************************************
54 **************************************************/
56 static const uint32_t crc32_tbl
[] = {
57 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
58 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
59 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
60 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
61 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
62 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
63 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
64 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
65 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
66 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
67 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
68 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
69 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
70 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
71 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
72 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
73 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
74 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
75 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
76 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
77 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
78 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
79 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
80 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
81 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
82 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
83 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
84 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
85 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
86 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
87 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
88 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
89 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
90 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
91 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
92 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
93 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
94 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
95 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
96 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
97 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
98 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
99 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
100 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
101 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
102 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
103 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
104 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
105 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
106 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
107 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
108 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
109 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
110 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
111 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
112 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
113 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
114 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
115 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
116 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
117 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
118 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
119 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
120 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
123 uint32_t otrx_crc32(uint32_t crc
, uint8_t *buf
, size_t len
) {
125 crc
= crc32_tbl
[(crc
^ *buf
) & 0xff] ^ (crc
>> 8);
133 /**************************************************
135 **************************************************/
137 static void otrx_check_parse_options(int argc
, char **argv
) {
140 while ((c
= getopt(argc
, argv
, "o:")) != -1) {
143 trx_offset
= atoi(optarg
);
149 static int otrx_check(int argc
, char **argv
) {
151 struct trx_header hdr
;
152 size_t bytes
, length
;
158 fprintf(stderr
, "No TRX file passed\n");
165 otrx_check_parse_options(argc
, argv
);
167 trx
= fopen(trx_path
, "r");
169 fprintf(stderr
, "Couldn't open %s\n", trx_path
);
174 fseek(trx
, trx_offset
, SEEK_SET
);
175 bytes
= fread(&hdr
, 1, sizeof(hdr
), trx
);
176 if (bytes
!= sizeof(hdr
)) {
177 fprintf(stderr
, "Couldn't read %s header\n", trx_path
);
182 if (le32_to_cpu(hdr
.magic
) != TRX_MAGIC
) {
183 fprintf(stderr
, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr
.magic
));
188 length
= le32_to_cpu(hdr
.length
);
189 if (length
< sizeof(hdr
)) {
190 fprintf(stderr
, "Length read from TRX too low (%zu B)\n", length
);
196 fseek(trx
, trx_offset
+ TRX_FLAGS_OFFSET
, SEEK_SET
);
197 length
-= TRX_FLAGS_OFFSET
;
198 while ((bytes
= fread(buf
, 1, otrx_min(sizeof(buf
), length
), trx
)) > 0) {
199 crc32
= otrx_crc32(crc32
, buf
, bytes
);
204 fprintf(stderr
, "Couldn't read last %zd B of data from %s\n", length
, trx_path
);
209 if (crc32
!= le32_to_cpu(hdr
.crc32
)) {
210 fprintf(stderr
, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32
, le32_to_cpu(hdr
.crc32
));
215 printf("Found a valid TRX version %d\n", le32_to_cpu(hdr
.version
));
223 /**************************************************
225 **************************************************/
227 static ssize_t
otrx_create_append_file(FILE *trx
, const char *in_path
) {
233 in
= fopen(in_path
, "r");
235 fprintf(stderr
, "Couldn't open %s\n", in_path
);
239 while ((bytes
= fread(buf
, 1, sizeof(buf
), in
)) > 0) {
240 if (fwrite(buf
, 1, bytes
, trx
) != bytes
) {
241 fprintf(stderr
, "Couldn't write %zu B to %s\n", bytes
, trx_path
);
253 static ssize_t
otrx_create_append_zeros(FILE *trx
, size_t length
) {
256 buf
= malloc(length
);
259 memset(buf
, 0, length
);
261 if (fwrite(buf
, 1, length
, trx
) != length
) {
262 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
;
288 fseek(trx
, 0, SEEK_SET
);
289 bytes
= fwrite(hdr
, 1, sizeof(struct trx_header
), trx
);
290 if (bytes
!= sizeof(struct trx_header
)) {
291 fprintf(stderr
, "Couldn't write TRX header to %s\n", trx_path
);
295 length
= le32_to_cpu(hdr
->length
);
298 fseek(trx
, TRX_FLAGS_OFFSET
, SEEK_SET
);
299 length
-= TRX_FLAGS_OFFSET
;
300 while ((bytes
= fread(buf
, 1, otrx_min(sizeof(buf
), length
), trx
)) > 0) {
301 crc32
= otrx_crc32(crc32
, buf
, bytes
);
304 hdr
->crc32
= cpu_to_le32(crc32
);
306 fseek(trx
, 0, SEEK_SET
);
307 bytes
= fwrite(hdr
, 1, sizeof(struct trx_header
), trx
);
308 if (bytes
!= sizeof(struct trx_header
)) {
309 fprintf(stderr
, "Couldn't write TRX header to %s\n", trx_path
);
316 static int otrx_create(int argc
, char **argv
) {
318 struct trx_header hdr
= {};
321 size_t curr_offset
= sizeof(hdr
);
327 hdr
.magic
= cpu_to_le32(TRX_MAGIC
);
330 fprintf(stderr
, "No TRX file passed\n");
336 trx
= fopen(trx_path
, "w+");
338 fprintf(stderr
, "Couldn't open %s\n", trx_path
);
342 fseek(trx
, curr_offset
, SEEK_SET
);
345 while ((c
= getopt(argc
, argv
, "f:A:a:b:M:")) != -1) {
348 if (curr_idx
>= TRX_MAX_PARTS
) {
350 fprintf(stderr
, "Reached TRX partitions limit, no place for %s\n", optarg
);
354 sbytes
= otrx_create_append_file(trx
, optarg
);
356 fprintf(stderr
, "Failed to append file %s\n", optarg
);
358 hdr
.offset
[curr_idx
++] = curr_offset
;
359 curr_offset
+= sbytes
;
362 sbytes
= otrx_create_align(trx
, curr_offset
, 4);
364 fprintf(stderr
, "Failed to append zeros\n");
366 curr_offset
+= sbytes
;
370 sbytes
= otrx_create_append_file(trx
, optarg
);
372 fprintf(stderr
, "Failed to append file %s\n", optarg
);
374 curr_offset
+= sbytes
;
377 sbytes
= otrx_create_align(trx
, curr_offset
, 4);
379 fprintf(stderr
, "Failed to append zeros\n");
381 curr_offset
+= sbytes
;
384 sbytes
= otrx_create_align(trx
, curr_offset
, strtol(optarg
, NULL
, 0));
386 fprintf(stderr
, "Failed to append zeros\n");
388 curr_offset
+= sbytes
;
391 sbytes
= strtol(optarg
, NULL
, 0) - curr_offset
;
393 fprintf(stderr
, "Current TRX length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset
, strtol(optarg
, NULL
, 0));
395 sbytes
= otrx_create_append_zeros(trx
, sbytes
);
397 fprintf(stderr
, "Failed to append zeros\n");
399 curr_offset
+= sbytes
;
404 magic
= strtoul(optarg
, &e
, 0);
405 if (errno
|| (e
== optarg
) || *e
)
406 fprintf(stderr
, "illegal magic string %s\n", optarg
);
408 hdr
.magic
= cpu_to_le32(magic
);
415 sbytes
= otrx_create_align(trx
, curr_offset
, 0x1000);
417 fprintf(stderr
, "Failed to append zeros\n");
419 curr_offset
+= sbytes
;
421 hdr
.length
= curr_offset
;
422 otrx_create_write_hdr(trx
, &hdr
);
429 /**************************************************
431 **************************************************/
433 static void otrx_extract_parse_options(int argc
, char **argv
) {
436 while ((c
= getopt(argc
, argv
, "c:e:o:1:2:3:")) != -1) {
439 trx_offset
= atoi(optarg
);
442 partition
[0] = optarg
;
445 partition
[1] = optarg
;
448 partition
[2] = optarg
;
454 static int otrx_extract_copy(FILE *trx
, size_t offset
, size_t length
, char *out_path
) {
460 out
= fopen(out_path
, "w");
462 fprintf(stderr
, "Couldn't open %s\n", out_path
);
467 buf
= malloc(length
);
469 fprintf(stderr
, "Couldn't alloc %zu B buffer\n", length
);
474 fseek(trx
, offset
, SEEK_SET
);
475 bytes
= fread(buf
, 1, length
, trx
);
476 if (bytes
!= length
) {
477 fprintf(stderr
, "Couldn't read %zu B of data from %s\n", length
, trx_path
);
482 bytes
= fwrite(buf
, 1, length
, out
);
483 if (bytes
!= length
) {
484 fprintf(stderr
, "Couldn't write %zu B to %s\n", length
, out_path
);
489 printf("Extracted 0x%zx bytes into %s\n", length
, out_path
);
499 static int otrx_extract(int argc
, char **argv
) {
501 struct trx_header hdr
;
507 fprintf(stderr
, "No TRX file passed\n");
514 otrx_extract_parse_options(argc
, argv
);
516 trx
= fopen(trx_path
, "r");
518 fprintf(stderr
, "Couldn't open %s\n", trx_path
);
523 fseek(trx
, trx_offset
, SEEK_SET
);
524 bytes
= fread(&hdr
, 1, sizeof(hdr
), trx
);
525 if (bytes
!= sizeof(hdr
)) {
526 fprintf(stderr
, "Couldn't read %s header\n", trx_path
);
531 if (le32_to_cpu(hdr
.magic
) != TRX_MAGIC
) {
532 fprintf(stderr
, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr
.magic
));
537 for (i
= 0; i
< TRX_MAX_PARTS
; i
++) {
542 if (!hdr
.offset
[i
]) {
543 printf("TRX doesn't contain partition %d, can't extract %s\n", i
+ 1, partition
[i
]);
547 if (i
+ 1 >= TRX_MAX_PARTS
|| !hdr
.offset
[i
+ 1])
548 length
= le32_to_cpu(hdr
.length
) - le32_to_cpu(hdr
.offset
[i
]);
550 length
= le32_to_cpu(hdr
.offset
[i
+ 1]) - le32_to_cpu(hdr
.offset
[i
]);
552 otrx_extract_copy(trx
, trx_offset
+ le32_to_cpu(hdr
.offset
[i
]), length
, partition
[i
]);
561 /**************************************************
563 **************************************************/
565 static void usage() {
568 printf("Checking TRX file:\n");
569 printf("\totrx check <file> [options]\tcheck if file is a valid TRX\n");
570 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
572 printf("Creating new TRX file:\n");
573 printf("\totrx create <file> [options] [partitions]\n");
574 printf("\t-f file\t\t\t\t[partition] start new partition with content copied from file\n");
575 printf("\t-A file\t\t\t\t[partition] append current partition with content copied from file\n");
576 printf("\t-a alignment\t\t\t[partition] align current partition\n");
577 printf("\t-b offset\t\t\t[partition] append zeros to partition till reaching absolute offset\n");
579 printf("Extracting from TRX file:\n");
580 printf("\totrx extract <file> [options]\textract partitions from TRX file\n");
581 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
582 printf("\t-1 file\t\t\t\tfile to extract 1st partition to (optional)\n");
583 printf("\t-2 file\t\t\t\tfile to extract 2nd partition to (optional)\n");
584 printf("\t-3 file\t\t\t\tfile to extract 3rd partition to (optional)\n");
587 int main(int argc
, char **argv
) {
589 if (!strcmp(argv
[1], "check"))
590 return otrx_check(argc
, argv
);
591 else if (!strcmp(argv
[1], "create"))
592 return otrx_create(argc
, argv
);
593 else if (!strcmp(argv
[1], "extract"))
594 return otrx_extract(argc
, argv
);