diff --git a/lib/external/libwolv b/lib/external/libwolv index e48ba7b38..76f8317e8 160000 --- a/lib/external/libwolv +++ b/lib/external/libwolv @@ -1 +1 @@ -Subproject commit e48ba7b3892eee151ed815e5b37ec33abbc66acd +Subproject commit 76f8317e8e7c761879a34227bed22a4e647ea353 diff --git a/lib/external/pattern_language b/lib/external/pattern_language index 1ae5969bd..ce644cf16 160000 --- a/lib/external/pattern_language +++ b/lib/external/pattern_language @@ -1 +1 @@ -Subproject commit 1ae5969bd65e422523ed9d42bf715bd387075797 +Subproject commit ce644cf16223f4e335a49e8f3e3cc3d9d9afe4ae diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index fca5242e8..9c1e9df2f 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -262,6 +262,18 @@ namespace hex { } + /** + * @brief Provides access to the current provider's pattern language runtime + * @return Runtime + */ + pl::PatternLanguage& getRuntime(); + + /** + * @brief Provides access to the current provider's pattern language runtime's lock + * @return Lock + */ + std::scoped_lock getRuntimeLock(); + /** * @brief Configures the pattern language runtime using ImHex's default settings * @param runtime The pattern language runtime to configure @@ -440,7 +452,7 @@ namespace hex { add(impl::Entry { unlocalizedCategory.c_str(), unlocalizedName.c_str(), - [=] { + [=, ...args = std::forward(args)] mutable { auto node = std::make_unique(std::forward(args)...); node->setUnlocalizedName(unlocalizedName); return node; diff --git a/lib/libimhex/include/hex/api/event.hpp b/lib/libimhex/include/hex/api/event.hpp index 4ae8ff524..e2efeb7b0 100644 --- a/lib/libimhex/include/hex/api/event.hpp +++ b/lib/libimhex/include/hex/api/event.hpp @@ -94,7 +94,7 @@ namespace hex { * @param token Token returned by subscribe */ static void unsubscribe(const EventList::iterator &token) noexcept { - s_events.remove(*token); + s_events.erase(token); } /** @@ -167,6 +167,7 @@ namespace hex { EVENT_DEF(EventPatternEditorChanged, const std::string&); EVENT_DEF(EventStoreContentDownloaded, const std::fs::path&); EVENT_DEF(EventStoreContentRemoved, const std::fs::path&); + EVENT_DEF(EventImHexClosing); EVENT_DEF(RequestOpenWindow, std::string); EVENT_DEF(RequestSelectionChange, Region); diff --git a/lib/libimhex/include/hex/providers/provider_data.hpp b/lib/libimhex/include/hex/providers/provider_data.hpp new file mode 100644 index 000000000..800e6872a --- /dev/null +++ b/lib/libimhex/include/hex/providers/provider_data.hpp @@ -0,0 +1,78 @@ +#pragma once + +#include +#include +#include + +#include +#include +#include + +namespace hex { + + template + class PerProvider { + public: + PerProvider() { this->onCreate(); } + PerProvider(const PerProvider&) = delete; + PerProvider(PerProvider&&) = delete; + PerProvider& operator=(const PerProvider&) = delete; + PerProvider& operator=(PerProvider&&) = delete; + + PerProvider(T data) : m_data({ { ImHexApi::Provider::get(), std::move(data) } }) { this->onCreate(); } + + ~PerProvider() = default; + + T* operator->() { + return &this->get(); + } + + const T* operator->() const { + return &this->get(); + } + + T& get(prv::Provider *provider = ImHexApi::Provider::get()) { + return this->m_data[provider]; + } + + const T& get(prv::Provider *provider = ImHexApi::Provider::get()) const { + return this->m_data[provider]; + } + + T& operator*() { + return this->get(); + } + + const T& operator*() const { + return this->get(); + } + + PerProvider& operator=(T data) { + this->m_data = std::move(data); + return *this; + } + + operator T&() { + return this->get(); + } + + private: + void onCreate() { + (void)EventManager::subscribe([this](prv::Provider *provider) { + this->m_data.emplace(provider, T()); + }); + + (void)EventManager::subscribe([this](prv::Provider *provider){ + this->m_data.erase(provider); + }); + + EventManager::subscribe([this] { + this->m_data.clear(); + }); + } + + private: + std::map m_data; + }; + +} \ No newline at end of file diff --git a/lib/libimhex/include/hex/ui/view.hpp b/lib/libimhex/include/hex/ui/view.hpp index 09f367d00..bbe9ddbea 100644 --- a/lib/libimhex/include/hex/ui/view.hpp +++ b/lib/libimhex/include/hex/ui/view.hpp @@ -13,6 +13,7 @@ #include #include #include +#include #include #include diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index ef0911ce6..d0d2515ba 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -259,6 +259,18 @@ namespace hex { return functionName; } + pl::PatternLanguage& getRuntime() { + static PerProvider runtime; + + return *runtime; + } + + std::scoped_lock getRuntimeLock() { + static std::mutex runtimeLock; + + return std::scoped_lock(runtimeLock); + } + void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider) { runtime.reset(); diff --git a/main/source/init/tasks.cpp b/main/source/init/tasks.cpp index be23bc59c..4e83b0797 100644 --- a/main/source/init/tasks.cpp +++ b/main/source/init/tasks.cpp @@ -267,7 +267,7 @@ namespace hex::init { // This is a bit of a hack but necessary because when ImHex gets closed, all plugins are unloaded in order for // destructors to be called correctly. To prevent crashes when ImHex exits, we need to delete all shared data - EventManager::clear(); + EventManager::post(); while (ImHexApi::Provider::isValid()) ImHexApi::Provider::remove(ImHexApi::Provider::get()); @@ -335,6 +335,8 @@ namespace hex::init { fs::setFileBrowserErrorCallback(nullptr); + EventManager::clear(); + return true; } diff --git a/plugins/builtin/include/content/helpers/provider_extra_data.hpp b/plugins/builtin/include/content/helpers/provider_extra_data.hpp deleted file mode 100644 index c745f47f0..000000000 --- a/plugins/builtin/include/content/helpers/provider_extra_data.hpp +++ /dev/null @@ -1,145 +0,0 @@ -#pragma once - -#include -#include - -#include -#include -#include -#include - -#include - -#include - -#include -#include - -namespace hex::plugin::builtin { - - class ProviderExtraData { - public: - struct Data { - Data() : patternLanguage(), bookmarks(), dataProcessor(), editor(), hashes(), yara() { - log::debug("Creating new extra data instance"); - } - - bool dataDirty = false; - - struct PatternLanguage { - struct PatternVariable { - bool inVariable; - bool outVariable; - - pl::core::Token::ValueType type; - pl::core::Token::Literal value; - }; - - enum class EnvVarType - { - Integer, - Float, - String, - Bool - }; - - struct EnvVar { - u64 id; - std::string name; - pl::core::Token::Literal value; - EnvVarType type; - - bool operator==(const EnvVar &other) const { - return this->id == other.id; - } - }; - - std::string sourceCode; - std::mutex runtimeMutex; - std::unique_ptr runtime = std::make_unique(); - std::vector> console; - bool executionDone = true; - - std::optional lastEvaluationError; - std::vector> lastEvaluationLog; - std::map lastEvaluationOutVars; - std::map patternVariables; - std::map sections; - - std::list envVarEntries; - } patternLanguage; - - std::list bookmarks; - - struct DataProcessor { - struct Workspace { - std::unique_ptr context = { []{ - ImNodesContext *ctx = ImNodes::CreateContext(); - ctx->Style = ImNodes::GetStyle(); - ctx->Io = ImNodes::GetIO(); - ctx->AttributeFlagStack = GImNodes->AttributeFlagStack; - - return ctx; - }(), ImNodes::DestroyContext }; - - std::list> nodes; - std::list endNodes; - std::list links; - std::vector dataOverlays; - std::optional currNodeError; - }; - - Workspace mainWorkspace; - std::vector workspaceStack; - } dataProcessor; - - struct HexEditor { - std::optional selectionStart = std::nullopt, selectionEnd = std::nullopt; - float scrollPosition = 0.0F; - } editor; - - struct Hashes { - std::vector hashFunctions; - } hashes; - - struct Yara { - struct YaraMatch { - std::string identifier; - std::string variable; - u64 address; - size_t size; - bool wholeDataMatch; - - mutable u32 highlightId; - mutable u32 tooltipId; - }; - - std::vector> rules; - std::vector matches; - std::vector sortedMatches; - } yara; - }; - - static Data& getCurrent() { - return get(ImHexApi::Provider::get()); - } - - static Data& get(const hex::prv::Provider *provider) { - return s_data[provider]; - } - - static void erase(hex::prv::Provider *provider) { - s_data.erase(provider); - } - - static bool markDirty() { - return getCurrent().dataDirty = true; - } - - private: - ProviderExtraData() = default; - - static inline std::map s_data = {}; - }; - -} \ No newline at end of file diff --git a/plugins/builtin/include/content/popups/popup_file_chooser.hpp b/plugins/builtin/include/content/popups/popup_file_chooser.hpp index 9e6ff9144..ce464aeee 100644 --- a/plugins/builtin/include/content/popups/popup_file_chooser.hpp +++ b/plugins/builtin/include/content/popups/popup_file_chooser.hpp @@ -10,7 +10,7 @@ namespace hex::plugin::builtin { class PopupFileChooser : public Popup { public: PopupFileChooser(const std::vector &files, const std::vector &validExtensions, bool multiple, const std::function &callback) - : hex::Popup("hex.builtin.common.choose_file", false), + : hex::Popup("hex.builtin.common.choose_file"), m_indices({ }), m_files(files), m_openCallback(callback), m_validExtensions(validExtensions), m_multiple(multiple) { } diff --git a/plugins/builtin/include/content/views/view_bookmarks.hpp b/plugins/builtin/include/content/views/view_bookmarks.hpp index 7ff4ebdfe..8042fb79a 100644 --- a/plugins/builtin/include/content/views/view_bookmarks.hpp +++ b/plugins/builtin/include/content/views/view_bookmarks.hpp @@ -15,14 +15,15 @@ namespace hex::plugin::builtin { void drawContent() override; private: - static bool importBookmarks(hex::prv::Provider *provider, const nlohmann::json &json); - static bool exportBookmarks(hex::prv::Provider *provider, nlohmann::json &json); + bool importBookmarks(hex::prv::Provider *provider, const nlohmann::json &json); + bool exportBookmarks(hex::prv::Provider *provider, nlohmann::json &json); void registerMenuItems(); private: std::string m_currFilter; std::list::iterator m_dragStartIterator; + PerProvider> m_bookmarks; }; } \ No newline at end of file diff --git a/plugins/builtin/include/content/views/view_data_processor.hpp b/plugins/builtin/include/content/views/view_data_processor.hpp index 52f8632b9..ab70e5981 100644 --- a/plugins/builtin/include/content/views/view_data_processor.hpp +++ b/plugins/builtin/include/content/views/view_data_processor.hpp @@ -7,7 +7,7 @@ #include #include -#include "content/helpers/provider_extra_data.hpp" +#include #include #include @@ -16,8 +16,26 @@ namespace hex::plugin::builtin { class ViewDataProcessor : public View { public: - using Workspace = ProviderExtraData::Data::DataProcessor::Workspace; + struct Workspace { + Workspace() = default; + std::unique_ptr context = { []{ + ImNodesContext *ctx = ImNodes::CreateContext(); + ctx->Style = ImNodes::GetStyle(); + ctx->Io = ImNodes::GetIO(); + ctx->AttributeFlagStack = GImNodes->AttributeFlagStack; + + return ctx; + }(), ImNodes::DestroyContext }; + + std::list> nodes; + std::list endNodes; + std::list links; + std::vector dataOverlays; + std::optional currNodeError; + }; + + public: ViewDataProcessor(); ~ViewDataProcessor() override; @@ -29,12 +47,14 @@ namespace hex::plugin::builtin { static std::unique_ptr loadNode(const nlohmann::json &data); static void loadNodes(Workspace &workspace, const nlohmann::json &data); - private: static void eraseLink(Workspace &workspace, int id); static void eraseNodes(Workspace &workspace, const std::vector &ids); static void processNodes(Workspace &workspace); void reloadCustomNodes(); + + std::vector &getWorkspaceStack() { return *this->m_workspaceStack; } + private: bool m_updateNodePositions = false; int m_rightClickedId = -1; @@ -48,6 +68,9 @@ namespace hex::plugin::builtin { }; std::vector m_customNodes; + + PerProvider m_mainWorkspace; + PerProvider> m_workspaceStack; }; } \ No newline at end of file diff --git a/plugins/builtin/include/content/views/view_hashes.hpp b/plugins/builtin/include/content/views/view_hashes.hpp index 337ffee15..bef9237c3 100644 --- a/plugins/builtin/include/content/views/view_hashes.hpp +++ b/plugins/builtin/include/content/views/view_hashes.hpp @@ -18,12 +18,15 @@ 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); + bool importHashes(prv::Provider *provider, const nlohmann::json &json); + bool exportHashes(prv::Provider *provider, nlohmann::json &json); private: ContentRegistry::Hashes::Hash *m_selectedHash = nullptr; std::string m_newHashName; + + PerProvider> m_hashFunctions; + }; } diff --git a/plugins/builtin/include/content/views/view_hex_editor.hpp b/plugins/builtin/include/content/views/view_hex_editor.hpp index a43e537eb..e272562c9 100644 --- a/plugins/builtin/include/content/views/view_hex_editor.hpp +++ b/plugins/builtin/include/content/views/view_hex_editor.hpp @@ -6,7 +6,6 @@ #include #include -#include #include namespace hex::plugin::builtin { @@ -74,6 +73,9 @@ namespace hex::plugin::builtin { bool m_shouldOpenPopup = false; std::unique_ptr m_currPopup; + + PerProvider> m_selectionStart, m_selectionEnd; + PerProvider m_scrollPosition; }; } \ No newline at end of file diff --git a/plugins/builtin/include/content/views/view_pattern_editor.hpp b/plugins/builtin/include/content/views/view_pattern_editor.hpp index 62bb4488e..e5998e3cf 100644 --- a/plugins/builtin/include/content/views/view_pattern_editor.hpp +++ b/plugins/builtin/include/content/views/view_pattern_editor.hpp @@ -1,4 +1,4 @@ -#pragma once + #pragma once #include #include @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -102,7 +101,32 @@ namespace hex::plugin::builtin { }; private: - using PlData = ProviderExtraData::Data::PatternLanguage; + struct PatternVariable { + bool inVariable; + bool outVariable; + + pl::core::Token::ValueType type; + pl::core::Token::Literal value; + }; + + enum class EnvVarType + { + Integer, + Float, + String, + Bool + }; + + struct EnvVar { + u64 id; + std::string name; + pl::core::Token::Literal value; + EnvVarType type; + + bool operator==(const EnvVar &other) const { + return this->id == other.id; + } + }; std::unique_ptr m_parserRuntime; @@ -130,10 +154,22 @@ namespace hex::plugin::builtin { ui::HexEditor m_sectionHexEditor; + PerProvider m_sourceCode; + PerProvider>> m_console; + PerProvider m_executionDone = true; + + PerProvider> m_lastEvaluationError; + PerProvider>> m_lastEvaluationLog; + PerProvider> m_lastEvaluationOutVars; + PerProvider> m_patternVariables; + PerProvider> m_sections; + + PerProvider> m_envVarEntries; + private: void drawConsole(ImVec2 size, const std::vector> &console); - void drawEnvVars(ImVec2 size, std::list &envVars); - void drawVariableSettings(ImVec2 size, std::map &patternVariables); + void drawEnvVars(ImVec2 size, std::list &envVars); + void drawVariableSettings(ImVec2 size, std::map &patternVariables); void drawSectionSelector(ImVec2 size, std::map §ions); void drawPatternTooltip(pl::ptrn::Pattern *pattern); diff --git a/plugins/builtin/include/content/views/view_yara.hpp b/plugins/builtin/include/content/views/view_yara.hpp index cd5058634..13bab6269 100644 --- a/plugins/builtin/include/content/views/view_yara.hpp +++ b/plugins/builtin/include/content/views/view_yara.hpp @@ -17,6 +17,22 @@ namespace hex::plugin::builtin { void drawContent() override; private: + struct YaraMatch { + std::string identifier; + std::string variable; + u64 address; + size_t size; + bool wholeDataMatch; + + mutable u32 highlightId; + mutable u32 tooltipId; + }; + + private: + PerProvider>> m_rules; + PerProvider> m_matches; + PerProvider> m_sortedMatches; + u32 m_selectedRule = 0; TaskHolder m_matcherTask; diff --git a/plugins/builtin/source/content/data_processor_nodes.cpp b/plugins/builtin/source/content/data_processor_nodes.cpp index 91a17447f..3c4c58d75 100644 --- a/plugins/builtin/source/content/data_processor_nodes.cpp +++ b/plugins/builtin/source/content/data_processor_nodes.cpp @@ -7,9 +7,6 @@ #include #include -#include - -#include #include #include @@ -22,7 +19,6 @@ #include #include -#include namespace hex::plugin::builtin { @@ -1166,10 +1162,10 @@ namespace hex::plugin::builtin { } void process() override { - auto &pl = ProviderExtraData::getCurrent().patternLanguage; + auto lock = ContentRegistry::PatternLanguage::getRuntimeLock(); + auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); - std::scoped_lock lock(pl.runtimeMutex); - const auto &outVars = pl.runtime->getOutVariables(); + const auto &outVars = runtime.getOutVariables(); if (outVars.contains(this->m_name)) { std::visit(wolv::util::overloaded { @@ -1201,303 +1197,6 @@ namespace hex::plugin::builtin { std::string m_name; }; - class NodeCustomInput : public dp::Node { - public: - NodeCustomInput() : Node("hex.builtin.nodes.custom.input.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input") }) { } - ~NodeCustomInput() override = default; - - void drawNode() override { - ImGui::PushItemWidth(100_scaled); - if (ImGui::Combo("##type", &this->m_type, "Integer\0Float\0Buffer\0")) { - this->setAttributes({ - { dp::Attribute(dp::Attribute::IOType::Out, this->getType(), "hex.builtin.nodes.common.input") } - }); - } - - if (ImGui::InputText("##name", this->m_name)) { - this->setUnlocalizedTitle(this->m_name); - } - - ImGui::PopItemWidth(); - } - - void setValue(auto value) { this->m_value = std::move(value); } - - const std::string &getName() const { return this->m_name; } - dp::Attribute::Type getType() const { - switch (this->m_type) { - default: - case 0: return dp::Attribute::Type::Integer; - case 1: return dp::Attribute::Type::Float; - case 2: return dp::Attribute::Type::Buffer; - } - } - - void process() override { - std::visit(wolv::util::overloaded { - [this](i128 value) { this->setIntegerOnOutput(0, value); }, - [this](long double value) { this->setFloatOnOutput(0, value); }, - [this](const std::vector &value) { this->setBufferOnOutput(0, value); } - }, this->m_value); - } - - void store(nlohmann::json &j) const override { - j = nlohmann::json::object(); - - j["name"] = this->m_name; - j["type"] = this->m_type; - } - - void load(const nlohmann::json &j) override { - this->m_name = j["name"].get(); - this->m_type = j["type"]; - - this->setUnlocalizedTitle(this->m_name); - this->setAttributes({ - { dp::Attribute(dp::Attribute::IOType::Out, this->getType(), "hex.builtin.nodes.common.input") } - }); - } - - private: - std::string m_name = LangEntry(this->getUnlocalizedName()); - int m_type = 0; - - std::variant> m_value; - }; - - class NodeCustomOutput : public dp::Node { - public: - NodeCustomOutput() : Node("hex.builtin.nodes.custom.output.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } - ~NodeCustomOutput() override = default; - - void drawNode() override { - ImGui::PushItemWidth(100_scaled); - if (ImGui::Combo("##type", &this->m_type, "Integer\0Float\0Buffer\0")) { - this->setAttributes({ - { dp::Attribute(dp::Attribute::IOType::In, this->getType(), "hex.builtin.nodes.common.output") } - }); - } - - if (ImGui::InputText("##name", this->m_name)) { - this->setUnlocalizedTitle(this->m_name); - } - - ImGui::PopItemWidth(); - } - - const std::string &getName() const { return this->m_name; } - dp::Attribute::Type getType() const { - switch (this->m_type) { - case 0: return dp::Attribute::Type::Integer; - case 1: return dp::Attribute::Type::Float; - case 2: return dp::Attribute::Type::Buffer; - default: return dp::Attribute::Type::Integer; - } - } - - void process() override { - switch (this->getType()) { - case dp::Attribute::Type::Integer: this->m_value = this->getIntegerOnInput(0); break; - case dp::Attribute::Type::Float: this->m_value = this->getFloatOnInput(0); break; - case dp::Attribute::Type::Buffer: this->m_value = this->getBufferOnInput(0); break; - } - } - - const auto& getValue() const { return this->m_value; } - - void store(nlohmann::json &j) const override { - j = nlohmann::json::object(); - - j["name"] = this->m_name; - j["type"] = this->m_type; - } - - void load(const nlohmann::json &j) override { - this->m_name = j["name"].get(); - this->m_type = j["type"]; - - this->setUnlocalizedTitle(this->m_name); - this->setAttributes({ - { dp::Attribute(dp::Attribute::IOType::In, this->getType(), "hex.builtin.nodes.common.output") } - }); - } - - private: - std::string m_name = LangEntry(this->getUnlocalizedName()); - int m_type = 0; - - std::variant> m_value; - }; - - class NodeCustom : public dp::Node { - public: - NodeCustom() : Node("hex.builtin.nodes.custom.custom.header", {}) { } - ~NodeCustom() override = default; - - void drawNode() override { - if (this->m_requiresAttributeUpdate) { - this->m_requiresAttributeUpdate = false; - this->setAttributes(this->findAttributes()); - } - - ImGui::PushItemWidth(200_scaled); - - bool editing = false; - if (this->m_editable) { - ImGui::InputTextIcon("##name", ICON_VS_SYMBOL_KEY, this->m_name); - editing = ImGui::IsItemActive(); - - if (ImGui::Button("hex.builtin.nodes.custom.custom.edit"_lang, ImVec2(200_scaled, ImGui::GetTextLineHeightWithSpacing()))) { - auto &data = ProviderExtraData::getCurrent().dataProcessor; - data.workspaceStack.push_back(&this->m_workspace); - - this->m_requiresAttributeUpdate = true; - } - } else { - this->setUnlocalizedTitle(this->m_name); - - if (this->getAttributes().empty()) { - ImGui::TextUnformatted("hex.builtin.nodes.custom.custom.edit_hint"_lang); - } - } - - this->m_editable = ImGui::GetIO().KeyShift || editing; - - ImGui::PopItemWidth(); - } - - void process() override { - auto indexFromId = [this](u32 id) -> std::optional { - const auto &attributes = this->getAttributes(); - for (u32 i = 0; i < attributes.size(); i++) - if (u32(attributes[i].getId()) == id) - return i; - return std::nullopt; - }; - - auto prevContext = ImNodes::GetCurrentContext(); - ImNodes::SetCurrentContext(this->m_workspace.context.get()); - ON_SCOPE_EXIT { ImNodes::SetCurrentContext(prevContext); }; - - // Forward inputs to input nodes values - for (auto &attribute : this->getAttributes()) { - auto index = indexFromId(attribute.getId()); - if (!index.has_value()) - continue; - - if (auto input = this->findInput(attribute.getUnlocalizedName()); input != nullptr) { - switch (attribute.getType()) { - case dp::Attribute::Type::Integer: { - const auto &value = this->getIntegerOnInput(*index); - input->setValue(value); - break; - } - case dp::Attribute::Type::Float: { - const auto &value = this->getFloatOnInput(*index); - input->setValue(value); - break; - } - case dp::Attribute::Type::Buffer: { - const auto &value = this->getBufferOnInput(*index); - input->setValue(value); - break; - } - } - } - } - - // Process all nodes in our workspace - for (auto &endNode : this->m_workspace.endNodes) { - endNode->resetOutputData(); - - for (auto &node : this->m_workspace.nodes) - node->resetProcessedInputs(); - - endNode->process(); - } - - // Forward output node values to outputs - for (auto &attribute : this->getAttributes()) { - auto index = indexFromId(attribute.getId()); - if (!index.has_value()) - continue; - - if (auto output = this->findOutput(attribute.getUnlocalizedName()); output != nullptr) { - switch (attribute.getType()) { - case dp::Attribute::Type::Integer: { - auto value = std::get(output->getValue()); - this->setIntegerOnOutput(*index, value); - break; - } - case dp::Attribute::Type::Float: { - auto value = std::get(output->getValue()); - this->setFloatOnOutput(*index, value); - break; - } - case dp::Attribute::Type::Buffer: { - auto value = std::get>(output->getValue()); - this->setBufferOnOutput(*index, value); - break; - } - } - } - } - } - - void store(nlohmann::json &j) const override { - j = nlohmann::json::object(); - - j["nodes"] = ViewDataProcessor::saveNodes(this->m_workspace); - } - - void load(const nlohmann::json &j) override { - ViewDataProcessor::loadNodes(this->m_workspace, j["nodes"]); - - this->m_name = LangEntry(this->getUnlocalizedTitle()).get(); - this->m_requiresAttributeUpdate = true; - } - - private: - std::vector findAttributes() { - std::vector result; - - for (auto &node : this->m_workspace.nodes) { - if (auto *inputNode = dynamic_cast(node.get()); inputNode != nullptr) - result.emplace_back(dp::Attribute::IOType::In, inputNode->getType(), inputNode->getName()); - else if (auto *outputNode = dynamic_cast(node.get()); outputNode != nullptr) - result.emplace_back(dp::Attribute::IOType::Out, outputNode->getType(), outputNode->getName()); - } - - return result; - } - - NodeCustomInput* findInput(const std::string &name) { - for (auto &node : this->m_workspace.nodes) { - if (auto *inputNode = dynamic_cast(node.get()); inputNode != nullptr && inputNode->getName() == name) - return inputNode; - } - - return nullptr; - } - - NodeCustomOutput* findOutput(const std::string &name) { - for (auto &node : this->m_workspace.nodes) { - if (auto *outputNode = dynamic_cast(node.get()); outputNode != nullptr && outputNode->getName() == name) - return outputNode; - } - - return nullptr; - } - - private: - std::string m_name = "hex.builtin.nodes.custom.custom.header"_lang; - - bool m_editable = false; - - bool m_requiresAttributeUpdate = false; - ProviderExtraData::Data::DataProcessor::Workspace m_workspace; - }; - void registerDataProcessorNodes() { ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.int"); ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.float"); @@ -1565,10 +1264,6 @@ namespace hex::plugin::builtin { ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.byte_distribution"); ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.pattern_language", "hex.builtin.nodes.pattern_language.out_var"); - - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.custom", "hex.builtin.nodes.custom.custom"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.custom", "hex.builtin.nodes.custom.input"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.custom", "hex.builtin.nodes.custom.output"); } } \ No newline at end of file diff --git a/plugins/builtin/source/content/events.cpp b/plugins/builtin/source/content/events.cpp index 2d2f54547..06f72ac50 100644 --- a/plugins/builtin/source/content/events.cpp +++ b/plugins/builtin/source/content/events.cpp @@ -8,8 +8,6 @@ #include -#include - #include #include @@ -131,10 +129,6 @@ namespace hex::plugin::builtin { } }); - EventManager::subscribe([](hex::prv::Provider *provider) { - ProviderExtraData::erase(provider); - }); - EventManager::subscribe([](const ImHexApi::HexEditor::ProviderRegion ®ion) { ImHexApi::HexEditor::impl::setCurrentSelection(region); }); diff --git a/plugins/builtin/source/content/views/view_bookmarks.cpp b/plugins/builtin/source/content/views/view_bookmarks.cpp index 6b29a3da2..2c4253b51 100644 --- a/plugins/builtin/source/content/views/view_bookmarks.cpp +++ b/plugins/builtin/source/content/views/view_bookmarks.cpp @@ -11,15 +11,13 @@ #include #include -#include - #include #include namespace hex::plugin::builtin { ViewBookmarks::ViewBookmarks() : View("hex.builtin.view.bookmarks.name") { - EventManager::subscribe(this, [](Region region, std::string name, std::string comment, color_t color) { + EventManager::subscribe(this, [this](Region region, std::string name, std::string comment, color_t color) { if (name.empty()) { name = hex::format("hex.builtin.view.bookmarks.default_title"_lang, region.address, region.address + region.size - 1); } @@ -27,7 +25,7 @@ namespace hex::plugin::builtin { if (color == 0x00) color = ImGui::GetColorU32(ImGuiCol_Header); - ProviderExtraData::getCurrent().bookmarks.push_back({ + this->m_bookmarks->push_back({ region, name, std::move(comment), @@ -37,13 +35,13 @@ namespace hex::plugin::builtin { ImHexApi::Provider::markDirty(); - EventManager::post(ProviderExtraData::getCurrent().bookmarks.back()); + EventManager::post(this->m_bookmarks->back()); }); - ImHexApi::HexEditor::addBackgroundHighlightingProvider([](u64 address, const u8* data, size_t size, bool) -> std::optional { + ImHexApi::HexEditor::addBackgroundHighlightingProvider([this](u64 address, const u8* data, size_t size, bool) -> std::optional { hex::unused(data); - for (const auto &bookmark : ProviderExtraData::getCurrent().bookmarks) { + for (const auto &bookmark : *this->m_bookmarks) { if (Region { address, size }.isWithin(bookmark.region)) return bookmark.color; } @@ -51,9 +49,9 @@ namespace hex::plugin::builtin { return std::nullopt; }); - ImHexApi::HexEditor::addTooltipProvider([](u64 address, const u8 *data, size_t size) { + ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) { hex::unused(data); - for (const auto &bookmark : ProviderExtraData::getCurrent().bookmarks) { + for (const auto &bookmark : *this->m_bookmarks) { if (!Region { address, size }.isWithin(bookmark.region)) continue; @@ -113,19 +111,19 @@ namespace hex::plugin::builtin { ProjectFile::registerPerProviderHandler({ .basePath = "bookmarks.json", .required = false, - .load = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { + .load = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { auto fileContent = tar.readString(basePath); if (fileContent.empty()) return true; auto data = nlohmann::json::parse(fileContent.begin(), fileContent.end()); - ProviderExtraData::get(provider).bookmarks.clear(); - return ViewBookmarks::importBookmarks(provider, data); + this->m_bookmarks->clear(); + return this->importBookmarks(provider, data); }, - .store = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { + .store = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { nlohmann::json data; - bool result = ViewBookmarks::exportBookmarks(provider, data); + bool result = this->exportBookmarks(provider, data); tar.writeString(basePath, data.dump(4)); return result; @@ -187,14 +185,13 @@ namespace hex::plugin::builtin { ImGui::NewLine(); if (ImGui::BeginChild("##bookmarks")) { - auto &bookmarks = ProviderExtraData::getCurrent().bookmarks; - if (bookmarks.empty()) { + if (this->m_bookmarks->empty()) { ImGui::TextFormattedCentered("hex.builtin.view.bookmarks.no_bookmarks"_lang); } int id = 1; - auto bookmarkToRemove = bookmarks.end(); - for (auto iter = bookmarks.begin(); iter != bookmarks.end(); iter++) { + auto bookmarkToRemove = this->m_bookmarks->end(); + for (auto iter = this->m_bookmarks->begin(); iter != this->m_bookmarks->end(); iter++) { auto &[region, name, comment, color, locked] = *iter; if (!this->m_currFilter.empty()) { @@ -219,16 +216,16 @@ namespace hex::plugin::builtin { bool open = true; if (!ImGui::CollapsingHeader(hex::format("{}###bookmark", name).c_str(), locked ? nullptr : &open)) { - if (ImGui::IsMouseClicked(0) && ImGui::IsItemActivated() && this->m_dragStartIterator == bookmarks.end()) + if (ImGui::IsMouseClicked(0) && ImGui::IsItemActivated() && this->m_dragStartIterator == this->m_bookmarks->end()) this->m_dragStartIterator = iter; - if (ImGui::IsItemHovered() && this->m_dragStartIterator != bookmarks.end()) { + if (ImGui::IsItemHovered() && this->m_dragStartIterator != this->m_bookmarks->end()) { std::iter_swap(iter, this->m_dragStartIterator); this->m_dragStartIterator = iter; } if (!ImGui::IsMouseDown(0)) - this->m_dragStartIterator = bookmarks.end(); + this->m_dragStartIterator = this->m_bookmarks->end(); } else { const auto rowHeight = ImGui::GetTextLineHeightWithSpacing() + 2 * ImGui::GetStyle().FramePadding.y; if (ImGui::BeginTable("##bookmark_table", 3, ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit)) { @@ -329,8 +326,8 @@ namespace hex::plugin::builtin { bookmarkToRemove = iter; } - if (bookmarkToRemove != bookmarks.end()) { - bookmarks.erase(bookmarkToRemove); + if (bookmarkToRemove != this->m_bookmarks->end()) { + this->m_bookmarks->erase(bookmarkToRemove); } } ImGui::EndChild(); @@ -342,7 +339,6 @@ namespace hex::plugin::builtin { if (!json.contains("bookmarks")) return false; - auto &bookmarks = ProviderExtraData::get(provider).bookmarks; for (const auto &bookmark : json["bookmarks"]) { if (!bookmark.contains("name") || !bookmark.contains("comment") || !bookmark.contains("color") || !bookmark.contains("region") || !bookmark.contains("locked")) continue; @@ -351,7 +347,7 @@ namespace hex::plugin::builtin { if (!region.contains("address") || !region.contains("size")) continue; - bookmarks.push_back({ + this->m_bookmarks.get(provider).push_back({ .region = { region["address"], region["size"] }, .name = bookmark["name"], .comment = bookmark["comment"], @@ -366,7 +362,7 @@ namespace hex::plugin::builtin { bool ViewBookmarks::exportBookmarks(prv::Provider *provider, nlohmann::json &json) { json["bookmarks"] = nlohmann::json::array(); size_t index = 0; - for (const auto &bookmark : ProviderExtraData::get(provider).bookmarks) { + for (const auto &bookmark : this->m_bookmarks.get(provider)) { json["bookmarks"][index] = { { "name", bookmark.name }, { "comment", bookmark.comment }, @@ -395,10 +391,10 @@ namespace hex::plugin::builtin { ContentRegistry::Interface::addMenuItemSeparator({ "hex.builtin.menu.file", "hex.builtin.menu.file.import" }, 3000); /* Import bookmarks */ - ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.import", "hex.builtin.menu.file.import.bookmark" }, 3050, Shortcut::None, []{ - fs::openFileBrowser(fs::DialogMode::Open, { { "Bookmarks File", "hexbm"} }, [&](const std::fs::path &path) { + ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.import", "hex.builtin.menu.file.import.bookmark" }, 3050, Shortcut::None, [this]{ + fs::openFileBrowser(fs::DialogMode::Open, { { "Bookmarks File", "hexbm"} }, [&, this](const std::fs::path &path) { try { - importBookmarks(ImHexApi::Provider::get(), nlohmann::json::parse(wolv::io::File(path, wolv::io::File::Mode::Read).readString())); + this->importBookmarks(ImHexApi::Provider::get(), nlohmann::json::parse(wolv::io::File(path, wolv::io::File::Mode::Read).readString())); } catch (...) { } }); }, ImHexApi::Provider::isValid); @@ -407,15 +403,15 @@ namespace hex::plugin::builtin { /* Export bookmarks */ - ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.export", "hex.builtin.menu.file.export.bookmark" }, 6250, Shortcut::None, []{ - fs::openFileBrowser(fs::DialogMode::Save, { { "Bookmarks File", "hexbm"} }, [&](const std::fs::path &path) { + ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.export", "hex.builtin.menu.file.export.bookmark" }, 6250, Shortcut::None, [this]{ + fs::openFileBrowser(fs::DialogMode::Save, { { "Bookmarks File", "hexbm"} }, [&, this](const std::fs::path &path) { nlohmann::json json; - exportBookmarks(ImHexApi::Provider::get(), json); + this->exportBookmarks(ImHexApi::Provider::get(), json); wolv::io::File(path, wolv::io::File::Mode::Create).writeString(json.dump(4)); }); - }, []{ - return ImHexApi::Provider::isValid() && !ProviderExtraData::getCurrent().bookmarks.empty(); + }, [this]{ + return ImHexApi::Provider::isValid() && !this->m_bookmarks->empty(); }); } diff --git a/plugins/builtin/source/content/views/view_data_processor.cpp b/plugins/builtin/source/content/views/view_data_processor.cpp index 242e8beb3..bf47b72f6 100644 --- a/plugins/builtin/source/content/views/view_data_processor.cpp +++ b/plugins/builtin/source/content/views/view_data_processor.cpp @@ -11,45 +11,338 @@ #include #include -#include - #include +#include namespace hex::plugin::builtin { + class NodeCustomInput : public dp::Node { + public: + NodeCustomInput() : Node("hex.builtin.nodes.custom.input.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input") }) { } + ~NodeCustomInput() override = default; + + void drawNode() override { + ImGui::PushItemWidth(100_scaled); + if (ImGui::Combo("##type", &this->m_type, "Integer\0Float\0Buffer\0")) { + this->setAttributes({ + { dp::Attribute(dp::Attribute::IOType::Out, this->getType(), "hex.builtin.nodes.common.input") } + }); + } + + if (ImGui::InputText("##name", this->m_name)) { + this->setUnlocalizedTitle(this->m_name); + } + + ImGui::PopItemWidth(); + } + + void setValue(auto value) { this->m_value = std::move(value); } + + const std::string &getName() const { return this->m_name; } + dp::Attribute::Type getType() const { + switch (this->m_type) { + default: + case 0: return dp::Attribute::Type::Integer; + case 1: return dp::Attribute::Type::Float; + case 2: return dp::Attribute::Type::Buffer; + } + } + + void process() override { + std::visit(wolv::util::overloaded { + [this](i128 value) { this->setIntegerOnOutput(0, value); }, + [this](long double value) { this->setFloatOnOutput(0, value); }, + [this](const std::vector &value) { this->setBufferOnOutput(0, value); } + }, this->m_value); + } + + void store(nlohmann::json &j) const override { + j = nlohmann::json::object(); + + j["name"] = this->m_name; + j["type"] = this->m_type; + } + + void load(const nlohmann::json &j) override { + this->m_name = j["name"].get(); + this->m_type = j["type"]; + + this->setUnlocalizedTitle(this->m_name); + this->setAttributes({ + { dp::Attribute(dp::Attribute::IOType::Out, this->getType(), "hex.builtin.nodes.common.input") } + }); + } + + private: + std::string m_name = LangEntry(this->getUnlocalizedName()); + int m_type = 0; + + std::variant> m_value; + }; + + class NodeCustomOutput : public dp::Node { + public: + NodeCustomOutput() : Node("hex.builtin.nodes.custom.output.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } + ~NodeCustomOutput() override = default; + + void drawNode() override { + ImGui::PushItemWidth(100_scaled); + if (ImGui::Combo("##type", &this->m_type, "Integer\0Float\0Buffer\0")) { + this->setAttributes({ + { dp::Attribute(dp::Attribute::IOType::In, this->getType(), "hex.builtin.nodes.common.output") } + }); + } + + if (ImGui::InputText("##name", this->m_name)) { + this->setUnlocalizedTitle(this->m_name); + } + + ImGui::PopItemWidth(); + } + + const std::string &getName() const { return this->m_name; } + dp::Attribute::Type getType() const { + switch (this->m_type) { + case 0: return dp::Attribute::Type::Integer; + case 1: return dp::Attribute::Type::Float; + case 2: return dp::Attribute::Type::Buffer; + default: return dp::Attribute::Type::Integer; + } + } + + void process() override { + switch (this->getType()) { + case dp::Attribute::Type::Integer: this->m_value = this->getIntegerOnInput(0); break; + case dp::Attribute::Type::Float: this->m_value = this->getFloatOnInput(0); break; + case dp::Attribute::Type::Buffer: this->m_value = this->getBufferOnInput(0); break; + } + } + + const auto& getValue() const { return this->m_value; } + + void store(nlohmann::json &j) const override { + j = nlohmann::json::object(); + + j["name"] = this->m_name; + j["type"] = this->m_type; + } + + void load(const nlohmann::json &j) override { + this->m_name = j["name"].get(); + this->m_type = j["type"]; + + this->setUnlocalizedTitle(this->m_name); + this->setAttributes({ + { dp::Attribute(dp::Attribute::IOType::In, this->getType(), "hex.builtin.nodes.common.output") } + }); + } + + private: + std::string m_name = LangEntry(this->getUnlocalizedName()); + int m_type = 0; + + std::variant> m_value; + }; + + class NodeCustom : public dp::Node { + public: + explicit NodeCustom(ViewDataProcessor *dataProcessor) : Node("hex.builtin.nodes.custom.custom.header", {}), m_dataProcessor(dataProcessor) { } + ~NodeCustom() override = default; + + void drawNode() override { + if (this->m_requiresAttributeUpdate) { + this->m_requiresAttributeUpdate = false; + this->setAttributes(this->findAttributes()); + } + + ImGui::PushItemWidth(200_scaled); + + bool editing = false; + if (this->m_editable) { + ImGui::InputTextIcon("##name", ICON_VS_SYMBOL_KEY, this->m_name); + editing = ImGui::IsItemActive(); + + if (ImGui::Button("hex.builtin.nodes.custom.custom.edit"_lang, ImVec2(200_scaled, ImGui::GetTextLineHeightWithSpacing()))) { + this->m_dataProcessor->getWorkspaceStack().push_back(&this->m_workspace); + + this->m_requiresAttributeUpdate = true; + } + } else { + this->setUnlocalizedTitle(this->m_name); + + if (this->getAttributes().empty()) { + ImGui::TextUnformatted("hex.builtin.nodes.custom.custom.edit_hint"_lang); + } + } + + this->m_editable = ImGui::GetIO().KeyShift || editing; + + ImGui::PopItemWidth(); + } + + void process() override { + auto indexFromId = [this](u32 id) -> std::optional { + const auto &attributes = this->getAttributes(); + for (u32 i = 0; i < attributes.size(); i++) + if (u32(attributes[i].getId()) == id) + return i; + return std::nullopt; + }; + + auto prevContext = ImNodes::GetCurrentContext(); + ImNodes::SetCurrentContext(this->m_workspace.context.get()); + ON_SCOPE_EXIT { ImNodes::SetCurrentContext(prevContext); }; + + // Forward inputs to input nodes values + for (auto &attribute : this->getAttributes()) { + auto index = indexFromId(attribute.getId()); + if (!index.has_value()) + continue; + + if (auto input = this->findInput(attribute.getUnlocalizedName()); input != nullptr) { + switch (attribute.getType()) { + case dp::Attribute::Type::Integer: { + const auto &value = this->getIntegerOnInput(*index); + input->setValue(value); + break; + } + case dp::Attribute::Type::Float: { + const auto &value = this->getFloatOnInput(*index); + input->setValue(value); + break; + } + case dp::Attribute::Type::Buffer: { + const auto &value = this->getBufferOnInput(*index); + input->setValue(value); + break; + } + } + } + } + + // Process all nodes in our workspace + for (auto &endNode : this->m_workspace.endNodes) { + endNode->resetOutputData(); + + for (auto &node : this->m_workspace.nodes) + node->resetProcessedInputs(); + + endNode->process(); + } + + // Forward output node values to outputs + for (auto &attribute : this->getAttributes()) { + auto index = indexFromId(attribute.getId()); + if (!index.has_value()) + continue; + + if (auto output = this->findOutput(attribute.getUnlocalizedName()); output != nullptr) { + switch (attribute.getType()) { + case dp::Attribute::Type::Integer: { + auto value = std::get(output->getValue()); + this->setIntegerOnOutput(*index, value); + break; + } + case dp::Attribute::Type::Float: { + auto value = std::get(output->getValue()); + this->setFloatOnOutput(*index, value); + break; + } + case dp::Attribute::Type::Buffer: { + auto value = std::get>(output->getValue()); + this->setBufferOnOutput(*index, value); + break; + } + } + } + } + } + + void store(nlohmann::json &j) const override { + j = nlohmann::json::object(); + + j["nodes"] = this->m_dataProcessor->saveNodes(this->m_workspace); + } + + void load(const nlohmann::json &j) override { + this->m_dataProcessor->loadNodes(this->m_workspace, j["nodes"]); + + this->m_name = LangEntry(this->getUnlocalizedTitle()).get(); + this->m_requiresAttributeUpdate = true; + } + + private: + std::vector findAttributes() { + std::vector result; + + for (auto &node : this->m_workspace.nodes) { + if (auto *inputNode = dynamic_cast(node.get()); inputNode != nullptr) + result.emplace_back(dp::Attribute::IOType::In, inputNode->getType(), inputNode->getName()); + else if (auto *outputNode = dynamic_cast(node.get()); outputNode != nullptr) + result.emplace_back(dp::Attribute::IOType::Out, outputNode->getType(), outputNode->getName()); + } + + return result; + } + + NodeCustomInput* findInput(const std::string &name) { + for (auto &node : this->m_workspace.nodes) { + if (auto *inputNode = dynamic_cast(node.get()); inputNode != nullptr && inputNode->getName() == name) + return inputNode; + } + + return nullptr; + } + + NodeCustomOutput* findOutput(const std::string &name) { + for (auto &node : this->m_workspace.nodes) { + if (auto *outputNode = dynamic_cast(node.get()); outputNode != nullptr && outputNode->getName() == name) + return outputNode; + } + + return nullptr; + } + + private: + std::string m_name = "hex.builtin.nodes.custom.custom.header"_lang; + + bool m_editable = false; + + bool m_requiresAttributeUpdate = false; + ViewDataProcessor *m_dataProcessor; + ViewDataProcessor::Workspace m_workspace; + }; + ViewDataProcessor::ViewDataProcessor() : View("hex.builtin.view.data_processor.name") { + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.custom", "hex.builtin.nodes.custom.custom", this); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.custom", "hex.builtin.nodes.custom.input"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.custom", "hex.builtin.nodes.custom.output"); + ProjectFile::registerPerProviderHandler({ .basePath = "data_processor.json", .required = false, .load = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) { auto save = tar.readString(basePath); - auto &data = ProviderExtraData::get(provider).dataProcessor; - ViewDataProcessor::loadNodes(data.mainWorkspace, save); + ViewDataProcessor::loadNodes(this->m_mainWorkspace.get(provider), save); this->m_updateNodePositions = true; return true; }, - .store = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) { - auto &data = ProviderExtraData::get(provider).dataProcessor; - - tar.writeString(basePath, ViewDataProcessor::saveNodes(data.mainWorkspace).dump(4)); + .store = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) { + tar.writeString(basePath, ViewDataProcessor::saveNodes(this->m_mainWorkspace.get(provider)).dump(4)); return true; } }); - EventManager::subscribe(this, [](const auto *provider) { - auto &data = ProviderExtraData::get(provider).dataProcessor; - - data.mainWorkspace = { }; - data.workspaceStack.push_back(&data.mainWorkspace); + EventManager::subscribe(this, [this](auto *provider) { + this->m_mainWorkspace.get(provider) = { }; + this->m_workspaceStack.get(provider).push_back(&this->m_mainWorkspace.get(provider)); }); - EventManager::subscribe(this, [this](const auto &, const auto &) { - auto &data = ProviderExtraData::getCurrent().dataProcessor; - - for (auto *workspace : data.workspaceStack) { + EventManager::subscribe(this, [this](const auto *, const auto *) { + for (auto *workspace : *this->m_workspaceStack) { for (auto &node : workspace->nodes) { node->setCurrentOverlay(nullptr); } @@ -60,48 +353,39 @@ namespace hex::plugin::builtin { this->m_updateNodePositions = true; }); - EventManager::subscribe(this, [] { - auto &workspace = *ProviderExtraData::getCurrent().dataProcessor.workspaceStack.back(); - - ViewDataProcessor::processNodes(workspace); + EventManager::subscribe(this, [this] { + ViewDataProcessor::processNodes(*this->m_workspaceStack->back()); }); /* Import bookmarks */ ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.import", "hex.builtin.menu.file.import.data_processor" }, 4050, Shortcut::None, [this]{ - auto &data = ProviderExtraData::getCurrent().dataProcessor; - fs::openFileBrowser(fs::DialogMode::Open, { {"hex.builtin.view.data_processor.name"_lang, "hexnode" } }, [&](const std::fs::path &path) { wolv::io::File file(path, wolv::io::File::Mode::Read); if (file.isValid()) { - ViewDataProcessor::loadNodes(data.mainWorkspace, file.readString()); + ViewDataProcessor::loadNodes(*this->m_mainWorkspace, file.readString()); this->m_updateNodePositions = true; } }); }, ImHexApi::Provider::isValid); /* Export bookmarks */ - ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.export", "hex.builtin.menu.file.export.data_processor" }, 8050, Shortcut::None, []{ - auto &data = ProviderExtraData::getCurrent().dataProcessor; - + ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.export", "hex.builtin.menu.file.export.data_processor" }, 8050, Shortcut::None, [this]{ fs::openFileBrowser(fs::DialogMode::Save, { {"hex.builtin.view.data_processor.name"_lang, "hexnode" } }, - [&](const std::fs::path &path) { + [&, this](const std::fs::path &path) { wolv::io::File file(path, wolv::io::File::Mode::Create); if (file.isValid()) - file.writeString(ViewDataProcessor::saveNodes(data.mainWorkspace).dump(4)); + file.writeString(ViewDataProcessor::saveNodes(*this->m_mainWorkspace).dump(4)); }); - }, []{ - auto &data = ProviderExtraData::getCurrent().dataProcessor; - return !data.workspaceStack.empty() && !data.workspaceStack.back()->nodes.empty() && ImHexApi::Provider::isValid(); + }, [this]{ + return !this->m_workspaceStack->empty() && !this->m_workspaceStack->back()->nodes.empty() && ImHexApi::Provider::isValid(); }); ContentRegistry::FileHandler::add({ ".hexnode" }, [this](const auto &path) { wolv::io::File file(path, wolv::io::File::Mode::Read); if (!file.isValid()) return false; - auto &data = ProviderExtraData::getCurrent().dataProcessor; - - ViewDataProcessor::loadNodes(data.mainWorkspace, file.readString()); + ViewDataProcessor::loadNodes(*this->m_mainWorkspace, file.readString()); this->m_updateNodePositions = true; return true; @@ -117,7 +401,7 @@ namespace hex::plugin::builtin { } - void ViewDataProcessor::eraseLink(ProviderExtraData::Data::DataProcessor::Workspace &workspace, int id) { + void ViewDataProcessor::eraseLink(Workspace &workspace, int id) { auto link = std::find_if(workspace.links.begin(), workspace.links.end(), [&id](auto link) { return link.getId() == id; }); if (link == workspace.links.end()) @@ -134,7 +418,7 @@ namespace hex::plugin::builtin { ImHexApi::Provider::markDirty(); } - void ViewDataProcessor::eraseNodes(ProviderExtraData::Data::DataProcessor::Workspace &workspace, const std::vector &ids) { + void ViewDataProcessor::eraseNodes(Workspace &workspace, const std::vector &ids) { for (int id : ids) { auto node = std::find_if(workspace.nodes.begin(), workspace.nodes.end(), [&id](const auto &node) { @@ -162,7 +446,7 @@ namespace hex::plugin::builtin { ImHexApi::Provider::markDirty(); } - void ViewDataProcessor::processNodes(ProviderExtraData::Data::DataProcessor::Workspace &workspace) { + void ViewDataProcessor::processNodes(Workspace &workspace) { if (workspace.dataOverlays.size() != workspace.endNodes.size()) { for (auto overlay : workspace.dataOverlays) ImHexApi::Provider::get()->deleteOverlay(overlay); @@ -220,8 +504,7 @@ namespace hex::plugin::builtin { } void ViewDataProcessor::drawContent() { - auto &data = ProviderExtraData::getCurrent().dataProcessor; - auto &workspace = *data.workspaceStack.back(); + auto &workspace = *this->m_workspaceStack->back(); bool popWorkspace = false; if (ImGui::Begin(View::toWindowName("hex.builtin.view.data_processor.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) { @@ -360,6 +643,8 @@ namespace hex::plugin::builtin { ImNodes::BeginNodeEditor(); for (auto &node : workspace.nodes) { + ImNodes::SnapNodeToGrid(node->getId()); + const bool hasError = workspace.currNodeError.has_value() && workspace.currNodeError->node == node.get(); if (hasError) @@ -471,7 +756,7 @@ namespace hex::plugin::builtin { if (workspace.nodes.empty()) ImGui::TextFormattedCentered("{}", "hex.builtin.view.data_processor.help_text"_lang); - if (data.workspaceStack.size() > 1) { + if (this->m_workspaceStack->size() > 1) { ImGui::SetCursorPos(ImVec2(ImGui::GetContentRegionAvail().x - ImGui::GetTextLineHeightWithSpacing() * 1.2F, ImGui::GetTextLineHeightWithSpacing() * 0.2F)); if (ImGui::IconButton(ICON_VS_CLOSE, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGray))) { popWorkspace = true; @@ -559,7 +844,7 @@ namespace hex::plugin::builtin { ImGui::End(); if (popWorkspace) { - data.workspaceStack.pop_back(); + this->m_workspaceStack->pop_back(); this->m_updateNodePositions = true; } } diff --git a/plugins/builtin/source/content/views/view_diff.cpp b/plugins/builtin/source/content/views/view_diff.cpp index 024d0263e..b55b81019 100644 --- a/plugins/builtin/source/content/views/view_diff.cpp +++ b/plugins/builtin/source/content/views/view_diff.cpp @@ -184,7 +184,7 @@ namespace hex::plugin::builtin { const auto height = ImGui::GetContentRegionAvail().y; - if (ImGui::BeginTable("##binary_diff", 2, ImGuiTableFlags_None, ImVec2(0, height - 200_scaled))) { + if (ImGui::BeginTable("##binary_diff", 2, ImGuiTableFlags_None, ImVec2(0, height - 250_scaled))) { ImGui::TableSetupColumn("hex.builtin.view.diff.provider_a"_lang); ImGui::TableSetupColumn("hex.builtin.view.diff.provider_b"_lang); ImGui::TableHeadersRow(); diff --git a/plugins/builtin/source/content/views/view_hashes.cpp b/plugins/builtin/source/content/views/view_hashes.cpp index 667b9bf01..683333e58 100644 --- a/plugins/builtin/source/content/views/view_hashes.cpp +++ b/plugins/builtin/source/content/views/view_hashes.cpp @@ -1,5 +1,4 @@ #include "content/views/view_hashes.hpp" -#include "content/helpers/provider_extra_data.hpp" #include #include @@ -9,18 +8,18 @@ namespace hex::plugin::builtin { ViewHashes::ViewHashes() : View("hex.builtin.view.hashes.name") { - EventManager::subscribe(this, [](const auto &providerRegion) { - for (auto &function : ProviderExtraData::get(providerRegion.getProvider()).hashes.hashFunctions) + EventManager::subscribe(this, [this](const auto &providerRegion) { + for (auto &function : this->m_hashFunctions.get(providerRegion.getProvider())) function.reset(); }); - ImHexApi::HexEditor::addTooltipProvider([](u64 address, const u8 *data, size_t 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) { - auto &hashFunctions = ProviderExtraData::get(selection->getProvider()).hashes.hashFunctions; + auto &hashFunctions = this->m_hashFunctions.get(selection->getProvider()); if (!hashFunctions.empty() && selection.has_value() && selection->overlaps(Region { address, size })) { ImGui::BeginTooltip(); @@ -62,20 +61,20 @@ namespace hex::plugin::builtin { ProjectFile::registerPerProviderHandler({ .basePath = "hashes.json", .required = false, - .load = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { + .load = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { auto fileContent = tar.readString(basePath); if (fileContent.empty()) return true; auto data = nlohmann::json::parse(fileContent.begin(), fileContent.end()); - ProviderExtraData::get(provider).hashes.hashFunctions.clear(); + this->m_hashFunctions->clear(); - return ViewHashes::importHashes(provider, data); + return this->importHashes(provider, data); }, - .store = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { + .store = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { nlohmann::json data; - bool result = ViewHashes::exportHashes(provider, data); + bool result = this->exportHashes(provider, data); tar.writeString(basePath, data.dump(4)); return result; @@ -96,8 +95,6 @@ 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) { @@ -134,7 +131,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) - hashFunctions.push_back(this->m_selectedHash->create(this->m_newHashName)); + this->m_hashFunctions->push_back(this->m_selectedHash->create(this->m_newHashName)); } ImGui::EndDisabled(); @@ -149,8 +146,8 @@ namespace hex::plugin::builtin { auto selection = ImHexApi::HexEditor::getSelection(); std::optional indexToRemove; - for (u32 i = 0; i < hashFunctions.size(); i++) { - auto &function = hashFunctions[i]; + for (u32 i = 0; i < this->m_hashFunctions->size(); i++) { + auto &function = (*this->m_hashFunctions)[i]; ImGui::PushID(i); @@ -195,7 +192,7 @@ namespace hex::plugin::builtin { } if (indexToRemove.has_value()) { - hashFunctions.erase(hashFunctions.begin() + indexToRemove.value()); + this->m_hashFunctions->erase(this->m_hashFunctions->begin() + indexToRemove.value()); } ImGui::EndTable(); @@ -213,7 +210,6 @@ namespace hex::plugin::builtin { 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; @@ -224,7 +220,7 @@ namespace hex::plugin::builtin { auto newFunction = newHash->create(hash["name"]); newFunction.getType()->load(hash["settings"]); - hashFunctions.push_back(std::move(newFunction)); + this->m_hashFunctions.get(provider).push_back(std::move(newFunction)); break; } } @@ -236,7 +232,7 @@ namespace hex::plugin::builtin { 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) { + for (const auto &hashFunction : this->m_hashFunctions.get(provider)) { json["hashes"][index] = { { "name", hashFunction.getName() }, { "type", hashFunction.getType()->getUnlocalizedName() }, diff --git a/plugins/builtin/source/content/views/view_hex_editor.cpp b/plugins/builtin/source/content/views/view_hex_editor.cpp index d5efd4e26..139f32951 100644 --- a/plugins/builtin/source/content/views/view_hex_editor.cpp +++ b/plugins/builtin/source/content/views/view_hex_editor.cpp @@ -12,7 +12,6 @@ #include #include -#include #include @@ -676,10 +675,8 @@ namespace hex::plugin::builtin { // Remove selection ShortcutManager::addShortcut(this, Keys::Escape, [this] { auto provider = ImHexApi::Provider::get(); - auto &data = ProviderExtraData::get(provider).editor; - - data.selectionStart.reset(); - data.selectionEnd.reset(); + this->m_selectionStart->reset(); + this->m_selectionEnd->reset(); EventManager::post(ImHexApi::HexEditor::ProviderRegion{ this->getSelection(), provider }); }); @@ -849,10 +846,8 @@ namespace hex::plugin::builtin { auto provider = ImHexApi::Provider::get(); if (region == Region::Invalid()) { - auto &providerData = ProviderExtraData::get(provider).editor; - - providerData.selectionStart.reset(); - providerData.selectionEnd.reset(); + this->m_selectionStart->reset(); + this->m_selectionEnd->reset(); EventManager::post(ImHexApi::HexEditor::ProviderRegion({ Region::Invalid(), nullptr })); return; @@ -871,14 +866,12 @@ namespace hex::plugin::builtin { EventManager::subscribe(this, [this](auto *oldProvider, auto *newProvider) { if (oldProvider != nullptr) { - auto &oldData = ProviderExtraData::get(oldProvider).editor; - auto selection = this->m_hexEditor.getSelection(); if (selection != Region::Invalid()) { - oldData.selectionStart = selection.getStartAddress(); - oldData.selectionEnd = selection.getEndAddress(); - oldData.scrollPosition = this->m_hexEditor.getScrollPosition(); + this->m_selectionStart.get(oldProvider) = selection.getStartAddress(); + this->m_selectionEnd.get(oldProvider) = selection.getEndAddress(); + this->m_scrollPosition.get(oldProvider) = this->m_hexEditor.getScrollPosition(); } } @@ -886,10 +879,8 @@ namespace hex::plugin::builtin { this->m_hexEditor.setScrollPosition(0); if (newProvider != nullptr) { - auto &newData = ProviderExtraData::get(newProvider).editor; - - this->m_hexEditor.setSelectionUnchecked(newData.selectionStart, newData.selectionEnd); - this->m_hexEditor.setScrollPosition(newData.scrollPosition); + this->m_hexEditor.setSelectionUnchecked(this->m_selectionStart.get(newProvider), this->m_selectionEnd.get(newProvider)); + this->m_hexEditor.setScrollPosition(this->m_scrollPosition.get(newProvider)); } this->m_hexEditor.forceUpdateScrollPosition(); diff --git a/plugins/builtin/source/content/views/view_pattern_data.cpp b/plugins/builtin/source/content/views/view_pattern_data.cpp index 0fdcaf4ab..8bc05c5c4 100644 --- a/plugins/builtin/source/content/views/view_pattern_data.cpp +++ b/plugins/builtin/source/content/views/view_pattern_data.cpp @@ -5,8 +5,6 @@ #include -#include - namespace hex::plugin::builtin { ViewPatternData::ViewPatternData() : View("hex.builtin.view.pattern_data.name") { @@ -32,18 +30,19 @@ namespace hex::plugin::builtin { if (ImGui::Begin(View::toWindowName("hex.builtin.view.pattern_data.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) { if (ImHexApi::Provider::isValid()) { auto provider = ImHexApi::Provider::get(); - auto &patternLanguage = ProviderExtraData::get(provider).patternLanguage; + + auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); const auto &patterns = [&] -> const auto& { - if (provider->isReadable() && patternLanguage.runtime != nullptr && patternLanguage.executionDone) - return ProviderExtraData::get(provider).patternLanguage.runtime->getAllPatterns(); + if (provider->isReadable()) + return runtime.getAllPatterns(); else { static const std::vector> empty; return empty; } }(); - if (!patternLanguage.executionDone) + if (runtime.isRunning()) this->m_patternDrawer.reset(); this->m_patternDrawer.draw(patterns); diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index f83df8c33..a46b08151 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -14,7 +14,6 @@ #include #include -#include #include #include @@ -110,7 +109,6 @@ namespace hex::plugin::builtin { auto provider = ImHexApi::Provider::get(); if (ImHexApi::Provider::isValid() && provider->isAvailable()) { - auto &extraData = ProviderExtraData::get(provider).patternLanguage; auto textEditorSize = ImGui::GetContentRegionAvail(); textEditorSize.y *= 3.75 / 5.0; @@ -122,19 +120,19 @@ namespace hex::plugin::builtin { if (ImGui::BeginTabBar("##settings")) { if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.console"_lang)) { - this->drawConsole(settingsSize, extraData.console); + this->drawConsole(settingsSize, *this->m_console); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.env_vars"_lang)) { - this->drawEnvVars(settingsSize, extraData.envVarEntries); + this->drawEnvVars(settingsSize, *this->m_envVarEntries); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.settings"_lang)) { - this->drawVariableSettings(settingsSize, extraData.patternVariables); + this->drawVariableSettings(settingsSize, *this->m_patternVariables); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.sections"_lang)) { - this->drawSectionSelector(settingsSize, extraData.sections); + this->drawSectionSelector(settingsSize, *this->m_sections); ImGui::EndTabItem(); } @@ -143,10 +141,10 @@ namespace hex::plugin::builtin { ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1); - auto &runtime = ProviderExtraData::getCurrent().patternLanguage.runtime; - if (runtime != nullptr && runtime->isRunning()) { + auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); + if (runtime.isRunning()) { if (ImGui::IconButton(ICON_VS_DEBUG_STOP, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) - runtime->abort(); + runtime.abort(); } else { if (ImGui::IconButton(ICON_VS_DEBUG_START, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen)) || this->m_triggerEvaluation) { this->m_triggerEvaluation = false; @@ -171,8 +169,8 @@ namespace hex::plugin::builtin { ImGui::SameLine(); ImGui::TextFormatted("{} / {}", - runtime->getCreatedPatternCount(), - runtime->getMaximumPatternCount()); + runtime.getCreatedPatternCount(), + runtime.getMaximumPatternCount()); } if (this->m_textEditor.IsTextChanged()) { @@ -258,7 +256,7 @@ namespace hex::plugin::builtin { ImGui::PopStyleColor(1); } - void ViewPatternEditor::drawEnvVars(ImVec2 size, std::list &envVars) { + void ViewPatternEditor::drawEnvVars(ImVec2 size, std::list &envVars) { static u32 envVarCounter = 1; if (ImGui::BeginChild("##env_vars", size, true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) { @@ -283,7 +281,7 @@ namespace hex::plugin::builtin { if (ImGui::BeginCombo("", Types[static_cast(type)])) { for (size_t i = 0; i < Types.size(); i++) { if (ImGui::Selectable(Types[i])) - type = static_cast(i); + type = static_cast(i); } ImGui::EndCombo(); @@ -300,7 +298,7 @@ namespace hex::plugin::builtin { ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x); switch (type) { - using enum PlData::EnvVarType; + using enum EnvVarType; case Integer: { i64 displayValue = hex::get_or(value, 0); @@ -335,7 +333,7 @@ namespace hex::plugin::builtin { ImGui::TableNextColumn(); if (ImGui::IconButton(ICON_VS_ADD, ImGui::GetStyleColorVec4(ImGuiCol_Text))) { - envVars.insert(std::next(iter), { envVarCounter++, "", i128(0), PlData::EnvVarType::Integer }); + envVars.insert(std::next(iter), { envVarCounter++, "", i128(0), EnvVarType::Integer }); } ImGui::SameLine(); @@ -359,7 +357,7 @@ namespace hex::plugin::builtin { ImGui::EndChild(); } - void ViewPatternEditor::drawVariableSettings(ImVec2 size, std::map &patternVariables) { + void ViewPatternEditor::drawVariableSettings(ImVec2 size, std::map &patternVariables) { if (ImGui::BeginChild("##settings", size, true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) { if (patternVariables.empty()) { ImGui::TextFormattedCentered("hex.builtin.view.pattern_editor.no_in_out_vars"_lang); @@ -413,6 +411,8 @@ namespace hex::plugin::builtin { } void ViewPatternEditor::drawSectionSelector(ImVec2 size, std::map §ions) { + auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); + if (ImGui::BeginTable("##sections_table", 3, ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, size)) { ImGui::TableSetupScrollFreeze(0, 1); ImGui::TableSetupColumn("hex.builtin.common.name"_lang, ImGuiTableColumnFlags_WidthStretch, 0.5F); @@ -439,14 +439,14 @@ namespace hex::plugin::builtin { auto hexEditor = auto(this->m_sectionHexEditor); - hexEditor.setBackgroundHighlightCallback([this, id](u64 address, const u8 *, size_t) -> std::optional { + hexEditor.setBackgroundHighlightCallback([this, id, &runtime](u64 address, const u8 *, size_t) -> std::optional { if (this->m_runningEvaluators != 0) return std::nullopt; if (!ImHexApi::Provider::isValid()) return std::nullopt; std::optional color; - for (const auto &pattern : ProviderExtraData::getCurrent().patternLanguage.runtime->getPatternsAtAddress(address, id)) { + for (const auto &pattern : runtime.getPatternsAtAddress(address, id)) { if (pattern->getVisibility() != pl::ptrn::Visibility::Visible) continue; @@ -462,25 +462,23 @@ namespace hex::plugin::builtin { auto patternProvider = ImHexApi::Provider::get(); - this->m_sectionWindowDrawer[patternProvider] = [id, patternProvider, dataProvider = std::move(dataProvider), hexEditor, patternDrawer = ui::PatternDrawer()] mutable { + this->m_sectionWindowDrawer[patternProvider] = [this, id, patternProvider, dataProvider = std::move(dataProvider), hexEditor, patternDrawer = ui::PatternDrawer(), &runtime] mutable { hexEditor.setProvider(dataProvider.get()); hexEditor.draw(480_scaled); patternDrawer.setSelectionCallback([&](const auto ®ion) { hexEditor.setSelection(region); }); - auto &patternLanguage = ProviderExtraData::get(patternProvider).patternLanguage; - - const auto &patterns = [&] -> const auto& { - if (patternProvider->isReadable() && patternLanguage.runtime != nullptr && patternLanguage.executionDone) - return ProviderExtraData::get(patternProvider).patternLanguage.runtime->getAllPatterns(id); + const auto &patterns = [&, this] -> const auto& { + if (patternProvider->isReadable() && *this->m_executionDone) + return runtime.getAllPatterns(id); else { static const std::vector> empty; return empty; } }(); - if (patternLanguage.executionDone) + if (*this->m_executionDone) patternDrawer.draw(patterns, 150_scaled); }; } @@ -509,28 +507,27 @@ namespace hex::plugin::builtin { this->m_sectionWindowDrawer.erase(provider); } - auto &extraData = ProviderExtraData::get(provider).patternLanguage; if (!this->m_lastEvaluationProcessed) { - extraData.console = extraData.lastEvaluationLog; + *this->m_console = this->m_lastEvaluationLog; if (!this->m_lastEvaluationResult) { - if (extraData.lastEvaluationError) { + if (this->m_lastEvaluationError->has_value()) { TextEditor::ErrorMarkers errorMarkers = { - { extraData.lastEvaluationError->line, extraData.lastEvaluationError->message } + { (*this->m_lastEvaluationError)->line, (*this->m_lastEvaluationError)->message } }; this->m_textEditor.SetErrorMarkers(errorMarkers); } } else { - for (auto &[name, variable] : extraData.patternVariables) { - if (variable.outVariable && extraData.lastEvaluationOutVars.contains(name)) - variable.value = extraData.lastEvaluationOutVars.at(name); + for (auto &[name, variable] : *this->m_patternVariables) { + if (variable.outVariable && this->m_lastEvaluationOutVars->contains(name)) + variable.value = this->m_lastEvaluationOutVars->at(name); } EventManager::post(); } this->m_lastEvaluationProcessed = true; - extraData.executionDone = true; + *this->m_executionDone = true; } } @@ -613,9 +610,10 @@ namespace hex::plugin::builtin { ContentRegistry::PatternLanguage::configureRuntime(*this->m_parserRuntime, nullptr); auto ast = this->m_parserRuntime->parseString(code); - auto &patternLanguage = ProviderExtraData::get(provider).patternLanguage; - patternLanguage.patternVariables.clear(); + auto &patternVariables = this->m_patternVariables.get(provider); + + patternVariables.clear(); if (ast) { for (auto &node : *ast) { @@ -624,9 +622,10 @@ namespace hex::plugin::builtin { if (type == nullptr) continue; auto builtinType = dynamic_cast(type->getType().get()); - if (builtinType == nullptr) continue; + if (builtinType == nullptr) + continue; - PlData::PatternVariable variable = { + PatternVariable variable = { .inVariable = variableDecl->isInVariable(), .outVariable = variableDecl->isOutVariable(), .type = builtinType->getType(), @@ -634,8 +633,8 @@ namespace hex::plugin::builtin { }; if (variable.inVariable || variable.outVariable) { - if (!patternLanguage.patternVariables.contains(variableDecl->getName())) - patternLanguage.patternVariables[variableDecl->getName()] = variable; + if (!patternVariables.contains(variableDecl->getName())) + patternVariables[variableDecl->getName()] = variable; } } } @@ -645,38 +644,36 @@ namespace hex::plugin::builtin { } void ViewPatternEditor::evaluatePattern(const std::string &code, prv::Provider *provider) { - auto &patternLanguage = ProviderExtraData::get(provider).patternLanguage; - this->m_runningEvaluators++; - patternLanguage.executionDone = false; + *this->m_executionDone = false; this->m_textEditor.SetErrorMarkers({}); - patternLanguage.console.clear(); + this->m_console->clear(); this->m_sectionWindowDrawer.clear(); - ContentRegistry::PatternLanguage::configureRuntime(*patternLanguage.runtime, provider); - EventManager::post(); EventManager::post(code); - TaskManager::createTask("hex.builtin.view.pattern_editor.evaluating", TaskManager::NoProgress, [this, &patternLanguage, code](auto &task) { - std::scoped_lock lock(patternLanguage.runtimeMutex); - auto &runtime = patternLanguage.runtime; + TaskManager::createTask("hex.builtin.view.pattern_editor.evaluating", TaskManager::NoProgress, [this, code, provider](auto &task) { + auto lock = ContentRegistry::PatternLanguage::getRuntimeLock(); - task.setInterruptCallback([&runtime] { runtime->abort(); }); + auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); + ContentRegistry::PatternLanguage::configureRuntime(runtime, provider); + + task.setInterruptCallback([&runtime] { runtime.abort(); }); std::map envVars; - for (const auto &[id, name, value, type] : patternLanguage.envVarEntries) + for (const auto &[id, name, value, type] : *this->m_envVarEntries) envVars.insert({ name, value }); std::map inVariables; - for (auto &[name, variable] : patternLanguage.patternVariables) { + for (auto &[name, variable] : *this->m_patternVariables) { if (variable.inVariable) inVariables[name] = variable.value; } - runtime->setDangerousFunctionCallHandler([this]{ + runtime.setDangerousFunctionCallHandler([this]{ this->m_dangerousFunctionCalled = true; while (this->m_dangerousFunctionsAllowed == DangerousFunctionPerms::Ask) { @@ -687,24 +684,24 @@ namespace hex::plugin::builtin { }); ON_SCOPE_EXIT { - patternLanguage.lastEvaluationLog = runtime->getConsoleLog(); - patternLanguage.lastEvaluationOutVars = runtime->getOutVariables(); - patternLanguage.sections = runtime->getSections(); + *this->m_lastEvaluationLog = runtime.getConsoleLog(); + *this->m_lastEvaluationOutVars = runtime.getOutVariables(); + *this->m_sections = runtime.getSections(); this->m_runningEvaluators--; this->m_lastEvaluationProcessed = false; - patternLanguage.lastEvaluationLog.emplace_back( + this->m_lastEvaluationLog->emplace_back( pl::core::LogConsole::Level::Info, - hex::format("Evaluation took {}", runtime->getLastRunningTime()) + hex::format("Evaluation took {}", runtime.getLastRunningTime()) ); }; - this->m_lastEvaluationResult = runtime->executeString(code, envVars, inVariables); + this->m_lastEvaluationResult = runtime.executeString(code, envVars, inVariables); if (!this->m_lastEvaluationResult) { - patternLanguage.lastEvaluationError = runtime->getError(); + *this->m_lastEvaluationError = runtime.getError(); } }); } @@ -729,27 +726,26 @@ namespace hex::plugin::builtin { }); EventManager::subscribe(this, [this](prv::Provider *provider) { - auto &patternLanguageData = ProviderExtraData::get(provider).patternLanguage; - patternLanguageData.runtime = std::make_unique(); - ContentRegistry::PatternLanguage::configureRuntime(*patternLanguageData.runtime, provider); + auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); + ContentRegistry::PatternLanguage::configureRuntime(runtime, provider); - TaskManager::createBackgroundTask("Analyzing file content", [this, provider, &data = patternLanguageData](auto &) { + TaskManager::createBackgroundTask("Analyzing file content", [this, provider](auto &) { if (!this->m_autoLoadPatterns) return; // Copy over current pattern source code to the new provider if (!this->m_syncPatternSourceCode) { - data.sourceCode = this->m_textEditor.GetText(); + *this->m_sourceCode = this->m_textEditor.GetText(); } - std::scoped_lock lock(data.runtimeMutex); - auto runtime = std::make_unique(); - ContentRegistry::PatternLanguage::configureRuntime(*runtime, provider); + auto lock = ContentRegistry::PatternLanguage::getRuntimeLock(); + auto& runtime = ContentRegistry::PatternLanguage::getRuntime(); + ContentRegistry::PatternLanguage::configureRuntime(runtime, provider); auto mimeType = magic::getMIMEType(provider); bool foundCorrectType = false; - runtime->addPragma("MIME", [&mimeType, &foundCorrectType](pl::PatternLanguage &runtime, const std::string &value) { + runtime.addPragma("MIME", [&mimeType, &foundCorrectType](pl::PatternLanguage &runtime, const std::string &value) { hex::unused(runtime); if (!magic::isValidMIMEType(value)) @@ -775,12 +771,12 @@ namespace hex::plugin::builtin { if (!file.isValid()) continue; - runtime->getInternals().preprocessor->preprocess(*runtime, file.readString()); + runtime.getInternals().preprocessor->preprocess(runtime, file.readString()); if (foundCorrectType) this->m_possiblePatternFiles.push_back(entry.path()); - runtime->reset(); + runtime.reset(); } } @@ -789,15 +785,16 @@ namespace hex::plugin::builtin { } }); - patternLanguageData.envVarEntries.push_back({ 0, "", 0, PlData::EnvVarType::Integer }); + this->m_envVarEntries->push_back({ 0, "", 0, EnvVarType::Integer }); }); EventManager::subscribe(this, [this](prv::Provider *oldProvider, prv::Provider *newProvider) { if (!this->m_syncPatternSourceCode) { - if (oldProvider != nullptr) ProviderExtraData::get(oldProvider).patternLanguage.sourceCode = this->m_textEditor.GetText(); + if (oldProvider != nullptr) + this->m_sourceCode.get(oldProvider) = this->m_textEditor.GetText(); if (newProvider != nullptr) - this->m_textEditor.SetText(wolv::util::trim(ProviderExtraData::get(newProvider).patternLanguage.sourceCode)); + this->m_textEditor.SetText(wolv::util::trim(this->m_sourceCode.get(newProvider))); else this->m_textEditor.SetText(""); } @@ -943,8 +940,10 @@ namespace hex::plugin::builtin { if (this->m_runningEvaluators != 0) return std::nullopt; + auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); + std::optional color; - for (const auto &pattern : ProviderExtraData::getCurrent().patternLanguage.runtime->getPatternsAtAddress(address)) { + for (const auto &pattern : runtime.getPatternsAtAddress(address)) { if (pattern->getVisibility() != pl::ptrn::Visibility::Visible) continue; @@ -960,7 +959,9 @@ namespace hex::plugin::builtin { ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) { hex::unused(data, size); - auto patterns = ProviderExtraData::getCurrent().patternLanguage.runtime->getPatternsAtAddress(address); + auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); + + auto patterns = runtime.getPatternsAtAddress(address); if (!patterns.empty() && !std::all_of(patterns.begin(), patterns.end(), [](const auto &pattern) { return pattern->getVisibility() == pl::ptrn::Visibility::Hidden; })) { ImGui::BeginTooltip(); @@ -994,7 +995,7 @@ namespace hex::plugin::builtin { std::string sourceCode = tar.readString(basePath); if (!this->m_syncPatternSourceCode) - ProviderExtraData::get(provider).patternLanguage.sourceCode = sourceCode; + this->m_sourceCode.get(provider) = sourceCode; if (provider == ImHexApi::Provider::get()) this->m_textEditor.SetText(sourceCode); @@ -1005,12 +1006,12 @@ namespace hex::plugin::builtin { std::string sourceCode; if (provider == ImHexApi::Provider::get()) - ProviderExtraData::get(provider).patternLanguage.sourceCode = this->m_textEditor.GetText(); + this->m_sourceCode.get(provider) = this->m_textEditor.GetText(); if (this->m_syncPatternSourceCode) sourceCode = this->m_textEditor.GetText(); else - sourceCode = ProviderExtraData::get(provider).patternLanguage.sourceCode; + sourceCode = this->m_sourceCode.get(provider); tar.writeString(basePath, wolv::util::trim(sourceCode)); return true; diff --git a/plugins/builtin/source/content/views/view_yara.cpp b/plugins/builtin/source/content/views/view_yara.cpp index 126dee5ea..15423da44 100644 --- a/plugins/builtin/source/content/views/view_yara.cpp +++ b/plugins/builtin/source/content/views/view_yara.cpp @@ -6,8 +6,6 @@ #include #include -#include "content/helpers/provider_extra_data.hpp" - #include #include @@ -46,7 +44,7 @@ namespace hex::plugin::builtin { ProjectFile::registerPerProviderHandler({ .basePath = "yara.json", .required = false, - .load = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { + .load = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { auto fileContent = tar.readString(basePath); if (fileContent.empty()) return true; @@ -60,8 +58,7 @@ namespace hex::plugin::builtin { if (!rules.is_array()) return false; - auto &extraData = ProviderExtraData::get(provider).yara; - extraData.matches.clear(); + this->m_matches.get(provider).clear(); for (auto &rule : rules) { if (!rule.contains("name") || !rule.contains("path")) @@ -73,18 +70,17 @@ namespace hex::plugin::builtin { if (!name.is_string() || !path.is_string()) return false; - extraData.rules.emplace_back(std::fs::path(name.get()), std::fs::path(path.get())); + this->m_rules.get(provider).emplace_back(std::fs::path(name.get()), std::fs::path(path.get())); } return true; }, - .store = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { + .store = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool { nlohmann::json data; data["rules"] = nlohmann::json::array(); - auto &extraData = ProviderExtraData::get(provider).yara; - for (auto &[name, path] : extraData.rules) { + for (auto &[name, path] : this->m_rules.get(provider)) { data["rules"].push_back({ { "name", wolv::util::toUTF8String(name) }, { "path", wolv::util::toUTF8String(path) } @@ -108,15 +104,10 @@ namespace hex::plugin::builtin { ImGui::TextUnformatted("hex.builtin.view.yara.header.rules"_lang); ImGui::Separator(); - auto &extraData = ProviderExtraData::getCurrent().yara; - auto &rules = extraData.rules; - auto &matches = extraData.matches; - auto &sortedMatches = extraData.sortedMatches; - if (ImGui::BeginListBox("##rules", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 5))) { - for (u32 i = 0; i < rules.size(); i++) { + for (u32 i = 0; i < this->m_rules->size(); i++) { const bool selected = (this->m_selectedRule == i); - if (ImGui::Selectable(wolv::util::toUTF8String(rules[i].first).c_str(), selected)) { + if (ImGui::Selectable(wolv::util::toUTF8String((*this->m_rules)[i].first).c_str(), selected)) { this->m_selectedRule = i; } } @@ -137,15 +128,15 @@ namespace hex::plugin::builtin { PopupFileChooser::open(paths, std::vector{ { "Yara File", "yara" }, { "Yara File", "yar" } }, true, [&](const auto &path) { - rules.push_back({ path.filename(), path }); + this->m_rules->push_back({ path.filename(), path }); }); } ImGui::SameLine(); if (ImGui::IconButton(ICON_VS_REMOVE, ImGui::GetStyleColorVec4(ImGuiCol_Text))) { - if (this->m_selectedRule < rules.size()) { - rules.erase(rules.begin() + this->m_selectedRule); - this->m_selectedRule = std::min(this->m_selectedRule, (u32)rules.size() - 1); + if (this->m_selectedRule < this->m_rules->size()) { + this->m_rules->erase(this->m_rules->begin() + this->m_selectedRule); + this->m_selectedRule = std::min(this->m_selectedRule, (u32)this->m_rules->size() - 1); } } @@ -176,13 +167,13 @@ namespace hex::plugin::builtin { ImGui::TableHeadersRow(); auto sortSpecs = ImGui::TableGetSortSpecs(); - if (!matches.empty() && (sortSpecs->SpecsDirty || sortedMatches.empty())) { - sortedMatches.clear(); - std::transform(matches.begin(), matches.end(), std::back_inserter(sortedMatches), [](auto &match) { + if (!this->m_matches->empty() && (sortSpecs->SpecsDirty || this->m_sortedMatches->empty())) { + this->m_sortedMatches->clear(); + std::transform(this->m_matches->begin(), this->m_matches->end(), std::back_inserter(*this->m_sortedMatches), [](auto &match) { return &match; }); - std::sort(sortedMatches.begin(), sortedMatches.end(), [&sortSpecs](ProviderExtraData::Data::Yara::YaraMatch *left, ProviderExtraData::Data::Yara::YaraMatch *right) -> bool { + std::sort(this->m_sortedMatches->begin(), this->m_sortedMatches->end(), [&sortSpecs](YaraMatch *left, YaraMatch *right) -> bool { if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("identifier")) return left->identifier < right->identifier; else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("variable")) @@ -196,18 +187,18 @@ namespace hex::plugin::builtin { }); if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Descending) - std::reverse(sortedMatches.begin(), sortedMatches.end()); + std::reverse(this->m_sortedMatches->begin(), this->m_sortedMatches->end()); sortSpecs->SpecsDirty = false; } if (!this->m_matcherTask.isRunning()) { ImGuiListClipper clipper; - clipper.Begin(sortedMatches.size()); + clipper.Begin(this->m_sortedMatches->size()); while (clipper.Step()) { for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - auto &[identifier, variableName, address, size, wholeDataMatch, highlightId, tooltipId] = *sortedMatches[i]; + auto &[identifier, variableName, address, size, wholeDataMatch, highlightId, tooltipId] = *(*this->m_sortedMatches)[i]; ImGui::TableNextRow(); ImGui::TableNextColumn(); ImGui::PushID(i); @@ -260,14 +251,12 @@ namespace hex::plugin::builtin { } void ViewYara::clearResult() { - auto &matches = ProviderExtraData::getCurrent().yara.matches; - - for (const auto &match : matches) { + for (const auto &match : *this->m_matches) { ImHexApi::HexEditor::removeBackgroundHighlight(match.highlightId); ImHexApi::HexEditor::removeTooltip(match.tooltipId); } - matches.clear(); + this->m_matches->clear(); this->m_consoleMessages.clear(); } @@ -277,20 +266,16 @@ namespace hex::plugin::builtin { this->m_matcherTask = TaskManager::createTask("hex.builtin.view.yara.matching", 0, [this](auto &task) { if (!ImHexApi::Provider::isValid()) return; - auto &extraData = ProviderExtraData::getCurrent().yara; - auto &rules = extraData.rules; - auto &matches = extraData.matches; - struct ResultContext { Task *task = nullptr; - std::vector newMatches; + std::vector newMatches; std::vector consoleMessages; }; ResultContext resultContext; resultContext.task = &task; - for (const auto &[fileName, filePath] : rules) { + for (const auto &[fileName, filePath] : *this->m_rules) { YR_COMPILER *compiler = nullptr; yr_compiler_create(&compiler); ON_SCOPE_EXIT { @@ -321,7 +306,7 @@ namespace hex::plugin::builtin { currFilePath.data() ); - wolv::io::File file(rules[this->m_selectedRule].second, wolv::io::File::Mode::Read); + wolv::io::File file((*this->m_rules)[this->m_selectedRule].second, wolv::io::File::Mode::Read); if (!file.isValid()) return; if (yr_compiler_add_file(compiler, file.getHandle(), nullptr, nullptr) != 0) { @@ -437,22 +422,23 @@ namespace hex::plugin::builtin { 0); } - TaskManager::doLater([this, &matches, resultContext] { - for (const auto &match : matches) { + TaskManager::doLater([this, resultContext] { + for (const auto &match : *this->m_matches) { ImHexApi::HexEditor::removeBackgroundHighlight(match.highlightId); ImHexApi::HexEditor::removeTooltip(match.tooltipId); } this->m_consoleMessages = resultContext.consoleMessages; - std::move(resultContext.newMatches.begin(), resultContext.newMatches.end(), std::back_inserter(matches)); + std::move(resultContext.newMatches.begin(), resultContext.newMatches.end(), std::back_inserter(*this->m_matches)); - auto uniques = std::set(matches.begin(), matches.end(), [](const auto &l, const auto &r) { + auto uniques = std::set(this->m_matches->begin(), this->m_matches->end(), [](const auto &l, const auto &r) { return std::tie(l.address, l.size, l.wholeDataMatch, l.identifier, l.variable) < std::tie(r.address, r.size, r.wholeDataMatch, r.identifier, r.variable); }); - matches.clear(); - std::move(uniques.begin(), uniques.end(), std::back_inserter(matches)); + + this->m_matches->clear(); + std::move(uniques.begin(), uniques.end(), std::back_inserter(*this->m_matches)); constexpr static color_t YaraColor = 0x70B4771F; for (auto &match : uniques) {