From 9ce18d1a42fc40ab977626fb07b9cb9abc55ed76 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Sun, 20 Jul 2025 11:11:51 +0200 Subject: [PATCH] feat: Added bfloat and fp24 data inspector entries --- lib/libimhex/include/hex/helpers/utils.hpp | 49 ++++++++++++++++++- lib/libimhex/source/helpers/utils.cpp | 37 -------------- plugins/builtin/romfs/lang/en_US.json | 2 + .../builtin/source/content/data_inspector.cpp | 28 ++++++++++- 4 files changed, 77 insertions(+), 39 deletions(-) diff --git a/lib/libimhex/include/hex/helpers/utils.hpp b/lib/libimhex/include/hex/helpers/utils.hpp index dbd1d6773..d6b909962 100644 --- a/lib/libimhex/include/hex/helpers/utils.hpp +++ b/lib/libimhex/include/hex/helpers/utils.hpp @@ -285,7 +285,54 @@ namespace hex { return result; } - [[nodiscard]] float float16ToFloat32(u16 float16); + template + [[nodiscard]] constexpr float customFloatToFloat32(u32 value) { + static_assert(ExponentBits <= 8, "ExponentBits must be less than 8"); + static_assert(ExponentBits + MantissaBits + 1 <= 32, "Format doesn't fit into a 32-bit float"); + + const u32 sign = value >> (ExponentBits + MantissaBits); + const u32 exponent = (value >> MantissaBits) & ((1u << ExponentBits) - 1); + u32 mantissa = value & ((1u << MantissaBits) - 1); + + // Calculate the bias for the input format and IEEE-754 float32 + i32 inputBias = (1 << (ExponentBits - 1)) - 1; + i32 float32Bias = 127; + + u32 result = 0; + + if (exponent == 0) { + if (mantissa == 0) { + // Zero + result = sign << 31; + } else { + // Subnormal + int shift = 0; + while ((mantissa & (1u << MantissaBits)) == 0) { + mantissa <<= 1; + shift++; + } + mantissa &= ((1u << MantissaBits) - 1); // clear implicit bit + int adjustedExp = float32Bias - inputBias - shift + 1; + result = (sign << 31) | (adjustedExp << 23) | (mantissa << (23 - MantissaBits)); + } + } else if (exponent == ((1u << ExponentBits) - 1)) { + // Inf or NaN + result = (sign << 31) | (0xFF << 23) | (mantissa << (23 - MantissaBits)); + } else { + // Normalized number + int adjustedExp = exponent - inputBias + float32Bias; + result = (sign << 31) | (adjustedExp << 23) | (mantissa << (23 - MantissaBits)); + } + + float floatResult; + std::memcpy(&floatResult, &result, sizeof(float)); + + return floatResult; + } + + [[nodiscard]] constexpr float float16ToFloat32(u16 float16) { + return customFloatToFloat32<5, 10>(float16); + } [[nodiscard]] inline bool equalsIgnoreCase(std::string_view left, std::string_view right) { return std::equal(left.begin(), left.end(), right.begin(), right.end(), [](char a, char b) { diff --git a/lib/libimhex/source/helpers/utils.cpp b/lib/libimhex/source/helpers/utils.cpp index 109f51f45..d37e9d666 100644 --- a/lib/libimhex/source/helpers/utils.cpp +++ b/lib/libimhex/source/helpers/utils.cpp @@ -612,43 +612,6 @@ namespace hex { return utf8; } - float float16ToFloat32(u16 float16) { - u32 sign = float16 >> 15; - u32 exponent = (float16 >> 10) & 0x1F; - u32 mantissa = float16 & 0x3FF; - - u32 result = 0x00; - - if (exponent == 0) { - if (mantissa == 0) { - // +- Zero - result = sign << 31; - } else { - // Subnormal value - exponent = 0x7F - 14; - - while ((mantissa & (1 << 10)) == 0) { - exponent--; - mantissa <<= 1; - } - - mantissa &= 0x3FF; - result = (sign << 31) | (exponent << 23) | (mantissa << 13); - } - } else if (exponent == 0x1F) { - // +-Inf or +-NaN - result = (sign << 31) | (0xFF << 23) | (mantissa << 13); - } else { - // Normal value - result = (sign << 31) | ((exponent + (0x7F - 15)) << 23) | (mantissa << 13); - } - - float floatResult = 0; - std::memcpy(&floatResult, &result, sizeof(float)); - - return floatResult; - } - bool isProcessElevated() { #if defined(OS_WINDOWS) bool elevated = false; diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index 15e1fdb89..3a3c8e739 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -78,6 +78,7 @@ "hex.builtin.drag_drop.text": "Drop files here to open them...", "hex.builtin.inspector.ascii": "ASCII Character", "hex.builtin.inspector.binary": "Binary (8 bit)", + "hex.builtin.inspector.bfloat": "bfloat16", "hex.builtin.inspector.bool": "bool", "hex.builtin.inspector.custom_encoding": "Custom Encoding", "hex.builtin.inspector.custom_encoding.change": "Select encoding", @@ -87,6 +88,7 @@ "hex.builtin.inspector.double": "double (64 bit)", "hex.builtin.inspector.float": "float (32 bit)", "hex.builtin.inspector.float16": "half float (16 bit)", + "hex.builtin.inspector.fp24": "fp24", "hex.builtin.inspector.guid": "GUID", "hex.builtin.inspector.i16": "int16_t", "hex.builtin.inspector.i24": "int24_t", diff --git a/plugins/builtin/source/content/data_inspector.cpp b/plugins/builtin/source/content/data_inspector.cpp index 00dc60474..18d99c07c 100644 --- a/plugins/builtin/source/content/data_inspector.cpp +++ b/plugins/builtin/source/content/data_inspector.cpp @@ -237,7 +237,7 @@ namespace hex::plugin::builtin { const auto formatString = style == Style::Hexadecimal ? "{0:a}" : "{0:G}"; - auto value = hex::format(formatString, float16ToFloat32(hex::changeEndianness(result, endian))); + auto value = hex::format(formatString, customFloatToFloat32<5, 10>(hex::changeEndianness(result, endian))); return [value] { ImGui::TextUnformatted(value.c_str()); return value; }; } @@ -282,6 +282,32 @@ namespace hex::plugin::builtin { stringToFloat ); + ContentRegistry::DataInspector::add("hex.builtin.inspector.bfloat16", sizeof(u16), + [](auto buffer, auto endian, auto style) { + u16 result = 0; + std::memcpy(&result, buffer.data(), sizeof(u16)); + + const auto formatString = style == Style::Hexadecimal ? "{0:a}" : "{0:G}"; + + auto value = hex::format(formatString, customFloatToFloat32<8, 7>(hex::changeEndianness(result, endian))); + + return [value] { ImGui::TextUnformatted(value.c_str()); return value; }; + } + ); + + ContentRegistry::DataInspector::add("hex.builtin.inspector.fp24", 3, + [](auto buffer, auto endian, auto style) { + u32 result = 0; + std::memcpy(&result, buffer.data(), 3); + + const auto formatString = style == Style::Hexadecimal ? "{0:a}" : "{0:G}"; + + auto value = hex::format(formatString, customFloatToFloat32<7, 16>(hex::changeEndianness(result, endian))); + + return [value] { ImGui::TextUnformatted(value.c_str()); return value; }; + } + ); + ContentRegistry::DataInspector::add("hex.builtin.inspector.sleb128", 1, (16 * 8 / 7) + 1, [](auto buffer, auto endian, auto style) { std::ignore = endian;