summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Text/BaseCodePageEncoding.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Text/BaseCodePageEncoding.cs')
-rw-r--r--src/mscorlib/src/System/Text/BaseCodePageEncoding.cs350
1 files changed, 350 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Text/BaseCodePageEncoding.cs b/src/mscorlib/src/System/Text/BaseCodePageEncoding.cs
new file mode 100644
index 0000000000..4c9ca6eaaf
--- /dev/null
+++ b/src/mscorlib/src/System/Text/BaseCodePageEncoding.cs
@@ -0,0 +1,350 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#if FEATURE_CODEPAGES_FILE
+namespace System.Text
+{
+ using System;
+ using System.Diagnostics.Contracts;
+ using System.Globalization;
+ using System.Runtime.InteropServices;
+ using System.Security;
+ using System.Collections;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.Serialization;
+ using System.Runtime.Versioning;
+ using System.Security.Permissions;
+ using Microsoft.Win32.SafeHandles;
+
+ // Our input file data structures look like:
+ //
+ // Header Structure Looks Like:
+ // struct NLSPlusHeader
+ // {
+ // WORD[16] filename; // 32 bytes
+ // WORD[4] version; // 8 bytes = 40 // I.e: 3, 2, 0, 0
+ // WORD count; // 2 bytes = 42 // Number of code page index's that'll follow
+ // }
+ //
+ // Each code page section looks like:
+ // struct NLSCodePageIndex
+ // {
+ // WORD[16] codePageName; // 32 bytes
+ // WORD codePage; // +2 bytes = 34
+ // WORD byteCount; // +2 bytes = 36
+ // DWORD offset; // +4 bytes = 40 // Bytes from beginning of FILE.
+ // }
+ //
+ // Each code page then has its own header
+ // struct NLSCodePage
+ // {
+ // WORD[16] codePageName; // 32 bytes
+ // WORD[4] version; // 8 bytes = 40 // I.e: 3.2.0.0
+ // WORD codePage; // 2 bytes = 42
+ // WORD byteCount; // 2 bytes = 44 // 1 or 2 byte code page (SBCS or DBCS)
+ // WORD unicodeReplace; // 2 bytes = 46 // default replacement unicode character
+ // WORD byteReplace; // 2 bytes = 48 // default replacement byte(s)
+ // BYTE[] data; // data section
+ // }
+
+ [Serializable]
+ internal abstract class BaseCodePageEncoding : EncodingNLS, ISerializable
+ {
+ // Static & Const stuff
+ internal const String CODE_PAGE_DATA_FILE_NAME = "codepages.nlp";
+ [NonSerialized]
+ protected int dataTableCodePage;
+
+ // Variables to help us allocate/mark our memory section correctly
+ [NonSerialized]
+ protected bool bFlagDataTable = true;
+ [NonSerialized]
+ protected int iExtraBytes = 0;
+
+ // Our private unicode to bytes best fit array and visa versa.
+ [NonSerialized]
+ protected char[] arrayUnicodeBestFit = null;
+ [NonSerialized]
+ protected char[] arrayBytesBestFit = null;
+
+ // This is used to help ISCII, EUCJP and ISO2022 figure out they're MlangEncodings
+ [NonSerialized]
+ protected bool m_bUseMlangTypeForSerialization = false;
+
+ [System.Security.SecuritySafeCritical] // static constructors should be safe to call
+ static BaseCodePageEncoding()
+ {
+ }
+
+ //
+ // This is the header for the native data table that we load from CODE_PAGE_DATA_FILE_NAME.
+ //
+ // Explicit layout is used here since a syntax like char[16] can not be used in sequential layout.
+ [StructLayout(LayoutKind.Explicit)]
+ internal unsafe struct CodePageDataFileHeader
+ {
+ [FieldOffset(0)]
+ internal char TableName; // WORD[16]
+ [FieldOffset(0x20)]
+ internal ushort Version; // WORD[4]
+ [FieldOffset(0x28)]
+ internal short CodePageCount; // WORD
+ [FieldOffset(0x2A)]
+ internal short unused1; // Add a unused WORD so that CodePages is aligned with DWORD boundary.
+ // Otherwise, 64-bit version will fail.
+ [FieldOffset(0x2C)]
+ internal CodePageIndex CodePages; // Start of code page index
+ }
+
+ [StructLayout(LayoutKind.Explicit, Pack=2)]
+ internal unsafe struct CodePageIndex
+ {
+ [FieldOffset(0)]
+ internal char CodePageName; // WORD[16]
+ [FieldOffset(0x20)]
+ internal short CodePage; // WORD
+ [FieldOffset(0x22)]
+ internal short ByteCount; // WORD
+ [FieldOffset(0x24)]
+ internal int Offset; // DWORD
+ }
+
+ [StructLayout(LayoutKind.Explicit)]
+ internal unsafe struct CodePageHeader
+ {
+ [FieldOffset(0)]
+ internal char CodePageName; // WORD[16]
+ [FieldOffset(0x20)]
+ internal ushort VersionMajor; // WORD
+ [FieldOffset(0x22)]
+ internal ushort VersionMinor; // WORD
+ [FieldOffset(0x24)]
+ internal ushort VersionRevision;// WORD
+ [FieldOffset(0x26)]
+ internal ushort VersionBuild; // WORD
+ [FieldOffset(0x28)]
+ internal short CodePage; // WORD
+ [FieldOffset(0x2a)]
+ internal short ByteCount; // WORD // 1 or 2 byte code page (SBCS or DBCS)
+ [FieldOffset(0x2c)]
+ internal char UnicodeReplace; // WORD // default replacement unicode character
+ [FieldOffset(0x2e)]
+ internal ushort ByteReplace; // WORD // default replacement bytes
+ [FieldOffset(0x30)]
+ internal short FirstDataWord; // WORD[]
+ }
+
+ // Initialize our global stuff
+ [SecurityCritical]
+ unsafe static CodePageDataFileHeader* m_pCodePageFileHeader =
+ (CodePageDataFileHeader*)GlobalizationAssembly.GetGlobalizationResourceBytePtr(
+ typeof(CharUnicodeInfo).Assembly, CODE_PAGE_DATA_FILE_NAME);
+
+ // Real variables
+ [NonSerialized]
+ [SecurityCritical]
+ unsafe protected CodePageHeader* pCodePage = null;
+
+ // Safe handle wrapper around section map view
+ [System.Security.SecurityCritical] // auto-generated
+ [NonSerialized]
+ protected SafeViewOfFileHandle safeMemorySectionHandle = null;
+
+ // Safe handle wrapper around mapped file handle
+ [System.Security.SecurityCritical] // auto-generated
+ [NonSerialized]
+ protected SafeFileMappingHandle safeFileMappingHandle = null;
+
+ [System.Security.SecurityCritical] // auto-generated
+ internal BaseCodePageEncoding(int codepage) : this(codepage, codepage)
+ {
+ }
+
+ [System.Security.SecurityCritical] // auto-generated
+ internal BaseCodePageEncoding(int codepage, int dataCodePage) :
+ base(codepage == 0? Microsoft.Win32.Win32Native.GetACP(): codepage)
+ {
+ // Remember number of code page that we'll be using the table for.
+ dataTableCodePage = dataCodePage;
+ LoadCodePageTables();
+ }
+
+ // Constructor called by serialization.
+ [System.Security.SecurityCritical] // auto-generated
+ internal BaseCodePageEncoding(SerializationInfo info, StreamingContext context) : base(0)
+ {
+ // We cannot ever call this, we've proxied ourselved to CodePageEncoding
+ throw new ArgumentNullException("this");
+ }
+
+ // ISerializable implementation
+ [System.Security.SecurityCritical] // auto-generated_required
+ void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
+ {
+ // Make sure to get the base stuff too This throws if info is null
+ SerializeEncoding(info, context);
+ Contract.Assert(info!=null, "[BaseCodePageEncoding.GetObjectData] Expected null info to throw");
+
+ // Just need Everett maxCharSize (BaseCodePageEncoding) or m_maxByteSize (MLangBaseCodePageEncoding)
+ info.AddValue(m_bUseMlangTypeForSerialization ? "m_maxByteSize" : "maxCharSize",
+ this.IsSingleByte ? 1 : 2);
+
+ // Use this class or MLangBaseCodePageEncoding as our deserializer.
+ info.SetType(m_bUseMlangTypeForSerialization ? typeof(MLangCodePageEncoding) :
+ typeof(CodePageEncoding));
+ }
+
+ // We need to load tables for our code page
+ [System.Security.SecurityCritical] // auto-generated
+ private unsafe void LoadCodePageTables()
+ {
+ CodePageHeader* pCodePage = FindCodePage(dataTableCodePage);
+
+ // Make sure we have one
+ if (pCodePage == null)
+ {
+ // Didn't have one
+ throw new NotSupportedException(
+ Environment.GetResourceString("NotSupported_NoCodepageData", CodePage));
+ }
+
+ // Remember our code page
+ this.pCodePage = pCodePage;
+
+ // We had it, so load it
+ LoadManagedCodePage();
+ }
+
+ // Look up the code page pointer
+ [System.Security.SecurityCritical] // auto-generated
+ private static unsafe CodePageHeader* FindCodePage(int codePage)
+ {
+ // We'll have to loop through all of the m_pCodePageIndex[] items to find our code page, this isn't
+ // binary or anything so its not monsterously fast.
+ for (int i = 0; i < m_pCodePageFileHeader->CodePageCount; i++)
+ {
+ CodePageIndex* pCodePageIndex = (&(m_pCodePageFileHeader->CodePages)) + i;
+
+ if (pCodePageIndex->CodePage == codePage)
+ {
+ // Found it!
+ CodePageHeader* pCodePage =
+ (CodePageHeader*)((byte*)m_pCodePageFileHeader + pCodePageIndex->Offset);
+ return pCodePage;
+ }
+ }
+
+ // Couldn't find it
+ return null;
+ }
+
+ // Get our code page byte count
+ [System.Security.SecurityCritical] // auto-generated
+ internal static unsafe int GetCodePageByteSize(int codePage)
+ {
+ // Get our code page info
+ CodePageHeader* pCodePage = FindCodePage(codePage);
+
+ // If null return 0
+ if (pCodePage == null)
+ return 0;
+
+ Contract.Assert(pCodePage->ByteCount == 1 || pCodePage->ByteCount == 2,
+ "[BaseCodePageEncoding] Code page (" + codePage + ") has invalid byte size (" + pCodePage->ByteCount + ") in table");
+ // Return what it says for byte count
+ return pCodePage->ByteCount;
+ }
+
+ // We have a managed code page entry, so load our tables
+ [System.Security.SecurityCritical]
+ protected abstract unsafe void LoadManagedCodePage();
+
+ // Allocate memory to load our code page
+ [System.Security.SecurityCritical] // auto-generated
+ protected unsafe byte* GetSharedMemory(int iSize)
+ {
+ // Build our name
+ String strName = GetMemorySectionName();
+
+ IntPtr mappedFileHandle;
+
+ // This gets shared memory for our map. If its can't, it gives us clean memory.
+ Byte *pMemorySection = EncodingTable.nativeCreateOpenFileMapping(strName, iSize, out mappedFileHandle);
+ Contract.Assert(pMemorySection != null,
+ "[BaseCodePageEncoding.GetSharedMemory] Expected non-null memory section to be opened");
+
+ // If that failed, we have to die.
+ if (pMemorySection == null)
+ throw new OutOfMemoryException(
+ Environment.GetResourceString("Arg_OutOfMemoryException"));
+
+ // if we have null file handle. this means memory was allocated after
+ // failing to open the mapped file.
+
+ if (mappedFileHandle != IntPtr.Zero)
+ {
+ safeMemorySectionHandle = new SafeViewOfFileHandle((IntPtr) pMemorySection, true);
+ safeFileMappingHandle = new SafeFileMappingHandle(mappedFileHandle, true);
+ }
+
+ return pMemorySection;
+ }
+
+ [System.Security.SecurityCritical] // auto-generated
+ protected unsafe virtual String GetMemorySectionName()
+ {
+ int iUseCodePage = this.bFlagDataTable ? dataTableCodePage : CodePage;
+
+ String strName = String.Format(CultureInfo.InvariantCulture, "NLS_CodePage_{0}_{1}_{2}_{3}_{4}",
+ iUseCodePage, this.pCodePage->VersionMajor, this.pCodePage->VersionMinor,
+ this.pCodePage->VersionRevision, this.pCodePage->VersionBuild);
+
+ return strName;
+ }
+
+ [System.Security.SecurityCritical]
+ protected abstract unsafe void ReadBestFitTable();
+
+ [System.Security.SecuritySafeCritical]
+ internal override char[] GetBestFitUnicodeToBytesData()
+ {
+ // Read in our best fit table if necessary
+ if (arrayUnicodeBestFit == null) ReadBestFitTable();
+
+ Contract.Assert(arrayUnicodeBestFit != null,
+ "[BaseCodePageEncoding.GetBestFitUnicodeToBytesData]Expected non-null arrayUnicodeBestFit");
+
+ // Normally we don't have any best fit data.
+ return arrayUnicodeBestFit;
+ }
+
+ [System.Security.SecuritySafeCritical]
+ internal override char[] GetBestFitBytesToUnicodeData()
+ {
+ // Read in our best fit table if necessary
+ if (arrayBytesBestFit == null) ReadBestFitTable();
+
+ Contract.Assert(arrayBytesBestFit != null,
+ "[BaseCodePageEncoding.GetBestFitBytesToUnicodeData]Expected non-null arrayBytesBestFit");
+
+ // Normally we don't have any best fit data.
+ return arrayBytesBestFit;
+ }
+
+ // During the AppDomain shutdown the Encoding class may already finalized and the memory section
+ // is invalid. so we detect that by validating the memory section handle then re-initialize the memory
+ // section by calling LoadManagedCodePage() method and eventually the mapped file handle and
+ // the memory section pointer will get finalized one more time.
+ [System.Security.SecurityCritical] // auto-generated
+ internal unsafe void CheckMemorySection()
+ {
+ if (safeMemorySectionHandle != null && safeMemorySectionHandle.DangerousGetHandle() == IntPtr.Zero)
+ {
+ LoadManagedCodePage();
+ }
+ }
+ }
+}
+
+#endif // FEATURE_CODEPAGES_FILE