Terraria v1.4.4.9
Terraria source code documentation
Loading...
Searching...
No Matches
Path.cs
Go to the documentation of this file.
3using System.Text;
4
5namespace System.IO;
6
7public static class Path
8{
9 private readonly struct Join3Payload
10 {
11 public unsafe readonly char* First;
12
13 public readonly int FirstLength;
14
15 public unsafe readonly char* Second;
16
17 public readonly int SecondLength;
18
19 public unsafe readonly char* Third;
20
21 public readonly int ThirdLength;
22
23 public readonly byte Separators;
24
25 public unsafe Join3Payload(char* first, int firstLength, char* second, int secondLength, char* third, int thirdLength, byte separators)
26 {
27 First = first;
28 FirstLength = firstLength;
29 Second = second;
30 SecondLength = secondLength;
31 Third = third;
32 ThirdLength = thirdLength;
33 Separators = separators;
34 }
35 }
36
37 private readonly struct Join4Payload
38 {
39 public unsafe readonly char* First;
40
41 public readonly int FirstLength;
42
43 public unsafe readonly char* Second;
44
45 public readonly int SecondLength;
46
47 public unsafe readonly char* Third;
48
49 public readonly int ThirdLength;
50
51 public unsafe readonly char* Fourth;
52
53 public readonly int FourthLength;
54
55 public readonly byte Separators;
56
57 public unsafe Join4Payload(char* first, int firstLength, char* second, int secondLength, char* third, int thirdLength, char* fourth, int fourthLength, byte separators)
58 {
59 First = first;
60 FirstLength = firstLength;
61 Second = second;
62 SecondLength = secondLength;
63 Third = third;
64 ThirdLength = thirdLength;
65 Fourth = fourth;
66 FourthLength = fourthLength;
67 Separators = separators;
68 }
69 }
70
71 public static readonly char DirectorySeparatorChar = '\\';
72
73 public static readonly char AltDirectorySeparatorChar = '/';
74
75 public static readonly char VolumeSeparatorChar = ':';
76
77 public static readonly char PathSeparator = ';';
78
79 [Obsolete("Path.InvalidPathChars has been deprecated. Use GetInvalidPathChars or GetInvalidFileNameChars instead.")]
80 public static readonly char[] InvalidPathChars = GetInvalidPathChars();
81
82 private static ReadOnlySpan<byte> Base32Char => "abcdefghijklmnopqrstuvwxyz012345"u8;
83
84 [return: NotNullIfNotNull("path")]
85 public static string? ChangeExtension(string? path, string? extension)
86 {
87 if (path == null)
88 {
89 return null;
90 }
91 int num = path.Length;
92 if (num == 0)
93 {
94 return string.Empty;
95 }
96 for (int num2 = path.Length - 1; num2 >= 0; num2--)
97 {
98 char c = path[num2];
99 if (c == '.')
100 {
101 num = num2;
102 break;
103 }
105 {
106 break;
107 }
108 }
109 if (extension == null)
110 {
111 return path.Substring(0, num);
112 }
113 ReadOnlySpan<char> readOnlySpan = path.AsSpan(0, num);
114 if (!extension.StartsWith('.'))
115 {
116 return string.Concat(readOnlySpan, ".", extension);
117 }
118 return string.Concat(readOnlySpan, extension);
119 }
120
121 public static string? GetDirectoryName(string? path)
122 {
123 if (path == null || PathInternal.IsEffectivelyEmpty(path.AsSpan()))
124 {
125 return null;
126 }
127 int directoryNameOffset = GetDirectoryNameOffset(path.AsSpan());
128 if (directoryNameOffset < 0)
129 {
130 return null;
131 }
132 return PathInternal.NormalizeDirectorySeparators(path.Substring(0, directoryNameOffset));
133 }
134
136 {
138 {
140 }
141 int directoryNameOffset = GetDirectoryNameOffset(path);
142 if (directoryNameOffset < 0)
143 {
145 }
146 return path.Slice(0, directoryNameOffset);
147 }
148
150 {
151 int rootLength = PathInternal.GetRootLength(path);
152 int num = path.Length;
153 if (num <= rootLength)
154 {
155 return -1;
156 }
157 while (num > rootLength && !PathInternal.IsDirectorySeparator(path[--num]))
158 {
159 }
160 while (num > rootLength && PathInternal.IsDirectorySeparator(path[num - 1]))
161 {
162 num--;
163 }
164 return num;
165 }
166
167 [return: NotNullIfNotNull("path")]
168 public static string? GetExtension(string? path)
169 {
170 if (path == null)
171 {
172 return null;
173 }
174 return GetExtension(path.AsSpan()).ToString();
175 }
176
178 {
179 int length = path.Length;
180 for (int num = length - 1; num >= 0; num--)
181 {
182 char c = path[num];
183 if (c == '.')
184 {
185 if (num != length - 1)
186 {
187 return path.Slice(num, length - num);
188 }
190 }
192 {
193 break;
194 }
195 }
197 }
198
199 [return: NotNullIfNotNull("path")]
200 public static string? GetFileName(string? path)
201 {
202 if (path == null)
203 {
204 return null;
205 }
206 ReadOnlySpan<char> fileName = GetFileName(path.AsSpan());
207 if (path.Length == fileName.Length)
208 {
209 return path;
210 }
211 return fileName.ToString();
212 }
213
215 {
216 int length = GetPathRoot(path).Length;
217 int num = path.Length;
218 while (--num >= 0)
219 {
220 if (num < length || PathInternal.IsDirectorySeparator(path[num]))
221 {
222 return path.Slice(num + 1, path.Length - num - 1);
223 }
224 }
225 return path;
226 }
227
228 [return: NotNullIfNotNull("path")]
229 public static string? GetFileNameWithoutExtension(string? path)
230 {
231 if (path == null)
232 {
233 return null;
234 }
235 ReadOnlySpan<char> fileNameWithoutExtension = GetFileNameWithoutExtension(path.AsSpan());
236 if (path.Length == fileNameWithoutExtension.Length)
237 {
238 return path;
239 }
240 return fileNameWithoutExtension.ToString();
241 }
242
244 {
245 ReadOnlySpan<char> fileName = GetFileName(path);
246 int num = fileName.LastIndexOf('.');
247 if (num != -1)
248 {
249 return fileName.Slice(0, num);
250 }
251 return fileName;
252 }
253
254 public unsafe static string GetRandomFileName()
255 {
256 byte* ptr = stackalloc byte[8];
257 Interop.GetRandomBytes(ptr, 8);
258 return string.Create(12, (IntPtr)ptr, delegate(Span<char> span, IntPtr key)
259 {
260 Populate83FileNameFromRandomBytes((byte*)(void*)key, 8, span);
261 });
262 }
263
264 public static bool IsPathFullyQualified(string path)
265 {
266 if (path == null)
267 {
268 throw new ArgumentNullException("path");
269 }
270 return IsPathFullyQualified(path.AsSpan());
271 }
272
274 {
276 }
277
278 public static bool HasExtension([NotNullWhen(true)] string? path)
279 {
280 if (path != null)
281 {
282 return HasExtension(path.AsSpan());
283 }
284 return false;
285 }
286
287 public static bool HasExtension(ReadOnlySpan<char> path)
288 {
289 for (int num = path.Length - 1; num >= 0; num--)
290 {
291 char c = path[num];
292 if (c == '.')
293 {
294 return num != path.Length - 1;
295 }
297 {
298 break;
299 }
300 }
301 return false;
302 }
303
304 public static string Combine(string path1, string path2)
305 {
306 if (path1 == null || path2 == null)
307 {
308 throw new ArgumentNullException((path1 == null) ? "path1" : "path2");
309 }
310 return CombineInternal(path1, path2);
311 }
312
313 public static string Combine(string path1, string path2, string path3)
314 {
315 if (path1 == null || path2 == null || path3 == null)
316 {
317 throw new ArgumentNullException((path1 == null) ? "path1" : ((path2 == null) ? "path2" : "path3"));
318 }
319 return CombineInternal(path1, path2, path3);
320 }
321
322 public static string Combine(string path1, string path2, string path3, string path4)
323 {
324 if (path1 == null || path2 == null || path3 == null || path4 == null)
325 {
326 throw new ArgumentNullException((path1 == null) ? "path1" : ((path2 == null) ? "path2" : ((path3 == null) ? "path3" : "path4")));
327 }
328 return CombineInternal(path1, path2, path3, path4);
329 }
330
331 public static string Combine(params string[] paths)
332 {
333 if (paths == null)
334 {
335 throw new ArgumentNullException("paths");
336 }
337 int num = 0;
338 int num2 = 0;
339 for (int i = 0; i < paths.Length; i++)
340 {
341 if (paths[i] == null)
342 {
343 throw new ArgumentNullException("paths");
344 }
345 if (paths[i].Length != 0)
346 {
347 if (IsPathRooted(paths[i]))
348 {
349 num2 = i;
350 num = paths[i].Length;
351 }
352 else
353 {
354 num += paths[i].Length;
355 }
356 char c = paths[i][paths[i].Length - 1];
358 {
359 num++;
360 }
361 }
362 }
363 Span<char> initialBuffer = stackalloc char[260];
364 ValueStringBuilder valueStringBuilder = new ValueStringBuilder(initialBuffer);
365 valueStringBuilder.EnsureCapacity(num);
366 for (int j = num2; j < paths.Length; j++)
367 {
368 if (paths[j].Length == 0)
369 {
370 continue;
371 }
372 if (valueStringBuilder.Length == 0)
373 {
374 valueStringBuilder.Append(paths[j]);
375 continue;
376 }
377 char c2 = valueStringBuilder[valueStringBuilder.Length - 1];
379 {
380 valueStringBuilder.Append('\\');
381 }
382 valueStringBuilder.Append(paths[j]);
383 }
384 return valueStringBuilder.ToString();
385 }
386
387 public static string Join(ReadOnlySpan<char> path1, ReadOnlySpan<char> path2)
388 {
389 if (path1.Length == 0)
390 {
391 return path2.ToString();
392 }
393 if (path2.Length == 0)
394 {
395 return path1.ToString();
396 }
397 return JoinInternal(path1, path2);
398 }
399
400 public static string Join(ReadOnlySpan<char> path1, ReadOnlySpan<char> path2, ReadOnlySpan<char> path3)
401 {
402 if (path1.Length == 0)
403 {
404 return Join(path2, path3);
405 }
406 if (path2.Length == 0)
407 {
408 return Join(path1, path3);
409 }
410 if (path3.Length == 0)
411 {
412 return Join(path1, path2);
413 }
414 return JoinInternal(path1, path2, path3);
415 }
416
417 public static string Join(ReadOnlySpan<char> path1, ReadOnlySpan<char> path2, ReadOnlySpan<char> path3, ReadOnlySpan<char> path4)
418 {
419 if (path1.Length == 0)
420 {
421 return Join(path2, path3, path4);
422 }
423 if (path2.Length == 0)
424 {
425 return Join(path1, path3, path4);
426 }
427 if (path3.Length == 0)
428 {
429 return Join(path1, path2, path4);
430 }
431 if (path4.Length == 0)
432 {
433 return Join(path1, path2, path3);
434 }
435 return JoinInternal(path1, path2, path3, path4);
436 }
437
438 public static string Join(string? path1, string? path2)
439 {
440 return Join(path1.AsSpan(), path2.AsSpan());
441 }
442
443 public static string Join(string? path1, string? path2, string? path3)
444 {
445 return Join(path1.AsSpan(), path2.AsSpan(), path3.AsSpan());
446 }
447
448 public static string Join(string? path1, string? path2, string? path3, string? path4)
449 {
450 return Join(path1.AsSpan(), path2.AsSpan(), path3.AsSpan(), path4.AsSpan());
451 }
452
453 public static string Join(params string?[] paths)
454 {
455 if (paths == null)
456 {
457 throw new ArgumentNullException("paths");
458 }
459 if (paths.Length == 0)
460 {
461 return string.Empty;
462 }
463 int num = 0;
464 for (int i = 0; i < paths.Length; i++)
465 {
466 num += paths[i]?.Length ?? 0;
467 }
468 num += paths.Length - 1;
469 Span<char> initialBuffer = stackalloc char[260];
470 ValueStringBuilder valueStringBuilder = new ValueStringBuilder(initialBuffer);
471 valueStringBuilder.EnsureCapacity(num);
472 foreach (string text in paths)
473 {
474 if (string.IsNullOrEmpty(text))
475 {
476 continue;
477 }
478 if (valueStringBuilder.Length == 0)
479 {
480 valueStringBuilder.Append(text);
481 continue;
482 }
483 if (!PathInternal.IsDirectorySeparator(valueStringBuilder[valueStringBuilder.Length - 1]) && !PathInternal.IsDirectorySeparator(text[0]))
484 {
485 valueStringBuilder.Append('\\');
486 }
487 valueStringBuilder.Append(text);
488 }
489 return valueStringBuilder.ToString();
490 }
491
492 public static bool TryJoin(ReadOnlySpan<char> path1, ReadOnlySpan<char> path2, Span<char> destination, out int charsWritten)
493 {
494 charsWritten = 0;
495 if (path1.Length == 0 && path2.Length == 0)
496 {
497 return true;
498 }
499 if (path1.Length == 0 || path2.Length == 0)
500 {
501 ref ReadOnlySpan<char> reference = ref path1.Length == 0 ? ref path2 : ref path1;
502 if (destination.Length < reference.Length)
503 {
504 return false;
505 }
506 reference.CopyTo(destination);
507 charsWritten = reference.Length;
508 return true;
509 }
511 int num = path1.Length + path2.Length + (flag ? 1 : 0);
512 if (destination.Length < num)
513 {
514 return false;
515 }
516 path1.CopyTo(destination);
517 if (flag)
518 {
520 }
521 path2.CopyTo(destination.Slice(path1.Length + (flag ? 1 : 0)));
522 charsWritten = num;
523 return true;
524 }
525
526 public static bool TryJoin(ReadOnlySpan<char> path1, ReadOnlySpan<char> path2, ReadOnlySpan<char> path3, Span<char> destination, out int charsWritten)
527 {
528 charsWritten = 0;
529 if (path1.Length == 0 && path2.Length == 0 && path3.Length == 0)
530 {
531 return true;
532 }
533 if (path1.Length == 0)
534 {
535 return TryJoin(path2, path3, destination, out charsWritten);
536 }
537 if (path2.Length == 0)
538 {
539 return TryJoin(path1, path3, destination, out charsWritten);
540 }
541 if (path3.Length == 0)
542 {
543 return TryJoin(path1, path2, destination, out charsWritten);
544 }
545 int num = ((!EndsInDirectorySeparator(path1) && !PathInternal.StartsWithDirectorySeparator(path2)) ? 1 : 0);
547 if (flag)
548 {
549 num++;
550 }
551 int num2 = path1.Length + path2.Length + path3.Length + num;
552 if (destination.Length < num2)
553 {
554 return false;
555 }
556 bool flag2 = TryJoin(path1, path2, destination, out charsWritten);
557 if (flag)
558 {
559 destination[charsWritten++] = DirectorySeparatorChar;
560 }
561 path3.CopyTo(destination.Slice(charsWritten));
562 charsWritten += path3.Length;
563 return true;
564 }
565
566 private static string CombineInternal(string first, string second)
567 {
568 if (string.IsNullOrEmpty(first))
569 {
570 return second;
571 }
572 if (string.IsNullOrEmpty(second))
573 {
574 return first;
575 }
576 if (IsPathRooted(second.AsSpan()))
577 {
578 return second;
579 }
580 return JoinInternal(first.AsSpan(), second.AsSpan());
581 }
582
583 private static string CombineInternal(string first, string second, string third)
584 {
585 if (string.IsNullOrEmpty(first))
586 {
587 return CombineInternal(second, third);
588 }
589 if (string.IsNullOrEmpty(second))
590 {
591 return CombineInternal(first, third);
592 }
593 if (string.IsNullOrEmpty(third))
594 {
595 return CombineInternal(first, second);
596 }
597 if (IsPathRooted(third.AsSpan()))
598 {
599 return third;
600 }
601 if (IsPathRooted(second.AsSpan()))
602 {
603 return CombineInternal(second, third);
604 }
605 return JoinInternal(first.AsSpan(), second.AsSpan(), third.AsSpan());
606 }
607
608 private static string CombineInternal(string first, string second, string third, string fourth)
609 {
610 if (string.IsNullOrEmpty(first))
611 {
612 return CombineInternal(second, third, fourth);
613 }
614 if (string.IsNullOrEmpty(second))
615 {
616 return CombineInternal(first, third, fourth);
617 }
618 if (string.IsNullOrEmpty(third))
619 {
620 return CombineInternal(first, second, fourth);
621 }
622 if (string.IsNullOrEmpty(fourth))
623 {
624 return CombineInternal(first, second, third);
625 }
626 if (IsPathRooted(fourth.AsSpan()))
627 {
628 return fourth;
629 }
630 if (IsPathRooted(third.AsSpan()))
631 {
632 return CombineInternal(third, fourth);
633 }
634 if (IsPathRooted(second.AsSpan()))
635 {
636 return CombineInternal(second, third, fourth);
637 }
638 return JoinInternal(first.AsSpan(), second.AsSpan(), third.AsSpan(), fourth.AsSpan());
639 }
640
641 private static string JoinInternal(ReadOnlySpan<char> first, ReadOnlySpan<char> second)
642 {
643 if (!PathInternal.IsDirectorySeparator(first[first.Length - 1]) && !PathInternal.IsDirectorySeparator(second[0]))
644 {
645 return string.Concat(first, "\\", second);
646 }
647 return string.Concat(first, second);
648 }
649
650 private unsafe static string JoinInternal(ReadOnlySpan<char> first, ReadOnlySpan<char> second, ReadOnlySpan<char> third)
651 {
652 byte b = (byte)((!PathInternal.IsDirectorySeparator(first[first.Length - 1]) && !PathInternal.IsDirectorySeparator(second[0])) ? 1 : 0);
653 byte b2 = (byte)((!PathInternal.IsDirectorySeparator(second[second.Length - 1]) && !PathInternal.IsDirectorySeparator(third[0])) ? 1 : 0);
654 fixed (char* first2 = &MemoryMarshal.GetReference(first))
655 {
656 fixed (char* second2 = &MemoryMarshal.GetReference(second))
657 {
658 fixed (char* third2 = &MemoryMarshal.GetReference(third))
659 {
660 Join3Payload join3Payload = new Join3Payload(first2, first.Length, second2, second.Length, third2, third.Length, (byte)(b | (b2 << 1)));
661 return string.Create(first.Length + second.Length + third.Length + b + b2, (IntPtr)(&join3Payload), delegate(Span<char> destination, IntPtr statePtr)
662 {
663 ref Join3Payload reference = ref *(Join3Payload*)(void*)statePtr;
664 new Span<char>(reference.First, reference.FirstLength).CopyTo(destination);
665 if (((uint)reference.Separators & (true ? 1u : 0u)) != 0)
666 {
667 destination[reference.FirstLength] = '\\';
668 }
669 new Span<char>(reference.Second, reference.SecondLength).CopyTo(destination.Slice(reference.FirstLength + (reference.Separators & 1)));
670 if ((reference.Separators & 2u) != 0)
671 {
672 destination[destination.Length - reference.ThirdLength - 1] = '\\';
673 }
674 new Span<char>(reference.Third, reference.ThirdLength).CopyTo(destination.Slice(destination.Length - reference.ThirdLength));
675 });
676 }
677 }
678 }
679 }
680
681 private unsafe static string JoinInternal(ReadOnlySpan<char> first, ReadOnlySpan<char> second, ReadOnlySpan<char> third, ReadOnlySpan<char> fourth)
682 {
683 byte b = (byte)((!PathInternal.IsDirectorySeparator(first[first.Length - 1]) && !PathInternal.IsDirectorySeparator(second[0])) ? 1 : 0);
684 byte b2 = (byte)((!PathInternal.IsDirectorySeparator(second[second.Length - 1]) && !PathInternal.IsDirectorySeparator(third[0])) ? 1 : 0);
685 byte b3 = (byte)((!PathInternal.IsDirectorySeparator(third[third.Length - 1]) && !PathInternal.IsDirectorySeparator(fourth[0])) ? 1 : 0);
686 fixed (char* first2 = &MemoryMarshal.GetReference(first))
687 {
688 fixed (char* second2 = &MemoryMarshal.GetReference(second))
689 {
690 fixed (char* third2 = &MemoryMarshal.GetReference(third))
691 {
692 fixed (char* fourth2 = &MemoryMarshal.GetReference(fourth))
693 {
694 Join4Payload join4Payload = new Join4Payload(first2, first.Length, second2, second.Length, third2, third.Length, fourth2, fourth.Length, (byte)(b | (b2 << 1) | (b3 << 2)));
695 return string.Create(first.Length + second.Length + third.Length + fourth.Length + b + b2 + b3, (IntPtr)(&join4Payload), delegate(Span<char> destination, IntPtr statePtr)
696 {
697 ref Join4Payload reference = ref *(Join4Payload*)(void*)statePtr;
698 new Span<char>(reference.First, reference.FirstLength).CopyTo(destination);
699 int firstLength = reference.FirstLength;
700 if (((uint)reference.Separators & (true ? 1u : 0u)) != 0)
701 {
702 destination[firstLength++] = '\\';
703 }
704 new Span<char>(reference.Second, reference.SecondLength).CopyTo(destination.Slice(firstLength));
705 firstLength += reference.SecondLength;
706 if ((reference.Separators & 2u) != 0)
707 {
708 destination[firstLength++] = '\\';
709 }
710 new Span<char>(reference.Third, reference.ThirdLength).CopyTo(destination.Slice(firstLength));
711 firstLength += reference.ThirdLength;
712 if ((reference.Separators & 4u) != 0)
713 {
714 destination[firstLength++] = '\\';
715 }
716 new Span<char>(reference.Fourth, reference.FourthLength).CopyTo(destination.Slice(firstLength));
717 });
718 }
719 }
720 }
721 }
722 }
723
724 private unsafe static void Populate83FileNameFromRandomBytes(byte* bytes, int byteCount, Span<char> chars)
725 {
726 byte b = *bytes;
727 byte b2 = bytes[1];
728 byte b3 = bytes[2];
729 byte b4 = bytes[3];
730 byte b5 = bytes[4];
731 chars[11] = (char)Base32Char[bytes[7] & 0x1F];
732 chars[0] = (char)Base32Char[b & 0x1F];
733 chars[1] = (char)Base32Char[b2 & 0x1F];
734 chars[2] = (char)Base32Char[b3 & 0x1F];
735 chars[3] = (char)Base32Char[b4 & 0x1F];
736 chars[4] = (char)Base32Char[b5 & 0x1F];
737 chars[5] = (char)Base32Char[((b & 0xE0) >> 5) | ((b4 & 0x60) >> 2)];
738 chars[6] = (char)Base32Char[((b2 & 0xE0) >> 5) | ((b5 & 0x60) >> 2)];
739 b3 >>= 5;
740 if ((b4 & 0x80u) != 0)
741 {
742 b3 = (byte)(b3 | 8u);
743 }
744 if ((b5 & 0x80u) != 0)
745 {
746 b3 = (byte)(b3 | 0x10u);
747 }
748 chars[7] = (char)Base32Char[b3];
749 chars[8] = '.';
750 chars[9] = (char)Base32Char[bytes[5] & 0x1F];
751 chars[10] = (char)Base32Char[bytes[6] & 0x1F];
752 }
753
754 public static string GetRelativePath(string relativeTo, string path)
755 {
756 return GetRelativePath(relativeTo, path, PathInternal.StringComparison);
757 }
758
759 private static string GetRelativePath(string relativeTo, string path, StringComparison comparisonType)
760 {
761 if (relativeTo == null)
762 {
763 throw new ArgumentNullException("relativeTo");
764 }
765 if (PathInternal.IsEffectivelyEmpty(relativeTo.AsSpan()))
766 {
767 throw new ArgumentException(SR.Arg_PathEmpty, "relativeTo");
768 }
769 if (path == null)
770 {
771 throw new ArgumentNullException("path");
772 }
773 if (PathInternal.IsEffectivelyEmpty(path.AsSpan()))
774 {
775 throw new ArgumentException(SR.Arg_PathEmpty, "path");
776 }
777 relativeTo = GetFullPath(relativeTo);
778 path = GetFullPath(path);
779 if (!PathInternal.AreRootsEqual(relativeTo, path, comparisonType))
780 {
781 return path;
782 }
783 int num = PathInternal.GetCommonPathLength(relativeTo, path, comparisonType == StringComparison.OrdinalIgnoreCase);
784 if (num == 0)
785 {
786 return path;
787 }
788 int num2 = relativeTo.Length;
789 if (EndsInDirectorySeparator(relativeTo.AsSpan()))
790 {
791 num2--;
792 }
793 bool flag = EndsInDirectorySeparator(path.AsSpan());
794 int num3 = path.Length;
795 if (flag)
796 {
797 num3--;
798 }
799 if (num2 == num3 && num >= num2)
800 {
801 return ".";
802 }
803 Span<char> initialBuffer = stackalloc char[260];
804 ValueStringBuilder valueStringBuilder = new ValueStringBuilder(initialBuffer);
805 valueStringBuilder.EnsureCapacity(Math.Max(relativeTo.Length, path.Length));
806 if (num < num2)
807 {
808 valueStringBuilder.Append("..");
809 for (int i = num + 1; i < num2; i++)
810 {
811 if (PathInternal.IsDirectorySeparator(relativeTo[i]))
812 {
813 valueStringBuilder.Append(DirectorySeparatorChar);
814 valueStringBuilder.Append("..");
815 }
816 }
817 }
818 else if (PathInternal.IsDirectorySeparator(path[num]))
819 {
820 num++;
821 }
822 int num4 = num3 - num;
823 if (flag)
824 {
825 num4++;
826 }
827 if (num4 > 0)
828 {
829 if (valueStringBuilder.Length > 0)
830 {
831 valueStringBuilder.Append(DirectorySeparatorChar);
832 }
833 valueStringBuilder.Append(path.AsSpan(num, num4));
834 }
835 return valueStringBuilder.ToString();
836 }
837
838 public static string TrimEndingDirectorySeparator(string path)
839 {
841 }
842
847
849 {
851 }
852
853 public static bool EndsInDirectorySeparator(string path)
854 {
856 }
857
858 public static char[] GetInvalidFileNameChars()
859 {
860 return new char[41]
861 {
862 '"', '<', '>', '|', '\0', '\u0001', '\u0002', '\u0003', '\u0004', '\u0005',
863 '\u0006', '\a', '\b', '\t', '\n', '\v', '\f', '\r', '\u000e', '\u000f',
864 '\u0010', '\u0011', '\u0012', '\u0013', '\u0014', '\u0015', '\u0016', '\u0017', '\u0018', '\u0019',
865 '\u001a', '\u001b', '\u001c', '\u001d', '\u001e', '\u001f', ':', '*', '?', '\\',
866 '/'
867 };
868 }
869
870 public static char[] GetInvalidPathChars()
871 {
872 return new char[33]
873 {
874 '|', '\0', '\u0001', '\u0002', '\u0003', '\u0004', '\u0005', '\u0006', '\a', '\b',
875 '\t', '\n', '\v', '\f', '\r', '\u000e', '\u000f', '\u0010', '\u0011', '\u0012',
876 '\u0013', '\u0014', '\u0015', '\u0016', '\u0017', '\u0018', '\u0019', '\u001a', '\u001b', '\u001c',
877 '\u001d', '\u001e', '\u001f'
878 };
879 }
880
881 public static string GetFullPath(string path)
882 {
883 if (path == null)
884 {
885 throw new ArgumentNullException("path");
886 }
887 if (PathInternal.IsEffectivelyEmpty(path.AsSpan()))
888 {
889 throw new ArgumentException(SR.Arg_PathEmpty, "path");
890 }
891 if (path.Contains('\0'))
892 {
894 }
895 return GetFullPathInternal(path);
896 }
897
898 public static string GetFullPath(string path, string basePath)
899 {
900 if (path == null)
901 {
902 throw new ArgumentNullException("path");
903 }
904 if (basePath == null)
905 {
906 throw new ArgumentNullException("basePath");
907 }
908 if (!IsPathFullyQualified(basePath))
909 {
911 }
912 if (basePath.Contains('\0') || path.Contains('\0'))
913 {
915 }
916 if (IsPathFullyQualified(path))
917 {
918 return GetFullPathInternal(path);
919 }
920 if (PathInternal.IsEffectivelyEmpty(path.AsSpan()))
921 {
922 return basePath;
923 }
924 int length = path.Length;
925 string text = ((length >= 1 && PathInternal.IsDirectorySeparator(path[0])) ? Join(GetPathRoot(basePath.AsSpan()), path.AsSpan(1)) : ((length < 2 || !PathInternal.IsValidDriveChar(path[0]) || path[1] != ':') ? JoinInternal(basePath.AsSpan(), path.AsSpan()) : ((!GetVolumeName(path.AsSpan()).EqualsOrdinal(GetVolumeName(basePath.AsSpan()))) ? ((!PathInternal.IsDevice(basePath.AsSpan())) ? path.Insert(2, "\\") : ((length == 2) ? JoinInternal(basePath.AsSpan(0, 4), path.AsSpan(), "\\".AsSpan()) : JoinInternal(basePath.AsSpan(0, 4), path.AsSpan(0, 2), "\\".AsSpan(), path.AsSpan(2)))) : Join(basePath.AsSpan(), path.AsSpan(2)))));
926 if (!PathInternal.IsDevice(text.AsSpan()))
927 {
929 }
931 }
932
933 private static string GetFullPathInternal(string path)
934 {
935 if (PathInternal.IsExtended(path.AsSpan()))
936 {
937 return path;
938 }
939 return PathHelper.Normalize(path);
940 }
941
942 public static string GetTempPath()
943 {
944 Span<char> initialBuffer = stackalloc char[260];
945 ValueStringBuilder builder = new ValueStringBuilder(initialBuffer);
946 GetTempPath(ref builder);
947 string result = PathHelper.Normalize(ref builder);
948 builder.Dispose();
949 return result;
950 }
951
952 private static void GetTempPath(ref ValueStringBuilder builder)
953 {
954 uint tempPathW;
955 while ((tempPathW = Interop.Kernel32.GetTempPathW(builder.Capacity, ref builder.GetPinnableReference())) > builder.Capacity)
956 {
957 builder.EnsureCapacity(checked((int)tempPathW));
958 }
959 if (tempPathW == 0)
960 {
962 }
963 builder.Length = (int)tempPathW;
964 }
965
966 public static string GetTempFileName()
967 {
968 Span<char> initialBuffer = stackalloc char[260];
969 ValueStringBuilder builder = new ValueStringBuilder(initialBuffer);
970 GetTempPath(ref builder);
971 initialBuffer = stackalloc char[260];
972 ValueStringBuilder path = new ValueStringBuilder(initialBuffer);
973 uint tempFileNameW = Interop.Kernel32.GetTempFileNameW(ref builder.GetPinnableReference(), "tmp", 0u, ref path.GetPinnableReference());
974 builder.Dispose();
975 if (tempFileNameW == 0)
976 {
978 }
979 path.Length = path.RawChars.IndexOf('\0');
980 string result = PathHelper.Normalize(ref path);
981 path.Dispose();
982 return result;
983 }
984
985 public static bool IsPathRooted([NotNullWhen(true)] string? path)
986 {
987 if (path != null)
988 {
989 return IsPathRooted(path.AsSpan());
990 }
991 return false;
992 }
993
994 public static bool IsPathRooted(ReadOnlySpan<char> path)
995 {
996 int length = path.Length;
997 if (length < 1 || !PathInternal.IsDirectorySeparator(path[0]))
998 {
999 if (length >= 2 && PathInternal.IsValidDriveChar(path[0]))
1000 {
1001 return path[1] == ':';
1002 }
1003 return false;
1004 }
1005 return true;
1006 }
1007
1008 public static string? GetPathRoot(string? path)
1009 {
1010 if (PathInternal.IsEffectivelyEmpty(path.AsSpan()))
1011 {
1012 return null;
1013 }
1014 ReadOnlySpan<char> pathRoot = GetPathRoot(path.AsSpan());
1015 if (path.Length == pathRoot.Length)
1016 {
1018 }
1020 }
1021
1023 {
1025 {
1027 }
1028 int rootLength = PathInternal.GetRootLength(path);
1029 if (rootLength > 0)
1030 {
1031 return path.Slice(0, rootLength);
1032 }
1034 }
1035
1037 {
1038 ReadOnlySpan<char> pathRoot = GetPathRoot(path);
1039 if (pathRoot.Length == 0)
1040 {
1041 return pathRoot;
1042 }
1043 int num = GetUncRootLength(path);
1044 if (num == -1)
1045 {
1046 num = (PathInternal.IsDevice(path) ? 4 : 0);
1047 }
1048 ReadOnlySpan<char> readOnlySpan = pathRoot.Slice(num);
1049 if (!EndsInDirectorySeparator(readOnlySpan))
1050 {
1051 return readOnlySpan;
1052 }
1053 return readOnlySpan.Slice(0, readOnlySpan.Length - 1);
1054 }
1055
1056 internal static int GetUncRootLength(ReadOnlySpan<char> path)
1057 {
1058 bool flag = PathInternal.IsDevice(path);
1059 if (!flag && path.Slice(0, 2).EqualsOrdinal("\\\\".AsSpan()))
1060 {
1061 return 2;
1062 }
1063 if (flag && path.Length >= 8 && (path.Slice(0, 8).EqualsOrdinal("\\\\?\\UNC\\".AsSpan()) || path.Slice(5, 4).EqualsOrdinal("UNC\\".AsSpan())))
1064 {
1065 return 8;
1066 }
1067 return -1;
1068 }
1069}
static uint GetTempPathW(int bufferLen, ref char buffer)
static uint GetTempFileNameW(ref char lpPathName, string lpPrefixString, uint uUnique, ref char lpTempFileName)
static unsafe void GetRandomBytes(byte *buffer, int length)
Definition Interop.cs:1871
static string Normalize(string path)
Definition PathHelper.cs:8
static bool EndsInDirectorySeparator(string path)
static string RemoveRelativeSegments(string path, int rootLength)
static bool IsValidDriveChar(char value)
static int GetRootLength(ReadOnlySpan< char > path)
static string TrimEndingDirectorySeparator(string path)
static bool IsDirectorySeparator(char c)
static bool StartsWithDirectorySeparator(ReadOnlySpan< char > path)
static bool IsDevice(ReadOnlySpan< char > path)
static bool IsExtended(ReadOnlySpan< char > path)
static bool AreRootsEqual(string first, string second, StringComparison comparisonType)
static string NormalizeDirectorySeparators(string path)
static bool IsPartiallyQualified(ReadOnlySpan< char > path)
static bool IsEffectivelyEmpty(ReadOnlySpan< char > path)
static StringComparison StringComparison
static int GetCommonPathLength(string first, string second, bool ignoreCase)
static string Combine(string path1, string path2, string path3, string path4)
Definition Path.cs:322
static ReadOnlySpan< char > TrimEndingDirectorySeparator(ReadOnlySpan< char > path)
Definition Path.cs:843
static ? string GetFileNameWithoutExtension(string? path)
Definition Path.cs:229
static ReadOnlySpan< char > GetDirectoryName(ReadOnlySpan< char > path)
Definition Path.cs:135
static string Combine(string path1, string path2)
Definition Path.cs:304
static ? string GetExtension(string? path)
Definition Path.cs:168
static char[] GetInvalidFileNameChars()
Definition Path.cs:858
static string CombineInternal(string first, string second, string third)
Definition Path.cs:583
static ? string GetFileName(string? path)
Definition Path.cs:200
static char[] GetInvalidPathChars()
Definition Path.cs:870
static readonly char PathSeparator
Definition Path.cs:77
static string GetFullPath(string path)
Definition Path.cs:881
static string CombineInternal(string first, string second)
Definition Path.cs:566
static string Combine(string path1, string path2, string path3)
Definition Path.cs:313
static unsafe string JoinInternal(ReadOnlySpan< char > first, ReadOnlySpan< char > second, ReadOnlySpan< char > third)
Definition Path.cs:650
static ReadOnlySpan< char > GetPathRoot(ReadOnlySpan< char > path)
Definition Path.cs:1022
static string Join(string? path1, string? path2, string? path3)
Definition Path.cs:443
static string GetTempFileName()
Definition Path.cs:966
static string Join(ReadOnlySpan< char > path1, ReadOnlySpan< char > path2, ReadOnlySpan< char > path3)
Definition Path.cs:400
static bool IsPathRooted([NotNullWhen(true)] string? path)
Definition Path.cs:985
static string Join(string? path1, string? path2, string? path3, string? path4)
Definition Path.cs:448
static bool HasExtension([NotNullWhen(true)] string? path)
Definition Path.cs:278
static bool EndsInDirectorySeparator(string path)
Definition Path.cs:853
static bool IsPathRooted(ReadOnlySpan< char > path)
Definition Path.cs:994
static string Join(ReadOnlySpan< char > path1, ReadOnlySpan< char > path2, ReadOnlySpan< char > path3, ReadOnlySpan< char > path4)
Definition Path.cs:417
static bool HasExtension(ReadOnlySpan< char > path)
Definition Path.cs:287
static string TrimEndingDirectorySeparator(string path)
Definition Path.cs:838
static readonly char[] InvalidPathChars
Definition Path.cs:80
static unsafe void Populate83FileNameFromRandomBytes(byte *bytes, int byteCount, Span< char > chars)
Definition Path.cs:724
static string Combine(params string[] paths)
Definition Path.cs:331
static string GetTempPath()
Definition Path.cs:942
static string Join(ReadOnlySpan< char > path1, ReadOnlySpan< char > path2)
Definition Path.cs:387
static ? string GetPathRoot(string? path)
Definition Path.cs:1008
static void GetTempPath(ref ValueStringBuilder builder)
Definition Path.cs:952
static int GetUncRootLength(ReadOnlySpan< char > path)
Definition Path.cs:1056
static readonly char AltDirectorySeparatorChar
Definition Path.cs:73
static readonly char DirectorySeparatorChar
Definition Path.cs:71
static bool IsPathFullyQualified(string path)
Definition Path.cs:264
static readonly char VolumeSeparatorChar
Definition Path.cs:75
static ReadOnlySpan< char > GetFileName(ReadOnlySpan< char > path)
Definition Path.cs:214
static bool IsPathFullyQualified(ReadOnlySpan< char > path)
Definition Path.cs:273
static string GetRelativePath(string relativeTo, string path, StringComparison comparisonType)
Definition Path.cs:759
static unsafe string GetRandomFileName()
Definition Path.cs:254
static bool TryJoin(ReadOnlySpan< char > path1, ReadOnlySpan< char > path2, Span< char > destination, out int charsWritten)
Definition Path.cs:492
static string GetFullPathInternal(string path)
Definition Path.cs:933
static string CombineInternal(string first, string second, string third, string fourth)
Definition Path.cs:608
static string Join(string? path1, string? path2)
Definition Path.cs:438
static bool TryJoin(ReadOnlySpan< char > path1, ReadOnlySpan< char > path2, ReadOnlySpan< char > path3, Span< char > destination, out int charsWritten)
Definition Path.cs:526
static bool EndsInDirectorySeparator(ReadOnlySpan< char > path)
Definition Path.cs:848
static int GetDirectoryNameOffset(ReadOnlySpan< char > path)
Definition Path.cs:149
static string GetFullPath(string path, string basePath)
Definition Path.cs:898
static ReadOnlySpan< char > GetVolumeName(ReadOnlySpan< char > path)
Definition Path.cs:1036
static ReadOnlySpan< char > GetFileNameWithoutExtension(ReadOnlySpan< char > path)
Definition Path.cs:243
static string Join(params string?[] paths)
Definition Path.cs:453
static ? string GetDirectoryName(string? path)
Definition Path.cs:121
static ReadOnlySpan< char > GetExtension(ReadOnlySpan< char > path)
Definition Path.cs:177
static string GetRelativePath(string relativeTo, string path)
Definition Path.cs:754
static string JoinInternal(ReadOnlySpan< char > first, ReadOnlySpan< char > second)
Definition Path.cs:641
static unsafe string JoinInternal(ReadOnlySpan< char > first, ReadOnlySpan< char > second, ReadOnlySpan< char > third, ReadOnlySpan< char > fourth)
Definition Path.cs:681
static ReadOnlySpan< byte > Base32Char
Definition Path.cs:82
static ? string ChangeExtension(string? path, string? extension)
Definition Path.cs:85
static Exception GetExceptionForLastWin32Error(string path="")
static byte Max(byte val1, byte val2)
Definition Math.cs:738
static string Argument_InvalidPathChars
Definition SR.cs:730
static string Arg_PathEmpty
Definition SR.cs:54
static string Arg_BasePathNotFullyQualified
Definition SR.cs:2070
Definition SR.cs:7
readonly int ThirdLength
Definition Path.cs:21
unsafe readonly char * Second
Definition Path.cs:15
unsafe readonly char * First
Definition Path.cs:11
readonly int FirstLength
Definition Path.cs:13
readonly int SecondLength
Definition Path.cs:17
readonly byte Separators
Definition Path.cs:23
unsafe Join3Payload(char *first, int firstLength, char *second, int secondLength, char *third, int thirdLength, byte separators)
Definition Path.cs:25
unsafe readonly char * Third
Definition Path.cs:19
readonly byte Separators
Definition Path.cs:55
unsafe readonly char * First
Definition Path.cs:39
readonly int ThirdLength
Definition Path.cs:49
unsafe readonly char * Second
Definition Path.cs:43
readonly int FourthLength
Definition Path.cs:53
readonly int FirstLength
Definition Path.cs:41
readonly int SecondLength
Definition Path.cs:45
unsafe readonly char * Third
Definition Path.cs:47
unsafe readonly char * Fourth
Definition Path.cs:51
unsafe Join4Payload(char *first, int firstLength, char *second, int secondLength, char *third, int thirdLength, char *fourth, int fourthLength, byte separators)
Definition Path.cs:57
void CopyTo(Span< T > destination)
static ReadOnlySpan< T > Empty
ReadOnlySpan< T > Slice(int start)
override string ToString()
void CopyTo(Span< T > destination)
Definition Span.cs:224