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

  1. // ==++==
  2. //
  3. //
  4. // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
  5. //
  6. // The use and distribution terms for this software are contained in the file
  7. // named license.txt, which can be found in the root of this distribution.
  8. // By using this software in any fashion, you are agreeing to be bound by the
  9. // terms of this license.
  10. //
  11. // You must not remove this notice, or any other, from this software.
  12. //
  13. //
  14. // ==--==
  15. ////////////////////////////////////////////////////////////////////////////
  16. //
  17. // Class: CultureInfo
  18. //
  19. //
  20. // Purpose: This class represents the software preferences of a particular
  21. // culture or community. It includes information such as the
  22. // language, writing system, and a calendar used by the culture
  23. // as well as methods for common operations such as printing
  24. // dates and sorting strings.
  25. //
  26. // Date: March 31, 1999
  27. //
  28. //
  29. // !!!! NOTE WHEN CHANGING THIS CLASS !!!!
  30. //
  31. // If adding or removing members to this class, please update CultureInfoBaseObject
  32. // in ndp/clr/src/vm/object.h. Note, the "actual" layout of the class may be
  33. // different than the order in which members are declared. For instance, all
  34. // reference types will come first in the class before value types (like ints, bools, etc)
  35. // regardless of the order in which they are declared. The best way to see the
  36. // actual order of the class is to do a !dumpobj on an instance of the managed
  37. // object inside of the debugger.
  38. //
  39. ////////////////////////////////////////////////////////////////////////////
  40. namespace System.Globalization
  41. {
  42.     using System;
  43.     using System.Threading;
  44.     using System.Collections;
  45.     using System.Runtime.CompilerServices;
  46.     using System.Runtime.InteropServices;
  47.     using System.Runtime.Serialization;
  48.     using System.Security.Permissions;
  49.     using System.Reflection;
  50.     using Microsoft.Win32;
  51.     using System.Runtime.Versioning;
  52.    
  53.     [Serializable()]
  54.     [System.Runtime.InteropServices.ComVisible(true)]
  55.     public class CultureInfo : ICloneable, IFormatProvider
  56.     {
  57.         //
  58.         // Special culture IDs
  59.         //
  60.         internal const int zh_CHT_CultureID = 31748;
  61.         // Serbian Neutral culture ID.
  62.         internal const int sr_CultureID = 31770;
  63.         internal const int sr_SP_Latn_CultureID = 2074;
  64.        
  65.         // Ietf name registry location
  66.        
  67.         //--------------------------------------------------------------------//
  68.         // Internal Information //
  69.         //--------------------------------------------------------------------//
  70.        
  71.         //--------------------------------------------------------------------//
  72.         // Data members to be serialized:
  73.         //--------------------------------------------------------------------//
  74.        
  75.         // This is the string used to construct CultureInfo.
  76.         // It is in the format of ISO639 (2 letter language name) plus dash plus
  77.         // ISO 3166 (2 letter region name). The language name is in lowercase and region name
  78.         // are in uppercase. (now part of cultureTableRecord)
  79.        
  80.         //
  81.         // This is the culture ID used in the NLS+ world. The concept of cultureID is similar
  82.         // to the concept of LCID in Win32. However, NLS+ support "neutral" culture
  83.         // which Win32 doesn't support.
  84.         //
  85.         // The format of culture ID (32 bits) is:
  86.         //
  87.         // 31 - 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
  88.         // +-----+ +---------+ +---------------+ +-----------------+
  89.         // | | | Primary language ID (10 bits)
  90.         // | | +----------- Sublanguage ID (6 its)
  91.         // | +----------------------- Sort ID (4 bits)
  92.         // +--------------------------------- Reserved (12 bits)
  93.         //
  94.         // Primary language ID and sublanguage ID can be zero to specify 'neutral' language.
  95.         // For example, cultureID 0x(0000)0009 is the English neutral culture.
  96.         // cultureID 0x(0000)0000 means the invariant culture (or called neutral culture).
  97.         //
  98.         // We'd just use cultureTableInfo.cultureID for ID, however cultureTableInfo doesn't
  99.         // remember the sort info.
  100.        
  101.         // WARNING
  102.         // WARNING: All member fields declared here must also be in ndp/clr/src/vm/object.h
  103.         // WARNING: They aren't really private because object.h can access them, but other C# stuff cannot
  104.         // WARNING
  105.         internal int cultureID;
  106.         internal bool m_isReadOnly = false;
  107.        
  108.         internal CompareInfo compareInfo = null;
  109.         internal TextInfo textInfo = null;
  110.         internal NumberFormatInfo numInfo = null;
  111.         internal DateTimeFormatInfo dateTimeInfo = null;
  112.         internal Calendar calendar = null;
  113.        
  114.         //
  115.         // The CultureTable instance that we are going to read data from.
  116.         // For supported culture, this will be the CultureTable instance that read data from mscorlib assembly.
  117.         // For customized culture, this will be the CultureTable instance that read data from user customized culture binary file.
  118.         //
  119.         [NonSerialized()]
  120.         internal CultureTableRecord m_cultureTableRecord;
  121.         [NonSerialized()]
  122.         internal bool m_isInherited;
  123.         [NonSerialized()]
  124.         private bool m_isSafeCrossDomain = false;
  125.         [NonSerialized()]
  126.         private int m_createdDomainID = 0;
  127.         [NonSerialized()]
  128.         private CultureInfo m_consoleFallbackCulture = null;
  129.        
  130.         //
  131.        
  132.         internal string m_name = null;
  133.        
  134.         // This will hold the non sorting name to be returned from CultureInfo.Name property.
  135.         // This has a de-DE style name even for de-DE_phoneb type cultures
  136.         [NonSerialized()]
  137.         private string m_nonSortName = null;
  138.        
  139.         // This will hold the sorting name to be returned from CultureInfo.SortName property.
  140.         // This might be completely unrelated to the culture name if a custom culture. Ie en-US for fj-FJ.
  141.         // Otherwise its the sort name, ie: de-DE or de-DE_phoneb
  142.         [NonSerialized()]
  143.         private string m_sortName = null;
  144.        
  145.         // Ietf name
  146.         [NonSerialized()]
  147.         private string m_ietfName = null;
  148.        
  149.         //--------------------------------------------------------------------//
  150.         //
  151.         // Static data members
  152.         //
  153.         //--------------------------------------------------------------------//
  154.        
  155.         //Get the current user default culture. This one is almost always used, so we create it by default.
  156.         private static CultureInfo m_userDefaultCulture = null;
  157.        
  158.         //
  159.         // All of the following will be created on demand.
  160.         //
  161.        
  162.         //The Invariant culture;
  163.         private static CultureInfo m_InvariantCultureInfo = null;
  164.        
  165.         //The culture used in the user interface. This is mostly used to load correct localized resources.
  166.         private static CultureInfo m_userDefaultUICulture = null;
  167.        
  168.         //This is the UI culture used to install the OS.
  169.         private static CultureInfo m_InstalledUICultureInfo = null;
  170.        
  171.         //This is a cache of all previously created cultures. Valid keys are LCIDs or the name. We use two hashtables to track them,
  172.         // depending on how they are called.
  173.         private static Hashtable m_LcidCachedCultures = null;
  174.         private static Hashtable m_NameCachedCultures = null;
  175.         private static Hashtable m_IetfCachedCultures = null;
  176.        
  177.         // May need a registry key if looking up ietf names by name
  178.        
  179.         //The parent culture.
  180.         [NonSerialized()]
  181.         private CultureInfo m_parent;
  182.        
  183.         //
  184.         // Helper Methods.
  185.         //
  186.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  187.         static internal extern bool IsValidLCID(int LCID, int flag);
  188.        
  189.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  190.         static internal extern bool IsWin9xInstalledCulture(string cultureKey, int LCID);
  191.        
  192.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  193.         unsafe static internal extern string nativeGetUserDefaultLCID(int* LCID, int lcidType);
  194.        
  195.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  196.         unsafe static internal extern string nativeGetUserDefaultUILanguage(int* LCID);
  197.        
  198.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  199.         unsafe static internal extern string nativeGetSystemDefaultUILanguage(int* LCID);
  200.        
  201.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  202.         static internal extern bool nativeSetThreadLocale(int LCID);
  203.        
  204.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  205.         static internal extern string nativeGetLocaleInfo(int LCID, int field);
  206.        
  207.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  208.         static internal extern int nativeGetCurrentCalendar();
  209.        
  210.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  211.         unsafe static internal extern bool nativeGetDTFIUserValues(int lcid, ref DTFIUserOverrideValues values);
  212.        
  213.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  214.         unsafe static internal extern bool nativeGetNFIUserValues(int lcid, NumberFormatInfo nfi);
  215.        
  216.         // <SyntheticSupport/>
  217.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  218.         unsafe static internal extern bool nativeGetCultureData(int lcid, ref CultureData cultureData);
  219.        
  220.         // <SyntheticSupport/>
  221.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  222.         static internal extern bool nativeEnumSystemLocales(out int[] localesArray);
  223.        
  224.         // <SyntheticSupport/>
  225.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  226.         static internal extern string nativeGetCultureName(int lcid, bool useSNameLCType, bool getMonthName);
  227.        
  228.         //
  229.         // Return the path to the Windows directory (such as c:\Windows). The returned string does NOT include the backslash.
  230.         //
  231.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  232.         static internal extern string nativeGetWindowsDirectory();
  233.        
  234.         //
  235.         // Check if the specified fileName exists in the file system or not.
  236.         //
  237.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  238.         static internal extern bool nativeFileExists(string fileName);
  239.        
  240.         //
  241.         // Get the static int array data used by globalization classes.
  242.         //
  243.         [MethodImplAttribute(MethodImplOptions.InternalCall)]
  244.         unsafe static internal extern int* nativeGetStaticInt32DataTable(int type, out int tableSize);
  245.        
  246.         internal const int LOCALE_INVARIANT = 127;
  247.         private const int LOCALE_NEUTRAL = 0;
  248.         internal const int LOCALE_USER_DEFAULT = 1024;
  249.         internal const int LOCALE_SYSTEM_DEFAULT = 2048;
  250.         internal const int LOCALE_CUSTOM_DEFAULT = 3072;
  251.         internal const int LOCALE_CUSTOM_UNSPECIFIED = 4096;
  252.         internal const int LOCALE_TRADITIONAL_SPANISH = 1034;
  253.         internal const int LCID_INSTALLED = 1;
  254.         internal const int LCID_SUPPORTED = 2;
  255.        
  256.         //
  257.         // The CultureTable instance that read data from culture.nlp in the mscorlib assembly.
  258.         //
  259.         unsafe static CultureInfo()
  260.         {
  261.            
  262.             if (m_InvariantCultureInfo == null) {
  263.                 CultureInfo temp = new CultureInfo(LOCALE_INVARIANT, false);
  264.                 temp.m_isReadOnly = true;
  265.                 m_InvariantCultureInfo = temp;
  266.             }
  267.             // First we set it to Invariant in case someone needs it before we're done finding it.
  268.             // For example, if we throw an exception in InitUserDefaultCulture, we will still need an valid
  269.             // m_userDefaultCulture to be used in Thread.CurrentCulture.
  270.             m_userDefaultCulture = m_userDefaultUICulture = m_InvariantCultureInfo;
  271.            
  272.             m_userDefaultCulture = InitUserDefaultCulture();
  273.             m_userDefaultUICulture = InitUserDefaultUICulture();
  274.            
  275.         }
  276.        
  277.         unsafe static CultureInfo InitUserDefaultCulture()
  278.         {
  279.             int LCID;
  280.             string strDefault = nativeGetUserDefaultLCID(&LCID, LOCALE_USER_DEFAULT);
  281.             CultureInfo temp = GetCultureByLCIDOrName(LCID, strDefault);
  282.             if (temp == null) {
  283.                 strDefault = nativeGetUserDefaultLCID(&LCID, LOCALE_SYSTEM_DEFAULT);
  284.                 temp = GetCultureByLCIDOrName(LCID, strDefault);
  285.                
  286.                 if (temp == null) {
  287.                     return (CultureInfo.InvariantCulture);
  288.                 }
  289.             }
  290.             temp.m_isReadOnly = true;
  291.            
  292.             return (temp);
  293.         }
  294.        
  295.         unsafe static CultureInfo InitUserDefaultUICulture()
  296.         {
  297.             int LCID;
  298.             string strDefault = nativeGetUserDefaultUILanguage(&LCID);
  299.             // In most of cases, UserDefaultCulture == UserDefaultUICulture, so we should use the same instance if possible.
  300.             if (LCID == UserDefaultCulture.LCID || strDefault == UserDefaultCulture.Name) {
  301.                 return (UserDefaultCulture);
  302.             }
  303.            
  304.             CultureInfo temp = GetCultureByLCIDOrName(LCID, strDefault);
  305.            
  306.             if (temp == null) {
  307.                 strDefault = nativeGetSystemDefaultUILanguage(&LCID);
  308.                 temp = GetCultureByLCIDOrName(LCID, strDefault);
  309.             }
  310.            
  311.             if (temp == null) {
  312.                 return (CultureInfo.InvariantCulture);
  313.             }
  314.            
  315.             temp.m_isReadOnly = true;
  316.            
  317.             return (temp);
  318.         }
  319.        
  320.        
  321.        
  322.         ////////////////////////////////////////////////////////////////////////
  323.         //
  324.         // CultureInfo Constructors
  325.         //
  326.         ////////////////////////////////////////////////////////////////////////
  327.        
  328.        
  329.         public CultureInfo(string name) : this(name, true)
  330.         {
  331.         }
  332.        
  333.        
  334.         public CultureInfo(string name, bool useUserOverride)
  335.         {
  336.             if (name == null) {
  337.                 throw new ArgumentNullException("name", Environment.GetResourceString("ArgumentNull_String"));
  338.             }
  339.            
  340.             this.m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(name, useUserOverride);
  341.             this.cultureID = this.m_cultureTableRecord.ActualCultureID;
  342.             this.m_name = this.m_cultureTableRecord.ActualName;
  343.             this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
  344.         }
  345.        
  346.        
  347.        
  348.         public CultureInfo(int culture) : this(culture, true)
  349.         {
  350.         }
  351.        
  352.        
  353.         unsafe public CultureInfo(int culture, bool useUserOverride)
  354.         {
  355.             // We don't check for other invalid LCIDS here...
  356.             if (culture < 0) {
  357.                 throw new ArgumentOutOfRangeException("culture", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
  358.             }
  359.            
  360.             switch (culture) {
  361.                 case LOCALE_CUSTOM_DEFAULT:
  362.                 case LOCALE_SYSTEM_DEFAULT:
  363.                 case LOCALE_NEUTRAL:
  364.                 case LOCALE_USER_DEFAULT:
  365.                 case LOCALE_CUSTOM_UNSPECIFIED:
  366.                     // CONSDIER: Support this LCID value any time the OS is using a custom culture as the user default.
  367.                     // Note that if this is to be supported that the code below is not correct since it assumes
  368.                     // the LCID value is describing the NLS+ culture, not the NLS locale.
  369.                     /*
  370.                     this.m_cultureTableRecord = CultureInfo.CurrentCulture.m_cultureTableRecord;
  371.                     this.cultureID = CultureInfo.CurrentCulture.cultureID;
  372.                     break;
  373. */                   
  374. /*
  375.                     String strSystemDefault = nativeGetUserDefaultLCID(&culture, LOCALE_SYSTEM_DEFAULT);
  376.                     CultureInfo systemDefault;
  377.                     // See if we can get our LOCALE_SYSTEM_DEFAULT
  378.                     systemDefault = GetCultureByLCIDOrName(culture, strSystemDefault);
  379.                     if (systemDefault == null)
  380.                         //                                               
  381.                         systemDefault = InvariantCulture;
  382.                     this.cultureID = systemDefault.cultureID;
  383.                     this.m_cultureTableRecord = systemDefault.m_cultureTableRecord;
  384.                     break;
  385. */                   
  386.                     // Can't support unknown custom cultures and we do not support neutral or
  387.                     // non-custom user locales.
  388. throw new ArgumentException(Environment.GetResourceString("Argument_CultureNotSupported", culture), "culture");
  389.                     break;
  390.                 default:
  391.                     this.cultureID = culture;
  392.                     // Now see if this LCID is supported in the system default culture.nlp table.
  393.                     this.m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(this.cultureID, useUserOverride);
  394.                     this.m_name = this.m_cultureTableRecord.ActualName;
  395.                     break;
  396.             }
  397.             m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
  398.         }
  399.        
  400.        
  401.         //
  402.         // CheckDomainSafetyObject throw if the object is customized object which cannot be attached to
  403.         // other object (like CultureInfo or DateTimeFormatInfo).
  404.         //
  405.        
  406.         static internal void CheckDomainSafetyObject(object obj, object container)
  407.         {
  408.             if (obj.GetType().Assembly != typeof(System.Globalization.CultureInfo).Assembly) {
  409.                
  410.                 throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("InvalidOperation_SubclassedObject"), obj.GetType(), container.GetType()));
  411.             }
  412.         }
  413.        
  414.         #region Serialization
  415.         // the following fields are defined to keep the compatibility with .NET V1.0/V1.1.
  416.         // don't change/remove the names/types of these fields.
  417.         private int m_dataItem;
  418.         private bool m_useUserOverride;
  419.        
  420.         [OnDeserialized()]
  421.         private void OnDeserialized(StreamingContext ctx)
  422.         {
  423.             // In .NET ver 1.0 we can get m_name = null if the Name property never requested
  424.             // before serializing the culture info object.
  425.            
  426.             BCLDebug.Assert(m_name != null || cultureID > 0, "[CultureInfo.OnDeserialized] m_name != null || cultureID>0");
  427.            
  428.             if (m_name != null && cultureID != LOCALE_TRADITIONAL_SPANISH)
  429.                 m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(m_name, m_useUserOverride);
  430.             else
  431.                 m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(cultureID, m_useUserOverride);
  432.            
  433.             m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
  434.            
  435.             if (m_name == null) {
  436.                 m_name = m_cultureTableRecord.ActualName;
  437.             }
  438.            
  439.             // in case we have non customized CultureInfo object we shouldn't allow any customized object
  440.             // to be attached to it for cross app domain safety.
  441.             if (this.GetType().Assembly == typeof(System.Globalization.CultureInfo).Assembly) {
  442.                 if (textInfo != null) {
  443.                     CheckDomainSafetyObject(textInfo, this);
  444.                 }
  445.                
  446.                 if (compareInfo != null) {
  447.                     CheckDomainSafetyObject(compareInfo, this);
  448.                 }
  449.             }
  450.         }
  451.        
  452.         [OnSerializing()]
  453.         private void OnSerializing(StreamingContext ctx)
  454.         {
  455.             m_name = m_cultureTableRecord.CultureName;
  456.             m_useUserOverride = m_cultureTableRecord.UseUserOverride;
  457.             m_dataItem = m_cultureTableRecord.EverettDataItem();
  458.         }
  459.         #endregion Serialization
  460.        
  461.         internal bool IsSafeCrossDomain {
  462.             get {
  463.                 BCLDebug.Assert(m_createdDomainID != 0, "[CultureInfo.IsSafeCrossDomain] m_createdDomainID != 0");
  464.                 return m_isSafeCrossDomain;
  465.             }
  466.         }
  467.        
  468.         internal int CreatedDomainID {
  469.             get {
  470.                 BCLDebug.Assert(m_createdDomainID != 0, "[CultureInfo.CreatedDomain] m_createdDomainID != 0");
  471.                 return m_createdDomainID;
  472.             }
  473.         }
  474.        
  475.         internal void StartCrossDomainTracking()
  476.         {
  477.            
  478.             // If we have decided about cross domain safety of this instance, we are done
  479.             if (m_createdDomainID != 0)
  480.                 return;
  481.            
  482.             if (this.GetType() == typeof(System.Globalization.CultureInfo)) {
  483.                 m_isSafeCrossDomain = true;
  484.             }
  485.            
  486.             // m_createdDomainID has to be assigned last. We use it to signal that we have
  487.             // completed the check.
  488.             System.Threading.Thread.MemoryBarrier();
  489.             m_createdDomainID = Thread.GetDomainID();
  490.         }
  491.        
  492.         // Constructor called by SQL Server's special munged culture - creates a culture with
  493.         // a TextInfo and CompareInfo that come from a supplied alternate source. This object
  494.         // is ALWAYS read-only.
  495.         // Note that we really cannot use an LCID version of this override as the cached
  496.         // name we create for it has to include both names, and the logic for this is in
  497.         // the GetCultureInfo override *only*.
  498.         internal CultureInfo(string cultureName, string textAndCompareCultureName)
  499.         {
  500.             if (cultureName == null) {
  501.                 throw new ArgumentNullException("cultureName", Environment.GetResourceString("ArgumentNull_String"));
  502.             }
  503.            
  504.             this.m_cultureTableRecord = CultureTableRecord.GetCultureTableRecord(cultureName, false);
  505.             this.cultureID = this.m_cultureTableRecord.ActualCultureID;
  506.             this.m_name = this.m_cultureTableRecord.ActualName;
  507.            
  508.             CultureInfo altCulture = GetCultureInfo(textAndCompareCultureName);
  509.            
  510.             this.compareInfo = altCulture.CompareInfo;
  511.             this.textInfo = altCulture.TextInfo;
  512.         }
  513.        
  514.        
  515.         // Get a culture when trying to create it from LCID or name
  516.         // This happens when asking windows for the locale information.
  517.         // In this case we want to use LCID if provided, otherwise use
  518.         // the name. Using LCID gives us system default values, using
  519.         // names would allow users to override system cultures when we
  520.         // don't expect them to.
  521.         //
  522.         // Note that this should pick up a CC of the same name for
  523.         // OS ELKS/LIPS/whatever, but will throw if no CC is installed.
  524.         private static CultureInfo GetCultureByLCIDOrName(int preferLCID, string fallbackToString)
  525.         {
  526.             // If we don't have a string or we don't have
  527.             CultureInfo culture = null;
  528.            
  529.             // We prefer LCID because that gives us the system values, but we can't use
  530.             // it if there's no lang part
  531.             if ((preferLCID & 1023) != 0) {
  532.                 // Try to get it
  533.                 try {
  534.                     culture = new CultureInfo(preferLCID);
  535.                 }
  536.                 catch (ArgumentException) {
  537.                 }
  538.             }
  539.            
  540.             if (culture == null && fallbackToString != null && fallbackToString.Length > 0) {
  541.                 // Try to get it
  542.                 try {
  543.                     culture = new CultureInfo(fallbackToString);
  544.                 }
  545.                 catch (ArgumentException) {
  546.                 }
  547.             }
  548.            
  549.             return culture;
  550.         }
  551.        
  552.        
  553.        
  554.         public static CultureInfo CreateSpecificCulture(string name)
  555.         {
  556.             CultureInfo culture;
  557.            
  558.             try {
  559.                 culture = new CultureInfo(name);
  560.             }
  561.             catch (ArgumentException exp) {
  562.                 // When CultureInfo throws this exception, it may be because someone passed the form
  563.                 // like "az-az" because it came out of an http accept lang. We should try a little
  564.                 // parsing to perhaps fall back to "az" here and use *it* to create the neutral.
  565.                
  566.                 int idx;
  567.                
  568.                 culture = null;
  569.                 for (idx = 0; idx < name.Length; idx++) {
  570.                     if ('-' == name[idx]) {
  571.                         try {
  572.                             culture = new CultureInfo(name.Substring(0, idx));
  573.                             break;
  574.                         }
  575.                         catch (ArgumentException) {
  576.                             // throw the original exception so the name in the string will be right
  577.                             throw (exp);
  578.                         }
  579.                     }
  580.                 }
  581.                
  582.                 if (null == culture) {
  583.                     // nothing to save here; throw the original exception
  584.                     throw (exp);
  585.                 }
  586.             }
  587.            
  588.             //In the most common case, they've given us a specific culture, so we'll just return that.
  589.             if (!(culture.IsNeutralCulture)) {
  590.                 return culture;
  591.             }
  592.            
  593.             int lcid = culture.LCID;
  594.             //If we have the Chinese locale, we have no way of producing a
  595.             //specific culture without encountering significant geopolitical
  596.             //issues. Based on that, we have no choice but to return.
  597.             if ((lcid & 1023) == 4) {
  598.                 throw new ArgumentException(Environment.GetResourceString("Argument_NoSpecificCulture"));
  599.             }
  600.            
  601.             return (new CultureInfo(culture.m_cultureTableRecord.SSPECIFICCULTURE));
  602.         }
  603.        
  604.         static internal bool VerifyCultureName(CultureInfo culture, bool throwException)
  605.         {
  606.             BCLDebug.Assert(culture != null, "[CultureInfo.VerifyCultureName]culture!=null");
  607.            
  608.             //If we have an instance of one of our CultureInfos, the user can't have changed the
  609.             //name and we know that all names are valid in files.
  610.             if (!culture.m_isInherited) {
  611.                 return true;
  612.             }
  613.            
  614.             // This function is used by ResourceManager.GetResourceFileName().
  615.             // ResourceManager searches for resource using CultureInfo.Name,
  616.             // so we should check against CultureInfo.Name.
  617.             string name = culture.Name;
  618.            
  619.             for (int i = 0; i < name.Length; i++) {
  620.                 char c = name[i];
  621.                 if (Char.IsLetterOrDigit(c) || c == '-' || c == '_') {
  622.                     continue;
  623.                 }
  624.                 if (throwException) {
  625.                     throw new ArgumentException(Environment.GetResourceString("Argument_InvalidResourceCultureName", name));
  626.                 }
  627.                 return false;
  628.             }
  629.             return true;
  630.         }
  631.        
  632.         //--------------------------------------------------------------------//
  633.         // Misc static functions //
  634.         //--------------------------------------------------------------------//
  635.        
  636.         static internal int GetSubLangID(int culture)
  637.         {
  638.             return ((culture >> 10) & 63);
  639.         }
  640.        
  641.         static internal int GetLangID(int culture)
  642.         {
  643.             return (culture & 65535);
  644.         }
  645.        
  646.         static internal int GetSortID(int lcid)
  647.         {
  648.             return ((lcid >> 16) & 15);
  649.         }
  650.        
  651.         ////////////////////////////////////////////////////////////////////////
  652.         //
  653.         // CurrentCulture
  654.         //
  655.         // This instance provides methods based on the current user settings.
  656.         // These settings are volatile and may change over the lifetime of the
  657.         // thread.
  658.         //
  659.         ////////////////////////////////////////////////////////////////////////
  660.        
  661.        
  662.         public static CultureInfo CurrentCulture {
  663.             get { return Thread.CurrentThread.CurrentCulture; }
  664.         }
  665.        
  666.         //
  667.         // This is the equivalence of the Win32 GetUserDefaultLCID()
  668.         //
  669.         static internal CultureInfo UserDefaultCulture {
  670.             get {
  671.                 CultureInfo temp = m_userDefaultCulture;
  672.                 if (temp == null) {
  673.                     //
  674.                     // setting the m_userDefaultCulture with invariant culture before intializing it is a protection
  675.                     // against recursion problem just in case if somebody called CurrentCulture from the CultureInfo
  676.                     // creation path. the recursion can happen if the current user culture is a replaced custom culture.
  677.                     //
  678.                    
  679.                     m_userDefaultCulture = CultureInfo.InvariantCulture;
  680.                     temp = InitUserDefaultCulture();
  681.                     m_userDefaultCulture = temp;
  682.                 }
  683.                 return (temp);
  684.             }
  685.         }
  686.        
  687.         //
  688.         // This is the equivalence of the Win32 GetUserDefaultUILanguage()
  689.         //
  690.         unsafe static internal CultureInfo UserDefaultUICulture {
  691.             get {
  692.                 CultureInfo temp = m_userDefaultUICulture;
  693.                 if (temp == null) {
  694.                     //
  695.                     // setting the m_userDefaultCulture with invariant culture before intializing it is a protection
  696.                     // against recursion problem just in case if somebody called CurrentUICulture from the CultureInfo
  697.                     // creation path. the recursion can happen if the current user culture is a replaced custom culture.
  698.                     //
  699.                    
  700.                     m_userDefaultUICulture = CultureInfo.InvariantCulture;
  701.                    
  702.                     temp = InitUserDefaultUICulture();
  703.                     m_userDefaultUICulture = temp;
  704.                 }
  705.                 return (temp);
  706.             }
  707.         }
  708.        
  709.        
  710.         public static CultureInfo CurrentUICulture {
  711.             get { return Thread.CurrentThread.CurrentUICulture; }
  712.         }
  713.        
  714.        
  715.         //
  716.         // This is the equivalence of the Win32 GetSystemDefaultUILanguage()
  717.         //
  718.         unsafe public static CultureInfo InstalledUICulture {
  719.             get {
  720.                 CultureInfo temp = m_InstalledUICultureInfo;
  721.                 if (temp == null) {
  722.                     int LCID;
  723.                     string strDefault = nativeGetSystemDefaultUILanguage(&LCID);
  724.                     temp = GetCultureByLCIDOrName(LCID, strDefault);
  725.                    
  726.                     if (temp == null) {
  727.                         temp = new CultureInfo(LOCALE_INVARIANT, true);
  728.                     }
  729.                    
  730.                     temp.m_isReadOnly = true;
  731.                     m_InstalledUICultureInfo = temp;
  732.                 }
  733.                 return (temp);
  734.             }
  735.         }
  736.        
  737.         ////////////////////////////////////////////////////////////////////////
  738.         //
  739.         // InvariantCulture
  740.         //
  741.         // This instance provides methods, for example for casing and sorting,
  742.         // that are independent of the system and current user settings. It
  743.         // should be used only by processes such as some system services that
  744.         // require such invariant results (eg. file systems). In general,
  745.         // the results are not linguistically correct and do not match any
  746.         // culture info.
  747.         //
  748.         ////////////////////////////////////////////////////////////////////////
  749.        
  750.        
  751.         public static CultureInfo InvariantCulture {
  752.             get { return (m_InvariantCultureInfo); }
  753.         }
  754.        
  755.        
  756.         ////////////////////////////////////////////////////////////////////////
  757.         //
  758.         // Parent
  759.         //
  760.         // Return the parent CultureInfo for the current instance.
  761.         //
  762.         ////////////////////////////////////////////////////////////////////////
  763.        
  764.         public virtual CultureInfo Parent {
  765.             get {
  766.                 if (null == m_parent) {
  767.                     try {
  768.                         int parentCulture = this.m_cultureTableRecord.IPARENT;
  769.                         if (parentCulture == LOCALE_INVARIANT) {
  770.                             m_parent = InvariantCulture;
  771.                         }
  772.                         else if (CultureTableRecord.IsCustomCultureId(parentCulture)) {
  773.                             // Customized culture -- use the string for the parent.
  774.                             m_parent = new CultureInfo(this.m_cultureTableRecord.SPARENT);
  775.                         }
  776.                         else {
  777.                             m_parent = new CultureInfo(parentCulture, this.m_cultureTableRecord.UseUserOverride);
  778.                         }
  779.                     }
  780.                     catch (ArgumentException) {
  781.                         // For whatever reason our IPARENT or SPARENT wasn't correct, so use invariant
  782.                         // We can't allow ourselves to fail. In case of custom cultures the parent of the
  783.                         // current custom culture isn't installed.
  784.                         m_parent = InvariantCulture;
  785.                     }
  786.                 }
  787.                 return m_parent;
  788.             }
  789.         }
  790.        
  791.         ////////////////////////////////////////////////////////////////////////
  792.         //
  793.         // LCID
  794.         //
  795.         // Returns a properly formed culture identifier for the current
  796.         // culture info.
  797.         //
  798.         ////////////////////////////////////////////////////////////////////////
  799.        
  800.        
  801.         public virtual int LCID {
  802.             get { return (this.cultureID); }
  803.         }
  804.        
  805.         ////////////////////////////////////////////////////////////////////////
  806.         //
  807.         // BaseInputLanguage
  808.         //
  809.         // Essentially an LCID, though one that may be different than LCID in the case
  810.         // of a customized culture (LCID == -1).
  811.         //
  812.         ////////////////////////////////////////////////////////////////////////
  813.        
  814.         [System.Runtime.InteropServices.ComVisible(false)]
  815.         public virtual int KeyboardLayoutId {
  816.             get {
  817.                 int keyId = this.m_cultureTableRecord.IINPUTLANGUAGEHANDLE;
  818.                
  819.                 // Not a customized culture, return the default Keyboard layout ID, which is the same as the language ID.
  820.                 return (keyId);
  821.             }
  822.         }
  823.        
  824.        
  825.         public static CultureInfo[] GetCultures(CultureTypes types)
  826.         {
  827.             return (CultureTable.Default.GetCultures(types));
  828.         }
  829.        
  830.        
  831.         ////////////////////////////////////////////////////////////////////////
  832.         //
  833.         // Name
  834.         //
  835.         // Returns the full name of the CultureInfo. The name is in format like
  836.         // "en-US" This version does NOT include sort information in the name.
  837.         //
  838.         ////////////////////////////////////////////////////////////////////////
  839.         public virtual string Name {
  840.             get {
  841.                 // We return non sorting name here.
  842.                 if (this.m_nonSortName == null) {
  843.                     this.m_nonSortName = this.m_cultureTableRecord.CultureName;
  844.                 }
  845.                 return this.m_nonSortName;
  846.             }
  847.         }
  848.        
  849.        
  850.         internal string SortName {
  851.             get {
  852.                 if (this.m_sortName == null) {
  853.                     if (CultureTableRecord.IsCustomCultureId(cultureID)) {
  854.                         CultureInfo sortCI = CultureInfo.GetCultureInfo(CompareInfoId);
  855.                        
  856.                         BCLDebug.Assert(!CultureTableRecord.IsCustomCultureId(sortCI.cultureID), "[CultureInfo.SortName]Expected non-custom sort id");
  857.                        
  858.                         if (CultureTableRecord.IsCustomCultureId(sortCI.cultureID)) {
  859.                             // m_name create could call SortName (not supposed to for CI),
  860.                             // but just to be safe, use SNAME not m_name
  861.                             this.m_sortName = m_cultureTableRecord.SNAME;
  862.                         }
  863.                         else {
  864.                             this.m_sortName = sortCI.SortName;
  865.                             // Name of culture doing our sort
  866.                         }
  867.                     }
  868.                     else {
  869.                         // If its not custom, our sort is our full name
  870.                         BCLDebug.Assert(m_name != null, "[CultureInfo.SortName]Always expect m_name to be set");
  871.                         this.m_sortName = this.m_name;
  872.                         // full name, including sort
  873.                     }
  874.                 }
  875.                 return this.m_sortName;
  876.             }
  877.         }
  878.        
  879.         [System.Runtime.InteropServices.ComVisible(false)]
  880.         public string IetfLanguageTag {
  881.             get {
  882.                 if (this.m_ietfName == null) {
  883.                     this.m_ietfName = this.m_cultureTableRecord.SIETFTAG;
  884.                 }
  885.                
  886.                 // IETF RFC 3066 name goes here
  887.                 return this.m_ietfName;
  888.             }
  889.         }
  890.        
  891.         ////////////////////////////////////////////////////////////////////////
  892.         //
  893.         // DisplayName
  894.         //
  895.         // Returns the full name of the CultureInfo in the localized language.
  896.         // For example, if the localized language of the runtime is Spanish and the CultureInfo is
  897.         // US English, "Ingles (Estados Unidos)" will be returned.
  898.         //
  899.         ////////////////////////////////////////////////////////////////////////
  900.        
  901.        
  902.         public virtual string DisplayName {
  903.             get {
  904.                 BCLDebug.Assert(m_name != null, "[CultureInfo.DisplayName]Always expect m_name to be set");
  905.                
  906.                 if (m_cultureTableRecord.IsCustomCulture) {
  907.                     if (m_cultureTableRecord.IsReplacementCulture) {
  908.                         // <SyntheticSupport/>
  909.                         if (m_cultureTableRecord.IsSynthetic)
  910.                             return m_cultureTableRecord.CultureNativeDisplayName;
  911.                         else
  912.                             return (Environment.GetResourceString("Globalization.ci_" + this.m_name));
  913.                     }
  914.                     else {
  915.                         return m_cultureTableRecord.SNATIVEDISPLAYNAME;
  916.                     }
  917.                 }
  918.                 else {
  919.                     // <SyntheticSupport/>
  920.                     if (m_cultureTableRecord.IsSynthetic)
  921.                         return m_cultureTableRecord.CultureNativeDisplayName;
  922.                     else
  923.                         return (Environment.GetResourceString("Globalization.ci_" + this.m_name));
  924.                 }
  925.             }
  926.         }
  927.        
  928.         ////////////////////////////////////////////////////////////////////////
  929.         //
  930.         // GetNativeName
  931.         //
  932.         // Returns the full name of the CultureInfo in the native language.
  933.         // For example, if the CultureInfo is US English, "English
  934.         // (United States)" will be returned.
  935.         //
  936.         ////////////////////////////////////////////////////////////////////////
  937.        
  938.        
  939.         public virtual string NativeName {
  940.             get { return (this.m_cultureTableRecord.SNATIVEDISPLAYNAME); }
  941.         }
  942.        
  943.         ////////////////////////////////////////////////////////////////////////
  944.         //
  945.         // GetEnglishName
  946.         //
  947.         // Returns the full name of the CultureInfo in English.
  948.         // For example, if the CultureInfo is US English, "English
  949.         // (United States)" will be returned.
  950.         //
  951.         ////////////////////////////////////////////////////////////////////////
  952.        
  953.        
  954.         public virtual string EnglishName {
  955.             get { return (this.m_cultureTableRecord.SENGDISPLAYNAME); }
  956.         }
  957.        
  958.        
  959.         public virtual string TwoLetterISOLanguageName {
  960.             get { return (this.m_cultureTableRecord.SISO639LANGNAME); }
  961.         }
  962.        
  963.        
  964.         public virtual string ThreeLetterISOLanguageName {
  965.             get { return (this.m_cultureTableRecord.SISO639LANGNAME2); }
  966.         }
  967.        
  968.         ////////////////////////////////////////////////////////////////////////
  969.         //
  970.         // GetAbbreviatedName
  971.         //
  972.         // Returns the abbreviated name for the current instance. The
  973.         // abbreviated form is usually based on the ISO 639 standard, for
  974.         // example the two letter abbreviation for English is "en".
  975.         //
  976.         ////////////////////////////////////////////////////////////////////////
  977.        
  978.        
  979.         public virtual string ThreeLetterWindowsLanguageName {
  980.             get { return (this.m_cultureTableRecord.SABBREVLANGNAME); }
  981.         }
  982.        
  983.         ////////////////////////////////////////////////////////////////////////
  984.         //
  985.         // CompareInfo Read-Only Property
  986.         //
  987.         // Gets the CompareInfo for this culture.
  988.         //
  989.         ////////////////////////////////////////////////////////////////////////
  990.        
  991.        
  992.         public virtual CompareInfo CompareInfo {
  993.             get {
  994.                 if (compareInfo == null) {
  995.                    
  996.                     CompareInfo temp;
  997.                    
  998.                    
  999.                     if (IsNeutralCulture && !CultureTableRecord.IsCustomCultureId(cultureID))
  1000.                         temp = CompareInfo.GetCompareInfo(cultureID);
  1001.                     else
  1002.                         temp = CompareInfo.GetCompareInfo(CompareInfoId);
  1003.                    
  1004.                     // The name is not preset when CompareInfo is set by LCID, so lets set it now.
  1005.                     temp.SetName(this.SortName);
  1006.                     compareInfo = temp;
  1007.                    
  1008.                 }
  1009.                 return (compareInfo);
  1010.             }
  1011.         }
  1012.        
  1013.         internal int CompareInfoId {
  1014.             get {
  1015.                 int compareId;
  1016.                
  1017.                 if (this.cultureID == LOCALE_TRADITIONAL_SPANISH) {
  1018.                     // Special case Trad. Spanish since there is no
  1019.                     // ICOMPAREINFO entry for them.
  1020.                     compareId = LOCALE_TRADITIONAL_SPANISH;
  1021.                 }
  1022.                 else if (GetSortID(this.cultureID) != 0) {
  1023.                     // Special case alternate sorts since there is no
  1024.                     // ICOMPAREINFO entry for them.
  1025.                     compareId = this.cultureID;
  1026.                 }
  1027.                 else {
  1028.                     compareId = unchecked((int)this.m_cultureTableRecord.ICOMPAREINFO);
  1029.                 }
  1030.                
  1031.                 return compareId;
  1032.             }
  1033.         }
  1034.        
  1035.         ////////////////////////////////////////////////////////////////////////
  1036.         //
  1037.         // TextInfo
  1038.         //
  1039.         // Gets the TextInfo for this culture.
  1040.         //
  1041.         ////////////////////////////////////////////////////////////////////////
  1042.        
  1043.        
  1044.         public virtual TextInfo TextInfo {
  1045.             get {
  1046.                 if (textInfo == null) {
  1047.                     // Make a new textInfo
  1048.                     TextInfo tempTextInfo = new TextInfo(this.m_cultureTableRecord);
  1049.                     tempTextInfo.SetReadOnlyState(m_isReadOnly);
  1050.                     textInfo = tempTextInfo;
  1051.                 }
  1052.                 return (textInfo);
  1053.             }
  1054.         }
  1055.        
  1056.         ////////////////////////////////////////////////////////////////////////
  1057.         //
  1058.         // Equals
  1059.         //
  1060.         // Implements Object.Equals(). Returns a boolean indicating whether
  1061.         // or not object refers to the same CultureInfo as the current instance.
  1062.         //
  1063.         ////////////////////////////////////////////////////////////////////////
  1064.        
  1065.        
  1066.         public override bool Equals(object value)
  1067.         {
  1068.             if (Object.ReferenceEquals(this, value))
  1069.                 return true;
  1070.            
  1071.             CultureInfo that = value as CultureInfo;
  1072.            
  1073.             if (that != null) {
  1074.                 // using CompareInfo to verify the data passed through the constructor
  1075.                 // CultureInfo(String cultureName, String textAndCompareCultureName)
  1076.                
  1077.                 return (this.Name.Equals(that.Name) && this.CompareInfo.Equals(that.CompareInfo));
  1078.             }
  1079.            
  1080.             return (false);
  1081.         }
  1082.        
  1083.        
  1084.         ////////////////////////////////////////////////////////////////////////
  1085.         //
  1086.         // GetHashCode
  1087.         //
  1088.         // Implements Object.GetHashCode(). Returns the hash code for the
  1089.         // CultureInfo. The hash code is guaranteed to be the same for CultureInfo A
  1090.         // and B where A.Equals(B) is true.
  1091.         //
  1092.         ////////////////////////////////////////////////////////////////////////
  1093.        
  1094.        
  1095.         public override int GetHashCode()
  1096.         {
  1097.             return (this.Name.GetHashCode() + this.CompareInfo.GetHashCode());
  1098.         }
  1099.        
  1100.        
  1101.         ////////////////////////////////////////////////////////////////////////
  1102.         //
  1103.         // ToString
  1104.         //
  1105.         // Implements Object.ToString(). Returns the name of the CultureInfo,
  1106.         // eg. "English (United States)".
  1107.         //
  1108.         ////////////////////////////////////////////////////////////////////////
  1109.        
  1110.        
  1111.         public override string ToString()
  1112.         {
  1113.             BCLDebug.Assert(m_name != null, "[CultureInfo.ToString]Always expect m_name to be set");
  1114.             return m_name;
  1115.         }
  1116.        
  1117.        
  1118.         public virtual object GetFormat(Type formatType)
  1119.         {
  1120.             if (formatType == typeof(NumberFormatInfo)) {
  1121.                 return (NumberFormat);
  1122.             }
  1123.             if (formatType == typeof(DateTimeFormatInfo)) {
  1124.                 return (DateTimeFormat);
  1125.             }
  1126.             return (null);
  1127.         }
  1128.        
  1129.         static internal void CheckNeutral(CultureInfo culture)
  1130.         {
  1131.             if (culture.IsNeutralCulture) {
  1132.                 BCLDebug.Assert(culture.m_name != null, "[CultureInfo.CheckNeutral]Always expect m_name to be set");
  1133.                 throw new NotSupportedException(Environment.GetResourceString("Argument_CultureInvalidFormat", culture.m_name));
  1134.             }
  1135.         }
  1136.        
  1137.         public virtual bool IsNeutralCulture {
  1138.             get { return this.m_cultureTableRecord.IsNeutralCulture; }
  1139.         }
  1140.        
  1141.         [System.Runtime.InteropServices.ComVisible(false)]
  1142.         public CultureTypes CultureTypes {
  1143.             get {
  1144.                 CultureTypes types = 0;
  1145.                
  1146.                 if (m_cultureTableRecord.IsNeutralCulture)
  1147.                     types |= CultureTypes.NeutralCultures;
  1148.                 else
  1149.                     types |= CultureTypes.SpecificCultures;
  1150.                
  1151.                 if (m_cultureTableRecord.IsSynthetic)
  1152.                     types |= CultureTypes.WindowsOnlyCultures | CultureTypes.InstalledWin32Cultures;
  1153.                 // Synthetic is installed culture too.
  1154.                 else {
  1155.                     // Not Synthetic
  1156.                     if (CultureTable.IsInstalledLCID(cultureID))
  1157.                         types |= CultureTypes.InstalledWin32Cultures;
  1158.                    
  1159.                     if (!m_cultureTableRecord.IsCustomCulture || m_cultureTableRecord.IsReplacementCulture)
  1160.                         types |= CultureTypes.FrameworkCultures;
  1161.                 }
  1162.                
  1163.                 if (m_cultureTableRecord.IsCustomCulture) {
  1164.                     types |= CultureTypes.UserCustomCulture;
  1165.                    
  1166.                     if (m_cultureTableRecord.IsReplacementCulture)
  1167.                         types |= CultureTypes.ReplacementCultures;
  1168.                 }
  1169.                
  1170.                
  1171.                 return types;
  1172.             }
  1173.         }
  1174.        
  1175.         public virtual NumberFormatInfo NumberFormat {
  1176.             get {
  1177.                 CultureInfo.CheckNeutral(this);
  1178.                 if (numInfo == null) {
  1179.                     NumberFormatInfo temp = new NumberFormatInfo(this.m_cultureTableRecord);
  1180.                     temp.isReadOnly = m_isReadOnly;
  1181.                     numInfo = temp;
  1182.                 }
  1183.                 return (numInfo);
  1184.             }
  1185.             set {
  1186.                 VerifyWritable();
  1187.                 if (value == null) {
  1188.                     throw new ArgumentNullException("value", Environment.GetResourceString("ArgumentNull_Obj"));
  1189.                 }
  1190.                 numInfo = value;
  1191.             }
  1192.         }
  1193.        
  1194.         ////////////////////////////////////////////////////////////////////////
  1195.         //
  1196.         // GetDateTimeFormatInfo
  1197.         //
  1198.         // Create a DateTimeFormatInfo, and fill in the properties according to
  1199.         // the CultureID.
  1200.         //
  1201.         ////////////////////////////////////////////////////////////////////////
  1202.        
  1203.        
  1204.         public virtual DateTimeFormatInfo DateTimeFormat {
  1205.             get {
  1206.                 if (dateTimeInfo == null) {
  1207.                     CultureInfo.CheckNeutral(this);
  1208.                     // Change the calendar of DTFI to the specified calendar of this CultureInfo.
  1209.                     DateTimeFormatInfo temp = new DateTimeFormatInfo(this.m_cultureTableRecord, GetLangID(cultureID), this.Calendar);
  1210.                     temp.m_isReadOnly = m_isReadOnly;
  1211.                     System.Threading.Thread.MemoryBarrier();
  1212.                     dateTimeInfo = temp;
  1213.                 }
  1214.                 return (dateTimeInfo);
  1215.             }
  1216.            
  1217.             set {
  1218.                 VerifyWritable();
  1219.                 if (value == null) {
  1220.                     throw new ArgumentNullException("value", Environment.GetResourceString("ArgumentNull_Obj"));
  1221.                 }
  1222.                 dateTimeInfo = value;
  1223.             }
  1224.         }
  1225.        
  1226.        
  1227.        
  1228.         unsafe public void ClearCachedData()
  1229.         {
  1230.             m_userDefaultUICulture = null;
  1231.             m_userDefaultCulture = null;
  1232.            
  1233.             RegionInfo.m_currentRegionInfo = null;
  1234.            
  1235.             TimeZone.ResetTimeZone();
  1236.            
  1237.             // Delete the cached cultures.
  1238.             m_LcidCachedCultures = null;
  1239.             m_NameCachedCultures = null;
  1240.             m_IetfCachedCultures = null;
  1241.            
  1242.             CultureTableRecord.ResetCustomCulturesCache();
  1243.             CompareInfo.ClearDefaultAssemblyCache();
  1244.         }
  1245.        
  1246. /*=================================GetCalendarInstance==========================
  1247.         **Action: Map a Win32 CALID to an instance of supported calendar.
  1248.         **Returns: An instance of calendar.
  1249.         **Arguments: calType    The Win32 CALID
  1250.         **Exceptions:
  1251.         **      Shouldn't throw exception since the calType value is from our data table or from Win32 registry.
  1252.         **      If we are in trouble (like getting a weird value from Win32 registry), just return the GregorianCalendar.
  1253.         ============================================================================*/       
  1254.         static internal Calendar GetCalendarInstance(int calType)
  1255.         {
  1256.             if (calType == Calendar.CAL_GREGORIAN) {
  1257.                 return (new GregorianCalendar());
  1258.             }
  1259.             return GetCalendarInstanceRare(calType);
  1260.         }
  1261.        
  1262.         //This function exists as a shortcut to prevent us from loading all of the non-gregorian
  1263.         //calendars unless they're required.
  1264.         static internal Calendar GetCalendarInstanceRare(int calType)
  1265.         {
  1266.             BCLDebug.Assert(calType != Calendar.CAL_GREGORIAN, "calType!=Calendar.CAL_GREGORIAN");
  1267.            
  1268.             switch (calType) {
  1269.                 case Calendar.CAL_GREGORIAN_US:
  1270.                 case Calendar.CAL_GREGORIAN_ME_FRENCH:
  1271.                 case Calendar.CAL_GREGORIAN_ARABIC:
  1272.                 case Calendar.CAL_GREGORIAN_XLIT_ENGLISH:
  1273.                 case Calendar.CAL_GREGORIAN_XLIT_FRENCH:
  1274.                     // Gregorian (U.S.) calendar
  1275.                     // Gregorian Middle East French calendar
  1276.                     // Gregorian Arabic calendar
  1277.                     // Gregorian Transliterated English calendar
  1278.                     // Gregorian Transliterated French calendar
  1279.                     return (new GregorianCalendar((GregorianCalendarTypes)calType));
  1280.                 case Calendar.CAL_TAIWAN:
  1281.                     // Taiwan Era calendar
  1282.                     return (new TaiwanCalendar());
  1283.                 case Calendar.CAL_JAPAN:
  1284.                     // Japanese Emperor Era calendar
  1285.                     return (new JapaneseCalendar());
  1286.                 case Calendar.CAL_KOREA:
  1287.                     // Korean Tangun Era calendar
  1288.                     return (new KoreanCalendar());
  1289.                 case Calendar.CAL_HIJRI:
  1290.                     // Hijri (Arabic Lunar) calendar
  1291.                     return (new HijriCalendar());
  1292.                 case Calendar.CAL_THAI:
  1293.                     // Thai calendar
  1294.                     return (new ThaiBuddhistCalendar());
  1295.                 case Calendar.CAL_HEBREW:
  1296.                     // Hebrew (Lunar) calendar
  1297.                     return (new HebrewCalendar());
  1298.                 case Calendar.CAL_PERSIAN:
  1299.                     return (new PersianCalendar());
  1300.                 case Calendar.CAL_UMALQURA:
  1301.                     return (new UmAlQuraCalendar());
  1302.                 case Calendar.CAL_CHINESELUNISOLAR:
  1303.                     return (new ChineseLunisolarCalendar());
  1304.                 case Calendar.CAL_JAPANESELUNISOLAR:
  1305.                     return (new JapaneseLunisolarCalendar());
  1306.                 case Calendar.CAL_KOREANLUNISOLAR:
  1307.                     return (new KoreanLunisolarCalendar());
  1308.                 case Calendar.CAL_TAIWANLUNISOLAR:
  1309.                     return (new TaiwanLunisolarCalendar());
  1310.             }
  1311.             return (new GregorianCalendar());
  1312.         }
  1313.        
  1314.        
  1315. /*=================================Calendar==========================
  1316.         **Action: Return/set the default calendar used by this culture.
  1317.         ** This value can be overridden by regional option if this is a current culture.
  1318.         **Returns:
  1319.         **Arguments:
  1320.         **Exceptions:
  1321.         **  ArgumentNull_Obj if the set value is null.
  1322.         ============================================================================*/       
  1323.        
  1324.        
  1325.         public virtual Calendar Calendar {
  1326.             get {
  1327.                 if (calendar == null) {
  1328.                     BCLDebug.Assert(this.m_cultureTableRecord.IOPTIONALCALENDARS.Length > 0, "this.m_cultureTableRecord.IOPTIONALCALENDARS.Length > 0");
  1329.                     // Get the default calendar for this culture. Note that the value can be
  1330.                     // from registry if this is a user default culture.
  1331.                     int calType = this.m_cultureTableRecord.ICALENDARTYPE;
  1332.                    
  1333.                     Calendar newObj = GetCalendarInstance(calType);
  1334.                     System.Threading.Thread.MemoryBarrier();
  1335.                     newObj.SetReadOnlyState(m_isReadOnly);
  1336.                     calendar = newObj;
  1337.                 }
  1338.                 return (calendar);
  1339.             }
  1340.         }
  1341.        
  1342. /*=================================OptionCalendars==========================
  1343.         **Action: Return an array of the optional calendar for this culture.
  1344.         **Returns: an array of Calendar.
  1345.         **Arguments:
  1346.         **Exceptions:
  1347.         ============================================================================*/       
  1348.        
  1349.        
  1350.         public virtual Calendar[] OptionalCalendars {
  1351.             get {
  1352.                 //
  1353.                 // This property always returns a new copy of the calendar array.
  1354.                 //
  1355.                 int[] calID = this.m_cultureTableRecord.IOPTIONALCALENDARS;
  1356.                 Calendar[] cals = new Calendar[calID.Length];
  1357.                 for (int i = 0; i < cals.Length; i++) {
  1358.                     cals[i] = GetCalendarInstance(calID[i]);
  1359.                 }
  1360.                 return (cals);
  1361.             }
  1362.         }
  1363.        
  1364.        
  1365.         public bool UseUserOverride {
  1366.             get { return (this.m_cultureTableRecord.UseUserOverride); }
  1367.         }
  1368.        
  1369.         [System.Runtime.InteropServices.ComVisible(false)]
  1370.         public CultureInfo GetConsoleFallbackUICulture()
  1371.         {
  1372.             CultureInfo temp = m_consoleFallbackCulture;
  1373.             if (temp == null) {
  1374.                 temp = GetCultureInfo(this.m_cultureTableRecord.SCONSOLEFALLBACKNAME);
  1375.                 temp.m_isReadOnly = true;
  1376.                 m_consoleFallbackCulture = temp;
  1377.             }
  1378.             return (temp);
  1379.         }
  1380.        
  1381.        
  1382.         public virtual object Clone()
  1383.         {
  1384.             CultureInfo ci = (CultureInfo)MemberwiseClone();
  1385.             ci.m_isReadOnly = false;
  1386.            
  1387.             if (!ci.IsNeutralCulture) {
  1388.                 //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
  1389.                 //they've already been allocated. If this is a derived type, we'll take a more generic codepath.
  1390.                 if (!m_isInherited) {
  1391.                     if (dateTimeInfo != null) {
  1392.                         ci.dateTimeInfo = (DateTimeFormatInfo)dateTimeInfo.Clone();
  1393.                     }
  1394.                     if (numInfo != null) {
  1395.                         ci.numInfo = (NumberFormatInfo)numInfo.Clone();
  1396.                     }
  1397.                    
  1398.                 }
  1399.                 else {
  1400.                     ci.DateTimeFormat = (DateTimeFormatInfo)this.DateTimeFormat.Clone();
  1401.                     ci.NumberFormat = (NumberFormatInfo)this.NumberFormat.Clone();
  1402.                 }
  1403.             }
  1404.            
  1405.             if (textInfo != null) {
  1406.                 ci.textInfo = (TextInfo)textInfo.Clone();
  1407.             }
  1408.            
  1409.             if (calendar != null) {
  1410.                 ci.calendar = (Calendar)calendar.Clone();
  1411.             }
  1412.            
  1413.             return (ci);
  1414.         }
  1415.        
  1416.        
  1417.         public static CultureInfo ReadOnly(CultureInfo ci)
  1418.         {
  1419.             if (ci == null) {
  1420.                 throw new ArgumentNullException("ci");
  1421.             }
  1422.             if (ci.IsReadOnly) {
  1423.                 return (ci);
  1424.             }
  1425.             CultureInfo info = (CultureInfo)(ci.MemberwiseClone());
  1426.            
  1427.             if (!ci.IsNeutralCulture) {
  1428.                 //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
  1429.                 //they've already been allocated. If this is a derived type, we'll take a more generic codepath.
  1430.                 if (!ci.m_isInherited) {
  1431.                     if (ci.dateTimeInfo != null) {
  1432.                         info.dateTimeInfo = DateTimeFormatInfo.ReadOnly(ci.dateTimeInfo);
  1433.                     }
  1434.                     if (ci.numInfo != null) {
  1435.                         info.numInfo = NumberFormatInfo.ReadOnly(ci.numInfo);
  1436.                     }
  1437.                    
  1438.                 }
  1439.                 else {
  1440.                     info.DateTimeFormat = DateTimeFormatInfo.ReadOnly(ci.DateTimeFormat);
  1441.                     info.NumberFormat = NumberFormatInfo.ReadOnly(ci.NumberFormat);
  1442.                 }
  1443.             }
  1444.            
  1445.             if (ci.textInfo != null) {
  1446.                 info.textInfo = TextInfo.ReadOnly(ci.textInfo);
  1447.             }
  1448.            
  1449.             if (ci.calendar != null) {
  1450.                 info.calendar = Calendar.ReadOnly(ci.calendar);
  1451.             }
  1452.            
  1453.             // Don't set the read-only flag too early.
  1454.             // We should set the read-only flag here. Otherwise, info.DateTimeFormat will not be able to set.
  1455.             info.m_isReadOnly = true;
  1456.            
  1457.             return (info);
  1458.         }
  1459.        
  1460.        
  1461.         public bool IsReadOnly {
  1462.             get { return (m_isReadOnly); }
  1463.         }
  1464.        
  1465.         private void VerifyWritable()
  1466.         {
  1467.             if (m_isReadOnly) {
  1468.                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
  1469.             }
  1470.         }
  1471.        
  1472.         // Helper function both both overloads of GetCachedReadOnlyCulture. If lcid is 0, we use the name.
  1473.         // If lcid is -1, use the altName and create one of those special SQL cultures.
  1474.         // If lcid is -2 we're looking for Ietf name
  1475.         static internal CultureInfo GetCultureInfoHelper(int lcid, string name, string altName)
  1476.         {
  1477.             // retval is our return value.
  1478.             CultureInfo retval;
  1479.            
  1480.             // Temporary hashtable for the names.
  1481.             Hashtable tempNameHT = m_NameCachedCultures;
  1482.            
  1483.             if (name != null)
  1484.                 name = CultureTableRecord.AnsiToLower(name);
  1485.            
  1486.             if (altName != null)
  1487.                 altName = CultureTableRecord.AnsiToLower(altName);
  1488.            
  1489.             // We expect the same result for all 3 hashtables, but will test individually for added safety.
  1490.             if (tempNameHT == null) {
  1491.                 tempNameHT = new Hashtable();
  1492.             }
  1493.             else {
  1494.                 // If we are called by name, check if the object exists in the hashtable. If so, return it.
  1495.                 if (lcid == -1) {
  1496.                     retval = (CultureInfo)tempNameHT[name + '�' + altName];
  1497.                     if (retval != null) {
  1498.                         return retval;
  1499.                     }
  1500.                 }
  1501.                 else if (lcid == 0) {
  1502.                     retval = (CultureInfo)tempNameHT[name];
  1503.                     if (retval != null) {
  1504.                         return retval;
  1505.                     }
  1506.                 }
  1507.             }
  1508.            
  1509.             // Next, the Lcid table.
  1510.             Hashtable tempLcidHT = m_LcidCachedCultures;
  1511.            
  1512.             if (tempLcidHT == null) {
  1513.                 // Case insensitive is not an issue here, save the constructor call.
  1514.                 tempLcidHT = new Hashtable();
  1515.             }
  1516.             else {
  1517.                 // If we were called by Lcid, check if the object exists in the table. If so, return it.
  1518.                 if (lcid > 0) {
  1519.                     retval = (CultureInfo)tempLcidHT[lcid];
  1520.                     if (retval != null) {
  1521.                         return retval;
  1522.                     }
  1523.                 }
  1524.             }
  1525.            
  1526.             // Last the Ietf name table
  1527.             Hashtable tempIetfHT = m_IetfCachedCultures;
  1528.            
  1529.             if (tempIetfHT == null) {
  1530.                 tempIetfHT = new Hashtable();
  1531.             }
  1532.             else {
  1533.                 // If we wanted ietf name, then lcid is -2
  1534.                 if (lcid == -2) {
  1535.                     retval = (CultureInfo)tempIetfHT[name];
  1536.                     if (retval != null) {
  1537.                         return retval;
  1538.                     }
  1539.                 }
  1540.             }
  1541.            
  1542.             // We now have two temporary hashtables and the desired object was not found.
  1543.             // We'll construct it. We catch any exceptions from the constructor call and return null.
  1544.             try {
  1545.                 switch (lcid) {
  1546.                     case -2:
  1547.                        
  1548.                         {
  1549.                             // -2 is Ietf name, map Ietf name to Culture name and get it by name
  1550.                             string cultureName = CultureTableRecord.GetCultureNameFromIetfName(name);
  1551.                             if (cultureName == null)
  1552.                                 return null;
  1553.                             retval = new CultureInfo(cultureName, false);
  1554.                             break;
  1555.                         }
  1556.                         break;
  1557.                     case -1:
  1558.                        
  1559.                         // call the private constructor
  1560.                         retval = new CultureInfo(name, altName);
  1561.                         break;
  1562.                     case 0:
  1563.                        
  1564.                         retval = new CultureInfo(name, false);
  1565.                         break;
  1566.                     default:
  1567.                        
  1568.                        
  1569.                         //
  1570.                         // checking the current culture first is a protection against recursion so the creation
  1571.                         // code of CompareInfo is calling GetCultureInfo.
  1572.                         // The recursion can happen if we have current user culture is replaced custom culture
  1573.                         // and we are trying to create object for that culture and current user culture is not
  1574.                         // stored in our cache.
  1575.                         //
  1576.                        
  1577.                         if (m_userDefaultCulture != null && m_userDefaultCulture.LCID == lcid) {
  1578.                             retval = (CultureInfo)m_userDefaultCulture.Clone();
  1579.                             retval.m_cultureTableRecord = retval.m_cultureTableRecord.CloneWithUserOverride(false);
  1580.                         }
  1581.                         else {
  1582.                             retval = new CultureInfo(lcid, false);
  1583.                         }
  1584.                         break;
  1585.                 }
  1586.             }
  1587.             catch (ArgumentException) {
  1588.                 return null;
  1589.             }
  1590.            
  1591.             // Set it to read-only
  1592.             retval.m_isReadOnly = true;
  1593.            
  1594.             if (lcid == -1) {
  1595.                 // This new culture will be added only to the name hash table.
  1596.                 tempNameHT[name + '�' + altName] = retval;
  1597.                
  1598.                 // when lcid == -1 then TextInfo object is already get created and we need to set it as read only.
  1599.                 retval.TextInfo.SetReadOnlyState(true);
  1600.             }
  1601.             else {
  1602.                 // We add this new culture info object to all 3 hash tables.
  1603.                 tempLcidHT[retval.LCID] = retval;
  1604.                
  1605.                 string newName = CultureTableRecord.AnsiToLower(retval.m_name);
  1606.                
  1607.                 tempNameHT[newName] = retval;
  1608.                
  1609.                 newName = retval.IetfLanguageTag;
  1610.                 if (newName != null) {
  1611.                     newName = CultureTableRecord.AnsiToLower(newName);
  1612.                     tempIetfHT[newName] = retval;
  1613.                 }
  1614.                
  1615.                 if (lcid == -2 && !name.Equals(newName))
  1616.                     tempIetfHT[name] = retval;
  1617.                
  1618.             }
  1619.            
  1620.             // Copy the two hashtables to the corresponding member variables. This will potentially overwrite
  1621.             // new tables simultaneously created by a new thread, but maximizes thread safety.
  1622.             // If it was funky name we don't need to cache Ietf or LCID names.
  1623.             if (-1 != lcid) {
  1624.                 // Only when we modify the lcid hash table, is there a need to overwrite.
  1625.                 m_LcidCachedCultures = tempLcidHT;
  1626.                 m_IetfCachedCultures = tempIetfHT;
  1627.             }
  1628.            
  1629.             m_NameCachedCultures = tempNameHT;
  1630.            
  1631.             // Finally, return our new CultureInfo object.
  1632.             return retval;
  1633.         }
  1634.        
  1635.         // Gets a cached copy of the specified culture from an internal hashtable (or creates it
  1636.         // if not found).
  1637.         public static CultureInfo GetCultureInfo(int culture)
  1638.         {
  1639.             // Must check for -1 now since the helper function uses the value to signal
  1640.             // the altCulture code path for SQL Server.
  1641.             // Also check for zero as this would fail trying to add as a key to the hash.
  1642.             if (culture <= 0) {
  1643.                 throw new ArgumentOutOfRangeException("culture", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
  1644.             }
  1645.            
  1646.             CultureInfo retval = GetCultureInfoHelper(culture, null, null);
  1647.             if (null == retval) {
  1648.                 throw new ArgumentException(Environment.GetResourceString("Argument_CultureNotSupported", culture), "culture");
  1649.             }
  1650.             return retval;
  1651.            
  1652.         }
  1653.        
  1654.         // Gets a cached copy of the specified culture from an internal hashtable (or creates it
  1655.         // if not found).
  1656.         public static CultureInfo GetCultureInfo(string name)
  1657.         {
  1658.             // Make sure we have a valid, non-zero length string as name
  1659.             if (name == null) {
  1660.                 throw new ArgumentNullException("name");
  1661.             }
  1662.            
  1663.             CultureInfo retval = GetCultureInfoHelper(0, name, null);
  1664.             if (retval == null) {
  1665.                 throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_InvalidCultureName"), name), "name");
  1666.             }
  1667.             return retval;
  1668.         }
  1669.        
  1670.         // Gets a cached copy of the specified culture from an internal hashtable (or creates it
  1671.         // if not found).
  1672.         public static CultureInfo GetCultureInfo(string name, string altName)
  1673.         {
  1674.             // Make sure we have a valid, non-zero length string as name
  1675.             if (null == name) {
  1676.                 throw new ArgumentNullException("name");
  1677.             }
  1678.            
  1679.             if (null == altName) {
  1680.                 throw new ArgumentNullException("altName");
  1681.             }
  1682.            
  1683.             CultureInfo retval = GetCultureInfoHelper(-1, name, altName);
  1684.             if (retval == null) {
  1685.                 throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_OneOfCulturesNotSupported"), name, altName), "name");
  1686.             }
  1687.             return retval;
  1688.         }
  1689.        
  1690.         // Get a cached copy of the specified culture from ietf language tag.
  1691.         public static CultureInfo GetCultureInfoByIetfLanguageTag(string name)
  1692.         {
  1693.             // Make sure we have a valid, non-zero length string as name
  1694.             if (null == name) {
  1695.                 throw new ArgumentNullException("name");
  1696.             }
  1697.            
  1698.             CultureInfo retval = GetCultureInfoHelper(-2, name, null);
  1699.             if (null == retval) {
  1700.                 throw new ArgumentException(String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_CultureIetfNotSupported"), name), "name");
  1701.             }
  1702.            
  1703.             return retval;
  1704.         }
  1705.        
  1706.         // Looks for Ietf names in the registry.
  1707.     }
  1708. }

Developer Fusion