From 7580f87029ac9f778ec632c7ccaed489d7ca1364 Mon Sep 17 00:00:00 2001 From: Jesse Plamondon-Willard Date: Tue, 8 Sep 2020 18:12:57 -0400 Subject: rename PathUtilities.NormalizePathSeparator, add normalization for more cases --- src/SMAPI.Toolkit/Utilities/PathUtilities.cs | 41 ++++++++++++++++++++++------ 1 file changed, 33 insertions(+), 8 deletions(-) (limited to 'src/SMAPI.Toolkit/Utilities') diff --git a/src/SMAPI.Toolkit/Utilities/PathUtilities.cs b/src/SMAPI.Toolkit/Utilities/PathUtilities.cs index bd5fafbc..c9fb6213 100644 --- a/src/SMAPI.Toolkit/Utilities/PathUtilities.cs +++ b/src/SMAPI.Toolkit/Utilities/PathUtilities.cs @@ -23,7 +23,7 @@ namespace StardewModdingAPI.Toolkit.Utilities public static readonly char[] PossiblePathSeparators = new[] { '/', '\\', Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }.Distinct().ToArray(); /// The preferred directory separator character in an asset key. - public static readonly string PreferredPathSeparator = Path.DirectorySeparatorChar.ToString(); + public static readonly char PreferredPathSeparator = Path.DirectorySeparatorChar; /********* @@ -40,15 +40,37 @@ namespace StardewModdingAPI.Toolkit.Utilities : path.Split(PathUtilities.PossiblePathSeparators, StringSplitOptions.RemoveEmptyEntries); } - /// Normalize path separators in a file path. + /// Normalize separators in a file path. /// The file path to normalize. [Pure] - public static string NormalizePathSeparators(string path) + public static string NormalizePath(string path) { - if (string.IsNullOrWhiteSpace(path)) + path = path?.Trim(); + if (string.IsNullOrEmpty(path)) return path; - return string.Join(PathUtilities.PreferredPathSeparator, path.Split(PathUtilities.PossiblePathSeparators)); + // get basic path format (e.g. /some/asset\\path/ => some\asset\path) + string[] segments = PathUtilities.GetSegments(path); + string newPath = string.Join(PathUtilities.PreferredPathSeparator.ToString(), segments); + + // keep root prefix + bool hasRoot = false; + if (path.StartsWith(PathUtilities.WindowsUncRoot)) + { + newPath = PathUtilities.WindowsUncRoot + newPath; + hasRoot = true; + } + else if (PathUtilities.PossiblePathSeparators.Contains(path[0])) + { + newPath = PathUtilities.PreferredPathSeparator + newPath; + hasRoot = true; + } + + // keep trailing separator + if ((!hasRoot || segments.Any()) && PathUtilities.PossiblePathSeparators.Contains(path[path.Length - 1])) + newPath += PathUtilities.PreferredPathSeparator; + + return newPath; } /// Get a directory or file path relative to a given source path. If no relative path is possible (e.g. the paths are on different drives), an absolute path is returned. @@ -69,7 +91,10 @@ namespace StardewModdingAPI.Toolkit.Utilities throw new InvalidOperationException($"Can't get path for '{targetPath}' relative to '{sourceDir}'."); // get relative path - string relative = PathUtilities.NormalizePathSeparators(Uri.UnescapeDataString(from.MakeRelativeUri(to).ToString())); + string rawUrl = Uri.UnescapeDataString(from.MakeRelativeUri(to).ToString()); + if (rawUrl.StartsWith("file://")) + rawUrl = PathUtilities.WindowsUncRoot + rawUrl.Substring("file://".Length); + string relative = PathUtilities.NormalizePath(rawUrl); // normalize if (relative == "") @@ -77,8 +102,8 @@ namespace StardewModdingAPI.Toolkit.Utilities else { // trim trailing slash from URL - if (relative.EndsWith(PathUtilities.PreferredPathSeparator)) - relative = relative.Substring(0, relative.Length - PathUtilities.PreferredPathSeparator.Length); + if (relative.EndsWith(PathUtilities.PreferredPathSeparator.ToString())) + relative = relative.Substring(0, relative.Length - 1); // fix root if (relative.StartsWith("file:") && !targetPath.Contains("file:")) -- cgit