Skip to content

Commit

Permalink
Fix CultureInfo creation with special Windows LCID values (dotnet#37834)
Browse files Browse the repository at this point in the history
* Fix CultureInfo creation with special Windows LCID values

* Restrict the test to Windows 10.
  • Loading branch information
tarekgh authored Jun 15, 2020
1 parent 7b13fb8 commit 02df47b
Show file tree
Hide file tree
Showing 6 changed files with 45 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,28 @@ public void Ctor_String_Invalid()
Assert.Throws<CultureNotFoundException>(() => new CultureInfo("xx-XX"));
}
}

[ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows10Version1903OrGreater))]
[InlineData(0x2000)]
[InlineData(0x2400)]
[InlineData(0x2800)]
[InlineData(0x2C00)]
[InlineData(0x3000)]
[InlineData(0x3400)]
[InlineData(0x3800)]
[InlineData(0x3C00)]
[InlineData(0x4000)]
[InlineData(0x4400)]
[InlineData(0x4800)]
[InlineData(0x4C00)]
public void TestCreationWithTemporaryLCID(int lcid)
{
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/926e694f-1797-4418-a922-343d1c5e91a6
// If a temporary LCID is assigned it will be dynamically assigned at runtime to be
// 0x2000, 0x2400, 0x2800, 0x2C00, 0x3000, 0x3400, 0x3800, 0x3C00, 0x4000, 0x4400, 0x4800, or 0x4C00,
// for the valid language-script-region tags.

Assert.NotEqual(lcid, new CultureInfo(lcid).LCID);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -234,14 +234,6 @@ private static string ConvertIcuTimeFormatString(ReadOnlySpan<char> icuFormatStr
return result.Slice(0, resultPos).ToString();
}

private static string? IcuLCIDToLocaleName(int culture)
{
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert(!GlobalizationMode.UseNls);

return IcuLocaleData.LCIDToLocaleName(culture);
}

private static int IcuLocaleNameToLCID(string cultureName)
{
Debug.Assert(!GlobalizationMode.Invariant);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -466,22 +466,6 @@ private static int NlsLocaleNameToLCID(string cultureName)
return Interop.Kernel32.LocaleNameToLCID(cultureName, Interop.Kernel32.LOCALE_ALLOW_NEUTRAL_NAMES);
}

private static unsafe string? NlsLCIDToLocaleName(int culture)
{
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert(GlobalizationMode.UseNls);

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 NlsGetAnsiCodePage(string cultureName)
{
Debug.Assert(GlobalizationMode.UseNls);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ private bool InitCultureDataCore()
return true;
}

private static string? LCIDToLocaleName(int culture)
{
Debug.Assert(!GlobalizationMode.Invariant);
return IcuLocaleData.LCIDToLocaleName(culture);
}

internal bool IsWin32Installed => false;

internal static unsafe CultureData GetCurrentRegionData() => CultureInfo.CurrentCulture._cultureData;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,5 +172,20 @@ internal static unsafe CultureData GetCurrentRegionData()
// Fallback to current locale data.
return CultureInfo.CurrentCulture._cultureData;
}

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;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -867,8 +867,7 @@ internal static CultureData GetCultureData(int culture, bool bUseUserOverride)
}

// Convert the lcid to a name, then use that
// Note that this will return neutral names (unlike Vista native API)
localeName = GlobalizationMode.UseNls ? NlsLCIDToLocaleName(culture) : IcuLCIDToLocaleName(culture);
localeName = LCIDToLocaleName(culture);

if (!string.IsNullOrEmpty(localeName))
{
Expand Down

0 comments on commit 02df47b

Please sign in to comment.