diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index fbb6440f4..15f04a899 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -206,6 +206,7 @@ namespace hex { struct Entry { std::string unlocalizedName; size_t requiredSize; + size_t maxSize; impl::GeneratorFunction generatorFunction; std::optional editingFunction; }; @@ -213,6 +214,7 @@ namespace hex { } void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional editingFunction = std::nullopt); + void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional editingFunction = std::nullopt); std::vector &getEntries(); } diff --git a/lib/libimhex/include/hex/helpers/crypto.hpp b/lib/libimhex/include/hex/helpers/crypto.hpp index d677545d3..08d5c8642 100644 --- a/lib/libimhex/include/hex/helpers/crypto.hpp +++ b/lib/libimhex/include/hex/helpers/crypto.hpp @@ -39,6 +39,11 @@ namespace hex::crypt { std::vector decode16(const std::string &input); std::string encode16(const std::vector &input); + i128 decodeSleb128(const std::vector &bytes); + u128 decodeUleb128(const std::vector &bytes); + std::vector encodeSleb128(i128 value); + std::vector encodeUleb128(u128 value); + enum class AESMode : u8 { ECB = 0, CBC = 1, diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index 13ccef7fa..a29e3c591 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -348,7 +348,13 @@ namespace hex { void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional editingFunction) { log::debug("Registered new data inspector format: {}", unlocalizedName); - getEntries().push_back({ unlocalizedName, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) }); + getEntries().push_back({ unlocalizedName, requiredSize, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) }); + } + + void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional editingFunction) { + log::info("Registered new data inspector format: {}", unlocalizedName); + + getEntries().push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) }); } std::vector &getEntries() { diff --git a/lib/libimhex/source/helpers/crypto.cpp b/lib/libimhex/source/helpers/crypto.cpp index 5a02c98e3..99609b482 100644 --- a/lib/libimhex/source/helpers/crypto.cpp +++ b/lib/libimhex/source/helpers/crypto.cpp @@ -422,6 +422,77 @@ namespace hex::crypt { return output; } + template + static T safeLeftShift(T t, u32 shift) { + if (shift >= sizeof(t) * 8) { + return 0; + } else { + return t << shift; + } + } + + template + static T decodeLeb128(const std::vector &bytes) { + T value = 0; + u32 shift = 0; + u8 b = 0; + for (u8 byte : bytes) { + b = byte; + value |= safeLeftShift(static_cast(byte & 0x7F), shift); + shift += 7; + if ((byte & 0x80) == 0) { + break; + } + } + if constexpr(std::is_signed::value) { + if ((b & 0x40) != 0) { + value |= safeLeftShift(~static_cast(0), shift); + } + } + return value; + } + + u128 decodeUleb128(const std::vector &bytes) { + return decodeLeb128(bytes); + } + + i128 decodeSleb128(const std::vector &bytes) { + return decodeLeb128(bytes); + } + + template + static std::vector encodeLeb128(T value) { + std::vector bytes; + u8 byte; + while (true) { + byte = value & 0x7F; + value >>= 7; + if constexpr(std::is_signed::value) { + if (value == 0 && (byte & 0x40) == 0) { + break; + } + if (value == -1 && (byte & 0x40) != 0) { + break; + } + } else { + if (value == 0) { + break; + } + } + bytes.push_back(byte | 0x80); + } + bytes.push_back(byte); + return bytes; + } + + std::vector encodeUleb128(u128 value) { + return encodeLeb128(value); + } + + std::vector encodeSleb128(i128 value) { + return encodeLeb128(value); + } + static std::vector aes(mbedtls_cipher_type_t type, mbedtls_operation_t operation, const std::vector &key, std::array nonce, std::array iv, const std::vector &input) { std::vector output; diff --git a/plugins/builtin/source/content/data_inspector.cpp b/plugins/builtin/source/content/data_inspector.cpp index 69992d165..e2ba30b28 100644 --- a/plugins/builtin/source/content/data_inspector.cpp +++ b/plugins/builtin/source/content/data_inspector.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include @@ -264,6 +265,42 @@ namespace hex::plugin::builtin { stringToFloat ); + ContentRegistry::DataInspector::add("hex.builtin.inspector.sleb128", 1, (sizeof(i128) * 8 / 7) + 1, + [](auto buffer, auto endian, auto style) { + hex::unused(endian); + + auto format = (style == Style::Decimal) ? "{0}{1:d}" : ((style == Style::Hexadecimal) ? "{0}0x{1:X}" : "{0}0o{1:o}"); + + auto number = hex::crypt::decodeSleb128(buffer); + bool negative = number < 0; + auto value = hex::format(format, negative ? "-" : "", std::abs(number)); + + return [value] { ImGui::TextUnformatted(value.c_str()); return value; }; + }, + [](const std::string &value, std::endian endian) -> std::vector { + hex::unused(endian); + + return hex::crypt::encodeSleb128(std::strtoll(value.c_str(), nullptr, 0)); + } + ); + + ContentRegistry::DataInspector::add("hex.builtin.inspector.uleb128", 1, (sizeof(u128) * 8 / 7) + 1, + [](auto buffer, auto endian, auto style) { + hex::unused(endian); + + auto format = (style == Style::Decimal) ? "{0:d}" : ((style == Style::Hexadecimal) ? "0x{0:X}" : "0o{0:o}"); + + auto value = hex::format(format, hex::crypt::decodeUleb128(buffer)); + + return [value] { ImGui::TextUnformatted(value.c_str()); return value; }; + }, + [](const std::string &value, std::endian endian) -> std::vector { + hex::unused(endian); + + return hex::crypt::encodeUleb128(std::strtoull(value.c_str(), nullptr, 0)); + } + ); + ContentRegistry::DataInspector::add("hex.builtin.inspector.bool", sizeof(bool), [](auto buffer, auto endian, auto style) { hex::unused(endian, style); diff --git a/plugins/builtin/source/content/views/view_data_inspector.cpp b/plugins/builtin/source/content/views/view_data_inspector.cpp index 76e64e3c0..94685e5ed 100644 --- a/plugins/builtin/source/content/views/view_data_inspector.cpp +++ b/plugins/builtin/source/content/views/view_data_inspector.cpp @@ -39,7 +39,7 @@ namespace hex::plugin::builtin { if (this->m_validBytes < entry.requiredSize) continue; - std::vector buffer(entry.requiredSize); + std::vector buffer(this->m_validBytes > entry.maxSize ? entry.maxSize : this->m_validBytes); provider->read(this->m_startAddress, buffer.data(), buffer.size()); if (this->m_invert) { diff --git a/plugins/builtin/source/lang/de_DE.cpp b/plugins/builtin/source/lang/de_DE.cpp index ef7477207..9e0e4743d 100644 --- a/plugins/builtin/source/lang/de_DE.cpp +++ b/plugins/builtin/source/lang/de_DE.cpp @@ -426,6 +426,8 @@ namespace hex::plugin::builtin { { "hex.builtin.inspector.float", "float (32 bit)" }, { "hex.builtin.inspector.double", "double (64 bit)" }, { "hex.builtin.inspector.long_double", "long double (128 bit)" }, + //{ "hex.builtin.inspector.sleb128", "Signed LEB128" }, + //{ "hex.builtin.inspector.uleb128", "Unsigned LEB128" }, { "hex.builtin.inspector.bool", "bool" }, { "hex.builtin.inspector.ascii", "ASCII Zeichen" }, { "hex.builtin.inspector.wide", "Wide Zeichen" }, diff --git a/plugins/builtin/source/lang/en_US.cpp b/plugins/builtin/source/lang/en_US.cpp index 38ce6e4f4..67f5b9911 100644 --- a/plugins/builtin/source/lang/en_US.cpp +++ b/plugins/builtin/source/lang/en_US.cpp @@ -431,6 +431,8 @@ namespace hex::plugin::builtin { { "hex.builtin.inspector.float", "float (32 bit)" }, { "hex.builtin.inspector.double", "double (64 bit)" }, { "hex.builtin.inspector.long_double", "long double (128 bit)" }, + { "hex.builtin.inspector.sleb128", "Signed LEB128" }, + { "hex.builtin.inspector.uleb128", "Unsigned LEB128" }, { "hex.builtin.inspector.bool", "bool" }, { "hex.builtin.inspector.ascii", "ASCII Character" }, { "hex.builtin.inspector.wide", "Wide Character" }, diff --git a/plugins/builtin/source/lang/it_IT.cpp b/plugins/builtin/source/lang/it_IT.cpp index 40e0739e7..29a32b8f5 100644 --- a/plugins/builtin/source/lang/it_IT.cpp +++ b/plugins/builtin/source/lang/it_IT.cpp @@ -429,6 +429,8 @@ namespace hex::plugin::builtin { { "hex.builtin.inspector.float", "float (32 bit)" }, { "hex.builtin.inspector.double", "double (64 bit)" }, { "hex.builtin.inspector.long_double", "long double (128 bit)" }, + //{ "hex.builtin.inspector.sleb128", "Signed LEB128" }, + //{ "hex.builtin.inspector.uleb128", "Unsigned LEB128" }, { "hex.builtin.inspector.bool", "bool" }, { "hex.builtin.inspector.ascii", "ASCII Character" }, { "hex.builtin.inspector.wide", "Wide Character" }, diff --git a/plugins/builtin/source/lang/ja_JP.cpp b/plugins/builtin/source/lang/ja_JP.cpp index 6998be5b0..b15b135a5 100644 --- a/plugins/builtin/source/lang/ja_JP.cpp +++ b/plugins/builtin/source/lang/ja_JP.cpp @@ -430,6 +430,8 @@ namespace hex::plugin::builtin { { "hex.builtin.inspector.float", "float (32 bit)" }, { "hex.builtin.inspector.double", "double (64 bit)" }, { "hex.builtin.inspector.long_double", "long double (128 bit)" }, + //{ "hex.builtin.inspector.sleb128", "Signed LEB128" }, + //{ "hex.builtin.inspector.uleb128", "Unsigned LEB128" }, { "hex.builtin.inspector.bool", "bool" }, { "hex.builtin.inspector.ascii", "ASCII文字" }, { "hex.builtin.inspector.wide", "Wide Character" }, diff --git a/plugins/builtin/source/lang/pt_BR.cpp b/plugins/builtin/source/lang/pt_BR.cpp index 75206f4fc..ec84bffa0 100644 --- a/plugins/builtin/source/lang/pt_BR.cpp +++ b/plugins/builtin/source/lang/pt_BR.cpp @@ -427,6 +427,8 @@ namespace hex::plugin::builtin { { "hex.builtin.inspector.float", "float (32 bit)" }, { "hex.builtin.inspector.double", "double (64 bit)" }, { "hex.builtin.inspector.long_double", "long double (128 bit)" }, + //{ "hex.builtin.inspector.sleb128", "Signed LEB128" }, + //{ "hex.builtin.inspector.uleb128", "Unsigned LEB128" }, { "hex.builtin.inspector.bool", "bool" }, { "hex.builtin.inspector.ascii", "ASCII Character" }, { "hex.builtin.inspector.wide", "Wide Character" }, diff --git a/plugins/builtin/source/lang/zh_CN.cpp b/plugins/builtin/source/lang/zh_CN.cpp index d12cc2351..8325713bd 100644 --- a/plugins/builtin/source/lang/zh_CN.cpp +++ b/plugins/builtin/source/lang/zh_CN.cpp @@ -431,6 +431,8 @@ namespace hex::plugin::builtin { { "hex.builtin.inspector.float", "float(32位单精度)" }, { "hex.builtin.inspector.double", "double(64位双精度)" }, { "hex.builtin.inspector.long_double", "long double(128位四精度)" }, + //{ "hex.builtin.inspector.sleb128", "Signed LEB128" }, + //{ "hex.builtin.inspector.uleb128", "Unsigned LEB128" }, { "hex.builtin.inspector.bool", "bool" }, { "hex.builtin.inspector.ascii", "ASCII 字符" }, { "hex.builtin.inspector.wide", "宽字符" }, diff --git a/plugins/builtin/source/lang/zh_TW.cpp b/plugins/builtin/source/lang/zh_TW.cpp index 729632092..afe7a9552 100644 --- a/plugins/builtin/source/lang/zh_TW.cpp +++ b/plugins/builtin/source/lang/zh_TW.cpp @@ -428,6 +428,8 @@ namespace hex::plugin::builtin { { "hex.builtin.inspector.float", "float (32 位元)" }, { "hex.builtin.inspector.double", "double (64 位元)" }, { "hex.builtin.inspector.long_double", "long double (128 位元)" }, + //{ "hex.builtin.inspector.sleb128", "Signed LEB128" }, + //{ "hex.builtin.inspector.uleb128", "Unsigned LEB128" }, { "hex.builtin.inspector.bool", "bool" }, { "hex.builtin.inspector.ascii", "ASCII 字元" }, { "hex.builtin.inspector.wide", "框字元" }, diff --git a/tests/algorithms/CMakeLists.txt b/tests/algorithms/CMakeLists.txt index 476f0f06a..540dea37b 100644 --- a/tests/algorithms/CMakeLists.txt +++ b/tests/algorithms/CMakeLists.txt @@ -12,6 +12,7 @@ set(AVAILABLE_TESTS # Crypto EncodeDecode16 EncodeDecode64 + EncodeDecodeLEB128 CRC32 CRC32Random CRC16 diff --git a/tests/algorithms/source/crypto.cpp b/tests/algorithms/source/crypto.cpp index f19e8a49f..4c3e7b096 100644 --- a/tests/algorithms/source/crypto.cpp +++ b/tests/algorithms/source/crypto.cpp @@ -100,6 +100,67 @@ TEST_SEQUENCE("EncodeDecode64") { TEST_SUCCESS(); }; +TEST_SEQUENCE("EncodeDecodeLEB128") { + TEST_ASSERT(hex::crypt::encodeUleb128(0) == (std::vector{ 0 })); + TEST_ASSERT(hex::crypt::encodeUleb128(0x7F) == (std::vector{ 0x7F })); + TEST_ASSERT(hex::crypt::encodeUleb128(0xFF) == (std::vector{ 0xFF, 0x01 })); + TEST_ASSERT(hex::crypt::encodeUleb128(0xF0F0) == (std::vector{ 0xF0, 0xE1, 0x03 })); + + TEST_ASSERT(hex::crypt::encodeSleb128(0) == (std::vector{ 0 })); + TEST_ASSERT(hex::crypt::encodeSleb128(0x7F) == (std::vector{ 0xFF, 0x00 })); + TEST_ASSERT(hex::crypt::encodeSleb128(0xFF) == (std::vector{ 0xFF, 0x01 })); + TEST_ASSERT(hex::crypt::encodeSleb128(0xF0F0) == (std::vector{ 0xF0, 0xE1, 0x03 })); + TEST_ASSERT(hex::crypt::encodeSleb128(-1) == (std::vector{ 0x7F })); + TEST_ASSERT(hex::crypt::encodeSleb128(-128) == (std::vector{ 0x80, 0x7F })); + + TEST_ASSERT(hex::crypt::decodeUleb128({}) == 0); + TEST_ASSERT(hex::crypt::decodeUleb128({ 1 }) == 0x01); + TEST_ASSERT(hex::crypt::decodeUleb128({ 0x7F }) == 0x7F); + TEST_ASSERT(hex::crypt::decodeUleb128({ 0xFF }) == 0x7F); + TEST_ASSERT(hex::crypt::decodeUleb128({ 0xFF, 0x7F }) == 0x3FFF); + TEST_ASSERT(hex::crypt::decodeUleb128({ + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x7F, + }) == ((static_cast(0xFFFF'FFFF'FFFF) << 64) | 0xFFFF'FFFF'FFFF'FFFF)); + TEST_ASSERT(hex::crypt::decodeUleb128({ 0xAA, 0xBB, 0xCC, 0x00, 0xFF }) == 0x131DAA); + + TEST_ASSERT(hex::crypt::decodeSleb128({}) == 0); + TEST_ASSERT(hex::crypt::decodeSleb128({ 1 }) == 0x01); + TEST_ASSERT(hex::crypt::decodeSleb128({ 0x3F }) == 0x3F); + TEST_ASSERT(hex::crypt::decodeSleb128({ 0x7F }) == -1); + TEST_ASSERT(hex::crypt::decodeSleb128({ 0xFF }) == -1); + TEST_ASSERT(hex::crypt::decodeSleb128({ 0xFF, 0x7F }) == -1); + TEST_ASSERT(hex::crypt::decodeSleb128({ + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0x7F, + }) == -1); + TEST_ASSERT(hex::crypt::decodeSleb128({ 0xAA, 0xBB, 0xCC, 0x00, 0xFF }) == 0x131DAA); + TEST_ASSERT(hex::crypt::decodeSleb128({ 0xAA, 0xBB, 0x4C }) == -0xCE256); + + std::random_device rd; + std::mt19937 gen(rd()); + std::uniform_int_distribution data; + + for (int i = 0; i < 1000; i++) { + std::vector original(sizeof(u128)); + std::generate(std::begin(original), std::end(original), [&]() { return data(gen); }); + u128 u = *reinterpret_cast(original.data()); + i128 s = *reinterpret_cast(original.data()); + auto encodedS = hex::crypt::encodeSleb128(s); + i128 decodedS = hex::crypt::decodeSleb128(encodedS); + auto encodedU = hex::crypt::encodeUleb128(u); + u128 decodedU = hex::crypt::decodeUleb128(encodedU); + TEST_ASSERT(decodedS == s, "encoded: {0} decoded: {1:X} original: {2:X}", encodedS, static_cast(decodedS), static_cast(s)); + TEST_ASSERT(decodedU == u, "encoded: {0} decoded: {1:X} original: {2:X}", encodedU, decodedU, u); + } + + TEST_SUCCESS(); +}; + struct CrcCheck { std::string name; int width; diff --git a/tests/helpers/source/utils.cpp b/tests/helpers/source/utils.cpp index 549a57cca..c20e0b576 100644 --- a/tests/helpers/source/utils.cpp +++ b/tests/helpers/source/utils.cpp @@ -29,4 +29,4 @@ TEST_SEQUENCE("ExtractBits") { TEST_ASSERT(hex::extract(20, 35, 0x8899AABBCCDDEEFFU) == 0xBCCD); TEST_SUCCESS(); -}; \ No newline at end of file +};