Expose missing Global/Encoding APIs in coreclr and remove empty stubs
[platform/upstream/coreclr.git] / src / mscorlib / src / System / Text / Normalization.cs
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.
4
5 namespace System.Text
6 {
7     using System;
8     using System.Security;
9     using System.Globalization;
10     using System.Text;
11     using System.Runtime.CompilerServices;
12     using System.Runtime.InteropServices;
13     using System.Runtime.Versioning;
14     using System.Diagnostics.Contracts;
15
16     // This is the enumeration for Normalization Forms
17 [System.Runtime.InteropServices.ComVisible(true)]
18     public enum NormalizationForm
19     {
20 #if !FEATURE_NORM_IDNA_ONLY     
21         FormC    = 1,
22         FormD    = 2,
23         FormKC   = 5,
24         FormKD   = 6
25 #endif // !FEATURE_NORM_IDNA_ONLY       
26     }
27
28     internal enum ExtendedNormalizationForms
29     {
30 #if !FEATURE_NORM_IDNA_ONLY     
31         FormC    = 1,
32         FormD    = 2,
33         FormKC   = 5,
34         FormKD   = 6,
35 #endif // !FEATURE_NORM_IDNA_ONLY        
36         FormIdna = 0xd,
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
44     }
45
46     // This internal class wraps up our normalization behavior
47
48     internal class Normalization
49     {
50         //
51         // Flags that track whether given normalization form was initialized
52         //
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;
68
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;
75
76         [System.Security.SecurityCritical]  // auto-generated
77         static private unsafe void InitializeForm(NormalizationForm form, String strDataFile)
78         {
79 #if FEATURE_COREFX_GLOBALIZATION
80             //TODO: Implement this fully.  We might need a PAL here.
81             throw new NotImplementedException();
82 #else
83             byte* pTables = null;
84
85             // Normalization uses OS on Win8
86             if (!Environment.IsWindows8OrAbove)
87             {
88                 if (strDataFile == null)
89                 {
90                     // They were supposed to have a form that we know about!
91                     throw new ArgumentException(
92                         Environment.GetResourceString("Argument_InvalidNormalizationForm"));
93                 }
94
95                 // Tell the DLL where to find our data
96                 pTables = GlobalizationAssembly.GetGlobalizationResourceBytePtr(
97                    typeof(Normalization).Assembly, strDataFile);
98                 if (pTables == null)
99                 {
100                     // Unable to load the specified normalizationForm,
101                     // tables not loaded from file
102                     throw new ArgumentException(
103                         Environment.GetResourceString("Argument_InvalidNormalizationForm"));
104                 }
105             }
106
107             nativeNormalizationInitNormalization(form, pTables);
108 #endif
109         }
110
111         [System.Security.SecurityCritical]  // auto-generated
112         static private void EnsureInitialized(NormalizationForm form)
113         {
114             switch ((ExtendedNormalizationForms)form)
115             {
116 #if !FEATURE_NORM_IDNA_ONLY
117                 case ExtendedNormalizationForms.FormC:
118                     if (NFC) return;
119                     InitializeForm(form, "normnfc.nlp");
120                     NFC = true;
121                     break;
122
123                 case ExtendedNormalizationForms.FormD:
124                     if (NFD) return;
125                     InitializeForm(form, "normnfd.nlp");
126                     NFD = true;
127                     break;
128
129                 case ExtendedNormalizationForms.FormKC:
130                     if (NFKC) return;
131                     InitializeForm(form, "normnfkc.nlp");
132                     NFKC = true;
133                     break;
134
135                 case ExtendedNormalizationForms.FormKD:
136                     if (NFKD) return;
137                     InitializeForm(form, "normnfkd.nlp");
138                     NFKD = true;
139                     break;
140 #endif // !FEATURE_NORM_IDNA_ONLY
141
142                 case ExtendedNormalizationForms.FormIdna:
143                     if (IDNA) return;
144                     InitializeForm(form, "normidna.nlp");
145                     IDNA = true;
146                     break;
147
148 #if !FEATURE_NORM_IDNA_ONLY
149                 case ExtendedNormalizationForms.FormCDisallowUnassigned:
150                     if (NFCDisallowUnassigned) return;
151                     InitializeForm(form, "normnfc.nlp");
152                     NFCDisallowUnassigned = true;
153                     break;
154
155                 case ExtendedNormalizationForms.FormDDisallowUnassigned:
156                     if (NFDDisallowUnassigned) return;
157                     InitializeForm(form, "normnfd.nlp");
158                     NFDDisallowUnassigned = true;
159                     break;
160
161                 case ExtendedNormalizationForms.FormKCDisallowUnassigned:
162                     if (NFKCDisallowUnassigned) return;
163                     InitializeForm(form, "normnfkc.nlp");
164                     NFKCDisallowUnassigned = true;
165                     break;
166
167                 case ExtendedNormalizationForms.FormKDDisallowUnassigned:
168                     if (NFKDDisallowUnassigned) return;
169                     InitializeForm(form, "normnfkd.nlp");
170                     NFKDDisallowUnassigned = true;
171                     break;
172 #endif // !FEATURE_NORM_IDNA_ONLY
173
174                 case ExtendedNormalizationForms.FormIdnaDisallowUnassigned:
175                     if (IDNADisallowUnassigned) return;
176                     InitializeForm(form, "normidna.nlp");
177                     IDNADisallowUnassigned = true;
178                     break;
179
180                 default:
181                     if (Other) return;
182                     InitializeForm(form, null);
183                     Other = true;
184                     break;
185             }
186         }
187
188         [System.Security.SecurityCritical]
189         internal static bool IsNormalized(String strInput, NormalizationForm normForm)
190         {
191             Contract.Requires(strInput != null);
192
193             EnsureInitialized(normForm);
194
195             int iError = ERROR_SUCCESS;
196             bool result = nativeNormalizationIsNormalizedString(
197                                 normForm, 
198                                 ref iError, 
199                                 strInput, 
200                                 strInput.Length);
201
202             switch(iError)
203             {
204                 // Success doesn't need to do anything
205                 case ERROR_SUCCESS:
206                     break;
207
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" ),
213                         "strInput");
214                 case ERROR_NOT_ENOUGH_MEMORY:
215                     throw new OutOfMemoryException(
216                         Environment.GetResourceString("Arg_OutOfMemoryException"));
217                 default:
218                     throw new InvalidOperationException(
219                         Environment.GetResourceString("UnknownError_Num", iError));
220             }
221
222             return result;
223         }
224
225         [System.Security.SecurityCritical]
226         internal static String Normalize(String strInput, NormalizationForm normForm)
227         {
228             Contract.Requires(strInput != null);
229
230             EnsureInitialized(normForm);
231
232             int iError = ERROR_SUCCESS;
233
234             // Guess our buffer size first
235             int iLength = nativeNormalizationNormalizeString(normForm, ref iError, strInput, strInput.Length, null, 0);
236
237             // Could have an error (actually it'd be quite hard to have an error here)
238             if (iError != ERROR_SUCCESS)
239             {
240                 if (iError == ERROR_INVALID_PARAMETER)
241                     throw new ArgumentException(
242                         Environment.GetResourceString("Argument_InvalidCharSequenceNoIndex" ),
243                         "strInput");
244
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"));
251
252                 // Who knows what happened?  Not us!
253                 throw new InvalidOperationException(
254                     Environment.GetResourceString("UnknownError_Num", iError));
255             }
256
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;
259
260             // Someplace to stick our buffer
261             char[] cBuffer = null;
262
263             for (;;)
264             {
265                 // (re)allocation buffer and normalize string
266                 cBuffer = new char[iLength];
267
268                 iLength = nativeNormalizationNormalizeString(
269                                     normForm, 
270                                     ref iError,
271                                     strInput, 
272                                     strInput.Length, 
273                                     cBuffer, 
274                                     cBuffer.Length);
275                 
276                 if (iError == ERROR_SUCCESS)
277                     break;
278
279                 // Could have an error (actually it'd be quite hard to have an error here)
280                 switch(iError)
281                 {
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");
285                         continue;
286
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 ),
292                             "strInput");
293                     case ERROR_NOT_ENOUGH_MEMORY:
294                         throw new OutOfMemoryException(
295                             Environment.GetResourceString("Arg_OutOfMemoryException"));
296
297                     default:
298                         // We shouldn't get here...
299                         throw new InvalidOperationException(
300                             Environment.GetResourceString("UnknownError_Num", iError));
301                 }
302             }
303
304             // Copy our buffer into our new string, which will be the appropriate size
305             return new String(cBuffer, 0, iLength);
306         }
307
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);
315
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);
321
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);
327 #else
328         unsafe private static int nativeNormalizationNormalizeString(
329             NormalizationForm normForm, ref int iError,
330             String lpSrcString, int cwSrcLength,
331             char[] lpDstString, int cwDstLength)
332         {
333             throw new NotImplementedException();
334         }
335
336         unsafe private static bool nativeNormalizationIsNormalizedString(
337             NormalizationForm normForm, ref int iError,
338             String lpString, int cwLength)
339         {
340             throw new NotImplementedException();
341         }
342
343         unsafe private static void nativeNormalizationInitNormalization(
344             NormalizationForm normForm, byte* pTableData)
345         {
346             throw new NotImplementedException();
347         }
348 #endif
349     }
350 }