131d8d6052eb8b268092889090e79a20be90bfb7
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 __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(uint8_t *buf
, size_t len
) {
124 uint32_t crc
= 0xffffffff;
127 crc
= crc32_tbl
[(crc
^ *buf
) & 0xff] ^ (crc
>> 8);
135 /**************************************************
137 **************************************************/
139 static void otrx_check_parse_options(int argc
, char **argv
) {
142 while ((c
= getopt(argc
, argv
, "o:")) != -1) {
145 trx_offset
= atoi(optarg
);
151 static int otrx_check(int argc
, char **argv
) {
153 struct trx_header hdr
;
154 size_t bytes
, length
;
161 fprintf(stderr
, "No TRX file passed\n");
168 otrx_check_parse_options(argc
, argv
);
170 trx
= fopen(trx_path
, "r");
172 fprintf(stderr
, "Couldn't open %s\n", trx_path
);
177 fseek(trx
, trx_offset
, SEEK_SET
);
178 bytes
= fread(&hdr
, 1, sizeof(hdr
), trx
);
179 if (bytes
!= sizeof(hdr
)) {
180 fprintf(stderr
, "Couldn't read %s header\n", trx_path
);
185 if (le32_to_cpu(hdr
.magic
) != TRX_MAGIC
) {
186 fprintf(stderr
, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr
.magic
));
191 length
= le32_to_cpu(hdr
.length
);
192 if (length
< sizeof(hdr
)) {
193 fprintf(stderr
, "Length read from TRX too low (%zu B)\n", length
);
199 fseek(trx
, trx_offset
+ TRX_FLAGS_OFFSET
, SEEK_SET
);
200 length
-= TRX_FLAGS_OFFSET
;
201 while ((bytes
= fread(buf
, 1, otrx_min(sizeof(buf
), length
), trx
)) > 0) {
202 for (i
= 0; i
< bytes
; i
++)
203 crc32
= crc32_tbl
[(crc32
^ buf
[i
]) & 0xff] ^ (crc32
>> 8);
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
);
302 buf
= malloc(length
);
304 fprintf(stderr
, "Couldn't alloc %zu B buffer\n", length
);
308 fseek(trx
, 0, SEEK_SET
);
309 bytes
= fread(buf
, 1, length
, trx
);
310 if (bytes
!= length
) {
311 fprintf(stderr
, "Couldn't read %zu B of data from %s\n", length
, trx_path
);
315 crc32
= otrx_crc32(buf
+ TRX_FLAGS_OFFSET
, length
- TRX_FLAGS_OFFSET
);
316 hdr
->crc32
= cpu_to_le32(crc32
);
318 fseek(trx
, 0, SEEK_SET
);
319 bytes
= fwrite(hdr
, 1, sizeof(struct trx_header
), trx
);
320 if (bytes
!= sizeof(struct trx_header
)) {
321 fprintf(stderr
, "Couldn't write TRX header to %s\n", trx_path
);
328 static int otrx_create(int argc
, char **argv
) {
330 struct trx_header hdr
= {};
333 size_t curr_offset
= sizeof(hdr
);
338 fprintf(stderr
, "No TRX file passed\n");
345 otrx_create_parse_options(argc
, argv
);
347 trx
= fopen(trx_path
, "w+");
349 fprintf(stderr
, "Couldn't open %s\n", trx_path
);
353 fseek(trx
, curr_offset
, SEEK_SET
);
356 while ((c
= getopt(argc
, argv
, "f:b:")) != -1) {
359 if (curr_idx
>= TRX_MAX_PARTS
) {
361 fprintf(stderr
, "Reached TRX partitions limit, no place for %s\n", optarg
);
365 sbytes
= otrx_create_append_file(trx
, optarg
);
367 fprintf(stderr
, "Failed to append file %s\n", optarg
);
369 hdr
.offset
[curr_idx
++] = curr_offset
;
370 curr_offset
+= sbytes
;
373 sbytes
= otrx_create_align(trx
, curr_offset
, 4);
375 fprintf(stderr
, "Failed to append zeros\n");
377 curr_offset
+= sbytes
;
381 sbytes
= strtol(optarg
, NULL
, 0) - curr_offset
;
383 fprintf(stderr
, "Current TRX length is 0x%zx, can't pad it with zeros to 0x%lx\n", curr_offset
, strtol(optarg
, NULL
, 0));
385 sbytes
= otrx_create_append_zeros(trx
, sbytes
);
387 fprintf(stderr
, "Failed to append zeros\n");
389 curr_offset
+= sbytes
;
397 hdr
.length
= curr_offset
;
398 otrx_create_write_hdr(trx
, &hdr
);
405 /**************************************************
407 **************************************************/
409 static void otrx_extract_parse_options(int argc
, char **argv
) {
412 while ((c
= getopt(argc
, argv
, "c:e:o:1:2:3:")) != -1) {
415 trx_offset
= atoi(optarg
);
418 partition
[0] = optarg
;
421 partition
[1] = optarg
;
424 partition
[2] = optarg
;
430 static int otrx_extract_copy(FILE *trx
, size_t offset
, size_t length
, char *out_path
) {
436 out
= fopen(out_path
, "w");
438 fprintf(stderr
, "Couldn't open %s\n", out_path
);
443 buf
= malloc(length
);
445 fprintf(stderr
, "Couldn't alloc %zu B buffer\n", length
);
450 fseek(trx
, offset
, SEEK_SET
);
451 bytes
= fread(buf
, 1, length
, trx
);
452 if (bytes
!= length
) {
453 fprintf(stderr
, "Couldn't read %zu B of data from %s\n", length
, trx_path
);
458 bytes
= fwrite(buf
, 1, length
, out
);
459 if (bytes
!= length
) {
460 fprintf(stderr
, "Couldn't write %zu B to %s\n", length
, out_path
);
465 printf("Extracted 0x%zx bytes into %s\n", length
, out_path
);
475 static int otrx_extract(int argc
, char **argv
) {
477 struct trx_header hdr
;
483 fprintf(stderr
, "No TRX file passed\n");
490 otrx_extract_parse_options(argc
, argv
);
492 trx
= fopen(trx_path
, "r");
494 fprintf(stderr
, "Couldn't open %s\n", trx_path
);
499 fseek(trx
, trx_offset
, SEEK_SET
);
500 bytes
= fread(&hdr
, 1, sizeof(hdr
), trx
);
501 if (bytes
!= sizeof(hdr
)) {
502 fprintf(stderr
, "Couldn't read %s header\n", trx_path
);
507 if (le32_to_cpu(hdr
.magic
) != TRX_MAGIC
) {
508 fprintf(stderr
, "Invalid TRX magic: 0x%08x\n", le32_to_cpu(hdr
.magic
));
513 for (i
= 0; i
< TRX_MAX_PARTS
; i
++) {
518 if (!hdr
.offset
[i
]) {
519 printf("TRX doesn't contain partition %d, can't extract %s\n", i
+ 1, partition
[i
]);
523 if (i
+ 1 >= TRX_MAX_PARTS
|| !hdr
.offset
[i
+ 1])
524 length
= le32_to_cpu(hdr
.length
) - le32_to_cpu(hdr
.offset
[i
]);
526 length
= le32_to_cpu(hdr
.offset
[i
+ 1]) - le32_to_cpu(hdr
.offset
[i
]);
528 otrx_extract_copy(trx
, trx_offset
+ le32_to_cpu(hdr
.offset
[i
]), length
, partition
[i
]);
537 /**************************************************
539 **************************************************/
541 static void usage() {
544 printf("Checking TRX file:\n");
545 printf("\totrx check <file> [options]\tcheck if file is a valid TRX\n");
546 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
548 printf("Creating new TRX file:\n");
549 printf("\totrx create <file> [options] [partitions]\n");
550 printf("\t-f file\t\t\t\t[partition] start new partition with content copied from file\n");
551 printf("\t-b offset\t\t\t[partition] append zeros to partition till reaching absolute offset\n");
553 printf("Extracting from TRX file:\n");
554 printf("\totrx extract <file> [options]\textract partitions from TRX file\n");
555 printf("\t-o offset\t\t\toffset of TRX data in file (default: 0)\n");
556 printf("\t-1 file\t\t\t\tfile to extract 1st partition to (optional)\n");
557 printf("\t-2 file\t\t\t\tfile to extract 2nd partition to (optional)\n");
558 printf("\t-3 file\t\t\t\tfile to extract 3rd partition to (optional)\n");
561 int main(int argc
, char **argv
) {
563 if (!strcmp(argv
[1], "check"))
564 return otrx_check(argc
, argv
);
565 else if (!strcmp(argv
[1], "create"))
566 return otrx_create(argc
, argv
);
567 else if (!strcmp(argv
[1], "extract"))
568 return otrx_extract(argc
, argv
);