asar coverage - build #266


src/asar/
File: src/asar/interface-lib.cpp
Date: 2025-03-01 20:27:29
Lines:
267/281
95.0%
Functions:
31/32
96.9%
Branches:
210/399
52.6%

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 266 static void fillerror(errordata& myerr, const char* errname, const char * type, const char * str, bool show_block)
101 {
102
1/2
✓ Branch 0 taken 266 times.
✗ Branch 1 not taken.
266 const char* current_filename = get_current_file_name();
103
2/2
✓ Branch 0 taken 265 times.
✓ Branch 1 taken 1 times.
266 if(current_filename) myerr.filename= duplicate_string(current_filename);
104 1 else myerr.filename = duplicate_string("");
105
1/2
✓ Branch 0 taken 266 times.
✗ Branch 1 not taken.
266 myerr.line=get_current_line();
106
1/2
✓ Branch 0 taken 266 times.
✗ Branch 1 not taken.
266 const char* current_block = get_current_block();
107
2/2
✓ Branch 0 taken 255 times.
✓ Branch 1 taken 11 times.
266 if (current_block) myerr.block= duplicate_string(current_block);
108 11 else myerr.block= duplicate_string("");
109 266 myerr.rawerrdata= duplicate_string(str);
110 266 string location;
111 266 string details;
112
1/2
✓ Branch 0 taken 266 times.
✗ Branch 1 not taken.
266 get_current_line_details(&location, &details);
113
11/21
✓ Branch 0 taken 130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 266 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 130 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 130 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 130 times.
✓ Branch 9 taken 136 times.
✓ Branch 10 taken 130 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 136 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 136 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 136 times.
✗ Branch 18 not taken.
✓ Branch 19 taken 136 times.
✗ Branch 20 not taken.
266 myerr.fullerrdata= duplicate_string(location+": "+type+str+details+get_callstack());
114 266 myerr.errname = duplicate_string(errname);
115
116 266 autoarray<printable_callstack_entry> printable_stack;
117
1/2
✓ Branch 0 taken 266 times.
✗ Branch 1 not taken.
266 get_full_printable_callstack(&printable_stack, 0, false);
118
119 266 myerr.callstacksize = printable_stack.count;
120 266 myerr.callstack = static_cast<stackentry*>(malloc(sizeof(stackentry) * myerr.callstacksize));
121
122
4/4
✓ Branch 0 taken 2324 times.
✓ Branch 1 taken 130 times.
✓ Branch 2 taken 1253 times.
✓ Branch 3 taken 136 times.
3843 for (int i = 0; i < myerr.callstacksize; ++i)
123 {
124 3577 stackentry& entry = const_cast<stackentry&>(myerr.callstack[i]);
125
126
1/2
✓ Branch 0 taken 3577 times.
✗ Branch 1 not taken.
3577 entry.fullpath = duplicate_string(printable_stack[i].fullpath);
127
1/2
✓ Branch 0 taken 3577 times.
✗ Branch 1 not taken.
3577 entry.prettypath = duplicate_string(printable_stack[i].prettypath);
128
1/2
✓ Branch 0 taken 3577 times.
✗ Branch 1 not taken.
3577 entry.lineno = printable_stack[i].lineno;
129
1/2
✓ Branch 0 taken 3577 times.
✗ Branch 1 not taken.
3577 entry.details = duplicate_string(printable_stack[i].details);
130 }
131 402 }
132
133 static bool ismath=false;
134 static string matherror;
135
136 531 void error_interface(int errid, int whichpass, const char * e_)
137 {
138 531 errored = true;
139
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 531 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 269 times.
531 if (ismath) matherror = e_;
140
2/2
✓ Branch 0 taken 222 times.
✓ Branch 1 taken 307 times.
529 else if (pass == whichpass) {
141 // don't show current block if the error came from an error command
142 222 bool show_block = (errid != error_id_error_command);
143
13/20
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 222 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 110 times.
✓ Branch 5 taken 112 times.
✓ Branch 6 taken 110 times.
✓ Branch 7 taken 112 times.
✓ Branch 8 taken 110 times.
✓ Branch 9 taken 112 times.
✓ Branch 10 taken 110 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 110 times.
✓ Branch 13 taken 112 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
✓ Branch 16 taken 112 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 112 times.
✗ Branch 19 not taken.
222 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 531 }
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 283 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 283 times.
381 for (int i=0;i<numprint;i++)
164 {
165 98 free_and_null(prints[i]);
166 }
167 283 prints.reset();
168 283 numprint=0;
169
170
2/2
✓ Branch 0 taken 222 times.
✓ Branch 1 taken 283 times.
505 for (int i=0;i<numerror;i++)
171 {
172 222 free_and_null(errors[i].filename);
173 222 free_and_null(errors[i].rawerrdata);
174 222 free_and_null(errors[i].fullerrdata);
175 222 free_and_null(errors[i].block);
176 222 free_and_null(errors[i].errname);
177
178
4/4
✓ Branch 0 taken 2324 times.
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 1249 times.
✓ Branch 3 taken 112 times.
3795 for (int j=0;j<errors[i].callstacksize;++j)
179 {
180 3573 stackentry& entry = const_cast<stackentry&>(errors[i].callstack[j]);
181 3573 free_and_null(entry.fullpath);
182 3573 free_and_null(entry.prettypath);
183 3573 free_and_null(entry.details);
184 }
185 222 free_and_null(errors[i].callstack);
186 }
187 283 errors.reset();
188 283 numerror=0;
189
190
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 283 times.
327 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 283 warnings.reset();
208 283 numwarn=0;
209
210
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 283 times.
306 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 283 ddata.reset();
216 283 definesinddata=0;
217
218
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 283 times.
290 for (int i=0;i<labelsinldata;i++)
219 7 free((void*)ldata[i].name);
220 283 ldata.reset();
221 283 labelsinldata=0;
222 #undef free_and_null
223
224 283 romCrc = 0;
225 283 clidefines.reset();
226 283 reset_warnings_to_default();
227
228 283 reseteverything();
229 283 }
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 279 static void asar_patch_begin(char * romdata_, int buflen, int * romlen_)
288 {
289
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 279 times.
279 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 279 else romdata_r = (unsigned char*)romdata_;
295 279 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 154 times.
279 memset((void*)romdata, 0, maxromsize);
298
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 154 times.
279 memcpy(const_cast<unsigned char*>(romdata), romdata_, (size_t)*romlen_);
299 279 resetdllstuff();
300 279 romlen = *romlen_;
301 279 romlen_r = *romlen_;
302 279 }
303
304 279 static void asar_patch_main(const char * patchloc)
305 {
306
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 278 times.
279 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 817 times.
✓ Branch 1 taken 269 times.
1086 for (pass = 0;pass < 3;pass++)
311 {
312
1/2
✓ Branch 0 taken 817 times.
✗ Branch 1 not taken.
817 initstuff();
313
2/2
✓ Branch 0 taken 807 times.
✓ Branch 1 taken 10 times.
817 assemblefile(patchloc);
314 // RPG Hacker: Necessary, because finishpass() can throws warning and errors.
315
3/8
✓ Branch 0 taken 360 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 807 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 447 times.
✗ Branch 7 not taken.
807 callstack_push cs_push(callstack_entry_type::FILE, filesystem->create_absolute_path(nullptr, patchloc));
316
1/2
✓ Branch 0 taken 807 times.
✗ Branch 1 not taken.
807 finishpass();
317 807 }
318 }
319
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 catch (errfatal&) {}
320 279 }
321
322 279 static bool asar_patch_end(char * romdata_, int buflen, int * romlen_)
323 {
324
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 279 times.
✓ Branch 2 taken 25 times.
✓ Branch 3 taken 129 times.
279 if (checksum_fix_enabled) fixchecksum();
325
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 279 times.
279 if (romdata_ != (const char*)romdata_r) free(const_cast<unsigned char*>(romdata_r));
326
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 279 times.
279 if (buflen < romlen) asar_throw_error(pass, error_type_null, error_id_buffer_too_small);
327
4/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 243 times.
✓ Branch 2 taken 37 times.
✓ Branch 3 taken 117 times.
279 if (errored)
328 {
329
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
73 if (numerror==0)
330 asar_throw_error(pass, error_type_null, error_id_internal_error, "phantom error");
331 73 free(const_cast<unsigned char*>(romdata));
332 73 return false;
333 }
334
2/3
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
206 if (*romlen_ != buflen)
335 {
336 206 *romlen_ = romlen;
337 }
338 206 romCrc = crc32((const uint8_t*)romdata, (size_t)romlen);
339
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);
340 206 free(const_cast<unsigned char*>(romdata));
341 206 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 4 EXPORT bool asar_init()
351 {
352
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;
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 2 EXPORT int asar_version()
361 {
362 2 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 8 EXPORT int asar_apiversion()
375 {
376 8 expectsNewAPI=true;
377 8 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 4 EXPORT void asar_close()
392 {
393 4 resetdllstuff();
394 4 }
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 279 EXPORT bool asar_patch(const struct patchparams_base *params)
408 {
409 279 auto execute_patch = [&]() {
410
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 154 times.
279 if (params == nullptr)
411 {
412 asar_throw_error(pass, error_type_null, error_id_params_null);
413 }
414
415
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 125 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 154 times.
279 if (params->structsize != sizeof(patchparams_v200))
416 {
417 asar_throw_error(pass, error_type_null, error_id_params_invalid_size);
418 }
419
420 154 patchparams paramscurrent;
421
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 154 times.
279 memset(&paramscurrent, 0, sizeof(paramscurrent));
422
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 154 times.
279 memcpy(&paramscurrent, params, (size_t)params->structsize);
423
424
425
1/2
✓ Branch 0 taken 279 times.
✗ Branch 1 not taken.
279 asar_patch_begin(paramscurrent.romdata, paramscurrent.buflen, paramscurrent.romlen);
426
427
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 154 times.
279 simple_callstacks = !paramscurrent.full_call_stack;
428
429 279 autoarray<string> includepaths;
430 279 autoarray<const char*> includepath_cstrs;
431
432
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 279 times.
280 for (int i = 0; i < paramscurrent.numincludepaths; ++i)
433 {
434
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");
435
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]);
436
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);
437 }
438
439
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 278 times.
279 if (paramscurrent.stdincludesfile != nullptr) {
440
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");
441
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 string stdincludespath = paramscurrent.stdincludesfile;
442
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 parse_std_includes(stdincludespath, includepaths);
443 1 }
444
445
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 279 times.
283 for (int i = 0; i < includepaths.count; ++i)
446 {
447
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]);
448 }
449
450 279 size_t includepath_count = (size_t)includepath_cstrs.count;
451
2/3
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
279 virtual_filesystem new_filesystem;
452
2/4
✓ Branch 0 taken 279 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 279 times.
✗ Branch 3 not taken.
279 new_filesystem.initialize(&includepath_cstrs[0], includepath_count);
453 279 filesystem = &new_filesystem;
454
455
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 279 times.
313 for(int i = 0; i < paramscurrent.memory_file_count; ++i) {
456 34 memoryfile f = paramscurrent.memory_files[i];
457
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);
458 }
459
460 279 clidefines.reset();
461
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 279 times.
282 for (int i = 0; i < paramscurrent.additional_define_count; ++i)
462 {
463
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 : "");
464
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 strip_whitespace(name);
465
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 name.strip_prefix('!'); // remove leading ! if present
466
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());
467
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)) {
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
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 : "");
472
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;
473
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 }
474
475
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 278 times.
279 if (paramscurrent.stddefinesfile != nullptr) {
476
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");
477
1/3
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 string stddefinespath = paramscurrent.stddefinesfile;
478
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 parse_std_defines(stddefinespath);
479 1 } else {
480
1/2
✓ Branch 0 taken 278 times.
✗ Branch 1 not taken.
278 parse_std_defines(nullptr); // needed to populate builtin defines
481 }
482
483
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 279 times.
281 for (int i = 0; i < paramscurrent.warning_setting_count; ++i)
484 {
485
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);
486
487
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (warnid != warning_id_end)
488 {
489
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);
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
4/4
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 154 times.
✓ Branch 2 taken 129 times.
✓ Branch 3 taken 25 times.
279 if(paramscurrent.override_checksum_gen) {
498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 129 times.
254 checksum_fix_enabled = paramscurrent.generate_checksum;
499 254 force_checksum_fix = true;
500 }
501
502
1/2
✓ Branch 0 taken 279 times.
✗ Branch 1 not taken.
279 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 279 times.
✗ Branch 1 not taken.
279 closecachedfiles();
507
508
1/2
✓ Branch 0 taken 279 times.
✗ Branch 1 not taken.
279 new_filesystem.destroy();
509 279 filesystem = nullptr;
510
511
1/2
✓ Branch 0 taken 279 times.
✗ Branch 1 not taken.
279 return asar_patch_end(paramscurrent.romdata, paramscurrent.buflen, paramscurrent.romlen);
512 279 };
513 #if defined(RUN_VIA_FIBER)
514 return run_as_fiber(execute_patch);
515 #elif defined(RUN_VIA_THREAD)
516
1/2
✓ Branch 0 taken 279 times.
✗ Branch 1 not taken.
558 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 57 EXPORT int asar_maxromsize()
529 {
530 57 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 269 EXPORT const struct errordata * asar_geterrors(int * count)
540 {
541 269 *count=numerror;
542 269 return errors;
543 }
544
545 /* $EXPORT$
546 * Get a list of all warnings.
547 */
548 269 EXPORT const struct errordata * asar_getwarnings(int * count)
549 {
550 269 *count=numwarn;
551 269 return warnings;
552 }
553
554 /* $EXPORT$
555 * Get a list of all printed data.
556 */
557 251 EXPORT const char * const * asar_getprints(int * count)
558 {
559 251 *count=numprint;
560 251 return prints;
561 }
562
563 /* $EXPORT$
564 * Get a list of all labels.
565 */
566 2 EXPORT const struct labeldata * asar_getalllabels(int * count)
567 {
568
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);
569 2 labelsinldata=0;
570 2 labels.each([](const string& name, const snes_label& label_data) {
571 7 labeldata label;
572
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 label.name = strdup(name);
573 7 label.location = (int)(label_data.pos & 0xFFFFFF);
574
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 ldata[labelsinldata++] = label;
575 7 });
576 2 *count=labelsinldata;
577 2 std::sort<labeldata*>(ldata, ldata + labelsinldata,
578
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; });
579 2 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 int i;
588 try {
589
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 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/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;
593 2 else return i&0xFFFFFF;
594 }
595
596 /* $EXPORT$
597 * Get the value of a define.
598 */
599 4 EXPORT const char * asar_getdefine(const char * name)
600 {
601
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
4 if (!defines.exists(name)) return "";
602 2 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 4 EXPORT const char * asar_resolvedefines(const char * data)
610 {
611
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;
612 4 out = "";
613 try
614 {
615
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
4 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 4 return out;
621 }
622
623 /* $EXPORT$
624 * Gets the values and names of all defines.
625 */
626 4 EXPORT const struct definedata * asar_getalldefines(int * count)
627 {
628
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 for (int i=0;i<definesinddata;i++)
629 {
630 free((void*)ddata[i].name);
631 free((void*)ddata[i].contents);
632 }
633 4 definesinddata=0;
634 4 defines.each([](const string& name, string& value) {
635 23 definedata define;
636 23 define.name = duplicate_string(name);
637 23 define.contents = duplicate_string(value);
638
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 ddata[definesinddata++] = define;
639 23 });
640 4 *count=definesinddata;
641 4 std::sort<definedata*>(ddata, ddata + definesinddata,
642
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; });
643 4 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 5 EXPORT double asar_math(const char * math_, const char ** error)
654 {
655 5 ns="";
656 5 namespace_list.reset();
657 5 sublabels.reset();
658 5 errored=false;
659 5 ismath=true;
660 5 initmathcore();
661 5 double rval=0;
662 try
663 {
664
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();
665 }
666
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 catch(errfatal&)
667 {
668 2 *error=matherror;
669 2 }
670 5 ismath=false;
671 5 deinitmathcore();
672 5 return rval;
673 5 }
674
675 /* $EXPORT$
676 * Get a list of all the blocks written to the ROM by calls such as
677 * asar_patch().
678 */
679 4 EXPORT const struct writtenblockdata * asar_getwrittenblocks(int * count)
680 {
681 4 *count = writtenblocks.count;
682 4 return writtenblocks;
683 }
684
685 /* $EXPORT$
686 * Get the mapper currently used by Asar.
687 */
688 9 EXPORT enum mapper_t asar_getmapper()
689 {
690
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 return mapper;
691 }
692
693 /* $EXPORT$
694 * Generates the contents of a symbols file for in a specific format.
695 */
696 2 EXPORT const char * asar_getsymbolsfile(const char* type){
697
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);
698 2 return symbolsfile;
699 }
700
701 #if defined(__clang__)
702 # pragma clang diagnostic pop
703 #endif
704