impr: Replace horrible pattern extra data class with a more modular system
This commit is contained in:
parent
535aeb5e39
commit
99a736df27
2
lib/external/libwolv
vendored
2
lib/external/libwolv
vendored
@ -1 +1 @@
|
||||
Subproject commit e48ba7b3892eee151ed815e5b37ec33abbc66acd
|
||||
Subproject commit 76f8317e8e7c761879a34227bed22a4e647ea353
|
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
@ -1 +1 @@
|
||||
Subproject commit 1ae5969bd65e422523ed9d42bf715bd387075797
|
||||
Subproject commit ce644cf16223f4e335a49e8f3e3cc3d9d9afe4ae
|
@ -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<std::mutex> 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>(args)] mutable {
|
||||
auto node = std::make_unique<T>(std::forward<Args>(args)...);
|
||||
node->setUnlocalizedName(unlocalizedName);
|
||||
return node;
|
||||
|
@ -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);
|
||||
|
78
lib/libimhex/include/hex/providers/provider_data.hpp
Normal file
78
lib/libimhex/include/hex/providers/provider_data.hpp
Normal file
@ -0,0 +1,78 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <concepts>
|
||||
#include <map>
|
||||
#include <utility>
|
||||
|
||||
namespace hex {
|
||||
|
||||
template<typename T>
|
||||
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<EventProviderOpened>([this](prv::Provider *provider) {
|
||||
this->m_data.emplace(provider, T());
|
||||
});
|
||||
|
||||
(void)EventManager::subscribe<EventProviderClosed>([this](prv::Provider *provider){
|
||||
this->m_data.erase(provider);
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventImHexClosing>([this] {
|
||||
this->m_data.clear();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<prv::Provider *, T> m_data;
|
||||
};
|
||||
|
||||
}
|
@ -13,6 +13,7 @@
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/providers/provider_data.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <hex/api/localization.hpp>
|
||||
|
@ -259,6 +259,18 @@ namespace hex {
|
||||
return functionName;
|
||||
}
|
||||
|
||||
pl::PatternLanguage& getRuntime() {
|
||||
static PerProvider<pl::PatternLanguage> runtime;
|
||||
|
||||
return *runtime;
|
||||
}
|
||||
|
||||
std::scoped_lock<std::mutex> getRuntimeLock() {
|
||||
static std::mutex runtimeLock;
|
||||
|
||||
return std::scoped_lock(runtimeLock);
|
||||
}
|
||||
|
||||
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider) {
|
||||
runtime.reset();
|
||||
|
||||
|
@ -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<EventImHexClosing>();
|
||||
|
||||
while (ImHexApi::Provider::isValid())
|
||||
ImHexApi::Provider::remove(ImHexApi::Provider::get());
|
||||
@ -335,6 +335,8 @@ namespace hex::init {
|
||||
|
||||
fs::setFileBrowserErrorCallback(nullptr);
|
||||
|
||||
EventManager::clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1,145 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <pl/pattern_language.hpp>
|
||||
#include <hex/data_processor/attribute.hpp>
|
||||
#include <hex/data_processor/node.hpp>
|
||||
#include <hex/data_processor/link.hpp>
|
||||
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
#include <imnodes.h>
|
||||
#include <imnodes_internal.h>
|
||||
|
||||
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<pl::PatternLanguage> runtime = std::make_unique<pl::PatternLanguage>();
|
||||
std::vector<std::pair<pl::core::LogConsole::Level, std::string>> console;
|
||||
bool executionDone = true;
|
||||
|
||||
std::optional<pl::core::err::PatternLanguageError> lastEvaluationError;
|
||||
std::vector<std::pair<pl::core::LogConsole::Level, std::string>> lastEvaluationLog;
|
||||
std::map<std::string, pl::core::Token::Literal> lastEvaluationOutVars;
|
||||
std::map<std::string, PatternVariable> patternVariables;
|
||||
std::map<u64, pl::api::Section> sections;
|
||||
|
||||
std::list<EnvVar> envVarEntries;
|
||||
} patternLanguage;
|
||||
|
||||
std::list<ImHexApi::Bookmarks::Entry> bookmarks;
|
||||
|
||||
struct DataProcessor {
|
||||
struct Workspace {
|
||||
std::unique_ptr<ImNodesContext, void(*)(ImNodesContext*)> context = { []{
|
||||
ImNodesContext *ctx = ImNodes::CreateContext();
|
||||
ctx->Style = ImNodes::GetStyle();
|
||||
ctx->Io = ImNodes::GetIO();
|
||||
ctx->AttributeFlagStack = GImNodes->AttributeFlagStack;
|
||||
|
||||
return ctx;
|
||||
}(), ImNodes::DestroyContext };
|
||||
|
||||
std::list<std::unique_ptr<dp::Node>> nodes;
|
||||
std::list<dp::Node*> endNodes;
|
||||
std::list<dp::Link> links;
|
||||
std::vector<hex::prv::Overlay *> dataOverlays;
|
||||
std::optional<dp::Node::NodeError> currNodeError;
|
||||
};
|
||||
|
||||
Workspace mainWorkspace;
|
||||
std::vector<Workspace*> workspaceStack;
|
||||
} dataProcessor;
|
||||
|
||||
struct HexEditor {
|
||||
std::optional<u64> selectionStart = std::nullopt, selectionEnd = std::nullopt;
|
||||
float scrollPosition = 0.0F;
|
||||
} editor;
|
||||
|
||||
struct Hashes {
|
||||
std::vector<ContentRegistry::Hashes::Hash::Function> 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<std::pair<std::fs::path, std::fs::path>> rules;
|
||||
std::vector<YaraMatch> matches;
|
||||
std::vector<YaraMatch*> 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<const hex::prv::Provider*, Data> s_data = {};
|
||||
};
|
||||
|
||||
}
|
@ -10,7 +10,7 @@ namespace hex::plugin::builtin {
|
||||
class PopupFileChooser : public Popup<PopupFileChooser> {
|
||||
public:
|
||||
PopupFileChooser(const std::vector<std::fs::path> &files, const std::vector<nfdfilteritem_t> &validExtensions, bool multiple, const std::function<void(std::fs::path)> &callback)
|
||||
: hex::Popup<PopupFileChooser>("hex.builtin.common.choose_file", false),
|
||||
: hex::Popup<PopupFileChooser>("hex.builtin.common.choose_file"),
|
||||
m_indices({ }), m_files(files),
|
||||
m_openCallback(callback),
|
||||
m_validExtensions(validExtensions), m_multiple(multiple) { }
|
||||
|
@ -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<ImHexApi::Bookmarks::Entry>::iterator m_dragStartIterator;
|
||||
PerProvider<std::list<ImHexApi::Bookmarks::Entry>> m_bookmarks;
|
||||
};
|
||||
|
||||
}
|
@ -7,7 +7,7 @@
|
||||
#include <hex/data_processor/node.hpp>
|
||||
#include <hex/data_processor/link.hpp>
|
||||
|
||||
#include "content/helpers/provider_extra_data.hpp"
|
||||
#include <imnodes_internal.h>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
@ -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<ImNodesContext, void(*)(ImNodesContext*)> context = { []{
|
||||
ImNodesContext *ctx = ImNodes::CreateContext();
|
||||
ctx->Style = ImNodes::GetStyle();
|
||||
ctx->Io = ImNodes::GetIO();
|
||||
ctx->AttributeFlagStack = GImNodes->AttributeFlagStack;
|
||||
|
||||
return ctx;
|
||||
}(), ImNodes::DestroyContext };
|
||||
|
||||
std::list<std::unique_ptr<dp::Node>> nodes;
|
||||
std::list<dp::Node*> endNodes;
|
||||
std::list<dp::Link> links;
|
||||
std::vector<hex::prv::Overlay *> dataOverlays;
|
||||
std::optional<dp::Node::NodeError> currNodeError;
|
||||
};
|
||||
|
||||
public:
|
||||
ViewDataProcessor();
|
||||
~ViewDataProcessor() override;
|
||||
|
||||
@ -29,12 +47,14 @@ namespace hex::plugin::builtin {
|
||||
static std::unique_ptr<dp::Node> 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<int> &ids);
|
||||
static void processNodes(Workspace &workspace);
|
||||
|
||||
void reloadCustomNodes();
|
||||
|
||||
std::vector<Workspace*> &getWorkspaceStack() { return *this->m_workspaceStack; }
|
||||
|
||||
private:
|
||||
bool m_updateNodePositions = false;
|
||||
int m_rightClickedId = -1;
|
||||
@ -48,6 +68,9 @@ namespace hex::plugin::builtin {
|
||||
};
|
||||
|
||||
std::vector<CustomNode> m_customNodes;
|
||||
|
||||
PerProvider<Workspace> m_mainWorkspace;
|
||||
PerProvider<std::vector<Workspace*>> m_workspaceStack;
|
||||
};
|
||||
|
||||
}
|
@ -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<std::vector<ContentRegistry::Hashes::Hash::Function>> m_hashFunctions;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/helpers/encoding_file.hpp>
|
||||
|
||||
#include <content/helpers/provider_extra_data.hpp>
|
||||
#include <ui/hex_editor.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
@ -74,6 +73,9 @@ namespace hex::plugin::builtin {
|
||||
|
||||
bool m_shouldOpenPopup = false;
|
||||
std::unique_ptr<Popup> m_currPopup;
|
||||
|
||||
PerProvider<std::optional<u64>> m_selectionStart, m_selectionEnd;
|
||||
PerProvider<float> m_scrollPosition;
|
||||
};
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
@ -7,7 +7,6 @@
|
||||
#include <pl/pattern_language.hpp>
|
||||
#include <pl/core/errors/error.hpp>
|
||||
|
||||
#include <content/helpers/provider_extra_data.hpp>
|
||||
#include <content/providers/memory_file_provider.hpp>
|
||||
|
||||
#include <ui/hex_editor.hpp>
|
||||
@ -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<pl::PatternLanguage> m_parserRuntime;
|
||||
|
||||
@ -130,10 +154,22 @@ namespace hex::plugin::builtin {
|
||||
|
||||
ui::HexEditor m_sectionHexEditor;
|
||||
|
||||
PerProvider<std::string> m_sourceCode;
|
||||
PerProvider<std::vector<std::pair<pl::core::LogConsole::Level, std::string>>> m_console;
|
||||
PerProvider<bool> m_executionDone = true;
|
||||
|
||||
PerProvider<std::optional<pl::core::err::PatternLanguageError>> m_lastEvaluationError;
|
||||
PerProvider<std::vector<std::pair<pl::core::LogConsole::Level, std::string>>> m_lastEvaluationLog;
|
||||
PerProvider<std::map<std::string, pl::core::Token::Literal>> m_lastEvaluationOutVars;
|
||||
PerProvider<std::map<std::string, PatternVariable>> m_patternVariables;
|
||||
PerProvider<std::map<u64, pl::api::Section>> m_sections;
|
||||
|
||||
PerProvider<std::list<EnvVar>> m_envVarEntries;
|
||||
|
||||
private:
|
||||
void drawConsole(ImVec2 size, const std::vector<std::pair<pl::core::LogConsole::Level, std::string>> &console);
|
||||
void drawEnvVars(ImVec2 size, std::list<PlData::EnvVar> &envVars);
|
||||
void drawVariableSettings(ImVec2 size, std::map<std::string, PlData::PatternVariable> &patternVariables);
|
||||
void drawEnvVars(ImVec2 size, std::list<EnvVar> &envVars);
|
||||
void drawVariableSettings(ImVec2 size, std::map<std::string, PatternVariable> &patternVariables);
|
||||
void drawSectionSelector(ImVec2 size, std::map<u64, pl::api::Section> §ions);
|
||||
|
||||
void drawPatternTooltip(pl::ptrn::Pattern *pattern);
|
||||
|
@ -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<std::vector<std::pair<std::fs::path, std::fs::path>>> m_rules;
|
||||
PerProvider<std::vector<YaraMatch>> m_matches;
|
||||
PerProvider<std::vector<YaraMatch*>> m_sortedMatches;
|
||||
|
||||
u32 m_selectedRule = 0;
|
||||
TaskHolder m_matcherTask;
|
||||
|
||||
|
@ -7,9 +7,6 @@
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <content/views/view_data_processor.hpp>
|
||||
|
||||
#include <content/helpers/provider_extra_data.hpp>
|
||||
#include <content/helpers/diagrams.hpp>
|
||||
|
||||
#include <cctype>
|
||||
@ -22,7 +19,6 @@
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
#include <wolv/utils/core.hpp>
|
||||
#include <wolv/utils/guards.hpp>
|
||||
|
||||
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<u8> &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<std::string>();
|
||||
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<i128, long double, std::vector<u8>> 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<std::string>();
|
||||
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<i128, long double, std::vector<u8>> 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<u32> {
|
||||
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<i128>(output->getValue());
|
||||
this->setIntegerOnOutput(*index, value);
|
||||
break;
|
||||
}
|
||||
case dp::Attribute::Type::Float: {
|
||||
auto value = std::get<long double>(output->getValue());
|
||||
this->setFloatOnOutput(*index, value);
|
||||
break;
|
||||
}
|
||||
case dp::Attribute::Type::Buffer: {
|
||||
auto value = std::get<std::vector<u8>>(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<dp::Attribute> findAttributes() {
|
||||
std::vector<dp::Attribute> result;
|
||||
|
||||
for (auto &node : this->m_workspace.nodes) {
|
||||
if (auto *inputNode = dynamic_cast<NodeCustomInput*>(node.get()); inputNode != nullptr)
|
||||
result.emplace_back(dp::Attribute::IOType::In, inputNode->getType(), inputNode->getName());
|
||||
else if (auto *outputNode = dynamic_cast<NodeCustomOutput*>(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<NodeCustomInput*>(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<NodeCustomOutput*>(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<NodeInteger>("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.int");
|
||||
ContentRegistry::DataProcessorNode::add<NodeFloat>("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.float");
|
||||
@ -1565,10 +1264,6 @@ namespace hex::plugin::builtin {
|
||||
ContentRegistry::DataProcessorNode::add<NodeVisualizerByteDistribution>("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.byte_distribution");
|
||||
|
||||
ContentRegistry::DataProcessorNode::add<NodePatternLanguageOutVariable>("hex.builtin.nodes.pattern_language", "hex.builtin.nodes.pattern_language.out_var");
|
||||
|
||||
ContentRegistry::DataProcessorNode::add<NodeCustom>("hex.builtin.nodes.custom", "hex.builtin.nodes.custom.custom");
|
||||
ContentRegistry::DataProcessorNode::add<NodeCustomInput>("hex.builtin.nodes.custom", "hex.builtin.nodes.custom.input");
|
||||
ContentRegistry::DataProcessorNode::add<NodeCustomOutput>("hex.builtin.nodes.custom", "hex.builtin.nodes.custom.output");
|
||||
}
|
||||
|
||||
}
|
@ -8,8 +8,6 @@
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <content/helpers/provider_extra_data.hpp>
|
||||
|
||||
#include <content/providers/file_provider.hpp>
|
||||
|
||||
#include <wolv/io/fs.hpp>
|
||||
@ -131,10 +129,6 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderDeleted>([](hex::prv::Provider *provider) {
|
||||
ProviderExtraData::erase(provider);
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventRegionSelected>([](const ImHexApi::HexEditor::ProviderRegion ®ion) {
|
||||
ImHexApi::HexEditor::impl::setCurrentSelection(region);
|
||||
});
|
||||
|
@ -11,15 +11,13 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <cstring>
|
||||
|
||||
#include <content/helpers/provider_extra_data.hpp>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
#include <wolv/utils/guards.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
ViewBookmarks::ViewBookmarks() : View("hex.builtin.view.bookmarks.name") {
|
||||
EventManager::subscribe<RequestAddBookmark>(this, [](Region region, std::string name, std::string comment, color_t color) {
|
||||
EventManager::subscribe<RequestAddBookmark>(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<EventBookmarkCreated>(ProviderExtraData::getCurrent().bookmarks.back());
|
||||
EventManager::post<EventBookmarkCreated>(this->m_bookmarks->back());
|
||||
});
|
||||
|
||||
ImHexApi::HexEditor::addBackgroundHighlightingProvider([](u64 address, const u8* data, size_t size, bool) -> std::optional<color_t> {
|
||||
ImHexApi::HexEditor::addBackgroundHighlightingProvider([this](u64 address, const u8* data, size_t size, bool) -> std::optional<color_t> {
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -11,45 +11,338 @@
|
||||
#include <imnodes_internal.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <content/helpers/provider_extra_data.hpp>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
#include <wolv/utils/guards.hpp>
|
||||
|
||||
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<u8> &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<std::string>();
|
||||
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<i128, long double, std::vector<u8>> 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<std::string>();
|
||||
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<i128, long double, std::vector<u8>> 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<u32> {
|
||||
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<i128>(output->getValue());
|
||||
this->setIntegerOnOutput(*index, value);
|
||||
break;
|
||||
}
|
||||
case dp::Attribute::Type::Float: {
|
||||
auto value = std::get<long double>(output->getValue());
|
||||
this->setFloatOnOutput(*index, value);
|
||||
break;
|
||||
}
|
||||
case dp::Attribute::Type::Buffer: {
|
||||
auto value = std::get<std::vector<u8>>(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<dp::Attribute> findAttributes() {
|
||||
std::vector<dp::Attribute> result;
|
||||
|
||||
for (auto &node : this->m_workspace.nodes) {
|
||||
if (auto *inputNode = dynamic_cast<NodeCustomInput*>(node.get()); inputNode != nullptr)
|
||||
result.emplace_back(dp::Attribute::IOType::In, inputNode->getType(), inputNode->getName());
|
||||
else if (auto *outputNode = dynamic_cast<NodeCustomOutput*>(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<NodeCustomInput*>(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<NodeCustomOutput*>(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<NodeCustom>("hex.builtin.nodes.custom", "hex.builtin.nodes.custom.custom", this);
|
||||
ContentRegistry::DataProcessorNode::add<NodeCustomInput>("hex.builtin.nodes.custom", "hex.builtin.nodes.custom.input");
|
||||
ContentRegistry::DataProcessorNode::add<NodeCustomOutput>("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<EventProviderCreated>(this, [](const auto *provider) {
|
||||
auto &data = ProviderExtraData::get(provider).dataProcessor;
|
||||
|
||||
data.mainWorkspace = { };
|
||||
data.workspaceStack.push_back(&data.mainWorkspace);
|
||||
EventManager::subscribe<EventProviderCreated>(this, [this](auto *provider) {
|
||||
this->m_mainWorkspace.get(provider) = { };
|
||||
this->m_workspaceStack.get(provider).push_back(&this->m_mainWorkspace.get(provider));
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderChanged>(this, [this](const auto &, const auto &) {
|
||||
auto &data = ProviderExtraData::getCurrent().dataProcessor;
|
||||
|
||||
for (auto *workspace : data.workspaceStack) {
|
||||
EventManager::subscribe<EventProviderChanged>(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<EventDataChanged>(this, [] {
|
||||
auto &workspace = *ProviderExtraData::getCurrent().dataProcessor.workspaceStack.back();
|
||||
|
||||
ViewDataProcessor::processNodes(workspace);
|
||||
EventManager::subscribe<EventDataChanged>(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<int> &ids) {
|
||||
void ViewDataProcessor::eraseNodes(Workspace &workspace, const std::vector<int> &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;
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include "content/views/view_hashes.hpp"
|
||||
#include "content/helpers/provider_extra_data.hpp"
|
||||
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <hex/helpers/crypto.hpp>
|
||||
@ -9,18 +8,18 @@
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
ViewHashes::ViewHashes() : View("hex.builtin.view.hashes.name") {
|
||||
EventManager::subscribe<EventRegionSelected>(this, [](const auto &providerRegion) {
|
||||
for (auto &function : ProviderExtraData::get(providerRegion.getProvider()).hashes.hashFunctions)
|
||||
EventManager::subscribe<EventRegionSelected>(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<u32> 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() },
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include <content/popups/popup_file_chooser.hpp>
|
||||
|
||||
#include <imgui_internal.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <thread>
|
||||
|
||||
@ -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<EventRegionSelected>(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<EventRegionSelected>(ImHexApi::HexEditor::ProviderRegion({ Region::Invalid(), nullptr }));
|
||||
|
||||
return;
|
||||
@ -871,14 +866,12 @@ namespace hex::plugin::builtin {
|
||||
|
||||
EventManager::subscribe<EventProviderChanged>(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();
|
||||
|
@ -5,8 +5,6 @@
|
||||
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
|
||||
#include <content/helpers/provider_extra_data.hpp>
|
||||
|
||||
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<std::shared_ptr<pl::ptrn::Pattern>> empty;
|
||||
return empty;
|
||||
}
|
||||
}();
|
||||
|
||||
if (!patternLanguage.executionDone)
|
||||
if (runtime.isRunning())
|
||||
this->m_patternDrawer.reset();
|
||||
|
||||
this->m_patternDrawer.draw(patterns);
|
||||
|
@ -14,7 +14,6 @@
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <hex/helpers/magic.hpp>
|
||||
|
||||
#include <content/helpers/provider_extra_data.hpp>
|
||||
#include <content/popups/popup_file_chooser.hpp>
|
||||
#include <content/popups/popup_question.hpp>
|
||||
|
||||
@ -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<PlData::EnvVar> &envVars) {
|
||||
void ViewPatternEditor::drawEnvVars(ImVec2 size, std::list<EnvVar> &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<int>(type)])) {
|
||||
for (size_t i = 0; i < Types.size(); i++) {
|
||||
if (ImGui::Selectable(Types[i]))
|
||||
type = static_cast<PlData::EnvVarType>(i);
|
||||
type = static_cast<EnvVarType>(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<i128>(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<std::string, PlData::PatternVariable> &patternVariables) {
|
||||
void ViewPatternEditor::drawVariableSettings(ImVec2 size, std::map<std::string, PatternVariable> &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<u64, pl::api::Section> §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<color_t> {
|
||||
hexEditor.setBackgroundHighlightCallback([this, id, &runtime](u64 address, const u8 *, size_t) -> std::optional<color_t> {
|
||||
if (this->m_runningEvaluators != 0)
|
||||
return std::nullopt;
|
||||
if (!ImHexApi::Provider::isValid())
|
||||
return std::nullopt;
|
||||
|
||||
std::optional<ImColor> 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<std::shared_ptr<pl::ptrn::Pattern>> 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<EventHighlightingChanged>();
|
||||
}
|
||||
|
||||
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<pl::core::ast::ASTNodeBuiltinType *>(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<EventHighlightingChanged>();
|
||||
EventManager::post<EventPatternExecuted>(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<std::string, pl::core::Token::Literal> 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<std::string, pl::core::Token::Literal> 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<EventProviderOpened>(this, [this](prv::Provider *provider) {
|
||||
auto &patternLanguageData = ProviderExtraData::get(provider).patternLanguage;
|
||||
patternLanguageData.runtime = std::make_unique<pl::PatternLanguage>();
|
||||
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<pl::PatternLanguage>();
|
||||
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<EventProviderChanged>(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<ImColor> 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;
|
||||
|
@ -6,8 +6,6 @@
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include "content/helpers/provider_extra_data.hpp"
|
||||
|
||||
#include <content/popups/popup_notification.hpp>
|
||||
#include <content/popups/popup_file_chooser.hpp>
|
||||
|
||||
@ -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::string>()), std::fs::path(path.get<std::string>()));
|
||||
this->m_rules.get(provider).emplace_back(std::fs::path(name.get<std::string>()), std::fs::path(path.get<std::string>()));
|
||||
}
|
||||
|
||||
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<nfdfilteritem_t>{ { "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<ProviderExtraData::Data::Yara::YaraMatch> newMatches;
|
||||
std::vector<YaraMatch> newMatches;
|
||||
std::vector<std::string> 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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user