diff options
author | Anirudh Agnihotry <anirudhagnihotry098@gmail.com> | 2018-03-08 23:55:00 +0300 |
---|---|---|
committer | Dan Moseley <danmose@microsoft.com> | 2018-03-09 02:10:30 +0300 |
commit | fa33b8a6887ed510ca3089f1a34788c68cd7e66f (patch) | |
tree | ab887382281d19a2331012157fb52ced0560a478 | |
parent | 2044e37b95eac1851361336bb366774b4b3c86d5 (diff) |
RemoveRelativeSegments moved from path to pathinternal (#16829)
Signed-off-by: dotnet-bot <dotnet-bot@microsoft.com>
4 files changed, 93 insertions, 89 deletions
diff --git a/src/System.Private.CoreLib/shared/System/IO/Path.Unix.cs b/src/System.Private.CoreLib/shared/System/IO/Path.Unix.cs index fd24cc810..10d295fec 100644 --- a/src/System.Private.CoreLib/shared/System/IO/Path.Unix.cs +++ b/src/System.Private.CoreLib/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/System.Private.CoreLib/shared/System/IO/Path.Windows.cs b/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs index 2f1a527d8..2d4a34347 100644 --- a/src/System.Private.CoreLib/shared/System/IO/Path.Windows.cs +++ b/src/System.Private.CoreLib/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/System.Private.CoreLib/shared/System/IO/Path.cs b/src/System.Private.CoreLib/shared/System/IO/Path.cs index cd1655e1f..1e40ab5e6 100644 --- a/src/System.Private.CoreLib/shared/System/IO/Path.cs +++ b/src/System.Private.CoreLib/shared/System/IO/Path.cs @@ -672,93 +672,6 @@ namespace System.IO } /// <summary> - /// Try to remove relative segments from the given path (without combining with a root). - /// </summary> - /// <param name="skip">Skip the specified number of characters before evaluating.</param> - 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; - } - } - - /// <summary> /// 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). /// </summary> diff --git a/src/System.Private.CoreLib/shared/System/IO/PathInternal.cs b/src/System.Private.CoreLib/shared/System/IO/PathInternal.cs index 02a873192..789be9112 100644 --- a/src/System.Private.CoreLib/shared/System/IO/PathInternal.cs +++ b/src/System.Private.CoreLib/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 { /// <summary>Contains internal path helpers that are shared between many projects.</summary> @@ -106,5 +109,93 @@ namespace System.IO length: firstRootLength, comparisonType: comparisonType) == 0; } + + /// <summary> + /// Try to remove relative segments from the given path (without combining with a root). + /// </summary> + /// <param name="skip">Skip the specified number of characters before evaluating.</param> + 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; + } + } } } |