user32.dll!GetProcessWindowStation
user32.dll!GetUserObjectInformationW
-<!-- GetGeoInfo is supported by the analyzer complain for nit using GetGeoInfoW instead and we need to keep the style of not using 'W' in the names -->
-kernel32.dll!GetGeoInfo
\ No newline at end of file
+<!-- GetGeoInfo is supported by the analyzer complain for not using GetGeoInfoW instead and we need to keep the style of not using 'W' in the names -->
+kernel32.dll!GetGeoInfo
+
+<!-- PInvokes to System.Globalization.Native shim -->
+libSystem.Globalization.Native!GlobalizationNative_ChangeCase
+libSystem.Globalization.Native!GlobalizationNative_ChangeCaseInvariant
+libSystem.Globalization.Native!GlobalizationNative_ChangeCaseTurkish
+libSystem.Globalization.Native!GlobalizationNative_CloseSortHandle
+libSystem.Globalization.Native!GlobalizationNative_CompareString
+libSystem.Globalization.Native!GlobalizationNative_CompareStringOrdinalIgnoreCase
+libSystem.Globalization.Native!GlobalizationNative_EndsWith
+libSystem.Globalization.Native!GlobalizationNative_EnumCalendarInfo
+libSystem.Globalization.Native!GlobalizationNative_GetCalendarInfo
+libSystem.Globalization.Native!GlobalizationNative_GetCalendars
+libSystem.Globalization.Native!GlobalizationNative_GetDefaultLocaleName
+libSystem.Globalization.Native!GlobalizationNative_GetICUVersion
+libSystem.Globalization.Native!GlobalizationNative_GetJapaneseEraStartDate
+libSystem.Globalization.Native!GlobalizationNative_GetLatestJapaneseEra
+libSystem.Globalization.Native!GlobalizationNative_GetLocaleInfoGroupingSizes
+libSystem.Globalization.Native!GlobalizationNative_GetLocaleInfoInt
+libSystem.Globalization.Native!GlobalizationNative_GetLocaleInfoString
+libSystem.Globalization.Native!GlobalizationNative_GetLocaleName
+libSystem.Globalization.Native!GlobalizationNative_GetLocales
+libSystem.Globalization.Native!GlobalizationNative_GetLocaleTimeFormat
+libSystem.Globalization.Native!GlobalizationNative_GetSortHandle
+libSystem.Globalization.Native!GlobalizationNative_GetSortKey
+libSystem.Globalization.Native!GlobalizationNative_GetSortVersion
+libSystem.Globalization.Native!GlobalizationNative_GetTimeZoneDisplayName
+libSystem.Globalization.Native!GlobalizationNative_IndexOf
+libSystem.Globalization.Native!GlobalizationNative_IndexOfOrdinalIgnoreCase
+libSystem.Globalization.Native!GlobalizationNative_IsNormalized
+libSystem.Globalization.Native!GlobalizationNative_IsPredefinedLocale
+libSystem.Globalization.Native!GlobalizationNative_LastIndexOf
+libSystem.Globalization.Native!GlobalizationNative_LoadICU
+libSystem.Globalization.Native!GlobalizationNative_NormalizeString
+libSystem.Globalization.Native!GlobalizationNative_StartsWith
+libSystem.Globalization.Native!GlobalizationNative_ToAscii
+libSystem.Globalization.Native!GlobalizationNative_ToUnicode
<Compile Include="$(BclSourcesRoot)\System\Variant.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetsUnix)' == 'true'">
- <Compile Include="$(CommonPath)Interop\Windows\Interop.BOOL.cs"> <!-- The CLR internally uses a BOOL type analogous to the Windows BOOL type on Unix -->
- <Link>Common\Interop\Windows\Interop.BOOL.cs</Link>
- </Compile>
<Compile Include="$(BclSourcesRoot)\Interop\Unix\Interop.Libraries.cs" />
<Compile Include="$(BclSourcesRoot)\System\DateTime.Unix.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Globalization\GlobalizationMode.Unix.cs" />
{
internal static partial class GlobalizationMode
{
+ // Order of these properties in Windows matter because GetUseIcuMode is dependent on Invariant.
+ // So we need Invariant to be initialized first.
+ internal static bool Invariant { get; } = GetGlobalizationInvariantMode();
+
+ internal static bool UseNls => false;
+
private static bool GetGlobalizationInvariantMode()
{
bool invariantEnabled = GetInvariantSwitchValue();
{
internal static partial class GlobalizationMode
{
- private static bool GetGlobalizationInvariantMode()
- {
- return GetInvariantSwitchValue();
- }
+ // Order of these properties in Windows matter because GetUseIcuMode is dependent on Invariant.
+ // So we need Invariant to be initialized first.
+ internal static bool Invariant { get; } = GetInvariantSwitchValue();
+
+ internal static bool UseNls { get; } = !Invariant &&
+ (GetSwitchValue("System.Globalization.UseNls", "DOTNET_SYSTEM_GLOBALIZATION_USENLS") ||
+ Interop.Globalization.LoadICU() == 0);
}
}
{
internal static partial class GlobalizationMode
{
- internal static bool Invariant { get; } = GetGlobalizationInvariantMode();
+ private static bool GetInvariantSwitchValue() =>
+ GetSwitchValue("System.Globalization.Invariant", "DOTNET_SYSTEM_GLOBALIZATION_INVARIANT");
- // GetInvariantSwitchValue calls CLRConfig first to detect if the switch is defined in the config file.
+ // GetSwitchValue calls CLRConfig first to detect if the switch is defined in the config file.
// if the switch is defined we just use the value of this switch. otherwise, we'll try to get the switch
// value from the environment variable if it is defined.
- internal static bool GetInvariantSwitchValue()
+ private static bool GetSwitchValue(string switchName, string envVariable)
{
- bool ret = CLRConfig.GetBoolValue("System.Globalization.Invariant", out bool exist);
+ bool ret = CLRConfig.GetBoolValue(switchName, out bool exist);
if (!exist)
{
- // Linux doesn't support environment variable names include dots
- string? switchValue = Environment.GetEnvironmentVariable("DOTNET_SYSTEM_GLOBALIZATION_INVARIANT");
+ string? switchValue = Environment.GetEnvironmentVariable(envVariable);
if (switchValue != null)
{
ret = bool.IsTrueStringIgnoreCase(switchValue) || switchValue.Equals("1");
--- /dev/null
+// 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.
+
+internal static partial class Interop
+{
+ internal static partial class Libraries
+ {
+ internal const string GlobalizationNative = "libSystem.Globalization.Native";
+ }
+}
{
// Shims
internal const string SystemNative = "libSystem.Native";
- internal const string GlobalizationNative = "libSystem.Globalization.Native";
internal const string NetSecurityNative = "libSystem.Net.Security.Native";
internal const string CryptoNative = "libSystem.Security.Cryptography.Native.OpenSsl";
internal const string CompressionNative = "libSystem.IO.Compression.Native";
// 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.Reflection;
using System.Runtime.InteropServices;
using System.Xml.Linq;
public static bool IsNotFedoraOrRedHatFamily => !IsFedora && !IsRedHatFamily;
public static bool IsNotDebian10 => !IsDebian10;
- private static Lazy<Version> m_icuVersion = new Lazy<Version>(GetICUVersion);
- public static Version ICUVersion => m_icuVersion.Value;
-
public static bool IsSuperUser => !IsWindows ?
libc.geteuid() == 0 :
throw new PlatformNotSupportedException();
}
}
- private static Version GetICUVersion()
- {
- int version = 0;
- Type interopGlobalization = Type.GetType("Interop+Globalization");
- if (interopGlobalization != null)
- {
- MethodInfo methodInfo = interopGlobalization.GetMethod("GetICUVersion", BindingFlags.NonPublic | BindingFlags.Static);
- if (methodInfo != null)
- {
- version = (int)methodInfo.Invoke(null, null);
- }
- }
-
- return new Version( version & 0xFF,
- (version >> 8) & 0xFF,
- (version >> 16) & 0xFF,
- version >> 24);
- }
-
private static Version GetOSXProductVersion()
{
if (IsOSX)
using System.IO;
using System.Security;
+using System.Reflection;
using System.Runtime.InteropServices;
using System.Runtime.CompilerServices;
using Microsoft.Win32;
}
}
+ private static Lazy<Version> m_icuVersion = new Lazy<Version>(GetICUVersion);
+ public static Version ICUVersion => m_icuVersion.Value;
+
+ public static bool IsIcuGlobalization => ICUVersion > new Version(0,0,0,0);
+ public static bool IsNlsGlobalization => !IsIcuGlobalization;
+
+ private static Version GetICUVersion()
+ {
+ int version = 0;
+ try
+ {
+ Type interopGlobalization = Type.GetType("Interop+Globalization");
+ if (interopGlobalization != null)
+ {
+ MethodInfo methodInfo = interopGlobalization.GetMethod("GetICUVersion", BindingFlags.NonPublic | BindingFlags.Static);
+ if (methodInfo != null)
+ {
+ version = (int)methodInfo.Invoke(null, null);
+ }
+ }
+ }
+ catch { }
+
+ return new Version(version >> 24,
+ (version >> 16) & 0xFF,
+ (version >> 8) & 0xFF,
+ version & 0xFF);
+ }
+
private static bool GetIsInContainer()
{
if (IsWindows)
using System.Threading;
using System.Threading.Tasks;
using Microsoft.DotNet.RemoteExecutor;
+using Microsoft.DotNet.XUnitExtensions;
using Xunit;
#pragma warning disable xUnit2009 // these are the tests for String and so should be using the explicit methods on String
Assert.Equal(expected, s.AsSpan().EndsWith(value.AsSpan(), comparisonType));
}
- [Theory]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/4673", TestPlatforms.AnyUnix)]
+ // NOTE: This is by design. ICU ignores the null characters (i.e. null characters have no weights for the string comparison).
+ // For desired behavior, use ordinal comparison instead of linguistic comparison.
+ // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673).
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
[InlineData(StringComparison.CurrentCulture)]
[InlineData(StringComparison.CurrentCultureIgnoreCase)]
[InlineData(StringComparison.Ordinal)]
Assert.False("test".AsSpan().EndsWith("\0st".AsSpan(), comparison));
}
- // NOTE: This is by design. Unix ignores the null characters (i.e. null characters have no weights for the string comparison).
+ // NOTE: This is by design. ICU ignores the null characters (i.e. null characters have no weights for the string comparison).
// For desired behavior, use ordinal comparison instead of linguistic comparison.
- // This is a known difference between Windows and Unix (https://github.com/dotnet/runtime/issues/4673).
- [Theory]
- [PlatformSpecific(TestPlatforms.Windows)]
+ // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673).
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
[InlineData(StringComparison.InvariantCulture)]
[InlineData(StringComparison.InvariantCultureIgnoreCase)]
public static void EndsWith_NullInStrings_NonOrdinal(StringComparison comparison)
string s1 = new string(first);
string s2 = new string(second);
- //On Linux there are some characters in the range of 0~32 which has a sort weight.
- //For example null character on Linux will be ignored if it is compared to anything
- //while on Windows null will be always compared as ordinal.
- //For desired behavior, use ordinal comparison instead of linguistic comparison.
- //This is a known difference between Windows and Unix (https://github.com/dotnet/runtime/issues/4673).
+ // On ICU there are some characters in the range of 0~32 which have a sort weight.
+ // For example null character on ICU will be ignored if it is compared to anything
+ // while on NLS null will be always compared as ordinal.
+ // For desired behavior, use ordinal comparison instead of linguistic comparison.
+ // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673).
bool b = s1.EndsWith(s2, StringComparison.Ordinal);
Assert.False(b);
yield return new object[] { StringComparison.Ordinal, false };
yield return new object[] { StringComparison.OrdinalIgnoreCase, false };
- // Windows and ICU disagree about how these strings compare in the default locale.
- yield return new object[] { StringComparison.InvariantCulture, PlatformDetection.IsWindows };
- yield return new object[] { StringComparison.InvariantCultureIgnoreCase, PlatformDetection.IsWindows };
+ // NLS and ICU disagree about how these strings compare in the default locale.
+ yield return new object[] { StringComparison.InvariantCulture, PlatformDetection.IsNlsGlobalization };
+ yield return new object[] { StringComparison.InvariantCultureIgnoreCase, PlatformDetection.IsNlsGlobalization };
}
[Theory]
#pragma warning restore IDE0043 // Format string contains invalid placeholder
}
- [Theory]
+ [ConditionalTheory]
[InlineData("Hello", 'l', 0, 5, 2)]
[InlineData("Hello", 'x', 0, 5, -1)]
[InlineData("Hello", 'l', 1, 4, 2)]
[InlineData("Hello", 'l', 0, 3, 2)]
[InlineData("Hello", 'o', 5, 0, -1)]
[InlineData("H" + SoftHyphen + "ello", 'e', 0, 3, 2)]
- // For some reason, this is failing on *nix with ordinal comparisons.
- // Possibly related issue: https://github.com/dotnet/runtime/issues/4673
- // [InlineData("Hello", '\0', 0, 5, -1)] // .NET strings are terminated with a null character, but they should not be included as part of the string
+ [InlineData("Hello", '\0', 0, 5, -1)] // .NET strings are terminated with a null character, but they should not be included as part of the string
[InlineData("\ud800\udfff", '\ud800', 0, 1, 0)] // Surrogate characters
[InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'A', 0, 26, 0)]
[InlineData("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 'B', 1, 25, 1)]
[InlineData("", 'H', 0, 0, -1)]
public static void IndexOf_SingleLetter(string s, char target, int startIndex, int count, int expected)
{
+ // This is by design. ICU ignores the null characters (i.e. null characters have no weights for the string comparison).
+ // For desired behavior, use ordinal comparison instead of linguistic comparison.
+ // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673).
+ if (target == '\0' && PlatformDetection.IsIcuGlobalization)
+ {
+ throw new SkipTestException("Target \\0 is not supported in ICU");
+ }
+
bool safeForCurrentCulture =
IsSafeForCurrentCultureComparisons(s)
&& IsSafeForCurrentCultureComparisons(target.ToString());
return true;
}
- [Theory]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/4673", TestPlatforms.AnyUnix)]
+ // NOTE: This is by design. ICU ignores the null characters (i.e. null characters have no weights for the string comparison).
+ // For desired behavior, use ordinal comparison instead of linguistic comparison.
+ // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673).
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
[InlineData("He\0lo", "He\0lo", 0)]
[InlineData("He\0lo", "He\0", 0)]
[InlineData("He\0lo", "\0", 2)]
string target = "ddzs";
/*
- There are differences between Windows and ICU regarding contractions.
- Windows has equal contraction collation weights, including case (target="Ddzs" same behavior as "ddzs").
+ There are differences between NLS and ICU regarding contractions.
+ NLS has equal contraction collation weights, including case (target="Ddzs" same behavior as "ddzs").
ICU has different contraction collation weights, depending on locale collation rules.
If CurrentCultureIgnoreCase is specified, ICU will use 'secondary' collation rules
which ignore the contraction collation weights (defined as 'tertiary' rules)
*/
- Assert.Equal(PlatformDetection.IsWindows ? 0 : -1, source.IndexOf(target));
- Assert.Equal(PlatformDetection.IsWindows ? 0 : -1, source.IndexOf(target, StringComparison.CurrentCulture));
+ Assert.Equal(PlatformDetection.IsNlsGlobalization ? 0 : -1, source.IndexOf(target));
+ Assert.Equal(PlatformDetection.IsNlsGlobalization ? 0 : -1, source.IndexOf(target, StringComparison.CurrentCulture));
Assert.Equal(0, source.IndexOf(target, StringComparison.CurrentCultureIgnoreCase));
Assert.Equal(-1, source.IndexOf(target, StringComparison.Ordinal));
ReadOnlySpan<char> span = source.AsSpan();
- Assert.Equal(PlatformDetection.IsWindows ? 0 : -1, span.IndexOf(target.AsSpan(), StringComparison.CurrentCulture));
+ Assert.Equal(PlatformDetection.IsNlsGlobalization ? 0 : -1, span.IndexOf(target.AsSpan(), StringComparison.CurrentCulture));
Assert.Equal(0, span.IndexOf(target.AsSpan(), StringComparison.CurrentCultureIgnoreCase));
Assert.Equal(-1, span.IndexOf(target.AsSpan(), StringComparison.Ordinal));
}
}
- [Theory]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/4673", TestPlatforms.AnyUnix)]
+ // NOTE: This is by design. ICU ignores the null characters (i.e. null characters have no weights for the string comparison).
+ // For desired behavior, use ordinal comparison instead of linguistic comparison.
+ // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673).
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
[InlineData("He\0lo", "He\0lo", 0)]
[InlineData("He\0lo", "He\0", 0)]
[InlineData("He\0lo", "\0", 2)]
Assert.Equal(expected, s.AsSpan().StartsWith(value.AsSpan(), comparisonType));
}
- [Theory]
- [ActiveIssue("https://github.com/dotnet/runtime/issues/4673", TestPlatforms.AnyUnix)]
+ // NOTE: This is by design. ICU ignores the null characters (i.e. null characters have no weights for the string comparison).
+ // For desired behavior, use ordinal comparison instead of linguistic comparison.
+ // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673).
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
[InlineData(StringComparison.CurrentCulture)]
[InlineData(StringComparison.CurrentCultureIgnoreCase)]
[InlineData(StringComparison.Ordinal)]
Assert.False(span.StartsWith(value, StringComparison.InvariantCultureIgnoreCase));
}
- // NOTE: This is by design. Unix ignores the null characters (i.e. null characters have no weights for the string comparison).
+ // NOTE: This is by design. ICU ignores the null characters (i.e. null characters have no weights for the string comparison).
// For desired behavior, use ordinal comparison instead of linguistic comparison.
- // This is a known difference between Windows and Unix (https://github.com/dotnet/runtime/issues/4673).
- [Theory]
- [PlatformSpecific(TestPlatforms.Windows)]
+ // This is a known difference between NLS and ICU (https://github.com/dotnet/runtime/issues/4673).
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
[InlineData(StringComparison.CurrentCulture)]
[InlineData(StringComparison.CurrentCultureIgnoreCase)]
[InlineData(StringComparison.InvariantCulture)]
#include "windows.h"
#endif
+// The args passed in should match InterlockedCompareExchangePointer Windows API
static int pal_atomic_cas_ptr(void* volatile* dest, void* exchange, void* comparand)
{
#if defined(TARGET_UNIX)
- return __atomic_compare_exchange_n(dest, exchange, comparand, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+ return __atomic_compare_exchange_n(dest, &comparand, exchange, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
#elif defined(TARGET_WINDOWS)
return InterlockedCompareExchangePointer(dest, exchange, comparand) == comparand;
#endif
pCollator = CloneCollatorWithOptions(pSortHandle->collatorsPerOption[0], options, pErr);
UCollator* pNull = NULL;
- if (!pal_atomic_cas_ptr((void* volatile*)&pSortHandle->collatorsPerOption[options], &pNull, pCollator))
+ if (!pal_atomic_cas_ptr((void* volatile*)&pSortHandle->collatorsPerOption[options], pCollator, pNull))
{
ucol_close(pCollator);
pCollator = pSortHandle->collatorsPerOption[options];
// return the current loaded ICU version
int32_t GlobalizationNative_GetICUVersion()
{
- int32_t version;
- u_getVersion((uint8_t *) &version);
- return version;
+ if (u_getVersion_ptr == NULL)
+ return 0;
+
+ UVersionInfo versionInfo;
+ u_getVersion(versionInfo);
+
+ return (versionInfo[0] << 24) + (versionInfo[1] << 16) + (versionInfo[2] << 8) + versionInfo[3];
}
using System.Collections.Generic;
using System.Globalization;
using System.Text;
+using Microsoft.DotNet.XUnitExtensions;
using Xunit;
namespace System.Data.SqlTypes.Tests
private static readonly UnicodeEncoding s_unicodeEncoding = new UnicodeEncoding(bigEndian: false, byteOrderMark: false, throwOnInvalidBytes: true);
- [ActiveIssue("https://github.com/dotnet/runtime/issues/18912", TestPlatforms.AnyUnix)] // TODO: Add this to the theory below when the issue is addressed on Unix
- [Theory]
+ [ConditionalTheory]
[InlineData("ja-JP", 0x0411)] // Japanese - Japan
- public static void SqlStringValidComparisonTest_Windows(string cultureName, int localeId) => SqlStringValidComparisonTest(cultureName, localeId);
-
- [Theory]
[InlineData("ar-SA", 0x0401)] // Arabic - Saudi Arabia
[InlineData("de-DE", 0x0407)] // German - Germany
[InlineData("hi-IN", 0x0439)] // Hindi - India
[InlineData("en-US", 0x0409)] // English - United States
public static void SqlStringValidComparisonTest(string cultureName, int localeId)
{
+ if (PlatformDetection.IsIcuGlobalization && cultureName == "ja-JP" && localeId == 0x0411)
+ {
+ // TODO: Remove this once: https://github.com/dotnet/runtime/issues/18912 is fixed on ICU.
+ throw new SkipTestException($"PlatformDetection.IsIcuGlobalization and cultureName == ja-JP");
+ }
+
var culture = new CultureInfo(cultureName);
const SqlCompareOptions DefaultCompareOption = SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType | SqlCompareOptions.IgnoreWidth;
Calendar calendar = Calendar;
Assert.All(DateTime_TestData(calendar), dt =>
{
- // JapaneseCalendar throws on Unix (ICU), but not on Windows
- if ((calendar is JapaneseCalendar && PlatformDetection.IsWindows) || calendar is HebrewCalendar || calendar is TaiwanLunisolarCalendar || calendar is JapaneseLunisolarCalendar)
+ // JapaneseCalendar throws on ICU, but not on NLS
+ if ((calendar is JapaneseCalendar && PlatformDetection.IsNlsGlobalization) || calendar is HebrewCalendar || calendar is TaiwanLunisolarCalendar || calendar is JapaneseLunisolarCalendar)
{
calendar.GetEra(dt);
}
private static string[] GetExpectedMonthNames()
{
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ if (PlatformDetection.IsNlsGlobalization)
{
return new string[]
{
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27213.1
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29923.206
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Globalization.Extensions.Tests", "tests\System.Globalization.Extensions.Tests.csproj", "{BC439554-4AB4-4C94-8E28-C00EDE4FD1C7}"
ProjectSection(ProjectDependencies) = postProject
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{A36A6300-3BE9-42CA-B7BC-62E926E07CC5}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Globalization.Extensions.Nls.Tests", "tests\NlsTests\System.Globalization.Extensions.Nls.Tests.csproj", "{CB60359A-D0ED-474E-B395-9589F1A5656A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
{3634FAA3-A33E-406A-94EE-5611C6CC2810}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3634FAA3-A33E-406A-94EE-5611C6CC2810}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3634FAA3-A33E-406A-94EE-5611C6CC2810}.Release|Any CPU.Build.0 = Release|Any CPU
- {A36A6300-3BE9-42CA-B7BC-62E926E07CC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A36A6300-3BE9-42CA-B7BC-62E926E07CC5}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A36A6300-3BE9-42CA-B7BC-62E926E07CC5}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A36A6300-3BE9-42CA-B7BC-62E926E07CC5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CB60359A-D0ED-474E-B395-9589F1A5656A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CB60359A-D0ED-474E-B395-9589F1A5656A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CB60359A-D0ED-474E-B395-9589F1A5656A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CB60359A-D0ED-474E-B395-9589F1A5656A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
{BC439554-4AB4-4C94-8E28-C00EDE4FD1C7} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{2B96AA10-84C0-4927-8611-8D2474B990E8} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
{3634FAA3-A33E-406A-94EE-5611C6CC2810} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
- {A36A6300-3BE9-42CA-B7BC-62E926E07CC5} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
+ {CB60359A-D0ED-474E-B395-9589F1A5656A} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {3E550ED4-6053-4B16-97D1-BAADB02924FE}
{
public class GetStringComparerTests
{
- private static bool s_isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
-
[Fact]
public void GetStringComparer_Invalid()
{
[InlineData("abc", "ABC", "en-US", CompareOptions.OrdinalIgnoreCase, 0, 0)]
[InlineData("Cot\u00E9", "cot\u00E9", "fr-FR", CompareOptions.IgnoreCase, 0, 0)]
[InlineData("cot\u00E9", "c\u00F4te", "fr-FR", CompareOptions.None, 1, -1)]
- public static void Compare(string x, string y, string cultureName, CompareOptions options, int expectedWindows, int expectedICU)
+ public static void Compare(string x, string y, string cultureName, CompareOptions options, int expectedNls, int expectedICU)
{
- int expected = s_isWindows ? expectedWindows : expectedICU;
+ int expected = PlatformDetection.IsNlsGlobalization ? expectedNls : expectedICU;
StringComparer comparer = new CultureInfo(cultureName).CompareInfo.GetStringComparer(options);
Assert.Equal(expected, Math.Sign(comparer.Compare(x, y)));
continue;
}
string ascii = c.ToString();
- if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // expected platform differences, see https://github.com/dotnet/runtime/issues/17190
+ if (PlatformDetection.IsIcuGlobalization) // expected platform differences, see https://github.com/dotnet/runtime/issues/17190
{
- if ((c >= 'A' && c <= 'Z'))
+ if (c >= 'A' && c <= 'Z')
{
yield return new object[] { ascii, 0, 1, ascii.ToLower() };
}
yield return new object[] { "abc" + (char)0x7F + "def", 0, 7, typeof(ArgumentException) };
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // expected platform differences, see https://github.com/dotnet/runtime/issues/17190
+ if (PlatformDetection.IsNlsGlobalization) // expected platform differences, see https://github.com/dotnet/runtime/issues/17190
{
yield return new object[] { "xn--\u1234", 0, 5, typeof(ArgumentException) };
yield return new object[] { "xn--\u1234pck", 0, 8, typeof(ArgumentException) };
/// </summary>
public class UseStd3AsciiRules
{
- private static bool s_isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
-
[Fact]
public void UseStd3AsciiRules_IsFalseByDefault()
{
var idnStd3False = new IdnMapping { UseStd3AsciiRules = false };
var idnStd3True = new IdnMapping { UseStd3AsciiRules = true };
- if (containsInvalidHyphen && !s_isWindows)
+ if (containsInvalidHyphen && PlatformDetection.IsIcuGlobalization)
{
// ICU always fails on leading/trailing hyphens regardless of the Std3 rules option.
AssertExtensions.Throws<ArgumentException>("unicode", () => idnStd3False.GetAscii(unicode));
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <TargetFrameworks>$(NetCoreAppCurrent)-Windows_NT</TargetFrameworks>
+ <TestRuntime>true</TestRuntime>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="..\GetStringComparerTests.cs">
+ <Link>GetStringComparerTests.cs</Link>
+ </Compile>
+ <Compile Include="..\IdnMapping\Data\ConformanceIdnaUnicodeTestResult.cs">
+ <Link>IdnMapping\Data\ConformanceIdnaUnicodeTestResult.cs</Link>
+ </Compile>
+ <Compile Include="..\IdnMapping\Data\Unicode_9_0\Unicode_9_0_IdnaTest.cs">
+ <Link>IdnMapping\Data\Unicode_9_0\Unicode_9_0_IdnaTest.cs</Link>
+ </Compile>
+ <Compile Include="..\IdnMapping\Data\Unicode_11_0\Unicode_11_0_IdnaTest.cs">
+ <Link>IdnMapping\Data\Unicode_11_0\Unicode_11_0_IdnaTest.cs</Link>
+ </Compile>
+ <Compile Include="..\IdnMapping\IdnMappingIdnaConformanceTests.cs">
+ <Link>IdnMapping\IdnMappingIdnaConformanceTests.cs</Link>
+ </Compile>
+ <Compile Include="..\IdnMapping\Data\Factory.cs">
+ <Link>IdnMapping\Data\Factory.cs</Link>
+ </Compile>
+ <Compile Include="..\IdnMapping\Data\ConformanceIdnaTestResult.cs">
+ <Link>IdnMapping\Data\ConformanceIdnaTestResult.cs</Link>
+ </Compile>
+ <Compile Include="..\IdnMapping\Data\Unicode_6_0\Unicode_6_0_IdnaTest.cs">
+ <Link>IdnMapping\Data\Unicode_6_0\Unicode_6_0_IdnaTest.cs</Link>
+ </Compile>
+ <Compile Include="..\IdnMapping\Data\Unicode_Win7\Unicode_Win7_IdnaTest.cs">
+ <Link>IdnMapping\Data\Unicode_Win7\Unicode_Win7_IdnaTest.cs</Link>
+ </Compile>
+ <Compile Include="..\IdnMapping\Data\IConformanceIdnaTest.cs">
+ <Link>IdnMapping\Data\IConformanceIdnaTest.cs</Link>
+ </Compile>
+ <Compile Include="..\IdnMapping\IdnMappingGetAsciiTests.cs">
+ <Link>IdnMapping\IdnMappingGetAsciiTests.cs</Link>
+ </Compile>
+ <Compile Include="..\IdnMapping\IdnMappingGetUnicodeTests.cs">
+ <Link>IdnMapping\IdnMappingGetUnicodeTests.cs</Link>
+ </Compile>
+ <Compile Include="..\IdnMapping\IdnMappingUseStd3AsciiRulesTests.cs">
+ <Link>IdnMapping\IdnMappingUseStd3AsciiRulesTests.cs</Link>
+ </Compile>
+ <Compile Include="..\Normalization\StringNormalizationTests.cs">
+ <Link>Normalization\StringNormalizationTests.cs</Link>
+ </Compile>
+ <Compile Include="..\Normalization\NormalizationAll.cs">
+ <Link>Normalization\NormalizationAll.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <EmbeddedResource Include="..\IdnMapping\Data\Unicode_6_0\IdnaTest_6.txt" />
+ <EmbeddedResource Include="..\IdnMapping\Data\Unicode_Win7\IdnaTest_Win7.txt" />
+ <EmbeddedResource Include="..\IdnMapping\Data\Unicode_9_0\IdnaTest_9.txt" />
+ <EmbeddedResource Include="..\IdnMapping\Data\Unicode_11_0\IdnaTest_11.txt" />
+ <EmbeddedResource Include="..\Normalization\Data\win8.txt">
+ <LogicalName>NormalizationDataWin8</LogicalName>
+ </EmbeddedResource>
+ <EmbeddedResource Include="..\Normalization\Data\win7.txt">
+ <LogicalName>NormalizationDataWin7</LogicalName>
+ </EmbeddedResource>
+ <None Include="runtimeconfig.template.json" />
+ </ItemGroup>
+</Project>
\ No newline at end of file
--- /dev/null
+{
+ "configProperties": {
+ "System.Globalization.UseNls": true
+ }
+}
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.27213.1
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.29923.206
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Globalization.Tests", "tests\System.Globalization.Tests.csproj", "{484C92C6-6D2C-45BC-A5E2-4A12BA228E1E}"
ProjectSection(ProjectDependencies) = postProject
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{2E666815-2EDB-464B-9DF6-380BF4789AD4}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "System.Globalization.Nls.Tests", "tests\NlsTests\System.Globalization.Nls.Tests.csproj", "{6B71E284-DA57-4657-9E08-A02BAFB877CC}"
+EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities", "..\Common\tests\TestUtilities\TestUtilities.csproj", "{443745F1-A200-432B-A666-3D0E9F938DED}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestUtilities.Unicode", "..\Common\tests\TestUtilities.Unicode\TestUtilities.Unicode.csproj", "{E5ECA266-C7E9-4597-8FFA-095BD6890407}"
{E1E58C98-808F-4065-9C1D-E6411166AF6F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E1E58C98-808F-4065-9C1D-E6411166AF6F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E1E58C98-808F-4065-9C1D-E6411166AF6F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6B71E284-DA57-4657-9E08-A02BAFB877CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6B71E284-DA57-4657-9E08-A02BAFB877CC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6B71E284-DA57-4657-9E08-A02BAFB877CC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6B71E284-DA57-4657-9E08-A02BAFB877CC}.Release|Any CPU.Build.0 = Release|Any CPU
{443745F1-A200-432B-A666-3D0E9F938DED}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{443745F1-A200-432B-A666-3D0E9F938DED}.Debug|Any CPU.Build.0 = Debug|Any CPU
{443745F1-A200-432B-A666-3D0E9F938DED}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A8926D9-1D4C-4069-8965-A626F6CA8C29} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{2395E8CA-73CB-40DF-BE40-A60BC189B737} = {E107E9C1-E893-4E87-987E-04EF0DCEAEFD}
{E1E58C98-808F-4065-9C1D-E6411166AF6F} = {2E666815-2EDB-464B-9DF6-380BF4789AD4}
+ {6B71E284-DA57-4657-9E08-A02BAFB877CC} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{443745F1-A200-432B-A666-3D0E9F938DED} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
{E5ECA266-C7E9-4597-8FFA-095BD6890407} = {1A2F9F4A-A032-433E-B914-ADD5992BB178}
EndGlobalSection
// On Windows, hiragana characters sort after katakana.
// On ICU, it is the opposite
- private static int s_expectedHiraganaToKatakanaCompare = PlatformDetection.IsWindows ? 1 : -1;
+ private static int s_expectedHiraganaToKatakanaCompare = PlatformDetection.IsNlsGlobalization ? 1 : -1;
// On Windows, all halfwidth characters sort before fullwidth characters.
// On ICU, half and fullwidth characters that aren't in the "Halfwidth and fullwidth forms" block U+FF00-U+FFEF
// sort before the corresponding characters that are in the block U+FF00-U+FFEF
- private static int s_expectedHalfToFullFormsComparison = PlatformDetection.IsWindows ? -1 : 1;
+ private static int s_expectedHalfToFullFormsComparison = PlatformDetection.IsNlsGlobalization ? -1 : 1;
private const string SoftHyphen = "\u00AD";
yield return new object[] { s_invariantCompare, "\u3070\u3073\u3076\u3079\u307C", "\u30D0\u30D3\u3076\u30D9\uFF8E\uFF9E", CompareOptions.None, s_expectedHiraganaToKatakanaCompare };
yield return new object[] { s_invariantCompare, "\u3060", "\uFF80\uFF9E", CompareOptions.None, s_expectedHiraganaToKatakanaCompare };
- bool isWindows = PlatformDetection.IsWindows;
+ bool useNls = PlatformDetection.IsNlsGlobalization;
- yield return new object[] { s_invariantCompare, "\u30C7\u30BF\u30D9\u30B9", "\uFF83\uFF9E\uFF80\uFF8D\uFF9E\uFF7D", CompareOptions.None, isWindows ? 1 : -1 };
- yield return new object[] { s_invariantCompare, "\u30C7", "\uFF83\uFF9E", CompareOptions.None, isWindows ? 1 : -1 };
- yield return new object[] { s_invariantCompare, "\u30C7\u30BF", "\uFF83\uFF9E\uFF80", CompareOptions.None, isWindows ? 1 : -1 };
- yield return new object[] { s_invariantCompare, "\u30C7\u30BF\u30D9", "\uFF83\uFF9E\uFF80\uFF8D\uFF9E", CompareOptions.None, isWindows ? 1 : -1 };
- yield return new object[] { s_invariantCompare, "\uFF83\uFF9E\uFF70\uFF80\uFF8D\uFF9E\uFF70\uFF7D", "\u3067\u30FC\u305F\u3079\u30FC\u3059", CompareOptions.None, isWindows ? -1 : 1 };
+ yield return new object[] { s_invariantCompare, "\u30C7\u30BF\u30D9\u30B9", "\uFF83\uFF9E\uFF80\uFF8D\uFF9E\uFF7D", CompareOptions.None, useNls ? 1 : -1 };
+ yield return new object[] { s_invariantCompare, "\u30C7", "\uFF83\uFF9E", CompareOptions.None, useNls ? 1 : -1 };
+ yield return new object[] { s_invariantCompare, "\u30C7\u30BF", "\uFF83\uFF9E\uFF80", CompareOptions.None, useNls ? 1 : -1 };
+ yield return new object[] { s_invariantCompare, "\u30C7\u30BF\u30D9", "\uFF83\uFF9E\uFF80\uFF8D\uFF9E", CompareOptions.None, useNls ? 1 : -1 };
+ yield return new object[] { s_invariantCompare, "\uFF83\uFF9E\uFF70\uFF80\uFF8D\uFF9E\uFF70\uFF7D", "\u3067\u30FC\u305F\u3079\u30FC\u3059", CompareOptions.None, useNls ? -1 : 1 };
}
public static IEnumerable<object[]> Compare_TestData()
yield return new object[] { new CultureInfo("es-ES").CompareInfo, "llegar", "lugar", CompareOptions.None, -1 };
// Misc differences between platforms
- bool isWindows = PlatformDetection.IsWindows;
-
- yield return new object[] { s_invariantCompare, "\u3042", "\u30A1", CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase, isWindows ? 1: 0 };
- yield return new object[] { s_invariantCompare, "'\u3000'", "''", CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase, isWindows ? 1 : -1 };
- yield return new object[] { s_invariantCompare, "\u30BF", "\uFF80", CompareOptions.None, isWindows ? 1 : -1 };
- yield return new object[] { s_invariantCompare, "'\u3000'", "''", CompareOptions.None, isWindows ? 1 : -1 };
- yield return new object[] { s_invariantCompare, "\u30FC", "\uFF70", CompareOptions.None, isWindows ? 0 : -1 };
- yield return new object[] { s_hungarianCompare, "dzsdzs", "ddzs", CompareOptions.None, isWindows ? 0 : -1 };
- yield return new object[] { s_invariantCompare, "Test's", "Tests", CompareOptions.None, isWindows ? 1 : -1 };
+ bool useNls = PlatformDetection.IsNlsGlobalization;
+
+ yield return new object[] { s_invariantCompare, "\u3042", "\u30A1", CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase, useNls ? 1: 0 };
+ yield return new object[] { s_invariantCompare, "'\u3000'", "''", CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase, useNls ? 1 : -1 };
+ yield return new object[] { s_invariantCompare, "\u30BF", "\uFF80", CompareOptions.None, useNls ? 1 : -1 };
+ yield return new object[] { s_invariantCompare, "'\u3000'", "''", CompareOptions.None, useNls ? 1 : -1 };
+ yield return new object[] { s_invariantCompare, "\u30FC", "\uFF70", CompareOptions.None, useNls ? 0 : -1 };
+ yield return new object[] { s_hungarianCompare, "dzsdzs", "ddzs", CompareOptions.None, useNls ? 0 : -1 };
+ yield return new object[] { s_invariantCompare, "Test's", "Tests", CompareOptions.None, useNls ? 1 : -1 };
yield return new object[] { new CultureInfo("de-DE").CompareInfo, "\u00DC", "UE", CompareOptions.None, -1 };
- yield return new object[] { new CultureInfo("de-DE_phoneb").CompareInfo, "\u00DC", "UE", CompareOptions.None, isWindows ? 0 : -1 };
- yield return new object[] { new CultureInfo("es-ES_tradnl").CompareInfo, "llegar", "lugar", CompareOptions.None, isWindows ? 1 : -1 };
+ yield return new object[] { new CultureInfo("de-DE_phoneb").CompareInfo, "\u00DC", "UE", CompareOptions.None, useNls ? 0 : -1 };
+ yield return new object[] { new CultureInfo("es-ES_tradnl").CompareInfo, "llegar", "lugar", CompareOptions.None, useNls ? 1 : -1 };
}
// There is a regression in Windows 190xx version with the Kana comparison. Avoid running this test there.
public static bool IsNotWindowsKanaRegressedVersion() => !PlatformDetection.IsWindows10Version1903OrGreater ||
+ PlatformDetection.IsIcuGlobalization ||
s_invariantCompare.Compare("\u3060", "\uFF80\uFF9E", CompareOptions.IgnoreKanaType | CompareOptions.IgnoreWidth | CompareOptions.IgnoreCase) == 0;
[Fact]
public void CompareWithUnassignedChars()
{
- int result = PlatformDetection.IsWindows ? 0 : -1;
+ int result = PlatformDetection.IsNlsGlobalization ? 0 : -1;
Compare(s_invariantCompare, "FooBar", "Foo\uFFFFBar", CompareOptions.None, result);
Compare(s_invariantCompare, "FooBar", "Foo\uFFFFBar", CompareOptions.IgnoreNonSpace, result);
}
yield return new object[] { s_currentCompare, "\u0131", "\u0130", 0, 1, CompareOptions.Ordinal, -1 };
// Platform differences
- yield return new object[] { s_hungarianCompare, "foobardzsdzs", "rddzs", 0, 12, CompareOptions.None, PlatformDetection.IsWindows ? 5 : -1};
+ yield return new object[] { s_hungarianCompare, "foobardzsdzs", "rddzs", 0, 12, CompareOptions.None, PlatformDetection.IsNlsGlobalization ? 5 : -1};
}
public static IEnumerable<object[]> IndexOf_Aesc_Ligature_TestData()
{
- bool isWindows = PlatformDetection.IsWindows;
+ bool useNls = PlatformDetection.IsNlsGlobalization;
// Searches for the ligature \u00C6
string source1 = "Is AE or ae the same as \u00C6 or \u00E6?";
- yield return new object[] { s_invariantCompare, source1, "AE", 8, 18, CompareOptions.None, isWindows ? 24 : -1};
+ yield return new object[] { s_invariantCompare, source1, "AE", 8, 18, CompareOptions.None, useNls ? 24 : -1};
yield return new object[] { s_invariantCompare, source1, "ae", 8, 18, CompareOptions.None, 9 };
yield return new object[] { s_invariantCompare, source1, "\u00C6", 8, 18, CompareOptions.None, 24 };
- yield return new object[] { s_invariantCompare, source1, "\u00E6", 8, 18, CompareOptions.None, isWindows ? 9 : -1};
+ yield return new object[] { s_invariantCompare, source1, "\u00E6", 8, 18, CompareOptions.None, useNls ? 9 : -1};
yield return new object[] { s_invariantCompare, source1, "AE", 8, 18, CompareOptions.Ordinal, -1 };
yield return new object[] { s_invariantCompare, source1, "ae", 8, 18, CompareOptions.Ordinal, 9 };
yield return new object[] { s_invariantCompare, source1, "\u00C6", 8, 18, CompareOptions.Ordinal, 24 };
yield return new object[] { s_invariantCompare, source1, "\u00E6", 8, 18, CompareOptions.Ordinal, -1 };
yield return new object[] { s_invariantCompare, source1, "AE", 8, 18, CompareOptions.IgnoreCase, 9 };
yield return new object[] { s_invariantCompare, source1, "ae", 8, 18, CompareOptions.IgnoreCase, 9 };
- yield return new object[] { s_invariantCompare, source1, "\u00C6", 8, 18, CompareOptions.IgnoreCase, isWindows? 9 : 24 };
- yield return new object[] { s_invariantCompare, source1, "\u00E6", 8, 18, CompareOptions.IgnoreCase, isWindows? 9 : 24 };
+ yield return new object[] { s_invariantCompare, source1, "\u00C6", 8, 18, CompareOptions.IgnoreCase, useNls ? 9 : 24 };
+ yield return new object[] { s_invariantCompare, source1, "\u00E6", 8, 18, CompareOptions.IgnoreCase, useNls ? 9 : 24 };
}
public static IEnumerable<object[]> IndexOf_U_WithDiaeresis_TestData()
[Fact]
public void IndexOf_UnassignedUnicode()
{
- bool isWindows = PlatformDetection.IsWindows;
- IndexOf_String(s_invariantCompare, "FooBar", "Foo\uFFFFBar", 0, 6, CompareOptions.None, isWindows ? 0 : -1);
- IndexOf_String(s_invariantCompare, "~FooBar", "Foo\uFFFFBar", 0, 7, CompareOptions.IgnoreNonSpace, isWindows ? 1 : -1);
+ bool useNls = PlatformDetection.IsNlsGlobalization;
+ IndexOf_String(s_invariantCompare, "FooBar", "Foo\uFFFFBar", 0, 6, CompareOptions.None, useNls ? 0 : -1);
+ IndexOf_String(s_invariantCompare, "~FooBar", "Foo\uFFFFBar", 0, 7, CompareOptions.IgnoreNonSpace, useNls ? 1 : -1);
}
[Fact]
yield return new object[] { s_invariantCompare, "Test's can be interesting", "Tests", CompareOptions.None, false };
// Platform differences
- yield return new object[] { s_hungarianCompare, "dzsdzsfoobar", "ddzsf", CompareOptions.None, PlatformDetection.IsWindows ? true : false };
- yield return new object[] { s_invariantCompare, "''Tests", "Tests", CompareOptions.IgnoreSymbols, PlatformDetection.IsWindows ? true : false };
- yield return new object[] { s_frenchCompare, "\u0153", "oe", CompareOptions.None, PlatformDetection.IsWindows ? true : false };
- yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uD800", CompareOptions.None, PlatformDetection.IsWindows ? true : false };
- yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uD800", CompareOptions.IgnoreCase, PlatformDetection.IsWindows ? true : false };
+ bool useNls = PlatformDetection.IsNlsGlobalization;
+ yield return new object[] { s_hungarianCompare, "dzsdzsfoobar", "ddzsf", CompareOptions.None, useNls ? true : false };
+ yield return new object[] { s_invariantCompare, "''Tests", "Tests", CompareOptions.IgnoreSymbols, useNls ? true : false };
+ yield return new object[] { s_frenchCompare, "\u0153", "oe", CompareOptions.None, useNls ? true : false };
+ yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uD800", CompareOptions.None, useNls ? true : false };
+ yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uD800", CompareOptions.IgnoreCase, useNls ? true : false };
// ICU bugs
// UInt16 overflow: https://unicode-org.atlassian.net/browse/ICU-20832 fixed in https://github.com/unicode-org/icu/pull/840 (ICU 65)
- if (PlatformDetection.IsWindows || PlatformDetection.ICUVersion.Major >= 65)
+ if (useNls || PlatformDetection.ICUVersion.Major >= 65)
{
yield return new object[] { s_frenchCompare, "b", new string('a', UInt16.MaxValue + 1), CompareOptions.None, false };
}
[Fact]
public void IsPrefix_UnassignedUnicode()
{
- bool result = PlatformDetection.IsWindows ? true : false;
+ bool result = PlatformDetection.IsNlsGlobalization ? true : false;
IsPrefix(s_invariantCompare, "FooBar", "Foo\uFFFFBar", CompareOptions.None, result);
IsPrefix(s_invariantCompare, "FooBar", "Foo\uFFFFBar", CompareOptions.IgnoreNonSpace, result);
}
yield return new object[] { s_invariantCompare, "a\u0000b", "b\u0000b", CompareOptions.None, false };
// Platform differences
- yield return new object[] { s_hungarianCompare, "foobardzsdzs", "rddzs", CompareOptions.None, PlatformDetection.IsWindows ? true : false };
- yield return new object[] { s_frenchCompare, "\u0153", "oe", CompareOptions.None, PlatformDetection.IsWindows ? true : false };
- yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uDC00", CompareOptions.None, PlatformDetection.IsWindows ? true : false };
- yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uDC00", CompareOptions.IgnoreCase, PlatformDetection.IsWindows ? true : false };
+ yield return new object[] { s_hungarianCompare, "foobardzsdzs", "rddzs", CompareOptions.None, PlatformDetection.IsIcuGlobalization ? false : true };
+ yield return new object[] { s_frenchCompare, "\u0153", "oe", CompareOptions.None, PlatformDetection.IsIcuGlobalization ? false : true };
+ yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uDC00", CompareOptions.None, PlatformDetection.IsIcuGlobalization ? false : true };
+ yield return new object[] { s_invariantCompare, "\uD800\uDC00", "\uDC00", CompareOptions.IgnoreCase, PlatformDetection.IsIcuGlobalization ? false : true };
}
[Theory]
[Fact]
public void IsSuffix_UnassignedUnicode()
{
- bool result = PlatformDetection.IsWindows ? true : false;
+ bool result = PlatformDetection.IsIcuGlobalization ? false : true;
IsSuffix(s_invariantCompare, "FooBar", "Foo\uFFFFBar", CompareOptions.None, result);
IsSuffix(s_invariantCompare, "FooBar", "Foo\uFFFFBar", CompareOptions.IgnoreNonSpace, result);
yield return new object[] { s_invariantCompare, "cbabababdbaba", "ab", 12, 13, CompareOptions.None, 10 };
// Platform differences
- yield return new object[] { s_hungarianCompare, "foobardzsdzs", "rddzs", 11, 12, CompareOptions.None, PlatformDetection.IsWindows ? 5 : -1 };
+ yield return new object[] { s_hungarianCompare, "foobardzsdzs", "rddzs", 11, 12, CompareOptions.None, PlatformDetection.IsNlsGlobalization ? 5 : -1 };
}
public static IEnumerable<object[]> LastIndexOf_Aesc_Ligature_TestData()
{
- bool isWindows = PlatformDetection.IsWindows;
+ bool useNls = PlatformDetection.IsNlsGlobalization;
// Searches for the ligature \u00C6
string source = "Is AE or ae the same as \u00C6 or \u00E6?";
- yield return new object[] { s_invariantCompare, source, "AE", 25, 18, CompareOptions.None, isWindows ? 24 : -1 };
+ yield return new object[] { s_invariantCompare, source, "AE", 25, 18, CompareOptions.None, useNls ? 24 : -1 };
yield return new object[] { s_invariantCompare, source, "ae", 25, 18, CompareOptions.None, 9 };
yield return new object[] { s_invariantCompare, source, '\u00C6', 25, 18, CompareOptions.None, 24 };
- yield return new object[] { s_invariantCompare, source, '\u00E6', 25, 18, CompareOptions.None, isWindows ? 9 : -1 };
+ yield return new object[] { s_invariantCompare, source, '\u00E6', 25, 18, CompareOptions.None, useNls ? 9 : -1 };
yield return new object[] { s_invariantCompare, source, "AE", 25, 18, CompareOptions.Ordinal, -1 };
yield return new object[] { s_invariantCompare, source, "ae", 25, 18, CompareOptions.Ordinal, 9 };
yield return new object[] { s_invariantCompare, source, '\u00C6', 25, 18, CompareOptions.Ordinal, 24 };
yield return new object[] { s_invariantCompare, source, '\u00E6', 25, 18, CompareOptions.Ordinal, -1 };
- yield return new object[] { s_invariantCompare, source, "AE", 25, 18, CompareOptions.IgnoreCase, isWindows ? 24 : 9 };
- yield return new object[] { s_invariantCompare, source, "ae", 25, 18, CompareOptions.IgnoreCase, isWindows ? 24 : 9 };
+ yield return new object[] { s_invariantCompare, source, "AE", 25, 18, CompareOptions.IgnoreCase, useNls ? 24 : 9 };
+ yield return new object[] { s_invariantCompare, source, "ae", 25, 18, CompareOptions.IgnoreCase, useNls ? 24 : 9 };
yield return new object[] { s_invariantCompare, source, '\u00C6', 25, 18, CompareOptions.IgnoreCase, 24 };
yield return new object[] { s_invariantCompare, source, '\u00E6', 25, 18, CompareOptions.IgnoreCase, 24 };
}
[Fact]
public void LastIndexOf_UnassignedUnicode()
{
- bool isWindows = PlatformDetection.IsWindows;
- LastIndexOf_String(s_invariantCompare, "FooBar", "Foo\uFFFFBar", 5, 6, CompareOptions.None, isWindows ? 0 : -1);
- LastIndexOf_String(s_invariantCompare, "~FooBar", "Foo\uFFFFBar", 6, 7, CompareOptions.IgnoreNonSpace, isWindows ? 1 : -1);
+ bool useNls = PlatformDetection.IsNlsGlobalization;
+ LastIndexOf_String(s_invariantCompare, "FooBar", "Foo\uFFFFBar", 5, 6, CompareOptions.None, useNls ? 0 : -1);
+ LastIndexOf_String(s_invariantCompare, "~FooBar", "Foo\uFFFFBar", 6, 7, CompareOptions.IgnoreNonSpace, useNls ? 1 : -1);
}
[Fact]
yield return new object[] { "tr-TR" , 0x041f };
}
- // On Windows, hiragana characters sort after katakana.
+ // On NLS, hiragana characters sort after katakana.
// On ICU, it is the opposite
- private static int s_expectedHiraganaToKatakanaCompare = PlatformDetection.IsWindows ? 1 : -1;
+ private static int s_expectedHiraganaToKatakanaCompare = PlatformDetection.IsNlsGlobalization ? 1 : -1;
- // On Windows, all halfwidth characters sort before fullwidth characters.
+ // On NLS, all halfwidth characters sort before fullwidth characters.
// On ICU, half and fullwidth characters that aren't in the "Halfwidth and fullwidth forms" block U+FF00-U+FFEF
// sort before the corresponding characters that are in the block U+FF00-U+FFEF
- private static int s_expectedHalfToFullFormsComparison = PlatformDetection.IsWindows ? -1 : 1;
+ private static int s_expectedHalfToFullFormsComparison = PlatformDetection.IsNlsGlobalization ? -1 : 1;
private static CompareInfo s_invariantCompare = CultureInfo.InvariantCulture.CompareInfo;
private static CompareInfo s_turkishCompare = new CultureInfo("tr-TR").CompareInfo;
{
public class CultureInfoAll
{
- [Fact]
[PlatformSpecific(TestPlatforms.Windows)] // P/Invoke to Win32 function
- public void TestAllCultures()
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
+ public void TestAllCultures_Nls()
{
Assert.True(EnumSystemLocalesEx(EnumLocales, LOCALE_WINDOWS, IntPtr.Zero, IntPtr.Zero), "EnumSystemLocalesEx has failed");
{
public static string EnUSEraName()
{
- return PlatformDetection.IsWindows ? "A.D." : "AD";
+ return PlatformDetection.IsNlsGlobalization ? "A.D." : "AD";
}
public static string EnUSAbbreviatedEraName()
{
- return PlatformDetection.IsWindows ? "AD" : "A";
+ return PlatformDetection.IsNlsGlobalization ? "AD" : "A";
}
public static string JaJPAbbreviatedEraName()
// For Windows<Win7 and others, the default calendar is Gregorian Calendar, AD is expected to be the Era Name
// CLDR has the Japanese abbreviated era name for the Gregorian Calendar in English - "AD",
// so for non-Windows machines it will be "AD".
- return PlatformDetection.IsWindows ? "\u897F\u66A6" : "AD";
+ return PlatformDetection.IsNlsGlobalization ? "\u897F\u66A6" : "AD";
}
public static string[] FrFRDayNames()
Assert.Throws<InvalidOperationException>(() => DateTimeFormatInfo.InvariantInfo.LongTimePattern = "HH:mm:ss");
}
- [Fact]
- [PlatformSpecific(TestPlatforms.AnyUnix)]
- public void LongTimePattern_CheckReadingTimeFormatWithSingleQuotes()
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))]
+ public void LongTimePattern_CheckReadingTimeFormatWithSingleQuotes_ICU()
{
// Usually fr-CA long time format has a single quotes e.g. "HH 'h' mm 'min' ss 's'".
// Ensuring when reading such formats from ICU we'll not eat the spaces after the single quotes.
}
catch
{
- if (PlatformDetection.IsWindows)
+ if (PlatformDetection.IsNlsGlobalization)
{
// Persian calendar is recently supported as one of the optional calendars for fa-IR
Assert.True(calendar is PersianCalendar, "Exception can occur only with PersianCalendar");
}
- else // !PlatformDetection.IsWindows
+ else // !PlatformDetection.IsNlsGlobalization
{
Assert.True(calendar is HijriCalendar || calendar is UmAlQuraCalendar || calendar is ThaiBuddhistCalendar ||
calendar is HebrewCalendar || calendar is KoreanCalendar, "failed to set the calendar on DTFI");
--- /dev/null
+// 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.Reflection;
+using Xunit;
+using Xunit.Sdk;
+
+namespace System.Globalization.Tests
+{
+ public class IcuTests
+ {
+ private static bool IsIcuCompatiblePlatform => PlatformDetection.IsNotWindows ||
+ (!PlatformDetection.IsMonoRuntime &&
+ PlatformDetection.IsWindows10Version1903OrGreater);
+
+ [ConditionalFact(nameof(IsIcuCompatiblePlatform))]
+ public static void IcuShouldBeUsedByDefault()
+ {
+ Type globalizationMode = Type.GetType("System.Globalization.GlobalizationMode");
+ if (globalizationMode != null)
+ {
+ MethodInfo methodInfo = globalizationMode.GetProperty("UseNls", BindingFlags.NonPublic | BindingFlags.Static)?.GetMethod;
+ if (methodInfo != null)
+ {
+ Assert.False((bool)methodInfo.Invoke(null, null));
+ return;
+ }
+ }
+
+ throw new XunitException("Couldn't get System.Globalization.GlobalizationMode.UseIcu property.");
+ }
+
+ [ConditionalFact(nameof(IsIcuCompatiblePlatform))]
+ public static void IcuShouldBeLoaded()
+ {
+ Assert.True(PlatformDetection.IsIcuGlobalization);
+ }
+ }
+}
yield return new object[] { "xn--de-jg4avhby1noc0d", 0, 21, "\u30D1\u30D5\u30A3\u30FC\u0064\u0065\u30EB\u30F3\u30D0" };
}
+ [Fact]
+ public static void IcuShouldNotBeLoaded()
+ {
+ Assert.False(PlatformDetection.IsIcuGlobalization);
+ }
+
[Theory]
[MemberData(nameof(Cultures_TestData))]
public void TestCultureData(string cultureName)
--- /dev/null
+// 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.Reflection;
+using Xunit;
+using Xunit.Sdk;
+
+namespace System.Globalization.Tests
+{
+ public class NlsSwitchTests
+ {
+ [Fact]
+ public static void NlsRuntimeSwitchIsHonored()
+ {
+ Type globalizationMode = Type.GetType("System.Globalization.GlobalizationMode");
+ if (globalizationMode != null)
+ {
+ MethodInfo methodInfo = globalizationMode.GetProperty("UseNls", BindingFlags.NonPublic | BindingFlags.Static)?.GetMethod;
+ if (methodInfo != null)
+ {
+ Assert.True((bool)methodInfo.Invoke(null, null));
+ return;
+ }
+ }
+
+ throw new XunitException("Couldn't get System.Globalization.GlobalizationMode.UseIcu property.");
+ }
+
+ [Fact]
+ public static void IcuShouldNotBeLoaded()
+ {
+ Assert.False(PlatformDetection.IsIcuGlobalization);
+ }
+ }
+}
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <TestRuntime>true</TestRuntime>
+ <IncludeRemoteExecutor>true</IncludeRemoteExecutor>
+ <!-- This test project is Windows only as it forces the use of NLS as the Globlaization platform -->
+ <TargetFrameworks>$(NetCoreAppCurrent)-Windows_NT</TargetFrameworks>
+ <UnicodeUcdVersion>13.0</UnicodeUcdVersion>
+ </PropertyGroup>
+ <ItemGroup>
+ <!-- Include tests from System.Globalization.Tests -->
+ <Compile Include="NlsSwitchTests.cs" />
+ <Compile Include="..\CompareInfo\CompareInfoTests.cs">
+ <Link>CompareInfo\CompareInfoTests.cs</Link>
+ </Compile>
+ <Compile Include="..\CompareInfo\CompareInfoTests.IndexOf.cs">
+ <Link>CompareInfo\CompareInfoTests.IndexOf.cs</Link>
+ </Compile>
+ <Compile Include="..\CompareInfo\CompareInfoTests.IsPrefix.cs">
+ <Link>CompareInfo\CompareInfoTests.IsPrefix.cs</Link>
+ </Compile>
+ <Compile Include="..\CompareInfo\CompareInfoTests.Compare.cs">
+ <Link>CompareInfo\CompareInfoTests.Compare.cs</Link>
+ </Compile>
+ <Compile Include="..\CompareInfo\CompareInfoTests.IsSuffix.cs">
+ <Link>CompareInfo\CompareInfoTests.IsSuffix.cs</Link>
+ </Compile>
+ <Compile Include="..\CompareInfo\CompareInfoTests.LastIndexOf.cs">
+ <Link>CompareInfo\CompareInfoTests.LastIndexOf.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoCurrentInfo.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoCurrentInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoValidateParseStyle.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoValidateParseStyle.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoData.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoData.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoCurrencySymbol.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoCurrencySymbol.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoNaNSymbol.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoNaNSymbol.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoPercentGroupSeparator.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoPercentGroupSeparator.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoPercentDecimalSeparator.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoPercentDecimalSeparator.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoPercentDecimalDigits.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoPercentDecimalDigits.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoPerMilleSymbol.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoPerMilleSymbol.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoPercentSymbol.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoPercentSymbol.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoPositiveSign.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoPositiveSign.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoPositiveInfinitySymbol.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoPositiveInfinitySymbol.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoNegativeSign.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoNegativeSign.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoNegativeInfinitySymbol.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoNegativeInfinitySymbol.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoNumberGroupSeparator.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoNumberGroupSeparator.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoNumberDecimalSeparator.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoNumberDecimalSeparator.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoNumberDecimalDigits.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoNumberDecimalDigits.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoNumberGroupSizes.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoNumberGroupSizes.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoNumberNegativePattern.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoNumberNegativePattern.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoPercentNegativePattern.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoPercentNegativePattern.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoPercentGroupSizes.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoPercentGroupSizes.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoPercentPositivePattern.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoPercentPositivePattern.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoAll.cs">
+ <Link>CultureInfo\CultureInfoAll.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoAsync.cs">
+ <Link>CultureInfo\CultureInfoAsync.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoCalendar.cs">
+ <Link>CultureInfo\CultureInfoCalendar.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoClone.cs">
+ <Link>CultureInfo\CultureInfoClone.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoCompareInfo.cs">
+ <Link>CultureInfo\CultureInfoCompareInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoCtor.cs">
+ <Link>CultureInfo\CultureInfoCtor.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoDateTimeFormat.cs">
+ <Link>CultureInfo\CultureInfoDateTimeFormat.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoEnglishName.cs">
+ <Link>CultureInfo\CultureInfoEnglishName.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoEquals.cs">
+ <Link>CultureInfo\CultureInfoEquals.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoGetFormat.cs">
+ <Link>CultureInfo\CultureInfoGetFormat.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoGetHashCode.cs">
+ <Link>CultureInfo\CultureInfoGetHashCode.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoIsNeutralCulture.cs">
+ <Link>CultureInfo\CultureInfoIsNeutralCulture.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoNativeName.cs">
+ <Link>CultureInfo\CultureInfoNativeName.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoNumberFormat.cs">
+ <Link>CultureInfo\CultureInfoNumberFormat.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoParent.cs">
+ <Link>CultureInfo\CultureInfoParent.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoReadOnly.cs">
+ <Link>CultureInfo\CultureInfoReadOnly.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoTwoLetterISOLanguageName.cs">
+ <Link>CultureInfo\CultureInfoTwoLetterISOLanguageName.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\CultureInfoCurrentCulture.cs">
+ <Link>CultureInfo\CultureInfoCurrentCulture.cs</Link>
+ </Compile>
+ <Compile Include="..\CultureInfo\GetCultureInfo.cs">
+ <Link>CultureInfo\GetCultureInfo.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoAbbreviatedDayNames.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoAbbreviatedDayNames.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoAbbreviatedMonthGenitiveNames.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoAbbreviatedMonthGenitiveNames.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoAbbreviatedMonthNames.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoAbbreviatedMonthNames.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoAMDesignator.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoAMDesignator.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoCalendar.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoCalendar.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoCalendarWeekRule.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoCalendarWeekRule.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoClone.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoClone.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoData.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoData.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoDayNames.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoDayNames.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoFirstDayOfWeek.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoFirstDayOfWeek.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoFullDateTimePattern.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoFullDateTimePattern.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoGetAbbreviatedDayName.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoGetAbbreviatedDayName.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoGetAbbreviatedEraName.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoGetAbbreviatedEraName.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoGetAbbreviatedMonthName.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoGetAbbreviatedMonthName.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoGetDayName.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoGetDayName.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoGetEra.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoGetEra.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoGetEraName.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoGetEraName.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoGetFormat.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoGetFormat.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoGetInstance.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoGetInstance.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoGetMonthName.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoGetMonthName.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoLongDatePattern.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoLongDatePattern.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoLongTimePattern.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoLongTimePattern.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoMonthDayPattern.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoMonthDayPattern.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoMonthGenitiveNames.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoMonthGenitiveNames.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoMonthNames.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoMonthNames.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoPMDesignator.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoPMDesignator.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoReadOnly.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoReadOnly.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoRFC1123Pattern.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoRFC1123Pattern.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoShortDatePattern.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoShortDatePattern.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoShortestDayNames.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoShortestDayNames.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoShortTimePattern.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoShortTimePattern.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoSortableDateTimePattern.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoSortableDateTimePattern.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoTests.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoTests.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoUniversalSortableDateTimePattern.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoUniversalSortableDateTimePattern.cs</Link>
+ </Compile>
+ <Compile Include="..\DateTimeFormatInfo\DateTimeFormatInfoYearMonthPattern.cs">
+ <Link>DateTimeFormatInfo\DateTimeFormatInfoYearMonthPattern.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoClone.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoClone.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoCurrencyDecimalDigits.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoCurrencyDecimalDigits.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoCurrencyDecimalSeparator.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoCurrencyDecimalSeparator.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoCurrencyGroupSeparator.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoCurrencyGroupSeparator.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoCurrencyGroupSizes.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoCurrencyGroupSizes.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoCurrencyNegativePattern.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoCurrencyNegativePattern.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoCurrencyPositivePattern.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoCurrencyPositivePattern.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoGetFormat.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoGetFormat.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoGetInstance.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoGetInstance.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoReadOnly.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoReadOnly.cs</Link>
+ </Compile>
+ <Compile Include="..\NumberFormatInfo\NumberFormatInfoTests.cs">
+ <Link>NumberFormatInfo\NumberFormatInfoTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Globalization\CharUnicodeInfoTestData.cs">
+ <Link>System\Globalization\CharUnicodeInfoTestData.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Globalization\CharUnicodeInfoTests.cs">
+ <Link>System\Globalization\CharUnicodeInfoTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Globalization\CharUnicodeInfoTests.Generated.cs">
+ <Link>System\Globalization\CharUnicodeInfoTests.Generated.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Globalization\CultureNotFoundExceptionTests.cs">
+ <Link>System\Globalization\CultureNotFoundExceptionTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Globalization\GraphemeBreakTest.cs">
+ <Link>System\Globalization\GraphemeBreakTest.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Globalization\RegionInfoTests.cs">
+ <Link>System\Globalization\RegionInfoTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Globalization\StringInfoTests.cs">
+ <Link>System\Globalization\StringInfoTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Globalization\SortVersionTests.cs">
+ <Link>System\Globalization\SortVersionTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Globalization\TextInfoTests.cs">
+ <Link>System\Globalization\TextInfoTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Globalization\TextElementEnumeratorTests.cs">
+ <Link>System\Globalization\TextElementEnumeratorTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Globalization\UnicodeCategoryTests.cs">
+ <Link>System\Globalization\UnicodeCategoryTests.cs</Link>
+ </Compile>
+ <!-- Helpers -->
+ <Compile Include="$(CommonTestPath)System\RandomDataGenerator.cs">
+ <Link>Common\System\RandomDataGenerator.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <PackageReference Include="System.Private.Runtime.UnicodeData" Version="$(SystemPrivateRuntimeUnicodeDataVersion)" ExcludeAssets="contentFiles" GeneratePathProperty="true" />
+ <EmbeddedResource Include="$(PkgSystem_Private_Runtime_UnicodeData)\contentFiles\any\any\$(UnicodeUcdVersion).0\ucd\UnicodeData.txt">
+ <Link>CharUnicodeInfo\UnicodeData.$(UnicodeUcdVersion).txt</Link>
+ <LogicalName>UnicodeData.txt</LogicalName>
+ </EmbeddedResource>
+ <EmbeddedResource Include="$(PkgSystem_Private_Runtime_UnicodeData)\contentFiles\any\any\$(UnicodeUcdVersion).0\ucd\auxiliary\GraphemeBreakTest.txt">
+ <Link>CharUnicodeInfo\GraphemeBreakTest-$(UnicodeUcdVersion).0.txt</Link>
+ <LogicalName>GraphemeBreakTest.txt</LogicalName>
+ </EmbeddedResource>
+ <None Include="runtimeconfig.template.json" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="$(CommonTestPath)CoreFx.Private.TestUtilities.Unicode\CoreFx.Private.TestUtilities.Unicode.csproj" />
+ </ItemGroup>
+</Project>
--- /dev/null
+{
+ "configProperties": {
+ "System.Globalization.UseNls": true
+ }
+}
[Theory]
[MemberData(nameof(CurrencyDecimalDigits_TestData))]
- public void CurrencyDecimalDigits_Get_ReturnsExpected(NumberFormatInfo format, int expectedWindows, int expectedIcu)
+ public void CurrencyDecimalDigits_Get_ReturnsExpected(NumberFormatInfo format, int expectedNls, int expectedIcu)
{
- int expected = PlatformDetection.IsWindows ? expectedWindows : expectedIcu;
+ int expected = PlatformDetection.IsNlsGlobalization ? expectedNls : expectedIcu;
Assert.Equal(expected, format.CurrencyDecimalDigits);
}
switch (localeName)
{
case "en-US":
- return PlatformDetection.IsWindows ? new int[] { 0 } : new int[] { 1, 0 };
+ return PlatformDetection.IsNlsGlobalization ? new int[] { 0 } : new int[] { 1, 0 };
case "en-CA":
- return PlatformDetection.IsWindows ? new int[] { 1 } : new int[] { 1, 0 };
+ return PlatformDetection.IsNlsGlobalization ? new int[] { 1 } : new int[] { 1, 0 };
case "fa-IR":
- if (PlatformDetection.IsWindows)
+ if (PlatformDetection.IsNlsGlobalization)
{
return (PlatformDetection.WindowsVersion < 10) ? new int[] { 3 } : new int[] { 6, 3 };
}
}
case "fr-CD":
- if (PlatformDetection.IsWindows)
+ if (PlatformDetection.IsNlsGlobalization)
{
return (PlatformDetection.WindowsVersion < 10) ? new int[] { 4 } : new int[] { 8 };
}
}
case "as":
- return PlatformDetection.IsWindows ? new int[] { 12 } : new int[] { 9 };
+ return PlatformDetection.IsNlsGlobalization ? new int[] { 12 } : new int[] { 9 };
case "es-BO":
- return (PlatformDetection.IsWindows && PlatformDetection.WindowsVersion < 10) ? new int[] { 14 } : new int[] { 1 };
+ return (PlatformDetection.IsNlsGlobalization && PlatformDetection.WindowsVersion < 10) ? new int[] { 14 } : new int[] { 1 };
case "fr-CA":
- return PlatformDetection.IsWindows ? new int[] { 15 } : new int[] { 8, 15 };
+ return PlatformDetection.IsNlsGlobalization ? new int[] { 15 } : new int[] { 8, 15 };
}
throw DateTimeFormatInfoData.GetCultureNotSupportedException(CultureInfo.GetCultureInfo(localeName));
[Theory]
[MemberData(nameof(NumberDecimalDigits_TestData))]
- public void NumberDecimalDigits_Get_ReturnsExpected(NumberFormatInfo format, int expectedWindows, int expectedIcu)
+ public void NumberDecimalDigits_Get_ReturnsExpected(NumberFormatInfo format, int expectedNls, int expectedIcu)
{
- int expected = PlatformDetection.IsWindows ? expectedWindows : expectedIcu;
+ int expected = PlatformDetection.IsNlsGlobalization ? expectedNls : expectedIcu;
Assert.Equal(expected, format.NumberDecimalDigits);
}
}
/// <summary>
- /// Not testing for Windows as the culture data can change
+ /// Not testing for NLS as the culture data can change
/// https://blogs.msdn.microsoft.com/shawnste/2005/04/05/culture-data-shouldnt-be-considered-stable-except-for-invariant/
/// In the CultureInfoAll test class we are testing the expected behavior
- /// for Windows by enumerating all locales on the system and then test them.
+ /// for NLS by enumerating all locales on the system and then test them.
/// </summary>
- [Theory]
- [PlatformSpecific(TestPlatforms.AnyUnix)]
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))]
[MemberData(nameof(PercentNegativePattern_TestData))]
- public void PercentNegativePattern_Get_ReturnsExpected(NumberFormatInfo format, int expected)
+ public void PercentNegativePattern_Get_ReturnsExpected_ICU(NumberFormatInfo format, int expected)
{
Assert.Equal(expected, format.PercentNegativePattern);
}
}
/// <summary>
- /// Not testing for Windows as the culture data can change
+ /// Not testing for NLS as the culture data can change
/// https://blogs.msdn.microsoft.com/shawnste/2005/04/05/culture-data-shouldnt-be-considered-stable-except-for-invariant/
/// In the CultureInfoAll test class we are testing the expected behavior
- /// for Windows by enumerating all locales on the system and then test them.
+ /// for NLS by enumerating all locales on the system and then test them.
/// </summary>
- [Theory]
- [PlatformSpecific(TestPlatforms.AnyUnix)]
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))]
[MemberData(nameof(PercentPositivePattern_TestData))]
- public void PercentPositivePattern_Get_ReturnsExpected(NumberFormatInfo format, int expected)
+ public void PercentPositivePattern_Get_ReturnsExpected_ICU(NumberFormatInfo format, int expected)
{
Assert.Equal(expected, format.PercentPositivePattern);
}
-<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<TestRuntime>true</TestRuntime>
<UnicodeUcdVersion>13.0</UnicodeUcdVersion>
</PropertyGroup>
<ItemGroup>
+ <Compile Include="IcuTests.cs" />
<Compile Include="CompareInfo\CompareInfoTests.cs" />
<Compile Include="CompareInfo\CompareInfoTests.IndexOf.cs" />
<Compile Include="CompareInfo\CompareInfoTests.IsPrefix.cs" />
AssertExtensions.Throws<ArgumentException>("name", () => new RegionInfo(name));
}
- [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNotWindows))]
- public void CurrentRegion()
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsIcuGlobalization))]
+ public void CurrentRegion_Icu()
{
using (new ThreadCultureChange("en-US"))
{
}
}
- [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows))]
- public void TestCurrentRegion()
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
+ public void TestCurrentRegion_Nls()
{
RemoteExecutor.Invoke(() =>
{
public static IEnumerable<object[]> RegionInfo_TestData()
{
yield return new object[] { 0x409, 244, "US Dollar", "US Dollar", "\u0055\u0053\u0020\u0044\u006f\u006c\u006c\u0061\u0072", "USA", "USA" };
- yield return new object[] { 0x411, 122, "Japanese Yen", "Japanese Yen", PlatformDetection.IsWindows ? "\u5186" : "\u65e5\u672c\u5186", "JPN", "JPN" };
+ yield return new object[] { 0x411, 122, "Japanese Yen", "Japanese Yen", PlatformDetection.IsNlsGlobalization ? "\u5186" : "\u65e5\u672c\u5186", "JPN", "JPN" };
yield return new object[] { 0x804, 45, "Chinese Yuan", "PRC Yuan Renminbi", "\u4eba\u6c11\u5e01", "CHN", "CHN" };
- yield return new object[] { 0x401, 205, "Saudi Riyal", "Saudi Riyal", PlatformDetection.IsWindows ?
+ yield return new object[] { 0x401, 205, "Saudi Riyal", "Saudi Riyal", PlatformDetection.IsNlsGlobalization ?
"\u0631\u064a\u0627\u0644\u00a0\u0633\u0639\u0648\u062f\u064a" :
"\u0631\u064a\u0627\u0644\u0020\u0633\u0639\u0648\u062f\u064a",
"SAU", "SAU" };
- yield return new object[] { 0x412, 134, "South Korean Won", "Korean Won", PlatformDetection.IsWindows ? "\uc6d0" : "\ub300\ud55c\ubbfc\uad6d\u0020\uc6d0", "KOR", "KOR" };
+ yield return new object[] { 0x412, 134, "South Korean Won", "Korean Won", PlatformDetection.IsNlsGlobalization ? "\uc6d0" : "\ub300\ud55c\ubbfc\uad6d\u0020\uc6d0", "KOR", "KOR" };
yield return new object[] { 0x40d, 117, "Israeli New Shekel", "Israeli New Sheqel",
- PlatformDetection.IsWindows || PlatformDetection.ICUVersion.Major >= 58 ? "\u05e9\u05e7\u05dc\u0020\u05d7\u05d3\u05e9" : "\u05e9\u05f4\u05d7", "ISR", "ISR" };
+ PlatformDetection.IsNlsGlobalization || PlatformDetection.ICUVersion.Major >= 58 ? "\u05e9\u05e7\u05dc\u0020\u05d7\u05d3\u05e9" : "\u05e9\u05f4\u05d7", "ISR", "ISR" };
}
[Theory]
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Calendar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarAlgorithmType.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Icu.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Nls.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarWeekRule.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendricalCalculationsHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CharUnicodeInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CharUnicodeInfoData.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\ChineseLunisolarCalendar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Icu.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Invariant.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Nls.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareOptions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Icu.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Nls.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureInfo.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureInfo.Icu.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureInfo.Nls.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureNotFoundException.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureTypes.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\DateTimeFormat.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HebrewCalendar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HebrewNumber.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IcuLocaleData.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IdnMapping.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IdnMapping.Icu.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IdnMapping.Nls.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\InternalGlobalizationHelper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\ISOWeek.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Icu.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Nls.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseLunisolarCalendar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JulianCalendar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\KoreanCalendar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\KoreanLunisolarCalendar.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.Icu.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.Nls.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\NumberFormatInfo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\NumberStyles.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\PersianCalendar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TaiwanLunisolarCalendar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextElementEnumerator.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.Icu.cs" />
+ <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.Nls.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\ThaiBuddhistCalendar.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TimeSpanFormat.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TimeSpanParse.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Void.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\WeakReference.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\WeakReference.T.cs" />
+ <Compile Include="$(CommonPath)Interop\Interop.Libraries.cs">
+ <Link>Common\Interop\Interop.Libraries.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\Interop.Calendar.cs">
+ <Link>Common\Interop\Interop.Calendar.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\Interop.Casing.cs">
+ <Link>Common\Interop\Interop.Casing.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\Interop.Collation.cs">
+ <Link>Common\Interop\Interop.Collation.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\Interop.ICU.cs">
+ <Link>Common\Interop\Interop.ICU.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\Interop.Idna.cs">
+ <Link>Common\Interop\Interop.Idna.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\Interop.Locale.cs">
+ <Link>Common\Interop\Interop.Locale.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\Interop.Normalization.cs">
+ <Link>Common\Interop\Interop.Normalization.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\Interop.ResultCode.cs">
+ <Link>Common\Interop\Interop.ResultCode.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\Interop.TimeZoneInfo.cs">
+ <Link>Common\Interop\Interop.TimeZoneInfo.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\Interop.Utils.cs">
+ <Link>Common\Interop\Interop.Utils.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\Windows\Interop.Errors.cs">
+ <Link>Common\Interop\Interop.Errors.cs</Link>
+ </Compile>
+ <!-- The CLR internally uses a BOOL type analogous to the Windows BOOL type on Unix -->
+ <Compile Include="$(CommonPath)Interop\Windows\Interop.BOOL.cs">
+ <Link>Common\Interop\Windows\Interop.BOOL.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.Globalization.cs">
+ <Link>Common\Interop\Windows\Kernel32\Interop.Globalization.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.ResolveLocaleName.cs">
+ <Link>Common\Interop\Windows\Kernel32\Interop.ResolveLocaleName.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\Windows\Normaliz\Interop.Idna.cs">
+ <Link>Common\Interop\Windows\Normaliz\Interop.Idna.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonPath)Interop\Windows\Normaliz\Interop.Normalization.cs">
+ <Link>Common\Interop\Windows\Normaliz\Interop.Normalization.cs</Link>
+ </Compile>
<Compile Include="$(CommonPath)System\HResults.cs">
<Link>Common\System\HResults.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\Crypt32\Interop.CryptProtectMemory.cs">
<Link>Common\Interop\Windows\Crypt32\Interop.CryptProtectMemory.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)Interop\Windows\Interop.BOOL.cs">
- <Link>Common\Interop\Windows\Interop.BOOL.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)Interop\Windows\Interop.BOOLEAN.cs">
<Link>Common\Interop\Windows\Interop.BOOLEAN.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GetTempPathW.cs">
<Link>Common\Interop\Windows\Kernel32\Interop.GetTempPathW.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.Globalization.cs">
- <Link>Common\Interop\Windows\Kernel32\Interop.Globalization.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.GlobalMemoryStatusEx.cs">
<Link>Common\Interop\Windows\Kernel32\Interop.GlobalMemoryStatusEx.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.ReadFile_SafeHandle_NativeOverlapped.cs">
<Link>Common\Interop\Windows\Kernel32\Interop.ReadFile_SafeHandle_NativeOverlapped.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.ResolveLocaleName.cs">
- <Link>Common\Interop\Windows\Kernel32\Interop.ResolveLocaleName.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.SECURITY_ATTRIBUTES.cs">
<Link>Common\Interop\Windows\Kernel32\Interop.SECURITY_ATTRIBUTES.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs">
<Link>Common\Interop\Windows\Kernel32\Interop.WriteFile_SafeHandle_NativeOverlapped.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)Interop\Windows\Normaliz\Interop.Idna.cs">
- <Link>Common\Interop\Windows\Normaliz\Interop.Idna.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)Interop\Windows\Normaliz\Interop.Normalization.cs">
- <Link>Common\Interop\Windows\Normaliz\Interop.Normalization.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)Interop\Windows\NtDll\Interop.NtQueryInformationFile.cs">
<Link>Common\Interop\Windows\NtDll\Interop.NtQueryInformationFile.cs</Link>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\DebugProvider.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Stopwatch.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Diagnostics\Tracing\RuntimeEventSourceHelper.Windows.cs" Condition="'$(FeaturePerfTracing)' == 'true'" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Windows.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureInfo.Windows.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Windows.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Win32.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IdnMapping.Windows.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Win32.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.Windows.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Guid.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\DriveInfoInternal.Windows.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.Windows.cs" />
<!-- CoreCLR uses PAL layer that emulates Windows API on Unix. This is bridge for that PAL layer. See issue dotnet/runtime/#31721. -->
<ItemGroup Condition="'$(TargetsWindows)' == 'true' or '$(FeatureCoreCLR)'=='true'">
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeWaitHandle.Windows.cs" />
- <Compile Include="$(CommonPath)Interop\Windows\Interop.Errors.cs" />
<Compile Include="$(CommonPath)Interop\Windows\OleAut32\Interop.SysAllocStringLen.cs">
<Link>Common\Interop\Windows\OleAut32\Interop.SysAllocStringLen.cs</Link>
</Compile>
<Compile Include="$(CommonPath)Interop\Unix\Interop.Libraries.cs">
<Link>Common\Interop\Unix\Interop.Libraries.cs</Link>
</Compile>
- <Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.Calendar.cs">
- <Link>Common\Interop\Unix\System.Globalization.Native\Interop.Calendar.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.Casing.cs">
- <Link>Common\Interop\Unix\System.Globalization.Native\Interop.Casing.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.Collation.cs">
- <Link>Common\Interop\Unix\System.Globalization.Native\Interop.Collation.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.ICU.cs">
- <Link>Common\Interop\Unix\System.Globalization.Native\Interop.ICU.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.Idna.cs">
- <Link>Common\Interop\Unix\System.Globalization.Native\Interop.Idna.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.Locale.cs">
- <Link>Common\Interop\Unix\System.Globalization.Native\Interop.Locale.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.Normalization.cs">
- <Link>Common\Interop\Unix\System.Globalization.Native\Interop.Normalization.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.ResultCode.cs">
- <Link>Common\Interop\Unix\System.Globalization.Native\Interop.ResultCode.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.TimeZoneInfo.cs">
- <Link>Common\Interop\Unix\System.Globalization.Native\Interop.TimeZoneInfo.cs</Link>
- </Compile>
- <Compile Include="$(CommonPath)Interop\Unix\System.Globalization.Native\Interop.Utils.cs">
- <Link>Common\Interop\Unix\System.Globalization.Native\Interop.Utils.cs</Link>
- </Compile>
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.Access.cs">
<Link>Common\Interop\Unix\System.Native\Interop.Access.cs</Link>
</Compile>
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.NoRegistry.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Environment.Unix.GetFolderPathCore.cs" Condition="'$(TargetsiOS)' != 'true' and '$(TargetstvOS)' != 'true'" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CalendarData.Unix.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CompareInfo.Unix.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureData.Unix.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\CultureInfo.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Globalization\HijriCalendar.Unix.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\IdnMapping.Unix.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\JapaneseCalendar.Unix.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\LocaleData.Unix.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\Normalization.Unix.cs" />
- <Compile Include="$(MSBuildThisFileDirectory)System\Globalization\TextInfo.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Guid.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\DriveInfoInternal.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\IO\FileStream.OSX.cs" Condition="'$(TargetsOSX)' == 'true' or '$(TargetsiOS)' == 'true' or '$(TargetstvOS)' == 'true'" />
internal static int GetSystemTwoDigitYearSetting(CalendarId CalID, int defaultYearValue)
{
- int twoDigitYearMax = CalendarData.GetTwoDigitYearMax(CalID);
+ int twoDigitYearMax = GlobalizationMode.UseNls ? CalendarData.NlsGetTwoDigitYearMax(CalID) : CalendarData.IcuGetTwoDigitYearMax(CalID);
return twoDigitYearMax >= 0 ? twoDigitYearMax : defaultYearValue;
}
}
internal partial class CalendarData
{
- private bool LoadCalendarDataFromSystem(string localeName, CalendarId calendarId)
+ private bool IcuLoadCalendarDataFromSystem(string localeName, CalendarId calendarId)
{
+ Debug.Assert(!GlobalizationMode.UseNls);
+
bool result = true;
// these can return null but are later replaced with String.Empty or other non-nullable value
return result;
}
- internal static int GetTwoDigitYearMax(CalendarId calendarId)
+ internal static int IcuGetTwoDigitYearMax(CalendarId calendarId)
{
+ Debug.Assert(!GlobalizationMode.UseNls);
+
// There is no user override for this value on Linux or in ICU.
// So just return -1 to use the hard-coded defaults.
return -1;
}
// Call native side to figure out which calendars are allowed
- internal static int GetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars)
+ internal static int IcuGetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
// NOTE: there are no 'user overrides' on Linux
int count = Interop.Globalization.GetCalendars(localeName, calendars, calendars.Length);
return count;
}
- private static bool SystemSupportsTaiwaneseCalendar()
+ private static bool IcuSystemSupportsTaiwaneseCalendar()
{
+ Debug.Assert(!GlobalizationMode.UseNls);
return true;
}
{
datePatterns = null;
- EnumCalendarsData callbackContext = default;
+ IcuEnumCalendarsData callbackContext = default;
callbackContext.Results = new List<string>();
callbackContext.DisallowDuplicates = true;
bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext);
{
monthNames = null;
- EnumCalendarsData callbackContext = default;
+ IcuEnumCalendarsData callbackContext = default;
callbackContext.Results = new List<string>();
bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext);
if (result)
{
calendarData = null;
- EnumCalendarsData callbackContext = default;
+ IcuEnumCalendarsData callbackContext = default;
callbackContext.Results = new List<string>();
bool result = EnumCalendarInfo(localeName, calendarId, dataType, ref callbackContext);
if (result)
return result;
}
- private static unsafe bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, ref EnumCalendarsData callbackContext)
+ private static unsafe bool EnumCalendarInfo(string localeName, CalendarId calendarId, CalendarDataType dataType, ref IcuEnumCalendarsData callbackContext)
{
return Interop.Globalization.EnumCalendarInfo(EnumCalendarInfoCallback, localeName, calendarId, dataType, (IntPtr)Unsafe.AsPointer(ref callbackContext));
}
{
try
{
- ref EnumCalendarsData callbackContext = ref Unsafe.As<byte, EnumCalendarsData>(ref *(byte*)context);
+ ref IcuEnumCalendarsData callbackContext = ref Unsafe.As<byte, IcuEnumCalendarsData>(ref *(byte*)context);
if (callbackContext.DisallowDuplicates)
{
}
}
- private struct EnumCalendarsData
+ private struct IcuEnumCalendarsData
{
public List<string> Results;
public bool DisallowDuplicates;
{
internal partial class CalendarData
{
- private bool LoadCalendarDataFromSystem(string localeName, CalendarId calendarId)
+ private bool NlsLoadCalendarDataFromSystem(string localeName, CalendarId calendarId)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
bool ret = true;
}
// Get native two digit year max
- internal static int GetTwoDigitYearMax(CalendarId calendarId) =>
- GlobalizationMode.Invariant ? Invariant.iTwoDigitYearMax :
- CallGetCalendarInfoEx(null, calendarId, CAL_ITWODIGITYEARMAX, out int twoDigitYearMax) ? twoDigitYearMax :
- -1;
+ internal static int NlsGetTwoDigitYearMax(CalendarId calendarId)
+ {
+ Debug.Assert(GlobalizationMode.UseNls);
+
+ return GlobalizationMode.Invariant ? Invariant.iTwoDigitYearMax :
+ CallGetCalendarInfoEx(null, calendarId, CAL_ITWODIGITYEARMAX, out int twoDigitYearMax) ?
+ twoDigitYearMax :
+ -1;
+ }
// Call native side to figure out which calendars are allowed
- internal static int GetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars)
+ internal static int NlsGetCalendars(string localeName, bool useUserOverride, CalendarId[] calendars)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
- EnumCalendarsData data = default;
+ NlsEnumCalendarsData data = default;
data.userOverride = 0;
data.calendars = new List<int>();
return data.calendars.Count;
}
- private static bool SystemSupportsTaiwaneseCalendar()
+ private static bool NlsSystemSupportsTaiwaneseCalendar()
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
// Taiwanese calendar get listed as one of the optional zh-TW calendars only when having zh-TW UI
return CallGetCalendarInfoEx("zh-TW", CalendarId.TAIWAN, CAL_SCALNAME, out string _);
// Taiwan calendar data is not always in all language version of OS due to Geopolical reasons.
// It is only available in zh-TW localized versions of Windows.
// Let's check if OS supports it. If not, fallback to Greogrian localized for Taiwan calendar.
- if (!SystemSupportsTaiwaneseCalendar())
+ if (!NlsSystemSupportsTaiwaneseCalendar())
{
calendar = CalendarId.GREGORIAN;
}
//
// struct to help our calendar data enumaration callback
//
- private struct EnumCalendarsData
+ public struct NlsEnumCalendarsData
{
public int userOverride; // user override value (if found)
public List<int> calendars; // list of calendars found so far
// [NativeCallable(CallingConvention = CallingConvention.StdCall)]
private static unsafe Interop.BOOL EnumCalendarsCallback(char* lpCalendarInfoString, uint calendar, IntPtr reserved, void* lParam)
{
- ref EnumCalendarsData context = ref Unsafe.As<byte, EnumCalendarsData>(ref *(byte*)lParam);
+ ref NlsEnumCalendarsData context = ref Unsafe.As<byte, NlsEnumCalendarsData>(ref *(byte*)lParam);
try
{
// If we had a user override, check to make sure this differs
Debug.Assert(!GlobalizationMode.Invariant);
- if (!LoadCalendarDataFromSystem(localeName, calendarId))
+ bool loadedCalendarData = GlobalizationMode.UseNls ?
+ NlsLoadCalendarDataFromSystem(localeName, calendarId) :
+ IcuLoadCalendarDataFromSystem(localeName, calendarId);
+
+ if (!loadedCalendarData)
{
// LoadCalendarDataFromSystem sometimes can fail on Linux if the installed ICU package is missing some resources.
// The ICU package can miss some resources in some cases like if someone compile and build the ICU package manually or ICU has a regression.
return "en-US";
}
+
+ private bool SystemSupportsTaiwaneseCalendar() => GlobalizationMode.UseNls ?
+ NlsSystemSupportsTaiwaneseCalendar() :
+ IcuSystemSupportsTaiwaneseCalendar();
}
}
public partial class CompareInfo
{
[NonSerialized]
- private IntPtr _sortHandle;
-
- [NonSerialized]
private bool _isAsciiEqualityOrdinal;
- private void InitSort(CultureInfo culture)
+ private void IcuInitSortHandle()
{
- _sortName = culture.SortName;
-
if (GlobalizationMode.Invariant)
{
_isAsciiEqualityOrdinal = true;
}
else
{
+ Debug.Assert(!GlobalizationMode.UseNls);
+
// Inline the following condition to avoid potential implementation cycles within globalization
//
// _isAsciiEqualityOrdinal = _sortName == "" || _sortName == "en" || _sortName.StartsWith("en-", StringComparison.Ordinal);
}
}
- internal static unsafe int IndexOfOrdinalCore(ReadOnlySpan<char> source, ReadOnlySpan<char> value, bool ignoreCase, bool fromBeginning)
+ private static unsafe int IcuIndexOfOrdinalCore(ReadOnlySpan<char> source, ReadOnlySpan<char> value, bool ignoreCase, bool fromBeginning)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert(!value.IsEmpty);
// Ordinal (non-linguistic) comparisons require the length of the target string to be no greater
return -1;
}
- internal static unsafe int LastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase)
+ private static unsafe int IcuLastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert(source != null);
Debug.Assert(value != null);
return -1;
}
- private static unsafe int CompareStringOrdinalIgnoreCase(ref char string1, int count1, ref char string2, int count2)
+ private static unsafe int IcuCompareStringOrdinalIgnoreCase(ref char string1, int count1, ref char string2, int count2)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert(count1 > 0);
Debug.Assert(count2 > 0);
// TODO https://github.com/dotnet/runtime/issues/8890:
// This method shouldn't be necessary, as we should be able to just use the overload
// that takes two spans. But due to this issue, that's adding significant overhead.
- private unsafe int CompareString(ReadOnlySpan<char> string1, string string2, CompareOptions options)
+ private unsafe int IcuCompareString(ReadOnlySpan<char> string1, string string2, CompareOptions options)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert(string2 != null);
Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
}
}
- private unsafe int CompareString(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2, CompareOptions options)
+ private unsafe int IcuCompareString(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2, CompareOptions options)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
// Unlike NLS, ICU (ucol_getSortKey) allows passing nullptr for either of the source arguments
}
}
- internal unsafe int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options, int* matchLengthPtr)
+ private unsafe int IcuIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options, int* matchLengthPtr)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert(!string.IsNullOrEmpty(source));
Debug.Assert(target != null);
return index != -1 ? index + startIndex : -1;
}
- // For now, this method is only called from Span APIs with either options == CompareOptions.None or CompareOptions.IgnoreCase
- internal unsafe int IndexOfCore(ReadOnlySpan<char> source, ReadOnlySpan<char> target, CompareOptions options, int* matchLengthPtr, bool fromBeginning)
+ private unsafe int IcuIndexOfCore(ReadOnlySpan<char> source, ReadOnlySpan<char> target, CompareOptions options, int* matchLengthPtr, bool fromBeginning)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert(source.Length != 0);
Debug.Assert(target.Length != 0);
}
}
- private unsafe int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options)
+ private unsafe int IcuLastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert(!string.IsNullOrEmpty(source));
Debug.Assert(target != null);
if (options == CompareOptions.Ordinal)
{
- return LastIndexOfOrdinalCore(source, target, startIndex, count, ignoreCase: false);
+ return IcuLastIndexOfOrdinalCore(source, target, startIndex, count, ignoreCase: false);
}
// startIndex is the index into source where we start search backwards from. leftStartIndex is the index into source
return lastIndex != -1 ? lastIndex + leftStartIndex : -1;
}
- private unsafe bool StartsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options)
+ private unsafe bool IcuStartsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options)
{
Debug.Assert(!GlobalizationMode.Invariant);
}
}
- private unsafe bool EndsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options)
+ private unsafe bool IcuEndsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert(!suffix.IsEmpty);
Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
}
}
- private unsafe SortKey CreateSortKey(string source, CompareOptions options)
+ private unsafe SortKey IcuCreateSortKey(string source, CompareOptions options)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
if (source==null) { throw new ArgumentNullException(nameof(source)); }
return new SortKey(this, source, options, keyData);
}
- private static unsafe bool IsSortable(char *text, int length)
+ private static unsafe bool IcuIsSortable(char *text, int length)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
int index = 0;
UnicodeCategory uc;
// ---- PAL layer ends here ----
// -----------------------------
- internal unsafe int GetHashCodeOfStringCore(ReadOnlySpan<char> source, CompareOptions options)
+ private unsafe int IcuGetHashCodeOfString(ReadOnlySpan<char> source, CompareOptions options)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
// according to ICU User Guide the performance of ucol_getSortKey is worse when it is called with null output buffer
return (options & CompareOptions.IgnoreSymbols) == 0;
}
- private SortVersion GetSortVersion()
+ private SortVersion IcuGetSortVersion()
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
int sortVersion = Interop.Globalization.GetSortVersion(_sortHandle);
return new SortVersion(sortVersion, LCID, new Guid(sortVersion, 0, 0, 0, 0, 0, 0,
{
public partial class CompareInfo
{
- internal static unsafe IntPtr GetSortHandle(string cultureName)
+ private void NlsInitSortHandle()
+ {
+ Debug.Assert(GlobalizationMode.UseNls);
+ _sortHandle = NlsGetSortHandle(_sortName);
+ }
+
+ internal static unsafe IntPtr NlsGetSortHandle(string cultureName)
{
if (GlobalizationMode.Invariant)
{
return IntPtr.Zero;
}
- private void InitSort(CultureInfo culture)
- {
- _sortName = culture.SortName;
- _sortHandle = GetSortHandle(_sortName);
- }
-
private static unsafe int FindStringOrdinal(
uint dwFindStringOrdinalFlags,
ReadOnlySpan<char> source,
}
}
- internal static int IndexOfOrdinalCore(ReadOnlySpan<char> source, ReadOnlySpan<char> value, bool ignoreCase, bool fromBeginning)
+ private static int NlsIndexOfOrdinalCore(ReadOnlySpan<char> source, ReadOnlySpan<char> value, bool ignoreCase, bool fromBeginning)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(source.Length != 0);
Debug.Assert(value.Length != 0);
return FindStringOrdinal(positionFlag, source, value, ignoreCase);
}
- internal static int LastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase)
+ private static int NlsLastIndexOfOrdinalCore(string source, string value, int startIndex, int count, bool ignoreCase)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(source != null);
Debug.Assert(value != null);
return result;
}
- private unsafe int GetHashCodeOfStringCore(ReadOnlySpan<char> source, CompareOptions options)
+ private unsafe int NlsGetHashCodeOfString(ReadOnlySpan<char> source, CompareOptions options)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
// LCMapStringEx doesn't support passing cchSrc = 0, so if given a null or empty input
}
}
- private static unsafe int CompareStringOrdinalIgnoreCase(ref char string1, int count1, ref char string2, int count2)
+ private static unsafe int NlsCompareStringOrdinalIgnoreCase(ref char string1, int count1, ref char string2, int count2)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(count1 > 0);
Debug.Assert(count2 > 0);
// TODO https://github.com/dotnet/runtime/issues/8890:
// This method shouldn't be necessary, as we should be able to just use the overload
// that takes two spans. But due to this issue, that's adding significant overhead.
- private unsafe int CompareString(ReadOnlySpan<char> string1, string string2, CompareOptions options)
+ private unsafe int NlsCompareString(ReadOnlySpan<char> string1, string string2, CompareOptions options)
{
Debug.Assert(string2 != null);
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
string? localeName = _sortHandle != IntPtr.Zero ? null : _sortName;
}
}
- private unsafe int CompareString(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2, CompareOptions options)
+ private unsafe int NlsCompareString(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2, CompareOptions options)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
string? localeName = _sortHandle != IntPtr.Zero ? null : _sortName;
}
}
- internal unsafe int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options, int* matchLengthPtr)
+ private unsafe int NlsIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options, int* matchLengthPtr)
{
Debug.Assert(!GlobalizationMode.Invariant);
return -1;
}
- internal unsafe int IndexOfCore(ReadOnlySpan<char> source, ReadOnlySpan<char> target, CompareOptions options, int* matchLengthPtr, bool fromBeginning)
+ private unsafe int NlsIndexOfCore(ReadOnlySpan<char> source, ReadOnlySpan<char> target, CompareOptions options, int* matchLengthPtr, bool fromBeginning)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(target.Length != 0);
Debug.Assert(options == CompareOptions.None || options == CompareOptions.IgnoreCase);
return FindString(positionFlag | (uint)GetNativeCompareFlags(options), source, target, matchLengthPtr);
}
- private unsafe int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options)
+ private unsafe int NlsLastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(!string.IsNullOrEmpty(source));
Debug.Assert(target != null);
return -1;
}
- private unsafe bool StartsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options)
+ private unsafe bool NlsStartsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options)
{
Debug.Assert(!GlobalizationMode.Invariant);
return FindString(FIND_STARTSWITH | (uint)GetNativeCompareFlags(options), source, prefix, null) >= 0;
}
- private unsafe bool EndsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options)
+ private unsafe bool NlsEndsWith(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(!suffix.IsEmpty);
Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
return FindString(FIND_ENDSWITH | (uint)GetNativeCompareFlags(options), source, suffix, null) >= 0;
}
- // PAL ends here
- [NonSerialized]
- private IntPtr _sortHandle;
-
private const uint LCMAP_SORTKEY = 0x00000400;
private const int FIND_STARTSWITH = 0x00100000;
return retValue;
}
- private unsafe SortKey CreateSortKey(string source, CompareOptions options)
+ private unsafe SortKey NlsCreateSortKey(string source, CompareOptions options)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
if (source == null) { throw new ArgumentNullException(nameof(source)); }
return new SortKey(this, source, options, keyData);
}
- private static unsafe bool IsSortable(char* text, int length)
+ private static unsafe bool NlsIsSortable(char* text, int length)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(text != null);
return Interop.Kernel32.IsNLSDefinedString(Interop.Kernel32.COMPARE_STRING, 0, IntPtr.Zero, text, length);
return nativeCompareFlags;
}
- private unsafe SortVersion GetSortVersion()
+ private unsafe SortVersion NlsGetSortVersion()
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Interop.Kernel32.NlsVersionInfoEx nlsVersion = default;
nlsVersion.dwNLSVersionInfoSize = sizeof(Interop.Kernel32.NlsVersionInfoEx);
private string m_name; // The name used to construct this CompareInfo. Do not rename (binary serialization)
[NonSerialized]
+ private IntPtr _sortHandle;
+
+ [NonSerialized]
private string _sortName = null!; // The name that defines our behavior
[OptionalField(VersionAdded = 3)]
}
char* pChar = &ch;
- return IsSortable(pChar, 1);
+ return IsSortableCore(pChar, 1);
}
public static unsafe bool IsSortable(string text)
fixed (char* pChar = text)
{
- return IsSortable(pChar, text.Length);
+ return IsSortableCore(pChar, text.Length);
+ }
+ }
+
+ private static unsafe bool IsSortableCore(char* pChar, int length) =>
+ GlobalizationMode.UseNls ?
+ NlsIsSortable(pChar, length) :
+ IcuIsSortable(pChar, length);
+
+ private void InitSort(CultureInfo culture)
+ {
+ _sortName = culture.SortName;
+
+ if (GlobalizationMode.UseNls)
+ {
+ NlsInitSortHandle();
+ }
+ else
+ {
+ IcuInitSortHandle();
}
}
return string.CompareOrdinal(string1, string2);
}
- return CompareString(string1.AsSpan(), string2.AsSpan(), options);
+ return CompareStringCore(string1.AsSpan(), string2.AsSpan(), options);
}
// TODO https://github.com/dotnet/runtime/issues/8890:
string.CompareOrdinal(string1, string2.AsSpan());
}
- return CompareString(string1, string2, options);
+ return CompareStringCore(string1, string2, options);
}
internal int CompareOptionNone(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2)
return GlobalizationMode.Invariant ?
string.CompareOrdinal(string1, string2) :
- CompareString(string1, string2, CompareOptions.None);
+ CompareStringCore(string1, string2, CompareOptions.None);
}
internal int CompareOptionIgnoreCase(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2)
return GlobalizationMode.Invariant ?
CompareOrdinalIgnoreCase(string1, string2) :
- CompareString(string1, string2, CompareOptions.IgnoreCase);
+ CompareStringCore(string1, string2, CompareOptions.IgnoreCase);
}
/// <summary>
return string.CompareOrdinal(span1, span2);
}
- return CompareString(span1, span2, options);
+ return CompareStringCore(span1, span2, options);
}
+ // TODO https://github.com/dotnet/runtime/issues/8890:
+ // This method shouldn't be necessary, as we should be able to just use the overload
+ // that takes two spans. But due to this issue, that's adding significant overhead.
+ private unsafe int CompareStringCore(ReadOnlySpan<char> string1, string string2, CompareOptions options) =>
+ GlobalizationMode.UseNls ?
+ NlsCompareString(string1, string2, options) :
+ IcuCompareString(string1, string2, options);
+
+ private unsafe int CompareStringCore(ReadOnlySpan<char> string1, ReadOnlySpan<char> string2, CompareOptions options) =>
+ GlobalizationMode.UseNls ?
+ NlsCompareString(string1, string2, options) :
+ IcuCompareString(string1, string2, options);
+
/// <summary>
/// CompareOrdinalIgnoreCase compare two string ordinally with ignoring the case.
/// it assumes the strings are Ascii string till we hit non Ascii character in strA or strB and then we continue the comparison by
range -= length;
- return CompareStringOrdinalIgnoreCase(ref charA, lengthA - range, ref charB, lengthB - range);
+ return CompareStringOrdinalIgnoreCaseCore(ref charA, lengthA - range, ref charB, lengthB - range);
}
internal static bool EqualsOrdinalIgnoreCase(ref char charA, ref char charB, int length)
{
if (!GlobalizationMode.Invariant)
{
- return CompareStringOrdinalIgnoreCase(ref charA, length, ref charB, length) == 0;
+ return CompareStringOrdinalIgnoreCaseCore(ref charA, length, ref charB, length) == 0;
}
else
{
}
}
+ private static unsafe int CompareStringOrdinalIgnoreCaseCore(ref char string1, int count1, ref char string2, int count2) =>
+ GlobalizationMode.UseNls ?
+ NlsCompareStringOrdinalIgnoreCase(ref string1, count1, ref string2, count2) :
+ IcuCompareStringOrdinalIgnoreCase(ref string1, count1, ref string2, count2);
+
/// <summary>
/// Determines whether prefix is a prefix of string. If prefix equals
/// string.Empty, true is returned.
return source.StartsWith(prefix, (options & CompareOptions.IgnoreCase) != 0 ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
}
- return StartsWith(source, prefix, options);
+ return StartsWithCore(source, prefix, options);
}
internal bool IsPrefix(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options)
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
- return StartsWith(source, prefix, options);
+ return StartsWithCore(source, prefix, options);
}
+ private unsafe bool StartsWithCore(ReadOnlySpan<char> source, ReadOnlySpan<char> prefix, CompareOptions options) =>
+ GlobalizationMode.UseNls ?
+ NlsStartsWith(source, prefix, options) :
+ IcuStartsWith(source, prefix, options);
+
public bool IsPrefix(string source, string prefix)
{
return IsPrefix(source, prefix, 0);
return source.EndsWith(suffix, (options & CompareOptions.IgnoreCase) != 0 ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal);
}
- return EndsWith(source, suffix, options);
+ return EndsWithCore(source, suffix, options);
}
internal bool IsSuffix(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options)
Debug.Assert(!GlobalizationMode.Invariant);
Debug.Assert((options & (CompareOptions.Ordinal | CompareOptions.OrdinalIgnoreCase)) == 0);
- return EndsWith(source, suffix, options);
+ return EndsWithCore(source, suffix, options);
}
public bool IsSuffix(string source, string suffix)
return IsSuffix(source, suffix, 0);
}
+ private unsafe bool EndsWithCore(ReadOnlySpan<char> source, ReadOnlySpan<char> suffix, CompareOptions options) =>
+ GlobalizationMode.UseNls ?
+ NlsEndsWith(source, suffix, options) :
+ IcuEndsWith(source, suffix, options);
+
/// <summary>
/// Returns the first index where value is found in string. The
/// search starts from startIndex and ends at endIndex. Returns -1 if
return IndexOfOrdinalCore(source, value, ignoreCase, fromBeginning: false);
}
+ private static int IndexOfOrdinalCore(ReadOnlySpan<char> source, ReadOnlySpan<char> value, bool ignoreCase, bool fromBeginning) =>
+ GlobalizationMode.UseNls ?
+ NlsIndexOfOrdinalCore(source, value, ignoreCase, fromBeginning) :
+ IcuIndexOfOrdinalCore(source, value, ignoreCase, fromBeginning);
+
internal unsafe int IndexOf(ReadOnlySpan<char> source, ReadOnlySpan<char> value, CompareOptions options)
{
Debug.Assert(!GlobalizationMode.Invariant);
}
}
+ private unsafe int IndexOfCore(string source, string target, int startIndex, int count, CompareOptions options, int* matchLengthPtr) =>
+ GlobalizationMode.UseNls ?
+ NlsIndexOfCore(source, target, startIndex, count, options, matchLengthPtr) :
+ IcuIndexOfCore(source, target, startIndex, count, options, matchLengthPtr);
+
+ private unsafe int IndexOfCore(ReadOnlySpan<char> source, ReadOnlySpan<char> target, CompareOptions options, int* matchLengthPtr, bool fromBeginning) =>
+ GlobalizationMode.UseNls ?
+ NlsIndexOfCore(source, target, options, matchLengthPtr, fromBeginning) :
+ IcuIndexOfCore(source, target, options, matchLengthPtr, fromBeginning);
+
internal static int IndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase)
{
Debug.Assert(source != null);
return LastIndexOfCore(source, value, startIndex, count, options);
}
- private static int LastIndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase)
+ private int LastIndexOfCore(string source, string target, int startIndex, int count, CompareOptions options) =>
+ GlobalizationMode.UseNls ?
+ NlsLastIndexOfCore(source, target, startIndex, count, options) :
+ IcuLastIndexOfCore(source, target, startIndex, count, options);
+
+ internal static int LastIndexOfOrdinal(string source, string value, int startIndex, int count, bool ignoreCase)
{
Debug.Assert(!string.IsNullOrEmpty(source));
Debug.Assert(value != null);
return -1;
}
- return LastIndexOfOrdinalCore(source, value, startIndex, count, ignoreCase);
+ return GlobalizationMode.UseNls ?
+ NlsLastIndexOfOrdinalCore(source, value, startIndex, count, ignoreCase) :
+ IcuLastIndexOfOrdinalCore(source, value, startIndex, count, ignoreCase);
}
/// <summary>
return InvariantCreateSortKey(source, options);
}
- return CreateSortKey(source, options);
+ return CreateSortKeyCore(source, options);
}
public SortKey GetSortKey(string source)
return InvariantCreateSortKey(source, CompareOptions.None);
}
- return CreateSortKey(source, CompareOptions.None);
+ return CreateSortKeyCore(source, CompareOptions.None);
}
+ private SortKey CreateSortKeyCore(string source, CompareOptions options) =>
+ GlobalizationMode.UseNls ?
+ NlsCreateSortKey(source, options) :
+ IcuCreateSortKey(source, options);
+
public override bool Equals(object? value)
{
return value is CompareInfo otherCompareInfo
}
}
+ private unsafe int GetHashCodeOfStringCore(ReadOnlySpan<char> source, CompareOptions options) =>
+ GlobalizationMode.UseNls ?
+ NlsGetHashCodeOfString(source, options) :
+ IcuGetHashCodeOfString(source, options);
+
public override string ToString() => "CompareInfo - " + Name;
public SortVersion Version
}
else
{
- m_SortVersion = GetSortVersion();
+ m_SortVersion = GlobalizationMode.UseNls ? NlsGetSortVersion() : IcuGetSortVersion();
}
}
/// 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()
+ private unsafe bool IcuInitCultureData()
{
Debug.Assert(_sRealName != null);
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
string realNameBuffer = _sRealName;
_bNeutral = TwoLetterISOCountryName.Length == 0;
- _sSpecificCulture = _bNeutral ? LocaleData.GetSpecificCultureName(_sRealName) : _sRealName;
+ _sSpecificCulture = _bNeutral ? IcuLocaleData.GetSpecificCultureName(_sRealName) : _sRealName;
// Remove the sort from sName unless custom culture
if (index > 0 && !_bNeutral && !IsCustomCultureId(_iLanguage))
return true;
}
- private string GetLocaleInfo(LocaleStringData type)
+ private string IcuGetLocaleInfo(LocaleStringData type)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
- Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo] Expected _sWindowsName to be populated already");
- return GetLocaleInfo(_sWindowsName, type);
+ Debug.Assert(_sWindowsName != null, "[CultureData.IcuGetLocaleInfo] Expected _sWindowsName to be populated already");
+ return IcuGetLocaleInfo(_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)
+ private unsafe string IcuGetLocaleInfo(string localeName, LocaleStringData type)
{
- Debug.Assert(localeName != null, "[CultureData.GetLocaleInfo] Expected localeName to be not be null");
+ Debug.Assert(!GlobalizationMode.UseNls);
+ Debug.Assert(localeName != null, "[CultureData.IcuGetLocaleInfo] 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);
+ return IcuGetLocaleInfo(localeName, LocaleStringData.NegativeSign) +
+ IcuGetLocaleInfo(localeName, LocaleStringData.PositiveInfinitySymbol);
}
char* buffer = stackalloc char[ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY];
if (!result)
{
// Failed, just use empty string
- Debug.Fail("[CultureData.GetLocaleInfo(LocaleStringData)] Failed");
+ Debug.Fail("[CultureData.IcuGetLocaleInfo(LocaleStringData)] Failed");
return string.Empty;
}
return new string(buffer);
}
- private int GetLocaleInfo(LocaleNumberData type)
+ private int IcuGetLocaleInfo(LocaleNumberData type)
{
- Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
- Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo(LocaleNumberData)] Expected _sWindowsName to be populated already");
+ Debug.Assert(_sWindowsName != null, "[CultureData.IcuGetLocaleInfo(LocaleNumberData)] Expected _sWindowsName to be populated already");
switch (type)
{
if (!result)
{
// Failed, just use 0
- Debug.Fail("[CultureData.GetLocaleInfo(LocaleNumberData)] failed");
+ Debug.Fail("[CultureData.IcuGetLocaleInfo(LocaleNumberData)] failed");
}
return value;
}
- private int[] GetLocaleInfo(LocaleGroupingData type)
+ private int[] IcuGetLocaleInfo(LocaleGroupingData type)
{
- Debug.Assert(_sWindowsName != null, "[CultureData.GetLocaleInfo(LocaleGroupingData)] Expected _sWindowsName to be populated already");
+ Debug.Assert(!GlobalizationMode.UseNls);
+ Debug.Assert(_sWindowsName != null, "[CultureData.IcuGetLocaleInfo(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");
+ Debug.Fail("[CultureData.IcuGetLocaleInfo(LocaleGroupingData type)] failed");
}
if (secondaryGroupingSize == 0)
return new int[] { primaryGroupingSize, secondaryGroupingSize };
}
- private string GetTimeFormatString() => GetTimeFormatString(shortFormat: false);
+ private string IcuGetTimeFormatString() => IcuGetTimeFormatString(shortFormat: false);
- private unsafe string GetTimeFormatString(bool shortFormat)
+ private unsafe string IcuGetTimeFormatString(bool shortFormat)
{
+ Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert(_sWindowsName != null, "[CultureData.GetTimeFormatString(bool shortFormat)] Expected _sWindowsName to be populated already");
char* buffer = stackalloc char[ICU_ULOC_KEYWORD_AND_VALUES_CAPACITY];
return ConvertIcuTimeFormatString(span.Slice(0, span.IndexOf('\0')));
}
- private int GetFirstDayOfWeek() => GetLocaleInfo(LocaleNumberData.FirstDayOfWeek);
+ private int IcuGetFirstDayOfWeek() => IcuGetLocaleInfo(LocaleNumberData.FirstDayOfWeek);
- private string[] GetTimeFormats()
+ private string[] IcuGetTimeFormats()
{
- string format = GetTimeFormatString(false);
+ string format = IcuGetTimeFormatString(false);
return new string[] { format };
}
- private string[] GetShortTimeFormats()
+ private string[] IcuGetShortTimeFormats()
{
- string format = GetTimeFormatString(true);
+ string format = IcuGetTimeFormatString(true);
return new string[] { format };
}
- private static CultureData? GetCultureDataFromRegionName(string? regionName)
+ private static CultureData? IcuGetCultureDataFromRegionName(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)
+ private static string IcuGetLanguageDisplayName(string cultureName)
{
- return new CultureInfo(cultureName)._cultureData.GetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName);
+ return new CultureInfo(cultureName)._cultureData.IcuGetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName);
}
- private static string? GetRegionDisplayName()
+ private static string? IcuGetRegionDisplayName()
{
// use the fallback which is to return NativeName
return null;
return result.Slice(0, resultPos).ToString();
}
- private static string? LCIDToLocaleName(int culture)
+ private static string? IcuLCIDToLocaleName(int culture)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
- return LocaleData.LCIDToLocaleName(culture);
+ return IcuLocaleData.LCIDToLocaleName(culture);
}
- private static int LocaleNameToLCID(string cultureName)
+ private static int IcuLocaleNameToLCID(string cultureName)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
- int lcid = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.Lcid);
+ int lcid = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.Lcid);
return lcid == -1 ? CultureInfo.LOCALE_CUSTOM_UNSPECIFIED : lcid;
}
- private static int GetAnsiCodePage(string cultureName)
+ private static int IcuGetAnsiCodePage(string cultureName)
{
- int ansiCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.AnsiCodePage);
+ Debug.Assert(!GlobalizationMode.UseNls);
+ int ansiCodePage = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.AnsiCodePage);
return ansiCodePage == -1 ? CultureData.Invariant.ANSICodePage : ansiCodePage;
}
- private static int GetOemCodePage(string cultureName)
+ private static int IcuGetOemCodePage(string cultureName)
{
- int oemCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.OemCodePage);
+ Debug.Assert(!GlobalizationMode.UseNls);
+ int oemCodePage = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.OemCodePage);
return oemCodePage == -1 ? CultureData.Invariant.OEMCodePage : oemCodePage;
}
- private static int GetMacCodePage(string cultureName)
+ private static int IcuGetMacCodePage(string cultureName)
{
- int macCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.MacCodePage);
+ Debug.Assert(!GlobalizationMode.UseNls);
+ int macCodePage = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.MacCodePage);
return macCodePage == -1 ? CultureData.Invariant.MacCodePage : macCodePage;
}
- private static int GetEbcdicCodePage(string cultureName)
+ private static int IcuGetEbcdicCodePage(string cultureName)
{
- int ebcdicCodePage = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.EbcdicCodePage);
+ Debug.Assert(!GlobalizationMode.UseNls);
+ int ebcdicCodePage = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.EbcdicCodePage);
return ebcdicCodePage == -1 ? CultureData.Invariant.EBCDICCodePage : ebcdicCodePage;
}
- private static int GetGeoId(string cultureName)
+ private static int IcuGetGeoId(string cultureName)
{
- int geoId = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.GeoId);
+ Debug.Assert(!GlobalizationMode.UseNls);
+ int geoId = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.GeoId);
return geoId == -1 ? CultureData.Invariant.GeoId : geoId;
}
- private static int GetDigitSubstitution(string cultureName)
+ private static int IcuGetDigitSubstitution(string cultureName)
{
- int digitSubstitution = LocaleData.GetLocaleDataNumericPart(cultureName, LocaleDataParts.DigitSubstitution);
+ Debug.Assert(!GlobalizationMode.UseNls);
+ int digitSubstitution = IcuLocaleData.GetLocaleDataNumericPart(cultureName, IcuLocaleDataParts.DigitSubstitution);
return digitSubstitution == -1 ? (int) DigitShapes.None : digitSubstitution;
}
- private static string GetThreeLetterWindowsLanguageName(string cultureName)
+ private static string IcuGetThreeLetterWindowsLanguageName(string cultureName)
{
- return LocaleData.GetThreeLetterWindowsLanguageName(cultureName) ?? "ZZZ" /* default lang name */;
+ Debug.Assert(!GlobalizationMode.UseNls);
+ return IcuLocaleData.GetThreeLetterWindowsLanguageName(cultureName) ?? "ZZZ" /* default lang name */;
}
- private static CultureInfo[] EnumCultures(CultureTypes types)
+ private static CultureInfo[] IcuEnumCultures(CultureTypes types)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
if ((types & (CultureTypes.NeutralCultures | CultureTypes.SpecificCultures)) == 0)
{
return list.ToArray();
}
- private static string GetConsoleFallbackName(string cultureName)
+ private static string IcuGetConsoleFallbackName(string cultureName)
{
- return LocaleData.GetConsoleUICulture(cultureName);
+ Debug.Assert(!GlobalizationMode.UseNls);
+ return IcuLocaleData.GetConsoleUICulture(cultureName);
}
-
- internal bool IsWin32Installed => false;
-
- internal bool IsReplacementCulture => false;
-
- internal static CultureData GetCurrentRegionData() => CultureInfo.CurrentCulture._cultureData;
}
}
/// 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()
+ private unsafe bool NlsInitCultureData()
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
int result;
string realNameBuffer = _sRealName;
return Interop.Kernel32.GetLocaleInfoEx(lpLocaleName, lcType, lpLCData, cchData);
}
- private string GetLocaleInfo(LocaleStringData type)
+ private string NlsGetLocaleInfo(LocaleStringData type)
{
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfo] Expected _sWindowsName to be populated by already");
- return GetLocaleInfo(_sWindowsName, type);
+ return NlsGetLocaleInfo(_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)
+ private string NlsGetLocaleInfo(string localeName, LocaleStringData type)
{
+ Debug.Assert(GlobalizationMode.UseNls);
uint lctype = (uint)type;
return GetLocaleInfoFromLCType(localeName, lctype, UseUserOverride);
}
- private int GetLocaleInfo(LocaleNumberData type)
+ private int NlsGetLocaleInfo(LocaleNumberData type)
{
+ Debug.Assert(GlobalizationMode.UseNls);
uint lctype = (uint)type;
// Fix lctype if we don't want overrides
return GetLocaleInfoExInt(_sWindowsName, lctype);
}
- private int[] GetLocaleInfo(LocaleGroupingData type)
+ private int[] NlsGetLocaleInfo(LocaleGroupingData type)
{
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already");
return ConvertWin32GroupString(GetLocaleInfoFromLCType(_sWindowsName, (uint)type, UseUserOverride));
}
- private string? GetTimeFormatString()
+ private string? NlsGetTimeFormatString()
{
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already");
return ReescapeWin32String(GetLocaleInfoFromLCType(_sWindowsName, Interop.Kernel32.LOCALE_STIMEFORMAT, UseUserOverride));
}
- private int GetFirstDayOfWeek()
+ private int NlsGetFirstDayOfWeek()
{
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(_sWindowsName != null, "[CultureData.DoGetLocaleInfoInt] Expected _sWindowsName to be populated by already");
int result = GetLocaleInfoExInt(_sWindowsName, Interop.Kernel32.LOCALE_IFIRSTDAYOFWEEK | (!UseUserOverride ? Interop.Kernel32.LOCALE_NOUSEROVERRIDE : 0));
return ConvertFirstDayOfWeekMonToSun(result);
}
- private string[]? GetTimeFormats()
+ private string[]? NlsGetTimeFormats()
{
// Note that this gets overrides for us all the time
+ Debug.Assert(GlobalizationMode.UseNls);
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()
+ private string[]? NlsGetShortTimeFormats()
{
// Note that this gets overrides for us all the time
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(_sWindowsName != null, "[CultureData.DoEnumShortTimeFormats] Expected _sWindowsName to be populated by already");
string[]? result = ReescapeWin32Strings(nativeEnumTimeFormats(_sWindowsName, Interop.Kernel32.TIME_NOSECONDS, UseUserOverride));
// 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)
+ private static CultureData? NlsGetCultureDataFromRegionName(string regionName)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(regionName != null);
EnumLocaleData context;
return null;
}
- private string GetLanguageDisplayName(string cultureName)
+ private string NlsGetLanguageDisplayName(string cultureName)
{
+ Debug.Assert(GlobalizationMode.UseNls);
+
// 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 = CultureInfo.GetUserDefaultCulture()) != null) &&
+ ((ci = CultureInfo.NlsGetUserDefaultCulture()) != null) &&
!CultureInfo.DefaultThreadCurrentUICulture.Name.Equals(ci.Name))
{
return NativeName;
}
else
{
- return GetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName);
+ return NlsGetLocaleInfo(cultureName, LocaleStringData.LocalizedDisplayName);
}
}
- private string GetRegionDisplayName()
+ private string NlsGetRegionDisplayName()
{
+ Debug.Assert(GlobalizationMode.UseNls);
+
// 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 NlsGetLocaleInfo(LocaleStringData.LocalizedCountryName);
}
return NativeCountryName;
return null;
}
- private static int LocaleNameToLCID(string cultureName)
+ private static int NlsLocaleNameToLCID(string cultureName)
{
Debug.Assert(!GlobalizationMode.Invariant);
return Interop.Kernel32.LocaleNameToLCID(cultureName, Interop.Kernel32.LOCALE_ALLOW_NEUTRAL_NAMES);
}
- private static unsafe string? LCIDToLocaleName(int culture)
+ 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);
return null;
}
- private int GetAnsiCodePage(string cultureName)
+ private int NlsGetAnsiCodePage(string cultureName)
{
- return GetLocaleInfo(LocaleNumberData.AnsiCodePage);
+ Debug.Assert(GlobalizationMode.UseNls);
+ return NlsGetLocaleInfo(LocaleNumberData.AnsiCodePage);
}
- private int GetOemCodePage(string cultureName)
+ private int NlsGetOemCodePage(string cultureName)
{
- return GetLocaleInfo(LocaleNumberData.OemCodePage);
+ Debug.Assert(GlobalizationMode.UseNls);
+ return NlsGetLocaleInfo(LocaleNumberData.OemCodePage);
}
- private int GetMacCodePage(string cultureName)
+ private int NlsGetMacCodePage(string cultureName)
{
- return GetLocaleInfo(LocaleNumberData.MacCodePage);
+ Debug.Assert(GlobalizationMode.UseNls);
+ return NlsGetLocaleInfo(LocaleNumberData.MacCodePage);
}
- private int GetEbcdicCodePage(string cultureName)
+ private int NlsGetEbcdicCodePage(string cultureName)
{
- return GetLocaleInfo(LocaleNumberData.EbcdicCodePage);
+ Debug.Assert(GlobalizationMode.UseNls);
+ return NlsGetLocaleInfo(LocaleNumberData.EbcdicCodePage);
}
- private int GetGeoId(string cultureName)
+ private int NlsGetGeoId(string cultureName)
{
- return GetLocaleInfo(LocaleNumberData.GeoId);
+ Debug.Assert(GlobalizationMode.UseNls);
+ return NlsGetLocaleInfo(LocaleNumberData.GeoId);
}
- private int GetDigitSubstitution(string cultureName)
+ private int NlsGetDigitSubstitution(string cultureName)
{
- return GetLocaleInfo(LocaleNumberData.DigitSubstitution);
+ Debug.Assert(GlobalizationMode.UseNls);
+ return NlsGetLocaleInfo(LocaleNumberData.DigitSubstitution);
}
- private string GetThreeLetterWindowsLanguageName(string cultureName)
+ private string NlsGetThreeLetterWindowsLanguageName(string cultureName)
{
- return GetLocaleInfo(cultureName, LocaleStringData.AbbreviatedWindowsLanguageName);
+ Debug.Assert(GlobalizationMode.UseNls);
+ return NlsGetLocaleInfo(cultureName, LocaleStringData.AbbreviatedWindowsLanguageName);
}
- private static CultureInfo[] EnumCultures(CultureTypes types)
+ private static CultureInfo[] NlsEnumCultures(CultureTypes types)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
uint flags = 0;
return cultures;
}
- private string GetConsoleFallbackName(string cultureName)
+ private string NlsGetConsoleFallbackName(string cultureName)
{
- return GetLocaleInfo(cultureName, LocaleStringData.ConsoleFallbackName);
+ Debug.Assert(GlobalizationMode.UseNls);
+ return NlsGetLocaleInfo(cultureName, LocaleStringData.ConsoleFallbackName);
}
- internal bool IsWin32Installed => true;
-
- internal bool IsReplacementCulture
+ internal bool NlsIsReplacementCulture
{
get
{
+ Debug.Assert(GlobalizationMode.UseNls);
EnumData context = default;
context.strings = new List<string>();
}
}
- internal static unsafe CultureData GetCurrentRegionData()
+ internal static unsafe CultureData NlsGetCurrentRegionData()
{
+ Debug.Assert(GlobalizationMode.UseNls);
Span<char> geoIso2Letters = stackalloc char[10];
int geoId = Interop.Kernel32.GetUserGeoID(Interop.Kernel32.GEOCLASS_NATION);
// If not found in the hard coded table we'll have to find a culture that works for us
if (!GlobalizationMode.Invariant && (retVal == null || retVal.IsNeutralCulture))
{
- retVal = GetCultureDataFromRegionName(cultureName);
+ retVal = GlobalizationMode.UseNls ? NlsGetCultureDataFromRegionName(cultureName) : IcuGetCultureDataFromRegionName(cultureName);
}
// If we found one we can use, then cache it for next time
}
#pragma warning restore 618
- return EnumCultures(types);
+ return GlobalizationMode.UseNls ? NlsEnumCultures(types) : IcuEnumCultures(types);
}
private static CultureData CreateCultureWithInvariantData()
culture._sRealName = cultureName;
// Ask native code if that one's real
- if (!culture.InitCultureData() && !culture.InitCompatibilityCultureData())
+ if (!culture.InitCultureDataCore() && !culture.InitCompatibilityCultureData())
{
return null;
}
}
_sRealName = fallbackCultureName;
- if (!InitCultureData())
+ if (!InitCultureDataCore())
{
return false;
}
return true;
}
+ private bool InitCultureDataCore() => GlobalizationMode.UseNls ?
+ NlsInitCultureData() :
+ IcuInitCultureData();
+
/// We'd rather people use the named version since this doesn't allow custom locales
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 = LCIDToLocaleName(culture);
+ localeName = GlobalizationMode.UseNls ? NlsLCIDToLocaleName(culture) : IcuLCIDToLocaleName(culture);
if (!string.IsNullOrEmpty(localeName))
{
// Parent name (which may be a custom locale/culture)
// Ask using the real name, so that we get parents of neutrals
- internal string ParentName => _sParent ??= GetLocaleInfo(_sRealName!, LocaleStringData.ParentName);
+ internal string ParentName => _sParent ??= GetLocaleInfoCore(_sRealName!, LocaleStringData.ParentName);
// Localized pretty name for this locale (ie: Inglis (estados Unitos))
internal string DisplayName
if (Name.Equals(ZH_CHT, StringComparison.OrdinalIgnoreCase))
{
- localizedDisplayName = GetLanguageDisplayName("zh-Hant");
+ localizedDisplayName = GetLanguageDisplayNameCore("zh-Hant");
}
else if (Name.Equals(ZH_CHS, StringComparison.OrdinalIgnoreCase))
{
- localizedDisplayName = GetLanguageDisplayName("zh-Hans");
+ localizedDisplayName = GetLanguageDisplayNameCore("zh-Hans");
}
else
{
- localizedDisplayName = GetLanguageDisplayName(Name);
+ localizedDisplayName = GetLanguageDisplayNameCore(Name);
}
}
catch
}
else
{
- localizedDisplayName = GetLocaleInfo(LocaleStringData.LocalizedDisplayName);
+ localizedDisplayName = GetLocaleInfoCore(LocaleStringData.LocalizedDisplayName);
}
}
}
}
}
+ private string GetLanguageDisplayNameCore(string cultureName) => GlobalizationMode.UseNls ?
+ NlsGetLanguageDisplayName(cultureName) :
+ IcuGetLanguageDisplayName(cultureName);
+
/// <summary>
/// English pretty name for this locale (ie: English (United States))
/// </summary>
}
else
{
- englishDisplayName = GetLocaleInfo(LocaleStringData.EnglishDisplayName);
+ englishDisplayName = GetLocaleInfoCore(LocaleStringData.EnglishDisplayName);
// if it isn't found build one:
if (string.IsNullOrEmpty(englishDisplayName))
}
else
{
- nativeDisplayName = GetLocaleInfo(LocaleStringData.NativeDisplayName);
+ nativeDisplayName = GetLocaleInfoCore(LocaleStringData.NativeDisplayName);
// if it isn't found build one:
if (string.IsNullOrEmpty(nativeDisplayName))
/// <summary>
/// iso 639 language name, ie: en
/// </summary>
- internal string TwoLetterISOLanguageName => _sISO639Language ??= GetLocaleInfo(LocaleStringData.Iso639LanguageTwoLetterName);
+ internal string TwoLetterISOLanguageName => _sISO639Language ??= GetLocaleInfoCore(LocaleStringData.Iso639LanguageTwoLetterName);
/// <summary>
/// iso 639 language name, ie: eng
/// </summary>
- internal string ThreeLetterISOLanguageName => _sISO639Language2 ??= GetLocaleInfo(LocaleStringData.Iso639LanguageThreeLetterName);
+ internal string ThreeLetterISOLanguageName => _sISO639Language2 ??= GetLocaleInfoCore(LocaleStringData.Iso639LanguageThreeLetterName);
/// <summary>
/// abbreviated windows language name (ie: enu) (non-standard, avoid this)
/// </summary>
- internal string ThreeLetterWindowsLanguageName => _sAbbrevLang ??= GetThreeLetterWindowsLanguageName(_sRealName!);
+ internal string ThreeLetterWindowsLanguageName => _sAbbrevLang ??= GlobalizationMode.UseNls ?
+ NlsGetThreeLetterWindowsLanguageName(_sRealName!) :
+ IcuGetThreeLetterWindowsLanguageName(_sRealName!);
/// <summary>
/// Localized name for this language (Windows Only) ie: Inglis
}
else
{
- _sLocalizedLanguage = GetLocaleInfo(LocaleStringData.LocalizedLanguageName);
+ _sLocalizedLanguage = GetLocaleInfoCore(LocaleStringData.LocalizedLanguageName);
}
}
/// <summary>
/// English name for this language (Windows Only) ie: German
/// </summary>
- private string EnglishLanguageName => _sEnglishLanguage ??= GetLocaleInfo(LocaleStringData.EnglishLanguageName);
+ private string EnglishLanguageName => _sEnglishLanguage ??= GetLocaleInfoCore(LocaleStringData.EnglishLanguageName);
/// <summary>
/// Native name of this language (Windows Only) ie: Deutsch
/// </summary>
- private string NativeLanguageName => _sNativeLanguage ??= GetLocaleInfo(LocaleStringData.NativeLanguageName);
+ private string NativeLanguageName => _sNativeLanguage ??= GetLocaleInfoCore(LocaleStringData.NativeLanguageName);
/// <summary>
/// region name (eg US)
/// </summary>
- internal string RegionName => _sRegionName ??= GetLocaleInfo(LocaleStringData.Iso3166CountryName);
+ internal string RegionName => _sRegionName ??= GetLocaleInfoCore(LocaleStringData.Iso3166CountryName);
internal int GeoId
{
{
if (_iGeoId == undef)
{
- _iGeoId = GetGeoId(_sRealName!);
+ _iGeoId = GlobalizationMode.UseNls ? NlsGetGeoId(_sRealName!) : IcuGetGeoId(_sRealName!);
}
return _iGeoId;
}
{
try
{
- localizedCountry = GetRegionDisplayName();
+ localizedCountry = GlobalizationMode.UseNls ? NlsGetRegionDisplayName() : IcuGetRegionDisplayName();
}
catch
{
/// <summary>
/// english country name (RegionInfo) ie: Germany
/// </summary>
- internal string EnglishCountryName => _sEnglishCountry ??= GetLocaleInfo(LocaleStringData.EnglishCountryName);
+ internal string EnglishCountryName => _sEnglishCountry ??= GetLocaleInfoCore(LocaleStringData.EnglishCountryName);
/// <summary>
/// native country name (RegionInfo) ie: Deutschland
/// </summary>
- internal string NativeCountryName => _sNativeCountry ??= GetLocaleInfo(LocaleStringData.NativeCountryName);
+ internal string NativeCountryName => _sNativeCountry ??= GetLocaleInfoCore(LocaleStringData.NativeCountryName);
/// <summary>
/// ISO 3166 Country Name
/// </summary>
- internal string TwoLetterISOCountryName => _sISO3166CountryName ??= GetLocaleInfo(LocaleStringData.Iso3166CountryName);
+ internal string TwoLetterISOCountryName => _sISO3166CountryName ??= GetLocaleInfoCore(LocaleStringData.Iso3166CountryName);
/// <summary>
/// 3 letter ISO 3166 country code
/// </summary>
- internal string ThreeLetterISOCountryName => _sISO3166CountryName2 ??= GetLocaleInfo(LocaleStringData.Iso3166CountryName2);
+ internal string ThreeLetterISOCountryName => _sISO3166CountryName2 ??= GetLocaleInfoCore(LocaleStringData.Iso3166CountryName2);
internal int KeyboardLayoutId
{
/// <summary>
/// Console fallback name (ie: locale to use for console apps for unicode-only locales)
/// </summary>
- internal string SCONSOLEFALLBACKNAME => _sConsoleFallbackName ??= GetConsoleFallbackName(_sRealName!);
+ internal string SCONSOLEFALLBACKNAME => _sConsoleFallbackName ??= GlobalizationMode.UseNls ?
+ NlsGetConsoleFallbackName(_sRealName!) :
+ IcuGetConsoleFallbackName(_sRealName!);
/// <summary>
/// (user can override) grouping of digits
/// </summary>
- internal int[] NumberGroupSizes => _waGrouping ??= GetLocaleInfo(LocaleGroupingData.Digit);
+ internal int[] NumberGroupSizes => _waGrouping ??= GetLocaleInfoCore(LocaleGroupingData.Digit);
/// <summary>
/// Not a Number
/// </summary>
- private string NaNSymbol => _sNaN ??= GetLocaleInfo(LocaleStringData.NaNSymbol);
+ private string NaNSymbol => _sNaN ??= GetLocaleInfoCore(LocaleStringData.NaNSymbol);
/// <summary>
/// + Infinity
/// </summary>
- private string PositiveInfinitySymbol => _sPositiveInfinity ??= GetLocaleInfo(LocaleStringData.PositiveInfinitySymbol);
+ private string PositiveInfinitySymbol => _sPositiveInfinity ??= GetLocaleInfoCore(LocaleStringData.PositiveInfinitySymbol);
/// <summary>
/// - Infinity
/// </summary>
- private string NegativeInfinitySymbol => _sNegativeInfinity ??= GetLocaleInfo(LocaleStringData.NegativeInfinitySymbol);
+ private string NegativeInfinitySymbol => _sNegativeInfinity ??= GetLocaleInfoCore(LocaleStringData.NegativeInfinitySymbol);
/// <summary>
/// Negative Percent (0-3)
if (_iNegativePercent == undef)
{
// Note that <= Windows Vista this is synthesized by native code
- _iNegativePercent = GetLocaleInfo(LocaleNumberData.NegativePercentFormat);
+ _iNegativePercent = GetLocaleInfoCore(LocaleNumberData.NegativePercentFormat);
}
return _iNegativePercent;
}
if (_iPositivePercent == undef)
{
// Note that <= Windows Vista this is synthesized by native code
- _iPositivePercent = GetLocaleInfo(LocaleNumberData.PositivePercentFormat);
+ _iPositivePercent = GetLocaleInfoCore(LocaleNumberData.PositivePercentFormat);
}
return _iPositivePercent;
}
/// <summary>
/// Percent (%) symbol
/// </summary>
- private string PercentSymbol => _sPercent ??= GetLocaleInfo(LocaleStringData.PercentSymbol);
+ private string PercentSymbol => _sPercent ??= GetLocaleInfoCore(LocaleStringData.PercentSymbol);
/// <summary>
/// PerMille symbol
/// </summary>
- private string PerMilleSymbol => _sPerMille ??= GetLocaleInfo(LocaleStringData.PerMilleSymbol);
+ private string PerMilleSymbol => _sPerMille ??= GetLocaleInfoCore(LocaleStringData.PerMilleSymbol);
/// <summary>
/// (user can override) local monetary symbol, eg: $
/// </summary>
- internal string CurrencySymbol => _sCurrency ??= GetLocaleInfo(LocaleStringData.MonetarySymbol);
+ internal string CurrencySymbol => _sCurrency ??= GetLocaleInfoCore(LocaleStringData.MonetarySymbol);
/// <summary>
/// international monetary symbol (RegionInfo), eg: USD
/// </summary>
- internal string ISOCurrencySymbol => _sIntlMonetarySymbol ??= GetLocaleInfo(LocaleStringData.Iso4217MonetarySymbol);
+ internal string ISOCurrencySymbol => _sIntlMonetarySymbol ??= GetLocaleInfoCore(LocaleStringData.Iso4217MonetarySymbol);
/// <summary>
/// English name for this currency (RegionInfo), eg: US Dollar
/// </summary>
- internal string CurrencyEnglishName => _sEnglishCurrency ??= GetLocaleInfo(LocaleStringData.CurrencyEnglishName);
+ internal string CurrencyEnglishName => _sEnglishCurrency ??= GetLocaleInfoCore(LocaleStringData.CurrencyEnglishName);
/// <summary>
/// Native name for this currency (RegionInfo), eg: Schweiz Frank
/// </summary>
- internal string CurrencyNativeName => _sNativeCurrency ??= GetLocaleInfo(LocaleStringData.CurrencyNativeName);
+ internal string CurrencyNativeName => _sNativeCurrency ??= GetLocaleInfoCore(LocaleStringData.CurrencyNativeName);
/// <summary>
/// (user can override) monetary grouping of digits
/// </summary>
- internal int[] CurrencyGroupSizes => _waMonetaryGrouping ??= GetLocaleInfo(LocaleGroupingData.Monetary);
+ internal int[] CurrencyGroupSizes => _waMonetaryGrouping ??= GetLocaleInfoCore(LocaleGroupingData.Monetary);
/// <summary>
/// (user can override) system of measurement 0=metric, 1=US (RegionInfo)
{
if (_iMeasure == undef)
{
- _iMeasure = GetLocaleInfo(LocaleNumberData.MeasurementSystem);
+ _iMeasure = GetLocaleInfoCore(LocaleNumberData.MeasurementSystem);
}
return _iMeasure;
}
/// <summary>
/// (user can override) list Separator
/// </summary>
- internal string ListSeparator => _sListSeparator ??= GetLocaleInfo(LocaleStringData.ListSeparator);
+ internal string ListSeparator => _sListSeparator ??= GetLocaleInfoCore(LocaleStringData.ListSeparator);
/// <summary>
/// (user can override) AM designator
/// </summary>
- internal string AMDesignator => _sAM1159 ??= GetLocaleInfo(LocaleStringData.AMDesignator);
+ internal string AMDesignator => _sAM1159 ??= GetLocaleInfoCore(LocaleStringData.AMDesignator);
/// <summary>
/// (user can override) PM designator
/// </summary>
- internal string PMDesignator => _sPM2359 ??= GetLocaleInfo(LocaleStringData.PMDesignator);
+ internal string PMDesignator => _sPM2359 ??= GetLocaleInfoCore(LocaleStringData.PMDesignator);
/// <summary>
/// (user can override) time format
{
Debug.Assert(!GlobalizationMode.Invariant);
- string[]? longTimes = GetTimeFormats();
+ string[]? longTimes = GlobalizationMode.UseNls ? NlsGetTimeFormats() : IcuGetTimeFormats();
if (longTimes == null || longTimes.Length == 0)
{
_saLongTimes = Invariant._saLongTimes!;
Debug.Assert(!GlobalizationMode.Invariant);
// Try to get the short times from the OS/culture.dll
- string[]? shortTimes = GetShortTimeFormats();
+ string[]? shortTimes = GlobalizationMode.UseNls ? NlsGetShortTimeFormats() : IcuGetShortTimeFormats();
if (shortTimes == null || shortTimes.Length == 0)
{
{
if (_iFirstDayOfWeek == undef)
{
- _iFirstDayOfWeek = GetFirstDayOfWeek();
+ _iFirstDayOfWeek = GlobalizationMode.UseNls ? NlsGetFirstDayOfWeek() : IcuGetFirstDayOfWeek();
}
return _iFirstDayOfWeek;
}
{
if (_iFirstWeekOfYear == undef)
{
- _iFirstWeekOfYear = GetLocaleInfo(LocaleNumberData.FirstWeekOfYear);
+ _iFirstWeekOfYear = GetLocaleInfoCore(LocaleNumberData.FirstWeekOfYear);
}
return _iFirstWeekOfYear;
}
// Default calendar should be first
CalendarId[] calendars = new CalendarId[23];
Debug.Assert(_sWindowsName != null, "[CultureData.CalendarIds] Expected _sWindowsName to be populated by already");
- int count = CalendarData.GetCalendars(_sWindowsName, _bUseOverrides, calendars);
+
+ int count = GlobalizationMode.UseNls
+ ? CalendarData.NlsGetCalendars(_sWindowsName, _bUseOverrides, calendars)
+ : CalendarData.IcuGetCalendars(_sWindowsName, _bUseOverrides, calendars);
// See if we had a calendar to add.
if (count == 0)
// Prior to Vista the enumeration didn't have default calendar first
if (temp.Length > 1)
{
- CalendarId i = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType);
+ CalendarId i = (CalendarId)GetLocaleInfoCore(LocaleNumberData.CalendarType);
if (temp[1] == i)
{
temp[1] = temp[0];
if (_iReadingLayout == undef)
{
Debug.Assert(_sRealName != null, "[CultureData.IsRightToLeft] Expected _sRealName to be populated by already");
- _iReadingLayout = GetLocaleInfo(LocaleNumberData.ReadingLayout);
+ _iReadingLayout = GetLocaleInfoCore(LocaleNumberData.ReadingLayout);
}
return _iReadingLayout;
{
if (_iDefaultAnsiCodePage == undef)
{
- _iDefaultAnsiCodePage = GetAnsiCodePage(_sRealName!);
+ _iDefaultAnsiCodePage = GlobalizationMode.UseNls ? NlsGetAnsiCodePage(_sRealName!) : IcuGetAnsiCodePage(_sRealName!);
}
return _iDefaultAnsiCodePage;
}
{
if (_iDefaultOemCodePage == undef)
{
- _iDefaultOemCodePage = GetOemCodePage(_sRealName!);
+ _iDefaultOemCodePage = GlobalizationMode.UseNls ? NlsGetOemCodePage(_sRealName!) : IcuGetOemCodePage(_sRealName!);
}
return _iDefaultOemCodePage;
}
{
if (_iDefaultMacCodePage == undef)
{
- _iDefaultMacCodePage = GetMacCodePage(_sRealName!);
+ _iDefaultMacCodePage = GlobalizationMode.UseNls ? NlsGetMacCodePage(_sRealName!) : IcuGetMacCodePage(_sRealName!);
}
return _iDefaultMacCodePage;
}
{
if (_iDefaultEbcdicCodePage == undef)
{
- _iDefaultEbcdicCodePage = GetEbcdicCodePage(_sRealName!);
+ _iDefaultEbcdicCodePage = GlobalizationMode.UseNls ? NlsGetEbcdicCodePage(_sRealName!) : IcuGetEbcdicCodePage(_sRealName!);
}
return _iDefaultEbcdicCodePage;
}
if (_iLanguage == 0)
{
Debug.Assert(_sRealName != null, "[CultureData.LCID] Expected this.sRealName to be populated already");
- _iLanguage = LocaleNameToLCID(_sRealName);
+ _iLanguage = GlobalizationMode.UseNls ? NlsLocaleNameToLCID(_sRealName) : IcuLocaleNameToLCID(_sRealName);
}
return _iLanguage;
}
internal bool IsInvariantCulture => string.IsNullOrEmpty(Name);
+ internal bool IsWin32Installed => GlobalizationMode.UseNls;
+
+ internal bool IsReplacementCulture => GlobalizationMode.UseNls ? NlsIsReplacementCulture : false;
+
+ internal static unsafe CultureData GetCurrentRegionData() => GlobalizationMode.UseNls ?
+ NlsGetCurrentRegionData() :
+ CultureInfo.CurrentCulture._cultureData;
+
/// <summary>
/// Get an instance of our default calendar
/// </summary>
return CultureInfo.GetCalendarInstance(CalendarIds[0]);
}
- CalendarId defaultCalId = (CalendarId)GetLocaleInfo(LocaleNumberData.CalendarType);
+ CalendarId defaultCalId = (CalendarId)GetLocaleInfoCore(LocaleNumberData.CalendarType);
if (defaultCalId == 0)
{
{
if (_sTimeSeparator == null)
{
- string? longTimeFormat = GetTimeFormatString();
+ string? longTimeFormat = GlobalizationMode.UseNls ? NlsGetTimeFormatString() : IcuGetTimeFormatString();
if (string.IsNullOrEmpty(longTimeFormat))
{
longTimeFormat = LongTimes[0];
{
Debug.Assert(_sWindowsName != null, "[CultureData.GetNFIValues] Expected _sWindowsName to be populated by already");
// String values
- nfi._positiveSign = GetLocaleInfo(LocaleStringData.PositiveSign);
- nfi._negativeSign = GetLocaleInfo(LocaleStringData.NegativeSign);
+ nfi._positiveSign = GetLocaleInfoCore(LocaleStringData.PositiveSign);
+ nfi._negativeSign = GetLocaleInfoCore(LocaleStringData.NegativeSign);
- nfi._numberDecimalSeparator = GetLocaleInfo(LocaleStringData.DecimalSeparator);
- nfi._numberGroupSeparator = GetLocaleInfo(LocaleStringData.ThousandSeparator);
- nfi._currencyGroupSeparator = GetLocaleInfo(LocaleStringData.MonetaryThousandSeparator);
- nfi._currencyDecimalSeparator = GetLocaleInfo(LocaleStringData.MonetaryDecimalSeparator);
- nfi._currencySymbol = GetLocaleInfo(LocaleStringData.MonetarySymbol);
+ nfi._numberDecimalSeparator = GetLocaleInfoCore(LocaleStringData.DecimalSeparator);
+ nfi._numberGroupSeparator = GetLocaleInfoCore(LocaleStringData.ThousandSeparator);
+ nfi._currencyGroupSeparator = GetLocaleInfoCore(LocaleStringData.MonetaryThousandSeparator);
+ nfi._currencyDecimalSeparator = GetLocaleInfoCore(LocaleStringData.MonetaryDecimalSeparator);
+ nfi._currencySymbol = GetLocaleInfoCore(LocaleStringData.MonetarySymbol);
// Numeric values
- nfi._numberDecimalDigits = GetLocaleInfo(LocaleNumberData.FractionalDigitsCount);
- nfi._currencyDecimalDigits = GetLocaleInfo(LocaleNumberData.MonetaryFractionalDigitsCount);
- nfi._currencyPositivePattern = GetLocaleInfo(LocaleNumberData.PositiveMonetaryNumberFormat);
- nfi._currencyNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeMonetaryNumberFormat);
- nfi._numberNegativePattern = GetLocaleInfo(LocaleNumberData.NegativeNumberFormat);
+ nfi._numberDecimalDigits = GetLocaleInfoCore(LocaleNumberData.FractionalDigitsCount);
+ nfi._currencyDecimalDigits = GetLocaleInfoCore(LocaleNumberData.MonetaryFractionalDigitsCount);
+ nfi._currencyPositivePattern = GetLocaleInfoCore(LocaleNumberData.PositiveMonetaryNumberFormat);
+ nfi._currencyNegativePattern = GetLocaleInfoCore(LocaleNumberData.NegativeMonetaryNumberFormat);
+ nfi._numberNegativePattern = GetLocaleInfoCore(LocaleNumberData.NegativeNumberFormat);
// LOCALE_SNATIVEDIGITS (array of 10 single character strings).
- string digits = GetLocaleInfo(LocaleStringData.Digits);
+ string digits = GetLocaleInfoCore(LocaleStringData.Digits);
nfi._nativeDigits = new string[10];
for (int i = 0; i < nfi._nativeDigits.Length; i++)
{
}
Debug.Assert(_sRealName != null);
- nfi._digitSubstitution = GetDigitSubstitution(_sRealName);
+ nfi._digitSubstitution = GlobalizationMode.UseNls ? NlsGetDigitSubstitution(_sRealName) : IcuGetDigitSubstitution(_sRealName);
}
// Gather additional data
/// </remarks>
internal static string AnsiToLower(string testString) => TextInfo.ToLowerAsciiInvariant(testString);
+ private int GetLocaleInfoCore(LocaleNumberData type) => GlobalizationMode.UseNls ?
+ NlsGetLocaleInfo(type) :
+ IcuGetLocaleInfo(type);
+
+ private string GetLocaleInfoCore(LocaleStringData type) => GlobalizationMode.UseNls ?
+ NlsGetLocaleInfo(type) :
+ IcuGetLocaleInfo(type);
+
+ private string GetLocaleInfoCore(string localeName, LocaleStringData type) => GlobalizationMode.UseNls ?
+ NlsGetLocaleInfo(localeName, type) :
+ IcuGetLocaleInfo(localeName, type);
+
+ private int[] GetLocaleInfoCore(LocaleGroupingData type) => GlobalizationMode.UseNls ?
+ NlsGetLocaleInfo(type) :
+ IcuGetLocaleInfo(type);
+
/// <remarks>
/// The numeric values of the enum members match their Win32 counterparts. The CultureData Win32 PAL implementation
/// takes a dependency on this fact, in order to prevent having to construct a mapping from internal values to LCTypes.
{
public partial class CultureInfo : IFormatProvider
{
- internal static CultureInfo GetUserDefaultCulture()
+ internal static CultureInfo IcuGetUserDefaultCulture()
{
+ Debug.Assert(!GlobalizationMode.UseNls);
+
if (GlobalizationMode.Invariant)
return CultureInfo.InvariantCulture;
return cultureInfo;
}
- private static CultureInfo GetPredefinedCultureInfo(string name)
+ private static CultureInfo IcuGetPredefinedCultureInfo(string name)
{
+ Debug.Assert(!GlobalizationMode.UseNls);
+
if (!Interop.Globalization.IsPredefinedLocale(name))
{
throw new CultureNotFoundException(nameof(name), SR.Format(SR.Argument_InvalidPredefinedCultureName, name));
return GetCultureInfo(name);
}
- private static CultureInfo GetUserDefaultUICulture()
+ private static CultureInfo IcuGetUserDefaultUICulture()
{
+ Debug.Assert(!GlobalizationMode.UseNls);
+
return InitializeUserDefaultCulture();
}
}
// 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.Diagnostics;
+
namespace System.Globalization
{
public partial class CultureInfo : IFormatProvider
{
- internal static CultureInfo GetUserDefaultCulture()
+ internal static CultureInfo NlsGetUserDefaultCulture()
{
+ Debug.Assert(GlobalizationMode.UseNls);
+
if (GlobalizationMode.Invariant)
return CultureInfo.InvariantCulture;
return GetCultureByName(strDefault);
}
- private static CultureInfo GetPredefinedCultureInfo(string name)
+ private static CultureInfo NlsGetPredefinedCultureInfo(string name)
{
+ Debug.Assert(GlobalizationMode.UseNls);
+
CultureInfo culture = GetCultureInfo(name);
string englishName = culture.EnglishName;
return culture;
}
- private static unsafe CultureInfo GetUserDefaultUICulture()
+ private static unsafe CultureInfo NlsGetUserDefaultUICulture()
{
+ Debug.Assert(GlobalizationMode.UseNls);
+
if (GlobalizationMode.Invariant)
return CultureInfo.InvariantCulture;
return new GregorianCalendar();
}
+ internal static CultureInfo GetUserDefaultCulture() => GlobalizationMode.UseNls ?
+ NlsGetUserDefaultCulture() :
+ IcuGetUserDefaultCulture();
+
+ private static CultureInfo GetUserDefaultUICulture() => GlobalizationMode.UseNls ?
+ NlsGetUserDefaultUICulture() :
+ IcuGetUserDefaultUICulture();
+
/// <summary>
/// Return/set the default calendar used by this culture.
/// This value can be overridden by regional option if this is a current culture.
if (predefinedOnly)
{
- return GetPredefinedCultureInfo(name);
+ return GlobalizationMode.UseNls ?
+ NlsGetPredefinedCultureInfo(name) :
+ IcuGetPredefinedCultureInfo(name);
}
return GetCultureInfo(name);
namespace System.Globalization
{
- internal enum LocaleDataParts
+ internal enum IcuLocaleDataParts
{
Lcid = 0,
AnsiCodePage = 1,
ConsoleLocaleIndex = 8
}
- internal static class LocaleData
+ internal static class IcuLocaleData
{
// this is done rather than using a large readonly array of strings to avoid
// generating a large amount of code in the static constructor.
return null;
}
- internal static int GetLocaleDataNumericPart(string cultureName, LocaleDataParts part)
+ internal static int GetLocaleDataNumericPart(string cultureName, IcuLocaleDataParts part)
{
int index = SearchCultureName(cultureName);
if (index < 0)
return c_threeLetterWindowsLanguageName.Substring(index * 3, 3);
}
- internal static string GetLocaleDataMappedCulture(string cultureName, LocaleDataParts part)
+ internal static string GetLocaleDataMappedCulture(string cultureName, IcuLocaleDataParts part)
{
int indexToIndicesTable = GetLocaleDataNumericPart(cultureName, part);
if (indexToIndicesTable < 0)
internal static string GetSpecificCultureName(string cultureName)
{
- return GetLocaleDataMappedCulture(cultureName, LocaleDataParts.SpecificLocaleIndex);
+ return GetLocaleDataMappedCulture(cultureName, IcuLocaleDataParts.SpecificLocaleIndex);
}
internal static string GetConsoleUICulture(string cultureName)
{
- return GetLocaleDataMappedCulture(cultureName, LocaleDataParts.ConsoleLocaleIndex);
+ return GetLocaleDataMappedCulture(cultureName, IcuLocaleDataParts.ConsoleLocaleIndex);
}
// SearchCultureName will binary search c_localeNames using s_localeNamesIndices.
{
public sealed partial class IdnMapping
{
- private unsafe string GetAsciiCore(string unicodeString, char* unicode, int count)
+ private unsafe string IcuGetAsciiCore(string unicodeString, char* unicode, int count)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert(unicodeString != null && unicodeString.Length >= count);
- uint flags = Flags;
+ uint flags = IcuFlags;
CheckInvalidIdnCharacters(unicode, count, flags, nameof(unicode));
const int StackallocThreshold = 512;
}
}
- private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count)
+ private unsafe string IcuGetUnicodeCore(string asciiString, char* ascii, int count)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert(asciiString != null && asciiString.Length >= count);
- uint flags = Flags;
+ uint flags = IcuFlags;
CheckInvalidIdnCharacters(ascii, count, flags, nameof(ascii));
const int StackAllocThreshold = 512;
if (count < StackAllocThreshold)
{
char* output = stackalloc char[count];
- return GetUnicodeCore(asciiString, ascii, count, flags, output, count, reattempt: true);
+ return IcuGetUnicodeCore(asciiString, ascii, count, flags, output, count, reattempt: true);
}
else
{
char[] output = new char[count];
fixed (char* pOutput = &output[0])
{
- return GetUnicodeCore(asciiString, ascii, count, flags, pOutput, count, reattempt: true);
+ return IcuGetUnicodeCore(asciiString, ascii, count, flags, pOutput, count, reattempt: true);
}
}
}
- private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength, bool reattempt)
+ private unsafe string IcuGetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength, bool reattempt)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
Debug.Assert(asciiString != null && asciiString.Length >= count);
int realLen = Interop.Globalization.ToUnicode(flags, ascii, count, output, outputLength);
char[] newOutput = new char[realLen];
fixed (char* pNewOutput = newOutput)
{
- return GetUnicodeCore(asciiString, ascii, count, flags, pNewOutput, realLen, reattempt: false);
+ return IcuGetUnicodeCore(asciiString, ascii, count, flags, pNewOutput, realLen, reattempt: false);
}
}
// ---- PAL layer ends here ----
// -----------------------------
- private uint Flags
+ private uint IcuFlags
{
get
{
{
public sealed partial class IdnMapping
{
- private unsafe string GetAsciiCore(string unicodeString, char* unicode, int count)
+ private unsafe string NlsGetAsciiCore(string unicodeString, char* unicode, int count)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(unicodeString != null && unicodeString.Length >= count);
- uint flags = Flags;
+ uint flags = NlsFlags;
// Determine the required length
int length = Interop.Normaliz.IdnToAscii(flags, unicode, count, null, 0);
if (length < StackAllocThreshold)
{
char* output = stackalloc char[length];
- return GetAsciiCore(unicodeString, unicode, count, flags, output, length);
+ return NlsGetAsciiCore(unicodeString, unicode, count, flags, output, length);
}
else
{
char[] output = new char[length];
fixed (char* pOutput = &output[0])
{
- return GetAsciiCore(unicodeString, unicode, count, flags, pOutput, length);
+ return NlsGetAsciiCore(unicodeString, unicode, count, flags, pOutput, length);
}
}
}
- private unsafe string GetAsciiCore(string unicodeString, char* unicode, int count, uint flags, char* output, int outputLength)
+ private unsafe string NlsGetAsciiCore(string unicodeString, char* unicode, int count, uint flags, char* output, int outputLength)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(unicodeString != null && unicodeString.Length >= count);
int length = Interop.Normaliz.IdnToAscii(flags, unicode, count, output, outputLength);
return GetStringForOutput(unicodeString, unicode, count, output, length);
}
- private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count)
+ private unsafe string NlsGetUnicodeCore(string asciiString, char* ascii, int count)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(asciiString != null && asciiString.Length >= count);
- uint flags = Flags;
+ uint flags = NlsFlags;
// Determine the required length
int length = Interop.Normaliz.IdnToUnicode(flags, ascii, count, null, 0);
if (length < StackAllocThreshold)
{
char* output = stackalloc char[length];
- return GetUnicodeCore(asciiString, ascii, count, flags, output, length);
+ return NlsGetUnicodeCore(asciiString, ascii, count, flags, output, length);
}
else
{
char[] output = new char[length];
fixed (char* pOutput = &output[0])
{
- return GetUnicodeCore(asciiString, ascii, count, flags, pOutput, length);
+ return NlsGetUnicodeCore(asciiString, ascii, count, flags, pOutput, length);
}
}
}
- private unsafe string GetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength)
+ private unsafe string NlsGetUnicodeCore(string asciiString, char* ascii, int count, uint flags, char* output, int outputLength)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(asciiString != null && asciiString.Length >= count);
int length = Interop.Normaliz.IdnToUnicode(flags, ascii, count, output, outputLength);
// ---- PAL layer ends here ----
// -----------------------------
- private uint Flags
+ private uint NlsFlags
{
get
{
{
fixed (char* pUnicode = unicode)
{
- return GetAsciiCore(unicode, pUnicode + index, count);
+ return GlobalizationMode.UseNls ?
+ NlsGetAsciiCore(unicode, pUnicode + index, count) :
+ IcuGetAsciiCore(unicode, pUnicode + index, count);
}
}
}
{
fixed (char* pAscii = ascii)
{
- return GetUnicodeCore(ascii, pAscii + index, count);
+ return GlobalizationMode.UseNls ?
+ NlsGetUnicodeCore(ascii, pAscii + index, count) :
+ IcuGetUnicodeCore(ascii, pAscii + index, count);
}
}
}
{
public partial class JapaneseCalendar : Calendar
{
- private static EraInfo[]? GetJapaneseEras()
+ private static EraInfo[]? IcuGetJapaneseEras()
{
if (GlobalizationMode.Invariant)
{
return null;
}
+ Debug.Assert(!GlobalizationMode.UseNls);
+
string[]? eraNames;
if (!CalendarData.EnumCalendarInfo("ja-JP", CalendarId.JAPAN, CalendarDataType.EraNames, out eraNames))
{
// 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.Diagnostics;
+
+#if TARGET_WINDOWS
using Internal.Win32;
+#endif
namespace System.Globalization
{
public partial class JapaneseCalendar : Calendar
{
+#if TARGET_WINDOWS
private const string JapaneseErasHive = @"System\CurrentControlSet\Control\Nls\Calendars\Japanese\Eras";
// We know about 4 built-in eras, however users may add additional era(s) from the
// . is a delimiter, but the value of . doesn't matter.
// '_' marks the space between the japanese era name, japanese abbreviated era name
// english name, and abbreviated english names.
- private static EraInfo[]? GetJapaneseEras()
+ private static EraInfo[]? NlsGetJapaneseEras()
{
+ Debug.Assert(GlobalizationMode.UseNls);
+
// Look in the registry key and see if we can find any ranges
int iFoundEras = 0;
EraInfo[]? registryEraRanges = null;
// Return our ranges
return registryEraRanges;
}
+#else
+ // no-op, in Unix we never call this function.
+ // the reason to have it is to simplify the build
+ // this way we avoid having to include RegistryKey
+ // and all it's windows PInvokes.
+ private static EraInfo[]? NlsGetJapaneseEras()
+ {
+ Debug.Fail("Should never be called non-Windows platforms.");
+ throw new PlatformNotSupportedException();
+ }
+#endif
//
// Compare two era ranges, eg just the ticks
{
// See if we need to build it
return s_japaneseEraInfo ??
- (s_japaneseEraInfo = GetJapaneseEras()) ??
+ (s_japaneseEraInfo = GlobalizationMode.UseNls ? NlsGetJapaneseEras() : IcuGetJapaneseEras()) ??
// See if we have to use the built-in eras
(s_japaneseEraInfo = new EraInfo[]
{
{
internal static partial class Normalization
{
- internal static unsafe bool IsNormalized(string strInput, NormalizationForm normalizationForm)
+ private static unsafe bool IcuIsNormalized(string strInput, NormalizationForm normalizationForm)
{
- if (GlobalizationMode.Invariant)
- {
- // In Invariant mode we assume all characters are normalized.
- // This is because we don't support any linguistic operation on the strings
- return true;
- }
+ Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
ValidateArguments(strInput, normalizationForm);
return ret == 1;
}
- internal static unsafe string Normalize(string strInput, NormalizationForm normalizationForm)
+ private static unsafe string IcuNormalize(string strInput, NormalizationForm normalizationForm)
{
- if (GlobalizationMode.Invariant)
- {
- // In Invariant mode we assume all characters are normalized.
- // This is because we don't support any linguistic operation on the strings
- return strInput;
- }
+ Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
ValidateArguments(strInput, normalizationForm);
{
internal static partial class Normalization
{
- internal static unsafe bool IsNormalized(string strInput, NormalizationForm normalizationForm)
+ private static unsafe bool NlsIsNormalized(string strInput, NormalizationForm normalizationForm)
{
- if (GlobalizationMode.Invariant)
- {
- // In Invariant mode we assume all characters are normalized.
- // This is because we don't support any linguistic operation on the strings
- return true;
- }
-
+ Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(strInput != null);
// The only way to know if IsNormalizedString failed is through checking the Win32 last error
return result != Interop.BOOL.FALSE;
}
- internal static unsafe string Normalize(string strInput, NormalizationForm normalizationForm)
+ private static unsafe string NlsNormalize(string strInput, NormalizationForm normalizationForm)
{
- if (GlobalizationMode.Invariant)
- {
- // In Invariant mode we assume all characters are normalized.
- // This is because we don't support any linguistic operation on the strings
- return strInput;
- }
-
+ Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(strInput != null);
if (strInput.Length == 0)
--- /dev/null
+// 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.Diagnostics;
+using System.Text;
+
+namespace System.Globalization
+{
+ internal static partial class Normalization
+ {
+ internal static bool IsNormalized(string strInput, NormalizationForm normalizationForm)
+ {
+ if (GlobalizationMode.Invariant)
+ {
+ // In Invariant mode we assume all characters are normalized.
+ // This is because we don't support any linguistic operation on the strings
+ return true;
+ }
+
+ return GlobalizationMode.UseNls ?
+ NlsIsNormalized(strInput, normalizationForm) :
+ IcuIsNormalized(strInput, normalizationForm);
+ }
+
+ internal static string Normalize(string strInput, NormalizationForm normalizationForm)
+ {
+ if (GlobalizationMode.Invariant)
+ {
+ // In Invariant mode we assume all characters are normalized.
+ // This is because we don't support any linguistic operation on the strings
+ return strInput;
+ }
+
+ return GlobalizationMode.UseNls ?
+ NlsNormalize(strInput, normalizationForm) :
+ IcuNormalize(strInput, normalizationForm);
+ }
+ }
+}
{
private Tristate _needsTurkishCasing = Tristate.NotInitialized;
- private void FinishInitialization() { }
-
// -----------------------------
// ---- PAL layer ends here ----
// -----------------------------
private bool IsInvariant { get { return _cultureName.Length == 0; } }
- internal unsafe void ChangeCase(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper)
+ internal unsafe void IcuChangeCase(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(!GlobalizationMode.UseNls);
if (IsInvariant)
{
{
public partial class TextInfo
{
- private unsafe void FinishInitialization()
- {
- _sortHandle = CompareInfo.GetSortHandle(_textInfoName);
- }
-
- private unsafe void ChangeCase(char* pSource, int pSourceLen, char* pResult, int pResultLen, bool toUpper)
+ private unsafe void NlsChangeCase(char* pSource, int pSourceLen, char* pResult, int pResultLen, bool toUpper)
{
Debug.Assert(!GlobalizationMode.Invariant);
+ Debug.Assert(GlobalizationMode.UseNls);
Debug.Assert(pSource != null);
Debug.Assert(pResult != null);
Debug.Assert(pSourceLen >= 0);
_cultureName = _cultureData.CultureName;
_textInfoName = _cultureData.TextInfoName;
- FinishInitialization();
+ if (GlobalizationMode.UseNls)
+ {
+ _sortHandle = CompareInfo.NlsGetSortHandle(_textInfoName);
+ }
}
private TextInfo(CultureData cultureData, bool readOnly)
Debug.Assert(!GlobalizationMode.Invariant);
char dst = default;
- ChangeCase(&c, 1, &dst, 1, toUpper);
+ ChangeCaseCore(&c, 1, &dst, 1, toUpper);
return dst;
}
// has a case conversion that's different from the invariant culture, even for ASCII data (e.g., tr-TR converts
// 'i' (U+0069) to Latin Capital Letter I With Dot Above (U+0130)).
- ChangeCase(pSource + currIdx, charCount, pDestination + currIdx, charCount, toUpper);
+ ChangeCaseCore(pSource + currIdx, charCount, pDestination + currIdx, charCount, toUpper);
}
Return:
// and run the culture-aware logic over the remainder of the data
fixed (char* pResult = result)
{
- ChangeCase(pSource + currIdx, source.Length - (int)currIdx, pResult + currIdx, result.Length - (int)currIdx, toUpper);
+ ChangeCaseCore(pSource + currIdx, source.Length - (int)currIdx, pResult + currIdx, result.Length - (int)currIdx, toUpper);
}
return result;
}
return inputIndex;
}
+ private unsafe void ChangeCaseCore(char* src, int srcLen, char* dstBuffer, int dstBufferCapacity, bool bToUpper)
+ {
+ if (GlobalizationMode.UseNls)
+ {
+ NlsChangeCase(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper);
+ }
+ else
+ {
+ IcuChangeCase(src, srcLen, dstBuffer, dstBufferCapacity, bToUpper);
+ }
+ }
+
// Used in ToTitleCase():
// When we find a starting letter, the following array decides if a category should be
// considered as word seprator or not.
--- /dev/null
+<Project Sdk="Microsoft.NET.Sdk">
+ <PropertyGroup>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+ <TestRuntime>true</TestRuntime>
+ <IncludeRemoteExecutor>true</IncludeRemoteExecutor>
+ <TargetFrameworks>$(NetCoreAppCurrent)-Windows_NT</TargetFrameworks>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="..\Helpers.cs">
+ <Link>Helpers.cs</Link>
+ </Compile>
+ <Compile Include="..\System\ArrayTests.cs">
+ <Link>System\ArrayTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\String.SplitTests.cs">
+ <Link>System\String.SplitTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\StringComparerTests.cs">
+ <Link>System\StringComparerTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\StringGetHashCodeTests.cs">
+ <Link>System\StringGetHashCodeTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\StringSplitExtensions.cs">
+ <Link>System\StringSplitExtensions.cs</Link>
+ </Compile>
+ <Compile Include="..\System\StringTests.cs">
+ <Link>System\StringTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Text\RuneTests.cs">
+ <Link>System\Text\RuneTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Text\RuneTests.TestData.cs">
+ <Link>System\Text\RuneTests.TestData.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Text\StringBuilderTests.cs">
+ <Link>System\Text\StringBuilderTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Uri.CreateStringTests.cs">
+ <Link>System\Uri.CreateStringTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Uri.CreateUriTests.cs">
+ <Link>System\Uri.CreateUriTests.cs</Link>
+ </Compile>
+ <Compile Include="..\System\Uri.MethodsTests.cs">
+ <Link>System\Uri.MethodsTests.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)System\EnumTypes.cs">
+ <Link>Common\System\EnumTypes.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)System\MockType.cs">
+ <Link>Common\System\MockType.cs</Link>
+ </Compile>
+ <Compile Include="$(CommonTestPath)Tests\System\StringTests.cs">
+ <Link>Common\System\StringTests.cs</Link>
+ </Compile>
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="$(CommonTestPath)CoreFx.Private.TestUtilities.Unicode\CoreFx.Private.TestUtilities.Unicode.csproj" />
+ </ItemGroup>
+</Project>
--- /dev/null
+{
+ "configProperties": {
+ "System.Globalization.UseNls": true
+ }
+}
<Link>Common\System\Collections\TestBase.NonGeneric.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)Tests\System\StringTests.cs">
- <Link>System\StringTests.cs</Link>
+ <Link>Common\System\StringTests.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)System\Collections\IDictionary.NonGeneric.Tests.cs">
<Link>Common\System\Collections\IDictionary.NonGeneric.Tests.cs</Link>
{
public static partial class RuneTests
{
- [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows8xOrLater))] // the localization tables used by our test data only exist on Win8+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows8xOrLater), nameof(PlatformDetection.IsNlsGlobalization))] // the localization tables used by our test data only exist on Win8+
[PlatformSpecific(TestPlatforms.Windows)]
[InlineData('0', '0', '0', "en-US")]
[InlineData('a', 'A', 'a', "en-US")]
}
// Invariant ToUpper / ToLower doesn't modify Turkish I or majuscule Eszett
- [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows8xOrLater))] // the localization tables used by our test data only exist on Win8+
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsWindows8xOrLater), nameof(PlatformDetection.IsNlsGlobalization))] // the localization tables used by our test data only exist on Win8+
[PlatformSpecific(TestPlatforms.Windows)]
[InlineData('0', '0', '0')]
[InlineData('a', 'A', 'a')]
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
+using System.Globalization;
using System.Linq;
using System.Runtime.InteropServices;
using Xunit;
Uri invalidPunicodeUri = new Uri("http://xn--\u1234pck.com");
yield return new object[] { invalidPunicodeUri, UriComponents.Host, "xn--\u1234pck.com" };
- if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) // expected platform differences, see https://github.com/dotnet/runtime/issues/17190
+ if (PlatformDetection.IsNlsGlobalization) // expected platform differences, see https://github.com/dotnet/runtime/issues/17190
{
yield return new object[] { invalidPunicodeUri, UriComponents.NormalizedHost, "xn--\u1234pck.com" };
}
AssertEqualOrdinal(Utf8Span.Empty, u8(""));
}
- [Theory]
[PlatformSpecific(TestPlatforms.Windows)]
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
[InlineData(null, null, StringComparison.OrdinalIgnoreCase, null, true)]
[InlineData("encyclopaedia", "encyclopædia", StringComparison.OrdinalIgnoreCase, null, false)]
[InlineData("encyclopaedia", "encyclopædia", StringComparison.InvariantCulture, null, true)]
}
}
- [Theory]
[PlatformSpecific(TestPlatforms.Windows)]
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
[MemberData(nameof(TryFindData_Char_WithComparison))]
public static void TryFind_Char_WithComparison(ustring source, char searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch)
{
}
}
- [Theory]
[PlatformSpecific(TestPlatforms.Windows)]
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
[MemberData(nameof(TryFindData_Rune_WithComparison))]
public static void TryFind_Rune_WithComparison(ustring source, Rune searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch)
{
}
}
- [Theory]
[PlatformSpecific(TestPlatforms.Windows)]
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
[MemberData(nameof(TryFindData_Utf8Span_WithComparison))]
public static void TryFind_Utf8Span_WithComparison(ustring source, ustring searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch)
{
}
}
- [Fact]
[PlatformSpecific(TestPlatforms.Windows)]
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
public static void GetHashCode_WithComparison()
{
// Since hash code generation is randomized, it's possible (though unlikely) that
public static IEnumerable<object[]> TryFindData_Char_WithComparison() => Utf8SpanTests.TryFindData_Char_WithComparison();
- [Theory]
[PlatformSpecific(TestPlatforms.Windows)]
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
[MemberData(nameof(TryFindData_Char_WithComparison))]
public static void TryFind_Char_WithComparison(ustring source, char searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch)
{
public static IEnumerable<object[]> TryFindData_Rune_WithComparison() => Utf8SpanTests.TryFindData_Rune_WithComparison();
- [Theory]
[PlatformSpecific(TestPlatforms.Windows)]
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
[MemberData(nameof(TryFindData_Rune_WithComparison))]
public static void TryFind_Rune_WithComparison(ustring source, Rune searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch)
{
public static IEnumerable<object[]> TryFindData_Utf8String_WithComparison() => Utf8SpanTests.TryFindData_Utf8Span_WithComparison();
- [Theory]
[PlatformSpecific(TestPlatforms.Windows)]
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
[MemberData(nameof(TryFindData_Utf8String_WithComparison))]
public static void TryFind_Utf8String_WithComparison(ustring source, ustring searchTerm, StringComparison comparison, CultureInfo currentCulture, Range? expectedForwardMatch, Range? expectedBackwardMatch)
{
}
}
- [Fact]
[PlatformSpecific(TestPlatforms.Windows)]
+ [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsNlsGlobalization))]
public static void GetHashCode_WithComparison()
{
// Since hash code generation is randomized, it's possible (though unlikely) that
{
internal partial class GlobalizationMode
{
+ internal static bool UseNls => false;
+
private static bool GetGlobalizationInvariantMode()
{
bool invariantEnabled = GetInvariantSwitchValue();
}
// Keep this in a separate method to avoid loading the native lib in invariant mode
- [MethodImplAttribute(MethodImplOptions.NoInlining)]
+ [MethodImpl(MethodImplOptions.NoInlining)]
private static void LoadICU()
{
int res = Interop.Globalization.LoadICU();
{
internal partial class GlobalizationMode
{
+ internal static bool UseNls => true;
+
private static bool GetGlobalizationInvariantMode()
{
return GetInvariantSwitchValue();
}
}
-}
\ No newline at end of file
+}