Port servicing fix (#15802)
[platform/upstream/coreclr.git] / src / mscorlib / src / System / Globalization / CultureData.cs
index a93b7d4..8992460 100644 (file)
@@ -2,20 +2,23 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 // See the LICENSE file in the project root for more information.
 
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Text;
+using System.Threading;
+
 namespace System.Globalization
 {
-
-    using System;
-    using System.Collections;
-    using System.Collections.Generic;
-    using System.Text;
-    using System.Threading;
-    using System.Runtime.CompilerServices;
-    using System.Runtime.InteropServices;
-    using System.Runtime.Versioning;
-    using System.Diagnostics;
-    using System.Diagnostics.Contracts;
-    using System.Security;
+#if CORECLR
+    using StringStringDictionary = Dictionary<string, string>;
+    using StringCultureDataDictionary = Dictionary<string, CultureData>;
+    using LcidToCultureNameDictionary = Dictionary<int, string>;
+    using Lock = Object;
+#else
+    using StringStringDictionary = LowLevelDictionary<string, string>;
+    using StringCultureDataDictionary = LowLevelDictionary<string, CultureData>;
+    using LcidToCultureNameDictionary = LowLevelDictionary<int, string>;
+#endif
 
     //
     // List of culture data
@@ -48,504 +51,263 @@ namespace System.Globalization
     //                en if you pass in en
     //                de-DE if you pass in de-DE_phoneb
     //
-
-    // StructLayout is needed here otherwise compiler can re-arrange the fields.
-    // We have to keep this in-sync with the definition in comnlsinfo.h
-    //
-    // WARNING WARNING WARNING
-    //
-    // WARNING: Anything changed here also needs to be updated on the native side (object.h see type CultureDataBaseObject)
-    // WARNING: The type loader will rearrange class member offsets so the mscorwks!CultureDataBaseObject
-    // WARNING: must be manually structured to match the true loaded class layout
-    //
-    [FriendAccessAllowed]
-    internal class CultureData
+    internal partial class CultureData
     {
-        const int undef = -1;
+        private const int LOCALE_NAME_MAX_LENGTH = 85;
+        private const int undef = -1;
 
         // Override flag
-        private String sRealName; // Name you passed in (ie: en-US, en, or de-DE_phoneb)
-        private String sWindowsName; // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in))
+        private String _sRealName; // Name you passed in (ie: en-US, en, or de-DE_phoneb)
+        private String _sWindowsName; // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in))
 
         // Identity
-        private String sName; // locale name (ie: en-us, NO sort info, but could be neutral)
-        private String sParent; // Parent name (which may be a custom locale/culture)
-        private String sLocalizedDisplayName; // Localized pretty name for this locale
-        private String sEnglishDisplayName; // English pretty name for this locale
-        private String sNativeDisplayName; // Native pretty name for this locale
-        private String sSpecificCulture; // The culture name to be used in CultureInfo.CreateSpecificCulture(), en-US form if neutral, sort name if sort
+        private String _sName; // locale name (ie: en-us, NO sort info, but could be neutral)
+        private String _sParent; // Parent name (which may be a custom locale/culture)
+        private String _sLocalizedDisplayName; // Localized pretty name for this locale
+        private String _sEnglishDisplayName; // English pretty name for this locale
+        private String _sNativeDisplayName; // Native pretty name for this locale
+        private String _sSpecificCulture; // The culture name to be used in CultureInfo.CreateSpecificCulture(), en-US form if neutral, sort name if sort
 
         // Language
-        private String sISO639Language; // ISO 639 Language Name
-        private String sLocalizedLanguage; // Localized name for this language
-        private String sEnglishLanguage; // English name for this language
-        private String sNativeLanguage; // Native name of this language
+        private String _sISO639Language; // ISO 639 Language Name
+        private String _sISO639Language2; // ISO 639 Language Name
+        private String _sLocalizedLanguage; // Localized name for this language
+        private String _sEnglishLanguage; // English name for this language
+        private String _sNativeLanguage; // Native name of this language
+        private String _sAbbrevLang; // abbreviated language name (Windows Language Name) ex: ENU
+        private string _sConsoleFallbackName; // The culture name for the console fallback UI culture
+        private int    _iInputLanguageHandle=undef;// input language handle
 
         // Region
-        private String sRegionName; // (RegionInfo)
-        private int iGeoId = undef; // GeoId
-        private String sLocalizedCountry; // localized country name
-        private String sEnglishCountry; // english country name (RegionInfo)
-        private String sNativeCountry; // native country name
-        private String sISO3166CountryName; // ISO 3166 (RegionInfo), ie: US
+        private String _sRegionName; // (RegionInfo)
+        private String _sLocalizedCountry; // localized country name
+        private String _sEnglishCountry; // english country name (RegionInfo)
+        private String _sNativeCountry; // native country name
+        private String _sISO3166CountryName; // ISO 3166 (RegionInfo), ie: US
+        private String _sISO3166CountryName2; // 3 char ISO 3166 country name 2 2(RegionInfo) ex: USA (ISO)
+        private int    _iGeoId = undef; // GeoId
 
         // Numbers
-        private String sPositiveSign; // (user can override) positive sign
-        private String sNegativeSign; // (user can override) negative sign
-        private String[] saNativeDigits; // (user can override) native characters for digits 0-9
+        private String _sPositiveSign; // (user can override) positive sign
+        private String _sNegativeSign; // (user can override) negative sign
         // (nfi populates these 5, don't have to be = undef)
-        private int iDigitSubstitution; // (user can override) Digit substitution 0=context, 1=none/arabic, 2=Native/national (2 seems to be unused)
-        private int iLeadingZeros; // (user can override) leading zeros 0 = no leading zeros, 1 = leading zeros
-        private int iDigits; // (user can override) number of fractional digits
-        private int iNegativeNumber; // (user can override) negative number format
-        private int[] waGrouping; // (user can override) grouping of digits
-        private String sDecimalSeparator; // (user can override) decimal separator
-        private String sThousandSeparator; // (user can override) thousands separator
-        private String sNaN; // Not a Number
-        private String sPositiveInfinity; // + Infinity
-        private String sNegativeInfinity; // - Infinity
+        private int _iDigits; // (user can override) number of fractional digits
+        private int _iNegativeNumber; // (user can override) negative number format
+        private int[] _waGrouping; // (user can override) grouping of digits
+        private String _sDecimalSeparator; // (user can override) decimal separator
+        private String _sThousandSeparator; // (user can override) thousands separator
+        private String _sNaN; // Not a Number
+        private String _sPositiveInfinity; // + Infinity
+        private String _sNegativeInfinity; // - Infinity
 
         // Percent
-        private int iNegativePercent = undef; // Negative Percent (0-3)
-        private int iPositivePercent = undef; // Positive Percent (0-11)
-        private String sPercent; // Percent (%) symbol
-        private String sPerMille; // PerMille (‰) symbol
+        private int _iNegativePercent = undef; // Negative Percent (0-3)
+        private int _iPositivePercent = undef; // Positive Percent (0-11)
+        private String _sPercent; // Percent (%) symbol
+        private String _sPerMille; // PerMille symbol
 
         // Currency
-        private String sCurrency; // (user can override) local monetary symbol
-        private String sIntlMonetarySymbol; // international monetary symbol (RegionInfo)
-        private String sEnglishCurrency; // English name for this currency
-        private String sNativeCurrency; // Native name for this currency
+        private String _sCurrency; // (user can override) local monetary symbol
+        private String _sIntlMonetarySymbol; // international monetary symbol (RegionInfo)
+        private String _sEnglishCurrency; // English name for this currency
+        private String _sNativeCurrency; // Native name for this currency
         // (nfi populates these 4, don't have to be = undef)
-        private int iCurrencyDigits; // (user can override) # local monetary fractional digits
-        private int iCurrency; // (user can override) positive currency format
-        private int iNegativeCurrency; // (user can override) negative currency format
-        private int[] waMonetaryGrouping; // (user can override) monetary grouping of digits
-        private String sMonetaryDecimal; // (user can override) monetary decimal separator
-        private String sMonetaryThousand; // (user can override) monetary thousands separator
+        private int _iCurrencyDigits; // (user can override) # local monetary fractional digits
+        private int _iCurrency; // (user can override) positive currency format
+        private int _iNegativeCurrency; // (user can override) negative currency format
+        private int[] _waMonetaryGrouping; // (user can override) monetary grouping of digits
+        private String _sMonetaryDecimal; // (user can override) monetary decimal separator
+        private String _sMonetaryThousand; // (user can override) monetary thousands separator
 
         // Misc
-        private int iMeasure = undef; // (user can override) system of measurement 0=metric, 1=US (RegionInfo)
-        private String sListSeparator; // (user can override) list separator
-        //        private int    iPaperSize               ; // default paper size (RegionInfo)
+        private int _iMeasure = undef; // (user can override) system of measurement 0=metric, 1=US (RegionInfo)
+        private String _sListSeparator; // (user can override) list separator
 
         // Time
-        private String sAM1159; // (user can override) AM designator
-        private String sPM2359; // (user can override) PM designator
-        private String sTimeSeparator;
-        private volatile String[] saLongTimes; // (user can override) time format
-        private volatile String[] saShortTimes; // short time format
-        private volatile String[] saDurationFormats; // time duration format
+        private String _sAM1159; // (user can override) AM designator
+        private String _sPM2359; // (user can override) PM designator
+        private String _sTimeSeparator;
+        private volatile String[] _saLongTimes; // (user can override) time format
+        private volatile String[] _saShortTimes; // short time format
+        private volatile String[] _saDurationFormats; // time duration format
 
         // Calendar specific data
-        private int iFirstDayOfWeek = undef; // (user can override) first day of week (gregorian really)
-        private int iFirstWeekOfYear = undef; // (user can override) first week of year (gregorian really)
-        private volatile int[] waCalendars; // all available calendar type(s).  The first one is the default calendar
+        private int _iFirstDayOfWeek = undef; // (user can override) first day of week (gregorian really)
+        private int _iFirstWeekOfYear = undef; // (user can override) first week of year (gregorian really)
+        private volatile CalendarId[] _waCalendars; // all available calendar type(s).  The first one is the default calendar
 
         // Store for specific data about each calendar
-        private CalendarData[] calendars; // Store for specific calendar data
+        private CalendarData[] _calendars; // Store for specific calendar data
 
         // Text information
-        private int iReadingLayout = undef; // Reading layout data
+        private int _iReadingLayout = undef; // Reading layout data
         // 0 - Left to right (eg en-US)
         // 1 - Right to left (eg arabic locales)
         // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
         // 3 - Vertical top to bottom with columns proceeding to the right
 
-        private String sTextInfo; // Text info name to use for custom
-        private String sCompareInfo; // Compare info name (including sorting key) to use if custom
-        private String sScripts; // Typical Scripts for this locale (latn;cyrl; etc)
-
-        private int iDefaultAnsiCodePage = undef; // default ansi code page ID (ACP)
-        private int iDefaultOemCodePage = undef; // default oem code page ID (OCP or OEM)
-        private int iDefaultMacCodePage = undef; // default macintosh code page
-        private int iDefaultEbcdicCodePage = undef; // default EBCDIC code page
-
-        // These are desktop only, not coreclr
-        private int    iLanguage; // locale ID (0409) - NO sort information
-        private String sAbbrevLang; // abbreviated language name (Windows Language Name) ex: ENU
-        private String sAbbrevCountry; // abbreviated country name (RegionInfo) (Windows Region Name) ex: USA
-        private String sISO639Language2; // 3 char ISO 639 lang name 2 ex: eng
-        private String sISO3166CountryName2; // 3 char ISO 3166 country name 2 2(RegionInfo) ex: USA (ISO)
-        private int    iInputLanguageHandle=undef;// input language handle
-        private String sConsoleFallbackName; // The culture name for the console fallback UI culture
-        private String sKeyboardsToInstall; // Keyboard installation string.
-        private String fontSignature; // Font signature (16 WORDS)
-
-        // The bools all need to be in one spot
-        private bool bUseOverrides; // use user overrides?
-        private bool bNeutral; // Flags for the culture (ie: neutral or not right now)
-        private bool bWin32Installed; // Flags indicate if the culture is Win32 installed
-        private bool bFramework; // Flags for indicate if the culture is one of Whidbey cultures
+        // CoreCLR depends on this even though its not exposed publicly.
+
+        private int _iDefaultAnsiCodePage = undef; // default ansi code page ID (ACP)
+        private int _iDefaultOemCodePage = undef; // default oem code page ID (OCP or OEM)
+        private int _iDefaultMacCodePage = undef; // default macintosh code page
+        private int _iDefaultEbcdicCodePage = undef; // default EBCDIC code page
+
+        private int _iLanguage; // locale ID (0409) - NO sort information
+        private bool _bUseOverrides; // use user overrides?
+        private bool _bNeutral; // Flags for the culture (ie: neutral or not right now)
 
         // Region Name to Culture Name mapping table
         // (In future would be nice to be in registry or something)
 
-        //Using a property so we avoid creating the dictionary untill we need it
-        private static Dictionary<string, string> RegionNames
+        //Using a property so we avoid creating the dictionary until we need it
+        private static StringStringDictionary RegionNames
         {
-            get 
+            get
             {
                 if (s_RegionNames == null)
                 {
-                    var regionNames = new Dictionary<string, string> {
-                       { "029", "en-029" },
-                       { "AE",  "ar-AE" },
-                       { "AF",  "prs-AF" },
-                       { "AL",  "sq-AL" },
-                       { "AM",  "hy-AM" },
-                       { "AR",  "es-AR" },
-                       { "AT",  "de-AT" },
-                       { "AU",  "en-AU" },
-                       { "AZ",  "az-Cyrl-AZ" },
-                       { "BA",  "bs-Latn-BA" },
-                       { "BD",  "bn-BD" },
-                       { "BE",  "nl-BE" },
-                       { "BG",  "bg-BG" },
-                       { "BH",  "ar-BH" },
-                       { "BN",  "ms-BN" },
-                       { "BO",  "es-BO" },
-                       { "BR",  "pt-BR" },
-                       { "BY",  "be-BY" },
-                       { "BZ",  "en-BZ" },
-                       { "CA",  "en-CA" },
-                       { "CH",  "it-CH" },
-                       { "CL",  "es-CL" },
-                       { "CN",  "zh-CN" },
-                       { "CO",  "es-CO" },
-                       { "CR",  "es-CR" },
-                       { "CS",  "sr-Cyrl-CS" },
-                       { "CZ",  "cs-CZ" },
-                       { "DE",  "de-DE" },
-                       { "DK",  "da-DK" },
-                       { "DO",  "es-DO" },
-                       { "DZ",  "ar-DZ" },
-                       { "EC",  "es-EC" },
-                       { "EE",  "et-EE" },
-                       { "EG",  "ar-EG" },
-                       { "ES",  "es-ES" },
-                       { "ET",  "am-ET" },
-                       { "FI",  "fi-FI" },
-                       { "FO",  "fo-FO" },
-                       { "FR",  "fr-FR" },
-                       { "GB",  "en-GB" },
-                       { "GE",  "ka-GE" },
-                       { "GL",  "kl-GL" },
-                       { "GR",  "el-GR" },
-                       { "GT",  "es-GT" },
-                       { "HK",  "zh-HK" },
-                       { "HN",  "es-HN" },
-                       { "HR",  "hr-HR" },
-                       { "HU",  "hu-HU" },
-                       { "ID",  "id-ID" },
-                       { "IE",  "en-IE" },
-                       { "IL",  "he-IL" },
-                       { "IN",  "hi-IN" },
-                       { "IQ",  "ar-IQ" },
-                       { "IR",  "fa-IR" },
-                       { "IS",  "is-IS" },
-                       { "IT",  "it-IT" },
-                       { "IV",  "" },
-                       { "JM",  "en-JM" },
-                       { "JO",  "ar-JO" },
-                       { "JP",  "ja-JP" },
-                       { "KE",  "sw-KE" },
-                       { "KG",  "ky-KG" },
-                       { "KH",  "km-KH" },
-                       { "KR",  "ko-KR" },
-                       { "KW",  "ar-KW" },
-                       { "KZ",  "kk-KZ" },
-                       { "LA",  "lo-LA" },
-                       { "LB",  "ar-LB" },
-                       { "LI",  "de-LI" },
-                       { "LK",  "si-LK" },
-                       { "LT",  "lt-LT" },
-                       { "LU",  "lb-LU" },
-                       { "LV",  "lv-LV" },
-                       { "LY",  "ar-LY" },
-                       { "MA",  "ar-MA" },
-                       { "MC",  "fr-MC" },
-                       { "ME",  "sr-Latn-ME" },
-                       { "MK",  "mk-MK" },
-                       { "MN",  "mn-MN" },
-                       { "MO",  "zh-MO" },
-                       { "MT",  "mt-MT" },
-                       { "MV",  "dv-MV" },
-                       { "MX",  "es-MX" },
-                       { "MY",  "ms-MY" },
-                       { "NG",  "ig-NG" },
-                       { "NI",  "es-NI" },
-                       { "NL",  "nl-NL" },
-                       { "NO",  "nn-NO" },
-                       { "NP",  "ne-NP" },
-                       { "NZ",  "en-NZ" },
-                       { "OM",  "ar-OM" },
-                       { "PA",  "es-PA" },
-                       { "PE",  "es-PE" },
-                       { "PH",  "en-PH" },
-                       { "PK",  "ur-PK" },
-                       { "PL",  "pl-PL" },
-                       { "PR",  "es-PR" },
-                       { "PT",  "pt-PT" },
-                       { "PY",  "es-PY" },
-                       { "QA",  "ar-QA" },
-                       { "RO",  "ro-RO" },
-                       { "RS",  "sr-Latn-RS" },
-                       { "RU",  "ru-RU" },
-                       { "RW",  "rw-RW" },
-                       { "SA",  "ar-SA" },
-                       { "SE",  "sv-SE" },
-                       { "SG",  "zh-SG" },
-                       { "SI",  "sl-SI" },
-                       { "SK",  "sk-SK" },
-                       { "SN",  "wo-SN" },
-                       { "SV",  "es-SV" },
-                       { "SY",  "ar-SY" },
-                       { "TH",  "th-TH" },
-                       { "TJ",  "tg-Cyrl-TJ" },
-                       { "TM",  "tk-TM" },
-                       { "TN",  "ar-TN" },
-                       { "TR",  "tr-TR" },
-                       { "TT",  "en-TT" },
-                       { "TW",  "zh-TW" },
-                       { "UA",  "uk-UA" },
-                       { "US",  "en-US" },
-                       { "UY",  "es-UY" },
-                       { "UZ",  "uz-Cyrl-UZ" },
-                       { "VE",  "es-VE" },
-                       { "VN",  "vi-VN" },
-                       { "YE",  "ar-YE" },
-                       { "ZA",  "af-ZA" },
-                       { "ZW",  "en-ZW" }
-                   };
-                   s_RegionNames = regionNames;
-               }
-                return s_RegionNames;
-            }
-        }
-        private volatile static Dictionary<string, string> s_RegionNames;
-
-        /////////////////////////////////////////////////////////////////////////
-        // Build our invariant information
-        //
-        // We need an invariant instance, which we build hard-coded
-        /////////////////////////////////////////////////////////////////////////
-        internal static CultureData Invariant  
-        {
-            get 
-            {
-                if (s_Invariant == null)
-                {
-                   // Make a new culturedata
-                   CultureData invariant = new CultureData();
-
-                   // Call the native code to get the value of bWin32Installed.
-                   // For versions <= Vista, we set this to false for compatibility with v2.
-                   // For Windows 7, the flag is true.
-                   invariant.bUseOverrides = false;
-                   invariant.sRealName = "";
-
-                   // Ask the native code to fill it out for us, we only need the field IsWin32Installed
-                   nativeInitCultureData(invariant);
-
-                   // Basics
-                   // Note that we override the resources since this IS NOT supposed to change (by definition)
-                   invariant.bUseOverrides = false;
-                   invariant.sRealName = "";                     // Name you passed in (ie: en-US, en, or de-DE_phoneb)
-                   invariant.sWindowsName = "";                     // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in))
-
-                   // Identity
-                   invariant.sName = "";                     // locale name (ie: en-us)
-                   invariant.sParent = "";                     // Parent name (which may be a custom locale/culture)
-                   invariant.bNeutral = false;                   // Flags for the culture (ie: neutral or not right now)
-                   // Don't set invariant.bWin32Installed, we used nativeInitCultureData for that.
-                   invariant.bFramework = true;
-
-                   invariant.sEnglishDisplayName = "Invariant Language (Invariant Country)"; // English pretty name for this locale
-                   invariant.sNativeDisplayName = "Invariant Language (Invariant Country)";  // Native pretty name for this locale
-                   invariant.sSpecificCulture = "";                     // The culture name to be used in CultureInfo.CreateSpecificCulture()
-
-                   // Language
-                   invariant.sISO639Language = "iv";                   // ISO 639 Language Name
-                   invariant.sLocalizedLanguage = "Invariant Language";   // Display name for this Language
-                   invariant.sEnglishLanguage = "Invariant Language";   // English name for this language
-                   invariant.sNativeLanguage = "Invariant Language";   // Native name of this language
-
-                   // Region
-                   invariant.sRegionName = "IV";                   // (RegionInfo)
-                   // Unused for now:
-                   //            invariant.iCountry              =1;                      // country code (RegionInfo)
-                   invariant.iGeoId = 244;                    // GeoId (Windows Only)
-                   invariant.sEnglishCountry = "Invariant Country";    // english country name (RegionInfo)
-                   invariant.sNativeCountry = "Invariant Country";    // native country name (Windows Only)
-                   invariant.sISO3166CountryName = "IV";                   // (RegionInfo), ie: US
-
-                   // Numbers
-                   invariant.sPositiveSign = "+";                    // positive sign
-                   invariant.sNegativeSign = "-";                    // negative sign
-                   invariant.saNativeDigits = new String[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; // native characters for digits 0-9
-                   invariant.iDigitSubstitution = 1;                      // Digit substitution 0=context, 1=none/arabic, 2=Native/national (2 seems to be unused) (Windows Only)
-                   invariant.iLeadingZeros = 1;                      // leading zeros 0=no leading zeros, 1=leading zeros
-                   invariant.iDigits = 2;                      // number of fractional digits
-                   invariant.iNegativeNumber = 1;                      // negative number format
-                   invariant.waGrouping = new int[] { 3 };          // grouping of digits
-                   invariant.sDecimalSeparator = ".";                    // decimal separator
-                   invariant.sThousandSeparator = ",";                    // thousands separator
-                   invariant.sNaN = "NaN";                  // Not a Number
-                   invariant.sPositiveInfinity = "Infinity";             // + Infinity
-                   invariant.sNegativeInfinity = "-Infinity";            // - Infinity
-
-                   // Percent
-                   invariant.iNegativePercent = 0;                      // Negative Percent (0-3)
-                   invariant.iPositivePercent = 0;                      // Positive Percent (0-11)
-                   invariant.sPercent = "%";                    // Percent (%) symbol
-                   invariant.sPerMille = "\x2030";               // PerMille(‰) symbol
-
-                   // Currency
-                   invariant.sCurrency = "\x00a4";                // local monetary symbol "¤: for international monetary symbol
-                   invariant.sIntlMonetarySymbol = "XDR";                  // international monetary symbol (RegionInfo)
-                   invariant.sEnglishCurrency = "International Monetary Fund"; // English name for this currency (Windows Only)
-                   invariant.sNativeCurrency = "International Monetary Fund"; // Native name for this currency (Windows Only)
-                   invariant.iCurrencyDigits = 2;                      // # local monetary fractional digits
-                   invariant.iCurrency = 0;                      // positive currency format
-                   invariant.iNegativeCurrency = 0;                      // negative currency format
-                   invariant.waMonetaryGrouping = new int[] { 3 };          // monetary grouping of digits
-                   invariant.sMonetaryDecimal = ".";                    // monetary decimal separator
-                   invariant.sMonetaryThousand = ",";                    // monetary thousands separator
-
-                   // Misc
-                   invariant.iMeasure = 0;                      // system of measurement 0=metric, 1=US (RegionInfo)
-                   invariant.sListSeparator = ",";                    // list separator
-                   // Unused for now:
-                   //            invariant.iPaperSize            =9;                      // default paper size (RegionInfo)
-                   //            invariant.waFontSignature       ="\x0002\x0000\x0000\x0000\x0000\x0000\x0000\x8000\x0001\x0000\x0000\x8000\x0001\x0000\x0000\x8000"; // Font signature (16 WORDS) (Windows Only)
-
-                   // Time
-                   invariant.sAM1159 = "AM";                   // AM designator
-                   invariant.sPM2359 = "PM";                   // PM designator
-                   invariant.saLongTimes = new String[] { "HH:mm:ss" };                             // time format
-                   invariant.saShortTimes = new String[] { "HH:mm", "hh:mm tt", "H:mm", "h:mm tt" }; // short time format
-                   invariant.saDurationFormats = new String[] { "HH:mm:ss" };                             // time duration format
-
-                   // Calendar specific data
-                   invariant.iFirstDayOfWeek = 0;                      // first day of week
-                   invariant.iFirstWeekOfYear = 0;                      // first week of year
-                   invariant.waCalendars = new int[] { (int)CalendarId.GREGORIAN };       // all available calendar type(s).  The first one is the default calendar
-
-                   // Store for specific data about each calendar
-                   invariant.calendars = new CalendarData[CalendarData.MAX_CALENDARS];
-                   invariant.calendars[0] = CalendarData.Invariant;
-
-                   // Text information
-                   invariant.iReadingLayout = 0;                      // Reading Layout = RTL
-
-                   invariant.sTextInfo = "";                     // Text info name to use for custom
-                   invariant.sCompareInfo = "";                     // Compare info name (including sorting key) to use if custom
-                   invariant.sScripts = "Latn;";                // Typical Scripts for this locale (latn,cyrl, etc)
-
-                   invariant.iLanguage = 0x007f;                 // locale ID (0409) - NO sort information
-                   invariant.iDefaultAnsiCodePage = 1252;                   // default ansi code page ID (ACP)
-                   invariant.iDefaultOemCodePage = 437;                    // default oem code page ID (OCP or OEM)
-                   invariant.iDefaultMacCodePage = 10000;                  // default macintosh code page
-                   invariant.iDefaultEbcdicCodePage = 037;                    // default EBCDIC code page
-            invariant.sAbbrevLang = "IVL";                     // abbreviated language name (Windows Language Name)
-            invariant.sAbbrevCountry = "IVC";                  // abbreviated country name (RegionInfo) (Windows Region Name)
-                   invariant.sISO639Language2 = "ivl";                  // 3 char ISO 639 lang name 2
-                   invariant.sISO3166CountryName2 = "ivc";                  // 3 char ISO 3166 country name 2 2(RegionInfo)
-                   invariant.iInputLanguageHandle = 0x007f;                 // input language handle
-                   invariant.sConsoleFallbackName = "";                     // The culture name for the console fallback UI culture
-                   invariant.sKeyboardsToInstall = "0409:00000409";        // Keyboard installation string.
-                   // Remember it
-                    s_Invariant = invariant;
-                }
-                return s_Invariant;
-            }
-        }
-        private volatile static CultureData s_Invariant;
-
-        ///////////////
-        // Constructors //
-        ///////////////
-        // Cache of cultures we've already looked up
-        private static volatile Dictionary<String, CultureData> s_cachedCultures;
-
-        [FriendAccessAllowed]
-        internal static CultureData GetCultureData(String cultureName, bool useUserOverride)
-        {
-            // First do a shortcut for Invariant
-            if (String.IsNullOrEmpty(cultureName))
-            {
-                return CultureData.Invariant;
-            }
-
-            // Try the hash table first
-            String hashName = AnsiToLower(useUserOverride ? cultureName : cultureName + '*');
-            Dictionary<String, CultureData> tempHashTable = s_cachedCultures;
-            if (tempHashTable == null)
-            {
-                // No table yet, make a new one
-                tempHashTable = new Dictionary<String, CultureData>();
-            }
-            else
-            {
-                // Check the hash table
-                CultureData retVal;
-                lock (((ICollection)tempHashTable).SyncRoot)
-                {
-                    tempHashTable.TryGetValue(hashName, out retVal);
+                    StringStringDictionary regionNames = new StringStringDictionary(211 /* prime */);
+
+                    regionNames.Add("029", "en-029");
+                    regionNames.Add("AE", "ar-AE");
+                    regionNames.Add("AF", "prs-AF");
+                    regionNames.Add("AL", "sq-AL");
+                    regionNames.Add("AM", "hy-AM");
+                    regionNames.Add("AR", "es-AR");
+                    regionNames.Add("AT", "de-AT");
+                    regionNames.Add("AU", "en-AU");
+                    regionNames.Add("AZ", "az-Cyrl-AZ");
+                    regionNames.Add("BA", "bs-Latn-BA");
+                    regionNames.Add("BD", "bn-BD");
+                    regionNames.Add("BE", "nl-BE");
+                    regionNames.Add("BG", "bg-BG");
+                    regionNames.Add("BH", "ar-BH");
+                    regionNames.Add("BN", "ms-BN");
+                    regionNames.Add("BO", "es-BO");
+                    regionNames.Add("BR", "pt-BR");
+                    regionNames.Add("BY", "be-BY");
+                    regionNames.Add("BZ", "en-BZ");
+                    regionNames.Add("CA", "en-CA");
+                    regionNames.Add("CH", "it-CH");
+                    regionNames.Add("CL", "es-CL");
+                    regionNames.Add("CN", "zh-CN");
+                    regionNames.Add("CO", "es-CO");
+                    regionNames.Add("CR", "es-CR");
+                    regionNames.Add("CS", "sr-Cyrl-CS");
+                    regionNames.Add("CZ", "cs-CZ");
+                    regionNames.Add("DE", "de-DE");
+                    regionNames.Add("DK", "da-DK");
+                    regionNames.Add("DO", "es-DO");
+                    regionNames.Add("DZ", "ar-DZ");
+                    regionNames.Add("EC", "es-EC");
+                    regionNames.Add("EE", "et-EE");
+                    regionNames.Add("EG", "ar-EG");
+                    regionNames.Add("ES", "es-ES");
+                    regionNames.Add("ET", "am-ET");
+                    regionNames.Add("FI", "fi-FI");
+                    regionNames.Add("FO", "fo-FO");
+                    regionNames.Add("FR", "fr-FR");
+                    regionNames.Add("GB", "en-GB");
+                    regionNames.Add("GE", "ka-GE");
+                    regionNames.Add("GL", "kl-GL");
+                    regionNames.Add("GR", "el-GR");
+                    regionNames.Add("GT", "es-GT");
+                    regionNames.Add("HK", "zh-HK");
+                    regionNames.Add("HN", "es-HN");
+                    regionNames.Add("HR", "hr-HR");
+                    regionNames.Add("HU", "hu-HU");
+                    regionNames.Add("ID", "id-ID");
+                    regionNames.Add("IE", "en-IE");
+                    regionNames.Add("IL", "he-IL");
+                    regionNames.Add("IN", "hi-IN");
+                    regionNames.Add("IQ", "ar-IQ");
+                    regionNames.Add("IR", "fa-IR");
+                    regionNames.Add("IS", "is-IS");
+                    regionNames.Add("IT", "it-IT");
+                    regionNames.Add("IV", "");
+                    regionNames.Add("JM", "en-JM");
+                    regionNames.Add("JO", "ar-JO");
+                    regionNames.Add("JP", "ja-JP");
+                    regionNames.Add("KE", "sw-KE");
+                    regionNames.Add("KG", "ky-KG");
+                    regionNames.Add("KH", "km-KH");
+                    regionNames.Add("KR", "ko-KR");
+                    regionNames.Add("KW", "ar-KW");
+                    regionNames.Add("KZ", "kk-KZ");
+                    regionNames.Add("LA", "lo-LA");
+                    regionNames.Add("LB", "ar-LB");
+                    regionNames.Add("LI", "de-LI");
+                    regionNames.Add("LK", "si-LK");
+                    regionNames.Add("LT", "lt-LT");
+                    regionNames.Add("LU", "lb-LU");
+                    regionNames.Add("LV", "lv-LV");
+                    regionNames.Add("LY", "ar-LY");
+                    regionNames.Add("MA", "ar-MA");
+                    regionNames.Add("MC", "fr-MC");
+                    regionNames.Add("ME", "sr-Latn-ME");
+                    regionNames.Add("MK", "mk-MK");
+                    regionNames.Add("MN", "mn-MN");
+                    regionNames.Add("MO", "zh-MO");
+                    regionNames.Add("MT", "mt-MT");
+                    regionNames.Add("MV", "dv-MV");
+                    regionNames.Add("MX", "es-MX");
+                    regionNames.Add("MY", "ms-MY");
+                    regionNames.Add("NG", "ig-NG");
+                    regionNames.Add("NI", "es-NI");
+                    regionNames.Add("NL", "nl-NL");
+                    regionNames.Add("NO", "nn-NO");
+                    regionNames.Add("NP", "ne-NP");
+                    regionNames.Add("NZ", "en-NZ");
+                    regionNames.Add("OM", "ar-OM");
+                    regionNames.Add("PA", "es-PA");
+                    regionNames.Add("PE", "es-PE");
+                    regionNames.Add("PH", "en-PH");
+                    regionNames.Add("PK", "ur-PK");
+                    regionNames.Add("PL", "pl-PL");
+                    regionNames.Add("PR", "es-PR");
+                    regionNames.Add("PT", "pt-PT");
+                    regionNames.Add("PY", "es-PY");
+                    regionNames.Add("QA", "ar-QA");
+                    regionNames.Add("RO", "ro-RO");
+                    regionNames.Add("RS", "sr-Latn-RS");
+                    regionNames.Add("RU", "ru-RU");
+                    regionNames.Add("RW", "rw-RW");
+                    regionNames.Add("SA", "ar-SA");
+                    regionNames.Add("SE", "sv-SE");
+                    regionNames.Add("SG", "zh-SG");
+                    regionNames.Add("SI", "sl-SI");
+                    regionNames.Add("SK", "sk-SK");
+                    regionNames.Add("SN", "wo-SN");
+                    regionNames.Add("SV", "es-SV");
+                    regionNames.Add("SY", "ar-SY");
+                    regionNames.Add("TH", "th-TH");
+                    regionNames.Add("TJ", "tg-Cyrl-TJ");
+                    regionNames.Add("TM", "tk-TM");
+                    regionNames.Add("TN", "ar-TN");
+                    regionNames.Add("TR", "tr-TR");
+                    regionNames.Add("TT", "en-TT");
+                    regionNames.Add("TW", "zh-TW");
+                    regionNames.Add("UA", "uk-UA");
+                    regionNames.Add("US", "en-US");
+                    regionNames.Add("UY", "es-UY");
+                    regionNames.Add("UZ", "uz-Cyrl-UZ");
+                    regionNames.Add("VE", "es-VE");
+                    regionNames.Add("VN", "vi-VN");
+                    regionNames.Add("YE", "ar-YE");
+                    regionNames.Add("ZA", "af-ZA");
+                    regionNames.Add("ZW", "en-ZW");
+
+                    s_RegionNames = regionNames;
                 }
-                if (retVal != null)
-                {
-                    return retVal;
-                }
-            }
 
-            // Not found in the hash table, need to see if we can build one that works for us
-            CultureData culture = CreateCultureData(cultureName, useUserOverride);
-            if (culture == null)
-            {
-                return null;
-            }
-
-            // Found one, add it to the cache
-            lock (((ICollection)tempHashTable).SyncRoot)
-            {
-                tempHashTable[hashName] = culture;
-            }
-
-            // Copy the hashtable to the corresponding member variables.  This will potentially overwrite
-            // new tables simultaneously created by a new thread, but maximizes thread safety.
-            s_cachedCultures = tempHashTable;
-
-            return culture;
-        }
-
-        private static CultureData CreateCultureData(string cultureName, bool useUserOverride)
-        {
-            CultureData culture = new CultureData();
-            culture.bUseOverrides = useUserOverride;
-            culture.sRealName = cultureName;
-
-            // Ask native code if that one's real
-            if (culture.InitCultureData() == false)
-            {
-                return null;
-            }
-
-            return culture;
-        }
-
-        private bool InitCultureData()
-        {
-            if (nativeInitCultureData(this) == false)
-            {
-                return false;
+                return s_RegionNames;
             }
-            return true;
         }
 
         // Cache of regions we've already looked up
-        private static volatile Dictionary<String, CultureData> s_cachedRegions;
+        private static volatile StringCultureDataDictionary s_cachedRegions;
+        private static volatile StringStringDictionary s_RegionNames;
 
         internal static CultureData GetCultureDataForRegion(String cultureName, bool useUserOverride)
         {
@@ -571,16 +333,16 @@ namespace System.Globalization
 
             // Try the hash table next
             String hashName = AnsiToLower(useUserOverride ? cultureName : cultureName + '*');
-            Dictionary<String, CultureData> tempHashTable = s_cachedRegions;
+            StringCultureDataDictionary tempHashTable = s_cachedRegions;
             if (tempHashTable == null)
             {
                 // No table yet, make a new one
-                tempHashTable = new Dictionary<String, CultureData>();
+                tempHashTable = new StringCultureDataDictionary();
             }
             else
             {
                 // Check the hash table
-                lock (((ICollection)tempHashTable).SyncRoot)
+                lock (s_lock)
                 {
                     tempHashTable.TryGetValue(hashName, out retVal);
                 }
@@ -598,36 +360,25 @@ namespace System.Globalization
             if (retVal == null || (retVal.IsNeutralCulture == true))
             {
                 // Not a valid mapping, try the hard coded table
-                if (RegionNames.ContainsKey(cultureName))
+                string name;
+                if (RegionNames.TryGetValue(cultureName, out name))
                 {
                     // Make sure we can get culture data for it
-                    retVal = GetCultureData(RegionNames[cultureName], useUserOverride);
+                    retVal = GetCultureData(name, useUserOverride);
                 }
             }
 
             // If not found in the hard coded table we'll have to find a culture that works for us
-            if (retVal == null || (retVal.IsNeutralCulture == true))
+            if (!GlobalizationMode.Invariant && (retVal == null || (retVal.IsNeutralCulture == true)))
             {
-                // Not found in the hard coded table, need to see if we can find a culture that works for us
-                // Not a real culture name, see if it matches a region name
-                // (we just return the first culture we match)
-                CultureInfo[] specifics = SpecificCultures;
-                for (int i = 0; i < specifics.Length; i++)
-                {
-                    if (String.Compare(specifics[i].m_cultureData.SREGIONNAME, cultureName, StringComparison.OrdinalIgnoreCase) == 0)
-                    {
-                        // Matched, use this culture
-                        retVal = specifics[i].m_cultureData;
-                        break;
-                    }
-                }
+                retVal = GetCultureDataFromRegionName(cultureName);
             }
 
-            // If we found one we can use, then cash it for next time
+            // If we found one we can use, then cache it for next time
             if (retVal != null && (retVal.IsNeutralCulture == false))
             {
                 // first add it to the cache
-                lock (((ICollection)tempHashTable).SyncRoot)
+                lock (s_lock)
                 {
                     tempHashTable[hashName] = retVal;
                 }
@@ -647,54 +398,11 @@ namespace System.Globalization
             return retVal;
         }
 
-#if FEATURE_USE_LCID
-        // Obtain locale name from LCID
-        // NOTE: This will get neutral names, unlike the OS API
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        internal static extern String LCIDToLocaleName(int lcid);
-
-        // We'd rather people use the named version since this doesn't allow custom locales
-        internal static CultureData GetCultureData(int culture, bool bUseUserOverride)
-        {
-            String localeName = null;
-            CultureData retVal = null;
-
-            if (localeName == null)
-            {
-                // Convert the lcid to a name, then use that
-                // Note that this'll return neutral names (unlike Vista native API)
-                localeName = LCIDToLocaleName(culture);
-            }
-
-            // If its not valid, then throw
-            if (String.IsNullOrEmpty(localeName))
-            {
-                // Could be valid for Invariant
-                if (culture == 0x007f)
-                    return Invariant;
-            }
-            else
-            {
-                // Valid name, use it
-                retVal = GetCultureData(localeName, bUseUserOverride);
-            }
-
-            // If not successful, throw
-            if (retVal == null)
-                throw new CultureNotFoundException(
-                    nameof(culture), culture, Environment.GetResourceString("Argument_CultureNotSupported"));
-
-            // Return the one we found
-            return retVal;
-        }
-#endif
-
         // Clear our internal caches
         internal static void ClearCachedData()
         {
             s_cachedCultures = null;
             s_cachedRegions = null;
-            s_replacementCultureNames = null;
         }
 
         internal static CultureInfo[] GetCultures(CultureTypes types)
@@ -703,23 +411,16 @@ namespace System.Globalization
 #pragma warning disable 618
             // Validate flags
             if ((int)types <= 0 || ((int)types & (int)~(CultureTypes.NeutralCultures | CultureTypes.SpecificCultures |
-                                                            CultureTypes.InstalledWin32Cultures | CultureTypes.UserCustomCulture |
-                                                            CultureTypes.ReplacementCultures | CultureTypes.WindowsOnlyCultures |
-                                                            CultureTypes.FrameworkCultures)) != 0)
+                                                        CultureTypes.InstalledWin32Cultures | CultureTypes.UserCustomCulture |
+                                                        CultureTypes.ReplacementCultures | CultureTypes.WindowsOnlyCultures |
+                                                        CultureTypes.FrameworkCultures)) != 0)
             {
-                throw new ArgumentOutOfRangeException(
-                                nameof(types),
-                                String.Format(
-                                    CultureInfo.CurrentCulture,
-                                    Environment.GetResourceString("ArgumentOutOfRange_Range"), CultureTypes.NeutralCultures, CultureTypes.FrameworkCultures));
+                throw new ArgumentOutOfRangeException(nameof(types),
+                              SR.Format(SR.ArgumentOutOfRange_Range, CultureTypes.NeutralCultures, CultureTypes.FrameworkCultures));
             }
 
-            //
-            // CHANGE FROM Whidbey
-            //
             // We have deprecated CultureTypes.FrameworkCultures.
             // When this enum is used, we will enumerate Whidbey framework cultures (for compatibility).
-            //
 
             // We have deprecated CultureTypes.WindowsOnlyCultures.
             // When this enum is used, we will return an empty array for this enum.
@@ -729,84 +430,356 @@ namespace System.Globalization
                 types &= (~CultureTypes.WindowsOnlyCultures);
             }
 
-            String[] cultureNames = null;
+            if (GlobalizationMode.Invariant)
+            {
+                // in invariant mode we always return invariant culture only from the enumeration
+                return new CultureInfo[1] { new CultureInfo("") };
+            }
 
-            //
-            // Call nativeEnumCultureNames() to get a string array of culture names based on the specified
-            // enumeration type.
-            //
-            // nativeEnumCultureNames is a QCall.  We need to use a reference to return the string array
-            // allocated from the QCall.  That ref has to be wrapped as object handle.
-            // See vm\qcall.h for details in QCall.
-            //
+#pragma warning restore 618
+            return EnumCultures(types);
+        }
+
+        private static CultureData CreateCultureWithInvariantData()
+        {
+            // Make a new culturedata
+            CultureData invariant = new CultureData();
+
+            // Basics
+            // Note that we override the resources since this IS NOT supposed to change (by definition)
+            invariant._bUseOverrides = false;
+            invariant._sRealName = "";                     // Name you passed in (ie: en-US, en, or de-DE_phoneb)
+            invariant._sWindowsName = "";                     // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in))
+
+            // Identity
+            invariant._sName = "";                     // locale name (ie: en-us)
+            invariant._sParent = "";                     // Parent name (which may be a custom locale/culture)
+            invariant._bNeutral = false;                   // Flags for the culture (ie: neutral or not right now)
+            invariant._sEnglishDisplayName = "Invariant Language (Invariant Country)"; // English pretty name for this locale
+            invariant._sNativeDisplayName = "Invariant Language (Invariant Country)";  // Native pretty name for this locale
+            invariant._sSpecificCulture = "";                     // The culture name to be used in CultureInfo.CreateSpecificCulture()
+
+            // Language
+            invariant._sISO639Language = "iv";                   // ISO 639 Language Name
+            invariant._sISO639Language2 = "ivl";                  // 3 char ISO 639 lang name 2
+            invariant._sLocalizedLanguage = "Invariant Language";   // Display name for this Language
+            invariant._sEnglishLanguage = "Invariant Language";   // English name for this language
+            invariant._sNativeLanguage = "Invariant Language";   // Native name of this language
+            invariant._sAbbrevLang = "IVL";                  // abbreviated language name (Windows Language Name)
+            invariant._sConsoleFallbackName = "";            // The culture name for the console fallback UI culture
+            invariant._iInputLanguageHandle = 0x07F;         // input language handle
+
+            // Region
+            invariant._sRegionName = "IV";                    // (RegionInfo)
+            invariant._sEnglishCountry = "Invariant Country"; // english country name (RegionInfo)
+            invariant._sNativeCountry = "Invariant Country";  // native country name (Windows Only)
+            invariant._sISO3166CountryName = "IV";            // (RegionInfo), ie: US
+            invariant._sISO3166CountryName2 = "ivc";          // 3 char ISO 3166 country name 2 2(RegionInfo)
+            invariant._iGeoId = 244;                          // GeoId (Windows Only)
+
+            // Numbers
+            invariant._sPositiveSign = "+";                    // positive sign
+            invariant._sNegativeSign = "-";                    // negative sign
+            invariant._iDigits = 2;                      // number of fractional digits
+            invariant._iNegativeNumber = 1;                      // negative number format
+            invariant._waGrouping = new int[] { 3 };          // grouping of digits
+            invariant._sDecimalSeparator = ".";                    // decimal separator
+            invariant._sThousandSeparator = ",";                    // thousands separator
+            invariant._sNaN = "NaN";                  // Not a Number
+            invariant._sPositiveInfinity = "Infinity";             // + Infinity
+            invariant._sNegativeInfinity = "-Infinity";            // - Infinity
+
+            // Percent
+            invariant._iNegativePercent = 0;                      // Negative Percent (0-3)
+            invariant._iPositivePercent = 0;                      // Positive Percent (0-11)
+            invariant._sPercent = "%";                    // Percent (%) symbol
+            invariant._sPerMille = "\x2030";               // PerMille symbol
+
+            // Currency
+            invariant._sCurrency = "\x00a4";                // local monetary symbol: for international monetary symbol
+            invariant._sIntlMonetarySymbol = "XDR";                  // international monetary symbol (RegionInfo)
+            invariant._sEnglishCurrency = "International Monetary Fund"; // English name for this currency (Windows Only)
+            invariant._sNativeCurrency = "International Monetary Fund"; // Native name for this currency (Windows Only)
+            invariant._iCurrencyDigits = 2;                      // # local monetary fractional digits
+            invariant._iCurrency = 0;                      // positive currency format
+            invariant._iNegativeCurrency = 0;                      // negative currency format
+            invariant._waMonetaryGrouping = new int[] { 3 };          // monetary grouping of digits
+            invariant._sMonetaryDecimal = ".";                    // monetary decimal separator
+            invariant._sMonetaryThousand = ",";                    // monetary thousands separator
+
+            // Misc
+            invariant._iMeasure = 0;                      // system of measurement 0=metric, 1=US (RegionInfo)
+            invariant._sListSeparator = ",";                    // list separator
+
+            // Time
+            invariant._sTimeSeparator = ":";
+            invariant._sAM1159 = "AM";                   // AM designator
+            invariant._sPM2359 = "PM";                   // PM designator
+            invariant._saLongTimes = new String[] { "HH:mm:ss" };                             // time format
+            invariant._saShortTimes = new String[] { "HH:mm", "hh:mm tt", "H:mm", "h:mm tt" }; // short time format
+            invariant._saDurationFormats = new String[] { "HH:mm:ss" };                             // time duration format
+
+
+            // Calendar specific data
+            invariant._iFirstDayOfWeek = 0;                      // first day of week
+            invariant._iFirstWeekOfYear = 0;                      // first week of year
+            invariant._waCalendars = new CalendarId[] { CalendarId.GREGORIAN };       // all available calendar type(s).  The first one is the default calendar
+
+            // Store for specific data about each calendar
+            invariant._calendars = new CalendarData[CalendarData.MAX_CALENDARS];
+            invariant._calendars[0] = CalendarData.Invariant;
+
+            // Text information
+            invariant._iReadingLayout = 0;
+
+            // These are desktop only, not coreclr
+
+            invariant._iLanguage = CultureInfo.LOCALE_INVARIANT;   // locale ID (0409) - NO sort information
+            invariant._iDefaultAnsiCodePage = 1252;         // default ansi code page ID (ACP)
+            invariant._iDefaultOemCodePage = 437;           // default oem code page ID (OCP or OEM)
+            invariant._iDefaultMacCodePage = 10000;         // default macintosh code page
+            invariant._iDefaultEbcdicCodePage = 037;        // default EBCDIC code page
+
+            if (GlobalizationMode.Invariant)
+            {
+                invariant._sLocalizedDisplayName = invariant._sNativeDisplayName;
+                invariant._sLocalizedCountry = invariant._sNativeCountry;
+            }
+
+            return invariant;
+        }
 
-            if (nativeEnumCultureNames((int)types, JitHelpers.GetObjectHandleOnStack(ref cultureNames)) == 0)
+        /////////////////////////////////////////////////////////////////////////
+        // Build our invariant information
+        //
+        // We need an invariant instance, which we build hard-coded
+        /////////////////////////////////////////////////////////////////////////
+        internal static CultureData Invariant
+        {
+            get
             {
-                return new CultureInfo[0];
+                if (s_Invariant == null)
+                {
+                    // Remember it
+                    s_Invariant = CreateCultureWithInvariantData();
+                }
+                return s_Invariant;
             }
+        }
+        private volatile static CultureData s_Invariant;
 
-            int arrayLength = cultureNames.Length;
+        ///////////////
+        // Constructors //
+        ///////////////
+        // Cache of cultures we've already looked up
+        private static volatile StringCultureDataDictionary s_cachedCultures;
+        private static readonly Lock s_lock = new Lock();
 
-            CultureInfo[] cultures = new CultureInfo[arrayLength];
+        internal static CultureData GetCultureData(String cultureName, bool useUserOverride)
+        {
+            // First do a shortcut for Invariant
+            if (String.IsNullOrEmpty(cultureName))
+            {
+                return CultureData.Invariant;
+            }
 
-            for (int i = 0; i < cultureNames.Length; i++)
+            // Try the hash table first
+            String hashName = AnsiToLower(useUserOverride ? cultureName : cultureName + '*');
+            StringCultureDataDictionary tempHashTable = s_cachedCultures;
+            if (tempHashTable == null)
             {
-                cultures[i] = new CultureInfo(cultureNames[i]);
+                // No table yet, make a new one
+                tempHashTable = new StringCultureDataDictionary();
+            }
+            else
+            {
+                // Check the hash table
+                bool ret;
+                CultureData retVal;
+                lock (s_lock)
+                {
+                    ret = tempHashTable.TryGetValue(hashName, out retVal);
+                }
+                if (ret && retVal != null)
+                {
+                    return retVal;
+                }
             }
-#pragma warning restore 618
 
-            return cultures;
-        }
+            // Not found in the hash table, need to see if we can build one that works for us
+            CultureData culture = CreateCultureData(cultureName, useUserOverride);
+            if (culture == null)
+            {
+                return null;
+            }
+
+            // Found one, add it to the cache
+            lock (s_lock)
+            {
+                tempHashTable[hashName] = culture;
+            }
+
+            // Copy the hashtable to the corresponding member variables.  This will potentially overwrite
+            // new tables simultaneously created by a new thread, but maximizes thread safety.
+            s_cachedCultures = tempHashTable;
 
-        internal static volatile CultureInfo[] specificCultures;
+            return culture;
+        }
 
-        private static CultureInfo[] SpecificCultures
+        private static string NormalizeCultureName(string name, out bool isNeutralName)
         {
-            get
+            isNeutralName = true;
+            int i = 0;
+
+            if (name.Length > LOCALE_NAME_MAX_LENGTH)
             {
-                if (specificCultures == null)
-                    specificCultures = GetCultures(CultureTypes.SpecificCultures);
+                // Theoretically we shouldn't hit this exception.
+                throw new ArgumentException(SR.Format(SR.Argument_InvalidId, nameof(name)));
+            }
+
+            Span<char> normalizedName = stackalloc char[name.Length];
 
-                return specificCultures;
+            bool changed = false;
+
+            while (i < name.Length && name[i] != '-' && name[i] != '_')
+            {
+                if (name[i] >= 'A' && name[i] <= 'Z')
+                {
+                    // lowercase characters before '-'
+                    normalizedName[i] = (char) (((int)name[i]) + 0x20);
+                    changed = true;
+                }
+                else
+                {
+                    normalizedName[i] = name[i];
+                }
+                i++;
             }
+
+            if (i < name.Length)
+            {
+                // this is not perfect to detect the non neutral cultures but it is good enough when we are running in invariant mode
+                isNeutralName = false;
+            }
+
+            while (i < name.Length)
+            {
+                if (name[i] >= 'a' && name[i] <= 'z')
+                {
+                    normalizedName[i] = (char) (((int)name[i]) - 0x20);
+                    changed = true;
+                }
+                else
+                {
+                    normalizedName[i] = name[i];
+                }
+                i++;
+            }
+
+            if (changed)
+                return new string(normalizedName);
+
+            return name;
         }
 
-        internal bool IsReplacementCulture
+        private static CultureData CreateCultureData(string cultureName, bool useUserOverride)
         {
-            get
+            if (GlobalizationMode.Invariant)
             {
-                return IsReplacementCultureName(this.SNAME);
+                if (cultureName.Length > LOCALE_NAME_MAX_LENGTH || !CultureInfo.VerifyCultureName(cultureName, false))
+                {
+                    return null;
+                }
+                CultureData cd = CreateCultureWithInvariantData();
+                cd._bUseOverrides = useUserOverride;
+                cd._sName = NormalizeCultureName(cultureName, out cd._bNeutral);
+                cd._sRealName = cd._sName;
+                cd._sWindowsName = cd._sName;
+                cd._iLanguage = CultureInfo.LOCALE_CUSTOM_UNSPECIFIED;
+
+                return cd;
             }
-        }
 
-        internal static volatile String[] s_replacementCultureNames;
+            CultureData culture = new CultureData();
+            culture._bUseOverrides = useUserOverride;
+            culture._sRealName = cultureName;
 
-        ////////////////////////////////////////////////////////////////////////
-        //
-        // Cache for the known replacement cultures.
-        // This is used by CultureInfo.CultureType to check if a culture is a
-        // replacement culture.
-        //
-        ////////////////////////////////////////////////////////////////////////
+            // Ask native code if that one's real
+            if (culture.InitCultureData() == false)
+            {
+                if (culture.InitCompatibilityCultureData() == false)
+                {
+                    return null;
+                }
+            }
 
+            return culture;
+        }
 
-        private static bool IsReplacementCultureName(String name)
+        private bool InitCompatibilityCultureData()
         {
-            Debug.Assert(name != null, "IsReplacementCultureName(): name should not be null");
-            String[] replacementCultureNames = s_replacementCultureNames;
-            if (replacementCultureNames == null)
+            // for compatibility handle the deprecated ids: zh-chs, zh-cht
+            string cultureName = _sRealName;
+
+            string fallbackCultureName;
+            string realCultureName;
+            switch (AnsiToLower(cultureName))
             {
-                if (nativeEnumCultureNames((int)CultureTypes.ReplacementCultures, JitHelpers.GetObjectHandleOnStack(ref replacementCultureNames)) == 0)
-                {
+                case "zh-chs":
+                    fallbackCultureName = "zh-Hans";
+                    realCultureName = "zh-CHS";
+                    break;
+                case "zh-cht":
+                    fallbackCultureName = "zh-Hant";
+                    realCultureName = "zh-CHT";
+                    break;
+                default:
                     return false;
-                }
+            }
 
-                // Even if we don't have any replacement cultures, the returned replacementCultureNames will still an empty string array, not null.
-                Debug.Assert(name != null, "IsReplacementCultureName(): replacementCultureNames should not be null");
-                Array.Sort(replacementCultureNames);
-                s_replacementCultureNames = replacementCultureNames;
+            _sRealName = fallbackCultureName;
+            if (InitCultureData() == false)
+            {
+                return false;
             }
-            return Array.BinarySearch(replacementCultureNames, name) >= 0;
+            // fixup our data
+            _sName = realCultureName; // the name that goes back to the user
+            _sParent = fallbackCultureName;
+
+            return true;
+        }
+
+        // We'd rather people use the named version since this doesn't allow custom locales
+        internal static CultureData GetCultureData(int culture, bool bUseUserOverride)
+        {
+            string localeName = null;
+            CultureData retVal = null;
+
+            if (culture == CultureInfo.LOCALE_INVARIANT)
+                return Invariant;
+
+            if (GlobalizationMode.Invariant)
+            {
+                // LCID is not supported in the InvariantMode
+                throw new CultureNotFoundException(nameof(culture), culture, SR.Argument_CultureNotSupported);
+            }
+
+            // Convert the lcid to a name, then use that
+            // Note that this will return neutral names (unlike Vista native API)
+            localeName = LCIDToLocaleName(culture);
+
+            if (!String.IsNullOrEmpty(localeName))
+            {
+                // Valid name, use it
+                retVal = GetCultureData(localeName, bUseUserOverride);
+            }
+
+            // If not successful, throw
+            if (retVal == null)
+                throw new CultureNotFoundException(nameof(culture), culture, SR.Argument_CultureNotSupported);
+
+            // Return the one we found
+            return retVal;
         }
 
         ////////////////////////////////////////////////////////////////////////
@@ -826,17 +799,17 @@ namespace System.Globalization
         {
             get
             {
-                Debug.Assert(this.sRealName != null, "[CultureData.CultureName] Expected this.sRealName to be populated by COMNlsInfo::nativeInitCultureData already");
+                Debug.Assert(_sRealName != null, "[CultureData.CultureName] Expected _sRealName to be populated by already");
                 // since windows doesn't know about zh-CHS and zh-CHT,
                 // we leave sRealName == zh-Hanx but we still need to
                 // pretend that it was zh-CHX.
-                switch (this.sName)
+                switch (_sName)
                 {
                     case "zh-CHS":
                     case "zh-CHT":
-                        return this.sName;
+                        return _sName;
                 }
-                return this.sRealName;
+                return _sRealName;
             }
         }
 
@@ -845,7 +818,7 @@ namespace System.Globalization
         {
             get
             {
-                return this.bUseOverrides;
+                return _bUseOverrides;
             }
         }
 
@@ -854,13 +827,11 @@ namespace System.Globalization
         {
             get
             {
-                //                Debug.Assert(this.sName != null,
-                //                    "[CultureData.SNAME] Expected this.sName to be populated by COMNlsInfo::nativeInitCultureData already");
-                if (this.sName == null)
+                if (_sName == null)
                 {
-                    this.sName = String.Empty;
+                    _sName = String.Empty;
                 }
-                return this.sName;
+                return _sName;
             }
         }
 
@@ -869,12 +840,12 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sParent == null)
+                if (_sParent == null)
                 {
                     // Ask using the real name, so that we get parents of neutrals
-                    this.sParent = DoGetLocaleInfo(this.sRealName, LOCALE_SPARENT);
+                    _sParent = GetLocaleInfo(_sRealName, LocaleStringData.ParentName);
                 }
-                return this.sParent;
+                return _sParent;
             }
         }
 
@@ -883,31 +854,73 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sLocalizedDisplayName == null)
+                if (_sLocalizedDisplayName == null)
                 {
+                    if (this.IsSupplementalCustomCulture)
+                    {
+                        if (this.IsNeutralCulture)
+                        {
+                            _sLocalizedDisplayName = this.SNATIVELANGUAGE;
+                        }
+                        else
+                        {
+                            _sLocalizedDisplayName = this.SNATIVEDISPLAYNAME;
+                        }
+                    }
+                    else
+                    {
+                        try
+                        {
+                            const string ZH_CHT = "zh-CHT";
+                            const string ZH_CHS = "zh-CHS";
+
+                            if (SNAME.Equals(ZH_CHT, StringComparison.OrdinalIgnoreCase))
+                            {
+                                _sLocalizedDisplayName = GetLanguageDisplayName("zh-Hant");
+                            }
+                            else if (SNAME.Equals(ZH_CHS, StringComparison.OrdinalIgnoreCase))
+                            {
+                                _sLocalizedDisplayName = GetLanguageDisplayName("zh-Hans");
+                            }
+                            else
+                            {
+                                _sLocalizedDisplayName = GetLanguageDisplayName(SNAME);
+                            }
+                        }
+                        catch (Exception)
+                        {
+                            // do nothing
+                        }
+                    }
                     // If it hasn't been found (Windows 8 and up), fallback to the system
-                    if (String.IsNullOrEmpty(this.sLocalizedDisplayName))
+                    if (String.IsNullOrEmpty(_sLocalizedDisplayName))
                     {
                         // If its neutral use the language name
                         if (this.IsNeutralCulture)
                         {
-                            this.sLocalizedDisplayName = this.SLOCALIZEDLANGUAGE;
+                            _sLocalizedDisplayName = this.SLOCALIZEDLANGUAGE;
                         }
                         else
                         {
-                            // We have to make the neutral distinction in case the OS returns a specific name
-                            if (CultureInfo.UserDefaultUICulture.Name.Equals(Thread.CurrentThread.CurrentUICulture.Name))
+                            // Usually the UI culture shouldn't be different than what we got from WinRT except
+                            // if DefaultThreadCurrentUICulture was set
+                            CultureInfo ci;
+
+                            if (CultureInfo.DefaultThreadCurrentUICulture != null &&
+                                ((ci = GetUserDefaultCulture()) != null) &&
+                                !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name))
                             {
-                                this.sLocalizedDisplayName = DoGetLocaleInfo(LOCALE_SLOCALIZEDDISPLAYNAME);
+                                _sLocalizedDisplayName = this.SNATIVEDISPLAYNAME;
                             }
-                            if (String.IsNullOrEmpty(this.sLocalizedDisplayName))
+                            else
                             {
-                                this.sLocalizedDisplayName = this.SNATIVEDISPLAYNAME;
+                                _sLocalizedDisplayName = GetLocaleInfo(LocaleStringData.LocalizedDisplayName);
                             }
                         }
                     }
                 }
-                return this.sLocalizedDisplayName;
+
+                return _sLocalizedDisplayName;
             }
         }
 
@@ -916,39 +929,47 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sEnglishDisplayName == null)
+                if (_sEnglishDisplayName == null)
                 {
                     // If its neutral use the language name
                     if (this.IsNeutralCulture)
                     {
-                        this.sEnglishDisplayName = this.SENGLISHLANGUAGE;
+                        _sEnglishDisplayName = this.SENGLISHLANGUAGE;
+                        // differentiate the legacy display names
+                        switch (_sName)
+                        {
+                            case "zh-CHS":
+                            case "zh-CHT":
+                                _sEnglishDisplayName += " Legacy";
+                                break;
+                        }
                     }
                     else
                     {
-                        this.sEnglishDisplayName = DoGetLocaleInfo(LOCALE_SENGLISHDISPLAYNAME);
+                        _sEnglishDisplayName = GetLocaleInfo(LocaleStringData.EnglishDisplayName);
 
                         // if it isn't found build one:
-                        if (String.IsNullOrEmpty(this.sEnglishDisplayName))
+                        if (String.IsNullOrEmpty(_sEnglishDisplayName))
                         {
                             // Our existing names mostly look like:
                             // "English" + "United States" -> "English (United States)"
                             // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)"
-                            if (this.SENGLISHLANGUAGE.EndsWith(')'))
+                            if (this.SENGLISHLANGUAGE[this.SENGLISHLANGUAGE.Length - 1] == ')')
                             {
                                 // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)"
-                                this.sEnglishDisplayName =
-                                    this.SENGLISHLANGUAGE.Substring(0, this.sEnglishLanguage.Length - 1) +
+                                _sEnglishDisplayName =
+                                    this.SENGLISHLANGUAGE.Substring(0, _sEnglishLanguage.Length - 1) +
                                     ", " + this.SENGCOUNTRY + ")";
                             }
                             else
                             {
                                 // "English" + "United States" -> "English (United States)"
-                                this.sEnglishDisplayName = this.SENGLISHLANGUAGE + " (" + this.SENGCOUNTRY + ")";
+                                _sEnglishDisplayName = this.SENGLISHLANGUAGE + " (" + this.SENGCOUNTRY + ")";
                             }
                         }
                     }
                 }
-                return this.sEnglishDisplayName;
+                return _sEnglishDisplayName;
             }
         }
 
@@ -957,37 +978,47 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sNativeDisplayName == null)
+                if (_sNativeDisplayName == null)
                 {
                     // If its neutral use the language name
                     if (this.IsNeutralCulture)
                     {
-                        this.sNativeDisplayName = this.SNATIVELANGUAGE;
+                        _sNativeDisplayName = this.SNATIVELANGUAGE;
+                        // differentiate the legacy display names
+                        switch (_sName)
+                        {
+                            case "zh-CHS":
+                                _sNativeDisplayName += " \u65E7\u7248";
+                                break;
+                            case "zh-CHT":
+                                _sNativeDisplayName += " \u820A\u7248";
+                                break;
+                        }
                     }
                     else
                     {
-                        this.sNativeDisplayName = DoGetLocaleInfo(LOCALE_SNATIVEDISPLAYNAME);
+                        _sNativeDisplayName = GetLocaleInfo(LocaleStringData.NativeDisplayName);
 
                         // if it isn't found build one:
-                        if (String.IsNullOrEmpty(this.sNativeDisplayName))
+                        if (String.IsNullOrEmpty(_sNativeDisplayName))
                         {
                             // These should primarily be "Deutsch (Deutschland)" type names
-                            this.sNativeDisplayName = this.SNATIVELANGUAGE + " (" + this.SNATIVECOUNTRY + ")";
+                            _sNativeDisplayName = this.SNATIVELANGUAGE + " (" + this.SNATIVECOUNTRY + ")";
                         }
                     }
                 }
-                return this.sNativeDisplayName;
+                return _sNativeDisplayName;
             }
         }
 
         // The culture name to be used in CultureInfo.CreateSpecificCulture()
-        internal String SSPECIFICCULTURE
+        internal string SSPECIFICCULTURE
         {
             get
             {
-                // This got populated when ComNlsInfo::nativeInitCultureData told us we had a culture
-                Debug.Assert(this.sSpecificCulture != null, "[CultureData.SSPECIFICCULTURE] Expected this.sSpecificCulture to be populated by COMNlsInfo::nativeInitCultureData already");
-                return this.sSpecificCulture;
+                // This got populated during the culture initialization
+                Debug.Assert(_sSpecificCulture != null, "[CultureData.SSPECIFICCULTURE] Expected this.sSpecificCulture to be populated by culture data initialization already");
+                return _sSpecificCulture;
             }
         }
 
@@ -1000,37 +1031,37 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sISO639Language == null)
+                if (_sISO639Language == null)
                 {
-                    this.sISO639Language = DoGetLocaleInfo(LOCALE_SISO639LANGNAME);
+                    _sISO639Language = GetLocaleInfo(LocaleStringData.Iso639LanguageTwoLetterName);
                 }
-                return this.sISO639Language;
+                return _sISO639Language;
             }
         }
 
         // iso 639 language name, ie: eng
-        internal String SISO639LANGNAME2
+        internal string SISO639LANGNAME2
         {
             get
             {
-                if (this.sISO639Language2 == null)
+                if (_sISO639Language2 == null)
                 {
-                    this.sISO639Language2 = DoGetLocaleInfo(LOCALE_SISO639LANGNAME2);
+                    _sISO639Language2 = GetLocaleInfo(LocaleStringData.Iso639LanguageThreeLetterName);
                 }
-                return this.sISO639Language2;
+                return _sISO639Language2;
             }
         }
 
         // abbreviated windows language name (ie: enu) (non-standard, avoid this)
-        internal String SABBREVLANGNAME
+        internal string SABBREVLANGNAME
         {
             get
             {
-                if (this.sAbbrevLang == null)
+                if (_sAbbrevLang == null)
                 {
-                    this.sAbbrevLang = DoGetLocaleInfo(LOCALE_SABBREVLANGNAME);
+                    _sAbbrevLang = GetThreeLetterWindowsLanguageName(_sRealName);
                 }
-                return this.sAbbrevLang;
+                return _sAbbrevLang;
             }
         }
 
@@ -1040,20 +1071,25 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sLocalizedLanguage == null)
+                if (_sLocalizedLanguage == null)
                 {
-                    if (CultureInfo.UserDefaultUICulture.Name.Equals(Thread.CurrentThread.CurrentUICulture.Name))
+                    // Usually the UI culture shouldn't be different than what we got from WinRT except
+                    // if DefaultThreadCurrentUICulture was set
+                    CultureInfo ci;
+
+                    if (CultureInfo.DefaultThreadCurrentUICulture != null &&
+                        ((ci = GetUserDefaultCulture()) != null) &&
+                        !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name))
                     {
-                        this.sLocalizedLanguage = DoGetLocaleInfo(LOCALE_SLOCALIZEDLANGUAGENAME);
+                        _sLocalizedLanguage = SNATIVELANGUAGE;
                     }
-                    // Some OS's might not have this resource or LCTYPE
-                    if (String.IsNullOrEmpty(this.sLocalizedLanguage))
+                    else
                     {
-                        this.sLocalizedLanguage = SNATIVELANGUAGE;
+                        _sLocalizedLanguage = GetLocaleInfo(LocaleStringData.LocalizedLanguageName);
                     }
                 }
 
-                return this.sLocalizedLanguage;
+                return _sLocalizedLanguage;
             }
         }
 
@@ -1062,11 +1098,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sEnglishLanguage == null)
+                if (_sEnglishLanguage == null)
                 {
-                    this.sEnglishLanguage = DoGetLocaleInfo(LOCALE_SENGLISHLANGUAGENAME);
+                    _sEnglishLanguage = GetLocaleInfo(LocaleStringData.EnglishLanguageName);
                 }
-                return this.sEnglishLanguage;
+                return _sEnglishLanguage;
             }
         }
 
@@ -1075,13 +1111,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sNativeLanguage == null)
+                if (_sNativeLanguage == null)
                 {
-                    {
-                        this.sNativeLanguage = DoGetLocaleInfo(LOCALE_SNATIVELANGUAGENAME);
-                    }
+                    _sNativeLanguage = GetLocaleInfo(LocaleStringData.NativeLanguageName);
                 }
-                return this.sNativeLanguage;
+                return _sNativeLanguage;
             }
         }
 
@@ -1094,24 +1128,23 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sRegionName == null)
+                if (_sRegionName == null)
                 {
-                    this.sRegionName = DoGetLocaleInfo(LOCALE_SISO3166CTRYNAME);
+                    _sRegionName = GetLocaleInfo(LocaleStringData.Iso3166CountryName);
                 }
-                return this.sRegionName;
+                return _sRegionName;
             }
         }
 
-        // GeoId
         internal int IGEOID
         {
             get
             {
-                if (this.iGeoId == undef)
+                if (_iGeoId == undef)
                 {
-                    this.iGeoId = DoGetLocaleInfoInt(LOCALE_IGEOID);
+                    _iGeoId = GetGeoId(_sRealName);
                 }
-                return this.iGeoId;
+                return _iGeoId;
             }
         }
 
@@ -1120,23 +1153,23 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sLocalizedCountry == null)
+                if (_sLocalizedCountry == null)
                 {
-                    // If it hasn't been found (Windows 8 and up), fallback to the system
-                    if (String.IsNullOrEmpty(this.sLocalizedCountry))
+                    try
                     {
-                        // We have to make the neutral distinction in case the OS returns a specific name
-                        if (CultureInfo.UserDefaultUICulture.Name.Equals(Thread.CurrentThread.CurrentUICulture.Name))
-                        {
-                            this.sLocalizedCountry = DoGetLocaleInfo(LOCALE_SLOCALIZEDCOUNTRYNAME);
-                        }
-                        if (String.IsNullOrEmpty(this.sLocalizedDisplayName))
-                        {
-                            this.sLocalizedCountry = SNATIVECOUNTRY;
-                        }
+                        _sLocalizedCountry = GetRegionDisplayName(SISO3166CTRYNAME);
+                    }
+                    catch (Exception)
+                    {
+                        // do nothing. we'll fallback
+                    }
+
+                    if (_sLocalizedCountry == null)
+                    {
+                        _sLocalizedCountry = SNATIVECOUNTRY;
                     }
                 }
-                return this.sLocalizedCountry;
+                return _sLocalizedCountry;
             }
         }
 
@@ -1145,11 +1178,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sEnglishCountry == null)
+                if (_sEnglishCountry == null)
                 {
-                    this.sEnglishCountry = DoGetLocaleInfo(LOCALE_SENGLISHCOUNTRYNAME);
+                    _sEnglishCountry = GetLocaleInfo(LocaleStringData.EnglishCountryName);
                 }
-                return this.sEnglishCountry;
+                return _sEnglishCountry;
             }
         }
 
@@ -1158,11 +1191,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sNativeCountry == null)
+                if (_sNativeCountry == null)
                 {
-                    this.sNativeCountry = DoGetLocaleInfo(LOCALE_SNATIVECOUNTRYNAME);
+                    _sNativeCountry = GetLocaleInfo(LocaleStringData.NativeCountryName);
                 }
-                return this.sNativeCountry;
+                return _sNativeCountry;
             }
         }
 
@@ -1171,90 +1204,70 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sISO3166CountryName == null)
+                if (_sISO3166CountryName == null)
                 {
-                    this.sISO3166CountryName = DoGetLocaleInfo(LOCALE_SISO3166CTRYNAME);
+                    _sISO3166CountryName = GetLocaleInfo(LocaleStringData.Iso3166CountryName);
                 }
-                return this.sISO3166CountryName;
+                return _sISO3166CountryName;
             }
         }
 
-        // ISO 3166 Country Name
+        // 3 letter ISO 3166 country code
         internal String SISO3166CTRYNAME2
         {
             get
             {
-                if (this.sISO3166CountryName2 == null)
-                {
-                    this.sISO3166CountryName2 = DoGetLocaleInfo(LOCALE_SISO3166CTRYNAME2);
-                }
-                return this.sISO3166CountryName2;
-            }
-        }
-
-        // abbreviated Country Name (windows version, non-standard, avoid)
-        internal String SABBREVCTRYNAME
-        {
-            get
-            {
-                if (this.sAbbrevCountry == null)
+                if (_sISO3166CountryName2 == null)
                 {
-                    this.sAbbrevCountry = DoGetLocaleInfo(LOCALE_SABBREVCTRYNAME);
+                    _sISO3166CountryName2 = GetLocaleInfo(LocaleStringData.Iso3166CountryName2);
                 }
-                return this.sAbbrevCountry;
+                return _sISO3166CountryName2;
             }
         }
 
-        // Console fallback name (ie: locale to use for console apps for unicode-only locales)
         internal int IINPUTLANGUAGEHANDLE
         {
             get
             {
-                if (this.iInputLanguageHandle == undef)
+                if (_iInputLanguageHandle == undef)
                 {
                     if (IsSupplementalCustomCulture)
                     {
-                        this.iInputLanguageHandle = 0x0409;
+                        _iInputLanguageHandle = 0x0409;
                     }
                     else
                     {
                         // Input Language is same as LCID for built-in cultures
-                        this.iInputLanguageHandle = this.ILANGUAGE;
+                        _iInputLanguageHandle = this.ILANGUAGE;
                     }
                 }
-                return this.iInputLanguageHandle;
+                return _iInputLanguageHandle;
             }
         }
 
         // Console fallback name (ie: locale to use for console apps for unicode-only locales)
-        internal String SCONSOLEFALLBACKNAME
+        internal string SCONSOLEFALLBACKNAME
         {
             get
             {
-                if (this.sConsoleFallbackName == null)
+                if (_sConsoleFallbackName == null)
                 {
-                    string consoleFallbackName = DoGetLocaleInfo(LOCALE_SCONSOLEFALLBACKNAME);
-                    if (consoleFallbackName == "es-ES_tradnl")
-                    {
-                        consoleFallbackName = "es-ES";
-                    }
-                    this.sConsoleFallbackName = consoleFallbackName;
+                    _sConsoleFallbackName = GetConsoleFallbackName(_sRealName);
                 }
-                return this.sConsoleFallbackName;
+                return _sConsoleFallbackName;
             }
         }
 
-
         // (user can override) grouping of digits
         internal int[] WAGROUPING
         {
             get
             {
-                if (this.waGrouping == null || UseUserOverride)
+                if (_waGrouping == null)
                 {
-                    this.waGrouping = ConvertWin32GroupString(DoGetLocaleInfo(LOCALE_SGROUPING));
+                    _waGrouping = GetLocaleInfo(LocaleGroupingData.Digit);
                 }
-                return this.waGrouping;
+                return _waGrouping;
             }
         }
 
@@ -1267,11 +1280,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sNaN == null)
+                if (_sNaN == null)
                 {
-                    this.sNaN = DoGetLocaleInfo(LOCALE_SNAN);
+                    _sNaN = GetLocaleInfo(LocaleStringData.NaNSymbol);
                 }
-                return this.sNaN;
+                return _sNaN;
             }
         }
 
@@ -1280,11 +1293,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sPositiveInfinity == null)
+                if (_sPositiveInfinity == null)
                 {
-                    this.sPositiveInfinity = DoGetLocaleInfo(LOCALE_SPOSINFINITY);
+                    _sPositiveInfinity = GetLocaleInfo(LocaleStringData.PositiveInfinitySymbol);
                 }
-                return this.sPositiveInfinity;
+                return _sPositiveInfinity;
             }
         }
 
@@ -1293,11 +1306,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sNegativeInfinity == null)
+                if (_sNegativeInfinity == null)
                 {
-                    this.sNegativeInfinity = DoGetLocaleInfo(LOCALE_SNEGINFINITY);
+                    _sNegativeInfinity = GetLocaleInfo(LocaleStringData.NegativeInfinitySymbol);
                 }
-                return this.sNegativeInfinity;
+                return _sNegativeInfinity;
             }
         }
 
@@ -1311,12 +1324,12 @@ namespace System.Globalization
         {
             get
             {
-                if (this.iNegativePercent == undef)
+                if (_iNegativePercent == undef)
                 {
                     // Note that <= Windows Vista this is synthesized by native code
-                    this.iNegativePercent = DoGetLocaleInfoInt(LOCALE_INEGATIVEPERCENT);
+                    _iNegativePercent = GetLocaleInfo(LocaleNumberData.NegativePercentFormat);
                 }
-                return this.iNegativePercent;
+                return _iNegativePercent;
             }
         }
 
@@ -1325,12 +1338,12 @@ namespace System.Globalization
         {
             get
             {
-                if (this.iPositivePercent == undef)
+                if (_iPositivePercent == undef)
                 {
                     // Note that <= Windows Vista this is synthesized by native code
-                    this.iPositivePercent = DoGetLocaleInfoInt(LOCALE_IPOSITIVEPERCENT);
+                    _iPositivePercent = GetLocaleInfo(LocaleNumberData.PositivePercentFormat);
                 }
-                return this.iPositivePercent;
+                return _iPositivePercent;
             }
         }
 
@@ -1339,26 +1352,24 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sPercent == null)
+                if (_sPercent == null)
                 {
-                    // Note that <= Windows Vista this is synthesized by native code
-                    this.sPercent = DoGetLocaleInfo(LOCALE_SPERCENT);
+                    _sPercent = GetLocaleInfo(LocaleStringData.PercentSymbol);
                 }
-                return this.sPercent;
+                return _sPercent;
             }
         }
 
-        // PerMille (‰) symbol
+        // PerMille symbol
         internal String SPERMILLE
         {
             get
             {
-                if (this.sPerMille == null)
+                if (_sPerMille == null)
                 {
-                    // Note that <= Windows Vista this is synthesized by native code
-                    this.sPerMille = DoGetLocaleInfo(LOCALE_SPERMILLE);
+                    _sPerMille = GetLocaleInfo(LocaleStringData.PerMilleSymbol);
                 }
-                return this.sPerMille;
+                return _sPerMille;
             }
         }
 
@@ -1371,11 +1382,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sCurrency == null || UseUserOverride)
+                if (_sCurrency == null)
                 {
-                    this.sCurrency = DoGetLocaleInfo(LOCALE_SCURRENCY);
+                    _sCurrency = GetLocaleInfo(LocaleStringData.MonetarySymbol);
                 }
-                return this.sCurrency;
+                return _sCurrency;
             }
         }
 
@@ -1384,11 +1395,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sIntlMonetarySymbol == null)
+                if (_sIntlMonetarySymbol == null)
                 {
-                    this.sIntlMonetarySymbol = DoGetLocaleInfo(LOCALE_SINTLSYMBOL);
+                    _sIntlMonetarySymbol = GetLocaleInfo(LocaleStringData.Iso4217MonetarySymbol);
                 }
-                return this.sIntlMonetarySymbol;
+                return _sIntlMonetarySymbol;
             }
         }
 
@@ -1397,11 +1408,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sEnglishCurrency == null)
+                if (_sEnglishCurrency == null)
                 {
-                    this.sEnglishCurrency = DoGetLocaleInfo(LOCALE_SENGCURRNAME);
+                    _sEnglishCurrency = GetLocaleInfo(LocaleStringData.CurrencyEnglishName);
                 }
-                return this.sEnglishCurrency;
+                return _sEnglishCurrency;
             }
         }
 
@@ -1410,11 +1421,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sNativeCurrency == null)
+                if (_sNativeCurrency == null)
                 {
-                    this.sNativeCurrency = DoGetLocaleInfo(LOCALE_SNATIVECURRNAME);
+                    _sNativeCurrency = GetLocaleInfo(LocaleStringData.CurrencyNativeName);
                 }
-                return this.sNativeCurrency;
+                return _sNativeCurrency;
             }
         }
 
@@ -1427,31 +1438,24 @@ namespace System.Globalization
         {
             get
             {
-                if (this.waMonetaryGrouping == null || UseUserOverride)
+                if (_waMonetaryGrouping == null)
                 {
-                    this.waMonetaryGrouping = ConvertWin32GroupString(DoGetLocaleInfo(LOCALE_SMONGROUPING));
+                    _waMonetaryGrouping = GetLocaleInfo(LocaleGroupingData.Monetary);
                 }
-                return this.waMonetaryGrouping;
+                return _waMonetaryGrouping;
             }
         }
 
-        //                internal String sMonetaryDecimal         ; // (user can override) monetary decimal separator
-        //                internal String sMonetaryThousand        ; // (user can override) monetary thousands separator
-
-        /////////
-        // Misc //
-        /////////
-
         // (user can override) system of measurement 0=metric, 1=US (RegionInfo)
         internal int IMEASURE
         {
             get
             {
-                if (this.iMeasure == undef || UseUserOverride)
+                if (_iMeasure == undef)
                 {
-                    this.iMeasure = DoGetLocaleInfoInt(LOCALE_IMEASURE);
+                    _iMeasure = GetLocaleInfo(LocaleNumberData.MeasurementSystem);
                 }
-                return this.iMeasure;
+                return _iMeasure;
             }
         }
 
@@ -1460,14 +1464,15 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sListSeparator == null || UseUserOverride)
+                if (_sListSeparator == null)
                 {
-                    this.sListSeparator = DoGetLocaleInfo(LOCALE_SLIST);
+                    _sListSeparator = GetLocaleInfo(LocaleStringData.ListSeparator);
                 }
-                return this.sListSeparator;
+                return _sListSeparator;
             }
         }
 
+
         ////////////////////////////
         // Calendar/Time (Gregorian) //
         ////////////////////////////
@@ -1477,11 +1482,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sAM1159 == null || UseUserOverride)
+                if (_sAM1159 == null)
                 {
-                    this.sAM1159 = DoGetLocaleInfo(LOCALE_S1159);
+                    _sAM1159 = GetLocaleInfo(LocaleStringData.AMDesignator);
                 }
-                return this.sAM1159;
+                return _sAM1159;
             }
         }
 
@@ -1490,11 +1495,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sPM2359 == null || UseUserOverride)
+                if (_sPM2359 == null)
                 {
-                    this.sPM2359 = DoGetLocaleInfo(LOCALE_S2359);
+                    _sPM2359 = GetLocaleInfo(LocaleStringData.PMDesignator);
                 }
-                return this.sPM2359;
+                return _sPM2359;
             }
         }
 
@@ -1503,32 +1508,38 @@ namespace System.Globalization
         {
             get
             {
-                if (this.saLongTimes == null || UseUserOverride)
+                if (_saLongTimes == null)
                 {
-                    String[] longTimes = DoEnumTimeFormats();
+                    Debug.Assert(!GlobalizationMode.Invariant);
+
+                    String[] longTimes = GetTimeFormats();
                     if (longTimes == null || longTimes.Length == 0)
                     {
-                        this.saLongTimes = Invariant.saLongTimes;
+                        _saLongTimes = Invariant._saLongTimes;
                     }
                     else
                     {
-                        this.saLongTimes = longTimes;
+                        _saLongTimes = longTimes;
                     }
                 }
-                return this.saLongTimes;
+                return _saLongTimes;
             }
         }
 
         // short time format
         // Short times (derived from long times format)
+        // TODO: NLS Arrowhead -  On Windows 7 we should have short times so this isn't necessary
         internal String[] ShortTimes
         {
             get
             {
-                if (this.saShortTimes == null || UseUserOverride)
+                if (_saShortTimes == null)
                 {
+                    Debug.Assert(!GlobalizationMode.Invariant);
+
                     // Try to get the short times from the OS/culture.dll
-                    String[] shortTimes = DoEnumShortTimeFormats();
+                    String[] shortTimes = null;
+                    shortTimes = GetShortTimeFormats();
 
                     if (shortTimes == null || shortTimes.Length == 0)
                     {
@@ -1539,13 +1550,24 @@ namespace System.Globalization
                         shortTimes = DeriveShortTimesFromLong();
                     }
 
+                    /* The above logic doesn't make sense on Mac, since the OS can provide us a "short time pattern".
+                     * currently this is the 4th element in the array returned by LongTimes.  We'll add this to our array
+                     * if it doesn't exist.
+                     */
+                    shortTimes = AdjustShortTimesForMac(shortTimes);
+
                     // Found short times, use them
-                    this.saShortTimes = shortTimes;
+                    _saShortTimes = shortTimes;
                 }
-                return this.saShortTimes;
+                return _saShortTimes;
             }
         }
 
+        private string[] AdjustShortTimesForMac(string[] shortTimes)
+        {
+            return shortTimes;
+        }
+
         private string[] DeriveShortTimesFromLong()
         {
             // Our logic is to look for h,H,m,s,t.  If we find an s, then we check the string
@@ -1611,13 +1633,19 @@ namespace System.Globalization
 
                         bool containsSpace;
                         int endIndex = GetIndexOfNextTokenAfterSeconds(time, j, out containsSpace);
-                        StringBuilder sb = new StringBuilder(time.Substring(0, j));
+
+                        string sep;
+
                         if (containsSpace)
                         {
-                            sb.Append(' ');
+                            sep = " ";
                         }
-                        sb.Append(time.Substring(endIndex));
-                        time = sb.ToString();
+                        else
+                        {
+                            sep = "";
+                        }
+
+                        time = time.Substring(0, j) + sep + time.Substring(endIndex);
                         break;
                     case 'm':
                     case 'H':
@@ -1670,12 +1698,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.iFirstDayOfWeek == undef || UseUserOverride)
+                if (_iFirstDayOfWeek == undef)
                 {
-                    // Have to convert it from windows to .Net formats
-                    this.iFirstDayOfWeek = ConvertFirstDayOfWeekMonToSun(DoGetLocaleInfoInt(LOCALE_IFIRSTDAYOFWEEK));
+                    _iFirstDayOfWeek = GetFirstDayOfWeek();
                 }
-                return this.iFirstDayOfWeek;
+                return _iFirstDayOfWeek;
             }
         }
 
@@ -1684,71 +1711,71 @@ namespace System.Globalization
         {
             get
             {
-                if (this.iFirstWeekOfYear == undef || UseUserOverride)
+                if (_iFirstWeekOfYear == undef)
                 {
-                    this.iFirstWeekOfYear = DoGetLocaleInfoInt(LOCALE_IFIRSTWEEKOFYEAR);
+                    _iFirstWeekOfYear = GetLocaleInfo(LocaleNumberData.FirstWeekOfYear);
                 }
-                return this.iFirstWeekOfYear;
+                return _iFirstWeekOfYear;
             }
         }
 
         // (user can override default only) short date format
-        internal String[] ShortDates(int calendarId)
+        internal String[] ShortDates(CalendarId calendarId)
         {
             return GetCalendar(calendarId).saShortDates;
         }
 
         // (user can override default only) long date format
-        internal String[] LongDates(int calendarId)
+        internal String[] LongDates(CalendarId calendarId)
         {
             return GetCalendar(calendarId).saLongDates;
         }
 
         // (user can override) date year/month format.
-        internal String[] YearMonths(int calendarId)
+        internal String[] YearMonths(CalendarId calendarId)
         {
             return GetCalendar(calendarId).saYearMonths;
         }
 
         // day names
-        internal string[] DayNames(int calendarId)
+        internal string[] DayNames(CalendarId calendarId)
         {
             return GetCalendar(calendarId).saDayNames;
         }
 
         // abbreviated day names
-        internal string[] AbbreviatedDayNames(int calendarId)
+        internal string[] AbbreviatedDayNames(CalendarId calendarId)
         {
             // Get abbreviated day names for this calendar from the OS if necessary
             return GetCalendar(calendarId).saAbbrevDayNames;
         }
 
         // The super short day names
-        internal string[] SuperShortDayNames(int calendarId)
+        internal string[] SuperShortDayNames(CalendarId calendarId)
         {
             return GetCalendar(calendarId).saSuperShortDayNames;
         }
 
         // month names
-        internal string[] MonthNames(int calendarId)
+        internal string[] MonthNames(CalendarId calendarId)
         {
             return GetCalendar(calendarId).saMonthNames;
         }
 
         // Genitive month names
-        internal string[] GenitiveMonthNames(int calendarId)
+        internal string[] GenitiveMonthNames(CalendarId calendarId)
         {
             return GetCalendar(calendarId).saMonthGenitiveNames;
         }
 
         // month names
-        internal string[] AbbreviatedMonthNames(int calendarId)
+        internal string[] AbbreviatedMonthNames(CalendarId calendarId)
         {
             return GetCalendar(calendarId).saAbbrevMonthNames;
         }
 
         // Genitive month names
-        internal string[] AbbreviatedGenitiveMonthNames(int calendarId)
+        internal string[] AbbreviatedGenitiveMonthNames(CalendarId calendarId)
         {
             return GetCalendar(calendarId).saAbbrevMonthGenitiveNames;
         }
@@ -1756,13 +1783,13 @@ namespace System.Globalization
         // Leap year month names
         // Note: This only applies to Hebrew, and it basically adds a "1" to the 6th month name
         // the non-leap names skip the 7th name in the normal month name array
-        internal string[] LeapYearMonthNames(int calendarId)
+        internal string[] LeapYearMonthNames(CalendarId calendarId)
         {
             return GetCalendar(calendarId).saLeapYearMonthNames;
         }
 
         // month/day format (single string, no override)
-        internal String MonthDay(int calendarId)
+        internal String MonthDay(CalendarId calendarId)
         {
             return GetCalendar(calendarId).sMonthDay;
         }
@@ -1774,29 +1801,30 @@ namespace System.Globalization
         /////////////
 
         // all available calendar type(s), The first one is the default calendar.
-        internal int[] CalendarIds
+        internal CalendarId[] CalendarIds
         {
             get
             {
-                if (this.waCalendars == null)
+                if (_waCalendars == null)
                 {
                     // We pass in an array of ints, and native side fills it up with count calendars.
                     // We then have to copy that list to a new array of the right size.
                     // Default calendar should be first
-                    int[] calendarInts = new int[23];
-                    Debug.Assert(this.sWindowsName != null, "[CultureData.CalendarIds] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
-                    int count = CalendarData.nativeGetCalendars(this.sWindowsName, this.bUseOverrides, calendarInts);
+                    CalendarId[] calendars = new CalendarId[23];
+                    Debug.Assert(_sWindowsName != null, "[CultureData.CalendarIds] Expected _sWindowsName to be populated by already");
+                    int count = CalendarData.GetCalendars(_sWindowsName, _bUseOverrides, calendars);
 
                     // See if we had a calendar to add.
                     if (count == 0)
                     {
                         // Failed for some reason, just grab Gregorian from Invariant
-                        this.waCalendars = Invariant.waCalendars;
+                        _waCalendars = Invariant._waCalendars;
                     }
                     else
                     {
                         // The OS may not return calendar 4 for zh-TW, but we've always allowed it.
-                        if (this.sWindowsName == "zh-TW")
+                        // TODO: Is this hack necessary long-term?
+                        if (_sWindowsName == "zh-TW")
                         {
                             bool found = false;
 
@@ -1804,7 +1832,7 @@ namespace System.Globalization
                             for (int i = 0; i < count; i++)
                             {
                                 // Stop if we found calendar four
-                                if (calendarInts[i] == Calendar.CAL_TAIWAN)
+                                if (calendars[i] == CalendarId.TAIWAN)
                                 {
                                     found = true;
                                     break;
@@ -1817,21 +1845,20 @@ namespace System.Globalization
                                 // Insert it as the 2nd calendar
                                 count++;
                                 // Copy them from the 2nd position to the end, -1 for skipping 1st, -1 for one being added.
-                                Array.Copy(calendarInts, 1, calendarInts, 2, 23 - 1 - 1);
-                                calendarInts[1] = Calendar.CAL_TAIWAN;
+                                Array.Copy(calendars, 1, calendars, 2, 23 - 1 - 1);
+                                calendars[1] = CalendarId.TAIWAN;
                             }
                         }
 
                         // It worked, remember the list
-                        int[] temp = new int[count];
-                        Array.Copy(calendarInts, temp, count);
+                        CalendarId[] temp = new CalendarId[count];
+                        Array.Copy(calendars, temp, count);
 
                         // Want 1st calendar to be default
                         // Prior to Vista the enumeration didn't have default calendar first
-                        // Only a coreclr concern, culture.dll does the right thing.
                         if (temp.Length > 1)
                         {
-                            int i = DoGetLocaleInfoInt(LOCALE_ICALENDARTYPE);
+                            CalendarId i = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType);
                             if (temp[1] == i)
                             {
                                 temp[1] = temp[0];
@@ -1839,45 +1866,45 @@ namespace System.Globalization
                             }
                         }
 
-                        this.waCalendars = temp;
+                        _waCalendars = temp;
                     }
                 }
 
-                return this.waCalendars;
+                return _waCalendars;
             }
         }
 
         // Native calendar names.  index of optional calendar - 1, empty if no optional calendar at that number
-        internal String CalendarName(int calendarId)
+        internal string CalendarName(CalendarId calendarId)
         {
             // Get the calendar
             return GetCalendar(calendarId).sNativeName;
         }
 
-        internal CalendarData GetCalendar(int calendarId)
+        internal CalendarData GetCalendar(CalendarId calendarId)
         {
-            Debug.Assert(calendarId > 0 && calendarId <= CalendarData.MAX_CALENDARS,
+            Debug.Assert(calendarId > 0 && calendarId <= CalendarId.LAST_CALENDAR,
                 "[CultureData.GetCalendar] Expect calendarId to be in a valid range");
 
             // arrays are 0 based, calendarIds are 1 based
-            int calendarIndex = calendarId - 1;
+            int calendarIndex = (int)calendarId - 1;
 
             // Have to have calendars
-            if (calendars == null)
+            if (_calendars == null)
             {
-                calendars = new CalendarData[CalendarData.MAX_CALENDARS];
+                _calendars = new CalendarData[CalendarData.MAX_CALENDARS];
             }
 
             // we need the following local variable to avoid returning null
             // when another thread creates a new array of CalendarData (above)
             // right after we insert the newly created CalendarData (below)
-            CalendarData calendarData = calendars[calendarIndex];
+            CalendarData calendarData = _calendars[calendarIndex];
             // Make sure that calendar has data
-            if (calendarData == null || UseUserOverride)
+            if (calendarData == null)
             {
-                Debug.Assert(this.sWindowsName != null, "[CultureData.GetCalendar] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
-                calendarData = new CalendarData(this.sWindowsName, calendarId, this.UseUserOverride);
-                calendars[calendarIndex] = calendarData;
+                Debug.Assert(_sWindowsName != null, "[CultureData.GetCalendar] Expected _sWindowsName to be populated by already");
+                calendarData = new CalendarData(_sWindowsName, calendarId, this.UseUserOverride);
+                _calendars[calendarIndex] = calendarData;
             }
 
             return calendarData;
@@ -1913,13 +1940,13 @@ namespace System.Globalization
         {
             get
             {
-                if (this.iReadingLayout == undef)
+                if (_iReadingLayout == undef)
                 {
-                    Debug.Assert(this.sRealName != null, "[CultureData.IsRightToLeft] Expected this.sRealName to be populated by COMNlsInfo::nativeInitCultureData already");
-                    this.iReadingLayout = DoGetLocaleInfoInt(LOCALE_IREADINGLAYOUT);
+                    Debug.Assert(_sRealName != null, "[CultureData.IsRightToLeft] Expected _sRealName to be populated by already");
+                    _iReadingLayout = GetLocaleInfo(LocaleNumberData.ReadingLayout);
                 }
 
-                return (this.iReadingLayout);
+                return (_iReadingLayout);
             }
         }
 
@@ -1934,23 +1961,10 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sTextInfo == null)
-                {
-                    // LOCALE_SSORTLOCALE is broken in Win7 for Alt sorts.
-                    // It is also not supported downlevel without culture.dll.
-                    if (IsNeutralCulture || IsSupplementalCustomCulture)
-                    {
-                        string sortLocale = DoGetLocaleInfo(LOCALE_SSORTLOCALE);
-                        this.sTextInfo = GetCultureData(sortLocale, bUseOverrides).SNAME;
-                    }
-
-                    if (this.sTextInfo == null)
-                    {
-                        this.sTextInfo = this.SNAME; // removes alternate sort
-                    }
-                }
-
-                return this.sTextInfo;
+                // Note: Custom cultures might point at another culture's textinfo, however windows knows how
+                // to redirect it to the desired textinfo culture, so this is OK.
+                Debug.Assert(_sRealName != null, "[CultureData.STEXTINFO] Expected _sRealName to be populated by already");
+                return (_sRealName);
             }
         }
 
@@ -1959,24 +1973,8 @@ namespace System.Globalization
         {
             get
             {
-                if (this.sCompareInfo == null)
-                {
-                    // LOCALE_SSORTLOCALE is broken in Win7 for Alt sorts.
-                    // It is also not supported downlevel without culture.dll.
-                    // We really only need it for the custom locale case though
-                    // since for all other cases, it is the same as sWindowsName
-                    if (IsSupplementalCustomCulture)
-                    {
-                        this.sCompareInfo = DoGetLocaleInfo(LOCALE_SSORTLOCALE);
-                    }
-
-                    if (this.sCompareInfo == null)
-                    {
-                        this.sCompareInfo = this.sWindowsName;
-                    }
-                }
-
-                return this.sCompareInfo;
+                Debug.Assert(_sRealName != null, "[CultureData.SCOMPAREINFO] Expected _sRealName to be populated by already");
+                return (_sRealName);
             }
         }
 
@@ -1988,16 +1986,15 @@ namespace System.Globalization
             }
         }
 
-
         internal int IDEFAULTANSICODEPAGE   // default ansi code page ID (ACP)
         {
             get
             {
-                if (this.iDefaultAnsiCodePage == undef)
+                if (_iDefaultAnsiCodePage == undef)
                 {
-                    this.iDefaultAnsiCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTANSICODEPAGE);
+                    _iDefaultAnsiCodePage = GetAnsiCodePage(_sRealName);
                 }
-                return this.iDefaultAnsiCodePage;
+                return _iDefaultAnsiCodePage;
             }
         }
 
@@ -2005,11 +2002,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.iDefaultOemCodePage == undef)
+                if (_iDefaultOemCodePage == undef)
                 {
-                    this.iDefaultOemCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTCODEPAGE);
+                    _iDefaultOemCodePage = GetOemCodePage(_sRealName);
                 }
-                return this.iDefaultOemCodePage;
+                return _iDefaultOemCodePage;
             }
         }
 
@@ -2017,11 +2014,11 @@ namespace System.Globalization
         {
             get
             {
-                if (this.iDefaultMacCodePage == undef)
+                if (_iDefaultMacCodePage == undef)
                 {
-                    this.iDefaultMacCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTMACCODEPAGE);
+                    _iDefaultMacCodePage = GetMacCodePage(_sRealName);
                 }
-                return this.iDefaultMacCodePage;
+                return _iDefaultMacCodePage;
             }
         }
 
@@ -2029,54 +2026,33 @@ namespace System.Globalization
         {
             get
             {
-                if (this.iDefaultEbcdicCodePage == undef)
+                if (_iDefaultEbcdicCodePage == undef)
                 {
-                    this.iDefaultEbcdicCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTEBCDICCODEPAGE);
+                    _iDefaultEbcdicCodePage = GetEbcdicCodePage(_sRealName);
                 }
-                return this.iDefaultEbcdicCodePage;
+                return _iDefaultEbcdicCodePage;
             }
         }
 
-        // Obtain locale name from LCID
-        // NOTE: This will get neutral names, unlike the OS API
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        internal static extern int LocaleNameToLCID(String localeName);
-
-        // These are desktop only, not coreclr
-        // locale ID (0409), including sort information
         internal int ILANGUAGE
         {
             get
             {
-                if (this.iLanguage == 0)
+                if (_iLanguage == 0)
                 {
-                    Debug.Assert(this.sRealName != null, "[CultureData.ILANGUAGE] Expected this.sRealName to be populated by COMNlsInfo::nativeInitCultureData already");
-                    this.iLanguage = LocaleNameToLCID(this.sRealName);
+                    Debug.Assert(_sRealName != null, "[CultureData.ILANGUAGE] Expected this.sRealName to be populated already");
+                    _iLanguage = LocaleNameToLCID(_sRealName);
                 }
-                return this.iLanguage;
+                return _iLanguage;
             }
         }
 
-        internal bool IsWin32Installed
-        {
-            get { return this.bWin32Installed; }
-        }
-
-        internal bool IsFramework
-        {
-            get { return this.bFramework; }
-        }
-
-        ////////////////////
-        // Derived properties //
-        ////////////////////
-
         internal bool IsNeutralCulture
         {
             get
             {
-                // NlsInfo::nativeInitCultureData told us if we're neutral or not
-                return this.bNeutral;
+                // InitCultureData told us if we're neutral or not
+                return _bNeutral;
             }
         }
 
@@ -2093,7 +2069,13 @@ namespace System.Globalization
         {
             get
             {
-                int defaultCalId = DoGetLocaleInfoInt(LOCALE_ICALENDARTYPE);
+                if (GlobalizationMode.Invariant)
+                {
+                    return CultureInfo.GetCalendarInstance(CalendarIds[0]);
+                }
+
+                CalendarId defaultCalId = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType);
+
                 if (defaultCalId == 0)
                 {
                     defaultCalId = this.CalendarIds[0];
@@ -2104,29 +2086,29 @@ namespace System.Globalization
         }
 
         // All of our era names
-        internal String[] EraNames(int calendarId)
+        internal String[] EraNames(CalendarId calendarId)
         {
             Debug.Assert(calendarId > 0, "[CultureData.saEraNames] Expected Calendar.ID > 0");
 
             return this.GetCalendar(calendarId).saEraNames;
         }
 
-        internal String[] AbbrevEraNames(int calendarId)
+        internal String[] AbbrevEraNames(CalendarId calendarId)
         {
             Debug.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0");
 
             return this.GetCalendar(calendarId).saAbbrevEraNames;
         }
 
-        internal String[] AbbreviatedEnglishEraNames(int calendarId)
+        internal String[] AbbreviatedEnglishEraNames(CalendarId calendarId)
         {
             Debug.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0");
 
             return this.GetCalendar(calendarId).saAbbrevEnglishEraNames;
         }
 
-        // String array DEFAULTS
-        // Note: GetDTFIOverrideValues does the user overrides for these, so we don't have to.
+        //// String array DEFAULTS
+        //// Note: GetDTFIOverrideValues does the user overrides for these, so we don't have to.
 
 
         // Time separator (derived from time format)
@@ -2134,23 +2116,23 @@ namespace System.Globalization
         {
             get
             {
-                if (sTimeSeparator == null || UseUserOverride)
+                if (_sTimeSeparator == null)
                 {
-                    string longTimeFormat = ReescapeWin32String(DoGetLocaleInfo(LOCALE_STIMEFORMAT));
+                    string longTimeFormat = GetTimeFormatString();
                     if (String.IsNullOrEmpty(longTimeFormat))
                     {
                         longTimeFormat = LongTimes[0];
                     }
 
                     // Compute STIME from time format
-                    sTimeSeparator = GetTimeSeparator(longTimeFormat);
+                    _sTimeSeparator = GetTimeSeparator(longTimeFormat);
                 }
-                return sTimeSeparator;
+                return _sTimeSeparator;
             }
         }
 
         // Date separator (derived from short date format)
-        internal String DateSeparator(int calendarId)
+        internal String DateSeparator(CalendarId calendarId)
         {
             return GetDateSeparator(ShortDates(calendarId)[0]);
         }
@@ -2178,11 +2160,11 @@ namespace System.Globalization
         // always build a stringbuilder because we need to remove the ' or \.
         //
         ////////////////////////////////////////////////////////////////////////////
-        static private String UnescapeNlsString(String str, int start, int end)
+        private static String UnescapeNlsString(String str, int start, int end)
         {
-            Contract.Requires(str != null);
-            Contract.Requires(start >= 0);
-            Contract.Requires(end >= 0);
+            Debug.Assert(str != null);
+            Debug.Assert(start >= 0);
+            Debug.Assert(end >= 0);
             StringBuilder result = null;
 
             for (int i = start; i < str.Length && i <= end; i++)
@@ -2221,102 +2203,7 @@ namespace System.Globalization
             return (result.ToString());
         }
 
-        ////////////////////////////////////////////////////////////////////////////
-        //
-        // Reescape a Win32 style quote string as a NLS+ style quoted string
-        //
-        // This is also the escaping style used by custom culture data files
-        //
-        // NLS+ uses \ to escape the next character, whether in a quoted string or
-        // not, so we always have to change \ to \\.
-        //
-        // NLS+ uses \' to escape a quote inside a quoted string so we have to change
-        // '' to \' (if inside a quoted string)
-        //
-        // We don't build the stringbuilder unless we find something to change
-        ////////////////////////////////////////////////////////////////////////////
-        static internal String ReescapeWin32String(String str)
-        {
-            // If we don't have data, then don't try anything
-            if (str == null)
-                return null;
-
-            StringBuilder result = null;
-
-            bool inQuote = false;
-            for (int i = 0; i < str.Length; i++)
-            {
-                // Look for quote
-                if (str[i] == '\'')
-                {
-                    // Already in quote?
-                    if (inQuote)
-                    {
-                        // See another single quote.  Is this '' of 'fred''s' or '''', or is it an ending quote?
-                        if (i + 1 < str.Length && str[i + 1] == '\'')
-                        {
-                            // Found another ', so we have ''.  Need to add \' instead.
-                            // 1st make sure we have our stringbuilder
-                            if (result == null)
-                                result = new StringBuilder(str, 0, i, str.Length * 2);
-
-                            // Append a \' and keep going (so we don't turn off quote mode)
-                            result.Append("\\'");
-                            i++;
-                            continue;
-                        }
-
-                        // Turning off quote mode, fall through to add it
-                        inQuote = false;
-                    }
-                    else
-                    {
-                        // Found beginning quote, fall through to add it
-                        inQuote = true;
-                    }
-                }
-                // Is there a single \ character?
-                else if (str[i] == '\\')
-                {
-                    // Found a \, need to change it to \\
-                    // 1st make sure we have our stringbuilder
-                    if (result == null)
-                        result = new StringBuilder(str, 0, i, str.Length * 2);
-
-                    // Append our \\ to the string & continue
-                    result.Append("\\\\");
-                    continue;
-                }
-
-                // If we have a builder we need to add our character
-                if (result != null)
-                    result.Append(str[i]);
-            }
-
-            // Unchanged string? , just return input string
-            if (result == null)
-                return str;
-
-            // String changed, need to use the builder
-            return result.ToString();
-        }
-
-        static internal String[] ReescapeWin32Strings(String[] array)
-        {
-            if (array != null)
-            {
-                for (int i = 0; i < array.Length; i++)
-                {
-                    array[i] = ReescapeWin32String(array[i]);
-                }
-            }
-
-            return array;
-        }
-
-        // NOTE: this method is used through reflection by System.Globalization.CultureXmlParser.ReadDateElement()
-        // and breaking changes here will not show up at build time, only at run time.
-        static private String GetTimeSeparator(String format)
+        private static String GetTimeSeparator(String format)
         {
             // Time format separator (ie: : in 12:39:00)
             //
@@ -2329,9 +2216,7 @@ namespace System.Globalization
             return GetSeparator(format, "Hhms");
         }
 
-        // NOTE: this method is used through reflection by System.Globalization.CultureXmlParser.ReadDateElement()
-        // and breaking changes here will not show up at build time, only at run time.
-        static private String GetDateSeparator(String format)
+        private static String GetDateSeparator(String format)
         {
             // Date format separator (ie: / in 9/1/03)
             //
@@ -2413,128 +2298,61 @@ namespace System.Globalization
             return -1;
         }
 
-        string DoGetLocaleInfo(uint lctype)
-        {
-            Debug.Assert(this.sWindowsName != null, "[CultureData.DoGetLocaleInfo] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
-            return DoGetLocaleInfo(this.sWindowsName, lctype);
-        }
-
-        // For LOCALE_SPARENT we need the option of using the "real" name (forcing neutral names) instead of the
-        // "windows" name, which can be specific for downlevel (< windows 7) os's.
-        string DoGetLocaleInfo(string localeName, uint lctype)
-        {
-            // Fix lctype if we don't want overrides
-            if (!UseUserOverride)
-            {
-                lctype |= LOCALE_NOUSEROVERRIDE;
-            }
-
-            // Ask OS for data
-            Debug.Assert(localeName != null, "[CultureData.DoGetLocaleInfo] Expected localeName to be not be null");
-            string result = CultureInfo.nativeGetLocaleInfoEx(localeName, lctype);
-            if (result == null)
-            {
-                // Failed, just use empty string
-                result = String.Empty;
-            }
-
-            return result;
-        }
-
-        int DoGetLocaleInfoInt(uint lctype)
-        {
-            // Fix lctype if we don't want overrides
-            if (!UseUserOverride)
-            {
-                lctype |= LOCALE_NOUSEROVERRIDE;
-            }
-
-            // Ask OS for data, note that we presume it returns success, so we have to know that
-            // sWindowsName is valid before calling.
-            Debug.Assert(this.sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
-            int result = CultureInfo.nativeGetLocaleInfoExInt(this.sWindowsName, lctype);
-
-            return result;
-        }
-
-        String[] DoEnumTimeFormats()
-        {
-            // Note that this gets overrides for us all the time
-            Debug.Assert(this.sWindowsName != null, "[CultureData.DoEnumTimeFormats] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
-            String[] result = ReescapeWin32Strings(nativeEnumTimeFormats(this.sWindowsName, 0, UseUserOverride));
-
-            return result;
-        }
-
-        String[] DoEnumShortTimeFormats()
-        {
-            // Note that this gets overrides for us all the time
-            Debug.Assert(this.sWindowsName != null, "[CultureData.DoEnumShortTimeFormats] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
-            String[] result = ReescapeWin32Strings(nativeEnumTimeFormats(this.sWindowsName, TIME_NOSECONDS, UseUserOverride));
-
-            return result;
-        }
-
-        /////////////////
-        // Static Helpers //
-        ////////////////
         internal static bool IsCustomCultureId(int cultureId)
         {
-            if (cultureId == CultureInfo.LOCALE_CUSTOM_DEFAULT || cultureId == CultureInfo.LOCALE_CUSTOM_UNSPECIFIED)
-                return true;
-
-            return false;
+            return (cultureId == CultureInfo.LOCALE_CUSTOM_DEFAULT || cultureId == CultureInfo.LOCALE_CUSTOM_UNSPECIFIED);
         }
 
-        ////////////////////////////////////////////////////////////////////////////
-        //
-        // Parameters:
-        //      calendarValueOnly   Retrieve the values which are affected by the calendar change of DTFI.
-        //                          This will cause values like longTimePattern not be retrieved since it is
-        //                          not affected by the Calendar property in DTFI.
-        //
-        ////////////////////////////////////////////////////////////////////////////
         internal void GetNFIValues(NumberFormatInfo nfi)
         {
-            if (this.IsInvariantCulture)
+            if (GlobalizationMode.Invariant || this.IsInvariantCulture)
             {
-                nfi.positiveSign = this.sPositiveSign;
-                nfi.negativeSign = this.sNegativeSign;
-
-                nfi.nativeDigits = this.saNativeDigits;
-                nfi.digitSubstitution = this.iDigitSubstitution;
+                // FUTURE: NumberFormatInfo already has default values for many of these fields.  Can we not do this?
+                nfi.positiveSign = _sPositiveSign;
+                nfi.negativeSign = _sNegativeSign;
 
-                nfi.numberGroupSeparator = this.sThousandSeparator;
-                nfi.numberDecimalSeparator = this.sDecimalSeparator;
-                nfi.numberDecimalDigits = this.iDigits;
-                nfi.numberNegativePattern = this.iNegativeNumber;
+                nfi.numberGroupSeparator = _sThousandSeparator;
+                nfi.numberDecimalSeparator = _sDecimalSeparator;
+                nfi.numberDecimalDigits = _iDigits;
+                nfi.numberNegativePattern = _iNegativeNumber;
 
-                nfi.currencySymbol = this.sCurrency;
-                nfi.currencyGroupSeparator = this.sMonetaryThousand;
-                nfi.currencyDecimalSeparator = this.sMonetaryDecimal;
-                nfi.currencyDecimalDigits = this.iCurrencyDigits;
-                nfi.currencyNegativePattern = this.iNegativeCurrency;
-                nfi.currencyPositivePattern = this.iCurrency;
+                nfi.currencySymbol = _sCurrency;
+                nfi.currencyGroupSeparator = _sMonetaryThousand;
+                nfi.currencyDecimalSeparator = _sMonetaryDecimal;
+                nfi.currencyDecimalDigits = _iCurrencyDigits;
+                nfi.currencyNegativePattern = _iNegativeCurrency;
+                nfi.currencyPositivePattern = _iCurrency;
             }
             else
             {
-                //
-                // We don't have information for the following four.  All cultures use
-                // the same value of the number formatting values.
-                //
-                // PercentDecimalDigits
-                // PercentDecimalSeparator
-                // PercentGroupSize
-                // PercentGroupSeparator
-                //
+                Debug.Assert(_sWindowsName != null, "[CultureData.GetNFIValues] Expected _sWindowsName to be populated by already");
+                // String values
+                nfi.positiveSign = GetLocaleInfo(LocaleStringData.PositiveSign);
+                nfi.negativeSign = GetLocaleInfo(LocaleStringData.NegativeSign);
 
-                //
-                // Ask native side for our data.
-                //
-                Debug.Assert(this.sWindowsName != null, "[CultureData.GetNFIValues] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
-                CultureData.nativeGetNumberFormatInfoValues(this.sWindowsName, nfi, UseUserOverride);
-            }
+                nfi.numberDecimalSeparator = GetLocaleInfo(LocaleStringData.DecimalSeparator);
+                nfi.numberGroupSeparator = GetLocaleInfo(LocaleStringData.ThousandSeparator);
+                nfi.currencyGroupSeparator = GetLocaleInfo(LocaleStringData.MonetaryThousandSeparator);
+                nfi.currencyDecimalSeparator = GetLocaleInfo(LocaleStringData.MonetaryDecimalSeparator);
+                nfi.currencySymbol = GetLocaleInfo(LocaleStringData.MonetarySymbol);
+
+                // Numeric values
+                nfi.numberDecimalDigits = GetLocaleInfo(LocaleNumberData.FractionalDigitsCount);
+                nfi.currencyDecimalDigits = GetLocaleInfo(LocaleNumberData.MonetaryFractionalDigitsCount);
+                nfi.currencyPositivePattern = GetLocaleInfo(LocaleNumberData.PositiveMonetaryNumberFormat);
+                nfi.currencyNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeMonetaryNumberFormat);
+                nfi.numberNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeNumberFormat);
 
+                // LOCALE_SNATIVEDIGITS (array of 10 single character strings).
+                string digits = GetLocaleInfo(LocaleStringData.Digits);
+                nfi.nativeDigits = new string[10];
+                for (int i = 0; i < nfi.nativeDigits.Length; i++)
+                {
+                    nfi.nativeDigits[i] = new string(digits[i], 1);
+                }
+
+                nfi.digitSubstitution = GetDigitSubstitution(_sRealName);
+            }
 
             //
             // Gather additional data
@@ -2569,289 +2387,188 @@ namespace System.Globalization
 
             //Special case for Italian.  The currency decimal separator in the control panel is the empty string. When the user
             //specifies C4 as the currency format, this results in the number apparently getting multiplied by 10000 because the
-            //decimal point doesn't show up.  We'll just workaround this here because our default currency format will never use nfi.
+            //decimal point doesn't show up.  We'll just hack this here because our default currency format will never use nfi.
             if (nfi.currencyDecimalSeparator == null || nfi.currencyDecimalSeparator.Length == 0)
             {
                 nfi.currencyDecimalSeparator = nfi.numberDecimalSeparator;
             }
         }
 
-        static private int ConvertFirstDayOfWeekMonToSun(int iTemp)
-        {
-            // Convert Mon-Sun to Sun-Sat format
-            iTemp++;
-            if (iTemp > 6)
-            {
-                // Wrap Sunday and convert invalid data to Sunday
-                iTemp = 0;
-            }
-            return iTemp;
-        }
-
         // Helper
         // This is ONLY used for caching names and shouldn't be used for anything else
         internal static string AnsiToLower(string testString)
         {
-            StringBuilder sb = new StringBuilder(testString.Length);
+            int index = 0;
 
-            for (int ich = 0; ich < testString.Length; ich++)
+            while (index<testString.Length && (testString[index]<'A' || testString[index]>'Z' ))
             {
-                char ch = testString[ich];
-                sb.Append(ch <= 'Z' && ch >= 'A' ? (char)(ch - 'A' + 'a') : ch);
+                index++;
             }
-
-            return (sb.ToString());
-        }
-
-        // If we get a group from windows, then its in 3;0 format with the 0 backwards
-        // of how NLS+ uses it (ie: if the string has a 0, then the int[] shouldn't and vice versa)
-        // EXCEPT in the case where the list only contains 0 in which NLS and NLS+ have the same meaning.
-        static private int[] ConvertWin32GroupString(String win32Str)
-        {
-            // None of these cases make any sense
-            if (win32Str == null || win32Str.Length == 0)
+            if (index >= testString.Length)
             {
-                return (new int[] { 3 });
+                return testString; // we didn't really change the string
             }
 
-            if (win32Str[0] == '0')
+            StringBuilder sb = new StringBuilder(testString.Length);
+            for (int i=0; i<index; i++)
             {
-                return (new int[] { 0 });
+                sb.Append(testString[i]);
             }
 
-            // Since its in n;n;n;n;n format, we can always get the length quickly
-            int[] values;
-            if (win32Str[win32Str.Length - 1] == '0')
-            {
-                // Trailing 0 gets dropped. 1;0 -> 1
-                values = new int[(win32Str.Length / 2)];
-            }
-            else
-            {
-                // Need extra space for trailing zero 1 -> 1;0
-                values = new int[(win32Str.Length / 2) + 2];
-                values[values.Length - 1] = 0;
-            }
+            sb.Append((char) (testString[index] -'A' + 'a'));
 
-            int i;
-            int j;
-            for (i = 0, j = 0; i < win32Str.Length && j < values.Length; i += 2, j++)
+            for (int ich = index+1; ich < testString.Length; ich++)
             {
-                // Note that this # shouldn't ever be zero, 'cause 0 is only at end
-                // But we'll test because its registry that could be anything
-                if (win32Str[i] < '1' || win32Str[i] > '9')
-                    return new int[] { 3 };
-
-                values[j] = (int)(win32Str[i] - '0');
+                char ch = testString[ich];
+                sb.Append(ch <= 'Z' && ch >= 'A' ? (char)(ch - 'A' + 'a') : ch);
             }
 
-            return (values);
+            return (sb.ToString());
         }
 
-        // LCTYPES for GetLocaleInfo
-        private const uint LOCALE_NOUSEROVERRIDE = 0x80000000;   // do not use user overrides
-        private const uint LOCALE_RETURN_NUMBER = 0x20000000;   // return number instead of string
-
-        // Modifier for genitive names
-        private const uint LOCALE_RETURN_GENITIVE_NAMES = 0x10000000;   //Flag to return the Genitive forms of month names
-
-        //
-        //  The following LCTypes are mutually exclusive in that they may NOT
-        //  be used in combination with each other.
-        //
-
-        //
-        // These are the various forms of the name of the locale:
-        //
-        private const uint LOCALE_SLOCALIZEDDISPLAYNAME = 0x00000002;   // localized name of locale, eg "German (Germany)" in UI language
-        private const uint LOCALE_SENGLISHDISPLAYNAME = 0x00000072;   // Display name (language + country usually) in English, eg "German (Germany)"
-        private const uint LOCALE_SNATIVEDISPLAYNAME = 0x00000073;   // Display name in native locale language, eg "Deutsch (Deutschland)
-
-        private const uint LOCALE_SLOCALIZEDLANGUAGENAME = 0x0000006f;   // Language Display Name for a language, eg "German" in UI language
-        private const uint LOCALE_SENGLISHLANGUAGENAME = 0x00001001;   // English name of language, eg "German"
-        private const uint LOCALE_SNATIVELANGUAGENAME = 0x00000004;   // native name of language, eg "Deutsch"
-
-        private const uint LOCALE_SLOCALIZEDCOUNTRYNAME = 0x00000006;   // localized name of country, eg "Germany" in UI language
-        private const uint LOCALE_SENGLISHCOUNTRYNAME = 0x00001002;   // English name of country, eg "Germany"
-        private const uint LOCALE_SNATIVECOUNTRYNAME = 0x00000008;   // native name of country, eg "Deutschland"
-
-
-        //        private const uint LOCALE_ILANGUAGE              =0x00000001;   // language id // Don't use, use NewApis::LocaleNameToLCID instead (GetLocaleInfo doesn't return neutrals)
-
-        //        private const uint LOCALE_SLANGUAGE              =LOCALE_SLOCALIZEDDISPLAYNAME;   // localized name of language (use LOCALE_SLOCALIZEDDISPLAYNAME instead)
-        //        private const uint LOCALE_SENGLANGUAGE           =LOCALE_SENGLISHLANGUAGENAME;   // English name of language (use LOCALE_SENGLISHLANGUAGENAME instead)
-        private const uint LOCALE_SABBREVLANGNAME = 0x00000003;   // abbreviated language name
-        //        private const uint LOCALE_SNATIVELANGNAME        =LOCALE_SNATIVELANGUAGENAME;   // native name of language (use LOCALE_SNATIVELANGUAGENAME instead)
-
-        private const uint LOCALE_ICOUNTRY = 0x00000005;   // country code
-        //        private const uint LOCALE_SCOUNTRY               =LOCALE_SLOCALIZEDCOUNTRYNAME;   // localized name of country (use LOCALE_SLOCALIZEDCOUNTRYNAME instead)
-        //        private const uint LOCALE_SENGCOUNTRY            =LOCALE_SENGLISHCOUNTRYNAME;   // English name of country (use LOCALE_SENGLISHCOUNTRYNAME instead)
-        private const uint LOCALE_SABBREVCTRYNAME = 0x00000007;   // abbreviated country name
-        //        private const uint LOCALE_SNATIVECTRYNAME        =LOCALE_SNATIVECOUNTRYNAME;   // native name of country ( use LOCALE_SNATIVECOUNTRYNAME instead)
-        private const uint LOCALE_IGEOID = 0x0000005B;   // geographical location id
-
-        private const uint LOCALE_IDEFAULTLANGUAGE = 0x00000009;   // default language id
-        private const uint LOCALE_IDEFAULTCOUNTRY = 0x0000000A;   // default country code
-        private const uint LOCALE_IDEFAULTCODEPAGE = 0x0000000B;   // default oem code page
-        private const uint LOCALE_IDEFAULTANSICODEPAGE = 0x00001004;   // default ansi code page
-        private const uint LOCALE_IDEFAULTMACCODEPAGE = 0x00001011;   // default mac code page
-
-        private const uint LOCALE_SLIST = 0x0000000C;   // list item separator
-        private const uint LOCALE_IMEASURE = 0x0000000D;   // 0 = metric, 1 = US
-
-        private const uint LOCALE_SDECIMAL = 0x0000000E;   // decimal separator
-        private const uint LOCALE_STHOUSAND = 0x0000000F;   // thousand separator
-        private const uint LOCALE_SGROUPING = 0x00000010;   // digit grouping
-        private const uint LOCALE_IDIGITS = 0x00000011;   // number of fractional digits
-        private const uint LOCALE_ILZERO = 0x00000012;   // leading zeros for decimal
-        private const uint LOCALE_INEGNUMBER = 0x00001010;   // negative number mode
-        private const uint LOCALE_SNATIVEDIGITS = 0x00000013;   // native digits for 0-9
-
-        private const uint LOCALE_SCURRENCY = 0x00000014;   // local monetary symbol
-        private const uint LOCALE_SINTLSYMBOL = 0x00000015;   // uintl monetary symbol
-        private const uint LOCALE_SMONDECIMALSEP = 0x00000016;   // monetary decimal separator
-        private const uint LOCALE_SMONTHOUSANDSEP = 0x00000017;   // monetary thousand separator
-        private const uint LOCALE_SMONGROUPING = 0x00000018;   // monetary grouping
-        private const uint LOCALE_ICURRDIGITS = 0x00000019;   // # local monetary digits
-        private const uint LOCALE_IINTLCURRDIGITS = 0x0000001A;   // # uintl monetary digits
-        private const uint LOCALE_ICURRENCY = 0x0000001B;   // positive currency mode
-        private const uint LOCALE_INEGCURR = 0x0000001C;   // negative currency mode
-
-        private const uint LOCALE_SDATE = 0x0000001D;   // date separator (derived from LOCALE_SSHORTDATE, use that instead)
-        private const uint LOCALE_STIME = 0x0000001E;   // time separator (derived from LOCALE_STIMEFORMAT, use that instead)
-        private const uint LOCALE_SSHORTDATE = 0x0000001F;   // short date format string
-        private const uint LOCALE_SLONGDATE = 0x00000020;   // long date format string
-        private const uint LOCALE_STIMEFORMAT = 0x00001003;   // time format string
-        private const uint LOCALE_IDATE = 0x00000021;   // short date format ordering (derived from LOCALE_SSHORTDATE, use that instead)
-        private const uint LOCALE_ILDATE = 0x00000022;   // long date format ordering (derived from LOCALE_SLONGDATE, use that instead)
-        private const uint LOCALE_ITIME = 0x00000023;   // time format specifier (derived from LOCALE_STIMEFORMAT, use that instead)
-        private const uint LOCALE_ITIMEMARKPOSN = 0x00001005;   // time marker position (derived from LOCALE_STIMEFORMAT, use that instead)
-        private const uint LOCALE_ICENTURY = 0x00000024;   // century format specifier (short date, LOCALE_SSHORTDATE is preferred)
-        private const uint LOCALE_ITLZERO = 0x00000025;   // leading zeros in time field (derived from LOCALE_STIMEFORMAT, use that instead)
-        private const uint LOCALE_IDAYLZERO = 0x00000026;   // leading zeros in day field (short date, LOCALE_SSHORTDATE is preferred)
-        private const uint LOCALE_IMONLZERO = 0x00000027;   // leading zeros in month field (short date, LOCALE_SSHORTDATE is preferred)
-        private const uint LOCALE_S1159 = 0x00000028;   // AM designator
-        private const uint LOCALE_S2359 = 0x00000029;   // PM designator
-
-        private const uint LOCALE_ICALENDARTYPE = 0x00001009;   // type of calendar specifier
-        private const uint LOCALE_IOPTIONALCALENDAR = 0x0000100B;   // additional calendar types specifier
-        private const uint LOCALE_IFIRSTDAYOFWEEK = 0x0000100C;   // first day of week specifier
-        private const uint LOCALE_IFIRSTWEEKOFYEAR = 0x0000100D;   // first week of year specifier
-
-        private const uint LOCALE_SDAYNAME1 = 0x0000002A;   // long name for Monday
-        private const uint LOCALE_SDAYNAME2 = 0x0000002B;   // long name for Tuesday
-        private const uint LOCALE_SDAYNAME3 = 0x0000002C;   // long name for Wednesday
-        private const uint LOCALE_SDAYNAME4 = 0x0000002D;   // long name for Thursday
-        private const uint LOCALE_SDAYNAME5 = 0x0000002E;   // long name for Friday
-        private const uint LOCALE_SDAYNAME6 = 0x0000002F;   // long name for Saturday
-        private const uint LOCALE_SDAYNAME7 = 0x00000030;   // long name for Sunday
-        private const uint LOCALE_SABBREVDAYNAME1 = 0x00000031;   // abbreviated name for Monday
-        private const uint LOCALE_SABBREVDAYNAME2 = 0x00000032;   // abbreviated name for Tuesday
-        private const uint LOCALE_SABBREVDAYNAME3 = 0x00000033;   // abbreviated name for Wednesday
-        private const uint LOCALE_SABBREVDAYNAME4 = 0x00000034;   // abbreviated name for Thursday
-        private const uint LOCALE_SABBREVDAYNAME5 = 0x00000035;   // abbreviated name for Friday
-        private const uint LOCALE_SABBREVDAYNAME6 = 0x00000036;   // abbreviated name for Saturday
-        private const uint LOCALE_SABBREVDAYNAME7 = 0x00000037;   // abbreviated name for Sunday
-        private const uint LOCALE_SMONTHNAME1 = 0x00000038;   // long name for January
-        private const uint LOCALE_SMONTHNAME2 = 0x00000039;   // long name for February
-        private const uint LOCALE_SMONTHNAME3 = 0x0000003A;   // long name for March
-        private const uint LOCALE_SMONTHNAME4 = 0x0000003B;   // long name for April
-        private const uint LOCALE_SMONTHNAME5 = 0x0000003C;   // long name for May
-        private const uint LOCALE_SMONTHNAME6 = 0x0000003D;   // long name for June
-        private const uint LOCALE_SMONTHNAME7 = 0x0000003E;   // long name for July
-        private const uint LOCALE_SMONTHNAME8 = 0x0000003F;   // long name for August
-        private const uint LOCALE_SMONTHNAME9 = 0x00000040;   // long name for September
-        private const uint LOCALE_SMONTHNAME10 = 0x00000041;   // long name for October
-        private const uint LOCALE_SMONTHNAME11 = 0x00000042;   // long name for November
-        private const uint LOCALE_SMONTHNAME12 = 0x00000043;   // long name for December
-        private const uint LOCALE_SMONTHNAME13 = 0x0000100E;   // long name for 13th month (if exists)
-        private const uint LOCALE_SABBREVMONTHNAME1 = 0x00000044;   // abbreviated name for January
-        private const uint LOCALE_SABBREVMONTHNAME2 = 0x00000045;   // abbreviated name for February
-        private const uint LOCALE_SABBREVMONTHNAME3 = 0x00000046;   // abbreviated name for March
-        private const uint LOCALE_SABBREVMONTHNAME4 = 0x00000047;   // abbreviated name for April
-        private const uint LOCALE_SABBREVMONTHNAME5 = 0x00000048;   // abbreviated name for May
-        private const uint LOCALE_SABBREVMONTHNAME6 = 0x00000049;   // abbreviated name for June
-        private const uint LOCALE_SABBREVMONTHNAME7 = 0x0000004A;   // abbreviated name for July
-        private const uint LOCALE_SABBREVMONTHNAME8 = 0x0000004B;   // abbreviated name for August
-        private const uint LOCALE_SABBREVMONTHNAME9 = 0x0000004C;   // abbreviated name for September
-        private const uint LOCALE_SABBREVMONTHNAME10 = 0x0000004D;   // abbreviated name for October
-        private const uint LOCALE_SABBREVMONTHNAME11 = 0x0000004E;   // abbreviated name for November
-        private const uint LOCALE_SABBREVMONTHNAME12 = 0x0000004F;   // abbreviated name for December
-        private const uint LOCALE_SABBREVMONTHNAME13 = 0x0000100F;   // abbreviated name for 13th month (if exists)
-
-        private const uint LOCALE_SPOSITIVESIGN = 0x00000050;   // positive sign
-        private const uint LOCALE_SNEGATIVESIGN = 0x00000051;   // negative sign
-        private const uint LOCALE_IPOSSIGNPOSN = 0x00000052;   // positive sign position (derived from INEGCURR)
-        private const uint LOCALE_INEGSIGNPOSN = 0x00000053;   // negative sign position (derived from INEGCURR)
-        private const uint LOCALE_IPOSSYMPRECEDES = 0x00000054;   // mon sym precedes pos amt (derived from ICURRENCY)
-        private const uint LOCALE_IPOSSEPBYSPACE = 0x00000055;   // mon sym sep by space from pos amt (derived from ICURRENCY)
-        private const uint LOCALE_INEGSYMPRECEDES = 0x00000056;   // mon sym precedes neg amt (derived from INEGCURR)
-        private const uint LOCALE_INEGSEPBYSPACE = 0x00000057;   // mon sym sep by space from neg amt (derived from INEGCURR)
-
-        private const uint LOCALE_FONTSIGNATURE = 0x00000058;   // font signature
-        private const uint LOCALE_SISO639LANGNAME = 0x00000059;   // ISO abbreviated language name
-        private const uint LOCALE_SISO3166CTRYNAME = 0x0000005A;   // ISO abbreviated country name
-
-        private const uint LOCALE_IDEFAULTEBCDICCODEPAGE = 0x00001012;   // default ebcdic code page
-        private const uint LOCALE_IPAPERSIZE = 0x0000100A;   // 1 = letter, 5 = legal, 8 = a3, 9 = a4
-        private const uint LOCALE_SENGCURRNAME = 0x00001007;   // english name of currency
-        private const uint LOCALE_SNATIVECURRNAME = 0x00001008;   // native name of currency
-        private const uint LOCALE_SYEARMONTH = 0x00001006;   // year month format string
-        private const uint LOCALE_SSORTNAME = 0x00001013;   // sort name
-        private const uint LOCALE_IDIGITSUBSTITUTION = 0x00001014;   // 0 = context, 1 = none, 2 = national
-
-        private const uint LOCALE_SNAME = 0x0000005c;   // locale name (with sort info) (ie: de-DE_phoneb)
-        private const uint LOCALE_SDURATION = 0x0000005d;   // time duration format
-        private const uint LOCALE_SKEYBOARDSTOINSTALL = 0x0000005e;   // (windows only) keyboards to install
-        private const uint LOCALE_SSHORTESTDAYNAME1 = 0x00000060;   // Shortest day name for Monday
-        private const uint LOCALE_SSHORTESTDAYNAME2 = 0x00000061;   // Shortest day name for Tuesday
-        private const uint LOCALE_SSHORTESTDAYNAME3 = 0x00000062;   // Shortest day name for Wednesday
-        private const uint LOCALE_SSHORTESTDAYNAME4 = 0x00000063;   // Shortest day name for Thursday
-        private const uint LOCALE_SSHORTESTDAYNAME5 = 0x00000064;   // Shortest day name for Friday
-        private const uint LOCALE_SSHORTESTDAYNAME6 = 0x00000065;   // Shortest day name for Saturday
-        private const uint LOCALE_SSHORTESTDAYNAME7 = 0x00000066;   // Shortest day name for Sunday
-        private const uint LOCALE_SISO639LANGNAME2 = 0x00000067;   // 3 character ISO abbreviated language name
-        private const uint LOCALE_SISO3166CTRYNAME2 = 0x00000068;   // 3 character ISO country name
-        private const uint LOCALE_SNAN = 0x00000069;   // Not a Number
-        private const uint LOCALE_SPOSINFINITY = 0x0000006a;   // + Infinity
-        private const uint LOCALE_SNEGINFINITY = 0x0000006b;   // - Infinity
-        private const uint LOCALE_SSCRIPTS = 0x0000006c;   // Typical scripts in the locale
-        private const uint LOCALE_SPARENT = 0x0000006d;   // Fallback name for resources
-        private const uint LOCALE_SCONSOLEFALLBACKNAME = 0x0000006e;   // Fallback name for within the console
-        //        private const uint LOCALE_SLANGDISPLAYNAME       =LOCALE_SLOCALIZEDLANGUAGENAME;   // Language Display Name for a language (use LOCALE_SLOCALIZEDLANGUAGENAME instead)
-
-        // Windows 7 LCTYPES
-        private const uint LOCALE_IREADINGLAYOUT = 0x00000070;   // Returns one of the following 4 reading layout values:
-        // 0 - Left to right (eg en-US)
-        // 1 - Right to left (eg arabic locales)
-        // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
-        // 3 - Vertical top to bottom with columns proceeding to the right
-        private const uint LOCALE_INEUTRAL = 0x00000071;   // Returns 0 for specific cultures, 1 for neutral cultures.
-        private const uint LOCALE_INEGATIVEPERCENT = 0x00000074;   // Returns 0-11 for the negative percent format
-        private const uint LOCALE_IPOSITIVEPERCENT = 0x00000075;   // Returns 0-3 for the positive percent formatIPOSITIVEPERCENT
-        private const uint LOCALE_SPERCENT = 0x00000076;   // Returns the percent symbol
-        private const uint LOCALE_SPERMILLE = 0x00000077;   // Returns the permille (U+2030) symbol
-        private const uint LOCALE_SMONTHDAY = 0x00000078;   // Returns the preferred month/day format
-        private const uint LOCALE_SSHORTTIME = 0x00000079;   // Returns the preferred short time format (ie: no seconds, just h:mm)
-        private const uint LOCALE_SOPENTYPELANGUAGETAG = 0x0000007a;   // Open type language tag, eg: "latn" or "dflt"
-        private const uint LOCALE_SSORTLOCALE = 0x0000007b;   // Name of locale to use for sorting/collation/casing behavior.
-
-        // Time formats enumerations
-        internal const uint TIME_NOSECONDS = 0x00000002;   // Don't use seconds (get short time format for enumtimeformats on win7+)
-
-        // Get our initial minimal culture data (name, parent, etc.)
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        internal static extern bool nativeInitCultureData(CultureData cultureData);
-
-        // Grab the NumberFormatInfo data
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        internal static extern bool nativeGetNumberFormatInfoValues(String localeName, NumberFormatInfo nfi, bool useUserOverride);
-
-        [MethodImplAttribute(MethodImplOptions.InternalCall)]
-        private static extern String[] nativeEnumTimeFormats(String localeName, uint dwFlags, bool useUserOverride);
-
-        [SuppressUnmanagedCodeSecurityAttribute()]
-        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
-        internal static extern int nativeEnumCultureNames(int cultureTypes, ObjectHandleOnStack retStringArray);
+        /// <remarks>
+        /// The numeric values of the enum members match their Win32 counterparts.  The CultureData Win32 PAL implementation
+        /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes.
+        /// </remarks>
+        private enum LocaleStringData : uint
+        {
+            /// <summary>localized name of locale, eg "German (Germany)" in UI language (corresponds to LOCALE_SLOCALIZEDDISPLAYNAME)</summary>
+            LocalizedDisplayName = 0x00000002,
+            /// <summary>Display name (language + country usually) in English, eg "German (Germany)" (corresponds to LOCALE_SENGLISHDISPLAYNAME)</summary>
+            EnglishDisplayName = 0x00000072,
+            /// <summary>Display name in native locale language, eg "Deutsch (Deutschland) (corresponds to LOCALE_SNATIVEDISPLAYNAME)</summary>
+            NativeDisplayName = 0x00000073,
+            /// <summary>Language Display Name for a language, eg "German" in UI language (corresponds to LOCALE_SLOCALIZEDLANGUAGENAME)</summary>
+            LocalizedLanguageName = 0x0000006f,
+            /// <summary>English name of language, eg "German" (corresponds to LOCALE_SENGLISHLANGUAGENAME)</summary>
+            EnglishLanguageName = 0x00001001,
+            /// <summary>native name of language, eg "Deutsch" (corresponds to LOCALE_SNATIVELANGUAGENAME)</summary>
+            NativeLanguageName = 0x00000004,
+            /// <summary>localized name of country, eg "Germany" in UI language (corresponds to LOCALE_SLOCALIZEDCOUNTRYNAME)</summary>
+            LocalizedCountryName = 0x00000006,
+            /// <summary>English name of country, eg "Germany" (corresponds to LOCALE_SENGLISHCOUNTRYNAME)</summary>
+            EnglishCountryName = 0x00001002,
+            /// <summary>native name of country, eg "Deutschland" (corresponds to LOCALE_SNATIVECOUNTRYNAME)</summary>
+            NativeCountryName = 0x00000008,
+            /// <summary>abbreviated language name (corresponds to LOCALE_SABBREVLANGNAME)</summary>
+            AbbreviatedWindowsLanguageName = 0x00000003,
+            /// <summary>list item separator (corresponds to LOCALE_SLIST)</summary>
+            ListSeparator = 0x0000000C,
+            /// <summary>decimal separator (corresponds to LOCALE_SDECIMAL)</summary>
+            DecimalSeparator = 0x0000000E,
+            /// <summary>thousand separator (corresponds to LOCALE_STHOUSAND)</summary>
+            ThousandSeparator = 0x0000000F,
+            /// <summary>digit grouping (corresponds to LOCALE_SGROUPING)</summary>
+            Digits = 0x00000013,
+            /// <summary>local monetary symbol (corresponds to LOCALE_SCURRENCY)</summary>
+            MonetarySymbol = 0x00000014,
+            /// <summary>English currency name (corresponds to LOCALE_SENGCURRNAME)</summary>
+            CurrencyEnglishName = 0x00001007,
+            /// <summary>Native currency name (corresponds to LOCALE_SNATIVECURRNAME)</summary>
+            CurrencyNativeName = 0x00001008,
+            /// <summary>uintl monetary symbol (corresponds to LOCALE_SINTLSYMBOL)</summary>
+            Iso4217MonetarySymbol = 0x00000015,
+            /// <summary>monetary decimal separator (corresponds to LOCALE_SMONDECIMALSEP)</summary>
+            MonetaryDecimalSeparator = 0x00000016,
+            /// <summary>monetary thousand separator (corresponds to LOCALE_SMONTHOUSANDSEP)</summary>
+            MonetaryThousandSeparator = 0x00000017,
+            /// <summary>AM designator (corresponds to LOCALE_S1159)</summary>
+            AMDesignator = 0x00000028,
+            /// <summary>PM designator (corresponds to LOCALE_S2359)</summary>
+            PMDesignator = 0x00000029,
+            /// <summary>positive sign (corresponds to LOCALE_SPOSITIVESIGN)</summary>
+            PositiveSign = 0x00000050,
+            /// <summary>negative sign (corresponds to LOCALE_SNEGATIVESIGN)</summary>
+            NegativeSign = 0x00000051,
+            /// <summary>ISO abbreviated language name (corresponds to LOCALE_SISO639LANGNAME)</summary>
+            Iso639LanguageTwoLetterName = 0x00000059,
+            /// <summary>ISO abbreviated country name (corresponds to LOCALE_SISO639LANGNAME2)</summary>
+            Iso639LanguageThreeLetterName = 0x00000067,
+            /// <summary>ISO abbreviated language name (corresponds to LOCALE_SISO639LANGNAME)</summary>
+            Iso639LanguageName = 0x00000059,
+            /// <summary>ISO abbreviated country name (corresponds to LOCALE_SISO3166CTRYNAME)</summary>
+            Iso3166CountryName = 0x0000005A,
+            /// <summary>3 letter ISO country code (corresponds to LOCALE_SISO3166CTRYNAME2)</summary>
+            Iso3166CountryName2 = 0x00000068,   // 3 character ISO country name
+            /// <summary>Not a Number (corresponds to LOCALE_SNAN)</summary>
+            NaNSymbol = 0x00000069,
+            /// <summary>+ Infinity (corresponds to LOCALE_SPOSINFINITY)</summary>
+            PositiveInfinitySymbol = 0x0000006a,
+            /// <summary>- Infinity (corresponds to LOCALE_SNEGINFINITY)</summary>
+            NegativeInfinitySymbol = 0x0000006b,
+            /// <summary>Fallback name for resources (corresponds to LOCALE_SPARENT)</summary>
+            ParentName = 0x0000006d,
+            /// <summary>Fallback name for within the console (corresponds to LOCALE_SCONSOLEFALLBACKNAME)</summary>
+            ConsoleFallbackName = 0x0000006e,
+            /// <summary>Returns the percent symbol (corresponds to LOCALE_SPERCENT)</summary>
+            PercentSymbol = 0x00000076,
+            /// <summary>Returns the permille (U+2030) symbol (corresponds to LOCALE_SPERMILLE)</summary>
+            PerMilleSymbol = 0x00000077
+        }
+
+        /// <remarks>
+        /// The numeric values of the enum members match their Win32 counterparts.  The CultureData Win32 PAL implementation
+        /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes.
+        /// </remarks>
+        private enum LocaleGroupingData : uint
+        {
+            /// <summary>digit grouping (corresponds to LOCALE_SGROUPING)</summary>
+            Digit = 0x00000010,
+            /// <summary>monetary grouping (corresponds to LOCALE_SMONGROUPING)</summary>
+            Monetary = 0x00000018,
+        }
+
+        /// <remarks>
+        /// The numeric values of the enum members match their Win32 counterparts.  The CultureData Win32 PAL implementation
+        /// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes.
+        /// </remarks>
+        private enum LocaleNumberData : uint
+        {
+            /// <summary>language id (corresponds to LOCALE_ILANGUAGE)</summary>
+            LanguageId = 0x00000001,
+            /// <summary>geographical location id, (corresponds to LOCALE_IGEOID)</summary>
+            GeoId = 0x0000005B,
+            /// <summary>0 = context, 1 = none, 2 = national (corresponds to LOCALE_IDIGITSUBSTITUTION)</summary>
+            DigitSubstitution = 0x00001014,
+            /// <summary>0 = metric, 1 = US (corresponds to LOCALE_IMEASURE)</summary>
+            MeasurementSystem = 0x0000000D,
+            /// <summary>number of fractional digits (corresponds to LOCALE_IDIGITS)</summary>
+            FractionalDigitsCount = 0x00000011,
+            /// <summary>negative number mode (corresponds to LOCALE_INEGNUMBER)</summary>
+            NegativeNumberFormat = 0x00001010,
+            /// <summary># local monetary digits (corresponds to LOCALE_ICURRDIGITS)</summary>
+            MonetaryFractionalDigitsCount = 0x00000019,
+            /// <summary>positive currency mode (corresponds to LOCALE_ICURRENCY)</summary>
+            PositiveMonetaryNumberFormat = 0x0000001B,
+            /// <summary>negative currency mode (corresponds to LOCALE_INEGCURR)</summary>
+            NegativeMonetaryNumberFormat = 0x0000001C,
+            /// <summary>type of calendar specifier (corresponds to LOCALE_ICALENDARTYPE)</summary>
+            CalendarType = 0x00001009,
+            /// <summary>first day of week specifier (corresponds to LOCALE_IFIRSTDAYOFWEEK)</summary>
+            FirstDayOfWeek = 0x0000100C,
+            /// <summary>first week of year specifier (corresponds to LOCALE_IFIRSTWEEKOFYEAR)</summary>
+            FirstWeekOfYear = 0x0000100D,
+            /// <summary>
+            /// Returns one of the following 4 reading layout values:
+            ///  0 - Left to right (eg en-US)
+            ///  1 - Right to left (eg arabic locales)
+            ///  2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
+            ///  3 - Vertical top to bottom with columns proceeding to the right
+            /// (corresponds to LOCALE_IREADINGLAYOUT)
+            /// </summary>
+            ReadingLayout = 0x00000070,
+            /// <summary>Returns 0-11 for the negative percent format (corresponds to LOCALE_INEGATIVEPERCENT)</summary>
+            NegativePercentFormat = 0x00000074,
+            /// <summary>Returns 0-3 for the positive percent format (corresponds to LOCALE_IPOSITIVEPERCENT)</summary>
+            PositivePercentFormat = 0x00000075,
+            /// <summary>default ansi code page (corresponds to LOCALE_IDEFAULTCODEPAGE)</summary>
+            OemCodePage = 0x0000000B,
+            /// <summary>default ansi code page (corresponds to LOCALE_IDEFAULTANSICODEPAGE)</summary>
+            AnsiCodePage = 0x00001004,
+            /// <summary>default mac code page (corresponds to LOCALE_IDEFAULTMACCODEPAGE)</summary>
+            MacCodePage = 0x00001011,
+            /// <summary>default ebcdic code page (corresponds to LOCALE_IDEFAULTEBCDICCODEPAGE)</summary>
+            EbcdicCodePage = 0x00001012,
+        }
     }
 }