diff --git a/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberDocumentViewerToolTipProvider.cs b/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberDocumentViewerToolTipProvider.cs index b8d392a0fa..a1349603e0 100644 --- a/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberDocumentViewerToolTipProvider.cs +++ b/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberDocumentViewerToolTipProvider.cs @@ -53,11 +53,10 @@ sealed class NumberDocumentViewerToolTipProvider : IDocumentViewerToolTipProvide return null; } - static readonly (int @base, int groupSize)[] numberBases = new (int, int)[] { - (2, 4), - (8, 4), - (10, 3), - (16, 4), + static readonly (int @base, int groupSize, string groupSeparator)[] numberBases = new (int, int, string)[] { + (2, 4, " "), + (10, 3, "_"), + (16, 0, string.Empty), }; object Create(IDocumentViewerToolTipProviderContext context, Func toBase) { var provider = context.Create(); @@ -74,26 +73,26 @@ object Create(IDocumentViewerToolTipProviderContext context, Func Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); - object CreateByte(IDocumentViewerToolTipProviderContext context, byte value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); - object CreateInt16(IDocumentViewerToolTipProviderContext context, short value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); - object CreateUInt16(IDocumentViewerToolTipProviderContext context, ushort value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); - object CreateInt32(IDocumentViewerToolTipProviderContext context, int value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); - object CreateUInt32(IDocumentViewerToolTipProviderContext context, uint value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); - object CreateInt64(IDocumentViewerToolTipProviderContext context, long value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); - object CreateUInt64(IDocumentViewerToolTipProviderContext context, ulong value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value)); + object CreateSByte(IDocumentViewerToolTipProviderContext context, sbyte value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(sbyte))); + object CreateByte(IDocumentViewerToolTipProviderContext context, byte value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(byte))); + object CreateInt16(IDocumentViewerToolTipProviderContext context, short value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(short))); + object CreateUInt16(IDocumentViewerToolTipProviderContext context, ushort value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(ushort))); + object CreateInt32(IDocumentViewerToolTipProviderContext context, int value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(int))); + object CreateUInt32(IDocumentViewerToolTipProviderContext context, uint value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(uint))); + object CreateInt64(IDocumentViewerToolTipProviderContext context, long value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(long))); + object CreateUInt64(IDocumentViewerToolTipProviderContext context, ulong value) => Create(context, (sb, n) => NumberUtils.ToString(sb, n, value, sizeof(ulong))); - object CreateFloat(IDocumentViewerToolTipProviderContext context, string valueStr, string serializedFormatStr, string serializedValueStr, Func getRawValue) { + object CreateFloat(IDocumentViewerToolTipProviderContext context, string valueStr, string serializedFormatStr, string serializedValueStr, Func getRawValue) { var provider = context.Create(); provider.Image = DsImages.ConstantPublic; - + var sb = new StringBuilder(); provider.Output.Write(BoxedTextColor.Number, valueStr); @@ -104,8 +103,7 @@ object CreateFloat(IDocumentViewerToolTipProviderContext context, string valueSt provider.Output.Write(BoxedTextColor.Number, serializedValueStr); provider.Output.WriteLine(); - var rawValueStr = getRawValue(); - rawValueStr = "0x" + NumberUtils.AddDigitSeparators(sb, rawValueStr, 4, "_"); + var rawValueStr = getRawValue(sb); provider.Output.Write(BoxedTextColor.Text, dnSpy_Resources.RawValue); provider.Output.Write(BoxedTextColor.Text, " "); provider.Output.Write(BoxedTextColor.Number, rawValueStr); @@ -115,16 +113,18 @@ object CreateFloat(IDocumentViewerToolTipProviderContext context, string valueSt object CreateSingle(IDocumentViewerToolTipProviderContext context, float value) { const string format = "G9"; + const bool upper = true; uint rawValue = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0); return CreateFloat(context, value.ToString(), format, value.ToString(format), - () => rawValue.ToString("X8")); + sb => NumberUtils.ToFixedSizeHexadecimalArray(sb, rawValue, 4, upper)); } object CreateDouble(IDocumentViewerToolTipProviderContext context, double value) { const string format = "G17"; + const bool upper = true; ulong rawValue = BitConverter.ToUInt64(BitConverter.GetBytes(value), 0); return CreateFloat(context, value.ToString(), format, value.ToString(format), - () => rawValue.ToString("X16")); + sb => NumberUtils.ToFixedSizeHexadecimalArray(sb, rawValue, 8, upper)); } } } diff --git a/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberUtils.cs b/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberUtils.cs index 2ed156d2df..e81627b1a0 100644 --- a/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberUtils.cs +++ b/dnSpy/dnSpy/Documents/Tabs/DocViewer/ToolTips/NumberUtils.cs @@ -23,22 +23,22 @@ You should have received a copy of the GNU General Public License namespace dnSpy.Documents.Tabs.DocViewer.ToolTips { static class NumberUtils { - internal static string ToString(StringBuilder sb, int @base, long value) { - if (value < 0) - return "-" + ToString(sb, @base, (ulong)(-value)); - return ToString(sb, @base, (ulong)value); + internal static string ToString(StringBuilder sb, int @base, long value, int @sizeof) { + if (@base == 10 && value < 0) + return "-" + ToString(sb, @base, (ulong)(-value), @sizeof); + return ToString(sb, @base, unchecked((ulong)value), @sizeof); } - internal static string ToString(StringBuilder sb, int @base, ulong value) { + internal static string ToString(StringBuilder sb, int @base, ulong value, int @sizeof) { const int digits = 0; const bool upper = true; switch (@base) { - case 2: return ToBinary(sb, value, digits); - case 8: return ToOctal(sb, value, digits); - case 10: return value.ToString(); - case 16: return ToHexadecimal(sb, value, digits, upper); - default: throw new ArgumentOutOfRangeException(nameof(@base)); + case 2: return ToBinary(sb, value, digits, @sizeof << 3); + case 8: return ToOctal(sb, value, digits, @sizeof << 2); + case 10: return value.ToString(); + case 16: return ToHexadecimal(sb, value, digits, @sizeof << 1, upper); + default: throw new ArgumentOutOfRangeException(nameof(@base)); } } @@ -60,7 +60,35 @@ internal static string AddDigitSeparators(StringBuilder sb, string rawNumber, in return sb.ToString(); } - static string ToHexadecimal(StringBuilder sb, ulong value, int digits, bool upper) { + internal static string ToFixedSizeHexadecimalArray(StringBuilder sb, ulong value, int bytesCount, bool upper) { + sb.Clear(); + + char hexHigh = upper ? (char)('A' - 10) : (char)('a' - 10); + while (bytesCount > 0) { + int ldigit = (int)(value & 0xF); + value >>= 4; + int hdigit = (int)(value & 0xF); + value >>= 4; + bytesCount--; + + if (hdigit > 9) + sb.Append((char)(hdigit + hexHigh)); + else + sb.Append((char)(hdigit + '0')); + + if (ldigit > 9) + sb.Append((char)(ldigit + hexHigh)); + else + sb.Append((char)(ldigit + '0')); + + if (bytesCount != 0) + sb.Append(' '); + } + + return sb.ToString(); + } + + static string ToHexadecimal(StringBuilder sb, ulong value, int digits, int maxDigits, bool upper) { sb.Clear(); if (digits == 0) { @@ -73,6 +101,9 @@ static string ToHexadecimal(StringBuilder sb, ulong value, int digits, bool uppe } } + if (digits > maxDigits) + digits = maxDigits; + char hexHigh = upper ? (char)('A' - 10) : (char)('a' - 10); for (int i = 0; i < digits; i++) { int digit = (int)((value >> ((digits - i - 1) << 2)) & 0xF); @@ -85,7 +116,7 @@ static string ToHexadecimal(StringBuilder sb, ulong value, int digits, bool uppe return sb.ToString(); } - static string ToOctal(StringBuilder sb, ulong value, int digits) { + static string ToOctal(StringBuilder sb, ulong value, int digits, int maxDigits) { sb.Clear(); if (digits == 0) { @@ -98,6 +129,9 @@ static string ToOctal(StringBuilder sb, ulong value, int digits) { } } + if (digits > maxDigits) + digits = maxDigits; + for (int i = 0; i < digits; i++) { int digit = (int)((value >> (digits - i - 1) * 3) & 7); sb.Append((char)(digit + '0')); @@ -106,7 +140,7 @@ static string ToOctal(StringBuilder sb, ulong value, int digits) { return sb.ToString(); } - static string ToBinary(StringBuilder sb, ulong value, int digits) { + static string ToBinary(StringBuilder sb, ulong value, int digits, int maxDigits) { sb.Clear(); if (digits == 0) { @@ -119,6 +153,9 @@ static string ToBinary(StringBuilder sb, ulong value, int digits) { } } + if (digits > maxDigits) + digits = maxDigits; + for (int i = 0; i < digits; i++) { int digit = (int)((value >> (digits - i - 1)) & 1); sb.Append((char)(digit + '0'));