Abstracted FILE handle into a generic data provider class

This commit is contained in:
WerWolv
2020-11-11 09:18:35 +01:00
parent c87bc6aebe
commit 434bb3494a
11 changed files with 229 additions and 93 deletions

View File

@@ -16,6 +16,8 @@ add_executable(ImHex
source/parser/lexer.cpp source/parser/lexer.cpp
source/parser/parser.cpp source/parser/parser.cpp
source/provider/file_provider.cpp
source/views/view_hexeditor.cpp source/views/view_hexeditor.cpp
source/views/view_pattern.cpp source/views/view_pattern.cpp
source/views/view_pattern_data.cpp source/views/view_pattern_data.cpp

View File

@@ -0,0 +1,28 @@
#pragma once
#include "providers/provider.hpp"
#include <string_view>
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;
};
}

View File

@@ -0,0 +1,21 @@
#pragma once
#include <hex.hpp>
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;
};
}

View File

@@ -4,18 +4,20 @@
#include <cstdio> #include <cstdio>
#include "providers/provider.hpp"
namespace hex { namespace hex {
class ViewHashes : public View { class ViewHashes : public View {
public: public:
ViewHashes(FILE* &file); ViewHashes(prv::Provider* &dataProvider);
virtual ~ViewHashes(); virtual ~ViewHashes();
virtual void createView() override; virtual void createView() override;
virtual void createMenu() override; virtual void createMenu() override;
private: private:
FILE* &m_file; prv::Provider* &m_dataProvider;
bool m_windowOpen = true; bool m_windowOpen = true;
int m_currHashFunction = 0; int m_currHashFunction = 0;

View File

@@ -14,11 +14,13 @@
#include "views/highlight.hpp" #include "views/highlight.hpp"
#include "providers/provider.hpp"
namespace hex { namespace hex {
class ViewHexEditor : public View { class ViewHexEditor : public View {
public: public:
ViewHexEditor(FILE* &file, std::vector<Highlight> &highlights); ViewHexEditor(prv::Provider* &dataProvider, std::vector<Highlight> &highlights);
virtual ~ViewHexEditor(); virtual ~ViewHexEditor();
virtual void createView() override; virtual void createView() override;
@@ -27,8 +29,7 @@ namespace hex {
private: private:
MemoryEditor m_memoryEditor; MemoryEditor m_memoryEditor;
FILE* &m_file; prv::Provider* &m_dataProvider;
size_t m_fileSize = 0;
std::vector<Highlight> &m_highlights; std::vector<Highlight> &m_highlights;
}; };

View File

@@ -10,18 +10,20 @@
#include <tuple> #include <tuple>
#include <cstdio> #include <cstdio>
#include "providers/provider.hpp"
namespace hex { namespace hex {
class ViewPatternData : public View { class ViewPatternData : public View {
public: public:
ViewPatternData(FILE* &file,std::vector<Highlight> &highlights); ViewPatternData(prv::Provider* &dataProvider, std::vector<Highlight> &highlights);
virtual ~ViewPatternData(); virtual ~ViewPatternData();
virtual void createView() override; virtual void createView() override;
virtual void createMenu() override; virtual void createMenu() override;
private: private:
FILE* &m_file; prv::Provider* &m_dataProvider;
std::vector<Highlight> &m_highlights; std::vector<Highlight> &m_highlights;
bool m_windowOpen = true; bool m_windowOpen = true;
}; };

View File

@@ -6,6 +6,8 @@
#include "views/view_pattern_data.hpp" #include "views/view_pattern_data.hpp"
#include "views/view_hashes.hpp" #include "views/view_hashes.hpp"
#include "providers/provider.hpp"
#include <tuple> #include <tuple>
#include <vector> #include <vector>
@@ -14,13 +16,13 @@ int main() {
// Shared Data // Shared Data
std::vector<hex::Highlight> highlights; std::vector<hex::Highlight> highlights;
FILE *file = nullptr; hex::prv::Provider *dataProvider = nullptr;
// Create views // Create views
window.addView<hex::ViewHexEditor>(file, highlights); window.addView<hex::ViewHexEditor>(dataProvider, highlights);
window.addView<hex::ViewPattern>(highlights); window.addView<hex::ViewPattern>(highlights);
window.addView<hex::ViewPatternData>(file, highlights); window.addView<hex::ViewPatternData>(dataProvider, highlights);
window.addView<hex::ViewHashes>(file); window.addView<hex::ViewHashes>(dataProvider);
window.loop(); window.loop();

View File

@@ -0,0 +1,59 @@
#include "providers/file_provider.hpp"
#include <cstdio>
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);
}
}

View File

@@ -6,7 +6,7 @@
namespace hex { 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) if (!this->m_windowOpen)
return; return;
static bool invalidate = false;
if (ImGui::Begin("Hashing", &this->m_windowOpen)) { if (ImGui::Begin("Hashing", &this->m_windowOpen)) {
ImGui::BeginChild("##scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav); ImGui::BeginChild("##scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav);
ImGui::NewLine(); 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::Combo("Hash Function", &this->m_currHashFunction, HashFunctionNames, sizeof(HashFunctionNames) / sizeof(const char*));
ImGui::Separator();
ImGui::NewLine();
ImGui::InputInt("Begin", &this->m_hashStart, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); ImGui::NewLine();
ImGui::InputInt("End", &this->m_hashEnd, 0, 0, ImGuiInputTextFlags_CharsHexadecimal); ImGui::Separator();
ImGui::NewLine();
ImGui::NewLine(); ImGui::InputInt("Begin", &this->m_hashStart, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
ImGui::Separator();
ImGui::NewLine();
switch (this->m_currHashFunction) { ImGui::InputInt("End", &this->m_hashEnd, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
case 0: // CRC16
{
if (this->m_file == nullptr)
break;
std::vector<u8> buffer(this->m_hashEnd - this->m_hashStart + 1, 0x00); ImGui::NewLine();
fseek(this->m_file, this->m_hashStart, SEEK_SET); ImGui::Separator();
fread(buffer.data(), 1, buffer.size(), this->m_file); ImGui::NewLine();
static int polynomial = 0, init = 0; if (this->m_hashEnd >= this->m_hashStart) {
std::vector<u8> buffer;
if (invalidate) {
buffer = std::vector<u8>(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<u32, 4> 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<u8> buffer(this->m_hashEnd - this->m_hashStart + 1, 0x00); invalidate = false;
fseek(this->m_file, this->m_hashStart, SEEK_SET);
fread(buffer.data(), 1, buffer.size(), this->m_file);
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<u8> 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(); ImGui::EndChild();

View File

@@ -1,20 +1,20 @@
#include "views/view_hexeditor.hpp" #include "views/view_hexeditor.hpp"
#include "providers/file_provider.hpp"
namespace hex { namespace hex {
ViewHexEditor::ViewHexEditor(FILE *&file, std::vector<Highlight> &highlights) ViewHexEditor::ViewHexEditor(prv::Provider* &dataProvider, std::vector<Highlight> &highlights)
: View(), m_file(file), m_highlights(highlights) { : View(), m_dataProvider(dataProvider), m_highlights(highlights) {
this->m_memoryEditor.ReadFn = [](const ImU8 *data, size_t off) -> ImU8 { this->m_memoryEditor.ReadFn = [](const ImU8 *data, size_t off) -> ImU8 {
ViewHexEditor *_this = (ViewHexEditor *) data; ViewHexEditor *_this = (ViewHexEditor *) data;
if (_this->m_file == nullptr) if (!_this->m_dataProvider->isAvailable() || !_this->m_dataProvider->isReadable())
return 0x00; return 0x00;
fseek(_this->m_file, off, SEEK_SET);
ImU8 byte; ImU8 byte;
fread(&byte, sizeof(ImU8), 1, _this->m_file); _this->m_dataProvider->read(off, &byte, sizeof(ImU8));
return byte; return byte;
}; };
@@ -22,13 +22,10 @@ namespace hex {
this->m_memoryEditor.WriteFn = [](ImU8 *data, size_t off, ImU8 d) -> void { this->m_memoryEditor.WriteFn = [](ImU8 *data, size_t off, ImU8 d) -> void {
ViewHexEditor *_this = (ViewHexEditor *) data; ViewHexEditor *_this = (ViewHexEditor *) data;
if (_this->m_file == nullptr) if (!_this->m_dataProvider->isAvailable() || !_this->m_dataProvider->isWritable())
return; return;
fseek(_this->m_file, off, SEEK_SET); _this->m_dataProvider->write(off, &d, sizeof(ImU8));
fwrite(&d, sizeof(ImU8), 1, _this->m_file);
}; };
this->m_memoryEditor.HighlightFn = [](const ImU8 *data, size_t off, bool next) -> bool { this->m_memoryEditor.HighlightFn = [](const ImU8 *data, size_t off, bool next) -> bool {
@@ -53,7 +50,7 @@ namespace hex {
ViewHexEditor::~ViewHexEditor() {} ViewHexEditor::~ViewHexEditor() {}
void ViewHexEditor::createView() { 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() { void ViewHexEditor::createMenu() {
@@ -61,14 +58,10 @@ namespace hex {
if (ImGui::MenuItem("Open File...")) { if (ImGui::MenuItem("Open File...")) {
auto filePath = openFileDialog(); auto filePath = openFileDialog();
if (filePath.has_value()) { if (filePath.has_value()) {
if (this->m_file != nullptr) if (this->m_dataProvider != nullptr)
fclose(this->m_file); delete this->m_dataProvider;
this->m_file = fopen(filePath->c_str(), "r+b"); this->m_dataProvider = new prv::FileProvider(filePath.value());
fseek(this->m_file, 0, SEEK_END);
this->m_fileSize = ftell(this->m_file);
rewind(this->m_file);
} }
} }

View File

@@ -4,8 +4,8 @@
namespace hex { namespace hex {
ViewPatternData::ViewPatternData(FILE* &file, std::vector<Highlight> &highlights) ViewPatternData::ViewPatternData(prv::Provider* &dataProvider, std::vector<Highlight> &highlights)
: View(), m_file(file), m_highlights(highlights) { : View(), m_dataProvider(dataProvider), m_highlights(highlights) {
} }
@@ -34,13 +34,15 @@ namespace hex {
for (auto& [offset, size, color, name] : this->m_highlights) { for (auto& [offset, size, color, name] : this->m_highlights) {
std::vector<u8> buffer(size + 1, 0x00); std::vector<u8> 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()); 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 else
ImGui::LabelText(name.c_str(), "[0x%08lx:0x%08lx] [ ARRAY ] \"%s\"", offset, offset + size, makeDisplayable(buffer.data(), buffer.size()).c_str()); ImGui::LabelText(name.c_str(), "[0x%08lx:0x%08lx] [ ARRAY ] \"%s\"", offset, offset + size, makeDisplayable(buffer.data(), buffer.size()).c_str());
} }