|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Globalization;
namespace System
{
public sealed partial class TimeZoneInfo
{
private static unsafe bool TryConvertIanaIdToWindowsId(string ianaId, bool allocate, out string? windowsId)
{
#if TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
windowsId = null;
return false;
#else
if (GlobalizationMode.Invariant ||
GlobalizationMode.UseNls ||
ianaId is null ||
ianaId.AsSpan().ContainsAny('\\', '\n', '\r')) // ICU uses these characters as a separator
{
windowsId = null;
return false;
}
char* buffer = stackalloc char[100];
int length = Interop.Globalization.IanaIdToWindowsId(ianaId, buffer, 100);
if (length > 0)
{
windowsId = allocate ? new string(buffer, 0, length) : null;
return true;
}
windowsId = null;
return false;
#endif
}
private static unsafe bool TryConvertWindowsIdToIanaId(string windowsId, string? region, bool allocate, out string? ianaId)
{
#if TARGET_MACCATALYST || TARGET_IOS || TARGET_TVOS
ianaId = null;
return false;
#else
// This functionality is not enabled in the browser for the sake of size reduction.
if (GlobalizationMode.Invariant || GlobalizationMode.UseNls || windowsId is null)
{
ianaId = null;
return false;
}
if (windowsId.Equals("utc", StringComparison.OrdinalIgnoreCase))
{
// Special case UTC, as previously ICU would convert it to "Etc/GMT" which is incorrect name for UTC.
ianaId = "Etc/UTC";
return true;
}
if (windowsId.AsSpan().ContainsAny('\\', '\n', '\r')) // ICU uses these characters as a separator
{
ianaId = null;
return false;
}
// regionPtr will point at the region name encoded as ASCII.
IntPtr regionPtr = IntPtr.Zero;
// Regions usually are 2 or 3 characters length.
const int MaxRegionNameLength = 11;
// Ensure uppercasing the region as ICU require the region names be uppercased, otherwise ICU will assume default region and return unexpected result.
if (region is not null && region.Length < MaxRegionNameLength)
{
byte* regionInAscii = stackalloc byte[region.Length + 1];
int i = 0;
for (; i < region.Length && region[i] <= '\u007F'; i++)
{
regionInAscii[i] = char.IsAsciiLetterLower(region[i]) ? (byte)((region[i] - 'a') + 'A') : (byte)region[i];
}
if (i >= region.Length)
{
regionInAscii[region.Length] = 0;
regionPtr = new IntPtr(regionInAscii);
}
// In case getting unexpected region names, we just fallback using the default region (passing null region name to the ICU API).
}
char* buffer = stackalloc char[100];
int length = Interop.Globalization.WindowsIdToIanaId(windowsId, regionPtr, buffer, 100);
if (length > 0)
{
ianaId = allocate ? new string(buffer, 0, length) : null;
return true;
}
ianaId = null;
return false;
#endif
}
}
}
|