From ef12798fe2ca76437e11b1101fa0bda27f8e360d Mon Sep 17 00:00:00 2001 From: WerWolv Date: Wed, 18 Jan 2023 14:30:56 +0100 Subject: [PATCH] feat: Allow custom hashes to be saved to projects --- .../include/hex/api/content_registry.hpp | 10 ++- .../content/helpers/provider_extra_data.hpp | 8 +- .../include/content/views/view_hashes.hpp | 6 +- plugins/builtin/source/content/hashes.cpp | 42 +++++++++ .../source/content/views/view_hashes.cpp | 87 +++++++++++++++++-- 5 files changed, 138 insertions(+), 15 deletions(-) diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index 0f4a1728c..d4e46a32e 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -436,11 +436,12 @@ namespace hex { public: using Callback = std::function(const Region&, prv::Provider *)>; - Function(const Hash *type, std::string name, Callback callback) + Function(Hash *type, std::string name, Callback callback) : m_type(type), m_name(std::move(name)), m_callback(std::move(callback)) { } + [[nodiscard]] Hash *getType() { return this->m_type; } [[nodiscard]] const Hash *getType() const { return this->m_type; } [[nodiscard]] const std::string &getName() const { return this->m_name; } @@ -457,7 +458,7 @@ namespace hex { } private: - const Hash *m_type; + Hash *m_type; std::string m_name; Callback m_callback; @@ -467,12 +468,15 @@ namespace hex { virtual void draw() { } [[nodiscard]] virtual Function create(std::string name) = 0; + [[nodiscard]] virtual nlohmann::json store() const = 0; + virtual void load(const nlohmann::json &json) = 0; + [[nodiscard]] const std::string &getUnlocalizedName() const { return this->m_unlocalizedName; } protected: - [[nodiscard]] Function create(const std::string &name, const Function::Callback &callback) const { + [[nodiscard]] Function create(const std::string &name, const Function::Callback &callback) { return { this, name, callback }; } diff --git a/plugins/builtin/include/content/helpers/provider_extra_data.hpp b/plugins/builtin/include/content/helpers/provider_extra_data.hpp index 30d28455d..5e01065f8 100644 --- a/plugins/builtin/include/content/helpers/provider_extra_data.hpp +++ b/plugins/builtin/include/content/helpers/provider_extra_data.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include #include @@ -8,6 +8,8 @@ #include #include +#include + namespace hex::plugin::builtin { class ProviderExtraData { @@ -73,6 +75,10 @@ namespace hex::plugin::builtin { std::optional selectionStart, selectionEnd; float scrollPosition = 0.0F; } editor; + + struct Hashes { + std::vector hashFunctions; + } hashes; }; static Data& getCurrent() { diff --git a/plugins/builtin/include/content/views/view_hashes.hpp b/plugins/builtin/include/content/views/view_hashes.hpp index 5f8ce53fb..337ffee15 100644 --- a/plugins/builtin/include/content/views/view_hashes.hpp +++ b/plugins/builtin/include/content/views/view_hashes.hpp @@ -17,11 +17,13 @@ namespace hex::plugin::builtin { void drawContent() override; + private: + static bool importHashes(prv::Provider *provider, const nlohmann::json &json); + static bool exportHashes(prv::Provider *provider, nlohmann::json &json); + private: ContentRegistry::Hashes::Hash *m_selectedHash = nullptr; std::string m_newHashName; - - std::vector m_hashFunctions; }; } diff --git a/plugins/builtin/source/content/hashes.cpp b/plugins/builtin/source/content/hashes.cpp index 69f0cd0c5..fd698201f 100644 --- a/plugins/builtin/source/content/hashes.cpp +++ b/plugins/builtin/source/content/hashes.cpp @@ -4,6 +4,8 @@ #include +#include + namespace hex::plugin::builtin { class HashMD5 : public ContentRegistry::Hashes::Hash { @@ -17,6 +19,9 @@ namespace hex::plugin::builtin { return { array.begin(), array.end() }; }); } + + [[nodiscard]] nlohmann::json store() const override { return { }; } + void load(const nlohmann::json &) override {} }; class HashSHA1 : public ContentRegistry::Hashes::Hash { @@ -30,6 +35,9 @@ namespace hex::plugin::builtin { return { array.begin(), array.end() }; }); } + + [[nodiscard]] nlohmann::json store() const override { return { }; } + void load(const nlohmann::json &) override {} }; class HashSHA224 : public ContentRegistry::Hashes::Hash { @@ -43,6 +51,9 @@ namespace hex::plugin::builtin { return { array.begin(), array.end() }; }); } + + [[nodiscard]] nlohmann::json store() const override { return { }; } + void load(const nlohmann::json &) override {} }; class HashSHA256 : public ContentRegistry::Hashes::Hash { @@ -56,6 +67,9 @@ namespace hex::plugin::builtin { return { array.begin(), array.end() }; }); } + + [[nodiscard]] nlohmann::json store() const override { return { }; } + void load(const nlohmann::json &) override {} }; class HashSHA384 : public ContentRegistry::Hashes::Hash { @@ -69,6 +83,9 @@ namespace hex::plugin::builtin { return { array.begin(), array.end() }; }); } + + [[nodiscard]] nlohmann::json store() const override { return { }; } + void load(const nlohmann::json &) override {} }; class HashSHA512 : public ContentRegistry::Hashes::Hash { @@ -82,6 +99,9 @@ namespace hex::plugin::builtin { return { array.begin(), array.end() }; }); } + + [[nodiscard]] nlohmann::json store() const override { return { }; } + void load(const nlohmann::json &) override {} }; template @@ -113,6 +133,28 @@ namespace hex::plugin::builtin { }); } + [[nodiscard]] nlohmann::json store() const override { + nlohmann::json result; + + result["polynomial"] = this->m_polynomial; + result["initialValue"] = this->m_initialValue; + result["xorOut"] = this->m_xorOut; + result["reflectIn"] = this->m_reflectIn; + result["reflectOut"] = this->m_reflectOut; + + return result; + } + + void load(const nlohmann::json &json) override { + try { + this->m_polynomial = json["polynomial"]; + this->m_initialValue = json["initialValue"]; + this->m_xorOut = json["xorOut"]; + this->m_reflectIn = json["reflectIn"]; + this->m_reflectOut = json["reflectOut"]; + } catch (std::exception&) { } + } + private: CRCFunction m_crcFunction; diff --git a/plugins/builtin/source/content/views/view_hashes.cpp b/plugins/builtin/source/content/views/view_hashes.cpp index 2bb7435ee..1608e2b65 100644 --- a/plugins/builtin/source/content/views/view_hashes.cpp +++ b/plugins/builtin/source/content/views/view_hashes.cpp @@ -1,5 +1,7 @@ #include "content/views/view_hashes.hpp" +#include "content/helpers/provider_extra_data.hpp" +#include #include #include @@ -7,18 +9,19 @@ namespace hex::plugin::builtin { ViewHashes::ViewHashes() : View("hex.builtin.view.hashes.name") { - EventManager::subscribe(this, [this](const auto &) { - for (auto &function : this->m_hashFunctions) + EventManager::subscribe(this, [](const auto &providerRegion) { + for (auto &function : ProviderExtraData::get(providerRegion.getProvider()).hashes.hashFunctions) function.reset(); }); - ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) { + ImHexApi::HexEditor::addTooltipProvider([](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 })) { + auto &hashFunctions = ProviderExtraData::get(selection->getProvider()).hashes.hashFunctions; + if (!hashFunctions.empty() && selection.has_value() && selection->overlaps(Region { address, size })) { ImGui::BeginTooltip(); if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) { @@ -31,7 +34,7 @@ namespace hex::plugin::builtin { 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) { + for (auto &function : hashFunctions) { ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::TextFormatted("{}", function.getName()); @@ -55,6 +58,29 @@ namespace hex::plugin::builtin { } } }); + + ProjectFile::registerPerProviderHandler({ + .basePath = "hashes.json", + .required = false, + .load = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { + auto fileContent = tar.read(basePath); + if (fileContent.empty()) + return true; + + auto data = nlohmann::json::parse(fileContent.begin(), fileContent.end()); + ProviderExtraData::get(provider).hashes.hashFunctions.clear(); + + return ViewHashes::importHashes(provider, data); + }, + .store = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { + nlohmann::json data; + + bool result = ViewHashes::exportHashes(provider, data); + tar.write(basePath, data.dump(4)); + + return result; + } + }); } ViewHashes::~ViewHashes() { @@ -70,6 +96,8 @@ namespace hex::plugin::builtin { } if (ImGui::Begin(View::toWindowName("hex.builtin.view.hashes.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) { + auto &hashFunctions = ProviderExtraData::get(ImHexApi::Provider::get()).hashes.hashFunctions; + if (ImGui::BeginCombo("hex.builtin.view.hashes.function"_lang, this->m_selectedHash != nullptr ? LangEntry(this->m_selectedHash->getUnlocalizedName()) : "")) { for (const auto hash : hashes) { @@ -106,7 +134,7 @@ namespace hex::plugin::builtin { 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)); + hashFunctions.push_back(this->m_selectedHash->create(this->m_newHashName)); } ImGui::EndDisabled(); @@ -121,8 +149,8 @@ namespace hex::plugin::builtin { auto selection = ImHexApi::HexEditor::getSelection(); std::optional indexToRemove; - for (u32 i = 0; i < this->m_hashFunctions.size(); i++) { - auto &function = this->m_hashFunctions[i]; + for (u32 i = 0; i < hashFunctions.size(); i++) { + auto &function = hashFunctions[i]; ImGui::PushID(i); @@ -167,7 +195,7 @@ namespace hex::plugin::builtin { } if (indexToRemove.has_value()) { - this->m_hashFunctions.erase(this->m_hashFunctions.begin() + indexToRemove.value()); + hashFunctions.erase(hashFunctions.begin() + indexToRemove.value()); } ImGui::EndTable(); @@ -179,4 +207,45 @@ namespace hex::plugin::builtin { ImGui::End(); } + bool ViewHashes::importHashes(prv::Provider *provider, const nlohmann::json &json) { + if (!json.contains("hashes")) + return false; + + const auto &hashes = ContentRegistry::Hashes::impl::getHashes(); + + auto &hashFunctions = ProviderExtraData::get(provider).hashes.hashFunctions; + for (const auto &hash : json["hashes"]) { + if (!hash.contains("name") || !hash.contains("type")) + continue; + + for (const auto &newHash : hashes) { + if (newHash->getUnlocalizedName() == hash["type"]) { + + auto newFunction = newHash->create(hash["name"]); + newFunction.getType()->load(hash["settings"]); + + hashFunctions.push_back(std::move(newFunction)); + break; + } + } + } + + return true; + } + + bool ViewHashes::exportHashes(prv::Provider *provider, nlohmann::json &json) { + json["hashes"] = nlohmann::json::array(); + size_t index = 0; + for (const auto &hashFunction : ProviderExtraData::get(provider).hashes.hashFunctions) { + json["hashes"][index] = { + { "name", hashFunction.getName() }, + { "type", hashFunction.getType()->getUnlocalizedName() }, + { "settings", hashFunction.getType()->store() } + }; + index++; + } + + return true; + } + }