asar coverage - build #92


src/asar/
File: src/asar/interface-lib.cpp
Date: 2024-01-19 17:27:19
Lines:
249/270
92.2%
Functions:
29/30
96.7%
Branches:
106/176
60.2%

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 186 void print(const char * str)
95 {
96 186 prints[numprint++]= duplicate_string(str);
97 186 }
98
99 468 static void fillerror(errordata& myerr, const char* errname, const char * type, const char * str, bool show_block)
100 {
101 468 const char* current_filename = get_current_file_name();
102
2/2
✓ Branch 0 taken 467 times.
✓ Branch 1 taken 1 times.
468 if(current_filename) myerr.filename= duplicate_string(current_filename);
103 1 else myerr.filename = duplicate_string("");
104 468 myerr.line=get_current_line();
105 468 const char* current_block = get_current_block();
106
2/2
✓ Branch 0 taken 447 times.
✓ Branch 1 taken 21 times.
468 if (current_block) myerr.block= duplicate_string(current_block);
107 21 else myerr.block= duplicate_string("");
108 468 myerr.rawerrdata= duplicate_string(str);
109 236 string location;
110 236 string details;
111
1/2
✓ Branch 0 taken 468 times.
✗ Branch 1 not taken.
468 get_current_line_details(&location, &details);
112
1/2
✓ Branch 0 taken 468 times.
✗ Branch 1 not taken.
936 myerr.fullerrdata= duplicate_string(location+": "+type+str+details+get_callstack());
113 468 myerr.errname = duplicate_string(errname);
114
115 236 autoarray<printable_callstack_entry> printable_stack;
116
1/2
✓ Branch 0 taken 468 times.
✗ Branch 1 not taken.
468 get_full_printable_callstack(&printable_stack, 0, false);
117
118 468 myerr.callstacksize = printable_stack.count;
119 468 myerr.callstack = static_cast<stackentry*>(malloc(sizeof(stackentry) * myerr.callstacksize));
120
121
2/2
✓ Branch 0 taken 11096 times.
✓ Branch 1 taken 468 times.
11564 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 468 }
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 70 void warn(int errid, const char * str)
148 {
149 // don't show current block if the warning came from a warn command
150 70 bool show_block = (errid != warning_id_warn_command);
151
2/4
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 70 times.
✗ Branch 3 not taken.
140 fillerror(warnings[numwarn++], get_warning_name((asar_warning_id)errid), STR "warning: (" + get_warning_name((asar_warning_id)errid) + "): ", str, show_block);
152 70 }
153
154 static autoarray<labeldata> ldata;
155 static int labelsinldata = 0;
156 static autoarray<definedata> ddata;
157 static int definesinddata=0;
158
159 495 static void resetdllstuff()
160 {
161 #define free_and_null(x) free((void*)x); x = nullptr
162
2/2
✓ Branch 0 taken 186 times.
✓ Branch 1 taken 495 times.
681 for (int i=0;i<numprint;i++)
163 {
164 186 free_and_null(prints[i]);
165 }
166 495 prints.reset();
167 495 numprint=0;
168
169
2/2
✓ Branch 0 taken 398 times.
✓ Branch 1 taken 495 times.
893 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 495 errors.reset();
187 495 numerror=0;
188
189
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 495 times.
565 for (int i=0;i<numwarn;i++)
190 {
191 70 free_and_null(warnings[i].filename);
192 70 free_and_null(warnings[i].rawerrdata);
193 70 free_and_null(warnings[i].fullerrdata);
194 70 free_and_null(warnings[i].block);
195 70 free_and_null(warnings[i].errname);
196
197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
140 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 70 free_and_null(warnings[i].callstack);
205 }
206 495 warnings.reset();
207 495 numwarn=0;
208
209
2/2
✓ Branch 0 taken 2163 times.
✓ Branch 1 taken 495 times.
2658 for (int i=0;i<definesinddata;i++)
210 {
211 2163 free_and_null(ddata[i].name);
212 2163 free_and_null(ddata[i].contents);
213 }
214 495 ddata.reset();
215 495 definesinddata=0;
216
217
2/2
✓ Branch 0 taken 327 times.
✓ Branch 1 taken 495 times.
822 for (int i=0;i<labelsinldata;i++)
218 327 free((void*)ldata[i].name);
219 495 ldata.reset();
220 495 labelsinldata=0;
221 #undef free_and_null
222
223 495 romCrc = 0;
224 495 clidefines.reset();
225 495 reset_warnings_to_default();
226
227 495 reseteverything();
228 495 }
229
230 #define maxromsize (16*1024*1024)
231
232 static bool expectsNewAPI = false;
233
234 327 static void addlabel(const string & name, const snes_label & label_data)
235 {
236 labeldata label;
237 327 label.name = strdup(name);
238 327 label.location = (int)(label_data.pos & 0xFFFFFF);
239 327 ldata[labelsinldata++] = label;
240 327 }
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 490 static void asar_patch_begin(char * romdata_, int buflen, int * romlen_)
295 {
296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 490 times.
490 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 490 else romdata_r = (unsigned char*)romdata_;
302 490 romdata = (unsigned char*)malloc(maxromsize);
303 // RPG Hacker: Without this memset, freespace commands can (and probably will) fail.
304 490 memset((void*)romdata, 0, maxromsize);
305 490 memcpy(const_cast<unsigned char*>(romdata), romdata_, (size_t)*romlen_);
306 490 resetdllstuff();
307 490 romlen = *romlen_;
308 490 romlen_r = *romlen_;
309 490 }
310
311 490 static void asar_patch_main(const char * patchloc)
312 {
313
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 489 times.
490 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 1430 times.
✓ Branch 1 taken 470 times.
1900 for (pass = 0;pass < 3;pass++)
318 {
319
1/2
✓ Branch 0 taken 1430 times.
✗ Branch 1 not taken.
1430 initstuff();
320
2/2
✓ Branch 0 taken 1410 times.
✓ Branch 1 taken 20 times.
1430 assemblefile(patchloc);
321 // RPG Hacker: Necessary, because finishpass() can throws warning and errors.
322
1/2
✓ Branch 0 taken 1410 times.
✗ Branch 1 not taken.
2085 callstack_push cs_push(callstack_entry_type::FILE, filesystem->create_absolute_path(nullptr, patchloc));
323
1/2
✓ Branch 0 taken 1410 times.
✗ Branch 1 not taken.
1410 finishpass();
324 1410 }
325 }
326
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
20 catch (errfatal&) {}
327 490 }
328
329 490 static bool asar_patch_end(char * romdata_, int buflen, int * romlen_)
330 {
331
2/2
✓ Branch 0 taken 246 times.
✓ Branch 1 taken 244 times.
490 if (checksum_fix_enabled) fixchecksum();
332
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 490 times.
490 if (romdata_ != (const char*)romdata_r) free(const_cast<unsigned char*>(romdata_r));
333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 490 times.
490 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 349 times.
490 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 349 times.
✗ Branch 1 not taken.
349 if (*romlen_ != buflen)
342 {
343 349 *romlen_ = romlen;
344 }
345 349 romCrc = crc32((const uint8_t*)romdata, (size_t)romlen);
346 349 memcpy(romdata_, romdata, (size_t)romlen);
347 349 free(const_cast<unsigned char*>(romdata));
348 349 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 169 EXPORT int asar_version()
368 {
369 169 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 490 EXPORT bool asar_patch(const struct patchparams_base *params)
415 {
416 490 auto execute_patch = [&]() {
417
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 490 times.
490 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 490 times.
490 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 490 memset(&paramscurrent, 0, sizeof(paramscurrent));
429 490 memcpy(&paramscurrent, params, (size_t)params->structsize);
430
431
432 490 asar_patch_begin(paramscurrent.romdata, paramscurrent.buflen, paramscurrent.romlen);
433
434 490 simple_callstacks = !paramscurrent.full_call_stack;
435
436 255 autoarray<string> includepaths;
437 255 autoarray<const char*> includepath_cstrs;
438
439
2/2
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 490 times.
728 for (int i = 0; i < paramscurrent.numincludepaths; ++i)
440 {
441
2/6
✓ Branch 0 taken 238 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 238 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
238 if (!path_is_absolute(paramscurrent.includepaths[i])) asar_throw_warning(pass, warning_id_relative_path_used, "include search");
442 238 string& newpath = includepaths.append(paramscurrent.includepaths[i]);
443 238 includepath_cstrs.append((const char*)newpath);
444 }
445
446
2/2
✓ Branch 0 taken 239 times.
✓ Branch 1 taken 251 times.
490 if (paramscurrent.stdincludesfile != nullptr) {
447
2/6
✓ Branch 0 taken 239 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 239 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
239 if (!path_is_absolute(paramscurrent.stdincludesfile)) asar_throw_warning(pass, warning_id_relative_path_used, "std includes file");
448 120 string stdincludespath = paramscurrent.stdincludesfile;
449
1/2
✓ Branch 0 taken 239 times.
✗ Branch 1 not taken.
239 parse_std_includes(stdincludespath, includepaths);
450 239 }
451
452
2/2
✓ Branch 0 taken 479 times.
✓ Branch 1 taken 490 times.
969 for (int i = 0; i < includepaths.count; ++i)
453 {
454 479 includepath_cstrs.append((const char*)includepaths[i]);
455 }
456
457 490 size_t includepath_count = (size_t)includepath_cstrs.count;
458 255 virtual_filesystem new_filesystem;
459
1/2
✓ Branch 0 taken 490 times.
✗ Branch 1 not taken.
490 new_filesystem.initialize(&includepath_cstrs[0], includepath_count);
460 490 filesystem = &new_filesystem;
461
462
2/2
✓ Branch 0 taken 262 times.
✓ Branch 1 taken 490 times.
752 for(int i = 0; i < paramscurrent.memory_file_count; ++i) {
463 262 memoryfile f = paramscurrent.memory_files[i];
464
1/2
✓ Branch 0 taken 262 times.
✗ Branch 1 not taken.
262 filesystem->add_memory_file(f.path, f.buffer, f.length);
465 }
466
467 490 clidefines.reset();
468
2/2
✓ Branch 0 taken 954 times.
✓ Branch 1 taken 490 times.
1444 for (int i = 0; i < paramscurrent.additional_define_count; ++i)
469 {
470
1/2
✓ Branch 0 taken 954 times.
✗ Branch 1 not taken.
1432 string name = (paramscurrent.additional_defines[i].name != nullptr ? paramscurrent.additional_defines[i].name : "");
471 954 strip_whitespace(name);
472 954 name.strip_prefix('!'); // remove leading ! if present
473
2/6
✓ Branch 0 taken 954 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 954 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
954 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 954 times.
954 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 716 times.
✓ Branch 1 taken 238 times.
1313 string contents = (paramscurrent.additional_defines[i].contents != nullptr ? paramscurrent.additional_defines[i].contents : "");
479
1/2
✓ Branch 0 taken 954 times.
✗ Branch 1 not taken.
954 clidefines.create(name) = contents;
480 954 }
481
482
2/2
✓ Branch 0 taken 239 times.
✓ Branch 1 taken 251 times.
490 if (paramscurrent.stddefinesfile != nullptr) {
483
2/6
✓ Branch 0 taken 239 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 239 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
239 if (!path_is_absolute(paramscurrent.stddefinesfile)) asar_throw_warning(pass, warning_id_relative_path_used, "std defines file");
484 120 string stddefinespath = paramscurrent.stddefinesfile;
485
1/2
✓ Branch 0 taken 239 times.
✗ Branch 1 not taken.
239 parse_std_defines(stddefinespath);
486 239 } else {
487
1/2
✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
251 parse_std_defines(nullptr); // needed to populate builtin defines
488 }
489
490
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 490 times.
492 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 232 times.
✓ Branch 1 taken 258 times.
490 if(paramscurrent.override_checksum_gen) {
505 232 checksum_fix_enabled = paramscurrent.generate_checksum;
506 232 force_checksum_fix = true;
507 }
508
509
1/2
✓ Branch 0 taken 490 times.
✗ Branch 1 not taken.
490 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 490 times.
✗ Branch 1 not taken.
490 closecachedfiles();
514
515
1/2
✓ Branch 0 taken 490 times.
✗ Branch 1 not taken.
490 new_filesystem.destroy();
516 490 filesystem = nullptr;
517
518
1/2
✓ Branch 0 taken 490 times.
✗ Branch 1 not taken.
490 return asar_patch_end(paramscurrent.romdata, paramscurrent.buflen, paramscurrent.romlen);
519 490 };
520 #if defined(RUN_VIA_FIBER)
521 235 return run_as_fiber(execute_patch);
522 #elif defined(RUN_VIA_THREAD)
523 return run_as_thread(execute_patch);
524 #else
525 255 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 208 EXPORT int asar_maxromsize()
536 {
537 208 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 487 EXPORT const struct errordata * asar_geterrors(int * count)
547 {
548 487 *count=numerror;
549 487 return errors;
550 }
551
552 /* $EXPORT$
553 * Get a list of all warnings.
554 */
555 487 EXPORT const struct errordata * asar_getwarnings(int * count)
556 {
557 487 *count=numwarn;
558 487 return warnings;
559 }
560
561 /* $EXPORT$
562 * Get a list of all printed data.
563 */
564 471 EXPORT const char * const * asar_getprints(int * count)
565 {
566 471 *count=numprint;
567 471 return prints;
568 }
569
570 /* $EXPORT$
571 * Get a list of all labels.
572 */
573 169 EXPORT const struct labeldata * asar_getalllabels(int * count)
574 {
575
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 169 times.
169 for (int i=0;i<labelsinldata;i++) free((void*)ldata[i].name);
576 169 labelsinldata=0;
577 169 labels.each(addlabel);
578 169 *count=labelsinldata;
579 169 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 170 EXPORT const char * asar_getdefine(const char * name)
601 {
602
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 167 times.
170 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 2163 static void adddef(const string& name, string& value)
621 {
622 definedata define;
623 2163 define.name= duplicate_string(name);
624 2163 define.contents= duplicate_string(value);
625 2163 ddata[definesinddata++]=define;
626 2163 }
627
628 /* $EXPORT$
629 * Gets the values and names of all defines.
630 */
631 171 EXPORT const struct definedata * asar_getalldefines(int * count)
632 {
633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 171 times.
171 for (int i=0;i<definesinddata;i++)
634 {
635 free((void*)ddata[i].name);
636 free((void*)ddata[i].contents);
637 }
638 171 definesinddata=0;
639 171 defines.each(adddef);
640 171 *count=definesinddata;
641 171 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 168 EXPORT double asar_math(const char * math_, const char ** error)
652 {
653 ns="";
654 168 namespace_list.reset();
655 168 sublabels.reset();
656 168 errored=false;
657 168 ismath=true;
658 168 initmathcore();
659 double rval=0;
660 try
661 {
662
1/2
✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
168 rval=(double)math(math_);
663 }
664 catch(errfatal&)
665 {
666 *error=matherror;
667 }
668 168 ismath=false;
669 168 deinitmathcore();
670 168 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 169 EXPORT const struct writtenblockdata * asar_getwrittenblocks(int * count)
678 {
679 169 *count = writtenblocks.count;
680 169 return writtenblocks;
681 }
682
683 /* $EXPORT$
684 * Get the mapper currently used by Asar.
685 */
686 176 EXPORT enum mapper_t asar_getmapper()
687 {
688 176 return mapper;
689 }
690
691 /* $EXPORT$
692 * Generates the contents of a symbols file for in a specific format.
693 */
694 168 EXPORT const char * asar_getsymbolsfile(const char* type){
695
1/2
✓ Branch 0 taken 168 times.
✗ Branch 1 not taken.
168 symbolsfile = create_symbols_file(type, romCrc);
696 168 return symbolsfile;
697 }
698
699 #if defined(__clang__)
700 # pragma clang diagnostic pop
701 #endif
702