2 // System.Globalization.CultureInfo.cs
4 // Miguel de Icaza (miguel@ximian.com)
5 // Dick Porter (dick@ximian.com)
7 // (C) 2001, 2002, 2003 Ximian, Inc. (http://www.ximian.com)
11 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
34 using System.Threading;
35 using System.Runtime.CompilerServices;
37 namespace System.Globalization
40 public class CultureInfo : ICloneable, IFormatProvider
42 static volatile CultureInfo invariant_culture_info;
44 const int NumOptionalCalendars = 5;
45 const int GregorianTypeMask = 0x00FFFFFF;
46 const int CalendarTypeBits = 24;
58 bool m_useUserOverride;
59 volatile NumberFormatInfo numInfo;
60 volatile DateTimeFormatInfo dateTimeInfo;
61 volatile TextInfo textInfo;
62 private string m_name;
65 private string displayname;
67 private string englishname;
69 private string nativename;
71 private string iso3lang;
73 private string iso2lang;
75 private string icu_name;
77 private string win3lang;
78 volatile CompareInfo compareInfo;
80 private unsafe readonly int *calendar_data;
82 private unsafe readonly void *textinfo_data;
84 private Calendar [] optional_calendars;
86 int m_dataItem; // MS.NET serializes this.
87 Calendar calendar; // MS.NET serializes this.
89 // Deserialized instances will set this to false
93 private static readonly string MSG_READONLY = "This instance is read only";
95 static public CultureInfo InvariantCulture {
97 return invariant_culture_info;
101 static CultureInfo ()
103 invariant_culture_info = new CultureInfo (0x7f, false);
104 invariant_culture_info.m_isReadOnly = true;
107 public static CultureInfo CreateSpecificCulture (string name)
110 throw new ArgumentNullException ("name");
113 if (name == String.Empty)
114 return InvariantCulture;
116 CultureInfo ci = new CultureInfo ();
117 if (!ConstructInternalLocaleFromSpecificName (ci, name.ToLowerInvariant ()))
118 throw new ArgumentException ("Culture name " + name +
119 " is not supported.", name);
124 public static CultureInfo CurrentCulture
127 return Thread.CurrentThread.CurrentCulture;
131 public static CultureInfo CurrentUICulture
134 return Thread.CurrentThread.CurrentUICulture;
138 internal static CultureInfo ConstructCurrentCulture ()
140 CultureInfo ci = new CultureInfo ();
141 if (!ConstructInternalLocaleFromCurrentLocale (ci))
142 ci = InvariantCulture;
146 internal static CultureInfo ConstructCurrentUICulture ()
148 return ConstructCurrentCulture ();
151 public virtual int LCID {
157 public virtual string Name {
163 public virtual string NativeName
166 if (!constructed) Construct ();
171 public virtual Calendar Calendar
173 get { return DateTimeFormat.Calendar; }
176 public virtual Calendar[] OptionalCalendars
179 return optional_calendars;
183 public virtual CultureInfo Parent
186 if (cultureID == 0x7f)
188 if (!constructed) Construct ();
189 if (parent_lcid == cultureID)
191 return new CultureInfo (parent_lcid);
195 public unsafe virtual TextInfo TextInfo
198 if (textInfo == null) {
200 if(textInfo == null) {
201 textInfo = new TextInfo (this, cultureID, textinfo_data);
210 public virtual string ThreeLetterISOLanguageName
213 if (!constructed) Construct ();
218 public virtual string ThreeLetterWindowsLanguageName
221 if (!constructed) Construct ();
226 public virtual string TwoLetterISOLanguageName
229 if (!constructed) Construct ();
234 public bool UseUserOverride
237 return m_useUserOverride;
241 internal string IcuName {
243 if (!constructed) Construct ();
248 public void ClearCachedData()
250 Thread.CurrentThread.CurrentCulture = null;
251 Thread.CurrentThread.CurrentUICulture = null;
254 public virtual object Clone()
256 if (!constructed) Construct ();
257 CultureInfo ci=(CultureInfo)MemberwiseClone ();
258 ci.m_isReadOnly=false;
259 ci.NumberFormat = (NumberFormatInfo)NumberFormat.Clone ();
260 ci.DateTimeFormat = (DateTimeFormatInfo)DateTimeFormat.Clone ();
264 public override bool Equals (object value)
266 CultureInfo b = value as CultureInfo;
269 return b.cultureID == cultureID;
273 public static CultureInfo[] GetCultures(CultureTypes types)
275 bool neutral=((types & CultureTypes.NeutralCultures)!=0);
276 bool specific=((types & CultureTypes.SpecificCultures)!=0);
277 bool installed=((types & CultureTypes.InstalledWin32Cultures)!=0); // TODO
279 CultureInfo [] infos = internal_get_cultures (neutral, specific, installed);
280 // The runtime returns a NULL in the first position of the array when
281 // 'neutral' is true. We fill it in with the InvariantCulture.
282 if (neutral && infos.Length > 0 && infos [0] == null)
283 infos [0] = InvariantCulture;
288 public override int GetHashCode()
293 public static CultureInfo ReadOnly(CultureInfo ci)
296 throw new ArgumentNullException("ci");
299 if(ci.m_isReadOnly) {
302 CultureInfo new_ci=(CultureInfo)ci.Clone ();
303 new_ci.m_isReadOnly=true;
308 public override string ToString()
313 public virtual CompareInfo CompareInfo
316 if (!constructed) Construct ();
317 if(compareInfo==null) {
319 if(compareInfo==null) {
320 compareInfo=new CompareInfo (this);
329 internal static bool IsIDNeutralCulture (int lcid)
332 if (!internal_is_lcid_neutral (lcid, out ret))
333 throw new ArgumentException (String.Format ("Culture id 0x{:x4} is not supported.", lcid));
338 public virtual bool IsNeutralCulture {
340 if (!constructed) Construct ();
341 if (cultureID == 0x7f)
344 return ((cultureID & 0xff00) == 0 || specific_lcid == 0);
348 internal void CheckNeutral ()
350 if (IsNeutralCulture) {
351 throw new NotSupportedException ("Culture \"" + m_name + "\" is " +
352 "a neutral culture. It can not be used in formatting " +
353 "and parsing and therefore cannot be set as the thread's " +
358 public virtual NumberFormatInfo NumberFormat {
360 if (!constructed) Construct ();
362 if (numInfo == null){
364 if (numInfo == null) {
365 numInfo = new NumberFormatInfo ();
366 construct_number_format ();
375 if (!constructed) Construct ();
376 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
379 throw new ArgumentNullException ("NumberFormat");
385 public virtual DateTimeFormatInfo DateTimeFormat
389 if (!constructed) Construct ();
391 if (dateTimeInfo == null)
395 if (dateTimeInfo == null) {
396 dateTimeInfo = new DateTimeFormatInfo();
397 construct_datetime_format ();
398 if (optional_calendars != null)
399 dateTimeInfo.Calendar = optional_calendars [0];
409 if (!constructed) Construct ();
410 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
413 throw new ArgumentNullException ("DateTimeFormat");
415 dateTimeInfo = value;
419 public virtual string DisplayName
422 if (!constructed) Construct ();
427 public virtual string EnglishName
430 if (!constructed) Construct ();
436 public static CultureInfo InstalledUICulture
443 public bool IsReadOnly
446 return(m_isReadOnly);
452 // IFormatProvider implementation
454 public virtual object GetFormat( Type formatType )
456 object format = null;
458 if ( formatType == typeof(NumberFormatInfo) )
459 format = NumberFormat;
460 else if ( formatType == typeof(DateTimeFormatInfo) )
461 format = DateTimeFormat;
468 construct_internal_locale_from_lcid (cultureID);
472 bool ConstructInternalLocaleFromName (string locale)
474 if (!construct_internal_locale_from_name (locale))
476 ConstructCalendars ();
480 bool ConstructInternalLocaleFromLcid (int lcid)
482 if (!construct_internal_locale_from_lcid (lcid))
484 ConstructCalendars ();
488 static bool ConstructInternalLocaleFromSpecificName (CultureInfo ci, string name)
490 if (!construct_internal_locale_from_specific_name (ci, name))
492 ci.ConstructCalendars ();
496 static bool ConstructInternalLocaleFromCurrentLocale (CultureInfo ci)
498 if (!construct_internal_locale_from_current_locale (ci))
500 ci.ConstructCalendars ();
504 static CultureInfo [] GetCultures (bool neutral, bool specific, bool installed)
506 CultureInfo [] cis = internal_get_cultures (neutral, specific, installed);
508 // The runtime returns a NULL in the first position of the array when
509 // 'neutral' is true. We fill it in with the InvariantCulture.
510 if (neutral && cis.Length > 0 && cis [0] == null)
511 cis [0] = InvariantCulture;
513 foreach (CultureInfo ci in cis)
514 ci.ConstructCalendars ();
519 [MethodImplAttribute (MethodImplOptions.InternalCall)]
520 private extern bool construct_internal_locale_from_lcid (int lcid);
522 [MethodImplAttribute (MethodImplOptions.InternalCall)]
523 private extern bool construct_internal_locale_from_name (string name);
525 [MethodImplAttribute (MethodImplOptions.InternalCall)]
526 private extern static bool construct_internal_locale_from_specific_name (CultureInfo ci,
529 [MethodImplAttribute (MethodImplOptions.InternalCall)]
530 private extern static bool construct_internal_locale_from_current_locale (CultureInfo ci);
532 [MethodImplAttribute (MethodImplOptions.InternalCall)]
533 private extern static CultureInfo [] internal_get_cultures (bool neutral, bool specific, bool installed);
535 [MethodImplAttribute (MethodImplOptions.InternalCall)]
536 private extern void construct_datetime_format ();
538 [MethodImplAttribute (MethodImplOptions.InternalCall)]
539 private extern void construct_number_format ();
541 // Returns false if the culture can not be found, sets is_neutral if it is
542 [MethodImplAttribute (MethodImplOptions.InternalCall)]
543 private extern static bool internal_is_lcid_neutral (int lcid, out bool is_neutral);
545 private unsafe void ConstructInvariant (bool use_user_override)
549 this.m_useUserOverride=use_user_override;
551 /* NumberFormatInfo defaults to the invariant data */
552 numInfo=NumberFormatInfo.InvariantInfo;
554 /* DateTimeFormatInfo defaults to the invariant data */
555 dateTimeInfo=DateTimeFormatInfo.InvariantInfo;
557 textInfo=new TextInfo (this, cultureID, this.textinfo_data);
560 displayname="Invariant Language (Invariant Country)";
561 englishname="Invariant Language (Invariant Country)";
562 nativename="Invariant Language (Invariant Country)";
565 icu_name="en_US_POSIX";
569 public CultureInfo (int culture, bool use_user_override)
572 throw new ArgumentOutOfRangeException ("Positive number required.",
577 if(culture==0x007f) {
578 /* Short circuit the invariant culture */
579 ConstructInvariant (use_user_override);
583 if (!ConstructInternalLocaleFromLcid (culture))
584 throw new ArgumentException (
585 String.Format ("Culture ID {0} (0x{0:X4}) is not a " +
586 "supported culture.", culture), "culture");
589 public CultureInfo (int culture) : this (culture, false) {}
591 public CultureInfo (string name, bool use_user_override)
594 throw new ArgumentNullException ();
599 /* Short circuit the invariant culture */
600 ConstructInvariant (use_user_override);
604 if (!ConstructInternalLocaleFromName (name.ToLowerInvariant ()))
605 throw new ArgumentException ("Culture name " + name +
606 " is not supported.", "name");
607 ConstructCalendars ();
610 public CultureInfo (string name) : this (name, true) {}
612 // This is used when creating by specific name and creating by
613 // current locale so we can initialize the object without
614 // doing any member initialization
615 private CultureInfo () { constructed = true; }
617 unsafe internal void ConstructCalendars ()
619 if (calendar_data == null)
622 optional_calendars = new Calendar [NumOptionalCalendars];
624 for (int i=0; i<NumOptionalCalendars; i++) {
626 int caldata = *(calendar_data + i);
627 int caltype = (caldata >> CalendarTypeBits);
630 GregorianCalendarTypes greg_type;
631 greg_type = (GregorianCalendarTypes) (caldata & GregorianTypeMask);
632 cal = new GregorianCalendar (greg_type);
635 cal = new HijriCalendar ();
638 cal = new ThaiBuddhistCalendar ();
641 throw new Exception ("invalid calendar type: " + caldata);
643 optional_calendars [i] = cal;