101a31004dcd4e69606ccba61b8caa2c8fbad168
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(uint8_t *buf
, size_t len
) {
128 uint32_t crc
= 0xffffffff;
131 crc
= crc32_tbl
[(crc
^ *buf
) & 0xff] ^ (crc
>> 8);
139 /**************************************************
141 **************************************************/
143 static void otrx_check_parse_options(int argc
, char **argv
) {
146 while ((c
= getopt(argc
, argv
, "o:")) != -1) {
149 trx_offset
= atoi(optarg
);
155 static int otrx_check(int argc
, char **argv
) {
157 struct trx_header hdr
;
158 size_t bytes
, length
;
165 fprintf(stderr
, "No TRX file passed\n");
172 otrx_check_parse_options(argc
, argv
);
174 trx
= fopen(trx_path
, "r");
176 fprintf(stderr
, "Couldn't open %s\n", trx_path
);
181 fseek(trx
, trx_offset
, SEEK_SET
);
182 bytes
= fread(&hdr
, 1, sizeof(hdr
), trx
);
183 if (bytes
!= sizeof(hdr
)) {
184 fprintf(stderr
, "Couldn't read %s header\n", trx_path
);
189 if (le32_to_cpu(hdr
.magic
) != TRX_MAGIC
) {
190 fprintf(stderr
, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr
.magic
));
195 length
= le32_to_cpu(hdr
.length
);
196 if (length
< sizeof(hdr
)) {
197 fprintf(stderr
, "Length read from TRX too low (%zu B)\n", length
);
203 fseek(trx
, trx_offset
+ TRX_FLAGS_OFFSET
, SEEK_SET
);
204 length
-= TRX_FLAGS_OFFSET
;
205 while ((bytes
= fread(buf
, 1, otrx_min(sizeof(buf
), length
), trx
)) > 0) {
206 for (i
= 0; i
< bytes
; i
++)
207 crc32
= crc32_tbl
[(crc32
^ buf
[i
]) & 0xff] ^ (crc32
>> 8);
212 fprintf(stderr
, "Couldn't read last %zd B of data from %s\n", length
, trx_path
);
217 if (crc32
!= le32_to_cpu(hdr
.crc32
)) {
218 fprintf(stderr
, "Invalid data crc32: 0x%08x instead of 0x%08x\n", crc32
, le32_to_cpu(hdr
.crc32
));
223 printf("Found a valid TRX version %d\n", le32_to_cpu(hdr
.version
));
231 /**************************************************
233 **************************************************/
235 static void otrx_create_parse_options(int argc
, char **argv
) {
238 static ssize_t
otrx_create_append_file(FILE *trx
, const char *in_path
) {
244 in
= fopen(in_path
, "r");
246 fprintf(stderr
, "Couldn't open %s\n", in_path
);
250 while ((bytes
= fread(buf
, 1, sizeof(buf
), in
)) > 0) {
251 if (fwrite(buf
, 1, bytes
, trx
) != bytes
) {
252 fprintf(stderr
, "Couldn't write %zu B to %s\n", bytes
, trx_path
);
264 static ssize_t
otrx_create_append_zeros(FILE *trx
, size_t length
) {
267 buf
= malloc(length
);
270 memset(buf
, 0, length
);
272 if (fwrite(buf
, 1, length
, trx
) != length
) {
273 fprintf(stderr
, "Couldn't write %zu B to %s\n", length
, trx_path
);
280 static ssize_t
otrx_create_align(FILE *trx
, size_t curr_offset
, size_t alignment
) {
281 if (curr_offset
& (alignment
- 1)) {
282 size_t length
= alignment
- (curr_offset
% alignment
);
283 return otrx_create_append_zeros(trx
, length
);
289 static int otrx_create_write_hdr(FILE *trx
, struct trx_header
*hdr
) {
290 size_t bytes
, length
;
294 hdr
->magic
= cpu_to_le32(TRX_MAGIC
);
297 fseek(trx
, 0, SEEK_SET
);
298 bytes
= fwrite(hdr
, 1, sizeof(struct trx_header
), trx
);
299 if (bytes
!= sizeof(struct trx_header
)) {
300 fprintf(stderr
, "Couldn't write TRX header to %s\n", trx_path
);
304 length
= le32_to_cpu(hdr
->length
);
306 buf
= malloc(length
);
308 fprintf(stderr
, "Couldn't alloc %zu B buffer\n", length
);
312 fseek(trx
, 0, SEEK_SET
);
313 bytes
= fread(buf
, 1, length
, trx
);
314 if (bytes
!= length
) {
315 fprintf(stderr
, "Couldn't read %zu B of data from %s\n", length
, trx_path
);
319 crc32
= otrx_crc32(buf
+ TRX_FLAGS_OFFSET
, length
- TRX_FLAGS_OFFSET
);
320 hdr
->crc32
= cpu_to_le32(crc32
);
322 fseek(trx
, 0, SEEK_SET
);
323 bytes
= fwrite(hdr
, 1, sizeof(struct trx_header
), trx
);
324 if (bytes
!= sizeof(struct trx_header
)) {
325 fprintf(stderr
, "Couldn't write TRX header to %s\n", trx_path
);
332 static int otrx_create(int argc
, char **argv
) {
334 struct trx_header hdr
= {};
337 size_t curr_offset
= sizeof(hdr
);
342 fprintf(stderr
, "No TRX file passed\n");
349 otrx_create_parse_options(argc
, argv
);
351 trx
= fopen(trx_path
, "w+");
353 fprintf(stderr
, "Couldn't open %s\n", trx_path
);
357 fseek(trx
, curr_offset
, SEEK_SET
);
360 while ((c
= getopt(argc
, argv
, "f:b:")) != -1) {
363 if (curr_idx
>= TRX_MAX_PARTS
) {
365 fprintf(stderr
, "Reached TRX partitions limit, no place for %s\n", optarg
);
369 sbytes
= otrx_create_append_file(trx
, optarg
);
371 fprintf(stderr
, "Failed to append file %s\n", optarg
);
373 hdr
.offset
[curr_idx
++] = curr_offset
;
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
;
385 sbytes
= strtol(optarg
, NULL
, 0) - curr_offset
;
387 fprintf(stderr
, "Current TRX length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset
, strtol(optarg
, NULL
, 0));
389 sbytes
= otrx_create_append_zeros(trx
, sbytes
);
391 fprintf(stderr
, "Failed to append zeros\n");
393 curr_offset
+= sbytes
;
401 hdr
.length
= curr_offset
;
402 otrx_create_write_hdr(trx
, &hdr
);
409 /**************************************************
411 **************************************************/
413 static void otrx_extract_parse_options(int argc
, char **argv
) {
416 while ((c
= getopt(argc
, argv
, "c:e:o:1:2:3:")) != -1) {
419 trx_offset
= atoi(optarg
);
422 partition
[0] = optarg
;
425 partition
[1] = optarg
;
428 partition
[2] = optarg
;
434 static int otrx_extract_copy(FILE *trx
, size_t offset
, size_t length
, char *out_path
) {
440 out
= fopen(out_path
, "w");
442 fprintf(stderr
, "Couldn't open %s\n", out_path
);
447 buf
= malloc(length
);
449 fprintf(stderr
, "Couldn't alloc %zu B buffer\n", length
);
454 fseek(trx
, offset
, SEEK_SET
);
455 bytes
= fread(buf
, 1, length
, trx
);
456 if (bytes
!= length
) {
457 fprintf(stderr
, "Couldn't read %zu B of data from %s\n", length
, trx_path
);
462 bytes
= fwrite(buf
, 1, length
, out
);
463 if (bytes
!= length
) {
464 fprintf(stderr
, "Couldn't write %zu B to %s\n", length
, out_path
);
469 printf("Extracted 0x%zx bytes into %s\n", length
, out_path
);
479 static int otrx_extract(int argc
, char **argv
) {
481 struct trx_header hdr
;
487 fprintf(stderr
, "No TRX file passed\n");
494 otrx_extract_parse_options(argc
, argv
);
496 trx
= fopen(trx_path
, "r");
498 fprintf(stderr
, "Couldn't open %s\n", trx_path
);
503 fseek(trx
, trx_offset
, SEEK_SET
);
504 bytes
= fread(&hdr
, 1, sizeof(hdr
), trx
);
505 if (bytes
!= sizeof(hdr
)) {
506 fprintf(stderr
, "Couldn't read %s header\n", trx_path
);
511 if (le32_to_cpu(hdr
.magic
) != TRX_MAGIC
) {
512 fprintf(stderr
, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr
.magic
));
517 for (i
= 0; i
< TRX_MAX_PARTS
; i
++) {
522 if (!hdr
.offset
[i
]) {
523 printf("TRX doesn't contain partition %d, can't extract %s\n", i
+ 1, partition
[i
]);
527 if (i
+ 1 >= TRX_MAX_PARTS
|| !hdr
.offset
[i
+ 1])
528 length
= le32_to_cpu(hdr
.length
) - le32_to_cpu(hdr
.offset
[i
]);
530 length
= le32_to_cpu(hdr
.offset
[i
+ 1]) - le32_to_cpu(hdr
.offset
[i
]);
532 otrx_extract_copy(trx
, trx_offset
+ le32_to_cpu(hdr
.offset
[i
]), length
, partition
[i
]);
541 /**************************************************
543 **************************************************/
545 static void usage() {
548 printf("Checking TRX file:\n");
549 printf("\totrx check <file> [options]\tcheck if file is a valid TRX\n");
550 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
552 printf("Creating new TRX file:\n");
553 printf("\totrx create <file> [options] [partitions]\n");
554 printf("\t-f file\t\t\t\t[partition] start new partition with content copied from file\n");
555 printf("\t-b offset\t\t\t[partition] append zeros to partition till reaching absolute offset\n");
557 printf("Extracting from TRX file:\n");
558 printf("\totrx extract <file> [options]\textract partitions from TRX file\n");
559 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
560 printf("\t-1 file\t\t\t\tfile to extract 1st partition to (optional)\n");
561 printf("\t-2 file\t\t\t\tfile to extract 2nd partition to (optional)\n");
562 printf("\t-3 file\t\t\t\tfile to extract 3rd partition to (optional)\n");
565 int main(int argc
, char **argv
) {
567 if (!strcmp(argv
[1], "check"))
568 return otrx_check(argc
, argv
);
569 else if (!strcmp(argv
[1], "create"))
570 return otrx_create(argc
, argv
);
571 else if (!strcmp(argv
[1], "extract"))
572 return otrx_extract(argc
, argv
);