File: system\globalization\culturedata.cs
Project: ndp\clr\src\bcl\mscorlib.csproj (mscorlib)
// ==++==
//
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//
// ==--==
namespace System.Globalization
{
 
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading;
#if !FEATURE_CORECLR
    using System.Reflection;
    using System.Resources;
#endif
    using System.Runtime.CompilerServices;
    using System.Runtime.InteropServices;
    using System.Runtime.Versioning;
    using System.Diagnostics.Contracts;
    using System.Security;
    using System.Security.Principal;
 
    //
    // List of culture data
    // Note the we cache overrides.
    // Note that localized names (resource names) aren't available from here.
    //
 
    //
    // Our names are a tad confusing.
    //
    // sWindowsName -- The name that windows thinks this culture is, ie:
    //                            en-US if you pass in en-US
    //                            de-DE_phoneb if you pass in de-DE_phoneb
    //                            fj-FJ if you pass in fj (neutral, on a pre-Windows 7 machine)
    //                            fj if you pass in fj (neutral, post-Windows 7 machine)
    //
    // sRealName -- The name you used to construct the culture, in pretty form
    //                       en-US if you pass in EN-us
    //                       en if you pass in en
    //                       de-DE_phoneb if you pass in de-DE_phoneb
    //
    // sSpecificCulture -- The specific culture for this culture
    //                             en-US for en-US
    //                             en-US for en
    //                             de-DE_phoneb for alt sort
    //                             fj-FJ for fj (neutral)
    //
    // sName -- The IETF name of this culture (ie: no sort info, could be neutral)
    //                en-US if you pass in en-US
    //                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
    {
        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))
 
        // 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
 
        // 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
 
        // Region
        private String sRegionName; // (RegionInfo)
        //        private int    iCountry=undef           ; // (user can override) ---- code (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
 
        // 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
        // (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
 
        // 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
 
        // 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
 
        // 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)
 
        // 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
 
        // 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
 
        // Store for specific data about each calendar
        private CalendarData[] calendars; // Store for specific calendar data
 
        // Text information
        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)
 
        // CoreCLR depends on this even though its not exposed publicly.
#if !FEATURE_CORECLR
        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)
#endif
 
        // 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)
#if !FEATURE_CORECLR
        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
#endif
 
#if !FEATURE_CORECLR
        // 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
        {
            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;
 
#endif
 
        /////////////////////////////////////////////////////////////////////////
        // 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();
 
#if !FEATURE_CORECLR
		    // 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);
#endif
 
		    // 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)
#if !FEATURE_CORECLR
		    // Don't set invariant.bWin32Installed, we used nativeInitCultureData for that.
		    invariant.bFramework = true;
#endif
 
		    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;                      // ---- 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)
 
		    // These are desktop only, not coreclr
	#if !FEATURE_CORECLR
		    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.
	#endif
		    // Remember it
                    s_Invariant = invariant;
                }
                return s_Invariant;
            }
        }
        private volatile static CultureData s_Invariant;
 
 
#if !FEATURE_CORECLR
        internal static volatile ResourceSet MscorlibResourceSet;
#endif
 
#if !FEATURE_CORECLR
        [System.Security.SecurityCritical]  // auto-generated
        private static bool IsResourcePresent(String resourceKey)
        {
            if (MscorlibResourceSet == null)
            {
                MscorlibResourceSet = new ResourceSet(typeof(Environment).Assembly.GetManifestResourceStream("mscorlib.resources"));
            }
            return MscorlibResourceSet.GetString(resourceKey) != null;
        }
#endif
 
        ///////////////
        // 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;
            }
 
            if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8)
            {
                // WinCE named some locales differently than Windows.
                if (cultureName.Equals("iw", StringComparison.OrdinalIgnoreCase))
                {
                    cultureName = "he";
                }
                else if (cultureName.Equals("tl", StringComparison.OrdinalIgnoreCase))
                {
                    cultureName = "fil";
                }
                else if (cultureName.Equals("english", StringComparison.OrdinalIgnoreCase))
                {
                    cultureName = "en";
                }
            }
 
            // 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);
                }
                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)
            {
#if !FEATURE_CORECLR
                if (culture.InitCompatibilityCultureData() == false
                 && culture.InitLegacyAlternateSortData() == false)
#endif
                {
                    return null;
                }
            }
 
            return culture;
        }
 
        private bool InitCultureData()
        {
            if (nativeInitCultureData(this) == false)
            {
                return false;
            }
 
#if !FEATURE_CORECLR
            if (CultureInfo.IsTaiwanSku)
            {
                TreatTaiwanParentChainAsHavingTaiwanAsSpecific();
            }
#endif
            return true;
        }
 
#if !FEATURE_CORECLR
        [System.Security.SecuritySafeCritical]
        private void TreatTaiwanParentChainAsHavingTaiwanAsSpecific()
        {
            if (IsNeutralInParentChainOfTaiwan() && IsOsPriorToWin7() && !IsReplacementCulture)
            {
                // force population of fields that should have information that is
                // different than zh-TW:
                string s = SNATIVELANGUAGE;
                s = SENGLISHLANGUAGE;
                s = SLOCALIZEDLANGUAGE;
                s = STEXTINFO;
                s = SCOMPAREINFO;
                s = FONTSIGNATURE;
                int i = IDEFAULTANSICODEPAGE;
                i = IDEFAULTOEMCODEPAGE;
                i = IDEFAULTMACCODEPAGE;
 
                // all other fields will be populated with values that are the same
                // as those for ----
                this.sSpecificCulture = "zh-TW";
                this.sWindowsName = "zh-TW";
            }
        }
 
        private bool IsNeutralInParentChainOfTaiwan()
        {
            return this.sRealName == "zh" || this.sRealName == "zh-Hant";
  }
 
        static readonly Version s_win7Version = new Version(6, 1);
        static private bool IsOsPriorToWin7()
        {
            return Environment.OSVersion.Platform == PlatformID.Win32NT &&
                   Environment.OSVersion.Version < s_win7Version;
        }
        static private bool IsOsWin7OrPrior()
        {
            return Environment.OSVersion.Platform == PlatformID.Win32NT &&
                Environment.OSVersion.Version < new Version(6, 2); // Win7 is 6.1.Build.Revision so we have to check for anything less than 6.2
        }
 
        private bool InitCompatibilityCultureData()
        {
            // for compatibility handle the deprecated ids: zh-chs, zh-cht
            string cultureName = this.sRealName;
 
            string fallbackCultureName;
            string realCultureName;
            switch (AnsiToLower(cultureName))
            {
                case "zh-chs":
                    fallbackCultureName = "zh-Hans";
                    realCultureName = "zh-CHS";
                    break;
                case "zh-cht":
                    fallbackCultureName = "zh-Hant";
                    realCultureName = "zh-CHT";
                    break;
                default:
                    return false;
            }
 
            this.sRealName = fallbackCultureName;
            if (InitCultureData() == false)
            {
                return false;
            }
            // fixup our data
            this.sName = realCultureName; // the name that goes back to the user
            this.sParent = fallbackCultureName;
            this.bFramework = true;
 
            return true;
        }
 
        private bool InitLegacyAlternateSortData()
        {
            if (!CompareInfo.IsLegacy20SortingBehaviorRequested)
            {
                return false;
            }
 
            // For V2 compatability, handle deprecated alternate sorts
            string cultureName = this.sRealName;
 
            switch (AnsiToLower(cultureName))
            {
                case "ko-kr_unicod":
                    cultureName = "ko-KR_unicod";
                    this.sRealName = "ko-KR";
                    this.iLanguage = 0x00010412;
                    break;
                case "ja-jp_unicod":
                    cultureName = "ja-JP_unicod";
                    this.sRealName = "ja-JP";
                    this.iLanguage = 0x00010411;
                    break;
                case "zh-hk_stroke":
                    cultureName = "zh-HK_stroke";
                    this.sRealName = "zh-HK";
                    this.iLanguage = 0x00020c04;
                    break;
                default:
                    return false;
            }
 
            if (nativeInitCultureData(this) == false)
            {
                return false;
            }
 
            this.sRealName = cultureName;
            this.sCompareInfo = cultureName;
            this.bFramework = true;
 
            return true;
        }
 
#if FEATURE_WIN32_REGISTRY
        private static String s_RegionKey = @"System\CurrentControlSet\Control\Nls\RegionMapping";
#endif // FEATURE_WIN32_REGISTRY
 
#endif // !FEATURE_CORECLR
        // Cache of regions we've already looked up
        private static volatile Dictionary<String, CultureData> s_cachedRegions;
 
        [System.Security.SecurityCritical]  // auto-generated
        internal static CultureData GetCultureDataForRegion(String cultureName, bool useUserOverride)
        {
            // First do a shortcut for Invariant
            if (String.IsNullOrEmpty(cultureName))
            {
                return CultureData.Invariant;
            }
 
            //
            // First check if GetCultureData() can find it (ie: its a real culture)
            //
            CultureData retVal = GetCultureData(cultureName, useUserOverride);
            if (retVal != null && (retVal.IsNeutralCulture == false)) return retVal;
 
            //
            // Not a specific culture, perhaps it's region-only name
            // (Remember this isn't a core clr path where that's not supported)
            //
 
            // If it was neutral remember that so that RegionInfo() can throw the right exception
            CultureData neutral = retVal;
 
            // Try the hash table next
            String hashName = AnsiToLower(useUserOverride ? cultureName : cultureName + '*');
            Dictionary<String, CultureData> tempHashTable = s_cachedRegions;
            if (tempHashTable == null)
            {
                // No table yet, make a new one
                tempHashTable = new Dictionary<String, CultureData>();
            }
            else
            {
                // Check the hash table
                lock (((ICollection)tempHashTable).SyncRoot)
                {
                    tempHashTable.TryGetValue(hashName, out retVal);
                }
                if (retVal != null)
                {
                    return retVal;
                }
            }
 
#if !FEATURE_CORECLR
            //
            // Not found in the hash table, look it up the hard way
            //
#if FEATURE_WIN32_REGISTRY
            // First try the registry in case there are overrides of our table
            try
            {
                // Open in read-only mode.
                // Use InternalOpenSubKey so that we avoid the security check.
                Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.InternalOpenSubKey(s_RegionKey, false);
 
                if (key != null)
                {
                    try
                    {
                        Object value = key.InternalGetValue(cultureName, null, false, false);
 
                        if (value != null)
                        {
                            // Get the name of the locale to try.
                            String specificForRegion = value.ToString();
 
                            // See if it's real
                            retVal = GetCultureData(specificForRegion, useUserOverride);
                        }
                    }
                    finally
                    {
                        key.Close();
                    }
                }
            }
            // If this fails for any reason, we'll just ignore it, likely it just isn't there.
            catch (ObjectDisposedException) { }
            catch (ArgumentException) { }
#endif // FEATURE_WIN32_REGISTRY
 
            // If not a valid mapping from the registry we'll have to try the hard coded table
            if (retVal == null || (retVal.IsNeutralCulture == true))
            {
                // Not a valid mapping, try the hard coded table
                if (RegionNames.ContainsKey(cultureName))
                {
                    // Make sure we can get culture data for it
                    retVal = GetCultureData(RegionNames[cultureName], useUserOverride);
                }
            }
#endif // !FEATURE_CORECLR
            // 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))
            {
                // 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;
                    }
                }
            }
 
            // If we found one we can use, then cash it for next time
            if (retVal != null && (retVal.IsNeutralCulture == false))
            {
                // first add it to the cache
                lock (((ICollection)tempHashTable).SyncRoot)
                {
                    tempHashTable[hashName] = retVal;
                }
 
                // 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_cachedRegions = tempHashTable;
            }
            else
            {
                // Unable to find a matching culture/region, return null or neutral
                // (regionInfo throws a more specific exception on neutrals)
                retVal = neutral;
            }
 
            // Return the found culture to use, null, or the neutral culture.
            return retVal;
        }
 
#if FEATURE_USE_LCID
        // Obtain locale name from LCID
        // NOTE: This will get neutral names, unlike the OS API
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [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 !FEATURE_CORECLR
            // If V2 legacy sort is requested, then provide deprecated alternate sorts
            if (CompareInfo.IsLegacy20SortingBehaviorRequested)
            {
                switch (culture)
                {
                    case 0x00010412:
                        localeName = "ko-KR_unicod";
                        break;
                    case 0x00010411:
                        localeName = "ja-JP_unicod";
                        break;
                    case 0x00020c04:
                        localeName = "zh-HK_stroke";
                        break;
                }
            }
#endif
 
            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
            {
#if !FEATURE_CORECLR
                switch (localeName)
                {
                    // for compatibility with Whidbey, when requesting
                    // a locale from LCID, return the old localeName
                    case "zh-Hans":
                        localeName = "zh-CHS";
                        break;
                    case "zh-Hant":
                        localeName = "zh-CHT";
                        break;
                }
#endif
                // Valid name, use it
                retVal = GetCultureData(localeName, bUseUserOverride);
            }
 
            // If not successful, throw
            if (retVal == null)
                throw new CultureNotFoundException(
                    "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;
#if !FEATURE_CORECLR
            s_cachedRegions = null;
            s_replacementCultureNames = null;
#endif
        }
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        internal static CultureInfo[] GetCultures(CultureTypes types)
        {
            // Disable  warning 618: System.Globalization.CultureTypes.FrameworkCultures' is obsolete
#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)
            {
                throw new ArgumentOutOfRangeException(
                                "types",
                                String.Format(
                                    CultureInfo.CurrentCulture,
                                    Environment.GetResourceString("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 compatability).
            //
 
            // We have deprecated CultureTypes.WindowsOnlyCultures.
            // When this enum is used, we will return an empty array for this enum.
            if ((types & CultureTypes.WindowsOnlyCultures) != 0)
            {
                // Remove the enum as it is an no-op.
                types &= (~CultureTypes.WindowsOnlyCultures);
            }
 
            String[] cultureNames = null;
 
            //
            // Call nativeEnumCultureNames() to get a string array of culture names based on the specified
            // enumeration type.
            //
            // nativeEnumCulturNames 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.
            //
 
            if (nativeEnumCultureNames((int)types, JitHelpers.GetObjectHandleOnStack(ref cultureNames)) == 0)
            {
                return new CultureInfo[0];
            }
 
            int arrayLength = cultureNames.Length;
 
            if ((types & (CultureTypes.NeutralCultures | CultureTypes.FrameworkCultures)) != 0) // add zh-CHT and zh-CHS
            {
                arrayLength += 2;
            }
 
            CultureInfo[] cultures = new CultureInfo[arrayLength];
 
            for (int i = 0; i < cultureNames.Length; i++)
            {
                cultures[i] = new CultureInfo(cultureNames[i]);
            }
 
            if ((types & (CultureTypes.NeutralCultures | CultureTypes.FrameworkCultures)) != 0) // add zh-CHT and zh-CHS
            {
                Contract.Assert(arrayLength == cultureNames.Length + 2, "CultureData.nativeEnumCultureNames() Incorrect array size");
                cultures[cultureNames.Length] = new CultureInfo("zh-CHS");
                cultures[cultureNames.Length + 1] = new CultureInfo("zh-CHT");
            }
 
#pragma warning restore 618
 
            return cultures;
        }
 
        internal static volatile CultureInfo[] specificCultures;
 
        private static CultureInfo[] SpecificCultures
        {
            get
            {
                if (specificCultures == null)
                    specificCultures = GetCultures(CultureTypes.SpecificCultures);
 
                return specificCultures;
            }
        }
 
#if !FEATURE_CORECLR
        internal bool IsReplacementCulture
        {
            get
            {
                return IsReplacementCultureName(this.SNAME);
            }
        }
 
        internal static volatile String[] s_replacementCultureNames;
 
        ////////////////////////////////////////////////////////////////////////
        //
        // Cache for the known replacement cultures.
        // This is used by CultureInfo.CultureType to check if a culture is a
        // replacement culture.
        //
        ////////////////////////////////////////////////////////////////////////
 
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        private static bool IsReplacementCultureName(String name)
        {
            Contract.Assert(name != null, "IsReplacementCultureName(): name should not be null");
            String[] replacementCultureNames = s_replacementCultureNames;
            if (replacementCultureNames == null)
            {
                if (nativeEnumCultureNames((int)CultureTypes.ReplacementCultures, JitHelpers.GetObjectHandleOnStack(ref replacementCultureNames)) == 0)
                {
                    return false;
                }
 
                // Even if we don't have any replacement cultures, the returned replacementCultureNames will still an empty string array, not null.
                Contract.Assert(name != null, "IsReplacementCultureName(): replacementCultureNames should not be null");
                Array.Sort(replacementCultureNames);
                s_replacementCultureNames = replacementCultureNames;
            }
            return Array.BinarySearch(replacementCultureNames, name) >= 0;
        }
#endif
 
        ////////////////////////////////////////////////////////////////////////
        //
        //  All the accessors
        //
        //  Accessors for our data object items
        //
        ////////////////////////////////////////////////////////////////////////
 
        ///////////
        // Identity //
        ///////////
 
        // The real name used to construct the locale (ie: de-DE_phoneb)
        internal String CultureName
        {
            get
            {
                Contract.Assert(this.sRealName != null, "[CultureData.CultureName] Expected this.sRealName to be populated by COMNlsInfo::nativeInitCultureData 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)
                {
                    case "zh-CHS":
                    case "zh-CHT":
                        return this.sName;
                }
                return this.sRealName;
            }
        }
 
        // Are overrides enabled?
        internal bool UseUserOverride
        {
            get
            {
                return this.bUseOverrides;
            }
        }
 
        // locale name (ie: de-DE, NO sort information)
        internal String SNAME
        {
            get
            {
                //                Contract.Assert(this.sName != null,
                //                    "[CultureData.SNAME] Expected this.sName to be populated by COMNlsInfo::nativeInitCultureData already");
                if (this.sName == null)
                {
                    this.sName = String.Empty;
                }
                return this.sName;
            }
        }
 
        // Parent name (which may be a custom locale/culture)
        internal String SPARENT
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sParent == null)
                {
                    // Ask using the real name, so that we get parents of neutrals
                    this.sParent = DoGetLocaleInfo(this.sRealName, LOCALE_SPARENT);
 
#if !FEATURE_CORECLR
                    // for compatibility, the chain should be:
                    // zh-CN -> zh-CHS -> zh-Hans -> zh
                    // zh-TW -> zh-CHT -> zh-Hant -> zh
                    Contract.Assert(this.sName != "zh-CHS" && this.sName != "zh-CHT",
                                    "sParent should have been initialized for zh-CHS and zh-CHT when they were constructed, otherwise we get recursion");
                    switch (this.sParent)
                    {
                        case "zh-Hans":
                            this.sParent = "zh-CHS";
                            break;
                        case "zh-Hant":
                            this.sParent = "zh-CHT";
                            break;
                    }
#endif
 
                }
                return this.sParent;
            }
        }
 
        // Localized pretty name for this locale (ie: Inglis (estados Unitos))
        internal String SLOCALIZEDDISPLAYNAME
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sLocalizedDisplayName == null)
                {
#if !FEATURE_CORECLR
                    String resourceKey = "Globalization.ci_" + this.sName;
                    if (IsResourcePresent(resourceKey))
                    {
                        this.sLocalizedDisplayName = Environment.GetResourceString(resourceKey);
                    }
#endif
                    // If it hasn't been found (Windows 8 and up), fallback to the system
                    if (String.IsNullOrEmpty(this.sLocalizedDisplayName))
                    {
                        // If its neutral use the language name
                        if (this.IsNeutralCulture)
                        {
                            this.sLocalizedDisplayName = this.SLOCALIZEDLANGUAGE;
                        }
#if FEATURE_LEGACYNETCF
                        // NetCF renders Invariant DisplayName differently from Windows
                        // Quirk it for NetCF apps
                        else if (CompatibilitySwitches.IsAppEarlierThanWindowsPhone8 && object.ReferenceEquals(this, s_Invariant))
                        {
                            this.sLocalizedDisplayName = this.SLOCALIZEDLANGUAGE;
                        }
#endif
                        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))
                            {
                                this.sLocalizedDisplayName = DoGetLocaleInfo(LOCALE_SLOCALIZEDDISPLAYNAME);
                            }
                            if (String.IsNullOrEmpty(this.sLocalizedDisplayName))
                            {
                                this.sLocalizedDisplayName = this.SNATIVEDISPLAYNAME;
                            }
                        }
                    }
                }
                return this.sLocalizedDisplayName;
            }
        }
 
        // English pretty name for this locale (ie: English (United States))
        internal String SENGDISPLAYNAME
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sEnglishDisplayName == null)
                {
                    // If its neutral use the language name
                    if (this.IsNeutralCulture)
                    {
                        this.sEnglishDisplayName = this.SENGLISHLANGUAGE;
#if !FEATURE_CORECLR
                        // differentiate the legacy display names
                        switch (this.sName)
                        {
                            case "zh-CHS":
                            case "zh-CHT":
                                this.sEnglishDisplayName += " Legacy";
                                break;
                        }
#endif
 
                    }
                    else
                    {
                        this.sEnglishDisplayName = DoGetLocaleInfo(LOCALE_SENGLISHDISPLAYNAME);
 
                        // if it isn't found build one:
                        if (String.IsNullOrEmpty(this.sEnglishDisplayName))
                        {
                            // Our existing names mostly look like:
                            // "English" + "United States" -> "English (United States)"
                            // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)"
                            if (this.SENGLISHLANGUAGE.EndsWith(')'))
                            {
                                // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)"
                                this.sEnglishDisplayName =
                                    this.SENGLISHLANGUAGE.Substring(0, this.sEnglishLanguage.Length - 1) +
                                    ", " + this.SENGCOUNTRY + ")";
                            }
                            else
                            {
                                // "English" + "United States" -> "English (United States)"
                                this.sEnglishDisplayName = this.SENGLISHLANGUAGE + " (" + this.SENGCOUNTRY + ")";
                            }
                        }
                    }
                }
                return this.sEnglishDisplayName;
            }
        }
 
        // Native pretty name for this locale (ie: Deutsch (Deutschland))
        internal String SNATIVEDISPLAYNAME
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sNativeDisplayName == null)
                {
                    // If its neutral use the language name
                    if (this.IsNeutralCulture)
                    {
                        this.sNativeDisplayName = this.SNATIVELANGUAGE;
#if !FEATURE_CORECLR
                        // differentiate the legacy display names
                        switch (this.sName)
                        {
                            case "zh-CHS":
                                this.sNativeDisplayName += " \u65E7\u7248";
                                break;
                            case "zh-CHT":
                                this.sNativeDisplayName += " \u820A\u7248";
                                break;
                        }
#endif
                    }
                    else
                    {
#if !FEATURE_CORECLR
                        if (IsIncorrectNativeLanguageForSinhala())
                        {
                            // work around bug in Windows 7 for native name of Sinhala
                            this.sNativeDisplayName ="\x0dc3\x0dd2\x0d82\x0dc4\x0dbd (\x0DC1\x0DCA\x200D\x0DBB\x0DD3\x0020\x0DBD\x0D82\x0D9A\x0DCF)";
                        }
                        else
#endif
                        {
                            this.sNativeDisplayName = DoGetLocaleInfo(LOCALE_SNATIVEDISPLAYNAME);
                        }
 
                        // if it isn't found build one:
                        if (String.IsNullOrEmpty(this.sNativeDisplayName))
                        {
                            // These should primarily be "Deutsch (Deutschland)" type names
                            this.sNativeDisplayName = this.SNATIVELANGUAGE + " (" + this.SNATIVECOUNTRY + ")";
                        }
                    }
                }
                return this.sNativeDisplayName;
            }
        }
 
        // The culture name to be used in CultureInfo.CreateSpecificCulture()
        internal String SSPECIFICCULTURE
        {
            get
            {
                // This got populated when ComNlsInfo::nativeInitCultureData told us we had a culture
                Contract.Assert(this.sSpecificCulture != null, "[CultureData.SSPECIFICCULTURE] Expected this.sSpecificCulture to be populated by COMNlsInfo::nativeInitCultureData already");
                return this.sSpecificCulture;
            }
        }
 
        /////////////
        // Language //
        /////////////
 
        // iso 639 language name, ie: en
        internal String SISO639LANGNAME
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sISO639Language == null)
                {
                    this.sISO639Language = DoGetLocaleInfo(LOCALE_SISO639LANGNAME);
                }
                return this.sISO639Language;
            }
        }
 
#if !FEATURE_CORECLR
        // iso 639 language name, ie: eng
        internal String SISO639LANGNAME2
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sISO639Language2 == null)
                {
                    this.sISO639Language2 = DoGetLocaleInfo(LOCALE_SISO639LANGNAME2);
                }
                return this.sISO639Language2;
            }
        }
 
        // abbreviated windows language name (ie: enu) (non-standard, avoid this)
        internal String SABBREVLANGNAME
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sAbbrevLang == null)
                {
                    this.sAbbrevLang = DoGetLocaleInfo(LOCALE_SABBREVLANGNAME);
                }
                return this.sAbbrevLang;
            }
        }
#endif
 
        // Localized name for this language (Windows Only) ie: Inglis
        // This is only valid for Windows 8 and higher neutrals:
        internal String SLOCALIZEDLANGUAGE
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sLocalizedLanguage == null)
                {
                    if (CultureInfo.UserDefaultUICulture.Name.Equals(Thread.CurrentThread.CurrentUICulture.Name))
                    {
                        this.sLocalizedLanguage = DoGetLocaleInfo(LOCALE_SLOCALIZEDLANGUAGENAME);
                    }
                    // Some OS's might not have this resource or LCTYPE
                    if (String.IsNullOrEmpty(this.sLocalizedLanguage))
                    {
                        this.sLocalizedLanguage = SNATIVELANGUAGE;
                    }
                }
 
                return this.sLocalizedLanguage;
            }
        }
 
        // English name for this language (Windows Only) ie: German
        internal String SENGLISHLANGUAGE
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sEnglishLanguage == null)
                {
                    this.sEnglishLanguage = DoGetLocaleInfo(LOCALE_SENGLISHLANGUAGENAME);
                }
                return this.sEnglishLanguage;
            }
        }
 
        // Native name of this language (Windows Only) ie: Deutsch
        internal String SNATIVELANGUAGE
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sNativeLanguage == null)
                {
#if !FEATURE_CORECLR
                    if (IsIncorrectNativeLanguageForSinhala())
                    {
                        // work around bug in Windows 7 for native language of Sinhala
                        this.sNativeLanguage = "\x0dc3\x0dd2\x0d82\x0dc4\x0dbd";
                    }
                    else
#endif
                    {
                        this.sNativeLanguage = DoGetLocaleInfo(LOCALE_SNATIVELANGUAGENAME);
                    }
                }
                return this.sNativeLanguage;
            }
        }
 
#if !FEATURE_CORECLR
        private bool IsIncorrectNativeLanguageForSinhala()
        {
            return IsOsWin7OrPrior()
                && (sName == "si-LK" || sName == "si")
                && !IsReplacementCulture;
        }
#endif
 
        ///////////
        // Region //
        ///////////
 
        // region name (eg US)
        internal String SREGIONNAME
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sRegionName == null)
                {
                    this.sRegionName = DoGetLocaleInfo(LOCALE_SISO3166CTRYNAME);
                }
                return this.sRegionName;
            }
        }
 
        // (user can override) ---- code (RegionInfo)
#if !FEATURE_CORECLR
        internal int ICOUNTRY
        {
            get
            {
                return DoGetLocaleInfoInt(LOCALE_ICOUNTRY);
            }
        }
#endif
 
        // GeoId
        internal int IGEOID
        {
            get
            {
                if (this.iGeoId == undef)
                {
                    this.iGeoId = DoGetLocaleInfoInt(LOCALE_IGEOID);
                }
                return this.iGeoId;
            }
        }
 
        // localized name for the ----
        internal string SLOCALIZEDCOUNTRY
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sLocalizedCountry == null)
                {
#if !FEATURE_CORECLR
                    String resourceKey = "Globalization.ri_" + this.SREGIONNAME;
                    if (IsResourcePresent(resourceKey))
                    {
                        this.sLocalizedCountry = Environment.GetResourceString(resourceKey);
                    }
#endif
                    // If it hasn't been found (Windows 8 and up), fallback to the system
                    if (String.IsNullOrEmpty(this.sLocalizedCountry))
                    {
                        // 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;
                        }
                    }
                }
                return this.sLocalizedCountry;
            }
        }
 
        // english ---- name (RegionInfo) ie: Germany
        internal String SENGCOUNTRY
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sEnglishCountry == null)
                {
                    this.sEnglishCountry = DoGetLocaleInfo(LOCALE_SENGLISHCOUNTRYNAME);
                }
                return this.sEnglishCountry;
            }
        }
 
        // native ---- name (RegionInfo) ie: Deutschland
        internal String SNATIVECOUNTRY
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sNativeCountry == null)
                {
                    this.sNativeCountry = DoGetLocaleInfo(LOCALE_SNATIVECOUNTRYNAME);
                }
                return this.sNativeCountry;
            }
        }
 
        // ISO 3166 ---- Name
        internal String SISO3166CTRYNAME
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sISO3166CountryName == null)
                {
                    this.sISO3166CountryName = DoGetLocaleInfo(LOCALE_SISO3166CTRYNAME);
                }
                return this.sISO3166CountryName;
            }
        }
 
#if !FEATURE_CORECLR
        // ISO 3166 ---- Name
        internal String SISO3166CTRYNAME2
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sISO3166CountryName2 == null)
                {
                    this.sISO3166CountryName2 = DoGetLocaleInfo(LOCALE_SISO3166CTRYNAME2);
                }
                return this.sISO3166CountryName2;
            }
        }
 
        // abbreviated ---- Name (windows version, non-standard, avoid)
        internal String SABBREVCTRYNAME
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sAbbrevCountry == null)
                {
                    this.sAbbrevCountry = DoGetLocaleInfo(LOCALE_SABBREVCTRYNAME);
                }
                return this.sAbbrevCountry;
            }
        }
 
#if !FEATURE_CORECLR
        // Default ----
        private int IDEFAULTCOUNTRY
        {
            get
            {
                return DoGetLocaleInfoInt(LOCALE_IDEFAULTCOUNTRY);
            }
        }
#endif
 
        // Console fallback name (ie: locale to use for console apps for unicode-only locales)
        internal int IINPUTLANGUAGEHANDLE
        {
            get
            {
                if (this.iInputLanguageHandle == undef)
                {
                    if (IsSupplementalCustomCulture)
                    {
                        // 
                        this.iInputLanguageHandle = 0x0409;
                    }
                    else
                    {
                        // Input Language is same as LCID for built-in cultures
                        this.iInputLanguageHandle = this.ILANGUAGE;
                    }
                }
                return this.iInputLanguageHandle;
            }
        }
 
        // Console fallback name (ie: locale to use for console apps for unicode-only locales)
        internal String SCONSOLEFALLBACKNAME
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sConsoleFallbackName == null)
                {
                    string consoleFallbackName = DoGetLocaleInfo(LOCALE_SCONSOLEFALLBACKNAME);
                    if (consoleFallbackName == "es-ES_tradnl")
                    {
                        consoleFallbackName = "es-ES";
                    }
                    this.sConsoleFallbackName = consoleFallbackName;
                }
                return this.sConsoleFallbackName;
            }
        }
#endif
 
        /////////////
        // Numbers //
        ////////////
 
        //                internal String sPositiveSign            ; // (user can override) positive sign
        //                internal String sNegativeSign            ; // (user can override) negative sign
        //                internal String[] saNativeDigits         ; // (user can override) native characters for digits 0-9
        //                internal int iDigitSubstitution       ; // (user can override) Digit substitution 0=context, 1=none/arabic, 2=Native/national (2 seems to be unused) (Windows Only)
        //                internal int iDigits                  ; // (user can override) number of fractional digits
        //                internal int iNegativeNumber          ; // (user can override) negative number format
 
#if !FEATURE_CORECLR
        // Leading zeroes
        private bool ILEADINGZEROS
        {
            get
            {
                return (DoGetLocaleInfoInt(LOCALE_ILZERO) == 1);
            }
        }
#endif
 
 
        // (user can override) grouping of digits
        internal int[] WAGROUPING
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.waGrouping == null
#if !FEATURE_CORECLR
                    || UseUserOverride
#endif
                    )
                {
                    this.waGrouping = ConvertWin32GroupString(DoGetLocaleInfo(LOCALE_SGROUPING));
                }
                return this.waGrouping;
            }
        }
 
 
        //                internal String sDecimalSeparator        ; // (user can override) decimal separator
        //                internal String sThousandSeparator       ; // (user can override) thousands separator
 
        // Not a Number
        internal String SNAN
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sNaN == null)
                {
                    this.sNaN = DoGetLocaleInfo(LOCALE_SNAN);
                }
                return this.sNaN;
            }
        }
 
        // + Infinity
        internal String SPOSINFINITY
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sPositiveInfinity == null)
                {
                    this.sPositiveInfinity = DoGetLocaleInfo(LOCALE_SPOSINFINITY);
                }
                return this.sPositiveInfinity;
            }
        }
 
        // - Infinity
        internal String SNEGINFINITY
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sNegativeInfinity == null)
                {
                    this.sNegativeInfinity = DoGetLocaleInfo(LOCALE_SNEGINFINITY);
                }
                return this.sNegativeInfinity;
            }
        }
 
 
        ////////////
        // Percent //
        ///////////
 
        // Negative Percent (0-3)
        internal int INEGATIVEPERCENT
        {
            get
            {
                if (this.iNegativePercent == undef)
                {
                    // Note that <= Windows Vista this is synthesized by native code
                    this.iNegativePercent = DoGetLocaleInfoInt(LOCALE_INEGATIVEPERCENT);
                }
                return this.iNegativePercent;
            }
        }
 
        // Positive Percent (0-11)
        internal int IPOSITIVEPERCENT
        {
            get
            {
                if (this.iPositivePercent == undef)
                {
                    // Note that <= Windows Vista this is synthesized by native code
                    this.iPositivePercent = DoGetLocaleInfoInt(LOCALE_IPOSITIVEPERCENT);
                }
                return this.iPositivePercent;
            }
        }
 
        // Percent (%) symbol
        internal String SPERCENT
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sPercent == null)
                {
                    // Note that <= Windows Vista this is synthesized by native code
                    this.sPercent = DoGetLocaleInfo(LOCALE_SPERCENT);
                }
                return this.sPercent;
            }
        }
 
        // PerMille (‰) symbol
        internal String SPERMILLE
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sPerMille == null)
                {
                    // Note that <= Windows Vista this is synthesized by native code
                    this.sPerMille = DoGetLocaleInfo(LOCALE_SPERMILLE);
                }
                return this.sPerMille;
            }
        }
 
        /////////////
        // Currency //
        /////////////
 
        // (user can override) local monetary symbol, eg: $
        internal String SCURRENCY
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sCurrency == null
#if !FEATURE_CORECLR
                    || UseUserOverride
#endif
                    )
                {
                    this.sCurrency = DoGetLocaleInfo(LOCALE_SCURRENCY);
                }
                return this.sCurrency;
            }
        }
 
        // international monetary symbol (RegionInfo), eg: USD
        internal String SINTLSYMBOL
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sIntlMonetarySymbol == null)
                {
                    this.sIntlMonetarySymbol = DoGetLocaleInfo(LOCALE_SINTLSYMBOL);
                }
                return this.sIntlMonetarySymbol;
            }
        }
 
        // English name for this currency (RegionInfo), eg: US Dollar
        internal String SENGLISHCURRENCY
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sEnglishCurrency == null)
                {
                    this.sEnglishCurrency = DoGetLocaleInfo(LOCALE_SENGCURRNAME);
                }
                return this.sEnglishCurrency;
            }
        }
 
        // Native name for this currency (RegionInfo), eg: Schweiz Frank
        internal String SNATIVECURRENCY
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sNativeCurrency == null)
                {
                    this.sNativeCurrency = DoGetLocaleInfo(LOCALE_SNATIVECURRNAME);
                }
                return this.sNativeCurrency;
            }
        }
 
        //                internal int iCurrencyDigits          ; // (user can override) # local monetary fractional digits
        //                internal int iCurrency                ; // (user can override) positive currency format
        //                internal int iNegativeCurrency        ; // (user can override) negative currency format
 
        // (user can override) monetary grouping of digits
        internal int[] WAMONGROUPING
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.waMonetaryGrouping == null
#if !FEATURE_CORECLR
                    || UseUserOverride
#endif
                    )
                {
                    this.waMonetaryGrouping = ConvertWin32GroupString(DoGetLocaleInfo(LOCALE_SMONGROUPING));
                }
                return this.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
#if !FEATURE_CORECLR
                    || UseUserOverride
#endif
                    )
                {
                    this.iMeasure = DoGetLocaleInfoInt(LOCALE_IMEASURE);
                }
                return this.iMeasure;
            }
        }
 
        // (user can override) list Separator
        internal String SLIST
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sListSeparator == null
#if !FEATURE_CORECLR
                    || UseUserOverride
#endif
                    )
                {
                    this.sListSeparator = DoGetLocaleInfo(LOCALE_SLIST);
                }
                return this.sListSeparator;
            }
        }
 
#if !FEATURE_CORECLR
        // Paper size
        private int IPAPERSIZE
        {
            get
            {
                return DoGetLocaleInfoInt(LOCALE_IPAPERSIZE);
            }
        }
#endif
 
        ////////////////////////////
        // Calendar/Time (Gregorian) //
        ////////////////////////////
 
        // (user can override) AM designator
        internal String SAM1159
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sAM1159 == null
#if !FEATURE_CORECLR
                    || UseUserOverride
#endif
                    )
                {
                    this.sAM1159 = DoGetLocaleInfo(LOCALE_S1159);
                }
                return this.sAM1159;
            }
        }
 
        // (user can override) PM designator
        internal String SPM2359
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                if (this.sPM2359 == null
#if !FEATURE_CORECLR
                    || UseUserOverride
#endif
                    )
                {
                    this.sPM2359 = DoGetLocaleInfo(LOCALE_S2359);
                }
                return this.sPM2359;
            }
        }
 
        // (user can override) time format
        internal String[] LongTimes
        {
            get
            {
                if (this.saLongTimes == null
#if !FEATURE_CORECLR
                    || UseUserOverride
#endif
                    )
                {
                    String[] longTimes = DoEnumTimeFormats();
                    if (longTimes == null || longTimes.Length == 0)
                    {
                        this.saLongTimes = Invariant.saLongTimes;
                    }
                    else
                    {
                        this.saLongTimes = longTimes;
                    }
                }
                return this.saLongTimes;
            }
        }
 
        // short time format
        // Short times (derived from long times format)
        // 
        internal String[] ShortTimes
        {
            get
            {
                if (this.saShortTimes == null
#if !FEATURE_CORECLR
                    || UseUserOverride
#endif
                    )
                {
                    // Try to get the short times from the OS/culture.dll
                    String[] shortTimes = DoEnumShortTimeFormats();
 
                    if (shortTimes == null || shortTimes.Length == 0)
                    {
                        //
                        // If we couldn't find short times, then compute them from long times
                        // (eg: CORECLR on < Win7 OS & fallback for missing culture.dll)
                        //
                        shortTimes = DeriveShortTimesFromLong();
                    }
 
                    // Found short times, use them
                    this.saShortTimes = shortTimes;
                }
                return this.saShortTimes;
            }
        }
 
        private string[] DeriveShortTimesFromLong()
        {
            // Our logic is to look for h,H,m,s,t.  If we find an s, then we check the string
            // between it and the previous marker, if any.  If its a short, unescaped separator,
            // then we don't retain that part.
            // We then check after the ss and remove anything before the next h,H,m,t...
            string[] shortTimes = new string[LongTimes.Length];
 
            for (int i = 0; i < LongTimes.Length; i++)
            {
                shortTimes[i] = StripSecondsFromPattern(LongTimes[i]);
            }
            return shortTimes;
        }
 
        private static string StripSecondsFromPattern(string time)
        {
            bool bEscape = false;
            int iLastToken = -1;
 
            // Find the seconds
            for (int j = 0; j < time.Length; j++)
            {
                // Change escape mode?
                if (time[j] == '\'')
                {
                    // Continue
                    bEscape = !bEscape;
                    continue;
                }
 
                // See if there was a single \
                if (time[j] == '\\')
                {
                    // Skip next char
                    j++;
                    continue;
                }
 
                if (bEscape)
                {
                    continue;
                }
 
                switch (time[j])
                {
                    // Check for seconds
                    case 's':
                        // Found seconds, see if there was something unescaped and short between
                        // the last marker and the seconds.  Windows says separator can be a
                        // maximum of three characters (without null)
                        // If 1st or last characters were ', then ignore it
                        if ((j - iLastToken) <= 4 && (j - iLastToken) > 1 &&
                            (time[iLastToken + 1] != '\'') &&
                            (time[j - 1] != '\''))
                        {
                            // There was something there we want to remember
                            if (iLastToken >= 0)
                            {
                                j = iLastToken + 1;
                            }
                        }
 
                        bool containsSpace;
                        int endIndex = GetIndexOfNextTokenAfterSeconds(time, j, out containsSpace);
                        StringBuilder sb = new StringBuilder(time.Substring(0, j));
                        if (containsSpace)
                        {
                            sb.Append(' ');
                        }
                        sb.Append(time.Substring(endIndex));
                        time = sb.ToString();
                        break;
                    case 'm':
                    case 'H':
                    case 'h':
                        iLastToken = j;
                        break;
                }
            }
            return time;
        }
 
        private static int GetIndexOfNextTokenAfterSeconds(string time, int index, out bool containsSpace)
        {
            bool bEscape = false;
            containsSpace = false;
            for (; index < time.Length; index++)
            {
                switch (time[index])
                {
                    case '\'':
                        bEscape = !bEscape;
                        continue;
                    case '\\':
                        index++;
                        if (time[index] == ' ')
                        {
                            containsSpace = true;
                        }
                        continue;
                    case ' ':
                        containsSpace = true;
                        break;
                    case 't':
                    case 'm':
                    case 'H':
                    case 'h':
                        if (bEscape)
                        {
                            continue;
                        }
                        return index;
                }
            }
            containsSpace = false;
            return index;
        }
 
        // time duration format
        internal String[] SADURATION
        {
            [System.Security.SecurityCritical]  // auto-generated
            get
            {
                // 
                if (this.saDurationFormats == null)
                {
                    String durationFormat = DoGetLocaleInfo(LOCALE_SDURATION);
                    this.saDurationFormats = new String[] { ReescapeWin32String(durationFormat) };
                }
                return this.saDurationFormats;
            }
        }
 
        // (user can override) first day of week
        internal int IFIRSTDAYOFWEEK
        {
            get
            {
                if (this.iFirstDayOfWeek == undef
#if !FEATURE_CORECLR
                    || UseUserOverride
#endif
                    )
                {
                    // Have to convert it from windows to .Net formats
                    this.iFirstDayOfWeek = ConvertFirstDayOfWeekMonToSun(DoGetLocaleInfoInt(LOCALE_IFIRSTDAYOFWEEK));
                }
                return this.iFirstDayOfWeek;
            }
        }
 
        // (user can override) first week of year
        internal int IFIRSTWEEKOFYEAR
        {
            get
            {
                if (this.iFirstWeekOfYear == undef
#if !FEATURE_CORECLR
                    || UseUserOverride
#endif
                    )
                {
                    this.iFirstWeekOfYear = DoGetLocaleInfoInt(LOCALE_IFIRSTWEEKOFYEAR);
                }
                return this.iFirstWeekOfYear;
            }
        }
 
        // (user can override default only) short date format
        internal String[] ShortDates(int calendarId)
        {
            return GetCalendar(calendarId).saShortDates;
        }
 
        // (user can override default only) long date format
        internal String[] LongDates(int calendarId)
        {
            return GetCalendar(calendarId).saLongDates;
        }
 
        // (user can override) date year/month format.
        internal String[] YearMonths(int calendarId)
        {
            return GetCalendar(calendarId).saYearMonths;
        }
 
        // day names
        internal string[] DayNames(int calendarId)
        {
            return GetCalendar(calendarId).saDayNames;
        }
 
        // abbreviated day names
        internal string[] AbbreviatedDayNames(int 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)
        {
            return GetCalendar(calendarId).saSuperShortDayNames;
        }
 
        // month names
        internal string[] MonthNames(int calendarId)
        {
            return GetCalendar(calendarId).saMonthNames;
        }
 
        // Genitive month names
        internal string[] GenitiveMonthNames(int calendarId)
        {
            return GetCalendar(calendarId).saMonthGenitiveNames;
        }
 
        // month names
        internal string[] AbbreviatedMonthNames(int calendarId)
        {
            return GetCalendar(calendarId).saAbbrevMonthNames;
        }
 
        // Genitive month names
        internal string[] AbbreviatedGenitiveMonthNames(int calendarId)
        {
            return GetCalendar(calendarId).saAbbrevMonthGenitiveNames;
        }
 
        // 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)
        {
            return GetCalendar(calendarId).saLeapYearMonthNames;
        }
 
        // month/day format (single string, no override)
        internal String MonthDay(int calendarId)
        {
            return GetCalendar(calendarId).sMonthDay;
        }
 
 
 
        /////////////
        // Calendars //
        /////////////
 
        // all available calendar type(s), The first one is the default calendar.
        internal int[] CalendarIds
        {
            get
            {
                if (this.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];
                    Contract.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);
 
                    // See if we had a calendar to add.
                    if (count == 0)
                    {
                        // Failed for some reason, just grab Gregorian from Invariant
                        this.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")
                        {
                            bool found = false;
 
                            // Do we need to insert calendar 4?
                            for (int i = 0; i < count; i++)
                            {
                                // Stop if we found calendar four
                                if (calendarInts[i] == Calendar.CAL_TAIWAN)
                                {
                                    found = true;
                                    break;
                                }
                            }
 
                            // If not found then insert it
                            if (!found)
                            {
                                // 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;
                            }
                        }
 
                        // It worked, remember the list
                        int[] temp = new int[count];
                        Array.Copy(calendarInts, 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 FEATURE_CORECLR
                        if (temp.Length > 1)
                        {
                            int i = DoGetLocaleInfoInt(LOCALE_ICALENDARTYPE);
                            if (temp[1] == i)
                            {
                                temp[1] = temp[0];
                                temp[0] = i;
                            }
                        }
#endif
 
                        this.waCalendars = temp;
                    }
                }
 
                return this.waCalendars;
            }
        }
 
        // Native calendar names.  index of optional calendar - 1, empty if no optional calendar at that number
        internal String CalendarName(int calendarId)
        {
            // Get the calendar
            return GetCalendar(calendarId).sNativeName;
        }
 
        internal CalendarData GetCalendar(int calendarId)
        {
            Contract.Assert(calendarId > 0 && calendarId <= CalendarData.MAX_CALENDARS,
                "[CultureData.GetCalendar] Expect calendarId to be in a valid range");
 
            // arrays are 0 based, calendarIds are 1 based
            int calendarIndex = calendarId - 1;
 
            // Have to have calendars
            if (calendars == null)
            {
                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];
            // Make sure that calendar has data
            if (calendarData == null
#if !FEATURE_CORECLR
                || UseUserOverride
#endif
                )
            {
                Contract.Assert(this.sWindowsName != null, "[CultureData.GetCalendar] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
                calendarData = new CalendarData(this.sWindowsName, calendarId, this.UseUserOverride);
#if !FEATURE_CORECLR
                //Work around issue where Win7 data for MonthDay contains invalid two sets of data separated by semicolon
                //even though MonthDay is not enumerated
                if (IsOsWin7OrPrior() && !IsSupplementalCustomCulture && !IsReplacementCulture)
                {
                    calendarData.FixupWin7MonthDaySemicolonBug();
                }
#endif
                calendars[calendarIndex] = calendarData;
            }
 
            return calendarData;
        }
 
        internal int CurrentEra(int calendarId)
        {
            return GetCalendar(calendarId).iCurrentEra;
        }
 
        ///////////////////
        // Text Information //
        ///////////////////
 
        // IsRightToLeft
        internal bool IsRightToLeft
        {
            get
            {
                // 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
                return (this.IREADINGLAYOUT == 1);
            }
        }
 
        // IREADINGLAYOUT
        // 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
        //
        // If exposed as a public API, we'd have an enum with those 4 values
        private int IREADINGLAYOUT
        {
            get
            {
                if (this.iReadingLayout == undef)
                {
                    Contract.Assert(this.sRealName != null, "[CultureData.IsRightToLeft] Expected this.sRealName to be populated by COMNlsInfo::nativeInitCultureData already");
                    this.iReadingLayout = DoGetLocaleInfoInt(LOCALE_IREADINGLAYOUT);
                }
 
                return (this.iReadingLayout);
            }
        }
 
        // The TextInfo name never includes that alternate sort and is always specific
        // For customs, it uses the SortLocale (since the textinfo is not exposed in Win7)
        // en -> en-US
        // en-US -> en-US
        // fj (custom neutral) -> en-US (assuming that en-US is the sort locale for fj)
        // fj_FJ (custom specific) -> en-US (assuming that en-US is the sort locale for fj-FJ)
        // es-ES_tradnl -> es-ES
        internal String STEXTINFO               // Text info name to use for text information
        {
#if !FEATURE_CORECLR
            [System.Security.SecuritySafeCritical]
#endif
            get
            {
#if FEATURE_CORECLR
                // 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.
                Contract.Assert(this.sWindowsName != null, "[CultureData.STEXTINFO] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
                return (this.sWindowsName);
#else
                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;
#endif
            }
        }
 
        // Compare info name (including sorting key) to use if custom
        internal String SCOMPAREINFO
        {
#if !FEATURE_CORECLR
            [System.Security.SecuritySafeCritical]
#endif
            get
            {
#if FEATURE_CORECLR
                // Note: Custom cultures might point at another culture's compareinfo, however windows knows how
                // to redirect it to the desired compareinfo culture, so this is OK.
                Contract.Assert(this.sWindowsName != null, "[CultureData.SCOMPAREINFO] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
                return (this.sWindowsName);
#else
                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;
#endif
            }
        }
 
        internal bool IsSupplementalCustomCulture
        {
            get
            {
#if FEATURE_CORECLR
                return false;
#else
                return IsCustomCultureId(this.ILANGUAGE);
#endif
            }
        }
 
#if !FEATURE_CORECLR
        // Typical Scripts for this locale (latn;cyrl; etc)
        // 
 
        private String SSCRIPTS
        {
            [System.Security.SecuritySafeCritical]  // auto-generated
            get
            {
                if (this.sScripts == null)
                {
                    this.sScripts = DoGetLocaleInfo(LOCALE_SSCRIPTS);
                }
                return this.sScripts;
            }
        }
 
        private String SOPENTYPELANGUAGETAG
        {
            [System.Security.SecuritySafeCritical]  // auto-generated
            get
            {
                return DoGetLocaleInfo(LOCALE_SOPENTYPELANGUAGETAG);
            }
        }
 
        private String FONTSIGNATURE
        {
            [System.Security.SecuritySafeCritical]  // auto-generated
            get
            {
                if (this.fontSignature == null)
                {
                    this.fontSignature = DoGetLocaleInfo(LOCALE_FONTSIGNATURE);
                }
                return this.fontSignature;
            }
        }
 
        private String SKEYBOARDSTOINSTALL
        {
            [System.Security.SecuritySafeCritical]  // auto-generated
            get
            {
                return DoGetLocaleInfo(LOCALE_SKEYBOARDSTOINSTALL);
            }
        }
 
#endif
 
#if !FEATURE_CORECLR
        internal int IDEFAULTANSICODEPAGE   // default ansi code page ID (ACP)
        {
            get
            {
                if (this.iDefaultAnsiCodePage == undef)
                {
                    this.iDefaultAnsiCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTANSICODEPAGE);
                }
                return this.iDefaultAnsiCodePage;
            }
        }
 
        internal int IDEFAULTOEMCODEPAGE   // default oem code page ID (OCP or OEM)
        {
            get
            {
                if (this.iDefaultOemCodePage == undef)
                {
                    this.iDefaultOemCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTCODEPAGE);
                }
                return this.iDefaultOemCodePage;
            }
        }
 
        internal int IDEFAULTMACCODEPAGE   // default macintosh code page
        {
            get
            {
                if (this.iDefaultMacCodePage == undef)
                {
                    this.iDefaultMacCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTMACCODEPAGE);
                }
                return this.iDefaultMacCodePage;
            }
        }
 
        internal int IDEFAULTEBCDICCODEPAGE   // default EBCDIC code page
        {
            get
            {
                if (this.iDefaultEbcdicCodePage == undef)
                {
                    this.iDefaultEbcdicCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTEBCDICCODEPAGE);
                }
                return this.iDefaultEbcdicCodePage;
            }
        }
 
        // Obtain locale name from LCID
        // NOTE: This will get neutral names, unlike the OS API
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [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)
                {
                    Contract.Assert(this.sRealName != null, "[CultureData.ILANGUAGE] Expected this.sRealName to be populated by COMNlsInfo::nativeInitCultureData already");
                    this.iLanguage = LocaleNameToLCID(this.sRealName);
                }
                return this.iLanguage;
            }
        }
 
        internal bool IsWin32Installed
        {
            get { return this.bWin32Installed; }
        }
 
        internal bool IsFramework
        {
            get { return this.bFramework; }
        }
#endif // !FEATURE_CORECLR
 
        ////////////////////
        // Derived properties //
        ////////////////////
 
        internal bool IsNeutralCulture
        {
            get
            {
                // NlsInfo::nativeInitCultureData told us if we're neutral or not
                return this.bNeutral;
            }
        }
 
        internal bool IsInvariantCulture
        {
            get
            {
                return String.IsNullOrEmpty(this.SNAME);
            }
        }
 
        // Get an instance of our default calendar
        internal Calendar DefaultCalendar
        {
            get
            {
                int defaultCalId = DoGetLocaleInfoInt(LOCALE_ICALENDARTYPE);
                if (defaultCalId == 0)
                {
                    defaultCalId = this.CalendarIds[0];
                }
 
                return CultureInfo.GetCalendarInstance(defaultCalId);
            }
        }
 
        // All of our era names
        internal String[] EraNames(int calendarId)
        {
            Contract.Assert(calendarId > 0, "[CultureData.saEraNames] Expected Calendar.ID > 0");
 
            return this.GetCalendar(calendarId).saEraNames;
        }
 
        internal String[] AbbrevEraNames(int calendarId)
        {
            Contract.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0");
 
            return this.GetCalendar(calendarId).saAbbrevEraNames;
        }
 
        internal String[] AbbreviatedEnglishEraNames(int calendarId)
        {
            Contract.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.
 
 
        // Time separator (derived from time format)
        internal String TimeSeparator
        {
            [System.Security.SecuritySafeCritical]  // auto-generated
            get
            {
                if (sTimeSeparator == null
#if !FEATURE_CORECLR
                    || UseUserOverride
#endif
                    )
                {
                    string longTimeFormat = ReescapeWin32String(DoGetLocaleInfo(LOCALE_STIMEFORMAT));
                    if (String.IsNullOrEmpty(longTimeFormat))
                    {
                        longTimeFormat = LongTimes[0];
                    }
 
                    // Compute STIME from time format
                    sTimeSeparator = GetTimeSeparator(longTimeFormat);
                }
                return sTimeSeparator;
            }
        }
 
        // Date separator (derived from short date format)
        internal String DateSeparator(int calendarId)
        {
            if (calendarId == Calendar.CAL_JAPAN && !AppContextSwitches.EnforceLegacyJapaneseDateParsing)
            {
                // The date separator is derived from the default short date pattern. So far this pattern is using
                // '/' as date separator when using the Japanese calendar which make the formatting and parsing work fine.
                // changing the default pattern is likely will happen in the near future which can easily break formatting
                // and parsing.
                // We are forcing here the date separator to '/' to ensure the parsing is not going to break when changing
                // the default short date pattern. The application still can override this in the code by DateTimeFormatInfo.DateSeparartor.
                return "/";
            }
 
            return GetDateSeparator(ShortDates(calendarId)[0]);
        }
 
        //////////////////////////////////////
        // Helper Functions to get derived properties //
        //////////////////////////////////////
 
        ////////////////////////////////////////////////////////////////////////////
        //
        // Unescape a NLS style quote string
        //
        // This removes single quotes:
        //      'fred' -> fred
        //      'fred -> fred
        //      fred' -> fred
        //      fred's -> freds
        //
        // This removes the first \ of escaped characters:
        //      fred\'s -> fred's
        //      a\\b -> a\b
        //      a\b -> ab
        //
        // We don't build the stringbuilder unless we find a ' or a \.  If we find a ' or a \, we
        // always build a stringbuilder because we need to remove the ' or \.
        //
        ////////////////////////////////////////////////////////////////////////////
        static private String UnescapeNlsString(String str, int start, int end)
        {
            Contract.Requires(str != null);
            Contract.Requires(start >= 0);
            Contract.Requires(end >= 0);
            StringBuilder result = null;
 
            for (int i = start; i < str.Length && i <= end; i++)
            {
                switch (str[i])
                {
                    case '\'':
                        if (result == null)
                        {
                            result = new StringBuilder(str, start, i - start, str.Length);
                        }
                        break;
                    case '\\':
                        if (result == null)
                        {
                            result = new StringBuilder(str, start, i - start, str.Length);
                        }
                        ++i;
                        if (i < str.Length)
                        {
                            result.Append(str[i]);
                        }
                        break;
                    default:
                        if (result != null)
                        {
                            result.Append(str[i]);
                        }
                        break;
                }
            }
 
            if (result == null)
                return (str.Substring(start, end - start + 1));
 
            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)
        {
            // Time format separator (ie: : in 12:39:00)
            //
            // We calculate this from the provided time format
            //
 
            //
            //  Find the time separator so that we can pretend we know STIME.
            //
            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)
        {
            // Date format separator (ie: / in 9/1/03)
            //
            // We calculate this from the provided short date
            //
 
            //
            //  Find the date separator so that we can pretend we know SDATE.
            //
            return GetSeparator(format, "dyM");
        }
 
        private static string GetSeparator(string format, string timeParts)
        {
            int index = IndexOfTimePart(format, 0, timeParts);
 
            if (index != -1)
            {
                // Found a time part, find out when it changes
                char cTimePart = format[index];
 
                do
                {
                    index++;
                } while (index < format.Length && format[index] == cTimePart);
 
                int separatorStart = index;
 
                // Now we need to find the end of the separator
                if (separatorStart < format.Length)
                {
                    int separatorEnd = IndexOfTimePart(format, separatorStart, timeParts);
                    if (separatorEnd != -1)
                    {
                        // From [separatorStart, count) is our string, except we need to unescape
                        return UnescapeNlsString(format, separatorStart, separatorEnd - 1);
                    }
                }
            }
 
            return String.Empty;
        }
 
        private static int IndexOfTimePart(string format, int startIndex, string timeParts)
        {
            Contract.Assert(startIndex >= 0, "startIndex cannot be negative");
            Contract.Assert(timeParts.IndexOfAny(new char[] { '\'', '\\' }) == -1, "timeParts cannot include quote characters");
            bool inQuote = false;
            for (int i = startIndex; i < format.Length; ++i)
            {
                // See if we have a time Part
                if (!inQuote && timeParts.IndexOf(format[i]) != -1)
                {
                    return i;
                }
                switch (format[i])
                {
                    case '\\':
                        if (i + 1 < format.Length)
                        {
                            ++i;
                            switch (format[i])
                            {
                                case '\'':
                                case '\\':
                                    break;
                                default:
                                    --i; //backup since we will move over this next
                                    break;
                            }
                        }
                        break;
                    case '\'':
                        inQuote = !inQuote;
                        break;
                }
            }
 
            return -1;
        }
 
        [System.Security.SecurityCritical]
        string DoGetLocaleInfo(uint lctype)
        {
            Contract.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.
        [System.Security.SecurityCritical]  // auto-generated
        string DoGetLocaleInfo(string localeName, uint lctype)
        {
            // Fix lctype if we don't want overrides
            if (!UseUserOverride)
            {
                lctype |= LOCALE_NOUSEROVERRIDE;
            }
 
            // Ask OS for data
            Contract.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.
            Contract.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
            Contract.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
            Contract.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;
        }
 
        ////////////////////////////////////////////////////////////////////////////
        //
        // 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.
        //
        ////////////////////////////////////////////////////////////////////////////
        [System.Security.SecurityCritical]  // auto-generated
        internal void GetNFIValues(NumberFormatInfo nfi)
        {
            if (this.IsInvariantCulture)
            {
                nfi.positiveSign = this.sPositiveSign;
                nfi.negativeSign = this.sNegativeSign;
 
#if !FEATURE_CORECLR
                nfi.nativeDigits = this.saNativeDigits;
                nfi.digitSubstitution = this.iDigitSubstitution;
#endif // !FEATURE_CORECLR
 
                nfi.numberGroupSeparator = this.sThousandSeparator;
                nfi.numberDecimalSeparator = this.sDecimalSeparator;
                nfi.numberDecimalDigits = this.iDigits;
                nfi.numberNegativePattern = this.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;
            }
            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
                //
 
                //
                // Ask native side for our data.
                //
                Contract.Assert(this.sWindowsName != null, "[CultureData.GetNFIValues] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
                CultureData.nativeGetNumberFormatInfoValues(this.sWindowsName, nfi, UseUserOverride);
            }
 
 
            //
            // Gather additional data
            //
            nfi.numberGroupSizes = this.WAGROUPING;
            nfi.currencyGroupSizes = this.WAMONGROUPING;
 
            // prefer the cached value since these do not have user overrides
            nfi.percentNegativePattern = this.INEGATIVEPERCENT;
            nfi.percentPositivePattern = this.IPOSITIVEPERCENT;
            nfi.percentSymbol = this.SPERCENT;
            nfi.perMilleSymbol = this.SPERMILLE;
 
            nfi.negativeInfinitySymbol = this.SNEGINFINITY;
            nfi.positiveInfinitySymbol = this.SPOSINFINITY;
            nfi.nanSymbol = this.SNAN;
 
            //
            // We don't have percent values, so use the number values
            //
            nfi.percentDecimalDigits = nfi.numberDecimalDigits;
            nfi.percentDecimalSeparator = nfi.numberDecimalSeparator;
            nfi.percentGroupSizes = nfi.numberGroupSizes;
            nfi.percentGroupSeparator = nfi.numberGroupSeparator;
 
            //
            // Clean up a few odd values
            //
 
            // Windows usually returns an empty positive sign, but we like it to be "+"
            if (nfi.positiveSign == null || nfi.positiveSign.Length == 0) nfi.positiveSign = "+";
 
            //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 hack this here because our default currency format will never use nfi.
            if (nfi.currencyDecimalSeparator == null || nfi.currencyDecimalSeparator.Length == 0)
            {
                nfi.currencyDecimalSeparator = nfi.numberDecimalSeparator;
            }
 
#if !FEATURE_CORECLR
            // 
            if ((932 == this.IDEFAULTANSICODEPAGE) ||
               (949 == this.IDEFAULTANSICODEPAGE))
            {
                // Legacy behavior for cultures that use Japanese/Korean default ANSI code pages
                // Note that this is a code point, not a character.  On Japanese/Korean machines this
                // will be rendered as their currency symbol, not rendered as a "\"
                nfi.ansiCurrencySymbol = "\x5c";
            }
#endif // !FEATURE_CORECLR
        }
 
        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);
 
            for (int ich = 0; ich < testString.Length; ich++)
            {
                char ch = testString[ich];
                sb.Append(ch <= 'Z' && ch >= 'A' ? (char)(ch - 'A' + 'a') : ch);
            }
 
            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)
            {
                return (new int[] { 3 });
            }
 
            if (win32Str[0] == '0')
            {
                return (new int[] { 0 });
            }
 
            // 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;
            }
 
            int i;
            int j;
            for (i = 0, j = 0; i < win32Str.Length && j < values.Length; i += 2, j++)
            {
                // 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');
            }
 
            return (values);
        }
 
        // 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.)
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern bool nativeInitCultureData(CultureData cultureData);
 
        // Grab the NumberFormatInfo data
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        internal static extern bool nativeGetNumberFormatInfoValues(String localeName, NumberFormatInfo nfi, bool useUserOverride);
 
        [System.Security.SecuritySafeCritical]  // auto-generated
        [ResourceExposure(ResourceScope.None)]
        [MethodImplAttribute(MethodImplOptions.InternalCall)]
        private static extern String[] nativeEnumTimeFormats(String localeName, uint dwFlags, bool useUserOverride);
 
        [System.Security.SecurityCritical]  // auto-generated
        [SuppressUnmanagedCodeSecurityAttribute()]
        [ResourceExposure(ResourceScope.None)]
        [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
        internal static extern int nativeEnumCultureNames(int cultureTypes, ObjectHandleOnStack retStringArray);
    }
}