From 3e6865ffa9e6bd04c059d13c380c26394b86812f Mon Sep 17 00:00:00 2001 From: WerWolv Date: Mon, 1 Mar 2021 08:56:49 +0100 Subject: [PATCH] sys/build: Properly support per-system metadata file paths (#181) * sys: Move away from metadata paths next to executable in the application Build system doesn't properly install / pack stuff yet * build: Updated README to contain better install instructions * sys: Search for imhex resource files in ~/Application Support * sys: MAX_PATH -> PATH_MAX * sys: Seach for imhex resource files in Application Support using NSFileManager (#180) * sys: Allow for multiple file search paths Also use install prefix instead of just /usr on Linux * build: Fixed IMHEX_INSTALL_PREFIX macro definition * build: Fix duplicate switch entry on Linux * docs: Updated readme to properly reflect new paths and dependencies * sys: Install files in their proper paths on linux (#183) * Install files in their proper paths on linux * Only create user directories * Follow the XDG specification on linux XDG specification specifies how to find config and data directories on linux systems. Specifically, it says this: - Data should be written to $XDG_DATA_HOME - Config should be written to $XDG_CONFIG_HOME - Data should be read from $XDG_DATA_HOME:$XDG_DATA_DIRS - Config should be read from $XDG_CONFIG_HOME:$XDG_CONFIG_DIRS The default values are this: - XDG_DATA_HOME: $HOME/.local/share - XDG_CONFIG_HOME: $HOME/.config - XDG_DATA_DIRS: /usr/share:/usr/local/share - XDG_CONFIG_DIRS: /etc/xdg Platforms with non-standard filesystems (like NixOS) will correctly set up those environment variables, allowing softwares to work unmodified. In order to make integration as simple as possible, we use a simple header-only dependency called XDGPP which does all the hard work for us to find the default directories. * Look for plugins in all Plugin Paths If the plugin folder was missing from one of the PluginPaths, we would immediately stop loading plugins. We now keep looking even if one of the path is missing. Co-authored-by: Nichole Mattera Co-authored-by: Robin Lambertz --- .gitmodules | 3 + README.md | 50 +++++++++-- cmake/build_helpers.cmake | 35 ++++---- external/xdgpp | 1 + include/window.hpp | 1 + plugins/libimhex/CMakeLists.txt | 61 +++++++++----- .../libimhex/include/hex/helpers/utils.hpp | 15 +++- .../libimhex/include/hex/helpers/utils_mac.h | 9 ++ .../libimhex/source/api/content_registry.cpp | 20 +++-- plugins/libimhex/source/helpers/utils.cpp | 83 +++++++++++++++++++ plugins/libimhex/source/helpers/utils_mac.mm | 56 +++++++++++++ plugins/libimhex/source/lang/preprocessor.cpp | 13 ++- source/helpers/loader_script_handler.cpp | 8 +- source/views/view_information.cpp | 8 +- source/views/view_pattern.cpp | 43 +++++----- source/window.cpp | 50 +++++++---- 16 files changed, 365 insertions(+), 91 deletions(-) create mode 160000 external/xdgpp create mode 100644 plugins/libimhex/include/hex/helpers/utils_mac.h create mode 100644 plugins/libimhex/source/helpers/utils_mac.mm diff --git a/.gitmodules b/.gitmodules index e3ab41e22..69d763c78 100644 --- a/.gitmodules +++ b/.gitmodules @@ -5,3 +5,6 @@ path = external/yara/yara url = https://github.com/VirusTotal/yara ignore = dirty +[submodule "external/xdgpp"] + path = external/xdgpp + url = https://git.sr.ht/~danyspin97/xdgpp diff --git a/README.md b/README.md index 58923f41b..fbe3586d2 100644 --- a/README.md +++ b/README.md @@ -113,15 +113,14 @@ You need a C++20 compatible compiler such as GCC 10.2.0 to compile ImHex. Moreov - libmagic, libgnurx, libtre, libintl, libiconv - libcrypto - capstone -- nlohmann json - Python3 - freetype2 - Brew (macOS only) +- Xcode (macOS only) -### Windows and Linux - -Find all-in-one dependency installation scripts for Arch Linux, Fedora, Debian/Ubuntu and/or MSYS2 in [dist](dist). +### Windows +On Windows, ImHex is built through msys2 / mingw. To install all dependencies, open a mys2 window and run the PKGCONFIG script in the (dist/msys2)[dist/msys2] folder. After all the dependencies are installed, run the following commands to build ImHex: ```sh @@ -135,8 +134,6 @@ make -j To create a standalone zipfile on Windows, get the Python standard library (e.g. from https://github.com/python/cpython/tree/master/Lib) and place the files and folders in `lib/python3.8` next to your built executable. Don't forget to also copy the `libpython3.8.dll` and `libwinpthread-1.dll` from your mingw setup next to the executable. -On both Windows and Linux: - - Copy the files from `python_libs` in the `lib` folder next to your built executable. - Place your magic databases in the `magic` folder next to your built executable - Place your patterns in the `pattern` folder next to your built executable @@ -154,6 +151,47 @@ CC=$(brew --prefix llvm)/bin/clang CXX=$(brew --prefix llvm)/bin/clang++ PKG_CON make -j ``` +Install the ImHex executable as well as libimhex.dylib to wherever ImHex should be installed. + +All other files belong in `~/Library/Application Support/imhex`: +``` +Patterns: ~/Library/Application Support/imhex/patterns +Pattern Includes: ~/Library/Application Support/imhex/includes +Magic files: ~/Library/Application Support/imhex/magic +Python: ~/Library/Application Support/imhex/lib/pythonX.X +Plugins: ~/Library/Application Support/imhex/plugins +Configuration: ~/Library/Application Support/imhex/config +Resources: ~/Library/Application Support/imhex/resources +``` + +### Linux + +Dependency installation scripts are available for many common Linux distributions in the (/dist)[dist] folder. +After all the dependencies are installed, run the following commands to build ImHex: + +```sh +mkdir build +cd build +cmake -DCMAKE_BUILD_TYPE=Release .. +make -j +``` + +--- + +Put the ImHex executable into the `/usr/bin` folder. +Put libimhex.so into the `/usr/lib` folder. +All other files belong in `/usr/share/imhex` or `~/.imhex`: +``` +Patterns: /usr/share/imhex/patterns +Pattern Includes: /usr/share/imhex/includes +Magic files: /usr/share/imhex/magic +Python: /usr/share/imhex/lib/pythonX.X +Plugins: /usr/share/imhex/imhex/plugins +Configuration: /usr/share/imhex/config +Resources: /usr/share/imhex/resources +``` +The `/usr` prefix can be customized by changing the cmake install path + ## Credits - Thanks a lot to ocornut for their amazing [Dear ImGui](https://github.com/ocornut/imgui) which is used for building the entire interface diff --git a/cmake/build_helpers.cmake b/cmake/build_helpers.cmake index 98f19a678..ed7b9fb81 100644 --- a/cmake/build_helpers.cmake +++ b/cmake/build_helpers.cmake @@ -71,10 +71,22 @@ endmacro() macro(detectOS) if (WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOS_WINDOWS") + set(CMAKE_INSTALL_BINDIR ".") + set(CMAKE_INSTALL_LIBDIR ".") + set(PLUGINS_INSTALL_LOCATION "plugins") + set(MAGIC_INSTALL_LOCATION "magic") elseif(APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOS_MACOS") + set(CMAKE_INSTALL_BINDIR ".") + set(CMAKE_INSTALL_LIBDIR ".") + set(PLUGINS_INSTALL_LOCATION "plugins") + set(MAGIC_INSTALL_LOCATION "magic") elseif(UNIX AND NOT APPLE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DOS_LINUX") + set(CMAKE_INSTALL_BINDIR "bin") + set(CMAKE_INSTALL_LIBDIR "lib") + set(PLUGINS_INSTALL_LOCATION "share/imhex/plugins") + set(MAGIC_INSTALL_LOCATION "share/imhex/magic") else() message(FATAL_ERROR "Unknown / unsupported system!") endif() @@ -145,11 +157,11 @@ macro(createPackage) file(MAKE_DIRECTORY "plugins") foreach (plugin IN LISTS PLUGINS) add_subdirectory("plugins/${plugin}") - set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins) + install(TARGETS ${plugin} DESTINATION ${PLUGINS_INSTALL_LOCATION}) add_dependencies(imhex ${plugin}) endforeach() - set_target_properties(libimhex PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}) + install(TARGETS libimhex DESTINATION ${CMAKE_INSTALL_LIBDIR}) if (WIN32) # Install binaries directly in the prefix, usually C:\Program Files\ImHex. @@ -188,10 +200,7 @@ macro(createPackage) endif() if (UNIX AND NOT APPLE) - install(TARGETS libimhex DESTINATION ${CMAKE_INSTALL_PREFIX}) - string(REPLACE ":" ";" EXTRA_MAGICDBS "${EXTRA_MAGICDBS}") - endif () if (NOT EXTRA_MAGICDBS STREQUAL "") @@ -199,9 +208,9 @@ macro(createPackage) if (NOT EXTRA_MAGICDBS STREQUAL "NOTFOUND") if (EXTRA_MAGICDBS MATCHES ".*\\.mgc") - install(FILES "${EXTRA_MAGICDBS}" DESTINATION magic/) + install(FILES "${EXTRA_MAGICDBS}" DESTINATION ${MAGIC_INSTALL_LOCATION}) else () - install(FILES "${EXTRA_MAGICDBS}.mgc" DESTINATION magic/) + install(FILES "${EXTRA_MAGICDBS}.mgc" DESTINATION ${MAGIC_INSTALL_LOCATION}) endif () endif () endif () @@ -214,12 +223,8 @@ macro(createPackage) COMMAND file -C -m ${CMAKE_SOURCE_DIR}/magic_dbs ) - foreach (plugin IN LISTS PLUGINS) - install(FILES "$" DESTINATION plugins/) - endforeach () - # Install the magicdb files. - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/magic_dbs.mgc DESTINATION magic/ RENAME imhex.mgc) + install(FILES ${CMAKE_CURRENT_BINARY_DIR}/magic_dbs.mgc DESTINATION ${MAGIC_INSTALL_LOCATION} RENAME imhex.mgc) if (CREATE_BUNDLE) include(PostprocessBundle) @@ -238,11 +243,7 @@ macro(createPackage) install(TARGETS imhex BUNDLE DESTINATION .) else() - if (WIN32) - install(TARGETS imhex RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) - else () - install(TARGETS imhex RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}) - endif () + install(TARGETS imhex RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() diff --git a/external/xdgpp b/external/xdgpp new file mode 160000 index 000000000..f01f81071 --- /dev/null +++ b/external/xdgpp @@ -0,0 +1 @@ +Subproject commit f01f810714443d0f10c333d4d1d9c0383be41375 diff --git a/include/window.hpp b/include/window.hpp index 7b47e51a4..c4834c930 100644 --- a/include/window.hpp +++ b/include/window.hpp @@ -36,6 +36,7 @@ namespace hex { void drawWelcomeScreen(); void resetLayout(); + void createDirectories() const; void initGLFW(); void initImGui(); void deinitGLFW(); diff --git a/plugins/libimhex/CMakeLists.txt b/plugins/libimhex/CMakeLists.txt index bdfd6ccfb..987a572fb 100644 --- a/plugins/libimhex/CMakeLists.txt +++ b/plugins/libimhex/CMakeLists.txt @@ -6,7 +6,7 @@ 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}/../../external/nlohmann_json ${CMAKE_CURRENT_BINARY_DIR}/external/nlohmann_json) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/nativefiledialog ${CMAKE_CURRENT_BINARY_DIR}/external/nativefiledialog) - +set(XDGPP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../../external/xdgpp") if (WIN32) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static-libstdc++ -static-libgcc -Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive") @@ -16,34 +16,53 @@ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") set(CMAKE_SHARED_LIBRARY_PREFIX "") -add_library(libimhex SHARED - source/api/event.cpp - source/api/imhex_api.cpp - source/api/content_registry.cpp +set(LIBIMHEX_SOURCES + source/api/event.cpp + source/api/imhex_api.cpp + source/api/content_registry.cpp - source/helpers/utils.cpp - source/helpers/shared_data.cpp - source/helpers/crypto.cpp - source/helpers/lang.cpp + source/helpers/utils.cpp + source/helpers/shared_data.cpp + source/helpers/crypto.cpp + source/helpers/lang.cpp - source/lang/pattern_language.cpp - source/lang/preprocessor.cpp - source/lang/lexer.cpp - source/lang/parser.cpp - source/lang/validator.cpp - source/lang/evaluator.cpp - source/lang/builtin_functions.cpp + source/lang/pattern_language.cpp + source/lang/preprocessor.cpp + source/lang/lexer.cpp + source/lang/parser.cpp + source/lang/validator.cpp + source/lang/evaluator.cpp + source/lang/builtin_functions.cpp - source/providers/provider.cpp + source/providers/provider.cpp - source/views/view.cpp - ) + source/views/view.cpp +) -target_include_directories(libimhex PUBLIC include ${MBEDTLS_INCLUDE_DIR}) +if (APPLE) + set(OSX_11_0_SDK_PATH /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk) + if (NOT CMAKE_OSX_SYSROOT) + if (IS_DIRECTORY ${OSX_11_0_SDK_PATH}) + set(CMAKE_OSX_SYSROOT ${OSX_11_0_SDK_PATH}) + else () + message(WARNING "CMAKE_OSX_SYSROOT not set and macOS 10.9 SDK not found! Using default one.") + endif () + endif () + set(CMAKE_OSX_DEPLOYMENT_TARGET 11.0) + + set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/utils_mac.mm) +endif () + +add_library(libimhex SHARED ${LIBIMHEX_SOURCES}) + +target_include_directories(libimhex PUBLIC include ${MBEDTLS_INCLUDE_DIR} ${XDGPP_INCLUDE_DIRS}) target_link_directories(libimhex PUBLIC ${MBEDTLS_LIBRARY_DIR}) if (WIN32) target_link_libraries(libimhex PUBLIC imgui nlohmann_json libmbedcrypto.a nfd) -else () +elseif (APPLE) + find_library(FOUNDATION NAMES Foundation) + target_link_libraries(libimhex PUBLIC imgui nlohmann_json mbedcrypto ${FOUNDATION} nfd) +else() target_link_libraries(libimhex PUBLIC imgui nlohmann_json mbedcrypto nfd) endif () \ No newline at end of file diff --git a/plugins/libimhex/include/hex/helpers/utils.hpp b/plugins/libimhex/include/hex/helpers/utils.hpp index b8d3388e7..9ea9ed053 100644 --- a/plugins/libimhex/include/hex/helpers/utils.hpp +++ b/plugins/libimhex/include/hex/helpers/utils.hpp @@ -224,10 +224,23 @@ namespace hex { trimRight(s); } + enum class ImHexPath { + Patterns, + PatternsInclude, + Magic, + Python, + Plugins, + Yara, + Config, + Resources + }; + + std::vector getPath(ImHexPath path); + #define SCOPE_EXIT(func) ScopeExit TOKEN_CONCAT(scopeGuard, __COUNTER__)([&] { func }) class ScopeExit { public: - ScopeExit(std::function func) : m_func(func) {} + ScopeExit(const std::function &func) : m_func(func) {} ~ScopeExit() { if (this->m_func != nullptr) this->m_func(); } void release() { diff --git a/plugins/libimhex/include/hex/helpers/utils_mac.h b/plugins/libimhex/include/hex/helpers/utils_mac.h new file mode 100644 index 000000000..29b22b6c2 --- /dev/null +++ b/plugins/libimhex/include/hex/helpers/utils_mac.h @@ -0,0 +1,9 @@ +#pragma once + +#if defined(OS_MACOS) + #include + + namespace hex { + std::string getPathForMac(ImHexPath path); + } +#endif diff --git a/plugins/libimhex/source/api/content_registry.cpp b/plugins/libimhex/source/api/content_registry.cpp index bc22823d3..9eb2edad0 100644 --- a/plugins/libimhex/source/api/content_registry.cpp +++ b/plugins/libimhex/source/api/content_registry.cpp @@ -10,15 +10,25 @@ namespace hex { /* Settings */ void ContentRegistry::Settings::load() { - std::ifstream settingsFile(std::filesystem::path((SharedData::mainArgv)[0]).parent_path() / "settings.json"); + for (const auto &dir : hex::getPath(ImHexPath::Config)) { + std::ifstream settingsFile(dir + "/settings.json"); - if (settingsFile.good()) - settingsFile >> getSettingsData(); + if (settingsFile.good()) { + settingsFile >> getSettingsData(); + break; + } + } } void ContentRegistry::Settings::store() { - std::ofstream settingsFile(std::filesystem::path((SharedData::mainArgv)[0]).parent_path() / "settings.json", std::ios::trunc); - settingsFile << getSettingsData(); + for (const auto &dir : hex::getPath(ImHexPath::Config)) { + std::ofstream settingsFile(dir + "/settings.json", std::ios::trunc); + + if (settingsFile.good()) { + settingsFile << getSettingsData(); + break; + } + } } void ContentRegistry::Settings::add(std::string_view unlocalizedCategory, std::string_view unlocalizedName, s64 defaultValue, const std::function &callback) { diff --git a/plugins/libimhex/source/helpers/utils.cpp b/plugins/libimhex/source/helpers/utils.cpp index e26a0c3e8..c157dd05b 100644 --- a/plugins/libimhex/source/helpers/utils.cpp +++ b/plugins/libimhex/source/helpers/utils.cpp @@ -3,6 +3,15 @@ #include #include #include +#include + +#if defined(OS_WINDOWS) + #include +#elif defined(OS_MACOS) + #include +#elif defined(OS_LINUX) + #include +#endif namespace hex { @@ -169,4 +178,78 @@ namespace hex { } + std::vector getPath(ImHexPath path) { + #if defined(OS_WINDOWS) + std::string exePath(MAX_PATH, '\0'); + GetModuleFileName(nullptr, exePath.data(), exePath.length()); + auto parentDir = std::filesystem::path(exePath).parent_path(); + + switch (path) { + case ImHexPath::Patterns: + return { (parentDir / "patterns").string() }; + case ImHexPath::PatternsInclude: + return { (parentDir / "includes").string() }; + case ImHexPath::Magic: + return { (parentDir / "magic").string() }; + case ImHexPath::Python: + return { parentDir.string() }; + case ImHexPath::Plugins: + return { (parentDir / "plugins").string() }; + case ImHexPath::Yara: + return { (parentDir / "yara").string() }; + case ImHexPath::Config: + return { (parentDir / "config").string() }; + case ImHexPath::Resources: + return { (parentDir / "resources").string() }; + default: __builtin_unreachable(); + } + #elif defined(OS_MACOS) + return { getPathForMac(path) }; + #else + std::vector configDirs = xdg::ConfigDirs(); + std::vector dataDirs = xdg::DataDirs(); + + configDirs.insert(configDirs.begin(), xdg::ConfigHomeDir()); + dataDirs.insert(dataDirs.begin(), xdg::DataHomeDir()); + + std::vector result; + + switch (path) { + case ImHexPath::Patterns: + std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), + [](auto p) { return (p / "imhex" / "patterns").string(); }); + return result; + case ImHexPath::PatternsInclude: + std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), + [](auto p) { return (p / "imhex" / "includes").string(); }); + return result; + case ImHexPath::Magic: + std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), + [](auto p) { return (p / "imhex" / "magic").string(); }); + return result; + case ImHexPath::Python: + std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), + [](auto p) { return (p / "imhex").string(); }); + return result; + case ImHexPath::Plugins: + std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), + [](auto p) { return (p / "imhex" / "plugins").string(); }); + return result; + case ImHexPath::Yara: + std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), + [](auto p) { return (p / "imhex" / "yara").string(); }); + return result; + case ImHexPath::Config: + std::transform(configDirs.begin(), configDirs.end(), std::back_inserter(result), + [](auto p) { return (p / "imhex").string(); }); + return result; + case ImHexPath::Resources: + std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), + [](auto p) { return (p / "imhex" / "resources").string(); }); + return result; + default: __builtin_unreachable(); + } + #endif + } + } \ No newline at end of file diff --git a/plugins/libimhex/source/helpers/utils_mac.mm b/plugins/libimhex/source/helpers/utils_mac.mm new file mode 100644 index 000000000..073e2b54b --- /dev/null +++ b/plugins/libimhex/source/helpers/utils_mac.mm @@ -0,0 +1,56 @@ +#if defined(OS_MACOS) + #include + + #include + + namespace hex { + std::string getPathForMac(ImHexPath path) { + @autoreleasepool { + NSError * error = nil; + NSURL * appSupportDir = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory + inDomain:NSUserDomainMask + appropriateForURL:nil + create:YES + error:&error]; + if (error != nil) { + __builtin_unreachable(); + } + + NSURL * result = nil; + switch (path) { + case ImHexPath::Patterns: + result = [appSupportDir URLByAppendingPathComponent:@"/imhex/patterns"]; + break; + + case ImHexPath::PatternsInclude: + result = [appSupportDir URLByAppendingPathComponent:@"/imhex/patterns"]; + break; + case ImHexPath::Magic: + result = [appSupportDir URLByAppendingPathComponent:@"/imhex/magic"]; + break; + case ImHexPath::Python: + result = [appSupportDir URLByAppendingPathComponent:@"/imhex"]; + break; + case ImHexPath::Plugins: + result = [appSupportDir URLByAppendingPathComponent:@"/imhex/plugins"]; + break; + case ImHexPath::Yara: + result = [appSupportDir URLByAppendingPathComponent:@"/imhex/yara"]; + break; + case ImHexPath::Config: + result = [appSupportDir URLByAppendingPathComponent:@"/imhex/config"]; + break; + case ImHexPath::Resources: + result = [appSupportDir URLByAppendingPathComponent:@"/imhex/resources"]; + break; + } + + if (result == nil) { + __builtin_unreachable(); + } + + return std::string([[result path] UTF8String]); + } + } + } +#endif diff --git a/plugins/libimhex/source/lang/preprocessor.cpp b/plugins/libimhex/source/lang/preprocessor.cpp index 2d2678acf..2a91ff06e 100644 --- a/plugins/libimhex/source/lang/preprocessor.cpp +++ b/plugins/libimhex/source/lang/preprocessor.cpp @@ -1,5 +1,7 @@ #include +#include + namespace hex::lang { Preprocessor::Preprocessor() { @@ -47,8 +49,15 @@ namespace hex::lang { } offset += 1; - if (includeFile[0] != '/') - includeFile = "include/" + includeFile; + if (includeFile[0] != '/') { + std::string tempPath = includeFile; + for (const auto &dir : hex::getPath(ImHexPath::PatternsInclude)) { + tempPath = hex::format("%s/%s", dir.c_str(), includeFile.c_str()); + if (std::filesystem::exists(includeFile)) + break; + } + includeFile = tempPath; + } FILE *file = fopen(includeFile.c_str(), "r"); if (file == nullptr) diff --git a/source/helpers/loader_script_handler.cpp b/source/helpers/loader_script_handler.cpp index 24aec6cf8..24d58e1e7 100644 --- a/source/helpers/loader_script_handler.cpp +++ b/source/helpers/loader_script_handler.cpp @@ -179,8 +179,12 @@ namespace hex { bool LoaderScript::processFile(std::string_view scriptPath) { Py_SetProgramName(Py_DecodeLocale((SharedData::mainArgv)[0], nullptr)); - if (std::filesystem::exists(std::filesystem::path((SharedData::mainArgv)[0]).parent_path().string() + "/lib/python" PYTHON_VERSION_MAJOR_MINOR)) - Py_SetPythonHome(Py_DecodeLocale(std::filesystem::path((SharedData::mainArgv)[0]).parent_path().string().c_str(), nullptr)); + for (const auto &dir : hex::getPath(ImHexPath::Python)) { + if (std::filesystem::exists(std::filesystem::path(dir + "/lib/python" PYTHON_VERSION_MAJOR_MINOR))) { + Py_SetPythonHome(Py_DecodeLocale(dir.c_str(), nullptr)); + break; + } + } PyImport_AppendInittab("_imhex", []() -> PyObject* { diff --git a/source/views/view_information.cpp b/source/views/view_information.cpp index 795d74df3..5821dd1e1 100644 --- a/source/views/view_information.cpp +++ b/source/views/view_information.cpp @@ -86,9 +86,11 @@ namespace hex { std::string magicFiles; std::error_code error; - for (const auto &entry : std::filesystem::directory_iterator("magic", error)) { - if (entry.is_regular_file() && entry.path().extension() == ".mgc") - magicFiles += entry.path().string() + MAGIC_PATH_SEPARATOR; + for (const auto &dir : hex::getPath(ImHexPath::Magic)) { + for (const auto &entry : std::filesystem::directory_iterator(dir, error)) { + if (entry.is_regular_file() && entry.path().extension() == ".mgc") + magicFiles += entry.path().string() + MAGIC_PATH_SEPARATOR; + } } if (!error) { diff --git a/source/views/view_pattern.cpp b/source/views/view_pattern.cpp index a6d85de6a..17c285bdb 100644 --- a/source/views/view_pattern.cpp +++ b/source/views/view_pattern.cpp @@ -106,9 +106,11 @@ namespace hex { std::string magicFiles; std::error_code error; - for (const auto &entry : std::filesystem::directory_iterator("magic", error)) { - if (entry.is_regular_file() && entry.path().extension() == ".mgc") - magicFiles += entry.path().string() + MAGIC_PATH_SEPARATOR; + for (const auto &dir : hex::getPath(ImHexPath::Magic)) { + for (const auto &entry : std::filesystem::directory_iterator(dir, error)) { + if (entry.is_regular_file() && entry.path().extension() == ".mgc") + magicFiles += entry.path().string() + MAGIC_PATH_SEPARATOR; + } } if (error) @@ -142,29 +144,32 @@ namespace hex { std::error_code errorCode; - for (auto &entry : std::filesystem::directory_iterator("patterns", errorCode)) { - if (!entry.is_regular_file()) - continue; + for (const auto &dir : hex::getPath(ImHexPath::Patterns)) { + for (auto &entry : std::filesystem::directory_iterator(dir, errorCode)) { + if (!entry.is_regular_file()) + continue; - FILE *file = fopen(entry.path().string().c_str(), "r"); + FILE *file = fopen(entry.path().string().c_str(), "r"); - if (file == nullptr) - continue; + if (file == nullptr) + continue; - fseek(file, 0, SEEK_END); - size_t size = ftell(file); - rewind(file); + fseek(file, 0, SEEK_END); + size_t size = ftell(file); + rewind(file); - std::vector patternBuffer( size + 1, 0x00); - fread(patternBuffer.data(), 1, size, file); - fclose(file); + std::vector patternBuffer( size + 1, 0x00); + fread(patternBuffer.data(), 1, size, file); + fclose(file); - preprocessor.preprocess(patternBuffer.data()); + preprocessor.preprocess(patternBuffer.data()); - if (foundCorrectType) - this->m_possiblePatternFiles.push_back(entry.path().filename().string()); + if (foundCorrectType) + this->m_possiblePatternFiles.push_back(entry.path().string()); + } } + if (!this->m_possiblePatternFiles.empty()) { this->m_selectedPatternFile = 0; View::doLater([] { ImGui::OpenPopup("hex.view.pattern.accept_pattern"_lang); }); @@ -297,7 +302,7 @@ namespace hex { ImGui::Text("hex.view.pattern.accept_pattern.question"_lang); confirmButtons("hex.common.yes"_lang, "hex.common.no"_lang, [this]{ - this->loadPatternFile("patterns/" + this->m_possiblePatternFiles[this->m_selectedPatternFile]); + this->loadPatternFile(this->m_possiblePatternFiles[this->m_selectedPatternFile]); ImGui::CloseCurrentPopup(); }, []{ ImGui::CloseCurrentPopup(); diff --git a/source/window.cpp b/source/window.cpp index 1660008d8..548e07759 100644 --- a/source/window.cpp +++ b/source/window.cpp @@ -50,6 +50,7 @@ namespace hex { hex::SharedData::mainArgc = argc; hex::SharedData::mainArgv = argv; + this->createDirectories(); this->initGLFW(); this->initImGui(); @@ -512,9 +513,18 @@ namespace hex { ImGui::DockBuilderFinish(dockId); } - void Window::initGLFW() { + void Window::createDirectories() const { + std::filesystem::create_directories(hex::getPath(ImHexPath::Patterns)[0]); + std::filesystem::create_directories(hex::getPath(ImHexPath::PatternsInclude)[0]); + std::filesystem::create_directories(hex::getPath(ImHexPath::Magic)[0]); + std::filesystem::create_directories(hex::getPath(ImHexPath::Plugins)[0]); + std::filesystem::create_directories(hex::getPath(ImHexPath::Resources)[0]); + std::filesystem::create_directories(hex::getPath(ImHexPath::Config)[0]); + } + + void Window::initGLFW() { glfwSetErrorCallback([](int error, const char* desc) { - fprintf(stderr, "Glfw Error %d: %s\n", error, desc); + fprintf(stderr, "Glfw Error %d: %s\n", error, desc); }); if (!glfwInit()) @@ -645,16 +655,14 @@ namespace hex { if (this->m_globalScale != 0.0f) style.ScaleAllSizes(this->m_globalScale); - #if defined(OS_WINDOWS) - std::filesystem::path resourcePath = std::filesystem::path((SharedData::mainArgv)[0]).parent_path(); - #elif defined(OS_LINUX) || defined(OS_MACOS) - std::filesystem::path resourcePath = "/usr/share/ImHex"; - #else - std::filesystem::path resourcePath = ""; - #warning "Unsupported OS for custom font support" - #endif + std::string fontFile; + for (const auto &dir : hex::getPath(ImHexPath::Resources)) { + fontFile = dir + "/font.ttf"; + if (std::filesystem::exists(fontFile)) + break; + } - if (!resourcePath.empty() && this->setFont(resourcePath / "font.ttf")) { + if (this->setFont(fontFile)) { } else { @@ -700,15 +708,27 @@ namespace hex { handler.UserData = this; ImGui::GetCurrentContext()->SettingsHandlers.push_back(handler); + static std::string iniFileName; + for (const auto &dir : hex::getPath(ImHexPath::Config)) { + if (std::filesystem::exists(dir)) { + iniFileName = dir + "/interface.ini"; + break; + } + } + io.IniFilename = iniFileName.c_str(); + ImGui_ImplGlfw_InitForOpenGL(this->m_window, true); ImGui_ImplOpenGL3_Init("#version 150"); } void Window::initPlugins() { - try { - auto pluginFolderPath = std::filesystem::path((SharedData::mainArgv)[0]).parent_path() / "plugins"; - PluginHandler::load(pluginFolderPath.string()); - } catch (std::runtime_error &e) { return; } + for (const auto &dir : hex::getPath(ImHexPath::Plugins)) { + try { + PluginHandler::load(dir); + } catch (std::runtime_error &e) { + // Plugin folder not found. Not a problem. + } + } for (const auto &plugin : PluginHandler::getPlugins()) { plugin.initializePlugin();