summaryrefslogtreecommitdiff
path: root/src/mscorlib/src/System/Globalization/CultureInfo.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/src/System/Globalization/CultureInfo.cs')
-rw-r--r--src/mscorlib/src/System/Globalization/CultureInfo.cs2023
1 files changed, 2023 insertions, 0 deletions
diff --git a/src/mscorlib/src/System/Globalization/CultureInfo.cs b/src/mscorlib/src/System/Globalization/CultureInfo.cs
new file mode 100644
index 0000000000..d620d2dc24
--- /dev/null
+++ b/src/mscorlib/src/System/Globalization/CultureInfo.cs
@@ -0,0 +1,2023 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+////////////////////////////////////////////////////////////////////////////
+//
+//
+//
+// 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.
+//
+//
+//
+// !!!! 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;
+ using System.Runtime.CompilerServices;
+ using System.Runtime.InteropServices;
+ using System.Runtime.Serialization;
+ using System.Runtime.Versioning;
+ using System.Security.Permissions;
+ using System.Reflection;
+ using Microsoft.Win32;
+ using System.Diagnostics.Contracts;
+ using System.Resources;
+
+ [Serializable]
+ [System.Runtime.InteropServices.ComVisible(true)]
+ public partial class CultureInfo : ICloneable, IFormatProvider {
+ //--------------------------------------------------------------------//
+ // Internal Information //
+ //--------------------------------------------------------------------//
+
+ //--------------------------------------------------------------------//
+ // Data members to be serialized:
+ //--------------------------------------------------------------------//
+
+ // We use an RFC4646 type string to construct CultureInfo.
+ // This string is stored in m_name and is authoritative.
+ // We use the m_cultureData to get the data for our object
+
+ // 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: The type loader will rearrange class member offsets so the mscorwks!CultureInfoBaseObject
+ // WARNING: must be manually structured to match the true loaded class layout
+ // WARNING
+ internal bool m_isReadOnly;
+ internal CompareInfo compareInfo;
+ internal TextInfo textInfo;
+ // Not serialized for now since we only build it privately for use in the CARIB (so rebuilding is OK)
+#if !FEATURE_CORECLR
+ [NonSerialized]internal RegionInfo regionInfo;
+#endif
+ internal NumberFormatInfo numInfo;
+ internal DateTimeFormatInfo dateTimeInfo;
+ internal Calendar calendar;
+ [OptionalField(VersionAdded = 1)]
+ internal int m_dataItem; // NEVER USED, DO NOT USE THIS! (Serialized in Whidbey/Everett)
+ [OptionalField(VersionAdded = 1)]
+ internal int cultureID = 0x007f; // NEVER USED, DO NOT USE THIS! (Serialized in Whidbey/Everett)
+ //
+ // The CultureData instance that we are going to read data from.
+ // For supported culture, this will be the CultureData instance that read data from mscorlib assembly.
+ // For customized culture, this will be the CultureData instance that read data from user customized culture binary file.
+ //
+ [NonSerialized]internal CultureData m_cultureData;
+
+ [NonSerialized]internal bool m_isInherited;
+#if FEATURE_LEAK_CULTURE_INFO
+ [NonSerialized]private bool m_isSafeCrossDomain;
+ [NonSerialized]private int m_createdDomainID;
+#endif // !FEATURE_CORECLR
+#if !FEATURE_CORECLR
+ [NonSerialized]private CultureInfo m_consoleFallbackCulture;
+#endif // !FEATURE_CORECLR
+
+ // 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)
+ // en en
+ //
+ // Note that in Silverlight we ask the OS for the text and sort behavior, so the
+ // textinfo and compareinfo names are the same as the name
+
+ // 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;
+
+ // 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;
+
+ // 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;
+
+
+ //--------------------------------------------------------------------//
+ //
+ // Static data members
+ //
+ //--------------------------------------------------------------------//
+
+ //Get the current user default culture. This one is almost always used, so we create it by default.
+ private static volatile CultureInfo s_userDefaultCulture;
+
+ //
+ // All of the following will be created on demand.
+ //
+
+ //The Invariant culture;
+ private static volatile CultureInfo s_InvariantCultureInfo;
+
+ //The culture used in the user interface. This is mostly used to load correct localized resources.
+ private static volatile CultureInfo s_userDefaultUICulture;
+
+ //This is the UI culture used to install the OS.
+ private static volatile CultureInfo s_InstalledUICultureInfo;
+
+ //These are defaults that we use if a thread has not opted into having an explicit culture
+ private static volatile CultureInfo s_DefaultThreadCurrentUICulture;
+ private static volatile CultureInfo s_DefaultThreadCurrentCulture;
+
+ //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 volatile Hashtable s_LcidCachedCultures;
+ private static volatile Hashtable s_NameCachedCultures;
+
+#if FEATURE_APPX
+ // When running under AppX, we use this to get some information about the language list
+ [SecurityCritical]
+ private static volatile WindowsRuntimeResourceManagerBase s_WindowsRuntimeResourceManager;
+
+ [ThreadStatic]
+ private static bool ts_IsDoingAppXCultureInfoLookup;
+#endif
+
+ //The parent culture.
+ [NonSerialized]private CultureInfo m_parent;
+
+ // LOCALE constants of interest to us internally and privately for LCID functions
+ // (ie: avoid using these and use names if possible)
+ internal const int LOCALE_NEUTRAL = 0x0000;
+ private const int LOCALE_USER_DEFAULT = 0x0400;
+ private const int LOCALE_SYSTEM_DEFAULT = 0x0800;
+ internal const int LOCALE_CUSTOM_DEFAULT = 0x0c00;
+ internal const int LOCALE_CUSTOM_UNSPECIFIED = 0x1000;
+ internal const int LOCALE_INVARIANT = 0x007F;
+ private const int LOCALE_TRADITIONAL_SPANISH = 0x040a;
+
+ //
+ // The CultureData instance that reads the data provided by our CultureData class.
+ //
+ //Using a field initializer rather than a static constructor so that the whole class can be lazy
+ //init.
+ private static readonly bool init = Init();
+ private static bool Init()
+ {
+
+ if (s_InvariantCultureInfo == null)
+ {
+ CultureInfo temp = new CultureInfo("", false);
+ temp.m_isReadOnly = true;
+ s_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
+ // s_userDefaultCulture to be used in Thread.CurrentCulture.
+ s_userDefaultCulture = s_userDefaultUICulture = s_InvariantCultureInfo;
+
+ s_userDefaultCulture = InitUserDefaultCulture();
+ s_userDefaultUICulture = InitUserDefaultUICulture();
+ return true;
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ static CultureInfo InitUserDefaultCulture()
+ {
+ String strDefault = GetDefaultLocaleName(LOCALE_USER_DEFAULT);
+ if (strDefault == null)
+ {
+ strDefault = GetDefaultLocaleName(LOCALE_SYSTEM_DEFAULT);
+
+ if (strDefault == null)
+ {
+ // If system default doesn't work, keep using the invariant
+ return (CultureInfo.InvariantCulture);
+ }
+ }
+ CultureInfo temp = GetCultureByName(strDefault, true);
+
+ temp.m_isReadOnly = true;
+
+ return (temp);
+ }
+
+ static CultureInfo InitUserDefaultUICulture()
+ {
+ String strDefault = GetUserDefaultUILanguage();
+
+ // In most of cases, UserDefaultCulture == UserDefaultUICulture, so we should use the same instance if possible.
+ if (strDefault == UserDefaultCulture.Name)
+ {
+ return (UserDefaultCulture);
+ }
+
+ CultureInfo temp = GetCultureByName( strDefault, true);
+
+ if (temp == null)
+ {
+ return (CultureInfo.InvariantCulture);
+ }
+
+ temp.m_isReadOnly = true;
+
+ return (temp);
+ }
+
+#if FEATURE_APPX
+ [SecuritySafeCritical]
+ internal static CultureInfo GetCultureInfoForUserPreferredLanguageInAppX()
+ {
+ // If a call to GetCultureInfoForUserPreferredLanguageInAppX() generated a recursive
+ // call to itself, return null, since we don't want to stack overflow. For example,
+ // this can happen if some code in this method ends up calling CultureInfo.CurrentCulture
+ // (which is common on check'd build because of BCLDebug logging which calls Int32.ToString()).
+ // In this case, returning null will mean CultureInfo.CurrentCulture gets the default Win32
+ // value, which should be fine.
+ if(ts_IsDoingAppXCultureInfoLookup)
+ {
+ return null;
+ }
+
+ // If running within a compilation process (mscorsvw.exe, for example), it is illegal to
+ // load any non-mscorlib assembly for execution. Since WindowsRuntimeResourceManager lives
+ // in System.Runtime.WindowsRuntime, caller will need to fall back to default Win32 value,
+ // which should be fine because we should only ever need to access FX resources during NGEN.
+ // FX resources are always loaded from satellite assemblies - even in AppX processes (see the
+ // comments in code:System.Resources.ResourceManager.SetAppXConfiguration for more details).
+ if (AppDomain.IsAppXNGen)
+ {
+ return null;
+ }
+
+ CultureInfo toReturn = null;
+
+ try
+ {
+ ts_IsDoingAppXCultureInfoLookup = true;
+
+ if(s_WindowsRuntimeResourceManager == null)
+ {
+ s_WindowsRuntimeResourceManager = ResourceManager.GetWinRTResourceManager();
+ }
+
+ toReturn = s_WindowsRuntimeResourceManager.GlobalResourceContextBestFitCultureInfo;
+ }
+ finally
+ {
+ ts_IsDoingAppXCultureInfoLookup = false;
+ }
+
+ return toReturn;
+ }
+
+ [SecuritySafeCritical]
+ internal static bool SetCultureInfoForUserPreferredLanguageInAppX(CultureInfo ci)
+ {
+ // If running within a compilation process (mscorsvw.exe, for example), it is illegal to
+ // load any non-mscorlib assembly for execution. Since WindowsRuntimeResourceManager lives
+ // in System.Runtime.WindowsRuntime, caller will need to fall back to default Win32 value,
+ // which should be fine because we should only ever need to access FX resources during NGEN.
+ // FX resources are always loaded from satellite assemblies - even in AppX processes (see the
+ // comments in code:System.Resources.ResourceManager.SetAppXConfiguration for more details).
+ if (AppDomain.IsAppXNGen)
+ {
+ return false;
+ }
+
+ if (s_WindowsRuntimeResourceManager == null)
+ {
+ s_WindowsRuntimeResourceManager = ResourceManager.GetWinRTResourceManager();
+ }
+
+ return s_WindowsRuntimeResourceManager.SetGlobalResourceContextDefaultCulture(ci);
+ }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // 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"));
+ }
+ Contract.EndContractBlock();
+
+ // Get our data providing record
+ this.m_cultureData = CultureData.GetCultureData(name, useUserOverride);
+
+ if (this.m_cultureData == null) {
+ throw new CultureNotFoundException("name", name, Environment.GetResourceString("Argument_CultureNotSupported"));
+ }
+
+ this.m_name = this.m_cultureData.CultureName;
+ this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
+ }
+
+
+#if FEATURE_USE_LCID
+ public CultureInfo(int culture) : this(culture, true) {
+ }
+
+ public 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"));
+ }
+ Contract.EndContractBlock();
+
+ InitializeFromCultureId(culture, useUserOverride);
+ }
+
+ private void InitializeFromCultureId(int culture, bool useUserOverride)
+ {
+ switch (culture)
+ {
+ case LOCALE_CUSTOM_DEFAULT:
+ case LOCALE_SYSTEM_DEFAULT:
+ 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 CultureNotFoundException(
+ "culture", culture, Environment.GetResourceString("Argument_CultureNotSupported"));
+
+ default:
+ // Now see if this LCID is supported in the system default CultureData table.
+ this.m_cultureData = CultureData.GetCultureData(culture, useUserOverride);
+ break;
+ }
+ this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
+ this.m_name = this.m_cultureData.CultureName;
+ }
+#endif // FEATURE_USE_LCID
+
+ //
+ // 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()));
+ }
+ Contract.EndContractBlock();
+ }
+
+#region Serialization
+ // We need to store the override from the culture data record.
+ private bool m_useUserOverride;
+
+ [OnDeserialized]
+ private void OnDeserialized(StreamingContext ctx)
+ {
+#if FEATURE_USE_LCID
+ // Whidbey+ should remember our name
+ // but v1 and v1.1 did not store name -- only lcid
+ // Whidbey did not store actual alternate sort name in m_name
+ // like we do in v4 so we can't use name for alternate sort
+ // e.g. for es-ES_tradnl: v2 puts es-ES in m_name; v4 puts es-ES_tradnl
+ if (m_name == null || IsAlternateSortLcid(cultureID))
+ {
+ Contract.Assert(cultureID >=0, "[CultureInfo.OnDeserialized] cultureID >= 0");
+ InitializeFromCultureId(cultureID, m_useUserOverride);
+ }
+ else
+ {
+#endif
+ Contract.Assert(m_name != null, "[CultureInfo.OnDeserialized] m_name != null");
+
+ this.m_cultureData = CultureData.GetCultureData(m_name, m_useUserOverride);
+ if (this.m_cultureData == null)
+ throw new CultureNotFoundException(
+ "m_name", m_name, Environment.GetResourceString("Argument_CultureNotSupported"));
+
+#if FEATURE_USE_LCID
+ }
+#endif
+ m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
+
+ // 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);
+ }
+ }
+ }
+
+#if FEATURE_USE_LCID
+ // A locale ID is a 32 bit value which is the combination of a
+ // language ID, a sort ID, and a reserved area. The bits are
+ // allocated as follows:
+ //
+ // +------------------------+-------+--------------------------------+
+ // | Reserved |Sort ID| Language ID |
+ // +------------------------+-------+--------------------------------+
+ // 31 20 19 16 15 0 bit
+ private const int LOCALE_SORTID_MASK = 0x000f0000;
+
+ static private bool IsAlternateSortLcid(int lcid)
+ {
+ if(lcid == LOCALE_TRADITIONAL_SPANISH)
+ {
+ return true;
+ }
+
+ return (lcid & LOCALE_SORTID_MASK) != 0;
+ }
+#endif
+
+ [OnSerializing]
+ private void OnSerializing(StreamingContext ctx)
+ {
+ this.m_name = this.m_cultureData.CultureName;
+ this.m_useUserOverride = this.m_cultureData.UseUserOverride;
+#if FEATURE_USE_LCID
+ // for compatibility with v2 serialize cultureID
+ this.cultureID = this.m_cultureData.ILANGUAGE;
+#endif
+ }
+#endregion Serialization
+
+#if FEATURE_LEAK_CULTURE_INFO
+ // Is it safe to send this CultureInfo as an instance member of a Thread cross AppDomain boundaries?
+ // For Silverlight, the answer is always no.
+ internal bool IsSafeCrossDomain {
+ get {
+ Contract.Assert(m_createdDomainID != 0, "[CultureInfo.IsSafeCrossDomain] m_createdDomainID != 0");
+ return m_isSafeCrossDomain;
+ }
+ }
+
+ internal int CreatedDomainID {
+ get {
+ Contract.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 FEATURE_LEAK_CULTURE_INFO isn't enabled, we never want to pass
+ // CultureInfo as an instance member of a Thread.
+ if (CanSendCrossDomain())
+ {
+ 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();
+ }
+#endif // FEATURE_LEAK_CULTURE_INFO
+
+ // Is it safe to pass the CultureInfo cross AppDomain boundaries, not necessarily as an instance
+ // member of Thread. This is different from IsSafeCrossDomain, which implies passing the CultureInfo
+ // as a Thread instance member.
+ internal bool CanSendCrossDomain()
+ {
+ bool isSafe = false;
+ if (this.GetType() == typeof(System.Globalization.CultureInfo))
+ {
+ isSafe = true;
+ }
+ return isSafe;
+ }
+
+ // 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"));
+ }
+ Contract.EndContractBlock();
+
+ this.m_cultureData = CultureData.GetCultureData(cultureName, false);
+ if (this.m_cultureData == null)
+ throw new CultureNotFoundException(
+ "cultureName", cultureName, Environment.GetResourceString("Argument_CultureNotSupported"));
+
+ this.m_name = this.m_cultureData.CultureName;
+
+ CultureInfo altCulture = GetCultureInfo(textAndCompareCultureName);
+ this.compareInfo = altCulture.CompareInfo;
+ this.textInfo = altCulture.TextInfo;
+ }
+
+ // We do this to try to return the system UI language and the default user languages
+ // The callers should have a fallback if this fails (like Invariant)
+ private static CultureInfo GetCultureByName(String name, bool userOverride)
+ {
+ // Try to get our culture
+ try
+ {
+ return userOverride ? new CultureInfo(name) : CultureInfo.GetCultureInfo(name);
+ }
+ catch (ArgumentException)
+ {
+ }
+
+ return null;
+ }
+
+ //
+ // Return a specific culture. A tad irrelevent now since we always return valid data
+ // for neutral locales.
+ //
+ // Note that there's interesting behavior that tries to find a smaller name, ala RFC4647,
+ // if we can't find a bigger name. That doesn't help with things like "zh" though, so
+ // the approach is of questionable value
+ //
+ public static CultureInfo CreateSpecificCulture(String name) {
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+
+ CultureInfo culture;
+
+ try {
+ culture = new CultureInfo(name);
+ } catch(ArgumentException) {
+ // 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;
+ }
+ }
+ }
+
+ if(null == culture) {
+ // nothing to save here; throw the original exception
+ throw;
+ }
+ }
+
+ //In the most common case, they've given us a specific culture, so we'll just return that.
+ if (!(culture.IsNeutralCulture)) {
+ return culture;
+ }
+
+ return (new CultureInfo(culture.m_cultureData.SSPECIFICCULTURE));
+ }
+
+ internal static bool VerifyCultureName(String cultureName, bool throwException)
+ {
+ // This function is used by ResourceManager.GetResourceFileName().
+ // ResourceManager searches for resource using CultureInfo.Name,
+ // so we should check against CultureInfo.Name.
+
+ for (int i=0; i<cultureName.Length; i++) {
+ char c = cultureName[i];
+
+ if (Char.IsLetterOrDigit(c) || c=='-' || c=='_') {
+ continue;
+ }
+ if (throwException) {
+ throw new ArgumentException(Environment.GetResourceString("Argument_InvalidResourceCultureName", cultureName));
+ }
+ return false;
+ }
+ return true;
+
+ }
+
+ internal static bool VerifyCultureName(CultureInfo culture, bool throwException) {
+ Contract.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;
+ }
+
+ return VerifyCultureName(culture.Name, throwException);
+
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // 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 {
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+
+#if !FEATURE_CORECLR
+ return Thread.CurrentThread.CurrentCulture;
+#else
+ // In the case of CoreCLR, Thread.m_CurrentCulture and
+ // Thread.m_CurrentUICulture are thread static so as not to let
+ // CultureInfo objects leak across AppDomain boundaries. The
+ // fact that these fields are thread static introduces overhead
+ // in accessing them (through Thread.CurrentCulture). There is
+ // also overhead in accessing Thread.CurrentThread. In this
+ // case, we can avoid the overhead of Thread.CurrentThread
+ // because these fields are thread static, and so do not
+ // require a Thread instance to be accessed.
+#if FEATURE_APPX
+ if(AppDomain.IsAppXModel()) {
+ CultureInfo culture = GetCultureInfoForUserPreferredLanguageInAppX();
+ if (culture != null)
+ return culture;
+ }
+#endif
+ return Thread.m_CurrentCulture ??
+ s_DefaultThreadCurrentCulture ??
+ s_userDefaultCulture ??
+ UserDefaultCulture;
+#endif
+ }
+
+ set {
+#if FEATURE_APPX
+ if (value == null) {
+ throw new ArgumentNullException("value");
+ }
+
+ if (AppDomain.IsAppXModel()) {
+ if (SetCultureInfoForUserPreferredLanguageInAppX(value)) {
+ // successfully set the culture, otherwise fallback to legacy path
+ return;
+ }
+ }
+#endif
+ Thread.CurrentThread.CurrentCulture = value;
+ }
+ }
+
+ //
+ // This is the equivalence of the Win32 GetUserDefaultLCID()
+ //
+ internal static CultureInfo UserDefaultCulture {
+ get
+ {
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+
+ CultureInfo temp = s_userDefaultCulture;
+ if (temp == null)
+ {
+ //
+ // setting the s_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.
+ //
+
+ s_userDefaultCulture = CultureInfo.InvariantCulture;
+ temp = InitUserDefaultCulture();
+ s_userDefaultCulture = temp;
+ }
+ return (temp);
+ }
+ }
+
+ //
+ // This is the equivalence of the Win32 GetUserDefaultUILanguage()
+ //
+ internal static CultureInfo UserDefaultUICulture {
+ get {
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+
+ CultureInfo temp = s_userDefaultUICulture;
+ if (temp == null)
+ {
+ //
+ // setting the s_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.
+ //
+
+ s_userDefaultUICulture = CultureInfo.InvariantCulture;
+
+ temp = InitUserDefaultUICulture();
+ s_userDefaultUICulture = temp;
+ }
+ return (temp);
+ }
+ }
+
+
+ public static CultureInfo CurrentUICulture {
+ get {
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+
+#if !FEATURE_CORECLR
+ return Thread.CurrentThread.CurrentUICulture;
+#else
+ // In the case of CoreCLR, Thread.m_CurrentCulture and
+ // Thread.m_CurrentUICulture are thread static so as not to let
+ // CultureInfo objects leak across AppDomain boundaries. The
+ // fact that these fields are thread static introduces overhead
+ // in accessing them (through Thread.CurrentCulture). There is
+ // also overhead in accessing Thread.CurrentThread. In this
+ // case, we can avoid the overhead of Thread.CurrentThread
+ // because these fields are thread static, and so do not
+ // require a Thread instance to be accessed.
+#if FEATURE_APPX
+ if(AppDomain.IsAppXModel()) {
+ CultureInfo culture = GetCultureInfoForUserPreferredLanguageInAppX();
+ if (culture != null)
+ return culture;
+ }
+#endif
+ return Thread.m_CurrentUICulture ??
+ s_DefaultThreadCurrentUICulture ??
+ s_userDefaultUICulture ??
+ UserDefaultUICulture;
+#endif
+ }
+
+ set {
+#if FEATURE_APPX
+ if (value == null) {
+ throw new ArgumentNullException("value");
+ }
+
+ if (AppDomain.IsAppXModel()) {
+ if (SetCultureInfoForUserPreferredLanguageInAppX(value)) {
+ // successfully set the culture, otherwise fallback to legacy path
+ return;
+ }
+ }
+#endif
+ Thread.CurrentThread.CurrentUICulture = value;
+ }
+ }
+
+
+ //
+ // This is the equivalence of the Win32 GetSystemDefaultUILanguage()
+ //
+ public static CultureInfo InstalledUICulture {
+ get {
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+
+ CultureInfo temp = s_InstalledUICultureInfo;
+ if (temp == null) {
+ String strDefault = GetSystemDefaultUILanguage();
+ temp = GetCultureByName(strDefault, true);
+
+ if (temp == null)
+ {
+ temp = InvariantCulture;
+ }
+
+ temp.m_isReadOnly = true;
+ s_InstalledUICultureInfo = temp;
+ }
+ return (temp);
+ }
+ }
+
+ public static CultureInfo DefaultThreadCurrentCulture {
+ get {
+ return s_DefaultThreadCurrentCulture;
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+#pragma warning disable 618
+ [SecurityPermission(SecurityAction.Demand, ControlThread = true)]
+#pragma warning restore 618
+ set {
+
+ // If you add pre-conditions to this method, check to see if you also need to
+ // add them to Thread.CurrentCulture.set.
+
+ s_DefaultThreadCurrentCulture = value;
+ }
+ }
+
+ public static CultureInfo DefaultThreadCurrentUICulture {
+ get {
+ return s_DefaultThreadCurrentUICulture;
+ }
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+#pragma warning disable 618
+ [SecurityPermission(SecurityAction.Demand, ControlThread = true)]
+#pragma warning restore 618
+ set {
+
+ //If they're trying to use a Culture with a name that we can't use in resource lookup,
+ //don't even let them set it on the thread.
+
+ // If you add more pre-conditions to this method, check to see if you also need to
+ // add them to Thread.CurrentUICulture.set.
+
+ if (value != null)
+ {
+ CultureInfo.VerifyCultureName(value, true);
+ }
+
+ s_DefaultThreadCurrentUICulture = value;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // 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 {
+ [Pure]
+ get {
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+ return (s_InvariantCultureInfo);
+ }
+ }
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // Parent
+ //
+ // Return the parent CultureInfo for the current instance.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+ public virtual CultureInfo Parent
+ {
+ [System.Security.SecuritySafeCritical] // auto-generated
+ get
+ {
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+
+ if (null == m_parent)
+ {
+ try
+ {
+ string parentName = this.m_cultureData.SPARENT;
+
+ if (String.IsNullOrEmpty(parentName))
+ {
+ m_parent = InvariantCulture;
+ }
+ else
+ {
+ m_parent = new CultureInfo(parentName, this.m_cultureData.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.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+#if FEATURE_USE_LCID
+ public virtual int LCID {
+ get {
+ return (this.m_cultureData.ILANGUAGE);
+ }
+ }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // BaseInputLanguage
+ //
+ // Essentially an LCID, though one that may be different than LCID in the case
+ // of a customized culture (LCID == LOCALE_CUSTOM_UNSPECIFIED).
+ //
+ ////////////////////////////////////////////////////////////////////////
+#if FEATURE_USE_LCID
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public virtual int KeyboardLayoutId
+ {
+ get
+ {
+ int keyId = this.m_cultureData.IINPUTLANGUAGEHANDLE;
+
+ // Not a customized culture, return the default Keyboard layout ID, which is the same as the language ID.
+ return (keyId);
+ }
+ }
+#endif
+
+ public static CultureInfo[] GetCultures(CultureTypes types) {
+ Contract.Ensures(Contract.Result<CultureInfo[]>() != null);
+ // internally we treat UserCustomCultures as Supplementals but v2
+ // treats as Supplementals and Replacements
+ if((types & CultureTypes.UserCustomCulture) == CultureTypes.UserCustomCulture)
+ {
+ types |= CultureTypes.ReplacementCultures;
+ }
+ return (CultureData.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 {
+ Contract.Ensures(Contract.Result<String>() != null);
+
+ // We return non sorting name here.
+ if (this.m_nonSortName == null) {
+ this.m_nonSortName = this.m_cultureData.SNAME;
+ if (this.m_nonSortName == null) {
+ this.m_nonSortName = String.Empty;
+ }
+ }
+ return this.m_nonSortName;
+ }
+ }
+
+ // This one has the sort information (ie: de-DE_phoneb)
+ internal String SortName
+ {
+ get
+ {
+ if (this.m_sortName == null)
+ {
+ this.m_sortName = this.m_cultureData.SCOMPAREINFO;
+ }
+
+ return this.m_sortName;
+ }
+ }
+
+#if !FEATURE_CORECLR
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public String IetfLanguageTag
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<String>() != null);
+
+ // special case the compatibility cultures
+ switch (this.Name)
+ {
+ case "zh-CHT":
+ return "zh-Hant";
+ case "zh-CHS":
+ return "zh-Hans";
+ default:
+ return this.Name;
+ }
+ }
+ }
+#endif
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // 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
+ {
+ [System.Security.SecuritySafeCritical] // auto-generated
+ get
+ {
+ Contract.Ensures(Contract.Result<String>() != null);
+ Contract.Assert(m_name != null, "[CultureInfo.DisplayName]Always expect m_name to be set");
+
+ return m_cultureData.SLOCALIZEDDISPLAYNAME;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // 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 {
+ [System.Security.SecuritySafeCritical] // auto-generated
+ get {
+ Contract.Ensures(Contract.Result<String>() != null);
+ return (this.m_cultureData.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 {
+ [System.Security.SecuritySafeCritical] // auto-generated
+ get {
+ Contract.Ensures(Contract.Result<String>() != null);
+ return (this.m_cultureData.SENGDISPLAYNAME);
+ }
+ }
+
+ // ie: en
+ public virtual String TwoLetterISOLanguageName {
+ [System.Security.SecuritySafeCritical] // auto-generated
+ get {
+ Contract.Ensures(Contract.Result<String>() != null);
+ return (this.m_cultureData.SISO639LANGNAME);
+ }
+ }
+
+ // ie: eng
+ public virtual String ThreeLetterISOLanguageName {
+ [System.Security.SecuritySafeCritical] // auto-generated
+ get {
+ Contract.Ensures(Contract.Result<String>() != null);
+ return (this.m_cultureData.SISO639LANGNAME2);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // ThreeLetterWindowsLanguageName
+ //
+ // Returns the 3 letter windows language name for the current instance. eg: "ENU"
+ // The ISO names are much preferred
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual String ThreeLetterWindowsLanguageName {
+ [System.Security.SecuritySafeCritical] // auto-generated
+ get {
+ Contract.Ensures(Contract.Result<String>() != null);
+ return (this.m_cultureData.SABBREVLANGNAME);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // CompareInfo Read-Only Property
+ //
+ // Gets the CompareInfo for this culture.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ public virtual CompareInfo CompareInfo
+ {
+ get
+ {
+ Contract.Ensures(Contract.Result<CompareInfo>() != null);
+
+ if (this.compareInfo == null)
+ {
+ // Since CompareInfo's don't have any overrideable properties, get the CompareInfo from
+ // the Non-Overridden CultureInfo so that we only create one CompareInfo per culture
+ CompareInfo temp = UseUserOverride
+ ? GetCultureInfo(this.m_name).CompareInfo
+ : new CompareInfo(this);
+ if (CompatibilitySwitches.IsCompatibilityBehaviorDefined)
+ {
+ this.compareInfo = temp;
+ }
+ else
+ {
+ return temp;
+ }
+ }
+ return (compareInfo);
+ }
+ }
+
+#if !FEATURE_CORECLR
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // RegionInfo
+ //
+ // Gets the RegionInfo for this culture.
+ //
+ ////////////////////////////////////////////////////////////////////////
+ private RegionInfo Region
+ {
+ get
+ {
+ if (regionInfo==null)
+ {
+ // Make a new regionInfo
+ RegionInfo tempRegionInfo = new RegionInfo(this.m_cultureData);
+ regionInfo = tempRegionInfo;
+ }
+ return (regionInfo);
+ }
+ }
+#endif // FEATURE_CORECLR
+
+
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // TextInfo
+ //
+ // Gets the TextInfo for this culture.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public virtual TextInfo TextInfo {
+ get {
+ Contract.Ensures(Contract.Result<TextInfo>() != null);
+
+ if (textInfo==null)
+ {
+ // Make a new textInfo
+ TextInfo tempTextInfo = new TextInfo(this.m_cultureData);
+ tempTextInfo.SetReadOnlyState(m_isReadOnly);
+
+ if (CompatibilitySwitches.IsCompatibilityBehaviorDefined)
+ {
+ textInfo = tempTextInfo;
+ }
+ else
+ {
+ return 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. "de-DE_phoneb", "en-US", or "fj-FJ".
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public override String ToString()
+ {
+ Contract.Ensures(Contract.Result<String>() != null);
+
+ Contract.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);
+ }
+
+ public virtual bool IsNeutralCulture {
+ get {
+ return this.m_cultureData.IsNeutralCulture;
+ }
+ }
+
+#if !FEATURE_CORECLR
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public CultureTypes CultureTypes
+ {
+ get
+ {
+ CultureTypes types = 0;
+
+ if (m_cultureData.IsNeutralCulture)
+ types |= CultureTypes.NeutralCultures;
+ else
+ types |= CultureTypes.SpecificCultures;
+
+ types |= m_cultureData.IsWin32Installed ? CultureTypes.InstalledWin32Cultures : 0;
+
+// Disable warning 618: System.Globalization.CultureTypes.FrameworkCultures' is obsolete
+#pragma warning disable 618
+ types |= m_cultureData.IsFramework ? CultureTypes.FrameworkCultures : 0;
+
+#pragma warning restore 618
+ types |= m_cultureData.IsSupplementalCustomCulture ? CultureTypes.UserCustomCulture : 0;
+ types |= m_cultureData.IsReplacementCulture ? CultureTypes.ReplacementCultures | CultureTypes.UserCustomCulture : 0;
+
+ return types;
+ }
+ }
+#endif
+
+ public virtual NumberFormatInfo NumberFormat {
+ get
+ {
+ Contract.Ensures(Contract.Result<NumberFormatInfo>() != null);
+
+ if (numInfo == null) {
+ NumberFormatInfo temp = new NumberFormatInfo(this.m_cultureData);
+ temp.isReadOnly = m_isReadOnly;
+ numInfo = temp;
+ }
+ return (numInfo);
+ }
+ set {
+ if (value == null) {
+ throw new ArgumentNullException("value",
+ Environment.GetResourceString("ArgumentNull_Obj"));
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ numInfo = value;
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////
+ //
+ // GetDateTimeFormatInfo
+ //
+ // Create a DateTimeFormatInfo, and fill in the properties according to
+ // the CultureID.
+ //
+ ////////////////////////////////////////////////////////////////////////
+
+
+ public virtual DateTimeFormatInfo DateTimeFormat {
+ get {
+ Contract.Ensures(Contract.Result<DateTimeFormatInfo>() != null);
+
+ if (dateTimeInfo == null) {
+ // Change the calendar of DTFI to the specified calendar of this CultureInfo.
+ DateTimeFormatInfo temp = new DateTimeFormatInfo(
+ this.m_cultureData, this.Calendar);
+ temp.m_isReadOnly = m_isReadOnly;
+ System.Threading.Thread.MemoryBarrier();
+ dateTimeInfo = temp;
+ }
+ return (dateTimeInfo);
+ }
+
+ set {
+ if (value == null) {
+ throw new ArgumentNullException("value",
+ Environment.GetResourceString("ArgumentNull_Obj"));
+ }
+ Contract.EndContractBlock();
+ VerifyWritable();
+ dateTimeInfo = value;
+ }
+ }
+
+
+
+ public void ClearCachedData() {
+ s_userDefaultUICulture = null;
+ s_userDefaultCulture = null;
+
+ RegionInfo.s_currentRegionInfo = null;
+#if !FEATURE_CORECLR // System.TimeZone does not exist in CoreCLR
+ TimeZone.ResetTimeZone();
+#endif // FEATURE_CORECLR
+ TimeZoneInfo.ClearCachedData();
+ // Delete the cached cultures.
+ s_LcidCachedCultures = null;
+ s_NameCachedCultures = null;
+
+ CultureData.ClearCachedData();
+ }
+
+ /*=================================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) {
+ Contract.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_THAI: // Thai calendar
+ return (new ThaiBuddhistCalendar());
+ case Calendar.CAL_HIJRI: // Hijri (Arabic Lunar) calendar
+ return (new HijriCalendar());
+ case Calendar.CAL_HEBREW: // Hebrew (Lunar) calendar
+ return (new HebrewCalendar());
+ case Calendar.CAL_UMALQURA:
+ return (new UmAlQuraCalendar());
+ case Calendar.CAL_PERSIAN:
+ return (new PersianCalendar());
+ 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 {
+ Contract.Ensures(Contract.Result<Calendar>() != null);
+ if (calendar == null) {
+ Contract.Assert(this.m_cultureData.CalendarIds.Length > 0, "this.m_cultureData.CalendarIds.Length > 0");
+ // Get the default calendar for this culture. Note that the value can be
+ // from registry if this is a user default culture.
+ Calendar newObj = this.m_cultureData.DefaultCalendar;
+
+ 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 {
+ Contract.Ensures(Contract.Result<Calendar[]>() != null);
+
+ //
+ // This property always returns a new copy of the calendar array.
+ //
+ int[] calID = this.m_cultureData.CalendarIds;
+ 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_cultureData.UseUserOverride);
+ }
+ }
+
+#if !FEATURE_CORECLR
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [System.Runtime.InteropServices.ComVisible(false)]
+ public CultureInfo GetConsoleFallbackUICulture()
+ {
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+
+ CultureInfo temp = m_consoleFallbackCulture;
+ if (temp == null)
+ {
+ temp = CreateSpecificCulture(this.m_cultureData.SCONSOLEFALLBACKNAME);
+ temp.m_isReadOnly = true;
+ m_consoleFallbackCulture = temp;
+ }
+ return (temp);
+ }
+#endif
+
+ public virtual Object Clone()
+ {
+ Contract.Ensures(Contract.Result<Object>() != null);
+
+ CultureInfo ci = (CultureInfo)MemberwiseClone();
+ ci.m_isReadOnly = false;
+
+ //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 (this.dateTimeInfo != null)
+ {
+ ci.dateTimeInfo = (DateTimeFormatInfo)this.dateTimeInfo.Clone();
+ }
+ if (this.numInfo != null)
+ {
+ ci.numInfo = (NumberFormatInfo)this.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");
+ }
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+ Contract.EndContractBlock();
+
+ if (ci.IsReadOnly) {
+ return (ci);
+ }
+ CultureInfo newInfo = (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) {
+ newInfo.dateTimeInfo = DateTimeFormatInfo.ReadOnly(ci.dateTimeInfo);
+ }
+ if (ci.numInfo != null) {
+ newInfo.numInfo = NumberFormatInfo.ReadOnly(ci.numInfo);
+ }
+
+ } else {
+ newInfo.DateTimeFormat = DateTimeFormatInfo.ReadOnly(ci.DateTimeFormat);
+ newInfo.NumberFormat = NumberFormatInfo.ReadOnly(ci.NumberFormat);
+ }
+ }
+
+ if (ci.textInfo != null)
+ {
+ newInfo.textInfo = TextInfo.ReadOnly(ci.textInfo);
+ }
+
+ if (ci.calendar != null)
+ {
+ newInfo.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.
+ newInfo.m_isReadOnly = true;
+
+ return (newInfo);
+ }
+
+
+ public bool IsReadOnly {
+ get {
+ return (m_isReadOnly);
+ }
+ }
+
+ private void VerifyWritable() {
+ if (m_isReadOnly) {
+ throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
+ }
+ Contract.EndContractBlock();
+ }
+
+ // For resource lookup, we consider a culture the invariant culture by name equality.
+ // We perform this check frequently during resource lookup, so adding a property for
+ // improved readability.
+ internal bool HasInvariantCultureName
+ {
+ get { return Name == CultureInfo.InvariantCulture.Name; }
+ }
+
+ // 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)
+ {
+ // There is a race condition in this code with the side effect that the second thread's value
+ // clobbers the first in the dictionary. This is an acceptable race condition since the CultureInfo objects
+ // are content equal (but not reference equal). Since we make no guarantees there, this race condition is
+ // acceptable.
+ // See code:Dictionary#DictionaryVersusHashtableThreadSafety for details on Dictionary versus
+ // Hashtable thread safety.
+
+ // retval is our return value.
+ CultureInfo retval;
+
+ // Temporary hashtable for the names.
+ Hashtable tempNameHT = s_NameCachedCultures;
+
+ if (name != null)
+ {
+ name = CultureData.AnsiToLower(name);
+ }
+
+ if (altName != null)
+ {
+ altName = CultureData.AnsiToLower(altName);
+ }
+
+ // We expect the same result for both hashtables, but will test individually for added safety.
+ if (tempNameHT == null)
+ {
+ tempNameHT = Hashtable.Synchronized(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;
+ }
+ }
+ }
+#if FEATURE_USE_LCID
+ // Next, the Lcid table.
+ Hashtable tempLcidHT = s_LcidCachedCultures;
+
+ if (tempLcidHT == null)
+ {
+ // Case insensitive is not an issue here, save the constructor call.
+ tempLcidHT = Hashtable.Synchronized(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;
+ }
+ }
+ }
+#endif
+ // 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:
+#if FEATURE_USE_LCID
+ retval = new CultureInfo(lcid, false);
+ break;
+#else
+ return null;
+#endif
+ }
+ }
+ 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
+ {
+ // 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 = CultureData.AnsiToLower(retval.m_name);
+
+ // We add this new culture info object to both tables.
+ tempNameHT[newName] = retval;
+#if FEATURE_USE_LCID
+ const int LCID_ZH_CHS_HANS = 0x0004;
+ const int LCID_ZH_CHT_HANT = 0x7c04;
+
+ if ((retval.LCID == LCID_ZH_CHS_HANS && newName == "zh-hans")
+ || (retval.LCID == LCID_ZH_CHT_HANT && newName == "zh-hant"))
+ {
+ // do nothing because we only want zh-CHS and zh-CHT to cache
+ // by lcid
+ }
+ else
+ {
+ tempLcidHT[retval.LCID] = retval;
+ }
+
+#endif
+ }
+
+#if FEATURE_USE_LCID
+ // 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.
+ s_LcidCachedCultures = tempLcidHT;
+ }
+#endif
+
+ s_NameCachedCultures = tempNameHT;
+
+ // Finally, return our new CultureInfo object.
+ return retval;
+ }
+
+#if FEATURE_USE_LCID
+ // Gets a cached copy of the specified culture from an internal hashtable (or creates it
+ // if not found). (LCID version)... use named version
+ 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"));
+ }
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+ Contract.EndContractBlock();
+ CultureInfo retval = GetCultureInfoHelper(culture, null, null);
+ if (null == retval)
+ {
+ throw new CultureNotFoundException(
+ "culture", culture, Environment.GetResourceString("Argument_CultureNotSupported"));
+ }
+ return retval;
+ }
+#endif
+
+ // Gets a cached copy of the specified culture from an internal hashtable (or creates it
+ // if not found). (Named version)
+ 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");
+ }
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+ Contract.EndContractBlock();
+
+ CultureInfo retval = GetCultureInfoHelper(0, name, null);
+ if (retval == null)
+ {
+ throw new CultureNotFoundException(
+ "name", name, Environment.GetResourceString("Argument_CultureNotSupported"));
+
+ }
+ 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");
+ }
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+ Contract.EndContractBlock();
+
+ CultureInfo retval = GetCultureInfoHelper(-1, name, altName);
+ if (retval == null)
+ {
+ throw new CultureNotFoundException("name or altName",
+ String.Format(
+ CultureInfo.CurrentCulture,
+ Environment.GetResourceString("Argument_OneOfCulturesNotSupported"),
+ name,
+ altName));
+ }
+ return retval;
+ }
+
+
+ // This function is deprecated, we don't like it
+ public static CultureInfo GetCultureInfoByIetfLanguageTag(string name)
+ {
+ Contract.Ensures(Contract.Result<CultureInfo>() != null);
+
+ // Disallow old zh-CHT/zh-CHS names
+ if (name == "zh-CHT" || name == "zh-CHS")
+ {
+ throw new CultureNotFoundException(
+ "name",
+ String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_CultureIetfNotSupported"), name)
+ );
+ }
+
+ CultureInfo ci = GetCultureInfo(name);
+
+ // Disallow alt sorts and es-es_TS
+ if (ci.LCID > 0xffff || ci.LCID == 0x040a)
+ {
+ throw new CultureNotFoundException(
+ "name",
+ String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_CultureIetfNotSupported"), name)
+ );
+ }
+
+ return ci;
+ }
+
+ private static volatile bool s_isTaiwanSku;
+ private static volatile bool s_haveIsTaiwanSku;
+ internal static bool IsTaiwanSku
+ {
+ get
+ {
+ if (!s_haveIsTaiwanSku)
+ {
+ s_isTaiwanSku = (GetSystemDefaultUILanguage() == "zh-TW");
+ s_haveIsTaiwanSku = true;
+ }
+ return (bool)s_isTaiwanSku;
+ }
+ }
+
+ //
+ // Helper Methods.
+ //
+
+ // Get Locale Info Ex calls. So we don't have to muck with the different int/string return types we declared two of these:
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern String nativeGetLocaleInfoEx(String localeName, uint field);
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern int nativeGetLocaleInfoExInt(String localeName, uint field);
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern bool nativeSetThreadLocale(String localeName);
+
+ [System.Security.SecurityCritical]
+ private static String GetDefaultLocaleName(int localeType)
+ {
+ Contract.Assert(localeType == LOCALE_USER_DEFAULT || localeType == LOCALE_SYSTEM_DEFAULT, "[CultureInfo.GetDefaultLocaleName] localeType must be LOCALE_USER_DEFAULT or LOCALE_SYSTEM_DEFAULT");
+
+ string localeName = null;
+ if(InternalGetDefaultLocaleName(localeType, JitHelpers.GetStringHandleOnStack(ref localeName)))
+ {
+ return localeName;
+ }
+ return string.Empty;
+ }
+
+ // Get the default locale name
+ [System.Security.SecurityCritical] // auto-generated
+ [SuppressUnmanagedCodeSecurity]
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool InternalGetDefaultLocaleName(int localetype, StringHandleOnStack localeString);
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ private static String GetUserDefaultUILanguage()
+ {
+ string userDefaultUiLanguage = null;
+ if(InternalGetUserDefaultUILanguage(JitHelpers.GetStringHandleOnStack(ref userDefaultUiLanguage)))
+ {
+ return userDefaultUiLanguage;
+ }
+ return String.Empty;
+ }
+
+ // Get the user's default UI language, return locale name
+ [System.Security.SecurityCritical] // auto-generated
+ [SuppressUnmanagedCodeSecurity]
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool InternalGetUserDefaultUILanguage(StringHandleOnStack userDefaultUiLanguage);
+
+ [System.Security.SecuritySafeCritical] // auto-generated
+ private static String GetSystemDefaultUILanguage()
+ {
+ string systemDefaultUiLanguage = null;
+ if(InternalGetSystemDefaultUILanguage(JitHelpers.GetStringHandleOnStack(ref systemDefaultUiLanguage)))
+ {
+ return systemDefaultUiLanguage;
+ }
+ return String.Empty;
+
+ }
+
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ [SuppressUnmanagedCodeSecurity]
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool InternalGetSystemDefaultUILanguage(StringHandleOnStack systemDefaultUiLanguage);
+
+// Added but disabled from desktop in .NET 4.0, stayed disabled in .NET 4.5
+#if FEATURE_CORECLR
+ [System.Security.SecurityCritical] // auto-generated
+ [MethodImplAttribute(MethodImplOptions.InternalCall)]
+ internal static extern String[] nativeGetResourceFallbackArray();
+#endif
+ }
+}
+