256 lines
10 KiB
C#
256 lines
10 KiB
C#
// ==++==
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//
|
|
// ==--==
|
|
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
|
|
[ResourceExposure(ResourceScope.None)] // Returns a pointer to a process-wide instance
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private unsafe static extern InternalEncodingDataItem *GetEncodingData();
|
|
|
|
//
|
|
// Return the number of encoding data items.
|
|
//
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)]
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private static extern int GetNumEncodingItems();
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.None)] // Returns a pointer to a process-wide instance
|
|
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
|
private unsafe static extern InternalCodePageDataItem* GetCodePageData();
|
|
|
|
[System.Security.SecurityCritical] // auto-generated
|
|
[ResourceExposure(ResourceScope.Machine)]
|
|
[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;
|
|
}
|
|
|
|
}
|