diff --git a/cmake/build_helpers.cmake b/cmake/build_helpers.cmake index d7785d1b7..f39cd9ff9 100644 --- a/cmake/build_helpers.cmake +++ b/cmake/build_helpers.cmake @@ -98,7 +98,7 @@ macro(configurePackingResources) endif() if (WIN32) - set(APPLICATION_TYPE) + set(APPLICATION_TYPE WIN32) set(IMHEX_ICON "${IMHEX_BASE_FOLDER}/resources/resource.rc") if (CREATE_PACKAGE) diff --git a/lib/libimhex/include/hex/api/imhex_api.hpp b/lib/libimhex/include/hex/api/imhex_api.hpp index db2e69777..5e8d67214 100644 --- a/lib/libimhex/include/hex/api/imhex_api.hpp +++ b/lib/libimhex/include/hex/api/imhex_api.hpp @@ -536,6 +536,13 @@ namespace hex { * @return Git commit branch */ std::string getCommitBranch(); + + enum class UpdateType { + Stable, + Nightly + }; + + bool updateImHex(UpdateType updateType); } /** diff --git a/lib/libimhex/include/hex/helpers/fmt.hpp b/lib/libimhex/include/hex/helpers/fmt.hpp index e674dde16..a424d8e0b 100644 --- a/lib/libimhex/include/hex/helpers/fmt.hpp +++ b/lib/libimhex/include/hex/helpers/fmt.hpp @@ -11,15 +11,4 @@ namespace hex { return fmt::format(fmt::runtime(format), args...); } - template - inline void print(std::string_view format, Args... args) { - fmt::print(fmt::runtime(format), args...); - } - - template - inline void println(std::string_view format, Args... args) { - fmt::print(fmt::runtime(format), args...); - fmt::print("\n"); - } - } \ No newline at end of file diff --git a/lib/libimhex/include/hex/helpers/logger.hpp b/lib/libimhex/include/hex/helpers/logger.hpp index b6dcf33d7..9ded39e7c 100644 --- a/lib/libimhex/include/hex/helpers/logger.hpp +++ b/lib/libimhex/include/hex/helpers/logger.hpp @@ -19,6 +19,7 @@ namespace hex::log { wolv::io::File& getFile(); bool isRedirected(); [[maybe_unused]] void redirectToFile(); + [[maybe_unused]] void enableColorPrinting(); extern std::mutex g_loggerMutex; @@ -50,8 +51,7 @@ namespace hex::log { fmt::print(dest, "{}", std::string(ProjectNameLength > 10 ? 0 : 10 - ProjectNameLength, ' ')); } - template - [[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) { + [[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto && ... args) { std::scoped_lock lock(impl::g_loggerMutex); auto dest = impl::getDestination(); @@ -66,7 +66,7 @@ namespace hex::log { } - [[maybe_unused]] void debug(const std::string &fmt, auto &&...args) { + [[maybe_unused]] void debug(const std::string &fmt, auto && ... args) { #if defined(DEBUG) hex::log::print(fg(fmt::color::light_green) | fmt::emphasis::bold, "[DEBUG]", fmt, args...); #else @@ -74,20 +74,39 @@ namespace hex::log { #endif } - [[maybe_unused]] void info(const std::string &fmt, auto &&...args) { + [[maybe_unused]] void info(const std::string &fmt, auto && ... args) { hex::log::print(fg(fmt::color::cadet_blue) | fmt::emphasis::bold, "[INFO] ", fmt, args...); } - [[maybe_unused]] void warn(const std::string &fmt, auto &&...args) { + [[maybe_unused]] void warn(const std::string &fmt, auto && ... args) { hex::log::print(fg(fmt::color::orange) | fmt::emphasis::bold, "[WARN] ", fmt, args...); } - [[maybe_unused]] void error(const std::string &fmt, auto &&...args) { + [[maybe_unused]] void error(const std::string &fmt, auto && ... args) { hex::log::print(fg(fmt::color::red) | fmt::emphasis::bold, "[ERROR]", fmt, args...); } - [[maybe_unused]] void fatal(const std::string &fmt, auto &&...args) { + [[maybe_unused]] void fatal(const std::string &fmt, auto && ... args) { hex::log::print(fg(fmt::color::purple) | fmt::emphasis::bold, "[FATAL]", fmt, args...); } + + [[maybe_unused]] void print(const std::string &fmt, auto && ... args) { + std::scoped_lock lock(impl::g_loggerMutex); + + auto dest = impl::getDestination(); + auto message = fmt::format(fmt::runtime(fmt), args...); + fmt::print(dest, "{}", message); + fflush(dest); + } + + [[maybe_unused]] void println(const std::string &fmt, auto && ... args) { + std::scoped_lock lock(impl::g_loggerMutex); + + auto dest = impl::getDestination(); + auto message = fmt::format(fmt::runtime(fmt), args...); + fmt::print(dest, "{}\n", message); + fflush(dest); + } + } \ No newline at end of file diff --git a/lib/libimhex/include/hex/helpers/utils.hpp b/lib/libimhex/include/hex/helpers/utils.hpp index ed9a0e72b..b7af49e99 100644 --- a/lib/libimhex/include/hex/helpers/utils.hpp +++ b/lib/libimhex/include/hex/helpers/utils.hpp @@ -59,7 +59,8 @@ namespace hex { [[nodiscard]] std::string toByteString(u64 bytes); [[nodiscard]] std::string makePrintable(u8 c); - void runCommand(const std::string &command); + void startProgram(const std::string &command); + int executeCommand(const std::string &command); void openWebpage(std::string url); [[nodiscard]] std::string encodeByteString(const std::vector &bytes); diff --git a/lib/libimhex/source/api/imhex_api.cpp b/lib/libimhex/source/api/imhex_api.cpp index 0eca8739c..2f02a5f12 100644 --- a/lib/libimhex/source/api/imhex_api.cpp +++ b/lib/libimhex/source/api/imhex_api.cpp @@ -5,8 +5,10 @@ #include #include #include +#include #include +#include #include #include @@ -639,6 +641,44 @@ namespace hex { #endif } + bool updateImHex(UpdateType updateType) { + // Get the path of the updater executable + std::fs::path executablePath; + + for (const auto &entry : std::fs::directory_iterator(wolv::io::fs::getExecutablePath()->parent_path())) { + if (entry.path().filename().string().starts_with("imhex-updater")) { + executablePath = entry.path(); + break; + } + } + + if (executablePath.empty() || !wolv::io::fs::exists(executablePath)) + return false; + + std::string updateTypeString; + switch (updateType) { + case UpdateType::Stable: + updateTypeString = "latest"; + break; + case UpdateType::Nightly: + updateTypeString = "nightly"; + break; + } + + EventManager::subscribe([executablePath, updateTypeString] { + hex::executeCommand( + hex::format("{} {}", + wolv::util::toUTF8String(executablePath), + updateTypeString + ) + ); + }); + + ImHexApi::System::closeImHex(); + + return true; + } + } namespace ImHexApi::Messaging { diff --git a/lib/libimhex/source/helpers/logger.cpp b/lib/libimhex/source/helpers/logger.cpp index e1f565727..a892f10d4 100644 --- a/lib/libimhex/source/helpers/logger.cpp +++ b/lib/libimhex/source/helpers/logger.cpp @@ -4,6 +4,10 @@ #include +#if defined(OS_WINDOWS) + #include +#endif + namespace hex::log::impl { static wolv::io::File s_loggerFile; @@ -36,6 +40,19 @@ namespace hex::log::impl { } } + void enableColorPrinting() { + #if defined(OS_WINDOWS) + auto hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE); + if (hConsole != INVALID_HANDLE_VALUE) { + DWORD mode = 0; + if (::GetConsoleMode(hConsole, &mode) == TRUE) { + mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT; + ::SetConsoleMode(hConsole, mode); + } + } + #endif + } + std::vector& getLogEntries() { static std::vector logEntries; diff --git a/lib/libimhex/source/helpers/utils.cpp b/lib/libimhex/source/helpers/utils.cpp index 1231fcb0a..5aed17aba 100644 --- a/lib/libimhex/source/helpers/utils.cpp +++ b/lib/libimhex/source/helpers/utils.cpp @@ -313,7 +313,7 @@ namespace hex { return std::to_string(value).substr(0, 5) + Suffixes[suffixIndex]; } - void runCommand(const std::string &command) { + void startProgram(const std::string &command) { #if defined(OS_WINDOWS) hex::unused(system(hex::format("start {0}", command).c_str())); @@ -326,6 +326,10 @@ namespace hex { #endif } + int executeCommand(const std::string &command) { + return ::system(command.c_str()); + } + void openWebpage(std::string url) { if (!url.contains("://")) url = "https://" + url; diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 43688d434..068970440 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -7,4 +7,8 @@ endif () add_subdirectory(gui) if (WIN32) add_subdirectory(forwarder) +endif () + +if (NOT EMSCRIPTEN) + add_subdirectory(updater) endif () \ No newline at end of file diff --git a/main/forwarder/source/main.cpp b/main/forwarder/source/main.cpp index 5a31c9c00..e43fc639f 100644 --- a/main/forwarder/source/main.cpp +++ b/main/forwarder/source/main.cpp @@ -28,8 +28,11 @@ #include -void handleConsoleWindow() { +void setupConsoleWindow() { + // Get the handle of the console window HWND consoleWindow = ::GetConsoleWindow(); + + // Get console process ID DWORD processId = 0; ::GetWindowThreadProcessId(consoleWindow, &processId); @@ -48,6 +51,11 @@ void handleConsoleWindow() { ::SetConsoleMode(hConsole, mode); } } + + // Set the __IMHEX_FORWARD_CONSOLE__ environment variable, + // to let ImHex know that it was launched from the forwarder + // and that it should forward it's console output to us + ::SetEnvironmentVariableA("__IMHEX_FORWARD_CONSOLE__", "1"); } } @@ -57,23 +65,26 @@ int launchExecutable() { auto executableFullPath = executablePath->parent_path() / "imhex-gui.exe"; ::PROCESS_INFORMATION process = { }; - ::STARTUPINFOW startupInfo = { }; - startupInfo.cb = sizeof(STARTUPINFOW); + ::STARTUPINFOW startupInfo = { .cb = sizeof(::STARTUPINFOW) }; // Create a new process for imhex-gui.exe with the same command line as the current process if (::CreateProcessW(executableFullPath.wstring().c_str(), ::GetCommandLineW(), nullptr, nullptr, FALSE, 0, nullptr, nullptr, &startupInfo, &process) == FALSE) { // Handle error if the process could not be created + // Get formatted error message from the OS auto errorCode = ::GetLastError(); auto errorMessageString = std::system_category().message(errorCode); + // Generate error message auto errorMessage = fmt::format("Failed to start ImHex:\n\nError code: 0x{:08X}\n\n{}", errorCode, errorMessageString); + // Display a message box with the error ::MessageBoxA(nullptr, errorMessage.c_str(), "ImHex Forwarder", MB_OK | MB_ICONERROR); return EXIT_FAILURE; } + // Wait for the main ImHex process to exit ::WaitForSingleObject(process.hProcess, INFINITE); ::CloseHandle(process.hProcess); @@ -81,8 +92,7 @@ int launchExecutable() { } int main() { - handleConsoleWindow(); - auto result = launchExecutable(); + setupConsoleWindow(); - return result; + return launchExecutable(); } \ No newline at end of file diff --git a/main/gui/source/crash_handlers.cpp b/main/gui/source/crash_handlers.cpp index cd88cea4a..4cd822189 100644 --- a/main/gui/source/crash_handlers.cpp +++ b/main/gui/source/crash_handlers.cpp @@ -32,7 +32,7 @@ namespace hex::crash { void resetCrashHandlers(); static void sendNativeMessage(const std::string& message) { - hex::nativeErrorMessage(hex::format("ImHex crashed during its loading.\nError: {}", message)); + hex::nativeErrorMessage(hex::format("ImHex crashed during initial setup!\nError: {}", message)); } // Function that decides what should happen on a crash @@ -136,15 +136,14 @@ namespace hex::crash { // Reset crash handlers, so we can't have a recursion if this code crashes resetCrashHandlers(); - handleCrash("Uncaught exception!"); - // Print the current exception info try { std::rethrow_exception(std::current_exception()); } catch (std::exception &ex) { std::string exceptionStr = hex::format("{}()::what() -> {}", llvm::itaniumDemangle(typeid(ex).name(), nullptr, nullptr, nullptr), ex.what()); - log::fatal("Program terminated with uncaught exception: {}", exceptionStr); + handleCrash(exceptionStr); + log::fatal("Program terminated with uncaught exception: {}", exceptionStr); } triggerSafeShutdown(); diff --git a/main/gui/source/main.cpp b/main/gui/source/main.cpp index 0c2885ce8..9a221ccd1 100644 --- a/main/gui/source/main.cpp +++ b/main/gui/source/main.cpp @@ -18,6 +18,7 @@ #include #include +#include #if defined(OS_WEB) #include diff --git a/main/gui/source/window/win_window.cpp b/main/gui/source/window/win_window.cpp index 880c1d3ae..95860efbc 100644 --- a/main/gui/source/window/win_window.cpp +++ b/main/gui/source/window/win_window.cpp @@ -26,6 +26,7 @@ #include #include #include + #include #include #include @@ -231,22 +232,52 @@ namespace hex { } + static void reopenConsoleHandle(u32 stdHandleNumber, i32 stdFileDescriptor, FILE *stdStream) { + // Get the Windows handle for the standard stream + HANDLE handle = ::GetStdHandle(stdHandleNumber); + + // Redirect the standard stream to the relevant console stream + if (stdFileDescriptor == STDIN_FILENO) + freopen("CONIN$", "rt", stdStream); + else + freopen("CONOUT$", "wt", stdStream); + + // Disable buffering + setvbuf(stdStream, nullptr, _IONBF, 0); + + // Reopen the standard stream as a file descriptor + auto unboundFd = [stdFileDescriptor, handle]{ + if (stdFileDescriptor == STDIN_FILENO) + return _open_osfhandle(intptr_t(handle), _O_RDONLY); + else + return _open_osfhandle(intptr_t(handle), _O_WRONLY); + }(); + + // Duplicate the file descriptor to the standard stream + dup2(unboundFd, stdFileDescriptor); + } + + void Window::initNative() { - HWND consoleWindow = ::GetConsoleWindow(); - DWORD processId = 0; - ::GetWindowThreadProcessId(consoleWindow, &processId); - if (GetCurrentProcessId() == processId) { - ShowWindow(consoleWindow, SW_HIDE); - log::impl::redirectToFile(); + // Check for the __IMHEX_FORWARD_CONSOLE__ environment variable that was set by the forwarder application + // If it's present attach to its console window + if (hex::getEnvironmentVariable("__IMHEX_FORWARD_CONSOLE__") == "1") { + ::AttachConsole(ATTACH_PARENT_PROCESS); + + // Reopen stdin, stdout and stderr to the console + reopenConsoleHandle(STD_INPUT_HANDLE, STDIN_FILENO, stdin); + reopenConsoleHandle(STD_OUTPUT_HANDLE, STDOUT_FILENO, stdout); + + // Explicitly don't forward stderr because some libraries like to write to it + // with no way to disable it (e.g., libmagic) + /* + reopenConsoleHandle(STD_ERROR_HANDLE, STDERR_FILENO, stderr); + */ + + // Enable ANSI colors in the console + log::impl::enableColorPrinting(); } else { - auto hConsole = ::GetStdHandle(STD_OUTPUT_HANDLE); - if (hConsole != INVALID_HANDLE_VALUE) { - DWORD mode = 0; - if (::GetConsoleMode(hConsole, &mode) == TRUE) { - mode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING | ENABLE_PROCESSED_OUTPUT; - ::SetConsoleMode(hConsole, mode); - } - } + log::impl::redirectToFile(); } ImHexApi::System::impl::setBorderlessWindowMode(true); @@ -256,11 +287,6 @@ namespace hex { if (std::fs::exists(path)) AddDllDirectory(path.c_str()); } - - // Various libraries sadly directly print to stderr with no way to disable it - // We redirect stderr to NUL to prevent this - freopen("NUL:", "w", stderr); - setvbuf(stderr, nullptr, _IONBF, 0); } void Window::setupNativeWindow() { diff --git a/main/updater/CMakeLists.txt b/main/updater/CMakeLists.txt new file mode 100644 index 000000000..ef9ba01f6 --- /dev/null +++ b/main/updater/CMakeLists.txt @@ -0,0 +1,15 @@ +project(updater) + +add_executable(updater ${APPLICATION_TYPE} + source/main.cpp +) + +add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}") +target_link_libraries(updater PRIVATE libimhex libwolv-io ${FMT_LIBRARIES}) +add_dependencies(imhex_all updater) +set_target_properties(updater PROPERTIES + OUTPUT_NAME "imhex-updater" + RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/../.. + CXX_VISIBILITY_PRESET hidden + POSITION_INDEPENDENT_CODE ON +) \ No newline at end of file diff --git a/main/updater/source/main.cpp b/main/updater/source/main.cpp new file mode 100644 index 000000000..33b286379 --- /dev/null +++ b/main/updater/source/main.cpp @@ -0,0 +1,167 @@ +#include +#include + +#include +#include + +using namespace std::literals::string_literals; + +std::string getUpdateUrl(std::string_view versionType, std::string_view operatingSystem) { + // Get the latest version info from the ImHex API + auto response = hex::HttpRequest("GET", + ImHexApiURL + fmt::format("/update/{}/{}", + versionType, + operatingSystem + ) + ).execute().get(); + + const auto &data = response.getData(); + + // Make sure we got a valid response + if (!response.isSuccess()) { + hex::log::error("Failed to get latest version info: ({}) {}", response.getStatusCode(), data); + + return { }; + } + + return data; +} + +std::optional downloadUpdate(const std::string &url, const std::string &type) { + // Download the update + auto response = hex::HttpRequest("GET", url).downloadFile().get(); + + // Make sure we got a valid response + if (!response.isSuccess()) { + hex::log::error("Failed to download update"); + return std::nullopt; + } + + const auto &data = response.getData(); + + // Write the update to a file + std::fs::path filePath; + { + constexpr static auto UpdateFileName = "update.hexupd"; + + // Loop over all available paths + wolv::io::File file; + for (const auto &path : hex::fs::getDefaultPaths(hex::fs::ImHexPath::Config)) { + // Remove any existing update files + wolv::io::fs::remove(path / UpdateFileName); + + // If a valid location hasn't been found already, try to create a new file + if (!file.isValid()) + file = wolv::io::File(path / UpdateFileName, wolv::io::File::Mode::Create); + } + + // If the update data can't be written to any of the default paths, the update cannot continue + if (!file.isValid()) { + hex::log::error("Failed to create update file"); + return std::nullopt; + } + + // Write the downloaded update data to the file + file.writeVector(data); + + // Save the path to the update file + filePath = file.getPath(); + } + + return filePath; +} + +std::string getUpdateType() { + #if defined (OS_WINDOWS) + if (!hex::ImHexApi::System::isPortableVersion()) + return "win-msi"; + #elif defined (OS_MACOS) + return "mac-dmg"; + #elif defined (OS_LINUX) + if (hex::executeCommand("lsb_release -a | grep Ubuntu") == 0) { + if (hex::executeCommand("lsb_release -a | grep 22.") == 0) + return "linux-deb-22.04"; + else if (hex::executeCommand("lsb_release -a | grep 23.") == 0) + return "linux-deb-23.04"; + } + #endif + + return ""; +} + +int installUpdate(const std::string &type, std::fs::path updatePath) { + struct UpdateHandler { + const char *type; + const char *extension; + const char *command; + }; + + constexpr static auto UpdateHandlers = { + UpdateHandler { "win-msi", ".msi", "msiexec /fa {} /passive" }, + UpdateHandler { "macos-dmg", ".dmg", "hdiutil attach {}" }, + UpdateHandler { "linux-deb-22.04", ".deb", "sudo apt update && sudo apt install -y --fix-broken {}" }, + UpdateHandler { "linux-deb-23.04", ".deb", "sudo apt update && sudo apt install -y --fix-broken {}" }, + }; + + for (const auto &handler : UpdateHandlers) { + if (type == handler.type) { + // Rename the update file to the correct extension + updatePath.replace_extension(handler.extension); + std::fs::rename(updatePath, updatePath); + + // Install the update using the correct command + hex::startProgram(hex::format(handler.command, updatePath.string())); + + return EXIT_SUCCESS; + } + } + + // If the installation type isn't handled here, the detected installation type doesn't support updates through the updater + hex::log::error("Install type cannot be updated"); + + // Open the latest release page in the default browser to allow the user to manually update + hex::openWebpage("https://github.com/WerWolv/ImHex/releases/latest"); + + return EXIT_FAILURE; +} + +int main(int argc, char **argv) { + hex::log::impl::enableColorPrinting(); + + // Check we have the correct number of arguments + if (argc != 2) { + hex::log::error("Failed to start updater: Invalid arguments"); + return EXIT_FAILURE; + } + + // Read the version type from the arguments + const auto versionType = argv[1]; + hex::log::info("Updater started with version type: {}", versionType); + + // Query the update type + const auto updateType = getUpdateType(); + hex::log::info("Detected OS String: {}", updateType); + + // Make sure we got a valid update type + if (updateType.empty()) { + hex::log::error("Failed to detect installation type"); + return EXIT_FAILURE; + } + + // Get the url to the requested update from the ImHex API + const auto updateUrl = getUpdateUrl(versionType, updateType); + if (updateUrl.empty()) { + hex::log::error("Failed to get update URL"); + return EXIT_FAILURE; + } + + hex::log::info("Update URL found: {}", updateUrl); + + // Download the update file + auto updatePath = downloadUpdate(updateUrl, updateType); + if (!updatePath.has_value()) + return EXIT_FAILURE; + + // Install the update + return installUpdate(updateType, *updatePath); +} \ No newline at end of file diff --git a/plugins/builtin/source/content/command_line_interface.cpp b/plugins/builtin/source/content/command_line_interface.cpp index ae751f692..fd1b91761 100644 --- a/plugins/builtin/source/content/command_line_interface.cpp +++ b/plugins/builtin/source/content/command_line_interface.cpp @@ -26,7 +26,7 @@ namespace hex::plugin::builtin { void handleVersionCommand(const std::vector &args) { hex::unused(args); - hex::print(romfs::get("logo.ans").string(), + hex::log::print(std::string(romfs::get("logo.ans").string()), ImHexApi::System::getImHexVersion(), ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash(), __DATE__, __TIME__, @@ -38,7 +38,7 @@ namespace hex::plugin::builtin { void handleHelpCommand(const std::vector &args) { hex::unused(args); - hex::print( + hex::log::print( "ImHex - A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.\n" "\n" "usage: imhex [subcommand] [options]\n" @@ -54,7 +54,7 @@ namespace hex::plugin::builtin { for (const auto &plugin : PluginManager::getPlugins()) { for (const auto &subCommand : plugin.getSubCommands()) { - hex::println(" --{}{: <{}} {}", subCommand.commandKey, "", longestCommand - subCommand.commandKey.size(), subCommand.commandDesc); + hex::log::println(" --{}{: <{}} {}", subCommand.commandKey, "", longestCommand - subCommand.commandKey.size(), subCommand.commandDesc); } } @@ -63,7 +63,7 @@ namespace hex::plugin::builtin { void handleOpenCommand(const std::vector &args) { if (args.empty()) { - hex::println("No files provided to open."); + hex::log::println("No files provided to open."); std::exit(EXIT_FAILURE); } @@ -89,8 +89,8 @@ namespace hex::plugin::builtin { void handleCalcCommand(const std::vector &args) { if (args.empty()) { - hex::println("No expression provided!"); - hex::println("Example: imhex --calc \"5 * 7\""); + hex::log::println("No expression provided!"); + hex::log::println("Example: imhex --calc \"5 * 7\""); std::exit(EXIT_FAILURE); } @@ -100,9 +100,9 @@ namespace hex::plugin::builtin { auto result = evaluator.evaluate(input); if (!result.has_value()) - hex::println("{}\n> '{}'", evaluator.getLastError().value(), input); + hex::log::println("{}\n> '{}'", evaluator.getLastError().value(), input); else - hex::println("{}", result.value()); + hex::log::println("{}", result.value()); std::exit(EXIT_SUCCESS); } @@ -110,19 +110,19 @@ namespace hex::plugin::builtin { void handlePluginsCommand(const std::vector &args) { hex::unused(args); - hex::println("Loaded plugins:"); + hex::log::println("Loaded plugins:"); for (const auto &plugin : PluginManager::getPlugins()) { - hex::print("- "); + hex::log::print("- "); if (plugin.isBuiltinPlugin()) - hex::print("\033[1;43m{}\033[0m", plugin.getPluginName()); + hex::log::print("\033[1;43m{}\033[0m", plugin.getPluginName()); else - hex::print("\033[1m{}\033[0m", plugin.getPluginName()); + hex::log::print("\033[1m{}\033[0m", plugin.getPluginName()); - hex::println(" by {}", plugin.getPluginAuthor()); + hex::log::println(" by {}", plugin.getPluginAuthor()); - hex::println(" \033[2;3m{}\033[0m", plugin.getPluginDescription()); + hex::log::println(" \033[2;3m{}\033[0m", plugin.getPluginDescription()); } std::exit(EXIT_SUCCESS); @@ -130,8 +130,8 @@ namespace hex::plugin::builtin { void handleHashCommand(const std::vector &args) { if (args.size() != 2) { - hex::println("usage: imhex --hash "); - hex::println("Available algorithms: md5, sha1, sha224, sha256, sha384, sha512"); + hex::log::println("usage: imhex --hash "); + hex::log::println("Available algorithms: md5, sha1, sha224, sha256, sha384, sha512"); std::exit(EXIT_FAILURE); } @@ -140,7 +140,7 @@ namespace hex::plugin::builtin { wolv::io::File file(filePath, wolv::io::File::Mode::Read); if (!file.isValid()) { - hex::println("Failed to open file: {}", wolv::util::toUTF8String(filePath)); + hex::log::println("Failed to open file: {}", wolv::util::toUTF8String(filePath)); std::exit(EXIT_FAILURE); } @@ -162,20 +162,20 @@ namespace hex::plugin::builtin { } else if (algorithm == "sha512") { result = toVector(hex::crypt::sha512(file.readVector())); } else { - hex::println("Unknown algorithm: {}", algorithm); - hex::println("Available algorithms: md5, sha1, sha224, sha256, sha384, sha512"); + hex::log::println("Unknown algorithm: {}", algorithm); + hex::log::println("Available algorithms: md5, sha1, sha224, sha256, sha384, sha512"); std::exit(EXIT_FAILURE); } - hex::println("{}({}) = {}", algorithm, wolv::util::toUTF8String(filePath.filename()), hex::crypt::encode16(result)); + hex::log::println("{}({}) = {}", algorithm, wolv::util::toUTF8String(filePath.filename()), hex::crypt::encode16(result)); std::exit(EXIT_SUCCESS); } void handleEncodeCommand(const std::vector &args) { if (args.size() != 2) { - hex::println("usage: imhex --encode "); - hex::println("Available algorithms: base64, hex"); + hex::log::println("usage: imhex --encode "); + hex::log::println("Available algorithms: base64, hex"); std::exit(EXIT_FAILURE); } @@ -189,19 +189,19 @@ namespace hex::plugin::builtin { } else if (algorithm == "hex") { result = hex::crypt::encode16(data); } else { - hex::println("Unknown algorithm: {}", algorithm); - hex::println("Available algorithms: base64, hex"); + hex::log::println("Unknown algorithm: {}", algorithm); + hex::log::println("Available algorithms: base64, hex"); std::exit(EXIT_FAILURE); } - hex::println("encode_{}({}) = {}", algorithm, args[1], result); + hex::log::println("encode_{}({}) = {}", algorithm, args[1], result); std::exit(EXIT_SUCCESS); } void handleDecodeCommand(const std::vector &args) { if (args.size() != 2) { - hex::println("usage: imhex --decode "); - hex::println("Available algorithms: base64, hex"); + hex::log::println("usage: imhex --decode "); + hex::log::println("Available algorithms: base64, hex"); std::exit(EXIT_FAILURE); } @@ -216,24 +216,24 @@ namespace hex::plugin::builtin { auto base16 = hex::crypt::decode16(std::string(data.begin(), data.end())); result = std::string(base16.begin(), base16.end()); } else { - hex::println("Unknown algorithm: {}", algorithm); - hex::println("Available algorithms: base64, hex"); + hex::log::println("Unknown algorithm: {}", algorithm); + hex::log::println("Available algorithms: base64, hex"); std::exit(EXIT_FAILURE); } - hex::print("decode_{}({}) = {}", algorithm, args[1], result); + hex::log::print("decode_{}({}) = {}", algorithm, args[1], result); std::exit(EXIT_SUCCESS); } void handleMagicCommand(const std::vector &args) { if (args.size() != 2) { - hex::println("usage: imhex --magic "); - hex::println("Available operations: mime, desc"); + hex::log::println("usage: imhex --magic "); + hex::log::println("Available operations: mime, desc"); std::exit(EXIT_FAILURE); } if (!magic::compile()) { - hex::print("Failed to compile magic database!"); + hex::log::print("Failed to compile magic database!"); std::exit(EXIT_FAILURE); } @@ -242,7 +242,7 @@ namespace hex::plugin::builtin { wolv::io::File file(filePath, wolv::io::File::Mode::Read); if (!file.isValid()) { - hex::println("Failed to open file: {}", wolv::util::toUTF8String(filePath)); + hex::log::println("Failed to open file: {}", wolv::util::toUTF8String(filePath)); std::exit(EXIT_FAILURE); } @@ -250,13 +250,13 @@ namespace hex::plugin::builtin { if (operation == "mime") { auto result = magic::getMIMEType(data); - hex::println("{}", result); + hex::log::println("{}", result); } else if (operation == "desc") { auto result = magic::getDescription(data); - hex::println("{}", result); + hex::log::println("{}", result); } else { - hex::println("Unknown operation: {}", operation); - hex::println("Available operations: mime, desc"); + hex::log::println("Unknown operation: {}", operation); + hex::log::println("Available operations: mime, desc"); std::exit(EXIT_FAILURE); } diff --git a/plugins/builtin/source/content/command_palette_commands.cpp b/plugins/builtin/source/content/command_palette_commands.cpp index 30845dc59..d8308b8ca 100644 --- a/plugins/builtin/source/content/command_palette_commands.cpp +++ b/plugins/builtin/source/content/command_palette_commands.cpp @@ -52,7 +52,7 @@ namespace hex::plugin::builtin { return hex::format("hex.builtin.command.cmd.result"_lang, input.data()); }, [](auto input) { - hex::runCommand(input); + hex::executeCommand(input); }); ContentRegistry::CommandPaletteCommands::addHandler( diff --git a/plugins/builtin/source/content/welcome_screen.cpp b/plugins/builtin/source/content/welcome_screen.cpp index 26c393f07..e391e0ff3 100644 --- a/plugins/builtin/source/content/welcome_screen.cpp +++ b/plugins/builtin/source/content/welcome_screen.cpp @@ -211,7 +211,7 @@ namespace hex::plugin::builtin { ImGui::UnderlinedText("hex.builtin.welcome.header.update"_lang); { if (ImGui::DescriptionButton("hex.builtin.welcome.update.title"_lang, hex::format("hex.builtin.welcome.update.desc"_lang, ImHexApi::System::getInitArguments()["update-available"]).c_str(), ImVec2(ImGui::GetContentRegionAvail().x * 0.8F, 0))) - hex::openWebpage("hex.builtin.welcome.update.link"_lang); + ImHexApi::System::updateImHex(ImHexApi::System::UpdateType::Stable); } } diff --git a/resources/resource.rc b/resources/resource.rc index bb524e2af..0b8d27fe3 100644 --- a/resources/resource.rc +++ b/resources/resource.rc @@ -19,9 +19,8 @@ GLFW_ICON ICON dist/windows/icon.ico BEGIN BLOCK "080904b0" BEGIN - VALUE "FileDescription", "🔍 A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM." VALUE "CompanyName", "WerWolv" - VALUE "FileDescription", "ImHex Hex Editor" + VALUE "FileDescription", "ImHex Hex Editor 🔍" VALUE "LegalCopyright", "WerWolv 2020-2023" VALUE "OriginalFilename", "imhex.exe" VALUE "ProductName", "ImHex"