From e9450b490f23ca7f6a513c44483377ab6a4b7455 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Sun, 16 Jul 2023 23:46:41 +0200 Subject: [PATCH] feat: Added --plugin, --calc, --hash, --encode and --decode subcommands --- .../source/subcommands/subcommands.cpp | 4 +- main/source/main.cpp | 7 +- plugins/builtin/CMakeLists.txt | 1 + .../content/command_line_interface.hpp | 22 ++ .../source/content/command_line_interface.cpp | 224 ++++++++++++++++++ plugins/builtin/source/plugin_builtin.cpp | 70 +----- 6 files changed, 265 insertions(+), 63 deletions(-) create mode 100644 plugins/builtin/include/content/command_line_interface.hpp create mode 100644 plugins/builtin/source/content/command_line_interface.cpp diff --git a/lib/libimhex/source/subcommands/subcommands.cpp b/lib/libimhex/source/subcommands/subcommands.cpp index 1e496ef9f..8971d7ad5 100644 --- a/lib/libimhex/source/subcommands/subcommands.cpp +++ b/lib/libimhex/source/subcommands/subcommands.cpp @@ -55,7 +55,7 @@ namespace hex::subcommands { if (arg == "--othercmd") { // save command to run if (currentSubCommand) { - subCommands.push_back({*currentSubCommand, currentSubCommandArgs}); + subCommands.emplace_back(*currentSubCommand, currentSubCommandArgs); } currentSubCommand = std::nullopt; @@ -78,7 +78,7 @@ namespace hex::subcommands { // save last command to run if (currentSubCommand) { - subCommands.push_back({*currentSubCommand, currentSubCommandArgs}); + subCommands.emplace_back(*currentSubCommand, currentSubCommandArgs); } // run the subcommands diff --git a/main/source/main.cpp b/main/source/main.cpp index 88401f7d0..16f5ae0e5 100644 --- a/main/source/main.cpp +++ b/main/source/main.cpp @@ -30,9 +30,6 @@ void loadPlugins() { int main(int argc, char **argv, char **envp) { Window::initNative(); - log::info("Welcome to ImHex {}!", ImHexApi::System::getImHexVersion()); - log::info("Compiled using commit {}@{}", ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash()); - hex::crash::setupCrashHandlers(); hex::unused(envp); @@ -43,6 +40,10 @@ int main(int argc, char **argv, char **envp) { hex::messaging::setupMessaging(); hex::subcommands::processArguments(args); + log::info("Welcome to ImHex {}!", ImHexApi::System::getImHexVersion()); + log::info("Compiled using commit {}@{}", ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash()); + + // Check if ImHex is installed in portable mode { if (const auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value()) { diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index 9624790c7..acbde6d8d 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(${PROJECT_NAME} SHARED source/content/background_services.cpp source/content/command_palette_commands.cpp + source/content/command_line_interface.cpp source/content/communication_interface.cpp source/content/data_inspector.cpp source/content/pl_builtin_functions.cpp diff --git a/plugins/builtin/include/content/command_line_interface.hpp b/plugins/builtin/include/content/command_line_interface.hpp new file mode 100644 index 000000000..3db0f45ee --- /dev/null +++ b/plugins/builtin/include/content/command_line_interface.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include +#include + +namespace hex::plugin::builtin { + + void handleVersionCommand(const std::vector &args); + void handleHelpCommand(const std::vector &args); + void handlePluginsCommand(const std::vector &args); + + void handleOpenCommand(const std::vector &args); + + void handleCalcCommand(const std::vector &args); + void handleHashCommand(const std::vector &args); + void handleEncodeCommand(const std::vector &args); + void handleDecodeCommand(const std::vector &args); + + + void registerCommandForwarders(); + +} \ 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 new file mode 100644 index 000000000..a5b04592a --- /dev/null +++ b/plugins/builtin/source/content/command_line_interface.cpp @@ -0,0 +1,224 @@ +#include "content/command_line_interface.hpp" + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include + +#include "content/helpers/math_evaluator.hpp" + +namespace hex::plugin::builtin { + + void handleVersionCommand(const std::vector &args) { + hex::unused(args); + + hex::print(romfs::get("logo.ans").string(), + ImHexApi::System::getImHexVersion(), + ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash(), + __DATE__, __TIME__, + ImHexApi::System::isPortableVersion() ? "Portable" : "Installed"); + + std::exit(EXIT_SUCCESS); + } + + void handleHelpCommand(const std::vector &args) { + hex::unused(args); + + hex::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" + "Available subcommands:\n" + ); + + size_t longestCommand = 0; + for (const auto &plugin : PluginManager::getPlugins()) { + for (const auto &subCommand : plugin.getSubCommands()) { + longestCommand = std::max(longestCommand, subCommand.commandKey.size()); + } + } + + for (const auto &plugin : PluginManager::getPlugins()) { + for (const auto &subCommand : plugin.getSubCommands()) { + hex::print(" --{}{: <{}} {}\n", subCommand.commandKey, "", longestCommand - subCommand.commandKey.size(), subCommand.commandDesc); + } + } + + std::exit(EXIT_SUCCESS); + } + + void handleOpenCommand(const std::vector &args) { + if (args.empty()) { + hex::print("No files provided to open."); + std::exit(EXIT_FAILURE); + } + + std::vector fullPaths; + bool doubleDashFound = false; + for (auto &arg : args) { + + // Skip the first argument named `--` + if (arg == "--" && !doubleDashFound) { + doubleDashFound = true; + } else { + auto path = std::filesystem::weakly_canonical(arg); + fullPaths.push_back(wolv::util::toUTF8String(path)); + } + } + + hex::subcommands::forwardSubCommand("open", fullPaths); + } + + void handleCalcCommand(const std::vector &args) { + if (args.empty()) { + hex::print("No expression provided!"); + std::exit(EXIT_FAILURE); + } + + MathEvaluator evaluator; + + auto input = hex::format("{}", fmt::join(args, " ")); + auto result = evaluator.evaluate(input); + + if (!result.has_value()) + hex::print("{}\n> '{}'", evaluator.getLastError().value(), input); + else + hex::print("{}", result.value()); + + std::exit(EXIT_SUCCESS); + } + + void handlePluginsCommand(const std::vector &args) { + hex::unused(args); + + hex::print("Loaded plugins:\n"); + + for (const auto &plugin : PluginManager::getPlugins()) { + hex::print("- "); + + if (plugin.isBuiltinPlugin()) + hex::print("{}", fmt::styled(plugin.getPluginName(), fmt::emphasis::bold | fmt::bg(fmt::terminal_color::yellow))); + else + hex::print("{}", fmt::styled(plugin.getPluginName(), fmt::emphasis::bold)); + + hex::print(" by {}\n", plugin.getPluginAuthor()); + + hex::print(" {}\n", fmt::styled(plugin.getPluginDescription(), fmt::emphasis::italic | fmt::emphasis::faint)); + } + + std::exit(EXIT_SUCCESS); + } + + void handleHashCommand(const std::vector &args) { + if (args.size() != 2) { + hex::print("usage: imhex --hash "); + std::exit(EXIT_FAILURE); + } + + const auto &algorithm = args[0]; + const auto &filePath = std::fs::path(args[1]); + + wolv::io::File file(filePath, wolv::io::File::Mode::Read); + if (!file.isValid()) { + hex::print("Failed to open file: {}", wolv::util::toUTF8String(filePath)); + std::exit(EXIT_FAILURE); + } + + constexpr static auto toVector = [](const auto &data) { + return std::vector(data.begin(), data.end()); + }; + + std::vector result; + if (algorithm == "md5") { + result = toVector(hex::crypt::md5(file.readVector())); + } else if (algorithm == "sha1") { + result = toVector(hex::crypt::sha1(file.readVector())); + } else if (algorithm == "sha224") { + result = toVector(hex::crypt::sha224(file.readVector())); + } else if (algorithm == "sha256") { + result = toVector(hex::crypt::sha256(file.readVector())); + } else if (algorithm == "sha384") { + result = toVector(hex::crypt::sha384(file.readVector())); + } else if (algorithm == "sha512") { + result = toVector(hex::crypt::sha512(file.readVector())); + } else { + hex::print("Unknown algorithm: {}", algorithm); + hex::print("Available algorithms: md5, sha1, sha224, sha256, sha384, sha512"); + std::exit(EXIT_FAILURE); + } + + hex::print("{}({}) = {}", 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::print("usage: imhex --encode "); + std::exit(EXIT_FAILURE); + } + + const auto &algorithm = args[0]; + const auto &data = std::vector(args[1].begin(), args[1].end()); + + std::string result; + if (algorithm == "base64") { + auto base64 = hex::crypt::encode64(data); + result = std::string(base64.begin(), base64.end()); + } else if (algorithm == "hex") { + result = hex::crypt::encode16(data); + } else { + hex::print("Unknown algorithm: {}", algorithm); + hex::print("Available algorithms: base64, hex"); + std::exit(EXIT_FAILURE); + } + + hex::print("encode_{}({}) = {}", algorithm, args[1], result); + std::exit(EXIT_SUCCESS); + } + + void handleDecodeCommand(const std::vector &args) { + if (args.size() != 2) { + hex::print("usage: imhex --decode "); + std::exit(EXIT_FAILURE); + } + + const auto &algorithm = args[0]; + const auto &data = std::vector(args[1].begin(), args[1].end()); + + std::string result; + if (algorithm == "base64") { + auto base64 = hex::crypt::decode64(data); + result = std::string(base64.begin(), base64.end()); + } else if (algorithm == "hex") { + auto base16 = hex::crypt::decode16(std::string(data.begin(), data.end())); + result = std::string(base16.begin(), base16.end()); + } else { + hex::print("Unknown algorithm: {}", algorithm); + hex::print("Available algorithms: base64, hex"); + std::exit(EXIT_FAILURE); + } + + hex::print("decode_{}({}) = {}", algorithm, args[1], result); + std::exit(EXIT_SUCCESS); + } + + + void registerCommandForwarders() { + hex::subcommands::registerSubCommand("open", [](const std::vector &args){ + for (auto &arg : args) { + EventManager::post(arg); + } + }); + } + +} \ No newline at end of file diff --git a/plugins/builtin/source/plugin_builtin.cpp b/plugins/builtin/source/plugin_builtin.cpp index a4f96a755..5f10b5043 100644 --- a/plugins/builtin/source/plugin_builtin.cpp +++ b/plugins/builtin/source/plugin_builtin.cpp @@ -1,13 +1,14 @@ #include -#include -#include #include #include +#include #include #include +#include "content/command_line_interface.hpp" + using namespace hex; namespace hex::plugin::builtin { @@ -45,67 +46,19 @@ namespace hex::plugin::builtin { void handleBorderlessWindowMode(); - void handleSubCommands(); - } IMHEX_PLUGIN_SUBCOMMANDS() { - { "version", "Print ImHex version and exit", [](const std::vector&) { - hex::print(romfs::get("logo.ans").string(), - ImHexApi::System::getImHexVersion(), - ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash(), - __DATE__, __TIME__, - ImHexApi::System::isPortableVersion() ? "Portable" : "Installed"); + { "help", "Print help about this command", hex::plugin::builtin::handleHelpCommand }, + { "version", "Print ImHex version", hex::plugin::builtin::handleVersionCommand }, + { "plugins", "Lists all plugins that have been installed", hex::plugin::builtin::handlePluginsCommand }, - exit(EXIT_SUCCESS); - }}, - { "help", "Print help about this command and exit", [](const std::vector&) { - hex::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" - "Available subcommands:\n" - ); + { "open", "Open files passed as argument. [default]", hex::plugin::builtin::handleOpenCommand }, - size_t longestCommand = 0; - for (const auto &plugin : PluginManager::getPlugins()) { - for (const auto &subCommand : plugin.getSubCommands()) { - longestCommand = std::max(longestCommand, subCommand.commandKey.size()); - } - } - - for (const auto &plugin : PluginManager::getPlugins()) { - for (const auto &subCommand : plugin.getSubCommands()) { - hex::print(" --{}{: <{}} {}\n", subCommand.commandKey, "", longestCommand - subCommand.commandKey.size(), subCommand.commandDesc); - } - } - - exit(EXIT_SUCCESS); - }}, - { "open", "Open files passed as argument. This is the default subcommand is none is entered", - [](const std::vector &args) { - - hex::subcommands::registerSubCommand("open", [](const std::vector &args){ - for (auto &arg : args) { - EventManager::post(arg); - } - }); - - std::vector fullPaths; - bool doubleDashFound = false; - for (auto &arg : args) { - - // Skip the first argument named `--` - if (arg == "--" && !doubleDashFound) { - doubleDashFound = true; - } else { - auto path = std::filesystem::weakly_canonical(arg); - fullPaths.push_back(wolv::util::toUTF8String(path)); - } - } - - hex::subcommands::forwardSubCommand("open", fullPaths); - }} + { "calc", "Evaluate a mathematical expression", hex::plugin::builtin::handleCalcCommand }, + { "hash", "Calculate the hash of a file", hex::plugin::builtin::handleHashCommand }, + { "encode", "Encode a string", hex::plugin::builtin::handleEncodeCommand }, + { "decode", "Decode a string", hex::plugin::builtin::handleDecodeCommand }, }; IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") { @@ -140,6 +93,7 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") { registerNetworkEndpoints(); registerFileHandlers(); registerProjectHandlers(); + registerCommandForwarders(); addFooterItems(); addTitleBarButtons();