@@ -10,31 +10,33 @@ namespace System.Globalization
10
10
{
11
11
internal static partial class Normalization
12
12
{
13
- private static unsafe bool IcuIsNormalized ( string strInput , NormalizationForm normalizationForm )
13
+ private static unsafe bool IcuIsNormalized ( ReadOnlySpan < char > source , NormalizationForm normalizationForm )
14
14
{
15
15
Debug . Assert ( ! GlobalizationMode . Invariant ) ;
16
16
Debug . Assert ( ! GlobalizationMode . UseNls ) ;
17
+ Debug . Assert ( ! source . IsEmpty ) ;
18
+ Debug . Assert ( normalizationForm is NormalizationForm . FormC or NormalizationForm . FormD or NormalizationForm . FormKC or NormalizationForm . FormKD ) ;
17
19
18
- ValidateArguments ( strInput , normalizationForm ) ;
20
+ ValidateArguments ( source , normalizationForm , nameof ( source ) ) ;
19
21
20
22
int ret ;
21
- fixed ( char * pInput = strInput )
23
+ fixed ( char * pInput = source )
22
24
{
23
25
#if TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
24
26
if ( GlobalizationMode . Hybrid )
25
27
{
26
- ret = Interop . Globalization . IsNormalizedNative ( normalizationForm , pInput , strInput . Length ) ;
28
+ ret = Interop . Globalization . IsNormalizedNative ( normalizationForm , pInput , source . Length ) ;
27
29
}
28
30
else
29
31
#endif
30
32
{
31
- ret = Interop . Globalization . IsNormalized ( normalizationForm , pInput , strInput . Length ) ;
33
+ ret = Interop . Globalization . IsNormalized ( normalizationForm , pInput , source . Length ) ;
32
34
}
33
35
}
34
36
35
37
if ( ret == - 1 )
36
38
{
37
- throw new ArgumentException ( SR . Argument_InvalidCharSequenceNoIndex , nameof ( strInput ) ) ;
39
+ throw new ArgumentException ( SR . Argument_InvalidCharSequenceNoIndex , nameof ( source ) ) ;
38
40
}
39
41
40
42
return ret == 1 ;
@@ -44,6 +46,7 @@ private static unsafe string IcuNormalize(string strInput, NormalizationForm nor
44
46
{
45
47
Debug . Assert ( ! GlobalizationMode . Invariant ) ;
46
48
Debug . Assert ( ! GlobalizationMode . UseNls ) ;
49
+ Debug . Assert ( normalizationForm == NormalizationForm . FormC || normalizationForm == NormalizationForm . FormD || normalizationForm == NormalizationForm . FormKC || normalizationForm == NormalizationForm . FormKD ) ;
47
50
48
51
ValidateArguments ( strInput , normalizationForm ) ;
49
52
@@ -114,25 +117,95 @@ private static unsafe string IcuNormalize(string strInput, NormalizationForm nor
114
117
}
115
118
}
116
119
117
- private static void ValidateArguments ( string strInput , NormalizationForm normalizationForm )
120
+ private static unsafe bool IcuTryNormalize ( ReadOnlySpan < char > source , Span < char > destination , out int charsWritten , NormalizationForm normalizationForm = NormalizationForm . FormC )
118
121
{
119
- Debug . Assert ( strInput != null ) ;
122
+ Debug . Assert ( ! GlobalizationMode . Invariant ) ;
123
+ Debug . Assert ( ! GlobalizationMode . UseNls ) ;
124
+ Debug . Assert ( ! source . IsEmpty ) ;
125
+ Debug . Assert ( normalizationForm == NormalizationForm . FormC || normalizationForm == NormalizationForm . FormD || normalizationForm == NormalizationForm . FormKC || normalizationForm == NormalizationForm . FormKD ) ;
120
126
121
- if ( ( OperatingSystem . IsBrowser ( ) || OperatingSystem . IsWasi ( ) ) && ( normalizationForm == NormalizationForm . FormKC || normalizationForm == NormalizationForm . FormKD ) )
127
+ if ( destination . IsEmpty )
122
128
{
123
- // Browser's ICU doesn't contain data needed for FormKC and FormKD
124
- throw new PlatformNotSupportedException ( ) ;
129
+ charsWritten = 0 ;
130
+ return false ;
131
+ }
132
+
133
+ ValidateArguments ( source , normalizationForm , nameof ( source ) ) ;
134
+
135
+ int realLen ;
136
+ fixed ( char * pInput = source )
137
+ fixed ( char * pDest = destination )
138
+ {
139
+ #if TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
140
+ if ( GlobalizationMode . Hybrid )
141
+ {
142
+ realLen = Interop . Globalization . NormalizeStringNative ( normalizationForm , pInput , source . Length , pDest , destination . Length ) ;
143
+ }
144
+ else
145
+ #endif
146
+ {
147
+ realLen = Interop . Globalization . NormalizeString ( normalizationForm , pInput , source . Length , pDest , destination . Length ) ;
148
+ }
149
+ }
150
+
151
+ if ( realLen < 0 )
152
+ {
153
+ throw new ArgumentException ( SR . Argument_InvalidCharSequenceNoIndex , nameof ( source ) ) ;
154
+ }
155
+
156
+ if ( realLen <= destination . Length )
157
+ {
158
+ charsWritten = realLen ;
159
+ return true ;
160
+ }
161
+
162
+ charsWritten = 0 ;
163
+ return false ;
164
+ }
165
+
166
+ private static unsafe int IcuGetNormalizedLength ( ReadOnlySpan < char > source , NormalizationForm normalizationForm )
167
+ {
168
+ Debug . Assert ( ! GlobalizationMode . Invariant ) ;
169
+ Debug . Assert ( ! GlobalizationMode . UseNls ) ;
170
+ Debug . Assert ( ! source . IsEmpty ) ;
171
+ Debug . Assert ( normalizationForm == NormalizationForm . FormC || normalizationForm == NormalizationForm . FormD || normalizationForm == NormalizationForm . FormKC || normalizationForm == NormalizationForm . FormKD ) ;
172
+
173
+ ValidateArguments ( source , normalizationForm , nameof ( source ) ) ;
174
+
175
+ int realLen ;
176
+ fixed ( char * pInput = source )
177
+ {
178
+ #if TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
179
+ if ( GlobalizationMode . Hybrid )
180
+ {
181
+ realLen = Interop . Globalization . NormalizeStringNative ( normalizationForm , pInput , source . Length , null , 0 ) ;
182
+ }
183
+ else
184
+ #endif
185
+ {
186
+ realLen = Interop . Globalization . NormalizeString ( normalizationForm , pInput , source . Length , null , 0 ) ;
187
+ }
188
+ }
189
+
190
+ if ( realLen < 0 )
191
+ {
192
+ throw new ArgumentException ( SR . Argument_InvalidCharSequenceNoIndex , nameof ( source ) ) ;
125
193
}
126
194
127
- if ( normalizationForm != NormalizationForm . FormC && normalizationForm != NormalizationForm . FormD &&
128
- normalizationForm != NormalizationForm . FormKC && normalizationForm != NormalizationForm . FormKD )
195
+ return realLen ;
196
+ }
197
+
198
+ private static void ValidateArguments ( ReadOnlySpan < char > strInput , NormalizationForm normalizationForm , string paramName = "strInput" )
199
+ {
200
+ if ( ( OperatingSystem . IsBrowser ( ) || OperatingSystem . IsWasi ( ) ) && ( normalizationForm == NormalizationForm . FormKC || normalizationForm == NormalizationForm . FormKD ) )
129
201
{
130
- throw new ArgumentException ( SR . Argument_InvalidNormalizationForm , nameof ( normalizationForm ) ) ;
202
+ // Browser's ICU doesn't contain data needed for FormKC and FormKD
203
+ throw new PlatformNotSupportedException ( SR . Argument_UnsupportedNormalizationFormInBrowser ) ;
131
204
}
132
205
133
206
if ( HasInvalidUnicodeSequence ( strInput ) )
134
207
{
135
- throw new ArgumentException ( SR . Argument_InvalidCharSequenceNoIndex , nameof ( strInput ) ) ;
208
+ throw new ArgumentException ( SR . Argument_InvalidCharSequenceNoIndex , paramName ) ;
136
209
}
137
210
}
138
211
@@ -143,7 +216,7 @@ private static void ValidateArguments(string strInput, NormalizationForm normali
143
216
/// We walk the string ourselves looking for these bad sequences so we can continue to throw
144
217
/// ArgumentException in these cases.
145
218
/// </summary>
146
- private static bool HasInvalidUnicodeSequence ( string s )
219
+ private static bool HasInvalidUnicodeSequence ( ReadOnlySpan < char > s )
147
220
{
148
221
for ( int i = 0 ; i < s . Length ; i ++ )
149
222
{
0 commit comments