b3cf1c0cb2ec3ba310be348343e29e3c650bffbc
[mono.git] / mcs / class / referencesource / mscorlib / system / globalization / cultureinfo.cs
1 // ==++==
2 //
3 //   Copyright (c) Microsoft Corporation.  All rights reserved.
4 //
5 // ==--==
6 ////////////////////////////////////////////////////////////////////////////
7 //
8 //  Class:    CultureInfo
9 //
10 //
11 //  Purpose:  This class represents the software preferences of a particular
12 //            culture or community.  It includes information such as the
13 //            language, writing system, and a calendar used by the culture
14 //            as well as methods for common operations such as printing
15 //            dates and sorting strings.
16 //
17 //  Date:     Microsoft 31, 1999
18 //
19 //
20 //  !!!! NOTE WHEN CHANGING THIS CLASS !!!!
21 //
22 //  If adding or removing members to this class, please update CultureInfoBaseObject
23 //  in ndp/clr/src/vm/object.h. Note, the "actual" layout of the class may be
24 //  different than the order in which members are declared. For instance, all
25 //  reference types will come first in the class before value types (like ints, bools, etc)
26 //  regardless of the order in which they are declared. The best way to see the
27 //  actual order of the class is to do a !dumpobj on an instance of the managed
28 //  object inside of the debugger.
29 //
30 ////////////////////////////////////////////////////////////////////////////
31
32 namespace System.Globalization {
33     using System;
34     using System.Security;
35     using System.Threading;
36     using System.Collections;
37     using System.Runtime;
38     using System.Runtime.CompilerServices;
39     using System.Runtime.InteropServices;
40     using System.Runtime.Serialization;
41     using System.Runtime.Versioning;
42     using System.Security.Permissions;
43     using System.Reflection;
44     using Microsoft.Win32;
45     using System.Diagnostics.Contracts;
46     using System.Resources;
47
48     [Serializable]
49     [System.Runtime.InteropServices.ComVisible(true)]
50     public class CultureInfo : ICloneable, IFormatProvider {
51         //--------------------------------------------------------------------//
52         //                        Internal Information                        //
53         //--------------------------------------------------------------------//
54
55         //--------------------------------------------------------------------//
56         // Data members to be serialized:
57         //--------------------------------------------------------------------//
58
59         // We use an RFC4646 type string to construct CultureInfo.
60         // This string is stored in m_name and is authoritative.
61         // We use the m_cultureData to get the data for our object
62
63         // WARNING
64         // WARNING: All member fields declared here must also be in ndp/clr/src/vm/object.h
65         // WARNING: They aren't really private because object.h can access them, but other C# stuff cannot
66         // WARNING: The type loader will rearrange class member offsets so the mscorwks!CultureInfoBaseObject
67         // WARNING: must be manually structured to match the true loaded class layout
68         // WARNING
69         internal bool m_isReadOnly;
70         internal CompareInfo compareInfo;
71         internal TextInfo textInfo;
72         // Not serialized for now since we only build it privately for use in the CARIB (so rebuilding is OK)
73 #if !FEATURE_CORECLR
74         [NonSerialized]internal RegionInfo regionInfo;
75 #endif
76         internal NumberFormatInfo numInfo;
77         internal DateTimeFormatInfo dateTimeInfo;
78         internal Calendar calendar;
79 #if !FEATURE_CORECLR
80         [OptionalField(VersionAdded = 1)]
81         internal int m_dataItem;       // NEVER USED, DO NOT USE THIS! (Serialized in Whidbey/Everett)
82         [OptionalField(VersionAdded = 1)]
83         internal int cultureID  = 0x007f;  // NEVER USED, DO NOT USE THIS! (Serialized in Whidbey/Everett)
84 #endif // !FEATURE_CORECLR
85         //
86         // The CultureData instance that we are going to read data from.
87         // For supported culture, this will be the CultureData instance that read data from mscorlib assembly.
88         // For customized culture, this will be the CultureData instance that read data from user customized culture binary file.
89         //
90         [NonSerialized]internal CultureData m_cultureData;
91         
92         [NonSerialized]internal bool m_isInherited;
93 #if FEATURE_LEAK_CULTURE_INFO
94         [NonSerialized]private bool m_isSafeCrossDomain;
95         [NonSerialized]private int m_createdDomainID;
96 #endif // !FEATURE_CORECLR
97 #if !FEATURE_CORECLR
98         [NonSerialized]private CultureInfo m_consoleFallbackCulture;
99 #endif // !FEATURE_CORECLR
100
101         // Names are confusing.  Here are 3 names we have:
102         //
103         //  new CultureInfo()   m_name        m_nonSortName   m_sortName
104         //      en-US           en-US           en-US           en-US
105         //      de-de_phoneb    de-DE_phoneb    de-DE           de-DE_phoneb
106         //      fj-fj (custom)  fj-FJ           fj-FJ           en-US (if specified sort is en-US)
107         //      en              en              
108         //
109         // Note that in Silverlight we ask the OS for the text and sort behavior, so the 
110         // textinfo and compareinfo names are the same as the name
111
112         // Note that the name used to be serialized for Everett; it is now serialized
113         // because alernate sorts can have alternate names.
114         // This has a de-DE, de-DE_phoneb or fj-FJ style name
115         internal string m_name;
116
117         // This will hold the non sorting name to be returned from CultureInfo.Name property.
118         // This has a de-DE style name even for de-DE_phoneb type cultures
119         [NonSerialized]private string m_nonSortName;
120
121         // This will hold the sorting name to be returned from CultureInfo.SortName property.
122         // This might be completely unrelated to the culture name if a custom culture.  Ie en-US for fj-FJ.
123         // Otherwise its the sort name, ie: de-DE or de-DE_phoneb
124         [NonSerialized]private string m_sortName;
125
126
127         //--------------------------------------------------------------------//
128         //
129         // Static data members
130         //
131         //--------------------------------------------------------------------//
132
133         //Get the current user default culture.  This one is almost always used, so we create it by default.
134         private static volatile CultureInfo s_userDefaultCulture;
135
136         //
137         // All of the following will be created on demand.
138         //
139
140         //The Invariant culture;
141         private static volatile CultureInfo s_InvariantCultureInfo;
142
143         //The culture used in the user interface. This is mostly used to load correct localized resources.
144         private static volatile CultureInfo s_userDefaultUICulture;
145
146         //This is the UI culture used to install the OS.
147         private static volatile CultureInfo s_InstalledUICultureInfo;
148
149         //These are defaults that we use if a thread has not opted into having an explicit culture
150         private static volatile CultureInfo s_DefaultThreadCurrentUICulture;
151         private static volatile CultureInfo s_DefaultThreadCurrentCulture;
152
153         //This is a cache of all previously created cultures.  Valid keys are LCIDs or the name.  We use two hashtables to track them,
154         // depending on how they are called.
155         private static volatile Hashtable s_LcidCachedCultures;
156         private static volatile Hashtable s_NameCachedCultures;
157
158 #if FEATURE_APPX
159         // When running under AppX, we use this to get some information about the language list
160         [SecurityCritical]
161         private static volatile WindowsRuntimeResourceManagerBase s_WindowsRuntimeResourceManager;
162
163         [ThreadStatic]
164         private static bool ts_IsDoingAppXCultureInfoLookup;
165 #endif
166
167         //The parent culture.
168         [NonSerialized]private CultureInfo m_parent;
169
170         // LOCALE constants of interest to us internally and privately for LCID functions
171         // (ie: avoid using these and use names if possible)
172         internal const int LOCALE_NEUTRAL              = 0x0000;
173         private  const int LOCALE_USER_DEFAULT         = 0x0400;
174         private  const int LOCALE_SYSTEM_DEFAULT       = 0x0800;
175         internal const int LOCALE_CUSTOM_DEFAULT       = 0x0c00;
176         internal const int LOCALE_CUSTOM_UNSPECIFIED   = 0x1000;
177         internal const int LOCALE_INVARIANT            = 0x007F;
178         private  const int LOCALE_TRADITIONAL_SPANISH  = 0x040a;
179
180         //
181         // The CultureData  instance that reads the data provided by our CultureData class.
182         //
183         //Using a field initializer rather than a static constructor so that the whole class can be lazy
184         //init.
185         private static readonly bool init = Init();
186         private static bool Init()
187         {
188
189             if (s_InvariantCultureInfo == null) 
190             {
191                 CultureInfo temp = new CultureInfo("", false);
192                 temp.m_isReadOnly = true;
193                 s_InvariantCultureInfo = temp;
194             }
195             // First we set it to Invariant in case someone needs it before we're done finding it.
196             // For example, if we throw an exception in InitUserDefaultCulture, we will still need an valid
197             // s_userDefaultCulture to be used in Thread.CurrentCulture.
198             s_userDefaultCulture = s_userDefaultUICulture = s_InvariantCultureInfo;
199
200             s_userDefaultCulture = InitUserDefaultCulture();
201             s_userDefaultUICulture = InitUserDefaultUICulture();
202             return true;
203         }
204
205         [System.Security.SecuritySafeCritical]  // auto-generated
206         static CultureInfo InitUserDefaultCulture()
207         {
208             String strDefault = GetDefaultLocaleName(LOCALE_USER_DEFAULT);
209             if (strDefault == null)
210             {
211                 strDefault = GetDefaultLocaleName(LOCALE_SYSTEM_DEFAULT);
212
213                 if (strDefault == null)
214                 {
215                     // If system default doesn't work, keep using the invariant
216                     return (CultureInfo.InvariantCulture);
217                 }
218             }
219             CultureInfo temp = GetCultureByName(strDefault, true);
220
221             temp.m_isReadOnly = true;
222
223             return (temp);
224         }
225
226         static CultureInfo InitUserDefaultUICulture()
227         {
228             String strDefault = GetUserDefaultUILanguage();
229
230             // In most of cases, UserDefaultCulture == UserDefaultUICulture, so we should use the same instance if possible.
231             if (strDefault == UserDefaultCulture.Name)
232             {
233                 return (UserDefaultCulture);
234             }
235
236             CultureInfo temp = GetCultureByName( strDefault, true);
237
238             if (temp == null)
239             {
240                 return (CultureInfo.InvariantCulture);
241             }
242
243             temp.m_isReadOnly = true;
244
245             return (temp);
246         }
247
248 #if FEATURE_APPX
249         [SecuritySafeCritical]
250         internal static CultureInfo GetCultureInfoForUserPreferredLanguageInAppX()
251         {
252             // If a call to GetCultureInfoForUserPreferredLanguageInAppX() generated a recursive
253             // call to itself, return null, since we don't want to stack overflow.  For example, 
254             // this can happen if some code in this method ends up calling CultureInfo.CurrentCulture
255             // (which is common on check'd build because of BCLDebug logging which calls Int32.ToString()).  
256             // In this case, returning null will mean CultureInfo.CurrentCulture gets the default Win32 
257             // value, which should be fine. 
258             if(ts_IsDoingAppXCultureInfoLookup)
259             {
260                 return null;
261             }
262
263             // If running within a compilation process (mscorsvw.exe, for example), it is illegal to
264             // load any non-mscorlib assembly for execution. Since WindowsRuntimeResourceManager lives
265             // in System.Runtime.WindowsRuntime, caller will need to fall back to default Win32 value,
266             // which should be fine because we should only ever need to access FX resources during NGEN.
267             // FX resources are always loaded from satellite assemblies - even in AppX processes (see the
268             // comments in code:System.Resources.ResourceManager.SetAppXConfiguration for more details).
269             if (AppDomain.IsAppXNGen)
270             {
271                 return null;
272             }
273
274             CultureInfo toReturn = null;
275
276             try 
277             {
278                 ts_IsDoingAppXCultureInfoLookup = true;
279
280                 if(s_WindowsRuntimeResourceManager == null)
281                 {
282                     s_WindowsRuntimeResourceManager = ResourceManager.GetWinRTResourceManager();
283                 }
284
285                 toReturn = s_WindowsRuntimeResourceManager.GlobalResourceContextBestFitCultureInfo;
286             } 
287             finally 
288             {
289                ts_IsDoingAppXCultureInfoLookup = false;
290             }
291  
292             return toReturn;
293         }
294
295         [SecuritySafeCritical]
296         internal static bool SetCultureInfoForUserPreferredLanguageInAppX(CultureInfo ci)
297         {
298             // If running within a compilation process (mscorsvw.exe, for example), it is illegal to
299             // load any non-mscorlib assembly for execution. Since WindowsRuntimeResourceManager lives
300             // in System.Runtime.WindowsRuntime, caller will need to fall back to default Win32 value,
301             // which should be fine because we should only ever need to access FX resources during NGEN.
302             // FX resources are always loaded from satellite assemblies - even in AppX processes (see the
303             // comments in code:System.Resources.ResourceManager.SetAppXConfiguration for more details).
304             if (AppDomain.IsAppXNGen)
305             {
306                 return false;
307             }
308
309             if (s_WindowsRuntimeResourceManager == null)
310             {
311                 s_WindowsRuntimeResourceManager = ResourceManager.GetWinRTResourceManager();
312             }
313
314             return s_WindowsRuntimeResourceManager.SetGlobalResourceContextDefaultCulture(ci);
315         }
316 #endif
317
318         ////////////////////////////////////////////////////////////////////////
319         //
320         //  CultureInfo Constructors
321         //
322         ////////////////////////////////////////////////////////////////////////
323
324
325         public CultureInfo(String name) : this(name, true) {
326         }
327
328
329         public CultureInfo(String name, bool useUserOverride) {
330             if (name==null) {
331                 throw new ArgumentNullException("name",
332                     Environment.GetResourceString("ArgumentNull_String"));
333             }
334             Contract.EndContractBlock();
335
336 #if FEATURE_LEGACYNETCF
337             // Windows Phone 7 and 7.1 do not support Bengali.  When running on Windows Phone 8,
338             // WinPhone 7.x apps get the old Mango text stack, not the Apollo text stack.  The Mango
339             // text stack cannot display characters in Bengali, such as the culture's native name.
340             // Phone apps are already written to catch an exception here and bypass this culture.
341             if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8 &&
342                 (name == "bn" || name == "bn-BD" || name == "bn-IN" ||  name == "ml" || name == "or"))
343                 throw new ArgumentException(Environment.GetResourceString("Argument_CultureNotSupported"));
344 #endif
345
346             // Get our data providing record
347             this.m_cultureData = CultureData.GetCultureData(name, useUserOverride);
348
349             if (this.m_cultureData == null) {
350 #if FEATURE_LEGACYNETCF
351                 if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
352                     throw new PlatformNotSupportedException(Environment.GetResourceString("Argument_CultureNotSupported"));
353 #endif
354                 throw new CultureNotFoundException("name", name, Environment.GetResourceString("Argument_CultureNotSupported"));
355             }
356
357             this.m_name = this.m_cultureData.CultureName;
358             this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
359         }
360
361
362 #if  FEATURE_USE_LCID         
363         public CultureInfo(int culture) : this(culture, true) {
364         }
365
366         public CultureInfo(int culture, bool useUserOverride) {
367             // We don't check for other invalid LCIDS here...
368             if (culture < 0) {
369                 throw new ArgumentOutOfRangeException("culture",
370                     Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
371             }
372             Contract.EndContractBlock();
373
374             InitializeFromCultureId(culture, useUserOverride);
375         }
376
377         private void InitializeFromCultureId(int culture, bool useUserOverride)
378         {
379             switch (culture)
380             {
381                 case LOCALE_CUSTOM_DEFAULT:
382                 case LOCALE_SYSTEM_DEFAULT:
383                 case LOCALE_NEUTRAL:
384                 case LOCALE_USER_DEFAULT:
385                 case LOCALE_CUSTOM_UNSPECIFIED:
386                     // Can't support unknown custom cultures and we do not support neutral or
387                     // non-custom user locales.
388                     throw new CultureNotFoundException(
389                         "culture", culture, Environment.GetResourceString("Argument_CultureNotSupported"));
390
391                 default:
392                     // Now see if this LCID is supported in the system default CultureData  table.
393                     this.m_cultureData = CultureData.GetCultureData(culture, useUserOverride);
394                     break;
395             }
396             this.m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
397             this.m_name = this.m_cultureData.CultureName;
398         }
399 #endif // FEATURE_USE_LCID
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         internal static void CheckDomainSafetyObject(Object obj, Object container)
407         {
408             if (obj.GetType().Assembly != typeof(System.Globalization.CultureInfo).Assembly) {
409                 
410                 throw new InvalidOperationException(
411                             String.Format(
412                                 CultureInfo.CurrentCulture, 
413                                 Environment.GetResourceString("InvalidOperation_SubclassedObject"), 
414                                 obj.GetType(),
415                                 container.GetType()));
416             }
417             Contract.EndContractBlock();
418         }
419
420 #region Serialization
421         // We need to store the override from the culture data record.
422         private bool    m_useUserOverride;
423
424         [OnDeserialized]
425         private void OnDeserialized(StreamingContext ctx)
426         {
427 #if  FEATURE_USE_LCID         
428             // Whidbey+ should remember our name
429             // but v1 and v1.1 did not store name -- only lcid
430             // Whidbey did not store actual alternate sort name in m_name
431             //   like we do in v4 so we can't use name for alternate sort
432             // e.g. for es-ES_tradnl: v2 puts es-ES in m_name; v4 puts es-ES_tradnl
433             if (m_name == null || IsAlternateSortLcid(cultureID))
434             {
435                 Contract.Assert(cultureID >=0, "[CultureInfo.OnDeserialized] cultureID >= 0");
436                 InitializeFromCultureId(cultureID, m_useUserOverride);
437             }
438             else
439             {
440 #endif
441                 Contract.Assert(m_name != null, "[CultureInfo.OnDeserialized] m_name != null");
442                 // 
443
444                 this.m_cultureData = CultureData.GetCultureData(m_name, m_useUserOverride);
445                 if (this.m_cultureData == null)
446                     throw new CultureNotFoundException(
447                         "m_name", m_name, Environment.GetResourceString("Argument_CultureNotSupported"));
448                     
449 #if  FEATURE_USE_LCID         
450             }
451 #endif
452             m_isInherited = (this.GetType() != typeof(System.Globalization.CultureInfo));
453
454             // in case we have non customized CultureInfo object we shouldn't allow any customized object  
455             // to be attached to it for cross app domain safety.
456             if (this.GetType().Assembly == typeof(System.Globalization.CultureInfo).Assembly)
457             {
458                 if (textInfo != null)
459                 {
460                     CheckDomainSafetyObject(textInfo, this);
461                 }
462                 
463                 if (compareInfo != null)
464                 {
465                     CheckDomainSafetyObject(compareInfo, this);
466                 }
467             }
468         }
469
470 #if  FEATURE_USE_LCID         
471         //  A locale ID is a 32 bit value which is the combination of a
472         //  language ID, a sort ID, and a reserved area.  The bits are
473         //  allocated as follows:
474         //
475         //  +------------------------+-------+--------------------------------+
476         //  |        Reserved        |Sort ID|           Language ID          |
477         //  +------------------------+-------+--------------------------------+
478         //  31                     20 19   16 15                             0   bit
479         private const int LOCALE_SORTID_MASK = 0x000f0000;
480
481         static private bool IsAlternateSortLcid(int lcid)
482         {
483             if(lcid == LOCALE_TRADITIONAL_SPANISH)
484             {
485                 return true;
486             }
487
488             return (lcid & LOCALE_SORTID_MASK) != 0;
489         }
490 #endif
491
492         [OnSerializing]
493         private void OnSerializing(StreamingContext ctx)
494         {
495             this.m_name              = this.m_cultureData.CultureName;
496             this.m_useUserOverride   = this.m_cultureData.UseUserOverride;
497 #if FEATURE_USE_LCID
498             // for compatibility with v2 serialize cultureID
499             this.cultureID = this.m_cultureData.ILANGUAGE;
500 #endif
501         }
502 #endregion Serialization
503
504 #if FEATURE_LEAK_CULTURE_INFO
505         // Is it safe to send this CultureInfo as an instance member of a Thread cross AppDomain boundaries?
506         // For Silverlight, the answer is always no.
507         internal bool IsSafeCrossDomain {
508             get {
509                 Contract.Assert(m_createdDomainID != 0, "[CultureInfo.IsSafeCrossDomain] m_createdDomainID != 0");
510                 return m_isSafeCrossDomain;
511             }
512         }
513
514         internal int CreatedDomainID {
515             get {
516                 Contract.Assert(m_createdDomainID != 0,  "[CultureInfo.CreatedDomain] m_createdDomainID != 0");
517                 return m_createdDomainID;
518             }
519         }
520
521         internal void StartCrossDomainTracking() {
522         
523             // If we have decided about cross domain safety of this instance, we are done
524             if (m_createdDomainID != 0)
525                 return;
526
527             // If FEATURE_LEAK_CULTURE_INFO isn't enabled, we never want to pass
528             // CultureInfo as an instance member of a Thread. 
529             if (CanSendCrossDomain())
530             {
531                 m_isSafeCrossDomain = true;
532             }
533
534             // m_createdDomainID has to be assigned last. We use it to signal that we have
535             // completed the check.
536             System.Threading.Thread.MemoryBarrier();
537             m_createdDomainID = Thread.GetDomainID();
538         }
539 #endif // FEATURE_LEAK_CULTURE_INFO
540
541         // Is it safe to pass the CultureInfo cross AppDomain boundaries, not necessarily as an instance
542         // member of Thread. This is different from IsSafeCrossDomain, which implies passing the CultureInfo
543         // as a Thread instance member. 
544         internal bool CanSendCrossDomain()
545         {
546             bool isSafe = false;
547             if (this.GetType() == typeof(System.Globalization.CultureInfo))
548             {
549                 isSafe = true;
550             }
551             return isSafe;
552         }
553
554         // Constructor called by SQL Server's special munged culture - creates a culture with
555         // a TextInfo and CompareInfo that come from a supplied alternate source. This object
556         // is ALWAYS read-only.
557         // Note that we really cannot use an LCID version of this override as the cached
558         // name we create for it has to include both names, and the logic for this is in
559         // the GetCultureInfo override *only*.
560         internal CultureInfo(String cultureName, String textAndCompareCultureName)
561         {
562             if (cultureName==null) {
563                 throw new ArgumentNullException("cultureName",
564                     Environment.GetResourceString("ArgumentNull_String"));
565             }
566             Contract.EndContractBlock();
567
568             this.m_cultureData = CultureData.GetCultureData(cultureName, false);
569             if (this.m_cultureData == null)
570                 throw new CultureNotFoundException(
571                     "cultureName", cultureName, Environment.GetResourceString("Argument_CultureNotSupported"));
572             
573             this.m_name = this.m_cultureData.CultureName;            
574
575             CultureInfo altCulture = GetCultureInfo(textAndCompareCultureName);
576             this.compareInfo = altCulture.CompareInfo;
577             this.textInfo = altCulture.TextInfo;
578         }
579
580         // We do this to try to return the system UI language and the default user languages
581         // The callers should have a fallback if this fails (like Invariant)
582         private static CultureInfo GetCultureByName(String name, bool userOverride)
583         {           
584             // Try to get our culture
585             try
586             {
587                 return userOverride ? new CultureInfo(name) : CultureInfo.GetCultureInfo(name);
588             }
589             catch (ArgumentException)
590             {
591             }
592
593             return null;
594         }
595
596         //
597         // Return a specific culture.  A tad irrelevent now since we always return valid data
598         // for neutral locales.
599         //
600         // Note that there's interesting behavior that tries to find a smaller name, ala RFC4647,
601         // if we can't find a bigger name.  That doesn't help with things like "zh" though, so
602         // the approach is of questionable value
603         //
604 #if !FEATURE_CORECLR
605         public static CultureInfo CreateSpecificCulture(String name) {
606             Contract.Ensures(Contract.Result<CultureInfo>() != null);
607
608             CultureInfo culture;
609
610             try {
611                 culture = new CultureInfo(name);
612             } catch(ArgumentException) {
613                 // When CultureInfo throws this exception, it may be because someone passed the form
614                 // like "az-az" because it came out of an http accept lang. We should try a little
615                 // parsing to perhaps fall back to "az" here and use *it* to create the neutral.
616
617                 int idx;
618
619                 culture = null;
620                 for(idx = 0; idx < name.Length; idx++) {
621                     if('-' == name[idx]) {
622                         try {
623                             culture = new CultureInfo(name.Substring(0, idx));
624                             break;
625                         } catch(ArgumentException) {
626                             // throw the original exception so the name in the string will be right
627                             throw;
628                         }
629                     }
630                 }
631
632                 if(null == culture) {
633                     // nothing to save here; throw the original exception
634                     throw;
635                 }
636             }
637
638             //In the most common case, they've given us a specific culture, so we'll just return that.
639             if (!(culture.IsNeutralCulture)) {
640                 return culture;
641             }
642
643             return (new CultureInfo(culture.m_cultureData.SSPECIFICCULTURE));
644         }
645 #endif // !FEATURE_CORECLR
646
647         internal static bool VerifyCultureName(String cultureName, bool throwException) 
648         {
649             // This function is used by ResourceManager.GetResourceFileName(). 
650             // ResourceManager searches for resource using CultureInfo.Name,
651             // so we should check against CultureInfo.Name.
652
653             for (int i=0; i<cultureName.Length; i++) {
654                 char c = cultureName[i];
655                 // 
656
657                 if (Char.IsLetterOrDigit(c) || c=='-' || c=='_') {
658                     continue;
659                 }
660                 if (throwException) {
661                     throw new ArgumentException(Environment.GetResourceString("Argument_InvalidResourceCultureName", cultureName));
662                 }
663                 return false;
664             }
665             return true;
666             
667         }
668
669         internal static bool VerifyCultureName(CultureInfo culture, bool throwException) {
670             Contract.Assert(culture!=null, "[CultureInfo.VerifyCultureName]culture!=null");
671
672             //If we have an instance of one of our CultureInfos, the user can't have changed the
673             //name and we know that all names are valid in files.
674             if (!culture.m_isInherited) {
675                 return true;
676             }
677
678             return VerifyCultureName(culture.Name, throwException);
679
680         }
681
682         ////////////////////////////////////////////////////////////////////////
683         //
684         //  CurrentCulture
685         //
686         //  This instance provides methods based on the current user settings.
687         //  These settings are volatile and may change over the lifetime of the
688         //  thread.
689         //
690         ////////////////////////////////////////////////////////////////////////
691
692
693         public static CultureInfo CurrentCulture
694         {
695             get {
696                 Contract.Ensures(Contract.Result<CultureInfo>() != null);
697
698 #if !FEATURE_CORECLR
699                 return Thread.CurrentThread.CurrentCulture;
700 #else
701                 // In the case of CoreCLR, Thread.m_CurrentCulture and
702                 // Thread.m_CurrentUICulture are thread static so as not to let
703                 // CultureInfo objects leak across AppDomain boundaries. The
704                 // fact that these fields are thread static introduces overhead
705                 // in accessing them (through Thread.CurrentCulture). There is
706                 // also overhead in accessing Thread.CurrentThread. In this
707                 // case, we can avoid the overhead of Thread.CurrentThread
708                 // because these fields are thread static, and so do not
709                 // require a Thread instance to be accessed.
710 #if FEATURE_APPX
711                 if(AppDomain.IsAppXModel()) {
712                     CultureInfo culture = GetCultureInfoForUserPreferredLanguageInAppX();
713                     if (culture != null)
714                         return culture;
715                 }
716 #endif
717                 return Thread.m_CurrentCulture ??
718                     s_DefaultThreadCurrentCulture ??
719                     s_userDefaultCulture ??
720                     UserDefaultCulture;
721 #endif
722             }
723
724             set {
725 #if FEATURE_APPX
726                     if (value == null) {
727                         throw new ArgumentNullException("value");
728                     }                    
729
730                     if (AppDomain.IsAppXModel()) {
731                         if (SetCultureInfoForUserPreferredLanguageInAppX(value)) {
732                             // successfully set the culture, otherwise fallback to legacy path
733                             return; 
734                         }
735                     }
736 #endif
737                     Thread.CurrentThread.CurrentCulture = value;
738             }
739         }
740
741         //
742         // This is the equivalence of the Win32 GetUserDefaultLCID()
743         //
744         internal static CultureInfo UserDefaultCulture {
745             get
746             {
747                 Contract.Ensures(Contract.Result<CultureInfo>() != null);
748
749                 CultureInfo temp = s_userDefaultCulture;
750                 if (temp == null)
751                 {
752                     //
753                     // setting the s_userDefaultCulture with invariant culture before intializing it is a protection
754                     // against recursion problem just in case if somebody called CurrentCulture from the CultureInfo
755                     // creation path. the recursion can happen if the current user culture is a replaced custom culture.
756                     //
757                     
758                     s_userDefaultCulture = CultureInfo.InvariantCulture;
759                     temp = InitUserDefaultCulture();
760                     s_userDefaultCulture = temp;
761                 }
762                 return (temp);
763             }
764         }
765
766         //
767         //  This is the equivalence of the Win32 GetUserDefaultUILanguage()
768         //
769         internal static CultureInfo UserDefaultUICulture {
770             get {
771                 Contract.Ensures(Contract.Result<CultureInfo>() != null);
772
773                 CultureInfo temp = s_userDefaultUICulture;
774                 if (temp == null) 
775                 {
776                     //
777                     // setting the s_userDefaultCulture with invariant culture before intializing it is a protection
778                     // against recursion problem just in case if somebody called CurrentUICulture from the CultureInfo
779                     // creation path. the recursion can happen if the current user culture is a replaced custom culture.
780                     //
781                     
782                     s_userDefaultUICulture = CultureInfo.InvariantCulture;
783                     
784                     temp = InitUserDefaultUICulture();
785                     s_userDefaultUICulture = temp;
786                 }
787                 return (temp);
788             }
789         }
790
791
792         public static CultureInfo CurrentUICulture {
793             get {
794                 Contract.Ensures(Contract.Result<CultureInfo>() != null);
795
796 #if !FEATURE_CORECLR
797                 return Thread.CurrentThread.CurrentUICulture;
798 #else
799                 // In the case of CoreCLR, Thread.m_CurrentCulture and
800                 // Thread.m_CurrentUICulture are thread static so as not to let
801                 // CultureInfo objects leak across AppDomain boundaries. The
802                 // fact that these fields are thread static introduces overhead
803                 // in accessing them (through Thread.CurrentCulture). There is
804                 // also overhead in accessing Thread.CurrentThread. In this
805                 // case, we can avoid the overhead of Thread.CurrentThread
806                 // because these fields are thread static, and so do not
807                 // require a Thread instance to be accessed.
808 #if FEATURE_APPX
809                 if(AppDomain.IsAppXModel()) {
810                     CultureInfo culture = GetCultureInfoForUserPreferredLanguageInAppX();
811                     if (culture != null)
812                         return culture;
813                 }
814 #endif
815                 return Thread.m_CurrentUICulture ??
816                     s_DefaultThreadCurrentUICulture ??
817                     s_userDefaultUICulture ??
818                     UserDefaultUICulture;
819 #endif
820             }
821
822             set {
823 #if FEATURE_APPX
824                     if (value == null) {
825                         throw new ArgumentNullException("value");
826                     }                    
827
828                     if (AppDomain.IsAppXModel()) {
829                         if (SetCultureInfoForUserPreferredLanguageInAppX(value)) {
830                             // successfully set the culture, otherwise fallback to legacy path
831                             return; 
832                         }
833                     }
834 #endif
835                     Thread.CurrentThread.CurrentUICulture = value;
836             }
837         }
838
839
840         //
841         // This is the equivalence of the Win32 GetSystemDefaultUILanguage()
842         //
843         // 
844         public static CultureInfo InstalledUICulture {
845             get {
846                 Contract.Ensures(Contract.Result<CultureInfo>() != null);
847
848                 CultureInfo temp = s_InstalledUICultureInfo;
849                 if (temp == null) {
850                     String strDefault = GetSystemDefaultUILanguage();
851                     temp = GetCultureByName(strDefault, true);
852
853                     if (temp == null)
854                     {
855                         temp = InvariantCulture;
856                     }
857
858                     temp.m_isReadOnly = true;
859                     s_InstalledUICultureInfo = temp;
860                 }
861                 return (temp);
862             }
863         }
864
865         public static CultureInfo DefaultThreadCurrentCulture {
866             get {
867                 return s_DefaultThreadCurrentCulture;
868             }
869
870             [System.Security.SecuritySafeCritical]  // auto-generated
871 #pragma warning disable 618
872             [SecurityPermission(SecurityAction.Demand, ControlThread = true)]
873 #pragma warning restore 618
874             set {
875
876                 // If you add pre-conditions to this method, check to see if you also need to 
877                 // add them to Thread.CurrentCulture.set.
878
879                 s_DefaultThreadCurrentCulture = value;
880             }
881         }
882
883         public static CultureInfo DefaultThreadCurrentUICulture {
884             get {
885                 return s_DefaultThreadCurrentUICulture;
886             }
887
888             [System.Security.SecuritySafeCritical]  // auto-generated
889 #pragma warning disable 618
890             [SecurityPermission(SecurityAction.Demand, ControlThread = true)]
891 #pragma warning restore 618
892             set {
893
894                 //If they're trying to use a Culture with a name that we can't use in resource lookup,
895                 //don't even let them set it on the thread.
896
897                 // If you add more pre-conditions to this method, check to see if you also need to 
898                 // add them to Thread.CurrentUICulture.set.
899
900                 if (value != null) 
901                 {                   
902                     CultureInfo.VerifyCultureName(value, true);
903                 }
904
905                 s_DefaultThreadCurrentUICulture = value;
906             }
907         }
908
909 #if FEATURE_LEGACYNETCF
910         //
911         // Helper methods to set default thread culture without security demand. Used
912         // by NetCF compatibility quirk. See comment in Thread.CurrentUICulture setter for details.
913         //
914         internal static void SetCurrentUICultureQuirk(CultureInfo value) {
915             s_DefaultThreadCurrentUICulture = value;
916         }
917
918         internal static void SetCurrentCultureQuirk(CultureInfo value) {
919             s_DefaultThreadCurrentCulture = value;
920         }
921 #endif
922
923
924         ////////////////////////////////////////////////////////////////////////
925         //
926         //  InvariantCulture
927         //
928         //  This instance provides methods, for example for casing and sorting,
929         //  that are independent of the system and current user settings.  It
930         //  should be used only by processes such as some system services that
931         //  require such invariant results (eg. file systems).  In general,
932         //  the results are not linguistically correct and do not match any
933         //  culture info.
934         //
935         ////////////////////////////////////////////////////////////////////////
936
937
938         public static CultureInfo InvariantCulture {
939             [Pure]
940             get {
941                 Contract.Ensures(Contract.Result<CultureInfo>() != null);
942                 return (s_InvariantCultureInfo);
943             }
944         }
945
946
947         ////////////////////////////////////////////////////////////////////////
948         //
949         //  Parent
950         //
951         //  Return the parent CultureInfo for the current instance.
952         //
953         ////////////////////////////////////////////////////////////////////////
954
955         public virtual CultureInfo Parent
956         {
957             [System.Security.SecuritySafeCritical]  // auto-generated
958             get
959             {
960                 Contract.Ensures(Contract.Result<CultureInfo>() != null);
961
962                 if (null == m_parent)
963                 {
964                     try
965                     {
966                         string parentName = this.m_cultureData.SPARENT;
967
968                         if (String.IsNullOrEmpty(parentName))
969                         {
970                             m_parent = InvariantCulture;
971                         }
972                         else
973                         {
974                             m_parent = new CultureInfo(parentName, this.m_cultureData.UseUserOverride);
975                         }
976                     }
977                     catch (ArgumentException)
978                     {
979                         // For whatever reason our IPARENT or SPARENT wasn't correct, so use invariant
980                         // We can't allow ourselves to fail.  In case of custom cultures the parent of the
981                         // current custom culture isn't installed.
982                         m_parent =  InvariantCulture;
983                     }
984                 }
985                 return m_parent;
986             }
987         }
988
989         ////////////////////////////////////////////////////////////////////////
990         //
991         //  LCID
992         //
993         //  Returns a properly formed culture identifier for the current
994         //  culture info.
995         //
996         ////////////////////////////////////////////////////////////////////////
997
998 #if FEATURE_USE_LCID
999         public virtual int LCID {
1000             get {
1001                 return (this.m_cultureData.ILANGUAGE);
1002             }
1003         }
1004 #endif
1005
1006         ////////////////////////////////////////////////////////////////////////
1007         //
1008         //  BaseInputLanguage
1009         //
1010         //  Essentially an LCID, though one that may be different than LCID in the case
1011         //  of a customized culture (LCID == LOCALE_CUSTOM_UNSPECIFIED).
1012         //
1013         ////////////////////////////////////////////////////////////////////////
1014 #if FEATURE_USE_LCID    
1015         [System.Runtime.InteropServices.ComVisible(false)]
1016         public virtual int KeyboardLayoutId
1017         {
1018             get
1019             {
1020                 int keyId = this.m_cultureData.IINPUTLANGUAGEHANDLE;
1021
1022                 // Not a customized culture, return the default Keyboard layout ID, which is the same as the language ID.
1023                 return (keyId);
1024             }
1025         }
1026 #endif
1027
1028 #if !FEATURE_CORECLR
1029         public static CultureInfo[] GetCultures(CultureTypes types) {
1030             Contract.Ensures(Contract.Result<CultureInfo[]>() != null);
1031             // internally we treat UserCustomCultures as Supplementals but v2
1032             // treats as Supplementals and Replacements
1033             if((types & CultureTypes.UserCustomCulture) == CultureTypes.UserCustomCulture)
1034             {
1035                 types |= CultureTypes.ReplacementCultures;
1036             }
1037             return (CultureData.GetCultures(types));
1038         }
1039 #endif
1040
1041         ////////////////////////////////////////////////////////////////////////
1042         //
1043         //  Name
1044         //
1045         //  Returns the full name of the CultureInfo. The name is in format like
1046         //  "en-US"  This version does NOT include sort information in the name.
1047         //
1048         ////////////////////////////////////////////////////////////////////////
1049         public virtual String Name {
1050             get {
1051                 Contract.Ensures(Contract.Result<String>() != null);
1052
1053                 // We return non sorting name here.
1054                 if (this.m_nonSortName == null) {
1055                     this.m_nonSortName = this.m_cultureData.SNAME;
1056                     if (this.m_nonSortName == null) {
1057                         this.m_nonSortName = String.Empty;
1058                     }
1059                 }
1060                 return this.m_nonSortName;
1061             }
1062         }
1063
1064         // This one has the sort information (ie: de-DE_phoneb)
1065         internal String SortName
1066         {
1067             get
1068             {
1069                 if (this.m_sortName == null)
1070                 {
1071                     this.m_sortName = this.m_cultureData.SCOMPAREINFO;
1072                 }
1073
1074                 return this.m_sortName;
1075             }
1076         }
1077
1078         // 
1079 #if !FEATURE_CORECLR
1080         [System.Runtime.InteropServices.ComVisible(false)]
1081         public String IetfLanguageTag
1082         {
1083             get
1084             {
1085                 Contract.Ensures(Contract.Result<String>() != null);
1086
1087                 // special case the compatibility cultures
1088                 switch (this.Name)
1089                 {
1090                     case "zh-CHT":
1091                         return "zh-Hant";
1092                     case "zh-CHS":
1093                         return "zh-Hans";
1094                     default:
1095                         return this.Name;
1096                 }
1097             }
1098         }
1099 #endif
1100
1101         ////////////////////////////////////////////////////////////////////////
1102         //
1103         //  DisplayName
1104         //
1105         //  Returns the full name of the CultureInfo in the localized language.
1106         //  For example, if the localized language of the runtime is Spanish and the CultureInfo is
1107         //  US English, "Ingles (Estados Unidos)" will be returned.
1108         //
1109         ////////////////////////////////////////////////////////////////////////
1110         public virtual String DisplayName
1111         {
1112             [System.Security.SecuritySafeCritical]  // auto-generated
1113             get
1114             {
1115                 Contract.Ensures(Contract.Result<String>() != null);
1116                 Contract.Assert(m_name != null, "[CultureInfo.DisplayName]Always expect m_name to be set");
1117
1118                 return m_cultureData.SLOCALIZEDDISPLAYNAME;
1119             }
1120         }
1121
1122         ////////////////////////////////////////////////////////////////////////
1123         //
1124         //  GetNativeName
1125         //
1126         //  Returns the full name of the CultureInfo in the native language.
1127         //  For example, if the CultureInfo is US English, "English
1128         //  (United States)" will be returned.
1129         //
1130         ////////////////////////////////////////////////////////////////////////
1131         public virtual String NativeName {
1132             [System.Security.SecuritySafeCritical]  // auto-generated
1133             get {
1134                 Contract.Ensures(Contract.Result<String>() != null);
1135                 return (this.m_cultureData.SNATIVEDISPLAYNAME);
1136             }
1137         }
1138
1139         ////////////////////////////////////////////////////////////////////////
1140         //
1141         //  GetEnglishName
1142         //
1143         //  Returns the full name of the CultureInfo in English.
1144         //  For example, if the CultureInfo is US English, "English
1145         //  (United States)" will be returned.
1146         //
1147         ////////////////////////////////////////////////////////////////////////
1148         public virtual String EnglishName {
1149             [System.Security.SecuritySafeCritical]  // auto-generated
1150             get {
1151                 Contract.Ensures(Contract.Result<String>() != null);
1152                 return (this.m_cultureData.SENGDISPLAYNAME);
1153             }
1154         }
1155       
1156         // ie: en
1157         public virtual String TwoLetterISOLanguageName {
1158             [System.Security.SecuritySafeCritical]  // auto-generated
1159             get {
1160                 Contract.Ensures(Contract.Result<String>() != null);
1161                 return (this.m_cultureData.SISO639LANGNAME);
1162             }
1163         }
1164
1165 #if !FEATURE_CORECLR
1166         // ie: eng
1167         public virtual String ThreeLetterISOLanguageName {
1168             [System.Security.SecuritySafeCritical]  // auto-generated
1169             get {
1170                 Contract.Ensures(Contract.Result<String>() != null);
1171                 return (this.m_cultureData.SISO639LANGNAME2);
1172             }
1173         }
1174
1175         ////////////////////////////////////////////////////////////////////////
1176         //
1177         //  ThreeLetterWindowsLanguageName
1178         //
1179         //  Returns the 3 letter windows language name for the current instance.  eg: "ENU"
1180         //  The ISO names are much preferred
1181         //
1182         ////////////////////////////////////////////////////////////////////////
1183         public virtual String ThreeLetterWindowsLanguageName {
1184             [System.Security.SecuritySafeCritical]  // auto-generated
1185             get {
1186                 Contract.Ensures(Contract.Result<String>() != null);
1187                 return (this.m_cultureData.SABBREVLANGNAME);
1188             }
1189         }
1190 #endif
1191
1192         ////////////////////////////////////////////////////////////////////////
1193         //
1194         //  CompareInfo               Read-Only Property
1195         //
1196         //  Gets the CompareInfo for this culture.
1197         //
1198         ////////////////////////////////////////////////////////////////////////
1199         public virtual CompareInfo CompareInfo
1200         {
1201             get
1202             {
1203                 Contract.Ensures(Contract.Result<CompareInfo>() != null);
1204
1205                 if (this.compareInfo == null)
1206                 {
1207                     // Since CompareInfo's don't have any overrideable properties, get the CompareInfo from
1208                     // the Non-Overridden CultureInfo so that we only create one CompareInfo per culture
1209                     CompareInfo temp = UseUserOverride 
1210                                         ? GetCultureInfo(this.m_name).CompareInfo 
1211                                         : new CompareInfo(this);
1212                     if (CompatibilitySwitches.IsCompatibilityBehaviorDefined)
1213                     {
1214                         this.compareInfo = temp;
1215                     }
1216                     else
1217                     {
1218                         return temp;
1219                     }
1220                 }
1221                 return (compareInfo);
1222             }
1223         }
1224
1225 #if !FEATURE_CORECLR
1226         ////////////////////////////////////////////////////////////////////////
1227         //
1228         //  RegionInfo
1229         //
1230         //  Gets the RegionInfo for this culture.
1231         //
1232         ////////////////////////////////////////////////////////////////////////
1233         private RegionInfo Region
1234         {
1235             get
1236             {
1237                 if (regionInfo==null)
1238                 {
1239                     // Make a new regionInfo
1240                     RegionInfo tempRegionInfo = new RegionInfo(this.m_cultureData);
1241                     regionInfo = tempRegionInfo;
1242                 }
1243                 return (regionInfo);
1244             }
1245         }
1246 #endif // FEATURE_CORECLR
1247
1248
1249
1250         ////////////////////////////////////////////////////////////////////////
1251         //
1252         //  TextInfo
1253         //
1254         //  Gets the TextInfo for this culture.
1255         //
1256         ////////////////////////////////////////////////////////////////////////
1257
1258
1259         public virtual TextInfo TextInfo {
1260             get {
1261                 Contract.Ensures(Contract.Result<TextInfo>() != null);
1262
1263                 if (textInfo==null) 
1264                 {
1265                     // Make a new textInfo
1266                     TextInfo tempTextInfo = new TextInfo(this.m_cultureData);
1267                     tempTextInfo.SetReadOnlyState(m_isReadOnly);
1268
1269                     if (CompatibilitySwitches.IsCompatibilityBehaviorDefined)
1270                     {
1271                         textInfo = tempTextInfo;
1272                     }
1273                     else
1274                     {
1275                         return tempTextInfo;
1276                     }
1277                 }
1278                 return (textInfo);
1279             }
1280         }
1281
1282         ////////////////////////////////////////////////////////////////////////
1283         //
1284         //  Equals
1285         //
1286         //  Implements Object.Equals().  Returns a boolean indicating whether
1287         //  or not object refers to the same CultureInfo as the current instance.
1288         //
1289         ////////////////////////////////////////////////////////////////////////
1290
1291
1292         public override bool Equals(Object value)
1293         {
1294             if (Object.ReferenceEquals(this, value))
1295                 return true;
1296
1297             CultureInfo that = value as CultureInfo;
1298
1299             if (that != null)
1300             {
1301                 // using CompareInfo to verify the data passed through the constructor
1302                 // CultureInfo(String cultureName, String textAndCompareCultureName)
1303
1304                 return (this.Name.Equals(that.Name) && this.CompareInfo.Equals(that.CompareInfo));
1305             }
1306
1307             return (false);
1308         }
1309
1310
1311         ////////////////////////////////////////////////////////////////////////
1312         //
1313         //  GetHashCode
1314         //
1315         //  Implements Object.GetHashCode().  Returns the hash code for the
1316         //  CultureInfo.  The hash code is guaranteed to be the same for CultureInfo A
1317         //  and B where A.Equals(B) is true.
1318         //
1319         ////////////////////////////////////////////////////////////////////////
1320
1321         public override int GetHashCode()
1322         {
1323             return (this.Name.GetHashCode() + this.CompareInfo.GetHashCode());
1324         }
1325
1326
1327         ////////////////////////////////////////////////////////////////////////
1328         //
1329         //  ToString
1330         //
1331         //  Implements Object.ToString().  Returns the name of the CultureInfo,
1332         //  eg. "de-DE_phoneb", "en-US", or "fj-FJ".
1333         //
1334         ////////////////////////////////////////////////////////////////////////
1335
1336
1337         public override String ToString()
1338         {
1339             Contract.Ensures(Contract.Result<String>() != null);
1340
1341             Contract.Assert(m_name != null, "[CultureInfo.ToString]Always expect m_name to be set");
1342             return m_name;
1343         }
1344
1345
1346         public virtual Object GetFormat(Type formatType) {
1347             if (formatType == typeof(NumberFormatInfo)) {
1348                 return (NumberFormat);
1349             }
1350             if (formatType == typeof(DateTimeFormatInfo)) {
1351                 return (DateTimeFormat);
1352             }
1353             return (null);
1354         }
1355
1356         public virtual bool IsNeutralCulture {
1357             get {
1358                 return this.m_cultureData.IsNeutralCulture;
1359             }
1360         }
1361
1362 #if !FEATURE_CORECLR
1363         [System.Runtime.InteropServices.ComVisible(false)]
1364         public CultureTypes CultureTypes
1365         {
1366             get
1367             {
1368                 CultureTypes types = 0;
1369
1370                 if (m_cultureData.IsNeutralCulture)
1371                     types |= CultureTypes.NeutralCultures;
1372                 else 
1373                     types |= CultureTypes.SpecificCultures;
1374
1375                 types |= m_cultureData.IsWin32Installed ? CultureTypes.InstalledWin32Cultures : 0;
1376
1377 // Disable  warning 618: System.Globalization.CultureTypes.FrameworkCultures' is obsolete
1378 #pragma warning disable 618
1379                 types |= m_cultureData.IsFramework ? CultureTypes.FrameworkCultures : 0;
1380
1381 #pragma warning restore 618
1382                 types |= m_cultureData.IsSupplementalCustomCulture ? CultureTypes.UserCustomCulture : 0;
1383                 types |= m_cultureData.IsReplacementCulture ? CultureTypes.ReplacementCultures | CultureTypes.UserCustomCulture : 0;
1384
1385                 return types;
1386             }
1387         }
1388 #endif
1389
1390         public virtual NumberFormatInfo NumberFormat {
1391             get 
1392             {
1393                 Contract.Ensures(Contract.Result<NumberFormatInfo>() != null);
1394
1395                 if (numInfo == null) {
1396                     NumberFormatInfo temp = new NumberFormatInfo(this.m_cultureData);
1397                     temp.isReadOnly = m_isReadOnly;
1398                     numInfo = temp;
1399                 }
1400                 return (numInfo);
1401             }
1402             set {
1403                 if (value == null) {
1404                     throw new ArgumentNullException("value",
1405                         Environment.GetResourceString("ArgumentNull_Obj"));
1406                 }
1407                 Contract.EndContractBlock();
1408                 VerifyWritable();
1409                 numInfo = value;
1410             }
1411         }
1412
1413         ////////////////////////////////////////////////////////////////////////
1414         //
1415         // GetDateTimeFormatInfo
1416         //
1417         // Create a DateTimeFormatInfo, and fill in the properties according to
1418         // the CultureID.
1419         //
1420         ////////////////////////////////////////////////////////////////////////
1421
1422
1423         public virtual DateTimeFormatInfo DateTimeFormat {
1424             get {
1425                 Contract.Ensures(Contract.Result<DateTimeFormatInfo>() != null);
1426
1427                 if (dateTimeInfo == null) {
1428                     // Change the calendar of DTFI to the specified calendar of this CultureInfo.
1429                     DateTimeFormatInfo temp = new DateTimeFormatInfo(
1430                         this.m_cultureData, this.Calendar);
1431                     temp.m_isReadOnly = m_isReadOnly;
1432                     System.Threading.Thread.MemoryBarrier();
1433                     dateTimeInfo = temp;
1434                 }
1435                 return (dateTimeInfo);
1436             }
1437
1438             set {
1439                 if (value == null) {
1440                     throw new ArgumentNullException("value",
1441                         Environment.GetResourceString("ArgumentNull_Obj"));
1442                 }
1443                 Contract.EndContractBlock();
1444                 VerifyWritable();
1445                 dateTimeInfo = value;
1446             }
1447         }
1448
1449
1450
1451         public void ClearCachedData() {
1452             s_userDefaultUICulture = null;
1453             s_userDefaultCulture = null;
1454
1455             RegionInfo.s_currentRegionInfo = null;
1456 #if !FEATURE_CORECLR && !FEATURE_PAL // System.TimeZone does not exist in CoreCLR
1457             TimeZone.ResetTimeZone();
1458 #endif // FEATURE_CORECLR
1459             TimeZoneInfo.ClearCachedData();
1460             // Delete the cached cultures.
1461             s_LcidCachedCultures = null;
1462             s_NameCachedCultures = null;
1463
1464             CultureData.ClearCachedData();
1465         }
1466
1467         /*=================================GetCalendarInstance==========================
1468         **Action: Map a Win32 CALID to an instance of supported calendar.
1469         **Returns: An instance of calendar.
1470         **Arguments: calType    The Win32 CALID
1471         **Exceptions:
1472         **      Shouldn't throw exception since the calType value is from our data table or from Win32 registry.
1473         **      If we are in trouble (like getting a weird value from Win32 registry), just return the GregorianCalendar.
1474         ============================================================================*/
1475         internal static Calendar GetCalendarInstance(int calType) {
1476             if (calType==Calendar.CAL_GREGORIAN) {
1477                 return (new GregorianCalendar());
1478             }
1479             return GetCalendarInstanceRare(calType);
1480         }
1481
1482         //This function exists as a shortcut to prevent us from loading all of the non-gregorian
1483         //calendars unless they're required.
1484         internal static Calendar GetCalendarInstanceRare(int calType) {
1485             Contract.Assert(calType!=Calendar.CAL_GREGORIAN, "calType!=Calendar.CAL_GREGORIAN");
1486
1487             switch (calType) {
1488                 case Calendar.CAL_GREGORIAN_US:               // Gregorian (U.S.) calendar
1489                 case Calendar.CAL_GREGORIAN_ME_FRENCH:        // Gregorian Middle East French calendar
1490                 case Calendar.CAL_GREGORIAN_ARABIC:           // Gregorian Arabic calendar
1491                 case Calendar.CAL_GREGORIAN_XLIT_ENGLISH:     // Gregorian Transliterated English calendar
1492                 case Calendar.CAL_GREGORIAN_XLIT_FRENCH:      // Gregorian Transliterated French calendar
1493                     return (new GregorianCalendar((GregorianCalendarTypes)calType));
1494                 case Calendar.CAL_TAIWAN:                     // Taiwan Era calendar
1495                     return (new TaiwanCalendar());
1496                 case Calendar.CAL_JAPAN:                      // Japanese Emperor Era calendar
1497                     return (new JapaneseCalendar());
1498                 case Calendar.CAL_KOREA:                      // Korean Tangun Era calendar
1499                     return (new KoreanCalendar());
1500                 case Calendar.CAL_THAI:                       // Thai calendar
1501                     return (new ThaiBuddhistCalendar());
1502                 case Calendar.CAL_HIJRI:                      // Hijri (Arabic Lunar) calendar
1503                     return (new HijriCalendar());
1504                 case Calendar.CAL_HEBREW:                     // Hebrew (Lunar) calendar
1505                     return (new HebrewCalendar());
1506                 case Calendar.CAL_UMALQURA:
1507                     return (new UmAlQuraCalendar());
1508                 case Calendar.CAL_PERSIAN:
1509                     return (new PersianCalendar());
1510                 case Calendar.CAL_CHINESELUNISOLAR:
1511                     return (new ChineseLunisolarCalendar());
1512                 case Calendar.CAL_JAPANESELUNISOLAR:
1513                     return (new JapaneseLunisolarCalendar());
1514                 case Calendar.CAL_KOREANLUNISOLAR:
1515                     return (new KoreanLunisolarCalendar());
1516                 case Calendar.CAL_TAIWANLUNISOLAR:
1517                     return (new TaiwanLunisolarCalendar());
1518             }
1519             return (new GregorianCalendar());
1520         }
1521
1522
1523         /*=================================Calendar==========================
1524         **Action: Return/set the default calendar used by this culture.
1525         ** This value can be overridden by regional option if this is a current culture.
1526         **Returns:
1527         **Arguments:
1528         **Exceptions:
1529         **  ArgumentNull_Obj if the set value is null.
1530         ============================================================================*/
1531
1532
1533         public virtual Calendar Calendar {
1534             get {
1535                 Contract.Ensures(Contract.Result<Calendar>() != null);
1536                 if (calendar == null) {
1537                     Contract.Assert(this.m_cultureData.CalendarIds.Length > 0, "this.m_cultureData.CalendarIds.Length > 0");
1538                     // Get the default calendar for this culture.  Note that the value can be
1539                     // from registry if this is a user default culture.
1540                     Calendar newObj = this.m_cultureData.DefaultCalendar;
1541
1542                     System.Threading.Thread.MemoryBarrier();
1543                     newObj.SetReadOnlyState(m_isReadOnly);
1544                     calendar = newObj;
1545                 }
1546                 return (calendar);
1547             }
1548         }
1549
1550         /*=================================OptionCalendars==========================
1551         **Action: Return an array of the optional calendar for this culture.
1552         **Returns: an array of Calendar.
1553         **Arguments:
1554         **Exceptions:
1555         ============================================================================*/
1556
1557
1558         public virtual Calendar[] OptionalCalendars {
1559             get {
1560                 Contract.Ensures(Contract.Result<Calendar[]>() != null);
1561
1562                 //
1563                 // This property always returns a new copy of the calendar array.
1564                 //
1565                 int[] calID = this.m_cultureData.CalendarIds;
1566                 Calendar [] cals = new Calendar[calID.Length];
1567                 for (int i = 0; i < cals.Length; i++) {
1568                     cals[i] = GetCalendarInstance(calID[i]);
1569                 }
1570                 return (cals);
1571             }
1572         }
1573
1574
1575         public bool UseUserOverride {
1576             get {
1577                 return (this.m_cultureData.UseUserOverride);
1578             }
1579         }
1580
1581 #if !FEATURE_CORECLR
1582         [System.Security.SecuritySafeCritical]  // auto-generated
1583         [System.Runtime.InteropServices.ComVisible(false)]
1584         public CultureInfo GetConsoleFallbackUICulture()
1585         {
1586             Contract.Ensures(Contract.Result<CultureInfo>() != null);
1587
1588             CultureInfo temp = m_consoleFallbackCulture;
1589             if (temp == null)
1590             {
1591                 temp = CreateSpecificCulture(this.m_cultureData.SCONSOLEFALLBACKNAME);
1592                 temp.m_isReadOnly = true;
1593                 m_consoleFallbackCulture = temp;
1594             }
1595             return (temp);
1596         }
1597 #endif
1598
1599         public virtual Object Clone()
1600         {
1601             Contract.Ensures(Contract.Result<Object>() != null);
1602
1603             CultureInfo ci = (CultureInfo)MemberwiseClone();
1604             ci.m_isReadOnly = false;
1605
1606             //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
1607             //they've already been allocated.  If this is a derived type, we'll take a more generic codepath.
1608             if (!m_isInherited) 
1609             {
1610                 if (this.dateTimeInfo != null)
1611                 {
1612                     ci.dateTimeInfo = (DateTimeFormatInfo)this.dateTimeInfo.Clone();
1613                 }
1614                 if (this.numInfo != null)
1615                 {
1616                     ci.numInfo = (NumberFormatInfo)this.numInfo.Clone();
1617                 }
1618
1619             }
1620             else
1621             {
1622                 ci.DateTimeFormat = (DateTimeFormatInfo)this.DateTimeFormat.Clone();
1623                 ci.NumberFormat   = (NumberFormatInfo)this.NumberFormat.Clone();
1624             }
1625
1626             if (textInfo != null)
1627             {
1628                 ci.textInfo = (TextInfo) textInfo.Clone();
1629             }
1630
1631             if (calendar != null)
1632             {
1633                 ci.calendar = (Calendar) calendar.Clone();
1634             }
1635
1636             return (ci);
1637         }
1638
1639
1640         public static CultureInfo ReadOnly(CultureInfo ci) {
1641             if (ci == null) {
1642                 throw new ArgumentNullException("ci");
1643             }
1644             Contract.Ensures(Contract.Result<CultureInfo>() != null);
1645             Contract.EndContractBlock();
1646
1647             if (ci.IsReadOnly) {
1648                 return (ci);
1649             }
1650             CultureInfo newInfo = (CultureInfo)(ci.MemberwiseClone());
1651
1652             if (!ci.IsNeutralCulture)
1653             {
1654                 //If this is exactly our type, we can make certain optimizations so that we don't allocate NumberFormatInfo or DTFI unless
1655                 //they've already been allocated.  If this is a derived type, we'll take a more generic codepath.
1656                 if (!ci.m_isInherited) {
1657                     if (ci.dateTimeInfo != null) {
1658                         newInfo.dateTimeInfo = DateTimeFormatInfo.ReadOnly(ci.dateTimeInfo);
1659                     }
1660                     if (ci.numInfo != null) {
1661                         newInfo.numInfo = NumberFormatInfo.ReadOnly(ci.numInfo);
1662                     }
1663
1664                 } else {
1665                     newInfo.DateTimeFormat = DateTimeFormatInfo.ReadOnly(ci.DateTimeFormat);
1666                     newInfo.NumberFormat = NumberFormatInfo.ReadOnly(ci.NumberFormat);
1667                 }
1668             }
1669             
1670             if (ci.textInfo != null)
1671             {
1672                 newInfo.textInfo = TextInfo.ReadOnly(ci.textInfo);
1673             }
1674
1675             if (ci.calendar != null)
1676             {
1677                 newInfo.calendar = Calendar.ReadOnly(ci.calendar);
1678             }
1679
1680             // Don't set the read-only flag too early.
1681             // We should set the read-only flag here.  Otherwise, info.DateTimeFormat will not be able to set.
1682             newInfo.m_isReadOnly = true;
1683
1684             return (newInfo);
1685         }
1686
1687
1688         public bool IsReadOnly {
1689             get {
1690                 return (m_isReadOnly);
1691             }
1692         }
1693
1694         private void VerifyWritable() {
1695             if (m_isReadOnly) {
1696                 throw new InvalidOperationException(Environment.GetResourceString("InvalidOperation_ReadOnly"));
1697             }
1698             Contract.EndContractBlock();
1699         }
1700
1701         // For resource lookup, we consider a culture the invariant culture by name equality. 
1702         // We perform this check frequently during resource lookup, so adding a property for
1703         // improved readability.
1704         internal bool HasInvariantCultureName
1705         {
1706             get { return Name == CultureInfo.InvariantCulture.Name; }
1707         }
1708
1709         // Helper function both both overloads of GetCachedReadOnlyCulture.  If lcid is 0, we use the name.
1710         // If lcid is -1, use the altName and create one of those special SQL cultures.
1711         internal static CultureInfo GetCultureInfoHelper(int lcid, string name, string altName)
1712         {
1713             // There is a race condition in this code with the side effect that the second thread's value
1714             // clobbers the first in the dictionary. This is an acceptable ---- since the CultureInfo objects
1715             // are content equal (but not reference equal). Since we make no guarantees there, this ---- is
1716             // acceptable.
1717             // See code:Dictionary#DictionaryVersusHashtableThreadSafety for details on Dictionary versus 
1718             // Hashtable thread safety.
1719
1720             // retval is our return value.
1721             CultureInfo retval;
1722
1723             // Temporary hashtable for the names.
1724             Hashtable tempNameHT = s_NameCachedCultures;
1725
1726             if (name != null)
1727             {
1728                 name = CultureData.AnsiToLower(name);
1729             }
1730             
1731             if (altName != null)
1732             {
1733                 altName = CultureData.AnsiToLower(altName);
1734             }
1735
1736             // We expect the same result for both hashtables, but will test individually for added safety.
1737             if (tempNameHT == null)
1738             {
1739                 tempNameHT = Hashtable.Synchronized(new Hashtable());
1740             }
1741             else
1742             {
1743                 // If we are called by name, check if the object exists in the hashtable.  If so, return it.
1744                 if (lcid == -1)
1745                 {
1746                     retval = (CultureInfo)tempNameHT[name + '\xfffd' + altName];
1747                     if (retval != null)
1748                     {
1749                         return retval;
1750                     }
1751                 }
1752                 else if (lcid == 0)
1753                 {
1754                     retval = (CultureInfo)tempNameHT[name];
1755                     if (retval != null)
1756                     {
1757                         return retval;
1758                     }
1759                 }
1760             }
1761 #if FEATURE_USE_LCID
1762             // Next, the Lcid table.
1763             Hashtable tempLcidHT = s_LcidCachedCultures;
1764
1765             if (tempLcidHT == null)
1766             {
1767                 // Case insensitive is not an issue here, save the constructor call.
1768                 tempLcidHT = Hashtable.Synchronized(new Hashtable());
1769             }
1770             else
1771             {
1772                 // If we were called by Lcid, check if the object exists in the table.  If so, return it.
1773                 if (lcid > 0)
1774                 {
1775                     retval = (CultureInfo) tempLcidHT[lcid];
1776                     if (retval != null)
1777                     {
1778                         return retval;
1779                     }
1780                 }
1781             }
1782 #endif
1783             // We now have two temporary hashtables and the desired object was not found.
1784             // We'll construct it.  We catch any exceptions from the constructor call and return null.
1785             try
1786             {
1787                 switch(lcid)
1788                 {
1789                     case -1:
1790                         // call the private constructor
1791                         retval = new CultureInfo(name, altName);
1792                         break;
1793
1794                     case 0:
1795                         retval = new CultureInfo(name, false);
1796                         break;
1797
1798                     default:
1799 #if FEATURE_USE_LCID
1800                         retval = new CultureInfo(lcid, false);
1801                         break;
1802 #else
1803                         return null;
1804 #endif
1805                 }
1806             }
1807             catch(ArgumentException)
1808             {
1809                 return null;
1810             }
1811
1812             // Set it to read-only
1813             retval.m_isReadOnly = true;
1814
1815             if (lcid == -1)
1816             {
1817                 // This new culture will be added only to the name hash table.
1818                 tempNameHT[name + '\xfffd' + altName] = retval;
1819
1820                 // when lcid == -1 then TextInfo object is already get created and we need to set it as read only.
1821                 retval.TextInfo.SetReadOnlyState(true);
1822             }
1823             else
1824             {
1825                 // Remember our name (as constructed).  Do NOT use alternate sort name versions because
1826                 // we have internal state representing the sort.  (So someone would get the wrong cached version)
1827                 string newName = CultureData.AnsiToLower(retval.m_name);
1828                 
1829                 // We add this new culture info object to both tables.
1830                 tempNameHT[newName] = retval;
1831 #if FEATURE_USE_LCID
1832                 const int LCID_ZH_CHS_HANS = 0x0004;
1833                 const int LCID_ZH_CHT_HANT = 0x7c04;
1834
1835                 if ((retval.LCID == LCID_ZH_CHS_HANS && newName == "zh-hans")
1836                  || (retval.LCID == LCID_ZH_CHT_HANT && newName == "zh-hant"))
1837                 {
1838                     // do nothing because we only want zh-CHS and zh-CHT to cache
1839                     // by lcid
1840                 }
1841                 else
1842                 {
1843                     tempLcidHT[retval.LCID] = retval;
1844                 }
1845
1846 #endif
1847             }
1848
1849 #if FEATURE_USE_LCID
1850             // Copy the two hashtables to the corresponding member variables.  This will potentially overwrite
1851             // new tables simultaneously created by a new thread, but maximizes thread safety.
1852             if(-1 != lcid)
1853             {
1854                 // Only when we modify the lcid hash table, is there a need to overwrite.
1855                 s_LcidCachedCultures = tempLcidHT;
1856             }
1857 #endif
1858
1859             s_NameCachedCultures = tempNameHT;
1860
1861             // Finally, return our new CultureInfo object.
1862             return retval;
1863         }
1864
1865 #if FEATURE_USE_LCID
1866         // Gets a cached copy of the specified culture from an internal hashtable (or creates it
1867         // if not found).  (LCID version)... use named version
1868         public static CultureInfo GetCultureInfo(int culture)
1869         {
1870             // Must check for -1 now since the helper function uses the value to signal
1871             // the altCulture code path for SQL Server.
1872             // Also check for zero as this would fail trying to add as a key to the hash.
1873             if (culture <= 0) {
1874                 throw new ArgumentOutOfRangeException("culture",
1875                     Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
1876             }
1877             Contract.Ensures(Contract.Result<CultureInfo>() != null);
1878             Contract.EndContractBlock();
1879             CultureInfo retval = GetCultureInfoHelper(culture, null, null);
1880             if (null == retval)
1881             {
1882                 throw new CultureNotFoundException(
1883                     "culture", culture, Environment.GetResourceString("Argument_CultureNotSupported"));
1884             }
1885             return retval;
1886         }
1887 #endif
1888
1889         // Gets a cached copy of the specified culture from an internal hashtable (or creates it
1890         // if not found).  (Named version)
1891         public static CultureInfo GetCultureInfo(string name)
1892         {
1893             // Make sure we have a valid, non-zero length string as name
1894             if (name == null)
1895             {
1896                 throw new ArgumentNullException("name");
1897             }
1898             Contract.Ensures(Contract.Result<CultureInfo>() != null);
1899             Contract.EndContractBlock();
1900
1901             CultureInfo retval = GetCultureInfoHelper(0, name, null);
1902             if (retval == null)
1903             {
1904                 throw new CultureNotFoundException(
1905                     "name", name, Environment.GetResourceString("Argument_CultureNotSupported"));
1906                 
1907             }
1908             return retval;
1909         }
1910
1911         // Gets a cached copy of the specified culture from an internal hashtable (or creates it
1912         // if not found).
1913         public static CultureInfo GetCultureInfo(string name, string altName)
1914         {
1915             // Make sure we have a valid, non-zero length string as name
1916             if (null == name)
1917             {
1918                 throw new ArgumentNullException("name");
1919             }
1920
1921             if (null == altName)
1922             {
1923                 throw new ArgumentNullException("altName");
1924             }
1925             Contract.Ensures(Contract.Result<CultureInfo>() != null);
1926             Contract.EndContractBlock();
1927
1928             CultureInfo retval = GetCultureInfoHelper(-1, name, altName);
1929             if (retval == null)
1930             {
1931                 throw new CultureNotFoundException("name or altName",
1932                                         String.Format(
1933                                             CultureInfo.CurrentCulture, 
1934                                             Environment.GetResourceString("Argument_OneOfCulturesNotSupported"), 
1935                                             name,
1936                                             altName));
1937             }
1938             return retval;
1939         }
1940
1941
1942 #if !FEATURE_CORECLR
1943         // This function is deprecated, we don't like it
1944         public static CultureInfo GetCultureInfoByIetfLanguageTag(string name)
1945         {
1946             Contract.Ensures(Contract.Result<CultureInfo>() != null);
1947
1948             // Disallow old zh-CHT/zh-CHS names
1949             if (name == "zh-CHT" || name == "zh-CHS")
1950             {
1951                 throw new CultureNotFoundException(
1952                             "name",
1953                             String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_CultureIetfNotSupported"), name)
1954                             );
1955             }
1956             
1957             CultureInfo ci = GetCultureInfo(name);
1958
1959             // Disallow alt sorts and es-es_TS
1960             if (ci.LCID > 0xffff || ci.LCID == 0x040a)
1961             {
1962                 throw new CultureNotFoundException(
1963                             "name",
1964                             String.Format(CultureInfo.CurrentCulture, Environment.GetResourceString("Argument_CultureIetfNotSupported"), name)
1965                             );
1966             }
1967             
1968             return ci;
1969         }
1970 #endif
1971         private static volatile bool s_isTaiwanSku;
1972         private static volatile bool s_haveIsTaiwanSku;
1973         internal static bool IsTaiwanSku
1974         {
1975             get
1976             {
1977                 if (!s_haveIsTaiwanSku)
1978                 {
1979                     s_isTaiwanSku = (GetSystemDefaultUILanguage() == "zh-TW");
1980                     s_haveIsTaiwanSku = true;
1981                 }
1982                 return (bool)s_isTaiwanSku;
1983             }
1984         }
1985
1986         //
1987         //  Helper Methods.
1988         //
1989         
1990         // Get Locale Info Ex calls.  So we don't have to muck with the different int/string return types we declared two of these:
1991         [System.Security.SecurityCritical]  // auto-generated
1992         [ResourceExposure(ResourceScope.None)]
1993         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1994         internal static extern String nativeGetLocaleInfoEx(String localeName, uint field);
1995         
1996         [System.Security.SecuritySafeCritical]  // auto-generated
1997         [ResourceExposure(ResourceScope.None)]
1998         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1999         internal static extern int nativeGetLocaleInfoExInt(String localeName, uint field);
2000
2001         [System.Security.SecurityCritical]  // auto-generated
2002         [ResourceExposure(ResourceScope.None)]
2003         [MethodImplAttribute(MethodImplOptions.InternalCall)]
2004         internal static extern bool nativeSetThreadLocale(String localeName);
2005
2006         [System.Security.SecurityCritical]
2007         private static String GetDefaultLocaleName(int localeType)
2008         {
2009             Contract.Assert(localeType == LOCALE_USER_DEFAULT || localeType == LOCALE_SYSTEM_DEFAULT, "[CultureInfo.GetDefaultLocaleName] localeType must be LOCALE_USER_DEFAULT or LOCALE_SYSTEM_DEFAULT");
2010
2011             string localeName = null;
2012             if(InternalGetDefaultLocaleName(localeType, JitHelpers.GetStringHandleOnStack(ref localeName)))
2013             {
2014                 return localeName;
2015             }
2016             return string.Empty;
2017         }
2018
2019         // Get the default locale name
2020         [System.Security.SecurityCritical]  // auto-generated
2021         [ResourceExposure(ResourceScope.None)]
2022         [SuppressUnmanagedCodeSecurity]
2023         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
2024         [return: MarshalAs(UnmanagedType.Bool)]
2025         private static extern bool InternalGetDefaultLocaleName(int localetype, StringHandleOnStack localeString);
2026
2027         [System.Security.SecuritySafeCritical] // auto-generated
2028         private static String GetUserDefaultUILanguage()
2029         {
2030             string userDefaultUiLanguage = null;
2031             if(InternalGetUserDefaultUILanguage(JitHelpers.GetStringHandleOnStack(ref userDefaultUiLanguage)))
2032             {
2033                 return userDefaultUiLanguage;
2034             }
2035             return String.Empty;
2036         }
2037         
2038         // Get the user's default UI language, return locale name
2039         [System.Security.SecurityCritical]  // auto-generated
2040         [ResourceExposure(ResourceScope.None)]
2041         [SuppressUnmanagedCodeSecurity]
2042         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
2043         [return: MarshalAs(UnmanagedType.Bool)]
2044         private static extern bool InternalGetUserDefaultUILanguage(StringHandleOnStack userDefaultUiLanguage);
2045
2046         [System.Security.SecuritySafeCritical] // auto-generated
2047         private static String GetSystemDefaultUILanguage()
2048         {
2049             string systemDefaultUiLanguage = null;
2050             if(InternalGetSystemDefaultUILanguage(JitHelpers.GetStringHandleOnStack(ref systemDefaultUiLanguage)))
2051             {
2052                 return systemDefaultUiLanguage;
2053             }
2054             return String.Empty;
2055
2056         }
2057
2058         [System.Security.SecurityCritical] // auto-generated
2059         [ResourceExposure(ResourceScope.None)]
2060         [MethodImplAttribute(MethodImplOptions.InternalCall)]
2061         [SuppressUnmanagedCodeSecurity]
2062         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
2063         [return: MarshalAs(UnmanagedType.Bool)]
2064         private static extern bool InternalGetSystemDefaultUILanguage(StringHandleOnStack systemDefaultUiLanguage);
2065
2066 // Added but disabled from desktop in .NET 4.0, stayed disabled in .NET 4.5
2067 #if FEATURE_CORECLR
2068         [System.Security.SecurityCritical]  // auto-generated
2069         [ResourceExposure(ResourceScope.None)]
2070         [MethodImplAttribute(MethodImplOptions.InternalCall)]
2071         internal static extern String[] nativeGetResourceFallbackArray();
2072 #endif
2073     }
2074 }
2075