ui/ux: Complete rewrite of the Hash view

This commit is contained in:
WerWolv
2022-05-30 16:36:46 +02:00
parent 05862ae991
commit fe6be686b7
15 changed files with 457 additions and 343 deletions

View File

@@ -3,46 +3,8 @@
#include <cstdint>
#include <cstddef>
#include <hex/helpers/types.hpp>
#include <hex/helpers/intrinsics.hpp>
constexpr static const auto ImHexApiURL = "https://api.werwolv.net/imhex";
constexpr static const auto GitHubApiURL = "https://api.github.com/repos/WerWolv/ImHex";
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using u128 = __uint128_t;
using i8 = std::int8_t;
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using i128 = __int128_t;
using color_t = u32;
namespace hex {
struct Region {
u64 address;
size_t size;
[[nodiscard]] constexpr bool isWithin(const Region &other) const {
return (this->address >= other.address) && ((this->address + this->size) <= (other.address + other.size));
}
[[nodiscard]] constexpr bool overlaps(const Region &other) const {
return ((this->address + this->size) >= other.address) && (this->address < (other.address + other.size));
}
[[nodiscard]] constexpr u64 getStartAddress() const {
return this->address;
}
[[nodiscard]] constexpr u64 getEndAddress() const {
return this->address + this->size - 1;
}
};
}

View File

@@ -421,6 +421,74 @@ namespace hex {
}
}
namespace Hashes {
class Hash {
public:
Hash(std::string name) : m_name(std::move(name)) {}
class Function {
public:
using Callback = std::function<std::vector<u8>(const Region&, prv::Provider *)>;
Function(const Hash *type, std::string name, Callback callback)
: m_type(type), m_name(std::move(name)), m_callback(std::move(callback)) {
}
[[nodiscard]] const Hash *getType() const { return this->m_type; }
[[nodiscard]] const std::string &getName() const { return this->m_name; }
const std::vector<u8>& get(const Region& region, prv::Provider *provider) {
if (this->m_cache.empty()) {
this->m_cache = this->m_callback(region, provider);
}
return this->m_cache;
}
void reset() {
this->m_cache.clear();
}
private:
const Hash *m_type;
std::string m_name;
Callback m_callback;
std::vector<u8> m_cache;
};
virtual void draw() { }
[[nodiscard]] virtual Function create(std::string name) = 0;
[[nodiscard]] const std::string &getName() const {
return this->m_name;
}
protected:
[[nodiscard]] Function create(const std::string &name, const Function::Callback &callback) const {
return { this, name, callback };
}
private:
std::string m_name;
};
namespace impl {
std::vector<Hash*> &getHashes();
void add(Hash* hash);
}
template<typename T, typename ... Args>
void add(Args && ... args) {
impl::add(new T(std::forward<Args>(args)...));
}
}
};
}

View File

@@ -0,0 +1,44 @@
#pragma once
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using u128 = __uint128_t;
using i8 = std::int8_t;
using i16 = std::int16_t;
using i32 = std::int32_t;
using i64 = std::int64_t;
using i128 = __int128_t;
using color_t = u32;
namespace hex {
struct Region {
u64 address;
size_t size;
[[nodiscard]] constexpr bool isWithin(const Region &other) const {
return (this->getStartAddress() >= other.getStartAddress()) && (this->getEndAddress() <= other.getEndAddress());
}
[[nodiscard]] constexpr bool overlaps(const Region &other) const {
return (this->getEndAddress() >= other.getStartAddress()) && (this->getStartAddress() < other.getEndAddress());
}
[[nodiscard]] constexpr u64 getStartAddress() const {
return this->address;
}
[[nodiscard]] constexpr u64 getEndAddress() const {
return this->address + this->size - 1;
}
[[nodiscard]] constexpr size_t getSize() const {
return this->size;
}
};
}

View File

@@ -74,7 +74,8 @@ namespace ImGui {
bool ToolBarButton(const char *symbol, ImVec4 color);
bool IconButton(const char *symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0));
bool InputIntegerPrefix(const char* label, const char *prefix, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputIntegerPrefix(const char* label, const char *prefix, void *value, ImGuiDataType type, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputHexadecimal(const char* label, u32 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputHexadecimal(const char* label, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
inline bool HasSecondPassed() {

View File

@@ -582,4 +582,18 @@ namespace hex {
}
namespace ContentRegistry::Hashes {
std::vector<Hash *> &impl::getHashes() {
static std::vector<Hash *> hashes;
return hashes;
}
void impl::add(Hash *hash) {
getHashes().push_back(hash);
}
}
}

View File

@@ -19,7 +19,7 @@ namespace ImGui {
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
auto &string = *static_cast<std::string *>(data->UserData);
string.resize(data->BufSize);
string.resize(data->BufTextLen);
data->Buf = string.data();
}
@@ -487,7 +487,7 @@ namespace ImGui {
return pressed;
}
bool InputIntegerPrefix(const char *label, const char *prefix, u64 *value, ImGuiInputTextFlags flags) {
bool InputIntegerPrefix(const char *label, const char *prefix, void *value, ImGuiDataType type, ImGuiInputTextFlags flags) {
auto window = ImGui::GetCurrentWindow();
const ImGuiID id = window->GetID(label);
const ImGuiStyle &style = GImGui->Style;
@@ -500,7 +500,7 @@ namespace ImGui {
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + frame_size.x);
char buf[64];
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), ImGuiDataType_U64, value, "%llX");
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), type, value, "%llX");
bool value_changed = false;
if (InputTextEx(label, nullptr, buf, IM_ARRAYSIZE(buf), ImVec2(CalcItemWidth() - frame_size.x, label_size.y + style.FramePadding.y * 2.0f), flags))
@@ -519,8 +519,12 @@ namespace ImGui {
return value_changed;
}
bool InputHexadecimal(const char *label, u32 *value, ImGuiInputTextFlags flags) {
return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U32, flags | ImGuiInputTextFlags_CharsHexadecimal);
}
bool InputHexadecimal(const char *label, u64 *value, ImGuiInputTextFlags flags) {
return InputIntegerPrefix(label, "0x", value, flags | ImGuiInputTextFlags_CharsHexadecimal);
return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U64, flags | ImGuiInputTextFlags_CharsHexadecimal);
}
void SmallProgressBar(float fraction, float yOffset) {

View File

@@ -22,6 +22,7 @@ add_library(${PROJECT_NAME} SHARED
source/content/welcome_screen.cpp
source/content/data_visualizers.cpp
source/content/events.cpp
source/content/hashes.cpp
source/content/providers/file_provider.cpp
source/content/providers/gdb_provider.cpp

View File

@@ -1,5 +1,7 @@
#pragma once
#include <hex/api/content_registry.hpp>
#include <hex/ui/view.hpp>
#include <array>
@@ -16,35 +18,10 @@ namespace hex::plugin::builtin {
void drawContent() override;
private:
enum class HashFunctions
{
Crc8,
Crc16,
Crc32,
Md5,
Sha1,
Sha224,
Sha256,
Sha384,
Sha512
};
ContentRegistry::Hashes::Hash *m_selectedHash = nullptr;
std::string m_newHashName;
bool m_shouldInvalidate = true;
int m_currHashFunction = 0;
u64 m_hashRegion[2] = { 0 };
bool m_shouldMatchSelection = false;
static constexpr std::array hashFunctionNames {
std::pair {HashFunctions::Crc8, "CRC8" },
std::pair { HashFunctions::Crc16, "CRC16" },
std::pair { HashFunctions::Crc32, "CRC32" },
std::pair { HashFunctions::Md5, "MD5" },
std::pair { HashFunctions::Sha1, "SHA-1" },
std::pair { HashFunctions::Sha224, "SHA-224"},
std::pair { HashFunctions::Sha256, "SHA-256"},
std::pair { HashFunctions::Sha384, "SHA-384"},
std::pair { HashFunctions::Sha512, "SHA-512"},
};
std::vector<ContentRegistry::Hashes::Hash::Function> m_hashFunctions;
};
}

View File

@@ -0,0 +1,140 @@
#include <hex/api/content_registry.hpp>
#include <hex/api/localization.hpp>
#include <hex/helpers/crypto.hpp>
#include <hex/ui/imgui_imhex_extensions.h>
namespace hex::plugin::builtin {
class HashMD5 : public ContentRegistry::Hashes::Hash {
public:
HashMD5() : Hash("hex.builtin.hash.md5"_lang) {}
Function create(std::string name) override {
return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector<u8> {
auto array = crypt::md5(provider, region.address, region.size);
return { array.begin(), array.end() };
});
}
};
class HashSHA1 : public ContentRegistry::Hashes::Hash {
public:
HashSHA1() : Hash("hex.builtin.hash.sha1"_lang) {}
Function create(std::string name) override {
return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector<u8> {
auto array = crypt::sha1(provider, region.address, region.size);
return { array.begin(), array.end() };
});
}
};
class HashSHA224 : public ContentRegistry::Hashes::Hash {
public:
HashSHA224() : Hash("hex.builtin.hash.sha224"_lang) {}
Function create(std::string name) override {
return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector<u8> {
auto array = crypt::sha224(provider, region.address, region.size);
return { array.begin(), array.end() };
});
}
};
class HashSHA256 : public ContentRegistry::Hashes::Hash {
public:
HashSHA256() : Hash("hex.builtin.hash.sha256"_lang) {}
Function create(std::string name) override {
return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector<u8> {
auto array = crypt::sha256(provider, region.address, region.size);
return { array.begin(), array.end() };
});
}
};
class HashSHA384 : public ContentRegistry::Hashes::Hash {
public:
HashSHA384() : Hash("hex.builtin.hash.sha384"_lang) {}
Function create(std::string name) override {
return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector<u8> {
auto array = crypt::sha384(provider, region.address, region.size);
return { array.begin(), array.end() };
});
}
};
class HashSHA512 : public ContentRegistry::Hashes::Hash {
public:
HashSHA512() : Hash("hex.builtin.hash.sha512") {}
Function create(std::string name) override {
return Hash::create(name, [](const Region& region, prv::Provider *provider) -> std::vector<u8> {
auto array = crypt::sha512(provider, region.address, region.size);
return { array.begin(), array.end() };
});
}
};
template<typename T>
class HashCRC : public ContentRegistry::Hashes::Hash {
public:
using CRCFunction = T(*)(prv::Provider*&, u64, size_t, u32, u32, u32, bool, bool);
HashCRC(const std::string &name, const CRCFunction &crcFunction, u32 polynomial, u32 initialValue, u32 xorOut)
: Hash(name), m_crcFunction(crcFunction), m_polynomial(polynomial), m_initialValue(initialValue), m_xorOut(xorOut) {}
void draw() override {
ImGui::InputHexadecimal("hex.builtin.hash.crc.poly"_lang, &this->m_polynomial);
ImGui::InputHexadecimal("hex.builtin.hash.crc.iv"_lang, &this->m_initialValue);
ImGui::InputHexadecimal("hex.builtin.hash.crc.xor_out"_lang, &this->m_xorOut);
ImGui::NewLine();
ImGui::Checkbox("hex.builtin.hash.crc.refl_in"_lang, &this->m_reflectIn);
ImGui::Checkbox("hex.builtin.hash.crc.refl_out"_lang, &this->m_reflectOut);
}
Function create(std::string name) override {
return Hash::create(name, [hash = *this](const Region& region, prv::Provider *provider) -> std::vector<u8> {
auto result = hash.m_crcFunction(provider, region.address, region.size, hash.m_polynomial, hash.m_initialValue, hash.m_xorOut, hash.m_reflectIn, hash.m_reflectOut);
std::vector<u8> bytes(sizeof(result), 0x00);
std::memcpy(bytes.data(), &result, bytes.size());
return bytes;
});
}
private:
CRCFunction m_crcFunction;
u32 m_polynomial;
u32 m_initialValue;
u32 m_xorOut;
bool m_reflectIn = false, m_reflectOut = false;
};
void registerHashes() {
ContentRegistry::Hashes::add<HashMD5>();
ContentRegistry::Hashes::add<HashSHA1>();
ContentRegistry::Hashes::add<HashSHA224>();
ContentRegistry::Hashes::add<HashSHA256>();
ContentRegistry::Hashes::add<HashSHA384>();
ContentRegistry::Hashes::add<HashSHA512>();
ContentRegistry::Hashes::add<HashCRC<u16>>("hex.builtin.hash.crc8"_lang, crypt::crc8, 0x07, 0x0000, 0x0000);
ContentRegistry::Hashes::add<HashCRC<u16>>("hex.builtin.hash.crc16"_lang, crypt::crc16, 0x8005, 0x0000, 0x0000);
ContentRegistry::Hashes::add<HashCRC<u32>>("hex.builtin.hash.crc32"_lang, crypt::crc32, 0x04C1'1DB7, 0xFFFF'FFFF, 0xFFFF'FFFF);
}
}

View File

@@ -61,7 +61,7 @@ namespace hex::plugin::builtin {
ImGui::BeginTooltip();
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();

View File

@@ -1,294 +1,180 @@
#include "content/views/view_hashes.hpp"
#include <hex/providers/provider.hpp>
#include <hex/helpers/crypto.hpp>
#include <vector>
namespace hex::plugin::builtin {
ViewHashes::ViewHashes() : View("hex.builtin.view.hashes.name") {
EventManager::subscribe<EventDataChanged>(this, [this]() {
this->m_shouldInvalidate = true;
EventManager::subscribe<EventRegionSelected>(this, [this](const Region &) {
for (auto &function : this->m_hashFunctions)
function.reset();
});
EventManager::subscribe<EventRegionSelected>(this, [this](Region region) {
if (this->m_shouldMatchSelection) {
if (region.address == size_t(-1)) {
this->m_hashRegion[0] = this->m_hashRegion[1] = 0;
} else {
this->m_hashRegion[0] = region.address;
this->m_hashRegion[1] = region.size;
ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) {
hex::unused(data);
auto selection = ImHexApi::HexEditor::getSelection();
if (ImGui::GetIO().KeyShift) {
if (!this->m_hashFunctions.empty() && selection.has_value() && selection->overlaps(Region { address, size })) {
ImGui::BeginTooltip();
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted("hex.builtin.view.hashes.name"_lang);
ImGui::Separator();
ImGui::Indent();
if (ImGui::BeginTable("##hashes_tooltip", 3, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit)) {
auto provider = ImHexApi::Provider::get();
for (auto &function : this->m_hashFunctions) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextFormatted("{}", function.getName());
ImGui::TableNextColumn();
ImGui::TextFormatted(" ");
ImGui::TableNextColumn();
if (provider != nullptr)
ImGui::TextFormatted("{}", crypt::encode16(function.get(*selection, provider)));
}
ImGui::EndTable();
}
ImGui::Unindent();
ImGui::EndTable();
}
ImGui::EndTooltip();
}
this->m_shouldInvalidate = true;
}
});
}
ViewHashes::~ViewHashes() {
EventManager::unsubscribe<EventDataChanged>(this);
EventManager::unsubscribe<EventRegionSelected>(this);
}
template<size_t Size>
static void formatBigHexInt(std::array<u8, Size> dataArray, char *buffer, size_t bufferSize) {
for (size_t i = 0; i < dataArray.size(); i++)
snprintf(buffer + 2 * i, bufferSize - 2 * i, "%02X", dataArray[i]);
}
void ViewHashes::drawContent() {
const auto &hashes = ContentRegistry::Hashes::impl::getHashes();
if (this->m_selectedHash == nullptr && !hashes.empty()) {
this->m_selectedHash = hashes.front();
}
if (ImGui::Begin(View::toWindowName("hex.builtin.view.hashes.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
if (ImGui::BeginChild("##scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav)) {
if (ImGui::BeginCombo("hex.builtin.view.hashes.function"_lang, this->m_selectedHash != nullptr ? this->m_selectedHash->getName().c_str() : "")) {
auto provider = ImHexApi::Provider::get();
if (ImHexApi::Provider::isValid() && provider->isAvailable()) {
ImGui::TextUnformatted("hex.builtin.common.region"_lang);
ImGui::Separator();
ImGui::InputScalarN("##nolabel", ImGuiDataType_U64, this->m_hashRegion, 2, nullptr, nullptr, "%08X", ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::Checkbox("hex.builtin.common.match_selection"_lang, &this->m_shouldMatchSelection);
if (ImGui::IsItemEdited()) {
// Force execution of Region Selection Event
ImHexApi::HexEditor::setSelection(0, 0);
this->m_shouldInvalidate = true;
}
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.hashes.settings"_lang);
ImGui::Separator();
if (ImGui::BeginCombo("hex.builtin.view.hashes.function"_lang, hashFunctionNames[this->m_currHashFunction].second, 0)) {
for (size_t i = 0; i < hashFunctionNames.size(); i++) {
bool is_selected = (static_cast<size_t>(this->m_currHashFunction) == i);
if (ImGui::Selectable(hashFunctionNames[i].second, is_selected))
this->m_currHashFunction = i;
if (is_selected)
ImGui::SetItemDefaultFocus(); // Set the initial focus when opening the combo (scrolling + for keyboard navigation support in the upcoming navigation branch)
}
ImGui::EndCombo();
this->m_shouldInvalidate = true;
}
size_t dataSize = provider->getSize();
if (this->m_hashRegion[1] >= provider->getBaseAddress() + dataSize)
this->m_hashRegion[1] = provider->getBaseAddress() + dataSize;
switch (hashFunctionNames[this->m_currHashFunction].first) {
case HashFunctions::Crc8:
{
static int polynomial = 0x07, init = 0x0000, xorout = 0x0000;
static bool reflectIn = false, reflectOut = false;
ImGui::InputInt("hex.builtin.view.hashes.iv"_lang, &init, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::InputInt("hex.builtin.view.hashes.xorout"_lang, &xorout, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::Checkbox("hex.builtin.common.reflectIn"_lang, &reflectIn);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::Checkbox("hex.builtin.common.reflectOut"_lang, &reflectOut);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::InputInt("hex.builtin.view.hashes.poly"_lang, &polynomial, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::NewLine();
static u8 result = 0;
if (this->m_shouldInvalidate)
result = crypt::crc8(provider, this->m_hashRegion[0], this->m_hashRegion[1], polynomial, init, xorout, reflectIn, reflectOut);
char buffer[sizeof(result) * 2 + 1];
snprintf(buffer, sizeof(buffer), "%02X", result);
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Crc16:
{
static int polynomial = 0x8005, init = 0x0000, xorout = 0x0000;
static bool reflectIn = false, reflectOut = false;
ImGui::InputInt("hex.builtin.view.hashes.iv"_lang, &init, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::InputInt("hex.builtin.view.hashes.xorout"_lang, &xorout, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::Checkbox("hex.builtin.common.reflectIn"_lang, &reflectIn);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::Checkbox("hex.builtin.common.reflectOut"_lang, &reflectOut);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::InputInt("hex.builtin.view.hashes.poly"_lang, &polynomial, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::NewLine();
static u16 result = 0;
if (this->m_shouldInvalidate)
result = crypt::crc16(provider, this->m_hashRegion[0], this->m_hashRegion[1], polynomial, init, xorout, reflectIn, reflectOut);
char buffer[sizeof(result) * 2 + 1];
snprintf(buffer, sizeof(buffer), "%04X", result);
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Crc32:
{
static int polynomial = 0x04C11DB7, init = 0xFFFFFFFF, xorout = 0xFFFFFFFF;
static bool reflectIn = true, reflectOut = true;
ImGui::InputInt("hex.builtin.view.hashes.iv"_lang, &init, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::InputInt("hex.builtin.view.hashes.xorout"_lang, &xorout, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::Checkbox("hex.builtin.common.reflectIn"_lang, &reflectIn);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::Checkbox("hex.builtin.common.reflectOut"_lang, &reflectOut);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::InputInt("hex.builtin.view.hashes.poly"_lang, &polynomial, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
if (ImGui::IsItemEdited()) this->m_shouldInvalidate = true;
ImGui::NewLine();
static u32 result = 0;
if (this->m_shouldInvalidate)
result = crypt::crc32(provider, this->m_hashRegion[0], this->m_hashRegion[1], polynomial, init, xorout, reflectIn, reflectOut);
char buffer[sizeof(result) * 2 + 1];
snprintf(buffer, sizeof(buffer), "%08X", result);
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Md5:
{
static std::array<u8, 16> result = { 0 };
if (this->m_shouldInvalidate)
result = crypt::md5(provider, this->m_hashRegion[0], this->m_hashRegion[1]);
char buffer[sizeof(result) * 2 + 1];
formatBigHexInt(result, buffer, sizeof(buffer));
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Sha1:
{
static std::array<u8, 20> result = { 0 };
if (this->m_shouldInvalidate)
result = crypt::sha1(provider, this->m_hashRegion[0], this->m_hashRegion[1]);
char buffer[sizeof(result) * 2 + 1];
formatBigHexInt(result, buffer, sizeof(buffer));
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Sha224:
{
static std::array<u8, 28> result = { 0 };
if (this->m_shouldInvalidate)
result = crypt::sha224(provider, this->m_hashRegion[0], this->m_hashRegion[1]);
char buffer[sizeof(result) * 2 + 1];
formatBigHexInt(result, buffer, sizeof(buffer));
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Sha256:
{
static std::array<u8, 32> result;
if (this->m_shouldInvalidate)
result = crypt::sha256(provider, this->m_hashRegion[0], this->m_hashRegion[1]);
char buffer[sizeof(result) * 2 + 1];
formatBigHexInt(result, buffer, sizeof(buffer));
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Sha384:
{
static std::array<u8, 48> result;
if (this->m_shouldInvalidate)
result = crypt::sha384(provider, this->m_hashRegion[0], this->m_hashRegion[1]);
char buffer[sizeof(result) * 2 + 1];
formatBigHexInt(result, buffer, sizeof(buffer));
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
case HashFunctions::Sha512:
{
static std::array<u8, 64> result;
if (this->m_shouldInvalidate)
result = crypt::sha512(provider, this->m_hashRegion[0], this->m_hashRegion[1]);
char buffer[sizeof(result) * 2 + 1];
formatBigHexInt(result, buffer, sizeof(buffer));
ImGui::NewLine();
ImGui::TextUnformatted("hex.builtin.view.hashes.result"_lang);
ImGui::Separator();
ImGui::InputText("##nolabel", buffer, ImGuiInputTextFlags_ReadOnly);
}
break;
for (const auto hash : hashes) {
if (ImGui::Selectable(hash->getName().c_str(), this->m_selectedHash == hash)) {
this->m_selectedHash = hash;
this->m_newHashName.clear();
}
}
this->m_shouldInvalidate = false;
ImGui::EndCombo();
}
if (this->m_newHashName.empty() && this->m_selectedHash != nullptr)
this->m_newHashName = hex::format("{} {}", this->m_selectedHash->getName(), static_cast<const char *>("hex.builtin.view.hashes.hash"_lang));
if (ImGui::BeginChild("##settings", ImVec2(ImGui::GetContentRegionAvailWidth(), 200_scaled), true)) {
if (this->m_selectedHash != nullptr) {
auto startPos = ImGui::GetCursorPosY();
this->m_selectedHash->draw();
// Check if no elements have been added
if (startPos == ImGui::GetCursorPosY()) {
ImGui::TextFormattedCentered("hex.builtin.view.hashes.no_settings"_lang);
}
}
}
ImGui::EndChild();
ImGui::NewLine();
ImGui::InputText("##Name", this->m_newHashName);
ImGui::SameLine();
ImGui::BeginDisabled(this->m_newHashName.empty() || this->m_selectedHash == nullptr);
if (ImGui::IconButton(ICON_VS_ADD, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
if (this->m_selectedHash != nullptr)
this->m_hashFunctions.push_back(this->m_selectedHash->create(this->m_newHashName));
}
ImGui::EndDisabled();
if (ImGui::BeginTable("##hashes", 3, ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Borders, ImVec2(ImGui::GetContentRegionAvailWidth(), ImGui::GetTextLineHeightWithSpacing() * 10))) {
ImGui::TableSetupColumn("hex.builtin.view.hashes.name"_lang);
ImGui::TableSetupColumn("hex.builtin.view.hashes.type"_lang);
ImGui::TableSetupColumn("hex.builtin.view.hashes.result"_lang, ImGuiTableColumnFlags_WidthStretch);
ImGui::TableHeadersRow();
auto provider = ImHexApi::Provider::get();
auto selection = ImHexApi::HexEditor::getSelection();
std::optional<u32> indexToRemove;
for (u32 i = 0; i < this->m_hashFunctions.size(); i++) {
auto &function = this->m_hashFunctions[i];
ImGui::PushID(i);
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::PushStyleColor(ImGuiCol_Header, 0x00);
ImGui::PushStyleColor(ImGuiCol_HeaderActive, 0x00);
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, 0x00);
ImGui::Selectable(function.getName().c_str(), false);
ImGui::PopStyleColor(3);
{
const auto ContextMenuId = hex::format("Context Menu {}", i);
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Right))
ImGui::OpenPopup(ContextMenuId.c_str());
if (ImGui::BeginPopup(ContextMenuId.c_str())) {
if (ImGui::MenuItem("hex.builtin.view.hashes.remove"_lang))
indexToRemove = i;
ImGui::EndPopup();
}
}
ImGui::TableNextColumn();
ImGui::TextFormatted("{}", function.getType()->getName());
ImGui::TableNextColumn();
std::string result;
if (provider != nullptr && selection.has_value())
result = crypt::encode16(function.get(*selection, provider));
else
result = "???";
ImGui::PushItemWidth(ImGui::GetContentRegionAvailWidth());
ImGui::InputText("##result", result, ImGuiInputTextFlags_ReadOnly);
ImGui::PopItemWidth();
ImGui::PopID();
}
if (indexToRemove.has_value()) {
this->m_hashFunctions.erase(this->m_hashFunctions.begin() + indexToRemove.value());
}
ImGui::EndTable();
}
ImGui::NewLine();
ImGui::TextWrapped("%s", static_cast<const char *>("hex.builtin.view.hashes.hover_info"_lang));
}
ImGui::End();
}

View File

@@ -439,7 +439,7 @@ namespace hex::plugin::builtin {
ImGui::BeginTooltip();
for (const auto &[id, tooltip] : tooltips) {
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();

View File

@@ -254,7 +254,7 @@ namespace hex::plugin::builtin {
if (child != nullptr) {
ImGui::BeginTooltip();
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();

View File

@@ -218,14 +218,14 @@ namespace hex::plugin::builtin {
{ "hex.builtin.view.disassembler.disassembly.bytes", "Byte" },
{ "hex.builtin.view.hashes.name", "Hashes" },
{ "hex.builtin.view.hashes.settings", "Settings" },
{ "hex.builtin.view.hashes.hash", "Hash" },
{ "hex.builtin.view.hashes.no_settings", "No settings available" },
{ "hex.builtin.view.hashes.function", "Hash function" },
{ "hex.builtin.view.hashes.iv", "Initial value" },
{ "hex.builtin.view.hashes.xorout", "Final XOR value" },
{ "hex.builtin.common.reflectIn", "Reflect input" },
{ "hex.builtin.common.reflectOut", "Reflect output" },
{ "hex.builtin.view.hashes.poly", "Polynomial" },
{ "hex.builtin.view.hashes.name", "Name" },
{ "hex.builtin.view.hashes.type", "Type" },
{ "hex.builtin.view.hashes.result", "Result" },
{ "hex.builtin.view.hashes.remove", "Remove hash" },
{ "hex.builtin.view.hashes.hover_info", "Hover over the Hex Editor selection and hold down SHIFT to view the hashes of that region." },
{ "hex.builtin.view.help.name", "Help" },
{ "hex.builtin.view.help.about.name", "About" },
@@ -733,6 +733,21 @@ namespace hex::plugin::builtin {
{ "hex.builtin.visualizer.floating_point.64bit", "Floating Point (64 bits)" },
{ "hex.builtin.visualizer.hexii", "HexII" },
{ "hex.builtin.visualizer.rgba8", "RGBA8 Color" },
{ "hex.builtin.hash.md5", "MD5" },
{ "hex.builtin.hash.sha1", "SHA1" },
{ "hex.builtin.hash.sha224", "SHA224" },
{ "hex.builtin.hash.sha256", "SHA256" },
{ "hex.builtin.hash.sha384", "SHA384" },
{ "hex.builtin.hash.sha512", "SHA512" },
{ "hex.builtin.hash.crc8", "CRC8" },
{ "hex.builtin.hash.crc16", "CRC16" },
{ "hex.builtin.hash.crc32", "CRC32" },
{ "hex.builtin.hash.crc.poly", "Polynomial" },
{ "hex.builtin.hash.crc.iv", "Initial Value" },
{ "hex.builtin.hash.crc.xor_out", "XOR Out" },
{ "hex.builtin.hash.crc.refl_in", "Reflect In" },
{ "hex.builtin.hash.crc.refl_out", "Reflect Out" },
});
}

View File

@@ -11,6 +11,7 @@ namespace hex::plugin::builtin {
void registerCommandPaletteCommands();
void registerSettings();
void registerDataProcessorNodes();
void registerHashes();
void registerProviders();
void registerDataFormatters();
void registerLayouts();
@@ -49,6 +50,7 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
registerCommandPaletteCommands();
registerSettings();
registerDataProcessorNodes();
registerHashes();
registerProviders();
registerDataFormatters();
createWelcomeScreen();