| Line |
Branch |
Exec |
Source |
| 1 |
|
|
#include "platform/file-helpers.h" |
| 2 |
|
|
|
| 3 |
|
|
|
| 4 |
|
|
// This function is based in part on nall, which is under the following licence. |
| 5 |
|
|
// This modified version is licenced under the LGPL version 3 or later. See the LICENSE file |
| 6 |
|
|
// for details. |
| 7 |
|
|
// |
| 8 |
|
|
// Copyright (c) 2006-2015 byuu |
| 9 |
|
|
// |
| 10 |
|
|
// Permission to use, copy, modify, and/or distribute this software for |
| 11 |
|
|
// any purpose with or without fee is hereby granted, provided that the |
| 12 |
|
|
// above copyright notice and this permission notice appear in all |
| 13 |
|
|
// copies. |
| 14 |
|
|
// |
| 15 |
|
|
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL |
| 16 |
|
|
// WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED |
| 17 |
|
|
// WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE |
| 18 |
|
|
// AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
| 19 |
|
|
// DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
| 20 |
|
|
// PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER |
| 21 |
|
|
// TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR |
| 22 |
|
|
// PERFORMANCE OF THIS SOFTWARE. |
| 23 |
|
20711 |
string dir(char const *name) |
| 24 |
|
|
{ |
| 25 |
4/4
✓ Branch 0 taken 140771 times.
✓ Branch 1 taken 10371 times.
✓ Branch 2 taken 141006 times.
✓ Branch 3 taken 1 times.
|
281778 |
for (signed i = (int)strlen(name); i >= 0; i--) |
| 26 |
|
|
{ |
| 27 |
5/6
✓ Branch 0 taken 130431 times.
✓ Branch 1 taken 10340 times.
✓ Branch 2 taken 130636 times.
✓ Branch 3 taken 140801 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 130636 times.
|
281777 |
if (name[i] == '/' || name[i] == '\\') |
| 28 |
|
|
{ |
| 29 |
|
20710 |
return string(name, i+1); |
| 30 |
|
|
} |
| 31 |
|
|
} |
| 32 |
|
1 |
return ""; |
| 33 |
|
|
} |
| 34 |
|
|
|
| 35 |
|
10332 |
string create_combined_path(const char* path1, const char* path2) |
| 36 |
|
|
{ |
| 37 |
2/3
✓ Branch 0 taken 5136 times.
✓ Branch 1 taken 5196 times.
✗ Branch 2 not taken.
|
10332 |
string combined = path1; |
| 38 |
|
|
|
| 39 |
|
10332 |
int length = combined.length(); |
| 40 |
|
|
|
| 41 |
9/12
✓ Branch 0 taken 10332 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5136 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5196 times.
✓ Branch 5 taken 5136 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 5136 times.
✓ Branch 8 taken 33 times.
✓ Branch 9 taken 5163 times.
✓ Branch 10 taken 33 times.
✓ Branch 11 taken 5163 times.
|
10332 |
if (combined.length() > 0 && path1[length - 1] != '\\' && path1[length - 1] != '/') |
| 42 |
|
|
{ |
| 43 |
2/4
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 33 times.
✗ Branch 3 not taken.
|
33 |
combined += get_native_path_separator(); |
| 44 |
|
|
} |
| 45 |
|
|
|
| 46 |
1/2
✓ Branch 0 taken 10332 times.
✗ Branch 1 not taken.
|
10332 |
combined += path2; |
| 47 |
|
|
|
| 48 |
2/3
✓ Branch 0 taken 5136 times.
✓ Branch 1 taken 5196 times.
✗ Branch 2 not taken.
|
20664 |
return normalize_path(combined); |
| 49 |
|
10332 |
} |
| 50 |
|
|
|
| 51 |
|
|
|
| 52 |
|
|
// RPG Hacker: This function attempts to normalize a path. |
| 53 |
|
|
// This means that it attempts to put it into a format |
| 54 |
|
|
// where a simple string compare between two paths |
| 55 |
|
|
// referring to the same file will hopefully always |
| 56 |
|
|
// succeed. |
| 57 |
|
|
// There are a few known problems and limitations: |
| 58 |
|
|
// - Relative paths are not recommended, as they can't be |
| 59 |
|
|
// resolved reliably. For example, in this path |
| 60 |
|
|
// ../patch/main.asm |
| 61 |
|
|
// we can't collapse the .. because we don't know the |
| 62 |
|
|
// parent directory. A comparison will also fail when |
| 63 |
|
|
// one piece of code uses a relative path while another |
| 64 |
|
|
// piece of code uses an absolute path. For those |
| 65 |
|
|
// reasons, it's recommended to always use absolute paths |
| 66 |
|
|
// everywhere if possible. |
| 67 |
|
|
// - Windows network paths like |
| 68 |
|
|
// \\MY_PC\patch\main.asm |
| 69 |
|
|
// Will likely break with this, since the function converts |
| 70 |
|
|
// all back slashes to forward slashes. I think Windows |
| 71 |
|
|
// actually requires back slashes for network paths. |
| 72 |
|
|
// - Currently, the code doesn't look at drive letters |
| 73 |
|
|
// and just treats them as folders, so a path like |
| 74 |
|
|
// C:/../patch/main.asm |
| 75 |
|
|
// would result in |
| 76 |
|
|
// patch/main.asm |
| 77 |
|
|
// (However, a path like that is invalid, anyways, so |
| 78 |
|
|
// this hopefully doesn't matter). |
| 79 |
|
22902 |
string normalize_path(const char* path) |
| 80 |
|
|
{ |
| 81 |
1/2
✓ Branch 0 taken 22902 times.
✗ Branch 1 not taken.
|
22902 |
string normalized = path; |
| 82 |
|
|
|
| 83 |
|
|
|
| 84 |
|
|
// RPG Hacker: Replace all \ in path by / |
| 85 |
|
|
// (Windows should work with / in paths just fine). |
| 86 |
|
|
// Note: will likely break network paths on Windows, |
| 87 |
|
|
// which still expect a prefix of \\, but does anyone |
| 88 |
|
|
// seriously even use them with Asar? |
| 89 |
2/2
✓ Branch 0 taken 642454 times.
✓ Branch 1 taken 22902 times.
|
665356 |
for (int i = 0; i < normalized.length(); ++i) |
| 90 |
|
|
{ |
| 91 |
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 318121 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 324333 times.
|
642454 |
if (normalized[i] == '\\') |
| 92 |
|
|
{ |
| 93 |
|
✗ |
normalized.temp_raw()[i]= '/'; |
| 94 |
|
|
} |
| 95 |
|
|
} |
| 96 |
|
|
|
| 97 |
|
|
// RPG Hacker: Collapse path by removing all unnecessary |
| 98 |
|
|
// . or .. path components. |
| 99 |
|
|
// As a little hack, just overwrite all the stuff we're |
| 100 |
|
|
// going to remove with 0x01 and remove it later. Probably |
| 101 |
|
|
// easier than to always shorten the path immediately. |
| 102 |
|
|
// Also using \x01 instead of \0 so that the path is still |
| 103 |
|
|
// easily readable in a debugger (since it normally just |
| 104 |
|
|
// assumes a string to end at \0). I don't think \x01 can |
| 105 |
|
|
// be used in valid paths, so this should be okay. |
| 106 |
|
22902 |
char* previous_dir_start_pos = nullptr; |
| 107 |
|
22902 |
char* current_dir_start_pos = normalized.temp_raw(); |
| 108 |
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 17733 times.
✓ Branch 2 taken 11632 times.
|
29365 |
while (*current_dir_start_pos == '/') |
| 109 |
|
|
{ |
| 110 |
|
6463 |
++current_dir_start_pos; |
| 111 |
|
|
} |
| 112 |
|
22902 |
char* current_dir_end_pos = current_dir_start_pos; |
| 113 |
|
|
|
| 114 |
|
|
|
| 115 |
3/3
✓ Branch 0 taken 47398 times.
✓ Branch 1 taken 57517 times.
✓ Branch 2 taken 11632 times.
|
116547 |
while (*current_dir_start_pos != '\0') |
| 116 |
|
|
{ |
| 117 |
6/6
✓ Branch 0 taken 293272 times.
✓ Branch 1 taken 331771 times.
✓ Branch 2 taken 316618 times.
✓ Branch 3 taken 11270 times.
✓ Branch 4 taken 284012 times.
✓ Branch 5 taken 11631 times.
|
659659 |
while (*current_dir_end_pos != '/' && *current_dir_end_pos != '\0') |
| 118 |
|
|
{ |
| 119 |
|
566014 |
++current_dir_end_pos; |
| 120 |
|
|
} |
| 121 |
|
|
|
| 122 |
|
93645 |
size_t length = (size_t)(current_dir_end_pos - current_dir_start_pos); |
| 123 |
6/6
✓ Branch 0 taken 92878 times.
✓ Branch 1 taken 767 times.
✓ Branch 2 taken 36 times.
✓ Branch 3 taken 92842 times.
✓ Branch 4 taken 36 times.
✓ Branch 5 taken 45453 times.
|
93645 |
if (length > 0 && strncmp(current_dir_start_pos, ".", length) == 0) |
| 124 |
|
|
{ |
| 125 |
|
|
// Found a . path component - remove it. |
| 126 |
2/2
✓ Branch 0 taken 72 times.
✓ Branch 1 taken 72 times.
|
144 |
while (current_dir_start_pos != current_dir_end_pos) |
| 127 |
|
|
{ |
| 128 |
|
72 |
*current_dir_start_pos = '\x01'; |
| 129 |
|
72 |
++current_dir_start_pos; |
| 130 |
|
|
} |
| 131 |
|
|
|
| 132 |
2/3
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
|
72 |
if (*current_dir_start_pos == '/') |
| 133 |
|
|
{ |
| 134 |
|
72 |
*current_dir_start_pos = '\x01'; |
| 135 |
|
72 |
++current_dir_end_pos; |
| 136 |
|
|
} |
| 137 |
|
|
} |
| 138 |
6/6
✓ Branch 0 taken 92806 times.
✓ Branch 1 taken 767 times.
✓ Branch 2 taken 48 times.
✓ Branch 3 taken 92758 times.
✓ Branch 4 taken 1857 times.
✓ Branch 5 taken 43596 times.
|
93573 |
else if (length > 0 && strncmp(current_dir_start_pos, "..", length) == 0) |
| 139 |
|
|
{ |
| 140 |
|
|
// Found a .. path component - if we have any known |
| 141 |
|
|
// folder before it, remove them both. |
| 142 |
2/2
✓ Branch 0 taken 1132 times.
✓ Branch 1 taken 773 times.
|
1905 |
if (previous_dir_start_pos != nullptr) |
| 143 |
|
|
{ |
| 144 |
|
|
// previous_dir_start_pos and current_dir_start_pos are immediately |
| 145 |
|
|
// set to something else shortly after, so it should be |
| 146 |
|
|
// okay to move them directly here and not use a |
| 147 |
|
|
// temporary variable. |
| 148 |
4/6
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 4894 times.
✓ Branch 2 taken 1276 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4858 times.
✗ Branch 5 not taken.
|
6170 |
while (*previous_dir_start_pos != '/' && *previous_dir_start_pos != '\0') |
| 149 |
|
|
{ |
| 150 |
|
5038 |
*previous_dir_start_pos = '\x01'; |
| 151 |
|
5038 |
++previous_dir_start_pos; |
| 152 |
|
|
} |
| 153 |
|
|
|
| 154 |
2/3
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1096 times.
✗ Branch 2 not taken.
|
1132 |
if (*previous_dir_start_pos == '/') |
| 155 |
|
|
{ |
| 156 |
|
1132 |
*previous_dir_start_pos = '\x01'; |
| 157 |
|
|
} |
| 158 |
|
|
|
| 159 |
2/2
✓ Branch 0 taken 2264 times.
✓ Branch 1 taken 1132 times.
|
3396 |
while (current_dir_start_pos != current_dir_end_pos) |
| 160 |
|
|
{ |
| 161 |
|
2264 |
*current_dir_start_pos = '\x01'; |
| 162 |
|
2264 |
++current_dir_start_pos; |
| 163 |
|
|
} |
| 164 |
|
|
|
| 165 |
3/3
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 1096 times.
✓ Branch 2 taken 3 times.
|
1132 |
if (*current_dir_start_pos == '/') |
| 166 |
|
|
{ |
| 167 |
|
1126 |
*current_dir_start_pos = '\x01'; |
| 168 |
|
1126 |
++current_dir_end_pos; |
| 169 |
|
|
} |
| 170 |
|
|
} |
| 171 |
|
|
|
| 172 |
|
1905 |
previous_dir_start_pos = nullptr; |
| 173 |
|
|
} |
| 174 |
|
|
else |
| 175 |
|
|
{ |
| 176 |
3/3
✓ Branch 0 taken 36050 times.
✓ Branch 1 taken 43993 times.
✓ Branch 2 taken 11625 times.
|
91668 |
if (*current_dir_end_pos == '/') |
| 177 |
|
|
{ |
| 178 |
|
68779 |
++current_dir_end_pos; |
| 179 |
|
|
} |
| 180 |
|
|
|
| 181 |
2/2
✓ Branch 0 taken 90901 times.
✓ Branch 1 taken 767 times.
|
91668 |
if (length > 0) |
| 182 |
|
|
{ |
| 183 |
|
90901 |
previous_dir_start_pos = current_dir_start_pos; |
| 184 |
|
|
} |
| 185 |
|
|
} |
| 186 |
|
|
|
| 187 |
|
93645 |
current_dir_start_pos = current_dir_end_pos; |
| 188 |
|
|
} |
| 189 |
|
|
|
| 190 |
|
|
|
| 191 |
|
|
// Now construct our new string by copying everything but the \x01 into it. |
| 192 |
|
22902 |
string copy; |
| 193 |
|
|
|
| 194 |
2/2
✓ Branch 0 taken 642454 times.
✓ Branch 1 taken 22902 times.
|
665356 |
for (int i = 0; i < normalized.length(); ++i) |
| 195 |
|
|
{ |
| 196 |
4/4
✓ Branch 0 taken 317728 times.
✓ Branch 1 taken 393 times.
✓ Branch 2 taken 315022 times.
✓ Branch 3 taken 9311 times.
|
642454 |
if (normalized[i] != '\x01') |
| 197 |
|
|
{ |
| 198 |
2/4
✓ Branch 0 taken 317728 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 315022 times.
✗ Branch 3 not taken.
|
632750 |
copy += normalized[i]; |
| 199 |
|
|
} |
| 200 |
|
|
} |
| 201 |
|
|
|
| 202 |
1/2
✓ Branch 0 taken 22902 times.
✗ Branch 1 not taken.
|
22902 |
normalized = copy; |
| 203 |
|
|
|
| 204 |
|
|
|
| 205 |
|
|
// RPG Hacker: On Windows, file paths are case-insensitive. |
| 206 |
|
|
// It isn't really good style to mix different cases, especially |
| 207 |
|
|
// when referring to the same file, but it's theoretically possible |
| 208 |
|
|
// to do so, so we need to handle it and not have Asar fail in this case. |
| 209 |
|
|
// The easiest way to handle it is to convert the entire path to lowercase. |
| 210 |
|
|
#if defined(windows) |
| 211 |
1/2
✓ Branch 0 taken 11270 times.
✗ Branch 1 not taken.
|
11270 |
normalized = lower(normalized); |
| 212 |
|
|
#endif |
| 213 |
|
|
|
| 214 |
|
|
|
| 215 |
|
|
// TODO: Maybe resolve symbolic links here? |
| 216 |
|
|
// Not sure if it's a good idea and if it's needed in the first place. |
| 217 |
|
|
// In theory, it could lead to some problems with files that exist |
| 218 |
|
|
// only in memory. |
| 219 |
|
22902 |
return normalized; |
| 220 |
|
22902 |
} |
| 221 |
|
|
|
| 222 |
|
✗ |
string get_base_name(char const *name) |
| 223 |
|
|
{ |
| 224 |
|
✗ |
for(int i = (int)strlen(name); i >= 0; --i) |
| 225 |
|
|
{ |
| 226 |
|
✗ |
if(name[i] == '/' || name[i] == '\\') |
| 227 |
|
|
{ |
| 228 |
|
|
//file has no extension |
| 229 |
|
|
break; |
| 230 |
|
|
} |
| 231 |
|
✗ |
if(name[i] == '.') |
| 232 |
|
|
{ |
| 233 |
|
✗ |
return string(name, i); |
| 234 |
|
|
} |
| 235 |
|
|
} |
| 236 |
|
✗ |
return string(name); |
| 237 |
|
|
} |
| 238 |
|
|
|