Line |
Branch |
Exec |
Source |
1 |
|
|
#include "asar.h" |
2 |
|
|
#include "crc32.h" |
3 |
|
|
#include "virtualfile.h" |
4 |
|
|
#include "platform/file-helpers.h" |
5 |
|
|
#include "interface-shared.h" |
6 |
|
|
#include "assembleblock.h" |
7 |
|
|
#include "asar_math.h" |
8 |
|
|
#include "platform/thread-helpers.h" |
9 |
|
|
|
10 |
|
|
#if defined(CPPCLI) |
11 |
|
|
#define EXPORT extern "C" |
12 |
|
|
#elif defined(_WIN32) |
13 |
|
|
#ifdef ASAR_SHARED |
14 |
|
|
#define EXPORT extern "C" __declspec(dllexport) |
15 |
|
|
#elif defined(ASAR_STATIC) |
16 |
|
|
#define EXPORT extern "C" |
17 |
|
|
#endif |
18 |
|
|
#else |
19 |
|
|
#define EXPORT extern "C" __attribute__ ((visibility ("default"))) |
20 |
|
|
#endif |
21 |
|
|
|
22 |
|
|
static autoarray<const char *> prints; |
23 |
|
|
static string symbolsfile; |
24 |
|
|
static int numprint; |
25 |
|
|
static uint32_t romCrc; |
26 |
|
|
|
27 |
|
|
#define APIVERSION 400 |
28 |
|
|
|
29 |
|
|
// note: somewhat fragile, assumes that every patchparams struct inherits from exactly the previous one |
30 |
|
|
/* $EXPORTSTRUCT_PP$ |
31 |
|
|
*/ |
32 |
|
|
struct patchparams_base { |
33 |
|
|
// The size of this struct. Set to (int)sizeof(patchparams). |
34 |
|
|
int structsize; |
35 |
|
|
}; |
36 |
|
|
|
37 |
|
|
|
38 |
|
|
/* $EXPORTSTRUCT$ |
39 |
|
|
*/ |
40 |
|
|
struct stackentry { |
41 |
|
|
const char * fullpath; |
42 |
|
|
const char * prettypath; |
43 |
|
|
int lineno; |
44 |
|
|
const char * details; |
45 |
|
|
}; |
46 |
|
|
|
47 |
|
|
/* $EXPORTSTRUCT$ |
48 |
|
|
*/ |
49 |
|
|
struct errordata { |
50 |
|
|
const char * fullerrdata; |
51 |
|
|
const char * rawerrdata; |
52 |
|
|
const char * block; |
53 |
|
|
const char * filename; |
54 |
|
|
int line; |
55 |
|
|
const struct stackentry * callstack; |
56 |
|
|
int callstacksize; |
57 |
|
|
const char * errname; |
58 |
|
|
}; |
59 |
|
|
static autoarray<errordata> errors; |
60 |
|
|
static int numerror; |
61 |
|
|
|
62 |
|
|
static autoarray<errordata> warnings; |
63 |
|
|
static int numwarn; |
64 |
|
|
|
65 |
|
|
/* $EXPORTSTRUCT$ |
66 |
|
|
*/ |
67 |
|
|
struct labeldata { |
68 |
|
|
const char * name; |
69 |
|
|
int location; |
70 |
|
|
}; |
71 |
|
|
|
72 |
|
|
/* $EXPORTSTRUCT$ |
73 |
|
|
*/ |
74 |
|
|
struct definedata { |
75 |
|
|
const char * name; |
76 |
|
|
const char * contents; |
77 |
|
|
}; |
78 |
|
|
|
79 |
|
|
/* $EXPORTSTRUCT$ |
80 |
|
|
*/ |
81 |
|
|
struct warnsetting { |
82 |
|
|
const char * warnid; |
83 |
|
|
bool enabled; |
84 |
|
|
}; |
85 |
|
|
|
86 |
|
|
/* $EXPORTSTRUCT$ |
87 |
|
|
*/ |
88 |
|
|
struct memoryfile { |
89 |
|
|
const char* path; |
90 |
|
|
const void* buffer; |
91 |
|
|
size_t length; |
92 |
|
|
}; |
93 |
|
|
|
94 |
|
190 |
void print(const char * str) |
95 |
|
|
{ |
96 |
|
190 |
prints[numprint++]= duplicate_string(str); |
97 |
|
190 |
} |
98 |
|
|
|
99 |
|
464 |
static void fillerror(errordata& myerr, const char* errname, const char * type, const char * str, bool show_block) |
100 |
|
|
{ |
101 |
|
464 |
const char* current_filename = get_current_file_name(); |
102 |
2/2
✓ Branch 0 taken 463 times.
✓ Branch 1 taken 1 times.
|
464 |
if(current_filename) myerr.filename= duplicate_string(current_filename); |
103 |
|
1 |
else myerr.filename = duplicate_string(""); |
104 |
|
464 |
myerr.line=get_current_line(); |
105 |
|
464 |
const char* current_block = get_current_block(); |
106 |
2/2
✓ Branch 0 taken 443 times.
✓ Branch 1 taken 21 times.
|
464 |
if (current_block) myerr.block= duplicate_string(current_block); |
107 |
|
21 |
else myerr.block= duplicate_string(""); |
108 |
|
464 |
myerr.rawerrdata= duplicate_string(str); |
109 |
|
234 |
string location; |
110 |
|
234 |
string details; |
111 |
1/2
✓ Branch 0 taken 464 times.
✗ Branch 1 not taken.
|
464 |
get_current_line_details(&location, &details); |
112 |
1/2
✓ Branch 0 taken 464 times.
✗ Branch 1 not taken.
|
928 |
myerr.fullerrdata= duplicate_string(location+": "+type+str+details+get_callstack()); |
113 |
|
464 |
myerr.errname = duplicate_string(errname); |
114 |
|
|
|
115 |
|
234 |
autoarray<printable_callstack_entry> printable_stack; |
116 |
1/2
✓ Branch 0 taken 464 times.
✗ Branch 1 not taken.
|
464 |
get_full_printable_callstack(&printable_stack, 0, false); |
117 |
|
|
|
118 |
|
464 |
myerr.callstacksize = printable_stack.count; |
119 |
|
464 |
myerr.callstack = static_cast<stackentry*>(malloc(sizeof(stackentry) * myerr.callstacksize)); |
120 |
|
|
|
121 |
2/2
✓ Branch 0 taken 11096 times.
✓ Branch 1 taken 464 times.
|
11560 |
for (int i = 0; i < myerr.callstacksize; ++i) |
122 |
|
|
{ |
123 |
|
11096 |
stackentry& entry = const_cast<stackentry&>(myerr.callstack[i]); |
124 |
|
|
|
125 |
|
11096 |
entry.fullpath = duplicate_string(printable_stack[i].fullpath); |
126 |
|
11096 |
entry.prettypath = duplicate_string(printable_stack[i].prettypath); |
127 |
|
11096 |
entry.lineno = printable_stack[i].lineno; |
128 |
|
11096 |
entry.details = duplicate_string(printable_stack[i].details); |
129 |
|
|
} |
130 |
|
464 |
} |
131 |
|
|
|
132 |
|
|
static bool ismath=false; |
133 |
|
|
static string matherror; |
134 |
|
|
|
135 |
|
963 |
void error_interface(int errid, int whichpass, const char * e_) |
136 |
|
|
{ |
137 |
|
963 |
errored = true; |
138 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 963 times.
|
963 |
if (ismath) matherror = e_; |
139 |
2/2
✓ Branch 0 taken 398 times.
✓ Branch 1 taken 565 times.
|
963 |
else if (pass == whichpass) { |
140 |
|
|
// don't show current block if the error came from an error command |
141 |
|
398 |
bool show_block = (errid != error_id_error_command); |
142 |
2/4
✓ Branch 0 taken 398 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 398 times.
✗ Branch 3 not taken.
|
796 |
fillerror(errors[numerror++], get_error_name((asar_error_id)errid), STR "error: (" + get_error_name((asar_error_id)errid) + "): ", e_, show_block); |
143 |
|
|
} |
144 |
|
|
else {}//ignore anything else |
145 |
|
963 |
} |
146 |
|
|
|
147 |
|
66 |
void warn(int errid, const char * str) |
148 |
|
|
{ |
149 |
|
|
// don't show current block if the warning came from a warn command |
150 |
|
66 |
bool show_block = (errid != warning_id_warn_command); |
151 |
2/4
✓ Branch 0 taken 66 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66 times.
✗ Branch 3 not taken.
|
132 |
fillerror(warnings[numwarn++], get_warning_name((asar_warning_id)errid), STR "warning: (" + get_warning_name((asar_warning_id)errid) + "): ", str, show_block); |
152 |
|
66 |
} |
153 |
|
|
|
154 |
|
|
static autoarray<labeldata> ldata; |
155 |
|
|
static int labelsinldata = 0; |
156 |
|
|
static autoarray<definedata> ddata; |
157 |
|
|
static int definesinddata=0; |
158 |
|
|
|
159 |
|
491 |
static void resetdllstuff() |
160 |
|
|
{ |
161 |
|
|
#define free_and_null(x) free((void*)x); x = nullptr |
162 |
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 491 times.
|
681 |
for (int i=0;i<numprint;i++) |
163 |
|
|
{ |
164 |
|
190 |
free_and_null(prints[i]); |
165 |
|
|
} |
166 |
|
491 |
prints.reset(); |
167 |
|
491 |
numprint=0; |
168 |
|
|
|
169 |
2/2
✓ Branch 0 taken 398 times.
✓ Branch 1 taken 491 times.
|
889 |
for (int i=0;i<numerror;i++) |
170 |
|
|
{ |
171 |
|
398 |
free_and_null(errors[i].filename); |
172 |
|
398 |
free_and_null(errors[i].rawerrdata); |
173 |
|
398 |
free_and_null(errors[i].fullerrdata); |
174 |
|
398 |
free_and_null(errors[i].block); |
175 |
|
398 |
free_and_null(errors[i].errname); |
176 |
|
|
|
177 |
2/2
✓ Branch 0 taken 11096 times.
✓ Branch 1 taken 398 times.
|
11892 |
for (int j=0;j<errors[i].callstacksize;++j) |
178 |
|
|
{ |
179 |
|
11096 |
stackentry& entry = const_cast<stackentry&>(errors[i].callstack[j]); |
180 |
|
11096 |
free_and_null(entry.fullpath); |
181 |
|
11096 |
free_and_null(entry.prettypath); |
182 |
|
11096 |
free_and_null(entry.details); |
183 |
|
|
} |
184 |
|
398 |
free_and_null(errors[i].callstack); |
185 |
|
|
} |
186 |
|
491 |
errors.reset(); |
187 |
|
491 |
numerror=0; |
188 |
|
|
|
189 |
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 491 times.
|
557 |
for (int i=0;i<numwarn;i++) |
190 |
|
|
{ |
191 |
|
66 |
free_and_null(warnings[i].filename); |
192 |
|
66 |
free_and_null(warnings[i].rawerrdata); |
193 |
|
66 |
free_and_null(warnings[i].fullerrdata); |
194 |
|
66 |
free_and_null(warnings[i].block); |
195 |
|
66 |
free_and_null(warnings[i].errname); |
196 |
|
|
|
197 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 66 times.
|
132 |
for (int j=0;j<warnings[i].callstacksize;++j) |
198 |
|
|
{ |
199 |
|
✗ |
stackentry& entry = const_cast<stackentry&>(warnings[i].callstack[j]); |
200 |
|
✗ |
free_and_null(entry.fullpath); |
201 |
|
✗ |
free_and_null(entry.prettypath); |
202 |
|
✗ |
free_and_null(entry.details); |
203 |
|
|
} |
204 |
|
66 |
free_and_null(warnings[i].callstack); |
205 |
|
|
} |
206 |
|
491 |
warnings.reset(); |
207 |
|
491 |
numwarn=0; |
208 |
|
|
|
209 |
2/2
✓ Branch 0 taken 2139 times.
✓ Branch 1 taken 491 times.
|
2630 |
for (int i=0;i<definesinddata;i++) |
210 |
|
|
{ |
211 |
|
2139 |
free_and_null(ddata[i].name); |
212 |
|
2139 |
free_and_null(ddata[i].contents); |
213 |
|
|
} |
214 |
|
491 |
ddata.reset(); |
215 |
|
491 |
definesinddata=0; |
216 |
|
|
|
217 |
2/2
✓ Branch 0 taken 323 times.
✓ Branch 1 taken 491 times.
|
814 |
for (int i=0;i<labelsinldata;i++) |
218 |
|
323 |
free((void*)ldata[i].name); |
219 |
|
491 |
ldata.reset(); |
220 |
|
491 |
labelsinldata=0; |
221 |
|
|
#undef free_and_null |
222 |
|
|
|
223 |
|
491 |
romCrc = 0; |
224 |
|
491 |
clidefines.reset(); |
225 |
|
491 |
reset_warnings_to_default(); |
226 |
|
|
|
227 |
|
491 |
reseteverything(); |
228 |
|
491 |
} |
229 |
|
|
|
230 |
|
|
#define maxromsize (16*1024*1024) |
231 |
|
|
|
232 |
|
|
static bool expectsNewAPI = false; |
233 |
|
|
|
234 |
|
323 |
static void addlabel(const string & name, const snes_label & label_data) |
235 |
|
|
{ |
236 |
|
|
labeldata label; |
237 |
|
323 |
label.name = strdup(name); |
238 |
|
323 |
label.location = (int)(label_data.pos & 0xFFFFFF); |
239 |
|
323 |
ldata[labelsinldata++] = label; |
240 |
|
323 |
} |
241 |
|
|
|
242 |
|
|
/* $EXPORTSTRUCT_PP$ |
243 |
|
|
*/ |
244 |
|
|
struct patchparams_v200 : public patchparams_base |
245 |
|
|
{ |
246 |
|
|
// Same parameters as asar_patch() |
247 |
|
|
const char * patchloc; |
248 |
|
|
char * romdata; |
249 |
|
|
int buflen; |
250 |
|
|
int * romlen; |
251 |
|
|
|
252 |
|
|
// Include paths to use when searching files. |
253 |
|
|
const char** includepaths; |
254 |
|
|
int numincludepaths; |
255 |
|
|
|
256 |
|
|
// A list of additional defines to make available to the patch. |
257 |
|
|
const struct definedata* additional_defines; |
258 |
|
|
int additional_define_count; |
259 |
|
|
|
260 |
|
|
// Path to a text file to parse standard include search paths from. |
261 |
|
|
// Set to NULL to not use any standard includes search paths. |
262 |
|
|
const char* stdincludesfile; |
263 |
|
|
|
264 |
|
|
// Path to a text file to parse standard defines from. |
265 |
|
|
// Set to NULL to not use any standard defines. |
266 |
|
|
const char* stddefinesfile; |
267 |
|
|
|
268 |
|
|
// A list of warnings to enable or disable. |
269 |
|
|
// Specify warnings in the format "WXXXX" where XXXX = warning ID. |
270 |
|
|
const struct warnsetting * warning_settings; |
271 |
|
|
int warning_setting_count; |
272 |
|
|
|
273 |
|
|
// List of memory files to create on the virtual filesystem. |
274 |
|
|
const struct memoryfile * memory_files; |
275 |
|
|
int memory_file_count; |
276 |
|
|
|
277 |
|
|
// Set override_checksum_gen to true and generate_checksum to true/false |
278 |
|
|
// to force generating/not generating a checksum. |
279 |
|
|
bool override_checksum_gen; |
280 |
|
|
bool generate_checksum; |
281 |
|
|
|
282 |
|
|
// Set this to true for generated error and warning texts to always |
283 |
|
|
// contain their full call stack. |
284 |
|
|
bool full_call_stack; |
285 |
|
|
}; |
286 |
|
|
|
287 |
|
|
/* $EXPORTSTRUCT_PP$ |
288 |
|
|
*/ |
289 |
|
|
struct patchparams : public patchparams_v200 |
290 |
|
|
{ |
291 |
|
|
|
292 |
|
|
}; |
293 |
|
|
|
294 |
|
486 |
static void asar_patch_begin(char * romdata_, int buflen, int * romlen_) |
295 |
|
|
{ |
296 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 486 times.
|
486 |
if (buflen != maxromsize) |
297 |
|
|
{ |
298 |
|
✗ |
romdata_r = (unsigned char*)malloc(maxromsize); |
299 |
|
✗ |
memcpy(const_cast<unsigned char*>(romdata_r)/*we just allocated this, it's safe to violate its const*/, romdata_, (size_t)*romlen_); |
300 |
|
|
} |
301 |
|
486 |
else romdata_r = (unsigned char*)romdata_; |
302 |
|
486 |
romdata = (unsigned char*)malloc(maxromsize); |
303 |
|
|
// RPG Hacker: Without this memset, freespace commands can (and probably will) fail. |
304 |
|
486 |
memset((void*)romdata, 0, maxromsize); |
305 |
|
486 |
memcpy(const_cast<unsigned char*>(romdata), romdata_, (size_t)*romlen_); |
306 |
|
486 |
resetdllstuff(); |
307 |
|
486 |
romlen = *romlen_; |
308 |
|
486 |
romlen_r = *romlen_; |
309 |
|
486 |
} |
310 |
|
|
|
311 |
|
486 |
static void asar_patch_main(const char * patchloc) |
312 |
|
|
{ |
313 |
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 485 times.
|
486 |
if (!path_is_absolute(patchloc)) asar_throw_warning(pass, warning_id_relative_path_used, "patch file"); |
314 |
|
|
|
315 |
|
|
try |
316 |
|
|
{ |
317 |
2/2
✓ Branch 0 taken 1418 times.
✓ Branch 1 taken 466 times.
|
1884 |
for (pass = 0;pass < 3;pass++) |
318 |
|
|
{ |
319 |
1/2
✓ Branch 0 taken 1418 times.
✗ Branch 1 not taken.
|
1418 |
initstuff(); |
320 |
2/2
✓ Branch 0 taken 1398 times.
✓ Branch 1 taken 20 times.
|
1418 |
assemblefile(patchloc); |
321 |
|
|
// RPG Hacker: Necessary, because finishpass() can throws warning and errors. |
322 |
1/2
✓ Branch 0 taken 1398 times.
✗ Branch 1 not taken.
|
2067 |
callstack_push cs_push(callstack_entry_type::FILE, filesystem->create_absolute_path(nullptr, patchloc)); |
323 |
1/2
✓ Branch 0 taken 1398 times.
✗ Branch 1 not taken.
|
1398 |
finishpass(); |
324 |
|
1398 |
} |
325 |
|
|
} |
326 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 |
catch (errfatal&) {} |
327 |
|
486 |
} |
328 |
|
|
|
329 |
|
486 |
static bool asar_patch_end(char * romdata_, int buflen, int * romlen_) |
330 |
|
|
{ |
331 |
2/2
✓ Branch 0 taken 244 times.
✓ Branch 1 taken 242 times.
|
486 |
if (checksum_fix_enabled) fixchecksum(); |
332 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 486 times.
|
486 |
if (romdata_ != (const char*)romdata_r) free(const_cast<unsigned char*>(romdata_r)); |
333 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 486 times.
|
486 |
if (buflen < romlen) asar_throw_error(pass, error_type_null, error_id_buffer_too_small); |
334 |
2/2
✓ Branch 0 taken 141 times.
✓ Branch 1 taken 345 times.
|
486 |
if (errored) |
335 |
|
|
{ |
336 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 141 times.
|
141 |
if (numerror==0) |
337 |
|
✗ |
asar_throw_error(pass, error_type_null, error_id_phantom_error); |
338 |
|
141 |
free(const_cast<unsigned char*>(romdata)); |
339 |
|
141 |
return false; |
340 |
|
|
} |
341 |
1/2
✓ Branch 0 taken 345 times.
✗ Branch 1 not taken.
|
345 |
if (*romlen_ != buflen) |
342 |
|
|
{ |
343 |
|
345 |
*romlen_ = romlen; |
344 |
|
|
} |
345 |
|
345 |
romCrc = crc32((const uint8_t*)romdata, (size_t)romlen); |
346 |
|
345 |
memcpy(romdata_, romdata, (size_t)romlen); |
347 |
|
345 |
free(const_cast<unsigned char*>(romdata)); |
348 |
|
345 |
return true; |
349 |
|
|
} |
350 |
|
|
|
351 |
|
|
#if defined(__clang__) |
352 |
|
|
# pragma clang diagnostic push |
353 |
|
|
# pragma clang diagnostic ignored "-Wmissing-prototypes" |
354 |
|
|
#endif |
355 |
|
|
|
356 |
|
|
// this and asar_close are hardcoded in each api |
357 |
|
5 |
EXPORT bool asar_init() |
358 |
|
|
{ |
359 |
|
5 |
if (!expectsNewAPI) return false; |
360 |
|
|
return true; |
361 |
|
|
} |
362 |
|
|
|
363 |
|
|
/* $EXPORT$ |
364 |
|
|
* Returns the version, in the format major*10000+minor*100+bugfix*1. This |
365 |
|
|
* means that 1.2.34 would be returned as 10234. |
366 |
|
|
*/ |
367 |
|
167 |
EXPORT int asar_version() |
368 |
|
|
{ |
369 |
|
167 |
return get_version_int(); |
370 |
|
|
} |
371 |
|
|
|
372 |
|
|
/* $EXPORT$ |
373 |
|
|
* Returns the API version, format major*100+minor. Minor is incremented on |
374 |
|
|
* backwards compatible changes; major is incremented on incompatible changes. |
375 |
|
|
* Does not have any correlation with the Asar version. |
376 |
|
|
* |
377 |
|
|
* It's not very useful directly, since asar_init() verifies this automatically. |
378 |
|
|
* Calling this one also sets a flag that makes asar_init not instantly return |
379 |
|
|
* false; this is so programs expecting an older API won't do anything unexpected. |
380 |
|
|
*/ |
381 |
|
9 |
EXPORT int asar_apiversion() |
382 |
|
|
{ |
383 |
|
9 |
expectsNewAPI=true; |
384 |
|
9 |
return APIVERSION; |
385 |
|
|
} |
386 |
|
|
|
387 |
|
|
/* $EXPORT$ |
388 |
|
|
* Clears out all errors, warnings and printed statements, and clears the file |
389 |
|
|
* cache. Not really useful, since asar_patch() already does this. |
390 |
|
|
*/ |
391 |
|
✗ |
EXPORT bool asar_reset() |
392 |
|
|
{ |
393 |
|
✗ |
resetdllstuff(); |
394 |
|
✗ |
pass=0; |
395 |
|
✗ |
return true; |
396 |
|
|
} |
397 |
|
|
|
398 |
|
5 |
EXPORT void asar_close() |
399 |
|
|
{ |
400 |
|
5 |
resetdllstuff(); |
401 |
|
5 |
} |
402 |
|
|
|
403 |
|
|
/* $EXPORT$ |
404 |
|
|
* Applies a patch. The first argument is a filename (so Asar knows where to |
405 |
|
|
* look for incsrc'd stuff); however, the ROM is in memory. |
406 |
|
|
* This function assumes there are no headers anywhere, neither in romdata nor |
407 |
|
|
* the sizes. romlen may be altered by this function; if this is undesirable, |
408 |
|
|
* set romlen equal to buflen. |
409 |
|
|
* The return value is whether any errors appeared (false=errors, call |
410 |
|
|
* asar_geterrors for details). If there is an error, romdata and romlen will |
411 |
|
|
* be left unchanged. |
412 |
|
|
* See the documentation of struct patchparams for more information. |
413 |
|
|
*/ |
414 |
|
486 |
EXPORT bool asar_patch(const struct patchparams_base *params) |
415 |
|
|
{ |
416 |
|
486 |
auto execute_patch = [&]() { |
417 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 486 times.
|
486 |
if (params == nullptr) |
418 |
|
|
{ |
419 |
|
✗ |
asar_throw_error(pass, error_type_null, error_id_params_null); |
420 |
|
|
} |
421 |
|
|
|
422 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 486 times.
|
486 |
if (params->structsize != sizeof(patchparams_v200)) |
423 |
|
|
{ |
424 |
|
✗ |
asar_throw_error(pass, error_type_null, error_id_params_invalid_size); |
425 |
|
|
} |
426 |
|
|
|
427 |
|
|
patchparams paramscurrent; |
428 |
|
486 |
memset(¶mscurrent, 0, sizeof(paramscurrent)); |
429 |
|
486 |
memcpy(¶mscurrent, params, (size_t)params->structsize); |
430 |
|
|
|
431 |
|
|
|
432 |
|
486 |
asar_patch_begin(paramscurrent.romdata, paramscurrent.buflen, paramscurrent.romlen); |
433 |
|
|
|
434 |
|
486 |
simple_callstacks = !paramscurrent.full_call_stack; |
435 |
|
|
|
436 |
|
253 |
autoarray<string> includepaths; |
437 |
|
253 |
autoarray<const char*> includepath_cstrs; |
438 |
|
|
|
439 |
2/2
✓ Branch 0 taken 236 times.
✓ Branch 1 taken 486 times.
|
722 |
for (int i = 0; i < paramscurrent.numincludepaths; ++i) |
440 |
|
|
{ |
441 |
2/6
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 236 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
236 |
if (!path_is_absolute(paramscurrent.includepaths[i])) asar_throw_warning(pass, warning_id_relative_path_used, "include search"); |
442 |
|
236 |
string& newpath = includepaths.append(paramscurrent.includepaths[i]); |
443 |
|
236 |
includepath_cstrs.append((const char*)newpath); |
444 |
|
|
} |
445 |
|
|
|
446 |
2/2
✓ Branch 0 taken 237 times.
✓ Branch 1 taken 249 times.
|
486 |
if (paramscurrent.stdincludesfile != nullptr) { |
447 |
2/6
✓ Branch 0 taken 237 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 237 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
237 |
if (!path_is_absolute(paramscurrent.stdincludesfile)) asar_throw_warning(pass, warning_id_relative_path_used, "std includes file"); |
448 |
|
119 |
string stdincludespath = paramscurrent.stdincludesfile; |
449 |
1/2
✓ Branch 0 taken 237 times.
✗ Branch 1 not taken.
|
237 |
parse_std_includes(stdincludespath, includepaths); |
450 |
|
237 |
} |
451 |
|
|
|
452 |
2/2
✓ Branch 0 taken 475 times.
✓ Branch 1 taken 486 times.
|
961 |
for (int i = 0; i < includepaths.count; ++i) |
453 |
|
|
{ |
454 |
|
475 |
includepath_cstrs.append((const char*)includepaths[i]); |
455 |
|
|
} |
456 |
|
|
|
457 |
|
486 |
size_t includepath_count = (size_t)includepath_cstrs.count; |
458 |
|
253 |
virtual_filesystem new_filesystem; |
459 |
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
|
486 |
new_filesystem.initialize(&includepath_cstrs[0], includepath_count); |
460 |
|
486 |
filesystem = &new_filesystem; |
461 |
|
|
|
462 |
2/2
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 486 times.
|
746 |
for(int i = 0; i < paramscurrent.memory_file_count; ++i) { |
463 |
|
260 |
memoryfile f = paramscurrent.memory_files[i]; |
464 |
1/2
✓ Branch 0 taken 260 times.
✗ Branch 1 not taken.
|
260 |
filesystem->add_memory_file(f.path, f.buffer, f.length); |
465 |
|
|
} |
466 |
|
|
|
467 |
|
486 |
clidefines.reset(); |
468 |
2/2
✓ Branch 0 taken 946 times.
✓ Branch 1 taken 486 times.
|
1432 |
for (int i = 0; i < paramscurrent.additional_define_count; ++i) |
469 |
|
|
{ |
470 |
1/2
✓ Branch 0 taken 946 times.
✗ Branch 1 not taken.
|
1420 |
string name = (paramscurrent.additional_defines[i].name != nullptr ? paramscurrent.additional_defines[i].name : ""); |
471 |
|
946 |
strip_whitespace(name); |
472 |
|
946 |
name.strip_prefix('!'); // remove leading ! if present |
473 |
2/6
✓ Branch 0 taken 946 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 946 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
946 |
if (!validatedefinename(name)) asar_throw_error(pass, error_type_null, error_id_cmdl_define_invalid, "asar_patch_ex() additional defines", name.data()); |
474 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 946 times.
|
946 |
if (clidefines.exists(name)) { |
475 |
|
✗ |
asar_throw_error(pass, error_type_null, error_id_cmdl_define_override, "asar_patch_ex() additional define", name.data()); |
476 |
|
|
return false; |
477 |
|
|
} |
478 |
2/2
✓ Branch 0 taken 710 times.
✓ Branch 1 taken 236 times.
|
1302 |
string contents = (paramscurrent.additional_defines[i].contents != nullptr ? paramscurrent.additional_defines[i].contents : ""); |
479 |
1/2
✓ Branch 0 taken 946 times.
✗ Branch 1 not taken.
|
946 |
clidefines.create(name) = contents; |
480 |
|
946 |
} |
481 |
|
|
|
482 |
2/2
✓ Branch 0 taken 237 times.
✓ Branch 1 taken 249 times.
|
486 |
if (paramscurrent.stddefinesfile != nullptr) { |
483 |
2/6
✓ Branch 0 taken 237 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 237 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
237 |
if (!path_is_absolute(paramscurrent.stddefinesfile)) asar_throw_warning(pass, warning_id_relative_path_used, "std defines file"); |
484 |
|
119 |
string stddefinespath = paramscurrent.stddefinesfile; |
485 |
1/2
✓ Branch 0 taken 237 times.
✗ Branch 1 not taken.
|
237 |
parse_std_defines(stddefinespath); |
486 |
|
237 |
} else { |
487 |
1/2
✓ Branch 0 taken 249 times.
✗ Branch 1 not taken.
|
249 |
parse_std_defines(nullptr); // needed to populate builtin defines |
488 |
|
|
} |
489 |
|
|
|
490 |
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 486 times.
|
488 |
for (int i = 0; i < paramscurrent.warning_setting_count; ++i) |
491 |
|
|
{ |
492 |
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 |
asar_warning_id warnid = parse_warning_id_from_string(paramscurrent.warning_settings[i].warnid); |
493 |
|
|
|
494 |
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 |
if (warnid != warning_id_end) |
495 |
|
|
{ |
496 |
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 |
set_warning_enabled(warnid, paramscurrent.warning_settings[i].enabled); |
497 |
|
|
} |
498 |
|
|
else |
499 |
|
|
{ |
500 |
|
✗ |
asar_throw_error(pass, error_type_null, error_id_invalid_warning_id, paramscurrent.warning_settings[i].warnid, "asar_patch_ex() warning_settings"); |
501 |
|
|
} |
502 |
|
|
} |
503 |
|
|
|
504 |
2/2
✓ Branch 0 taken 230 times.
✓ Branch 1 taken 256 times.
|
486 |
if(paramscurrent.override_checksum_gen) { |
505 |
|
230 |
checksum_fix_enabled = paramscurrent.generate_checksum; |
506 |
|
230 |
force_checksum_fix = true; |
507 |
|
|
} |
508 |
|
|
|
509 |
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
|
486 |
asar_patch_main(paramscurrent.patchloc); |
510 |
|
|
|
511 |
|
|
// RPG Hacker: Required before the destroy() below, |
512 |
|
|
// otherwise it will leak memory. |
513 |
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
|
486 |
closecachedfiles(); |
514 |
|
|
|
515 |
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
|
486 |
new_filesystem.destroy(); |
516 |
|
486 |
filesystem = nullptr; |
517 |
|
|
|
518 |
1/2
✓ Branch 0 taken 486 times.
✗ Branch 1 not taken.
|
486 |
return asar_patch_end(paramscurrent.romdata, paramscurrent.buflen, paramscurrent.romlen); |
519 |
|
486 |
}; |
520 |
|
|
#if defined(RUN_VIA_FIBER) |
521 |
|
233 |
return run_as_fiber(execute_patch); |
522 |
|
|
#elif defined(RUN_VIA_THREAD) |
523 |
|
|
return run_as_thread(execute_patch); |
524 |
|
|
#else |
525 |
|
253 |
return execute_patch(); |
526 |
|
|
#endif |
527 |
|
|
} |
528 |
|
|
|
529 |
|
|
/* $EXPORT$ |
530 |
|
|
* Returns the maximum possible size of the output ROM from asar_patch(). |
531 |
|
|
* Giving this size to buflen guarantees you will not get any buffer too small |
532 |
|
|
* errors; however, it is safe to give smaller buffers if you don't expect any |
533 |
|
|
* ROMs larger than 4MB or something. |
534 |
|
|
*/ |
535 |
|
206 |
EXPORT int asar_maxromsize() |
536 |
|
|
{ |
537 |
|
206 |
return maxromsize; |
538 |
|
|
} |
539 |
|
|
|
540 |
|
|
/* $EXPORT$ |
541 |
|
|
* Get a list of all errors. |
542 |
|
|
* All pointers from these functions are valid only until the same function is |
543 |
|
|
* called again, or until asar_patch, asar_reset or asar_close is called, |
544 |
|
|
* whichever comes first. Copy the contents if you need it for a longer time. |
545 |
|
|
*/ |
546 |
|
483 |
EXPORT const struct errordata * asar_geterrors(int * count) |
547 |
|
|
{ |
548 |
|
483 |
*count=numerror; |
549 |
|
483 |
return errors; |
550 |
|
|
} |
551 |
|
|
|
552 |
|
|
/* $EXPORT$ |
553 |
|
|
* Get a list of all warnings. |
554 |
|
|
*/ |
555 |
|
483 |
EXPORT const struct errordata * asar_getwarnings(int * count) |
556 |
|
|
{ |
557 |
|
483 |
*count=numwarn; |
558 |
|
483 |
return warnings; |
559 |
|
|
} |
560 |
|
|
|
561 |
|
|
/* $EXPORT$ |
562 |
|
|
* Get a list of all printed data. |
563 |
|
|
*/ |
564 |
|
467 |
EXPORT const char * const * asar_getprints(int * count) |
565 |
|
|
{ |
566 |
|
467 |
*count=numprint; |
567 |
|
467 |
return prints; |
568 |
|
|
} |
569 |
|
|
|
570 |
|
|
/* $EXPORT$ |
571 |
|
|
* Get a list of all labels. |
572 |
|
|
*/ |
573 |
|
167 |
EXPORT const struct labeldata * asar_getalllabels(int * count) |
574 |
|
|
{ |
575 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 167 times.
|
167 |
for (int i=0;i<labelsinldata;i++) free((void*)ldata[i].name); |
576 |
|
167 |
labelsinldata=0; |
577 |
|
167 |
labels.each(addlabel); |
578 |
|
167 |
*count=labelsinldata; |
579 |
|
167 |
return ldata; |
580 |
|
|
} |
581 |
|
|
|
582 |
|
|
/* $EXPORT$ |
583 |
|
|
* Get the ROM location of one label. -1 means "not found". |
584 |
|
|
*/ |
585 |
|
4 |
EXPORT int asar_getlabelval(const char * name) |
586 |
|
|
{ |
587 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 |
if (!stricmp(name, ":$:opcodes:$:")) return numopcodes;//aaah, you found me |
588 |
|
|
int i; |
589 |
|
|
try { |
590 |
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 |
i=(int)labelval(&name).pos; |
591 |
|
|
} |
592 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 |
catch(errfatal&) { return -1; } |
593 |
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
|
3 |
if (*name || i<0) return -1; |
594 |
|
3 |
else return i&0xFFFFFF; |
595 |
|
|
} |
596 |
|
|
|
597 |
|
|
/* $EXPORT$ |
598 |
|
|
* Get the value of a define. |
599 |
|
|
*/ |
600 |
|
168 |
EXPORT const char * asar_getdefine(const char * name) |
601 |
|
|
{ |
602 |
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 165 times.
|
168 |
if (!defines.exists(name)) return ""; |
603 |
|
3 |
return defines.find(name); |
604 |
|
|
} |
605 |
|
|
|
606 |
|
|
/* $EXPORT$ |
607 |
|
|
* Parses all defines in the parameter. Note that it may emit errors. |
608 |
|
|
*/ |
609 |
|
2 |
EXPORT const char * asar_resolvedefines(const char * data) |
610 |
|
|
{ |
611 |
2/4
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
|
3 |
static string out; |
612 |
|
|
try |
613 |
|
|
{ |
614 |
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 |
resolvedefines(out, data); |
615 |
|
|
} |
616 |
|
✗ |
catch(errfatal&){} |
617 |
|
2 |
return out; |
618 |
|
|
} |
619 |
|
|
|
620 |
|
2139 |
static void adddef(const string& name, string& value) |
621 |
|
|
{ |
622 |
|
|
definedata define; |
623 |
|
2139 |
define.name= duplicate_string(name); |
624 |
|
2139 |
define.contents= duplicate_string(value); |
625 |
|
2139 |
ddata[definesinddata++]=define; |
626 |
|
2139 |
} |
627 |
|
|
|
628 |
|
|
/* $EXPORT$ |
629 |
|
|
* Gets the values and names of all defines. |
630 |
|
|
*/ |
631 |
|
169 |
EXPORT const struct definedata * asar_getalldefines(int * count) |
632 |
|
|
{ |
633 |
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 169 times.
|
169 |
for (int i=0;i<definesinddata;i++) |
634 |
|
|
{ |
635 |
|
✗ |
free((void*)ddata[i].name); |
636 |
|
✗ |
free((void*)ddata[i].contents); |
637 |
|
|
} |
638 |
|
169 |
definesinddata=0; |
639 |
|
169 |
defines.each(adddef); |
640 |
|
169 |
*count=definesinddata; |
641 |
|
169 |
return ddata; |
642 |
|
|
} |
643 |
|
|
|
644 |
|
|
/* $EXPORT$ |
645 |
|
|
* Parses a string containing math. It automatically assumes global scope (no |
646 |
|
|
* namespaces), and has access to all functions and labels from the last call |
647 |
|
|
* to asar_patch. Remember to check error to see if it's successful (NULL) or |
648 |
|
|
* if it failed (non-NULL, contains a descriptive string). It does not affect |
649 |
|
|
* asar_geterrors. |
650 |
|
|
*/ |
651 |
|
166 |
EXPORT double asar_math(const char * math_, const char ** error) |
652 |
|
|
{ |
653 |
|
|
ns=""; |
654 |
|
166 |
namespace_list.reset(); |
655 |
|
166 |
sublabels.reset(); |
656 |
|
166 |
errored=false; |
657 |
|
166 |
ismath=true; |
658 |
|
166 |
initmathcore(); |
659 |
|
|
double rval=0; |
660 |
|
|
try |
661 |
|
|
{ |
662 |
1/2
✓ Branch 0 taken 166 times.
✗ Branch 1 not taken.
|
166 |
rval=(double)math(math_); |
663 |
|
|
} |
664 |
|
✗ |
catch(errfatal&) |
665 |
|
|
{ |
666 |
|
✗ |
*error=matherror; |
667 |
|
✗ |
} |
668 |
|
166 |
ismath=false; |
669 |
|
166 |
deinitmathcore(); |
670 |
|
166 |
return rval; |
671 |
|
|
} |
672 |
|
|
|
673 |
|
|
/* $EXPORT$ |
674 |
|
|
* Get a list of all the blocks written to the ROM by calls such as |
675 |
|
|
* asar_patch(). |
676 |
|
|
*/ |
677 |
|
167 |
EXPORT const struct writtenblockdata * asar_getwrittenblocks(int * count) |
678 |
|
|
{ |
679 |
|
167 |
*count = writtenblocks.count; |
680 |
|
167 |
return writtenblocks; |
681 |
|
|
} |
682 |
|
|
|
683 |
|
|
/* $EXPORT$ |
684 |
|
|
* Get the mapper currently used by Asar. |
685 |
|
|
*/ |
686 |
|
174 |
EXPORT enum mapper_t asar_getmapper() |
687 |
|
|
{ |
688 |
|
174 |
return mapper; |
689 |
|
|
} |
690 |
|
|
|
691 |
|
|
/* $EXPORT$ |
692 |
|
|
* Generates the contents of a symbols file for in a specific format. |
693 |
|
|
*/ |
694 |
|
166 |
EXPORT const char * asar_getsymbolsfile(const char* type){ |
695 |
1/2
✓ Branch 0 taken 166 times.
✗ Branch 1 not taken.
|
166 |
symbolsfile = create_symbols_file(type, romCrc); |
696 |
|
166 |
return symbolsfile; |
697 |
|
|
} |
698 |
|
|
|
699 |
|
|
#if defined(__clang__) |
700 |
|
|
# pragma clang diagnostic pop |
701 |
|
|
#endif |
702 |
|
|
|