Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 39 additions & 5 deletions src/corefx/System.Globalization.Native/locale.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,9 @@ Locale GetLocale(const UChar* localeName, bool canonize)

if (localeName != NULL)
{
int32_t len = u_strlen(localeName);
u_UCharsToChars(localeName, localeNameTemp, len + 1);
// use UnicodeString.extract instead of u_UCharsToChars; u_UCharsToChars considers '@' a variant and stops
UnicodeString str(localeName, -1, ULOC_FULLNAME_CAPACITY);
str.extract(0, str.length(), localeNameTemp);
}

Locale loc;
Expand All @@ -64,9 +65,10 @@ UErrorCode u_charsToUChars_safe(const char *str, UChar* value, int32_t valueLeng
return U_ZERO_ERROR;
}

void FixupLocaleName(UChar* value, int32_t valueLength)
int FixupLocaleName(UChar* value, int32_t valueLength)
{
for (int i = 0; i < valueLength; i++)
int i = 0;
for (; i < valueLength; i++)
{
if (value[i] == (UChar)'\0')
{
Expand All @@ -77,8 +79,9 @@ void FixupLocaleName(UChar* value, int32_t valueLength)
value[i] = (UChar)'-';
}
}
}

return i;
}

extern "C" int32_t GetLocaleName(const UChar* localeName, UChar* value, int32_t valueLength)
{
Expand All @@ -100,3 +103,34 @@ extern "C" int32_t GetLocaleName(const UChar* localeName, UChar* value, int32_t

return UErrorCodeToBool(status);
}

extern "C" int32_t GetDefaultLocaleName(UChar* value, int32_t valueLength)
{
Locale locale = GetLocale(NULL);
if (locale.isBogus())
{
// ICU should be able to get default locale
return UErrorCodeToBool(U_INTERNAL_PROGRAM_ERROR);
}

UErrorCode status = u_charsToUChars_safe(locale.getBaseName(), value, valueLength);
if (U_SUCCESS(status))
{
int localeNameLen = FixupLocaleName(value, valueLength);

// if collation is present, return that to managed side
char collationValueTemp[ULOC_KEYWORDS_CAPACITY];
if (locale.getKeywordValue("collation", collationValueTemp, ULOC_KEYWORDS_CAPACITY, status) > 0)
{
// copy the collation; managed uses a "_" to represent collation (not "@collation=")
status = u_charsToUChars_safe("_", &value[localeNameLen], valueLength - localeNameLen);
if (U_SUCCESS(status))
{
status = u_charsToUChars_safe(collationValueTemp, &value[localeNameLen + 1], valueLength - localeNameLen - 1);
}
}
}

return UErrorCodeToBool(status);
}

5 changes: 3 additions & 2 deletions src/corefx/System.Globalization.Native/locale.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ UErrorCode u_charsToUChars_safe(const char *str, UChar* value, int32_t valueLeng
Function:
FixupLocaleName

Replace underscores with hyphens to interop with existing .NET code
Replace underscores with hyphens to interop with existing .NET code.
Returns the length of the string.
*/
void FixupLocaleName(UChar* value, int32_t valueLength);
int FixupLocaleName(UChar* value, int32_t valueLength);
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ internal static partial class GlobalizationInterop
[return: MarshalAs(UnmanagedType.Bool)]
internal unsafe static extern bool GetLocaleInfoString(string localeName, uint localeStringData, [Out] StringBuilder value, int valueLength);

[DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
internal unsafe static extern bool GetDefaultLocaleName([Out] StringBuilder value, int valueLength);

[DllImport(Libraries.GlobalizationInterop, CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
internal unsafe static extern bool GetLocaleTimeFormat(string localeName, bool shortFormat, [Out] StringBuilder value, int valueLength);
Expand Down
92 changes: 50 additions & 42 deletions src/mscorlib/corefx/System/Globalization/CultureData.Unix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ namespace System.Globalization
{
internal partial class CultureData
{
// Win32 constants
const string LOCALE_NAME_SYSTEM_DEFAULT = @"!x-sys-default-locale";

// 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
Expand All @@ -30,47 +27,35 @@ private unsafe bool InitCultureData()
Contract.Assert(this.sRealName != null);

string alternateSortName = string.Empty;
string realNameBuffer = null;
int index;
string realNameBuffer = this.sRealName;

bool useSystemDefault = (this.sRealName == LOCALE_NAME_SYSTEM_DEFAULT);
if (!useSystemDefault) //ICU uses null to obtain the default (system) locale
// Basic validation
if (realNameBuffer.Contains("@"))
{
realNameBuffer = this.sRealName;

// Basic validation
if (realNameBuffer.Contains("@"))
{
return false; // don't allow ICU variants to come in directly
}
return false; // don't allow ICU variants to come in directly
}

// Replace _ (alternate sort) with @collation= for ICU
index = realNameBuffer.IndexOf('_');
if (index > 0)
// Replace _ (alternate sort) with @collation= for ICU
int index = realNameBuffer.IndexOf('_');
if (index > 0)
{
if (index >= (realNameBuffer.Length - 1) // must have characters after _
|| realNameBuffer.Substring(index + 1).Contains("_")) // only one _ allowed
{
if (index >= (realNameBuffer.Length - 1) // must have characters after _
|| realNameBuffer.Substring(index + 1).Contains("_")) // only one _ allowed
{
return false; // fail
}
alternateSortName = realNameBuffer.Substring(index + 1);
realNameBuffer = realNameBuffer.Substring(0, index) + ICU_COLLATION_KEYWORD + alternateSortName;
return false; // fail
}
alternateSortName = realNameBuffer.Substring(index + 1);
realNameBuffer = realNameBuffer.Substring(0, index) + ICU_COLLATION_KEYWORD + alternateSortName;
}

// Get the locale name from ICU
StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY);
if (!Interop.GlobalizationInterop.GetLocaleName(realNameBuffer, sb, sb.Capacity))
if (!GetLocaleName(realNameBuffer, out this.sWindowsName))
{
StringBuilderCache.Release(sb);
return false; // fail
}

// Success - use the locale name returned which may be different than realNameBuffer (casing)
this.sWindowsName = StringBuilderCache.GetStringAndRelease(sb); // the name passed to subsequent ICU calls

// Replace the ICU collation keyword with an _
index = realNameBuffer.IndexOf(ICU_COLLATION_KEYWORD, StringComparison.Ordinal);
index = this.sWindowsName.IndexOf(ICU_COLLATION_KEYWORD, StringComparison.Ordinal);
if (index >= 0)
{
this.sName = this.sWindowsName.Substring(0, index) + "_" + alternateSortName;
Expand All @@ -79,21 +64,13 @@ private unsafe bool InitCultureData()
{
this.sName = this.sWindowsName;
}

this.sRealName = this.sName;
this.sSpecificCulture = this.sRealName; // we don't attempt to find a non-neutral locale if a neutral is passed in (unlike win32)

this.iLanguage = this.ILANGUAGE;
if (this.iLanguage == 0)
{
if (useSystemDefault)
{
this.iLanguage = LOCALE_CUSTOM_DEFAULT;
}
else
{
this.iLanguage = LOCALE_CUSTOM_UNSPECIFIED;
}
this.iLanguage = LOCALE_CUSTOM_UNSPECIFIED;
}

this.bNeutral = (this.SISO3166CTRYNAME.Length == 0);
Expand All @@ -106,10 +83,41 @@ private unsafe bool InitCultureData()
this.sName = this.sWindowsName.Substring(0, index);
}
}
return true;
}

internal static bool GetLocaleName(string localeName, out string windowsName)
{
// Get the locale name from ICU
StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY);
if (!Interop.GlobalizationInterop.GetLocaleName(localeName, sb, sb.Capacity))
{
StringBuilderCache.Release(sb);
windowsName = null;
return false; // fail
}

// Success - use the locale name returned which may be different than realNameBuffer (casing)
windowsName = StringBuilderCache.GetStringAndRelease(sb); // the name passed to subsequent ICU calls
return true;
}

internal static bool GetDefaultLocaleName(out string windowsName)
{
// Get the default (system) locale name from ICU
StringBuilder sb = StringBuilderCache.Acquire(ICU_ULOC_FULLNAME_CAPACITY);
if (!Interop.GlobalizationInterop.GetDefaultLocaleName(sb, sb.Capacity))
{
StringBuilderCache.Release(sb);
windowsName = null;
return false; // fail
}

// Success - use the locale name returned which may be different than realNameBuffer (casing)
windowsName = StringBuilderCache.GetStringAndRelease(sb); // the name passed to subsequent ICU calls
return true;
}

private string GetLocaleInfo(LocaleStringData type)
{
Contract.Assert(this.sWindowsName != null, "[CultureData.GetLocaleInfo] Expected this.sWindowsName to be populated already");
Expand Down Expand Up @@ -244,7 +252,7 @@ private static string GetRegionDisplayName(string isoCountryCode)

private static CultureInfo GetUserDefaultCulture()
{
return new CultureInfo(LOCALE_NAME_SYSTEM_DEFAULT);
return CultureInfo.GetUserDefaultCulture();
}
}
}
8 changes: 4 additions & 4 deletions src/mscorlib/corefx/System/Globalization/CultureData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1679,8 +1679,8 @@ private int IREADINGLAYOUT
{
// Note: Custom cultures might point at another culture's textinfo, however windows knows how
// to redirect it to the desired textinfo culture, so this is OK.
Contract.Assert(this.sWindowsName != null, "[CultureData.STEXTINFO] Expected this.sWindowsName to be populated by already");
return (this.sWindowsName);
Contract.Assert(this.sRealName != null, "[CultureData.STEXTINFO] Expected this.sRealName to be populated by already");
return (this.sRealName);
}
}

Expand All @@ -1689,8 +1689,8 @@ internal String SCOMPAREINFO
{
get
{
Contract.Assert(this.sWindowsName != null, "[CultureData.SCOMPAREINFO] Expected this.sWindowsName to be populated by already");
return (this.sWindowsName);
Contract.Assert(this.sRealName != null, "[CultureData.SCOMPAREINFO] Expected this.sRealName to be populated by already");
return (this.sRealName);
}
}

Expand Down
28 changes: 16 additions & 12 deletions src/mscorlib/corefx/System/Globalization/CultureInfo.Unix.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,26 @@ namespace System.Globalization
{
public partial class CultureInfo : IFormatProvider
{
/// <summary>
/// Gets the default user culture from WinRT, if available.
/// </summary>
/// <remarks>
/// This method may return null, if there is no default user culture or if WinRT isn't available.
/// </remarks>
private static CultureInfo GetUserDefaultCultureCacheOverride()
{
// TODO: Implement this fully.
return null;
return null; // ICU doesn't provide a user override
}

private static CultureInfo GetUserDefaultCulture()
internal static CultureInfo GetUserDefaultCulture()
{
// TODO: Implement this fully.
return CultureInfo.InvariantCulture;
CultureInfo cultureInfo = null;
string localeName;
if (CultureData.GetDefaultLocaleName(out localeName))
{
cultureInfo = GetCultureByName(localeName, true);
cultureInfo.m_isReadOnly = true;
}
else
{
cultureInfo = CultureInfo.InvariantCulture;
}

return cultureInfo;
}
}
}
}