mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-04-02 13:37:42 -05:00
feat: Move hashes into plugin, merged in extra hashes plugin
This commit is contained in:
440
plugins/hashes/source/content/hashes.cpp
Normal file
440
plugins/hashes/source/content/hashes.cpp
Normal file
@@ -0,0 +1,440 @@
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
#include <hex/helpers/crypto.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/providers/buffered_reader.hpp>
|
||||
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <wolv/literals.hpp>
|
||||
|
||||
#include <HashFactory.h>
|
||||
|
||||
namespace hex::plugin::hashes {
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace wolv::literals;
|
||||
|
||||
std::vector<u8> hashProviderRegion(const Region& region, prv::Provider *provider, auto &hashFunction) {
|
||||
auto reader = prv::ProviderReader(provider);
|
||||
reader.seek(region.getStartAddress());
|
||||
reader.setEndAddress(region.getEndAddress());
|
||||
|
||||
for (u64 address = region.getStartAddress(); address < region.getEndAddress(); address += 1_MiB) {
|
||||
u64 readSize = std::min<u64>(1_MiB, (region.getEndAddress() - address) + 1);
|
||||
|
||||
auto data = reader.read(address, readSize);
|
||||
hashFunction->TransformBytes({ data.begin(), data.end() }, address - region.getStartAddress(), data.size());
|
||||
}
|
||||
|
||||
auto result = hashFunction->TransformFinal();
|
||||
|
||||
auto bytes = result->GetBytes();
|
||||
return { bytes.begin(), bytes.end() };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class HashMD5 : public ContentRegistry::Hashes::Hash {
|
||||
public:
|
||||
HashMD5() : Hash("hex.hashes.hash.md5") {}
|
||||
|
||||
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() };
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] nlohmann::json store() const override { return { }; }
|
||||
void load(const nlohmann::json &) override {}
|
||||
};
|
||||
|
||||
class HashSHA1 : public ContentRegistry::Hashes::Hash {
|
||||
public:
|
||||
HashSHA1() : Hash("hex.hashes.hash.sha1") {}
|
||||
|
||||
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() };
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] nlohmann::json store() const override { return { }; }
|
||||
void load(const nlohmann::json &) override {}
|
||||
};
|
||||
|
||||
class HashSHA224 : public ContentRegistry::Hashes::Hash {
|
||||
public:
|
||||
HashSHA224() : Hash("hex.hashes.hash.sha224") {}
|
||||
|
||||
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() };
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] nlohmann::json store() const override { return { }; }
|
||||
void load(const nlohmann::json &) override {}
|
||||
};
|
||||
|
||||
class HashSHA256 : public ContentRegistry::Hashes::Hash {
|
||||
public:
|
||||
HashSHA256() : Hash("hex.hashes.hash.sha256") {}
|
||||
|
||||
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() };
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] nlohmann::json store() const override { return { }; }
|
||||
void load(const nlohmann::json &) override {}
|
||||
};
|
||||
|
||||
class HashSHA384 : public ContentRegistry::Hashes::Hash {
|
||||
public:
|
||||
HashSHA384() : Hash("hex.hashes.hash.sha384") {}
|
||||
|
||||
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() };
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] nlohmann::json store() const override { return { }; }
|
||||
void load(const nlohmann::json &) override {}
|
||||
};
|
||||
|
||||
class HashSHA512 : public ContentRegistry::Hashes::Hash {
|
||||
public:
|
||||
HashSHA512() : Hash("hex.hashes.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() };
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] nlohmann::json store() const override { return { }; }
|
||||
void load(const nlohmann::json &) override {}
|
||||
};
|
||||
|
||||
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, bool reflectIn = false, bool reflectOut = false)
|
||||
: Hash(name), m_crcFunction(crcFunction), m_polynomial(polynomial), m_initialValue(initialValue), m_xorOut(xorOut), m_reflectIn(reflectIn), m_reflectOut(reflectOut) {}
|
||||
|
||||
void draw() override {
|
||||
ImGuiExt::InputHexadecimal("hex.hashes.hash.common.poly"_lang, &this->m_polynomial);
|
||||
ImGuiExt::InputHexadecimal("hex.hashes.hash.common.iv"_lang, &this->m_initialValue);
|
||||
ImGuiExt::InputHexadecimal("hex.hashes.hash.common.xor_out"_lang, &this->m_xorOut);
|
||||
|
||||
ImGui::NewLine();
|
||||
|
||||
ImGui::Checkbox("hex.hashes.hash.common.refl_in"_lang, &this->m_reflectIn);
|
||||
ImGui::Checkbox("hex.hashes.hash.common.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());
|
||||
|
||||
if constexpr (std::endian::native == std::endian::little)
|
||||
std::reverse(bytes.begin(), bytes.end());
|
||||
|
||||
return bytes;
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] nlohmann::json store() const override {
|
||||
nlohmann::json result;
|
||||
|
||||
result["polynomial"] = this->m_polynomial;
|
||||
result["initialValue"] = this->m_initialValue;
|
||||
result["xorOut"] = this->m_xorOut;
|
||||
result["reflectIn"] = this->m_reflectIn;
|
||||
result["reflectOut"] = this->m_reflectOut;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void load(const nlohmann::json &json) override {
|
||||
try {
|
||||
this->m_polynomial = json.at("polynomial");
|
||||
this->m_initialValue = json.at("initialValue");
|
||||
this->m_xorOut = json.at("xorOut");
|
||||
this->m_reflectIn = json.at("reflectIn");
|
||||
this->m_reflectOut = json.at("reflectOut");
|
||||
} catch (std::exception&) { }
|
||||
}
|
||||
|
||||
private:
|
||||
CRCFunction m_crcFunction;
|
||||
|
||||
u32 m_polynomial;
|
||||
u32 m_initialValue;
|
||||
u32 m_xorOut;
|
||||
bool m_reflectIn = false, m_reflectOut = false;
|
||||
};
|
||||
|
||||
class HashBasic : public ContentRegistry::Hashes::Hash {
|
||||
public:
|
||||
using FactoryFunction = IHash(*)();
|
||||
|
||||
explicit HashBasic(FactoryFunction function) : Hash(function()->GetName()), m_factoryFunction(function) {}
|
||||
|
||||
Function create(std::string name) override {
|
||||
return Hash::create(name, [hash = *this](const Region& region, prv::Provider *provider) -> std::vector<u8> {
|
||||
IHash hashFunction = hash.m_factoryFunction();
|
||||
|
||||
hashFunction->Initialize();
|
||||
|
||||
return hashProviderRegion(region, provider, hashFunction);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] nlohmann::json store() const override { return { }; }
|
||||
void load(const nlohmann::json &) override {}
|
||||
|
||||
private:
|
||||
FactoryFunction m_factoryFunction;
|
||||
};
|
||||
|
||||
class HashWithKey : public ContentRegistry::Hashes::Hash {
|
||||
public:
|
||||
using FactoryFunction = IHashWithKey(*)();
|
||||
|
||||
explicit HashWithKey(FactoryFunction function) : Hash(function()->GetName()), m_factoryFunction(function) {}
|
||||
|
||||
void draw() override {
|
||||
ImGui::InputText("hex.hashes.hash.common.key"_lang, this->m_key, ImGuiInputTextFlags_CharsHexadecimal);
|
||||
}
|
||||
|
||||
Function create(std::string name) override {
|
||||
return Hash::create(name, [hash = *this, key = hex::parseByteString(this->m_key)](const Region& region, prv::Provider *provider) -> std::vector<u8> {
|
||||
IHashWithKey hashFunction = hash.m_factoryFunction();
|
||||
|
||||
hashFunction->Initialize();
|
||||
hashFunction->SetKey(key);
|
||||
|
||||
return hashProviderRegion(region, provider, hashFunction);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] nlohmann::json store() const override { return { }; }
|
||||
void load(const nlohmann::json &) override {}
|
||||
|
||||
private:
|
||||
FactoryFunction m_factoryFunction;
|
||||
|
||||
std::string m_key;
|
||||
};
|
||||
|
||||
class HashInitialValue : public ContentRegistry::Hashes::Hash {
|
||||
public:
|
||||
using FactoryFunction = IHash(*)(const Int32);
|
||||
|
||||
explicit HashInitialValue(FactoryFunction function) : Hash(function(0)->GetName()), m_factoryFunction(function) {}
|
||||
|
||||
void draw() override {
|
||||
ImGuiExt::InputHexadecimal("hex.hashes.hash.common.iv"_lang, &this->m_initialValue);
|
||||
}
|
||||
|
||||
Function create(std::string name) override {
|
||||
return Hash::create(name, [hash = *this](const Region& region, prv::Provider *provider) -> std::vector<u8> {
|
||||
IHash hashFunction = hash.m_factoryFunction(Int32(hash.m_initialValue));
|
||||
|
||||
hashFunction->Initialize();
|
||||
|
||||
return hashProviderRegion(region, provider, hashFunction);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] nlohmann::json store() const override { return { }; }
|
||||
void load(const nlohmann::json &) override {}
|
||||
|
||||
private:
|
||||
FactoryFunction m_factoryFunction;
|
||||
u32 m_initialValue = 0x00;
|
||||
};
|
||||
|
||||
class HashTiger : public ContentRegistry::Hashes::Hash {
|
||||
public:
|
||||
using FactoryFunction = IHash(*)(const Int32, const HashRounds&);
|
||||
|
||||
explicit HashTiger(std::string name, FactoryFunction function) : Hash(std::move(name)), m_factoryFunction(function) {}
|
||||
void draw() override {
|
||||
ImGui::Combo("hex.hashes.hash.common.size"_lang, &this->m_hashSize, "128 Bits\0" "160 Bits\0" "192 Bits\0");
|
||||
ImGui::Combo("hex.hashes.hash.common.rounds"_lang, &this->m_hashRounds, "3 Rounds\0" "4 Rounds\0" "5 Rounds\0" "8 Rounds\0");
|
||||
}
|
||||
|
||||
Function create(std::string name) override {
|
||||
return Hash::create(name, [hash = *this](const Region& region, prv::Provider *provider) -> std::vector<u8> {
|
||||
Int32 hashSize = 16;
|
||||
switch (hash.m_hashSize) {
|
||||
case 0: hashSize = 16; break;
|
||||
case 1: hashSize = 20; break;
|
||||
case 2: hashSize = 24; break;
|
||||
}
|
||||
|
||||
HashRounds hashRounds = HashRounds::Rounds3;
|
||||
switch (hash.m_hashRounds) {
|
||||
case 0: hashRounds = HashRounds::Rounds3; break;
|
||||
case 1: hashRounds = HashRounds::Rounds4; break;
|
||||
case 2: hashRounds = HashRounds::Rounds5; break;
|
||||
case 3: hashRounds = HashRounds::Rounds8; break;
|
||||
}
|
||||
|
||||
IHash hashFunction = hash.m_factoryFunction(hashSize, hashRounds);
|
||||
|
||||
hashFunction->Initialize();
|
||||
|
||||
return hashProviderRegion(region, provider, hashFunction);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] nlohmann::json store() const override { return { }; }
|
||||
void load(const nlohmann::json &) override {}
|
||||
|
||||
private:
|
||||
FactoryFunction m_factoryFunction;
|
||||
|
||||
int m_hashSize = 0, m_hashRounds = 0;
|
||||
};
|
||||
|
||||
template<typename Config, typename T1, typename T2>
|
||||
class HashBlake2 : public ContentRegistry::Hashes::Hash {
|
||||
public:
|
||||
using FactoryFunction = IHash(*)(T1 a_Config, T2 a_TreeConfig);
|
||||
|
||||
explicit HashBlake2(std::string name, FactoryFunction function) : Hash(std::move(name)), m_factoryFunction(function) {}
|
||||
void draw() override {
|
||||
ImGui::InputText("hex.hashes.hash.common.salt"_lang, this->m_salt, ImGuiInputTextFlags_CharsHexadecimal);
|
||||
ImGui::InputText("hex.hashes.hash.common.key"_lang, this->m_key, ImGuiInputTextFlags_CharsHexadecimal);
|
||||
ImGui::InputText("hex.hashes.hash.common.personalization"_lang, this->m_personalization, ImGuiInputTextFlags_CharsHexadecimal);
|
||||
ImGui::Combo("hex.hashes.hash.common.size"_lang, &this->m_hashSize, "128 Bits\0" "160 Bits\0" "192 Bits\0" "224 Bits\0" "256 Bits\0" "288 Bits\0" "384 Bits\0" "512 Bits\0");
|
||||
|
||||
}
|
||||
|
||||
Function create(std::string name) override {
|
||||
return Hash::create(name, [hash = *this, key = hex::parseByteString(this->m_key), salt = hex::parseByteString(this->m_salt), personalization = hex::parseByteString(this->m_personalization)](const Region& region, prv::Provider *provider) -> std::vector<u8> {
|
||||
u32 hashSize = 16;
|
||||
switch (hash.m_hashSize) {
|
||||
case 0: hashSize = 16; break;
|
||||
case 1: hashSize = 20; break;
|
||||
case 2: hashSize = 24; break;
|
||||
case 3: hashSize = 28; break;
|
||||
case 4: hashSize = 32; break;
|
||||
case 5: hashSize = 36; break;
|
||||
case 6: hashSize = 48; break;
|
||||
case 7: hashSize = 64; break;
|
||||
}
|
||||
|
||||
auto config = Config::GetDefaultConfig();
|
||||
config->SetKey(key);
|
||||
config->SetSalt(salt);
|
||||
config->SetPersonalization(personalization);
|
||||
config->SetHashSize(hashSize);
|
||||
IHash hashFunction = hash.m_factoryFunction(config, nullptr);
|
||||
|
||||
hashFunction->Initialize();
|
||||
|
||||
return hashProviderRegion(region, provider, hashFunction);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] nlohmann::json store() const override { return { }; }
|
||||
void load(const nlohmann::json &) override {}
|
||||
|
||||
private:
|
||||
FactoryFunction m_factoryFunction;
|
||||
std::string m_salt, m_key, m_personalization;
|
||||
int m_hashSize = 0;
|
||||
};
|
||||
|
||||
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<u8>>("hex.hashes.hash.crc8", crypt::crc8, 0x07, 0x0000, 0x0000);
|
||||
ContentRegistry::Hashes::add<HashCRC<u16>>("hex.hashes.hash.crc16", crypt::crc16, 0x8005, 0x0000, 0x0000);
|
||||
ContentRegistry::Hashes::add<HashCRC<u32>>("hex.hashes.hash.crc32", crypt::crc32, 0x04C1'1DB7, 0xFFFF'FFFF, 0xFFFF'FFFF, true, true);
|
||||
ContentRegistry::Hashes::add<HashCRC<u32>>("hex.hashes.hash.crc32mpeg", crypt::crc32, 0x04C1'1DB7, 0xFFFF'FFFF, 0x0000'0000, false, false);
|
||||
ContentRegistry::Hashes::add<HashCRC<u32>>("hex.hashes.hash.crc32posix", crypt::crc32, 0x04C1'1DB7, 0x0000'0000, 0xFFFF'FFFF, false, false);
|
||||
ContentRegistry::Hashes::add<HashCRC<u32>>("hex.hashes.hash.crc32c", crypt::crc32, 0x1EDC'6F41, 0xFFFF'FFFF, 0xFFFF'FFFF, true, true);
|
||||
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Checksum::CreateAdler32);
|
||||
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateAP);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateBKDR);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateBernstein);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateBernstein1);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateDEK);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateDJB);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateELF);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateFNV1a_32);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateFNV32);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateJS);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateOneAtTime);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreatePJW);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateRotating);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateRS);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateSDBM);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateShiftAndXor);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash32::CreateSuperFast);
|
||||
|
||||
hex::ContentRegistry::Hashes::add<HashWithKey>(HashFactory::Hash32::CreateMurmur2_32);
|
||||
hex::ContentRegistry::Hashes::add<HashWithKey>(HashFactory::Hash32::CreateMurmurHash3_x86_32);
|
||||
hex::ContentRegistry::Hashes::add<HashWithKey>(HashFactory::Hash32::CreateXXHash32);
|
||||
|
||||
hex::ContentRegistry::Hashes::add<HashInitialValue>(HashFactory::Hash32::CreateJenkins3);
|
||||
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash64::CreateFNV64);
|
||||
hex::ContentRegistry::Hashes::add<HashBasic>(HashFactory::Hash64::CreateFNV1a_64);
|
||||
|
||||
hex::ContentRegistry::Hashes::add<HashWithKey>(HashFactory::Hash64::CreateMurmur2_64);
|
||||
hex::ContentRegistry::Hashes::add<HashWithKey>(HashFactory::Hash64::CreateSipHash64_2_4);
|
||||
hex::ContentRegistry::Hashes::add<HashWithKey>(HashFactory::Hash64::CreateXXHash64);
|
||||
|
||||
hex::ContentRegistry::Hashes::add<HashWithKey>(HashFactory::Hash128::CreateSipHash128_2_4);
|
||||
hex::ContentRegistry::Hashes::add<HashWithKey>(HashFactory::Hash128::CreateMurmurHash3_x86_128);
|
||||
hex::ContentRegistry::Hashes::add<HashWithKey>(HashFactory::Hash128::CreateMurmurHash3_x64_128);
|
||||
|
||||
hex::ContentRegistry::Hashes::add<HashTiger>("hex.hashes.hash.tiger", HashFactory::Crypto::CreateTiger);
|
||||
hex::ContentRegistry::Hashes::add<HashTiger>("hex.hashes.hash.tiger2", HashFactory::Crypto::CreateTiger2);
|
||||
|
||||
hex::ContentRegistry::Hashes::add<HashBlake2<Blake2BConfig, IBlake2BConfig, IBlake2BTreeConfig>>("hex.hashes.hash.blake2b", HashFactory::Crypto::CreateBlake2B);
|
||||
hex::ContentRegistry::Hashes::add<HashBlake2<Blake2SConfig, IBlake2SConfig, IBlake2STreeConfig>>("hex.hashes.hash.blake2s", HashFactory::Crypto::CreateBlake2S);
|
||||
}
|
||||
|
||||
}
|
||||
289
plugins/hashes/source/content/views/view_hashes.cpp
Normal file
289
plugins/hashes/source/content/views/view_hashes.cpp
Normal file
@@ -0,0 +1,289 @@
|
||||
#include "content/views/view_hashes.hpp"
|
||||
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <hex/api/achievement_manager.hpp>
|
||||
#include <hex/providers/memory_provider.hpp>
|
||||
|
||||
#include <hex/ui/popup.hpp>
|
||||
#include <hex/helpers/crypto.hpp>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace hex::plugin::hashes {
|
||||
|
||||
class PopupTextHash : public Popup<PopupTextHash> {
|
||||
public:
|
||||
explicit PopupTextHash(const ContentRegistry::Hashes::Hash::Function &hash)
|
||||
: hex::Popup<PopupTextHash>(hash.getName(), true, false),
|
||||
m_hash(hash) { }
|
||||
|
||||
void drawContent() override {
|
||||
ImGuiExt::Header(this->getUnlocalizedName(), true);
|
||||
|
||||
ImGui::PushItemWidth(-1);
|
||||
if (ImGui::InputTextMultiline("##input", m_input)) {
|
||||
prv::MemoryProvider provider({ m_input.begin(), m_input.end() });
|
||||
|
||||
m_hash.reset();
|
||||
auto bytes = m_hash.get(Region { 0x00, provider.getActualSize() }, &provider);
|
||||
|
||||
m_result = crypt::encode16(bytes);
|
||||
}
|
||||
|
||||
ImGui::NewLine();
|
||||
ImGui::InputText("##result", m_result, ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape)))
|
||||
this->close();
|
||||
}
|
||||
|
||||
[[nodiscard]] ImGuiWindowFlags getFlags() const override {
|
||||
return ImGuiWindowFlags_AlwaysAutoResize;
|
||||
}
|
||||
|
||||
ImVec2 getMinSize() const override {
|
||||
return scaled({ 400, 200 });
|
||||
}
|
||||
|
||||
ImVec2 getMaxSize() const override { return this->getMinSize(); }
|
||||
|
||||
private:
|
||||
std::string m_input;
|
||||
std::string m_result;
|
||||
ContentRegistry::Hashes::Hash::Function m_hash;
|
||||
};
|
||||
|
||||
ViewHashes::ViewHashes() : View::Window("hex.hashes.view.hashes.name") {
|
||||
EventRegionSelected::subscribe(this, [this](const auto &providerRegion) {
|
||||
for (auto &function : m_hashFunctions.get(providerRegion.getProvider()))
|
||||
function.reset();
|
||||
});
|
||||
|
||||
ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) {
|
||||
hex::unused(data);
|
||||
|
||||
auto selection = ImHexApi::HexEditor::getSelection();
|
||||
|
||||
if (selection.has_value() && ImGui::GetIO().KeyShift) {
|
||||
auto &hashFunctions = m_hashFunctions.get(selection->getProvider());
|
||||
if (!hashFunctions.empty() && selection.has_value() && selection->overlaps(Region { address, size })) {
|
||||
ImGui::BeginTooltip();
|
||||
|
||||
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip, ImMax(ImGui::GetContentRegionAvail(), ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 5)))) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::TextUnformatted("hex.hashes.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 : hashFunctions) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGuiExt::TextFormatted("{}", function.getName());
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGuiExt::TextFormatted(" ");
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
if (provider != nullptr)
|
||||
ImGuiExt::TextFormatted("{}", crypt::encode16(function.get(*selection, provider)));
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::Unindent();
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ProjectFile::registerPerProviderHandler({
|
||||
.basePath = "hashes.json",
|
||||
.required = false,
|
||||
.load = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool {
|
||||
auto fileContent = tar.readString(basePath);
|
||||
if (fileContent.empty())
|
||||
return true;
|
||||
|
||||
auto data = nlohmann::json::parse(fileContent.begin(), fileContent.end());
|
||||
m_hashFunctions->clear();
|
||||
|
||||
return this->importHashes(provider, data);
|
||||
},
|
||||
.store = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool {
|
||||
nlohmann::json data;
|
||||
|
||||
bool result = this->exportHashes(provider, data);
|
||||
tar.writeString(basePath, data.dump(4));
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ViewHashes::~ViewHashes() {
|
||||
EventRegionSelected::unsubscribe(this);
|
||||
}
|
||||
|
||||
|
||||
void ViewHashes::drawContent() {
|
||||
const auto &hashes = ContentRegistry::Hashes::impl::getHashes();
|
||||
|
||||
if (m_selectedHash == nullptr && !hashes.empty()) {
|
||||
m_selectedHash = hashes.front().get();
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("hex.hashes.view.hashes.function"_lang, m_selectedHash != nullptr ? Lang(m_selectedHash->getUnlocalizedName()) : "")) {
|
||||
|
||||
for (const auto &hash : hashes) {
|
||||
if (ImGui::Selectable(Lang(hash->getUnlocalizedName()), m_selectedHash == hash.get())) {
|
||||
m_selectedHash = hash.get();
|
||||
m_newHashName.clear();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (m_newHashName.empty() && m_selectedHash != nullptr)
|
||||
m_newHashName = hex::format("{} {}", Lang(m_selectedHash->getUnlocalizedName()), static_cast<const char *>("hex.hashes.view.hashes.hash"_lang));
|
||||
|
||||
if (ImGui::BeginChild("##settings", ImVec2(ImGui::GetContentRegionAvail().x, 200_scaled), true)) {
|
||||
if (m_selectedHash != nullptr) {
|
||||
auto startPos = ImGui::GetCursorPosY();
|
||||
m_selectedHash->draw();
|
||||
|
||||
// Check if no elements have been added
|
||||
if (startPos == ImGui::GetCursorPosY()) {
|
||||
ImGuiExt::TextFormattedCentered("hex.hashes.view.hashes.no_settings"_lang);
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
|
||||
ImGuiExt::InputTextIcon("##hash_name", ICON_VS_SYMBOL_KEY, m_newHashName);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::BeginDisabled(m_newHashName.empty() || m_selectedHash == nullptr);
|
||||
if (ImGuiExt::IconButton(ICON_VS_ADD, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
|
||||
if (m_selectedHash != nullptr) {
|
||||
m_hashFunctions->push_back(m_selectedHash->create(m_newHashName));
|
||||
AchievementManager::unlockAchievement("hex.builtin.achievement.misc", "hex.hashes.achievement.misc.create_hash.name");
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGuiExt::HelpHover("hex.hashes.view.hashes.hover_info"_lang);
|
||||
|
||||
if (ImGui::BeginTable("##hashes", 4, ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Borders | ImGuiTableFlags_ScrollY)) {
|
||||
ImGui::TableSetupColumn("hex.hashes.view.hashes.table.name"_lang);
|
||||
ImGui::TableSetupColumn("hex.hashes.view.hashes.table.type"_lang);
|
||||
ImGui::TableSetupColumn("hex.hashes.view.hashes.table.result"_lang, ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("##buttons", ImGuiTableColumnFlags_WidthFixed, 50_scaled);
|
||||
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
auto selection = ImHexApi::HexEditor::getSelection();
|
||||
|
||||
std::optional<u32> indexToRemove;
|
||||
for (u32 i = 0; i < m_hashFunctions->size(); i++) {
|
||||
auto &function = (*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);
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGuiExt::TextFormatted("{}", Lang(function.getType()->getUnlocalizedName()));
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
std::string result;
|
||||
if (provider != nullptr && selection.has_value())
|
||||
result = crypt::encode16(function.get(*selection, provider));
|
||||
else
|
||||
result = "???";
|
||||
|
||||
ImGui::PushItemWidth(-1);
|
||||
ImGui::InputText("##result", result, ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (ImGuiExt::IconButton(ICON_VS_OPEN_PREVIEW, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
|
||||
PopupTextHash::open(function);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGuiExt::IconButton(ICON_VS_X, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) {
|
||||
indexToRemove = i;
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
if (indexToRemove.has_value()) {
|
||||
m_hashFunctions->erase(m_hashFunctions->begin() + indexToRemove.value());
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
|
||||
bool ViewHashes::importHashes(prv::Provider *provider, const nlohmann::json &json) {
|
||||
if (!json.contains("hashes"))
|
||||
return false;
|
||||
|
||||
const auto &hashes = ContentRegistry::Hashes::impl::getHashes();
|
||||
|
||||
for (const auto &hash : json["hashes"]) {
|
||||
if (!hash.contains("name") || !hash.contains("type") || !hash.contains("settings"))
|
||||
continue;
|
||||
|
||||
for (const auto &newHash : hashes) {
|
||||
if (newHash->getUnlocalizedName() == hash["type"].get<std::string>()) {
|
||||
|
||||
auto newFunction = newHash->create(hash["name"]);
|
||||
newFunction.getType()->load(hash["settings"]);
|
||||
|
||||
m_hashFunctions.get(provider).push_back(std::move(newFunction));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ViewHashes::exportHashes(prv::Provider *provider, nlohmann::json &json) {
|
||||
json["hashes"] = nlohmann::json::array();
|
||||
size_t index = 0;
|
||||
for (const auto &hashFunction : m_hashFunctions.get(provider)) {
|
||||
json["hashes"][index] = {
|
||||
{ "name", hashFunction.getName() },
|
||||
{ "type", hashFunction.getType()->getUnlocalizedName() },
|
||||
{ "settings", hashFunction.getType()->store() }
|
||||
};
|
||||
index++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
33
plugins/hashes/source/plugin_hashes.cpp
Normal file
33
plugins/hashes/source/plugin_hashes.cpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#include <hex/plugin.hpp>
|
||||
|
||||
#include <hex/api/achievement_manager.hpp>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <romfs/romfs.hpp>
|
||||
|
||||
#include <content/views/view_hashes.hpp>
|
||||
|
||||
namespace hex::plugin::hashes {
|
||||
|
||||
void registerHashes();
|
||||
|
||||
}
|
||||
|
||||
using namespace hex;
|
||||
using namespace hex::plugin::hashes;
|
||||
|
||||
IMHEX_PLUGIN_SETUP("Hashes", "WerWolv", "Hashing algorithms") {
|
||||
hex::log::debug("Using romfs: '{}'", romfs::name());
|
||||
for (auto &path : romfs::list("lang"))
|
||||
hex::ContentRegistry::Language::addLocalization(nlohmann::json::parse(romfs::get(path).string()));
|
||||
|
||||
registerHashes();
|
||||
ContentRegistry::Views::add<ViewHashes>();
|
||||
|
||||
AchievementManager::addAchievement<Achievement>("hex.builtin.achievement.misc", "hex.hashes.achievement.misc.create_hash.name")
|
||||
.setDescription("hex.hashes.achievement.misc.create_hash.desc")
|
||||
.setIcon(romfs::get("assets/achievements/fortune-cookie.png").span())
|
||||
.addRequirement("hex.builtin.achievement.starting_out.open_file.name");
|
||||
}
|
||||
Reference in New Issue
Block a user