diff options
Diffstat (limited to 'src/mscorlib/src/System/Globalization/EncodingTable.cs')
-rw-r--r-- | src/mscorlib/src/System/Globalization/EncodingTable.cs | 249 |
1 files changed, 249 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Globalization/EncodingTable.cs b/src/mscorlib/src/System/Globalization/EncodingTable.cs new file mode 100644 index 0000000000..2a553c19b3 --- /dev/null +++ b/src/mscorlib/src/System/Globalization/EncodingTable.cs @@ -0,0 +1,249 @@ +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace System.Globalization +{ + using System; + using System.Text; + using System.Collections; + using System.Collections.Generic; + using System.Runtime.CompilerServices; + using System.Runtime.InteropServices; + using System.Runtime.Versioning; + using System.Security; + using System.Threading; + using System.Diagnostics.Contracts; + // + // Data table for encoding classes. Used by System.Text.Encoding. + // This class contains two hashtables to allow System.Text.Encoding + // to retrieve the data item either by codepage value or by webName. + // + + // Only statics, does not need to be marked with the serializable attribute + internal static class EncodingTable + { + + //This number is the size of the table in native. The value is retrieved by + //calling the native GetNumEncodingItems(). + private static int lastEncodingItem = GetNumEncodingItems() - 1; + + //This number is the size of the code page table. Its generated when we walk the table the first time. + private static volatile int lastCodePageItem; + + // + // This points to a native data table which maps an encoding name to the correct code page. + // + [SecurityCritical] + unsafe internal static InternalEncodingDataItem *encodingDataPtr = GetEncodingData(); + // + // This points to a native data table which stores the properties for the code page, and + // the table is indexed by code page. + // + [SecurityCritical] + unsafe internal static InternalCodePageDataItem *codePageDataPtr = GetCodePageData(); + // + // This caches the mapping of an encoding name to a code page. + // + private static Hashtable hashByName = Hashtable.Synchronized(new Hashtable(StringComparer.OrdinalIgnoreCase)); + // + // THe caches the data item which is indexed by the code page value. + // + private static Hashtable hashByCodePage = Hashtable.Synchronized(new Hashtable()); + + [System.Security.SecuritySafeCritical] // static constructors should be safe to call + static EncodingTable() + { + } + + // Find the data item by binary searching the table that we have in native. + // nativeCompareOrdinalWC is an internal-only function. + [System.Security.SecuritySafeCritical] // auto-generated + unsafe private static int internalGetCodePageFromName(String name) { + int left = 0; + int right = lastEncodingItem; + int index; + int result; + + //Binary search the array until we have only a couple of elements left and then + //just walk those elements. + while ((right - left)>3) { + index = ((right - left)/2) + left; + + result = String.nativeCompareOrdinalIgnoreCaseWC(name, encodingDataPtr[index].webName); + + if (result == 0) { + //We found the item, return the associated codepage. + return (encodingDataPtr[index].codePage); + } else if (result<0) { + //The name that we're looking for is less than our current index. + right = index; + } else { + //The name that we're looking for is greater than our current index + left = index; + } + } + + //Walk the remaining elements (it'll be 3 or fewer). + for (; left<=right; left++) { + if (String.nativeCompareOrdinalIgnoreCaseWC(name, encodingDataPtr[left].webName) == 0) { + return (encodingDataPtr[left].codePage); + } + } + // The encoding name is not valid. + throw new ArgumentException( + String.Format( + CultureInfo.CurrentCulture, + Environment.GetResourceString("Argument_EncodingNotSupported"), name), "name"); + } + + // Return a list of all EncodingInfo objects describing all of our encodings + [System.Security.SecuritySafeCritical] // auto-generated + internal static unsafe EncodingInfo[] GetEncodings() + { + if (lastCodePageItem == 0) + { + int count; + for (count = 0; codePageDataPtr[count].codePage != 0; count++) + { + // Count them + } + lastCodePageItem = count; + } + + EncodingInfo[] arrayEncodingInfo = new EncodingInfo[lastCodePageItem]; + + int i; + for (i = 0; i < lastCodePageItem; i++) + { + arrayEncodingInfo[i] = new EncodingInfo(codePageDataPtr[i].codePage, CodePageDataItem.CreateString(codePageDataPtr[i].Names, 0), + Environment.GetResourceString("Globalization.cp_" + codePageDataPtr[i].codePage)); + } + + return arrayEncodingInfo; + } + + /*=================================GetCodePageFromName========================== + **Action: Given a encoding name, return the correct code page number for this encoding. + **Returns: The code page for the encoding. + **Arguments: + ** name the name of the encoding + **Exceptions: + ** ArgumentNullException if name is null. + ** internalGetCodePageFromName will throw ArgumentException if name is not a valid encoding name. + ============================================================================*/ + + internal static int GetCodePageFromName(String name) + { + if (name==null) { + throw new ArgumentNullException("name"); + } + Contract.EndContractBlock(); + + Object codePageObj; + + // + // The name is case-insensitive, but ToLower isn't free. Check for + // the code page in the given capitalization first. + // + codePageObj = hashByName[name]; + + if (codePageObj!=null) { + return ((int)codePageObj); + } + + //Okay, we didn't find it in the hash table, try looking it up in the + //unmanaged data. + int codePage = internalGetCodePageFromName(name); + + hashByName[name] = codePage; + + return codePage; + } + + [System.Security.SecuritySafeCritical] // auto-generated + unsafe internal static CodePageDataItem GetCodePageDataItem(int codepage) { + CodePageDataItem dataItem; + + // We synchronize around dictionary gets/sets. There's still a possibility that two threads + // will create a CodePageDataItem and the second will clobber the first in the dictionary. + // However, that's acceptable because the contents are correct and we make no guarantees + // other than that. + + //Look up the item in the hashtable. + dataItem = (CodePageDataItem)hashByCodePage[codepage]; + + //If we found it, return it. + if (dataItem!=null) { + return dataItem; + } + + + //If we didn't find it, try looking it up now. + //If we find it, add it to the hashtable. + //This is a linear search, but we probably won't be doing it very often. + // + int i = 0; + int data; + while ((data = codePageDataPtr[i].codePage) != 0) { + if (data == codepage) { + dataItem = new CodePageDataItem(i); + hashByCodePage[codepage] = dataItem; + return (dataItem); + } + i++; + } + + //Nope, we didn't find it. + return null; + } + + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private unsafe static extern InternalEncodingDataItem *GetEncodingData(); + + // + // Return the number of encoding data items. + // + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private static extern int GetNumEncodingItems(); + + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + private unsafe static extern InternalCodePageDataItem* GetCodePageData(); + + [System.Security.SecurityCritical] // auto-generated + [MethodImplAttribute(MethodImplOptions.InternalCall)] + internal unsafe static extern byte* nativeCreateOpenFileMapping( + String inSectionName, int inBytesToAllocate, out IntPtr mappedFileHandle); + } + + /*=================================InternalEncodingDataItem========================== + **Action: This is used to map a encoding name to a correct code page number. By doing this, + ** we can get the properties of this encoding via the InternalCodePageDataItem. + ** + ** We use this structure to access native data exposed by the native side. + ============================================================================*/ + + [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)] + internal unsafe struct InternalEncodingDataItem { + [SecurityCritical] + internal sbyte * webName; + internal UInt16 codePage; + } + + /*=================================InternalCodePageDataItem========================== + **Action: This is used to access the properties related to a code page. + ** We use this structure to access native data exposed by the native side. + ============================================================================*/ + + [System.Runtime.InteropServices.StructLayout(LayoutKind.Sequential)] + internal unsafe struct InternalCodePageDataItem { + internal UInt16 codePage; + internal UInt16 uiFamilyCodePage; + internal uint flags; + [SecurityCritical] + internal sbyte * Names; + } + +} |