-
Notifications
You must be signed in to change notification settings - Fork 5
/
cartutils.c
341 lines (286 loc) · 7.78 KB
/
cartutils.c
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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
/*
* Based on f2a by Ulrich Hecht <uli@emulinks.de>
* if2a by D. Gauchard <deyv@free.fr>
* F2A Ultra support by Vincent Rubiolo <vincent.rubiolo@free.fr>
* Licensed under the terms of the GNU Public License version 2
*/
#include <stdio.h>
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <stdarg.h>
#include <sys/stat.h>
#include "libf2a.h"
int cart_verbose = 0;
int cart_io_sim = 0;
int filesize (const char* filename)
{
struct stat st;
if (stat(filename, &st) < 0)
{
printerrno("stat(%s)", filename);
return -1;
}
return st.st_size;
}
unsigned char* load_from_file(const char* filename, unsigned char* user_buffer, int* size)
{
// if buffer is NULL then memory is allocated and *size updated
// if buffer is not NULL, then
// - if *size if 0, then it is updated, otherwise it is used
// - buffer is filled with *size bytes
// (filesize must be >= *size)
// returns NULL if error otherwise the (possibly allocated) buffer
FILE* f;
int fsize;
unsigned char* buffer = user_buffer;
if ((fsize = filesize(filename)) < 0)
return NULL;
if (*size == 0)
*size = fsize;
if (*size > fsize)
{
printerr("Problem during size check for file %s (requested size %i < file size %i)\n", filename, *size, fsize);
return NULL;
}
if (!buffer && (buffer = (unsigned char*)malloc(*size)) == NULL)
{
printerrno("malloc(%i) for file '%s' loading", *size, filename);
return NULL;
}
if ((f = fopen(filename, "rb")) == NULL)
{
printerrno("fopen(%s)", filename);
if (!user_buffer)
free(buffer);
return NULL;
}
if (fread(buffer, *size, 1, f) != 1)
{
if (ferror(f))
printerrno("read(%s)", filename);
else
printerr("Could not read %i bytes from file %s\n", fsize, filename);
if (!user_buffer)
free(buffer);
return NULL;
}
fclose(f);
return buffer;
}
int buffer_from_file(const char* filename, unsigned char* buffer, int size_to_check)
{
// fills in buffer with contents of file named 'filename'
// checks that file is at minimum of size size_to_check
return load_from_file(filename, buffer, &size_to_check)? 0: -1;
}
unsigned char* download_from_file(const char* filename, int* size)
{
// load whole file, modify *size
*size = 0;
return load_from_file(filename, NULL, size);
}
int buffer_to_file(const char* filename, const unsigned char* buffer, int size_to_write)
{
// writes the contents of buffer into file named 'filename'
// if file exists, its contents get overwritten
FILE* f;
int res;
if ((f = fopen(filename, "wb")) == NULL)
{
printerrno("fopen(%s)", filename);
return -1;
}
if ((res = fwrite(buffer, size_to_write, 1, f)) != 1)
{
if (ferror(f))
printerrno("write(%s)", filename);
else
printerr("Could not write to file %s\n", filename);
return -1;
}
fclose(f);
return 0;
}
// binware_load:
// * parameters
// this function setups the dst binware according to the parameters.
// const binware_s binware[] is the binware array (null terminated) containing available internal choices
// char* file (can be null) is the user selection
// name is a text string to be displayed for verbosity
// * how to use
// file can be either
// - a digit ("0", "1"...) matching the desired internal binary (the digit is the index inside binware[])
// - a file name matching an existing file to load
// if the file is a digit and fits the binware[] array size, the matching binware is selected
// if the digit does not fit, the file is loaded
// if the file is null or cannot be loaded, an error is emitted and the list of available internal binaries is displayed
// (no error is emitted if the file matches the special string "list")
int binware_load (binware_s* dst, const binware_s binware[], const char* file, const char* name)
{
struct stat st;
// No file specified or file is a digit
if (!file || (strlen(file) == 1 && isdigit(file[0])))
{
int i;
int n;
if (file)
{
n = file[0] - '0';
for (i = 0; binware[i].size && i != n; i++);
}
else
i = 0; // default/fallback is to use first internal binary
if (binware[i].size || i == 0)
{
*dst = binware[i];
if (cart_verbose)
{
if (dst->name)
print("Will use internal file %s for %s if needed\n", dst->name, name);
else
print("No available binware for %s\n", name);
}
return 0;
}
}
if (stat(file, &st) == -1)
{
int error = errno;
if (error == ENOENT)
{
int i;
// This was a real file : print the errno
if (strcmp(file, "list") !=0)
printerr("%s: %s\n", file, strerror(error));
// In all cases, print help about internal binaries
print("Available internal files for %s:\n", name);
for (i = 0; binware[i].size; i++)
print("\t%i = %s (%i bytes)\n", i, binware[i].name, binware[i].size);
print("or\tname = any external file name\n");
// If the name was 'list', this is not an error
if (strcmp(file, "list") == 0)
return 0;
}
return -1;
}
if ((dst->data = download_from_file(file, &dst->size)) == NULL)
return -1;
dst->name = file;
if (cart_verbose)
print("Will use external file %s for %s if needed\n", dst->name, name);
return 0;
}
//////////////////////////////////////
// ntohl/htonl/ntohs/htons replacement
static int little_endian = -1;
int is_littleendian_host (void)
{
assert(little_endian != -1);
return little_endian != 0;
}
void check_endianness (void)
{
u_int16_t x = 1;
little_endian = ((char*)&x)[0] != 0;
if (cart_verbose > 1)
print("%s-endian host detected\n", little_endian? "Little": "Big");
}
u_int16_t swap16 (u_int16_t x)
{
u_int16_t y = x;
((char*)&y)[0] = ((char*)&x)[1];
((char*)&y)[1] = ((char*)&x)[0];
return y;
}
u_int32_t swap32 (u_int32_t x)
{
u_int32_t y = x;
((char*)&y)[0] = ((char*)&x)[3];
((char*)&y)[1] = ((char*)&x)[2];
((char*)&y)[2] = ((char*)&x)[1];
((char*)&y)[3] = ((char*)&x)[0];
return y;
}
u_int16_t ntoh16 (u_int16_t x)
{
assert(little_endian != -1);
return little_endian? swap16(x): x;
}
u_int16_t hton16 (u_int16_t x)
{
assert(little_endian != -1);
return little_endian? swap16(x): x;
}
u_int32_t ntoh32 (u_int32_t x)
{
assert(little_endian != -1);
return little_endian? swap32(x): x;
}
u_int32_t hton32 (u_int32_t x)
{
assert(little_endian != -1);
return little_endian? swap32(x): x;
}
u_int16_t tolittleendian16 (u_int16_t x)
{
assert(little_endian != -1);
return little_endian? x: swap16(x);
}
u_int32_t tolittleendian32 (u_int32_t x)
{
assert(little_endian != -1);
return little_endian? x: swap32(x);
}
//////////////////////////////////////
// default (terminal) print functions
#define PRINTLEN 256
// this one exactly acts like printf(...) does
void regular_print (const char* format, ...)
{
va_list ap;
va_start(ap, format);
vprintf(format, ap);
va_end(ap);
#if _WIN32
fflush(stdout);
#endif
}
// this one exactly acts like fprintf(stderr, ...) does
void regular_printerr (const char* format, ...)
{
va_list ap;
va_start(ap, format);
vfprintf(stderr, format, ap);
va_end(ap);
#if _WIN32
fflush(stderr);
#endif
}
// this one uses printerr and acts like perror(...) does
// it is even more interesting since text can be formatted like with printf
// (\n added though - for perror() compatibility)
void printerrno (const char* format, ...)
{
static char dialog[PRINTLEN];
va_list ap;
int err = errno;
va_start(ap,format);
vsnprintf(dialog, PRINTLEN, format, ap);
va_end(ap);
printerr("[errno=%i: %s] %s\n", err, strerror(err), dialog);
}
void regular_printflush (void)
{
fflush(stdout);
}
void regular_printerrflush (void)
{
fflush(stderr);
}
print_f print = regular_print;
printflush_f printflush = regular_printflush;
print_f printerr = regular_printerr;
printflush_f printerrflush = regular_printerrflush;