diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index f987939bb..4ff7122dd 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -9,5 +9,12 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/lib/libimhex/CMakeLists.txt b/lib/libimhex/CMakeLists.txt
index d6cfc8abe..c23cd3620 100644
--- a/lib/libimhex/CMakeLists.txt
+++ b/lib/libimhex/CMakeLists.txt
@@ -123,6 +123,7 @@ set(LIBIMHEX_SOURCES
source/helpers/project_file_handler.cpp
source/helpers/encoding_file.cpp
source/helpers/loader_script_handler.cpp
+ source/helpers/logger.cpp
source/pattern_language/pattern_language.cpp
source/pattern_language/preprocessor.cpp
diff --git a/lib/libimhex/include/hex/helpers/file.hpp b/lib/libimhex/include/hex/helpers/file.hpp
index 122664324..33834f298 100644
--- a/lib/libimhex/include/hex/helpers/file.hpp
+++ b/lib/libimhex/include/hex/helpers/file.hpp
@@ -26,13 +26,16 @@ namespace hex {
Create
};
- explicit File(const fs::path &path, Mode mode);
- File();
+ explicit File(const fs::path &path, Mode mode) noexcept;
+ File() noexcept;
File(const File&) = delete;
File(File &&other) noexcept;
~File();
+ File& operator=(File &&other) noexcept;
+
+
[[nodiscard]] bool isValid() const { return this->m_file != nullptr; }
void seek(u64 offset);
diff --git a/lib/libimhex/include/hex/helpers/logger.hpp b/lib/libimhex/include/hex/helpers/logger.hpp
index 5fa9b231b..01b568e42 100644
--- a/lib/libimhex/include/hex/helpers/logger.hpp
+++ b/lib/libimhex/include/hex/helpers/logger.hpp
@@ -5,36 +5,54 @@
namespace hex::log {
+ FILE *getDestination();
+ bool isRedirected();
+
+ template
+ void print(fmt::format_string fmt, T&&... args) {
+ fmt::print(getDestination(), fmt, args...);
+ }
+
+ template
+ void print(const fmt::text_style& ts, const S& fmt, const Args&... args) {
+ if (isRedirected())
+ fmt::print(getDestination(), fmt::runtime(fmt), args...);
+ else
+ fmt::print(getDestination(), ts, fmt, args...);
+ }
+
void debug(const std::string &fmt, auto ... args) {
#if defined(DEBUG)
- fmt::print(fg(fmt::color::green_yellow) | fmt::emphasis::bold, "[DEBUG] ");
- fmt::print(fmt::runtime(fmt), args...);
- fmt::print("\n");
+ log::print(fg(fmt::color::green_yellow) | fmt::emphasis::bold, "[DEBUG] ");
+ log::print(fmt::runtime(fmt), args...);
+ log::print("\n");
#endif
}
void info(const std::string &fmt, auto ... args) {
- fmt::print(fg(fmt::color::cadet_blue) | fmt::emphasis::bold, "[INFO] ");
- fmt::print(fmt::runtime(fmt), args...);
- fmt::print("\n");
+ log::print(fg(fmt::color::cadet_blue) | fmt::emphasis::bold, "[INFO] ");
+ log::print(fmt::runtime(fmt), args...);
+ log::print("\n");
}
void warn(const std::string &fmt, auto ... args) {
- fmt::print(fg(fmt::color::orange) | fmt::emphasis::bold, "[WARN] ");
- fmt::print(fmt::runtime(fmt), args...);
- fmt::print("\n");
+ log::print(fg(fmt::color::orange) | fmt::emphasis::bold, "[WARN] ");
+ log::print(fmt::runtime(fmt), args...);
+ log::print("\n");
}
void error(const std::string &fmt, auto ... args) {
- fmt::print(fg(fmt::color::red) | fmt::emphasis::bold, "[ERROR] ");
- fmt::print(fmt::runtime(fmt), args...);
- fmt::print("\n");
+ log::print(fg(fmt::color::red) | fmt::emphasis::bold, "[ERROR] ");
+ log::print(fmt::runtime(fmt), args...);
+ log::print("\n");
}
void fatal(const std::string &fmt, auto ... args) {
- fmt::print(fg(fmt::color::purple) | fmt::emphasis::bold, "[FATAL] ");
- fmt::print(fmt::runtime(fmt), args...);
- fmt::print("\n");
+ log::print(fg(fmt::color::purple) | fmt::emphasis::bold, "[FATAL] ");
+ log::print(fmt::runtime(fmt), args...);
+ log::print("\n");
}
+ void redirectToFile();
+
}
\ No newline at end of file
diff --git a/lib/libimhex/include/hex/helpers/paths.hpp b/lib/libimhex/include/hex/helpers/paths.hpp
index dc9895d75..3d67db337 100644
--- a/lib/libimhex/include/hex/helpers/paths.hpp
+++ b/lib/libimhex/include/hex/helpers/paths.hpp
@@ -17,7 +17,8 @@ namespace hex {
Yara,
Config,
Resources,
- Constants
+ Constants,
+ Logs
};
std::string getExecutablePath();
diff --git a/lib/libimhex/source/helpers/file.cpp b/lib/libimhex/source/helpers/file.cpp
index 6ca2f125d..35767c6e0 100644
--- a/lib/libimhex/source/helpers/file.cpp
+++ b/lib/libimhex/source/helpers/file.cpp
@@ -3,7 +3,7 @@
namespace hex {
- File::File(const fs::path &path, Mode mode) : m_path(path) {
+ File::File(const fs::path &path, Mode mode) noexcept : m_path(path) {
if (mode == File::Mode::Read)
this->m_file = fopen64(path.string().c_str(), "rb");
else if (mode == File::Mode::Write)
@@ -13,7 +13,7 @@ namespace hex {
this->m_file = fopen64(path.string().c_str(), "w+b");
}
- File::File() {
+ File::File() noexcept {
this->m_file = nullptr;
}
@@ -26,6 +26,16 @@ namespace hex {
this->close();
}
+ File& File::operator=(File &&other) noexcept {
+ this->m_file = other.m_file;
+ other.m_file = nullptr;
+
+ this->m_path = std::move(other.m_path);
+
+ return *this;
+ }
+
+
void File::seek(u64 offset) {
fseeko64(this->m_file, offset, SEEK_SET);
}
diff --git a/lib/libimhex/source/helpers/logger.cpp b/lib/libimhex/source/helpers/logger.cpp
new file mode 100644
index 000000000..18ea0bf25
--- /dev/null
+++ b/lib/libimhex/source/helpers/logger.cpp
@@ -0,0 +1,33 @@
+#include
+#include
+#include
+#include
+
+#include
+
+namespace hex::log {
+
+ static File g_loggerFile;
+
+ FILE* getDestination() {
+ if (g_loggerFile.isValid())
+ return g_loggerFile.getHandle();
+ else
+ return stdout;
+ }
+
+ bool isRedirected() {
+ return g_loggerFile.isValid();
+ }
+
+ void redirectToFile() {
+ if (g_loggerFile.isValid()) return;
+
+ for (const auto &path : hex::getPath(ImHexPath::Logs)) {
+ g_loggerFile = File(path / hex::format("{0:%Y%m%d_%H%M%S}.log", fmt::localtime(std::chrono::system_clock::now())), File::Mode::Create);
+
+ if (g_loggerFile.isValid()) break;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/lib/libimhex/source/helpers/paths.cpp b/lib/libimhex/source/helpers/paths.cpp
index ba119306a..b21e68e3b 100644
--- a/lib/libimhex/source/helpers/paths.cpp
+++ b/lib/libimhex/source/helpers/paths.cpp
@@ -98,6 +98,11 @@ namespace hex {
return (path / "constants").string();
});
break;
+ case ImHexPath::Logs:
+ std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path){
+ return (path / "logs").string();
+ });
+ break;
default: __builtin_unreachable();
}
#elif defined(OS_MACOS)
@@ -137,6 +142,9 @@ namespace hex {
case ImHexPath::Constants:
result.push_back((applicationSupportDir / "constants").string());
break;
+ case ImHexPath::Logs:
+ result.push_back((applicationSupportDir / "logs").string());
+ break;
default: __builtin_unreachable();
}
#else
@@ -191,6 +199,10 @@ namespace hex {
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result),
[](auto p) { return (p / "constants").string(); });
break;
+ case ImHexPath::Logs:
+ std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result),
+ [](auto p) { return (p / "logs").string(); });
+ break;
default: __builtin_unreachable();
}
#endif
diff --git a/main/include/helpers/plugin_manager.hpp b/main/include/helpers/plugin_manager.hpp
index 91e46416b..f55696b42 100644
--- a/main/include/helpers/plugin_manager.hpp
+++ b/main/include/helpers/plugin_manager.hpp
@@ -16,17 +16,18 @@ namespace hex {
class Plugin {
public:
- Plugin(const fs::path &path);
+ explicit Plugin(const fs::path &path);
Plugin(const Plugin&) = delete;
Plugin(Plugin &&other) noexcept;
~Plugin();
- void initializePlugin() const;
+ [[nodiscard]] bool initializePlugin() const;
[[nodiscard]] std::string getPluginName() const;
[[nodiscard]] std::string getPluginAuthor() const;
[[nodiscard]] std::string getPluginDescription() const;
void setImGuiContext(ImGuiContext *ctx) const;
+ [[nodiscard]] const fs::path& getPath() const;
private:
using InitializePluginFunc = void(*)();
@@ -36,6 +37,7 @@ namespace hex {
using SetImGuiContextFunc = void(*)(ImGuiContext*);
void *m_handle = nullptr;
+ fs::path m_path;
InitializePluginFunc m_initializePluginFunction = nullptr;
GetPluginNameFunc m_getPluginNameFunction = nullptr;
diff --git a/main/source/helpers/plugin_manager.cpp b/main/source/helpers/plugin_manager.cpp
index aabb9e040..baee65e87 100644
--- a/main/source/helpers/plugin_manager.cpp
+++ b/main/source/helpers/plugin_manager.cpp
@@ -14,7 +14,7 @@ namespace hex {
constexpr auto GetPluginDescriptionSymbol = "_ZN3hex6plugin{0}{1}8internal20getPluginDescriptionEv";
constexpr auto SetImGuiContextSymbol = "_ZN3hex6plugin{0}{1}8internal15setImGuiContextEP12ImGuiContext";
- Plugin::Plugin(const fs::path &path) {
+ Plugin::Plugin(const fs::path &path) : m_path(path) {
this->m_handle = dlopen(path.string().c_str(), RTLD_LAZY);
if (this->m_handle == nullptr) {
@@ -33,6 +33,8 @@ namespace hex {
Plugin::Plugin(Plugin &&other) noexcept {
this->m_handle = other.m_handle;
+ this->m_path = std::move(other.m_path);
+
this->m_initializePluginFunction = other.m_initializePluginFunction;
this->m_getPluginNameFunction = other.m_getPluginNameFunction;
this->m_getPluginAuthorFunction = other.m_getPluginAuthorFunction;
@@ -52,9 +54,13 @@ namespace hex {
dlclose(this->m_handle);
}
- void Plugin::initializePlugin() const {
- if (this->m_initializePluginFunction != nullptr)
+ bool Plugin::initializePlugin() const {
+ if (this->m_initializePluginFunction != nullptr) {
this->m_initializePluginFunction();
+ return true;
+ } else {
+ return false;
+ }
}
std::string Plugin::getPluginName() const {
@@ -83,6 +89,12 @@ namespace hex {
this->m_setImGuiContextFunction(ctx);
}
+ const fs::path &Plugin::getPath() const {
+ return this->m_path;
+ }
+
+
+
bool PluginManager::load(const fs::path &pluginFolder) {
if (!fs::exists(pluginFolder))
return false;
diff --git a/main/source/init/splash_window.cpp b/main/source/init/splash_window.cpp
index 3576c9405..e0040fbf7 100644
--- a/main/source/init/splash_window.cpp
+++ b/main/source/init/splash_window.cpp
@@ -49,7 +49,8 @@ namespace hex::init {
try {
status = task() && status;
- } catch (...) {
+ } catch (std::exception &e) {
+ log::error("Init task {} threw an exception: {}", name, e.what());
status = false;
}
diff --git a/main/source/init/tasks.cpp b/main/source/init/tasks.cpp
index 5f4bb3164..f02b5c592 100644
--- a/main/source/init/tasks.cpp
+++ b/main/source/init/tasks.cpp
@@ -57,7 +57,7 @@ namespace hex::init {
bool createDirectories() {
bool result = true;
- std::array paths = {
+ constexpr std::array paths = {
ImHexPath::Patterns,
ImHexPath::PatternsInclude,
ImHexPath::Magic,
@@ -66,7 +66,8 @@ namespace hex::init {
ImHexPath::Config,
ImHexPath::Constants,
ImHexPath::Yara,
- ImHexPath::Python
+ ImHexPath::Python,
+ ImHexPath::Logs
};
for (auto path : paths) {
@@ -225,7 +226,8 @@ namespace hex::init {
}
for (const auto &plugin : PluginManager::getPlugins()) {
- plugin.initializePlugin();
+ if (!plugin.initializePlugin())
+ log::error("Failed to initialize plugin {}", plugin.getPath().filename().string());
}
return true;
diff --git a/main/source/window/linux_window.cpp b/main/source/window/linux_window.cpp
index 6a03987e4..5f9b9e5e9 100644
--- a/main/source/window/linux_window.cpp
+++ b/main/source/window/linux_window.cpp
@@ -3,13 +3,18 @@
#if defined(OS_LINUX)
#include
+ #include
+
#include
#include
+ #include
namespace hex {
void Window::initNative() {
-
+ if (!isatty(STDOUT_FILENO)) {
+ log::redirectToFile();
+ }
}
void Window::setupNativeWindow() {
diff --git a/main/source/window/macos_window.cpp b/main/source/window/macos_window.cpp
index fe5aa11fc..2e1fec93d 100644
--- a/main/source/window/macos_window.cpp
+++ b/main/source/window/macos_window.cpp
@@ -2,12 +2,17 @@
#if defined(OS_MACOS)
+ #include
+
#include
+ #include
namespace hex {
void Window::initNative() {
-
+ if (!isatty(STDOUT_FILENO)) {
+ log::redirectToFile();
+ }
}
void Window::setupNativeWindow() {
diff --git a/main/source/window/win_window.cpp b/main/source/window/win_window.cpp
index 28a9a6d12..01c950855 100644
--- a/main/source/window/win_window.cpp
+++ b/main/source/window/win_window.cpp
@@ -172,25 +172,26 @@
// Redirect cin, cout and cerr to that console
freopen("CONIN$", "r", stdin);
freopen("CONOUT$", "w", stdout);
- freopen("CONERR$", "w", stderr);
+ freopen("CONOUT$", "w", stderr);
setvbuf(stdin, nullptr, _IONBF, 0);
setvbuf(stdout, nullptr, _IONBF, 0);
setvbuf(stderr, nullptr, _IONBF, 0);
fmt::print("\n");
- }
-
- // Enable color format specifiers in console
- {
- auto hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);
- if (hConsole != INVALID_HANDLE_VALUE) {
- DWORD mode = 0;
- if (::GetConsoleMode(hConsole, &mode)) {
- mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
- ::SetConsoleMode(hConsole, mode);
+ // Enable color format specifiers in console
+ {
+ auto hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE);
+ if (hConsole != INVALID_HANDLE_VALUE) {
+ DWORD mode = 0;
+ if (::GetConsoleMode(hConsole, &mode)) {
+ mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT;
+ ::SetConsoleMode(hConsole, mode);
+ }
}
}
+ } else {
+ log::redirectToFile();
}
// Open new files in already existing ImHex instance