asar coverage - build #269


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