From e2d3897f9a8d5ba94af7fd8c0226301d77eb5e2d Mon Sep 17 00:00:00 2001 From: Azuk 443 Date: Fri, 22 Sep 2023 23:15:01 +0800 Subject: [PATCH 01/13] Add System.Convert.ToHexStringLower with tests --- .../src/System/Convert.cs | 53 ++++++++++++++++++- .../System.Runtime/ref/System.Runtime.cs | 3 ++ .../System/Convert.ToHexString.cs | 40 +++++++++++++- 3 files changed, 94 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Convert.cs b/src/libraries/System.Private.CoreLib/src/System/Convert.cs index ebf4ee8caaebfe..758cf10540b267 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Convert.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Convert.cs @@ -3077,7 +3077,6 @@ public static string ToHexString(ReadOnlySpan bytes) return HexConverter.ToString(bytes, HexConverter.Casing.Upper); } - /// /// Converts a span of 8-bit unsigned integers to its equivalent span representation that is encoded with uppercase hex characters. /// @@ -3102,5 +3101,57 @@ public static bool TryToHexString(ReadOnlySpan source, Span destinat charsWritten = source.Length * 2; return true; } + + /// + /// Converts an array of 8-bit unsigned integers to its equivalent string representation that is encoded with lowercase hex characters. + /// + /// An array of 8-bit unsigned integers. + /// The string representation in hex of the elements in . + /// is null. + /// is too large to be encoded. + public static string ToHexStringLower(byte[] inArray) + { + ArgumentNullException.ThrowIfNull(inArray); + + return ToHexStringLower(new ReadOnlySpan(inArray)); + } + + /// + /// Converts a subset of an array of 8-bit unsigned integers to its equivalent string representation that is encoded with lowercase hex characters. + /// Parameters specify the subset as an offset in the input array and the number of elements in the array to convert. + /// + /// An array of 8-bit unsigned integers. + /// An offset in . + /// The number of elements of to convert. + /// The string representation in hex of elements of , starting at position . + /// is null. + /// or is negative. + /// plus is greater than the length of . + /// is too large to be encoded. + public static string ToHexStringLower(byte[] inArray, int offset, int length) + { + ArgumentNullException.ThrowIfNull(inArray); + + ArgumentOutOfRangeException.ThrowIfNegative(length); + ArgumentOutOfRangeException.ThrowIfNegative(offset); + ArgumentOutOfRangeException.ThrowIfGreaterThan(offset, inArray.Length - length); + + return ToHexStringLower(new ReadOnlySpan(inArray, offset, length)); + } + + /// + /// Converts a span of 8-bit unsigned integers to its equivalent string representation that is encoded with lowercase hex characters. + /// + /// A span of 8-bit unsigned integers. + /// The string representation in hex of the elements in . + /// is too large to be encoded. + public static string ToHexStringLower(ReadOnlySpan bytes) + { + if (bytes.Length == 0) + return string.Empty; + ArgumentOutOfRangeException.ThrowIfGreaterThan(bytes.Length, int.MaxValue / 2, nameof(bytes)); + + return HexConverter.ToString(bytes, HexConverter.Casing.Lower); + } } // class Convert } // namespace diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index 231f2ab0584fb6..a3b07513dcf127 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -1285,6 +1285,9 @@ public static partial class Convert public static string ToHexString(byte[] inArray, int offset, int length) { throw null; } public static string ToHexString(System.ReadOnlySpan bytes) { throw null; } public static bool TryToHexString(System.ReadOnlySpan source, System.Span destination, out int charsWritten) { throw null; } + public static string ToHexStringLower(byte[] inArray) { throw null; } + public static string ToHexStringLower(byte[] inArray, int offset, int length) { throw null; } + public static string ToHexStringLower(System.ReadOnlySpan bytes) { throw null; } public static short ToInt16(bool value) { throw null; } public static short ToInt16(byte value) { throw null; } public static short ToInt16(char value) { throw null; } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.ToHexString.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.ToHexString.cs index b92685667dd50d..ed553d88d2f419 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.ToHexString.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.ToHexString.cs @@ -6,7 +6,7 @@ using System.Collections.Generic; namespace System.Tests -{ +{ public class ConvertToHexStringTests { [Fact] @@ -16,6 +16,13 @@ public static void KnownByteSequence() Assert.Equal("000102FDFEFF", Convert.ToHexString(inputBytes)); } + [Fact] + public static void KnownByteSequenceLower() + { + byte[] inputBytes = new byte[] { 0x00, 0x01, 0x02, 0xFD, 0xFE, 0xFF }; + Assert.Equal("000102fdfeff", Convert.ToHexStringLower(inputBytes)); + } + [Fact] public static void CompleteValueRange() { @@ -30,11 +37,26 @@ public static void CompleteValueRange() Assert.Equal(sb.ToString(), Convert.ToHexString(values)); } + [Fact] + public static void CompleteValueRangeLower() + { + byte[] values = new byte[256]; + StringBuilder sb = new StringBuilder(256); + for (int i = 0; i < values.Length; i++) + { + values[i] = (byte)i; + sb.Append($"{i:x2}"); + } + + Assert.Equal(sb.ToString(), Convert.ToHexStringLower(values)); + } + [Fact] public static void ZeroLength() { byte[] inputBytes = Convert.FromHexString("000102FDFEFF"); Assert.Same(string.Empty, Convert.ToHexString(inputBytes, 0, 0)); + Assert.Same(string.Empty, Convert.ToHexStringLower(inputBytes, 0, 0)); } [Fact] @@ -42,6 +64,8 @@ public static void InvalidInputBuffer() { AssertExtensions.Throws("inArray", () => Convert.ToHexString(null)); AssertExtensions.Throws("inArray", () => Convert.ToHexString(null, 0, 0)); + AssertExtensions.Throws("inArray", () => Convert.ToHexStringLower(null)); + AssertExtensions.Throws("inArray", () => Convert.ToHexStringLower(null, 0, 0)); } [Fact] @@ -50,6 +74,8 @@ public static void InvalidOffset() byte[] inputBytes = Convert.FromHexString("000102FDFEFF"); AssertExtensions.Throws("offset", () => Convert.ToHexString(inputBytes, -1, inputBytes.Length)); AssertExtensions.Throws("offset", () => Convert.ToHexString(inputBytes, inputBytes.Length, inputBytes.Length)); + AssertExtensions.Throws("offset", () => Convert.ToHexStringLower(inputBytes, -1, inputBytes.Length)); + AssertExtensions.Throws("offset", () => Convert.ToHexStringLower(inputBytes, inputBytes.Length, inputBytes.Length)); } [Fact] @@ -59,12 +85,16 @@ public static void InvalidLength() AssertExtensions.Throws("length", () => Convert.ToHexString(inputBytes, 0, -1)); AssertExtensions.Throws("offset", () => Convert.ToHexString(inputBytes, 0, inputBytes.Length + 1)); AssertExtensions.Throws("offset", () => Convert.ToHexString(inputBytes, 1, inputBytes.Length)); + AssertExtensions.Throws("length", () => Convert.ToHexStringLower(inputBytes, 0, -1)); + AssertExtensions.Throws("offset", () => Convert.ToHexStringLower(inputBytes, 0, inputBytes.Length + 1)); + AssertExtensions.Throws("offset", () => Convert.ToHexStringLower(inputBytes, 1, inputBytes.Length)); } [Fact] public static unsafe void InputTooLarge() { AssertExtensions.Throws("bytes", () => Convert.ToHexString(new ReadOnlySpan((void*)0, Int32.MaxValue))); + AssertExtensions.Throws("bytes", () => Convert.ToHexStringLower(new ReadOnlySpan((void*)0, Int32.MaxValue))); } public static IEnumerable ToHexStringTestData() @@ -106,5 +136,13 @@ public static unsafe void ToHexString(byte[] input, string expected) string actual = Convert.ToHexString(input); Assert.Equal(expected, actual); } + + [Theory] + [MemberData(nameof(ToHexStringTestData))] + public static unsafe void ToHexStringLower(byte[] input, string expected) + { + string actual = Convert.ToHexStringLower(input); + Assert.Equal(expected, actual.ToLower()); + } } } From 73e0be61c351da14e8a3508564094c17db1ff3d7 Mon Sep 17 00:00:00 2001 From: Azuk 443 Date: Fri, 22 Sep 2023 23:31:04 +0800 Subject: [PATCH 02/13] fix typo --- .../System/Convert.ToHexString.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.ToHexString.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.ToHexString.cs index ed553d88d2f419..fdcc022b03f90a 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.ToHexString.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.ToHexString.cs @@ -142,7 +142,7 @@ public static unsafe void ToHexString(byte[] input, string expected) public static unsafe void ToHexStringLower(byte[] input, string expected) { string actual = Convert.ToHexStringLower(input); - Assert.Equal(expected, actual.ToLower()); + Assert.Equal(expected.ToLower(), actual); } } } From 0d55d0c4ef582bc83accc1eb932a39dd58ee8188 Mon Sep 17 00:00:00 2001 From: Azuk 443 Date: Sat, 28 Oct 2023 15:09:10 +0800 Subject: [PATCH 03/13] Use new public API `Convert.ToHexStringLower` --- .../src/System/Diagnostics/Activity.cs | 10 +++++----- .../AuthenticationHelper.Digest.cs | 2 +- .../src/System/Net/Quic/Internal/MsQuicTlsSecret.cs | 12 ++++++------ .../src/Internal/Cryptography/PkcsHelpers.cs | 2 +- .../Security/Cryptography/Xml/SignedXmlDebugLog.cs | 2 +- .../src/System/Security/Cryptography/Xml/Utils.cs | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs index 1a5365594438ea..1edeeefd248f82 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs @@ -1782,7 +1782,7 @@ public static ActivityTraceId CreateFromBytes(ReadOnlySpan idData) if (idData.Length != 16) throw new ArgumentOutOfRangeException(nameof(idData)); - return new ActivityTraceId(HexConverter.ToString(idData, HexConverter.Casing.Lower)); + return new ActivityTraceId(Convert.ToHexStringLower(idData)); } public static ActivityTraceId CreateFromUtf8String(ReadOnlySpan idData) => new ActivityTraceId(idData); @@ -1861,7 +1861,7 @@ private ActivityTraceId(ReadOnlySpan idData) span[1] = BinaryPrimitives.ReverseEndianness(span[1]); } - _hexString = HexConverter.ToString(MemoryMarshal.AsBytes(span), HexConverter.Casing.Lower); + _hexString = Convert.ToHexStringLower(MemoryMarshal.AsBytes(span)); } /// @@ -1956,14 +1956,14 @@ public static unsafe ActivitySpanId CreateRandom() { ulong id; ActivityTraceId.SetToRandomBytes(new Span(&id, sizeof(ulong))); - return new ActivitySpanId(HexConverter.ToString(new ReadOnlySpan(&id, sizeof(ulong)), HexConverter.Casing.Lower)); + return new ActivitySpanId(Convert.ToHexStringLower(new ReadOnlySpan(&id, sizeof(ulong)))); } public static ActivitySpanId CreateFromBytes(ReadOnlySpan idData) { if (idData.Length != 8) throw new ArgumentOutOfRangeException(nameof(idData)); - return new ActivitySpanId(HexConverter.ToString(idData, HexConverter.Casing.Lower)); + return new ActivitySpanId(Convert.ToHexStringLower(idData)); } public static ActivitySpanId CreateFromUtf8String(ReadOnlySpan idData) => new ActivitySpanId(idData); @@ -2031,7 +2031,7 @@ private unsafe ActivitySpanId(ReadOnlySpan idData) id = BinaryPrimitives.ReverseEndianness(id); } - _hexString = HexConverter.ToString(new ReadOnlySpan(&id, sizeof(ulong)), HexConverter.Casing.Lower); + _hexString = Convert.ToHexStringLower(new ReadOnlySpan(&id, sizeof(ulong))); } /// diff --git a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.Digest.cs b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.Digest.cs index 58cf311b01ee89..ba07a0d702cd20 100644 --- a/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.Digest.cs +++ b/src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.Digest.cs @@ -230,7 +230,7 @@ private static string ComputeHash(string data, string algorithm) #pragma warning restore CA5351 } - return HexConverter.ToString(hashBuffer.Slice(0, written), HexConverter.Casing.Lower); + return Convert.ToHexStringLower(hashBuffer.Slice(0, written)); } internal sealed class DigestResponse diff --git a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicTlsSecret.cs b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicTlsSecret.cs index f151f123129097..26f69c1653aa83 100644 --- a/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicTlsSecret.cs +++ b/src/libraries/System.Net.Quic/src/System/Net/Quic/Internal/MsQuicTlsSecret.cs @@ -63,27 +63,27 @@ public unsafe void WriteSecret() string clientRandom = string.Empty; if (_tlsSecrets->IsSet.ClientRandom != 0) { - clientRandom = HexConverter.ToString(new ReadOnlySpan(_tlsSecrets->ClientRandom, 32)); + clientRandom = Convert.ToHexString(new ReadOnlySpan(_tlsSecrets->ClientRandom, 32)); } if (_tlsSecrets->IsSet.ClientHandshakeTrafficSecret != 0) { - s_fileStream.Write(Encoding.ASCII.GetBytes($"CLIENT_HANDSHAKE_TRAFFIC_SECRET {clientRandom} {HexConverter.ToString(new ReadOnlySpan(_tlsSecrets->ClientHandshakeTrafficSecret, _tlsSecrets->SecretLength))}\n")); + s_fileStream.Write(Encoding.ASCII.GetBytes($"CLIENT_HANDSHAKE_TRAFFIC_SECRET {clientRandom} {Convert.ToHexString(new ReadOnlySpan(_tlsSecrets->ClientHandshakeTrafficSecret, _tlsSecrets->SecretLength))}\n")); } if (_tlsSecrets->IsSet.ServerHandshakeTrafficSecret != 0) { - s_fileStream.Write(Encoding.ASCII.GetBytes($"SERVER_HANDSHAKE_TRAFFIC_SECRET {clientRandom} {HexConverter.ToString(new ReadOnlySpan(_tlsSecrets->ServerHandshakeTrafficSecret, _tlsSecrets->SecretLength))}\n")); + s_fileStream.Write(Encoding.ASCII.GetBytes($"SERVER_HANDSHAKE_TRAFFIC_SECRET {clientRandom} {Convert.ToHexString(new ReadOnlySpan(_tlsSecrets->ServerHandshakeTrafficSecret, _tlsSecrets->SecretLength))}\n")); } if (_tlsSecrets->IsSet.ClientTrafficSecret0 != 0) { - s_fileStream.Write(Encoding.ASCII.GetBytes($"CLIENT_TRAFFIC_SECRET_0 {clientRandom} {HexConverter.ToString(new ReadOnlySpan(_tlsSecrets->ClientTrafficSecret0, _tlsSecrets->SecretLength))}\n")); + s_fileStream.Write(Encoding.ASCII.GetBytes($"CLIENT_TRAFFIC_SECRET_0 {clientRandom} {Convert.ToHexString(new ReadOnlySpan(_tlsSecrets->ClientTrafficSecret0, _tlsSecrets->SecretLength))}\n")); } if (_tlsSecrets->IsSet.ServerTrafficSecret0 != 0) { - s_fileStream.Write(Encoding.ASCII.GetBytes($"SERVER_TRAFFIC_SECRET_0 {clientRandom} {HexConverter.ToString(new ReadOnlySpan(_tlsSecrets->ServerTrafficSecret0, _tlsSecrets->SecretLength))}\n")); + s_fileStream.Write(Encoding.ASCII.GetBytes($"SERVER_TRAFFIC_SECRET_0 {clientRandom} {Convert.ToHexString(new ReadOnlySpan(_tlsSecrets->ServerTrafficSecret0, _tlsSecrets->SecretLength))}\n")); } if (_tlsSecrets->IsSet.ClientEarlyTrafficSecret != 0) { - s_fileStream.Write(Encoding.ASCII.GetBytes($"CLIENT_EARLY_TRAFFIC_SECRET {clientRandom} {HexConverter.ToString(new ReadOnlySpan(_tlsSecrets->ClientEarlyTrafficSecret, _tlsSecrets->SecretLength))}\n")); + s_fileStream.Write(Encoding.ASCII.GetBytes($"CLIENT_EARLY_TRAFFIC_SECRET {clientRandom} {Convert.ToHexString(new ReadOnlySpan(_tlsSecrets->ClientEarlyTrafficSecret, _tlsSecrets->SecretLength))}\n")); } s_fileStream.Flush(); } diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs index 758be866d1caf2..ef6a8a22c161ad 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs @@ -367,7 +367,7 @@ public static string ToSerialString(this byte[] serialBytes) #if NETCOREAPP || NETSTANDARD2_1 private static string ToUpperHexString(ReadOnlySpan ba) { - return HexConverter.ToString(ba, HexConverter.Casing.Upper); + return Convert.ToHexString(ba); } #else private static string ToUpperHexString(ReadOnlySpan ba) diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs index 64268c03726a88..7fb6053fdf34dc 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs @@ -197,7 +197,7 @@ private static string FormatBytes(byte[]? bytes) if (bytes == null) return NullString; - return HexConverter.ToString(bytes, HexConverter.Casing.Lower); + return Convert.ToHexStringLower(bytes); } /// diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs index 0483550c4b7818..38f21e49db9278 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs @@ -722,7 +722,7 @@ internal static X509Certificate2Collection BuildBagOfCerts(KeyInfoX509Data keyIn internal static string EncodeHexString(byte[] sArray) { - return HexConverter.ToString(sArray); + return Convert.ToHexString(sArray); } internal static byte[] DecodeHexString(string s) From 8ba2f8907f6a72fa5ed71bc15db86cb23f66e69f Mon Sep 17 00:00:00 2001 From: Azuk 443 Date: Tue, 14 Nov 2023 18:29:59 +0800 Subject: [PATCH 04/13] Add `Convert.TryToHexStringLower` --- .../src/System/Convert.cs | 25 +++++++++++++++++++ .../System.Runtime/ref/System.Runtime.cs | 1 + 2 files changed, 26 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Convert.cs b/src/libraries/System.Private.CoreLib/src/System/Convert.cs index 758cf10540b267..23caa722f106c5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Convert.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Convert.cs @@ -3153,5 +3153,30 @@ public static string ToHexStringLower(ReadOnlySpan bytes) return HexConverter.ToString(bytes, HexConverter.Casing.Lower); } + + /// + /// Converts a span of 8-bit unsigned integers to its equivalent span representation that is encoded with lowercase hex characters. + /// + /// A span of 8-bit unsigned integers. + /// The span representation in hex of the elements in . + /// When this method returns, contains the number of chars that were written in . + /// true if the conversion was successful; otherwise, false. + public static bool TryToHexStringLower(ReadOnlySpan source, Span destination, out int charsWritten) + { + if (source.Length == 0) + { + charsWritten = 0; + return true; + } + else if (source.Length > int.MaxValue / 2 || destination.Length > source.Length * 2) + { + charsWritten = 0; + return false; + } + + HexConverter.EncodeToUtf16(source, destination, HexConverter.Casing.Lower); + charsWritten = source.Length * 2; + return true; + } } // class Convert } // namespace diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index a3b07513dcf127..f44120923c360e 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -1288,6 +1288,7 @@ public static partial class Convert public static string ToHexStringLower(byte[] inArray) { throw null; } public static string ToHexStringLower(byte[] inArray, int offset, int length) { throw null; } public static string ToHexStringLower(System.ReadOnlySpan bytes) { throw null; } + public static bool TryToHexStringLower(System.ReadOnlySpan source, System.Span destination, out int charsWritten) { throw null; } public static short ToInt16(bool value) { throw null; } public static short ToInt16(byte value) { throw null; } public static short ToInt16(char value) { throw null; } From 3356999227efae76a4f0b42b2c2d46202b395321 Mon Sep 17 00:00:00 2001 From: Azuk 443 Date: Thu, 16 Nov 2023 17:35:20 +0800 Subject: [PATCH 05/13] format code --- src/libraries/System.Private.CoreLib/src/System/Convert.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Convert.cs b/src/libraries/System.Private.CoreLib/src/System/Convert.cs index 23caa722f106c5..6b57d805c908c3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Convert.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Convert.cs @@ -3098,7 +3098,7 @@ public static bool TryToHexString(ReadOnlySpan source, Span destinat } HexConverter.EncodeToUtf16(source, destination); - charsWritten = source.Length * 2; + charsWritten = source.Length * 2; return true; } @@ -3175,7 +3175,7 @@ public static bool TryToHexStringLower(ReadOnlySpan source, Span des } HexConverter.EncodeToUtf16(source, destination, HexConverter.Casing.Lower); - charsWritten = source.Length * 2; + charsWritten = source.Length * 2; return true; } } // class Convert From 07f6c56861c56ddde83446ddf5e114da1e8ea249 Mon Sep 17 00:00:00 2001 From: Azuk 443 Date: Thu, 16 Nov 2023 17:36:46 +0800 Subject: [PATCH 06/13] sort methods --- src/libraries/System.Runtime/ref/System.Runtime.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs index f44120923c360e..c75fead73c04c8 100644 --- a/src/libraries/System.Runtime/ref/System.Runtime.cs +++ b/src/libraries/System.Runtime/ref/System.Runtime.cs @@ -1284,11 +1284,9 @@ public static partial class Convert public static string ToHexString(byte[] inArray) { throw null; } public static string ToHexString(byte[] inArray, int offset, int length) { throw null; } public static string ToHexString(System.ReadOnlySpan bytes) { throw null; } - public static bool TryToHexString(System.ReadOnlySpan source, System.Span destination, out int charsWritten) { throw null; } public static string ToHexStringLower(byte[] inArray) { throw null; } public static string ToHexStringLower(byte[] inArray, int offset, int length) { throw null; } public static string ToHexStringLower(System.ReadOnlySpan bytes) { throw null; } - public static bool TryToHexStringLower(System.ReadOnlySpan source, System.Span destination, out int charsWritten) { throw null; } public static short ToInt16(bool value) { throw null; } public static short ToInt16(byte value) { throw null; } public static short ToInt16(char value) { throw null; } @@ -1581,6 +1579,8 @@ public static partial class Convert public static bool TryFromBase64Chars(System.ReadOnlySpan chars, System.Span bytes, out int bytesWritten) { throw null; } public static bool TryFromBase64String(string s, System.Span bytes, out int bytesWritten) { throw null; } public static bool TryToBase64Chars(System.ReadOnlySpan bytes, System.Span chars, out int charsWritten, System.Base64FormattingOptions options = System.Base64FormattingOptions.None) { throw null; } + public static bool TryToHexString(System.ReadOnlySpan source, System.Span destination, out int charsWritten) { throw null; } + public static bool TryToHexStringLower(System.ReadOnlySpan source, System.Span destination, out int charsWritten) { throw null; } } public delegate TOutput Converter(TInput input); public readonly partial struct DateOnly : System.IComparable, System.IComparable, System.IEquatable, System.IFormattable, System.IParsable, System.ISpanFormattable, System.ISpanParsable, System.IUtf8SpanFormattable From 32a7d9313f6872b4db7789bd0a6727fdd14cc5c0 Mon Sep 17 00:00:00 2001 From: Azuk 443 Date: Thu, 16 Nov 2023 17:48:07 +0800 Subject: [PATCH 07/13] use old `HexConverter` API on `System.Diagnostics.DiagnosticSource` --- .../src/System/Diagnostics/Activity.cs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs index 1edeeefd248f82..b5f5385a190d00 100644 --- a/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs +++ b/src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/Activity.cs @@ -1782,7 +1782,11 @@ public static ActivityTraceId CreateFromBytes(ReadOnlySpan idData) if (idData.Length != 16) throw new ArgumentOutOfRangeException(nameof(idData)); +#if NET9_0_OR_GREATER return new ActivityTraceId(Convert.ToHexStringLower(idData)); +#else + return new ActivityTraceId(HexConverter.ToString(idData, HexConverter.Casing.Lower)); +#endif } public static ActivityTraceId CreateFromUtf8String(ReadOnlySpan idData) => new ActivityTraceId(idData); @@ -1861,7 +1865,11 @@ private ActivityTraceId(ReadOnlySpan idData) span[1] = BinaryPrimitives.ReverseEndianness(span[1]); } +#if NET9_0_OR_GREATER _hexString = Convert.ToHexStringLower(MemoryMarshal.AsBytes(span)); +#else + _hexString = HexConverter.ToString(MemoryMarshal.AsBytes(span), HexConverter.Casing.Lower); +#endif } /// @@ -1956,14 +1964,22 @@ public static unsafe ActivitySpanId CreateRandom() { ulong id; ActivityTraceId.SetToRandomBytes(new Span(&id, sizeof(ulong))); +#if NET9_0_OR_GREATER return new ActivitySpanId(Convert.ToHexStringLower(new ReadOnlySpan(&id, sizeof(ulong)))); +#else + return new ActivitySpanId(HexConverter.ToString(new ReadOnlySpan(&id, sizeof(ulong)), HexConverter.Casing.Lower)); +#endif } public static ActivitySpanId CreateFromBytes(ReadOnlySpan idData) { if (idData.Length != 8) throw new ArgumentOutOfRangeException(nameof(idData)); +#if NET9_0_OR_GREATER return new ActivitySpanId(Convert.ToHexStringLower(idData)); +#else + return new ActivitySpanId(HexConverter.ToString(idData, HexConverter.Casing.Lower)); +#endif } public static ActivitySpanId CreateFromUtf8String(ReadOnlySpan idData) => new ActivitySpanId(idData); @@ -2031,7 +2047,11 @@ private unsafe ActivitySpanId(ReadOnlySpan idData) id = BinaryPrimitives.ReverseEndianness(id); } +#if NET9_0_OR_GREATER _hexString = Convert.ToHexStringLower(new ReadOnlySpan(&id, sizeof(ulong))); +#else + _hexString = HexConverter.ToString(new ReadOnlySpan(&id, sizeof(ulong)), HexConverter.Casing.Lower); +#endif } /// From c7c91792377e66f8dac0e0d9eee67e8bdb92dd39 Mon Sep 17 00:00:00 2001 From: Azuk 443 Date: Thu, 16 Nov 2023 18:01:14 +0800 Subject: [PATCH 08/13] Add unit test for `Convert.TryToHexStringLower` --- .../System/Convert.FromHexString.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.FromHexString.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.FromHexString.cs index ad032d931f2bbd..8e72b7749ef423 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.FromHexString.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.FromHexString.cs @@ -86,6 +86,7 @@ public static void ToHexFromHexRoundtrip() { const int loopCount = 50; Span buffer = stackalloc char[loopCount * 2]; + Span bufferLower = stackalloc char[loopCount * 2]; for (int i = 1; i < loopCount; i++) { byte[] data = Security.Cryptography.RandomNumberGenerator.GetBytes(i); @@ -97,6 +98,12 @@ public static void ToHexFromHexRoundtrip() AssertExtensions.SequenceEqual(hex.AsSpan(), currentBuffer); Assert.Equal(hex.Length, written); + Span currentBufferLower = bufferLower.Slice(0, i * 2); + tryHex = Convert.TryToHexStringLower(data, currentBufferLower, out written); + Assert.True(tryHex); + AssertExtensions.SequenceEqual(currentBuffer, currentBufferLower); + Assert.Equal(hex.Length, written); + TestSequence(data, hex); TestSequence(data, hex.ToLowerInvariant()); TestSequence(data, hex.ToUpperInvariant()); From 9f43dbddce343bfd19957e9361772111c393e28b Mon Sep 17 00:00:00 2001 From: Azuk 443 Date: Thu, 16 Nov 2023 19:00:00 +0800 Subject: [PATCH 09/13] bug fix --- .../System/Convert.FromHexString.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.FromHexString.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.FromHexString.cs index 8e72b7749ef423..dc80b4c0e9b787 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.FromHexString.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Convert.FromHexString.cs @@ -101,7 +101,7 @@ public static void ToHexFromHexRoundtrip() Span currentBufferLower = bufferLower.Slice(0, i * 2); tryHex = Convert.TryToHexStringLower(data, currentBufferLower, out written); Assert.True(tryHex); - AssertExtensions.SequenceEqual(currentBuffer, currentBufferLower); + AssertExtensions.SequenceEqual(hex.ToLowerInvariant().AsSpan(), currentBufferLower); Assert.Equal(hex.Length, written); TestSequence(data, hex); From 660890f25a57207114e310af705439eecf75bbbc Mon Sep 17 00:00:00 2001 From: Azuk 443 Date: Thu, 16 Nov 2023 20:22:52 +0800 Subject: [PATCH 10/13] add if-defs for libs --- .../src/Internal/Cryptography/PkcsHelpers.cs | 7 ++++++- .../System/Security/Cryptography/Xml/SignedXmlDebugLog.cs | 4 ++++ .../src/System/Security/Cryptography/Xml/Utils.cs | 7 +++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs index ef6a8a22c161ad..6351a376c0bc72 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs @@ -364,11 +364,16 @@ public static string ToSerialString(this byte[] serialBytes) return ToUpperHexString(serialBytes); } -#if NETCOREAPP || NETSTANDARD2_1 +#if NET5_0_OR_GREATER private static string ToUpperHexString(ReadOnlySpan ba) { return Convert.ToHexString(ba); } +#elif NETCOREAPP || NETSTANDARD2_1 + private static string ToUpperHexString(ReadOnlySpan ba) + { + return HexConverter.ToString(ba, HexConverter.Casing.Upper); + } #else private static string ToUpperHexString(ReadOnlySpan ba) { diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs index 7fb6053fdf34dc..476de02a3fa4c3 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/SignedXmlDebugLog.cs @@ -197,7 +197,11 @@ private static string FormatBytes(byte[]? bytes) if (bytes == null) return NullString; +#if NET9_0_OR_GREATER return Convert.ToHexStringLower(bytes); +#else + return HexConverter.ToString(bytes, HexConverter.Casing.Lower); +#endif } /// diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs index 38f21e49db9278..ffffeefa5bac37 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs @@ -720,10 +720,17 @@ internal static X509Certificate2Collection BuildBagOfCerts(KeyInfoX509Data keyIn return collection; } +#if NET5_0_OR_GREATER internal static string EncodeHexString(byte[] sArray) { return Convert.ToHexString(sArray); } +#else + internal static string EncodeHexString(byte[] sArray) + { + return HexConverter.ToString(sArray); + } +#endif internal static byte[] DecodeHexString(string s) { From e56b06ae2f28d494c626abcf409ce33411046953 Mon Sep 17 00:00:00 2001 From: Azuk 443 Date: Sat, 18 Nov 2023 12:54:39 +0800 Subject: [PATCH 11/13] removed whitespace --- src/libraries/System.Private.CoreLib/src/System/Convert.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Convert.cs b/src/libraries/System.Private.CoreLib/src/System/Convert.cs index 6b57d805c908c3..ca8979c231f8b7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Convert.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Convert.cs @@ -3091,7 +3091,7 @@ public static bool TryToHexString(ReadOnlySpan source, Span destinat charsWritten = 0; return true; } - else if (source.Length > int.MaxValue / 2 || destination.Length > source.Length * 2) + else if (source.Length > int.MaxValue / 2 || destination.Length > source.Length * 2) { charsWritten = 0; return false; @@ -3168,7 +3168,7 @@ public static bool TryToHexStringLower(ReadOnlySpan source, Span des charsWritten = 0; return true; } - else if (source.Length > int.MaxValue / 2 || destination.Length > source.Length * 2) + else if (source.Length > int.MaxValue / 2 || destination.Length > source.Length * 2) { charsWritten = 0; return false; From 1dc62ae3fd1e777a086fda203032e3f7b3862d77 Mon Sep 17 00:00:00 2001 From: Azuk 443 Date: Sat, 18 Nov 2023 13:20:10 +0800 Subject: [PATCH 12/13] TEST: test if Convert.ToHexString works without if-def --- .../src/System/Security/Cryptography/Xml/Utils.cs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs index ffffeefa5bac37..38f21e49db9278 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs @@ -720,17 +720,10 @@ internal static X509Certificate2Collection BuildBagOfCerts(KeyInfoX509Data keyIn return collection; } -#if NET5_0_OR_GREATER internal static string EncodeHexString(byte[] sArray) { return Convert.ToHexString(sArray); } -#else - internal static string EncodeHexString(byte[] sArray) - { - return HexConverter.ToString(sArray); - } -#endif internal static byte[] DecodeHexString(string s) { From a5609b5e8e626b68aa92d05fd78e1e435e38f1d4 Mon Sep 17 00:00:00 2001 From: Azuk 443 Date: Sat, 18 Nov 2023 13:52:16 +0800 Subject: [PATCH 13/13] Revert "TEST: test if Convert.ToHexString works without if-def" This reverts commit 1dc62ae3fd1e777a086fda203032e3f7b3862d77. --- .../src/System/Security/Cryptography/Xml/Utils.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs index 38f21e49db9278..ffffeefa5bac37 100644 --- a/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs +++ b/src/libraries/System.Security.Cryptography.Xml/src/System/Security/Cryptography/Xml/Utils.cs @@ -720,10 +720,17 @@ internal static X509Certificate2Collection BuildBagOfCerts(KeyInfoX509Data keyIn return collection; } +#if NET5_0_OR_GREATER internal static string EncodeHexString(byte[] sArray) { return Convert.ToHexString(sArray); } +#else + internal static string EncodeHexString(byte[] sArray) + { + return HexConverter.ToString(sArray); + } +#endif internal static byte[] DecodeHexString(string s) {