mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-30 05:05:19 -05:00
Added Plugin support (#102)
* Build refactoring and initial plugin support * Possibly fixed linux / mac build * Added libdl to libglad build script * Add glfw to imgui dependencies * Refactored common functionality into "libimhex" for plugins * Added plugin loading and example plugin * Added proper API for creating a custom view and a custom tools entry with plugins
This commit is contained in:
@@ -1,58 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
namespace hex {
|
||||
|
||||
enum class Events {
|
||||
FileLoaded,
|
||||
DataChanged,
|
||||
PatternChanged,
|
||||
FileDropped,
|
||||
WindowClosing,
|
||||
RegionSelected,
|
||||
|
||||
SelectionChangeRequest,
|
||||
|
||||
AddBookmark,
|
||||
AppendPatternLanguageCode,
|
||||
|
||||
ProjectFileStore,
|
||||
ProjectFileLoad
|
||||
};
|
||||
|
||||
struct EventHandler {
|
||||
void *owner;
|
||||
Events eventType;
|
||||
std::function<void(const void*)> callback;
|
||||
};
|
||||
|
||||
class EventManager {
|
||||
public:
|
||||
|
||||
void post(Events eventType, const void *userData) {
|
||||
for (auto &handler : this->m_eventHandlers)
|
||||
if (eventType == handler.eventType)
|
||||
handler.callback(userData);
|
||||
}
|
||||
|
||||
void subscribe(Events eventType, void *owner, std::function<void(const void*)> callback) {
|
||||
for (auto &handler : this->m_eventHandlers)
|
||||
if (eventType == handler.eventType && owner == handler.owner)
|
||||
return;
|
||||
|
||||
this->m_eventHandlers.push_back(EventHandler { owner, eventType, callback });
|
||||
}
|
||||
|
||||
void unsubscribe(Events eventType, void *sender) {
|
||||
std::erase_if(this->m_eventHandlers, [&eventType, &sender](EventHandler handler) {
|
||||
return eventType == handler.eventType && sender == handler.owner;
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<EventHandler> m_eventHandlers;
|
||||
};
|
||||
|
||||
}
|
||||
48
include/helpers/plugin_handler.hpp
Normal file
48
include/helpers/plugin_handler.hpp
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include "views/view.hpp"
|
||||
|
||||
#include <string_view>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class Plugin {
|
||||
public:
|
||||
Plugin(std::string_view path);
|
||||
~Plugin();
|
||||
|
||||
void setImGuiContext(ImGuiContext *ctx) const;
|
||||
View* createView() const;
|
||||
void drawToolsEntry() const;
|
||||
|
||||
private:
|
||||
using SetImGuiContextFunc = void(*)(ImGuiContext*);
|
||||
using CreateViewFunc = View*(*)();
|
||||
using DrawToolsEntryFunc = void(*)();
|
||||
|
||||
void *m_handle = nullptr;
|
||||
|
||||
SetImGuiContextFunc m_setImGuiContextFunction = nullptr;
|
||||
CreateViewFunc m_createViewFunction = nullptr;
|
||||
DrawToolsEntryFunc m_drawToolsEntryFunction = nullptr;
|
||||
|
||||
};
|
||||
|
||||
class PluginHandler {
|
||||
public:
|
||||
PluginHandler() = delete;
|
||||
|
||||
static void load(std::string_view pluginFolder);
|
||||
static void unload();
|
||||
static void reload();
|
||||
|
||||
static const auto& getPlugins() {
|
||||
return PluginHandler::s_plugins;
|
||||
}
|
||||
|
||||
private:
|
||||
static inline std::string s_pluginFolder;
|
||||
static inline std::vector<Plugin> s_plugins;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
using u8 = std::uint8_t;
|
||||
using u16 = std::uint16_t;
|
||||
using u32 = std::uint32_t;
|
||||
using u64 = std::uint64_t;
|
||||
using u128 = __uint128_t;
|
||||
|
||||
using s8 = std::int8_t;
|
||||
using s16 = std::int16_t;
|
||||
using s32 = std::int32_t;
|
||||
using s64 = std::int64_t;
|
||||
using s128 = __int128_t;
|
||||
|
||||
#include "lang/result.hpp"
|
||||
#include "lang/results.hpp"
|
||||
|
||||
extern int mainArgc;
|
||||
extern char **mainArgv;
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
#define MAGIC_PATH_SEPARATOR ";"
|
||||
#else
|
||||
#define MAGIC_PATH_SEPARATOR ":"
|
||||
#endif
|
||||
@@ -17,7 +17,7 @@ namespace hex::lang {
|
||||
public:
|
||||
Evaluator(prv::Provider* &provider, std::endian defaultDataEndianess);
|
||||
|
||||
std::pair<Result, std::vector<PatternData*>> evaluate(const std::vector<ASTNode*>& ast);
|
||||
std::optional<std::vector<PatternData*>> evaluate(const std::vector<ASTNode*>& ast);
|
||||
|
||||
const std::pair<u32, std::string>& getError() { return this->m_error; }
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "token.hpp"
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@@ -13,7 +14,7 @@ namespace hex::lang {
|
||||
public:
|
||||
Lexer();
|
||||
|
||||
std::pair<Result, std::vector<Token>> lex(const std::string& code);
|
||||
std::optional<std::vector<Token>> lex(const std::string& code);
|
||||
|
||||
const std::pair<u32, std::string>& getError() { return this->m_error; }
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ namespace hex::lang {
|
||||
|
||||
using TokenIter = std::vector<Token>::const_iterator;
|
||||
|
||||
std::pair<Result, std::vector<ASTNode*>> parse(const std::vector<Token> &tokens);
|
||||
std::optional<std::vector<ASTNode*>> parse(const std::vector<Token> &tokens);
|
||||
|
||||
const std::pair<u32, std::string>& getError() { return this->m_error; }
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ namespace hex::lang {
|
||||
public:
|
||||
Preprocessor();
|
||||
|
||||
std::pair<Result, std::string> preprocess(const std::string& code, bool initialRun = true);
|
||||
std::optional<std::string> preprocess(const std::string& code, bool initialRun = true);
|
||||
|
||||
void addPragmaHandler(std::string pragmaType, std::function<bool(std::string)> function);
|
||||
void addDefaultPragmaHandlers();
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace hex::lang {
|
||||
|
||||
class Result {
|
||||
public:
|
||||
constexpr Result(const std::uint8_t module, const std::uint32_t desc) noexcept : m_result((module << 24) | (desc & 0x00FFFFFF)) { }
|
||||
|
||||
constexpr std::uint32_t getResult() const noexcept { return this->m_result; }
|
||||
constexpr std::uint8_t getModule() const noexcept { return this->m_result >> 24; }
|
||||
constexpr std::uint32_t getDescription() const noexcept { return this->m_result & 0x00FFFFFF; }
|
||||
|
||||
constexpr bool succeeded() const noexcept { return this->m_result == 0; }
|
||||
constexpr bool failed() const noexcept { return !succeeded(); }
|
||||
private:
|
||||
const std::uint32_t m_result;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "result.hpp"
|
||||
|
||||
namespace hex::lang {
|
||||
|
||||
constexpr Result ResultSuccess(0, 0);
|
||||
|
||||
constexpr Result ResultPreprocessingError(1, 1);
|
||||
constexpr Result ResultLexicalError(2, 1);
|
||||
constexpr Result ResultParseError(3, 1);
|
||||
constexpr Result ResultEvaluatorError(4, 1);
|
||||
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
class Provider {
|
||||
public:
|
||||
constexpr static size_t PageSize = 0x1000'0000;
|
||||
|
||||
Provider() {
|
||||
this->m_patches.emplace_back();
|
||||
}
|
||||
|
||||
virtual ~Provider() = default;
|
||||
|
||||
virtual bool isAvailable() = 0;
|
||||
virtual bool isReadable() = 0;
|
||||
virtual bool isWritable() = 0;
|
||||
|
||||
virtual void read(u64 offset, void *buffer, size_t size) { this->readRaw(offset, buffer, size); }
|
||||
virtual void write(u64 offset, const void *buffer, size_t size) { this->writeRaw(offset, buffer, size); }
|
||||
|
||||
virtual void readRaw(u64 offset, void *buffer, size_t size) = 0;
|
||||
virtual void writeRaw(u64 offset, const void *buffer, size_t size) = 0;
|
||||
virtual size_t getActualSize() = 0;
|
||||
|
||||
std::map<u64, u8>& getPatches() { return this->m_patches.back(); }
|
||||
void applyPatches() {
|
||||
for (auto &[patchAddress, patch] : this->m_patches.back())
|
||||
this->writeRaw(patchAddress, &patch, 1);
|
||||
}
|
||||
|
||||
u32 getPageCount() { return std::ceil(this->getActualSize() / double(PageSize)); }
|
||||
u32 getCurrentPage() const { return this->m_currPage; }
|
||||
void setCurrentPage(u32 page) { if (page < getPageCount()) this->m_currPage = page; }
|
||||
|
||||
virtual size_t getBaseAddress() {
|
||||
return PageSize * this->m_currPage;
|
||||
}
|
||||
|
||||
virtual size_t getSize() {
|
||||
return std::min(this->getActualSize() - PageSize * this->m_currPage, PageSize);
|
||||
}
|
||||
|
||||
virtual std::optional<u32> getPageOfAddress(u64 address) {
|
||||
u32 page = std::floor(address / double(PageSize));
|
||||
|
||||
if (page >= this->getPageCount())
|
||||
return { };
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
virtual std::vector<std::pair<std::string, std::string>> getDataInformation() = 0;
|
||||
|
||||
protected:
|
||||
u32 m_currPage = 0;
|
||||
|
||||
std::vector<std::map<u64, u8>> m_patches;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
#include "helpers/event.hpp"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
|
||||
namespace hex {
|
||||
|
||||
class View {
|
||||
public:
|
||||
View(std::string viewName) : m_viewName(viewName) { }
|
||||
virtual ~View() { }
|
||||
|
||||
virtual void createView() = 0;
|
||||
virtual void createMenu() { }
|
||||
virtual bool handleShortcut(int key, int mods) { return false; }
|
||||
|
||||
static std::vector<std::function<void()>>& getDeferedCalls() {
|
||||
return View::s_deferedCalls;
|
||||
}
|
||||
|
||||
static void postEvent(Events eventType, const void *userData = nullptr) {
|
||||
View::s_eventManager.post(eventType, userData);
|
||||
}
|
||||
|
||||
static void drawCommonInterfaces() {
|
||||
if (ImGui::BeginPopupModal("Error", nullptr, ImGuiWindowFlags_NoResize)) {
|
||||
ImGui::NewLine();
|
||||
if (ImGui::BeginChild("##scrolling", ImVec2(300, 100))) {
|
||||
ImGui::SetCursorPosX((300 - ImGui::CalcTextSize(View::s_errorMessage.c_str(), nullptr, false).x) / 2.0F);
|
||||
ImGui::TextWrapped("%s", View::s_errorMessage.c_str());
|
||||
ImGui::EndChild();
|
||||
}
|
||||
ImGui::NewLine();
|
||||
ImGui::SetCursorPosX(75);
|
||||
if (ImGui::Button("Okay", ImVec2(150, 20)))
|
||||
ImGui::CloseCurrentPopup();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
static void showErrorPopup(std::string_view errorMessage) {
|
||||
View::s_errorMessage = errorMessage;
|
||||
|
||||
ImGui::OpenPopup("Error");
|
||||
}
|
||||
|
||||
static void setWindowPosition(s32 x, s32 y) {
|
||||
View::s_windowPos = ImVec2(x, y);
|
||||
}
|
||||
|
||||
static const ImVec2& getWindowPosition() {
|
||||
return View::s_windowPos;
|
||||
}
|
||||
|
||||
static void setWindowSize(s32 width, s32 height) {
|
||||
View::s_windowSize = ImVec2(width, height);
|
||||
}
|
||||
|
||||
static const ImVec2& getWindowSize() {
|
||||
return View::s_windowSize;
|
||||
}
|
||||
|
||||
virtual bool hasViewMenuItemEntry() { return true; }
|
||||
virtual ImVec2 getMinSize() { return ImVec2(480, 720); }
|
||||
virtual ImVec2 getMaxSize() { return ImVec2(FLT_MAX, FLT_MAX); }
|
||||
|
||||
bool& getWindowOpenState() {
|
||||
return this->m_windowOpen;
|
||||
}
|
||||
|
||||
const std::string getName() const {
|
||||
return this->m_viewName;
|
||||
}
|
||||
|
||||
protected:
|
||||
void subscribeEvent(Events eventType, std::function<void(const void*)> callback) {
|
||||
View::s_eventManager.subscribe(eventType, this, callback);
|
||||
}
|
||||
|
||||
void unsubscribeEvent(Events eventType) {
|
||||
View::s_eventManager.unsubscribe(eventType, this);
|
||||
}
|
||||
|
||||
void doLater(std::function<void()> &&function) {
|
||||
View::s_deferedCalls.push_back(function);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private:
|
||||
std::string m_viewName;
|
||||
bool m_windowOpen = false;
|
||||
|
||||
static inline EventManager s_eventManager;
|
||||
static inline std::vector<std::function<void()>> s_deferedCalls;
|
||||
|
||||
static inline std::string s_errorMessage;
|
||||
|
||||
static inline ImVec2 s_windowPos;
|
||||
static inline ImVec2 s_windowSize;
|
||||
};
|
||||
|
||||
void confirmButtons(const char *textLeft, const char *textRight, auto leftButtonFn, auto rightButtonFn) {
|
||||
auto width = ImGui::GetWindowWidth();
|
||||
ImGui::SetCursorPosX(width / 9);
|
||||
if (ImGui::Button(textLeft, ImVec2(width / 3, 0)))
|
||||
leftButtonFn();
|
||||
ImGui::SameLine();
|
||||
ImGui::SetCursorPosX(width / 9 * 5);
|
||||
if (ImGui::Button(textRight, ImVec2(width / 3, 0)))
|
||||
rightButtonFn();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,8 +16,8 @@ namespace hex {
|
||||
explicit ViewBookmarks(prv::Provider* &dataProvider);
|
||||
~ViewBookmarks() override;
|
||||
|
||||
void createView() override;
|
||||
void createMenu() override;
|
||||
void drawContent() override;
|
||||
void drawMenu() override;
|
||||
|
||||
private:
|
||||
prv::Provider* &m_dataProvider;
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace hex {
|
||||
ViewCommandPalette();
|
||||
~ViewCommandPalette() override;
|
||||
|
||||
void createView() override;
|
||||
void createMenu() override;
|
||||
void drawContent() override;
|
||||
void drawMenu() override;
|
||||
|
||||
bool handleShortcut(int key, int mods) override;
|
||||
|
||||
|
||||
@@ -54,8 +54,8 @@ namespace hex {
|
||||
explicit ViewDataInspector(prv::Provider* &dataProvider);
|
||||
~ViewDataInspector() override;
|
||||
|
||||
void createView() override;
|
||||
void createMenu() override;
|
||||
void drawContent() override;
|
||||
void drawMenu() override;
|
||||
|
||||
private:
|
||||
prv::Provider* &m_dataProvider;
|
||||
|
||||
@@ -27,8 +27,8 @@ namespace hex {
|
||||
explicit ViewDisassembler(prv::Provider* &dataProvider);
|
||||
~ViewDisassembler() override;
|
||||
|
||||
void createView() override;
|
||||
void createMenu() override;
|
||||
void drawContent() override;
|
||||
void drawMenu() override;
|
||||
|
||||
private:
|
||||
prv::Provider* &m_dataProvider;
|
||||
|
||||
@@ -13,8 +13,8 @@ namespace hex {
|
||||
explicit ViewHashes(prv::Provider* &dataProvider);
|
||||
~ViewHashes() override;
|
||||
|
||||
void createView() override;
|
||||
void createMenu() override;
|
||||
void drawContent() override;
|
||||
void drawMenu() override;
|
||||
|
||||
private:
|
||||
prv::Provider* &m_dataProvider;
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace hex {
|
||||
ViewHelp();
|
||||
~ViewHelp() override;
|
||||
|
||||
void createView() override;
|
||||
void createMenu() override;
|
||||
void drawContent() override;
|
||||
void drawMenu() override;
|
||||
|
||||
bool hasViewMenuItemEntry() override { return false; }
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@ namespace hex {
|
||||
ViewHexEditor(prv::Provider* &dataProvider, std::vector<lang::PatternData*> &patternData);
|
||||
~ViewHexEditor() override;
|
||||
|
||||
void createView() override;
|
||||
void createMenu() override;
|
||||
void drawContent() override;
|
||||
void drawMenu() override;
|
||||
bool handleShortcut(int key, int mods) override;
|
||||
|
||||
private:
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace hex {
|
||||
explicit ViewInformation(prv::Provider* &dataProvider);
|
||||
~ViewInformation() override;
|
||||
|
||||
void createView() override;
|
||||
void createMenu() override;
|
||||
void drawContent() override;
|
||||
void drawMenu() override;
|
||||
|
||||
private:
|
||||
prv::Provider* &m_dataProvider;
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace hex {
|
||||
explicit ViewPatches(prv::Provider* &dataProvider);
|
||||
~ViewPatches() override;
|
||||
|
||||
void createView() override;
|
||||
void createMenu() override;
|
||||
void drawContent() override;
|
||||
void drawMenu() override;
|
||||
|
||||
private:
|
||||
prv::Provider* &m_dataProvider;
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace hex {
|
||||
explicit ViewPattern(prv::Provider* &dataProvider, std::vector<lang::PatternData*> &patternData);
|
||||
~ViewPattern() override;
|
||||
|
||||
void createMenu() override;
|
||||
void createView() override;
|
||||
void drawMenu() override;
|
||||
void drawContent() override;
|
||||
|
||||
private:
|
||||
std::vector<lang::PatternData*> &m_patternData;
|
||||
|
||||
@@ -19,8 +19,8 @@ namespace hex {
|
||||
ViewPatternData(prv::Provider* &dataProvider, std::vector<lang::PatternData*> &patternData);
|
||||
~ViewPatternData() override;
|
||||
|
||||
void createView() override;
|
||||
void createMenu() override;
|
||||
void drawContent() override;
|
||||
void drawMenu() override;
|
||||
|
||||
private:
|
||||
|
||||
|
||||
@@ -20,8 +20,8 @@ namespace hex {
|
||||
explicit ViewStrings(prv::Provider* &dataProvider);
|
||||
~ViewStrings() override;
|
||||
|
||||
void createView() override;
|
||||
void createMenu() override;
|
||||
void drawContent() override;
|
||||
void drawMenu() override;
|
||||
|
||||
private:
|
||||
prv::Provider* &m_dataProvider;
|
||||
|
||||
@@ -18,8 +18,8 @@ namespace hex {
|
||||
ViewTools(hex::prv::Provider* &provider);
|
||||
~ViewTools() override;
|
||||
|
||||
void createView() override;
|
||||
void createMenu() override;
|
||||
void drawContent() override;
|
||||
void drawMenu() override;
|
||||
|
||||
private:
|
||||
hex::prv::Provider* &m_dataProvider;
|
||||
|
||||
@@ -39,11 +39,14 @@ namespace hex {
|
||||
|
||||
void initGLFW();
|
||||
void initImGui();
|
||||
void initPlugins();
|
||||
void deinitGLFW();
|
||||
void deinitImGui();
|
||||
void deinitPlugins();
|
||||
|
||||
GLFWwindow* m_window;
|
||||
std::vector<View*> m_views;
|
||||
std::vector<View*> m_pluginViews;
|
||||
|
||||
float m_globalScale = 1.0f, m_fontScale = 1.0f;
|
||||
bool m_fpsVisible = false;
|
||||
|
||||
Reference in New Issue
Block a user