asar coverage - build #127


src/asar/
File: src/asar/platform/file-helpers.cpp
Date: 2024-01-21 09:08:27
Lines:
61/67
91.0%
Functions:
3/4
75.0%
Branches:
67/90
74.4%

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 49370 string dir(char const *name)
24 {
25
2/2
✓ Branch 0 taken 670601 times.
✓ Branch 1 taken 1 times.
670602 for (signed i = (int)strlen(name); i >= 0; i--)
26 {
27
3/4
✓ Branch 0 taken 621232 times.
✓ Branch 1 taken 49369 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 621232 times.
670601 if (name[i] == '/' || name[i] == '\\')
28 {
29 49369 return string(name, i+1);
30 }
31 }
32 1 return "";
33 }
34
35 24538 string create_combined_path(const char* path1, const char* path2)
36 {
37
1/2
✓ Branch 0 taken 9029 times.
✗ Branch 1 not taken.
9029 string combined = path1;
38
39
1/2
✓ Branch 0 taken 9029 times.
✗ Branch 1 not taken.
9029 int length = combined.length();
40
41
8/10
✓ Branch 0 taken 24538 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 24538 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 9067 times.
✓ Branch 5 taken 15471 times.
✓ Branch 6 taken 50 times.
✓ Branch 7 taken 8979 times.
✓ Branch 8 taken 50 times.
✓ Branch 9 taken 8979 times.
24538 if (combined.length() > 0 && path1[length - 1] != '\\' && path1[length - 1] != '/')
42 {
43
2/4
✓ Branch 0 taken 88 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 50 times.
✗ Branch 3 not taken.
88 combined += get_native_path_separator();
44 }
45
46
1/2
✓ Branch 0 taken 9029 times.
✗ Branch 1 not taken.
24538 combined += path2;
47
48
1/2
✓ Branch 0 taken 9029 times.
✗ Branch 1 not taken.
49076 return normalize_path(combined);
49 24538 }
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 55216 string normalize_path(const char* path)
80 {
81
1/2
✓ Branch 0 taken 21211 times.
✗ Branch 1 not taken.
21211 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
4/4
✓ Branch 0 taken 1621825 times.
✓ Branch 1 taken 34005 times.
✓ Branch 2 taken 644749 times.
✓ Branch 3 taken 21211 times.
2645700 for (int i = 0; i < normalized.length(); ++i)
90 {
91
2/2
✓ Branch 0 taken 5024 times.
✓ Branch 1 taken 1595590 times.
1600614 if (normalized[i] == '\\')
92 {
93 5024 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 21211 char* previous_dir_start_pos = nullptr;
107 21211 char* current_dir_start_pos = normalized.temp_raw();
108
2/2
✓ Branch 0 taken 12160 times.
✓ Branch 1 taken 55216 times.
67376 while (*current_dir_start_pos == '/')
109 {
110 12160 ++current_dir_start_pos;
111 }
112 21211 char* current_dir_end_pos = current_dir_start_pos;
113
114
115
2/2
✓ Branch 0 taken 235421 times.
✓ Branch 1 taken 55216 times.
290637 while (*current_dir_start_pos != '\0')
116 {
117
4/4
✓ Branch 0 taken 1465844 times.
✓ Branch 1 taken 180206 times.
✓ Branch 2 taken 1410629 times.
✓ Branch 3 taken 55215 times.
1646050 while (*current_dir_end_pos != '/' && *current_dir_end_pos != '\0')
118 {
119 1410629 ++current_dir_end_pos;
120 }
121
122 235421 size_t length = (size_t)(current_dir_end_pos - current_dir_start_pos);
123
4/4
✓ Branch 0 taken 233040 times.
✓ Branch 1 taken 2381 times.
✓ Branch 2 taken 216 times.
✓ Branch 3 taken 232824 times.
235421 if (length > 0 && strncmp(current_dir_start_pos, ".", length) == 0)
124 {
125 // Found a . path component - remove it.
126
2/2
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 216 times.
432 while (current_dir_start_pos != current_dir_end_pos)
127 {
128 216 *current_dir_start_pos = '\x01';
129 216 ++current_dir_start_pos;
130 }
131
132
1/2
✓ Branch 0 taken 216 times.
✗ Branch 1 not taken.
216 if (*current_dir_start_pos == '/')
133 {
134 216 *current_dir_start_pos = '\x01';
135 216 ++current_dir_end_pos;
136 }
137 }
138
4/4
✓ Branch 0 taken 90303 times.
✓ Branch 1 taken 144875 times.
✓ Branch 2 taken 5721 times.
✓ Branch 3 taken 84438 times.
235178 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 3466 times.
✓ Branch 1 taken 2399 times.
5865 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
3/4
✓ Branch 0 taken 27119 times.
✓ Branch 1 taken 3466 times.
✓ Branch 2 taken 27119 times.
✗ Branch 3 not taken.
30585 while (*previous_dir_start_pos != '/' && *previous_dir_start_pos != '\0')
149 {
150 27119 *previous_dir_start_pos = '\x01';
151 27119 ++previous_dir_start_pos;
152 }
153
154
1/2
✓ Branch 0 taken 3466 times.
✗ Branch 1 not taken.
3466 if (*previous_dir_start_pos == '/')
155 {
156 3466 *previous_dir_start_pos = '\x01';
157 }
158
159
2/2
✓ Branch 0 taken 6932 times.
✓ Branch 1 taken 3466 times.
10398 while (current_dir_start_pos != current_dir_end_pos)
160 {
161 6932 *current_dir_start_pos = '\x01';
162 6932 ++current_dir_start_pos;
163 }
164
165
2/2
✓ Branch 0 taken 3448 times.
✓ Branch 1 taken 18 times.
3466 if (*current_dir_start_pos == '/')
166 {
167 3448 *current_dir_start_pos = '\x01';
168 3448 ++current_dir_end_pos;
169 }
170 }
171
172 5721 previous_dir_start_pos = nullptr;
173 }
174 else
175 {
176
2/2
✓ Branch 0 taken 174161 times.
✓ Branch 1 taken 55179 times.
229340 if (*current_dir_end_pos == '/')
177 {
178 174161 ++current_dir_end_pos;
179 }
180
181
2/2
✓ Branch 0 taken 226959 times.
✓ Branch 1 taken 2381 times.
229340 if (length > 0)
182 {
183 84438 previous_dir_start_pos = current_dir_start_pos;
184 }
185 }
186
187 92621 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 21211 string copy;
193
194
4/4
✓ Branch 0 taken 1621825 times.
✓ Branch 1 taken 34005 times.
✓ Branch 2 taken 644749 times.
✓ Branch 3 taken 21211 times.
2645700 for (int i = 0; i < normalized.length(); ++i)
195 {
196
2/2
✓ Branch 0 taken 1559217 times.
✓ Branch 1 taken 41397 times.
1600614 if (normalized[i] != '\x01')
197 {
198
1/2
✓ Branch 0 taken 604531 times.
✗ Branch 1 not taken.
1559217 copy += normalized[i];
199 }
200 }
201
202
1/2
✓ Branch 0 taken 21211 times.
✗ Branch 1 not taken.
21211 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 34005 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 76427 return normalized;
220 55216 }
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