1 // SPDX-License-Identifier: GPL-2.0-or-later
5 * Copyright (C) 2015-2017 Rafał Miłecki <zajec5@gmail.com>
18 #if !defined(__BYTE_ORDER)
19 #error "Unknown byte order"
22 #if __BYTE_ORDER == __BIG_ENDIAN
23 #define cpu_to_le32(x) bswap_32(x)
24 #define le32_to_cpu(x) bswap_32(x)
25 #elif __BYTE_ORDER == __LITTLE_ENDIAN
26 #define cpu_to_le32(x) (x)
27 #define le32_to_cpu(x) (x)
29 #error "Unsupported endianness"
32 #define TRX_MAGIC 0x30524448
33 #define TRX_FLAGS_OFFSET 12
34 #define TRX_MAX_PARTS 3
47 struct trx_header hdr
;
51 size_t trx_offset
= 0;
52 char *partition
[TRX_MAX_PARTS
] = {};
54 static inline size_t otrx_min(size_t x
, size_t y
) {
58 /**************************************************
60 **************************************************/
62 static const uint32_t crc32_tbl
[] = {
63 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
64 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
65 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
66 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
67 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
68 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
69 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
70 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
71 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
72 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
73 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
74 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
75 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
76 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
77 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
78 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
79 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
80 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
81 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
82 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
83 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
84 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
85 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
86 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
87 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
88 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
89 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
90 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
91 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
92 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
93 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
94 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
95 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
96 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
97 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
98 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
99 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
100 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
101 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
102 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
103 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
104 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
105 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
106 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
107 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
108 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
109 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
110 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
111 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
112 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
113 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
114 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
115 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
116 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
117 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
118 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
119 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
120 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
121 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
122 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
123 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
124 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
125 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
126 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
129 uint32_t otrx_crc32(uint32_t crc
, uint8_t *buf
, size_t len
) {
131 crc
= crc32_tbl
[(crc
^ *buf
) & 0xff] ^ (crc
>> 8);
139 /**************************************************
141 **************************************************/
143 static FILE *otrx_open(const char *pathname
, const char *mode
) {
144 if (strcmp(pathname
, "-"))
145 return fopen(pathname
, mode
);
147 if (isatty(fileno(stdin
))) {
148 fprintf(stderr
, "Reading from TTY stdin is unsupported\n");
155 static int otrx_skip(FILE *fp
, size_t length
)
157 if (fseek(fp
, length
, SEEK_CUR
)) {
162 bytes
= fread(buf
, 1, otrx_min(sizeof(buf
), length
), fp
);
172 static void otrx_close(FILE *fp
) {
177 static int otrx_open_parse(const char *pathname
, const char *mode
,
178 struct otrx_ctx
*otrx
)
184 otrx
->fp
= otrx_open(pathname
, mode
);
186 fprintf(stderr
, "Couldn't open %s\n", pathname
);
191 if (trx_offset
&& otrx_skip(otrx
->fp
, trx_offset
)) {
192 fprintf(stderr
, "Couldn't skip first %zd B\n", trx_offset
);
197 bytes
= fread(&otrx
->hdr
, 1, sizeof(otrx
->hdr
), otrx
->fp
);
198 if (bytes
!= sizeof(otrx
->hdr
)) {
199 fprintf(stderr
, "Couldn't read %s header\n", pathname
);
204 if (le32_to_cpu(otrx
->hdr
.magic
) != TRX_MAGIC
) {
205 fprintf(stderr
, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(otrx
->hdr
.magic
));
210 length
= le32_to_cpu(otrx
->hdr
.length
);
211 if (length
< sizeof(otrx
->hdr
)) {
212 fprintf(stderr
, "Length read from TRX too low (%zu B)\n", length
);
220 otrx_close(otrx
->fp
);
225 /**************************************************
227 **************************************************/
229 static void otrx_check_parse_options(int argc
, char **argv
) {
232 while ((c
= getopt(argc
, argv
, "o:")) != -1) {
235 trx_offset
= atoi(optarg
);
241 static int otrx_check(int argc
, char **argv
) {
242 struct otrx_ctx otrx
= { };
243 size_t bytes
, length
;
249 fprintf(stderr
, "No TRX file passed\n");
256 otrx_check_parse_options(argc
, argv
);
258 err
= otrx_open_parse(trx_path
, "r", &otrx
);
260 fprintf(stderr
, "Couldn't open & parse %s: %d\n", trx_path
, err
);
266 crc32
= otrx_crc32(crc32
, (uint8_t *)&otrx
.hdr
+ TRX_FLAGS_OFFSET
, sizeof(otrx
.hdr
) - TRX_FLAGS_OFFSET
);
267 length
= le32_to_cpu(otrx
.hdr
.length
) - sizeof(otrx
.hdr
);
268 while ((bytes
= fread(buf
, 1, otrx_min(sizeof(buf
), length
), otrx
.fp
)) > 0) {
269 crc32
= otrx_crc32(crc32
, buf
, bytes
);
274 fprintf(stderr
, "Couldn't read last %zd B of data from %s\n", length
, trx_path
);
279 if (crc32
!= le32_to_cpu(otrx
.hdr
.crc32
)) {
280 fprintf(stderr
, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32
, le32_to_cpu(otrx
.hdr
.crc32
));
285 printf("Found a valid TRX version %d\n", le32_to_cpu(otrx
.hdr
.version
));
293 /**************************************************
295 **************************************************/
297 static ssize_t
otrx_create_append_file(FILE *trx
, const char *in_path
) {
303 in
= fopen(in_path
, "r");
305 fprintf(stderr
, "Couldn't open %s\n", in_path
);
309 while ((bytes
= fread(buf
, 1, sizeof(buf
), in
)) > 0) {
310 if (fwrite(buf
, 1, bytes
, trx
) != bytes
) {
311 fprintf(stderr
, "Couldn't write %zu B to %s\n", bytes
, trx_path
);
323 static ssize_t
otrx_create_append_zeros(FILE *trx
, size_t length
) {
326 buf
= malloc(length
);
329 memset(buf
, 0, length
);
331 if (fwrite(buf
, 1, length
, trx
) != length
) {
332 fprintf(stderr
, "Couldn't write %zu B to %s\n", length
, trx_path
);
342 static ssize_t
otrx_create_align(FILE *trx
, size_t curr_offset
, size_t alignment
) {
343 if (curr_offset
& (alignment
- 1)) {
344 size_t length
= alignment
- (curr_offset
% alignment
);
345 return otrx_create_append_zeros(trx
, length
);
351 static int otrx_create_write_hdr(FILE *trx
, struct trx_header
*hdr
) {
352 size_t bytes
, length
;
358 fseek(trx
, 0, SEEK_SET
);
359 bytes
= fwrite(hdr
, 1, sizeof(struct trx_header
), trx
);
360 if (bytes
!= sizeof(struct trx_header
)) {
361 fprintf(stderr
, "Couldn't write TRX header to %s\n", trx_path
);
365 length
= le32_to_cpu(hdr
->length
);
368 fseek(trx
, TRX_FLAGS_OFFSET
, SEEK_SET
);
369 length
-= TRX_FLAGS_OFFSET
;
370 while ((bytes
= fread(buf
, 1, otrx_min(sizeof(buf
), length
), trx
)) > 0) {
371 crc32
= otrx_crc32(crc32
, buf
, bytes
);
374 hdr
->crc32
= cpu_to_le32(crc32
);
376 fseek(trx
, 0, SEEK_SET
);
377 bytes
= fwrite(hdr
, 1, sizeof(struct trx_header
), trx
);
378 if (bytes
!= sizeof(struct trx_header
)) {
379 fprintf(stderr
, "Couldn't write TRX header to %s\n", trx_path
);
386 static int otrx_create(int argc
, char **argv
) {
388 struct trx_header hdr
= {};
391 size_t curr_offset
= sizeof(hdr
);
397 hdr
.magic
= cpu_to_le32(TRX_MAGIC
);
400 fprintf(stderr
, "No TRX file passed\n");
406 trx
= fopen(trx_path
, "w+");
408 fprintf(stderr
, "Couldn't open %s\n", trx_path
);
412 fseek(trx
, curr_offset
, SEEK_SET
);
415 while ((c
= getopt(argc
, argv
, "f:A:a:b:M:")) != -1) {
418 if (curr_idx
>= TRX_MAX_PARTS
) {
420 fprintf(stderr
, "Reached TRX partitions limit, no place for %s\n", optarg
);
424 sbytes
= otrx_create_append_file(trx
, optarg
);
426 fprintf(stderr
, "Failed to append file %s\n", optarg
);
428 hdr
.offset
[curr_idx
++] = curr_offset
;
429 curr_offset
+= sbytes
;
432 sbytes
= otrx_create_align(trx
, curr_offset
, 4);
434 fprintf(stderr
, "Failed to append zeros\n");
436 curr_offset
+= sbytes
;
440 sbytes
= otrx_create_append_file(trx
, optarg
);
442 fprintf(stderr
, "Failed to append file %s\n", optarg
);
444 curr_offset
+= sbytes
;
447 sbytes
= otrx_create_align(trx
, curr_offset
, 4);
449 fprintf(stderr
, "Failed to append zeros\n");
451 curr_offset
+= sbytes
;
454 sbytes
= otrx_create_align(trx
, curr_offset
, strtol(optarg
, NULL
, 0));
456 fprintf(stderr
, "Failed to append zeros\n");
458 curr_offset
+= sbytes
;
461 sbytes
= strtol(optarg
, NULL
, 0) - curr_offset
;
463 fprintf(stderr
, "Current TRX length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset
, strtol(optarg
, NULL
, 0));
465 sbytes
= otrx_create_append_zeros(trx
, sbytes
);
467 fprintf(stderr
, "Failed to append zeros\n");
469 curr_offset
+= sbytes
;
474 magic
= strtoul(optarg
, &e
, 0);
475 if (errno
|| (e
== optarg
) || *e
)
476 fprintf(stderr
, "illegal magic string %s\n", optarg
);
478 hdr
.magic
= cpu_to_le32(magic
);
485 sbytes
= otrx_create_align(trx
, curr_offset
, 0x1000);
487 fprintf(stderr
, "Failed to append zeros\n");
489 curr_offset
+= sbytes
;
491 hdr
.length
= curr_offset
;
492 otrx_create_write_hdr(trx
, &hdr
);
499 /**************************************************
501 **************************************************/
503 static void otrx_extract_parse_options(int argc
, char **argv
) {
506 while ((c
= getopt(argc
, argv
, "c:e:o:1:2:3:")) != -1) {
509 trx_offset
= atoi(optarg
);
512 partition
[0] = optarg
;
515 partition
[1] = optarg
;
518 partition
[2] = optarg
;
524 static int otrx_extract_copy(FILE *trx
, size_t offset
, size_t length
, char *out_path
) {
530 out
= fopen(out_path
, "w");
532 fprintf(stderr
, "Couldn't open %s\n", out_path
);
537 buf
= malloc(length
);
539 fprintf(stderr
, "Couldn't alloc %zu B buffer\n", length
);
544 fseek(trx
, offset
, SEEK_SET
);
545 bytes
= fread(buf
, 1, length
, trx
);
546 if (bytes
!= length
) {
547 fprintf(stderr
, "Couldn't read %zu B of data from %s\n", length
, trx_path
);
552 bytes
= fwrite(buf
, 1, length
, out
);
553 if (bytes
!= length
) {
554 fprintf(stderr
, "Couldn't write %zu B to %s\n", length
, out_path
);
559 printf("Extracted 0x%zx bytes into %s\n", length
, out_path
);
569 static int otrx_extract(int argc
, char **argv
) {
570 struct otrx_ctx otrx
= { };
575 fprintf(stderr
, "No TRX file passed\n");
582 otrx_extract_parse_options(argc
, argv
);
584 err
= otrx_open_parse(trx_path
, "r", &otrx
);
586 fprintf(stderr
, "Couldn't open & parse %s: %d\n", trx_path
, err
);
591 for (i
= 0; i
< TRX_MAX_PARTS
; i
++) {
596 if (!otrx
.hdr
.offset
[i
]) {
597 printf("TRX doesn't contain partition %d, can't extract %s\n", i
+ 1, partition
[i
]);
601 if (i
+ 1 >= TRX_MAX_PARTS
|| !otrx
.hdr
.offset
[i
+ 1])
602 length
= le32_to_cpu(otrx
.hdr
.length
) - le32_to_cpu(otrx
.hdr
.offset
[i
]);
604 length
= le32_to_cpu(otrx
.hdr
.offset
[i
+ 1]) - le32_to_cpu(otrx
.hdr
.offset
[i
]);
606 otrx_extract_copy(otrx
.fp
, trx_offset
+ le32_to_cpu(otrx
.hdr
.offset
[i
]), length
, partition
[i
]);
614 /**************************************************
616 **************************************************/
618 static void usage() {
621 printf("Checking TRX file:\n");
622 printf("\totrx check <file> [options]\tcheck if file is a valid TRX\n");
623 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
625 printf("Creating new TRX file:\n");
626 printf("\totrx create <file> [options] [partitions]\n");
627 printf("\t-f file\t\t\t\t[partition] start new partition with content copied from file\n");
628 printf("\t-A file\t\t\t\t[partition] append current partition with content copied from file\n");
629 printf("\t-a alignment\t\t\t[partition] align current partition\n");
630 printf("\t-b offset\t\t\t[partition] append zeros to partition till reaching absolute offset\n");
632 printf("Extracting from TRX file:\n");
633 printf("\totrx extract <file> [options]\textract partitions from TRX file\n");
634 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
635 printf("\t-1 file\t\t\t\tfile to extract 1st partition to (optional)\n");
636 printf("\t-2 file\t\t\t\tfile to extract 2nd partition to (optional)\n");
637 printf("\t-3 file\t\t\t\tfile to extract 3rd partition to (optional)\n");
640 int main(int argc
, char **argv
) {
642 if (!strcmp(argv
[1], "check"))
643 return otrx_check(argc
, argv
);
644 else if (!strcmp(argv
[1], "create"))
645 return otrx_create(argc
, argv
);
646 else if (!strcmp(argv
[1], "extract"))
647 return otrx_extract(argc
, argv
);