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(¶mscurrent, 0, sizeof(paramscurrent)); |
422 |
|
531 |
memcpy(¶mscurrent, 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 |
|
|
|