@@ -115,6 +115,25 @@ internal static bool AreRootsEqual(string first, string second, StringComparison
115115 /// </summary>
116116 /// <param name="rootLength">The length of the root of the given path</param>
117117 internal static string RemoveRelativeSegments ( string path , int rootLength )
118+ {
119+ Span < char > initialBuffer = stackalloc char [ 260 /* PathInternal.MaxShortPath */ ] ;
120+ ValueStringBuilder sb = new ValueStringBuilder ( initialBuffer ) ;
121+
122+ if ( RemoveRelativeSegments ( path . AsSpan ( ) , rootLength , ref sb ) )
123+ {
124+ path = sb . ToString ( ) ;
125+ }
126+
127+ sb . Dispose ( ) ;
128+ return path ;
129+ }
130+
131+ /// <summary>
132+ /// Try to remove relative segments from the given path (without combining with a root).
133+ /// </summary>
134+ /// <param name="rootLength">The length of the root of the given path</param>
135+ /// <returns>"true" if the path was modified</returns>
136+ internal static bool RemoveRelativeSegments ( ReadOnlySpan < char > path , int rootLength , ref ValueStringBuilder sb )
118137 {
119138 Debug . Assert ( rootLength > 0 ) ;
120139 bool flippedSeparator = false ;
@@ -126,15 +145,12 @@ internal static string RemoveRelativeSegments(string path, int rootLength)
126145 if ( PathInternal . IsDirectorySeparator ( path [ skip - 1 ] ) )
127146 skip -- ;
128147
129- Span < char > initialBuffer = stackalloc char [ 260 /* PathInternal.MaxShortPath */ ] ;
130- ValueStringBuilder sb = new ValueStringBuilder ( initialBuffer ) ;
131-
132148 // Remove "//", "/./", and "/../" from the path by copying each character to the output,
133149 // except the ones we're removing, such that the builder contains the normalized path
134150 // at the end.
135151 if ( skip > 0 )
136152 {
137- sb . Append ( path . AsSpan ( 0 , skip ) ) ;
153+ sb . Append ( path . Slice ( 0 , skip ) ) ;
138154 }
139155
140156 for ( int i = skip ; i < path . Length ; i ++ )
@@ -182,7 +198,7 @@ internal static string RemoveRelativeSegments(string path, int rootLength)
182198
183199 i += 2 ;
184200 continue ;
185- }
201+ }
186202 }
187203
188204 // Normalize the directory separator if needed
@@ -198,11 +214,16 @@ internal static string RemoveRelativeSegments(string path, int rootLength)
198214 // If we haven't changed the source path, return the original
199215 if ( ! flippedSeparator && sb . Length == path . Length )
200216 {
201- sb . Dispose ( ) ;
202- return path ;
217+ return false ;
218+ }
219+
220+ // We may have eaten the trailing separator from the root when we started and not replaced it
221+ if ( skip != rootLength && sb . Length < rootLength )
222+ {
223+ sb . Append ( path [ rootLength - 1 ] ) ;
203224 }
204225
205- return sb . Length < rootLength ? path . Substring ( 0 , rootLength ) : sb . ToString ( ) ;
226+ return true ;
206227 }
207228 }
208229}
0 commit comments