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();