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:
parent
b9324f44e6
commit
dbbc525174
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
@ -85,6 +85,7 @@ jobs:
|
||||
mingw-w64-${{ matrix.arch }}-polly
|
||||
mingw-w64-${{ matrix.arch }}-python
|
||||
mingw-w64-${{ matrix.arch }}-freetype
|
||||
mingw-w64-${{ matrix.arch }}-dlfcn
|
||||
|
||||
- name: ✋ Build
|
||||
run: |
|
||||
|
@ -2,8 +2,8 @@ cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(imhex VERSION 1.5.0)
|
||||
|
||||
SET(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
|
||||
SET(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
|
||||
set(CMAKE_FIND_PACKAGE_SORT_ORDER NATURAL)
|
||||
set(CMAKE_FIND_PACKAGE_SORT_DIRECTION DEC)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
# Enforce that we use non system Python 3 on macOS.
|
||||
@ -17,10 +17,11 @@ pkg_search_module(CRYPTO REQUIRED libcrypto)
|
||||
pkg_search_module(CAPSTONE REQUIRED capstone)
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(nlohmann_json REQUIRED)
|
||||
find_package(Freetype REQUIRED)
|
||||
find_package(Python COMPONENTS Interpreter Development)
|
||||
|
||||
add_subdirectory(external/llvm/Demangle)
|
||||
add_subdirectory(external/ImGui)
|
||||
add_subdirectory(plugins/libimhex)
|
||||
|
||||
if(Python_VERSION LESS 3)
|
||||
message(STATUS ${PYTHON_VERSION_MAJOR_MINOR})
|
||||
@ -33,32 +34,32 @@ if(NOT MAGIC_FOUND)
|
||||
endif()
|
||||
|
||||
# Add include directories
|
||||
include_directories(include ${GLFW_INCLUDE_DIRS} ${GLM_INCLUDE_DIRS} ${CRYPTO_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${FREETYPE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} libs/ImGui/include libs/glad/include ${Python_INCLUDE_DIRS})
|
||||
include_directories(include ${GLFW_INCLUDE_DIRS} ${GLM_INCLUDE_DIRS} ${CRYPTO_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${Python_INCLUDE_DIRS})
|
||||
|
||||
# Get Python major and minor
|
||||
string(REPLACE "." ";" PYTHON_VERSION_MAJOR_MINOR ${Python_VERSION})
|
||||
list(REMOVE_AT PYTHON_VERSION_MAJOR_MINOR 2)
|
||||
list(JOIN PYTHON_VERSION_MAJOR_MINOR "." PYTHON_VERSION_MAJOR_MINOR)
|
||||
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} -DIMGUI_IMPL_OPENGL_LOADER_GLAD -DPYTHON_VERSION_MAJOR_MINOR=\"\\\"${PYTHON_VERSION_MAJOR_MINOR}\"\\\"")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} -DPYTHON_VERSION_MAJOR_MINOR=\"\\\"${PYTHON_VERSION_MAJOR_MINOR}\"\\\"")
|
||||
|
||||
# Detect current OS / System
|
||||
if (MSYS OR MINGW)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOS_WINDOWS -static-libstdc++ -static-libgcc -static")
|
||||
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wl,-subsystem,windows")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOS_WINDOWS -static-libstdc++ -static-libgcc -static")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Wl,-subsystem,windows")
|
||||
elseif(APPLE)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOS_MACOS")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOS_MACOS")
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOS_LINUX")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOS_LINUX")
|
||||
else()
|
||||
message(FATAL_ERROR "Unknown / unsupported system!")
|
||||
endif()
|
||||
|
||||
# Detect 32 vs. 64 bit system
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DARCH_64_BIT")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DARCH_64_BIT")
|
||||
elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DARCH_32_BIT")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DARCH_32_BIT")
|
||||
endif()
|
||||
|
||||
# Get the current working branch
|
||||
@ -77,11 +78,11 @@ execute_process(
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGIT_COMMIT_HASH=\"\\\"${GIT_COMMIT_HASH}\"\\\"")
|
||||
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGIT_BRANCH=\"\\\"${GIT_BRANCH}\"\\\"")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGIT_COMMIT_HASH=\"\\\"${GIT_COMMIT_HASH}\"\\\"")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGIT_BRANCH=\"\\\"${GIT_BRANCH}\"\\\"")
|
||||
|
||||
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DRELEASE -DIMHEX_VERSION=\"\\\"${PROJECT_VERSION}\"\\\"")
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG -DIMHEX_VERSION=\"\\\"${PROJECT_VERSION}-Debug\"\\\"")
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -DRELEASE -DIMHEX_VERSION=\"\\\"${PROJECT_VERSION}\"\\\"")
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DDEBUG -DIMHEX_VERSION=\"\\\"${PROJECT_VERSION}-Debug\"\\\"")
|
||||
|
||||
add_executable(imhex
|
||||
source/main.cpp
|
||||
@ -93,6 +94,7 @@ add_executable(imhex
|
||||
source/helpers/math_evaluator.cpp
|
||||
source/helpers/project_file_handler.cpp
|
||||
source/helpers/loader_script_handler.cpp
|
||||
source/helpers/plugin_handler.cpp
|
||||
|
||||
source/lang/preprocessor.cpp
|
||||
source/lang/lexer.cpp
|
||||
@ -116,18 +118,6 @@ add_executable(imhex
|
||||
source/views/view_patches.cpp
|
||||
source/views/view_command_palette.cpp
|
||||
|
||||
libs/glad/source/glad.c
|
||||
|
||||
libs/ImGui/source/imgui.cpp
|
||||
libs/ImGui/source/imgui_draw.cpp
|
||||
libs/ImGui/source/imgui_widgets.cpp
|
||||
libs/ImGui/source/imgui_demo.cpp
|
||||
libs/ImGui/source/imgui_freetype.cpp
|
||||
libs/ImGui/source/imgui_impl_glfw.cpp
|
||||
libs/ImGui/source/imgui_impl_opengl3.cpp
|
||||
libs/ImGui/source/ImGuiFileBrowser.cpp
|
||||
libs/ImGui/source/TextEditor.cpp
|
||||
|
||||
resource.rc
|
||||
)
|
||||
|
||||
@ -136,9 +126,9 @@ set_target_properties(imhex PROPERTIES CXX_VISIBILITY_PRESET hidden)
|
||||
target_link_directories(imhex PRIVATE ${GLFW_LIBRARY_DIRS} ${CRYPTO_LIBRARY_DIRS} ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS})
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(imhex libglfw3.a libgcc.a libstdc++.a libmagic.a libgnurx.a libtre.a libintl.a libiconv.a shlwapi.lib libcrypto.a libwinpthread.a libcapstone.a LLVMDemangle ${Python_LIBRARIES} nlohmann_json::nlohmann_json Freetype::Freetype)
|
||||
target_link_libraries(imhex libglfw3.a libgcc.a libstdc++.a libmagic.a libgnurx.a libtre.a libintl.a libiconv.a shlwapi.lib libcrypto.a libwinpthread.a libcapstone.a LLVMDemangle imgui libimhex ${Python_LIBRARIES} nlohmann_json::nlohmann_json dl)
|
||||
elseif (UNIX)
|
||||
target_link_libraries(imhex glfw magic crypto ${CMAKE_DL_LIBS} capstone LLVMDemangle ${Python_LIBRARIES} nlohmann_json::nlohmann_json Freetype::Freetype)
|
||||
target_link_libraries(imhex glfw magic crypto ${CMAKE_DL_LIBS} capstone LLVMDemangle imgui libimhex ${Python_LIBRARIES} nlohmann_json::nlohmann_json dl)
|
||||
endif()
|
||||
|
||||
install(TARGETS imhex DESTINATION bin)
|
||||
|
3
dist/get_deps_msys2.sh
vendored
3
dist/get_deps_msys2.sh
vendored
@ -12,4 +12,5 @@ pacman -S --needed \
|
||||
mingw-w64-x86_64-openssl \
|
||||
mingw-w64-x86_64-polly \
|
||||
mingw-w64-x86_64-python \
|
||||
mingw-w64-x86_64-freetype
|
||||
mingw-w64-x86_64-freetype \
|
||||
mingw-w64-x86_64-dlfcn
|
||||
|
35
external/ImGui/CMakeLists.txt
vendored
Normal file
35
external/ImGui/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,35 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(imgui)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(Freetype REQUIRED)
|
||||
pkg_search_module(GLFW REQUIRED glfw3)
|
||||
|
||||
add_library(imgui
|
||||
source/imgui.cpp
|
||||
source/imgui_demo.cpp
|
||||
source/imgui_draw.cpp
|
||||
source/imgui_freetype.cpp
|
||||
source/imgui_impl_glfw.cpp
|
||||
source/imgui_impl_opengl3.cpp
|
||||
source/imgui_widgets.cpp
|
||||
source/ImGuiFileBrowser.cpp
|
||||
source/TextEditor.cpp
|
||||
)
|
||||
|
||||
add_compile_definitions(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../glad ${CMAKE_CURRENT_BINARY_DIR}/external/glad)
|
||||
|
||||
target_include_directories(imgui PUBLIC include)
|
||||
target_include_directories(imgui PRIVATE ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS})
|
||||
|
||||
target_link_directories(imgui PRIVATE ${GLFW_LIBRARY_DIRS})
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(imgui Freetype::Freetype glad libglfw3.a)
|
||||
elseif (UNIX)
|
||||
target_link_libraries(imgui Freetype::Freetype glad glfw)
|
||||
endif()
|
11
external/glad/CMakeLists.txt
vendored
Normal file
11
external/glad/CMakeLists.txt
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(glad)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
add_library(glad
|
||||
source/glad.c
|
||||
)
|
||||
|
||||
target_include_directories(glad PUBLIC include)
|
||||
target_link_libraries(glad PRIVATE dl)
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
@ -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;
|
||||
|
16
plugins/example/CMakeLists.txt
Normal file
16
plugins/example/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(example)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/ImGui ${CMAKE_CURRENT_BINARY_DIR}/external/ImGui)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../libimhex ${CMAKE_CURRENT_BINARY_DIR}/plugins/libimhex)
|
||||
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "plugin")
|
||||
|
||||
add_library(example SHARED
|
||||
source/plugin_example.cpp
|
||||
)
|
||||
|
||||
target_include_directories(example PUBLIC include)
|
||||
target_link_libraries(example imgui libimhex)
|
33
plugins/example/source/plugin_example.cpp
Normal file
33
plugins/example/source/plugin_example.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <views/view.hpp>
|
||||
#include <imgui.h>
|
||||
|
||||
class ViewExample : public hex::View {
|
||||
public:
|
||||
ViewExample() : hex::View("Example") {}
|
||||
~ViewExample() override {}
|
||||
|
||||
void drawContent() override {
|
||||
if (ImGui::Begin("Example")) {
|
||||
ImGui::Text("Custom plugin window");
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
};
|
||||
|
||||
IMHEX_PLUGIN {
|
||||
|
||||
View* createView() {
|
||||
return new ViewExample();
|
||||
}
|
||||
|
||||
void drawToolsEntry() {
|
||||
if (ImGui::CollapsingHeader("Example Tool")) {
|
||||
ImGui::Text("Custom Plugin tool");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
19
plugins/libimhex/CMakeLists.txt
Normal file
19
plugins/libimhex/CMakeLists.txt
Normal file
@ -0,0 +1,19 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(libimhex)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
if (TARGET libimhex)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/ImGui ${CMAKE_CURRENT_BINARY_DIR}/external/ImGui)
|
||||
endif()
|
||||
|
||||
set(CMAKE_STATIC_LIBRARY_PREFIX "")
|
||||
|
||||
add_library(libimhex STATIC
|
||||
source/helpers/event.cpp
|
||||
source/providers/provider.cpp
|
||||
source/views/view.cpp
|
||||
)
|
||||
|
||||
target_include_directories(libimhex PUBLIC include)
|
||||
target_link_libraries(libimhex PRIVATE imgui)
|
41
plugins/libimhex/include/helpers/event.hpp
Normal file
41
plugins/libimhex/include/helpers/event.hpp
Normal file
@ -0,0 +1,41 @@
|
||||
#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);
|
||||
void subscribe(Events eventType, void *owner, std::function<void(const void*)> callback);
|
||||
void unsubscribe(Events eventType, void *sender);
|
||||
|
||||
private:
|
||||
std::vector<EventHandler> m_eventHandlers;
|
||||
};
|
||||
|
||||
}
|
@ -15,12 +15,16 @@ 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;
|
||||
|
||||
#define IMHEX_PLUGIN namespace hex::plugin::internal { \
|
||||
void setImGuiContext(ImGuiContext *ctx) { \
|
||||
ImGui::SetCurrentContext(ctx); \
|
||||
} \
|
||||
} \
|
||||
namespace hex::plugin
|
||||
|
||||
#ifdef OS_WINDOWS
|
||||
#define MAGIC_PATH_SEPARATOR ";"
|
||||
#else
|
49
plugins/libimhex/include/providers/provider.hpp
Normal file
49
plugins/libimhex/include/providers/provider.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
class Provider {
|
||||
public:
|
||||
constexpr static size_t PageSize = 0x1000'0000;
|
||||
|
||||
Provider();
|
||||
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);
|
||||
virtual void write(u64 offset, const void *buffer, size_t 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();
|
||||
void applyPatches();
|
||||
|
||||
u32 getPageCount();
|
||||
u32 getCurrentPage() const;
|
||||
void setCurrentPage(u32 page);
|
||||
|
||||
virtual size_t getBaseAddress();
|
||||
virtual size_t getSize();
|
||||
virtual std::optional<u32> getPageOfAddress(u64 address);
|
||||
|
||||
virtual std::vector<std::pair<std::string, std::string>> getDataInformation() = 0;
|
||||
|
||||
protected:
|
||||
u32 m_currPage = 0;
|
||||
|
||||
std::vector<std::map<u64, u8>> m_patches;
|
||||
};
|
||||
|
||||
}
|
71
plugins/libimhex/include/views/view.hpp
Normal file
71
plugins/libimhex/include/views/view.hpp
Normal file
@ -0,0 +1,71 @@
|
||||
#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);
|
||||
virtual ~View() = default;
|
||||
|
||||
virtual void drawContent() = 0;
|
||||
virtual void drawMenu();
|
||||
virtual bool handleShortcut(int key, int mods);
|
||||
|
||||
static std::vector<std::function<void()>>& getDeferedCalls();
|
||||
|
||||
static void postEvent(Events eventType, const void *userData = nullptr);
|
||||
|
||||
static void drawCommonInterfaces();
|
||||
|
||||
static void showErrorPopup(std::string_view errorMessage);
|
||||
|
||||
static void setWindowPosition(s32 x, s32 y);
|
||||
|
||||
static const ImVec2& getWindowPosition();
|
||||
|
||||
static void setWindowSize(s32 width, s32 height);
|
||||
|
||||
static const ImVec2& getWindowSize();
|
||||
|
||||
virtual bool hasViewMenuItemEntry();
|
||||
virtual ImVec2 getMinSize();
|
||||
virtual ImVec2 getMaxSize();
|
||||
|
||||
bool& getWindowOpenState();
|
||||
|
||||
const std::string getName() const;
|
||||
|
||||
protected:
|
||||
void subscribeEvent(Events eventType, std::function<void(const void*)> callback);
|
||||
|
||||
void unsubscribeEvent(Events eventType);
|
||||
|
||||
void doLater(std::function<void()> &&function);
|
||||
|
||||
protected:
|
||||
void confirmButtons(const char *textLeft, const char *textRight, std::function<void()> leftButtonFn, std::function<void()> rightButtonFn);
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
25
plugins/libimhex/source/helpers/event.cpp
Normal file
25
plugins/libimhex/source/helpers/event.cpp
Normal file
@ -0,0 +1,25 @@
|
||||
#include "helpers/event.hpp"
|
||||
|
||||
namespace hex {
|
||||
|
||||
void EventManager::post(Events eventType, const void *userData) {
|
||||
for (auto &handler : this->m_eventHandlers)
|
||||
if (eventType == handler.eventType)
|
||||
handler.callback(userData);
|
||||
}
|
||||
|
||||
void EventManager::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 EventManager::unsubscribe(Events eventType, void *sender) {
|
||||
std::erase_if(this->m_eventHandlers, [&eventType, &sender](EventHandler handler) {
|
||||
return eventType == handler.eventType && sender == handler.owner;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
66
plugins/libimhex/source/providers/provider.cpp
Normal file
66
plugins/libimhex/source/providers/provider.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
#include "providers/provider.hpp"
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
Provider::Provider() {
|
||||
this->m_patches.emplace_back();
|
||||
}
|
||||
|
||||
void Provider::read(u64 offset, void *buffer, size_t size) {
|
||||
this->readRaw(offset, buffer, size);
|
||||
}
|
||||
|
||||
void Provider::write(u64 offset, const void *buffer, size_t size) {
|
||||
this->writeRaw(offset, buffer, size);
|
||||
}
|
||||
|
||||
|
||||
std::map<u64, u8>& Provider::getPatches() {
|
||||
return this->m_patches.back();
|
||||
}
|
||||
|
||||
void Provider::applyPatches() {
|
||||
for (auto &[patchAddress, patch] : this->m_patches.back())
|
||||
this->writeRaw(patchAddress, &patch, 1);
|
||||
}
|
||||
|
||||
u32 Provider::getPageCount() {
|
||||
return std::ceil(this->getActualSize() / double(PageSize));
|
||||
}
|
||||
|
||||
u32 Provider::getCurrentPage() const {
|
||||
return this->m_currPage;
|
||||
}
|
||||
|
||||
void Provider::setCurrentPage(u32 page) {
|
||||
if (page < getPageCount())
|
||||
this->m_currPage = page;
|
||||
}
|
||||
|
||||
|
||||
size_t Provider::getBaseAddress() {
|
||||
return PageSize * this->m_currPage;
|
||||
}
|
||||
|
||||
size_t Provider::getSize() {
|
||||
return std::min(this->getActualSize() - PageSize * this->m_currPage, PageSize);
|
||||
}
|
||||
|
||||
std::optional<u32> Provider::getPageOfAddress(u64 address) {
|
||||
u32 page = std::floor(address / double(PageSize));
|
||||
|
||||
if (page >= this->getPageCount())
|
||||
return { };
|
||||
|
||||
return page;
|
||||
}
|
||||
|
||||
}
|
107
plugins/libimhex/source/views/view.cpp
Normal file
107
plugins/libimhex/source/views/view.cpp
Normal file
@ -0,0 +1,107 @@
|
||||
#include "views/view.hpp"
|
||||
|
||||
#include "imgui.h"
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace hex {
|
||||
|
||||
|
||||
View::View(std::string viewName) : m_viewName(viewName) { }
|
||||
|
||||
void View::drawMenu() { }
|
||||
bool View::handleShortcut(int key, int mods) { return false; }
|
||||
|
||||
std::vector<std::function<void()>>& View::getDeferedCalls() {
|
||||
return View::s_deferedCalls;
|
||||
}
|
||||
|
||||
void View::postEvent(Events eventType, const void *userData) {
|
||||
View::s_eventManager.post(eventType, userData);
|
||||
}
|
||||
|
||||
void View::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();
|
||||
}
|
||||
}
|
||||
|
||||
void View::showErrorPopup(std::string_view errorMessage) {
|
||||
View::s_errorMessage = errorMessage;
|
||||
|
||||
ImGui::OpenPopup("Error");
|
||||
}
|
||||
|
||||
void View::setWindowPosition(s32 x, s32 y) {
|
||||
View::s_windowPos = ImVec2(x, y);
|
||||
}
|
||||
|
||||
const ImVec2& View::getWindowPosition() {
|
||||
return View::s_windowPos;
|
||||
}
|
||||
|
||||
void View::setWindowSize(s32 width, s32 height) {
|
||||
View::s_windowSize = ImVec2(width, height);
|
||||
}
|
||||
|
||||
const ImVec2& View::getWindowSize() {
|
||||
return View::s_windowSize;
|
||||
}
|
||||
|
||||
bool View::hasViewMenuItemEntry() {
|
||||
return true;
|
||||
}
|
||||
|
||||
ImVec2 View::getMinSize() {
|
||||
return ImVec2(480, 720);
|
||||
}
|
||||
|
||||
ImVec2 View::getMaxSize() {
|
||||
return ImVec2(FLT_MAX, FLT_MAX);
|
||||
}
|
||||
|
||||
|
||||
bool& View::getWindowOpenState() {
|
||||
return this->m_windowOpen;
|
||||
}
|
||||
|
||||
const std::string View::getName() const {
|
||||
return this->m_viewName;
|
||||
}
|
||||
|
||||
void View::subscribeEvent(Events eventType, std::function<void(const void*)> callback) {
|
||||
View::s_eventManager.subscribe(eventType, this, callback);
|
||||
}
|
||||
|
||||
void View::unsubscribeEvent(Events eventType) {
|
||||
View::s_eventManager.unsubscribe(eventType, this);
|
||||
}
|
||||
|
||||
void View::doLater(std::function<void()> &&function) {
|
||||
View::s_deferedCalls.push_back(function);
|
||||
}
|
||||
|
||||
void View::confirmButtons(const char *textLeft, const char *textRight, std::function<void()> leftButtonFn, std::function<void()> 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();
|
||||
}
|
||||
|
||||
}
|
70
source/helpers/plugin_handler.cpp
Normal file
70
source/helpers/plugin_handler.cpp
Normal file
@ -0,0 +1,70 @@
|
||||
#include "helpers/plugin_handler.hpp"
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <filesystem>
|
||||
|
||||
namespace hex {
|
||||
|
||||
// hex::plugin::createView(void)
|
||||
constexpr auto CreateViewSymbol = "_ZN3hex6plugin10createViewEv";
|
||||
// hex::plugin::drawToolsEntry(void)
|
||||
constexpr auto DrawToolsEntrySymbol = "_ZN3hex6plugin14drawToolsEntryEv";
|
||||
// hex::plugin::internal::setImGuiContext(ImGuiContext*)
|
||||
constexpr auto SetImGuiContextSymbol = "_ZN3hex6plugin8internal15setImGuiContextEP12ImGuiContext";
|
||||
|
||||
Plugin::Plugin(std::string_view path) {
|
||||
this->m_handle = dlopen(path.data(), RTLD_LAZY);
|
||||
|
||||
if (this->m_handle == nullptr)
|
||||
return;
|
||||
|
||||
this->m_createViewFunction = reinterpret_cast<CreateViewFunc>(dlsym(this->m_handle, CreateViewSymbol));
|
||||
this->m_drawToolsEntryFunction = reinterpret_cast<DrawToolsEntryFunc>(dlsym(this->m_handle, DrawToolsEntrySymbol));
|
||||
this->m_setImGuiContextFunction = reinterpret_cast<SetImGuiContextFunc>(dlsym(this->m_handle, SetImGuiContextSymbol));
|
||||
}
|
||||
|
||||
Plugin::~Plugin() {
|
||||
if (this->m_handle != nullptr)
|
||||
dlclose(this->m_handle);
|
||||
}
|
||||
|
||||
void Plugin::setImGuiContext(ImGuiContext *ctx) const {
|
||||
if (this->m_setImGuiContextFunction != nullptr)
|
||||
this->m_setImGuiContextFunction(ctx);
|
||||
}
|
||||
|
||||
View* Plugin::createView() const {
|
||||
if (this->m_createViewFunction != nullptr)
|
||||
return this->m_createViewFunction();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Plugin::drawToolsEntry() const {
|
||||
if (this->m_drawToolsEntryFunction != nullptr)
|
||||
this->m_drawToolsEntryFunction();
|
||||
}
|
||||
|
||||
|
||||
void PluginHandler::load(std::string_view pluginFolder) {
|
||||
PluginHandler::unload();
|
||||
|
||||
if (!std::filesystem::exists(pluginFolder))
|
||||
throw std::runtime_error("Failed to find plugin folder");
|
||||
|
||||
PluginHandler::s_pluginFolder = pluginFolder;
|
||||
|
||||
for (auto& pluginPath : std::filesystem::directory_iterator(pluginFolder))
|
||||
PluginHandler::s_plugins.emplace_back(pluginPath.path().string());
|
||||
}
|
||||
|
||||
void PluginHandler::unload() {
|
||||
PluginHandler::s_plugins.clear();
|
||||
PluginHandler::s_pluginFolder.clear();
|
||||
}
|
||||
|
||||
void PluginHandler::reload() {
|
||||
PluginHandler::load(PluginHandler::s_pluginFolder);
|
||||
}
|
||||
|
||||
}
|
@ -347,7 +347,7 @@ namespace hex::lang {
|
||||
return { nullptr, 0 };
|
||||
}
|
||||
|
||||
std::pair<Result, std::vector<PatternData*>> Evaluator::evaluate(const std::vector<ASTNode *> &ast) {
|
||||
std::optional<std::vector<PatternData*>> Evaluator::evaluate(const std::vector<ASTNode *> &ast) {
|
||||
|
||||
// Evaluate types
|
||||
for (const auto &node : ast) {
|
||||
@ -420,9 +420,9 @@ namespace hex::lang {
|
||||
|
||||
for (const auto &var : variables)
|
||||
if (var == nullptr)
|
||||
return { ResultEvaluatorError, { } };
|
||||
return { };
|
||||
|
||||
return { ResultSuccess, variables };
|
||||
return variables;
|
||||
}
|
||||
|
||||
}
|
@ -66,7 +66,7 @@ namespace hex::lang {
|
||||
return integer;
|
||||
}
|
||||
|
||||
std::pair<Result, std::vector<Token>> Lexer::lex(const std::string& code) {
|
||||
std::optional<std::vector<Token>> Lexer::lex(const std::string& code) {
|
||||
std::vector<Token> tokens;
|
||||
u32 offset = 0;
|
||||
|
||||
@ -142,7 +142,7 @@ namespace hex::lang {
|
||||
|
||||
if (offset >= code.length()) {
|
||||
this->m_error = { lineNumber, "Invalid character literal" };
|
||||
return { ResultLexicalError, { } };
|
||||
return { };
|
||||
}
|
||||
|
||||
char character = code[offset];
|
||||
@ -152,19 +152,19 @@ namespace hex::lang {
|
||||
|
||||
if (offset >= code.length()) {
|
||||
this->m_error = { lineNumber, "Invalid character literal" };
|
||||
return { ResultLexicalError, { } };
|
||||
return { };
|
||||
}
|
||||
|
||||
if (code[offset] != '\\' && code[offset] != '\'') {
|
||||
this->m_error = { lineNumber, "Invalid escape sequence" };
|
||||
return { ResultLexicalError, { } };
|
||||
return { };
|
||||
}
|
||||
|
||||
character = code[offset];
|
||||
} else {
|
||||
if (code[offset] == '\\' || code[offset] == '\'' || character == '\n' || character == '\r') {
|
||||
this->m_error = { lineNumber, "Invalid character literal" };
|
||||
return { ResultLexicalError, { } };
|
||||
return { };
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,7 +172,7 @@ namespace hex::lang {
|
||||
|
||||
if (offset >= code.length() || code[offset] != '\'') {
|
||||
this->m_error = { lineNumber, "Missing terminating ' after character literal" };
|
||||
return { ResultLexicalError, { } };
|
||||
return { };
|
||||
}
|
||||
|
||||
tokens.push_back({ .type = Token::Type::Integer, .integerToken = { .integer = character }, .lineNumber = lineNumber });
|
||||
@ -240,19 +240,19 @@ namespace hex::lang {
|
||||
|
||||
if (!integer.has_value()) {
|
||||
this->m_error = { lineNumber, "Invalid integer literal" };
|
||||
return { ResultLexicalError, {}};
|
||||
return { };
|
||||
}
|
||||
|
||||
tokens.push_back({ .type = Token::Type::Integer, .integerToken = { .integer = integer.value() }, .lineNumber = lineNumber });
|
||||
offset += (end - &code[offset]);
|
||||
} else {
|
||||
this->m_error = { lineNumber, "Unknown token" };
|
||||
return { ResultLexicalError, {} };
|
||||
return { };
|
||||
}
|
||||
}
|
||||
|
||||
tokens.push_back({ .type = Token::Type::EndOfProgram, .lineNumber = lineNumber });
|
||||
|
||||
return { ResultSuccess, tokens };
|
||||
return tokens;
|
||||
}
|
||||
}
|
@ -649,15 +649,15 @@ namespace hex::lang {
|
||||
return program;
|
||||
}
|
||||
|
||||
std::pair<Result, std::vector<ASTNode*>> Parser::parse(const std::vector<Token> &tokens) {
|
||||
std::optional<std::vector<ASTNode*>> Parser::parse(const std::vector<Token> &tokens) {
|
||||
auto currentToken = tokens.begin();
|
||||
|
||||
auto program = parseTillToken(currentToken, Token::Type::EndOfProgram);
|
||||
|
||||
if (program.empty() || currentToken != tokens.end())
|
||||
return { ResultParseError, { } };
|
||||
return { };
|
||||
|
||||
return { ResultSuccess, program };
|
||||
return program;
|
||||
}
|
||||
|
||||
}
|
@ -6,7 +6,7 @@ namespace hex::lang {
|
||||
|
||||
}
|
||||
|
||||
std::pair<Result, std::string> Preprocessor::preprocess(const std::string& code, bool initialRun) {
|
||||
std::optional<std::string> Preprocessor::preprocess(const std::string& code, bool initialRun) {
|
||||
u32 offset = 0;
|
||||
u32 lineNumber = 1;
|
||||
|
||||
@ -29,7 +29,7 @@ namespace hex::lang {
|
||||
offset += 1;
|
||||
|
||||
if (code[offset] != '<' && code[offset] != '"')
|
||||
return { ResultPreprocessingError, "" };
|
||||
return { };
|
||||
|
||||
char endChar = code[offset];
|
||||
if (endChar == '<') endChar = '>';
|
||||
@ -42,7 +42,7 @@ namespace hex::lang {
|
||||
offset += 1;
|
||||
|
||||
if (offset >= code.length())
|
||||
return { ResultPreprocessingError, "" };
|
||||
return { };
|
||||
}
|
||||
offset += 1;
|
||||
|
||||
@ -51,7 +51,7 @@ namespace hex::lang {
|
||||
|
||||
FILE *file = fopen(includeFile.c_str(), "r");
|
||||
if (file == nullptr)
|
||||
return { ResultPreprocessingError, "" };
|
||||
return { };
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t size = ftell(file);
|
||||
@ -61,11 +61,11 @@ namespace hex::lang {
|
||||
fread(buffer, size, 1, file);
|
||||
buffer[size] = 0x00;
|
||||
|
||||
auto [result, preprocessedInclude] = this->preprocess(buffer, false);
|
||||
if (result.failed())
|
||||
return { ResultPreprocessingError, "" };
|
||||
auto preprocessedInclude = this->preprocess(buffer, false);
|
||||
if (!preprocessedInclude.has_value())
|
||||
return { };
|
||||
|
||||
output += preprocessedInclude;
|
||||
output += preprocessedInclude.value();
|
||||
|
||||
delete[] buffer;
|
||||
|
||||
@ -81,7 +81,7 @@ namespace hex::lang {
|
||||
defineName += code[offset];
|
||||
|
||||
if (offset >= code.length() || code[offset] == '\n' || code[offset] == '\r')
|
||||
return { ResultPreprocessingError, "" };
|
||||
return { };
|
||||
offset += 1;
|
||||
}
|
||||
|
||||
@ -91,14 +91,14 @@ namespace hex::lang {
|
||||
std::string replaceValue;
|
||||
while (code[offset] != '\n' && code[offset] != '\r') {
|
||||
if (offset >= code.length())
|
||||
return { ResultPreprocessingError, "" };
|
||||
return { };
|
||||
|
||||
replaceValue += code[offset];
|
||||
offset += 1;
|
||||
}
|
||||
|
||||
if (replaceValue.empty())
|
||||
return { ResultPreprocessingError, "" };
|
||||
return { };
|
||||
|
||||
this->m_defines.emplace(defineName, replaceValue);
|
||||
} else if (code.substr(offset, 6) == "pragma") {
|
||||
@ -112,7 +112,7 @@ namespace hex::lang {
|
||||
pragmaKey += code[offset];
|
||||
|
||||
if (offset >= code.length() || code[offset] == '\n' || code[offset] == '\r')
|
||||
return { ResultPreprocessingError, "" };
|
||||
return { };
|
||||
|
||||
offset += 1;
|
||||
}
|
||||
@ -123,18 +123,18 @@ namespace hex::lang {
|
||||
std::string pragmaValue;
|
||||
while (code[offset] != '\n' && code[offset] != '\r') {
|
||||
if (offset >= code.length())
|
||||
return { ResultPreprocessingError, "" };
|
||||
return { };
|
||||
|
||||
pragmaValue += code[offset];
|
||||
offset += 1;
|
||||
}
|
||||
|
||||
if (pragmaValue.empty())
|
||||
return { ResultPreprocessingError, "" };
|
||||
return { };
|
||||
|
||||
this->m_pragmas.emplace(pragmaKey, pragmaValue);
|
||||
} else
|
||||
return { ResultPreprocessingError, "" };
|
||||
return { };
|
||||
}
|
||||
|
||||
if (code[offset] == '\n')
|
||||
@ -158,13 +158,13 @@ namespace hex::lang {
|
||||
for (const auto &[type, value] : this->m_pragmas) {
|
||||
if (this->m_pragmaHandlers.contains(type)) {
|
||||
if (!this->m_pragmaHandlers[type](value))
|
||||
return { ResultPreprocessingError, { } };
|
||||
return { };
|
||||
} else
|
||||
return { ResultPreprocessingError, { } };
|
||||
return { };
|
||||
}
|
||||
}
|
||||
|
||||
return { ResultSuccess, output };
|
||||
return output;
|
||||
}
|
||||
|
||||
void Preprocessor::addPragmaHandler(std::string pragmaType, std::function<bool(std::string)> function) {
|
||||
|
@ -39,7 +39,7 @@ namespace hex {
|
||||
View::unsubscribeEvent(Events::ProjectFileStore);
|
||||
}
|
||||
|
||||
void ViewBookmarks::createView() {
|
||||
void ViewBookmarks::drawContent() {
|
||||
if (ImGui::Begin("Bookmarks", &this->getWindowOpenState())) {
|
||||
if (ImGui::BeginChild("##scrolling")) {
|
||||
|
||||
@ -107,7 +107,7 @@ namespace hex {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ViewBookmarks::createMenu() {
|
||||
void ViewBookmarks::drawMenu() {
|
||||
|
||||
}
|
||||
|
||||
|
@ -17,7 +17,7 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
void ViewCommandPalette::createView() {
|
||||
void ViewCommandPalette::drawContent() {
|
||||
|
||||
auto windowPos = View::getWindowPosition();
|
||||
auto windowSize = View::getWindowSize();
|
||||
@ -54,7 +54,7 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
void ViewCommandPalette::createMenu() {
|
||||
void ViewCommandPalette::drawMenu() {
|
||||
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ namespace hex {
|
||||
View::unsubscribeEvent(Events::RegionSelected);
|
||||
}
|
||||
|
||||
void ViewDataInspector::createView() {
|
||||
void ViewDataInspector::drawContent() {
|
||||
if (this->m_shouldInvalidate) {
|
||||
this->m_shouldInvalidate = false;
|
||||
|
||||
@ -165,7 +165,7 @@ namespace hex {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ViewDataInspector::createMenu() {
|
||||
void ViewDataInspector::drawMenu() {
|
||||
|
||||
}
|
||||
|
||||
|
@ -29,7 +29,7 @@ namespace hex {
|
||||
View::unsubscribeEvent(Events::RegionSelected);
|
||||
}
|
||||
|
||||
void ViewDisassembler::createView() {
|
||||
void ViewDisassembler::drawContent() {
|
||||
if (this->m_shouldInvalidate) {
|
||||
this->m_disassembly.clear();
|
||||
|
||||
@ -282,7 +282,7 @@ namespace hex {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ViewDisassembler::createMenu() {
|
||||
void ViewDisassembler::drawMenu() {
|
||||
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ namespace hex {
|
||||
snprintf(buffer + 8 * i, bufferSize - 8 * i, "%08X", hex::changeEndianess(dataArray[i], std::endian::big));
|
||||
}
|
||||
|
||||
void ViewHashes::createView() {
|
||||
void ViewHashes::drawContent() {
|
||||
if (ImGui::Begin("Hashing", &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
|
||||
ImGui::BeginChild("##scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav);
|
||||
|
||||
@ -240,7 +240,7 @@ namespace hex {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ViewHashes::createMenu() {
|
||||
void ViewHashes::drawMenu() {
|
||||
|
||||
}
|
||||
|
||||
|
@ -275,13 +275,13 @@ namespace hex {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ViewHelp::createView() {
|
||||
void ViewHelp::drawContent() {
|
||||
this->drawAboutPopup();
|
||||
this->drawPatternHelpPopup();
|
||||
this->drawMathEvaluatorHelp();
|
||||
}
|
||||
|
||||
void ViewHelp::createMenu() {
|
||||
void ViewHelp::drawMenu() {
|
||||
if (ImGui::BeginMenu("Help")) {
|
||||
if (ImGui::MenuItem("About", "")) {
|
||||
View::doLater([] { ImGui::OpenPopup("About"); });
|
||||
|
@ -101,7 +101,7 @@ namespace hex {
|
||||
this->m_dataProvider = nullptr;
|
||||
}
|
||||
|
||||
void ViewHexEditor::createView() {
|
||||
void ViewHexEditor::drawContent() {
|
||||
size_t dataSize = (this->m_dataProvider == nullptr || !this->m_dataProvider->isReadable()) ? 0x00 : this->m_dataProvider->getSize();
|
||||
|
||||
this->m_memoryEditor.DrawWindow("Hex Editor", &this->getWindowOpenState(), this, dataSize, dataSize == 0 ? 0x00 : this->m_dataProvider->getBaseAddress());
|
||||
@ -266,7 +266,7 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
void ViewHexEditor::createMenu() {
|
||||
void ViewHexEditor::drawMenu() {
|
||||
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
if (ImGui::MenuItem("Open File...", "CTRL + O")) {
|
||||
|
@ -46,7 +46,7 @@ namespace hex {
|
||||
return entropy / 8;
|
||||
}
|
||||
|
||||
void ViewInformation::createView() {
|
||||
void ViewInformation::drawContent() {
|
||||
if (ImGui::Begin("Data Information", &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
|
||||
ImGui::BeginChild("##scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav);
|
||||
|
||||
@ -188,7 +188,7 @@ namespace hex {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ViewInformation::createMenu() {
|
||||
void ViewInformation::drawMenu() {
|
||||
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ namespace hex {
|
||||
View::unsubscribeEvent(Events::ProjectFileLoad);
|
||||
}
|
||||
|
||||
void ViewPatches::createView() {
|
||||
void ViewPatches::drawContent() {
|
||||
if (ImGui::Begin("Patches", &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
|
||||
|
||||
if (this->m_dataProvider != nullptr && this->m_dataProvider->isReadable()) {
|
||||
@ -84,7 +84,7 @@ namespace hex {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ViewPatches::createMenu() {
|
||||
void ViewPatches::drawMenu() {
|
||||
|
||||
}
|
||||
|
||||
|
@ -167,7 +167,7 @@ namespace hex {
|
||||
View::unsubscribeEvent(Events::ProjectFileLoad);
|
||||
}
|
||||
|
||||
void ViewPattern::createMenu() {
|
||||
void ViewPattern::drawMenu() {
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
if (ImGui::MenuItem("Load pattern...")) {
|
||||
View::doLater([]{ ImGui::OpenPopup("Open Hex Pattern"); });
|
||||
@ -176,7 +176,7 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
void ViewPattern::createView() {
|
||||
void ViewPattern::drawContent() {
|
||||
if (ImGui::Begin("Pattern", &this->getWindowOpenState(), ImGuiWindowFlags_None | ImGuiWindowFlags_NoCollapse)) {
|
||||
if (this->m_dataProvider != nullptr && this->m_dataProvider->isAvailable()) {
|
||||
this->m_textEditor.Render("Pattern");
|
||||
@ -279,43 +279,43 @@ namespace hex {
|
||||
});
|
||||
preprocessor.addDefaultPragmaHandlers();
|
||||
|
||||
auto [preprocessingResult, preprocesedCode] = preprocessor.preprocess(buffer);
|
||||
if (preprocessingResult.failed()) {
|
||||
auto preprocesedCode = preprocessor.preprocess(buffer);
|
||||
if (!preprocesedCode.has_value()) {
|
||||
this->m_textEditor.SetErrorMarkers({ preprocessor.getError() });
|
||||
return;
|
||||
}
|
||||
|
||||
hex::lang::Lexer lexer;
|
||||
auto [lexResult, tokens] = lexer.lex(preprocesedCode);
|
||||
if (lexResult.failed()) {
|
||||
auto tokens = lexer.lex(preprocesedCode.value());
|
||||
if (!tokens.has_value()) {
|
||||
this->m_textEditor.SetErrorMarkers({ lexer.getError() });
|
||||
return;
|
||||
}
|
||||
|
||||
hex::lang::Parser parser;
|
||||
auto [parseResult, ast] = parser.parse(tokens);
|
||||
if (parseResult.failed()) {
|
||||
auto ast = parser.parse(tokens.value());
|
||||
if (!ast.has_value()) {
|
||||
this->m_textEditor.SetErrorMarkers({ parser.getError() });
|
||||
printf("%d %s\n", parser.getError().first, parser.getError().second.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
hex::ScopeExit deleteAst([&ast=ast]{ for(auto &node : ast) delete node; });
|
||||
hex::ScopeExit deleteAst([&ast]{ for(auto &node : ast.value()) delete node; });
|
||||
|
||||
hex::lang::Validator validator;
|
||||
auto validatorResult = validator.validate(ast);
|
||||
auto validatorResult = validator.validate(ast.value());
|
||||
if (!validatorResult) {
|
||||
this->m_textEditor.SetErrorMarkers({ validator.getError() });
|
||||
return;
|
||||
}
|
||||
|
||||
hex::lang::Evaluator evaluator(this->m_dataProvider, defaultDataEndianess);
|
||||
auto [evaluateResult, patternData] = evaluator.evaluate(ast);
|
||||
if (evaluateResult.failed()) {
|
||||
auto patternData = evaluator.evaluate(ast.value());
|
||||
if (!patternData.has_value()) {
|
||||
this->m_textEditor.SetErrorMarkers({ evaluator.getError() });
|
||||
return;
|
||||
}
|
||||
this->m_patternData = patternData;
|
||||
this->m_patternData = patternData.value();
|
||||
|
||||
this->postEvent(Events::PatternChanged);
|
||||
}
|
||||
|
@ -48,7 +48,7 @@ namespace hex {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ViewPatternData::createView() {
|
||||
void ViewPatternData::drawContent() {
|
||||
if (ImGui::Begin("Pattern Data", &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
|
||||
if (this->m_dataProvider != nullptr && this->m_dataProvider->isReadable()) {
|
||||
|
||||
@ -69,7 +69,7 @@ namespace hex {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ViewPatternData::createMenu() {
|
||||
void ViewPatternData::drawMenu() {
|
||||
|
||||
}
|
||||
|
||||
|
@ -46,7 +46,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
|
||||
void ViewStrings::createView() {
|
||||
void ViewStrings::drawContent() {
|
||||
if (this->m_shouldInvalidate) {
|
||||
this->m_shouldInvalidate = false;
|
||||
|
||||
@ -181,7 +181,7 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
void ViewStrings::createMenu() {
|
||||
void ViewStrings::drawMenu() {
|
||||
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include <optional>
|
||||
|
||||
#include "providers/provider.hpp"
|
||||
#include "helpers/plugin_handler.hpp"
|
||||
#include "helpers/utils.hpp"
|
||||
|
||||
#include <llvm/Demangle/Demangle.h>
|
||||
@ -291,7 +292,7 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
void ViewTools::createView() {
|
||||
void ViewTools::drawContent() {
|
||||
if (ImGui::Begin("Tools", &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
|
||||
|
||||
this->drawDemangler();
|
||||
@ -300,11 +301,14 @@ namespace hex {
|
||||
this->drawMathEvaluator();
|
||||
this->drawColorPicker();
|
||||
|
||||
for (const auto& plugin : PluginHandler::getPlugins())
|
||||
plugin.drawToolsEntry();
|
||||
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void ViewTools::createMenu() {
|
||||
void ViewTools::drawMenu() {
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "hex.hpp"
|
||||
#include "window.hpp"
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
|
||||
@ -10,6 +11,8 @@
|
||||
#include "imgui_impl_opengl3.h"
|
||||
#include "imgui_freetype.h"
|
||||
|
||||
#include "helpers/plugin_handler.hpp"
|
||||
|
||||
#include <glad/glad.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
@ -47,11 +50,13 @@ namespace hex {
|
||||
Window::Window() {
|
||||
this->initGLFW();
|
||||
this->initImGui();
|
||||
this->initPlugins();
|
||||
}
|
||||
|
||||
Window::~Window() {
|
||||
this->deinitImGui();
|
||||
this->deinitGLFW();
|
||||
this->deinitPlugins();
|
||||
|
||||
for (auto &view : this->m_views)
|
||||
delete view;
|
||||
@ -61,6 +66,9 @@ namespace hex {
|
||||
while (!glfwWindowShouldClose(this->m_window)) {
|
||||
this->frameBegin();
|
||||
|
||||
for (const auto &plugin : PluginHandler::getPlugins())
|
||||
plugin.setImGuiContext(ImGui::GetCurrentContext());
|
||||
|
||||
for (const auto &call : View::getDeferedCalls())
|
||||
call();
|
||||
View::getDeferedCalls().clear();
|
||||
@ -70,7 +78,15 @@ namespace hex {
|
||||
continue;
|
||||
|
||||
ImGui::SetNextWindowSizeConstraints(view->getMinSize(), view->getMaxSize());
|
||||
view->createView();
|
||||
view->drawContent();
|
||||
}
|
||||
|
||||
for (auto &view : this->m_pluginViews) {
|
||||
if (!view->getWindowOpenState())
|
||||
continue;
|
||||
|
||||
ImGui::SetNextWindowSizeConstraints(view->getMinSize(), view->getMaxSize());
|
||||
view->drawContent();
|
||||
}
|
||||
|
||||
View::drawCommonInterfaces();
|
||||
@ -145,11 +161,25 @@ namespace hex {
|
||||
if (view->hasViewMenuItemEntry())
|
||||
ImGui::MenuItem((view->getName() + " View").c_str(), "", &view->getWindowOpenState());
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Plugin Views")) {
|
||||
for (auto &view : this->m_pluginViews) {
|
||||
if (view->hasViewMenuItemEntry())
|
||||
ImGui::MenuItem((view->getName() + " View").c_str(), "", &view->getWindowOpenState());
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
for (auto &view : this->m_views) {
|
||||
view->createMenu();
|
||||
view->drawMenu();
|
||||
}
|
||||
|
||||
for (auto &view : this->m_pluginViews) {
|
||||
view->drawMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("View")) {
|
||||
@ -173,12 +203,24 @@ namespace hex {
|
||||
}
|
||||
|
||||
if (auto &[key, mods] = Window::s_currShortcut; key != -1) {
|
||||
bool shortcutHandled = false;
|
||||
for (auto &view : this->m_pluginViews) {
|
||||
if (view->getWindowOpenState()) {
|
||||
if (view->handleShortcut(key, mods)) {
|
||||
shortcutHandled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!shortcutHandled) {
|
||||
for (auto &view : this->m_views) {
|
||||
if (view->getWindowOpenState()) {
|
||||
if (view->handleShortcut(key, mods))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Window::s_currShortcut = { -1, -1 };
|
||||
}
|
||||
@ -334,6 +376,15 @@ namespace hex {
|
||||
ImGui_ImplOpenGL3_Init("#version 150");
|
||||
}
|
||||
|
||||
void Window::initPlugins() {
|
||||
PluginHandler::load((std::filesystem::path(mainArgv[0]).parent_path() / "plugins").string());
|
||||
|
||||
for (const auto &plugin : PluginHandler::getPlugins()) {
|
||||
if (auto view = plugin.createView(); view != nullptr)
|
||||
this->m_pluginViews.push_back(view);
|
||||
}
|
||||
}
|
||||
|
||||
void Window::deinitGLFW() {
|
||||
glfwDestroyWindow(this->m_window);
|
||||
glfwTerminate();
|
||||
@ -345,4 +396,11 @@ namespace hex {
|
||||
ImGui::DestroyContext();
|
||||
}
|
||||
|
||||
void Window::deinitPlugins() {
|
||||
PluginHandler::unload();
|
||||
|
||||
for (auto &view : this->m_pluginViews)
|
||||
delete view;
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user