Fix copy&paste bug (#17059)
[platform/upstream/coreclr.git] / src / mscorlib / src / System / Globalization / EncodingTable.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 using System;
6 using System.Text;
7 using System.Collections;
8 using System.Collections.Generic;
9 using System.Runtime.CompilerServices;
10 using System.Runtime.InteropServices;
11 using System.Runtime.Versioning;
12 using System.Security;
13 using System.Threading;
14
15 namespace System.Globalization
16 {
17     //
18     // Data table for encoding classes.  Used by System.Text.Encoding.
19     // This class contains two hashtables to allow System.Text.Encoding
20     // to retrieve the data item either by codepage value or by webName.
21     //
22
23     // Only statics, does not need to be marked with the serializable attribute
24     internal static class EncodingTable
25     {
26         //This number is the size of the table in native.  The value is retrieved by
27         //calling the native GetNumEncodingItems().
28         private static int lastEncodingItem = GetNumEncodingItems() - 1;
29
30         //This number is the size of the code page table.  Its generated when we walk the table the first time.
31         private static volatile int lastCodePageItem;
32
33         //
34         // This points to a native data table which maps an encoding name to the correct code page.        
35         //
36         internal static unsafe InternalEncodingDataItem* encodingDataPtr = GetEncodingData();
37         //
38         // This points to a native data table which stores the properties for the code page, and
39         // the table is indexed by code page.
40         //
41         internal static unsafe InternalCodePageDataItem* codePageDataPtr = GetCodePageData();
42         //
43         // This caches the mapping of an encoding name to a code page.
44         //
45         private static Hashtable hashByName = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase));
46         //
47         // THe caches the data item which is indexed by the code page value.
48         //
49         private static Hashtable hashByCodePage = Hashtable.Synchronized(new Hashtable());
50
51         // Find the data item by binary searching the table that we have in native.
52         // nativeCompareOrdinalWC is an internal-only function.
53         private static unsafe int internalGetCodePageFromName(String name)
54         {
55             int left = 0;
56             int right = lastEncodingItem;
57             int index;
58             int result;
59
60             //Binary search the array until we have only a couple of elements left and then
61             //just walk those elements.
62             while ((right - left) > 3)
63             {
64                 index = ((right - left) / 2) + left;
65
66                 result = String.nativeCompareOrdinalIgnoreCaseWC(name, encodingDataPtr[index].webName);
67
68                 if (result == 0)
69                 {
70                     //We found the item, return the associated codepage.
71                     return (encodingDataPtr[index].codePage);
72                 }
73                 else if (result < 0)
74                 {
75                     //The name that we're looking for is less than our current index.
76                     right = index;
77                 }
78                 else
79                 {
80                     //The name that we're looking for is greater than our current index
81                     left = index;
82                 }
83             }
84
85             //Walk the remaining elements (it'll be 3 or fewer).
86             for (; left <= right; left++)
87             {
88                 if (String.nativeCompareOrdinalIgnoreCaseWC(name, encodingDataPtr[left].webName) == 0)
89                 {
90                     return (encodingDataPtr[left].codePage);
91                 }
92             }
93             // The encoding name is not valid.
94             throw new ArgumentException(
95                 String.Format(
96                     CultureInfo.CurrentCulture,
97                     SR.Argument_EncodingNotSupported, name), nameof(name));
98         }
99
100         // Return a list of all EncodingInfo objects describing all of our encodings
101         internal static unsafe EncodingInfo[] GetEncodings()
102         {
103             if (lastCodePageItem == 0)
104             {
105                 int count;
106                 for (count = 0; codePageDataPtr[count].codePage != 0; count++)
107                 {
108                     // Count them
109                 }
110                 lastCodePageItem = count;
111             }
112
113             EncodingInfo[] arrayEncodingInfo = new EncodingInfo[lastCodePageItem];
114
115             int i;
116             for (i = 0; i < lastCodePageItem; i++)
117             {
118                 arrayEncodingInfo[i] = new EncodingInfo(codePageDataPtr[i].codePage, CodePageDataItem.CreateString(codePageDataPtr[i].Names, 0),
119                     SR.GetResourceString("Globalization_cp_" + codePageDataPtr[i].codePage));
120             }
121
122             return arrayEncodingInfo;
123         }
124
125         /*=================================GetCodePageFromName==========================
126         **Action: Given a encoding name, return the correct code page number for this encoding.
127         **Returns: The code page for the encoding.
128         **Arguments:
129         **  name    the name of the encoding
130         **Exceptions:
131         **  ArgumentNullException if name is null.
132         **  internalGetCodePageFromName will throw ArgumentException if name is not a valid encoding name.
133         ============================================================================*/
134
135         internal static int GetCodePageFromName(String name)
136         {
137             if (name == null)
138             {
139                 throw new ArgumentNullException(nameof(name));
140             }
141
142             Object codePageObj;
143
144             //
145             // The name is case-insensitive, but ToLower isn't free.  Check for
146             // the code page in the given capitalization first.
147             //
148             codePageObj = hashByName[name];
149
150             if (codePageObj != null)
151             {
152                 return ((int)codePageObj);
153             }
154
155             //Okay, we didn't find it in the hash table, try looking it up in the 
156             //unmanaged data.
157             int codePage = internalGetCodePageFromName(name);
158
159             hashByName[name] = codePage;
160
161             return codePage;
162         }
163
164         internal static unsafe CodePageDataItem GetCodePageDataItem(int codepage)
165         {
166             CodePageDataItem dataItem;
167
168             // We synchronize around dictionary gets/sets. There's still a possibility that two threads
169             // will create a CodePageDataItem and the second will clobber the first in the dictionary. 
170             // However, that's acceptable because the contents are correct and we make no guarantees
171             // other than that. 
172
173             //Look up the item in the hashtable.
174             dataItem = (CodePageDataItem)hashByCodePage[codepage];
175
176             //If we found it, return it.
177             if (dataItem != null)
178             {
179                 return dataItem;
180             }
181
182
183             //If we didn't find it, try looking it up now.
184             //If we find it, add it to the hashtable.
185             //This is a linear search, but we probably won't be doing it very often.
186             //
187             int i = 0;
188             int data;
189             while ((data = codePageDataPtr[i].codePage) != 0)
190             {
191                 if (data == codepage)
192                 {
193                     dataItem = new CodePageDataItem(i);
194                     hashByCodePage[codepage] = dataItem;
195                     return (dataItem);
196                 }
197                 i++;
198             }
199
200             //Nope, we didn't find it.
201             return null;
202         }
203
204         [MethodImplAttribute(MethodImplOptions.InternalCall)]
205         private static extern unsafe InternalEncodingDataItem* GetEncodingData();
206
207         //
208         // Return the number of encoding data items.
209         //
210         [MethodImplAttribute(MethodImplOptions.InternalCall)]
211         private static extern int GetNumEncodingItems();
212
213         [MethodImplAttribute(MethodImplOptions.InternalCall)]
214         private static extern unsafe InternalCodePageDataItem* GetCodePageData();
215     }
216
217     /*=================================InternalEncodingDataItem==========================
218     **Action: This is used to map a encoding name to a correct code page number. By doing this,
219     ** we can get the properties of this encoding via the InternalCodePageDataItem.
220     **
221     ** We use this structure to access native data exposed by the native side.
222     ============================================================================*/
223
224     [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
225     internal unsafe struct InternalEncodingDataItem
226     {
227         internal sbyte* webName;
228         internal UInt16 codePage;
229     }
230
231     /*=================================InternalCodePageDataItem==========================
232     **Action: This is used to access the properties related to a code page.
233     ** We use this structure to access native data exposed by the native side.
234     ============================================================================*/
235
236     [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)]
237     internal unsafe struct InternalCodePageDataItem
238     {
239         internal UInt16 codePage;
240         internal UInt16 uiFamilyCodePage;
241         internal uint flags;
242         internal sbyte* Names;
243     }
244 }