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;
}
}