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;
43 internal static int BootstrapCultureID;
45 const int NumOptionalCalendars = 5;
46 const int GregorianTypeMask = 0x00FFFFFF;
47 const int CalendarTypeBits = 24;
59 bool m_useUserOverride;
60 volatile NumberFormatInfo numInfo;
61 volatile DateTimeFormatInfo dateTimeInfo;
62 volatile TextInfo textInfo;
63 private string m_name;
66 private string displayname;
68 private string englishname;
70 private string nativename;
72 private string iso3lang;
74 private string iso2lang;
76 private string icu_name;
78 private string win3lang;
79 volatile CompareInfo compareInfo;
81 private unsafe readonly int *calendar_data;
83 private unsafe readonly void *textinfo_data;
85 private Calendar [] optional_calendars;
87 int m_dataItem; // MS.NET serializes this.
88 Calendar calendar; // MS.NET serializes this.
90 // Deserialized instances will set this to false
94 private static readonly string MSG_READONLY = "This instance is read only";
96 static public CultureInfo InvariantCulture {
98 return invariant_culture_info;
102 static CultureInfo ()
104 invariant_culture_info = new CultureInfo (0x7f, false);
105 invariant_culture_info.m_isReadOnly = true;
108 public static CultureInfo CreateSpecificCulture (string name)
111 throw new ArgumentNullException ("name");
114 if (name == String.Empty)
115 return InvariantCulture;
117 CultureInfo ci = new CultureInfo ();
118 if (!ConstructInternalLocaleFromSpecificName (ci, name.ToLowerInvariant ()))
119 throw new ArgumentException ("Culture name " + name +
120 " is not supported.", name);
125 public static CultureInfo CurrentCulture
128 return Thread.CurrentThread.CurrentCulture;
132 public static CultureInfo CurrentUICulture
135 return Thread.CurrentThread.CurrentUICulture;
139 internal static CultureInfo ConstructCurrentCulture ()
141 CultureInfo ci = new CultureInfo ();
142 if (!ConstructInternalLocaleFromCurrentLocale (ci))
143 ci = InvariantCulture;
144 BootstrapCultureID = ci.cultureID;
148 internal static CultureInfo ConstructCurrentUICulture ()
150 return ConstructCurrentCulture ();
153 public virtual int LCID {
159 public virtual string Name {
165 public virtual string NativeName
168 if (!constructed) Construct ();
173 public virtual Calendar Calendar
175 get { return DateTimeFormat.Calendar; }
178 public virtual Calendar[] OptionalCalendars
181 if (optional_calendars == null) {
183 if (optional_calendars == null)
184 ConstructCalendars ();
187 return optional_calendars;
191 public virtual CultureInfo Parent
194 if (cultureID == 0x7f)
196 if (!constructed) Construct ();
197 if (parent_lcid == cultureID)
199 return new CultureInfo (parent_lcid);
203 public unsafe virtual TextInfo TextInfo
206 if (textInfo == null) {
208 if(textInfo == null) {
209 textInfo = new TextInfo (this, cultureID, textinfo_data);
218 public virtual string ThreeLetterISOLanguageName
221 if (!constructed) Construct ();
226 public virtual string ThreeLetterWindowsLanguageName
229 if (!constructed) Construct ();
234 public virtual string TwoLetterISOLanguageName
237 if (!constructed) Construct ();
242 public bool UseUserOverride
245 return m_useUserOverride;
249 internal string IcuName {
251 if (!constructed) Construct ();
256 public void ClearCachedData()
258 Thread.CurrentThread.CurrentCulture = null;
259 Thread.CurrentThread.CurrentUICulture = null;
262 public virtual object Clone()
264 if (!constructed) Construct ();
265 CultureInfo ci=(CultureInfo)MemberwiseClone ();
266 ci.m_isReadOnly=false;
267 ci.NumberFormat = (NumberFormatInfo)NumberFormat.Clone ();
268 ci.DateTimeFormat = (DateTimeFormatInfo)DateTimeFormat.Clone ();
272 public override bool Equals (object value)
274 CultureInfo b = value as CultureInfo;
277 return b.cultureID == cultureID;
281 public static CultureInfo[] GetCultures(CultureTypes types)
283 bool neutral=((types & CultureTypes.NeutralCultures)!=0);
284 bool specific=((types & CultureTypes.SpecificCultures)!=0);
285 bool installed=((types & CultureTypes.InstalledWin32Cultures)!=0); // TODO
287 CultureInfo [] infos = internal_get_cultures (neutral, specific, installed);
288 // The runtime returns a NULL in the first position of the array when
289 // 'neutral' is true. We fill it in with the InvariantCulture.
290 if (neutral && infos.Length > 0 && infos [0] == null)
291 infos [0] = InvariantCulture;
296 public override int GetHashCode()
301 public static CultureInfo ReadOnly(CultureInfo ci)
304 throw new ArgumentNullException("ci");
307 if(ci.m_isReadOnly) {
310 CultureInfo new_ci=(CultureInfo)ci.Clone ();
311 new_ci.m_isReadOnly=true;
316 public override string ToString()
321 public virtual CompareInfo CompareInfo
324 if (!constructed) Construct ();
325 if(compareInfo==null) {
327 if(compareInfo==null) {
328 compareInfo=new CompareInfo (this);
337 internal static bool IsIDNeutralCulture (int lcid)
340 if (!internal_is_lcid_neutral (lcid, out ret))
341 throw new ArgumentException (String.Format ("Culture id 0x{:x4} is not supported.", lcid));
346 public virtual bool IsNeutralCulture {
348 if (!constructed) Construct ();
349 if (cultureID == 0x7f)
352 return ((cultureID & 0xff00) == 0 || specific_lcid == 0);
356 internal void CheckNeutral ()
358 if (IsNeutralCulture) {
359 throw new NotSupportedException ("Culture \"" + m_name + "\" is " +
360 "a neutral culture. It can not be used in formatting " +
361 "and parsing and therefore cannot be set as the thread's " +
366 public virtual NumberFormatInfo NumberFormat {
368 if (!constructed) Construct ();
370 if (numInfo == null){
372 if (numInfo == null) {
373 numInfo = new NumberFormatInfo ();
374 construct_number_format ();
383 if (!constructed) Construct ();
384 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
387 throw new ArgumentNullException ("NumberFormat");
393 public virtual DateTimeFormatInfo DateTimeFormat
397 if (!constructed) Construct ();
399 if (dateTimeInfo == null)
403 if (dateTimeInfo == null) {
404 dateTimeInfo = new DateTimeFormatInfo();
405 construct_datetime_format ();
406 if (optional_calendars != null)
407 dateTimeInfo.Calendar = optional_calendars [0];
417 if (!constructed) Construct ();
418 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
421 throw new ArgumentNullException ("DateTimeFormat");
423 dateTimeInfo = value;
427 public virtual string DisplayName
430 if (!constructed) Construct ();
435 public virtual string EnglishName
438 if (!constructed) Construct ();
444 public static CultureInfo InstalledUICulture
451 public bool IsReadOnly
454 return(m_isReadOnly);
460 // IFormatProvider implementation
462 public virtual object GetFormat( Type formatType )
464 object format = null;
466 if ( formatType == typeof(NumberFormatInfo) )
467 format = NumberFormat;
468 else if ( formatType == typeof(DateTimeFormatInfo) )
469 format = DateTimeFormat;
476 construct_internal_locale_from_lcid (cultureID);
480 bool ConstructInternalLocaleFromName (string locale)
482 if (!construct_internal_locale_from_name (locale))
487 bool ConstructInternalLocaleFromLcid (int lcid)
489 if (!construct_internal_locale_from_lcid (lcid))
494 static bool ConstructInternalLocaleFromSpecificName (CultureInfo ci, string name)
496 if (!construct_internal_locale_from_specific_name (ci, name))
501 static bool ConstructInternalLocaleFromCurrentLocale (CultureInfo ci)
503 if (!construct_internal_locale_from_current_locale (ci))
508 static CultureInfo [] GetCultures (bool neutral, bool specific, bool installed)
510 CultureInfo [] cis = internal_get_cultures (neutral, specific, installed);
512 // The runtime returns a NULL in the first position of the array when
513 // 'neutral' is true. We fill it in with the InvariantCulture.
514 if (neutral && cis.Length > 0 && cis [0] == null)
515 cis [0] = InvariantCulture;
520 [MethodImplAttribute (MethodImplOptions.InternalCall)]
521 private extern bool construct_internal_locale_from_lcid (int lcid);
523 [MethodImplAttribute (MethodImplOptions.InternalCall)]
524 private extern bool construct_internal_locale_from_name (string name);
526 [MethodImplAttribute (MethodImplOptions.InternalCall)]
527 private extern static bool construct_internal_locale_from_specific_name (CultureInfo ci,
530 [MethodImplAttribute (MethodImplOptions.InternalCall)]
531 private extern static bool construct_internal_locale_from_current_locale (CultureInfo ci);
533 [MethodImplAttribute (MethodImplOptions.InternalCall)]
534 private extern static CultureInfo [] internal_get_cultures (bool neutral, bool specific, bool installed);
536 [MethodImplAttribute (MethodImplOptions.InternalCall)]
537 private extern void construct_datetime_format ();
539 [MethodImplAttribute (MethodImplOptions.InternalCall)]
540 private extern void construct_number_format ();
542 // Returns false if the culture can not be found, sets is_neutral if it is
543 [MethodImplAttribute (MethodImplOptions.InternalCall)]
544 private extern static bool internal_is_lcid_neutral (int lcid, out bool is_neutral);
546 private unsafe void ConstructInvariant (bool use_user_override)
550 this.m_useUserOverride=use_user_override;
552 /* NumberFormatInfo defaults to the invariant data */
553 numInfo=NumberFormatInfo.InvariantInfo;
555 /* DateTimeFormatInfo defaults to the invariant data */
556 dateTimeInfo=DateTimeFormatInfo.InvariantInfo;
558 textInfo=new TextInfo (this, cultureID, this.textinfo_data);
561 displayname="Invariant Language (Invariant Country)";
562 englishname="Invariant Language (Invariant Country)";
563 nativename="Invariant Language (Invariant Country)";
566 icu_name="en_US_POSIX";
570 public CultureInfo (int culture, bool use_user_override)
573 throw new ArgumentOutOfRangeException ("Positive number required.",
578 if(culture==0x007f) {
579 /* Short circuit the invariant culture */
580 ConstructInvariant (use_user_override);
584 if (!ConstructInternalLocaleFromLcid (culture))
585 throw new ArgumentException (
586 String.Format ("Culture ID {0} (0x{0:X4}) is not a " +
587 "supported culture.", culture), "culture");
590 public CultureInfo (int culture) : this (culture, false) {}
592 public CultureInfo (string name, bool use_user_override)
595 throw new ArgumentNullException ();
600 /* Short circuit the invariant culture */
601 ConstructInvariant (use_user_override);
605 if (!ConstructInternalLocaleFromName (name.ToLowerInvariant ()))
606 throw new ArgumentException ("Culture name " + name +
607 " is not supported.", "name");
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) {
620 optional_calendars = new Calendar [] {new GregorianCalendar (GregorianCalendarTypes.Localized)};
624 optional_calendars = new Calendar [NumOptionalCalendars];
626 for (int i=0; i<NumOptionalCalendars; i++) {
628 int caldata = *(calendar_data + i);
629 int caltype = (caldata >> CalendarTypeBits);
632 GregorianCalendarTypes greg_type;
633 greg_type = (GregorianCalendarTypes) (caldata & GregorianTypeMask);
634 cal = new GregorianCalendar (greg_type);
637 cal = new HijriCalendar ();
640 cal = new ThaiBuddhistCalendar ();
643 throw new Exception ("invalid calendar type: " + caldata);
645 optional_calendars [i] = cal;