Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
PathInternal.cs
Go to the documentation of this file.
3using System.Text;
4
5namespace System.IO;
6
7internal static class PathInternal
8{
10 {
11 get
12 {
14 return StringComparison.OrdinalIgnoreCase;
15 }
16 }
17
18 internal static bool IsCaseSensitive
19 {
20 get
21 {
23 {
24 }
25 return false;
26 }
27 }
28
30 {
31 if (path.Length > 0)
32 {
33 return IsDirectorySeparator(path[0]);
34 }
35 return false;
36 }
37
38 internal static string EnsureTrailingSeparator(string path)
39 {
40 if (!EndsInDirectorySeparator(path.AsSpan()))
41 {
42 return path + "\\";
43 }
44 return path;
45 }
46
47 internal static bool IsRoot(ReadOnlySpan<char> path)
48 {
49 return path.Length == GetRootLength(path);
50 }
51
52 internal static int GetCommonPathLength(string first, string second, bool ignoreCase)
53 {
54 int num = EqualStartingCharacterCount(first, second, ignoreCase);
55 if (num == 0)
56 {
57 return num;
58 }
59 if (num == first.Length && (num == second.Length || IsDirectorySeparator(second[num])))
60 {
61 return num;
62 }
63 if (num == second.Length && IsDirectorySeparator(first[num]))
64 {
65 return num;
66 }
67 while (num > 0 && !IsDirectorySeparator(first[num - 1]))
68 {
69 num--;
70 }
71 return num;
72 }
73
74 internal unsafe static int EqualStartingCharacterCount(string first, string second, bool ignoreCase)
75 {
76 //The blocks IL_0037, IL_005c, IL_006c, IL_0072, IL_0078, IL_0080, IL_0083 are reachable both inside and outside the pinned region starting at IL_0032. ILSpy has duplicated these blocks in order to place them both within and outside the `fixed` statement.
77 if (string.IsNullOrEmpty(first) || string.IsNullOrEmpty(second))
78 {
79 return 0;
80 }
81 int num = 0;
82 fixed (char* ptr2 = first)
83 {
84 char* intPtr;
85 if (second == null)
86 {
87 char* ptr;
88 intPtr = (ptr = null);
89 char* ptr3 = ptr2;
90 char* ptr4 = ptr;
91 char* ptr5 = ptr3 + first.Length;
92 char* ptr6 = ptr4 + second.Length;
93 while (ptr3 != ptr5 && ptr4 != ptr6 && (*ptr3 == *ptr4 || (ignoreCase && char.ToUpperInvariant(*ptr3) == char.ToUpperInvariant(*ptr4))))
94 {
95 num++;
96 ptr3++;
97 ptr4++;
98 }
99 }
100 else
101 {
102 fixed (char* ptr7 = &second.GetPinnableReference())
103 {
104 char* ptr;
105 intPtr = (ptr = ptr7);
106 char* ptr3 = ptr2;
107 char* ptr4 = ptr;
108 char* ptr5 = ptr3 + first.Length;
109 char* ptr6 = ptr4 + second.Length;
110 while (ptr3 != ptr5 && ptr4 != ptr6 && (*ptr3 == *ptr4 || (ignoreCase && char.ToUpperInvariant(*ptr3) == char.ToUpperInvariant(*ptr4))))
111 {
112 num++;
113 ptr3++;
114 ptr4++;
115 }
116 }
117 }
118 }
119 return num;
120 }
121
122 internal static bool AreRootsEqual(string first, string second, StringComparison comparisonType)
123 {
124 int rootLength = GetRootLength(first.AsSpan());
125 int rootLength2 = GetRootLength(second.AsSpan());
126 if (rootLength == rootLength2)
127 {
128 return string.Compare(first, 0, second, 0, rootLength, comparisonType) == 0;
129 }
130 return false;
131 }
132
133 internal static string RemoveRelativeSegments(string path, int rootLength)
134 {
135 Span<char> initialBuffer = stackalloc char[260];
136 ValueStringBuilder sb = new ValueStringBuilder(initialBuffer);
137 if (RemoveRelativeSegments(path.AsSpan(), rootLength, ref sb))
138 {
139 path = sb.ToString();
140 }
141 sb.Dispose();
142 return path;
143 }
144
145 internal static bool RemoveRelativeSegments(ReadOnlySpan<char> path, int rootLength, ref ValueStringBuilder sb)
146 {
147 bool flag = false;
148 int num = rootLength;
149 if (IsDirectorySeparator(path[num - 1]))
150 {
151 num--;
152 }
153 if (num > 0)
154 {
155 sb.Append(path.Slice(0, num));
156 }
157 for (int i = num; i < path.Length; i++)
158 {
159 char c = path[i];
160 if (IsDirectorySeparator(c) && i + 1 < path.Length)
161 {
162 if (IsDirectorySeparator(path[i + 1]))
163 {
164 continue;
165 }
166 if ((i + 2 == path.Length || IsDirectorySeparator(path[i + 2])) && path[i + 1] == '.')
167 {
168 i++;
169 continue;
170 }
171 if (i + 2 < path.Length && (i + 3 == path.Length || IsDirectorySeparator(path[i + 3])) && path[i + 1] == '.' && path[i + 2] == '.')
172 {
173 int num2;
174 for (num2 = sb.Length - 1; num2 >= num; num2--)
175 {
176 if (IsDirectorySeparator(sb[num2]))
177 {
178 sb.Length = ((i + 3 >= path.Length && num2 == num) ? (num2 + 1) : num2);
179 break;
180 }
181 }
182 if (num2 < num)
183 {
184 sb.Length = num;
185 }
186 i += 2;
187 continue;
188 }
189 }
190 if (c != '\\' && c == '/')
191 {
192 c = '\\';
193 flag = true;
194 }
195 sb.Append(c);
196 }
197 if (!flag && sb.Length == path.Length)
198 {
199 return false;
200 }
201 if (num != rootLength && sb.Length < rootLength)
202 {
203 sb.Append(path[rootLength - 1]);
204 }
205 return true;
206 }
207
208 [return: NotNullIfNotNull("path")]
209 internal static string TrimEndingDirectorySeparator(string path)
210 {
211 if (!EndsInDirectorySeparator(path) || IsRoot(path.AsSpan()))
212 {
213 return path;
214 }
215 return path.Substring(0, path.Length - 1);
216 }
217
218 internal static bool EndsInDirectorySeparator(string path)
219 {
220 if (!string.IsNullOrEmpty(path))
221 {
222 return IsDirectorySeparator(path[path.Length - 1]);
223 }
224 return false;
225 }
226
228 {
229 if (!EndsInDirectorySeparator(path) || IsRoot(path))
230 {
231 return path;
232 }
233 return path.Slice(0, path.Length - 1);
234 }
235
237 {
238 if (path.Length > 0)
239 {
240 return IsDirectorySeparator(path[path.Length - 1]);
241 }
242 return false;
243 }
244
245 internal static string GetLinkTargetFullPath(string path, string pathToTarget)
246 {
247 if (!IsPartiallyQualified(pathToTarget.AsSpan()))
248 {
249 return pathToTarget;
250 }
251 return Path.Join(Path.GetDirectoryName(path.AsSpan()), pathToTarget.AsSpan());
252 }
253
254 internal static bool IsValidDriveChar(char value)
255 {
256 if (value < 'A' || value > 'Z')
257 {
258 if (value >= 'a')
259 {
260 return value <= 'z';
261 }
262 return false;
263 }
264 return true;
265 }
266
267 internal static bool EndsWithPeriodOrSpace(string path)
268 {
269 if (string.IsNullOrEmpty(path))
270 {
271 return false;
272 }
273 char c = path[path.Length - 1];
274 if (c != ' ')
275 {
276 return c == '.';
277 }
278 return true;
279 }
280
281 [return: NotNullIfNotNull("path")]
282 internal static string EnsureExtendedPrefixIfNeeded(string path)
283 {
284 if (path != null && (path.Length >= 260 || EndsWithPeriodOrSpace(path)))
285 {
286 return EnsureExtendedPrefix(path);
287 }
288 return path;
289 }
290
291 internal static string EnsureExtendedPrefix(string path)
292 {
293 if (IsPartiallyQualified(path.AsSpan()) || IsDevice(path.AsSpan()))
294 {
295 return path;
296 }
297 if (path.StartsWith("\\\\", StringComparison.OrdinalIgnoreCase))
298 {
299 return path.Insert(2, "?\\UNC\\");
300 }
301 return "\\\\?\\" + path;
302 }
303
304 internal static bool IsDevice(ReadOnlySpan<char> path)
305 {
306 if (!IsExtended(path))
307 {
308 if (path.Length >= 4 && IsDirectorySeparator(path[0]) && IsDirectorySeparator(path[1]) && (path[2] == '.' || path[2] == '?'))
309 {
310 return IsDirectorySeparator(path[3]);
311 }
312 return false;
313 }
314 return true;
315 }
316
317 internal static bool IsDeviceUNC(ReadOnlySpan<char> path)
318 {
319 if (path.Length >= 8 && IsDevice(path) && IsDirectorySeparator(path[7]) && path[4] == 'U' && path[5] == 'N')
320 {
321 return path[6] == 'C';
322 }
323 return false;
324 }
325
326 internal static bool IsExtended(ReadOnlySpan<char> path)
327 {
328 if (path.Length >= 4 && path[0] == '\\' && (path[1] == '\\' || path[1] == '?') && path[2] == '?')
329 {
330 return path[3] == '\\';
331 }
332 return false;
333 }
334
335 internal static int GetRootLength(ReadOnlySpan<char> path)
336 {
337 int length = path.Length;
338 int i = 0;
339 bool flag = IsDevice(path);
340 bool flag2 = flag && IsDeviceUNC(path);
341 if ((!flag || flag2) && length > 0 && IsDirectorySeparator(path[0]))
342 {
343 if (flag2 || (length > 1 && IsDirectorySeparator(path[1])))
344 {
345 i = (flag2 ? 8 : 2);
346 int num = 2;
347 for (; i < length; i++)
348 {
349 if (IsDirectorySeparator(path[i]) && --num <= 0)
350 {
351 break;
352 }
353 }
354 }
355 else
356 {
357 i = 1;
358 }
359 }
360 else if (flag)
361 {
362 for (i = 4; i < length && !IsDirectorySeparator(path[i]); i++)
363 {
364 }
365 if (i < length && i > 4 && IsDirectorySeparator(path[i]))
366 {
367 i++;
368 }
369 }
370 else if (length >= 2 && path[1] == ':' && IsValidDriveChar(path[0]))
371 {
372 i = 2;
373 if (length > 2 && IsDirectorySeparator(path[2]))
374 {
375 i++;
376 }
377 }
378 return i;
379 }
380
381 internal static bool IsPartiallyQualified(ReadOnlySpan<char> path)
382 {
383 if (path.Length < 2)
384 {
385 return true;
386 }
387 if (IsDirectorySeparator(path[0]))
388 {
389 if (path[1] != '?')
390 {
391 return !IsDirectorySeparator(path[1]);
392 }
393 return false;
394 }
395 if (path.Length >= 3 && path[1] == ':' && IsDirectorySeparator(path[2]))
396 {
397 return !IsValidDriveChar(path[0]);
398 }
399 return true;
400 }
401
402 [MethodImpl(MethodImplOptions.AggressiveInlining)]
403 internal static bool IsDirectorySeparator(char c)
404 {
405 if (c != '\\')
406 {
407 return c == '/';
408 }
409 return true;
410 }
411
412 [return: NotNullIfNotNull("path")]
413 internal static string NormalizeDirectorySeparators(string path)
414 {
415 if (string.IsNullOrEmpty(path))
416 {
417 return path;
418 }
419 bool flag = true;
420 for (int i = 0; i < path.Length; i++)
421 {
422 char c = path[i];
423 if (IsDirectorySeparator(c) && (c != '\\' || (i > 0 && i + 1 < path.Length && IsDirectorySeparator(path[i + 1]))))
424 {
425 flag = false;
426 break;
427 }
428 }
429 if (flag)
430 {
431 return path;
432 }
433 Span<char> initialBuffer = stackalloc char[260];
434 ValueStringBuilder valueStringBuilder = new ValueStringBuilder(initialBuffer);
435 int num = 0;
436 if (IsDirectorySeparator(path[num]))
437 {
438 num++;
439 valueStringBuilder.Append('\\');
440 }
441 for (int j = num; j < path.Length; j++)
442 {
443 char c = path[j];
445 {
446 if (j + 1 < path.Length && IsDirectorySeparator(path[j + 1]))
447 {
448 continue;
449 }
450 c = '\\';
451 }
452 valueStringBuilder.Append(c);
453 }
454 return valueStringBuilder.ToString();
455 }
456
457 internal static bool IsEffectivelyEmpty(ReadOnlySpan<char> path)
458 {
459 if (path.IsEmpty)
460 {
461 return true;
462 }
463 ReadOnlySpan<char> readOnlySpan = path;
464 for (int i = 0; i < readOnlySpan.Length; i++)
465 {
466 char c = readOnlySpan[i];
467 if (c != ' ')
468 {
469 return false;
470 }
471 }
472 return true;
473 }
474}
static bool EndsInDirectorySeparator(string path)
static string RemoveRelativeSegments(string path, int rootLength)
static bool IsValidDriveChar(char value)
static int GetRootLength(ReadOnlySpan< char > path)
static bool EndsInDirectorySeparator(ReadOnlySpan< char > path)
static string TrimEndingDirectorySeparator(string path)
static unsafe int EqualStartingCharacterCount(string first, string second, bool ignoreCase)
static bool IsCaseSensitive
static string GetLinkTargetFullPath(string path, string pathToTarget)
static bool IsDirectorySeparator(char c)
static bool EndsWithPeriodOrSpace(string path)
static bool StartsWithDirectorySeparator(ReadOnlySpan< char > path)
static string EnsureExtendedPrefix(string path)
static bool IsDevice(ReadOnlySpan< char > path)
static ReadOnlySpan< char > TrimEndingDirectorySeparator(ReadOnlySpan< char > path)
static bool IsExtended(ReadOnlySpan< char > path)
static bool RemoveRelativeSegments(ReadOnlySpan< char > path, int rootLength, ref ValueStringBuilder sb)
static bool AreRootsEqual(string first, string second, StringComparison comparisonType)
static string NormalizeDirectorySeparators(string path)
static bool IsDeviceUNC(ReadOnlySpan< char > path)
static bool IsPartiallyQualified(ReadOnlySpan< char > path)
static bool IsRoot(ReadOnlySpan< char > path)
static string EnsureExtendedPrefixIfNeeded(string path)
static bool IsEffectivelyEmpty(ReadOnlySpan< char > path)
static int GetCommonPathLength(string first, string second, bool ignoreCase)
static string EnsureTrailingSeparator(string path)
static string Join(ReadOnlySpan< char > path1, ReadOnlySpan< char > path2)
Definition Path.cs:387
static ? string GetDirectoryName(string? path)
Definition Path.cs:121
ReadOnlySpan< T > Slice(int start)