Merge pull request #1659 from alexanderkyte/stringbuilder-referencesource
[mono.git] / mcs / class / corlib / System.Globalization / CultureInfo.cs
index 9c7bb548501efae7d36d29c121b9455b5c3b0c38..641a7c650cea706132018601cf715bc21439bcc9 100644 (file)
@@ -34,6 +34,7 @@ using System.Collections.Generic;
 using System.Threading;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
+using System.Diagnostics.Contracts;
 
 namespace System.Globalization
 {
@@ -60,7 +61,7 @@ namespace System.Globalization
                bool m_useUserOverride;
                [NonSerialized]
                volatile NumberFormatInfo numInfo;
-               volatile DateTimeFormatInfo dateTimeInfo;
+               internal volatile DateTimeFormatInfo dateTimeInfo;
                volatile TextInfo textInfo;
                private string m_name;
                
@@ -98,6 +99,9 @@ namespace System.Globalization
                [NonSerialized]
                // Used by Thread.set_CurrentCulture
                internal byte[] cached_serialized_form;
+
+               [NonSerialized]internal CultureData m_cultureData;
+               [NonSerialized]internal bool m_isInherited;
                
                internal const int InvariantCultureId = 0x7F;
                const int CalendarTypeBits = 8;
@@ -378,7 +382,6 @@ namespace System.Globalization
 
                        RegionInfo.ClearCachedData ();
                        TimeZone.ClearCachedData ();
-                       DateTime.ClearCachedData ();
                        TimeZoneInfo.ClearCachedData ();
                }
 
@@ -418,6 +421,11 @@ namespace System.Globalization
                                infos [0] = (CultureInfo) InvariantCulture.Clone ();
                        }
 
+                       for (int i = 1; i < infos.Length; ++i) {
+                               var ci = infos [i];
+                               infos [i].m_cultureData = CultureData.GetCultureData (ci.m_name, false, ci.datetime_index, ci.CalendarType, ci.iso2lang);
+                       }
+
                        return infos;
                }
 
@@ -519,17 +527,10 @@ namespace System.Globalization
                                if (!constructed) Construct ();
                                CheckNeutral ();
 
-                               // TODO: Have to lock because construct_datetime_format is not atomic
-                               lock (this) {
-                                       if (cultureID == InvariantCultureId && m_isReadOnly)
-                                               dateTimeInfo = DateTimeFormatInfo.InvariantInfo;
-                                       else if (dateTimeInfo == null) {
-                                               dateTimeInfo = new DateTimeFormatInfo (this, m_isReadOnly);
-                                               if (cultureID != InvariantCultureId)
-                                                       construct_datetime_format ();
-                                       }
-                               }
-
+                               var temp = new DateTimeFormatInfo (m_cultureData, Calendar);
+                               temp.m_isReadOnly = m_isReadOnly;
+                               System.Threading.Thread.MemoryBarrier();
+                               dateTimeInfo = temp;
                                return dateTimeInfo;
                        }
 
@@ -604,9 +605,6 @@ namespace System.Globalization
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                private extern static CultureInfo [] internal_get_cultures (bool neutral, bool specific, bool installed);
 
-               [MethodImplAttribute (MethodImplOptions.InternalCall)]
-               private extern void construct_datetime_format ();
-
                [MethodImplAttribute (MethodImplOptions.InternalCall)]
                private extern void construct_number_format ();
 
@@ -629,7 +627,7 @@ namespace System.Globalization
                        iso3lang="IVL";
                        iso2lang="iv";
                        win3lang="IVL";
-                       default_calendar_type = 1 << CalendarTypeBits;
+                       default_calendar_type = 1 << CalendarTypeBits | (int) GregorianCalendarTypes.Localized;
                }
 
                private unsafe TextInfo CreateTextInfo (bool readOnly)
@@ -655,6 +653,7 @@ namespace System.Globalization
                        if (culture == InvariantCultureId) {
                                /* Short circuit the invariant culture */
                                ConstructInvariant (read_only);
+                               m_cultureData = CultureData.Invariant;
                                return;
                        }
 
@@ -665,6 +664,8 @@ namespace System.Globalization
                                var msg = string.Format (InvariantCulture, "Culture ID {0} (0x{1}) is not a supported culture.", culture.ToString (InvariantCulture), culture.ToString ("X4", InvariantCulture));
                                throw new CultureNotFoundException ("culture", msg);
                        }
+
+                       m_cultureData = CultureData.GetCultureData (m_name, m_useUserOverride, datetime_index, CalendarType, iso2lang);
                }
 
                public CultureInfo (string name) : this (name, true) {}
@@ -680,16 +681,20 @@ namespace System.Globalization
                        constructed = true;
                        m_isReadOnly = read_only;
                        m_useUserOverride = useUserOverride;
+                       m_isInherited = GetType() != typeof(System.Globalization.CultureInfo);
 
                        if (name.Length == 0) {
                                /* Short circuit the invariant culture */
                                ConstructInvariant (read_only);
+                               m_cultureData = CultureData.Invariant;
                                return;
                        }
 
                        if (!construct_internal_locale_from_name (name.ToLowerInvariant ())) {
                                throw CreateNotFoundException (name);
                        }
+
+                       m_cultureData = CultureData.GetCultureData (m_name, useUserOverride, datetime_index, CalendarType, iso2lang);
                }
 
                // This is used when creating by specific name and creating by
@@ -806,6 +811,7 @@ namespace System.Globalization
                        if (ci.IsNeutralCulture)
                                ci = CreateSpecificCultureFromNeutral (ci.Name);
 
+                       ci.m_cultureData = CultureData.GetCultureData (ci.m_name, false, ci.datetime_index, ci.CalendarType, ci.iso2lang);
                        return ci;
                }
 
@@ -979,6 +985,23 @@ namespace System.Globalization
                        return new CultureInfo (id);
                }
 
+               internal int CalendarType {
+                       get {
+                               switch (default_calendar_type >> CalendarTypeBits) {
+                               case 1:
+                                       return Calendar.CAL_GREGORIAN;
+                               case 2:
+                                       return Calendar.CAL_THAI;
+                               case 3:
+                                       return Calendar.CAL_UMALQURA;
+                               case 4:
+                                       return Calendar.CAL_HIJRI;
+                               default:
+                                       throw new NotImplementedException ("CalendarType");
+                               }
+                       }
+               }
+
                static Calendar CreateCalendar (int calendarType)
                {
                        string name = null;
@@ -1002,7 +1025,7 @@ namespace System.Globalization
 
                        Type type = Type.GetType (name, false);
                        if (type == null)
-                               return CreateCalendar (1 << CalendarTypeBits); // return invariant calandar if not found
+                               return new GregorianCalendar (GregorianCalendarTypes.Localized); // return invariant calendar if not found
                        return (Calendar) Activator.CreateInstance (type);
                }
 
@@ -1028,5 +1051,59 @@ namespace System.Globalization
                                Thread.default_ui_culture = value;
                        }
                }
+
+#region reference sources
+               // TODO:
+               internal static readonly bool IsTaiwanSku;
+
+        //
+        // CheckDomainSafetyObject throw if the object is customized object which cannot be attached to 
+        // other object (like CultureInfo or DateTimeFormatInfo).
+        //
+
+        internal static void CheckDomainSafetyObject(Object obj, Object container)
+        {
+            if (obj.GetType().Assembly != typeof(System.Globalization.CultureInfo).Assembly) {
+                
+                throw new InvalidOperationException(
+                            String.Format(
+                                CultureInfo.CurrentCulture, 
+                                Environment.GetResourceString("InvalidOperation_SubclassedObject"), 
+                                obj.GetType(),
+                                container.GetType()));
+            }
+            Contract.EndContractBlock();
+        }
+
+        // For resource lookup, we consider a culture the invariant culture by name equality.
+        // We perform this check frequently during resource lookup, so adding a property for
+        // improved readability.
+        internal bool HasInvariantCultureName
+        {
+            get { return Name == CultureInfo.InvariantCulture.Name; }
+        }
+
+        internal static bool VerifyCultureName(String cultureName, bool throwException)
+        {
+            // This function is used by ResourceManager.GetResourceFileName(). 
+            // ResourceManager searches for resource using CultureInfo.Name,
+            // so we should check against CultureInfo.Name.
+
+            for (int i=0; i<cultureName.Length; i++) {
+                char c = cultureName[i];
+                // 
+
+                if (Char.IsLetterOrDigit(c) || c=='-' || c=='_') {
+                    continue;
+                }
+                if (throwException) {
+                    throw new ArgumentException(Environment.GetResourceString("Argument_InvalidResourceCultureName", cultureName));
+                }
+                return false;
+            }
+            return true;
+        }
+
+#endregion
        }
 }