Merge pull request #7945 from ramarag/MemoryFailPoint
[platform/upstream/coreclr.git] / src / mscorlib / src / System / Globalization / CultureData.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 namespace System.Globalization
6 {
7
8     using System;
9     using System.Collections;
10     using System.Collections.Generic;
11     using System.Text;
12     using System.Threading;
13 #if !FEATURE_CORECLR
14     using System.Reflection;
15     using System.Resources;
16 #endif
17     using System.Runtime.CompilerServices;
18     using System.Runtime.InteropServices;
19     using System.Runtime.Versioning;
20     using System.Diagnostics.Contracts;
21     using System.Security;
22
23     //
24     // List of culture data
25     // Note the we cache overrides.
26     // Note that localized names (resource names) aren't available from here.
27     //
28
29     //
30     // Our names are a tad confusing.
31     //
32     // sWindowsName -- The name that windows thinks this culture is, ie:
33     //                            en-US if you pass in en-US
34     //                            de-DE_phoneb if you pass in de-DE_phoneb
35     //                            fj-FJ if you pass in fj (neutral, on a pre-Windows 7 machine)
36     //                            fj if you pass in fj (neutral, post-Windows 7 machine)
37     //
38     // sRealName -- The name you used to construct the culture, in pretty form
39     //                       en-US if you pass in EN-us
40     //                       en if you pass in en
41     //                       de-DE_phoneb if you pass in de-DE_phoneb
42     //
43     // sSpecificCulture -- The specific culture for this culture
44     //                             en-US for en-US
45     //                             en-US for en
46     //                             de-DE_phoneb for alt sort
47     //                             fj-FJ for fj (neutral)
48     //
49     // sName -- The IETF name of this culture (ie: no sort info, could be neutral)
50     //                en-US if you pass in en-US
51     //                en if you pass in en
52     //                de-DE if you pass in de-DE_phoneb
53     //
54
55     // StructLayout is needed here otherwise compiler can re-arrange the fields.
56     // We have to keep this in-sync with the definition in comnlsinfo.h
57     //
58     // WARNING WARNING WARNING
59     //
60     // WARNING: Anything changed here also needs to be updated on the native side (object.h see type CultureDataBaseObject)
61     // WARNING: The type loader will rearrange class member offsets so the mscorwks!CultureDataBaseObject
62     // WARNING: must be manually structured to match the true loaded class layout
63     //
64     [FriendAccessAllowed]
65     internal class CultureData
66     {
67         const int undef = -1;
68
69         // Override flag
70         private String sRealName; // Name you passed in (ie: en-US, en, or de-DE_phoneb)
71         private String sWindowsName; // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in))
72
73         // Identity
74         private String sName; // locale name (ie: en-us, NO sort info, but could be neutral)
75         private String sParent; // Parent name (which may be a custom locale/culture)
76         private String sLocalizedDisplayName; // Localized pretty name for this locale
77         private String sEnglishDisplayName; // English pretty name for this locale
78         private String sNativeDisplayName; // Native pretty name for this locale
79         private String sSpecificCulture; // The culture name to be used in CultureInfo.CreateSpecificCulture(), en-US form if neutral, sort name if sort
80
81         // Language
82         private String sISO639Language; // ISO 639 Language Name
83         private String sLocalizedLanguage; // Localized name for this language
84         private String sEnglishLanguage; // English name for this language
85         private String sNativeLanguage; // Native name of this language
86
87         // Region
88         private String sRegionName; // (RegionInfo)
89         private int iGeoId = undef; // GeoId
90         private String sLocalizedCountry; // localized country name
91         private String sEnglishCountry; // english country name (RegionInfo)
92         private String sNativeCountry; // native country name
93         private String sISO3166CountryName; // ISO 3166 (RegionInfo), ie: US
94
95         // Numbers
96         private String sPositiveSign; // (user can override) positive sign
97         private String sNegativeSign; // (user can override) negative sign
98         private String[] saNativeDigits; // (user can override) native characters for digits 0-9
99         // (nfi populates these 5, don't have to be = undef)
100         private int iDigitSubstitution; // (user can override) Digit substitution 0=context, 1=none/arabic, 2=Native/national (2 seems to be unused)
101         private int iLeadingZeros; // (user can override) leading zeros 0 = no leading zeros, 1 = leading zeros
102         private int iDigits; // (user can override) number of fractional digits
103         private int iNegativeNumber; // (user can override) negative number format
104         private int[] waGrouping; // (user can override) grouping of digits
105         private String sDecimalSeparator; // (user can override) decimal separator
106         private String sThousandSeparator; // (user can override) thousands separator
107         private String sNaN; // Not a Number
108         private String sPositiveInfinity; // + Infinity
109         private String sNegativeInfinity; // - Infinity
110
111         // Percent
112         private int iNegativePercent = undef; // Negative Percent (0-3)
113         private int iPositivePercent = undef; // Positive Percent (0-11)
114         private String sPercent; // Percent (%) symbol
115         private String sPerMille; // PerMille (‰) symbol
116
117         // Currency
118         private String sCurrency; // (user can override) local monetary symbol
119         private String sIntlMonetarySymbol; // international monetary symbol (RegionInfo)
120         private String sEnglishCurrency; // English name for this currency
121         private String sNativeCurrency; // Native name for this currency
122         // (nfi populates these 4, don't have to be = undef)
123         private int iCurrencyDigits; // (user can override) # local monetary fractional digits
124         private int iCurrency; // (user can override) positive currency format
125         private int iNegativeCurrency; // (user can override) negative currency format
126         private int[] waMonetaryGrouping; // (user can override) monetary grouping of digits
127         private String sMonetaryDecimal; // (user can override) monetary decimal separator
128         private String sMonetaryThousand; // (user can override) monetary thousands separator
129
130         // Misc
131         private int iMeasure = undef; // (user can override) system of measurement 0=metric, 1=US (RegionInfo)
132         private String sListSeparator; // (user can override) list separator
133         //        private int    iPaperSize               ; // default paper size (RegionInfo)
134
135         // Time
136         private String sAM1159; // (user can override) AM designator
137         private String sPM2359; // (user can override) PM designator
138         private String sTimeSeparator;
139         private volatile String[] saLongTimes; // (user can override) time format
140         private volatile String[] saShortTimes; // short time format
141         private volatile String[] saDurationFormats; // time duration format
142
143         // Calendar specific data
144         private int iFirstDayOfWeek = undef; // (user can override) first day of week (gregorian really)
145         private int iFirstWeekOfYear = undef; // (user can override) first week of year (gregorian really)
146         private volatile int[] waCalendars; // all available calendar type(s).  The first one is the default calendar
147
148         // Store for specific data about each calendar
149         private CalendarData[] calendars; // Store for specific calendar data
150
151         // Text information
152         private int iReadingLayout = undef; // Reading layout data
153         // 0 - Left to right (eg en-US)
154         // 1 - Right to left (eg arabic locales)
155         // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
156         // 3 - Vertical top to bottom with columns proceeding to the right
157
158         private String sTextInfo; // Text info name to use for custom
159         private String sCompareInfo; // Compare info name (including sorting key) to use if custom
160         private String sScripts; // Typical Scripts for this locale (latn;cyrl; etc)
161
162         private int iDefaultAnsiCodePage = undef; // default ansi code page ID (ACP)
163         private int iDefaultOemCodePage = undef; // default oem code page ID (OCP or OEM)
164         private int iDefaultMacCodePage = undef; // default macintosh code page
165         private int iDefaultEbcdicCodePage = undef; // default EBCDIC code page
166
167         // These are desktop only, not coreclr
168         private int    iLanguage; // locale ID (0409) - NO sort information
169         private String sAbbrevLang; // abbreviated language name (Windows Language Name) ex: ENU
170         private String sAbbrevCountry; // abbreviated country name (RegionInfo) (Windows Region Name) ex: USA
171         private String sISO639Language2; // 3 char ISO 639 lang name 2 ex: eng
172         private String sISO3166CountryName2; // 3 char ISO 3166 country name 2 2(RegionInfo) ex: USA (ISO)
173         private int    iInputLanguageHandle=undef;// input language handle
174         private String sConsoleFallbackName; // The culture name for the console fallback UI culture
175         private String sKeyboardsToInstall; // Keyboard installation string.
176         private String fontSignature; // Font signature (16 WORDS)
177
178         // The bools all need to be in one spot
179         private bool bUseOverrides; // use user overrides?
180         private bool bNeutral; // Flags for the culture (ie: neutral or not right now)
181         private bool bWin32Installed; // Flags indicate if the culture is Win32 installed
182         private bool bFramework; // Flags for indicate if the culture is one of Whidbey cultures
183
184         // Region Name to Culture Name mapping table
185         // (In future would be nice to be in registry or something)
186
187         //Using a property so we avoid creating the dictionary untill we need it
188         private static Dictionary<string, string> RegionNames
189         {
190             get 
191             {
192                 if (s_RegionNames == null)
193                 {
194                     var regionNames = new Dictionary<string, string> {
195                         { "029", "en-029" },
196                         { "AE",  "ar-AE" },
197                         { "AF",  "prs-AF" },
198                         { "AL",  "sq-AL" },
199                         { "AM",  "hy-AM" },
200                         { "AR",  "es-AR" },
201                         { "AT",  "de-AT" },
202                         { "AU",  "en-AU" },
203                         { "AZ",  "az-Cyrl-AZ" },
204                         { "BA",  "bs-Latn-BA" },
205                         { "BD",  "bn-BD" },
206                         { "BE",  "nl-BE" },
207                         { "BG",  "bg-BG" },
208                         { "BH",  "ar-BH" },
209                         { "BN",  "ms-BN" },
210                         { "BO",  "es-BO" },
211                         { "BR",  "pt-BR" },
212                         { "BY",  "be-BY" },
213                         { "BZ",  "en-BZ" },
214                         { "CA",  "en-CA" },
215                         { "CH",  "it-CH" },
216                         { "CL",  "es-CL" },
217                         { "CN",  "zh-CN" },
218                         { "CO",  "es-CO" },
219                         { "CR",  "es-CR" },
220                         { "CS",  "sr-Cyrl-CS" },
221                         { "CZ",  "cs-CZ" },
222                         { "DE",  "de-DE" },
223                         { "DK",  "da-DK" },
224                         { "DO",  "es-DO" },
225                         { "DZ",  "ar-DZ" },
226                         { "EC",  "es-EC" },
227                         { "EE",  "et-EE" },
228                         { "EG",  "ar-EG" },
229                         { "ES",  "es-ES" },
230                         { "ET",  "am-ET" },
231                         { "FI",  "fi-FI" },
232                         { "FO",  "fo-FO" },
233                         { "FR",  "fr-FR" },
234                         { "GB",  "en-GB" },
235                         { "GE",  "ka-GE" },
236                         { "GL",  "kl-GL" },
237                         { "GR",  "el-GR" },
238                         { "GT",  "es-GT" },
239                         { "HK",  "zh-HK" },
240                         { "HN",  "es-HN" },
241                         { "HR",  "hr-HR" },
242                         { "HU",  "hu-HU" },
243                         { "ID",  "id-ID" },
244                         { "IE",  "en-IE" },
245                         { "IL",  "he-IL" },
246                         { "IN",  "hi-IN" },
247                         { "IQ",  "ar-IQ" },
248                         { "IR",  "fa-IR" },
249                         { "IS",  "is-IS" },
250                         { "IT",  "it-IT" },
251                         { "IV",  "" },
252                         { "JM",  "en-JM" },
253                         { "JO",  "ar-JO" },
254                         { "JP",  "ja-JP" },
255                         { "KE",  "sw-KE" },
256                         { "KG",  "ky-KG" },
257                         { "KH",  "km-KH" },
258                         { "KR",  "ko-KR" },
259                         { "KW",  "ar-KW" },
260                         { "KZ",  "kk-KZ" },
261                         { "LA",  "lo-LA" },
262                         { "LB",  "ar-LB" },
263                         { "LI",  "de-LI" },
264                         { "LK",  "si-LK" },
265                         { "LT",  "lt-LT" },
266                         { "LU",  "lb-LU" },
267                         { "LV",  "lv-LV" },
268                         { "LY",  "ar-LY" },
269                         { "MA",  "ar-MA" },
270                         { "MC",  "fr-MC" },
271                         { "ME",  "sr-Latn-ME" },
272                         { "MK",  "mk-MK" },
273                         { "MN",  "mn-MN" },
274                         { "MO",  "zh-MO" },
275                         { "MT",  "mt-MT" },
276                         { "MV",  "dv-MV" },
277                         { "MX",  "es-MX" },
278                         { "MY",  "ms-MY" },
279                         { "NG",  "ig-NG" },
280                         { "NI",  "es-NI" },
281                         { "NL",  "nl-NL" },
282                         { "NO",  "nn-NO" },
283                         { "NP",  "ne-NP" },
284                         { "NZ",  "en-NZ" },
285                         { "OM",  "ar-OM" },
286                         { "PA",  "es-PA" },
287                         { "PE",  "es-PE" },
288                         { "PH",  "en-PH" },
289                         { "PK",  "ur-PK" },
290                         { "PL",  "pl-PL" },
291                         { "PR",  "es-PR" },
292                         { "PT",  "pt-PT" },
293                         { "PY",  "es-PY" },
294                         { "QA",  "ar-QA" },
295                         { "RO",  "ro-RO" },
296                         { "RS",  "sr-Latn-RS" },
297                         { "RU",  "ru-RU" },
298                         { "RW",  "rw-RW" },
299                         { "SA",  "ar-SA" },
300                         { "SE",  "sv-SE" },
301                         { "SG",  "zh-SG" },
302                         { "SI",  "sl-SI" },
303                         { "SK",  "sk-SK" },
304                         { "SN",  "wo-SN" },
305                         { "SV",  "es-SV" },
306                         { "SY",  "ar-SY" },
307                         { "TH",  "th-TH" },
308                         { "TJ",  "tg-Cyrl-TJ" },
309                         { "TM",  "tk-TM" },
310                         { "TN",  "ar-TN" },
311                         { "TR",  "tr-TR" },
312                         { "TT",  "en-TT" },
313                         { "TW",  "zh-TW" },
314                         { "UA",  "uk-UA" },
315                         { "US",  "en-US" },
316                         { "UY",  "es-UY" },
317                         { "UZ",  "uz-Cyrl-UZ" },
318                         { "VE",  "es-VE" },
319                         { "VN",  "vi-VN" },
320                         { "YE",  "ar-YE" },
321                         { "ZA",  "af-ZA" },
322                         { "ZW",  "en-ZW" }
323                     };
324                     s_RegionNames = regionNames;
325                 }
326                 return s_RegionNames;
327             }
328         }
329         private volatile static Dictionary<string, string> s_RegionNames;
330
331         /////////////////////////////////////////////////////////////////////////
332         // Build our invariant information
333         //
334         // We need an invariant instance, which we build hard-coded
335         /////////////////////////////////////////////////////////////////////////
336         internal static CultureData Invariant  
337         {
338             get 
339             {
340                 if (s_Invariant == null)
341                 {
342                     // Make a new culturedata
343                     CultureData invariant = new CultureData();
344
345                     // Call the native code to get the value of bWin32Installed.
346                     // For versions <= Vista, we set this to false for compatibility with v2.
347                     // For Windows 7, the flag is true.
348                     invariant.bUseOverrides = false;
349                     invariant.sRealName = "";
350
351                     // Ask the native code to fill it out for us, we only need the field IsWin32Installed
352                     nativeInitCultureData(invariant);
353
354                     // Basics
355                     // Note that we override the resources since this IS NOT supposed to change (by definition)
356                     invariant.bUseOverrides = false;
357                     invariant.sRealName = "";                     // Name you passed in (ie: en-US, en, or de-DE_phoneb)
358                     invariant.sWindowsName = "";                     // Name OS thinks the object is (ie: de-DE_phoneb, or en-US (even if en was passed in))
359
360                     // Identity
361                     invariant.sName = "";                     // locale name (ie: en-us)
362                     invariant.sParent = "";                     // Parent name (which may be a custom locale/culture)
363                     invariant.bNeutral = false;                   // Flags for the culture (ie: neutral or not right now)
364                     // Don't set invariant.bWin32Installed, we used nativeInitCultureData for that.
365                     invariant.bFramework = true;
366
367                     invariant.sEnglishDisplayName = "Invariant Language (Invariant Country)"; // English pretty name for this locale
368                     invariant.sNativeDisplayName = "Invariant Language (Invariant Country)";  // Native pretty name for this locale
369                     invariant.sSpecificCulture = "";                     // The culture name to be used in CultureInfo.CreateSpecificCulture()
370
371                     // Language
372                     invariant.sISO639Language = "iv";                   // ISO 639 Language Name
373                     invariant.sLocalizedLanguage = "Invariant Language";   // Display name for this Language
374                     invariant.sEnglishLanguage = "Invariant Language";   // English name for this language
375                     invariant.sNativeLanguage = "Invariant Language";   // Native name of this language
376
377                     // Region
378                     invariant.sRegionName = "IV";                   // (RegionInfo)
379                     // Unused for now:
380                     //            invariant.iCountry              =1;                      // country code (RegionInfo)
381                     invariant.iGeoId = 244;                    // GeoId (Windows Only)
382                     invariant.sEnglishCountry = "Invariant Country";    // english country name (RegionInfo)
383                     invariant.sNativeCountry = "Invariant Country";    // native country name (Windows Only)
384                     invariant.sISO3166CountryName = "IV";                   // (RegionInfo), ie: US
385
386                     // Numbers
387                     invariant.sPositiveSign = "+";                    // positive sign
388                     invariant.sNegativeSign = "-";                    // negative sign
389                     invariant.saNativeDigits = new String[] { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; // native characters for digits 0-9
390                     invariant.iDigitSubstitution = 1;                      // Digit substitution 0=context, 1=none/arabic, 2=Native/national (2 seems to be unused) (Windows Only)
391                     invariant.iLeadingZeros = 1;                      // leading zeros 0=no leading zeros, 1=leading zeros
392                     invariant.iDigits = 2;                      // number of fractional digits
393                     invariant.iNegativeNumber = 1;                      // negative number format
394                     invariant.waGrouping = new int[] { 3 };          // grouping of digits
395                     invariant.sDecimalSeparator = ".";                    // decimal separator
396                     invariant.sThousandSeparator = ",";                    // thousands separator
397                     invariant.sNaN = "NaN";                  // Not a Number
398                     invariant.sPositiveInfinity = "Infinity";             // + Infinity
399                     invariant.sNegativeInfinity = "-Infinity";            // - Infinity
400
401                     // Percent
402                     invariant.iNegativePercent = 0;                      // Negative Percent (0-3)
403                     invariant.iPositivePercent = 0;                      // Positive Percent (0-11)
404                     invariant.sPercent = "%";                    // Percent (%) symbol
405                     invariant.sPerMille = "\x2030";               // PerMille(‰) symbol
406
407                     // Currency
408                     invariant.sCurrency = "\x00a4";                // local monetary symbol "¤: for international monetary symbol
409                     invariant.sIntlMonetarySymbol = "XDR";                  // international monetary symbol (RegionInfo)
410                     invariant.sEnglishCurrency = "International Monetary Fund"; // English name for this currency (Windows Only)
411                     invariant.sNativeCurrency = "International Monetary Fund"; // Native name for this currency (Windows Only)
412                     invariant.iCurrencyDigits = 2;                      // # local monetary fractional digits
413                     invariant.iCurrency = 0;                      // positive currency format
414                     invariant.iNegativeCurrency = 0;                      // negative currency format
415                     invariant.waMonetaryGrouping = new int[] { 3 };          // monetary grouping of digits
416                     invariant.sMonetaryDecimal = ".";                    // monetary decimal separator
417                     invariant.sMonetaryThousand = ",";                    // monetary thousands separator
418
419                     // Misc
420                     invariant.iMeasure = 0;                      // system of measurement 0=metric, 1=US (RegionInfo)
421                     invariant.sListSeparator = ",";                    // list separator
422                     // Unused for now:
423                     //            invariant.iPaperSize            =9;                      // default paper size (RegionInfo)
424                     //            invariant.waFontSignature       ="\x0002\x0000\x0000\x0000\x0000\x0000\x0000\x8000\x0001\x0000\x0000\x8000\x0001\x0000\x0000\x8000"; // Font signature (16 WORDS) (Windows Only)
425
426                     // Time
427                     invariant.sAM1159 = "AM";                   // AM designator
428                     invariant.sPM2359 = "PM";                   // PM designator
429                     invariant.saLongTimes = new String[] { "HH:mm:ss" };                             // time format
430                     invariant.saShortTimes = new String[] { "HH:mm", "hh:mm tt", "H:mm", "h:mm tt" }; // short time format
431                     invariant.saDurationFormats = new String[] { "HH:mm:ss" };                             // time duration format
432
433                     // Calendar specific data
434                     invariant.iFirstDayOfWeek = 0;                      // first day of week
435                     invariant.iFirstWeekOfYear = 0;                      // first week of year
436                     invariant.waCalendars = new int[] { (int)CalendarId.GREGORIAN };       // all available calendar type(s).  The first one is the default calendar
437
438                     // Store for specific data about each calendar
439                     invariant.calendars = new CalendarData[CalendarData.MAX_CALENDARS];
440                     invariant.calendars[0] = CalendarData.Invariant;
441
442                     // Text information
443                     invariant.iReadingLayout = 0;                      // Reading Layout = RTL
444
445                     invariant.sTextInfo = "";                     // Text info name to use for custom
446                     invariant.sCompareInfo = "";                     // Compare info name (including sorting key) to use if custom
447                     invariant.sScripts = "Latn;";                // Typical Scripts for this locale (latn,cyrl, etc)
448
449                     invariant.iLanguage = 0x007f;                 // locale ID (0409) - NO sort information
450                     invariant.iDefaultAnsiCodePage = 1252;                   // default ansi code page ID (ACP)
451                     invariant.iDefaultOemCodePage = 437;                    // default oem code page ID (OCP or OEM)
452                     invariant.iDefaultMacCodePage = 10000;                  // default macintosh code page
453                     invariant.iDefaultEbcdicCodePage = 037;                    // default EBCDIC code page
454             invariant.sAbbrevLang = "IVL";                     // abbreviated language name (Windows Language Name)
455             invariant.sAbbrevCountry = "IVC";                  // abbreviated country name (RegionInfo) (Windows Region Name)
456                     invariant.sISO639Language2 = "ivl";                  // 3 char ISO 639 lang name 2
457                     invariant.sISO3166CountryName2 = "ivc";                  // 3 char ISO 3166 country name 2 2(RegionInfo)
458                     invariant.iInputLanguageHandle = 0x007f;                 // input language handle
459                     invariant.sConsoleFallbackName = "";                     // The culture name for the console fallback UI culture
460                     invariant.sKeyboardsToInstall = "0409:00000409";        // Keyboard installation string.
461                     // Remember it
462                     s_Invariant = invariant;
463                 }
464                 return s_Invariant;
465             }
466         }
467         private volatile static CultureData s_Invariant;
468
469
470 #if !FEATURE_CORECLR
471         internal static volatile ResourceSet MscorlibResourceSet;
472 #endif
473
474 #if !FEATURE_CORECLR
475         [System.Security.SecurityCritical]  // auto-generated
476         private static bool IsResourcePresent(String resourceKey)
477         {
478             if (MscorlibResourceSet == null)
479             {
480                 MscorlibResourceSet = new ResourceSet(typeof(Environment).Assembly.GetManifestResourceStream("mscorlib.resources"));
481             }
482             return MscorlibResourceSet.GetString(resourceKey) != null;
483         }
484 #endif
485
486         ///////////////
487         // Constructors //
488         ///////////////
489         // Cache of cultures we've already looked up
490         private static volatile Dictionary<String, CultureData> s_cachedCultures;
491
492         [FriendAccessAllowed]
493         internal static CultureData GetCultureData(String cultureName, bool useUserOverride)
494         {
495             // First do a shortcut for Invariant
496             if (String.IsNullOrEmpty(cultureName))
497             {
498                 return CultureData.Invariant;
499             }
500
501             // Try the hash table first
502             String hashName = AnsiToLower(useUserOverride ? cultureName : cultureName + '*');
503             Dictionary<String, CultureData> tempHashTable = s_cachedCultures;
504             if (tempHashTable == null)
505             {
506                 // No table yet, make a new one
507                 tempHashTable = new Dictionary<String, CultureData>();
508             }
509             else
510             {
511                 // Check the hash table
512                 CultureData retVal;
513                 lock (((ICollection)tempHashTable).SyncRoot)
514                 {
515                     tempHashTable.TryGetValue(hashName, out retVal);
516                 }
517                 if (retVal != null)
518                 {
519                     return retVal;
520                 }
521             }
522
523             // Not found in the hash table, need to see if we can build one that works for us
524             CultureData culture = CreateCultureData(cultureName, useUserOverride);
525             if (culture == null)
526             {
527                 return null;
528             }
529
530             // Found one, add it to the cache
531             lock (((ICollection)tempHashTable).SyncRoot)
532             {
533                 tempHashTable[hashName] = culture;
534             }
535
536             // Copy the hashtable to the corresponding member variables.  This will potentially overwrite
537             // new tables simultaneously created by a new thread, but maximizes thread safety.
538             s_cachedCultures = tempHashTable;
539
540             return culture;
541         }
542
543         private static CultureData CreateCultureData(string cultureName, bool useUserOverride)
544         {
545             CultureData culture = new CultureData();
546             culture.bUseOverrides = useUserOverride;
547             culture.sRealName = cultureName;
548
549             // Ask native code if that one's real
550             if (culture.InitCultureData() == false)
551             {
552 #if !FEATURE_CORECLR
553                 if (culture.InitCompatibilityCultureData() == false
554                  && culture.InitLegacyAlternateSortData() == false)
555 #endif
556                 {
557                     return null;
558                 }
559             }
560
561             return culture;
562         }
563
564         private bool InitCultureData()
565         {
566             if (nativeInitCultureData(this) == false)
567             {
568                 return false;
569             }
570
571 #if !FEATURE_CORECLR
572             if (CultureInfo.IsTaiwanSku)
573             {
574                 TreatTaiwanParentChainAsHavingTaiwanAsSpecific();
575             }
576 #endif
577             return true;
578         }
579
580 #if !FEATURE_CORECLR
581         [System.Security.SecuritySafeCritical]
582         private void TreatTaiwanParentChainAsHavingTaiwanAsSpecific()
583         {
584             if (IsNeutralInParentChainOfTaiwan() && IsOsPriorToWin7() && !IsReplacementCulture)
585             {
586                 // force population of fields that should have information that is
587                 // different than zh-TW:
588                 string s = SNATIVELANGUAGE;
589                 s = SENGLISHLANGUAGE;
590                 s = SLOCALIZEDLANGUAGE;
591                 s = STEXTINFO;
592                 s = SCOMPAREINFO;
593                 s = FONTSIGNATURE;
594                 int i = IDEFAULTANSICODEPAGE;
595                 i = IDEFAULTOEMCODEPAGE;
596                 i = IDEFAULTMACCODEPAGE;
597
598                 this.sSpecificCulture = "zh-TW";
599                 this.sWindowsName = "zh-TW";
600             }
601         }
602
603         private bool IsNeutralInParentChainOfTaiwan()
604         {
605             return this.sRealName == "zh" || this.sRealName == "zh-Hant";
606   }
607
608         static readonly Version s_win7Version = new Version(6, 1);
609         static private bool IsOsPriorToWin7()
610         {
611             return Environment.OSVersion.Platform == PlatformID.Win32NT &&
612                    Environment.OSVersion.Version < s_win7Version;
613         }
614         static private bool IsOsWin7OrPrior()
615         {
616             return Environment.OSVersion.Platform == PlatformID.Win32NT &&
617                 Environment.OSVersion.Version < new Version(6, 2); // Win7 is 6.1.Build.Revision so we have to check for anything less than 6.2
618         }
619
620         private bool InitCompatibilityCultureData()
621         {
622             // for compatibility handle the deprecated ids: zh-chs, zh-cht
623             string cultureName = this.sRealName;
624
625             string fallbackCultureName;
626             string realCultureName;
627             switch (AnsiToLower(cultureName))
628             {
629                 case "zh-chs":
630                     fallbackCultureName = "zh-Hans";
631                     realCultureName = "zh-CHS";
632                     break;
633                 case "zh-cht":
634                     fallbackCultureName = "zh-Hant";
635                     realCultureName = "zh-CHT";
636                     break;
637                 default:
638                     return false;
639             }
640
641             this.sRealName = fallbackCultureName;
642             if (InitCultureData() == false)
643             {
644                 return false;
645             }
646             // fixup our data
647             this.sName = realCultureName; // the name that goes back to the user
648             this.sParent = fallbackCultureName;
649             this.bFramework = true;
650
651             return true;
652         }
653
654         private bool InitLegacyAlternateSortData()
655         {
656             if (!CompareInfo.IsLegacy20SortingBehaviorRequested)
657             {
658                 return false;
659             }
660
661             // For V2 compatibility, handle deprecated alternate sorts
662             string cultureName = this.sRealName;
663
664             switch (AnsiToLower(cultureName))
665             {
666                 case "ko-kr_unicod":
667                     cultureName = "ko-KR_unicod";
668                     this.sRealName = "ko-KR";
669                     this.iLanguage = 0x00010412;
670                     break;
671                 case "ja-jp_unicod":
672                     cultureName = "ja-JP_unicod";
673                     this.sRealName = "ja-JP";
674                     this.iLanguage = 0x00010411;
675                     break;
676                 case "zh-hk_stroke":
677                     cultureName = "zh-HK_stroke";
678                     this.sRealName = "zh-HK";
679                     this.iLanguage = 0x00020c04;
680                     break;
681                 default:
682                     return false;
683             }
684
685             if (nativeInitCultureData(this) == false)
686             {
687                 return false;
688             }
689
690             this.sRealName = cultureName;
691             this.sCompareInfo = cultureName;
692             this.bFramework = true;
693
694             return true;
695         }
696
697 #if FEATURE_WIN32_REGISTRY
698         private static String s_RegionKey = @"System\CurrentControlSet\Control\Nls\RegionMapping";
699 #endif // FEATURE_WIN32_REGISTRY
700
701 #endif // !FEATURE_CORECLR
702         // Cache of regions we've already looked up
703         private static volatile Dictionary<String, CultureData> s_cachedRegions;
704
705         [System.Security.SecurityCritical]  // auto-generated
706         internal static CultureData GetCultureDataForRegion(String cultureName, bool useUserOverride)
707         {
708             // First do a shortcut for Invariant
709             if (String.IsNullOrEmpty(cultureName))
710             {
711                 return CultureData.Invariant;
712             }
713
714             //
715             // First check if GetCultureData() can find it (ie: its a real culture)
716             //
717             CultureData retVal = GetCultureData(cultureName, useUserOverride);
718             if (retVal != null && (retVal.IsNeutralCulture == false)) return retVal;
719
720             //
721             // Not a specific culture, perhaps it's region-only name
722             // (Remember this isn't a core clr path where that's not supported)
723             //
724
725             // If it was neutral remember that so that RegionInfo() can throw the right exception
726             CultureData neutral = retVal;
727
728             // Try the hash table next
729             String hashName = AnsiToLower(useUserOverride ? cultureName : cultureName + '*');
730             Dictionary<String, CultureData> tempHashTable = s_cachedRegions;
731             if (tempHashTable == null)
732             {
733                 // No table yet, make a new one
734                 tempHashTable = new Dictionary<String, CultureData>();
735             }
736             else
737             {
738                 // Check the hash table
739                 lock (((ICollection)tempHashTable).SyncRoot)
740                 {
741                     tempHashTable.TryGetValue(hashName, out retVal);
742                 }
743                 if (retVal != null)
744                 {
745                     return retVal;
746                 }
747             }
748
749             //
750             // Not found in the hash table, look it up the hard way
751             //
752 #if !FEATURE_CORECLR
753 #if FEATURE_WIN32_REGISTRY
754             // First try the registry in case there are overrides of our table
755             try
756             {
757                 // Open in read-only mode.
758                 // Use InternalOpenSubKey so that we avoid the security check.
759                 Microsoft.Win32.RegistryKey key = Microsoft.Win32.Registry.LocalMachine.InternalOpenSubKey(s_RegionKey, false);
760
761                 if (key != null)
762                 {
763                     try
764                     {
765                         Object value = key.InternalGetValue(cultureName, null, false, false);
766
767                         if (value != null)
768                         {
769                             // Get the name of the locale to try.
770                             String specificForRegion = value.ToString();
771
772                             // See if it's real
773                             retVal = GetCultureData(specificForRegion, useUserOverride);
774                         }
775                     }
776                     finally
777                     {
778                         key.Close();
779                     }
780                 }
781             }
782             // If this fails for any reason, we'll just ignore it, likely it just isn't there.
783             catch (ObjectDisposedException) { }
784             catch (ArgumentException) { }
785 #endif // FEATURE_WIN32_REGISTRY
786 #endif // !FEATURE_CORECLR
787
788             // If not a valid mapping from the registry we'll have to try the hard coded table
789             if (retVal == null || (retVal.IsNeutralCulture == true))
790             {
791                 // Not a valid mapping, try the hard coded table
792                 if (RegionNames.ContainsKey(cultureName))
793                 {
794                     // Make sure we can get culture data for it
795                     retVal = GetCultureData(RegionNames[cultureName], useUserOverride);
796                 }
797             }
798
799             // If not found in the hard coded table we'll have to find a culture that works for us
800             if (retVal == null || (retVal.IsNeutralCulture == true))
801             {
802                 // Not found in the hard coded table, need to see if we can find a culture that works for us
803                 // Not a real culture name, see if it matches a region name
804                 // (we just return the first culture we match)
805                 CultureInfo[] specifics = SpecificCultures;
806                 for (int i = 0; i < specifics.Length; i++)
807                 {
808                     if (String.Compare(specifics[i].m_cultureData.SREGIONNAME, cultureName, StringComparison.OrdinalIgnoreCase) == 0)
809                     {
810                         // Matched, use this culture
811                         retVal = specifics[i].m_cultureData;
812                         break;
813                     }
814                 }
815             }
816
817             // If we found one we can use, then cash it for next time
818             if (retVal != null && (retVal.IsNeutralCulture == false))
819             {
820                 // first add it to the cache
821                 lock (((ICollection)tempHashTable).SyncRoot)
822                 {
823                     tempHashTable[hashName] = retVal;
824                 }
825
826                 // Copy the hashtable to the corresponding member variables.  This will potentially overwrite
827                 // new tables simultaneously created by a new thread, but maximizes thread safety.
828                 s_cachedRegions = tempHashTable;
829             }
830             else
831             {
832                 // Unable to find a matching culture/region, return null or neutral
833                 // (regionInfo throws a more specific exception on neutrals)
834                 retVal = neutral;
835             }
836
837             // Return the found culture to use, null, or the neutral culture.
838             return retVal;
839         }
840
841 #if FEATURE_USE_LCID
842         // Obtain locale name from LCID
843         // NOTE: This will get neutral names, unlike the OS API
844         [System.Security.SecuritySafeCritical]  // auto-generated
845         [MethodImplAttribute(MethodImplOptions.InternalCall)]
846         internal static extern String LCIDToLocaleName(int lcid);
847
848         // We'd rather people use the named version since this doesn't allow custom locales
849         internal static CultureData GetCultureData(int culture, bool bUseUserOverride)
850         {
851             String localeName = null;
852             CultureData retVal = null;
853
854 #if !FEATURE_CORECLR
855             // If V2 legacy sort is requested, then provide deprecated alternate sorts
856             if (CompareInfo.IsLegacy20SortingBehaviorRequested)
857             {
858                 switch (culture)
859                 {
860                     case 0x00010412:
861                         localeName = "ko-KR_unicod";
862                         break;
863                     case 0x00010411:
864                         localeName = "ja-JP_unicod";
865                         break;
866                     case 0x00020c04:
867                         localeName = "zh-HK_stroke";
868                         break;
869                 }
870             }
871 #endif
872
873             if (localeName == null)
874             {
875                 // Convert the lcid to a name, then use that
876                 // Note that this'll return neutral names (unlike Vista native API)
877                 localeName = LCIDToLocaleName(culture);
878             }
879
880             // If its not valid, then throw
881             if (String.IsNullOrEmpty(localeName))
882             {
883                 // Could be valid for Invariant
884                 if (culture == 0x007f)
885                     return Invariant;
886             }
887             else
888             {
889 #if !FEATURE_CORECLR
890                 switch (localeName)
891                 {
892                     // for compatibility with Whidbey, when requesting
893                     // a locale from LCID, return the old localeName
894                     case "zh-Hans":
895                         localeName = "zh-CHS";
896                         break;
897                     case "zh-Hant":
898                         localeName = "zh-CHT";
899                         break;
900                 }
901 #endif
902                 // Valid name, use it
903                 retVal = GetCultureData(localeName, bUseUserOverride);
904             }
905
906             // If not successful, throw
907             if (retVal == null)
908                 throw new CultureNotFoundException(
909                     nameof(culture), culture, Environment.GetResourceString("Argument_CultureNotSupported"));
910
911             // Return the one we found
912             return retVal;
913         }
914 #endif
915
916         // Clear our internal caches
917         internal static void ClearCachedData()
918         {
919             s_cachedCultures = null;
920             s_cachedRegions = null;
921             s_replacementCultureNames = null;
922         }
923
924         [System.Security.SecuritySafeCritical]  // auto-generated
925         internal static CultureInfo[] GetCultures(CultureTypes types)
926         {
927             // Disable  warning 618: System.Globalization.CultureTypes.FrameworkCultures' is obsolete
928 #pragma warning disable 618
929             // Validate flags
930             if ((int)types <= 0 || ((int)types & (int)~(CultureTypes.NeutralCultures | CultureTypes.SpecificCultures |
931                                                             CultureTypes.InstalledWin32Cultures | CultureTypes.UserCustomCulture |
932                                                             CultureTypes.ReplacementCultures | CultureTypes.WindowsOnlyCultures |
933                                                             CultureTypes.FrameworkCultures)) != 0)
934             {
935                 throw new ArgumentOutOfRangeException(
936                                 nameof(types),
937                                 String.Format(
938                                     CultureInfo.CurrentCulture,
939                                     Environment.GetResourceString("ArgumentOutOfRange_Range"), CultureTypes.NeutralCultures, CultureTypes.FrameworkCultures));
940             }
941
942             //
943             // CHANGE FROM Whidbey
944             //
945             // We have deprecated CultureTypes.FrameworkCultures.
946             // When this enum is used, we will enumerate Whidbey framework cultures (for compatibility).
947             //
948
949             // We have deprecated CultureTypes.WindowsOnlyCultures.
950             // When this enum is used, we will return an empty array for this enum.
951             if ((types & CultureTypes.WindowsOnlyCultures) != 0)
952             {
953                 // Remove the enum as it is an no-op.
954                 types &= (~CultureTypes.WindowsOnlyCultures);
955             }
956
957             String[] cultureNames = null;
958
959             //
960             // Call nativeEnumCultureNames() to get a string array of culture names based on the specified
961             // enumeration type.
962             //
963             // nativeEnumCultureNames is a QCall.  We need to use a reference to return the string array
964             // allocated from the QCall.  That ref has to be wrapped as object handle.
965             // See vm\qcall.h for details in QCall.
966             //
967
968             if (nativeEnumCultureNames((int)types, JitHelpers.GetObjectHandleOnStack(ref cultureNames)) == 0)
969             {
970                 return new CultureInfo[0];
971             }
972
973             int arrayLength = cultureNames.Length;
974
975 #if !FEATURE_CORECLR
976             if ((types & (CultureTypes.NeutralCultures | CultureTypes.FrameworkCultures)) != 0) // add zh-CHT and zh-CHS
977             {
978                 arrayLength += 2;
979             }
980 #endif // FEATURE_CORECLR
981
982             CultureInfo[] cultures = new CultureInfo[arrayLength];
983
984             for (int i = 0; i < cultureNames.Length; i++)
985             {
986                 cultures[i] = new CultureInfo(cultureNames[i]);
987             }
988
989 #if !FEATURE_CORECLR
990             if ((types & (CultureTypes.NeutralCultures | CultureTypes.FrameworkCultures)) != 0) // add zh-CHT and zh-CHS
991             {
992                 Contract.Assert(arrayLength == cultureNames.Length + 2, "CultureData.nativeEnumCultureNames() Incorrect array size");
993                 cultures[cultureNames.Length] = new CultureInfo("zh-CHS");
994                 cultures[cultureNames.Length + 1] = new CultureInfo("zh-CHT");
995             }
996 #endif // FEATURE_CORECLR
997
998 #pragma warning restore 618
999
1000             return cultures;
1001         }
1002
1003         internal static volatile CultureInfo[] specificCultures;
1004
1005         private static CultureInfo[] SpecificCultures
1006         {
1007             get
1008             {
1009                 if (specificCultures == null)
1010                     specificCultures = GetCultures(CultureTypes.SpecificCultures);
1011
1012                 return specificCultures;
1013             }
1014         }
1015
1016         internal bool IsReplacementCulture
1017         {
1018             get
1019             {
1020                 return IsReplacementCultureName(this.SNAME);
1021             }
1022         }
1023
1024         internal static volatile String[] s_replacementCultureNames;
1025
1026         ////////////////////////////////////////////////////////////////////////
1027         //
1028         // Cache for the known replacement cultures.
1029         // This is used by CultureInfo.CultureType to check if a culture is a
1030         // replacement culture.
1031         //
1032         ////////////////////////////////////////////////////////////////////////
1033
1034
1035         [System.Security.SecuritySafeCritical]  // auto-generated
1036         private static bool IsReplacementCultureName(String name)
1037         {
1038             Contract.Assert(name != null, "IsReplacementCultureName(): name should not be null");
1039             String[] replacementCultureNames = s_replacementCultureNames;
1040             if (replacementCultureNames == null)
1041             {
1042                 if (nativeEnumCultureNames((int)CultureTypes.ReplacementCultures, JitHelpers.GetObjectHandleOnStack(ref replacementCultureNames)) == 0)
1043                 {
1044                     return false;
1045                 }
1046
1047                 // Even if we don't have any replacement cultures, the returned replacementCultureNames will still an empty string array, not null.
1048                 Contract.Assert(name != null, "IsReplacementCultureName(): replacementCultureNames should not be null");
1049                 Array.Sort(replacementCultureNames);
1050                 s_replacementCultureNames = replacementCultureNames;
1051             }
1052             return Array.BinarySearch(replacementCultureNames, name) >= 0;
1053         }
1054
1055         ////////////////////////////////////////////////////////////////////////
1056         //
1057         //  All the accessors
1058         //
1059         //  Accessors for our data object items
1060         //
1061         ////////////////////////////////////////////////////////////////////////
1062
1063         ///////////
1064         // Identity //
1065         ///////////
1066
1067         // The real name used to construct the locale (ie: de-DE_phoneb)
1068         internal String CultureName
1069         {
1070             get
1071             {
1072                 Contract.Assert(this.sRealName != null, "[CultureData.CultureName] Expected this.sRealName to be populated by COMNlsInfo::nativeInitCultureData already");
1073                 // since windows doesn't know about zh-CHS and zh-CHT,
1074                 // we leave sRealName == zh-Hanx but we still need to
1075                 // pretend that it was zh-CHX.
1076                 switch (this.sName)
1077                 {
1078                     case "zh-CHS":
1079                     case "zh-CHT":
1080                         return this.sName;
1081                 }
1082                 return this.sRealName;
1083             }
1084         }
1085
1086         // Are overrides enabled?
1087         internal bool UseUserOverride
1088         {
1089             get
1090             {
1091                 return this.bUseOverrides;
1092             }
1093         }
1094
1095         // locale name (ie: de-DE, NO sort information)
1096         internal String SNAME
1097         {
1098             get
1099             {
1100                 //                Contract.Assert(this.sName != null,
1101                 //                    "[CultureData.SNAME] Expected this.sName to be populated by COMNlsInfo::nativeInitCultureData already");
1102                 if (this.sName == null)
1103                 {
1104                     this.sName = String.Empty;
1105                 }
1106                 return this.sName;
1107             }
1108         }
1109
1110         // Parent name (which may be a custom locale/culture)
1111         internal String SPARENT
1112         {
1113             [System.Security.SecurityCritical]  // auto-generated
1114             get
1115             {
1116                 if (this.sParent == null)
1117                 {
1118                     // Ask using the real name, so that we get parents of neutrals
1119                     this.sParent = DoGetLocaleInfo(this.sRealName, LOCALE_SPARENT);
1120
1121 #if !FEATURE_CORECLR
1122                     // for compatibility, the chain should be:
1123                     // zh-CN -> zh-CHS -> zh-Hans -> zh
1124                     // zh-TW -> zh-CHT -> zh-Hant -> zh
1125                     Contract.Assert(this.sName != "zh-CHS" && this.sName != "zh-CHT",
1126                                     "sParent should have been initialized for zh-CHS and zh-CHT when they were constructed, otherwise we get recursion");
1127                     switch (this.sParent)
1128                     {
1129                         case "zh-Hans":
1130                             this.sParent = "zh-CHS";
1131                             break;
1132                         case "zh-Hant":
1133                             this.sParent = "zh-CHT";
1134                             break;
1135                     }
1136 #endif
1137
1138                 }
1139                 return this.sParent;
1140             }
1141         }
1142
1143         // Localized pretty name for this locale (ie: Inglis (estados Unitos))
1144         internal String SLOCALIZEDDISPLAYNAME
1145         {
1146             [System.Security.SecurityCritical]  // auto-generated
1147             get
1148             {
1149                 if (this.sLocalizedDisplayName == null)
1150                 {
1151 #if !FEATURE_CORECLR
1152                     String resourceKey = "Globalization.ci_" + this.sName;
1153                     if (IsResourcePresent(resourceKey))
1154                     {
1155                         this.sLocalizedDisplayName = Environment.GetResourceString(resourceKey);
1156                     }
1157 #endif
1158                     // If it hasn't been found (Windows 8 and up), fallback to the system
1159                     if (String.IsNullOrEmpty(this.sLocalizedDisplayName))
1160                     {
1161                         // If its neutral use the language name
1162                         if (this.IsNeutralCulture)
1163                         {
1164                             this.sLocalizedDisplayName = this.SLOCALIZEDLANGUAGE;
1165                         }
1166                         else
1167                         {
1168                             // We have to make the neutral distinction in case the OS returns a specific name
1169                             if (CultureInfo.UserDefaultUICulture.Name.Equals(Thread.CurrentThread.CurrentUICulture.Name))
1170                             {
1171                                 this.sLocalizedDisplayName = DoGetLocaleInfo(LOCALE_SLOCALIZEDDISPLAYNAME);
1172                             }
1173                             if (String.IsNullOrEmpty(this.sLocalizedDisplayName))
1174                             {
1175                                 this.sLocalizedDisplayName = this.SNATIVEDISPLAYNAME;
1176                             }
1177                         }
1178                     }
1179                 }
1180                 return this.sLocalizedDisplayName;
1181             }
1182         }
1183
1184         // English pretty name for this locale (ie: English (United States))
1185         internal String SENGDISPLAYNAME
1186         {
1187             [System.Security.SecurityCritical]  // auto-generated
1188             get
1189             {
1190                 if (this.sEnglishDisplayName == null)
1191                 {
1192                     // If its neutral use the language name
1193                     if (this.IsNeutralCulture)
1194                     {
1195                         this.sEnglishDisplayName = this.SENGLISHLANGUAGE;
1196 #if !FEATURE_CORECLR
1197                         // differentiate the legacy display names
1198                         switch (this.sName)
1199                         {
1200                             case "zh-CHS":
1201                             case "zh-CHT":
1202                                 this.sEnglishDisplayName += " Legacy";
1203                                 break;
1204                         }
1205 #endif
1206
1207                     }
1208                     else
1209                     {
1210                         this.sEnglishDisplayName = DoGetLocaleInfo(LOCALE_SENGLISHDISPLAYNAME);
1211
1212                         // if it isn't found build one:
1213                         if (String.IsNullOrEmpty(this.sEnglishDisplayName))
1214                         {
1215                             // Our existing names mostly look like:
1216                             // "English" + "United States" -> "English (United States)"
1217                             // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)"
1218                             if (this.SENGLISHLANGUAGE.EndsWith(')'))
1219                             {
1220                                 // "Azeri (Latin)" + "Azerbaijan" -> "Azeri (Latin, Azerbaijan)"
1221                                 this.sEnglishDisplayName =
1222                                     this.SENGLISHLANGUAGE.Substring(0, this.sEnglishLanguage.Length - 1) +
1223                                     ", " + this.SENGCOUNTRY + ")";
1224                             }
1225                             else
1226                             {
1227                                 // "English" + "United States" -> "English (United States)"
1228                                 this.sEnglishDisplayName = this.SENGLISHLANGUAGE + " (" + this.SENGCOUNTRY + ")";
1229                             }
1230                         }
1231                     }
1232                 }
1233                 return this.sEnglishDisplayName;
1234             }
1235         }
1236
1237         // Native pretty name for this locale (ie: Deutsch (Deutschland))
1238         internal String SNATIVEDISPLAYNAME
1239         {
1240             [System.Security.SecurityCritical]  // auto-generated
1241             get
1242             {
1243                 if (this.sNativeDisplayName == null)
1244                 {
1245                     // If its neutral use the language name
1246                     if (this.IsNeutralCulture)
1247                     {
1248                         this.sNativeDisplayName = this.SNATIVELANGUAGE;
1249 #if !FEATURE_CORECLR
1250                         // differentiate the legacy display names
1251                         switch (this.sName)
1252                         {
1253                             case "zh-CHS":
1254                                 this.sNativeDisplayName += " \u65E7\u7248";
1255                                 break;
1256                             case "zh-CHT":
1257                                 this.sNativeDisplayName += " \u820A\u7248";
1258                                 break;
1259                         }
1260 #endif
1261                     }
1262                     else
1263                     {
1264 #if !FEATURE_CORECLR
1265                         if (IsIncorrectNativeLanguageForSinhala())
1266                         {
1267                             // work around bug in Windows 7 for native name of Sinhala
1268                             this.sNativeDisplayName ="\x0dc3\x0dd2\x0d82\x0dc4\x0dbd (\x0DC1\x0DCA\x200D\x0DBB\x0DD3\x0020\x0DBD\x0D82\x0D9A\x0DCF)";
1269                         }
1270                         else
1271 #endif
1272                         {
1273                             this.sNativeDisplayName = DoGetLocaleInfo(LOCALE_SNATIVEDISPLAYNAME);
1274                         }
1275
1276                         // if it isn't found build one:
1277                         if (String.IsNullOrEmpty(this.sNativeDisplayName))
1278                         {
1279                             // These should primarily be "Deutsch (Deutschland)" type names
1280                             this.sNativeDisplayName = this.SNATIVELANGUAGE + " (" + this.SNATIVECOUNTRY + ")";
1281                         }
1282                     }
1283                 }
1284                 return this.sNativeDisplayName;
1285             }
1286         }
1287
1288         // The culture name to be used in CultureInfo.CreateSpecificCulture()
1289         internal String SSPECIFICCULTURE
1290         {
1291             get
1292             {
1293                 // This got populated when ComNlsInfo::nativeInitCultureData told us we had a culture
1294                 Contract.Assert(this.sSpecificCulture != null, "[CultureData.SSPECIFICCULTURE] Expected this.sSpecificCulture to be populated by COMNlsInfo::nativeInitCultureData already");
1295                 return this.sSpecificCulture;
1296             }
1297         }
1298
1299         /////////////
1300         // Language //
1301         /////////////
1302
1303         // iso 639 language name, ie: en
1304         internal String SISO639LANGNAME
1305         {
1306             [System.Security.SecurityCritical]  // auto-generated
1307             get
1308             {
1309                 if (this.sISO639Language == null)
1310                 {
1311                     this.sISO639Language = DoGetLocaleInfo(LOCALE_SISO639LANGNAME);
1312                 }
1313                 return this.sISO639Language;
1314             }
1315         }
1316
1317         // iso 639 language name, ie: eng
1318         internal String SISO639LANGNAME2
1319         {
1320             [System.Security.SecurityCritical]  // auto-generated
1321             get
1322             {
1323                 if (this.sISO639Language2 == null)
1324                 {
1325                     this.sISO639Language2 = DoGetLocaleInfo(LOCALE_SISO639LANGNAME2);
1326                 }
1327                 return this.sISO639Language2;
1328             }
1329         }
1330
1331         // abbreviated windows language name (ie: enu) (non-standard, avoid this)
1332         internal String SABBREVLANGNAME
1333         {
1334             [System.Security.SecurityCritical]  // auto-generated
1335             get
1336             {
1337                 if (this.sAbbrevLang == null)
1338                 {
1339                     this.sAbbrevLang = DoGetLocaleInfo(LOCALE_SABBREVLANGNAME);
1340                 }
1341                 return this.sAbbrevLang;
1342             }
1343         }
1344
1345         // Localized name for this language (Windows Only) ie: Inglis
1346         // This is only valid for Windows 8 and higher neutrals:
1347         internal String SLOCALIZEDLANGUAGE
1348         {
1349             [System.Security.SecurityCritical]  // auto-generated
1350             get
1351             {
1352                 if (this.sLocalizedLanguage == null)
1353                 {
1354                     if (CultureInfo.UserDefaultUICulture.Name.Equals(Thread.CurrentThread.CurrentUICulture.Name))
1355                     {
1356                         this.sLocalizedLanguage = DoGetLocaleInfo(LOCALE_SLOCALIZEDLANGUAGENAME);
1357                     }
1358                     // Some OS's might not have this resource or LCTYPE
1359                     if (String.IsNullOrEmpty(this.sLocalizedLanguage))
1360                     {
1361                         this.sLocalizedLanguage = SNATIVELANGUAGE;
1362                     }
1363                 }
1364
1365                 return this.sLocalizedLanguage;
1366             }
1367         }
1368
1369         // English name for this language (Windows Only) ie: German
1370         internal String SENGLISHLANGUAGE
1371         {
1372             [System.Security.SecurityCritical]  // auto-generated
1373             get
1374             {
1375                 if (this.sEnglishLanguage == null)
1376                 {
1377                     this.sEnglishLanguage = DoGetLocaleInfo(LOCALE_SENGLISHLANGUAGENAME);
1378                 }
1379                 return this.sEnglishLanguage;
1380             }
1381         }
1382
1383         // Native name of this language (Windows Only) ie: Deutsch
1384         internal String SNATIVELANGUAGE
1385         {
1386             [System.Security.SecurityCritical]  // auto-generated
1387             get
1388             {
1389                 if (this.sNativeLanguage == null)
1390                 {
1391 #if !FEATURE_CORECLR
1392                     if (IsIncorrectNativeLanguageForSinhala())
1393                     {
1394                         this.sNativeLanguage = "\x0dc3\x0dd2\x0d82\x0dc4\x0dbd";
1395                     }
1396                     else
1397 #endif
1398                     {
1399                         this.sNativeLanguage = DoGetLocaleInfo(LOCALE_SNATIVELANGUAGENAME);
1400                     }
1401                 }
1402                 return this.sNativeLanguage;
1403             }
1404         }
1405
1406 #if !FEATURE_CORECLR
1407         private bool IsIncorrectNativeLanguageForSinhala()
1408         {
1409             return IsOsWin7OrPrior() 
1410                 && (sName == "si-LK" || sName == "si")
1411                 && !IsReplacementCulture;
1412         }
1413 #endif
1414
1415         ///////////
1416         // Region //
1417         ///////////
1418
1419         // region name (eg US)
1420         internal String SREGIONNAME
1421         {
1422             [System.Security.SecurityCritical]  // auto-generated
1423             get
1424             {
1425                 if (this.sRegionName == null)
1426                 {
1427                     this.sRegionName = DoGetLocaleInfo(LOCALE_SISO3166CTRYNAME);
1428                 }
1429                 return this.sRegionName;
1430             }
1431         }
1432
1433         // (user can override) country code (RegionInfo)
1434         internal int ICOUNTRY
1435         {
1436             get
1437             {
1438                 return DoGetLocaleInfoInt(LOCALE_ICOUNTRY);
1439             }
1440         }
1441
1442         // GeoId
1443         internal int IGEOID
1444         {
1445             get
1446             {
1447                 if (this.iGeoId == undef)
1448                 {
1449                     this.iGeoId = DoGetLocaleInfoInt(LOCALE_IGEOID);
1450                 }
1451                 return this.iGeoId;
1452             }
1453         }
1454
1455         // localized name for the country
1456         internal string SLOCALIZEDCOUNTRY
1457         {
1458             [System.Security.SecurityCritical]  // auto-generated
1459             get
1460             {
1461                 if (this.sLocalizedCountry == null)
1462                 {
1463 #if !FEATURE_CORECLR
1464                     String resourceKey = "Globalization.ri_" + this.SREGIONNAME;
1465                     if (IsResourcePresent(resourceKey))
1466                     {
1467                         this.sLocalizedCountry = Environment.GetResourceString(resourceKey);
1468                     }
1469 #endif
1470                     // If it hasn't been found (Windows 8 and up), fallback to the system
1471                     if (String.IsNullOrEmpty(this.sLocalizedCountry))
1472                     {
1473                         // We have to make the neutral distinction in case the OS returns a specific name
1474                         if (CultureInfo.UserDefaultUICulture.Name.Equals(Thread.CurrentThread.CurrentUICulture.Name))
1475                         {
1476                             this.sLocalizedCountry = DoGetLocaleInfo(LOCALE_SLOCALIZEDCOUNTRYNAME);
1477                         }
1478                         if (String.IsNullOrEmpty(this.sLocalizedDisplayName))
1479                         {
1480                             this.sLocalizedCountry = SNATIVECOUNTRY;
1481                         }
1482                     }
1483                 }
1484                 return this.sLocalizedCountry;
1485             }
1486         }
1487
1488         // english country name (RegionInfo) ie: Germany
1489         internal String SENGCOUNTRY
1490         {
1491             [System.Security.SecurityCritical]  // auto-generated
1492             get
1493             {
1494                 if (this.sEnglishCountry == null)
1495                 {
1496                     this.sEnglishCountry = DoGetLocaleInfo(LOCALE_SENGLISHCOUNTRYNAME);
1497                 }
1498                 return this.sEnglishCountry;
1499             }
1500         }
1501
1502         // native country name (RegionInfo) ie: Deutschland
1503         internal String SNATIVECOUNTRY
1504         {
1505             [System.Security.SecurityCritical]  // auto-generated
1506             get
1507             {
1508                 if (this.sNativeCountry == null)
1509                 {
1510                     this.sNativeCountry = DoGetLocaleInfo(LOCALE_SNATIVECOUNTRYNAME);
1511                 }
1512                 return this.sNativeCountry;
1513             }
1514         }
1515
1516         // ISO 3166 Country Name
1517         internal String SISO3166CTRYNAME
1518         {
1519             [System.Security.SecurityCritical]  // auto-generated
1520             get
1521             {
1522                 if (this.sISO3166CountryName == null)
1523                 {
1524                     this.sISO3166CountryName = DoGetLocaleInfo(LOCALE_SISO3166CTRYNAME);
1525                 }
1526                 return this.sISO3166CountryName;
1527             }
1528         }
1529
1530         // ISO 3166 Country Name
1531         internal String SISO3166CTRYNAME2
1532         {
1533             [System.Security.SecurityCritical]  // auto-generated
1534             get
1535             {
1536                 if (this.sISO3166CountryName2 == null)
1537                 {
1538                     this.sISO3166CountryName2 = DoGetLocaleInfo(LOCALE_SISO3166CTRYNAME2);
1539                 }
1540                 return this.sISO3166CountryName2;
1541             }
1542         }
1543
1544         // abbreviated Country Name (windows version, non-standard, avoid)
1545         internal String SABBREVCTRYNAME
1546         {
1547             [System.Security.SecurityCritical]  // auto-generated
1548             get
1549             {
1550                 if (this.sAbbrevCountry == null)
1551                 {
1552                     this.sAbbrevCountry = DoGetLocaleInfo(LOCALE_SABBREVCTRYNAME);
1553                 }
1554                 return this.sAbbrevCountry;
1555             }
1556         }
1557
1558         // Default Country
1559         private int IDEFAULTCOUNTRY
1560         {
1561             get
1562             {
1563                 return DoGetLocaleInfoInt(LOCALE_IDEFAULTCOUNTRY);
1564             }
1565         }
1566
1567         // Console fallback name (ie: locale to use for console apps for unicode-only locales)
1568         internal int IINPUTLANGUAGEHANDLE
1569         {
1570             get
1571             {
1572                 if (this.iInputLanguageHandle == undef)
1573                 {
1574                     if (IsSupplementalCustomCulture)
1575                     {
1576                         this.iInputLanguageHandle = 0x0409;
1577                     }
1578                     else
1579                     {
1580                         // Input Language is same as LCID for built-in cultures
1581                         this.iInputLanguageHandle = this.ILANGUAGE;
1582                     }
1583                 }
1584                 return this.iInputLanguageHandle;
1585             }
1586         }
1587
1588         // Console fallback name (ie: locale to use for console apps for unicode-only locales)
1589         internal String SCONSOLEFALLBACKNAME
1590         {
1591             [System.Security.SecurityCritical]  // auto-generated
1592             get
1593             {
1594                 if (this.sConsoleFallbackName == null)
1595                 {
1596                     string consoleFallbackName = DoGetLocaleInfo(LOCALE_SCONSOLEFALLBACKNAME);
1597                     if (consoleFallbackName == "es-ES_tradnl")
1598                     {
1599                         consoleFallbackName = "es-ES";
1600                     }
1601                     this.sConsoleFallbackName = consoleFallbackName;
1602                 }
1603                 return this.sConsoleFallbackName;
1604             }
1605         }
1606
1607         /////////////
1608         // Numbers //
1609         ////////////
1610
1611         //                internal String sPositiveSign            ; // (user can override) positive sign
1612         //                internal String sNegativeSign            ; // (user can override) negative sign
1613         //                internal String[] saNativeDigits         ; // (user can override) native characters for digits 0-9
1614         //                internal int iDigitSubstitution       ; // (user can override) Digit substitution 0=context, 1=none/arabic, 2=Native/national (2 seems to be unused) (Windows Only)
1615         //                internal int iDigits                  ; // (user can override) number of fractional digits
1616         //                internal int iNegativeNumber          ; // (user can override) negative number format
1617
1618         // Leading zeroes
1619         private bool ILEADINGZEROS
1620         {
1621             get
1622             {
1623                 return (DoGetLocaleInfoInt(LOCALE_ILZERO) == 1);
1624             }
1625         }
1626
1627
1628         // (user can override) grouping of digits
1629         internal int[] WAGROUPING
1630         {
1631             [System.Security.SecurityCritical]  // auto-generated
1632             get
1633             {
1634                 if (this.waGrouping == null || UseUserOverride)
1635                 {
1636                     this.waGrouping = ConvertWin32GroupString(DoGetLocaleInfo(LOCALE_SGROUPING));
1637                 }
1638                 return this.waGrouping;
1639             }
1640         }
1641
1642
1643         //                internal String sDecimalSeparator        ; // (user can override) decimal separator
1644         //                internal String sThousandSeparator       ; // (user can override) thousands separator
1645
1646         // Not a Number
1647         internal String SNAN
1648         {
1649             [System.Security.SecurityCritical]  // auto-generated
1650             get
1651             {
1652                 if (this.sNaN == null)
1653                 {
1654                     this.sNaN = DoGetLocaleInfo(LOCALE_SNAN);
1655                 }
1656                 return this.sNaN;
1657             }
1658         }
1659
1660         // + Infinity
1661         internal String SPOSINFINITY
1662         {
1663             [System.Security.SecurityCritical]  // auto-generated
1664             get
1665             {
1666                 if (this.sPositiveInfinity == null)
1667                 {
1668                     this.sPositiveInfinity = DoGetLocaleInfo(LOCALE_SPOSINFINITY);
1669                 }
1670                 return this.sPositiveInfinity;
1671             }
1672         }
1673
1674         // - Infinity
1675         internal String SNEGINFINITY
1676         {
1677             [System.Security.SecurityCritical]  // auto-generated
1678             get
1679             {
1680                 if (this.sNegativeInfinity == null)
1681                 {
1682                     this.sNegativeInfinity = DoGetLocaleInfo(LOCALE_SNEGINFINITY);
1683                 }
1684                 return this.sNegativeInfinity;
1685             }
1686         }
1687
1688
1689         ////////////
1690         // Percent //
1691         ///////////
1692
1693         // Negative Percent (0-3)
1694         internal int INEGATIVEPERCENT
1695         {
1696             get
1697             {
1698                 if (this.iNegativePercent == undef)
1699                 {
1700                     // Note that <= Windows Vista this is synthesized by native code
1701                     this.iNegativePercent = DoGetLocaleInfoInt(LOCALE_INEGATIVEPERCENT);
1702                 }
1703                 return this.iNegativePercent;
1704             }
1705         }
1706
1707         // Positive Percent (0-11)
1708         internal int IPOSITIVEPERCENT
1709         {
1710             get
1711             {
1712                 if (this.iPositivePercent == undef)
1713                 {
1714                     // Note that <= Windows Vista this is synthesized by native code
1715                     this.iPositivePercent = DoGetLocaleInfoInt(LOCALE_IPOSITIVEPERCENT);
1716                 }
1717                 return this.iPositivePercent;
1718             }
1719         }
1720
1721         // Percent (%) symbol
1722         internal String SPERCENT
1723         {
1724             [System.Security.SecurityCritical]  // auto-generated
1725             get
1726             {
1727                 if (this.sPercent == null)
1728                 {
1729                     // Note that <= Windows Vista this is synthesized by native code
1730                     this.sPercent = DoGetLocaleInfo(LOCALE_SPERCENT);
1731                 }
1732                 return this.sPercent;
1733             }
1734         }
1735
1736         // PerMille (‰) symbol
1737         internal String SPERMILLE
1738         {
1739             [System.Security.SecurityCritical]  // auto-generated
1740             get
1741             {
1742                 if (this.sPerMille == null)
1743                 {
1744                     // Note that <= Windows Vista this is synthesized by native code
1745                     this.sPerMille = DoGetLocaleInfo(LOCALE_SPERMILLE);
1746                 }
1747                 return this.sPerMille;
1748             }
1749         }
1750
1751         /////////////
1752         // Currency //
1753         /////////////
1754
1755         // (user can override) local monetary symbol, eg: $
1756         internal String SCURRENCY
1757         {
1758             [System.Security.SecurityCritical]  // auto-generated
1759             get
1760             {
1761                 if (this.sCurrency == null || UseUserOverride)
1762                 {
1763                     this.sCurrency = DoGetLocaleInfo(LOCALE_SCURRENCY);
1764                 }
1765                 return this.sCurrency;
1766             }
1767         }
1768
1769         // international monetary symbol (RegionInfo), eg: USD
1770         internal String SINTLSYMBOL
1771         {
1772             [System.Security.SecurityCritical]  // auto-generated
1773             get
1774             {
1775                 if (this.sIntlMonetarySymbol == null)
1776                 {
1777                     this.sIntlMonetarySymbol = DoGetLocaleInfo(LOCALE_SINTLSYMBOL);
1778                 }
1779                 return this.sIntlMonetarySymbol;
1780             }
1781         }
1782
1783         // English name for this currency (RegionInfo), eg: US Dollar
1784         internal String SENGLISHCURRENCY
1785         {
1786             [System.Security.SecurityCritical]  // auto-generated
1787             get
1788             {
1789                 if (this.sEnglishCurrency == null)
1790                 {
1791                     this.sEnglishCurrency = DoGetLocaleInfo(LOCALE_SENGCURRNAME);
1792                 }
1793                 return this.sEnglishCurrency;
1794             }
1795         }
1796
1797         // Native name for this currency (RegionInfo), eg: Schweiz Frank
1798         internal String SNATIVECURRENCY
1799         {
1800             [System.Security.SecurityCritical]  // auto-generated
1801             get
1802             {
1803                 if (this.sNativeCurrency == null)
1804                 {
1805                     this.sNativeCurrency = DoGetLocaleInfo(LOCALE_SNATIVECURRNAME);
1806                 }
1807                 return this.sNativeCurrency;
1808             }
1809         }
1810
1811         //                internal int iCurrencyDigits          ; // (user can override) # local monetary fractional digits
1812         //                internal int iCurrency                ; // (user can override) positive currency format
1813         //                internal int iNegativeCurrency        ; // (user can override) negative currency format
1814
1815         // (user can override) monetary grouping of digits
1816         internal int[] WAMONGROUPING
1817         {
1818             [System.Security.SecurityCritical]  // auto-generated
1819             get
1820             {
1821                 if (this.waMonetaryGrouping == null || UseUserOverride)
1822                 {
1823                     this.waMonetaryGrouping = ConvertWin32GroupString(DoGetLocaleInfo(LOCALE_SMONGROUPING));
1824                 }
1825                 return this.waMonetaryGrouping;
1826             }
1827         }
1828
1829         //                internal String sMonetaryDecimal         ; // (user can override) monetary decimal separator
1830         //                internal String sMonetaryThousand        ; // (user can override) monetary thousands separator
1831
1832         /////////
1833         // Misc //
1834         /////////
1835
1836         // (user can override) system of measurement 0=metric, 1=US (RegionInfo)
1837         internal int IMEASURE
1838         {
1839             get
1840             {
1841                 if (this.iMeasure == undef || UseUserOverride)
1842                 {
1843                     this.iMeasure = DoGetLocaleInfoInt(LOCALE_IMEASURE);
1844                 }
1845                 return this.iMeasure;
1846             }
1847         }
1848
1849         // (user can override) list Separator
1850         internal String SLIST
1851         {
1852             [System.Security.SecurityCritical]  // auto-generated
1853             get
1854             {
1855                 if (this.sListSeparator == null || UseUserOverride)
1856                 {
1857                     this.sListSeparator = DoGetLocaleInfo(LOCALE_SLIST);
1858                 }
1859                 return this.sListSeparator;
1860             }
1861         }
1862
1863         // Paper size
1864         private int IPAPERSIZE
1865         {
1866             get
1867             {
1868                 return DoGetLocaleInfoInt(LOCALE_IPAPERSIZE);
1869             }
1870         }
1871
1872         ////////////////////////////
1873         // Calendar/Time (Gregorian) //
1874         ////////////////////////////
1875
1876         // (user can override) AM designator
1877         internal String SAM1159
1878         {
1879             [System.Security.SecurityCritical]  // auto-generated
1880             get
1881             {
1882                 if (this.sAM1159 == null || UseUserOverride)
1883                 {
1884                     this.sAM1159 = DoGetLocaleInfo(LOCALE_S1159);
1885                 }
1886                 return this.sAM1159;
1887             }
1888         }
1889
1890         // (user can override) PM designator
1891         internal String SPM2359
1892         {
1893             [System.Security.SecurityCritical]  // auto-generated
1894             get
1895             {
1896                 if (this.sPM2359 == null || UseUserOverride)
1897                 {
1898                     this.sPM2359 = DoGetLocaleInfo(LOCALE_S2359);
1899                 }
1900                 return this.sPM2359;
1901             }
1902         }
1903
1904         // (user can override) time format
1905         internal String[] LongTimes
1906         {
1907             get
1908             {
1909                 if (this.saLongTimes == null || UseUserOverride)
1910                 {
1911                     String[] longTimes = DoEnumTimeFormats();
1912                     if (longTimes == null || longTimes.Length == 0)
1913                     {
1914                         this.saLongTimes = Invariant.saLongTimes;
1915                     }
1916                     else
1917                     {
1918                         this.saLongTimes = longTimes;
1919                     }
1920                 }
1921                 return this.saLongTimes;
1922             }
1923         }
1924
1925         // short time format
1926         // Short times (derived from long times format)
1927         internal String[] ShortTimes
1928         {
1929             get
1930             {
1931                 if (this.saShortTimes == null || UseUserOverride)
1932                 {
1933                     // Try to get the short times from the OS/culture.dll
1934                     String[] shortTimes = DoEnumShortTimeFormats();
1935
1936                     if (shortTimes == null || shortTimes.Length == 0)
1937                     {
1938                         //
1939                         // If we couldn't find short times, then compute them from long times
1940                         // (eg: CORECLR on < Win7 OS & fallback for missing culture.dll)
1941                         //
1942                         shortTimes = DeriveShortTimesFromLong();
1943                     }
1944
1945                     // Found short times, use them
1946                     this.saShortTimes = shortTimes;
1947                 }
1948                 return this.saShortTimes;
1949             }
1950         }
1951
1952         private string[] DeriveShortTimesFromLong()
1953         {
1954             // Our logic is to look for h,H,m,s,t.  If we find an s, then we check the string
1955             // between it and the previous marker, if any.  If its a short, unescaped separator,
1956             // then we don't retain that part.
1957             // We then check after the ss and remove anything before the next h,H,m,t...
1958             string[] shortTimes = new string[LongTimes.Length];
1959
1960             for (int i = 0; i < LongTimes.Length; i++)
1961             {
1962                 shortTimes[i] = StripSecondsFromPattern(LongTimes[i]);
1963             }
1964             return shortTimes;
1965         }
1966
1967         private static string StripSecondsFromPattern(string time)
1968         {
1969             bool bEscape = false;
1970             int iLastToken = -1;
1971
1972             // Find the seconds
1973             for (int j = 0; j < time.Length; j++)
1974             {
1975                 // Change escape mode?
1976                 if (time[j] == '\'')
1977                 {
1978                     // Continue
1979                     bEscape = !bEscape;
1980                     continue;
1981                 }
1982
1983                 // See if there was a single \
1984                 if (time[j] == '\\')
1985                 {
1986                     // Skip next char
1987                     j++;
1988                     continue;
1989                 }
1990
1991                 if (bEscape)
1992                 {
1993                     continue;
1994                 }
1995
1996                 switch (time[j])
1997                 {
1998                     // Check for seconds
1999                     case 's':
2000                         // Found seconds, see if there was something unescaped and short between
2001                         // the last marker and the seconds.  Windows says separator can be a
2002                         // maximum of three characters (without null)
2003                         // If 1st or last characters were ', then ignore it
2004                         if ((j - iLastToken) <= 4 && (j - iLastToken) > 1 &&
2005                             (time[iLastToken + 1] != '\'') &&
2006                             (time[j - 1] != '\''))
2007                         {
2008                             // There was something there we want to remember
2009                             if (iLastToken >= 0)
2010                             {
2011                                 j = iLastToken + 1;
2012                             }
2013                         }
2014
2015                         bool containsSpace;
2016                         int endIndex = GetIndexOfNextTokenAfterSeconds(time, j, out containsSpace);
2017                         StringBuilder sb = new StringBuilder(time.Substring(0, j));
2018                         if (containsSpace)
2019                         {
2020                             sb.Append(' ');
2021                         }
2022                         sb.Append(time.Substring(endIndex));
2023                         time = sb.ToString();
2024                         break;
2025                     case 'm':
2026                     case 'H':
2027                     case 'h':
2028                         iLastToken = j;
2029                         break;
2030                 }
2031             }
2032             return time;
2033         }
2034
2035         private static int GetIndexOfNextTokenAfterSeconds(string time, int index, out bool containsSpace)
2036         {
2037             bool bEscape = false;
2038             containsSpace = false;
2039             for (; index < time.Length; index++)
2040             {
2041                 switch (time[index])
2042                 {
2043                     case '\'':
2044                         bEscape = !bEscape;
2045                         continue;
2046                     case '\\':
2047                         index++;
2048                         if (time[index] == ' ')
2049                         {
2050                             containsSpace = true;
2051                         }
2052                         continue;
2053                     case ' ':
2054                         containsSpace = true;
2055                         break;
2056                     case 't':
2057                     case 'm':
2058                     case 'H':
2059                     case 'h':
2060                         if (bEscape)
2061                         {
2062                             continue;
2063                         }
2064                         return index;
2065                 }
2066             }
2067             containsSpace = false;
2068             return index;
2069         }
2070
2071         // time duration format
2072         internal String[] SADURATION
2073         {
2074             [System.Security.SecurityCritical]  // auto-generated
2075             get
2076             {
2077                 if (this.saDurationFormats == null)
2078                 {
2079                     String durationFormat = DoGetLocaleInfo(LOCALE_SDURATION);
2080                     this.saDurationFormats = new String[] { ReescapeWin32String(durationFormat) };
2081                 }
2082                 return this.saDurationFormats;
2083             }
2084         }
2085
2086         // (user can override) first day of week
2087         internal int IFIRSTDAYOFWEEK
2088         {
2089             get
2090             {
2091                 if (this.iFirstDayOfWeek == undef || UseUserOverride)
2092                 {
2093                     // Have to convert it from windows to .Net formats
2094                     this.iFirstDayOfWeek = ConvertFirstDayOfWeekMonToSun(DoGetLocaleInfoInt(LOCALE_IFIRSTDAYOFWEEK));
2095                 }
2096                 return this.iFirstDayOfWeek;
2097             }
2098         }
2099
2100         // (user can override) first week of year
2101         internal int IFIRSTWEEKOFYEAR
2102         {
2103             get
2104             {
2105                 if (this.iFirstWeekOfYear == undef || UseUserOverride)
2106                 {
2107                     this.iFirstWeekOfYear = DoGetLocaleInfoInt(LOCALE_IFIRSTWEEKOFYEAR);
2108                 }
2109                 return this.iFirstWeekOfYear;
2110             }
2111         }
2112
2113         // (user can override default only) short date format
2114         internal String[] ShortDates(int calendarId)
2115         {
2116             return GetCalendar(calendarId).saShortDates;
2117         }
2118
2119         // (user can override default only) long date format
2120         internal String[] LongDates(int calendarId)
2121         {
2122             return GetCalendar(calendarId).saLongDates;
2123         }
2124
2125         // (user can override) date year/month format.
2126         internal String[] YearMonths(int calendarId)
2127         {
2128             return GetCalendar(calendarId).saYearMonths;
2129         }
2130
2131         // day names
2132         internal string[] DayNames(int calendarId)
2133         {
2134             return GetCalendar(calendarId).saDayNames;
2135         }
2136
2137         // abbreviated day names
2138         internal string[] AbbreviatedDayNames(int calendarId)
2139         {
2140             // Get abbreviated day names for this calendar from the OS if necessary
2141             return GetCalendar(calendarId).saAbbrevDayNames;
2142         }
2143
2144         // The super short day names
2145         internal string[] SuperShortDayNames(int calendarId)
2146         {
2147             return GetCalendar(calendarId).saSuperShortDayNames;
2148         }
2149
2150         // month names
2151         internal string[] MonthNames(int calendarId)
2152         {
2153             return GetCalendar(calendarId).saMonthNames;
2154         }
2155
2156         // Genitive month names
2157         internal string[] GenitiveMonthNames(int calendarId)
2158         {
2159             return GetCalendar(calendarId).saMonthGenitiveNames;
2160         }
2161
2162         // month names
2163         internal string[] AbbreviatedMonthNames(int calendarId)
2164         {
2165             return GetCalendar(calendarId).saAbbrevMonthNames;
2166         }
2167
2168         // Genitive month names
2169         internal string[] AbbreviatedGenitiveMonthNames(int calendarId)
2170         {
2171             return GetCalendar(calendarId).saAbbrevMonthGenitiveNames;
2172         }
2173
2174         // Leap year month names
2175         // Note: This only applies to Hebrew, and it basically adds a "1" to the 6th month name
2176         // the non-leap names skip the 7th name in the normal month name array
2177         internal string[] LeapYearMonthNames(int calendarId)
2178         {
2179             return GetCalendar(calendarId).saLeapYearMonthNames;
2180         }
2181
2182         // month/day format (single string, no override)
2183         internal String MonthDay(int calendarId)
2184         {
2185             return GetCalendar(calendarId).sMonthDay;
2186         }
2187
2188
2189
2190         /////////////
2191         // Calendars //
2192         /////////////
2193
2194         // all available calendar type(s), The first one is the default calendar.
2195         internal int[] CalendarIds
2196         {
2197             get
2198             {
2199                 if (this.waCalendars == null)
2200                 {
2201                     // We pass in an array of ints, and native side fills it up with count calendars.
2202                     // We then have to copy that list to a new array of the right size.
2203                     // Default calendar should be first
2204                     int[] calendarInts = new int[23];
2205                     Contract.Assert(this.sWindowsName != null, "[CultureData.CalendarIds] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
2206                     int count = CalendarData.nativeGetCalendars(this.sWindowsName, this.bUseOverrides, calendarInts);
2207
2208                     // See if we had a calendar to add.
2209                     if (count == 0)
2210                     {
2211                         // Failed for some reason, just grab Gregorian from Invariant
2212                         this.waCalendars = Invariant.waCalendars;
2213                     }
2214                     else
2215                     {
2216                         // The OS may not return calendar 4 for zh-TW, but we've always allowed it.
2217                         if (this.sWindowsName == "zh-TW")
2218                         {
2219                             bool found = false;
2220
2221                             // Do we need to insert calendar 4?
2222                             for (int i = 0; i < count; i++)
2223                             {
2224                                 // Stop if we found calendar four
2225                                 if (calendarInts[i] == Calendar.CAL_TAIWAN)
2226                                 {
2227                                     found = true;
2228                                     break;
2229                                 }
2230                             }
2231
2232                             // If not found then insert it
2233                             if (!found)
2234                             {
2235                                 // Insert it as the 2nd calendar
2236                                 count++;
2237                                 // Copy them from the 2nd position to the end, -1 for skipping 1st, -1 for one being added.
2238                                 Array.Copy(calendarInts, 1, calendarInts, 2, 23 - 1 - 1);
2239                                 calendarInts[1] = Calendar.CAL_TAIWAN;
2240                             }
2241                         }
2242
2243                         // It worked, remember the list
2244                         int[] temp = new int[count];
2245                         Array.Copy(calendarInts, temp, count);
2246
2247                         // Want 1st calendar to be default
2248                         // Prior to Vista the enumeration didn't have default calendar first
2249                         // Only a coreclr concern, culture.dll does the right thing.
2250 #if FEATURE_CORECLR
2251                         if (temp.Length > 1)
2252                         {
2253                             int i = DoGetLocaleInfoInt(LOCALE_ICALENDARTYPE);
2254                             if (temp[1] == i)
2255                             {
2256                                 temp[1] = temp[0];
2257                                 temp[0] = i;
2258                             }
2259                         }
2260 #endif
2261
2262                         this.waCalendars = temp;
2263                     }
2264                 }
2265
2266                 return this.waCalendars;
2267             }
2268         }
2269
2270         // Native calendar names.  index of optional calendar - 1, empty if no optional calendar at that number
2271         internal String CalendarName(int calendarId)
2272         {
2273             // Get the calendar
2274             return GetCalendar(calendarId).sNativeName;
2275         }
2276
2277         internal CalendarData GetCalendar(int calendarId)
2278         {
2279             Contract.Assert(calendarId > 0 && calendarId <= CalendarData.MAX_CALENDARS,
2280                 "[CultureData.GetCalendar] Expect calendarId to be in a valid range");
2281
2282             // arrays are 0 based, calendarIds are 1 based
2283             int calendarIndex = calendarId - 1;
2284
2285             // Have to have calendars
2286             if (calendars == null)
2287             {
2288                 calendars = new CalendarData[CalendarData.MAX_CALENDARS];
2289             }
2290
2291             // we need the following local variable to avoid returning null
2292             // when another thread creates a new array of CalendarData (above)
2293             // right after we insert the newly created CalendarData (below)
2294             CalendarData calendarData = calendars[calendarIndex];
2295             // Make sure that calendar has data
2296             if (calendarData == null || UseUserOverride)
2297             {
2298                 Contract.Assert(this.sWindowsName != null, "[CultureData.GetCalendar] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
2299                 calendarData = new CalendarData(this.sWindowsName, calendarId, this.UseUserOverride);
2300 #if !FEATURE_CORECLR
2301                 //Work around issue where Win7 data for MonthDay contains invalid two sets of data separated by semicolon
2302                 //even though MonthDay is not enumerated
2303                 if (IsOsWin7OrPrior() && !IsSupplementalCustomCulture && !IsReplacementCulture)
2304                 {
2305                     calendarData.FixupWin7MonthDaySemicolonBug();
2306                 }
2307 #endif
2308                 calendars[calendarIndex] = calendarData;
2309             }
2310
2311             return calendarData;
2312         }
2313
2314         internal int CurrentEra(int calendarId)
2315         {
2316             return GetCalendar(calendarId).iCurrentEra;
2317         }
2318
2319         ///////////////////
2320         // Text Information //
2321         ///////////////////
2322
2323         // IsRightToLeft
2324         internal bool IsRightToLeft
2325         {
2326             get
2327             {
2328                 // Returns one of the following 4 reading layout values:
2329                 // 0 - Left to right (eg en-US)
2330                 // 1 - Right to left (eg arabic locales)
2331                 // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
2332                 // 3 - Vertical top to bottom with columns proceeding to the right
2333                 return (this.IREADINGLAYOUT == 1);
2334             }
2335         }
2336
2337         // IREADINGLAYOUT
2338         // Returns one of the following 4 reading layout values:
2339         // 0 - Left to right (eg en-US)
2340         // 1 - Right to left (eg arabic locales)
2341         // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
2342         // 3 - Vertical top to bottom with columns proceeding to the right
2343         //
2344         // If exposed as a public API, we'd have an enum with those 4 values
2345         private int IREADINGLAYOUT
2346         {
2347             get
2348             {
2349                 if (this.iReadingLayout == undef)
2350                 {
2351                     Contract.Assert(this.sRealName != null, "[CultureData.IsRightToLeft] Expected this.sRealName to be populated by COMNlsInfo::nativeInitCultureData already");
2352                     this.iReadingLayout = DoGetLocaleInfoInt(LOCALE_IREADINGLAYOUT);
2353                 }
2354
2355                 return (this.iReadingLayout);
2356             }
2357         }
2358
2359         // The TextInfo name never includes that alternate sort and is always specific
2360         // For customs, it uses the SortLocale (since the textinfo is not exposed in Win7)
2361         // en -> en-US
2362         // en-US -> en-US
2363         // fj (custom neutral) -> en-US (assuming that en-US is the sort locale for fj)
2364         // fj_FJ (custom specific) -> en-US (assuming that en-US is the sort locale for fj-FJ)
2365         // es-ES_tradnl -> es-ES
2366         internal String STEXTINFO               // Text info name to use for text information
2367         {
2368             [System.Security.SecuritySafeCritical]
2369             get
2370             {
2371                 if (this.sTextInfo == null)
2372                 {
2373                     // LOCALE_SSORTLOCALE is broken in Win7 for Alt sorts.
2374                     // It is also not supported downlevel without culture.dll.
2375                     if (IsNeutralCulture || IsSupplementalCustomCulture)
2376                     {
2377                         string sortLocale = DoGetLocaleInfo(LOCALE_SSORTLOCALE);
2378                         this.sTextInfo = GetCultureData(sortLocale, bUseOverrides).SNAME;
2379                     }
2380
2381                     if (this.sTextInfo == null)
2382                     {
2383                         this.sTextInfo = this.SNAME; // removes alternate sort
2384                     }
2385                 }
2386
2387                 return this.sTextInfo;
2388             }
2389         }
2390
2391         // Compare info name (including sorting key) to use if custom
2392         internal String SCOMPAREINFO
2393         {
2394             [System.Security.SecuritySafeCritical]
2395             get
2396             {
2397                 if (this.sCompareInfo == null)
2398                 {
2399                     // LOCALE_SSORTLOCALE is broken in Win7 for Alt sorts.
2400                     // It is also not supported downlevel without culture.dll.
2401                     // We really only need it for the custom locale case though
2402                     // since for all other cases, it is the same as sWindowsName
2403                     if (IsSupplementalCustomCulture)
2404                     {
2405                         this.sCompareInfo = DoGetLocaleInfo(LOCALE_SSORTLOCALE);
2406                     }
2407
2408                     if (this.sCompareInfo == null)
2409                     {
2410                         this.sCompareInfo = this.sWindowsName;
2411                     }
2412                 }
2413
2414                 return this.sCompareInfo;
2415             }
2416         }
2417
2418         internal bool IsSupplementalCustomCulture
2419         {
2420             get
2421             {
2422                 return IsCustomCultureId(this.ILANGUAGE);
2423             }
2424         }
2425
2426         // Typical Scripts for this locale (latn;cyrl; etc)
2427
2428         private String SSCRIPTS
2429         {
2430             [System.Security.SecuritySafeCritical]  // auto-generated
2431             get
2432             {
2433                 if (this.sScripts == null)
2434                 {
2435                     this.sScripts = DoGetLocaleInfo(LOCALE_SSCRIPTS);
2436                 }
2437                 return this.sScripts;
2438             }
2439         }
2440
2441         private String SOPENTYPELANGUAGETAG
2442         {
2443             [System.Security.SecuritySafeCritical]  // auto-generated
2444             get
2445             {
2446                 return DoGetLocaleInfo(LOCALE_SOPENTYPELANGUAGETAG);
2447             }
2448         }
2449
2450         private String FONTSIGNATURE
2451         {
2452             [System.Security.SecuritySafeCritical]  // auto-generated
2453             get
2454             {
2455                 if (this.fontSignature == null)
2456                 {
2457                     this.fontSignature = DoGetLocaleInfo(LOCALE_FONTSIGNATURE);
2458                 }
2459                 return this.fontSignature;
2460             }
2461         }
2462
2463         private String SKEYBOARDSTOINSTALL
2464         {
2465             [System.Security.SecuritySafeCritical]  // auto-generated
2466             get
2467             {
2468                 return DoGetLocaleInfo(LOCALE_SKEYBOARDSTOINSTALL);
2469             }
2470         }
2471
2472
2473         internal int IDEFAULTANSICODEPAGE   // default ansi code page ID (ACP)
2474         {
2475             get
2476             {
2477                 if (this.iDefaultAnsiCodePage == undef)
2478                 {
2479                     this.iDefaultAnsiCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTANSICODEPAGE);
2480                 }
2481                 return this.iDefaultAnsiCodePage;
2482             }
2483         }
2484
2485         internal int IDEFAULTOEMCODEPAGE   // default oem code page ID (OCP or OEM)
2486         {
2487             get
2488             {
2489                 if (this.iDefaultOemCodePage == undef)
2490                 {
2491                     this.iDefaultOemCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTCODEPAGE);
2492                 }
2493                 return this.iDefaultOemCodePage;
2494             }
2495         }
2496
2497         internal int IDEFAULTMACCODEPAGE   // default macintosh code page
2498         {
2499             get
2500             {
2501                 if (this.iDefaultMacCodePage == undef)
2502                 {
2503                     this.iDefaultMacCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTMACCODEPAGE);
2504                 }
2505                 return this.iDefaultMacCodePage;
2506             }
2507         }
2508
2509         internal int IDEFAULTEBCDICCODEPAGE   // default EBCDIC code page
2510         {
2511             get
2512             {
2513                 if (this.iDefaultEbcdicCodePage == undef)
2514                 {
2515                     this.iDefaultEbcdicCodePage = DoGetLocaleInfoInt(LOCALE_IDEFAULTEBCDICCODEPAGE);
2516                 }
2517                 return this.iDefaultEbcdicCodePage;
2518             }
2519         }
2520
2521         // Obtain locale name from LCID
2522         // NOTE: This will get neutral names, unlike the OS API
2523         [System.Security.SecuritySafeCritical]  // auto-generated
2524         [MethodImplAttribute(MethodImplOptions.InternalCall)]
2525         internal static extern int LocaleNameToLCID(String localeName);
2526
2527         // These are desktop only, not coreclr
2528         // locale ID (0409), including sort information
2529         internal int ILANGUAGE
2530         {
2531             get
2532             {
2533                 if (this.iLanguage == 0)
2534                 {
2535                     Contract.Assert(this.sRealName != null, "[CultureData.ILANGUAGE] Expected this.sRealName to be populated by COMNlsInfo::nativeInitCultureData already");
2536                     this.iLanguage = LocaleNameToLCID(this.sRealName);
2537                 }
2538                 return this.iLanguage;
2539             }
2540         }
2541
2542         internal bool IsWin32Installed
2543         {
2544             get { return this.bWin32Installed; }
2545         }
2546
2547         internal bool IsFramework
2548         {
2549             get { return this.bFramework; }
2550         }
2551
2552         ////////////////////
2553         // Derived properties //
2554         ////////////////////
2555
2556         internal bool IsNeutralCulture
2557         {
2558             get
2559             {
2560                 // NlsInfo::nativeInitCultureData told us if we're neutral or not
2561                 return this.bNeutral;
2562             }
2563         }
2564
2565         internal bool IsInvariantCulture
2566         {
2567             get
2568             {
2569                 return String.IsNullOrEmpty(this.SNAME);
2570             }
2571         }
2572
2573         // Get an instance of our default calendar
2574         internal Calendar DefaultCalendar
2575         {
2576             get
2577             {
2578                 int defaultCalId = DoGetLocaleInfoInt(LOCALE_ICALENDARTYPE);
2579                 if (defaultCalId == 0)
2580                 {
2581                     defaultCalId = this.CalendarIds[0];
2582                 }
2583
2584                 return CultureInfo.GetCalendarInstance(defaultCalId);
2585             }
2586         }
2587
2588         // All of our era names
2589         internal String[] EraNames(int calendarId)
2590         {
2591             Contract.Assert(calendarId > 0, "[CultureData.saEraNames] Expected Calendar.ID > 0");
2592
2593             return this.GetCalendar(calendarId).saEraNames;
2594         }
2595
2596         internal String[] AbbrevEraNames(int calendarId)
2597         {
2598             Contract.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0");
2599
2600             return this.GetCalendar(calendarId).saAbbrevEraNames;
2601         }
2602
2603         internal String[] AbbreviatedEnglishEraNames(int calendarId)
2604         {
2605             Contract.Assert(calendarId > 0, "[CultureData.saAbbrevEraNames] Expected Calendar.ID > 0");
2606
2607             return this.GetCalendar(calendarId).saAbbrevEnglishEraNames;
2608         }
2609
2610         // String array DEFAULTS
2611         // Note: GetDTFIOverrideValues does the user overrides for these, so we don't have to.
2612
2613
2614         // Time separator (derived from time format)
2615         internal String TimeSeparator
2616         {
2617             [System.Security.SecuritySafeCritical]  // auto-generated
2618             get
2619             {
2620                 if (sTimeSeparator == null || UseUserOverride)
2621                 {
2622                     string longTimeFormat = ReescapeWin32String(DoGetLocaleInfo(LOCALE_STIMEFORMAT));
2623                     if (String.IsNullOrEmpty(longTimeFormat))
2624                     {
2625                         longTimeFormat = LongTimes[0];
2626                     }
2627
2628                     // Compute STIME from time format
2629                     sTimeSeparator = GetTimeSeparator(longTimeFormat);
2630                 }
2631                 return sTimeSeparator;
2632             }
2633         }
2634
2635         // Date separator (derived from short date format)
2636         internal String DateSeparator(int calendarId)
2637         {
2638             return GetDateSeparator(ShortDates(calendarId)[0]);
2639         }
2640
2641         //////////////////////////////////////
2642         // Helper Functions to get derived properties //
2643         //////////////////////////////////////
2644
2645         ////////////////////////////////////////////////////////////////////////////
2646         //
2647         // Unescape a NLS style quote string
2648         //
2649         // This removes single quotes:
2650         //      'fred' -> fred
2651         //      'fred -> fred
2652         //      fred' -> fred
2653         //      fred's -> freds
2654         //
2655         // This removes the first \ of escaped characters:
2656         //      fred\'s -> fred's
2657         //      a\\b -> a\b
2658         //      a\b -> ab
2659         //
2660         // We don't build the stringbuilder unless we find a ' or a \.  If we find a ' or a \, we
2661         // always build a stringbuilder because we need to remove the ' or \.
2662         //
2663         ////////////////////////////////////////////////////////////////////////////
2664         static private String UnescapeNlsString(String str, int start, int end)
2665         {
2666             Contract.Requires(str != null);
2667             Contract.Requires(start >= 0);
2668             Contract.Requires(end >= 0);
2669             StringBuilder result = null;
2670
2671             for (int i = start; i < str.Length && i <= end; i++)
2672             {
2673                 switch (str[i])
2674                 {
2675                     case '\'':
2676                         if (result == null)
2677                         {
2678                             result = new StringBuilder(str, start, i - start, str.Length);
2679                         }
2680                         break;
2681                     case '\\':
2682                         if (result == null)
2683                         {
2684                             result = new StringBuilder(str, start, i - start, str.Length);
2685                         }
2686                         ++i;
2687                         if (i < str.Length)
2688                         {
2689                             result.Append(str[i]);
2690                         }
2691                         break;
2692                     default:
2693                         if (result != null)
2694                         {
2695                             result.Append(str[i]);
2696                         }
2697                         break;
2698                 }
2699             }
2700
2701             if (result == null)
2702                 return (str.Substring(start, end - start + 1));
2703
2704             return (result.ToString());
2705         }
2706
2707         ////////////////////////////////////////////////////////////////////////////
2708         //
2709         // Reescape a Win32 style quote string as a NLS+ style quoted string
2710         //
2711         // This is also the escaping style used by custom culture data files
2712         //
2713         // NLS+ uses \ to escape the next character, whether in a quoted string or
2714         // not, so we always have to change \ to \\.
2715         //
2716         // NLS+ uses \' to escape a quote inside a quoted string so we have to change
2717         // '' to \' (if inside a quoted string)
2718         //
2719         // We don't build the stringbuilder unless we find something to change
2720         ////////////////////////////////////////////////////////////////////////////
2721         static internal String ReescapeWin32String(String str)
2722         {
2723             // If we don't have data, then don't try anything
2724             if (str == null)
2725                 return null;
2726
2727             StringBuilder result = null;
2728
2729             bool inQuote = false;
2730             for (int i = 0; i < str.Length; i++)
2731             {
2732                 // Look for quote
2733                 if (str[i] == '\'')
2734                 {
2735                     // Already in quote?
2736                     if (inQuote)
2737                     {
2738                         // See another single quote.  Is this '' of 'fred''s' or '''', or is it an ending quote?
2739                         if (i + 1 < str.Length && str[i + 1] == '\'')
2740                         {
2741                             // Found another ', so we have ''.  Need to add \' instead.
2742                             // 1st make sure we have our stringbuilder
2743                             if (result == null)
2744                                 result = new StringBuilder(str, 0, i, str.Length * 2);
2745
2746                             // Append a \' and keep going (so we don't turn off quote mode)
2747                             result.Append("\\'");
2748                             i++;
2749                             continue;
2750                         }
2751
2752                         // Turning off quote mode, fall through to add it
2753                         inQuote = false;
2754                     }
2755                     else
2756                     {
2757                         // Found beginning quote, fall through to add it
2758                         inQuote = true;
2759                     }
2760                 }
2761                 // Is there a single \ character?
2762                 else if (str[i] == '\\')
2763                 {
2764                     // Found a \, need to change it to \\
2765                     // 1st make sure we have our stringbuilder
2766                     if (result == null)
2767                         result = new StringBuilder(str, 0, i, str.Length * 2);
2768
2769                     // Append our \\ to the string & continue
2770                     result.Append("\\\\");
2771                     continue;
2772                 }
2773
2774                 // If we have a builder we need to add our character
2775                 if (result != null)
2776                     result.Append(str[i]);
2777             }
2778
2779             // Unchanged string? , just return input string
2780             if (result == null)
2781                 return str;
2782
2783             // String changed, need to use the builder
2784             return result.ToString();
2785         }
2786
2787         static internal String[] ReescapeWin32Strings(String[] array)
2788         {
2789             if (array != null)
2790             {
2791                 for (int i = 0; i < array.Length; i++)
2792                 {
2793                     array[i] = ReescapeWin32String(array[i]);
2794                 }
2795             }
2796
2797             return array;
2798         }
2799
2800         // NOTE: this method is used through reflection by System.Globalization.CultureXmlParser.ReadDateElement()
2801         // and breaking changes here will not show up at build time, only at run time.
2802         static private String GetTimeSeparator(String format)
2803         {
2804             // Time format separator (ie: : in 12:39:00)
2805             //
2806             // We calculate this from the provided time format
2807             //
2808
2809             //
2810             //  Find the time separator so that we can pretend we know STIME.
2811             //
2812             return GetSeparator(format, "Hhms");
2813         }
2814
2815         // NOTE: this method is used through reflection by System.Globalization.CultureXmlParser.ReadDateElement()
2816         // and breaking changes here will not show up at build time, only at run time.
2817         static private String GetDateSeparator(String format)
2818         {
2819             // Date format separator (ie: / in 9/1/03)
2820             //
2821             // We calculate this from the provided short date
2822             //
2823
2824             //
2825             //  Find the date separator so that we can pretend we know SDATE.
2826             //
2827             return GetSeparator(format, "dyM");
2828         }
2829
2830         private static string GetSeparator(string format, string timeParts)
2831         {
2832             int index = IndexOfTimePart(format, 0, timeParts);
2833
2834             if (index != -1)
2835             {
2836                 // Found a time part, find out when it changes
2837                 char cTimePart = format[index];
2838
2839                 do
2840                 {
2841                     index++;
2842                 } while (index < format.Length && format[index] == cTimePart);
2843
2844                 int separatorStart = index;
2845
2846                 // Now we need to find the end of the separator
2847                 if (separatorStart < format.Length)
2848                 {
2849                     int separatorEnd = IndexOfTimePart(format, separatorStart, timeParts);
2850                     if (separatorEnd != -1)
2851                     {
2852                         // From [separatorStart, count) is our string, except we need to unescape
2853                         return UnescapeNlsString(format, separatorStart, separatorEnd - 1);
2854                     }
2855                 }
2856             }
2857
2858             return String.Empty;
2859         }
2860
2861         private static int IndexOfTimePart(string format, int startIndex, string timeParts)
2862         {
2863             Contract.Assert(startIndex >= 0, "startIndex cannot be negative");
2864             Contract.Assert(timeParts.IndexOfAny(new char[] { '\'', '\\' }) == -1, "timeParts cannot include quote characters");
2865             bool inQuote = false;
2866             for (int i = startIndex; i < format.Length; ++i)
2867             {
2868                 // See if we have a time Part
2869                 if (!inQuote && timeParts.IndexOf(format[i]) != -1)
2870                 {
2871                     return i;
2872                 }
2873                 switch (format[i])
2874                 {
2875                     case '\\':
2876                         if (i + 1 < format.Length)
2877                         {
2878                             ++i;
2879                             switch (format[i])
2880                             {
2881                                 case '\'':
2882                                 case '\\':
2883                                     break;
2884                                 default:
2885                                     --i; //backup since we will move over this next
2886                                     break;
2887                             }
2888                         }
2889                         break;
2890                     case '\'':
2891                         inQuote = !inQuote;
2892                         break;
2893                 }
2894             }
2895
2896             return -1;
2897         }
2898
2899         [System.Security.SecurityCritical]
2900         string DoGetLocaleInfo(uint lctype)
2901         {
2902             Contract.Assert(this.sWindowsName != null, "[CultureData.DoGetLocaleInfo] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
2903             return DoGetLocaleInfo(this.sWindowsName, lctype);
2904         }
2905
2906         // For LOCALE_SPARENT we need the option of using the "real" name (forcing neutral names) instead of the
2907         // "windows" name, which can be specific for downlevel (< windows 7) os's.
2908         [System.Security.SecurityCritical]  // auto-generated
2909         string DoGetLocaleInfo(string localeName, uint lctype)
2910         {
2911             // Fix lctype if we don't want overrides
2912             if (!UseUserOverride)
2913             {
2914                 lctype |= LOCALE_NOUSEROVERRIDE;
2915             }
2916
2917             // Ask OS for data
2918             Contract.Assert(localeName != null, "[CultureData.DoGetLocaleInfo] Expected localeName to be not be null");
2919             string result = CultureInfo.nativeGetLocaleInfoEx(localeName, lctype);
2920             if (result == null)
2921             {
2922                 // Failed, just use empty string
2923                 result = String.Empty;
2924             }
2925
2926             return result;
2927         }
2928
2929         int DoGetLocaleInfoInt(uint lctype)
2930         {
2931             // Fix lctype if we don't want overrides
2932             if (!UseUserOverride)
2933             {
2934                 lctype |= LOCALE_NOUSEROVERRIDE;
2935             }
2936
2937             // Ask OS for data, note that we presume it returns success, so we have to know that
2938             // sWindowsName is valid before calling.
2939             Contract.Assert(this.sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
2940             int result = CultureInfo.nativeGetLocaleInfoExInt(this.sWindowsName, lctype);
2941
2942             return result;
2943         }
2944
2945         String[] DoEnumTimeFormats()
2946         {
2947             // Note that this gets overrides for us all the time
2948             Contract.Assert(this.sWindowsName != null, "[CultureData.DoEnumTimeFormats] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
2949             String[] result = ReescapeWin32Strings(nativeEnumTimeFormats(this.sWindowsName, 0, UseUserOverride));
2950
2951             return result;
2952         }
2953
2954         String[] DoEnumShortTimeFormats()
2955         {
2956             // Note that this gets overrides for us all the time
2957             Contract.Assert(this.sWindowsName != null, "[CultureData.DoEnumShortTimeFormats] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
2958             String[] result = ReescapeWin32Strings(nativeEnumTimeFormats(this.sWindowsName, TIME_NOSECONDS, UseUserOverride));
2959
2960             return result;
2961         }
2962
2963         /////////////////
2964         // Static Helpers //
2965         ////////////////
2966         internal static bool IsCustomCultureId(int cultureId)
2967         {
2968             if (cultureId == CultureInfo.LOCALE_CUSTOM_DEFAULT || cultureId == CultureInfo.LOCALE_CUSTOM_UNSPECIFIED)
2969                 return true;
2970
2971             return false;
2972         }
2973
2974         ////////////////////////////////////////////////////////////////////////////
2975         //
2976         // Parameters:
2977         //      calendarValueOnly   Retrieve the values which are affected by the calendar change of DTFI.
2978         //                          This will cause values like longTimePattern not be retrieved since it is
2979         //                          not affected by the Calendar property in DTFI.
2980         //
2981         ////////////////////////////////////////////////////////////////////////////
2982         [System.Security.SecurityCritical]  // auto-generated
2983         internal void GetNFIValues(NumberFormatInfo nfi)
2984         {
2985             if (this.IsInvariantCulture)
2986             {
2987                 nfi.positiveSign = this.sPositiveSign;
2988                 nfi.negativeSign = this.sNegativeSign;
2989
2990                 nfi.nativeDigits = this.saNativeDigits;
2991                 nfi.digitSubstitution = this.iDigitSubstitution;
2992
2993                 nfi.numberGroupSeparator = this.sThousandSeparator;
2994                 nfi.numberDecimalSeparator = this.sDecimalSeparator;
2995                 nfi.numberDecimalDigits = this.iDigits;
2996                 nfi.numberNegativePattern = this.iNegativeNumber;
2997
2998                 nfi.currencySymbol = this.sCurrency;
2999                 nfi.currencyGroupSeparator = this.sMonetaryThousand;
3000                 nfi.currencyDecimalSeparator = this.sMonetaryDecimal;
3001                 nfi.currencyDecimalDigits = this.iCurrencyDigits;
3002                 nfi.currencyNegativePattern = this.iNegativeCurrency;
3003                 nfi.currencyPositivePattern = this.iCurrency;
3004             }
3005             else
3006             {
3007                 //
3008                 // We don't have information for the following four.  All cultures use
3009                 // the same value of the number formatting values.
3010                 //
3011                 // PercentDecimalDigits
3012                 // PercentDecimalSeparator
3013                 // PercentGroupSize
3014                 // PercentGroupSeparator
3015                 //
3016
3017                 //
3018                 // Ask native side for our data.
3019                 //
3020                 Contract.Assert(this.sWindowsName != null, "[CultureData.GetNFIValues] Expected this.sWindowsName to be populated by COMNlsInfo::nativeInitCultureData already");
3021                 CultureData.nativeGetNumberFormatInfoValues(this.sWindowsName, nfi, UseUserOverride);
3022             }
3023
3024
3025             //
3026             // Gather additional data
3027             //
3028             nfi.numberGroupSizes = this.WAGROUPING;
3029             nfi.currencyGroupSizes = this.WAMONGROUPING;
3030
3031             // prefer the cached value since these do not have user overrides
3032             nfi.percentNegativePattern = this.INEGATIVEPERCENT;
3033             nfi.percentPositivePattern = this.IPOSITIVEPERCENT;
3034             nfi.percentSymbol = this.SPERCENT;
3035             nfi.perMilleSymbol = this.SPERMILLE;
3036
3037             nfi.negativeInfinitySymbol = this.SNEGINFINITY;
3038             nfi.positiveInfinitySymbol = this.SPOSINFINITY;
3039             nfi.nanSymbol = this.SNAN;
3040
3041             //
3042             // We don't have percent values, so use the number values
3043             //
3044             nfi.percentDecimalDigits = nfi.numberDecimalDigits;
3045             nfi.percentDecimalSeparator = nfi.numberDecimalSeparator;
3046             nfi.percentGroupSizes = nfi.numberGroupSizes;
3047             nfi.percentGroupSeparator = nfi.numberGroupSeparator;
3048
3049             //
3050             // Clean up a few odd values
3051             //
3052
3053             // Windows usually returns an empty positive sign, but we like it to be "+"
3054             if (nfi.positiveSign == null || nfi.positiveSign.Length == 0) nfi.positiveSign = "+";
3055
3056             //Special case for Italian.  The currency decimal separator in the control panel is the empty string. When the user
3057             //specifies C4 as the currency format, this results in the number apparently getting multiplied by 10000 because the
3058             //decimal point doesn't show up.  We'll just workaround this here because our default currency format will never use nfi.
3059             if (nfi.currencyDecimalSeparator == null || nfi.currencyDecimalSeparator.Length == 0)
3060             {
3061                 nfi.currencyDecimalSeparator = nfi.numberDecimalSeparator;
3062             }
3063
3064 #if !FEATURE_CORECLR
3065             if ((932 == this.IDEFAULTANSICODEPAGE) ||
3066                (949 == this.IDEFAULTANSICODEPAGE))
3067             {
3068                 // Legacy behavior for cultures that use Japanese/Korean default ANSI code pages
3069                 // Note that this is a code point, not a character.  On Japanese/Korean machines this
3070                 // will be rendered as their currency symbol, not rendered as a "\"
3071                 nfi.ansiCurrencySymbol = "\x5c";
3072             }
3073 #endif // !FEATURE_CORECLR
3074         }
3075
3076         static private int ConvertFirstDayOfWeekMonToSun(int iTemp)
3077         {
3078             // Convert Mon-Sun to Sun-Sat format
3079             iTemp++;
3080             if (iTemp > 6)
3081             {
3082                 // Wrap Sunday and convert invalid data to Sunday
3083                 iTemp = 0;
3084             }
3085             return iTemp;
3086         }
3087
3088         // Helper
3089         // This is ONLY used for caching names and shouldn't be used for anything else
3090         internal static string AnsiToLower(string testString)
3091         {
3092             StringBuilder sb = new StringBuilder(testString.Length);
3093
3094             for (int ich = 0; ich < testString.Length; ich++)
3095             {
3096                 char ch = testString[ich];
3097                 sb.Append(ch <= 'Z' && ch >= 'A' ? (char)(ch - 'A' + 'a') : ch);
3098             }
3099
3100             return (sb.ToString());
3101         }
3102
3103         // If we get a group from windows, then its in 3;0 format with the 0 backwards
3104         // of how NLS+ uses it (ie: if the string has a 0, then the int[] shouldn't and vice versa)
3105         // EXCEPT in the case where the list only contains 0 in which NLS and NLS+ have the same meaning.
3106         static private int[] ConvertWin32GroupString(String win32Str)
3107         {
3108             // None of these cases make any sense
3109             if (win32Str == null || win32Str.Length == 0)
3110             {
3111                 return (new int[] { 3 });
3112             }
3113
3114             if (win32Str[0] == '0')
3115             {
3116                 return (new int[] { 0 });
3117             }
3118
3119             // Since its in n;n;n;n;n format, we can always get the length quickly
3120             int[] values;
3121             if (win32Str[win32Str.Length - 1] == '0')
3122             {
3123                 // Trailing 0 gets dropped. 1;0 -> 1
3124                 values = new int[(win32Str.Length / 2)];
3125             }
3126             else
3127             {
3128                 // Need extra space for trailing zero 1 -> 1;0
3129                 values = new int[(win32Str.Length / 2) + 2];
3130                 values[values.Length - 1] = 0;
3131             }
3132
3133             int i;
3134             int j;
3135             for (i = 0, j = 0; i < win32Str.Length && j < values.Length; i += 2, j++)
3136             {
3137                 // Note that this # shouldn't ever be zero, 'cause 0 is only at end
3138                 // But we'll test because its registry that could be anything
3139                 if (win32Str[i] < '1' || win32Str[i] > '9')
3140                     return new int[] { 3 };
3141
3142                 values[j] = (int)(win32Str[i] - '0');
3143             }
3144
3145             return (values);
3146         }
3147
3148         // LCTYPES for GetLocaleInfo
3149         private const uint LOCALE_NOUSEROVERRIDE = 0x80000000;   // do not use user overrides
3150         private const uint LOCALE_RETURN_NUMBER = 0x20000000;   // return number instead of string
3151
3152         // Modifier for genitive names
3153         private const uint LOCALE_RETURN_GENITIVE_NAMES = 0x10000000;   //Flag to return the Genitive forms of month names
3154
3155         //
3156         //  The following LCTypes are mutually exclusive in that they may NOT
3157         //  be used in combination with each other.
3158         //
3159
3160         //
3161         // These are the various forms of the name of the locale:
3162         //
3163         private const uint LOCALE_SLOCALIZEDDISPLAYNAME = 0x00000002;   // localized name of locale, eg "German (Germany)" in UI language
3164         private const uint LOCALE_SENGLISHDISPLAYNAME = 0x00000072;   // Display name (language + country usually) in English, eg "German (Germany)"
3165         private const uint LOCALE_SNATIVEDISPLAYNAME = 0x00000073;   // Display name in native locale language, eg "Deutsch (Deutschland)
3166
3167         private const uint LOCALE_SLOCALIZEDLANGUAGENAME = 0x0000006f;   // Language Display Name for a language, eg "German" in UI language
3168         private const uint LOCALE_SENGLISHLANGUAGENAME = 0x00001001;   // English name of language, eg "German"
3169         private const uint LOCALE_SNATIVELANGUAGENAME = 0x00000004;   // native name of language, eg "Deutsch"
3170
3171         private const uint LOCALE_SLOCALIZEDCOUNTRYNAME = 0x00000006;   // localized name of country, eg "Germany" in UI language
3172         private const uint LOCALE_SENGLISHCOUNTRYNAME = 0x00001002;   // English name of country, eg "Germany"
3173         private const uint LOCALE_SNATIVECOUNTRYNAME = 0x00000008;   // native name of country, eg "Deutschland"
3174
3175
3176         //        private const uint LOCALE_ILANGUAGE              =0x00000001;   // language id // Don't use, use NewApis::LocaleNameToLCID instead (GetLocaleInfo doesn't return neutrals)
3177
3178         //        private const uint LOCALE_SLANGUAGE              =LOCALE_SLOCALIZEDDISPLAYNAME;   // localized name of language (use LOCALE_SLOCALIZEDDISPLAYNAME instead)
3179         //        private const uint LOCALE_SENGLANGUAGE           =LOCALE_SENGLISHLANGUAGENAME;   // English name of language (use LOCALE_SENGLISHLANGUAGENAME instead)
3180         private const uint LOCALE_SABBREVLANGNAME = 0x00000003;   // abbreviated language name
3181         //        private const uint LOCALE_SNATIVELANGNAME        =LOCALE_SNATIVELANGUAGENAME;   // native name of language (use LOCALE_SNATIVELANGUAGENAME instead)
3182
3183         private const uint LOCALE_ICOUNTRY = 0x00000005;   // country code
3184         //        private const uint LOCALE_SCOUNTRY               =LOCALE_SLOCALIZEDCOUNTRYNAME;   // localized name of country (use LOCALE_SLOCALIZEDCOUNTRYNAME instead)
3185         //        private const uint LOCALE_SENGCOUNTRY            =LOCALE_SENGLISHCOUNTRYNAME;   // English name of country (use LOCALE_SENGLISHCOUNTRYNAME instead)
3186         private const uint LOCALE_SABBREVCTRYNAME = 0x00000007;   // abbreviated country name
3187         //        private const uint LOCALE_SNATIVECTRYNAME        =LOCALE_SNATIVECOUNTRYNAME;   // native name of country ( use LOCALE_SNATIVECOUNTRYNAME instead)
3188         private const uint LOCALE_IGEOID = 0x0000005B;   // geographical location id
3189
3190         private const uint LOCALE_IDEFAULTLANGUAGE = 0x00000009;   // default language id
3191         private const uint LOCALE_IDEFAULTCOUNTRY = 0x0000000A;   // default country code
3192         private const uint LOCALE_IDEFAULTCODEPAGE = 0x0000000B;   // default oem code page
3193         private const uint LOCALE_IDEFAULTANSICODEPAGE = 0x00001004;   // default ansi code page
3194         private const uint LOCALE_IDEFAULTMACCODEPAGE = 0x00001011;   // default mac code page
3195
3196         private const uint LOCALE_SLIST = 0x0000000C;   // list item separator
3197         private const uint LOCALE_IMEASURE = 0x0000000D;   // 0 = metric, 1 = US
3198
3199         private const uint LOCALE_SDECIMAL = 0x0000000E;   // decimal separator
3200         private const uint LOCALE_STHOUSAND = 0x0000000F;   // thousand separator
3201         private const uint LOCALE_SGROUPING = 0x00000010;   // digit grouping
3202         private const uint LOCALE_IDIGITS = 0x00000011;   // number of fractional digits
3203         private const uint LOCALE_ILZERO = 0x00000012;   // leading zeros for decimal
3204         private const uint LOCALE_INEGNUMBER = 0x00001010;   // negative number mode
3205         private const uint LOCALE_SNATIVEDIGITS = 0x00000013;   // native digits for 0-9
3206
3207         private const uint LOCALE_SCURRENCY = 0x00000014;   // local monetary symbol
3208         private const uint LOCALE_SINTLSYMBOL = 0x00000015;   // uintl monetary symbol
3209         private const uint LOCALE_SMONDECIMALSEP = 0x00000016;   // monetary decimal separator
3210         private const uint LOCALE_SMONTHOUSANDSEP = 0x00000017;   // monetary thousand separator
3211         private const uint LOCALE_SMONGROUPING = 0x00000018;   // monetary grouping
3212         private const uint LOCALE_ICURRDIGITS = 0x00000019;   // # local monetary digits
3213         private const uint LOCALE_IINTLCURRDIGITS = 0x0000001A;   // # uintl monetary digits
3214         private const uint LOCALE_ICURRENCY = 0x0000001B;   // positive currency mode
3215         private const uint LOCALE_INEGCURR = 0x0000001C;   // negative currency mode
3216
3217         private const uint LOCALE_SDATE = 0x0000001D;   // date separator (derived from LOCALE_SSHORTDATE, use that instead)
3218         private const uint LOCALE_STIME = 0x0000001E;   // time separator (derived from LOCALE_STIMEFORMAT, use that instead)
3219         private const uint LOCALE_SSHORTDATE = 0x0000001F;   // short date format string
3220         private const uint LOCALE_SLONGDATE = 0x00000020;   // long date format string
3221         private const uint LOCALE_STIMEFORMAT = 0x00001003;   // time format string
3222         private const uint LOCALE_IDATE = 0x00000021;   // short date format ordering (derived from LOCALE_SSHORTDATE, use that instead)
3223         private const uint LOCALE_ILDATE = 0x00000022;   // long date format ordering (derived from LOCALE_SLONGDATE, use that instead)
3224         private const uint LOCALE_ITIME = 0x00000023;   // time format specifier (derived from LOCALE_STIMEFORMAT, use that instead)
3225         private const uint LOCALE_ITIMEMARKPOSN = 0x00001005;   // time marker position (derived from LOCALE_STIMEFORMAT, use that instead)
3226         private const uint LOCALE_ICENTURY = 0x00000024;   // century format specifier (short date, LOCALE_SSHORTDATE is preferred)
3227         private const uint LOCALE_ITLZERO = 0x00000025;   // leading zeros in time field (derived from LOCALE_STIMEFORMAT, use that instead)
3228         private const uint LOCALE_IDAYLZERO = 0x00000026;   // leading zeros in day field (short date, LOCALE_SSHORTDATE is preferred)
3229         private const uint LOCALE_IMONLZERO = 0x00000027;   // leading zeros in month field (short date, LOCALE_SSHORTDATE is preferred)
3230         private const uint LOCALE_S1159 = 0x00000028;   // AM designator
3231         private const uint LOCALE_S2359 = 0x00000029;   // PM designator
3232
3233         private const uint LOCALE_ICALENDARTYPE = 0x00001009;   // type of calendar specifier
3234         private const uint LOCALE_IOPTIONALCALENDAR = 0x0000100B;   // additional calendar types specifier
3235         private const uint LOCALE_IFIRSTDAYOFWEEK = 0x0000100C;   // first day of week specifier
3236         private const uint LOCALE_IFIRSTWEEKOFYEAR = 0x0000100D;   // first week of year specifier
3237
3238         private const uint LOCALE_SDAYNAME1 = 0x0000002A;   // long name for Monday
3239         private const uint LOCALE_SDAYNAME2 = 0x0000002B;   // long name for Tuesday
3240         private const uint LOCALE_SDAYNAME3 = 0x0000002C;   // long name for Wednesday
3241         private const uint LOCALE_SDAYNAME4 = 0x0000002D;   // long name for Thursday
3242         private const uint LOCALE_SDAYNAME5 = 0x0000002E;   // long name for Friday
3243         private const uint LOCALE_SDAYNAME6 = 0x0000002F;   // long name for Saturday
3244         private const uint LOCALE_SDAYNAME7 = 0x00000030;   // long name for Sunday
3245         private const uint LOCALE_SABBREVDAYNAME1 = 0x00000031;   // abbreviated name for Monday
3246         private const uint LOCALE_SABBREVDAYNAME2 = 0x00000032;   // abbreviated name for Tuesday
3247         private const uint LOCALE_SABBREVDAYNAME3 = 0x00000033;   // abbreviated name for Wednesday
3248         private const uint LOCALE_SABBREVDAYNAME4 = 0x00000034;   // abbreviated name for Thursday
3249         private const uint LOCALE_SABBREVDAYNAME5 = 0x00000035;   // abbreviated name for Friday
3250         private const uint LOCALE_SABBREVDAYNAME6 = 0x00000036;   // abbreviated name for Saturday
3251         private const uint LOCALE_SABBREVDAYNAME7 = 0x00000037;   // abbreviated name for Sunday
3252         private const uint LOCALE_SMONTHNAME1 = 0x00000038;   // long name for January
3253         private const uint LOCALE_SMONTHNAME2 = 0x00000039;   // long name for February
3254         private const uint LOCALE_SMONTHNAME3 = 0x0000003A;   // long name for March
3255         private const uint LOCALE_SMONTHNAME4 = 0x0000003B;   // long name for April
3256         private const uint LOCALE_SMONTHNAME5 = 0x0000003C;   // long name for May
3257         private const uint LOCALE_SMONTHNAME6 = 0x0000003D;   // long name for June
3258         private const uint LOCALE_SMONTHNAME7 = 0x0000003E;   // long name for July
3259         private const uint LOCALE_SMONTHNAME8 = 0x0000003F;   // long name for August
3260         private const uint LOCALE_SMONTHNAME9 = 0x00000040;   // long name for September
3261         private const uint LOCALE_SMONTHNAME10 = 0x00000041;   // long name for October
3262         private const uint LOCALE_SMONTHNAME11 = 0x00000042;   // long name for November
3263         private const uint LOCALE_SMONTHNAME12 = 0x00000043;   // long name for December
3264         private const uint LOCALE_SMONTHNAME13 = 0x0000100E;   // long name for 13th month (if exists)
3265         private const uint LOCALE_SABBREVMONTHNAME1 = 0x00000044;   // abbreviated name for January
3266         private const uint LOCALE_SABBREVMONTHNAME2 = 0x00000045;   // abbreviated name for February
3267         private const uint LOCALE_SABBREVMONTHNAME3 = 0x00000046;   // abbreviated name for March
3268         private const uint LOCALE_SABBREVMONTHNAME4 = 0x00000047;   // abbreviated name for April
3269         private const uint LOCALE_SABBREVMONTHNAME5 = 0x00000048;   // abbreviated name for May
3270         private const uint LOCALE_SABBREVMONTHNAME6 = 0x00000049;   // abbreviated name for June
3271         private const uint LOCALE_SABBREVMONTHNAME7 = 0x0000004A;   // abbreviated name for July
3272         private const uint LOCALE_SABBREVMONTHNAME8 = 0x0000004B;   // abbreviated name for August
3273         private const uint LOCALE_SABBREVMONTHNAME9 = 0x0000004C;   // abbreviated name for September
3274         private const uint LOCALE_SABBREVMONTHNAME10 = 0x0000004D;   // abbreviated name for October
3275         private const uint LOCALE_SABBREVMONTHNAME11 = 0x0000004E;   // abbreviated name for November
3276         private const uint LOCALE_SABBREVMONTHNAME12 = 0x0000004F;   // abbreviated name for December
3277         private const uint LOCALE_SABBREVMONTHNAME13 = 0x0000100F;   // abbreviated name for 13th month (if exists)
3278
3279         private const uint LOCALE_SPOSITIVESIGN = 0x00000050;   // positive sign
3280         private const uint LOCALE_SNEGATIVESIGN = 0x00000051;   // negative sign
3281         private const uint LOCALE_IPOSSIGNPOSN = 0x00000052;   // positive sign position (derived from INEGCURR)
3282         private const uint LOCALE_INEGSIGNPOSN = 0x00000053;   // negative sign position (derived from INEGCURR)
3283         private const uint LOCALE_IPOSSYMPRECEDES = 0x00000054;   // mon sym precedes pos amt (derived from ICURRENCY)
3284         private const uint LOCALE_IPOSSEPBYSPACE = 0x00000055;   // mon sym sep by space from pos amt (derived from ICURRENCY)
3285         private const uint LOCALE_INEGSYMPRECEDES = 0x00000056;   // mon sym precedes neg amt (derived from INEGCURR)
3286         private const uint LOCALE_INEGSEPBYSPACE = 0x00000057;   // mon sym sep by space from neg amt (derived from INEGCURR)
3287
3288         private const uint LOCALE_FONTSIGNATURE = 0x00000058;   // font signature
3289         private const uint LOCALE_SISO639LANGNAME = 0x00000059;   // ISO abbreviated language name
3290         private const uint LOCALE_SISO3166CTRYNAME = 0x0000005A;   // ISO abbreviated country name
3291
3292         private const uint LOCALE_IDEFAULTEBCDICCODEPAGE = 0x00001012;   // default ebcdic code page
3293         private const uint LOCALE_IPAPERSIZE = 0x0000100A;   // 1 = letter, 5 = legal, 8 = a3, 9 = a4
3294         private const uint LOCALE_SENGCURRNAME = 0x00001007;   // english name of currency
3295         private const uint LOCALE_SNATIVECURRNAME = 0x00001008;   // native name of currency
3296         private const uint LOCALE_SYEARMONTH = 0x00001006;   // year month format string
3297         private const uint LOCALE_SSORTNAME = 0x00001013;   // sort name
3298         private const uint LOCALE_IDIGITSUBSTITUTION = 0x00001014;   // 0 = context, 1 = none, 2 = national
3299
3300         private const uint LOCALE_SNAME = 0x0000005c;   // locale name (with sort info) (ie: de-DE_phoneb)
3301         private const uint LOCALE_SDURATION = 0x0000005d;   // time duration format
3302         private const uint LOCALE_SKEYBOARDSTOINSTALL = 0x0000005e;   // (windows only) keyboards to install
3303         private const uint LOCALE_SSHORTESTDAYNAME1 = 0x00000060;   // Shortest day name for Monday
3304         private const uint LOCALE_SSHORTESTDAYNAME2 = 0x00000061;   // Shortest day name for Tuesday
3305         private const uint LOCALE_SSHORTESTDAYNAME3 = 0x00000062;   // Shortest day name for Wednesday
3306         private const uint LOCALE_SSHORTESTDAYNAME4 = 0x00000063;   // Shortest day name for Thursday
3307         private const uint LOCALE_SSHORTESTDAYNAME5 = 0x00000064;   // Shortest day name for Friday
3308         private const uint LOCALE_SSHORTESTDAYNAME6 = 0x00000065;   // Shortest day name for Saturday
3309         private const uint LOCALE_SSHORTESTDAYNAME7 = 0x00000066;   // Shortest day name for Sunday
3310         private const uint LOCALE_SISO639LANGNAME2 = 0x00000067;   // 3 character ISO abbreviated language name
3311         private const uint LOCALE_SISO3166CTRYNAME2 = 0x00000068;   // 3 character ISO country name
3312         private const uint LOCALE_SNAN = 0x00000069;   // Not a Number
3313         private const uint LOCALE_SPOSINFINITY = 0x0000006a;   // + Infinity
3314         private const uint LOCALE_SNEGINFINITY = 0x0000006b;   // - Infinity
3315         private const uint LOCALE_SSCRIPTS = 0x0000006c;   // Typical scripts in the locale
3316         private const uint LOCALE_SPARENT = 0x0000006d;   // Fallback name for resources
3317         private const uint LOCALE_SCONSOLEFALLBACKNAME = 0x0000006e;   // Fallback name for within the console
3318         //        private const uint LOCALE_SLANGDISPLAYNAME       =LOCALE_SLOCALIZEDLANGUAGENAME;   // Language Display Name for a language (use LOCALE_SLOCALIZEDLANGUAGENAME instead)
3319
3320         // Windows 7 LCTYPES
3321         private const uint LOCALE_IREADINGLAYOUT = 0x00000070;   // Returns one of the following 4 reading layout values:
3322         // 0 - Left to right (eg en-US)
3323         // 1 - Right to left (eg arabic locales)
3324         // 2 - Vertical top to bottom with columns to the left and also left to right (ja-JP locales)
3325         // 3 - Vertical top to bottom with columns proceeding to the right
3326         private const uint LOCALE_INEUTRAL = 0x00000071;   // Returns 0 for specific cultures, 1 for neutral cultures.
3327         private const uint LOCALE_INEGATIVEPERCENT = 0x00000074;   // Returns 0-11 for the negative percent format
3328         private const uint LOCALE_IPOSITIVEPERCENT = 0x00000075;   // Returns 0-3 for the positive percent formatIPOSITIVEPERCENT
3329         private const uint LOCALE_SPERCENT = 0x00000076;   // Returns the percent symbol
3330         private const uint LOCALE_SPERMILLE = 0x00000077;   // Returns the permille (U+2030) symbol
3331         private const uint LOCALE_SMONTHDAY = 0x00000078;   // Returns the preferred month/day format
3332         private const uint LOCALE_SSHORTTIME = 0x00000079;   // Returns the preferred short time format (ie: no seconds, just h:mm)
3333         private const uint LOCALE_SOPENTYPELANGUAGETAG = 0x0000007a;   // Open type language tag, eg: "latn" or "dflt"
3334         private const uint LOCALE_SSORTLOCALE = 0x0000007b;   // Name of locale to use for sorting/collation/casing behavior.
3335
3336         // Time formats enumerations
3337         internal const uint TIME_NOSECONDS = 0x00000002;   // Don't use seconds (get short time format for enumtimeformats on win7+)
3338
3339         // Get our initial minimal culture data (name, parent, etc.)
3340         [System.Security.SecuritySafeCritical]  // auto-generated
3341         [MethodImplAttribute(MethodImplOptions.InternalCall)]
3342         internal static extern bool nativeInitCultureData(CultureData cultureData);
3343
3344         // Grab the NumberFormatInfo data
3345         [System.Security.SecuritySafeCritical]  // auto-generated
3346         [MethodImplAttribute(MethodImplOptions.InternalCall)]
3347         internal static extern bool nativeGetNumberFormatInfoValues(String localeName, NumberFormatInfo nfi, bool useUserOverride);
3348
3349         [System.Security.SecuritySafeCritical]  // auto-generated
3350         [MethodImplAttribute(MethodImplOptions.InternalCall)]
3351         private static extern String[] nativeEnumTimeFormats(String localeName, uint dwFlags, bool useUserOverride);
3352
3353         [System.Security.SecurityCritical]  // auto-generated
3354         [SuppressUnmanagedCodeSecurityAttribute()]
3355         [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
3356         internal static extern int nativeEnumCultureNames(int cultureTypes, ObjectHandleOnStack retStringArray);
3357     }
3358 }