System.Drawing: added email to icon and test file headers
[mono.git] / mcs / class / corlib / System.Globalization / CultureInfo.cs
1 //
2 // System.Globalization.CultureInfo.cs
3 //
4 // Authors:
5 // Miguel de Icaza (miguel@ximian.com)
6 // Dick Porter (dick@ximian.com)
7 // Marek Safar (marek.safar@gmail.com)
8 //
9 // (C) 2001, 2002, 2003 Ximian, Inc. (http://www.ximian.com)
10 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
11 // Copyright (C) 2012 Xamarin Inc (http://www.xamarin.com)
12 //
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:
20 // 
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 // 
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.
31 //
32
33 using System.Collections;
34 using System.Threading;
35 using System.Runtime.CompilerServices;
36 using System.Runtime.InteropServices;
37
38 namespace System.Globalization
39 {
40         [System.Runtime.InteropServices.ComVisible (true)]
41         [Serializable]
42         [StructLayout (LayoutKind.Sequential)]
43         public class CultureInfo : ICloneable, IFormatProvider
44         {
45                 static volatile CultureInfo invariant_culture_info = new CultureInfo (InvariantCultureId, false, true);
46                 static object shared_table_lock = new object ();
47                 internal static int BootstrapCultureID;
48
49 #pragma warning disable 169, 649
50                 bool m_isReadOnly;
51                 int  cultureID;
52                 [NonSerialized]
53                 int parent_lcid;
54                 [NonSerialized]
55                 int datetime_index;
56                 [NonSerialized]
57                 int number_index;
58                 [NonSerialized]
59                 int default_calendar_type;
60                 bool m_useUserOverride;
61                 [NonSerialized]
62                 volatile NumberFormatInfo numInfo;
63                 volatile DateTimeFormatInfo dateTimeInfo;
64                 volatile TextInfo textInfo;
65                 private string m_name;
66                 
67                 [NonSerialized]
68                 private string englishname;
69                 [NonSerialized]
70                 private string nativename;
71                 [NonSerialized]
72                 private string iso3lang;
73                 [NonSerialized]
74                 private string iso2lang;
75                 [NonSerialized]
76                 private string win3lang;
77                 [NonSerialized]
78                 private string territory;
79                 [NonSerialized]
80                 string[] native_calendar_names;
81
82                 volatile CompareInfo compareInfo;
83                 [NonSerialized]
84                 private unsafe readonly void *textinfo_data;
85
86                 int m_dataItem;         // MS.NET serializes this.
87 #pragma warning restore 169, 649
88
89                 Calendar calendar;
90
91                 [NonSerialized]
92                 CultureInfo parent_culture;
93
94                 // Deserialized instances will set this to false
95                 [NonSerialized]
96                 bool constructed;
97
98                 [NonSerialized]
99                 // Used by Thread.set_CurrentCulture
100                 internal byte[] cached_serialized_form;
101                 
102                 const int InvariantCultureId = 0x7F;
103                 const int CalendarTypeBits = 8;
104
105                 const string MSG_READONLY = "This instance is read only";
106                 
107                 public static CultureInfo InvariantCulture {
108                         get {
109                                 return invariant_culture_info;
110                         }
111                 }
112
113                 public static CultureInfo CreateSpecificCulture (string name)
114                 {
115                         if (name == null) {
116                                 throw new ArgumentNullException ("name");
117                         }
118
119                         if (name == String.Empty)
120                                 return InvariantCulture;
121
122                         CultureInfo ci = new CultureInfo ();
123                         if (!construct_internal_locale_from_specific_name (ci, name.ToLowerInvariant ()))
124                                 throw new ArgumentException ("Culture name " + name +
125                                                 " is not supported.", name);
126
127                         return ci;
128                 }
129
130                 public static CultureInfo CurrentCulture 
131                 {
132                         get {
133                                 return Thread.CurrentThread.CurrentCulture;
134                         }
135                 }
136
137                 public static CultureInfo CurrentUICulture 
138                 {
139                         get {
140                                 return Thread.CurrentThread.CurrentUICulture;
141                         }
142                 }
143
144                 internal static CultureInfo ConstructCurrentCulture ()
145                 {
146                         CultureInfo ci = new CultureInfo ();
147                         if (!ConstructInternalLocaleFromCurrentLocale (ci))
148                                 ci = InvariantCulture;
149                         BootstrapCultureID = ci.cultureID;
150                         return ci;
151                 }
152
153                 internal static CultureInfo ConstructCurrentUICulture ()
154                 {
155                         return ConstructCurrentCulture ();
156                 }
157
158                 // it is used for RegionInfo.
159                 internal string Territory {
160                         get { return territory; }
161                 }
162
163 #if !NET_2_1
164                 // FIXME: It is implemented, but would be hell slow.
165                 [ComVisible (false)]
166                 public CultureTypes CultureTypes {
167                         get {
168                                 CultureTypes ret = (CultureTypes) 0;
169                                 foreach (CultureTypes v in Enum.GetValues (typeof (CultureTypes)))
170                                         if (Array.IndexOf (GetCultures (v), this) >= 0)
171                                                 ret |= v;
172                                 return ret;
173                         }
174                 }
175
176                 [ComVisible (false)]
177                 public CultureInfo GetConsoleFallbackUICulture ()
178                 {
179                         // as documented in MSDN ...
180                         switch (Name) {
181                         case "ar": case "ar-BH": case "ar-EG": case "ar-IQ":
182                         case "ar-JO": case "ar-KW": case "ar-LB": case "ar-LY":
183                         case "ar-QA": case "ar-SA": case "ar-SY": case "ar-AE":
184                         case "ar-YE":
185                         case "dv": case "dv-MV":
186                         case "fa": case "fa-IR":
187                         case "gu": case "gu-IN":
188                         case "he": case "he-IL":
189                         case "hi": case "hi-IN":
190                         case "kn": case "kn-IN":
191                         case "kok": case "kok-IN":
192                         case "mr": case "mr-IN":
193                         case "pa": case "pa-IN":
194                         case "sa": case "sa-IN":
195                         case "syr": case "syr-SY":
196                         case "ta": case "ta-IN":
197                         case "te": case "te-IN":
198                         case "th": case "th-TH":
199                         case "ur": case "ur-PK":
200                         case "vi": case "vi-VN":
201                                 return GetCultureInfo ("en");
202                         case "ar-DZ": case "ar-MA": case "ar-TN":
203                                 return GetCultureInfo ("fr");
204                         }
205                         return (CultureTypes & CultureTypes.WindowsOnlyCultures) != 0 ? CultureInfo.InvariantCulture : this;
206                 }
207
208                 [ComVisible (false)]
209                 public string IetfLanguageTag {
210                         // There could be more consistent way to implement
211                         // it, but right now it works just fine with this...
212                         get {
213                                 switch (Name) {
214                                 case "zh-CHS":
215                                         return "zh-Hans";
216                                 case "zh-CHT":
217                                         return "zh-Hant";
218                                 default:
219                                         return Name;
220                                 }
221                         }
222                 }
223
224                 // For specific cultures it basically returns LCID.
225                 // For neutral cultures it is mapped to the default(?) specific
226                 // culture, where the LCID of the specific culture seems to be
227                 // n + 1024 by default. zh-CHS is the only exception which is 
228                 // mapped to 2052, not 1028 (zh-CHT is mapped to 1028 instead).
229                 // There are very few exceptions, here I simply list them here.
230                 // It is Windows-specific property anyways, so no worthy of
231                 // trying to do some complex things with locale-builder.
232                 [ComVisible (false)]
233                 public virtual int KeyboardLayoutId {
234                         get {
235                                 switch (LCID) {
236                                 case 4: // zh-CHS (neutral)
237                                         return 2052;
238                                 case 1034: // es-ES Spanish 2
239                                         return 3082;
240                                 case 31748: // zh-CHT (neutral)
241                                         return 1028;
242                                 case 31770: // sr (neutral)
243                                         return 2074;
244                                 default:
245                                         return LCID < 1024 ? LCID + 1024 : LCID;
246                                 }
247                         }
248                 }
249 #endif
250
251                 public virtual int LCID {
252                         get {
253                                 return cultureID;
254                         }
255                 }
256
257                 public virtual string Name {
258                         get {
259 #if MOONLIGHT
260                                 if (m_name == "zh-CHS")
261                                         return "zh-Hans";
262                                 if (m_name == "zh-CHT")
263                                         return "zh-Hant";
264 #endif
265                                 return(m_name);
266                         }
267                 }
268
269                 public virtual string NativeName {
270                         get {
271                                 if (!constructed) Construct ();
272                                 return nativename;
273                         }
274                 }
275
276                 internal string NativeCalendarName {
277                         get {
278                                 if (!constructed) Construct ();
279                                 return native_calendar_names[(default_calendar_type >> CalendarTypeBits) - 1];
280                         }
281                 }
282                 
283                 public virtual Calendar Calendar {
284                         get {
285                                 if (calendar == null) {
286                                         if (!constructed) Construct ();
287                                         calendar = CreateCalendar (default_calendar_type);
288                                 }
289
290                                 return calendar;
291                         }
292                 }
293
294                 [MonoLimitation ("Optional calendars are not supported only default calendar is returned")]
295                 public virtual Calendar[] OptionalCalendars {
296                         get {
297                                 return new[] { Calendar };
298                         }
299                 }
300
301                 public virtual CultureInfo Parent
302                 {
303                         get {
304                                 if (parent_culture == null) {
305                                         if (!constructed)
306                                                 Construct ();
307                                         if (parent_lcid == cultureID)
308                                                 return null;
309                                         
310                                         if (parent_lcid == InvariantCultureId)
311                                                 parent_culture = InvariantCulture;
312                                         else if (cultureID == InvariantCultureId)
313                                                 parent_culture = this;
314                                         else
315                                                 parent_culture = new CultureInfo (parent_lcid);
316                                 }
317                                 return parent_culture;
318                         }
319                 }
320
321                 public virtual TextInfo TextInfo
322                 {
323                         get {
324                                 if (textInfo == null) {
325                                         if (!constructed) Construct ();
326                                         lock (this) {
327                                                 if(textInfo == null) {
328                                                         textInfo = CreateTextInfo (m_isReadOnly);
329                                                 }
330                                         }
331                                 }
332                                 
333                                 return(textInfo);
334                         }
335                 }
336
337                 public virtual string ThreeLetterISOLanguageName {
338                         get {
339                                 if (!constructed) Construct ();
340                                 return iso3lang;
341                         }
342                 }
343
344                 public virtual string ThreeLetterWindowsLanguageName
345                 {
346                         get {
347                                 if (!constructed) Construct ();
348                                 return(win3lang);
349                         }
350                 }
351
352                 public virtual string TwoLetterISOLanguageName {
353                         get {
354                                 if (!constructed) Construct ();
355                                 return(iso2lang);
356                         }
357                 }
358
359                 public bool UseUserOverride
360                 {
361                         get {
362                                 return m_useUserOverride;
363                         }
364                 }
365
366                 public void ClearCachedData()
367                 {
368                         Thread.CurrentThread.CurrentCulture = null;
369                         Thread.CurrentThread.CurrentUICulture = null;
370                 }
371
372                 public virtual object Clone()
373                 {
374                         if (!constructed) Construct ();
375                         CultureInfo ci=(CultureInfo)MemberwiseClone ();
376                         ci.m_isReadOnly=false;
377                         ci.cached_serialized_form=null;
378                         if (!IsNeutralCulture) {
379                                 ci.NumberFormat = (NumberFormatInfo)NumberFormat.Clone ();
380                                 ci.DateTimeFormat = (DateTimeFormatInfo)DateTimeFormat.Clone ();
381                         }
382                         return(ci);
383                 }
384
385                 public override bool Equals (object value)
386                 {
387                         CultureInfo b = value as CultureInfo;
388                         
389                         if (b != null)
390                                 return b.cultureID == cultureID;
391                         return false;
392                 }
393
394 #if !MOONLIGHT
395                 public static CultureInfo[] GetCultures(CultureTypes types)
396                 {
397                         bool neutral=((types & CultureTypes.NeutralCultures)!=0);
398                         bool specific=((types & CultureTypes.SpecificCultures)!=0);
399                         bool installed=((types & CultureTypes.InstalledWin32Cultures)!=0);  // TODO
400
401                         CultureInfo [] infos = internal_get_cultures (neutral, specific, installed);
402                         // The runtime returns a NULL in the first position of the array when
403                         // 'neutral' is true. We fill it in with a clone of InvariantCulture
404                         // since it must not be read-only
405                         if (neutral && infos.Length > 0 && infos [0] == null) {
406                                 infos [0] = (CultureInfo) InvariantCulture.Clone ();
407                         }
408
409                         return infos;
410                 }
411 #endif
412
413                 public override int GetHashCode ()
414                 {
415                         return cultureID.GetHashCode ();
416                 }
417
418                 public static CultureInfo ReadOnly(CultureInfo ci)
419                 {
420                         if(ci==null) {
421                                 throw new ArgumentNullException("ci");
422                         }
423
424                         if(ci.m_isReadOnly) {
425                                 return(ci);
426                         } else {
427                                 CultureInfo new_ci=(CultureInfo)ci.Clone ();
428                                 new_ci.m_isReadOnly=true;
429                                 if (new_ci.numInfo != null)
430                                         new_ci.numInfo = NumberFormatInfo.ReadOnly (new_ci.numInfo);
431                                 if (new_ci.dateTimeInfo != null)
432                                         new_ci.dateTimeInfo = DateTimeFormatInfo.ReadOnly (new_ci.dateTimeInfo);
433                                 if (new_ci.textInfo != null)
434                                         new_ci.textInfo = TextInfo.ReadOnly (new_ci.textInfo);
435                                 return(new_ci);
436                         }
437                 }
438
439                 public override string ToString()
440                 {
441                         return(m_name);
442                 }
443                 
444                 public virtual CompareInfo CompareInfo
445                 {
446                         get {
447                                 if(compareInfo==null) {
448                                         if (!constructed)
449                                                 Construct ();
450
451                                         lock (this) {
452                                                 if(compareInfo==null) {
453                                                         compareInfo=new CompareInfo (this);
454                                                 }
455                                         }
456                                 }
457                                 
458                                 return(compareInfo);
459                         }
460                 }
461
462                 public virtual bool IsNeutralCulture {
463                         get {
464                                 if (cultureID == InvariantCultureId)
465                                         return false;
466
467                                 if (!constructed) Construct ();
468                                 return territory == null;
469                         }
470                 }
471
472                 internal void CheckNeutral ()
473                 {
474 #if !MOONLIGHT && !NET_4_0
475                         if (IsNeutralCulture) {
476                                 throw new NotSupportedException ("Culture \"" + m_name + "\" is " +
477                                                 "a neutral culture. It can not be used in formatting " +
478                                                 "and parsing and therefore cannot be set as the thread's " +
479                                                 "current culture.");
480                         }
481 #endif
482                 }
483
484                 public virtual NumberFormatInfo NumberFormat {
485                         get {
486                                 if (!constructed) Construct ();
487                                 CheckNeutral ();
488                                 if (numInfo == null){
489                                         lock (this){
490                                                 if (numInfo == null) {
491                                                         numInfo = new NumberFormatInfo (m_isReadOnly);
492                                                         construct_number_format ();
493                                                 }
494                                         }
495                                 }
496
497                                 return numInfo;
498                         }
499
500                         set {
501                                 if (!constructed) Construct ();
502                                 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
503
504                                 if (value == null)
505                                         throw new ArgumentNullException ("NumberFormat");
506                                 
507                                 numInfo = value;
508                         }
509                 }
510
511                 public virtual DateTimeFormatInfo DateTimeFormat {
512                         get {
513                                 if (dateTimeInfo != null)
514                                         return dateTimeInfo;
515
516                                 if (!constructed) Construct ();
517                                 CheckNeutral ();
518
519                                 // TODO: Have to lock because construct_datetime_format is not atomic
520                                 lock (this) {
521                                         if (cultureID == InvariantCultureId && m_isReadOnly)
522                                                 dateTimeInfo = DateTimeFormatInfo.InvariantInfo;
523                                         else if (dateTimeInfo == null) {
524                                                 dateTimeInfo = new DateTimeFormatInfo (this, m_isReadOnly);
525                                                 if (cultureID != InvariantCultureId)
526                                                         construct_datetime_format ();
527                                         }
528                                 }
529
530                                 return dateTimeInfo;
531                         }
532
533                         set {
534                                 if (!constructed) Construct ();
535                                 if (m_isReadOnly) throw new InvalidOperationException(MSG_READONLY);
536
537                                 if (value == null)
538                                         throw new ArgumentNullException ("DateTimeFormat");
539                                 
540                                 dateTimeInfo = value;
541                         }
542                 }
543
544                 public virtual string DisplayName {
545                         get {
546                                 // Mono is not localized and will always return english name regardless of OS locale
547                                 return EnglishName;
548                         }
549                 }
550
551                 public virtual string EnglishName {
552                         get {
553                                 if (!constructed) Construct ();
554                                 return englishname;
555                         }
556                 }
557
558                 public static CultureInfo InstalledUICulture
559                 {
560                         get { return GetCultureInfo (BootstrapCultureID); }
561                 }
562
563                 public bool IsReadOnly {
564                         get {
565                                 return m_isReadOnly;
566                         }
567                 }
568                 
569
570                 // 
571                 // IFormatProvider implementation
572                 //
573                 public virtual object GetFormat( Type formatType )
574                 {
575                         object format = null;
576
577                         if ( formatType == typeof(NumberFormatInfo) )
578                                 format = NumberFormat;
579                         else if ( formatType == typeof(DateTimeFormatInfo) )
580                                 format = DateTimeFormat;
581                         
582                         return format;
583                 }
584                 
585                 void Construct ()
586                 {
587                         construct_internal_locale_from_lcid (cultureID);
588                         constructed = true;
589                 }
590
591                 static bool ConstructInternalLocaleFromCurrentLocale (CultureInfo ci)
592                 {
593                         if (!construct_internal_locale_from_current_locale (ci))
594                                 return false;
595                         return true;
596                 }
597
598                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
599                 private extern bool construct_internal_locale_from_lcid (int lcid);
600
601                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
602                 private extern bool construct_internal_locale_from_name (string name);
603
604                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
605                 private extern static bool construct_internal_locale_from_specific_name (CultureInfo ci,
606                                 string name);
607
608                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
609                 private extern static bool construct_internal_locale_from_current_locale (CultureInfo ci);
610
611                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
612                 private extern static CultureInfo [] internal_get_cultures (bool neutral, bool specific, bool installed);
613
614                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
615                 private extern void construct_datetime_format ();
616
617                 [MethodImplAttribute (MethodImplOptions.InternalCall)]
618                 private extern void construct_number_format ();
619
620                 private void ConstructInvariant (bool read_only)
621                 {
622                         cultureID = InvariantCultureId;
623
624                         /* NumberFormatInfo defaults to the invariant data */
625                         numInfo=NumberFormatInfo.InvariantInfo;
626
627                         if (!read_only) {
628                                 numInfo = (NumberFormatInfo) numInfo.Clone ();
629                         }
630
631                         textInfo = CreateTextInfo (read_only);
632
633                         m_name=String.Empty;
634                         englishname=
635                         nativename="Invariant Language (Invariant Country)";
636                         iso3lang="IVL";
637                         iso2lang="iv";
638                         win3lang="IVL";
639                         default_calendar_type = 1 << CalendarTypeBits;
640                 }
641
642                 private unsafe TextInfo CreateTextInfo (bool readOnly)
643                 {
644                         return new TextInfo (this, cultureID, this.textinfo_data, readOnly);
645                 }
646
647                 public CultureInfo (int culture) : this (culture, true) {}
648
649                 public CultureInfo (int culture, bool useUserOverride) :
650                         this (culture, useUserOverride, false) {}
651
652                 private CultureInfo (int culture, bool useUserOverride, bool read_only)
653                 {
654                         if (culture < 0)
655                                 throw new ArgumentOutOfRangeException ("culture", "Positive "
656                                         + "number required.");
657
658                         constructed = true;
659                         m_isReadOnly = read_only;
660                         m_useUserOverride = useUserOverride;
661
662                         if (culture == InvariantCultureId) {
663                                 /* Short circuit the invariant culture */
664                                 ConstructInvariant (read_only);
665                                 return;
666                         }
667
668                         if (!construct_internal_locale_from_lcid (culture)) {
669 #if NET_4_0
670                                 throw new CultureNotFoundException ("culture", 
671                                         String.Format ("Culture ID {0} (0x{0:X4}) is not a " +
672                                                         "supported culture.", culture));
673 #else
674                                 throw new ArgumentException (
675                                         String.Format ("Culture ID {0} (0x{0:X4}) is not a " +
676                                                         "supported culture.", culture), "culture");
677 #endif
678                         }
679                 }
680
681                 public CultureInfo (string name) : this (name, true) {}
682
683                 public CultureInfo (string name, bool useUserOverride) :
684                         this (name, useUserOverride, false) {}
685
686                 private CultureInfo (string name, bool useUserOverride, bool read_only)
687                 {
688                         if (name == null)
689                                 throw new ArgumentNullException ("name");
690
691                         constructed = true;
692                         m_isReadOnly = read_only;
693                         m_useUserOverride = useUserOverride;
694
695                         if (name.Length == 0) {
696                                 /* Short circuit the invariant culture */
697                                 ConstructInvariant (read_only);
698                                 return;
699                         }
700
701                         if (!construct_internal_locale_from_name (name.ToLowerInvariant ())) {
702 #if NET_4_0
703                                 throw new CultureNotFoundException ("name",
704                                                 "Culture name " + name + " is not supported.");
705 #else
706                                 throw new ArgumentException ("Culture name " + name +
707                                                 " is not supported.", "name");
708 #endif
709                         }
710                 }
711
712                 // This is used when creating by specific name and creating by
713                 // current locale so we can initialize the object without
714                 // doing any member initialization
715                 private CultureInfo () { constructed = true; }
716                 static Hashtable shared_by_number, shared_by_name;
717                 
718                 static void insert_into_shared_tables (CultureInfo c)
719                 {
720                         if (shared_by_number == null){
721                                 shared_by_number = new Hashtable ();
722                                 shared_by_name = new Hashtable ();
723                         }
724                         shared_by_number [c.cultureID] = c;
725                         shared_by_name [c.m_name] = c;
726                 }
727                 
728                 public static CultureInfo GetCultureInfo (int culture)
729                 {
730                         CultureInfo c;
731                         
732                         lock (shared_table_lock){
733                                 if (shared_by_number != null){
734                                         c = shared_by_number [culture] as CultureInfo;
735
736                                         if (c != null)
737                                                 return (CultureInfo) c;
738                                 }
739                                 c = new CultureInfo (culture, false, true);
740                                 insert_into_shared_tables (c);
741                                 return c;
742                         }
743                 }
744
745                 public static CultureInfo GetCultureInfo (string name)
746                 {
747                         if (name == null)
748                                 throw new ArgumentNullException ("name");
749
750                         CultureInfo c;
751                         lock (shared_table_lock){
752                                 if (shared_by_name != null){
753                                         c = shared_by_name [name] as CultureInfo;
754
755                                         if (c != null)
756                                                 return (CultureInfo) c;
757                                 }
758                                 c = new CultureInfo (name, false, true);
759                                 insert_into_shared_tables (c);
760                                 return c;
761                         }
762                 }
763
764                 [MonoTODO ("Currently it ignores the altName parameter")]
765                 public static CultureInfo GetCultureInfo (string name, string altName) {
766                         if (name == null)
767                                 throw new ArgumentNullException ("null");
768                         if (altName == null)
769                                 throw new ArgumentNullException ("null");
770
771                         return GetCultureInfo (name);
772                 }
773
774                 public static CultureInfo GetCultureInfoByIetfLanguageTag (string name)
775                 {
776                         // There could be more consistent way to implement
777                         // it, but right now it works just fine with this...
778                         switch (name) {
779                         case "zh-Hans":
780                                 return GetCultureInfo ("zh-CHS");
781                         case "zh-Hant":
782                                 return GetCultureInfo ("zh-CHT");
783                         default:
784                                 return GetCultureInfo (name);
785                         }
786                 }
787
788                 // used in runtime (icall.c) to construct CultureInfo for
789                 // AssemblyName of assemblies
790                 internal static CultureInfo CreateCulture (string name, bool reference)
791                 {
792                         bool read_only;
793                         bool use_user_override;
794
795                         bool invariant = name.Length == 0;
796                         if (reference) {
797                                 use_user_override = invariant ? false : true;
798                                 read_only = false;
799                         } else {
800                                 read_only = false;
801                                 use_user_override = invariant ? false : true;
802                         }
803
804                         return new CultureInfo (name, use_user_override, read_only);
805                 }
806
807                 static Calendar CreateCalendar (int calendarType)
808                 {
809                         switch (calendarType >> CalendarTypeBits) {
810                         case 1:
811                                 GregorianCalendarTypes greg_type;
812                                 greg_type = (GregorianCalendarTypes) (calendarType & 0xFF);
813                                 return new GregorianCalendar (greg_type);
814                         case 2:
815                                 return new ThaiBuddhistCalendar ();
816                         case 3:
817                                 return new UmAlQuraCalendar ();
818                         case 4:
819                                 return new HijriCalendar ();
820                         default:
821                                 throw new NotImplementedException ("Unknown calendar type: " + calendarType);
822                         }
823                 }
824         }
825 }