| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431 |
- // 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;
- using System.Collections.Generic;
- using System.Diagnostics;
- using System.Runtime.InteropServices;
- using System.Security;
- using System.Text;
- namespace System.Globalization
- {
- internal partial class CultureData
- {
- // ICU constants
- const int ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY = 100; // max size of keyword or value
- const int ICU_ULOC_FULLNAME_CAPACITY = 157; // max size of locale name
- const string ICU_COLLATION_KEYWORD = "@collation=";
-
-
- /// <summary>
- /// This method uses the sRealName field (which is initialized by the constructor before this is called) to
- /// initialize the rest of the state of CultureData based on the underlying OS globalization library.
- /// </summary>
- private unsafe bool InitCultureData()
- {
- Debug.Assert(_sRealName != null);
- Debug.Assert(!GlobalizationMode.Invariant);
- string realNameBuffer = _sRealName;
- // Basic validation
- if (realNameBuffer.Contains('@'))
- {
- return false; // don't allow ICU variants to come in directly
- }
- // Replace _ (alternate sort) with @collation= for ICU
- ReadOnlySpan<char> alternateSortName = default;
- int index = realNameBuffer.IndexOf('_');
- if (index > 0)
- {
- if (index >= (realNameBuffer.Length - 1) // must have characters after _
- || realNameBuffer.IndexOf('_', index + 1) >= 0) // only one _ allowed
- {
- return false; // fail
- }
- alternateSortName = realNameBuffer.AsSpan(index + 1);
- realNameBuffer = string.Concat(realNameBuffer.AsSpan(0, index), ICU_COLLATION_KEYWORD, alternateSortName);
- }
- // Get the locale name from ICU
- if (!GetLocaleName(realNameBuffer, out _sWindowsName))
- {
- return false; // fail
- }
- // Replace the ICU collation keyword with an _
- index = _sWindowsName.IndexOf(ICU_COLLATION_KEYWORD, StringComparison.Ordinal);
- if (index >= 0)
- {
- _sName = string.Concat(_sWindowsName.AsSpan(0, index), "_", alternateSortName);
- }
- else
- {
- _sName = _sWindowsName;
- }
- _sRealName = _sName;
- _iLanguage = this.ILANGUAGE;
- if (_iLanguage == 0)
- {
- _iLanguage = CultureInfo.LOCALE_CUSTOM_UNSPECIFIED;
- }
- _bNeutral = (this.SISO3166CTRYNAME.Length == 0);
-
- _sSpecificCulture = _bNeutral ? LocaleData.GetSpecificCultureName(_sRealName) : _sRealName;
-
- // Remove the sort from sName unless custom culture
- if (index>0 && !_bNeutral && !IsCustomCultureId(_iLanguage))
- {
- _sName = _sWindowsName.Substring(0, index);
- }
- return true;
- }
- internal static unsafe bool GetLocaleName(string localeName, out string windowsName)
- {
- // Get the locale name from ICU
- char* buffer = stackalloc char[ICU_ULOC_FULLNAME_CAPACITY];
- if (!Interop.Globalization.GetLocaleName(localeName, buffer, ICU_ULOC_FULLNAME_CAPACITY))
- {
- windowsName = null;
- return false; // fail
- }
- // Success - use the locale name returned which may be different than realNameBuffer (casing)
- windowsName = new string(buffer); // the name passed to subsequent ICU calls
- return true;
- }
- internal static unsafe bool GetDefaultLocaleName(out string windowsName)
- {
- // Get the default (system) locale name from ICU
- char* buffer = stackalloc char[ICU_ULOC_FULLNAME_CAPACITY];
- if (!Interop.Globalization.GetDefaultLocaleName(buffer, ICU_ULOC_FULLNAME_CAPACITY))
- {
- windowsName = null;
- return false; // fail
- }
- // Success - use the locale name returned which may be different than realNameBuffer (casing)
- windowsName = new string(buffer); // the name passed to subsequent ICU calls
- return true;
- }
-
- private string GetLocaleInfo(LocaleStringData type)
- {
- Debug.Assert(!GlobalizationMode.Invariant);
-
- Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo] Expected _sWindowsName to be populated 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 unsafe string GetLocaleInfo(string localeName, LocaleStringData type)
- {
- Debug.Assert(localeName != null, "[CultureData.GetLocaleInfo] Expected localeName to be not be null");
- switch (type)
- {
- case LocaleStringData.NegativeInfinitySymbol:
- // not an equivalent in ICU; prefix the PositiveInfinitySymbol with NegativeSign
- return GetLocaleInfo(localeName, LocaleStringData.NegativeSign) +
- GetLocaleInfo(localeName, LocaleStringData.PositiveInfinitySymbol);
- }
- char* buffer = stackalloc char[ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY];
- bool result = Interop.Globalization.GetLocaleInfoString(localeName, (uint)type, buffer, ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY);
- if (!result)
- {
- // Failed, just use empty string
- Debug.Fail("[CultureData.GetLocaleInfo(LocaleStringData)] Failed");
- return string.Empty;
- }
- return new string(buffer);
- }
- private int GetLocaleInfo(LocaleNumberData type)
- {
- Debug.Assert(!GlobalizationMode.Invariant);
- Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo(LocaleNumberData)] Expected _sWindowsName to be populated already");
- switch (type)
- {
- case LocaleNumberData.CalendarType:
- // returning 0 will cause the first supported calendar to be returned, which is the preferred calendar
- return 0;
- }
-
- int value = 0;
- bool result = Interop.Globalization.GetLocaleInfoInt(_sWindowsName, (uint)type, ref value);
- if (!result)
- {
- // Failed, just use 0
- Debug.Fail("[CultureData.GetLocaleInfo(LocaleNumberData)] failed");
- }
- return value;
- }
- private int[] GetLocaleInfo(LocaleGroupingData type)
- {
- Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo(LocaleGroupingData)] Expected _sWindowsName to be populated already");
- int primaryGroupingSize = 0;
- int secondaryGroupingSize = 0;
- bool result = Interop.Globalization.GetLocaleInfoGroupingSizes(_sWindowsName, (uint)type, ref primaryGroupingSize, ref secondaryGroupingSize);
- if (!result)
- {
- Debug.Fail("[CultureData.GetLocaleInfo(LocaleGroupingData type)] failed");
- }
- if (secondaryGroupingSize == 0)
- {
- return new int[] { primaryGroupingSize };
- }
- return new int[] { primaryGroupingSize, secondaryGroupingSize };
- }
- private string GetTimeFormatString()
- {
- return GetTimeFormatString(false);
- }
- private unsafe string GetTimeFormatString(bool shortFormat)
- {
- Debug.Assert(_sWindowsName != null, "[CultureData.GetTimeFormatString(bool shortFormat)] Expected _sWindowsName to be populated already");
- char* buffer = stackalloc char[ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY];
- bool result = Interop.Globalization.GetLocaleTimeFormat(_sWindowsName, shortFormat, buffer, ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY);
- if (!result)
- {
- // Failed, just use empty string
- Debug.Fail("[CultureData.GetTimeFormatString(bool shortFormat)] Failed");
- return string.Empty;
- }
- var span = new ReadOnlySpan<char>(buffer, ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY);
- return ConvertIcuTimeFormatString(span.Slice(0, span.IndexOf('\0')));
- }
- private int GetFirstDayOfWeek()
- {
- return this.GetLocaleInfo(LocaleNumberData.FirstDayOfWeek);
- }
- private string[] GetTimeFormats()
- {
- string format = GetTimeFormatString(false);
- return new string[] { format };
- }
- private string[] GetShortTimeFormats()
- {
- string format = GetTimeFormatString(true);
- return new string[] { format };
- }
- private static CultureData GetCultureDataFromRegionName(string regionName)
- {
- // no support to lookup by region name, other than the hard-coded list in CultureData
- return null;
- }
- private static string GetLanguageDisplayName(string cultureName)
- {
- return new CultureInfo(cultureName)._cultureData.GetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName);
- }
- private static string GetRegionDisplayName(string isoCountryCode)
- {
- // use the fallback which is to return NativeName
- return null;
- }
- private static CultureInfo GetUserDefaultCulture()
- {
- return CultureInfo.GetUserDefaultCulture();
- }
- private static string ConvertIcuTimeFormatString(ReadOnlySpan<char> icuFormatString)
- {
- Debug.Assert(icuFormatString.Length < ICU_ULOC_FULLNAME_CAPACITY);
- Span<char> result = stackalloc char[ICU_ULOC_FULLNAME_CAPACITY];
- bool amPmAdded = false;
- int resultPos = 0;
- for (int i = 0; i < icuFormatString.Length; i++)
- {
- switch (icuFormatString[i])
- {
- case ':':
- case '.':
- case 'H':
- case 'h':
- case 'm':
- case 's':
- result[resultPos++] = icuFormatString[i];
- break;
- case ' ':
- case '\u00A0':
- // Convert nonbreaking spaces into regular spaces
- result[resultPos++] = ' ';
- break;
- case 'a': // AM/PM
- if (!amPmAdded)
- {
- amPmAdded = true;
- result[resultPos++] = 't';
- result[resultPos++] = 't';
- }
- break;
- }
- }
- return result.Slice(0, resultPos).ToString();
- }
-
- private static string LCIDToLocaleName(int culture)
- {
- Debug.Assert(!GlobalizationMode.Invariant);
- return LocaleData.LCIDToLocaleName(culture);
- }
- private static int LocaleNameToLCID(string cultureName)
- {
- Debug.Assert(!GlobalizationMode.Invariant);
-
- int lcid = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.Lcid);
- return lcid == -1 ? CultureInfo.LOCALE_CUSTOM_UNSPECIFIED : lcid;
- }
-
- private static int GetAnsiCodePage(string cultureName)
- {
- int ansiCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.AnsiCodePage);
- return ansiCodePage == -1 ? CultureData.Invariant.IDEFAULTANSICODEPAGE : ansiCodePage;
- }
- private static int GetOemCodePage(string cultureName)
- {
- int oemCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.OemCodePage);
- return oemCodePage == -1 ? CultureData.Invariant.IDEFAULTOEMCODEPAGE : oemCodePage;
- }
- private static int GetMacCodePage(string cultureName)
- {
- int macCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.MacCodePage);
- return macCodePage == -1 ? CultureData.Invariant.IDEFAULTMACCODEPAGE : macCodePage;
- }
- private static int GetEbcdicCodePage(string cultureName)
- {
- int ebcdicCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.EbcdicCodePage);
- return ebcdicCodePage == -1 ? CultureData.Invariant.IDEFAULTEBCDICCODEPAGE : ebcdicCodePage;
- }
- private static int GetGeoId(string cultureName)
- {
- int geoId = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.GeoId);
- return geoId == -1 ? CultureData.Invariant.IGEOID : geoId;
- }
-
- private static int GetDigitSubstitution(string cultureName)
- {
- int digitSubstitution = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.DigitSubstitution);
- return digitSubstitution == -1 ? (int) DigitShapes.None : digitSubstitution;
- }
- private static string GetThreeLetterWindowsLanguageName(string cultureName)
- {
- string langName = LocaleData.GetThreeLetterWindowsLanguageName(cultureName);
- return langName == null ? "ZZZ" /* default lang name */ : langName;
- }
- private static CultureInfo[] EnumCultures(CultureTypes types)
- {
- Debug.Assert(!GlobalizationMode.Invariant);
-
- if ((types & (CultureTypes.NeutralCultures | CultureTypes.SpecificCultures)) == 0)
- {
- return Array.Empty<CultureInfo>();
- }
-
- int bufferLength = Interop.Globalization.GetLocales(null, 0);
- if (bufferLength <= 0)
- {
- return Array.Empty<CultureInfo>();
- }
-
- char [] chars = new char[bufferLength];
-
- bufferLength = Interop.Globalization.GetLocales(chars, bufferLength);
- if (bufferLength <= 0)
- {
- return Array.Empty<CultureInfo>();
- }
-
- bool enumNeutrals = (types & CultureTypes.NeutralCultures) != 0;
- bool enumSpecificss = (types & CultureTypes.SpecificCultures) != 0;
-
- List<CultureInfo> list = new List<CultureInfo>();
- if (enumNeutrals)
- {
- list.Add(CultureInfo.InvariantCulture);
- }
-
- int index = 0;
- while (index < bufferLength)
- {
- int length = (int) chars[index++];
- if (index + length <= bufferLength)
- {
- CultureInfo ci = CultureInfo.GetCultureInfo(new string(chars, index, length));
- if ((enumNeutrals && ci.IsNeutralCulture) || (enumSpecificss && !ci.IsNeutralCulture))
- {
- list.Add(ci);
- }
- }
-
- index += length;
- }
-
- return list.ToArray();
- }
-
- private static string GetConsoleFallbackName(string cultureName)
- {
- return LocaleData.GetConsoleUICulture(cultureName);
- }
-
- internal bool IsFramework // not applicable on Linux based systems
- {
- get { return false; }
- }
-
- internal bool IsWin32Installed // not applicable on Linux based systems
- {
- get { return false; }
- }
-
- internal bool IsReplacementCulture // not applicable on Linux based systems
- {
- get { return false; }
- }
- }
- }
|