asar coverage - build #262


src/asar/
File: src/asar/interface-lib.cpp
Date: 2025-02-27 19:01:43
Lines:
260/278
93.5%
Functions:
31/32
96.9%
Branches:
158/272
58.1%

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