22using System . Diagnostics ;
33using System . Runtime . CompilerServices ;
44using System . Text . Encodings . Web ;
5- using DotNext . Buffers ;
65
76namespace DotNext . IO ;
87
8+ using Buffers ;
9+
910/// <summary>
1011/// Represents operations to work with <c>file://</c> scheme.
1112/// </summary>
@@ -18,6 +19,10 @@ public static class FileUri
1819 // \\.\folder => file://./folder
1920 private const string FileScheme = "file://" ;
2021 private const string UncPrefix = @"\\" ;
22+ private const char DriveSeparatorChar = ':' ;
23+
24+ private static readonly SearchValues < char > Delimiters =
25+ SearchValues . Create ( OperatingSystem . IsWindows ( ) ? [ Path . DirectorySeparatorChar , DriveSeparatorChar ] : [ Path . DirectorySeparatorChar ] ) ;
2126
2227 /// <summary>
2328 /// Encodes file name as URI.
@@ -79,6 +84,7 @@ private static void ThrowIfNotFullyQualified(ReadOnlySpan<char> fileName)
7984 private static bool TryEncodeCore ( ReadOnlySpan < char > fileName , UrlEncoder encoder , Span < char > output , out int charsWritten )
8085 {
8186 const char slash = '/' ;
87+ const char escapedDriveSeparatorChar = '|' ;
8288 var result = false ;
8389 var writer = new SpanWriter < char > ( output ) ;
8490 writer . Write ( FileScheme ) ;
@@ -92,31 +98,36 @@ private static bool TryEncodeCore(ReadOnlySpan<char> fileName, UrlEncoder encode
9298 }
9399 else
94100 {
95- writer . Add ( Path . DirectorySeparatorChar ) ;
101+ writer . Add ( slash ) ;
96102 }
97103
98104 while ( ! fileName . IsEmpty )
99105 {
100- var index = fileName . IndexOf ( Path . DirectorySeparatorChar ) ;
106+ var index = fileName . IndexOfAny ( Delimiters ) ;
107+ char replacement ;
101108 ReadOnlySpan < char > component ;
102109 if ( index >= 0 )
103110 {
104111 component = fileName . Slice ( 0 , index ) ;
105112 fileName = fileName . Slice ( index + 1 ) ;
113+ replacement = OperatingSystem . IsWindows ( ) && fileName [ index ] is DriveSeparatorChar
114+ ? escapedDriveSeparatorChar
115+ : slash ;
106116 }
107117 else
108118 {
109119 component = fileName ;
110120 fileName = default ;
121+ replacement = '\0 ' ;
111122 }
112123
113124 result = encoder . Encode ( component , writer . RemainingSpan , out _ , out charsWritten ) is OperationStatus . Done ;
114125 if ( ! result )
115126 break ;
116127
117128 writer . Advance ( charsWritten ) ;
118- if ( index >= 0 )
119- writer . Add ( Path . DirectorySeparatorChar ) ;
129+ if ( replacement is not ' \0 ' )
130+ writer . Add ( replacement ) ;
120131 }
121132
122133 charsWritten = writer . WrittenCount ;
0 commit comments