From dbbc5251742515a3bf0e1c4d899cc4039bb2d645 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Tue, 22 Dec 2020 18:10:01 +0100 Subject: [PATCH] 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 --- .github/workflows/build.yml | 1 + CMakeLists.txt | 48 +++---- dist/get_deps_msys2.sh | 3 +- external/ImGui/CMakeLists.txt | 35 +++++ .../ImGui/include/Dirent/dirent.h | 0 .../ImGui/include/ImGuiFileBrowser.h | 0 {libs => external}/ImGui/include/TextEditor.h | 0 {libs => external}/ImGui/include/imconfig.h | 0 {libs => external}/ImGui/include/imgui.h | 0 .../ImGui/include/imgui_freetype.h | 0 .../ImGui/include/imgui_impl_glfw.h | 0 .../ImGui/include/imgui_impl_opengl3.h | 0 .../ImGui/include/imgui_internal.h | 0 .../ImGui/include/imgui_memory_editor.h | 0 .../ImGui/include/imstb_rectpack.h | 0 .../ImGui/include/imstb_textedit.h | 0 .../ImGui/include/imstb_truetype.h | 0 .../ImGui/source/ImGuiFileBrowser.cpp | 0 .../ImGui/source/TextEditor.cpp | 0 {libs => external}/ImGui/source/imgui.cpp | 0 .../ImGui/source/imgui_demo.cpp | 0 .../ImGui/source/imgui_draw.cpp | 0 .../ImGui/source/imgui_freetype.cpp | 0 .../ImGui/source/imgui_impl_glfw.cpp | 0 .../ImGui/source/imgui_impl_opengl3.cpp | 0 .../ImGui/source/imgui_widgets.cpp | 0 external/glad/CMakeLists.txt | 11 ++ .../glad/include/KHR/khrplatform.h | 0 {libs => external}/glad/include/glad/glad.h | 0 {libs => external}/glad/source/glad.c | 0 include/helpers/event.hpp | 58 --------- include/helpers/plugin_handler.hpp | 48 +++++++ include/lang/evaluator.hpp | 2 +- include/lang/lexer.hpp | 3 +- include/lang/parser.hpp | 2 +- include/lang/preprocessor.hpp | 2 +- include/lang/result.hpp | 21 --- include/lang/results.hpp | 14 -- include/providers/provider.hpp | 69 ---------- include/views/view.hpp | 122 ------------------ include/views/view_bookmarks.hpp | 4 +- include/views/view_command_palette.hpp | 4 +- include/views/view_data_inspector.hpp | 4 +- include/views/view_disassembler.hpp | 4 +- include/views/view_hashes.hpp | 4 +- include/views/view_help.hpp | 4 +- include/views/view_hexeditor.hpp | 4 +- include/views/view_information.hpp | 4 +- include/views/view_patches.hpp | 4 +- include/views/view_pattern.hpp | 4 +- include/views/view_pattern_data.hpp | 4 +- include/views/view_strings.hpp | 4 +- include/views/view_tools.hpp | 4 +- include/window.hpp | 3 + plugins/example/CMakeLists.txt | 16 +++ plugins/example/source/plugin_example.cpp | 33 +++++ plugins/libimhex/CMakeLists.txt | 19 +++ plugins/libimhex/include/helpers/event.hpp | 41 ++++++ {include => plugins/libimhex/include}/hex.hpp | 10 +- .../libimhex/include/providers/provider.hpp | 49 +++++++ plugins/libimhex/include/views/view.hpp | 71 ++++++++++ plugins/libimhex/source/helpers/event.cpp | 25 ++++ .../libimhex/source/providers/provider.cpp | 66 ++++++++++ plugins/libimhex/source/views/view.cpp | 107 +++++++++++++++ source/helpers/plugin_handler.cpp | 70 ++++++++++ source/lang/evaluator.cpp | 6 +- source/lang/lexer.cpp | 18 +-- source/lang/parser.cpp | 6 +- source/lang/preprocessor.cpp | 36 +++--- source/views/view_bookmarks.cpp | 4 +- source/views/view_command_palette.cpp | 4 +- source/views/view_data_inspector.cpp | 4 +- source/views/view_disassembler.cpp | 4 +- source/views/view_hashes.cpp | 4 +- source/views/view_help.cpp | 4 +- source/views/view_hexeditor.cpp | 4 +- source/views/view_information.cpp | 4 +- source/views/view_patches.cpp | 4 +- source/views/view_pattern.cpp | 26 ++-- source/views/view_pattern_data.cpp | 4 +- source/views/view_strings.cpp | 4 +- source/views/view_tools.cpp | 8 +- source/window.cpp | 68 +++++++++- 83 files changed, 791 insertions(+), 422 deletions(-) create mode 100644 external/ImGui/CMakeLists.txt rename {libs => external}/ImGui/include/Dirent/dirent.h (100%) rename {libs => external}/ImGui/include/ImGuiFileBrowser.h (100%) rename {libs => external}/ImGui/include/TextEditor.h (100%) rename {libs => external}/ImGui/include/imconfig.h (100%) rename {libs => external}/ImGui/include/imgui.h (100%) rename {libs => external}/ImGui/include/imgui_freetype.h (100%) rename {libs => external}/ImGui/include/imgui_impl_glfw.h (100%) rename {libs => external}/ImGui/include/imgui_impl_opengl3.h (100%) rename {libs => external}/ImGui/include/imgui_internal.h (100%) rename {libs => external}/ImGui/include/imgui_memory_editor.h (100%) rename {libs => external}/ImGui/include/imstb_rectpack.h (100%) rename {libs => external}/ImGui/include/imstb_textedit.h (100%) rename {libs => external}/ImGui/include/imstb_truetype.h (100%) rename {libs => external}/ImGui/source/ImGuiFileBrowser.cpp (100%) rename {libs => external}/ImGui/source/TextEditor.cpp (100%) rename {libs => external}/ImGui/source/imgui.cpp (100%) rename {libs => external}/ImGui/source/imgui_demo.cpp (100%) rename {libs => external}/ImGui/source/imgui_draw.cpp (100%) rename {libs => external}/ImGui/source/imgui_freetype.cpp (100%) rename {libs => external}/ImGui/source/imgui_impl_glfw.cpp (100%) rename {libs => external}/ImGui/source/imgui_impl_opengl3.cpp (100%) rename {libs => external}/ImGui/source/imgui_widgets.cpp (100%) create mode 100644 external/glad/CMakeLists.txt rename {libs => external}/glad/include/KHR/khrplatform.h (100%) rename {libs => external}/glad/include/glad/glad.h (100%) rename {libs => external}/glad/source/glad.c (100%) delete mode 100644 include/helpers/event.hpp create mode 100644 include/helpers/plugin_handler.hpp delete mode 100644 include/lang/result.hpp delete mode 100644 include/lang/results.hpp delete mode 100644 include/providers/provider.hpp delete mode 100644 include/views/view.hpp create mode 100644 plugins/example/CMakeLists.txt create mode 100644 plugins/example/source/plugin_example.cpp create mode 100644 plugins/libimhex/CMakeLists.txt create mode 100644 plugins/libimhex/include/helpers/event.hpp rename {include => plugins/libimhex/include}/hex.hpp (53%) create mode 100644 plugins/libimhex/include/providers/provider.hpp create mode 100644 plugins/libimhex/include/views/view.hpp create mode 100644 plugins/libimhex/source/helpers/event.cpp create mode 100644 plugins/libimhex/source/providers/provider.cpp create mode 100644 plugins/libimhex/source/views/view.cpp create mode 100644 source/helpers/plugin_handler.cpp diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b3e53c3a2..4af460d8f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 9be490a6d..292eeb494 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) diff --git a/dist/get_deps_msys2.sh b/dist/get_deps_msys2.sh index 0a5858ece..bf0a24780 100755 --- a/dist/get_deps_msys2.sh +++ b/dist/get_deps_msys2.sh @@ -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 diff --git a/external/ImGui/CMakeLists.txt b/external/ImGui/CMakeLists.txt new file mode 100644 index 000000000..c7bd42328 --- /dev/null +++ b/external/ImGui/CMakeLists.txt @@ -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() diff --git a/libs/ImGui/include/Dirent/dirent.h b/external/ImGui/include/Dirent/dirent.h similarity index 100% rename from libs/ImGui/include/Dirent/dirent.h rename to external/ImGui/include/Dirent/dirent.h diff --git a/libs/ImGui/include/ImGuiFileBrowser.h b/external/ImGui/include/ImGuiFileBrowser.h similarity index 100% rename from libs/ImGui/include/ImGuiFileBrowser.h rename to external/ImGui/include/ImGuiFileBrowser.h diff --git a/libs/ImGui/include/TextEditor.h b/external/ImGui/include/TextEditor.h similarity index 100% rename from libs/ImGui/include/TextEditor.h rename to external/ImGui/include/TextEditor.h diff --git a/libs/ImGui/include/imconfig.h b/external/ImGui/include/imconfig.h similarity index 100% rename from libs/ImGui/include/imconfig.h rename to external/ImGui/include/imconfig.h diff --git a/libs/ImGui/include/imgui.h b/external/ImGui/include/imgui.h similarity index 100% rename from libs/ImGui/include/imgui.h rename to external/ImGui/include/imgui.h diff --git a/libs/ImGui/include/imgui_freetype.h b/external/ImGui/include/imgui_freetype.h similarity index 100% rename from libs/ImGui/include/imgui_freetype.h rename to external/ImGui/include/imgui_freetype.h diff --git a/libs/ImGui/include/imgui_impl_glfw.h b/external/ImGui/include/imgui_impl_glfw.h similarity index 100% rename from libs/ImGui/include/imgui_impl_glfw.h rename to external/ImGui/include/imgui_impl_glfw.h diff --git a/libs/ImGui/include/imgui_impl_opengl3.h b/external/ImGui/include/imgui_impl_opengl3.h similarity index 100% rename from libs/ImGui/include/imgui_impl_opengl3.h rename to external/ImGui/include/imgui_impl_opengl3.h diff --git a/libs/ImGui/include/imgui_internal.h b/external/ImGui/include/imgui_internal.h similarity index 100% rename from libs/ImGui/include/imgui_internal.h rename to external/ImGui/include/imgui_internal.h diff --git a/libs/ImGui/include/imgui_memory_editor.h b/external/ImGui/include/imgui_memory_editor.h similarity index 100% rename from libs/ImGui/include/imgui_memory_editor.h rename to external/ImGui/include/imgui_memory_editor.h diff --git a/libs/ImGui/include/imstb_rectpack.h b/external/ImGui/include/imstb_rectpack.h similarity index 100% rename from libs/ImGui/include/imstb_rectpack.h rename to external/ImGui/include/imstb_rectpack.h diff --git a/libs/ImGui/include/imstb_textedit.h b/external/ImGui/include/imstb_textedit.h similarity index 100% rename from libs/ImGui/include/imstb_textedit.h rename to external/ImGui/include/imstb_textedit.h diff --git a/libs/ImGui/include/imstb_truetype.h b/external/ImGui/include/imstb_truetype.h similarity index 100% rename from libs/ImGui/include/imstb_truetype.h rename to external/ImGui/include/imstb_truetype.h diff --git a/libs/ImGui/source/ImGuiFileBrowser.cpp b/external/ImGui/source/ImGuiFileBrowser.cpp similarity index 100% rename from libs/ImGui/source/ImGuiFileBrowser.cpp rename to external/ImGui/source/ImGuiFileBrowser.cpp diff --git a/libs/ImGui/source/TextEditor.cpp b/external/ImGui/source/TextEditor.cpp similarity index 100% rename from libs/ImGui/source/TextEditor.cpp rename to external/ImGui/source/TextEditor.cpp diff --git a/libs/ImGui/source/imgui.cpp b/external/ImGui/source/imgui.cpp similarity index 100% rename from libs/ImGui/source/imgui.cpp rename to external/ImGui/source/imgui.cpp diff --git a/libs/ImGui/source/imgui_demo.cpp b/external/ImGui/source/imgui_demo.cpp similarity index 100% rename from libs/ImGui/source/imgui_demo.cpp rename to external/ImGui/source/imgui_demo.cpp diff --git a/libs/ImGui/source/imgui_draw.cpp b/external/ImGui/source/imgui_draw.cpp similarity index 100% rename from libs/ImGui/source/imgui_draw.cpp rename to external/ImGui/source/imgui_draw.cpp diff --git a/libs/ImGui/source/imgui_freetype.cpp b/external/ImGui/source/imgui_freetype.cpp similarity index 100% rename from libs/ImGui/source/imgui_freetype.cpp rename to external/ImGui/source/imgui_freetype.cpp diff --git a/libs/ImGui/source/imgui_impl_glfw.cpp b/external/ImGui/source/imgui_impl_glfw.cpp similarity index 100% rename from libs/ImGui/source/imgui_impl_glfw.cpp rename to external/ImGui/source/imgui_impl_glfw.cpp diff --git a/libs/ImGui/source/imgui_impl_opengl3.cpp b/external/ImGui/source/imgui_impl_opengl3.cpp similarity index 100% rename from libs/ImGui/source/imgui_impl_opengl3.cpp rename to external/ImGui/source/imgui_impl_opengl3.cpp diff --git a/libs/ImGui/source/imgui_widgets.cpp b/external/ImGui/source/imgui_widgets.cpp similarity index 100% rename from libs/ImGui/source/imgui_widgets.cpp rename to external/ImGui/source/imgui_widgets.cpp diff --git a/external/glad/CMakeLists.txt b/external/glad/CMakeLists.txt new file mode 100644 index 000000000..19320959e --- /dev/null +++ b/external/glad/CMakeLists.txt @@ -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) \ No newline at end of file diff --git a/libs/glad/include/KHR/khrplatform.h b/external/glad/include/KHR/khrplatform.h similarity index 100% rename from libs/glad/include/KHR/khrplatform.h rename to external/glad/include/KHR/khrplatform.h diff --git a/libs/glad/include/glad/glad.h b/external/glad/include/glad/glad.h similarity index 100% rename from libs/glad/include/glad/glad.h rename to external/glad/include/glad/glad.h diff --git a/libs/glad/source/glad.c b/external/glad/source/glad.c similarity index 100% rename from libs/glad/source/glad.c rename to external/glad/source/glad.c diff --git a/include/helpers/event.hpp b/include/helpers/event.hpp deleted file mode 100644 index b6d016eba..000000000 --- a/include/helpers/event.hpp +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include -#include - -namespace hex { - - enum class Events { - FileLoaded, - DataChanged, - PatternChanged, - FileDropped, - WindowClosing, - RegionSelected, - - SelectionChangeRequest, - - AddBookmark, - AppendPatternLanguageCode, - - ProjectFileStore, - ProjectFileLoad - }; - - struct EventHandler { - void *owner; - Events eventType; - std::function 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 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 m_eventHandlers; - }; - -} \ No newline at end of file diff --git a/include/helpers/plugin_handler.hpp b/include/helpers/plugin_handler.hpp new file mode 100644 index 000000000..6a547457d --- /dev/null +++ b/include/helpers/plugin_handler.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include "views/view.hpp" + +#include + +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 s_plugins; + }; + +} \ No newline at end of file diff --git a/include/lang/evaluator.hpp b/include/lang/evaluator.hpp index 78f5b3b91..16bac1cfa 100644 --- a/include/lang/evaluator.hpp +++ b/include/lang/evaluator.hpp @@ -17,7 +17,7 @@ namespace hex::lang { public: Evaluator(prv::Provider* &provider, std::endian defaultDataEndianess); - std::pair> evaluate(const std::vector& ast); + std::optional> evaluate(const std::vector& ast); const std::pair& getError() { return this->m_error; } diff --git a/include/lang/lexer.hpp b/include/lang/lexer.hpp index c78ec7a60..cef75995b 100644 --- a/include/lang/lexer.hpp +++ b/include/lang/lexer.hpp @@ -4,6 +4,7 @@ #include "token.hpp" +#include #include #include @@ -13,7 +14,7 @@ namespace hex::lang { public: Lexer(); - std::pair> lex(const std::string& code); + std::optional> lex(const std::string& code); const std::pair& getError() { return this->m_error; } diff --git a/include/lang/parser.hpp b/include/lang/parser.hpp index 84f5f68ee..f24596631 100644 --- a/include/lang/parser.hpp +++ b/include/lang/parser.hpp @@ -14,7 +14,7 @@ namespace hex::lang { using TokenIter = std::vector::const_iterator; - std::pair> parse(const std::vector &tokens); + std::optional> parse(const std::vector &tokens); const std::pair& getError() { return this->m_error; } diff --git a/include/lang/preprocessor.hpp b/include/lang/preprocessor.hpp index 13381582a..e137517f5 100644 --- a/include/lang/preprocessor.hpp +++ b/include/lang/preprocessor.hpp @@ -16,7 +16,7 @@ namespace hex::lang { public: Preprocessor(); - std::pair preprocess(const std::string& code, bool initialRun = true); + std::optional preprocess(const std::string& code, bool initialRun = true); void addPragmaHandler(std::string pragmaType, std::function function); void addDefaultPragmaHandlers(); diff --git a/include/lang/result.hpp b/include/lang/result.hpp deleted file mode 100644 index c4c310006..000000000 --- a/include/lang/result.hpp +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include - -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; - }; - -} \ No newline at end of file diff --git a/include/lang/results.hpp b/include/lang/results.hpp deleted file mode 100644 index 705e0836e..000000000 --- a/include/lang/results.hpp +++ /dev/null @@ -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); - -} \ No newline at end of file diff --git a/include/providers/provider.hpp b/include/providers/provider.hpp deleted file mode 100644 index 6e146ff89..000000000 --- a/include/providers/provider.hpp +++ /dev/null @@ -1,69 +0,0 @@ -#pragma once - -#include - -#include -#include -#include -#include -#include - -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& 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 getPageOfAddress(u64 address) { - u32 page = std::floor(address / double(PageSize)); - - if (page >= this->getPageCount()) - return { }; - - return page; - } - - virtual std::vector> getDataInformation() = 0; - - protected: - u32 m_currPage = 0; - - std::vector> m_patches; - }; - -} \ No newline at end of file diff --git a/include/views/view.hpp b/include/views/view.hpp deleted file mode 100644 index 96171dca2..000000000 --- a/include/views/view.hpp +++ /dev/null @@ -1,122 +0,0 @@ -#pragma once - -#include - -#include "imgui.h" - -#include "helpers/event.hpp" - -#include -#include -#include - - -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>& 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 callback) { - View::s_eventManager.subscribe(eventType, this, callback); - } - - void unsubscribeEvent(Events eventType) { - View::s_eventManager.unsubscribe(eventType, this); - } - - void doLater(std::function &&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> 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(); - } - -} \ No newline at end of file diff --git a/include/views/view_bookmarks.hpp b/include/views/view_bookmarks.hpp index 34d9a0ee1..0eed7e7aa 100644 --- a/include/views/view_bookmarks.hpp +++ b/include/views/view_bookmarks.hpp @@ -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; diff --git a/include/views/view_command_palette.hpp b/include/views/view_command_palette.hpp index 761a750a8..89fc67584 100644 --- a/include/views/view_command_palette.hpp +++ b/include/views/view_command_palette.hpp @@ -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; diff --git a/include/views/view_data_inspector.hpp b/include/views/view_data_inspector.hpp index def75e460..e68ec5cf3 100644 --- a/include/views/view_data_inspector.hpp +++ b/include/views/view_data_inspector.hpp @@ -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; diff --git a/include/views/view_disassembler.hpp b/include/views/view_disassembler.hpp index a6874e681..97cdf8027 100644 --- a/include/views/view_disassembler.hpp +++ b/include/views/view_disassembler.hpp @@ -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; diff --git a/include/views/view_hashes.hpp b/include/views/view_hashes.hpp index 282e4b509..eebc9ab98 100644 --- a/include/views/view_hashes.hpp +++ b/include/views/view_hashes.hpp @@ -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; diff --git a/include/views/view_help.hpp b/include/views/view_help.hpp index e80614d78..3bfaa93cd 100644 --- a/include/views/view_help.hpp +++ b/include/views/view_help.hpp @@ -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; } diff --git a/include/views/view_hexeditor.hpp b/include/views/view_hexeditor.hpp index c386b6cfa..80ef550d2 100644 --- a/include/views/view_hexeditor.hpp +++ b/include/views/view_hexeditor.hpp @@ -23,8 +23,8 @@ namespace hex { ViewHexEditor(prv::Provider* &dataProvider, std::vector &patternData); ~ViewHexEditor() override; - void createView() override; - void createMenu() override; + void drawContent() override; + void drawMenu() override; bool handleShortcut(int key, int mods) override; private: diff --git a/include/views/view_information.hpp b/include/views/view_information.hpp index 0ef6c6760..82c13629a 100644 --- a/include/views/view_information.hpp +++ b/include/views/view_information.hpp @@ -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; diff --git a/include/views/view_patches.hpp b/include/views/view_patches.hpp index 931f20ed0..9804276e1 100644 --- a/include/views/view_patches.hpp +++ b/include/views/view_patches.hpp @@ -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; diff --git a/include/views/view_pattern.hpp b/include/views/view_pattern.hpp index 564a26b6c..3886f1cc6 100644 --- a/include/views/view_pattern.hpp +++ b/include/views/view_pattern.hpp @@ -20,8 +20,8 @@ namespace hex { explicit ViewPattern(prv::Provider* &dataProvider, std::vector &patternData); ~ViewPattern() override; - void createMenu() override; - void createView() override; + void drawMenu() override; + void drawContent() override; private: std::vector &m_patternData; diff --git a/include/views/view_pattern_data.hpp b/include/views/view_pattern_data.hpp index 11fa29f67..ff62e26f1 100644 --- a/include/views/view_pattern_data.hpp +++ b/include/views/view_pattern_data.hpp @@ -19,8 +19,8 @@ namespace hex { ViewPatternData(prv::Provider* &dataProvider, std::vector &patternData); ~ViewPatternData() override; - void createView() override; - void createMenu() override; + void drawContent() override; + void drawMenu() override; private: diff --git a/include/views/view_strings.hpp b/include/views/view_strings.hpp index 96d0f4633..267ac0964 100644 --- a/include/views/view_strings.hpp +++ b/include/views/view_strings.hpp @@ -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; diff --git a/include/views/view_tools.hpp b/include/views/view_tools.hpp index ac7ad2ca7..9a2a24561 100644 --- a/include/views/view_tools.hpp +++ b/include/views/view_tools.hpp @@ -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; diff --git a/include/window.hpp b/include/window.hpp index e23c55b82..a9de9ce45 100644 --- a/include/window.hpp +++ b/include/window.hpp @@ -39,11 +39,14 @@ namespace hex { void initGLFW(); void initImGui(); + void initPlugins(); void deinitGLFW(); void deinitImGui(); + void deinitPlugins(); GLFWwindow* m_window; std::vector m_views; + std::vector m_pluginViews; float m_globalScale = 1.0f, m_fontScale = 1.0f; bool m_fpsVisible = false; diff --git a/plugins/example/CMakeLists.txt b/plugins/example/CMakeLists.txt new file mode 100644 index 000000000..47df1ea4c --- /dev/null +++ b/plugins/example/CMakeLists.txt @@ -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) diff --git a/plugins/example/source/plugin_example.cpp b/plugins/example/source/plugin_example.cpp new file mode 100644 index 000000000..c2d142855 --- /dev/null +++ b/plugins/example/source/plugin_example.cpp @@ -0,0 +1,33 @@ +#include + +#include +#include + +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"); + } + } + +} + + diff --git a/plugins/libimhex/CMakeLists.txt b/plugins/libimhex/CMakeLists.txt new file mode 100644 index 000000000..295071afc --- /dev/null +++ b/plugins/libimhex/CMakeLists.txt @@ -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) diff --git a/plugins/libimhex/include/helpers/event.hpp b/plugins/libimhex/include/helpers/event.hpp new file mode 100644 index 000000000..5997a7137 --- /dev/null +++ b/plugins/libimhex/include/helpers/event.hpp @@ -0,0 +1,41 @@ +#pragma once + +#include +#include + +namespace hex { + + enum class Events { + FileLoaded, + DataChanged, + PatternChanged, + FileDropped, + WindowClosing, + RegionSelected, + + SelectionChangeRequest, + + AddBookmark, + AppendPatternLanguageCode, + + ProjectFileStore, + ProjectFileLoad + }; + + struct EventHandler { + void *owner; + Events eventType; + std::function callback; + }; + + class EventManager { + public: + void post(Events eventType, const void *userData); + void subscribe(Events eventType, void *owner, std::function callback); + void unsubscribe(Events eventType, void *sender); + + private: + std::vector m_eventHandlers; + }; + +} \ No newline at end of file diff --git a/include/hex.hpp b/plugins/libimhex/include/hex.hpp similarity index 53% rename from include/hex.hpp rename to plugins/libimhex/include/hex.hpp index f9d84ed64..8bd385608 100644 --- a/include/hex.hpp +++ b/plugins/libimhex/include/hex.hpp @@ -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 diff --git a/plugins/libimhex/include/providers/provider.hpp b/plugins/libimhex/include/providers/provider.hpp new file mode 100644 index 000000000..1fd548ab2 --- /dev/null +++ b/plugins/libimhex/include/providers/provider.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include + +#include +#include +#include +#include + +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& getPatches(); + void applyPatches(); + + u32 getPageCount(); + u32 getCurrentPage() const; + void setCurrentPage(u32 page); + + virtual size_t getBaseAddress(); + virtual size_t getSize(); + virtual std::optional getPageOfAddress(u64 address); + + virtual std::vector> getDataInformation() = 0; + + protected: + u32 m_currPage = 0; + + std::vector> m_patches; + }; + +} \ No newline at end of file diff --git a/plugins/libimhex/include/views/view.hpp b/plugins/libimhex/include/views/view.hpp new file mode 100644 index 000000000..f1602cfce --- /dev/null +++ b/plugins/libimhex/include/views/view.hpp @@ -0,0 +1,71 @@ +#pragma once + +#include + +#include "imgui.h" + +#include "helpers/event.hpp" + +#include +#include +#include + + +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>& 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 callback); + + void unsubscribeEvent(Events eventType); + + void doLater(std::function &&function); + + protected: + void confirmButtons(const char *textLeft, const char *textRight, std::function leftButtonFn, std::function rightButtonFn); + private: + std::string m_viewName; + bool m_windowOpen = false; + + static inline EventManager s_eventManager; + static inline std::vector> s_deferedCalls; + + static inline std::string s_errorMessage; + + static inline ImVec2 s_windowPos; + static inline ImVec2 s_windowSize; + }; + +} \ No newline at end of file diff --git a/plugins/libimhex/source/helpers/event.cpp b/plugins/libimhex/source/helpers/event.cpp new file mode 100644 index 000000000..5fa81d632 --- /dev/null +++ b/plugins/libimhex/source/helpers/event.cpp @@ -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 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; + }); + } + +} \ No newline at end of file diff --git a/plugins/libimhex/source/providers/provider.cpp b/plugins/libimhex/source/providers/provider.cpp new file mode 100644 index 000000000..1b202faaf --- /dev/null +++ b/plugins/libimhex/source/providers/provider.cpp @@ -0,0 +1,66 @@ +#include "providers/provider.hpp" + +#include + +#include +#include +#include +#include +#include + +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& 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 Provider::getPageOfAddress(u64 address) { + u32 page = std::floor(address / double(PageSize)); + + if (page >= this->getPageCount()) + return { }; + + return page; + } + +} \ No newline at end of file diff --git a/plugins/libimhex/source/views/view.cpp b/plugins/libimhex/source/views/view.cpp new file mode 100644 index 000000000..28bff617a --- /dev/null +++ b/plugins/libimhex/source/views/view.cpp @@ -0,0 +1,107 @@ +#include "views/view.hpp" + +#include "imgui.h" + +#include +#include +#include + +namespace hex { + + + View::View(std::string viewName) : m_viewName(viewName) { } + + void View::drawMenu() { } + bool View::handleShortcut(int key, int mods) { return false; } + + std::vector>& 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 callback) { + View::s_eventManager.subscribe(eventType, this, callback); + } + + void View::unsubscribeEvent(Events eventType) { + View::s_eventManager.unsubscribe(eventType, this); + } + + void View::doLater(std::function &&function) { + View::s_deferedCalls.push_back(function); + } + + void View::confirmButtons(const char *textLeft, const char *textRight, std::function leftButtonFn, std::function 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(); + } + +} \ No newline at end of file diff --git a/source/helpers/plugin_handler.cpp b/source/helpers/plugin_handler.cpp new file mode 100644 index 000000000..4b64aab37 --- /dev/null +++ b/source/helpers/plugin_handler.cpp @@ -0,0 +1,70 @@ +#include "helpers/plugin_handler.hpp" + +#include +#include + +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(dlsym(this->m_handle, CreateViewSymbol)); + this->m_drawToolsEntryFunction = reinterpret_cast(dlsym(this->m_handle, DrawToolsEntrySymbol)); + this->m_setImGuiContextFunction = reinterpret_cast(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); + } + +} diff --git a/source/lang/evaluator.cpp b/source/lang/evaluator.cpp index 9b2f5d3d0..2c0f8ccdd 100644 --- a/source/lang/evaluator.cpp +++ b/source/lang/evaluator.cpp @@ -347,7 +347,7 @@ namespace hex::lang { return { nullptr, 0 }; } - std::pair> Evaluator::evaluate(const std::vector &ast) { + std::optional> Evaluator::evaluate(const std::vector &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; } } \ No newline at end of file diff --git a/source/lang/lexer.cpp b/source/lang/lexer.cpp index f0aed7cc5..9cf2a2d92 100644 --- a/source/lang/lexer.cpp +++ b/source/lang/lexer.cpp @@ -66,7 +66,7 @@ namespace hex::lang { return integer; } - std::pair> Lexer::lex(const std::string& code) { + std::optional> Lexer::lex(const std::string& code) { std::vector 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; } } \ No newline at end of file diff --git a/source/lang/parser.cpp b/source/lang/parser.cpp index 50f281323..3d906ef5e 100644 --- a/source/lang/parser.cpp +++ b/source/lang/parser.cpp @@ -649,15 +649,15 @@ namespace hex::lang { return program; } - std::pair> Parser::parse(const std::vector &tokens) { + std::optional> Parser::parse(const std::vector &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; } } \ No newline at end of file diff --git a/source/lang/preprocessor.cpp b/source/lang/preprocessor.cpp index f5309fc4f..d3e8d0b60 100644 --- a/source/lang/preprocessor.cpp +++ b/source/lang/preprocessor.cpp @@ -6,7 +6,7 @@ namespace hex::lang { } - std::pair Preprocessor::preprocess(const std::string& code, bool initialRun) { + std::optional 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 function) { diff --git a/source/views/view_bookmarks.cpp b/source/views/view_bookmarks.cpp index 92f5d9e37..e7c66bea5 100644 --- a/source/views/view_bookmarks.cpp +++ b/source/views/view_bookmarks.cpp @@ -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() { } diff --git a/source/views/view_command_palette.cpp b/source/views/view_command_palette.cpp index e4d056767..954529985 100644 --- a/source/views/view_command_palette.cpp +++ b/source/views/view_command_palette.cpp @@ -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() { } diff --git a/source/views/view_data_inspector.cpp b/source/views/view_data_inspector.cpp index af9f1a59b..ee719f638 100644 --- a/source/views/view_data_inspector.cpp +++ b/source/views/view_data_inspector.cpp @@ -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() { } diff --git a/source/views/view_disassembler.cpp b/source/views/view_disassembler.cpp index 2f8c4687c..dddb5eb4b 100644 --- a/source/views/view_disassembler.cpp +++ b/source/views/view_disassembler.cpp @@ -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() { } diff --git a/source/views/view_hashes.cpp b/source/views/view_hashes.cpp index 763b09dc5..1753ff91d 100644 --- a/source/views/view_hashes.cpp +++ b/source/views/view_hashes.cpp @@ -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() { } diff --git a/source/views/view_help.cpp b/source/views/view_help.cpp index 06e970e4b..2850565f9 100644 --- a/source/views/view_help.cpp +++ b/source/views/view_help.cpp @@ -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"); }); diff --git a/source/views/view_hexeditor.cpp b/source/views/view_hexeditor.cpp index b76d8cd29..2c5dfa04d 100644 --- a/source/views/view_hexeditor.cpp +++ b/source/views/view_hexeditor.cpp @@ -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")) { diff --git a/source/views/view_information.cpp b/source/views/view_information.cpp index bf9439d5e..1d4ccea54 100644 --- a/source/views/view_information.cpp +++ b/source/views/view_information.cpp @@ -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() { } diff --git a/source/views/view_patches.cpp b/source/views/view_patches.cpp index 754e9ae72..67517ff80 100644 --- a/source/views/view_patches.cpp +++ b/source/views/view_patches.cpp @@ -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() { } diff --git a/source/views/view_pattern.cpp b/source/views/view_pattern.cpp index 80587e665..bc97f483b 100644 --- a/source/views/view_pattern.cpp +++ b/source/views/view_pattern.cpp @@ -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); } diff --git a/source/views/view_pattern_data.cpp b/source/views/view_pattern_data.cpp index 16d33e684..5e23fa924 100644 --- a/source/views/view_pattern_data.cpp +++ b/source/views/view_pattern_data.cpp @@ -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() { } diff --git a/source/views/view_strings.cpp b/source/views/view_strings.cpp index a49eb3cde..ff6965fd7 100644 --- a/source/views/view_strings.cpp +++ b/source/views/view_strings.cpp @@ -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() { } diff --git a/source/views/view_tools.cpp b/source/views/view_tools.cpp index a0d4c0dda..a8d757289 100644 --- a/source/views/view_tools.cpp +++ b/source/views/view_tools.cpp @@ -5,6 +5,7 @@ #include #include "providers/provider.hpp" +#include "helpers/plugin_handler.hpp" #include "helpers/utils.hpp" #include @@ -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() { } diff --git a/source/window.cpp b/source/window.cpp index 34a2d4dfd..5ddee9bb4 100644 --- a/source/window.cpp +++ b/source/window.cpp @@ -1,6 +1,7 @@ -#include "hex.hpp" #include "window.hpp" +#include + #include #include @@ -10,6 +11,8 @@ #include "imgui_impl_opengl3.h" #include "imgui_freetype.h" +#include "helpers/plugin_handler.hpp" + #include #include @@ -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,10 +203,22 @@ namespace hex { } if (auto &[key, mods] = Window::s_currShortcut; key != -1) { - for (auto &view : this->m_views) { + bool shortcutHandled = false; + for (auto &view : this->m_pluginViews) { if (view->getWindowOpenState()) { - if (view->handleShortcut(key, mods)) + 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; + } } } @@ -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; + } + } \ No newline at end of file