Skip to content

Commit

Permalink
feat: Added --plugin, --calc, --hash, --encode and --decode subcommands
Browse files Browse the repository at this point in the history
  • Loading branch information
WerWolv committed Jul 16, 2023
1 parent 1588365 commit e9450b4
Show file tree
Hide file tree
Showing 6 changed files with 267 additions and 65 deletions.
4 changes: 2 additions & 2 deletions lib/libimhex/source/subcommands/subcommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down
7 changes: 4 additions & 3 deletions main/source/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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()) {
Expand Down
1 change: 1 addition & 0 deletions plugins/builtin/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
22 changes: 22 additions & 0 deletions plugins/builtin/include/content/command_line_interface.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#pragma once

#include <string>
#include <vector>

namespace hex::plugin::builtin {

void handleVersionCommand(const std::vector<std::string> &args);
void handleHelpCommand(const std::vector<std::string> &args);
void handlePluginsCommand(const std::vector<std::string> &args);

void handleOpenCommand(const std::vector<std::string> &args);

void handleCalcCommand(const std::vector<std::string> &args);
void handleHashCommand(const std::vector<std::string> &args);
void handleEncodeCommand(const std::vector<std::string> &args);
void handleDecodeCommand(const std::vector<std::string> &args);


void registerCommandForwarders();

}
224 changes: 224 additions & 0 deletions plugins/builtin/source/content/command_line_interface.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,224 @@
#include "content/command_line_interface.hpp"

#include <hex/api/imhex_api.hpp>
#include <hex/api/event.hpp>

#include <hex/helpers/fmt.hpp>
#include <fmt/ranges.h>

#include <hex/helpers/crypto.hpp>
#include <romfs/romfs.hpp>

#include <hex/api/plugin_manager.hpp>
#include <hex/subcommands/subcommands.hpp>

#include <wolv/utils/string.hpp>

#include "content/helpers/math_evaluator.hpp"

namespace hex::plugin::builtin {

void handleVersionCommand(const std::vector<std::string> &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<std::string> &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<std::string> &args) {
if (args.empty()) {
hex::print("No files provided to open.");
std::exit(EXIT_FAILURE);
}

std::vector<std::string> 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<std::string> &args) {
if (args.empty()) {
hex::print("No expression provided!");
std::exit(EXIT_FAILURE);
}

MathEvaluator<long double> 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<std::string> &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<std::string> &args) {
if (args.size() != 2) {
hex::print("usage: imhex --hash <algorithm> <file>");
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<u8>(data.begin(), data.end());
};

std::vector<u8> 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<std::string> &args) {
if (args.size() != 2) {
hex::print("usage: imhex --encode <algorithm> <string>");
std::exit(EXIT_FAILURE);
}

const auto &algorithm = args[0];
const auto &data = std::vector<u8>(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<std::string> &args) {
if (args.size() != 2) {
hex::print("usage: imhex --decode <algorithm> <string>");
std::exit(EXIT_FAILURE);
}

const auto &algorithm = args[0];
const auto &data = std::vector<u8>(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<std::string> &args){
for (auto &arg : args) {
EventManager::post<RequestOpenFile>(arg);
}
});
}

}
74 changes: 14 additions & 60 deletions plugins/builtin/source/plugin_builtin.cpp
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#include <hex/plugin.hpp>
#include <hex/subcommands/subcommands.hpp>

#include <hex/api/event.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/subcommands/subcommands.hpp>

#include <romfs/romfs.hpp>
#include <nlohmann/json.hpp>

#include "content/command_line_interface.hpp"

using namespace hex;

namespace hex::plugin::builtin {
Expand Down Expand Up @@ -45,67 +46,19 @@ namespace hex::plugin::builtin {

void handleBorderlessWindowMode();

void handleSubCommands();

}

IMHEX_PLUGIN_SUBCOMMANDS() {
{ "version", "Print ImHex version and exit", [](const std::vector<std::string>&) {
hex::print(romfs::get("logo.ans").string(),
ImHexApi::System::getImHexVersion(),
ImHexApi::System::getCommitBranch(), ImHexApi::System::getCommitHash(),
__DATE__, __TIME__,
ImHexApi::System::isPortableVersion() ? "Portable" : "Installed");

exit(EXIT_SUCCESS);
}},
{ "help", "Print help about this command and exit", [](const std::vector<std::string>&) {
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);
}
}

exit(EXIT_SUCCESS);
}},
{ "open", "Open files passed as argument. This is the default subcommand is none is entered",
[](const std::vector<std::string> &args) {

hex::subcommands::registerSubCommand("open", [](const std::vector<std::string> &args){
for (auto &arg : args) {
EventManager::post<RequestOpenFile>(arg);
}
});

std::vector<std::string> 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);
}}
{ "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 },

{ "open", "Open files passed as argument. [default]", hex::plugin::builtin::handleOpenCommand },

{ "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") {
Expand Down Expand Up @@ -140,6 +93,7 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
registerNetworkEndpoints();
registerFileHandlers();
registerProjectHandlers();
registerCommandForwarders();

addFooterItems();
addTitleBarButtons();
Expand Down

0 comments on commit e9450b4

Please sign in to comment.