1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
9 using System.Globalization;
11 using System.Runtime.CompilerServices;
12 using System.Runtime.InteropServices;
13 using System.Runtime.Versioning;
14 using System.Diagnostics.Contracts;
16 // This is the enumeration for Normalization Forms
17 [System.Runtime.InteropServices.ComVisible(true)]
18 public enum NormalizationForm
20 #if !FEATURE_NORM_IDNA_ONLY
25 #endif // !FEATURE_NORM_IDNA_ONLY
28 internal enum ExtendedNormalizationForms
30 #if !FEATURE_NORM_IDNA_ONLY
35 #endif // !FEATURE_NORM_IDNA_ONLY
37 #if !FEATURE_NORM_IDNA_ONLY
38 FormCDisallowUnassigned = 0x101,
39 FormDDisallowUnassigned = 0x102,
40 FormKCDisallowUnassigned = 0x105,
41 FormKDDisallowUnassigned = 0x106,
42 #endif // !FEATURE_NORM_IDNA_ONLY
43 FormIdnaDisallowUnassigned = 0x10d
46 // This internal class wraps up our normalization behavior
48 internal class Normalization
51 // Flags that track whether given normalization form was initialized
53 #if !FEATURE_NORM_IDNA_ONLY
54 private static volatile bool NFC;
55 private static volatile bool NFD;
56 private static volatile bool NFKC;
57 private static volatile bool NFKD;
58 #endif // !FEATURE_NORM_IDNA_ONLY
59 private static volatile bool IDNA;
60 #if !FEATURE_NORM_IDNA_ONLY
61 private static volatile bool NFCDisallowUnassigned;
62 private static volatile bool NFDDisallowUnassigned;
63 private static volatile bool NFKCDisallowUnassigned;
64 private static volatile bool NFKDDisallowUnassigned;
65 #endif // !FEATURE_NORM_IDNA_ONLY
66 private static volatile bool IDNADisallowUnassigned;
67 private static volatile bool Other;
69 // These are error codes we get back from the Normalization DLL
70 private const int ERROR_SUCCESS = 0;
71 private const int ERROR_NOT_ENOUGH_MEMORY = 8;
72 private const int ERROR_INVALID_PARAMETER = 87;
73 private const int ERROR_INSUFFICIENT_BUFFER = 122;
74 private const int ERROR_NO_UNICODE_TRANSLATION = 1113;
76 [System.Security.SecurityCritical] // auto-generated
77 static private unsafe void InitializeForm(NormalizationForm form, String strDataFile)
79 #if FEATURE_COREFX_GLOBALIZATION
80 //TODO: Implement this fully. We might need a PAL here.
81 throw new NotImplementedException();
85 // Normalization uses OS on Win8
86 if (!Environment.IsWindows8OrAbove)
88 if (strDataFile == null)
90 // They were supposed to have a form that we know about!
91 throw new ArgumentException(
92 Environment.GetResourceString("Argument_InvalidNormalizationForm"));
95 // Tell the DLL where to find our data
96 pTables = GlobalizationAssembly.GetGlobalizationResourceBytePtr(
97 typeof(Normalization).Assembly, strDataFile);
100 // Unable to load the specified normalizationForm,
101 // tables not loaded from file
102 throw new ArgumentException(
103 Environment.GetResourceString("Argument_InvalidNormalizationForm"));
107 nativeNormalizationInitNormalization(form, pTables);
111 [System.Security.SecurityCritical] // auto-generated
112 static private void EnsureInitialized(NormalizationForm form)
114 switch ((ExtendedNormalizationForms)form)
116 #if !FEATURE_NORM_IDNA_ONLY
117 case ExtendedNormalizationForms.FormC:
119 InitializeForm(form, "normnfc.nlp");
123 case ExtendedNormalizationForms.FormD:
125 InitializeForm(form, "normnfd.nlp");
129 case ExtendedNormalizationForms.FormKC:
131 InitializeForm(form, "normnfkc.nlp");
135 case ExtendedNormalizationForms.FormKD:
137 InitializeForm(form, "normnfkd.nlp");
140 #endif // !FEATURE_NORM_IDNA_ONLY
142 case ExtendedNormalizationForms.FormIdna:
144 InitializeForm(form, "normidna.nlp");
148 #if !FEATURE_NORM_IDNA_ONLY
149 case ExtendedNormalizationForms.FormCDisallowUnassigned:
150 if (NFCDisallowUnassigned) return;
151 InitializeForm(form, "normnfc.nlp");
152 NFCDisallowUnassigned = true;
155 case ExtendedNormalizationForms.FormDDisallowUnassigned:
156 if (NFDDisallowUnassigned) return;
157 InitializeForm(form, "normnfd.nlp");
158 NFDDisallowUnassigned = true;
161 case ExtendedNormalizationForms.FormKCDisallowUnassigned:
162 if (NFKCDisallowUnassigned) return;
163 InitializeForm(form, "normnfkc.nlp");
164 NFKCDisallowUnassigned = true;
167 case ExtendedNormalizationForms.FormKDDisallowUnassigned:
168 if (NFKDDisallowUnassigned) return;
169 InitializeForm(form, "normnfkd.nlp");
170 NFKDDisallowUnassigned = true;
172 #endif // !FEATURE_NORM_IDNA_ONLY
174 case ExtendedNormalizationForms.FormIdnaDisallowUnassigned:
175 if (IDNADisallowUnassigned) return;
176 InitializeForm(form, "normidna.nlp");
177 IDNADisallowUnassigned = true;
182 InitializeForm(form, null);
188 [System.Security.SecurityCritical]
189 internal static bool IsNormalized(String strInput, NormalizationForm normForm)
191 Contract.Requires(strInput != null);
193 EnsureInitialized(normForm);
195 int iError = ERROR_SUCCESS;
196 bool result = nativeNormalizationIsNormalizedString(
204 // Success doesn't need to do anything
208 // Do appropriate stuff for the individual errors:
209 case ERROR_INVALID_PARAMETER:
210 case ERROR_NO_UNICODE_TRANSLATION:
211 throw new ArgumentException(
212 Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex" ),
214 case ERROR_NOT_ENOUGH_MEMORY:
215 throw new OutOfMemoryException(
216 Environment.GetResourceString("Arg_OutOfMemoryException"));
218 throw new InvalidOperationException(
219 Environment.GetResourceString("UnknownError_Num", iError));
225 [System.Security.SecurityCritical]
226 internal static String Normalize(String strInput, NormalizationForm normForm)
228 Contract.Requires(strInput != null);
230 EnsureInitialized(normForm);
232 int iError = ERROR_SUCCESS;
234 // Guess our buffer size first
235 int iLength = nativeNormalizationNormalizeString(normForm, ref iError, strInput, strInput.Length, null, 0);
237 // Could have an error (actually it'd be quite hard to have an error here)
238 if (iError != ERROR_SUCCESS)
240 if (iError == ERROR_INVALID_PARAMETER)
241 throw new ArgumentException(
242 Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex" ),
245 // We shouldn't really be able to get here..., guessing length is
246 // a trivial math function...
247 // Can't really be Out of Memory, but just in case:
248 if (iError == ERROR_NOT_ENOUGH_MEMORY)
249 throw new OutOfMemoryException(
250 Environment.GetResourceString("Arg_OutOfMemoryException"));
252 // Who knows what happened? Not us!
253 throw new InvalidOperationException(
254 Environment.GetResourceString("UnknownError_Num", iError));
257 // Don't break for empty strings (only possible for D & KD and not really possible at that)
258 if (iLength == 0) return String.Empty;
260 // Someplace to stick our buffer
261 char[] cBuffer = null;
265 // (re)allocation buffer and normalize string
266 cBuffer = new char[iLength];
268 iLength = nativeNormalizationNormalizeString(
276 if (iError == ERROR_SUCCESS)
279 // Could have an error (actually it'd be quite hard to have an error here)
282 // Do appropriate stuff for the individual errors:
283 case ERROR_INSUFFICIENT_BUFFER:
284 Contract.Assert(iLength > cBuffer.Length, "Buffer overflow should have iLength > cBuffer.Length");
287 case ERROR_INVALID_PARAMETER:
288 case ERROR_NO_UNICODE_TRANSLATION:
289 // Illegal code point or order found. Ie: FFFE or D800 D800, etc.
290 throw new ArgumentException(
291 Environment.GetResourceString("Argument_InvalidCharSequence", iLength ),
293 case ERROR_NOT_ENOUGH_MEMORY:
294 throw new OutOfMemoryException(
295 Environment.GetResourceString("Arg_OutOfMemoryException"));
298 // We shouldn't get here...
299 throw new InvalidOperationException(
300 Environment.GetResourceString("UnknownError_Num", iError));
304 // Copy our buffer into our new string, which will be the appropriate size
305 return new String(cBuffer, 0, iLength);
308 #if !FEATURE_COREFX_GLOBALIZATION
309 [System.Security.SecurityCritical] // auto-generated
310 [MethodImplAttribute(MethodImplOptions.InternalCall)]
311 unsafe private static extern int nativeNormalizationNormalizeString(
312 NormalizationForm normForm, ref int iError,
313 String lpSrcString, int cwSrcLength,
314 char[] lpDstString, int cwDstLength);
316 [System.Security.SecurityCritical] // auto-generated
317 [MethodImplAttribute(MethodImplOptions.InternalCall)]
318 unsafe private static extern bool nativeNormalizationIsNormalizedString(
319 NormalizationForm normForm, ref int iError,
320 String lpString, int cwLength);
322 [System.Security.SecurityCritical] // auto-generated
323 [SuppressUnmanagedCodeSecurity]
324 [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
325 unsafe private static extern void nativeNormalizationInitNormalization(
326 NormalizationForm normForm, byte* pTableData);
328 unsafe private static int nativeNormalizationNormalizeString(
329 NormalizationForm normForm, ref int iError,
330 String lpSrcString, int cwSrcLength,
331 char[] lpDstString, int cwDstLength)
333 throw new NotImplementedException();
336 unsafe private static bool nativeNormalizationIsNormalizedString(
337 NormalizationForm normForm, ref int iError,
338 String lpString, int cwLength)
340 throw new NotImplementedException();
343 unsafe private static void nativeNormalizationInitNormalization(
344 NormalizationForm normForm, byte* pTableData)
346 throw new NotImplementedException();