| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774 |
- // Licensed to the .NET Foundation under one or more agreements.
- // The .NET Foundation licenses this file to you under the MIT license.
- // See the LICENSE file in the project root for more information.
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Runtime.CompilerServices;
- using System.Runtime.InteropServices;
- using System.Text;
- using Internal.Runtime.CompilerServices;
- #if ENABLE_WINRT
- using Internal.Runtime.Augments;
- #endif
- namespace System.Globalization
- {
- internal partial class CultureData
- {
- private const uint LOCALE_NOUSEROVERRIDE = 0x80000000;
- private const uint LOCALE_RETURN_NUMBER = 0x20000000;
- private const uint LOCALE_SISO3166CTRYNAME = 0x0000005A;
- private const uint TIME_NOSECONDS = 0x00000002;
- /// <summary>
- /// Check with the OS to see if this is a valid culture.
- /// If so we populate a limited number of fields. If its not valid we return false.
- ///
- /// The fields we populate:
- ///
- /// sWindowsName -- The name that windows thinks this culture is, ie:
- /// en-US if you pass in en-US
- /// de-DE_phoneb if you pass in de-DE_phoneb
- /// fj-FJ if you pass in fj (neutral, on a pre-Windows 7 machine)
- /// fj if you pass in fj (neutral, post-Windows 7 machine)
- ///
- /// sRealName -- The name you used to construct the culture, in pretty form
- /// en-US if you pass in EN-us
- /// en if you pass in en
- /// de-DE_phoneb if you pass in de-DE_phoneb
- ///
- /// sSpecificCulture -- The specific culture for this culture
- /// en-US for en-US
- /// en-US for en
- /// de-DE_phoneb for alt sort
- /// fj-FJ for fj (neutral)
- ///
- /// sName -- The IETF name of this culture (ie: no sort info, could be neutral)
- /// en-US if you pass in en-US
- /// en if you pass in en
- /// de-DE if you pass in de-DE_phoneb
- ///
- /// bNeutral -- TRUE if it is a neutral locale
- ///
- /// For a neutral we just populate the neutral name, but we leave the windows name pointing to the
- /// windows locale that's going to provide data for us.
- /// </summary>
- private unsafe bool InitCultureData()
- {
- Debug.Assert(!GlobalizationMode.Invariant);
- const uint LOCALE_ILANGUAGE = 0x00000001;
- const uint LOCALE_INEUTRAL = 0x00000071;
- const uint LOCALE_SNAME = 0x0000005c;
- int result;
- string realNameBuffer = _sRealName;
- char* pBuffer = stackalloc char[LOCALE_NAME_MAX_LENGTH];
- result = GetLocaleInfoEx(realNameBuffer, LOCALE_SNAME, pBuffer, LOCALE_NAME_MAX_LENGTH);
- // Did it fail?
- if (result == 0)
- {
- return false;
- }
- // It worked, note that the name is the locale name, so use that (even for neutrals)
- // We need to clean up our "real" name, which should look like the windows name right now
- // so overwrite the input with the cleaned up name
- _sRealName = new string(pBuffer, 0, result - 1);
- realNameBuffer = _sRealName;
- // Check for neutrality, don't expect to fail
- // (buffer has our name in it, so we don't have to do the gc. stuff)
- result = GetLocaleInfoEx(realNameBuffer, LOCALE_INEUTRAL | LOCALE_RETURN_NUMBER, pBuffer, sizeof(int) / sizeof(char));
- if (result == 0)
- {
- return false;
- }
- // Remember our neutrality
- _bNeutral = *((uint*)pBuffer) != 0;
- // Note: Parents will be set dynamically
- // Start by assuming the windows name will be the same as the specific name since windows knows
- // about specifics on all versions. Only for downlevel Neutral locales does this have to change.
- _sWindowsName = realNameBuffer;
- // Neutrals and non-neutrals are slightly different
- if (_bNeutral)
- {
- // Neutral Locale
- // IETF name looks like neutral name
- _sName = realNameBuffer;
- // Specific locale name is whatever ResolveLocaleName (win7+) returns.
- // (Buffer has our name in it, and we can recycle that because windows resolves it before writing to the buffer)
- result = Interop.Kernel32.ResolveLocaleName(realNameBuffer, pBuffer, LOCALE_NAME_MAX_LENGTH);
- // 0 is failure, 1 is invariant (""), which we expect
- if (result < 1)
- {
- return false;
- }
- // We found a locale name, so use it.
- // In vista this should look like a sort name (de-DE_phoneb) or a specific culture (en-US) and be in the "pretty" form
- _sSpecificCulture = new string(pBuffer, 0, result - 1);
- }
- else
- {
- // Specific Locale
- // Specific culture's the same as the locale name since we know its not neutral
- // On mac we'll use this as well, even for neutrals. There's no obvious specific
- // culture to use and this isn't exposed, but behaviorally this is correct on mac.
- // Note that specifics include the sort name (de-DE_phoneb)
- _sSpecificCulture = realNameBuffer;
- _sName = realNameBuffer;
- // We need the IETF name (sname)
- // If we aren't an alt sort locale then this is the same as the windows name.
- // If we are an alt sort locale then this is the same as the part before the _ in the windows name
- // This is for like de-DE_phoneb and es-ES_tradnl that hsouldn't have the _ part
- result = GetLocaleInfoEx(realNameBuffer, LOCALE_ILANGUAGE | LOCALE_RETURN_NUMBER, pBuffer, sizeof(int) / sizeof(char));
- if (result == 0)
- {
- return false;
- }
- _iLanguage = *((int*)pBuffer);
- if (!IsCustomCultureId(_iLanguage))
- {
- // not custom locale
- int index = realNameBuffer.IndexOf('_');
- if (index > 0 && index < realNameBuffer.Length)
- {
- _sName = realNameBuffer.Substring(0, index);
- }
- }
- }
- // It succeeded.
- return true;
- }
- // Wrappers around the GetLocaleInfoEx APIs which handle marshalling the returned
- // data as either and Int or string.
- internal static unsafe string GetLocaleInfoEx(string localeName, uint field)
- {
- // REVIEW: Determine the maximum size for the buffer
- const int BUFFER_SIZE = 530;
- char* pBuffer = stackalloc char[BUFFER_SIZE];
- int resultCode = GetLocaleInfoEx(localeName, field, pBuffer, BUFFER_SIZE);
- if (resultCode > 0)
- {
- return new string(pBuffer);
- }
- return null;
- }
- internal static unsafe int GetLocaleInfoExInt(string localeName, uint field)
- {
- const uint LOCALE_RETURN_NUMBER = 0x20000000;
- field |= LOCALE_RETURN_NUMBER;
- int value = 0;
- GetLocaleInfoEx(localeName, field, (char*) &value, sizeof(int));
- return value;
- }
- internal static unsafe int GetLocaleInfoEx(string lpLocaleName, uint lcType, char* lpLCData, int cchData)
- {
- Debug.Assert(!GlobalizationMode.Invariant);
- return Interop.Kernel32.GetLocaleInfoEx(lpLocaleName, lcType, lpLCData, cchData);
- }
- private string GetLocaleInfo(LocaleStringData type)
- {
- Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfo] Expected _sWindowsName to be populated by already");
- return GetLocaleInfo(_sWindowsName, type);
- }
- // For LOCALE_SPARENT we need the option of using the "real" name (forcing neutral names) instead of the
- // "windows" name, which can be specific for downlevel (< windows 7) os's.
- private string GetLocaleInfo(string localeName, LocaleStringData type)
- {
- uint lctype = (uint)type;
- return GetLocaleInfoFromLCType(localeName, lctype, UseUserOverride);
- }
- private int GetLocaleInfo(LocaleNumberData type)
- {
- uint lctype = (uint)type;
- // Fix lctype if we don't want overrides
- if (!UseUserOverride)
- {
- lctype |= LOCALE_NOUSEROVERRIDE;
- }
- // Ask OS for data, note that we presume it returns success, so we have to know that
- // sWindowsName is valid before calling.
- Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already");
- return GetLocaleInfoExInt(_sWindowsName, lctype);
- }
- private int[] GetLocaleInfo(LocaleGroupingData type)
- {
- return ConvertWin32GroupString(GetLocaleInfoFromLCType(_sWindowsName, (uint)type, UseUserOverride));
- }
- private string GetTimeFormatString()
- {
- const uint LOCALE_STIMEFORMAT = 0x00001003;
- return ReescapeWin32String(GetLocaleInfoFromLCType(_sWindowsName, LOCALE_STIMEFORMAT, UseUserOverride));
- }
- private int GetFirstDayOfWeek()
- {
- Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already");
- const uint LOCALE_IFIRSTDAYOFWEEK = 0x0000100C;
- int result = GetLocaleInfoExInt(_sWindowsName, LOCALE_IFIRSTDAYOFWEEK | (!UseUserOverride ? LOCALE_NOUSEROVERRIDE : 0));
- // Win32 and .NET disagree on the numbering for days of the week, so we have to convert.
- return ConvertFirstDayOfWeekMonToSun(result);
- }
- private string[] GetTimeFormats()
- {
- // Note that this gets overrides for us all the time
- Debug.Assert(_sWindowsName != null, "[CultureData.DoEnumTimeFormats] Expected _sWindowsName to be populated by already");
- string[] result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, 0, UseUserOverride));
- return result;
- }
- private string[] GetShortTimeFormats()
- {
- // Note that this gets overrides for us all the time
- Debug.Assert(_sWindowsName != null, "[CultureData.DoEnumShortTimeFormats] Expected _sWindowsName to be populated by already");
- string[] result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, TIME_NOSECONDS, UseUserOverride));
- return result;
- }
- // Enumerate all system cultures and then try to find out which culture has
- // region name match the requested region name
- private static CultureData GetCultureDataFromRegionName(string regionName)
- {
- Debug.Assert(!GlobalizationMode.Invariant);
- Debug.Assert(regionName != null);
- const uint LOCALE_SUPPLEMENTAL = 0x00000002;
- const uint LOCALE_SPECIFICDATA = 0x00000020;
- EnumLocaleData context = new EnumLocaleData();
- context.cultureName = null;
- context.regionName = regionName;
- unsafe
- {
- Interop.Kernel32.EnumSystemLocalesEx(EnumSystemLocalesProc, LOCALE_SPECIFICDATA | LOCALE_SUPPLEMENTAL, Unsafe.AsPointer(ref context), IntPtr.Zero);
- }
- if (context.cultureName != null)
- {
- // we got a matched culture
- return GetCultureData(context.cultureName, true);
- }
- return null;
- }
- private string GetLanguageDisplayName(string cultureName)
- {
- #if ENABLE_WINRT
- return WinRTInterop.Callbacks.GetLanguageDisplayName(cultureName);
- #else
- // Usually the UI culture shouldn't be different than what we got from WinRT except
- // if DefaultThreadCurrentUICulture was set
- CultureInfo ci;
- if (CultureInfo.DefaultThreadCurrentUICulture != null &&
- ((ci = GetUserDefaultCulture()) != null) &&
- !CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name))
- {
- return SNATIVEDISPLAYNAME;
- }
- else
- {
- return GetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName);
- }
- #endif // ENABLE_WINRT
- }
- private string GetRegionDisplayName(string isoCountryCode)
- {
- #if ENABLE_WINRT
- return WinRTInterop.Callbacks.GetRegionDisplayName(isoCountryCode);
- #else
- // If the current UI culture matching the OS UI language, we'll get the display name from the OS.
- // otherwise, we use the native name as we don't carry resources for the region display names anyway.
- if (CultureInfo.CurrentUICulture.Name.Equals(CultureInfo.UserDefaultUICulture.Name))
- {
- return GetLocaleInfo(LocaleStringData.LocalizedCountryName);
- }
- return SNATIVECOUNTRY;
- #endif // ENABLE_WINRT
- }
- private static CultureInfo GetUserDefaultCulture()
- {
- #if ENABLE_WINRT
- return (CultureInfo)WinRTInterop.Callbacks.GetUserDefaultCulture();
- #else
- return CultureInfo.GetUserDefaultCulture();
- #endif // ENABLE_WINRT
- }
- // PAL methods end here.
- private static string GetLocaleInfoFromLCType(string localeName, uint lctype, bool useUserOveride)
- {
- Debug.Assert(localeName != null, "[CultureData.GetLocaleInfoFromLCType] Expected localeName to be not be null");
- // Fix lctype if we don't want overrides
- if (!useUserOveride)
- {
- lctype |= LOCALE_NOUSEROVERRIDE;
- }
- // Ask OS for data
- string result = GetLocaleInfoEx(localeName, lctype);
- if (result == null)
- {
- // Failed, just use empty string
- result = string.Empty;
- }
- return result;
- }
- ////////////////////////////////////////////////////////////////////////////
- //
- // Reescape a Win32 style quote string as a NLS+ style quoted string
- //
- // This is also the escaping style used by custom culture data files
- //
- // NLS+ uses \ to escape the next character, whether in a quoted string or
- // not, so we always have to change \ to \\.
- //
- // NLS+ uses \' to escape a quote inside a quoted string so we have to change
- // '' to \' (if inside a quoted string)
- //
- // We don't build the stringbuilder unless we find something to change
- ////////////////////////////////////////////////////////////////////////////
- internal static string ReescapeWin32String(string str)
- {
- // If we don't have data, then don't try anything
- if (str == null)
- return null;
- StringBuilder result = null;
- bool inQuote = false;
- for (int i = 0; i < str.Length; i++)
- {
- // Look for quote
- if (str[i] == '\'')
- {
- // Already in quote?
- if (inQuote)
- {
- // See another single quote. Is this '' of 'fred''s' or '''', or is it an ending quote?
- if (i + 1 < str.Length && str[i + 1] == '\'')
- {
- // Found another ', so we have ''. Need to add \' instead.
- // 1st make sure we have our stringbuilder
- if (result == null)
- result = new StringBuilder(str, 0, i, str.Length * 2);
- // Append a \' and keep going (so we don't turn off quote mode)
- result.Append("\\'");
- i++;
- continue;
- }
- // Turning off quote mode, fall through to add it
- inQuote = false;
- }
- else
- {
- // Found beginning quote, fall through to add it
- inQuote = true;
- }
- }
- // Is there a single \ character?
- else if (str[i] == '\\')
- {
- // Found a \, need to change it to \\
- // 1st make sure we have our stringbuilder
- if (result == null)
- result = new StringBuilder(str, 0, i, str.Length * 2);
- // Append our \\ to the string & continue
- result.Append("\\\\");
- continue;
- }
- // If we have a builder we need to add our character
- if (result != null)
- result.Append(str[i]);
- }
- // Unchanged string? , just return input string
- if (result == null)
- return str;
- // String changed, need to use the builder
- return result.ToString();
- }
- internal static string[] ReescapeWin32Strings(string[] array)
- {
- if (array != null)
- {
- for (int i = 0; i < array.Length; i++)
- {
- array[i] = ReescapeWin32String(array[i]);
- }
- }
- return array;
- }
- // If we get a group from windows, then its in 3;0 format with the 0 backwards
- // of how NLS+ uses it (ie: if the string has a 0, then the int[] shouldn't and vice versa)
- // EXCEPT in the case where the list only contains 0 in which NLS and NLS+ have the same meaning.
- private static int[] ConvertWin32GroupString(string win32Str)
- {
- // None of these cases make any sense
- if (win32Str == null || win32Str.Length == 0)
- {
- return (new int[] { 3 });
- }
- if (win32Str[0] == '0')
- {
- return (new int[] { 0 });
- }
- // Since its in n;n;n;n;n format, we can always get the length quickly
- int[] values;
- if (win32Str[win32Str.Length - 1] == '0')
- {
- // Trailing 0 gets dropped. 1;0 -> 1
- values = new int[(win32Str.Length / 2)];
- }
- else
- {
- // Need extra space for trailing zero 1 -> 1;0
- values = new int[(win32Str.Length / 2) + 2];
- values[values.Length - 1] = 0;
- }
- int i;
- int j;
- for (i = 0, j = 0; i < win32Str.Length && j < values.Length; i += 2, j++)
- {
- // Note that this # shouldn't ever be zero, 'cause 0 is only at end
- // But we'll test because its registry that could be anything
- if (win32Str[i] < '1' || win32Str[i] > '9')
- return new int[] { 3 };
- values[j] = (int)(win32Str[i] - '0');
- }
- return (values);
- }
- private static int ConvertFirstDayOfWeekMonToSun(int iTemp)
- {
- // Convert Mon-Sun to Sun-Sat format
- iTemp++;
- if (iTemp > 6)
- {
- // Wrap Sunday and convert invalid data to Sunday
- iTemp = 0;
- }
- return iTemp;
- }
- // Context for EnumCalendarInfoExEx callback.
- private struct EnumLocaleData
- {
- public string regionName;
- public string cultureName;
- }
- // EnumSystemLocaleEx callback.
- // [NativeCallable(CallingConvention = CallingConvention.StdCall)]
- private static unsafe Interop.BOOL EnumSystemLocalesProc(char* lpLocaleString, uint flags, void* contextHandle)
- {
- ref EnumLocaleData context = ref Unsafe.As<byte, EnumLocaleData>(ref *(byte*)contextHandle);
- try
- {
- string cultureName = new string(lpLocaleString);
- string regionName = GetLocaleInfoEx(cultureName, LOCALE_SISO3166CTRYNAME);
- if (regionName != null && regionName.Equals(context.regionName, StringComparison.OrdinalIgnoreCase))
- {
- context.cultureName = cultureName;
- return Interop.BOOL.FALSE; // we found a match, then stop the enumeration
- }
- return Interop.BOOL.TRUE;
- }
- catch (Exception)
- {
- return Interop.BOOL.FALSE;
- }
- }
- // EnumSystemLocaleEx callback.
- // [NativeCallable(CallingConvention = CallingConvention.StdCall)]
- private static unsafe Interop.BOOL EnumAllSystemLocalesProc(char* lpLocaleString, uint flags, void* contextHandle)
- {
- ref EnumData context = ref Unsafe.As<byte, EnumData>(ref *(byte*)contextHandle);
- try
- {
- context.strings.Add(new string(lpLocaleString));
- return Interop.BOOL.TRUE;
- }
- catch (Exception)
- {
- return Interop.BOOL.FALSE;
- }
- }
- // Context for EnumTimeFormatsEx callback.
- private struct EnumData
- {
- public List<string> strings;
- }
- // EnumTimeFormatsEx callback itself.
- // [NativeCallable(CallingConvention = CallingConvention.StdCall)]
- private static unsafe Interop.BOOL EnumTimeCallback(char* lpTimeFormatString, void* lParam)
- {
- ref EnumData context = ref Unsafe.As<byte, EnumData>(ref *(byte*)lParam);
- try
- {
- context.strings.Add(new string(lpTimeFormatString));
- return Interop.BOOL.TRUE;
- }
- catch (Exception)
- {
- return Interop.BOOL.FALSE;
- }
- }
- private static unsafe string[] nativeEnumTimeFormats(string localeName, uint dwFlags, bool useUserOverride)
- {
- const uint LOCALE_SSHORTTIME = 0x00000079;
- const uint LOCALE_STIMEFORMAT = 0x00001003;
- EnumData data = new EnumData();
- data.strings = new List<string>();
- // Now call the enumeration API. Work is done by our callback function
- Interop.Kernel32.EnumTimeFormatsEx(EnumTimeCallback, localeName, (uint)dwFlags, Unsafe.AsPointer(ref data));
- if (data.strings.Count > 0)
- {
- // Now we need to allocate our stringarray and populate it
- string[] results = data.strings.ToArray();
- if (!useUserOverride && data.strings.Count > 1)
- {
- // Since there is no "NoUserOverride" aware EnumTimeFormatsEx, we always get an override
- // The override is the first entry if it is overriden.
- // We can check if we have overrides by checking the GetLocaleInfo with no override
- // If we do have an override, we don't know if it is a user defined override or if the
- // user has just selected one of the predefined formats so we can't just remove it
- // but we can move it down.
- uint lcType = (dwFlags == TIME_NOSECONDS) ? LOCALE_SSHORTTIME : LOCALE_STIMEFORMAT;
- string timeFormatNoUserOverride = GetLocaleInfoFromLCType(localeName, lcType, useUserOverride);
- if (timeFormatNoUserOverride != "")
- {
- string firstTimeFormat = results[0];
- if (timeFormatNoUserOverride != firstTimeFormat)
- {
- results[0] = results[1];
- results[1] = firstTimeFormat;
- }
- }
- }
- return results;
- }
- return null;
- }
- private static int LocaleNameToLCID(string cultureName)
- {
- Debug.Assert(!GlobalizationMode.Invariant);
- return Interop.Kernel32.LocaleNameToLCID(cultureName, Interop.Kernel32.LOCALE_ALLOW_NEUTRAL_NAMES);
- }
- private static unsafe string LCIDToLocaleName(int culture)
- {
- Debug.Assert(!GlobalizationMode.Invariant);
- char *pBuffer = stackalloc char[Interop.Kernel32.LOCALE_NAME_MAX_LENGTH + 1]; // +1 for the null termination
- int length = Interop.Kernel32.LCIDToLocaleName(culture, pBuffer, Interop.Kernel32.LOCALE_NAME_MAX_LENGTH + 1, Interop.Kernel32.LOCALE_ALLOW_NEUTRAL_NAMES);
- if (length > 0)
- {
- return new string(pBuffer);
- }
- return null;
- }
- private int GetAnsiCodePage(string cultureName)
- {
- return GetLocaleInfo(LocaleNumberData.AnsiCodePage);
- }
- private int GetOemCodePage(string cultureName)
- {
- return GetLocaleInfo(LocaleNumberData.OemCodePage);
- }
- private int GetMacCodePage(string cultureName)
- {
- return GetLocaleInfo(LocaleNumberData.MacCodePage);
- }
- private int GetEbcdicCodePage(string cultureName)
- {
- return GetLocaleInfo(LocaleNumberData.EbcdicCodePage);
- }
- private int GetGeoId(string cultureName)
- {
- return GetLocaleInfo(LocaleNumberData.GeoId);
- }
- private int GetDigitSubstitution(string cultureName)
- {
- return GetLocaleInfo(LocaleNumberData.DigitSubstitution);
- }
- private string GetThreeLetterWindowsLanguageName(string cultureName)
- {
- return GetLocaleInfo(cultureName, LocaleStringData.AbbreviatedWindowsLanguageName);
- }
- private static CultureInfo[] EnumCultures(CultureTypes types)
- {
- Debug.Assert(!GlobalizationMode.Invariant);
- uint flags = 0;
- #pragma warning disable 618
- if ((types & (CultureTypes.FrameworkCultures | CultureTypes.InstalledWin32Cultures | CultureTypes.ReplacementCultures)) != 0)
- {
- flags |= Interop.Kernel32.LOCALE_NEUTRALDATA | Interop.Kernel32.LOCALE_SPECIFICDATA;
- }
- #pragma warning restore 618
- if ((types & CultureTypes.NeutralCultures) != 0)
- {
- flags |= Interop.Kernel32.LOCALE_NEUTRALDATA;
- }
- if ((types & CultureTypes.SpecificCultures) != 0)
- {
- flags |= Interop.Kernel32.LOCALE_SPECIFICDATA;
- }
- if ((types & CultureTypes.UserCustomCulture) != 0)
- {
- flags |= Interop.Kernel32.LOCALE_SUPPLEMENTAL;
- }
- if ((types & CultureTypes.ReplacementCultures) != 0)
- {
- flags |= Interop.Kernel32.LOCALE_SUPPLEMENTAL;
- }
- EnumData context = new EnumData();
- context.strings = new List<string>();
- unsafe
- {
- Interop.Kernel32.EnumSystemLocalesEx(EnumAllSystemLocalesProc, flags, Unsafe.AsPointer(ref context), IntPtr.Zero);
- }
- CultureInfo [] cultures = new CultureInfo[context.strings.Count];
- for (int i = 0; i < cultures.Length; i++)
- {
- cultures[i] = new CultureInfo(context.strings[i]);
- }
- return cultures;
- }
- private string GetConsoleFallbackName(string cultureName)
- {
- return GetLocaleInfo(cultureName, LocaleStringData.ConsoleFallbackName);
- }
- internal bool IsFramework
- {
- get { return false; }
- }
- internal bool IsWin32Installed
- {
- get { return true; }
- }
- internal bool IsReplacementCulture
- {
- get
- {
- EnumData context = new EnumData();
- context.strings = new List<string>();
- unsafe
- {
- Interop.Kernel32.EnumSystemLocalesEx(EnumAllSystemLocalesProc, Interop.Kernel32.LOCALE_REPLACEMENT, Unsafe.AsPointer(ref context), IntPtr.Zero);
- }
- for (int i=0; i<context.strings.Count; i++)
- {
- if (string.Compare(context.strings[i], _sWindowsName, StringComparison.OrdinalIgnoreCase) == 0)
- return true;
- }
- return false;
- }
- }
- }
- }
|