Branch data Line data Source code
1 : : #include "asar.h"
2 : : #include "virtualfile.h"
3 : : #include "unicode.h"
4 : :
5 : : #include "platform/file-helpers.h"
6 : :
7 : : #define typed_malloc(type, count) (type*)malloc(sizeof(type)*(count))
8 : : #define typed_realloc(type, ptr, count) (type*)realloc(ptr, sizeof(type)*(count))
9 : :
10 : :
11 : : // Detects if str starts with a UTF-8 byte order mark.
12 : : // If so, throws a warning, then returns the number of bytes we should skip ahead in the string.
13 : 726 : size_t check_bom(const char* str)
14 : : {
15 : : // RPG Hacker: We could also check for BoMs of incompatible encodings here (like UTF-16)
16 : : // and throw errors, but not sure if that's worth adding. Asar never supported any wide
17 : : // encodings to begin with, so it's unreasonable to assume that any UTF-16 patches currently
18 : : // exist for it. As for future patches, those should be caught by the "must be UTF-8" checks
19 : : // I have already implemented further below.
20 : : // I think UTF-8 + BoM is the only case that could lead to confusion if we didn't handle it,
21 : : // so that's why I have added this.
22 [ + + + - : 726 : if (str[0u] == '\xEF' && str[1u] == '\xBB' && str[2u] == '\xBF')
+ - ]
23 : : {
24 : 2 : asar_throw_warning(0, warning_id_byte_order_mark_utf8);
25 : 2 : return 3u;
26 : : }
27 : :
28 : 362 : return 0u;
29 : : }
30 : :
31 : :
32 : 274 : char * readfile(const char * fname, const char * basepath)
33 : : {
34 : 274 : virtual_file_handle myfile = filesystem->open_file(fname, basepath);
35 [ + + ]: 274 : if (myfile == INVALID_VIRTUAL_FILE_HANDLE) return nullptr;
36 : 268 : size_t datalen = filesystem->get_file_size(myfile);
37 : 268 : char * data= typed_malloc(char, datalen+1);
38 : 268 : data[filesystem->read_file(myfile, data, 0u, datalen)] = 0;
39 : 268 : filesystem->close_file(myfile);
40 : :
41 [ + + ]: 268 : if (!is_valid_utf8(data))
42 : : {
43 : 2 : free(data);
44 : 2 : asar_throw_error(0, error_type_block, error_id_invalid_utf8);
45 : : }
46 [ + + ]: 266 : if(check_bom(data)){
47 : 2 : data[0] = ' ';
48 : 2 : data[1] = ' ';
49 : 2 : data[2] = ' ';
50 : : }
51 : 133 : return data;
52 : : }
53 : :
54 : : // RPG Hacker: like readfile(), but doesn't use virtual file system
55 : : // and instead read our file directly.
56 : 460 : char * readfilenative(const char * fname)
57 : : {
58 : 460 : FileHandleType myfile = open_file(fname, FileOpenMode_Read);
59 [ + + ]: 460 : if (myfile == InvalidFileHandle) return nullptr;
60 : 460 : size_t datalen = (size_t)get_file_size(myfile);
61 : 460 : char * data = typed_malloc(char, datalen + 1);
62 : 460 : data[read_file(myfile, data, datalen)] = 0;
63 : 460 : close_file(myfile);
64 : :
65 [ - + ]: 460 : if (!is_valid_utf8(data)) asar_throw_error(0, error_type_block, error_id_invalid_utf8);
66 [ - + ]: 460 : if(check_bom(data)){
67 : 0 : data[0] = ' ';
68 : 0 : data[1] = ' ';
69 : 0 : data[2] = ' ';
70 : : }
71 : 230 : return data;
72 : : }
73 : :
74 : 240 : bool readfile(const char * fname, const char * basepath, char ** data, int * len)
75 : : {
76 : 240 : virtual_file_handle myfile = filesystem->open_file(fname, basepath);
77 [ + + ]: 240 : if (!myfile) return false;
78 : 228 : size_t datalen = filesystem->get_file_size(myfile);
79 : 228 : *data= typed_malloc(char, datalen);
80 : 228 : *len = (int)filesystem->read_file(myfile, *data, 0, datalen);
81 : 228 : filesystem->close_file(myfile);
82 : 228 : return true;
83 : : }
84 : :
85 : : #define isq(n) (((0x2227 ^ (0x0101 * (n))) - 0x0101UL) & ~(0x2227 ^ (0x0101 * (n))) & 0x8080UL)
86 : : #define isqp(n) (((0x22272829 ^ (0x01010101 * (n))) - 0x01010101UL) & ~(0x22272829 ^ (0x01010101 * (n))) & 0x80808080UL)
87 : :
88 : : // RPG Hacker: Only index this with ASCII characters.
89 : : // Anything else doesn't make sense, anyways.
90 : : const bool qparlut[128] = {
91 : : 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
92 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
93 : : 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0,
94 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
95 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
97 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
98 : : 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99 : : };
100 : :
101 : : //this will leave the last char found as the one pointed at
102 : 64369 : inline bool skip_quote(char *&str)
103 : : {
104 : :
105 [ + + ]: 64369 : if(*str == '"') str = strchr(str + 1, '"');
106 [ + + ]: 58602 : else if(*str == '\'')
107 : : {
108 : : int codepoint;
109 : 834 : str += utf8_val(&codepoint, str + 1) + 1;
110 [ - + ]: 834 : if(*str != '\'') return false;
111 : : }
112 : 64369 : return str;
113 : : }
114 : :
115 : : //eat 1 char or quote/par
116 : 11280 : inline bool skip_par(char *&str)
117 : : {
118 : 5640 : int par = 0;
119 [ + + + + : 11280 : if(*str != '\'' && *str != '"' && *str != '(' && *str != ')')
+ + - + ]
120 : : {
121 : 9054 : str++;
122 : 9054 : return true;
123 : : }
124 : : while(true)
125 : : {
126 : 13482 : char *t = str;
127 [ + + ]: 13482 : if(*str == '"') t = strchr(t + 1, '"');
128 [ - + ]: 13140 : else if(*str == '\'')
129 : : {
130 : : int codepoint;
131 : 0 : t += utf8_val(&codepoint, t + 1) + 1;
132 [ # # ]: 0 : if(*t != '\'') return false;
133 : : }
134 [ + + ]: 13140 : else if(*t == '(')
135 : : {
136 : 2040 : par++;
137 : : }
138 [ + + ]: 11100 : else if(*t == ')')
139 : : {
140 : 2040 : par--;
141 [ - + ]: 2040 : if(par < 0) return false;
142 : : }
143 : :
144 : 13482 : str = t + 1;
145 [ + + + + ]: 13482 : if(!*str || !par) return par == 0 ? true : false;
146 : 5628 : }
147 : : }
148 : :
149 : : //instr should not be duplicate chars. Instr should also not be 1 char
150 : 45331 : string& string::qreplace(const char * instr, const char * outstr)
151 : : {
152 : 23771 : string& thisstring =*this;
153 [ + + ]: 45331 : if (!strstr(thisstring, instr)) return thisstring;
154 : 30 : int inlen = strlen(instr);
155 : 30 : string out;
156 [ + + ]: 492 : for (int i=0;thisstring[i];)
157 : : {
158 [ + + ]: 462 : if (!strncmp((const char*)thisstring +i, instr, inlen))
159 : : {
160 : 30 : out+=outstr;
161 : 30 : i+=inlen;
162 : : }
163 : : // randomdude999: prevent appending the null terminator to the output
164 [ + - + - ]: 432 : else if(!isq(thisstring[i])) out+= thisstring[i++];
165 : : else
166 : : {
167 : 0 : char *start = raw() + i;
168 : 0 : char *end = start;
169 [ # # # # ]: 0 : if(!skip_quote(end)) return thisstring;
170 : 0 : out.append(raw(), i, end - start + i + 1);
171 : 0 : i += end - start + 1;
172 : :
173 : : }
174 : : }
175 : 15 : thisstring =out;
176 : 30 : return thisstring;
177 : 30 : }
178 : :
179 : 48983 : string& string::qnormalize()
180 : : {
181 : 25597 : string& thisstring =*this;
182 : 48983 : string out;
183 : 25597 : char *startstr = thisstring.raw();
184 : 25597 : char *str = startstr;
185 [ + + ]: 103193 : while(str = strpbrk(str, "'\" \t,\r"))
186 : : {
187 [ + + ]: 54246 : if(is_space(*str))
188 : : {
189 [ + + + + : 41783 : if(str[0] == ' ' && !is_space(str[1]))
+ + ]
190 : : {
191 : 41723 : str++;
192 : 41723 : continue;
193 : : }
194 : 60 : out.append(startstr, 0, str - startstr);
195 : 60 : out += ' ';
196 [ + + ]: 252 : while(is_space(*str)) str++;
197 : 30 : startstr = str;
198 [ + + ]: 12463 : }else if(*str == ',')
199 : : {
200 : 6004 : str++;
201 [ + + ]: 6004 : if(is_space(*str))
202 : : {
203 : 1716 : out.append(startstr, 0, str - startstr);
204 [ + + ]: 3462 : while(is_space(*str)) str++;
205 : 858 : startstr = str;
206 : : }
207 : : }
208 : : else
209 : : {
210 : 6459 : str = strchr(str + 1, *str); //confirm quotes has already been run, so this should be okay
211 [ + + ]: 6459 : if(!str) return thisstring;
212 : 6423 : str++;
213 : : }
214 : : }
215 [ + + ]: 48947 : if(startstr != thisstring.raw())
216 : : {
217 : 1398 : out.append(startstr, 0, strlen(startstr)); //the remaining
218 : :
219 : 699 : thisstring = out;
220 : : }
221 : 25579 : return thisstring;
222 : 48983 : }
223 : :
224 : 21074 : bool confirmquotes(const char * str)
225 : : {
226 [ + + ]: 22086 : while(*str)
227 : : {
228 : 7528 : char *dquote = strchr((char *)str, '"');
229 : 7528 : char *squote = strchr((char *)str, '\'');
230 [ + + + + ]: 15056 : if(dquote || squote)
231 : : {
232 [ + + + + : 1022 : if(dquote && (dquote < squote || !squote))
+ + ]
233 : : {
234 : 820 : dquote = strchr(dquote+1, '"');
235 [ + + ]: 816 : if(dquote) str = dquote+1;
236 : 4 : else return false;
237 : : }
238 : : else
239 : : {
240 : : int codepoint;
241 : 202 : squote += utf8_val(&codepoint, squote + 1) + 1;
242 [ + + ]: 202 : if(*squote == '\'') str = squote+1;
243 : 2 : else return false;
244 : : }
245 : 506 : }
246 : : else
247 : : {
248 : 7017 : return true;
249 : : }
250 : : }
251 : 3515 : return true;
252 : : }
253 : :
254 : 734 : bool confirmqpar(const char * str)
255 : : {
256 : : //todo fully optimize
257 : 367 : int par = 0;
258 [ - + + + ]: 9806 : while((unsigned char)*str >= 128 || !qparlut[*str]) str++;
259 [ + + ]: 2532 : while(*str)
260 : : {
261 [ + + ]: 1798 : if(*str == '"')
262 : : {
263 : 366 : str = strchr(str + 1, '"');
264 [ - + ]: 366 : if(!str++) return false;
265 : : }
266 [ + + ]: 1432 : else if(*str == '\'')
267 : : {
268 : : int codepoint;
269 : 24 : str += utf8_val(&codepoint, str + 1) + 1;
270 [ + - ]: 24 : if(*str == '\'') str++;
271 : 0 : else return false;
272 : : }
273 : : else
274 : : {
275 : 1408 : par += 1 - ((*str++ - '(') << 1);
276 [ - + ]: 1408 : if(par < 0) return false;
277 : : }
278 [ - + + + ]: 4550 : while((unsigned char)*str >= 128 || !qparlut[*str]) str++;
279 : : }
280 : 734 : return !par;
281 : : }
282 : :
283 : 52254 : char ** split(char * str, char key, int * len)
284 : : {
285 : 52254 : char *thisentry=strchr(str, key);
286 [ + + ]: 52254 : if (!thisentry)
287 : : {
288 : 28124 : char ** out= typed_malloc(char*, 2);
289 : 28124 : out[0]=str;
290 : 28124 : out[1]=nullptr;
291 [ + + ]: 28124 : if (len) *len=1;
292 : 28124 : return out;
293 : : }
294 : 12065 : int count=15; //makes the default alloc 8 elements, sounds fair.
295 : 24130 : char ** outdata= typed_malloc(char*, (size_t)count+1);
296 : :
297 : 12065 : int newcount=0;
298 : 24130 : outdata[newcount++]=str;
299 : : do{
300 : 41220 : *thisentry = 0;
301 : 41220 : thisentry++;
302 : 41220 : outdata[newcount++]=thisentry;
303 [ + + ]: 41220 : if(newcount >= count)
304 : : {
305 : 260 : count *= 2;
306 : 260 : outdata = typed_realloc(char *, outdata, count);
307 : : }
308 [ + + ]: 41220 : }while((thisentry = strchr(thisentry, key)));
309 : :
310 : 24130 : outdata[newcount]= nullptr;
311 [ + + ]: 24130 : if (len) *len=newcount;
312 : 12065 : return outdata;
313 : : }
314 : :
315 : 56281 : char ** qsplit(char * str, char key, int * len)
316 : : {
317 [ + + + + ]: 56281 : if (!strchr(str, '"') && !strchr(str, '\'')) return split(str, key, len);
318 : :
319 : 4019 : int count=15;
320 : 5827 : char ** outdata= typed_malloc(char*, (size_t)count+1);
321 : 4019 : int newcount=0;
322 : 5827 : char * thisentry=str;
323 : 5827 : outdata[newcount++]=thisentry;
324 [ + + ]: 57093 : while (*thisentry) /*todo fix*/
325 : : {
326 [ + + ]: 51266 : if (*thisentry == key)
327 : : {
328 : 6091 : *thisentry=0;
329 : 6091 : thisentry++;
330 : 6091 : outdata[newcount++]=thisentry;
331 [ - + ]: 6091 : if(newcount >= count)
332 : : {
333 : 0 : count *= 2;
334 : 0 : outdata = typed_realloc(char *, outdata, count);
335 : : }
336 : : }
337 [ + - + - ]: 45175 : else if(skip_quote(thisentry)) thisentry++;
338 : 0 : else return nullptr;
339 : : }
340 : 5827 : outdata[newcount]= nullptr;
341 [ + + ]: 5827 : if (len) *len=newcount;
342 : 4019 : return outdata;
343 : : }
344 : :
345 : 45331 : char ** qsplitstr(char * str, const char * key, int * len)
346 : : {
347 : : //check if the str is found first
348 [ + + ]: 45331 : if (!strstr(str, key))
349 : : {
350 : 44947 : char ** out= typed_malloc(char*, 2);
351 : 44947 : out[0]=str;
352 : 44947 : out[1]=nullptr;
353 [ - + ]: 44947 : if (len) *len=1;
354 : 44947 : return out;
355 : : }
356 : :
357 : 384 : int keylen=(int)strlen(key);
358 : 192 : int count=15;
359 : 384 : char ** outdata= typed_malloc(char*, (size_t)count+1);
360 : 192 : int newcount=0;
361 : 384 : char * thisentry=str;
362 : 384 : outdata[newcount++]=thisentry;
363 [ + + ]: 21294 : while (*thisentry) /*todo fix*/
364 : : {
365 [ + + ]: 20910 : if (!strncmp(thisentry, key, (size_t)keylen))
366 : : {
367 : 1716 : *thisentry=0;
368 : 1716 : thisentry+=keylen;
369 : 1716 : outdata[newcount++]=thisentry;
370 [ - + ]: 1716 : if(newcount >= count)
371 : : {
372 : 0 : count *= 2;
373 : 0 : outdata = typed_realloc(char *, outdata, count);
374 : : }
375 : : }
376 [ + - + - ]: 19194 : else if(skip_quote(thisentry)) thisentry++;
377 : 0 : else return nullptr;
378 : : }
379 : 384 : outdata[newcount]= nullptr;
380 [ - + ]: 384 : if (len) *len=newcount;
381 : 192 : return outdata;
382 : : }
383 : :
384 : : //this function is most commonly called in cases where additional chars are very likely
385 : 11160 : char ** qpsplit(char * str, char key, int * len)
386 : : {
387 [ + + + - : 11160 : if (!strchr(str, '(') && !strchr(str, ')')) return qsplit(str, key, len);
+ - ]
388 : 963 : int count=7;
389 : 1926 : char ** outdata= typed_malloc(char*, (size_t)count+1);
390 : :
391 : 963 : int newcount=0;
392 : 1926 : char * thisentry=str;
393 : 1926 : outdata[newcount++]=thisentry;
394 [ + + ]: 13620 : while (*thisentry)
395 : : {
396 : : //skippar(*thisentry, thisentry++, return nullptr;)
397 [ + + ]: 11694 : if (*thisentry == key)
398 : : {
399 : 894 : *thisentry=0;
400 : 894 : thisentry++;
401 : 894 : outdata[newcount++]=thisentry;
402 [ + + ]: 894 : if(newcount >= count)
403 : : {
404 : 12 : count *= 2;
405 : 12 : outdata = typed_realloc(char *, outdata, count);
406 : : }
407 : : }
408 [ + - - + ]: 10800 : else if(!skip_par(thisentry)) return nullptr;
409 : : }
410 : 1926 : outdata[newcount]= nullptr;
411 [ + + ]: 1926 : if (len) *len=newcount;
412 : 963 : return outdata;
413 : : }
414 : :
415 : 840 : string &itrim(string &input, const char * left, const char * right)
416 : : {
417 : 420 : bool nukeright=true;
418 : 420 : int totallen=input.length();
419 : 840 : int rightlen=(int)strlen(right);
420 [ + - + - ]: 840 : if (rightlen && rightlen<=totallen)
421 : : {
422 : 840 : const char * rightend=right+rightlen;
423 : 840 : const char * strend=input.data()+totallen;
424 [ + + ]: 2820 : while (right!=rightend)
425 : : {
426 : 1980 : rightend--;
427 : 1980 : strend--;
428 [ - + ]: 1980 : if (to_lower(*strend)!=to_lower(*rightend)) nukeright=false;
429 : : }
430 [ + - ]: 840 : if (nukeright)
431 : : {
432 : 840 : totallen-=rightlen;
433 : 420 : input.truncate(totallen);
434 : : }
435 : : }
436 : 420 : bool nukeleft=true;
437 : 840 : int leftlen = strlen(left);
438 [ + + + + : 840 : if(leftlen == 1 && input.data()[0] == left[0])
+ + ]
439 : : {
440 : 204 : return input = string(input.data()+1, (input.length()-1));
441 : : }
442 : : else
443 : : {
444 [ - + ]: 636 : for (int i = 0; i < leftlen; i++)
445 : : {
446 [ # # ]: 0 : if (to_lower(input.data()[i])!=to_lower(left[i])) nukeleft=false;
447 : : }
448 [ + - + - : 954 : if (nukeleft) input = string(input.data()+leftlen, (input.length()-leftlen));
+ - + - ]
449 : : }
450 : 318 : return input;
451 : : }
452 : :
453 : 0 : char* strqpchr(char* str, char key)
454 : : {
455 [ # # ]: 0 : while (*str)
456 : : {
457 [ # # ]: 0 : if (*str == key) return str;
458 [ # # ]: 0 : else if(!skip_par(str)) return nullptr;
459 : : }
460 : 0 : return nullptr;
461 : : }
462 : :
463 : 126 : char* strqpstr(char* str, const char* key)
464 : : {
465 : 126 : size_t keylen = strlen(key);
466 [ + + ]: 606 : while (*str)
467 : : {
468 [ + + ]: 600 : if (!strncmp(str, key, keylen)) return str;
469 [ - + ]: 480 : else if(!skip_par(str)) return nullptr;
470 : : }
471 : 3 : return nullptr;
472 : : }
473 : :
474 : : extern const uint8_t char_props[256] = {
475 : : //x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF
476 : : 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x80,0x00,0x00, // 0x
477 : : 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 1x
478 : : 0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 2x !"#$%&'()*+,-./
479 : : 0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x41,0x00,0x00,0x00,0x00,0x00,0x00, // 3x 0123456789:;<=>?
480 : : 0x00,0x23,0x23,0x23,0x23,0x23,0x23,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22, // 4x @ABCDEFGHIJKLMNO
481 : : 0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x22,0x00,0x00,0x00,0x00,0x08, // 5x PQRSTUVWXYZ[\]^_
482 : : 0x00,0x25,0x25,0x25,0x25,0x25,0x25,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, // 6x `abcdefghijklmno
483 : : 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x00,0x00,0x00,0x00,0x00, // 7x pqrstuvwxyz{|}~
484 : : 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 8x
485 : : 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 9x
486 : : 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Ax
487 : : 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Bx
488 : : 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Cx
489 : : 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Dx
490 : : 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Ex
491 : : 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Fx
492 : : };
|