@@ -7,14 +7,14 @@ namespace System.Globalization
77{
88 public sealed partial class IdnMapping
99 {
10- private unsafe string IcuGetAsciiCore ( string unicodeString , char * unicode , int count )
10+ private string IcuGetAsciiCore ( string unicodeString , int index , int count )
1111 {
1212 Debug . Assert ( ! GlobalizationMode . Invariant ) ;
1313 Debug . Assert ( ! GlobalizationMode . UseNls ) ;
14- Debug . Assert ( unicodeString != null && unicodeString . Length >= count ) ;
1514
15+ ReadOnlySpan < char > unicode = unicodeString . AsSpan ( index , count ) ;
1616 uint flags = IcuFlags ;
17- CheckInvalidIdnCharacters ( unicode , count , flags , nameof ( unicode ) ) ;
17+ CheckInvalidIdnCharacters ( unicode , flags , nameof ( unicode ) ) ;
1818
1919 const int StackallocThreshold = 512 ;
2020 // Each unicode character is represented by up to 3 ASCII chars
@@ -23,85 +23,126 @@ private unsafe string IcuGetAsciiCore(string unicodeString, char* unicode, int c
2323 int actualLength ;
2424 if ( ( uint ) estimatedLength < StackallocThreshold )
2525 {
26- char * outputStack = stackalloc char [ estimatedLength ] ;
26+ Span < char > outputStack = stackalloc char [ estimatedLength ] ;
2727 actualLength = Interop . Globalization . ToAscii ( flags , unicode , count , outputStack , estimatedLength ) ;
2828 if ( actualLength > 0 && actualLength <= estimatedLength )
2929 {
30- return GetStringForOutput ( unicodeString , unicode , count , outputStack , actualLength ) ;
30+ return GetStringForOutput ( unicodeString , unicode , outputStack . Slice ( 0 , actualLength ) ) ;
3131 }
3232 }
3333 else
3434 {
35- actualLength = Interop . Globalization . ToAscii ( flags , unicode , count , null , 0 ) ;
35+ actualLength = Interop . Globalization . ToAscii ( flags , unicode , count , Span < char > . Empty , 0 ) ;
3636 }
3737 if ( actualLength == 0 )
3838 {
3939 throw new ArgumentException ( SR . Argument_IdnIllegalName , nameof ( unicode ) ) ;
4040 }
4141
4242 char [ ] outputHeap = new char [ actualLength ] ;
43- fixed ( char * pOutputHeap = & outputHeap [ 0 ] )
43+ actualLength = Interop . Globalization . ToAscii ( flags , unicode , count , outputHeap , actualLength ) ;
44+ if ( actualLength == 0 || actualLength > outputHeap . Length )
4445 {
45- actualLength = Interop . Globalization . ToAscii ( flags , unicode , count , pOutputHeap , actualLength ) ;
46- if ( actualLength == 0 || actualLength > outputHeap . Length )
46+ throw new ArgumentException ( SR . Argument_IdnIllegalName , nameof ( unicode ) ) ;
47+ }
48+
49+ return GetStringForOutput ( unicodeString , unicode , outputHeap . AsSpan ( 0 , actualLength ) ) ;
50+ }
51+
52+ private bool IcuTryGetAsciiCore ( ReadOnlySpan < char > unicode , Span < char > destination , out int charsWritten )
53+ {
54+ Debug . Assert ( ! GlobalizationMode . Invariant ) ;
55+ Debug . Assert ( ! GlobalizationMode . UseNls ) ;
56+
57+ uint flags = IcuFlags ;
58+ CheckInvalidIdnCharacters ( unicode , flags , nameof ( unicode ) ) ;
59+
60+ int actualLength = Interop . Globalization . ToAscii ( flags , unicode , unicode . Length , destination , destination . Length ) ;
61+
62+ if ( actualLength <= destination . Length )
63+ {
64+ if ( actualLength == 0 )
4765 {
4866 throw new ArgumentException ( SR . Argument_IdnIllegalName , nameof ( unicode ) ) ;
4967 }
50- return GetStringForOutput ( unicodeString , unicode , count , pOutputHeap , actualLength ) ;
68+
69+ charsWritten = actualLength ;
70+ return true ;
5171 }
72+
73+ charsWritten = 0 ;
74+ return false ;
5275 }
5376
54- private unsafe string IcuGetUnicodeCore ( string asciiString , char * ascii , int count )
77+ private string IcuGetUnicodeCore ( string asciiString , int index , int count )
5578 {
5679 Debug . Assert ( ! GlobalizationMode . Invariant ) ;
5780 Debug . Assert ( ! GlobalizationMode . UseNls ) ;
58- Debug . Assert ( asciiString != null && asciiString . Length >= count ) ;
5981
82+ ReadOnlySpan < char > ascii = asciiString . AsSpan ( index , count ) ;
6083 uint flags = IcuFlags ;
61- CheckInvalidIdnCharacters ( ascii , count , flags , nameof ( ascii ) ) ;
84+ CheckInvalidIdnCharacters ( ascii , flags , nameof ( ascii ) ) ;
6285
6386 const int StackAllocThreshold = 512 ;
6487 if ( ( uint ) count < StackAllocThreshold )
6588 {
66- char * output = stackalloc char [ count ] ;
67- return IcuGetUnicodeCore ( asciiString , ascii , count , flags , output , count , reattempt : true ) ;
89+ Span < char > output = stackalloc char [ count ] ;
90+ return IcuGetUnicodeCore ( asciiString , ascii , flags , output , reattempt : true ) ;
6891 }
6992 else
7093 {
7194 char [ ] output = new char [ count ] ;
72- fixed ( char * pOutput = & output [ 0 ] )
73- {
74- return IcuGetUnicodeCore ( asciiString , ascii , count , flags , pOutput , count , reattempt : true ) ;
75- }
95+ return IcuGetUnicodeCore ( asciiString , ascii , flags , output , reattempt : true ) ;
7696 }
7797 }
7898
79- private unsafe string IcuGetUnicodeCore ( string asciiString , char * ascii , int count , uint flags , char * output , int outputLength , bool reattempt )
99+ private static string IcuGetUnicodeCore ( string asciiString , ReadOnlySpan < char > ascii , uint flags , Span < char > output , bool reattempt )
80100 {
81101 Debug . Assert ( ! GlobalizationMode . Invariant ) ;
82102 Debug . Assert ( ! GlobalizationMode . UseNls ) ;
83- Debug . Assert ( asciiString != null && asciiString . Length >= count ) ;
84103
85- int realLen = Interop . Globalization . ToUnicode ( flags , ascii , count , output , outputLength ) ;
104+ int realLen = Interop . Globalization . ToUnicode ( flags , ascii , ascii . Length , output , output . Length ) ;
86105
87106 if ( realLen == 0 )
88107 {
89108 throw new ArgumentException ( SR . Argument_IdnIllegalName , nameof ( ascii ) ) ;
90109 }
91- else if ( realLen <= outputLength )
110+ else if ( realLen <= output . Length )
92111 {
93- return GetStringForOutput ( asciiString , ascii , count , output , realLen ) ;
112+ return GetStringForOutput ( asciiString , ascii , output . Slice ( 0 , realLen ) ) ;
94113 }
95114 else if ( reattempt )
96115 {
97116 char [ ] newOutput = new char [ realLen ] ;
98- fixed ( char * pNewOutput = newOutput )
117+ return IcuGetUnicodeCore ( asciiString , ascii , flags , newOutput , reattempt : false ) ;
118+ }
119+
120+ throw new ArgumentException ( SR . Argument_IdnIllegalName , nameof ( ascii ) ) ;
121+ }
122+
123+ private bool IcuTryGetUnicodeCore ( ReadOnlySpan < char > ascii , Span < char > destination , out int charsWritten )
124+ {
125+ Debug . Assert ( ! GlobalizationMode . Invariant ) ;
126+ Debug . Assert ( ! GlobalizationMode . UseNls ) ;
127+
128+ uint flags = IcuFlags ;
129+ CheckInvalidIdnCharacters ( ascii , flags , nameof ( ascii ) ) ;
130+
131+ int actualLength = Interop . Globalization . ToUnicode ( flags , ascii , ascii . Length , destination , destination . Length ) ;
132+
133+ if ( actualLength <= destination . Length )
134+ {
135+ if ( actualLength == 0 )
99136 {
100- return IcuGetUnicodeCore ( asciiString , ascii , count , flags , pNewOutput , realLen , reattempt : false ) ;
137+ throw new ArgumentException ( SR . Argument_IdnIllegalName , nameof ( ascii ) ) ;
101138 }
139+
140+ charsWritten = actualLength ;
141+ return true ;
102142 }
103143
104- throw new ArgumentException ( SR . Argument_IdnIllegalName , nameof ( ascii ) ) ;
144+ charsWritten = 0 ;
145+ return false ;
105146 }
106147
107148 private uint IcuFlags
@@ -122,11 +163,11 @@ private uint IcuFlags
122163 /// To match Windows behavior, we walk the string ourselves looking for these
123164 /// bad characters so we can continue to throw ArgumentException in these cases.
124165 /// </summary>
125- private static unsafe void CheckInvalidIdnCharacters ( char * s , int count , uint flags , string paramName )
166+ private static void CheckInvalidIdnCharacters ( ReadOnlySpan < char > s , uint flags , string paramName )
126167 {
127168 if ( ( flags & Interop . Globalization . UseStd3AsciiRules ) == 0 )
128169 {
129- for ( int i = 0 ; i < count ; i ++ )
170+ for ( int i = 0 ; i < s . Length ; i ++ )
130171 {
131172 char c = s [ i ] ;
132173
0 commit comments