diff --git a/PolyShim.Tests/Net50/ConvertTests.cs b/PolyShim.Tests/Net50/ConvertTests.cs new file mode 100644 index 0000000..91b72f7 --- /dev/null +++ b/PolyShim.Tests/Net50/ConvertTests.cs @@ -0,0 +1,29 @@ +using System; +using FluentAssertions; +using Xunit; + +namespace PolyShim.Tests.Net50; + +public class ConvertTests +{ + [Fact] + public void FromHexString_Test() + { + // Act & assert + Convert.FromHexString("4A6F686E").Should().Equal("John"u8.ToArray()); + Convert.FromHexString("4a6f686e").Should().Equal("John"u8.ToArray()); + Convert.FromHexString("4A6f686E").Should().Equal("John"u8.ToArray()); + Convert.FromHexString("").Should().BeEmpty(); + Assert.Throws(() => Convert.FromHexString("4A6F686")); // Odd length + Assert.Throws(() => Convert.FromHexString("4A6F68GH")); // Invalid character + } + + [Fact] + public void ToHexString_Test() + { + // Act & assert + Convert.ToHexString("John"u8.ToArray()).Should().Be("4A6F686E"); + Convert.ToHexString([]).Should().Be(""); + Convert.ToHexString("John"u8.ToArray(), 1, 2).Should().Be("6F68"); + } +} diff --git a/PolyShim.Tests/Net90/ConvertTests.cs b/PolyShim.Tests/Net90/ConvertTests.cs new file mode 100644 index 0000000..dde01bf --- /dev/null +++ b/PolyShim.Tests/Net90/ConvertTests.cs @@ -0,0 +1,17 @@ +using System; +using FluentAssertions; +using Xunit; + +namespace PolyShim.Tests.Net90; + +public class ConvertTests +{ + [Fact] + public void ToHexStringLower_Test() + { + // Act & assert + Convert.ToHexStringLower("John"u8.ToArray()).Should().Be("4a6f686e"); + Convert.ToHexStringLower([]).Should().Be(""); + Convert.ToHexStringLower("John"u8.ToArray(), 1, 2).Should().Be("6f68"); + } +} diff --git a/PolyShim/Net50/Convert.cs b/PolyShim/Net50/Convert.cs new file mode 100644 index 0000000..b806648 --- /dev/null +++ b/PolyShim/Net50/Convert.cs @@ -0,0 +1,66 @@ +#if (NETCOREAPP && !NET5_0_OR_GREATER) || (NETFRAMEWORK) || (NETSTANDARD) +#nullable enable +// ReSharper disable RedundantUsingDirective +// ReSharper disable CheckNamespace +// ReSharper disable InconsistentNaming +// ReSharper disable PartialTypeWithSinglePart + +using System; + +internal static partial class PolyfillExtensions +{ + extension(Convert) + { + // https://learn.microsoft.com/dotnet/api/system.convert.fromhexstring#system-convert-fromhexstring(system-string) + public static byte[] FromHexString(string s) + { + static int GetHexValue(char c) + { + if (c is >= '0' and <= '9') + return c - '0'; + if (c is >= 'A' and <= 'F') + return c - 'A' + 10; + if (c is >= 'a' and <= 'f') + return c - 'a' + 10; + + throw new FormatException($"Invalid hex character '{c}'."); + } + + if (s.Length % 2 != 0) + throw new FormatException("The hex string must have an even length."); + + var byteCount = s.Length / 2; + var bytes = new byte[byteCount]; + + for (var i = 0; i < byteCount; i++) + { + var highNibble = s[i * 2]; + var lowNibble = s[i * 2 + 1]; + + bytes[i] = (byte)((GetHexValue(highNibble) << 4) + GetHexValue(lowNibble)); + } + + return bytes; + } + + // https://learn.microsoft.com/dotnet/api/system.convert.tohexstring#system-convert-tohexstring(system-byte()-system-int32-system-int32) + public static string ToHexString(byte[] value, int startIndex, int length) + { + var c = new char[length * 2]; + + for (var i = 0; i < length; i++) + { + var b = value[startIndex + i] >> 4; + c[i * 2] = (char)(55 + b + (((b - 10) >> 31) & -7)); + b = value[startIndex + i] & 0xF; + c[i * 2 + 1] = (char)(55 + b + (((b - 10) >> 31) & -7)); + } + + return new string(c); + } + + // https://learn.microsoft.com/dotnet/api/system.convert.tohexstring#system-convert-tohexstring(system-byte()) + public static string ToHexString(byte[] value) => ToHexString(value, 0, value.Length); + } +} +#endif diff --git a/PolyShim/Net90/Convert.cs b/PolyShim/Net90/Convert.cs new file mode 100644 index 0000000..9ac441a --- /dev/null +++ b/PolyShim/Net90/Convert.cs @@ -0,0 +1,23 @@ +#if (NETCOREAPP && !NET9_0_OR_GREATER) || (NETFRAMEWORK) || (NETSTANDARD) +#nullable enable +// ReSharper disable RedundantUsingDirective +// ReSharper disable CheckNamespace +// ReSharper disable InconsistentNaming +// ReSharper disable PartialTypeWithSinglePart + +using System; + +internal static partial class PolyfillExtensions +{ + extension(Convert) + { + // https://learn.microsoft.com/dotnet/api/system.convert.tohexstringlower#system-convert-tohexstringlower(system-byte()-system-int32-system-int32) + public static string ToHexStringLower(byte[] value, int startIndex, int length) => + Convert.ToHexString(value, startIndex, length).ToLowerInvariant(); + + // https://learn.microsoft.com/dotnet/api/system.convert.tohexstringlower#system-convert-tohexstringlower(system-byte()) + public static string ToHexStringLower(byte[] value) => + ToHexStringLower(value, 0, value.Length); + } +} +#endif diff --git a/PolyShim/Signatures.md b/PolyShim/Signatures.md index 0d51a86..dd78c38 100644 --- a/PolyShim/Signatures.md +++ b/PolyShim/Signatures.md @@ -1,8 +1,8 @@ # Signatures -- **Total:** 259 +- **Total:** 264 - **Types:** 62 -- **Members:** 197 +- **Members:** 202 ___ @@ -26,6 +26,12 @@ ___ - [`Task CancelAsync()`](https://learn.microsoft.com/dotnet/api/system.threading.cancellationtokensource.cancelasync) .NET 8.0 - `CompilerFeatureRequiredAttribute` - [**[class]**](https://learn.microsoft.com/dotnet/api/system.runtime.compilerservices.compilerfeaturerequiredattribute) .NET 7.0 +- `Convert` + - [`byte[] FromHexString(string)`](https://learn.microsoft.com/dotnet/api/system.convert.fromhexstring#system-convert-fromhexstring(system-string)) .NET 5.0 + - [`string ToHexString(byte[], int, int)`](https://learn.microsoft.com/dotnet/api/system.convert.tohexstring#system-convert-tohexstring(system-byte()-system-int32-system-int32)) .NET 5.0 + - [`string ToHexString(byte[])`](https://learn.microsoft.com/dotnet/api/system.convert.tohexstring#system-convert-tohexstring(system-byte())) .NET 5.0 + - [`string ToHexStringLower(byte[], int, int)`](https://learn.microsoft.com/dotnet/api/system.convert.tohexstringlower#system-convert-tohexstringlower(system-byte()-system-int32-system-int32)) .NET 9.0 + - [`string ToHexStringLower(byte[])`](https://learn.microsoft.com/dotnet/api/system.convert.tohexstringlower#system-convert-tohexstringlower(system-byte())) .NET 9.0 - `DateTime` - [`DateTime UnixEpoch`](https://learn.microsoft.com/dotnet/api/system.datetime.unixepoch) .NET Core 2.1 - `DateTimeOffset`