namespace AIStudio.Tools; /// /// Shared rules for comparing and resolving file system paths. /// public static class PathTools { /// /// How to compare file system paths: Windows treats them case-insensitively, Linux and /// macOS do not. There, two files may differ in casing alone. /// public static readonly StringComparison COMPARISON = OperatingSystem.IsWindows() ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; /// /// The comparer matching COMPARISON, for path-keyed lookups. /// public static readonly StringComparer COMPARER = OperatingSystem.IsWindows() ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal; /// /// Determines whether a path lies below the given directory. /// /// /// The directory itself does not count as lying below itself. A path which cannot be resolved /// counts as lying elsewhere. /// /// The directory. /// The path to check. /// Whether the path lies below the directory. public static bool IsInsideDirectory(string directory, string path) { try { var fullDirectory = Path.GetFullPath(directory); var directoryPrefix = fullDirectory.EndsWith(Path.DirectorySeparatorChar) ? fullDirectory : fullDirectory + Path.DirectorySeparatorChar; return Path.GetFullPath(path).StartsWith(directoryPrefix, COMPARISON); } catch (Exception exception) when (exception is ArgumentException or NotSupportedException or PathTooLongException) { return false; } } /// /// Finds the place where a file dialog opens for a path which may no longer exist. /// /// /// Given a file or a folder which was moved or renamed, the native dialog cannot open its place /// and falls back to wherever it was used last. The nearest folder which still exists is the /// better start: the file or the folder was moved from there, so its new place is often close by. /// A relative path, or a path of another operating system, e.g. from a backup, has no such folder. /// /// The file or the folder the dialog should open at. /// The path itself when it exists, else its nearest parent folder which exists, or null when there is none. public static string? FindNearestExistingPath(string path) { if (string.IsNullOrWhiteSpace(path) || !Path.IsPathFullyQualified(path)) return null; if (File.Exists(path) || Directory.Exists(path)) return path; for (var directory = Path.GetDirectoryName(path); !string.IsNullOrEmpty(directory); directory = Path.GetDirectoryName(directory)) if (Directory.Exists(directory)) return directory; return null; } }