CultureInfo.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / clr / src / BCL / System / Globalization / CultureInfo.cs / 1 / CultureInfo.cs

                            // ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
////////////////////////////////////////////////////////////////////////////
// 
//  Class:    CultureInfo 
//
// 
//  Purpose:  This class represents the software preferences of a particular
//            culture or community.  It includes information such as the
//            language, writing system, and a calendar used by the culture
//            as well as methods for common operations such as printing 
//            dates and sorting strings.
// 
//  Date:     [....] 31, 1999 
//
// 
//  !!!! NOTE WHEN CHANGING THIS CLASS !!!!
//
//  If adding or removing members to this class, please update CultureInfoBaseObject
//  in ndp/clr/src/vm/object.h. Note, the "actual" layout of the class may be 
//  different than the order in which members are declared. For instance, all
//  reference types will come first in the class before value types (like ints, bools, etc) 
//  regardless of the order in which they are declared. The best way to see the 
//  actual order of the class is to do a !dumpobj on an instance of the managed
//  object inside of the debugger. 
//
////////////////////////////////////////////////////////////////////////////

namespace System.Globalization { 
    using System;
    using System.Security; 
    using System.Threading; 
    using System.Collections;
    using System.Runtime.CompilerServices; 
    using System.Runtime.InteropServices;
    using System.Runtime.Serialization;
    using System.Security.Permissions;
    using System.Reflection; 
    using Microsoft.Win32;
    using System.Runtime.Versioning; 
 
    [Serializable]
[System.Runtime.InteropServices.ComVisible(true)] 
    public class CultureInfo : ICloneable, IFormatProvider {
        //
        // Special culture IDs
        // 
        internal const int zh_CHT_CultureID = 0x7c04;
        internal const int zh_CHS_CultureID = 0x0004; 
        // Serbian Neutral culture ID. 
        internal const int sr_CultureID = 0x7c1a;
        internal const int sr_SP_Latn_CultureID = 0x081a; 


        //--------------------------------------------------------------------//
        //                        Internal Information                        // 
        //-------------------------------------------------------------------//
 
        //-------------------------------------------------------------------// 
        // Data members to be serialized:
        //-------------------------------------------------------------------// 

        // This is the string used to construct CultureInfo.
        // It is in the format of ISO639 (2 letter language name) plus dash plus
        // ISO 3166 (2 letter region name).  The language name is in lowercase and region name 
        // are in uppercase. (now part of cultureTableRecord)
 
        // 
        // This is the culture ID used in the NLS+ world.  The concept of cultureID is similar
        // to the concept of LCID in Win32.  However, NLS+ support "neutral" culture 
        // which Win32 doesn't support.
        //
        // The format of culture ID (32 bits) is:
        // 
        // 31 - 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
        // +-----+ +---------+ +---------------+ +-----------------+ 
        //    |         |           |            Primary language ID (10 bits) 
        //    |         |           +----------- Sublanguage ID (6 its)
        //    |         +----------------------- Sort ID (4 bits) 
        //    +--------------------------------- Reserved (12 bits)
        //
        // Primary language ID and sublanguage ID can be zero to specify 'neutral' language.
        // For example, cultureID 0x(0000)0009 is the English neutral culture. 
        // cultureID 0x(0000)0000 means the invariant culture (or called neutral culture).
        // 
        // We'd just use cultureTableInfo.cultureID for ID, however cultureTableInfo doesn't 
        // remember the sort info.
 
        // WARNING
        // WARNING: All member fields declared here must also be in ndp/clr/src/vm/object.h
        // WARNING: They aren't really private because object.h can access them, but other C# stuff cannot
        // WARNING 
        internal int cultureID;
        internal bool m_isReadOnly=false; 
 
        internal CompareInfo compareInfo = null;
        internal TextInfo textInfo = null; 
        internal NumberFormatInfo numInfo = null;
        internal DateTimeFormatInfo dateTimeInfo = null;
        internal Calendar calendar = null;
 
        //
        // The CultureTable instance that we are going to read data from. 
        // For supported culture, this will be the CultureTable instance that read data from mscorlib assembly. 
        // For customized culture, this will be the CultureTable instance that read data from user customized culture binary file.
        // 
        [NonSerialized]internal CultureTableRecord m_cultureTableRecord;
        [NonSerialized]internal bool m_isInherited;
        [NonSerialized]private bool m_isSafeCrossDomain = false;
        [NonSerialized]private int m_createdDomainID = 0; 
        [NonSerialized]private CultureInfo m_consoleFallbackCulture = null;
 
        // Names are confusing.  Here are 3 names we have: 
        //
        //  new CultureInfo()   m_name        m_nonSortName   m_sortName 
        //      en-US           en-US           en-US           en-US
        //      de-de_phoneb    de-DE_phoneb    de-DE           de-DE_phoneb
        //      fj-fj (custom)  fj-FJ           fj-FJ           en-US (if specified sort is en-US)
 
        // Note that the name used to be serialized for Everett; it is now serialized
        // because alernate sorts can have alternate names. 
        // This has a de-DE, de-DE_phoneb or fj-FJ style name 
        internal string m_name = null;
 
        // This will hold the non sorting name to be returned from CultureInfo.Name property.
        // This has a de-DE style name even for de-DE_phoneb type cultures
        [NonSerialized]private string m_nonSortName = null;
 
        // This will hold the sorting name to be returned from CultureInfo.SortName property.
        // This might be completely unrelated to the culture name if a custom culture.  Ie en-US for fj-FJ. 
        // Otherwise its the sort name, ie: de-DE or de-DE_phoneb 
        [NonSerialized]private string m_sortName = null;
 

        //--------------------------------------------------------------------//
        //
        // Static data members 
        //
        //-------------------------------------------------------------------// 
 
        //Get the current user default culture.  This one is almost always used, so we create it by default.
        private static CultureInfo m_userDefaultCulture   = null; 

        //
        // All of the following will be created on demand.
        // 

        //The Invariant culture; 
        private static CultureInfo m_InvariantCultureInfo = null; 

        //The culture used in the user interface. This is mostly used to load correct localized resources. 
        private static CultureInfo m_userDefaultUICulture = null;

        //This is the UI culture used to install the OS.
        private static CultureInfo m_InstalledUICultureInfo = null; 

        //This is a cache of all previously created cultures.  Valid keys are LCIDs or the name.  We use two hashtables to track them, 
        // depending on how they are called. 
        private static Hashtable m_LcidCachedCultures = null;
        private static Hashtable m_NameCachedCultures = null; 


        //The parent culture.
        [NonSerialized]private CultureInfo m_parent; 

        // 
        //  Helper Methods. 
        //
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern bool IsValidLCID(int LCID, int flag);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern bool IsWin9xInstalledCulture(string cultureKey, int LCID); 

        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern unsafe String nativeGetUserDefaultLCID(int* LCID, int lcidType); 

        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern unsafe String nativeGetUserDefaultUILanguage(int* LCID);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern unsafe String nativeGetSystemDefaultUILanguage(int* LCID); 

        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern bool nativeSetThreadLocale(int LCID); 

        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern String nativeGetLocaleInfo(int LCID, int field);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern int nativeGetCurrentCalendar(); 

        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern unsafe bool nativeGetDTFIUserValues(int lcid, ref DTFIUserOverrideValues values); 

        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern unsafe bool nativeGetNFIUserValues(int lcid, NumberFormatInfo nfi);

        // 
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern unsafe bool nativeGetCultureData(int lcid, ref CultureData cultureData);
 
        //  
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern bool nativeEnumSystemLocales(out int [] localesArray); 

        // 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern string nativeGetCultureName(int lcid, bool useSNameLCType, bool getMonthName); 

        // 
        // Return the path to the Windows directory (such as c:\Windows).  The returned string does NOT include the backslash. 
        //
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern string nativeGetWindowsDirectory();

        //
        // Check if the specified fileName exists in the file system or not. 
        //
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern bool nativeFileExists(String fileName); 

        // 
        // Get the static int array data used by globalization classes.
        //
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern unsafe int* nativeGetStaticInt32DataTable(int type, out int tableSize); 
#if !FEATURE_PAL
        // 
        // we didn't make LCMapStringW fast call because in the debug mscorwks we should call LCMapStringW through a wrapper 
        // which can switch to ansi version randomally (to simulate the running in the ansi platforms).
        // 
        // we just need to call the Unicode version all the time as we check running on the Unicode platforms before we proceed
        // while getting the culture data (in nativeGetCultureData)
        //
        //  
        internal static unsafe int GetNativeSortKey(int lcid, int flags, string source, int cchSrc, out byte [] sortKey)
        { 
            sortKey = null; 
            int length;
 
            if (String.IsNullOrEmpty(source) || cchSrc == 0)
            {
                // Empty strings get an empty sort key
                sortKey = new byte[0]; 
                // Fake value to test though so we can verify our flags
                source = "\x0000"; 
                cchSrc = 1; 
            }
 
            fixed (char *src = source)
            {
                length = Win32Native.LCMapStringW(lcid, flags | Win32Native.LCMAP_SORTKEY, src, cchSrc, null, 0);
                if (length == 0) 
                {
                    return -1; 
                } 

                // If input was empty, return the empty byte[] we made earlier and skip this 
                if (sortKey == null)
                {
                    sortKey = new byte[length];
 
                    fixed (byte* key = sortKey)
                    { 
                        length = Win32Native.LCMapStringW(lcid, flags | Win32Native.LCMAP_SORTKEY, src, cchSrc, (char*)key, length); 
                    }
                } 
            }
            return length;
        }
 
#endif // !FEATURE_PAL
 
        internal const int LOCALE_INVARIANT            = 0x007f; 
        private  const int LOCALE_NEUTRAL              = 0x0000;
        internal const int LOCALE_USER_DEFAULT         = 0x0400; 
        internal const int LOCALE_SYSTEM_DEFAULT       = 0x0800;
        internal const int LOCALE_CUSTOM_DEFAULT       = 0x0c00;
        internal const int LOCALE_CUSTOM_UNSPECIFIED   = 0x1000;
        internal const int LOCALE_TRADITIONAL_SPANISH  = 0x040a; 
        internal const int LCID_INSTALLED              = 0x0001;
        internal const int LCID_SUPPORTED              = 0x0002; 
 
        //
        // The CultureTable instance that read data from culture.nlp in the mscorlib assembly. 
        //
        static unsafe CultureInfo()
        {
 
            if (m_InvariantCultureInfo == null)
            { 
                CultureInfo temp = new CultureInfo(LOCALE_INVARIANT, false); 
                temp.m_isReadOnly = true;
                m_InvariantCultureInfo = temp; 
            }
            // First we set it to Invariant in case someone needs it before we're done finding it.
            // For example, if we throw an exception in InitUserDefaultCulture, we will still need an valid
            // m_userDefaultCulture to be used in Thread.CurrentCulture. 
            m_userDefaultCulture = m_userDefaultUICulture = m_InvariantCultureInfo;
 
            m_userDefaultCulture = InitUserDefaultCulture(); 
            m_userDefaultUICulture = InitUserDefaultUICulture();
 
        }

        static unsafe CultureInfo InitUserDefaultCulture()
        { 
            int LCID;
            String strDefault = nativeGetUserDefaultLCID(&LCID, LOCALE_USER_DEFAULT); 
            CultureInfo temp = GetCultureByLCIDOrName(LCID, strDefault); 
            if (temp == null)
            { 
                strDefault = nativeGetUserDefaultLCID(&LCID, LOCALE_SYSTEM_DEFAULT);
                temp = GetCultureByLCIDOrName(LCID, strDefault);

                if (temp == null) 
                {
                    // If system default doesn't work, keep using the invariant 
                    return (CultureInfo.InvariantCulture); 
                }
            } 
            temp.m_isReadOnly = true;

            return (temp);
        } 

        static unsafe CultureInfo InitUserDefaultUICulture() 
        { 
            int LCID;
            String strDefault = nativeGetUserDefaultUILanguage(&LCID); 
            // In most of cases, UserDefaultCulture == UserDefaultUICulture, so we should use the same instance if possible.
            if (LCID == UserDefaultCulture.LCID || strDefault == UserDefaultCulture.Name)
            {
                return (UserDefaultCulture); 
            }
 
            CultureInfo temp = GetCultureByLCIDOrName(LCID, strDefault); 

            if (temp == null) 
            {
                strDefault = nativeGetSystemDefaultUILanguage(&LCID);
                temp = GetCultureByLCIDOrName(LCID, strDefault);
            } 

            if (temp == null) 
            { 
                return (CultureInfo.InvariantCulture);
            } 

            temp.m_isReadOnly = true;

            return (temp); 
        }
 
 

        //////////////////////////////////////////////////////////////////////// 
        //
        //  CultureInfo Constructors
        //
        //////////////////////////////////////////////////////////////////////// 

 
        public CultureInfo(String name) : this(name, true) { 
        }
 

        public CultureInfo(String name, bool useUserOverride) {
            if (name==null) {
                throw new ArgumentNullException("name", 
                    Environment.GetResourceString("ArgumentNull_String"));
            } 
 
            this.m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(name, useUserOverride);
            this.cultureID = this.m_cultureTableRecord.ActualCultureID; 
            this.m_name = this.m_cultureTableRecord.ActualName;
            this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
        }
 

 
        public CultureInfo(int culture) : this(culture, true) { 
        }
 

        public unsafe CultureInfo(int culture, bool useUserOverride) {
            // We don't check for other invalid LCIDS here...
            if (culture < 0) { 
                throw new ArgumentOutOfRangeException("culture",
                    Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum")); 
            } 

            switch (culture) 
            {
                case LOCALE_CUSTOM_DEFAULT:
                    // CONSDIER: Support this LCID value any time the OS is using a custom culture as the user default.
                    //           Note that if this is to be supported that the code below is not correct since it assumes 
                    //           the LCID value is describing the NLS+ culture, not the NLS locale.
/* 
                    this.m_cultureTableRecord = CultureInfo.CurrentCulture.m_cultureTableRecord; 
                    this.cultureID = CultureInfo.CurrentCulture.cultureID;
                    break; 
*/
                case LOCALE_SYSTEM_DEFAULT:
/*
                    String strSystemDefault = nativeGetUserDefaultLCID(&culture, LOCALE_SYSTEM_DEFAULT); 
                    CultureInfo systemDefault;
 
                    // See if we can get our LOCALE_SYSTEM_DEFAULT 
                    systemDefault = GetCultureByLCIDOrName(culture, strSystemDefault);
 
                    if (systemDefault == null)
                        // That didn't work, try invariant
                        systemDefault = InvariantCulture;
 
                    this.cultureID = systemDefault.cultureID;
                    this.m_cultureTableRecord = systemDefault.m_cultureTableRecord; 
                    break; 
*/
                case LOCALE_NEUTRAL: 
                case LOCALE_USER_DEFAULT:
                case LOCALE_CUSTOM_UNSPECIFIED:
                    // Can't support unknown custom cultures and we do not support neutral or
                    // non-custom user locales. 
                    throw new ArgumentException(
                        Environment.GetResourceString("Argument_CultureNotSupported", culture), "culture"); 
                default: 
                    this.cultureID = culture;
                    // Now see if this LCID is supported in the system default culture.nlp table. 
                    this.m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(this.cultureID, useUserOverride);
                    this.m_name = this.m_cultureTableRecord.ActualName;
                    break;
            } 
            m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
        } 
 

        // 
        // CheckDomainSafetyObject throw if the object is customized object which cannot be attached to
        // other object (like CultureInfo or DateTimeFormatInfo).
        //
 
        internal static void CheckDomainSafetyObject(Object obj, Object container)
        { 
            if (obj.GetType().Assembly != typeof(System.Globalization.CultureInfo).Assembly) { 

                throw new InvalidOperationException( 
                            String.Format(
                                CultureInfo.CurrentCulture,
                                Environment.GetResourceString("InvalidOperation_SubclassedObject"),
                                obj.GetType(), 
                                container.GetType()));
            } 
        } 

#region Serialization 
        // the following fields are defined to keep the compatibility with .NET V1.0/V1.1.
        // don't change/remove the names/types of these fields.
        private int     m_dataItem;
        private bool    m_useUserOverride; 

        [OnDeserialized] 
        private void OnDeserialized(StreamingContext ctx) 
        {
            // In .NET ver 1.0 we can get m_name = null if the Name property never requested 
            // before serializing the culture info object.

            BCLDebug.Assert(m_name != null || cultureID>0,  "[CultureInfo.OnDeserialized] m_name != null || cultureID>0");
 
            if (m_name != null && cultureID != LOCALE_TRADITIONAL_SPANISH)
                m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(m_name, m_useUserOverride); 
            else 
                m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(cultureID, m_useUserOverride);
 
            m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));

            if (m_name == null)
            { 
                m_name = m_cultureTableRecord.ActualName;
            } 
 
            // in case we have non customized CultureInfo object we shouldn't allow any customized object
            // to be attached to it for cross app domain safety. 
            if (this.GetType().Assembly == typeof(System.Globalization.CultureInfo).Assembly)
            {
                if (textInfo != null)
                { 
                    CheckDomainSafetyObject(textInfo, this);
                } 
 
                if (compareInfo != null)
                { 
                    CheckDomainSafetyObject(compareInfo, this);
                }
            }
        } 

        [OnSerializing] 
        private void OnSerializing(StreamingContext ctx) 
        {
            m_name              = m_cultureTableRecord.CultureName; 
            m_useUserOverride   = m_cultureTableRecord.UseUserOverride;
            m_dataItem          = m_cultureTableRecord.EverettDataItem();
        }
#endregion Serialization 

        internal bool IsSafeCrossDomain { 
            get { 
                BCLDebug.Assert(m_createdDomainID != 0, "[CultureInfo.IsSafeCrossDomain] m_createdDomainID != 0");
                return m_isSafeCrossDomain; 
            }
        }

        internal int CreatedDomainID { 
            get {
                BCLDebug.Assert(m_createdDomainID != 0,  "[CultureInfo.CreatedDomain] m_createdDomainID != 0"); 
                return m_createdDomainID; 
            }
        } 

        internal void StartCrossDomainTracking() {

            // If we have decided about cross domain safety of this instance, we are done 
            if (m_createdDomainID != 0)
                return; 
 
            if (this.GetType() == typeof(System.Globalization.CultureInfo))
            { 
                m_isSafeCrossDomain = true;
            }

            // m_createdDomainID has to be assigned last. We use it to signal that we have 
            // completed the check.
            System.Threading.Thread.MemoryBarrier(); 
            m_createdDomainID = Thread.GetDomainID(); 
        }
 
        // Constructor called by SQL Server's special munged culture - creates a culture with
        // a TextInfo and CompareInfo that come from a supplied alternate source. This object
        // is ALWAYS read-only.
        // Note that we really cannot use an LCID version of this override as the cached 
        // name we create for it has to include both names, and the logic for this is in
        // the GetCultureInfo override *only*. 
        internal CultureInfo(String cultureName, String textAndCompareCultureName) 
        {
            if (cultureName==null) { 
                throw new ArgumentNullException("cultureName",
                    Environment.GetResourceString("ArgumentNull_String"));
            }
 
            this.m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(cultureName, false);
            this.cultureID = this.m_cultureTableRecord.ActualCultureID; 
            this.m_name = this.m_cultureTableRecord.ActualName; 

            CultureInfo altCulture = GetCultureInfo(textAndCompareCultureName); 

            this.compareInfo = altCulture.CompareInfo;
            this.textInfo = altCulture.TextInfo;
        } 

 
        // Get a culture when trying to create it from LCID or name 
        // This happens when asking windows for the locale information.
        // In this case we want to use LCID if provided, otherwise use 
        // the name.  Using LCID gives us system default values, using
        // names would allow users to override system cultures when we
        // don't expect them to.
        // 
        // Note that this should pick up a CC of the same name for
        // OS ELKS/LIPS/whatever, but will throw if no CC is installed. 
        private static CultureInfo GetCultureByLCIDOrName(int preferLCID, String fallbackToString) 
        {
            // If we don't have a string or we don't have 
            CultureInfo culture = null;

            // We prefer LCID because that gives us the system values, but we can't use
            // it if there's no lang part 
            if ((preferLCID & 0x3ff) != 0)
            { 
                // Try to get it 
                try
                { 
                    culture = new CultureInfo(preferLCID);
                }
                catch (ArgumentException)
                { 
                }
            } 
 
            // If it didn't work by # we need to try string (if possible)
            if (culture == null && fallbackToString != null && fallbackToString.Length > 0) 
            {
                // Try to get it
                try
                { 
                    culture = new CultureInfo(fallbackToString);
                } 
                catch (ArgumentException) 
                {
                } 
            }

            return culture;
        } 

 
 
        public static CultureInfo CreateSpecificCulture(String name) {
            CultureInfo culture; 

            try {
                culture = new CultureInfo(name);
            } catch(ArgumentException exp) { 
                // When CultureInfo throws this exception, it may be because someone passed the form
                // like "az-az" because it came out of an http accept lang. We should try a little 
                // parsing to perhaps fall back to "az" here and use *it* to create the neutral. 

                int idx; 

                culture = null;
                for(idx = 0; idx < name.Length; idx++) {
                    if('-' == name[idx]) { 
                        try {
                            culture = new CultureInfo(name.Substring(0, idx)); 
                            break; 
                        } catch(ArgumentException) {
                            // throw the original exception so the name in the string will be right 
                            throw(exp);
                        }
                    }
                } 

                if(null == culture) { 
                    // nothing to save here; throw the original exception 
                    throw(exp);
                } 
            }

            //In the most common case, they've given us a specific culture, so we'll just return that.
            if (!(culture.IsNeutralCulture)) { 
                return culture;
            } 
 
                int lcid = culture.LCID;
                //If we have the Chinese locale, we have no way of producing a 
                //specific culture without encountering significant geopolitical
                //issues.  Based on that, we have no choice but to return.
                if ((lcid & 0x3FF)==0x04) {
                    throw new ArgumentException(Environment.GetResourceString("Argument_NoSpecificCulture")); 
                }
 
            return (new CultureInfo(culture.m_cultureTableRecord.SSPECIFICCULTURE)); 
        }
 
        internal static bool VerifyCultureName(CultureInfo culture, bool throwException) {
            BCLDebug.Assert(culture!=null, "[CultureInfo.VerifyCultureName]culture!=null");

            //If we have an instance of one of our CultureInfos, the user can't have changed the 
            //name and we know that all names are valid in files.
            if (!culture.m_isInherited) { 
                return true; 
            }
 
            // This function is used by ResourceManager.GetResourceFileName().
            // ResourceManager searches for resource using CultureInfo.Name,
            // so we should check against CultureInfo.Name.
            String name = culture.Name; 

            for (int i=0; i> 10) & 0x3f); 
        }
 
        internal static int GetLangID(int culture)
        {
            return (culture & 0xffff);
        } 

        internal static int GetSortID(int lcid) 
        { 
            return ((lcid >> 16) & 0xf);
        } 

        ////////////////////////////////////////////////////////////////////////
        //
        //  CurrentCulture 
        //
        //  This instance provides methods based on the current user settings. 
        //  These settings are volatile and may change over the lifetime of the 
        //  thread.
        // 
        ////////////////////////////////////////////////////////////////////////


        public static CultureInfo CurrentCulture 
        {
            get { 
                return Thread.CurrentThread.CurrentCulture; 
            }
        } 

        //
        // This is the equivalence of the Win32 GetUserDefaultLCID()
        // 
        internal static CultureInfo UserDefaultCulture {
            get 
            { 
                CultureInfo temp = m_userDefaultCulture;
                if (temp == null) 
                {
                    //
                    // setting the m_userDefaultCulture with invariant culture before intializing it is a protection
                    // against recursion problem just in case if somebody called CurrentCulture from the CultureInfo 
                    // creation path. the recursion can happen if the current user culture is a replaced custom culture.
                    // 
 
                    m_userDefaultCulture = CultureInfo.InvariantCulture;
                    temp = InitUserDefaultCulture(); 
                    m_userDefaultCulture = temp;
                }
                return (temp);
            } 
        }
 
        // 
        //  This is the equivalence of the Win32 GetUserDefaultUILanguage()
        // 
        internal static unsafe CultureInfo UserDefaultUICulture {
            get {
                CultureInfo temp = m_userDefaultUICulture;
                if (temp == null) 
                {
                    // 
                    // setting the m_userDefaultCulture with invariant culture before intializing it is a protection 
                    // against recursion problem just in case if somebody called CurrentUICulture from the CultureInfo
                    // creation path. the recursion can happen if the current user culture is a replaced custom culture. 
                    //

                    m_userDefaultUICulture = CultureInfo.InvariantCulture;
 
                    temp = InitUserDefaultUICulture();
                    m_userDefaultUICulture = temp; 
                } 
                return (temp);
            } 
        }


        public static CultureInfo CurrentUICulture { 
            get {
                return Thread.CurrentThread.CurrentUICulture; 
            } 
        }
 

        //
        // This is the equivalence of the Win32 GetSystemDefaultUILanguage()
        // 
        public static unsafe CultureInfo InstalledUICulture {
            get { 
                CultureInfo temp = m_InstalledUICultureInfo; 
                if (temp == null) {
                    int LCID; 
                    String strDefault = nativeGetSystemDefaultUILanguage(&LCID);
                    temp = GetCultureByLCIDOrName(LCID, strDefault);

                    if (temp == null) 
                    {
                        temp = new CultureInfo(LOCALE_INVARIANT, true); 
                    } 

                    temp.m_isReadOnly = true; 
                    m_InstalledUICultureInfo = temp;
                }
                return (temp);
            } 
        }
 
        //////////////////////////////////////////////////////////////////////// 
        //
        //  InvariantCulture 
        //
        //  This instance provides methods, for example for casing and sorting,
        //  that are independent of the system and current user settings.  It
        //  should be used only by processes such as some system services that 
        //  require such invariant results (eg. file systems).  In general,
        //  the results are not linguistically correct and do not match any 
        //  culture info. 
        //
        //////////////////////////////////////////////////////////////////////// 


        public static CultureInfo InvariantCulture {
            get { 
                return (m_InvariantCultureInfo);
            } 
        } 

 
        ////////////////////////////////////////////////////////////////////////
        //
        //  Parent
        // 
        //  Return the parent CultureInfo for the current instance.
        // 
        //////////////////////////////////////////////////////////////////////// 

        public virtual CultureInfo Parent 
        {
            get
            {
                if (null == m_parent) 
                {
                    try 
                    { 
                        int parentCulture = this.m_cultureTableRecord.IPARENT;
                        if (parentCulture == LOCALE_INVARIANT) 
                        {
                            m_parent = InvariantCulture;
                        }
                        else if (CultureTableRecord.IsCustomCultureId(parentCulture) || 
                                 CultureTable.IsOldNeutralChineseCulture(this))
                        { 
                            // Customized culture -- use the string for the parent. 
                            m_parent = new CultureInfo(this.m_cultureTableRecord.SPARENT);
                        } 
                        else
                        {
                            m_parent = new CultureInfo(parentCulture, this.m_cultureTableRecord.UseUserOverride);
                        } 
                    }
                    catch (ArgumentException) 
                    { 
                        // For whatever reason our IPARENT or SPARENT wasn't correct, so use invariant
                        // We can't allow ourselves to fail.  In case of custom cultures the parent of the 
                        // current custom culture isn't installed.
                        m_parent =  InvariantCulture;
                    }
                } 
                return m_parent;
            } 
        } 

        //////////////////////////////////////////////////////////////////////// 
        //
        //  LCID
        //
        //  Returns a properly formed culture identifier for the current 
        //  culture info.
        // 
        //////////////////////////////////////////////////////////////////////// 

 
        public virtual int LCID {
            get {
                return (this.cultureID);
            } 
        }
 
        //////////////////////////////////////////////////////////////////////// 
        //
        //  BaseInputLanguage 
        //
        //  Essentially an LCID, though one that may be different than LCID in the case
        //  of a customized culture (LCID == -1).
        // 
        ////////////////////////////////////////////////////////////////////////
 
        [System.Runtime.InteropServices.ComVisible(false)] 
        public virtual int KeyboardLayoutId
        { 
            get
            {
                int keyId = this.m_cultureTableRecord.IINPUTLANGUAGEHANDLE;
 
                // Not a customized culture, return the default Keyboard layout ID, which is the same as the language ID.
                return (keyId); 
            } 
        }
 

        public static CultureInfo[] GetCultures(CultureTypes types) {
            return (CultureTable.Default.GetCultures(types));
        } 

 
        //////////////////////////////////////////////////////////////////////// 
        //
        //  Name 
        //
        //  Returns the full name of the CultureInfo. The name is in format like
        //  "en-US"  This version does NOT include sort information in the name.
        // 
        ////////////////////////////////////////////////////////////////////////
        public virtual String Name { 
            get { 
                // We return non sorting name here.
                if (this.m_nonSortName == null) { 
                    this.m_nonSortName  = this.m_cultureTableRecord.CultureName;
                }
                return this.m_nonSortName;
            } 
        }
 
 
        internal String SortName
        { 
            get
            {
                if (this.m_sortName == null)
                { 
                    if (CultureTableRecord.IsCustomCultureId(cultureID))
                    { 
                        CultureInfo sortCI = CultureInfo.GetCultureInfo(CompareInfoId); 

                        BCLDebug.Assert(!CultureTableRecord.IsCustomCultureId(sortCI.cultureID), 
                                        "[CultureInfo.SortName]Expected non-custom sort id");

                        if (CultureTableRecord.IsCustomCultureId(sortCI.cultureID))
                        { 
                            // m_name create could call SortName (not supposed to for CI),
                            // but just to be safe, use SNAME not m_name 
                            this.m_sortName = m_cultureTableRecord.SNAME; 
                        }
                        else 
                        {
                            this.m_sortName = sortCI.SortName;  // Name of culture doing our sort
                        }
                    } 
                    else
                    { 
                        // If its not custom, our sort is our full name 
                        BCLDebug.Assert(m_name != null, "[CultureInfo.SortName]Always expect m_name to be set");
                        this.m_sortName = this.m_name;          // full name, including sort 
                    }
                }
                return this.m_sortName;
            } 
        }
 
        [System.Runtime.InteropServices.ComVisible(false)] 
        public String IetfLanguageTag
        { 
            get
            {
                if (CultureTable.IsOldNeutralChineseCulture(this))
                { 
                    if (this.LCID == zh_CHT_CultureID)    // zh-CHT
                        return CultureTable.NewTraditionalChineseCultureName; 
                    if (this.LCID == zh_CHS_CultureID)    // zh-CHS 
                        return CultureTable.NewSimplifiedChineseCultureName;
                } 
                return this.Name;
            }
        }
 
        ////////////////////////////////////////////////////////////////////////
        // 
        //  DisplayName 
        //
        //  Returns the full name of the CultureInfo in the localized language. 
        //  For example, if the localized language of the runtime is Spanish and the CultureInfo is
        //  US English, "Ingles (Estados Unidos)" will be returned.
        //
        //////////////////////////////////////////////////////////////////////// 

 
        public virtual String DisplayName 
        {
            get 
            {
                BCLDebug.Assert(m_name != null, "[CultureInfo.DisplayName]Always expect m_name to be set");

                if (m_cultureTableRecord.IsCustomCulture) 
                {
                    if (m_cultureTableRecord.IsReplacementCulture) 
                    { 
                        // 
                        if (m_cultureTableRecord.IsSynthetic) 
                            return m_cultureTableRecord.CultureNativeDisplayName;
                        else
                            return (Environment.GetResourceString("Globalization.ci_" + this.m_name));
                    } 
                    else
                    { 
                        return m_cultureTableRecord.SNATIVEDISPLAYNAME; 
                    }
                } 
                else
                {
                    // 
                    if (m_cultureTableRecord.IsSynthetic) 
                        return m_cultureTableRecord.CultureNativeDisplayName;
                    else 
                        return (Environment.GetResourceString("Globalization.ci_" + this.m_name)); 
                }
            } 
        }

        ////////////////////////////////////////////////////////////////////////
        // 
        //  GetNativeName
        // 
        //  Returns the full name of the CultureInfo in the native language. 
        //  For example, if the CultureInfo is US English, "English
        //  (United States)" will be returned. 
        //
        ////////////////////////////////////////////////////////////////////////

 
        public virtual String NativeName {
            get { 
                return (this.m_cultureTableRecord.SNATIVEDISPLAYNAME); 
            }
        } 

        ////////////////////////////////////////////////////////////////////////
        //
        //  GetEnglishName 
        //
        //  Returns the full name of the CultureInfo in English. 
        //  For example, if the CultureInfo is US English, "English 
        //  (United States)" will be returned.
        // 
        ////////////////////////////////////////////////////////////////////////


        public virtual String EnglishName { 
            get {
                return (this.m_cultureTableRecord.SENGDISPLAYNAME); 
            } 
        }
 

        public virtual String TwoLetterISOLanguageName {
            get {
                return (this.m_cultureTableRecord.SISO639LANGNAME); 
            }
        } 
 

        public virtual String ThreeLetterISOLanguageName { 
            get {
                return (this.m_cultureTableRecord.SISO639LANGNAME2);
            }
        } 

        //////////////////////////////////////////////////////////////////////// 
        // 
        //  GetAbbreviatedName
        // 
        //  Returns the abbreviated name for the current instance.  The
        //  abbreviated form is usually based on the ISO 639 standard, for
        //  example the two letter abbreviation for English is "en".
        // 
        ////////////////////////////////////////////////////////////////////////
 
 
       public virtual String ThreeLetterWindowsLanguageName {
            get { 
                return (this.m_cultureTableRecord.SABBREVLANGNAME);
            }
        }
 
        ////////////////////////////////////////////////////////////////////////
        // 
        //  CompareInfo               Read-Only Property 
        //
        //  Gets the CompareInfo for this culture. 
        //
        ////////////////////////////////////////////////////////////////////////

 
        public virtual CompareInfo CompareInfo {
            get { 
                if (compareInfo==null) { 

                    CompareInfo temp; 

                    // In case of non custom neutral cultures we always return compare info with neutral culture id
                    // and neutral culture name. this to be compatible with Everett.
 
                    if (IsNeutralCulture && !CultureTableRecord.IsCustomCultureId(cultureID))
                        temp = CompareInfo.GetCompareInfo(cultureID); 
                    else 
                        temp = CompareInfo.GetCompareInfo(CompareInfoId);
 
                    // The name is not preset when CompareInfo is set by LCID, so lets set it now.
                    temp.SetName(this.SortName);
                    compareInfo = temp;
 
                }
                return (compareInfo); 
            } 
        }
 
        internal int CompareInfoId {
            get {
                int compareId;
 
                if (this.cultureID == LOCALE_TRADITIONAL_SPANISH) {
                    // Special case Trad. Spanish since there is no 
                    // ICOMPAREINFO entry for them. 
                    compareId = LOCALE_TRADITIONAL_SPANISH;
                } else if (GetSortID(this.cultureID) != 0) { 
                    // Special case alternate sorts since there is no
                    // ICOMPAREINFO entry for them.
                    compareId = this.cultureID;
                } else { 
                    compareId = unchecked((int)this.m_cultureTableRecord.ICOMPAREINFO);
                } 
 
                return compareId;
            } 
        }

        ////////////////////////////////////////////////////////////////////////
        // 
        //  TextInfo
        // 
        //  Gets the TextInfo for this culture. 
        //
        //////////////////////////////////////////////////////////////////////// 


        public virtual TextInfo TextInfo {
            get { 
                if (textInfo==null) {
                    // Make a new textInfo 
                    TextInfo tempTextInfo = new TextInfo(this.m_cultureTableRecord); 
                    tempTextInfo.SetReadOnlyState(m_isReadOnly);
                    textInfo = tempTextInfo; 
                }
                return (textInfo);
            }
        } 

        //////////////////////////////////////////////////////////////////////// 
        // 
        //  Equals
        // 
        //  Implements Object.Equals().  Returns a boolean indicating whether
        //  or not object refers to the same CultureInfo as the current instance.
        //
        //////////////////////////////////////////////////////////////////////// 

 
        public override bool Equals(Object value) 
        {
            if (Object.ReferenceEquals(this, value)) 
                return true;

            CultureInfo that = value as CultureInfo;
 
            if (that != null)
            { 
                // using CompareInfo to verify the data passed through the constructor 
                // CultureInfo(String cultureName, String textAndCompareCultureName)
 
                return (this.Name.Equals(that.Name) && this.CompareInfo.Equals(that.CompareInfo));
            }

            return (false); 
        }
 
 
        ////////////////////////////////////////////////////////////////////////
        // 
        //  GetHashCode
        //
        //  Implements Object.GetHashCode().  Returns the hash code for the
        //  CultureInfo.  The hash code is guaranteed to be the same for CultureInfo A 
        //  and B where A.Equals(B) is true.
        // 
        //////////////////////////////////////////////////////////////////////// 

 
        public override int GetHashCode()
        {
            return (this.Name.GetHashCode() + this.CompareInfo.GetHashCode());
        } 

 
        //////////////////////////////////////////////////////////////////////// 
        //
        //  ToString 
        //
        //  Implements Object.ToString().  Returns the name of the CultureInfo,
        //  eg. "English (United States)".
        // 
        ////////////////////////////////////////////////////////////////////////
 
 
        public override String ToString()
        { 
            BCLDebug.Assert(m_name != null, "[CultureInfo.ToString]Always expect m_name to be set");
            return m_name;
        }
 

        public virtual Object GetFormat(Type formatType) { 
            if (formatType == typeof(NumberFormatInfo)) { 
                return (NumberFormat);
            } 
            if (formatType == typeof(DateTimeFormatInfo)) {
                return (DateTimeFormat);
            }
            return (null); 
        }
 
        internal static void CheckNeutral(CultureInfo culture) { 
            if (culture.IsNeutralCulture) {
                    BCLDebug.Assert(culture.m_name != null, "[CultureInfo.CheckNeutral]Always expect m_name to be set"); 
                    throw new NotSupportedException(
                                    Environment.GetResourceString("Argument_CultureInvalidFormat",
                                    culture.m_name));
            } 
        }
 
        public virtual bool IsNeutralCulture { 
            get {
                return this.m_cultureTableRecord.IsNeutralCulture; 
            }
        }

        [System.Runtime.InteropServices.ComVisible(false)] 
        public CultureTypes CultureTypes
        { 
            get 
            {
                CultureTypes types = 0; 

                if (m_cultureTableRecord.IsNeutralCulture)
                    types |= CultureTypes.NeutralCultures;
                else 
                    types |= CultureTypes.SpecificCultures;
 
                if (m_cultureTableRecord.IsSynthetic) 
                    types |= CultureTypes.WindowsOnlyCultures | CultureTypes.InstalledWin32Cultures; // Synthetic is installed culture too.
                else 
                {
                    // Not Synthetic
                    if (CultureTable.IsInstalledLCID(cultureID))
                        types |= CultureTypes.InstalledWin32Cultures; 

                    if (!m_cultureTableRecord.IsCustomCulture || m_cultureTableRecord.IsReplacementCulture) 
                        types |= CultureTypes.FrameworkCultures; 
                }
 
                if (m_cultureTableRecord.IsCustomCulture)
                {
                    types |= CultureTypes.UserCustomCulture;
 
                    if (m_cultureTableRecord.IsReplacementCulture)
                        types |= CultureTypes.ReplacementCultures; 
                } 

 
                return types;
            }
        }
 
        public virtual NumberFormatInfo NumberFormat {
            get { 
                CultureInfo.CheckNeutral(this); 
                if (numInfo == null) {
                    NumberFormatInfo temp = new NumberFormatInfo(this.m_cultureTableRecord); 
                    temp.isReadOnly = m_isReadOnly;
                    numInfo = temp;
                }
                return (numInfo); 
            }
            set { 
                VerifyWritable(); 
                if (value == null) {
                    throw new ArgumentNullException("value", 
                        Environment.GetResourceString("ArgumentNull_Obj"));
                }
                numInfo = value;
            } 
        }
 
        //////////////////////////////////////////////////////////////////////// 
        //
        // GetDateTimeFormatInfo 
        //
        // Create a DateTimeFormatInfo, and fill in the properties according to
        // the CultureID.
        // 
        ////////////////////////////////////////////////////////////////////////
 
 
        public virtual DateTimeFormatInfo DateTimeFormat {
            get { 
                if (dateTimeInfo == null) {
                    CultureInfo.CheckNeutral(this);
                    // Change the calendar of DTFI to the specified calendar of this CultureInfo.
                    DateTimeFormatInfo temp = new DateTimeFormatInfo( 
                        this.m_cultureTableRecord, GetLangID(cultureID), this.Calendar);
                    temp.m_isReadOnly = m_isReadOnly; 
                    System.Threading.Thread.MemoryBarrier(); 
                    dateTimeInfo = temp;
                } 
                return (dateTimeInfo);
            }

            set { 
                VerifyWritable();
                if (value == null) { 
                    throw new ArgumentNullException("value", 
                        Environment.GetResourceString("ArgumentNull_Obj"));
                } 
                dateTimeInfo = value;
            }
        }
 

 
        public unsafe void ClearCachedData() { 
            m_userDefaultUICulture = null;
            m_userDefaultCulture = null; 

            RegionInfo.m_currentRegionInfo = null;

            TimeZone.ResetTimeZone(); 

            // Delete the cached cultures. 
            m_LcidCachedCultures = null; 
            m_NameCachedCultures = null;
 
            CultureTableRecord.ResetCustomCulturesCache();
            CompareInfo.ClearDefaultAssemblyCache();
        }
 
        /*=================================GetCalendarInstance==========================
        **Action: Map a Win32 CALID to an instance of supported calendar. 
        **Returns: An instance of calendar. 
        **Arguments: calType    The Win32 CALID
        **Exceptions: 
        **      Shouldn't throw exception since the calType value is from our data table or from Win32 registry.
        **      If we are in trouble (like getting a weird value from Win32 registry), just return the GregorianCalendar.
        ============================================================================*/
        internal static Calendar GetCalendarInstance(int calType) { 
            if (calType==Calendar.CAL_GREGORIAN) {
                return (new GregorianCalendar()); 
            } 
            return GetCalendarInstanceRare(calType);
        } 

        //This function exists as a shortcut to prevent us from loading all of the non-gregorian
        //calendars unless they're required.
        internal static Calendar GetCalendarInstanceRare(int calType) { 
            BCLDebug.Assert(calType!=Calendar.CAL_GREGORIAN, "calType!=Calendar.CAL_GREGORIAN");
 
            switch (calType) { 
                case Calendar.CAL_GREGORIAN_US:               // Gregorian (U.S.) calendar
                case Calendar.CAL_GREGORIAN_ME_FRENCH:        // Gregorian Middle East French calendar 
                case Calendar.CAL_GREGORIAN_ARABIC:           // Gregorian Arabic calendar
                case Calendar.CAL_GREGORIAN_XLIT_ENGLISH:     // Gregorian Transliterated English calendar
                case Calendar.CAL_GREGORIAN_XLIT_FRENCH:      // Gregorian Transliterated French calendar
                    return (new GregorianCalendar((GregorianCalendarTypes)calType)); 
                case Calendar.CAL_TAIWAN:                     // Taiwan Era calendar
                    return (new TaiwanCalendar()); 
                case Calendar.CAL_JAPAN:                      // Japanese Emperor Era calendar 
                    return (new JapaneseCalendar());
                case Calendar.CAL_KOREA:                      // Korean Tangun Era calendar 
                    return (new KoreanCalendar());
                case Calendar.CAL_HIJRI:                      // Hijri (Arabic Lunar) calendar
                    return (new HijriCalendar());
                case Calendar.CAL_THAI:                       // Thai calendar 
                    return (new ThaiBuddhistCalendar());
                case Calendar.CAL_HEBREW:                     // Hebrew (Lunar) calendar 
                    return (new HebrewCalendar()); 
                case Calendar.CAL_PERSIAN:
                    return (new PersianCalendar()); 
                case Calendar.CAL_UMALQURA:
                    return (new UmAlQuraCalendar());
                case Calendar.CAL_CHINESELUNISOLAR:
                    return (new ChineseLunisolarCalendar()); 
                case Calendar.CAL_JAPANESELUNISOLAR:
                    return (new JapaneseLunisolarCalendar()); 
                case Calendar.CAL_KOREANLUNISOLAR: 
                    return (new KoreanLunisolarCalendar());
                case Calendar.CAL_TAIWANLUNISOLAR: 
                    return (new TaiwanLunisolarCalendar());
            }
            return (new GregorianCalendar());
        } 

 
        /*=================================Calendar========================== 
        **Action: Return/set the default calendar used by this culture.
        ** This value can be overridden by regional option if this is a current culture. 
        **Returns:
        **Arguments:
        **Exceptions:
        **  ArgumentNull_Obj if the set value is null. 
        ============================================================================*/
 
 
        public virtual Calendar Calendar {
            get { 
                if (calendar == null) {
                    BCLDebug.Assert(this.m_cultureTableRecord.IOPTIONALCALENDARS.Length > 0, "this.m_cultureTableRecord.IOPTIONALCALENDARS.Length > 0");
                    // Get the default calendar for this culture.  Note that the value can be
                    // from registry if this is a user default culture. 
                    int calType = this.m_cultureTableRecord.ICALENDARTYPE;
 
                    Calendar newObj = GetCalendarInstance(calType); 
                    System.Threading.Thread.MemoryBarrier();
                    newObj.SetReadOnlyState(m_isReadOnly); 
                    calendar = newObj;
                }
                return (calendar);
            } 
        }
 
        /*=================================OptionCalendars========================== 
        **Action: Return an array of the optional calendar for this culture.
        **Returns: an array of Calendar. 
        **Arguments:
        **Exceptions:
        ============================================================================*/
 

        public virtual Calendar[] OptionalCalendars { 
            get { 
                //
                // This property always returns a new copy of the calendar array. 
                //
                int[] calID = this.m_cultureTableRecord.IOPTIONALCALENDARS;
                Calendar [] cals = new Calendar[calID.Length];
                for (int i = 0; i < cals.Length; i++) { 
                    cals[i] = GetCalendarInstance(calID[i]);
                } 
                return (cals); 
            }
        } 


        public bool UseUserOverride {
            get { 
                return (this.m_cultureTableRecord.UseUserOverride);
            } 
        } 

        [System.Runtime.InteropServices.ComVisible(false)] 
        public CultureInfo GetConsoleFallbackUICulture()
        {
            CultureInfo temp = m_consoleFallbackCulture;
            if (temp == null) 
            {
                temp = GetCultureInfo(this.m_cultureTableRecord.SCONSOLEFALLBACKNAME); 
                temp.m_isReadOnly = true; 
                m_consoleFallbackCulture = temp;
            } 
            return (temp);
        }

 
        public virtual Object Clone()
        { 
            CultureInfo ci = (CultureInfo)MemberwiseClone(); 
            ci.m_isReadOnly = false;
 
            if (!ci.IsNeutralCulture)
            {
                //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
                //they've already been allocated.  If this is a derived type, we'll take a more generic codepath. 
                if (!m_isInherited)
                { 
                    if (dateTimeInfo != null) { 
                        ci.dateTimeInfo = (DateTimeFormatInfo)dateTimeInfo.Clone();
                    } 
                    if (numInfo != null) {
                        ci.numInfo = (NumberFormatInfo)numInfo.Clone();
                    }
 
                } else {
                    ci.DateTimeFormat = (DateTimeFormatInfo)this.DateTimeFormat.Clone(); 
                    ci.NumberFormat   = (NumberFormatInfo)this.NumberFormat.Clone(); 
                }
            } 

            if (textInfo != null)
            {
                ci.textInfo = (TextInfo) textInfo.Clone(); 
            }
 
            if (calendar != null) 
            {
                ci.calendar = (Calendar) calendar.Clone(); 
            }

            return (ci);
        } 

 
        public static CultureInfo ReadOnly(CultureInfo ci) { 
            if (ci == null) {
                throw new ArgumentNullException("ci"); 
            }
            if (ci.IsReadOnly) {
                return (ci);
            } 
            CultureInfo info = (CultureInfo)(ci.MemberwiseClone());
 
            if (!ci.IsNeutralCulture) 
            {
                //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless 
                //they've already been allocated.  If this is a derived type, we'll take a more generic codepath.
                if (!ci.m_isInherited) {
                    if (ci.dateTimeInfo != null) {
                        info.dateTimeInfo = DateTimeFormatInfo.ReadOnly(ci.dateTimeInfo); 
                    }
                    if (ci.numInfo != null) { 
                        info.numInfo = NumberFormatInfo.ReadOnly(ci.numInfo); 
                    }
 
                } else {
                    info.DateTimeFormat = DateTimeFormatInfo.ReadOnly(ci.DateTimeFormat);
                    info.NumberFormat = NumberFormatInfo.ReadOnly(ci.NumberFormat);
                } 
            }
 
            if (ci.textInfo != null) 
            {
                info.textInfo = TextInfo.ReadOnly(ci.textInfo); 
            }

            if (ci.calendar != null)
            { 
                info.calendar = Calendar.ReadOnly(ci.calendar);
            } 
 
            // Don't set the read-only flag too early.
            // We should set the read-only flag here.  Otherwise, info.DateTimeFormat will not be able to set. 
            info.m_isReadOnly = true;

            return (info);
        } 

 
        public bool IsReadOnly { 
            get {
                return (m_isReadOnly); 
            }
        }

        private void VerifyWritable() { 
            if (m_isReadOnly) {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly")); 
            } 
        }
 
        // Helper function both both overloads of GetCachedReadOnlyCulture.  If lcid is 0, we use the name.
        // If lcid is -1, use the altName and create one of those special SQL cultures.
        internal static CultureInfo GetCultureInfoHelper(int lcid, string name, string altName)
        { 
            // retval is our return value.
            CultureInfo retval; 
 
            // Temporary hashtable for the names.
            Hashtable tempNameHT = m_NameCachedCultures; 

            if (name != null)
                name = CultureTableRecord.AnsiToLower(name);
 
            if (altName != null)
                altName = CultureTableRecord.AnsiToLower(altName); 
 
            // We expect the same result for all 3 hashtables, but will test individually for added safety.
            if (tempNameHT == null) 
            {
                tempNameHT = new Hashtable();
            }
            else 
            {
                // If we are called by name, check if the object exists in the hashtable.  If so, return it. 
                if (lcid == -1) 
                {
                    retval = (CultureInfo) tempNameHT[name + '\xfffd' + altName]; 
                    if (retval != null)
                    {
                        return retval;
                    } 
                }
                else if (lcid == 0) 
                { 
                    retval = (CultureInfo) tempNameHT[name];
                    if (retval != null) 
                    {
                        return retval;
                    }
                } 
            }
 
            // Next, the Lcid table. 
            Hashtable tempLcidHT = m_LcidCachedCultures;
 
            if (tempLcidHT == null)
            {
                // Case insensitive is not an issue here, save the constructor call.
                tempLcidHT = new Hashtable(); 
            }
            else 
            { 
                // If we were called by Lcid, check if the object exists in the table.  If so, return it.
                if (lcid > 0) 
                {
                    retval = (CultureInfo) tempLcidHT[lcid];
                    if (retval != null)
                    { 
                        return retval;
                    } 
                } 
            }
 
            // We now have two temporary hashtables and the desired object was not found.
            // We'll construct it.  We catch any exceptions from the constructor call and return null.
            try
            { 
                switch(lcid)
                { 
                    case -1: 
                        // call the private constructor
                        retval = new CultureInfo(name, altName); 
                        break;

                    case 0:
                        retval = new CultureInfo(name, false); 
                        break;
 
                    default: 

                        // 
                        // checking the current culture first is a protection against recursion so the creation
                        // code of CompareInfo is calling GetCultureInfo.
                        // The recursion can happen if we have current user culture is replaced custom culture
                        // and we are trying to create object for that culture and current user culture is not 
                        // stored in our cache.
                        // 
 
                        if (m_userDefaultCulture != null && m_userDefaultCulture.LCID == lcid)
                        { 
                            retval = (CultureInfo) m_userDefaultCulture.Clone();
                            retval.m_cultureTableRecord = retval.m_cultureTableRecord.CloneWithUserOverride(false);
                        }
                        else 
                        {
                            retval = new CultureInfo(lcid, false); 
                        } 
                        break;
                } 
            }
            catch(ArgumentException)
            {
                return null; 
            }
 
            // Set it to read-only 
            retval.m_isReadOnly = true;
 
            if (lcid == -1)
            {
                // This new culture will be added only to the name hash table.
                tempNameHT[name + '\xfffd' + altName] = retval; 

                // when lcid == -1 then TextInfo object is already get created and we need to set it as read only. 
                retval.TextInfo.SetReadOnlyState(true); 
            }
            else 
            {
                // for zh-Hant & zh-Hans we don't store the culture to the LCID cache because the same
                // LCID should point to zh-CHT or zh-CHS instead.
                if (!CultureTable.IsNewNeutralChineseCulture(retval)) 
                {
                    // We add this new culture info object to all 3 hash tables. 
                    tempLcidHT[retval.LCID] = retval; 
                }
 
                // Remember our name (as constructed).  Do NOT use alternate sort name versions because
                // we have internal state representing the sort.  (So someone would get the wrong cached version)
                string newName = CultureTableRecord.AnsiToLower(retval.m_name);
 
                tempNameHT[newName] = retval;
            } 
 
            // Copy the two hashtables to the corresponding member variables.  This will potentially overwrite
            // new tables simultaneously created by a new thread, but maximizes thread safety. 
            if(-1 != lcid)
            {
                // Only when we modify the lcid hash table, is there a need to overwrite.
                m_LcidCachedCultures = tempLcidHT; 
            }
 
            m_NameCachedCultures = tempNameHT; 

            // Finally, return our new CultureInfo object. 
            return retval;
        }

        // Gets a cached copy of the specified culture from an internal hashtable (or creates it 
        // if not found).
        public static CultureInfo GetCultureInfo(int culture) 
        { 
            // Must check for -1 now since the helper function uses the value to signal
            // the altCulture code path for SQL Server. 
            // Also check for zero as this would fail trying to add as a key to the hash.
            if (culture <= 0) {
                throw new ArgumentOutOfRangeException("culture",
                    Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum")); 
            }
 
            CultureInfo retval = GetCultureInfoHelper(culture, null, null); 
            if (null == retval)
            { 
                throw new ArgumentException(
                    Environment.GetResourceString("Argument_CultureNotSupported", culture), "culture");
            }
            return retval; 

        } 
 
        // Gets a cached copy of the specified culture from an internal hashtable (or creates it
        // if not found). 
        public static CultureInfo GetCultureInfo(string name)
        {
            // Make sure we have a valid, non-zero length string as name
            if (name == null) 
            {
                throw new ArgumentNullException("name"); 
            } 

            CultureInfo retval = GetCultureInfoHelper(0, name, null); 
            if (retval == null)
            {
                throw new ArgumentException(
                                String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_InvalidCultureName"), name), 
                                "name");
            } 
            return retval; 
        }
 
        // Gets a cached copy of the specified culture from an internal hashtable (or creates it
        // if not found).
        public static CultureInfo GetCultureInfo(string name, string altName)
        { 
            // Make sure we have a valid, non-zero length string as name
            if (null == name) 
            { 
                throw new ArgumentNullException("name");
            } 

            if (null == altName)
            {
                throw new ArgumentNullException("altName"); 
            }
 
            CultureInfo retval = GetCultureInfoHelper(-1, name, altName); 
            if (retval == null)
            { 
                throw new ArgumentException(
                                String.Format(
                                    CultureInfo.CurrentCulture,
                                    Environment.GetResourceString("Argument_OneOfCulturesNotSupported"), 
                                    name,
                                    altName), 
                                "name"); 
            }
            return retval; 
        }

        public static CultureInfo GetCultureInfoByIetfLanguageTag(string name)
        { 
            if (CultureTable.TraditionalChineseCultureName.Equals(name, StringComparison.OrdinalIgnoreCase) ||
                CultureTable.SimplifiedChineseCultureName.Equals(name, StringComparison.OrdinalIgnoreCase)) 
            { 
                throw new ArgumentException(
                                String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString( 
                                    "Argument_CultureIetfNotSupported"), name),
                                    "name");
            }
 
            CultureInfo ci = GetCultureInfo(name);
 
            if (CultureInfo.GetSortID(ci.cultureID) != 0 || ci.cultureID == CultureTableRecord.SPANISH_TRADITIONAL_SORT) 
            {
                throw new ArgumentException( 
                                String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString(
                                    "Argument_CultureIetfNotSupported"), name),
                                    "name");
            } 

            return ci; 
        } 
    }
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// ==++== 
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--== 
////////////////////////////////////////////////////////////////////////////
// 
//  Class:    CultureInfo 
//
// 
//  Purpose:  This class represents the software preferences of a particular
//            culture or community.  It includes information such as the
//            language, writing system, and a calendar used by the culture
//            as well as methods for common operations such as printing 
//            dates and sorting strings.
// 
//  Date:     [....] 31, 1999 
//
// 
//  !!!! NOTE WHEN CHANGING THIS CLASS !!!!
//
//  If adding or removing members to this class, please update CultureInfoBaseObject
//  in ndp/clr/src/vm/object.h. Note, the "actual" layout of the class may be 
//  different than the order in which members are declared. For instance, all
//  reference types will come first in the class before value types (like ints, bools, etc) 
//  regardless of the order in which they are declared. The best way to see the 
//  actual order of the class is to do a !dumpobj on an instance of the managed
//  object inside of the debugger. 
//
////////////////////////////////////////////////////////////////////////////

namespace System.Globalization { 
    using System;
    using System.Security; 
    using System.Threading; 
    using System.Collections;
    using System.Runtime.CompilerServices; 
    using System.Runtime.InteropServices;
    using System.Runtime.Serialization;
    using System.Security.Permissions;
    using System.Reflection; 
    using Microsoft.Win32;
    using System.Runtime.Versioning; 
 
    [Serializable]
[System.Runtime.InteropServices.ComVisible(true)] 
    public class CultureInfo : ICloneable, IFormatProvider {
        //
        // Special culture IDs
        // 
        internal const int zh_CHT_CultureID = 0x7c04;
        internal const int zh_CHS_CultureID = 0x0004; 
        // Serbian Neutral culture ID. 
        internal const int sr_CultureID = 0x7c1a;
        internal const int sr_SP_Latn_CultureID = 0x081a; 


        //--------------------------------------------------------------------//
        //                        Internal Information                        // 
        //-------------------------------------------------------------------//
 
        //-------------------------------------------------------------------// 
        // Data members to be serialized:
        //-------------------------------------------------------------------// 

        // This is the string used to construct CultureInfo.
        // It is in the format of ISO639 (2 letter language name) plus dash plus
        // ISO 3166 (2 letter region name).  The language name is in lowercase and region name 
        // are in uppercase. (now part of cultureTableRecord)
 
        // 
        // This is the culture ID used in the NLS+ world.  The concept of cultureID is similar
        // to the concept of LCID in Win32.  However, NLS+ support "neutral" culture 
        // which Win32 doesn't support.
        //
        // The format of culture ID (32 bits) is:
        // 
        // 31 - 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
        // +-----+ +---------+ +---------------+ +-----------------+ 
        //    |         |           |            Primary language ID (10 bits) 
        //    |         |           +----------- Sublanguage ID (6 its)
        //    |         +----------------------- Sort ID (4 bits) 
        //    +--------------------------------- Reserved (12 bits)
        //
        // Primary language ID and sublanguage ID can be zero to specify 'neutral' language.
        // For example, cultureID 0x(0000)0009 is the English neutral culture. 
        // cultureID 0x(0000)0000 means the invariant culture (or called neutral culture).
        // 
        // We'd just use cultureTableInfo.cultureID for ID, however cultureTableInfo doesn't 
        // remember the sort info.
 
        // WARNING
        // WARNING: All member fields declared here must also be in ndp/clr/src/vm/object.h
        // WARNING: They aren't really private because object.h can access them, but other C# stuff cannot
        // WARNING 
        internal int cultureID;
        internal bool m_isReadOnly=false; 
 
        internal CompareInfo compareInfo = null;
        internal TextInfo textInfo = null; 
        internal NumberFormatInfo numInfo = null;
        internal DateTimeFormatInfo dateTimeInfo = null;
        internal Calendar calendar = null;
 
        //
        // The CultureTable instance that we are going to read data from. 
        // For supported culture, this will be the CultureTable instance that read data from mscorlib assembly. 
        // For customized culture, this will be the CultureTable instance that read data from user customized culture binary file.
        // 
        [NonSerialized]internal CultureTableRecord m_cultureTableRecord;
        [NonSerialized]internal bool m_isInherited;
        [NonSerialized]private bool m_isSafeCrossDomain = false;
        [NonSerialized]private int m_createdDomainID = 0; 
        [NonSerialized]private CultureInfo m_consoleFallbackCulture = null;
 
        // Names are confusing.  Here are 3 names we have: 
        //
        //  new CultureInfo()   m_name        m_nonSortName   m_sortName 
        //      en-US           en-US           en-US           en-US
        //      de-de_phoneb    de-DE_phoneb    de-DE           de-DE_phoneb
        //      fj-fj (custom)  fj-FJ           fj-FJ           en-US (if specified sort is en-US)
 
        // Note that the name used to be serialized for Everett; it is now serialized
        // because alernate sorts can have alternate names. 
        // This has a de-DE, de-DE_phoneb or fj-FJ style name 
        internal string m_name = null;
 
        // This will hold the non sorting name to be returned from CultureInfo.Name property.
        // This has a de-DE style name even for de-DE_phoneb type cultures
        [NonSerialized]private string m_nonSortName = null;
 
        // This will hold the sorting name to be returned from CultureInfo.SortName property.
        // This might be completely unrelated to the culture name if a custom culture.  Ie en-US for fj-FJ. 
        // Otherwise its the sort name, ie: de-DE or de-DE_phoneb 
        [NonSerialized]private string m_sortName = null;
 

        //--------------------------------------------------------------------//
        //
        // Static data members 
        //
        //-------------------------------------------------------------------// 
 
        //Get the current user default culture.  This one is almost always used, so we create it by default.
        private static CultureInfo m_userDefaultCulture   = null; 

        //
        // All of the following will be created on demand.
        // 

        //The Invariant culture; 
        private static CultureInfo m_InvariantCultureInfo = null; 

        //The culture used in the user interface. This is mostly used to load correct localized resources. 
        private static CultureInfo m_userDefaultUICulture = null;

        //This is the UI culture used to install the OS.
        private static CultureInfo m_InstalledUICultureInfo = null; 

        //This is a cache of all previously created cultures.  Valid keys are LCIDs or the name.  We use two hashtables to track them, 
        // depending on how they are called. 
        private static Hashtable m_LcidCachedCultures = null;
        private static Hashtable m_NameCachedCultures = null; 


        //The parent culture.
        [NonSerialized]private CultureInfo m_parent; 

        // 
        //  Helper Methods. 
        //
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern bool IsValidLCID(int LCID, int flag);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern bool IsWin9xInstalledCulture(string cultureKey, int LCID); 

        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern unsafe String nativeGetUserDefaultLCID(int* LCID, int lcidType); 

        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern unsafe String nativeGetUserDefaultUILanguage(int* LCID);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern unsafe String nativeGetSystemDefaultUILanguage(int* LCID); 

        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern bool nativeSetThreadLocale(int LCID); 

        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern String nativeGetLocaleInfo(int LCID, int field);

        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern int nativeGetCurrentCalendar(); 

        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern unsafe bool nativeGetDTFIUserValues(int lcid, ref DTFIUserOverrideValues values); 

        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern unsafe bool nativeGetNFIUserValues(int lcid, NumberFormatInfo nfi);

        // 
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern unsafe bool nativeGetCultureData(int lcid, ref CultureData cultureData);
 
        //  
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern bool nativeEnumSystemLocales(out int [] localesArray); 

        // 
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern string nativeGetCultureName(int lcid, bool useSNameLCType, bool getMonthName); 

        // 
        // Return the path to the Windows directory (such as c:\Windows).  The returned string does NOT include the backslash. 
        //
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern string nativeGetWindowsDirectory();

        //
        // Check if the specified fileName exists in the file system or not. 
        //
        [MethodImplAttribute(MethodImplOptions.InternalCall)] 
        internal static extern bool nativeFileExists(String fileName); 

        // 
        // Get the static int array data used by globalization classes.
        //
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern unsafe int* nativeGetStaticInt32DataTable(int type, out int tableSize); 
#if !FEATURE_PAL
        // 
        // we didn't make LCMapStringW fast call because in the debug mscorwks we should call LCMapStringW through a wrapper 
        // which can switch to ansi version randomally (to simulate the running in the ansi platforms).
        // 
        // we just need to call the Unicode version all the time as we check running on the Unicode platforms before we proceed
        // while getting the culture data (in nativeGetCultureData)
        //
        //  
        internal static unsafe int GetNativeSortKey(int lcid, int flags, string source, int cchSrc, out byte [] sortKey)
        { 
            sortKey = null; 
            int length;
 
            if (String.IsNullOrEmpty(source) || cchSrc == 0)
            {
                // Empty strings get an empty sort key
                sortKey = new byte[0]; 
                // Fake value to test though so we can verify our flags
                source = "\x0000"; 
                cchSrc = 1; 
            }
 
            fixed (char *src = source)
            {
                length = Win32Native.LCMapStringW(lcid, flags | Win32Native.LCMAP_SORTKEY, src, cchSrc, null, 0);
                if (length == 0) 
                {
                    return -1; 
                } 

                // If input was empty, return the empty byte[] we made earlier and skip this 
                if (sortKey == null)
                {
                    sortKey = new byte[length];
 
                    fixed (byte* key = sortKey)
                    { 
                        length = Win32Native.LCMapStringW(lcid, flags | Win32Native.LCMAP_SORTKEY, src, cchSrc, (char*)key, length); 
                    }
                } 
            }
            return length;
        }
 
#endif // !FEATURE_PAL
 
        internal const int LOCALE_INVARIANT            = 0x007f; 
        private  const int LOCALE_NEUTRAL              = 0x0000;
        internal const int LOCALE_USER_DEFAULT         = 0x0400; 
        internal const int LOCALE_SYSTEM_DEFAULT       = 0x0800;
        internal const int LOCALE_CUSTOM_DEFAULT       = 0x0c00;
        internal const int LOCALE_CUSTOM_UNSPECIFIED   = 0x1000;
        internal const int LOCALE_TRADITIONAL_SPANISH  = 0x040a; 
        internal const int LCID_INSTALLED              = 0x0001;
        internal const int LCID_SUPPORTED              = 0x0002; 
 
        //
        // The CultureTable instance that read data from culture.nlp in the mscorlib assembly. 
        //
        static unsafe CultureInfo()
        {
 
            if (m_InvariantCultureInfo == null)
            { 
                CultureInfo temp = new CultureInfo(LOCALE_INVARIANT, false); 
                temp.m_isReadOnly = true;
                m_InvariantCultureInfo = temp; 
            }
            // First we set it to Invariant in case someone needs it before we're done finding it.
            // For example, if we throw an exception in InitUserDefaultCulture, we will still need an valid
            // m_userDefaultCulture to be used in Thread.CurrentCulture. 
            m_userDefaultCulture = m_userDefaultUICulture = m_InvariantCultureInfo;
 
            m_userDefaultCulture = InitUserDefaultCulture(); 
            m_userDefaultUICulture = InitUserDefaultUICulture();
 
        }

        static unsafe CultureInfo InitUserDefaultCulture()
        { 
            int LCID;
            String strDefault = nativeGetUserDefaultLCID(&LCID, LOCALE_USER_DEFAULT); 
            CultureInfo temp = GetCultureByLCIDOrName(LCID, strDefault); 
            if (temp == null)
            { 
                strDefault = nativeGetUserDefaultLCID(&LCID, LOCALE_SYSTEM_DEFAULT);
                temp = GetCultureByLCIDOrName(LCID, strDefault);

                if (temp == null) 
                {
                    // If system default doesn't work, keep using the invariant 
                    return (CultureInfo.InvariantCulture); 
                }
            } 
            temp.m_isReadOnly = true;

            return (temp);
        } 

        static unsafe CultureInfo InitUserDefaultUICulture() 
        { 
            int LCID;
            String strDefault = nativeGetUserDefaultUILanguage(&LCID); 
            // In most of cases, UserDefaultCulture == UserDefaultUICulture, so we should use the same instance if possible.
            if (LCID == UserDefaultCulture.LCID || strDefault == UserDefaultCulture.Name)
            {
                return (UserDefaultCulture); 
            }
 
            CultureInfo temp = GetCultureByLCIDOrName(LCID, strDefault); 

            if (temp == null) 
            {
                strDefault = nativeGetSystemDefaultUILanguage(&LCID);
                temp = GetCultureByLCIDOrName(LCID, strDefault);
            } 

            if (temp == null) 
            { 
                return (CultureInfo.InvariantCulture);
            } 

            temp.m_isReadOnly = true;

            return (temp); 
        }
 
 

        //////////////////////////////////////////////////////////////////////// 
        //
        //  CultureInfo Constructors
        //
        //////////////////////////////////////////////////////////////////////// 

 
        public CultureInfo(String name) : this(name, true) { 
        }
 

        public CultureInfo(String name, bool useUserOverride) {
            if (name==null) {
                throw new ArgumentNullException("name", 
                    Environment.GetResourceString("ArgumentNull_String"));
            } 
 
            this.m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(name, useUserOverride);
            this.cultureID = this.m_cultureTableRecord.ActualCultureID; 
            this.m_name = this.m_cultureTableRecord.ActualName;
            this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
        }
 

 
        public CultureInfo(int culture) : this(culture, true) { 
        }
 

        public unsafe CultureInfo(int culture, bool useUserOverride) {
            // We don't check for other invalid LCIDS here...
            if (culture < 0) { 
                throw new ArgumentOutOfRangeException("culture",
                    Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum")); 
            } 

            switch (culture) 
            {
                case LOCALE_CUSTOM_DEFAULT:
                    // CONSDIER: Support this LCID value any time the OS is using a custom culture as the user default.
                    //           Note that if this is to be supported that the code below is not correct since it assumes 
                    //           the LCID value is describing the NLS+ culture, not the NLS locale.
/* 
                    this.m_cultureTableRecord = CultureInfo.CurrentCulture.m_cultureTableRecord; 
                    this.cultureID = CultureInfo.CurrentCulture.cultureID;
                    break; 
*/
                case LOCALE_SYSTEM_DEFAULT:
/*
                    String strSystemDefault = nativeGetUserDefaultLCID(&culture, LOCALE_SYSTEM_DEFAULT); 
                    CultureInfo systemDefault;
 
                    // See if we can get our LOCALE_SYSTEM_DEFAULT 
                    systemDefault = GetCultureByLCIDOrName(culture, strSystemDefault);
 
                    if (systemDefault == null)
                        // That didn't work, try invariant
                        systemDefault = InvariantCulture;
 
                    this.cultureID = systemDefault.cultureID;
                    this.m_cultureTableRecord = systemDefault.m_cultureTableRecord; 
                    break; 
*/
                case LOCALE_NEUTRAL: 
                case LOCALE_USER_DEFAULT:
                case LOCALE_CUSTOM_UNSPECIFIED:
                    // Can't support unknown custom cultures and we do not support neutral or
                    // non-custom user locales. 
                    throw new ArgumentException(
                        Environment.GetResourceString("Argument_CultureNotSupported", culture), "culture"); 
                default: 
                    this.cultureID = culture;
                    // Now see if this LCID is supported in the system default culture.nlp table. 
                    this.m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(this.cultureID, useUserOverride);
                    this.m_name = this.m_cultureTableRecord.ActualName;
                    break;
            } 
            m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
        } 
 

        // 
        // CheckDomainSafetyObject throw if the object is customized object which cannot be attached to
        // other object (like CultureInfo or DateTimeFormatInfo).
        //
 
        internal static void CheckDomainSafetyObject(Object obj, Object container)
        { 
            if (obj.GetType().Assembly != typeof(System.Globalization.CultureInfo).Assembly) { 

                throw new InvalidOperationException( 
                            String.Format(
                                CultureInfo.CurrentCulture,
                                Environment.GetResourceString("InvalidOperation_SubclassedObject"),
                                obj.GetType(), 
                                container.GetType()));
            } 
        } 

#region Serialization 
        // the following fields are defined to keep the compatibility with .NET V1.0/V1.1.
        // don't change/remove the names/types of these fields.
        private int     m_dataItem;
        private bool    m_useUserOverride; 

        [OnDeserialized] 
        private void OnDeserialized(StreamingContext ctx) 
        {
            // In .NET ver 1.0 we can get m_name = null if the Name property never requested 
            // before serializing the culture info object.

            BCLDebug.Assert(m_name != null || cultureID>0,  "[CultureInfo.OnDeserialized] m_name != null || cultureID>0");
 
            if (m_name != null && cultureID != LOCALE_TRADITIONAL_SPANISH)
                m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(m_name, m_useUserOverride); 
            else 
                m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(cultureID, m_useUserOverride);
 
            m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));

            if (m_name == null)
            { 
                m_name = m_cultureTableRecord.ActualName;
            } 
 
            // in case we have non customized CultureInfo object we shouldn't allow any customized object
            // to be attached to it for cross app domain safety. 
            if (this.GetType().Assembly == typeof(System.Globalization.CultureInfo).Assembly)
            {
                if (textInfo != null)
                { 
                    CheckDomainSafetyObject(textInfo, this);
                } 
 
                if (compareInfo != null)
                { 
                    CheckDomainSafetyObject(compareInfo, this);
                }
            }
        } 

        [OnSerializing] 
        private void OnSerializing(StreamingContext ctx) 
        {
            m_name              = m_cultureTableRecord.CultureName; 
            m_useUserOverride   = m_cultureTableRecord.UseUserOverride;
            m_dataItem          = m_cultureTableRecord.EverettDataItem();
        }
#endregion Serialization 

        internal bool IsSafeCrossDomain { 
            get { 
                BCLDebug.Assert(m_createdDomainID != 0, "[CultureInfo.IsSafeCrossDomain] m_createdDomainID != 0");
                return m_isSafeCrossDomain; 
            }
        }

        internal int CreatedDomainID { 
            get {
                BCLDebug.Assert(m_createdDomainID != 0,  "[CultureInfo.CreatedDomain] m_createdDomainID != 0"); 
                return m_createdDomainID; 
            }
        } 

        internal void StartCrossDomainTracking() {

            // If we have decided about cross domain safety of this instance, we are done 
            if (m_createdDomainID != 0)
                return; 
 
            if (this.GetType() == typeof(System.Globalization.CultureInfo))
            { 
                m_isSafeCrossDomain = true;
            }

            // m_createdDomainID has to be assigned last. We use it to signal that we have 
            // completed the check.
            System.Threading.Thread.MemoryBarrier(); 
            m_createdDomainID = Thread.GetDomainID(); 
        }
 
        // Constructor called by SQL Server's special munged culture - creates a culture with
        // a TextInfo and CompareInfo that come from a supplied alternate source. This object
        // is ALWAYS read-only.
        // Note that we really cannot use an LCID version of this override as the cached 
        // name we create for it has to include both names, and the logic for this is in
        // the GetCultureInfo override *only*. 
        internal CultureInfo(String cultureName, String textAndCompareCultureName) 
        {
            if (cultureName==null) { 
                throw new ArgumentNullException("cultureName",
                    Environment.GetResourceString("ArgumentNull_String"));
            }
 
            this.m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(cultureName, false);
            this.cultureID = this.m_cultureTableRecord.ActualCultureID; 
            this.m_name = this.m_cultureTableRecord.ActualName; 

            CultureInfo altCulture = GetCultureInfo(textAndCompareCultureName); 

            this.compareInfo = altCulture.CompareInfo;
            this.textInfo = altCulture.TextInfo;
        } 

 
        // Get a culture when trying to create it from LCID or name 
        // This happens when asking windows for the locale information.
        // In this case we want to use LCID if provided, otherwise use 
        // the name.  Using LCID gives us system default values, using
        // names would allow users to override system cultures when we
        // don't expect them to.
        // 
        // Note that this should pick up a CC of the same name for
        // OS ELKS/LIPS/whatever, but will throw if no CC is installed. 
        private static CultureInfo GetCultureByLCIDOrName(int preferLCID, String fallbackToString) 
        {
            // If we don't have a string or we don't have 
            CultureInfo culture = null;

            // We prefer LCID because that gives us the system values, but we can't use
            // it if there's no lang part 
            if ((preferLCID & 0x3ff) != 0)
            { 
                // Try to get it 
                try
                { 
                    culture = new CultureInfo(preferLCID);
                }
                catch (ArgumentException)
                { 
                }
            } 
 
            // If it didn't work by # we need to try string (if possible)
            if (culture == null && fallbackToString != null && fallbackToString.Length > 0) 
            {
                // Try to get it
                try
                { 
                    culture = new CultureInfo(fallbackToString);
                } 
                catch (ArgumentException) 
                {
                } 
            }

            return culture;
        } 

 
 
        public static CultureInfo CreateSpecificCulture(String name) {
            CultureInfo culture; 

            try {
                culture = new CultureInfo(name);
            } catch(ArgumentException exp) { 
                // When CultureInfo throws this exception, it may be because someone passed the form
                // like "az-az" because it came out of an http accept lang. We should try a little 
                // parsing to perhaps fall back to "az" here and use *it* to create the neutral. 

                int idx; 

                culture = null;
                for(idx = 0; idx < name.Length; idx++) {
                    if('-' == name[idx]) { 
                        try {
                            culture = new CultureInfo(name.Substring(0, idx)); 
                            break; 
                        } catch(ArgumentException) {
                            // throw the original exception so the name in the string will be right 
                            throw(exp);
                        }
                    }
                } 

                if(null == culture) { 
                    // nothing to save here; throw the original exception 
                    throw(exp);
                } 
            }

            //In the most common case, they've given us a specific culture, so we'll just return that.
            if (!(culture.IsNeutralCulture)) { 
                return culture;
            } 
 
                int lcid = culture.LCID;
                //If we have the Chinese locale, we have no way of producing a 
                //specific culture without encountering significant geopolitical
                //issues.  Based on that, we have no choice but to return.
                if ((lcid & 0x3FF)==0x04) {
                    throw new ArgumentException(Environment.GetResourceString("Argument_NoSpecificCulture")); 
                }
 
            return (new CultureInfo(culture.m_cultureTableRecord.SSPECIFICCULTURE)); 
        }
 
        internal static bool VerifyCultureName(CultureInfo culture, bool throwException) {
            BCLDebug.Assert(culture!=null, "[CultureInfo.VerifyCultureName]culture!=null");

            //If we have an instance of one of our CultureInfos, the user can't have changed the 
            //name and we know that all names are valid in files.
            if (!culture.m_isInherited) { 
                return true; 
            }
 
            // This function is used by ResourceManager.GetResourceFileName().
            // ResourceManager searches for resource using CultureInfo.Name,
            // so we should check against CultureInfo.Name.
            String name = culture.Name; 

            for (int i=0; i> 10) & 0x3f); 
        }
 
        internal static int GetLangID(int culture)
        {
            return (culture & 0xffff);
        } 

        internal static int GetSortID(int lcid) 
        { 
            return ((lcid >> 16) & 0xf);
        } 

        ////////////////////////////////////////////////////////////////////////
        //
        //  CurrentCulture 
        //
        //  This instance provides methods based on the current user settings. 
        //  These settings are volatile and may change over the lifetime of the 
        //  thread.
        // 
        ////////////////////////////////////////////////////////////////////////


        public static CultureInfo CurrentCulture 
        {
            get { 
                return Thread.CurrentThread.CurrentCulture; 
            }
        } 

        //
        // This is the equivalence of the Win32 GetUserDefaultLCID()
        // 
        internal static CultureInfo UserDefaultCulture {
            get 
            { 
                CultureInfo temp = m_userDefaultCulture;
                if (temp == null) 
                {
                    //
                    // setting the m_userDefaultCulture with invariant culture before intializing it is a protection
                    // against recursion problem just in case if somebody called CurrentCulture from the CultureInfo 
                    // creation path. the recursion can happen if the current user culture is a replaced custom culture.
                    // 
 
                    m_userDefaultCulture = CultureInfo.InvariantCulture;
                    temp = InitUserDefaultCulture(); 
                    m_userDefaultCulture = temp;
                }
                return (temp);
            } 
        }
 
        // 
        //  This is the equivalence of the Win32 GetUserDefaultUILanguage()
        // 
        internal static unsafe CultureInfo UserDefaultUICulture {
            get {
                CultureInfo temp = m_userDefaultUICulture;
                if (temp == null) 
                {
                    // 
                    // setting the m_userDefaultCulture with invariant culture before intializing it is a protection 
                    // against recursion problem just in case if somebody called CurrentUICulture from the CultureInfo
                    // creation path. the recursion can happen if the current user culture is a replaced custom culture. 
                    //

                    m_userDefaultUICulture = CultureInfo.InvariantCulture;
 
                    temp = InitUserDefaultUICulture();
                    m_userDefaultUICulture = temp; 
                } 
                return (temp);
            } 
        }


        public static CultureInfo CurrentUICulture { 
            get {
                return Thread.CurrentThread.CurrentUICulture; 
            } 
        }
 

        //
        // This is the equivalence of the Win32 GetSystemDefaultUILanguage()
        // 
        public static unsafe CultureInfo InstalledUICulture {
            get { 
                CultureInfo temp = m_InstalledUICultureInfo; 
                if (temp == null) {
                    int LCID; 
                    String strDefault = nativeGetSystemDefaultUILanguage(&LCID);
                    temp = GetCultureByLCIDOrName(LCID, strDefault);

                    if (temp == null) 
                    {
                        temp = new CultureInfo(LOCALE_INVARIANT, true); 
                    } 

                    temp.m_isReadOnly = true; 
                    m_InstalledUICultureInfo = temp;
                }
                return (temp);
            } 
        }
 
        //////////////////////////////////////////////////////////////////////// 
        //
        //  InvariantCulture 
        //
        //  This instance provides methods, for example for casing and sorting,
        //  that are independent of the system and current user settings.  It
        //  should be used only by processes such as some system services that 
        //  require such invariant results (eg. file systems).  In general,
        //  the results are not linguistically correct and do not match any 
        //  culture info. 
        //
        //////////////////////////////////////////////////////////////////////// 


        public static CultureInfo InvariantCulture {
            get { 
                return (m_InvariantCultureInfo);
            } 
        } 

 
        ////////////////////////////////////////////////////////////////////////
        //
        //  Parent
        // 
        //  Return the parent CultureInfo for the current instance.
        // 
        //////////////////////////////////////////////////////////////////////// 

        public virtual CultureInfo Parent 
        {
            get
            {
                if (null == m_parent) 
                {
                    try 
                    { 
                        int parentCulture = this.m_cultureTableRecord.IPARENT;
                        if (parentCulture == LOCALE_INVARIANT) 
                        {
                            m_parent = InvariantCulture;
                        }
                        else if (CultureTableRecord.IsCustomCultureId(parentCulture) || 
                                 CultureTable.IsOldNeutralChineseCulture(this))
                        { 
                            // Customized culture -- use the string for the parent. 
                            m_parent = new CultureInfo(this.m_cultureTableRecord.SPARENT);
                        } 
                        else
                        {
                            m_parent = new CultureInfo(parentCulture, this.m_cultureTableRecord.UseUserOverride);
                        } 
                    }
                    catch (ArgumentException) 
                    { 
                        // For whatever reason our IPARENT or SPARENT wasn't correct, so use invariant
                        // We can't allow ourselves to fail.  In case of custom cultures the parent of the 
                        // current custom culture isn't installed.
                        m_parent =  InvariantCulture;
                    }
                } 
                return m_parent;
            } 
        } 

        //////////////////////////////////////////////////////////////////////// 
        //
        //  LCID
        //
        //  Returns a properly formed culture identifier for the current 
        //  culture info.
        // 
        //////////////////////////////////////////////////////////////////////// 

 
        public virtual int LCID {
            get {
                return (this.cultureID);
            } 
        }
 
        //////////////////////////////////////////////////////////////////////// 
        //
        //  BaseInputLanguage 
        //
        //  Essentially an LCID, though one that may be different than LCID in the case
        //  of a customized culture (LCID == -1).
        // 
        ////////////////////////////////////////////////////////////////////////
 
        [System.Runtime.InteropServices.ComVisible(false)] 
        public virtual int KeyboardLayoutId
        { 
            get
            {
                int keyId = this.m_cultureTableRecord.IINPUTLANGUAGEHANDLE;
 
                // Not a customized culture, return the default Keyboard layout ID, which is the same as the language ID.
                return (keyId); 
            } 
        }
 

        public static CultureInfo[] GetCultures(CultureTypes types) {
            return (CultureTable.Default.GetCultures(types));
        } 

 
        //////////////////////////////////////////////////////////////////////// 
        //
        //  Name 
        //
        //  Returns the full name of the CultureInfo. The name is in format like
        //  "en-US"  This version does NOT include sort information in the name.
        // 
        ////////////////////////////////////////////////////////////////////////
        public virtual String Name { 
            get { 
                // We return non sorting name here.
                if (this.m_nonSortName == null) { 
                    this.m_nonSortName  = this.m_cultureTableRecord.CultureName;
                }
                return this.m_nonSortName;
            } 
        }
 
 
        internal String SortName
        { 
            get
            {
                if (this.m_sortName == null)
                { 
                    if (CultureTableRecord.IsCustomCultureId(cultureID))
                    { 
                        CultureInfo sortCI = CultureInfo.GetCultureInfo(CompareInfoId); 

                        BCLDebug.Assert(!CultureTableRecord.IsCustomCultureId(sortCI.cultureID), 
                                        "[CultureInfo.SortName]Expected non-custom sort id");

                        if (CultureTableRecord.IsCustomCultureId(sortCI.cultureID))
                        { 
                            // m_name create could call SortName (not supposed to for CI),
                            // but just to be safe, use SNAME not m_name 
                            this.m_sortName = m_cultureTableRecord.SNAME; 
                        }
                        else 
                        {
                            this.m_sortName = sortCI.SortName;  // Name of culture doing our sort
                        }
                    } 
                    else
                    { 
                        // If its not custom, our sort is our full name 
                        BCLDebug.Assert(m_name != null, "[CultureInfo.SortName]Always expect m_name to be set");
                        this.m_sortName = this.m_name;          // full name, including sort 
                    }
                }
                return this.m_sortName;
            } 
        }
 
        [System.Runtime.InteropServices.ComVisible(false)] 
        public String IetfLanguageTag
        { 
            get
            {
                if (CultureTable.IsOldNeutralChineseCulture(this))
                { 
                    if (this.LCID == zh_CHT_CultureID)    // zh-CHT
                        return CultureTable.NewTraditionalChineseCultureName; 
                    if (this.LCID == zh_CHS_CultureID)    // zh-CHS 
                        return CultureTable.NewSimplifiedChineseCultureName;
                } 
                return this.Name;
            }
        }
 
        ////////////////////////////////////////////////////////////////////////
        // 
        //  DisplayName 
        //
        //  Returns the full name of the CultureInfo in the localized language. 
        //  For example, if the localized language of the runtime is Spanish and the CultureInfo is
        //  US English, "Ingles (Estados Unidos)" will be returned.
        //
        //////////////////////////////////////////////////////////////////////// 

 
        public virtual String DisplayName 
        {
            get 
            {
                BCLDebug.Assert(m_name != null, "[CultureInfo.DisplayName]Always expect m_name to be set");

                if (m_cultureTableRecord.IsCustomCulture) 
                {
                    if (m_cultureTableRecord.IsReplacementCulture) 
                    { 
                        // 
                        if (m_cultureTableRecord.IsSynthetic) 
                            return m_cultureTableRecord.CultureNativeDisplayName;
                        else
                            return (Environment.GetResourceString("Globalization.ci_" + this.m_name));
                    } 
                    else
                    { 
                        return m_cultureTableRecord.SNATIVEDISPLAYNAME; 
                    }
                } 
                else
                {
                    // 
                    if (m_cultureTableRecord.IsSynthetic) 
                        return m_cultureTableRecord.CultureNativeDisplayName;
                    else 
                        return (Environment.GetResourceString("Globalization.ci_" + this.m_name)); 
                }
            } 
        }

        ////////////////////////////////////////////////////////////////////////
        // 
        //  GetNativeName
        // 
        //  Returns the full name of the CultureInfo in the native language. 
        //  For example, if the CultureInfo is US English, "English
        //  (United States)" will be returned. 
        //
        ////////////////////////////////////////////////////////////////////////

 
        public virtual String NativeName {
            get { 
                return (this.m_cultureTableRecord.SNATIVEDISPLAYNAME); 
            }
        } 

        ////////////////////////////////////////////////////////////////////////
        //
        //  GetEnglishName 
        //
        //  Returns the full name of the CultureInfo in English. 
        //  For example, if the CultureInfo is US English, "English 
        //  (United States)" will be returned.
        // 
        ////////////////////////////////////////////////////////////////////////


        public virtual String EnglishName { 
            get {
                return (this.m_cultureTableRecord.SENGDISPLAYNAME); 
            } 
        }
 

        public virtual String TwoLetterISOLanguageName {
            get {
                return (this.m_cultureTableRecord.SISO639LANGNAME); 
            }
        } 
 

        public virtual String ThreeLetterISOLanguageName { 
            get {
                return (this.m_cultureTableRecord.SISO639LANGNAME2);
            }
        } 

        //////////////////////////////////////////////////////////////////////// 
        // 
        //  GetAbbreviatedName
        // 
        //  Returns the abbreviated name for the current instance.  The
        //  abbreviated form is usually based on the ISO 639 standard, for
        //  example the two letter abbreviation for English is "en".
        // 
        ////////////////////////////////////////////////////////////////////////
 
 
       public virtual String ThreeLetterWindowsLanguageName {
            get { 
                return (this.m_cultureTableRecord.SABBREVLANGNAME);
            }
        }
 
        ////////////////////////////////////////////////////////////////////////
        // 
        //  CompareInfo               Read-Only Property 
        //
        //  Gets the CompareInfo for this culture. 
        //
        ////////////////////////////////////////////////////////////////////////

 
        public virtual CompareInfo CompareInfo {
            get { 
                if (compareInfo==null) { 

                    CompareInfo temp; 

                    // In case of non custom neutral cultures we always return compare info with neutral culture id
                    // and neutral culture name. this to be compatible with Everett.
 
                    if (IsNeutralCulture && !CultureTableRecord.IsCustomCultureId(cultureID))
                        temp = CompareInfo.GetCompareInfo(cultureID); 
                    else 
                        temp = CompareInfo.GetCompareInfo(CompareInfoId);
 
                    // The name is not preset when CompareInfo is set by LCID, so lets set it now.
                    temp.SetName(this.SortName);
                    compareInfo = temp;
 
                }
                return (compareInfo); 
            } 
        }
 
        internal int CompareInfoId {
            get {
                int compareId;
 
                if (this.cultureID == LOCALE_TRADITIONAL_SPANISH) {
                    // Special case Trad. Spanish since there is no 
                    // ICOMPAREINFO entry for them. 
                    compareId = LOCALE_TRADITIONAL_SPANISH;
                } else if (GetSortID(this.cultureID) != 0) { 
                    // Special case alternate sorts since there is no
                    // ICOMPAREINFO entry for them.
                    compareId = this.cultureID;
                } else { 
                    compareId = unchecked((int)this.m_cultureTableRecord.ICOMPAREINFO);
                } 
 
                return compareId;
            } 
        }

        ////////////////////////////////////////////////////////////////////////
        // 
        //  TextInfo
        // 
        //  Gets the TextInfo for this culture. 
        //
        //////////////////////////////////////////////////////////////////////// 


        public virtual TextInfo TextInfo {
            get { 
                if (textInfo==null) {
                    // Make a new textInfo 
                    TextInfo tempTextInfo = new TextInfo(this.m_cultureTableRecord); 
                    tempTextInfo.SetReadOnlyState(m_isReadOnly);
                    textInfo = tempTextInfo; 
                }
                return (textInfo);
            }
        } 

        //////////////////////////////////////////////////////////////////////// 
        // 
        //  Equals
        // 
        //  Implements Object.Equals().  Returns a boolean indicating whether
        //  or not object refers to the same CultureInfo as the current instance.
        //
        //////////////////////////////////////////////////////////////////////// 

 
        public override bool Equals(Object value) 
        {
            if (Object.ReferenceEquals(this, value)) 
                return true;

            CultureInfo that = value as CultureInfo;
 
            if (that != null)
            { 
                // using CompareInfo to verify the data passed through the constructor 
                // CultureInfo(String cultureName, String textAndCompareCultureName)
 
                return (this.Name.Equals(that.Name) && this.CompareInfo.Equals(that.CompareInfo));
            }

            return (false); 
        }
 
 
        ////////////////////////////////////////////////////////////////////////
        // 
        //  GetHashCode
        //
        //  Implements Object.GetHashCode().  Returns the hash code for the
        //  CultureInfo.  The hash code is guaranteed to be the same for CultureInfo A 
        //  and B where A.Equals(B) is true.
        // 
        //////////////////////////////////////////////////////////////////////// 

 
        public override int GetHashCode()
        {
            return (this.Name.GetHashCode() + this.CompareInfo.GetHashCode());
        } 

 
        //////////////////////////////////////////////////////////////////////// 
        //
        //  ToString 
        //
        //  Implements Object.ToString().  Returns the name of the CultureInfo,
        //  eg. "English (United States)".
        // 
        ////////////////////////////////////////////////////////////////////////
 
 
        public override String ToString()
        { 
            BCLDebug.Assert(m_name != null, "[CultureInfo.ToString]Always expect m_name to be set");
            return m_name;
        }
 

        public virtual Object GetFormat(Type formatType) { 
            if (formatType == typeof(NumberFormatInfo)) { 
                return (NumberFormat);
            } 
            if (formatType == typeof(DateTimeFormatInfo)) {
                return (DateTimeFormat);
            }
            return (null); 
        }
 
        internal static void CheckNeutral(CultureInfo culture) { 
            if (culture.IsNeutralCulture) {
                    BCLDebug.Assert(culture.m_name != null, "[CultureInfo.CheckNeutral]Always expect m_name to be set"); 
                    throw new NotSupportedException(
                                    Environment.GetResourceString("Argument_CultureInvalidFormat",
                                    culture.m_name));
            } 
        }
 
        public virtual bool IsNeutralCulture { 
            get {
                return this.m_cultureTableRecord.IsNeutralCulture; 
            }
        }

        [System.Runtime.InteropServices.ComVisible(false)] 
        public CultureTypes CultureTypes
        { 
            get 
            {
                CultureTypes types = 0; 

                if (m_cultureTableRecord.IsNeutralCulture)
                    types |= CultureTypes.NeutralCultures;
                else 
                    types |= CultureTypes.SpecificCultures;
 
                if (m_cultureTableRecord.IsSynthetic) 
                    types |= CultureTypes.WindowsOnlyCultures | CultureTypes.InstalledWin32Cultures; // Synthetic is installed culture too.
                else 
                {
                    // Not Synthetic
                    if (CultureTable.IsInstalledLCID(cultureID))
                        types |= CultureTypes.InstalledWin32Cultures; 

                    if (!m_cultureTableRecord.IsCustomCulture || m_cultureTableRecord.IsReplacementCulture) 
                        types |= CultureTypes.FrameworkCultures; 
                }
 
                if (m_cultureTableRecord.IsCustomCulture)
                {
                    types |= CultureTypes.UserCustomCulture;
 
                    if (m_cultureTableRecord.IsReplacementCulture)
                        types |= CultureTypes.ReplacementCultures; 
                } 

 
                return types;
            }
        }
 
        public virtual NumberFormatInfo NumberFormat {
            get { 
                CultureInfo.CheckNeutral(this); 
                if (numInfo == null) {
                    NumberFormatInfo temp = new NumberFormatInfo(this.m_cultureTableRecord); 
                    temp.isReadOnly = m_isReadOnly;
                    numInfo = temp;
                }
                return (numInfo); 
            }
            set { 
                VerifyWritable(); 
                if (value == null) {
                    throw new ArgumentNullException("value", 
                        Environment.GetResourceString("ArgumentNull_Obj"));
                }
                numInfo = value;
            } 
        }
 
        //////////////////////////////////////////////////////////////////////// 
        //
        // GetDateTimeFormatInfo 
        //
        // Create a DateTimeFormatInfo, and fill in the properties according to
        // the CultureID.
        // 
        ////////////////////////////////////////////////////////////////////////
 
 
        public virtual DateTimeFormatInfo DateTimeFormat {
            get { 
                if (dateTimeInfo == null) {
                    CultureInfo.CheckNeutral(this);
                    // Change the calendar of DTFI to the specified calendar of this CultureInfo.
                    DateTimeFormatInfo temp = new DateTimeFormatInfo( 
                        this.m_cultureTableRecord, GetLangID(cultureID), this.Calendar);
                    temp.m_isReadOnly = m_isReadOnly; 
                    System.Threading.Thread.MemoryBarrier(); 
                    dateTimeInfo = temp;
                } 
                return (dateTimeInfo);
            }

            set { 
                VerifyWritable();
                if (value == null) { 
                    throw new ArgumentNullException("value", 
                        Environment.GetResourceString("ArgumentNull_Obj"));
                } 
                dateTimeInfo = value;
            }
        }
 

 
        public unsafe void ClearCachedData() { 
            m_userDefaultUICulture = null;
            m_userDefaultCulture = null; 

            RegionInfo.m_currentRegionInfo = null;

            TimeZone.ResetTimeZone(); 

            // Delete the cached cultures. 
            m_LcidCachedCultures = null; 
            m_NameCachedCultures = null;
 
            CultureTableRecord.ResetCustomCulturesCache();
            CompareInfo.ClearDefaultAssemblyCache();
        }
 
        /*=================================GetCalendarInstance==========================
        **Action: Map a Win32 CALID to an instance of supported calendar. 
        **Returns: An instance of calendar. 
        **Arguments: calType    The Win32 CALID
        **Exceptions: 
        **      Shouldn't throw exception since the calType value is from our data table or from Win32 registry.
        **      If we are in trouble (like getting a weird value from Win32 registry), just return the GregorianCalendar.
        ============================================================================*/
        internal static Calendar GetCalendarInstance(int calType) { 
            if (calType==Calendar.CAL_GREGORIAN) {
                return (new GregorianCalendar()); 
            } 
            return GetCalendarInstanceRare(calType);
        } 

        //This function exists as a shortcut to prevent us from loading all of the non-gregorian
        //calendars unless they're required.
        internal static Calendar GetCalendarInstanceRare(int calType) { 
            BCLDebug.Assert(calType!=Calendar.CAL_GREGORIAN, "calType!=Calendar.CAL_GREGORIAN");
 
            switch (calType) { 
                case Calendar.CAL_GREGORIAN_US:               // Gregorian (U.S.) calendar
                case Calendar.CAL_GREGORIAN_ME_FRENCH:        // Gregorian Middle East French calendar 
                case Calendar.CAL_GREGORIAN_ARABIC:           // Gregorian Arabic calendar
                case Calendar.CAL_GREGORIAN_XLIT_ENGLISH:     // Gregorian Transliterated English calendar
                case Calendar.CAL_GREGORIAN_XLIT_FRENCH:      // Gregorian Transliterated French calendar
                    return (new GregorianCalendar((GregorianCalendarTypes)calType)); 
                case Calendar.CAL_TAIWAN:                     // Taiwan Era calendar
                    return (new TaiwanCalendar()); 
                case Calendar.CAL_JAPAN:                      // Japanese Emperor Era calendar 
                    return (new JapaneseCalendar());
                case Calendar.CAL_KOREA:                      // Korean Tangun Era calendar 
                    return (new KoreanCalendar());
                case Calendar.CAL_HIJRI:                      // Hijri (Arabic Lunar) calendar
                    return (new HijriCalendar());
                case Calendar.CAL_THAI:                       // Thai calendar 
                    return (new ThaiBuddhistCalendar());
                case Calendar.CAL_HEBREW:                     // Hebrew (Lunar) calendar 
                    return (new HebrewCalendar()); 
                case Calendar.CAL_PERSIAN:
                    return (new PersianCalendar()); 
                case Calendar.CAL_UMALQURA:
                    return (new UmAlQuraCalendar());
                case Calendar.CAL_CHINESELUNISOLAR:
                    return (new ChineseLunisolarCalendar()); 
                case Calendar.CAL_JAPANESELUNISOLAR:
                    return (new JapaneseLunisolarCalendar()); 
                case Calendar.CAL_KOREANLUNISOLAR: 
                    return (new KoreanLunisolarCalendar());
                case Calendar.CAL_TAIWANLUNISOLAR: 
                    return (new TaiwanLunisolarCalendar());
            }
            return (new GregorianCalendar());
        } 

 
        /*=================================Calendar========================== 
        **Action: Return/set the default calendar used by this culture.
        ** This value can be overridden by regional option if this is a current culture. 
        **Returns:
        **Arguments:
        **Exceptions:
        **  ArgumentNull_Obj if the set value is null. 
        ============================================================================*/
 
 
        public virtual Calendar Calendar {
            get { 
                if (calendar == null) {
                    BCLDebug.Assert(this.m_cultureTableRecord.IOPTIONALCALENDARS.Length > 0, "this.m_cultureTableRecord.IOPTIONALCALENDARS.Length > 0");
                    // Get the default calendar for this culture.  Note that the value can be
                    // from registry if this is a user default culture. 
                    int calType = this.m_cultureTableRecord.ICALENDARTYPE;
 
                    Calendar newObj = GetCalendarInstance(calType); 
                    System.Threading.Thread.MemoryBarrier();
                    newObj.SetReadOnlyState(m_isReadOnly); 
                    calendar = newObj;
                }
                return (calendar);
            } 
        }
 
        /*=================================OptionCalendars========================== 
        **Action: Return an array of the optional calendar for this culture.
        **Returns: an array of Calendar. 
        **Arguments:
        **Exceptions:
        ============================================================================*/
 

        public virtual Calendar[] OptionalCalendars { 
            get { 
                //
                // This property always returns a new copy of the calendar array. 
                //
                int[] calID = this.m_cultureTableRecord.IOPTIONALCALENDARS;
                Calendar [] cals = new Calendar[calID.Length];
                for (int i = 0; i < cals.Length; i++) { 
                    cals[i] = GetCalendarInstance(calID[i]);
                } 
                return (cals); 
            }
        } 


        public bool UseUserOverride {
            get { 
                return (this.m_cultureTableRecord.UseUserOverride);
            } 
        } 

        [System.Runtime.InteropServices.ComVisible(false)] 
        public CultureInfo GetConsoleFallbackUICulture()
        {
            CultureInfo temp = m_consoleFallbackCulture;
            if (temp == null) 
            {
                temp = GetCultureInfo(this.m_cultureTableRecord.SCONSOLEFALLBACKNAME); 
                temp.m_isReadOnly = true; 
                m_consoleFallbackCulture = temp;
            } 
            return (temp);
        }

 
        public virtual Object Clone()
        { 
            CultureInfo ci = (CultureInfo)MemberwiseClone(); 
            ci.m_isReadOnly = false;
 
            if (!ci.IsNeutralCulture)
            {
                //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
                //they've already been allocated.  If this is a derived type, we'll take a more generic codepath. 
                if (!m_isInherited)
                { 
                    if (dateTimeInfo != null) { 
                        ci.dateTimeInfo = (DateTimeFormatInfo)dateTimeInfo.Clone();
                    } 
                    if (numInfo != null) {
                        ci.numInfo = (NumberFormatInfo)numInfo.Clone();
                    }
 
                } else {
                    ci.DateTimeFormat = (DateTimeFormatInfo)this.DateTimeFormat.Clone(); 
                    ci.NumberFormat   = (NumberFormatInfo)this.NumberFormat.Clone(); 
                }
            } 

            if (textInfo != null)
            {
                ci.textInfo = (TextInfo) textInfo.Clone(); 
            }
 
            if (calendar != null) 
            {
                ci.calendar = (Calendar) calendar.Clone(); 
            }

            return (ci);
        } 

 
        public static CultureInfo ReadOnly(CultureInfo ci) { 
            if (ci == null) {
                throw new ArgumentNullException("ci"); 
            }
            if (ci.IsReadOnly) {
                return (ci);
            } 
            CultureInfo info = (CultureInfo)(ci.MemberwiseClone());
 
            if (!ci.IsNeutralCulture) 
            {
                //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless 
                //they've already been allocated.  If this is a derived type, we'll take a more generic codepath.
                if (!ci.m_isInherited) {
                    if (ci.dateTimeInfo != null) {
                        info.dateTimeInfo = DateTimeFormatInfo.ReadOnly(ci.dateTimeInfo); 
                    }
                    if (ci.numInfo != null) { 
                        info.numInfo = NumberFormatInfo.ReadOnly(ci.numInfo); 
                    }
 
                } else {
                    info.DateTimeFormat = DateTimeFormatInfo.ReadOnly(ci.DateTimeFormat);
                    info.NumberFormat = NumberFormatInfo.ReadOnly(ci.NumberFormat);
                } 
            }
 
            if (ci.textInfo != null) 
            {
                info.textInfo = TextInfo.ReadOnly(ci.textInfo); 
            }

            if (ci.calendar != null)
            { 
                info.calendar = Calendar.ReadOnly(ci.calendar);
            } 
 
            // Don't set the read-only flag too early.
            // We should set the read-only flag here.  Otherwise, info.DateTimeFormat will not be able to set. 
            info.m_isReadOnly = true;

            return (info);
        } 

 
        public bool IsReadOnly { 
            get {
                return (m_isReadOnly); 
            }
        }

        private void VerifyWritable() { 
            if (m_isReadOnly) {
                throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly")); 
            } 
        }
 
        // Helper function both both overloads of GetCachedReadOnlyCulture.  If lcid is 0, we use the name.
        // If lcid is -1, use the altName and create one of those special SQL cultures.
        internal static CultureInfo GetCultureInfoHelper(int lcid, string name, string altName)
        { 
            // retval is our return value.
            CultureInfo retval; 
 
            // Temporary hashtable for the names.
            Hashtable tempNameHT = m_NameCachedCultures; 

            if (name != null)
                name = CultureTableRecord.AnsiToLower(name);
 
            if (altName != null)
                altName = CultureTableRecord.AnsiToLower(altName); 
 
            // We expect the same result for all 3 hashtables, but will test individually for added safety.
            if (tempNameHT == null) 
            {
                tempNameHT = new Hashtable();
            }
            else 
            {
                // If we are called by name, check if the object exists in the hashtable.  If so, return it. 
                if (lcid == -1) 
                {
                    retval = (CultureInfo) tempNameHT[name + '\xfffd' + altName]; 
                    if (retval != null)
                    {
                        return retval;
                    } 
                }
                else if (lcid == 0) 
                { 
                    retval = (CultureInfo) tempNameHT[name];
                    if (retval != null) 
                    {
                        return retval;
                    }
                } 
            }
 
            // Next, the Lcid table. 
            Hashtable tempLcidHT = m_LcidCachedCultures;
 
            if (tempLcidHT == null)
            {
                // Case insensitive is not an issue here, save the constructor call.
                tempLcidHT = new Hashtable(); 
            }
            else 
            { 
                // If we were called by Lcid, check if the object exists in the table.  If so, return it.
                if (lcid > 0) 
                {
                    retval = (CultureInfo) tempLcidHT[lcid];
                    if (retval != null)
                    { 
                        return retval;
                    } 
                } 
            }
 
            // We now have two temporary hashtables and the desired object was not found.
            // We'll construct it.  We catch any exceptions from the constructor call and return null.
            try
            { 
                switch(lcid)
                { 
                    case -1: 
                        // call the private constructor
                        retval = new CultureInfo(name, altName); 
                        break;

                    case 0:
                        retval = new CultureInfo(name, false); 
                        break;
 
                    default: 

                        // 
                        // checking the current culture first is a protection against recursion so the creation
                        // code of CompareInfo is calling GetCultureInfo.
                        // The recursion can happen if we have current user culture is replaced custom culture
                        // and we are trying to create object for that culture and current user culture is not 
                        // stored in our cache.
                        // 
 
                        if (m_userDefaultCulture != null && m_userDefaultCulture.LCID == lcid)
                        { 
                            retval = (CultureInfo) m_userDefaultCulture.Clone();
                            retval.m_cultureTableRecord = retval.m_cultureTableRecord.CloneWithUserOverride(false);
                        }
                        else 
                        {
                            retval = new CultureInfo(lcid, false); 
                        } 
                        break;
                } 
            }
            catch(ArgumentException)
            {
                return null; 
            }
 
            // Set it to read-only 
            retval.m_isReadOnly = true;
 
            if (lcid == -1)
            {
                // This new culture will be added only to the name hash table.
                tempNameHT[name + '\xfffd' + altName] = retval; 

                // when lcid == -1 then TextInfo object is already get created and we need to set it as read only. 
                retval.TextInfo.SetReadOnlyState(true); 
            }
            else 
            {
                // for zh-Hant & zh-Hans we don't store the culture to the LCID cache because the same
                // LCID should point to zh-CHT or zh-CHS instead.
                if (!CultureTable.IsNewNeutralChineseCulture(retval)) 
                {
                    // We add this new culture info object to all 3 hash tables. 
                    tempLcidHT[retval.LCID] = retval; 
                }
 
                // Remember our name (as constructed).  Do NOT use alternate sort name versions because
                // we have internal state representing the sort.  (So someone would get the wrong cached version)
                string newName = CultureTableRecord.AnsiToLower(retval.m_name);
 
                tempNameHT[newName] = retval;
            } 
 
            // Copy the two hashtables to the corresponding member variables.  This will potentially overwrite
            // new tables simultaneously created by a new thread, but maximizes thread safety. 
            if(-1 != lcid)
            {
                // Only when we modify the lcid hash table, is there a need to overwrite.
                m_LcidCachedCultures = tempLcidHT; 
            }
 
            m_NameCachedCultures = tempNameHT; 

            // Finally, return our new CultureInfo object. 
            return retval;
        }

        // Gets a cached copy of the specified culture from an internal hashtable (or creates it 
        // if not found).
        public static CultureInfo GetCultureInfo(int culture) 
        { 
            // Must check for -1 now since the helper function uses the value to signal
            // the altCulture code path for SQL Server. 
            // Also check for zero as this would fail trying to add as a key to the hash.
            if (culture <= 0) {
                throw new ArgumentOutOfRangeException("culture",
                    Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum")); 
            }
 
            CultureInfo retval = GetCultureInfoHelper(culture, null, null); 
            if (null == retval)
            { 
                throw new ArgumentException(
                    Environment.GetResourceString("Argument_CultureNotSupported", culture), "culture");
            }
            return retval; 

        } 
 
        // Gets a cached copy of the specified culture from an internal hashtable (or creates it
        // if not found). 
        public static CultureInfo GetCultureInfo(string name)
        {
            // Make sure we have a valid, non-zero length string as name
            if (name == null) 
            {
                throw new ArgumentNullException("name"); 
            } 

            CultureInfo retval = GetCultureInfoHelper(0, name, null); 
            if (retval == null)
            {
                throw new ArgumentException(
                                String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_InvalidCultureName"), name), 
                                "name");
            } 
            return retval; 
        }
 
        // Gets a cached copy of the specified culture from an internal hashtable (or creates it
        // if not found).
        public static CultureInfo GetCultureInfo(string name, string altName)
        { 
            // Make sure we have a valid, non-zero length string as name
            if (null == name) 
            { 
                throw new ArgumentNullException("name");
            } 

            if (null == altName)
            {
                throw new ArgumentNullException("altName"); 
            }
 
            CultureInfo retval = GetCultureInfoHelper(-1, name, altName); 
            if (retval == null)
            { 
                throw new ArgumentException(
                                String.Format(
                                    CultureInfo.CurrentCulture,
                                    Environment.GetResourceString("Argument_OneOfCulturesNotSupported"), 
                                    name,
                                    altName), 
                                "name"); 
            }
            return retval; 
        }

        public static CultureInfo GetCultureInfoByIetfLanguageTag(string name)
        { 
            if (CultureTable.TraditionalChineseCultureName.Equals(name, StringComparison.OrdinalIgnoreCase) ||
                CultureTable.SimplifiedChineseCultureName.Equals(name, StringComparison.OrdinalIgnoreCase)) 
            { 
                throw new ArgumentException(
                                String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString( 
                                    "Argument_CultureIetfNotSupported"), name),
                                    "name");
            }
 
            CultureInfo ci = GetCultureInfo(name);
 
            if (CultureInfo.GetSortID(ci.cultureID) != 0 || ci.cultureID == CultureTableRecord.SPANISH_TRADITIONAL_SORT) 
            {
                throw new ArgumentException( 
                                String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString(
                                    "Argument_CultureIetfNotSupported"), name),
                                    "name");
            } 

            return ci; 
        } 
    }
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK