1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
|
/* SPDX-FileCopyrightText: (C) 2025 ZeldaRET */
/* SPDX-License-Identifier: MIT */
#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "endian.h"
#define NORETURN __attribute__((noreturn))
static void NORETURN
verror(const char *fmt, va_list args)
{
fputs("\x1b[91merror\x1b[97m: ", stderr);
vfprintf(stderr, fmt, args);
fputs("\x1b[0m", stderr);
exit(EXIT_FAILURE);
}
static void NORETURN
error(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
verror(fmt, args);
va_end(args);
}
static void NORETURN
error_post_open(const char *path_to_rm, FILE *file_to_rm, const char *fmt, ...)
{
// cleanup output file
fclose(file_to_rm);
if (remove(path_to_rm) != 0)
fprintf(stderr, "error calling remove(): %s", strerror(errno));
// error as normal
va_list args;
va_start(args, fmt);
verror(fmt, args);
va_end(args);
}
static void NORETURN
usage(const char *progname)
{
fprintf(stderr,
"usage: %s -t <fmt> [-pad] input.bin output.inc.c" "\n"
" fmt must be one of { 1, 2, 4, 8 }" "\n"
" if pad, align to fmt by filling with 0s, otherwise error if input is not aligned" "\n",
progname);
exit(EXIT_FAILURE);
}
#define BYTES_PER_ROW 32
#define LINE_MASK (BYTES_PER_ROW - 1)
int
main(int argc, char **argv)
{
const char *progname = argv[0];
const char *inpath = NULL;
const char *outpath = NULL;
const char *fmt_opt = NULL;
int fmt = 0;
bool pad = false;
// Collect arguments
int narg = 0;
for (int i = 1; i < argc; i++) {
if (argv[i][0] == '-') {
if (strcmp(argv[i], "-t") == 0) {
if (++i == argc)
usage(progname);
fmt_opt = argv[i];
char *end;
fmt = strtol(argv[i], &end, 10);
if (end != &argv[i][strlen(argv[i])])
error("Invalid base 10 integer %s\n", argv[i]);
} else if (strcmp(argv[i], "-pad") == 0) {
pad = true;
} else {
usage(progname);
}
} else {
switch (narg) {
case 0:
inpath = argv[i];
break;
case 1:
outpath = argv[i];
break;
default:
usage(progname);
break;
}
narg++;
}
}
// Check arguments
if (inpath == NULL || outpath == NULL || fmt_opt == NULL)
usage(progname);
if (fmt != 1 && fmt != 2 && fmt != 4 && fmt != 8)
error("Invalid fmt option '%s'. Valid options: [1, 2, 4, 8]\n", fmt_opt);
// Open the input binary file
FILE *infile = fopen(inpath, "rb");
if (infile == NULL)
error("Failed to open input file '%s' for reading: %s\n", inpath, strerror(errno));
// Get size
if (fseek(infile, 0, SEEK_END) != 0)
error("Could not ascertain input file size, could not seek to end: %s\n", strerror(errno));
size_t file_size = ftell(infile);
if (fseek(infile, 0, SEEK_SET) != 0)
error("Could not ascertain input file size, could not seek to start: %s\n", strerror(errno));
// Check alignment
if ((file_size & (fmt - 1)) != 0 && !pad) {
// Not aligned to data size and don't pad, error
error("Input file '%s' size (%lu) is not aligned to %d bytes\n", inpath, file_size, fmt);
}
// Open the output text file
FILE *outfile = fopen(outpath, "w");
if (outfile == NULL)
error("Failed to open output file '%s' for writing: %s\n", outpath, strerror(errno));
// Write data. If the input binary size was not aligned we either don't get this far or the option
// to pad with 0s is set.
bool was_newline = false;
for (size_t p = 0; p < file_size; p += fmt) {
size_t rem = fmt;
if (rem > file_size - p) // For any remaining unaligned data, rest will be padded with 0
rem = file_size - p;
// Read input
uint64_t d = 0;
if (fread(&d, 1, rem, infile) != rem)
error_post_open(outpath, outfile, "Error reading from input file '%s': %s\n", inpath, strerror(errno));
// Byteswap + shift
d = be64toh(d) >> (64 - 8 * fmt);
// Write output
bool was_newline = (((p + fmt) & LINE_MASK) == 0);
char end = was_newline ? '\n' : ' ';
if (fprintf(outfile, "0x%0*" PRIX64 ",%c", 2 * fmt, d, end) < 0)
error_post_open(outpath, outfile, "Error writing to output file '%s': %s\n", outpath, strerror(errno));
}
if (!was_newline) {
if (fputs("\n", outfile) == EOF)
error_post_open(outpath, outfile, "Error writing to output file '%s': %s\n", outpath, strerror(errno));
}
fclose(infile);
fclose(outfile);
return EXIT_SUCCESS;
}
|