The Labs \ Source Viewer \ SSCLI \ System.Globalization \ ExceptionTableItem

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. ////////////////////////////////////////////////////////////////////////////
  16. //
  17. // Class: TextInfo
  18. //
  19. // Purpose: This Class defines behaviors specific to a writing system.
  20. // A writing system is the collection of scripts and
  21. // orthographic rules required to represent a language as text.
  22. //
  23. // Date: March 31, 1999
  24. //
  25. ////////////////////////////////////////////////////////////////////////////
  26. namespace System.Globalization
  27. {
  28.     using System;
  29.     using System.Text;
  30.     using System.Threading;
  31.     using System.Runtime.InteropServices;
  32.     using System.Runtime.CompilerServices;
  33.     using System.Runtime.Serialization;
  34.     using System.Security.Permissions;
  35.    
  36.    
  37.     [Serializable()]
  38.     [System.Runtime.InteropServices.ComVisible(true)]
  39.     public class TextInfo : ICloneable, IDeserializationCallback
  40.     {
  41.         //--------------------------------------------------------------------//
  42.         // Internal Information //
  43.         //--------------------------------------------------------------------//
  44.        
  45.        
  46.         //
  47.         // Variables.
  48.         //
  49.        
  50.         [OptionalField(VersionAdded = 2)]
  51.         private string m_listSeparator;
  52.        
  53.         [OptionalField(VersionAdded = 2)]
  54.         private bool m_isReadOnly = false;
  55.        
  56.         //
  57.         // Basically, this is the language ID (LANGID) used to call Win32 NLS APIs except that
  58.         // the value can be zero for the invariant culture.
  59.         // The reason for this data member to exist is that Win32 APIs
  60.         // doesn't take all of the culture IDs supported in NLS+.
  61.         // For example, NLS+ support culture IDs like 0x0000, 0x0009.
  62.         // However, these are not valid locale IDs in Win32. Therefore,
  63.         // we use a table to map a culutre ID like
  64.         // 0x0009 to 0x0409.
  65.         //
  66.        
  67.         // m_textInfoID should be either 0 or a supported language ID. See TextInfo(m_textInfoID)
  68.         // for comments.
  69.         [NonSerialized()]
  70.         private int m_textInfoID;
  71.         [NonSerialized()]
  72.         private string m_name = null;
  73.         [NonSerialized()]
  74.         private CultureTableRecord m_cultureTableRecord;
  75.         [NonSerialized()]
  76.         private TextInfo m_casingTextInfo;
  77.        
  78.         //
  79.         // m_pNativeTextInfo is a 32-bit pointer value pointing to a native C++ NativeTextInfo object.
  80.         // The C++ NativeTextInfo is providing the implemenation of uppercasing/lowercasing.
  81.         //
  82.         // Note: m_pNativeTextInfo is intialized with invariant in case of synthetic cultuers
  83.         [NonSerialized()]
  84.         unsafe private void* m_pNativeTextInfo;
  85.         unsafe private static void* m_pInvariantNativeTextInfo;
  86.         unsafe private static void* m_pDefaultCasingTable;
  87.        
  88.         // This file contains the default casing data (uppercasing/lowercasing/titlecasing), and the table to
  89.         // map cultures with exceptions to an exception sub-table in CASING_EXCEPTIONS_FILE_NAME.
  90.         private const string CASING_FILE_NAME = "l_intl.nlp";
  91.         // This file contains the casing data for cultures with exceptions.
  92.         private const string CASING_EXCEPTIONS_FILE_NAME = "l_except.nlp";
  93.        
  94.         //
  95.         // This is the header for the native data table that we load from charinfo.nlp.
  96.         //
  97.         [StructLayout(LayoutKind.Explicit)]
  98.         unsafe internal struct TextInfoDataHeader
  99.         {
  100.             [FieldOffset(0)]
  101.             internal char TableName;
  102.             // WCHAR[16]
  103.             [FieldOffset(32)]
  104.             internal ushort version;
  105.             // WORD[4]
  106.             [FieldOffset(40)]
  107.             internal uint OffsetToUpperCasingTable;
  108.             // DWORD
  109.             [FieldOffset(44)]
  110.             internal uint OffsetToLowerCasingTable;
  111.             // DWORD
  112.             [FieldOffset(48)]
  113.             internal uint OffsetToTitleCaseTable;
  114.             // DWORD
  115.             [FieldOffset(52)]
  116.             internal uint PlaneOffset;
  117.             // Each plane has DWORD offset for uppercase and DWORD offset for lowercase.
  118.             // 0xb4 = 0x34 + 8*16
  119.             [FieldOffset(180)]
  120.             internal ushort exceptionCount;
  121.             [FieldOffset(182)]
  122.             internal ushort exceptionLangId;
  123.         }
  124.        
  125.         [StructLayout(LayoutKind.Sequential, Pack = 2)]
  126.         internal struct ExceptionTableItem
  127.         {
  128.             internal ushort langID;
  129.             // The lcid that contains the exceptions.
  130.             internal ushort exceptIndex;
  131.             // The name of the exception tables.
  132.         }
  133.        
  134.        
  135.         // The base pointer of the defult casing table
  136.         unsafe static byte* m_pDataTable;
  137.         // The total count of cultures with exceptions.
  138.         static int m_exceptionCount;
  139.         // The pointer to the exception index table. This table maps a culture with exceptions
  140.         // to a sub-table in the exception data table.
  141.         unsafe static ExceptionTableItem* m_exceptionTable;
  142.        
  143.         // The base pointer for exception data file.
  144.         unsafe static byte* m_pExceptionFile;
  145.         // This array caches the native pointer of the NativeTextInfo get by calling InternalAllocateCasingTable.
  146.        
  147.         // NOTE: use long to hold native pointers.
  148.         //static unsafe void*[] m_exceptionNativeTextInfo;
  149.         unsafe static long[] m_exceptionNativeTextInfo;
  150.        
  151.         ////////////////////////////////////////////////////////////////////////
  152.         //
  153.         // Actions:
  154.         // This is the static ctor for TextInfo. It does the following items:
  155.         // * Get the total count of cultures with exceptions.
  156.         // * Set up an exception index table so that we can check if a culture has exception. If yes, which sub-table
  157.         // in the exception table file we should use for this culture.
  158.         // * Set up a cache for NativeTextInfo that we create for cultures with exceptions.
  159.         //
  160.         ////////////////////////////////////////////////////////////////////////
  161.        
  162.         unsafe static TextInfo()
  163.         {
  164.             //with AppDomains active, the static initializer is no longer good enough to ensure that only one
  165.             //thread is ever in AllocateDefaultCasingTable at a given time.
  166.             //We use InterlockedExchangePointer in the native side to ensure that only one instance of native CasingTable instance
  167.             //is created per process.
  168.            
  169.             //We check if the table is already allocated in native, so we only need to synchronize
  170.             //access in managed.
  171.             byte* temp = GlobalizationAssembly.GetGlobalizationResourceBytePtr(typeof(TextInfo).Assembly, CASING_FILE_NAME);
  172.             System.Threading.Thread.MemoryBarrier();
  173.             m_pDataTable = temp;
  174.            
  175.             TextInfoDataHeader* pHeader = (TextInfoDataHeader*)m_pDataTable;
  176.             m_exceptionCount = pHeader->exceptionCount;
  177.             // Setup exception tables
  178.             m_exceptionTable = (ExceptionTableItem*)&(pHeader->exceptionLangId);
  179.             m_exceptionNativeTextInfo = new long[m_exceptionCount];
  180.            
  181.             // Create the native NativeTextInfo for the default linguistic casing table.
  182.             m_pDefaultCasingTable = AllocateDefaultCasingTable(m_pDataTable);
  183.            
  184.             BCLDebug.Assert(m_pDataTable != null, "Error in reading the table.");
  185.             BCLDebug.Assert(m_pDefaultCasingTable != null, "m_pDefaultCasingTable != null");
  186.         }
  187.        
  188.         // Private object for locking instead of locking on a public type for SQL reliability work.
  189.         private static object s_InternalSyncObject;
  190.         private static object InternalSyncObject {
  191.             get {
  192.                 if (s_InternalSyncObject == null) {
  193.                     object o = new object();
  194.                     Interlocked.CompareExchange(ref s_InternalSyncObject, o, null);
  195.                 }
  196.                 return s_InternalSyncObject;
  197.             }
  198.         }
  199.        
  200.         ////////////////////////////////////////////////////////////////////////
  201.         //
  202.         // TextInfo Constructors
  203.         //
  204.         // Implements CultureInfo.TextInfo.
  205.         //
  206.         ////////////////////////////////////////////////////////////////////////
  207.         unsafe internal TextInfo(CultureTableRecord table)
  208.         {
  209.             this.m_cultureTableRecord = table;
  210.             this.m_textInfoID = this.m_cultureTableRecord.ITEXTINFO;
  211.            
  212.             if (table.IsSynthetic) {
  213.                 // <SyntheticSupport/>
  214.                 //
  215.                 // we just initialize m_pNativeTextInfo with variant to make the synthetic TextInfo works when
  216.                 // GetCaseInsensitiveHashCode and ChangeCaseSurrogate get called. otherwise m_pNativeTextInfo
  217.                 // is not used at all in TextInfo with synthetic cultures.
  218.                 //
  219.                 m_pNativeTextInfo = InvariantNativeTextInfo;
  220.             }
  221.             else {
  222.                 this.m_pNativeTextInfo = GetNativeTextInfo(this.m_textInfoID);
  223.             }
  224.         }
  225.        
  226.        
  227.         ////////////////////////////////////////////////////////////////////////
  228.         //
  229.         // Return the native TextInfo instance for the invariant culture.
  230.         //
  231.         ////////////////////////////////////////////////////////////////////////
  232.        
  233.         unsafe static internal void* InvariantNativeTextInfo {
  234.             get {
  235.                 if (m_pInvariantNativeTextInfo == null) {
  236.                     lock (InternalSyncObject) {
  237.                         if (m_pInvariantNativeTextInfo == null) {
  238.                             m_pInvariantNativeTextInfo = GetNativeTextInfo(CultureInfo.LOCALE_INVARIANT);
  239.                         }
  240.                     }
  241.                 }
  242.                 BCLDebug.Assert(m_pInvariantNativeTextInfo != null, "TextInfo.InvariantNativeTextInfo: m_pInvariantNativeTextInfo != null");
  243.                 return (m_pInvariantNativeTextInfo);
  244.             }
  245.         }
  246.        
  247.         #region Serialization
  248.         // The following field is used only for the supplemental custom culture serialization to remember
  249.         // the name of the custom culture so we can reconstruct the text info properly during the deserialization.
  250.        
  251.         [OptionalField(VersionAdded = 2)]
  252.         private string customCultureName;
  253.        
  254.        
  255.         internal int m_nDataItem;
  256.         internal bool m_useUserOverride;
  257.         internal int m_win32LangID;
  258.        
  259.        
  260.         [OnDeserializing()]
  261.         private void OnDeserializing(StreamingContext ctx)
  262.         {
  263.             m_cultureTableRecord = null;
  264.             m_win32LangID = 0;
  265.         }
  266.        
  267.         unsafe private void OnDeserialized()
  268.         {
  269.             // this method will be called twice because of the support of IDeserializationCallback
  270.             if (m_cultureTableRecord == null) {
  271.                 if (m_win32LangID == 0) {
  272.                     m_win32LangID = CultureTableRecord.IdFromEverettDataItem(m_nDataItem);
  273.                 }
  274.                
  275.                 if (customCultureName != null) {
  276.                     m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(customCultureName, m_useUserOverride);
  277.                 }
  278.                 else {
  279.                     m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(m_win32LangID, m_useUserOverride);
  280.                 }
  281.                
  282.                 m_textInfoID = m_cultureTableRecord.ITEXTINFO;
  283.                
  284.                 if (m_cultureTableRecord.IsSynthetic) {
  285.                     // <SyntheticSupport/>
  286.                     m_pNativeTextInfo = InvariantNativeTextInfo;
  287.                 }
  288.                 else {
  289.                     m_pNativeTextInfo = GetNativeTextInfo(m_textInfoID);
  290.                 }
  291.             }
  292.         }
  293.        
  294.        
  295.         [OnDeserialized()]
  296.         private void OnDeserialized(StreamingContext ctx)
  297.         {
  298.             OnDeserialized();
  299.         }
  300.        
  301.         [OnSerializing()]
  302.         private void OnSerializing(StreamingContext ctx)
  303.         {
  304.             m_nDataItem = m_cultureTableRecord.EverettDataItem();
  305.             m_useUserOverride = m_cultureTableRecord.UseUserOverride;
  306.            
  307.             if (CultureTableRecord.IsCustomCultureId(m_cultureTableRecord.CultureID)) {
  308.                 customCultureName = m_cultureTableRecord.SNAME;
  309.                 m_win32LangID = m_textInfoID;
  310.             }
  311.             else {
  312.                 customCultureName = null;
  313.                 m_win32LangID = m_cultureTableRecord.CultureID;
  314.             }
  315.            
  316.         }
  317.        
  318.         #endregion Serialization
  319.        
  320.        
  321.         unsafe static internal void* GetNativeTextInfo(int cultureID)
  322.         {
  323.         }
  324.        
  325.        
  326.         // First, assume this culture does not has exceptions. I.e. we should use the default casingg table.
  327.         // So we assign the native NativeTextInfo for the default casing table to it.
  328.         void* pNativeTextInfo = m_pDefaultCasingTable;
  329.     }
  330. }
  331. // Now, go thru the exception table to see if it has exception or not.

Developer Fusion