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