From: Anirudh Agnihotry Date: Thu, 8 Mar 2018 20:55:00 +0000 (-0800) Subject: RemoveRelativeSegments moved from path to pathinternal (#16829) X-Git-Tag: accepted/tizen/unified/20190422.045933~2709 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=66d2738ea96fcce753dec1370e79a0c78f7b6adb;p=platform%2Fupstream%2Fcoreclr.git RemoveRelativeSegments moved from path to pathinternal (#16829) --- diff --git a/src/mscorlib/shared/System/IO/Path.Unix.cs b/src/mscorlib/shared/System/IO/Path.Unix.cs index fd24cc8..10d295f 100644 --- a/src/mscorlib/shared/System/IO/Path.Unix.cs +++ b/src/mscorlib/shared/System/IO/Path.Unix.cs @@ -34,7 +34,7 @@ namespace System.IO // We would ideally use realpath to do this, but it resolves symlinks, requires that the file actually exist, // and turns it into a full path, which we only want if fullCheck is true. - string collapsedString = RemoveRelativeSegments(path); + string collapsedString = PathInternal.RemoveRelativeSegments(path); Debug.Assert(collapsedString.Length < path.Length || collapsedString.ToString() == path, "Either we've removed characters, or the string should be unmodified from the input path."); diff --git a/src/mscorlib/shared/System/IO/Path.Windows.cs b/src/mscorlib/shared/System/IO/Path.Windows.cs index 2f1a527..2d4a343 100644 --- a/src/mscorlib/shared/System/IO/Path.Windows.cs +++ b/src/mscorlib/shared/System/IO/Path.Windows.cs @@ -122,7 +122,7 @@ namespace System.IO // Windows doesn't root them properly. As such we need to manually remove segments. return PathInternal.IsDevice(combinedPath) // Paths at this point are in the form of \\?\C:\.\tmp we skip to the last character of the root when calling RemoveRelativeSegments to remove relative paths in such cases. - ? RemoveRelativeSegments(combinedPath, PathInternal.GetRootLength(combinedPath) - 1) + ? PathInternal.RemoveRelativeSegments(combinedPath, PathInternal.GetRootLength(combinedPath) - 1) : GetFullPath(combinedPath); } diff --git a/src/mscorlib/shared/System/IO/Path.cs b/src/mscorlib/shared/System/IO/Path.cs index cd1655e..1e40ab5 100644 --- a/src/mscorlib/shared/System/IO/Path.cs +++ b/src/mscorlib/shared/System/IO/Path.cs @@ -672,93 +672,6 @@ namespace System.IO } /// - /// Try to remove relative segments from the given path (without combining with a root). - /// - /// Skip the specified number of characters before evaluating. - private static string RemoveRelativeSegments(string path, int skip = 0) - { - bool flippedSeparator = false; - - // Remove "//", "/./", and "/../" from the path by copying each character to the output, - // except the ones we're removing, such that the builder contains the normalized path - // at the end. - StringBuilder sb = StringBuilderCache.Acquire(path.Length); - if (skip > 0) - { - sb.Append(path, 0, skip); - } - - for (int i = skip; i < path.Length; i++) - { - char c = path[i]; - - if (PathInternal.IsDirectorySeparator(c) && i + 1 < path.Length) - { - // Skip this character if it's a directory separator and if the next character is, too, - // e.g. "parent//child" => "parent/child" - if (PathInternal.IsDirectorySeparator(path[i + 1])) - { - continue; - } - - // Skip this character and the next if it's referring to the current directory, - // e.g. "parent/./child" => "parent/child" - if ((i + 2 == path.Length || PathInternal.IsDirectorySeparator(path[i + 2])) && - path[i + 1] == '.') - { - i++; - continue; - } - - // Skip this character and the next two if it's referring to the parent directory, - // e.g. "parent/child/../grandchild" => "parent/grandchild" - if (i + 2 < path.Length && - (i + 3 == path.Length || PathInternal.IsDirectorySeparator(path[i + 3])) && - path[i + 1] == '.' && path[i + 2] == '.') - { - // Unwind back to the last slash (and if there isn't one, clear out everything). - int s; - for (s = sb.Length - 1; s >= 0; s--) - { - if (PathInternal.IsDirectorySeparator(sb[s])) - { - sb.Length = (i + 3 >= path.Length && s <= skip ) ? s + 1 : s; // to avoid removing the complete "\tmp\" segment in cases like \\?\C:\tmp\..\, C:\tmp\.. - break; - } - } - if (s < 0) - { - sb.Length = 0; - } - - i += 2; - continue; - } - } - - // Normalize the directory separator if needed - if (c != PathInternal.DirectorySeparatorChar && c == PathInternal.AltDirectorySeparatorChar) - { - c = PathInternal.DirectorySeparatorChar; - flippedSeparator = true; - } - - sb.Append(c); - } - - if (flippedSeparator || sb.Length != path.Length) - { - return StringBuilderCache.GetStringAndRelease(sb); - } - else - { - // We haven't changed the source path, return the original - StringBuilderCache.Release(sb); - return path; - } - } - - /// /// Create a relative path from one path to another. Paths will be resolved before calculating the difference. /// Default path comparison for the active platform will be used (OrdinalIgnoreCase for Windows or Mac, Ordinal for Unix). /// diff --git a/src/mscorlib/shared/System/IO/PathInternal.cs b/src/mscorlib/shared/System/IO/PathInternal.cs index 02a8731..789be91 100644 --- a/src/mscorlib/shared/System/IO/PathInternal.cs +++ b/src/mscorlib/shared/System/IO/PathInternal.cs @@ -2,6 +2,9 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +using System.Diagnostics; +using System.Text; + namespace System.IO { /// Contains internal path helpers that are shared between many projects. @@ -106,5 +109,93 @@ namespace System.IO length: firstRootLength, comparisonType: comparisonType) == 0; } + + /// + /// Try to remove relative segments from the given path (without combining with a root). + /// + /// Skip the specified number of characters before evaluating. + internal static string RemoveRelativeSegments(string path, int skip = 0) + { + Debug.Assert(skip >= 0); + bool flippedSeparator = false; + + // Remove "//", "/./", and "/../" from the path by copying each character to the output, + // except the ones we're removing, such that the builder contains the normalized path + // at the end. + StringBuilder sb = StringBuilderCache.Acquire(path.Length); + if (skip > 0) + { + sb.Append(path, 0, skip); + } + + for (int i = skip; i < path.Length; i++) + { + char c = path[i]; + + if (PathInternal.IsDirectorySeparator(c) && i + 1 < path.Length) + { + // Skip this character if it's a directory separator and if the next character is, too, + // e.g. "parent//child" => "parent/child" + if (PathInternal.IsDirectorySeparator(path[i + 1])) + { + continue; + } + + // Skip this character and the next if it's referring to the current directory, + // e.g. "parent/./child" => "parent/child" + if ((i + 2 == path.Length || PathInternal.IsDirectorySeparator(path[i + 2])) && + path[i + 1] == '.') + { + i++; + continue; + } + + // Skip this character and the next two if it's referring to the parent directory, + // e.g. "parent/child/../grandchild" => "parent/grandchild" + if (i + 2 < path.Length && + (i + 3 == path.Length || PathInternal.IsDirectorySeparator(path[i + 3])) && + path[i + 1] == '.' && path[i + 2] == '.') + { + // Unwind back to the last slash (and if there isn't one, clear out everything). + int s; + for (s = sb.Length - 1; s >= skip; s--) + { + if (PathInternal.IsDirectorySeparator(sb[s])) + { + sb.Length = (i + 3 >= path.Length && s == skip) ? s + 1 : s; // to avoid removing the complete "\tmp\" segment in cases like \\?\C:\tmp\..\, C:\tmp\.. + break; + } + } + if (s < skip) + { + sb.Length = skip; + } + + i += 2; + continue; + } + } + + // Normalize the directory separator if needed + if (c != PathInternal.DirectorySeparatorChar && c == PathInternal.AltDirectorySeparatorChar) + { + c = PathInternal.DirectorySeparatorChar; + flippedSeparator = true; + } + + sb.Append(c); + } + + if (flippedSeparator || sb.Length != path.Length) + { + return StringBuilderCache.GetStringAndRelease(sb); + } + else + { + // We haven't changed the source path, return the original + StringBuilderCache.Release(sb); + return path; + } + } } }