From 434bb3494a504d35a0688a09ec950b98b3a0051f Mon Sep 17 00:00:00 2001 From: WerWolv Date: Wed, 11 Nov 2020 09:18:35 +0100 Subject: [PATCH] Abstracted FILE handle into a generic data provider class --- CMakeLists.txt | 2 + include/providers/file_provider.hpp | 28 ++++++ include/providers/provider.hpp | 21 +++++ include/views/view_hashes.hpp | 6 +- include/views/view_hexeditor.hpp | 7 +- include/views/view_pattern_data.hpp | 6 +- source/main.cpp | 10 +- source/provider/file_provider.cpp | 59 ++++++++++++ source/views/view_hashes.cpp | 136 ++++++++++++++++------------ source/views/view_hexeditor.cpp | 31 +++---- source/views/view_pattern_data.cpp | 16 ++-- 11 files changed, 229 insertions(+), 93 deletions(-) create mode 100644 include/providers/file_provider.hpp create mode 100644 include/providers/provider.hpp create mode 100644 source/provider/file_provider.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index dca81f177..3b133c31b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,8 @@ add_executable(ImHex source/parser/lexer.cpp source/parser/parser.cpp + source/provider/file_provider.cpp + source/views/view_hexeditor.cpp source/views/view_pattern.cpp source/views/view_pattern_data.cpp diff --git a/include/providers/file_provider.hpp b/include/providers/file_provider.hpp new file mode 100644 index 000000000..a8ee322d5 --- /dev/null +++ b/include/providers/file_provider.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "providers/provider.hpp" + +#include + +namespace hex::prv { + + class FileProvider : public Provider { + public: + FileProvider(std::string_view path); + virtual ~FileProvider(); + + virtual bool isAvailable() override; + virtual bool isReadable() override; + virtual bool isWritable() override; + + virtual void read(u64 offset, void *buffer, size_t size) override; + virtual void write(u64 offset, void *buffer, size_t size) override; + virtual size_t getSize() override; + + private: + FILE *m_file; + + bool m_readable, m_writable; + }; + +} \ No newline at end of file diff --git a/include/providers/provider.hpp b/include/providers/provider.hpp new file mode 100644 index 000000000..572282bda --- /dev/null +++ b/include/providers/provider.hpp @@ -0,0 +1,21 @@ +#pragma once + +#include + +namespace hex::prv { + + class Provider { + public: + Provider() { } + virtual ~Provider() { } + + virtual bool isAvailable() = 0; + virtual bool isReadable() = 0; + virtual bool isWritable() = 0; + + virtual void read(u64 offset, void *buffer, size_t size) = 0; + virtual void write(u64 offset, void *buffer, size_t size) = 0; + virtual size_t getSize() = 0; + }; + +} \ No newline at end of file diff --git a/include/views/view_hashes.hpp b/include/views/view_hashes.hpp index 1d423b7af..c6a1abe75 100644 --- a/include/views/view_hashes.hpp +++ b/include/views/view_hashes.hpp @@ -4,18 +4,20 @@ #include +#include "providers/provider.hpp" + namespace hex { class ViewHashes : public View { public: - ViewHashes(FILE* &file); + ViewHashes(prv::Provider* &dataProvider); virtual ~ViewHashes(); virtual void createView() override; virtual void createMenu() override; private: - FILE* &m_file; + prv::Provider* &m_dataProvider; bool m_windowOpen = true; int m_currHashFunction = 0; diff --git a/include/views/view_hexeditor.hpp b/include/views/view_hexeditor.hpp index 4c984f350..7cc48cd8b 100644 --- a/include/views/view_hexeditor.hpp +++ b/include/views/view_hexeditor.hpp @@ -14,11 +14,13 @@ #include "views/highlight.hpp" +#include "providers/provider.hpp" + namespace hex { class ViewHexEditor : public View { public: - ViewHexEditor(FILE* &file, std::vector &highlights); + ViewHexEditor(prv::Provider* &dataProvider, std::vector &highlights); virtual ~ViewHexEditor(); virtual void createView() override; @@ -27,8 +29,7 @@ namespace hex { private: MemoryEditor m_memoryEditor; - FILE* &m_file; - size_t m_fileSize = 0; + prv::Provider* &m_dataProvider; std::vector &m_highlights; }; diff --git a/include/views/view_pattern_data.hpp b/include/views/view_pattern_data.hpp index 91294ed0c..8fd6064e1 100644 --- a/include/views/view_pattern_data.hpp +++ b/include/views/view_pattern_data.hpp @@ -10,18 +10,20 @@ #include #include +#include "providers/provider.hpp" + namespace hex { class ViewPatternData : public View { public: - ViewPatternData(FILE* &file,std::vector &highlights); + ViewPatternData(prv::Provider* &dataProvider, std::vector &highlights); virtual ~ViewPatternData(); virtual void createView() override; virtual void createMenu() override; private: - FILE* &m_file; + prv::Provider* &m_dataProvider; std::vector &m_highlights; bool m_windowOpen = true; }; diff --git a/source/main.cpp b/source/main.cpp index ad6099b5f..4829f2f0e 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -6,6 +6,8 @@ #include "views/view_pattern_data.hpp" #include "views/view_hashes.hpp" +#include "providers/provider.hpp" + #include #include @@ -14,13 +16,13 @@ int main() { // Shared Data std::vector highlights; - FILE *file = nullptr; + hex::prv::Provider *dataProvider = nullptr; // Create views - window.addView(file, highlights); + window.addView(dataProvider, highlights); window.addView(highlights); - window.addView(file, highlights); - window.addView(file); + window.addView(dataProvider, highlights); + window.addView(dataProvider); window.loop(); diff --git a/source/provider/file_provider.cpp b/source/provider/file_provider.cpp new file mode 100644 index 000000000..f410c8b96 --- /dev/null +++ b/source/provider/file_provider.cpp @@ -0,0 +1,59 @@ +#include "providers/file_provider.hpp" + +#include + +namespace hex::prv { + + FileProvider::FileProvider(std::string_view path) { + this->m_file = fopen(path.data(), "r+b"); + + this->m_readable = true; + this->m_writable = true; + + if (this->m_file == nullptr) { + this->m_file = fopen(path.data(), "rb"); + this->m_writable = false; + } + } + + FileProvider::~FileProvider() { + if (this->m_file != nullptr) + fclose(this->m_file); + } + + + bool FileProvider::isAvailable() { + return this->m_file != nullptr; + } + + bool FileProvider::isReadable() { + return this->m_readable; + } + + bool FileProvider::isWritable() { + return this->m_writable; + } + + + void FileProvider::read(u64 offset, void *buffer, size_t size) { + if ((offset + size) > this->getSize() || buffer == nullptr || size == 0) + return; + + fseek(this->m_file, offset, SEEK_SET); + fread(buffer, 1, size, this->m_file); + } + + void FileProvider::write(u64 offset, void *buffer, size_t size) { + if (buffer == nullptr || size == 0) + return; + + fseek(this->m_file, offset, SEEK_SET); + fwrite(buffer, 1, size, this->m_file); + } + + size_t FileProvider::getSize() { + fseek(this->m_file, 0, SEEK_END); + return ftell(this->m_file); + } + +} \ No newline at end of file diff --git a/source/views/view_hashes.cpp b/source/views/view_hashes.cpp index e1ba944f4..feebfe43b 100644 --- a/source/views/view_hashes.cpp +++ b/source/views/view_hashes.cpp @@ -6,7 +6,7 @@ namespace hex { - ViewHashes::ViewHashes(FILE* &file) : View(), m_file(file) { + ViewHashes::ViewHashes(prv::Provider* &dataProvider) : View(), m_dataProvider(dataProvider) { } @@ -19,77 +19,101 @@ namespace hex { if (!this->m_windowOpen) return; + static bool invalidate = false; + if (ImGui::Begin("Hashing", &this->m_windowOpen)) { ImGui::BeginChild("##scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav); ImGui::NewLine(); - ImGui::Combo("Hash Function", &this->m_currHashFunction, HashFunctionNames, sizeof(HashFunctionNames) / sizeof(const char*)); + if (this->m_dataProvider != nullptr && this->m_dataProvider->isAvailable()) { - ImGui::NewLine(); - ImGui::Separator(); - ImGui::NewLine(); + ImGui::Combo("Hash Function", &this->m_currHashFunction, HashFunctionNames, sizeof(HashFunctionNames) / sizeof(const char*)); - ImGui::InputInt("Begin", &this->m_hashStart, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - ImGui::InputInt("End", &this->m_hashEnd, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); + ImGui::NewLine(); + ImGui::Separator(); + ImGui::NewLine(); - ImGui::NewLine(); - ImGui::Separator(); - ImGui::NewLine(); + ImGui::InputInt("Begin", &this->m_hashStart, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - switch (this->m_currHashFunction) { - case 0: // CRC16 - { - if (this->m_file == nullptr) - break; + ImGui::InputInt("End", &this->m_hashEnd, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - std::vector buffer(this->m_hashEnd - this->m_hashStart + 1, 0x00); - fseek(this->m_file, this->m_hashStart, SEEK_SET); - fread(buffer.data(), 1, buffer.size(), this->m_file); + ImGui::NewLine(); + ImGui::Separator(); + ImGui::NewLine(); - static int polynomial = 0, init = 0; + if (this->m_hashEnd >= this->m_hashStart) { + + std::vector buffer; + + if (invalidate) { + buffer = std::vector(this->m_hashEnd - this->m_hashStart + 1, 0x00); + this->m_dataProvider->read(this->m_hashStart, buffer.data(), buffer.size()); + } + + switch (this->m_currHashFunction) { + case 0: // CRC16 + { + static int polynomial = 0, init = 0; + + ImGui::InputInt("Initial Value", &init, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); + ImGui::InputInt("Polynomial", &polynomial, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); + + ImGui::NewLine(); + ImGui::Separator(); + ImGui::NewLine(); + + static u16 result = 0; + + if (invalidate) + result = crc16(buffer.data(), buffer.size(), polynomial, init); + + ImGui::LabelText("##nolabel", "%X", result); + } + break; + case 1: // CRC32 + { + static int polynomial = 0, init = 0; + + ImGui::InputInt("Initial Value", &init, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); + ImGui::InputInt("Polynomial", &polynomial, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); + + ImGui::NewLine(); + ImGui::Separator(); + ImGui::NewLine(); + + static u32 result = 0; + + if (invalidate) + result = crc32(buffer.data(), buffer.size(), polynomial, init); + + ImGui::LabelText("##nolabel", "%X", result); + } + break; + case 2: // MD5 + { + static std::array result; + + if (invalidate) + result = md5(buffer.data(), buffer.size()); + + ImGui::LabelText("##nolabel", "%08X%08X%08X%08X", + __builtin_bswap32(result[0]), + __builtin_bswap32(result[1]), + __builtin_bswap32(result[2]), + __builtin_bswap32(result[3])); + } + break; + } - ImGui::InputInt("Initial Value", &init, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - ImGui::InputInt("Polynomial", &polynomial, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - ImGui::NewLine(); - ImGui::Separator(); - ImGui::NewLine(); - ImGui::LabelText("Result", "%X", crc16(buffer.data(), buffer.size(), polynomial, init)); } - break; - case 1: // CRC32 - { - if (this->m_file == nullptr) - break; - std::vector buffer(this->m_hashEnd - this->m_hashStart + 1, 0x00); - fseek(this->m_file, this->m_hashStart, SEEK_SET); - fread(buffer.data(), 1, buffer.size(), this->m_file); + invalidate = false; - static int polynomial = 0, init = 0; + ImGui::SameLine(); + if (ImGui::Button("Hash")) + invalidate = true; - ImGui::InputInt("Initial Value", &init, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - ImGui::InputInt("Polynomial", &polynomial, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); - ImGui::NewLine(); - ImGui::Separator(); - ImGui::NewLine(); - ImGui::LabelText("Result", "%X", crc32(buffer.data(), buffer.size(), polynomial, init)); - } - break; - case 2: // MD5 - { - if (this->m_file == nullptr) - break; - - std::vector buffer(this->m_hashEnd - this->m_hashStart + 1, 0x00); - fseek(this->m_file, this->m_hashStart, SEEK_SET); - fread(buffer.data(), 1, buffer.size(), this->m_file); - - auto result = md5(buffer.data(), buffer.size()); - - ImGui::LabelText("Result", "%08X%08X%08X%08X", __builtin_bswap32(result[0]), __builtin_bswap32(result[1]), __builtin_bswap32(result[2]), __builtin_bswap32(result[3])); - } - break; } ImGui::EndChild(); diff --git a/source/views/view_hexeditor.cpp b/source/views/view_hexeditor.cpp index 01d7aed6d..1ae897f32 100644 --- a/source/views/view_hexeditor.cpp +++ b/source/views/view_hexeditor.cpp @@ -1,20 +1,20 @@ #include "views/view_hexeditor.hpp" +#include "providers/file_provider.hpp" + namespace hex { - ViewHexEditor::ViewHexEditor(FILE *&file, std::vector &highlights) - : View(), m_file(file), m_highlights(highlights) { + ViewHexEditor::ViewHexEditor(prv::Provider* &dataProvider, std::vector &highlights) + : View(), m_dataProvider(dataProvider), m_highlights(highlights) { this->m_memoryEditor.ReadFn = [](const ImU8 *data, size_t off) -> ImU8 { ViewHexEditor *_this = (ViewHexEditor *) data; - if (_this->m_file == nullptr) + if (!_this->m_dataProvider->isAvailable() || !_this->m_dataProvider->isReadable()) return 0x00; - fseek(_this->m_file, off, SEEK_SET); - ImU8 byte; - fread(&byte, sizeof(ImU8), 1, _this->m_file); + _this->m_dataProvider->read(off, &byte, sizeof(ImU8)); return byte; }; @@ -22,13 +22,10 @@ namespace hex { this->m_memoryEditor.WriteFn = [](ImU8 *data, size_t off, ImU8 d) -> void { ViewHexEditor *_this = (ViewHexEditor *) data; - if (_this->m_file == nullptr) + if (!_this->m_dataProvider->isAvailable() || !_this->m_dataProvider->isWritable()) return; - fseek(_this->m_file, off, SEEK_SET); - - fwrite(&d, sizeof(ImU8), 1, _this->m_file); - + _this->m_dataProvider->write(off, &d, sizeof(ImU8)); }; this->m_memoryEditor.HighlightFn = [](const ImU8 *data, size_t off, bool next) -> bool { @@ -53,7 +50,7 @@ namespace hex { ViewHexEditor::~ViewHexEditor() {} void ViewHexEditor::createView() { - this->m_memoryEditor.DrawWindow("Hex Editor", this, this->m_file == nullptr ? 0x00 : this->m_fileSize); + this->m_memoryEditor.DrawWindow("Hex Editor", this, (this->m_dataProvider == nullptr || !this->m_dataProvider->isReadable()) ? 0x00 : this->m_dataProvider->getSize()); } void ViewHexEditor::createMenu() { @@ -61,14 +58,10 @@ namespace hex { if (ImGui::MenuItem("Open File...")) { auto filePath = openFileDialog(); if (filePath.has_value()) { - if (this->m_file != nullptr) - fclose(this->m_file); + if (this->m_dataProvider != nullptr) + delete this->m_dataProvider; - this->m_file = fopen(filePath->c_str(), "r+b"); - - fseek(this->m_file, 0, SEEK_END); - this->m_fileSize = ftell(this->m_file); - rewind(this->m_file); + this->m_dataProvider = new prv::FileProvider(filePath.value()); } } diff --git a/source/views/view_pattern_data.cpp b/source/views/view_pattern_data.cpp index c7e018741..d8fc0d0f2 100644 --- a/source/views/view_pattern_data.cpp +++ b/source/views/view_pattern_data.cpp @@ -4,8 +4,8 @@ namespace hex { - ViewPatternData::ViewPatternData(FILE* &file, std::vector &highlights) - : View(), m_file(file), m_highlights(highlights) { + ViewPatternData::ViewPatternData(prv::Provider* &dataProvider, std::vector &highlights) + : View(), m_dataProvider(dataProvider), m_highlights(highlights) { } @@ -34,13 +34,15 @@ namespace hex { for (auto& [offset, size, color, name] : this->m_highlights) { std::vector buffer(size + 1, 0x00); - u64 data = 0; - fseek(this->m_file, offset, SEEK_SET); - fread(buffer.data(), 1, size, this->m_file); - std::memcpy(&data, buffer.data(), size); - if (size <= 8) + this->m_dataProvider->read(offset, buffer.data(), size); + + if (size <= 8) { + u64 data = 0; + std::memcpy(&data, buffer.data(), size); + ImGui::LabelText(name.c_str(), "[0x%08lx:0x%08lx] %lu (0x%08lx) \"%s\"", offset, offset + size, data, data, makeDisplayable(buffer.data(), buffer.size()).c_str()); + } else ImGui::LabelText(name.c_str(), "[0x%08lx:0x%08lx] [ ARRAY ] \"%s\"", offset, offset + size, makeDisplayable(buffer.data(), buffer.size()).c_str()); }