diff --git a/lib/libimhex/include/hex.hpp b/lib/libimhex/include/hex.hpp index 0906bf357..83afd35c7 100644 --- a/lib/libimhex/include/hex.hpp +++ b/lib/libimhex/include/hex.hpp @@ -3,46 +3,8 @@ #include #include +#include #include constexpr static const auto ImHexApiURL = "https://api.werwolv.net/imhex"; constexpr static const auto GitHubApiURL = "https://api.github.com/repos/WerWolv/ImHex"; - -using u8 = std::uint8_t; -using u16 = std::uint16_t; -using u32 = std::uint32_t; -using u64 = std::uint64_t; -using u128 = __uint128_t; - -using i8 = std::int8_t; -using i16 = std::int16_t; -using i32 = std::int32_t; -using i64 = std::int64_t; -using i128 = __int128_t; - -using color_t = u32; - -namespace hex { - - struct Region { - u64 address; - size_t size; - - [[nodiscard]] constexpr bool isWithin(const Region &other) const { - return (this->address >= other.address) && ((this->address + this->size) <= (other.address + other.size)); - } - - [[nodiscard]] constexpr bool overlaps(const Region &other) const { - return ((this->address + this->size) >= other.address) && (this->address < (other.address + other.size)); - } - - [[nodiscard]] constexpr u64 getStartAddress() const { - return this->address; - } - - [[nodiscard]] constexpr u64 getEndAddress() const { - return this->address + this->size - 1; - } - }; - -} diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index 0425c3cbc..620ec9344 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -421,6 +421,74 @@ namespace hex { } } + + namespace Hashes { + + class Hash { + public: + Hash(std::string name) : m_name(std::move(name)) {} + + class Function { + public: + using Callback = std::function(const Region&, prv::Provider *)>; + + Function(const Hash *type, std::string name, Callback callback) + : m_type(type), m_name(std::move(name)), m_callback(std::move(callback)) { + + } + + [[nodiscard]] const Hash *getType() const { return this->m_type; } + [[nodiscard]] const std::string &getName() const { return this->m_name; } + + const std::vector& get(const Region& region, prv::Provider *provider) { + if (this->m_cache.empty()) { + this->m_cache = this->m_callback(region, provider); + } + + return this->m_cache; + } + + void reset() { + this->m_cache.clear(); + } + + private: + const Hash *m_type; + std::string m_name; + Callback m_callback; + + std::vector m_cache; + }; + + virtual void draw() { } + [[nodiscard]] virtual Function create(std::string name) = 0; + + [[nodiscard]] const std::string &getName() const { + return this->m_name; + } + + protected: + [[nodiscard]] Function create(const std::string &name, const Function::Callback &callback) const { + return { this, name, callback }; + } + + private: + std::string m_name; + }; + + namespace impl { + + std::vector &getHashes(); + + void add(Hash* hash); + } + + template + void add(Args && ... args) { + impl::add(new T(std::forward(args)...)); + } + + } }; } diff --git a/lib/libimhex/include/hex/helpers/types.hpp b/lib/libimhex/include/hex/helpers/types.hpp new file mode 100644 index 000000000..dafc5dd2f --- /dev/null +++ b/lib/libimhex/include/hex/helpers/types.hpp @@ -0,0 +1,44 @@ +#pragma once + +using u8 = std::uint8_t; +using u16 = std::uint16_t; +using u32 = std::uint32_t; +using u64 = std::uint64_t; +using u128 = __uint128_t; + +using i8 = std::int8_t; +using i16 = std::int16_t; +using i32 = std::int32_t; +using i64 = std::int64_t; +using i128 = __int128_t; + +using color_t = u32; + +namespace hex { + + struct Region { + u64 address; + size_t size; + + [[nodiscard]] constexpr bool isWithin(const Region &other) const { + return (this->getStartAddress() >= other.getStartAddress()) && (this->getEndAddress() <= other.getEndAddress()); + } + + [[nodiscard]] constexpr bool overlaps(const Region &other) const { + return (this->getEndAddress() >= other.getStartAddress()) && (this->getStartAddress() < other.getEndAddress()); + } + + [[nodiscard]] constexpr u64 getStartAddress() const { + return this->address; + } + + [[nodiscard]] constexpr u64 getEndAddress() const { + return this->address + this->size - 1; + } + + [[nodiscard]] constexpr size_t getSize() const { + return this->size; + } + }; + +} \ No newline at end of file diff --git a/lib/libimhex/include/hex/ui/imgui_imhex_extensions.h b/lib/libimhex/include/hex/ui/imgui_imhex_extensions.h index 100a8c95f..f554259d5 100644 --- a/lib/libimhex/include/hex/ui/imgui_imhex_extensions.h +++ b/lib/libimhex/include/hex/ui/imgui_imhex_extensions.h @@ -74,7 +74,8 @@ namespace ImGui { bool ToolBarButton(const char *symbol, ImVec4 color); bool IconButton(const char *symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0)); - bool InputIntegerPrefix(const char* label, const char *prefix, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None); + bool InputIntegerPrefix(const char* label, const char *prefix, void *value, ImGuiDataType type, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None); + bool InputHexadecimal(const char* label, u32 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None); bool InputHexadecimal(const char* label, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None); inline bool HasSecondPassed() { diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index ac84153e9..1299b7cc8 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -582,4 +582,18 @@ namespace hex { } + namespace ContentRegistry::Hashes { + + std::vector &impl::getHashes() { + static std::vector hashes; + + return hashes; + } + + void impl::add(Hash *hash) { + getHashes().push_back(hash); + } + + } + } diff --git a/lib/libimhex/source/ui/imgui_imhex_extensions.cpp b/lib/libimhex/source/ui/imgui_imhex_extensions.cpp index a62ee9297..354d32e7e 100644 --- a/lib/libimhex/source/ui/imgui_imhex_extensions.cpp +++ b/lib/libimhex/source/ui/imgui_imhex_extensions.cpp @@ -19,7 +19,7 @@ namespace ImGui { if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) { auto &string = *static_cast(data->UserData); - string.resize(data->BufSize); + string.resize(data->BufTextLen); data->Buf = string.data(); } @@ -487,7 +487,7 @@ namespace ImGui { return pressed; } - bool InputIntegerPrefix(const char *label, const char *prefix, u64 *value, ImGuiInputTextFlags flags) { + bool InputIntegerPrefix(const char *label, const char *prefix, void *value, ImGuiDataType type, ImGuiInputTextFlags flags) { auto window = ImGui::GetCurrentWindow(); const ImGuiID id = window->GetID(label); const ImGuiStyle &style = GImGui->Style; @@ -500,7 +500,7 @@ namespace ImGui { ImGui::SetCursorPosX(ImGui::GetCursorPosX() + frame_size.x); char buf[64]; - DataTypeFormatString(buf, IM_ARRAYSIZE(buf), ImGuiDataType_U64, value, "%llX"); + DataTypeFormatString(buf, IM_ARRAYSIZE(buf), type, value, "%llX"); bool value_changed = false; if (InputTextEx(label, nullptr, buf, IM_ARRAYSIZE(buf), ImVec2(CalcItemWidth() - frame_size.x, label_size.y + style.FramePadding.y * 2.0f), flags)) @@ -519,8 +519,12 @@ namespace ImGui { return value_changed; } + bool InputHexadecimal(const char *label, u32 *value, ImGuiInputTextFlags flags) { + return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U32, flags | ImGuiInputTextFlags_CharsHexadecimal); + } + bool InputHexadecimal(const char *label, u64 *value, ImGuiInputTextFlags flags) { - return InputIntegerPrefix(label, "0x", value, flags | ImGuiInputTextFlags_CharsHexadecimal); + return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U64, flags | ImGuiInputTextFlags_CharsHexadecimal); } void SmallProgressBar(float fraction, float yOffset) { diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index 4572c01a6..51324f43d 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -22,6 +22,7 @@ add_library(${PROJECT_NAME} SHARED source/content/welcome_screen.cpp source/content/data_visualizers.cpp source/content/events.cpp + source/content/hashes.cpp source/content/providers/file_provider.cpp source/content/providers/gdb_provider.cpp diff --git a/plugins/builtin/include/content/views/view_hashes.hpp b/plugins/builtin/include/content/views/view_hashes.hpp index fda7b6f2c..5f8ce53fb 100644 --- a/plugins/builtin/include/content/views/view_hashes.hpp +++ b/plugins/builtin/include/content/views/view_hashes.hpp @@ -1,5 +1,7 @@ #pragma once +#include + #include #include @@ -16,35 +18,10 @@ namespace hex::plugin::builtin { void drawContent() override; private: - enum class HashFunctions - { - Crc8, - Crc16, - Crc32, - Md5, - Sha1, - Sha224, - Sha256, - Sha384, - Sha512 - }; + ContentRegistry::Hashes::Hash *m_selectedHash = nullptr; + std::string m_newHashName; - bool m_shouldInvalidate = true; - int m_currHashFunction = 0; - u64 m_hashRegion[2] = { 0 }; - bool m_shouldMatchSelection = false; - - static constexpr std::array hashFunctionNames { - std::pair {HashFunctions::Crc8, "CRC8" }, - std::pair { HashFunctions::Crc16, "CRC16" }, - std::pair { HashFunctions::Crc32, "CRC32" }, - std::pair { HashFunctions::Md5, "MD5" }, - std::pair { HashFunctions::Sha1, "SHA-1" }, - std::pair { HashFunctions::Sha224, "SHA-224"}, - std::pair { HashFunctions::Sha256, "SHA-256"}, - std::pair { HashFunctions::Sha384, "SHA-384"}, - std::pair { HashFunctions::Sha512, "SHA-512"}, - }; + std::vector m_hashFunctions; }; } diff --git a/plugins/builtin/source/content/hashes.cpp b/plugins/builtin/source/content/hashes.cpp new file mode 100644 index 000000000..cff3dbcf2 --- /dev/null +++ b/plugins/builtin/source/content/hashes.cpp @@ -0,0 +1,140 @@ +#include +#include +#include + +#include + +namespace hex::plugin::builtin { + + class HashMD5 : public ContentRegistry::Hashes::Hash { + public: + HashMD5() : Hash("hex.builtin.hash.md5"_lang) {} + + Function create(std::string name) override { + return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector { + auto array = crypt::md5(provider, region.address, region.size); + + return { array.begin(), array.end() }; + }); + } + }; + + class HashSHA1 : public ContentRegistry::Hashes::Hash { + public: + HashSHA1() : Hash("hex.builtin.hash.sha1"_lang) {} + + Function create(std::string name) override { + return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector { + auto array = crypt::sha1(provider, region.address, region.size); + + return { array.begin(), array.end() }; + }); + } + }; + + class HashSHA224 : public ContentRegistry::Hashes::Hash { + public: + HashSHA224() : Hash("hex.builtin.hash.sha224"_lang) {} + + Function create(std::string name) override { + return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector { + auto array = crypt::sha224(provider, region.address, region.size); + + return { array.begin(), array.end() }; + }); + } + }; + + class HashSHA256 : public ContentRegistry::Hashes::Hash { + public: + HashSHA256() : Hash("hex.builtin.hash.sha256"_lang) {} + + Function create(std::string name) override { + return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector { + auto array = crypt::sha256(provider, region.address, region.size); + + return { array.begin(), array.end() }; + }); + } + }; + + class HashSHA384 : public ContentRegistry::Hashes::Hash { + public: + HashSHA384() : Hash("hex.builtin.hash.sha384"_lang) {} + + Function create(std::string name) override { + return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector { + auto array = crypt::sha384(provider, region.address, region.size); + + return { array.begin(), array.end() }; + }); + } + }; + + class HashSHA512 : public ContentRegistry::Hashes::Hash { + public: + HashSHA512() : Hash("hex.builtin.hash.sha512") {} + + Function create(std::string name) override { + return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector { + auto array = crypt::sha512(provider, region.address, region.size); + + return { array.begin(), array.end() }; + }); + } + }; + + template + class HashCRC : public ContentRegistry::Hashes::Hash { + public: + using CRCFunction = T(*)(prv::Provider*&, u64, size_t, u32, u32, u32, bool, bool); + HashCRC(const std::string &name, const CRCFunction &crcFunction, u32 polynomial, u32 initialValue, u32 xorOut) + : Hash(name), m_crcFunction(crcFunction), m_polynomial(polynomial), m_initialValue(initialValue), m_xorOut(xorOut) {} + + void draw() override { + ImGui::InputHexadecimal("hex.builtin.hash.crc.poly"_lang, &this->m_polynomial); + ImGui::InputHexadecimal("hex.builtin.hash.crc.iv"_lang, &this->m_initialValue); + ImGui::InputHexadecimal("hex.builtin.hash.crc.xor_out"_lang, &this->m_xorOut); + + ImGui::NewLine(); + + ImGui::Checkbox("hex.builtin.hash.crc.refl_in"_lang, &this->m_reflectIn); + ImGui::Checkbox("hex.builtin.hash.crc.refl_out"_lang, &this->m_reflectOut); + } + + Function create(std::string name) override { + return Hash::create(name, [hash = *this](const Region& region, prv::Provider *provider) -> std::vector { + auto result = hash.m_crcFunction(provider, region.address, region.size, hash.m_polynomial, hash.m_initialValue, hash.m_xorOut, hash.m_reflectIn, hash.m_reflectOut); + + std::vector bytes(sizeof(result), 0x00); + std::memcpy(bytes.data(), &result, bytes.size()); + + return bytes; + }); + } + + private: + CRCFunction m_crcFunction; + + u32 m_polynomial; + u32 m_initialValue; + u32 m_xorOut; + bool m_reflectIn = false, m_reflectOut = false; + }; + + void registerHashes() { + ContentRegistry::Hashes::add(); + + ContentRegistry::Hashes::add(); + ContentRegistry::Hashes::add(); + ContentRegistry::Hashes::add(); + ContentRegistry::Hashes::add(); + ContentRegistry::Hashes::add(); + + ContentRegistry::Hashes::add>("hex.builtin.hash.crc8"_lang, crypt::crc8, 0x07, 0x0000, 0x0000); + ContentRegistry::Hashes::add>("hex.builtin.hash.crc16"_lang, crypt::crc16, 0x8005, 0x0000, 0x0000); + ContentRegistry::Hashes::add>("hex.builtin.hash.crc32"_lang, crypt::crc32, 0x04C1'1DB7, 0xFFFF'FFFF, 0xFFFF'FFFF); + + } + +} \ No newline at end of file diff --git a/plugins/builtin/source/content/views/view_bookmarks.cpp b/plugins/builtin/source/content/views/view_bookmarks.cpp index 8edd14c4e..627d9f397 100644 --- a/plugins/builtin/source/content/views/view_bookmarks.cpp +++ b/plugins/builtin/source/content/views/view_bookmarks.cpp @@ -61,7 +61,7 @@ namespace hex::plugin::builtin { ImGui::BeginTooltip(); - if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) { + if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) { ImGui::TableNextRow(); ImGui::TableNextColumn(); diff --git a/plugins/builtin/source/content/views/view_hashes.cpp b/plugins/builtin/source/content/views/view_hashes.cpp index 8e9e1bc99..12b0c9095 100644 --- a/plugins/builtin/source/content/views/view_hashes.cpp +++ b/plugins/builtin/source/content/views/view_hashes.cpp @@ -1,294 +1,180 @@ #include "content/views/view_hashes.hpp" -#include #include #include - namespace hex::plugin::builtin { ViewHashes::ViewHashes() : View("hex.builtin.view.hashes.name") { - EventManager::subscribe(this, [this]() { - this->m_shouldInvalidate = true; + EventManager::subscribe(this, [this](const Region &) { + for (auto &function : this->m_hashFunctions) + function.reset(); }); - EventManager::subscribe(this, [this](Region region) { - if (this->m_shouldMatchSelection) { - if (region.address == size_t(-1)) { - this->m_hashRegion[0] = this->m_hashRegion[1] = 0; - } else { - this->m_hashRegion[0] = region.address; - this->m_hashRegion[1] = region.size; + ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) { + hex::unused(data); + + auto selection = ImHexApi::HexEditor::getSelection(); + + if (ImGui::GetIO().KeyShift) { + if (!this->m_hashFunctions.empty() && selection.has_value() && selection->overlaps(Region { address, size })) { + ImGui::BeginTooltip(); + + if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::TextUnformatted("hex.builtin.view.hashes.name"_lang); + ImGui::Separator(); + + ImGui::Indent(); + if (ImGui::BeginTable("##hashes_tooltip", 3, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit)) { + auto provider = ImHexApi::Provider::get(); + for (auto &function : this->m_hashFunctions) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextFormatted("{}", function.getName()); + + ImGui::TableNextColumn(); + ImGui::TextFormatted(" "); + + ImGui::TableNextColumn(); + if (provider != nullptr) + ImGui::TextFormatted("{}", crypt::encode16(function.get(*selection, provider))); + } + + ImGui::EndTable(); + } + ImGui::Unindent(); + + ImGui::EndTable(); + } + + ImGui::EndTooltip(); } - this->m_shouldInvalidate = true; } }); } ViewHashes::~ViewHashes() { - EventManager::unsubscribe(this); EventManager::unsubscribe(this); } - template - static void formatBigHexInt(std::array dataArray, char *buffer, size_t bufferSize) { - for (size_t i = 0; i < dataArray.size(); i++) - snprintf(buffer + 2 * i, bufferSize - 2 * i, "%02X", dataArray[i]); - } - void ViewHashes::drawContent() { + const auto &hashes = ContentRegistry::Hashes::impl::getHashes(); + + if (this->m_selectedHash == nullptr && !hashes.empty()) { + this->m_selectedHash = hashes.front(); + } + if (ImGui::Begin(View::toWindowName("hex.builtin.view.hashes.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) { - if (ImGui::BeginChild("##scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav)) { + if (ImGui::BeginCombo("hex.builtin.view.hashes.function"_lang, this->m_selectedHash != nullptr ? this->m_selectedHash->getName().c_str() : "")) { - - auto provider = ImHexApi::Provider::get(); - if (ImHexApi::Provider::isValid() && provider->isAvailable()) { - - ImGui::TextUnformatted("hex.builtin.common.region"_lang); - ImGui::Separator(); - - ImGui::InputScalarN("##nolabel", ImGuiDataType_U64, this->m_hashRegion, 2, nullptr, nullptr, "%08X", ImGuiInputTextFlags_CharsHexadecimal); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::Checkbox("hex.builtin.common.match_selection"_lang, &this->m_shouldMatchSelection); - if (ImGui::IsItemEdited()) { - // Force execution of Region Selection Event - ImHexApi::HexEditor::setSelection(0, 0); - this->m_shouldInvalidate = true; - } - - ImGui::NewLine(); - ImGui::TextUnformatted("hex.builtin.view.hashes.settings"_lang); - ImGui::Separator(); - - if (ImGui::BeginCombo("hex.builtin.view.hashes.function"_lang, hashFunctionNames[this->m_currHashFunction].second, 0)) { - for (size_t i = 0; i < hashFunctionNames.size(); i++) { - bool is_selected = (static_cast(this->m_currHashFunction) == i); - if (ImGui::Selectable(hashFunctionNames[i].second, is_selected)) - this->m_currHashFunction = i; - if (is_selected) - ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch) - } - ImGui::EndCombo(); - this->m_shouldInvalidate = true; - } - - size_t dataSize = provider->getSize(); - if (this->m_hashRegion[1] >= provider->getBaseAddress() + dataSize) - this->m_hashRegion[1] = provider->getBaseAddress() + dataSize; - - - switch (hashFunctionNames[this->m_currHashFunction].first) { - case HashFunctions::Crc8: - { - static int polynomial = 0x07, init = 0x0000, xorout = 0x0000; - static bool reflectIn = false, reflectOut = false; - - ImGui::InputInt("hex.builtin.view.hashes.iv"_lang, &init, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::InputInt("hex.builtin.view.hashes.xorout"_lang, &xorout, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::Checkbox("hex.builtin.common.reflectIn"_lang, &reflectIn); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::Checkbox("hex.builtin.common.reflectOut"_lang, &reflectOut); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::InputInt("hex.builtin.view.hashes.poly"_lang, &polynomial, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::NewLine(); - - static u8 result = 0; - - if (this->m_shouldInvalidate) - result = crypt::crc8(provider, this->m_hashRegion[0], this->m_hashRegion[1], polynomial, init, xorout, reflectIn, reflectOut); - - char buffer[sizeof(result) * 2 + 1]; - snprintf(buffer, sizeof(buffer), "%02X", result); - - ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang); - ImGui::Separator(); - ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly); - } - break; - case HashFunctions::Crc16: - { - static int polynomial = 0x8005, init = 0x0000, xorout = 0x0000; - static bool reflectIn = false, reflectOut = false; - - ImGui::InputInt("hex.builtin.view.hashes.iv"_lang, &init, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::InputInt("hex.builtin.view.hashes.xorout"_lang, &xorout, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::Checkbox("hex.builtin.common.reflectIn"_lang, &reflectIn); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::Checkbox("hex.builtin.common.reflectOut"_lang, &reflectOut); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::InputInt("hex.builtin.view.hashes.poly"_lang, &polynomial, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::NewLine(); - - static u16 result = 0; - - if (this->m_shouldInvalidate) - result = crypt::crc16(provider, this->m_hashRegion[0], this->m_hashRegion[1], polynomial, init, xorout, reflectIn, reflectOut); - - char buffer[sizeof(result) * 2 + 1]; - snprintf(buffer, sizeof(buffer), "%04X", result); - - ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang); - ImGui::Separator(); - ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly); - } - break; - case HashFunctions::Crc32: - { - static int polynomial = 0x04C11DB7, init = 0xFFFFFFFF, xorout = 0xFFFFFFFF; - static bool reflectIn = true, reflectOut = true; - - - ImGui::InputInt("hex.builtin.view.hashes.iv"_lang, &init, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::InputInt("hex.builtin.view.hashes.xorout"_lang, &xorout, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::Checkbox("hex.builtin.common.reflectIn"_lang, &reflectIn); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::Checkbox("hex.builtin.common.reflectOut"_lang, &reflectOut); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::InputInt("hex.builtin.view.hashes.poly"_lang, &polynomial, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true; - - ImGui::NewLine(); - - static u32 result = 0; - - if (this->m_shouldInvalidate) - result = crypt::crc32(provider, this->m_hashRegion[0], this->m_hashRegion[1], polynomial, init, xorout, reflectIn, reflectOut); - - char buffer[sizeof(result) * 2 + 1]; - snprintf(buffer, sizeof(buffer), "%08X", result); - - ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang); - ImGui::Separator(); - ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly); - } - break; - case HashFunctions::Md5: - { - static std::array result = { 0 }; - - if (this->m_shouldInvalidate) - result = crypt::md5(provider, this->m_hashRegion[0], this->m_hashRegion[1]); - - char buffer[sizeof(result) * 2 + 1]; - formatBigHexInt(result, buffer, sizeof(buffer)); - - ImGui::NewLine(); - ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang); - ImGui::Separator(); - ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly); - } - break; - case HashFunctions::Sha1: - { - static std::array result = { 0 }; - - if (this->m_shouldInvalidate) - result = crypt::sha1(provider, this->m_hashRegion[0], this->m_hashRegion[1]); - - char buffer[sizeof(result) * 2 + 1]; - formatBigHexInt(result, buffer, sizeof(buffer)); - - ImGui::NewLine(); - ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang); - ImGui::Separator(); - ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly); - } - break; - case HashFunctions::Sha224: - { - static std::array result = { 0 }; - - if (this->m_shouldInvalidate) - result = crypt::sha224(provider, this->m_hashRegion[0], this->m_hashRegion[1]); - - char buffer[sizeof(result) * 2 + 1]; - formatBigHexInt(result, buffer, sizeof(buffer)); - - ImGui::NewLine(); - ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang); - ImGui::Separator(); - ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly); - } - break; - case HashFunctions::Sha256: - { - static std::array result; - - if (this->m_shouldInvalidate) - result = crypt::sha256(provider, this->m_hashRegion[0], this->m_hashRegion[1]); - - char buffer[sizeof(result) * 2 + 1]; - formatBigHexInt(result, buffer, sizeof(buffer)); - - ImGui::NewLine(); - ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang); - ImGui::Separator(); - ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly); - } - break; - case HashFunctions::Sha384: - { - static std::array result; - - if (this->m_shouldInvalidate) - result = crypt::sha384(provider, this->m_hashRegion[0], this->m_hashRegion[1]); - - char buffer[sizeof(result) * 2 + 1]; - formatBigHexInt(result, buffer, sizeof(buffer)); - - ImGui::NewLine(); - ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang); - ImGui::Separator(); - ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly); - } - break; - case HashFunctions::Sha512: - { - static std::array result; - - if (this->m_shouldInvalidate) - result = crypt::sha512(provider, this->m_hashRegion[0], this->m_hashRegion[1]); - - char buffer[sizeof(result) * 2 + 1]; - formatBigHexInt(result, buffer, sizeof(buffer)); - - ImGui::NewLine(); - ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang); - ImGui::Separator(); - ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly); - } - break; + for (const auto hash : hashes) { + if (ImGui::Selectable(hash->getName().c_str(), this->m_selectedHash == hash)) { + this->m_selectedHash = hash; + this->m_newHashName.clear(); } } - this->m_shouldInvalidate = false; + ImGui::EndCombo(); + } + + if (this->m_newHashName.empty() && this->m_selectedHash != nullptr) + this->m_newHashName = hex::format("{} {}", this->m_selectedHash->getName(), static_cast("hex.builtin.view.hashes.hash"_lang)); + + if (ImGui::BeginChild("##settings", ImVec2(ImGui::GetContentRegionAvailWidth(), 200_scaled), true)) { + if (this->m_selectedHash != nullptr) { + auto startPos = ImGui::GetCursorPosY(); + this->m_selectedHash->draw(); + + // Check if no elements have been added + if (startPos == ImGui::GetCursorPosY()) { + ImGui::TextFormattedCentered("hex.builtin.view.hashes.no_settings"_lang); + } + } } ImGui::EndChild(); + + ImGui::NewLine(); + + ImGui::InputText("##Name", this->m_newHashName); + ImGui::SameLine(); + + ImGui::BeginDisabled(this->m_newHashName.empty() || this->m_selectedHash == nullptr); + if (ImGui::IconButton(ICON_VS_ADD, ImGui::GetStyleColorVec4(ImGuiCol_Text))) { + if (this->m_selectedHash != nullptr) + this->m_hashFunctions.push_back(this->m_selectedHash->create(this->m_newHashName)); + } + ImGui::EndDisabled(); + + if (ImGui::BeginTable("##hashes", 3, ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Borders, ImVec2(ImGui::GetContentRegionAvailWidth(), ImGui::GetTextLineHeightWithSpacing() * 10))) { + ImGui::TableSetupColumn("hex.builtin.view.hashes.name"_lang); + ImGui::TableSetupColumn("hex.builtin.view.hashes.type"_lang); + ImGui::TableSetupColumn("hex.builtin.view.hashes.result"_lang, ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableHeadersRow(); + + auto provider = ImHexApi::Provider::get(); + auto selection = ImHexApi::HexEditor::getSelection(); + + std::optional indexToRemove; + for (u32 i = 0; i < this->m_hashFunctions.size(); i++) { + auto &function = this->m_hashFunctions[i]; + + ImGui::PushID(i); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::PushStyleColor(ImGuiCol_Header, 0x00); + ImGui::PushStyleColor(ImGuiCol_HeaderActive, 0x00); + ImGui::PushStyleColor(ImGuiCol_HeaderHovered, 0x00); + ImGui::Selectable(function.getName().c_str(), false); + ImGui::PopStyleColor(3); + + { + const auto ContextMenuId = hex::format("Context Menu {}", i); + + if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) + ImGui::OpenPopup(ContextMenuId.c_str()); + + if (ImGui::BeginPopup(ContextMenuId.c_str())) { + if (ImGui::MenuItem("hex.builtin.view.hashes.remove"_lang)) + indexToRemove = i; + + ImGui::EndPopup(); + } + } + + ImGui::TableNextColumn(); + ImGui::TextFormatted("{}", function.getType()->getName()); + + ImGui::TableNextColumn(); + std::string result; + if (provider != nullptr && selection.has_value()) + result = crypt::encode16(function.get(*selection, provider)); + else + result = "???"; + + ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth()); + ImGui::InputText("##result", result, ImGuiInputTextFlags_ReadOnly); + ImGui::PopItemWidth(); + + ImGui::PopID(); + } + + if (indexToRemove.has_value()) { + this->m_hashFunctions.erase(this->m_hashFunctions.begin() + indexToRemove.value()); + } + + ImGui::EndTable(); + } + + ImGui::NewLine(); + ImGui::TextWrapped("%s", static_cast("hex.builtin.view.hashes.hover_info"_lang)); } ImGui::End(); } diff --git a/plugins/builtin/source/content/views/view_hex_editor.cpp b/plugins/builtin/source/content/views/view_hex_editor.cpp index 04f53bf33..587505bcc 100644 --- a/plugins/builtin/source/content/views/view_hex_editor.cpp +++ b/plugins/builtin/source/content/views/view_hex_editor.cpp @@ -439,7 +439,7 @@ namespace hex::plugin::builtin { ImGui::BeginTooltip(); for (const auto &[id, tooltip] : tooltips) { - if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) { + if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) { ImGui::TableNextRow(); ImGui::TableNextColumn(); diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index 7e3409582..16249e689 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -254,7 +254,7 @@ namespace hex::plugin::builtin { if (child != nullptr) { ImGui::BeginTooltip(); - if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) { + if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) { ImGui::TableNextRow(); ImGui::TableNextColumn(); diff --git a/plugins/builtin/source/lang/en_US.cpp b/plugins/builtin/source/lang/en_US.cpp index 17642c496..74fc1d633 100644 --- a/plugins/builtin/source/lang/en_US.cpp +++ b/plugins/builtin/source/lang/en_US.cpp @@ -218,14 +218,14 @@ namespace hex::plugin::builtin { { "hex.builtin.view.disassembler.disassembly.bytes", "Byte" }, { "hex.builtin.view.hashes.name", "Hashes" }, - { "hex.builtin.view.hashes.settings", "Settings" }, + { "hex.builtin.view.hashes.hash", "Hash" }, + { "hex.builtin.view.hashes.no_settings", "No settings available" }, { "hex.builtin.view.hashes.function", "Hash function" }, - { "hex.builtin.view.hashes.iv", "Initial value" }, - { "hex.builtin.view.hashes.xorout", "Final XOR value" }, - { "hex.builtin.common.reflectIn", "Reflect input" }, - { "hex.builtin.common.reflectOut", "Reflect output" }, - { "hex.builtin.view.hashes.poly", "Polynomial" }, + { "hex.builtin.view.hashes.name", "Name" }, + { "hex.builtin.view.hashes.type", "Type" }, { "hex.builtin.view.hashes.result", "Result" }, + { "hex.builtin.view.hashes.remove", "Remove hash" }, + { "hex.builtin.view.hashes.hover_info", "Hover over the Hex Editor selection and hold down SHIFT to view the hashes of that region." }, { "hex.builtin.view.help.name", "Help" }, { "hex.builtin.view.help.about.name", "About" }, @@ -733,6 +733,21 @@ namespace hex::plugin::builtin { { "hex.builtin.visualizer.floating_point.64bit", "Floating Point (64 bits)" }, { "hex.builtin.visualizer.hexii", "HexII" }, { "hex.builtin.visualizer.rgba8", "RGBA8 Color" }, + + { "hex.builtin.hash.md5", "MD5" }, + { "hex.builtin.hash.sha1", "SHA1" }, + { "hex.builtin.hash.sha224", "SHA224" }, + { "hex.builtin.hash.sha256", "SHA256" }, + { "hex.builtin.hash.sha384", "SHA384" }, + { "hex.builtin.hash.sha512", "SHA512" }, + { "hex.builtin.hash.crc8", "CRC8" }, + { "hex.builtin.hash.crc16", "CRC16" }, + { "hex.builtin.hash.crc32", "CRC32" }, + { "hex.builtin.hash.crc.poly", "Polynomial" }, + { "hex.builtin.hash.crc.iv", "Initial Value" }, + { "hex.builtin.hash.crc.xor_out", "XOR Out" }, + { "hex.builtin.hash.crc.refl_in", "Reflect In" }, + { "hex.builtin.hash.crc.refl_out", "Reflect Out" }, }); } diff --git a/plugins/builtin/source/plugin_builtin.cpp b/plugins/builtin/source/plugin_builtin.cpp index 2f3cf7470..d70e2b903 100644 --- a/plugins/builtin/source/plugin_builtin.cpp +++ b/plugins/builtin/source/plugin_builtin.cpp @@ -11,6 +11,7 @@ namespace hex::plugin::builtin { void registerCommandPaletteCommands(); void registerSettings(); void registerDataProcessorNodes(); + void registerHashes(); void registerProviders(); void registerDataFormatters(); void registerLayouts(); @@ -49,6 +50,7 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") { registerCommandPaletteCommands(); registerSettings(); registerDataProcessorNodes(); + registerHashes(); registerProviders(); registerDataFormatters(); createWelcomeScreen();