Refactor, added a pattern data display
This commit is contained in:
parent
01b4ac8661
commit
35946564a6
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -13,10 +13,15 @@ SET(CMAKE_C_FLAGS ${CMAKE_C_FLAGS} -mwindows)
|
||||
add_executable(ImHex WIN32
|
||||
source/main.cpp
|
||||
source/window.cpp
|
||||
source/utils.cpp
|
||||
|
||||
source/parser/lexer.cpp
|
||||
source/parser/parser.cpp
|
||||
|
||||
source/views/view_hexeditor.cpp
|
||||
source/views/view_pattern.cpp
|
||||
source/views/view_pattern_data.cpp
|
||||
|
||||
libs/glad/source/glad.c
|
||||
|
||||
libs/ImGui/source/imgui.cpp
|
||||
|
@ -10,42 +10,6 @@
|
||||
|
||||
namespace hex {
|
||||
|
||||
std::optional<std::string> openFileDialog() {
|
||||
HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
||||
if (SUCCEEDED(hr)) {
|
||||
IFileOpenDialog *pFileOpen;
|
||||
|
||||
hr = CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_ALL, IID_IFileOpenDialog, reinterpret_cast<void**>(&pFileOpen));
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = pFileOpen->Show(nullptr);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
IShellItem *pItem;
|
||||
hr = pFileOpen->GetResult(&pItem);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
PWSTR pszFilePath;
|
||||
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
|
||||
|
||||
std::string result = converter.to_bytes(pszFilePath);
|
||||
|
||||
CoTaskMemFree(pszFilePath);
|
||||
|
||||
return result;
|
||||
}
|
||||
pItem->Release();
|
||||
}
|
||||
}
|
||||
pFileOpen->Release();
|
||||
}
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
return { };
|
||||
}
|
||||
std::optional<std::string> openFileDialog();
|
||||
|
||||
}
|
20
include/views/highlight.hpp
Normal file
20
include/views/highlight.hpp
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <string>
|
||||
|
||||
namespace hex {
|
||||
|
||||
struct Highlight {
|
||||
Highlight(u64 offset, size_t size, u32 color, std::string name)
|
||||
: offset(offset), size(size), color(color), name(name) {
|
||||
|
||||
}
|
||||
|
||||
u64 offset;
|
||||
size_t size;
|
||||
u32 color;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
}
|
@ -12,106 +12,25 @@
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
#include "views/highlight.hpp"
|
||||
|
||||
namespace hex {
|
||||
|
||||
class ViewHexEditor : public View {
|
||||
public:
|
||||
ViewHexEditor() : View() {
|
||||
this->m_memoryEditor.ReadFn = [](const ImU8* data, size_t off) -> ImU8 {
|
||||
ViewHexEditor *_this = (ViewHexEditor*)data;
|
||||
ViewHexEditor(FILE* &file, std::vector<Highlight> &highlights);
|
||||
virtual ~ViewHexEditor();
|
||||
|
||||
if (_this->m_file == nullptr)
|
||||
return 0x00;
|
||||
|
||||
fseek(_this->m_file, off, SEEK_SET);
|
||||
|
||||
ImU8 byte;
|
||||
fread(&byte, sizeof(ImU8), 1, _this->m_file);
|
||||
|
||||
return byte;
|
||||
};
|
||||
|
||||
this->m_memoryEditor.WriteFn = [](ImU8* data, size_t off, ImU8 d) -> void {
|
||||
ViewHexEditor *_this = (ViewHexEditor*)data;
|
||||
|
||||
if (_this->m_file == nullptr)
|
||||
return;
|
||||
|
||||
fseek(_this->m_file, off, SEEK_SET);
|
||||
|
||||
fwrite(&d, sizeof(ImU8), 1, _this->m_file);
|
||||
|
||||
};
|
||||
|
||||
this->m_memoryEditor.HighlightFn = [](const ImU8* data, size_t off, bool next) -> bool {
|
||||
ViewHexEditor *_this = (ViewHexEditor*)data;
|
||||
|
||||
for (auto& [offset, size, color] : _this->m_highlights) {
|
||||
if (next && off == (offset + size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (off >= offset && off < (offset + size)) {
|
||||
_this->m_memoryEditor.HighlightColor = color;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
_this->m_memoryEditor.HighlightColor = 0x50C08080;
|
||||
return false;
|
||||
};
|
||||
}
|
||||
virtual ~ViewHexEditor() { }
|
||||
|
||||
virtual void createView() override {
|
||||
this->m_memoryEditor.DrawWindow("Hex Editor", this, this->m_file == nullptr ? 0x00 : this->m_fileSize);
|
||||
}
|
||||
|
||||
virtual void createMenu() override {
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
if (ImGui::MenuItem("Open File...")) {
|
||||
auto filePath = openFileDialog();
|
||||
if (filePath.has_value()) {
|
||||
if (this->m_file != nullptr)
|
||||
fclose(this->m_file);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Window")) {
|
||||
ImGui::MenuItem("Hex View", "", &this->m_memoryEditor.Open);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void setHighlight(u64 offset, size_t size, u32 color = 0) {
|
||||
if (color == 0)
|
||||
color = std::mt19937(std::random_device()())();
|
||||
|
||||
color |= 0xFF00'0000;
|
||||
|
||||
this->m_highlights.emplace_back(offset, size, color);
|
||||
}
|
||||
|
||||
void clearHighlights() {
|
||||
this->m_highlights.clear();
|
||||
}
|
||||
virtual void createView() override;
|
||||
virtual void createMenu() override;
|
||||
|
||||
private:
|
||||
MemoryEditor m_memoryEditor;
|
||||
|
||||
FILE *m_file = nullptr;
|
||||
FILE* &m_file;
|
||||
size_t m_fileSize = 0;
|
||||
|
||||
std::vector<std::tuple<u64, size_t, u32>> m_highlights;
|
||||
std::vector<Highlight> &m_highlights;
|
||||
};
|
||||
|
||||
}
|
@ -8,207 +8,30 @@
|
||||
#include <concepts>
|
||||
#include <cstring>
|
||||
|
||||
#include "views/view_hexeditor.hpp"
|
||||
#include "views/highlight.hpp"
|
||||
|
||||
namespace hex {
|
||||
|
||||
class ViewPattern : public View {
|
||||
public:
|
||||
ViewPattern(ViewHexEditor *hexEditor) : View(), m_hexEditor(hexEditor) {
|
||||
this->m_buffer = new char[0xFFFFFF];
|
||||
std::memset(this->m_buffer, 0x00, 0xFFFFFF);
|
||||
}
|
||||
virtual ~ViewPattern() {
|
||||
delete[] this->m_buffer;
|
||||
}
|
||||
ViewPattern(std::vector<Highlight> &highlights);
|
||||
virtual ~ViewPattern();
|
||||
|
||||
virtual void createMenu() {
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
if (ImGui::MenuItem("Load pattern...")) {
|
||||
auto filePath = openFileDialog();
|
||||
if (filePath.has_value()) {
|
||||
FILE *file = fopen(filePath->c_str(), "r+b");
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t size = ftell(file);
|
||||
rewind(file);
|
||||
|
||||
if (size > 0xFF'FFFF)
|
||||
return;
|
||||
|
||||
fread(this->m_buffer, size, 1, file);
|
||||
|
||||
fclose(file);
|
||||
|
||||
this->parsePattern(this->m_buffer);
|
||||
}
|
||||
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Window")) {
|
||||
ImGui::MenuItem("Pattern View", "", &this->m_windowOpen);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void createView() override {
|
||||
if (!this->m_windowOpen)
|
||||
return;
|
||||
|
||||
ImGui::Begin("Pattern", &this->m_windowOpen, ImGuiWindowFlags_None);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
|
||||
|
||||
auto size = ImGui::GetWindowSize();
|
||||
size.y -= 50;
|
||||
ImGui::InputTextMultiline("Pattern", this->m_buffer, 0xFFFF, size, ImGuiInputTextFlags_AllowTabInput | ImGuiInputTextFlags_CallbackEdit,
|
||||
[](ImGuiInputTextCallbackData* data) -> int {
|
||||
auto _this = static_cast<ViewPattern*>(data->UserData);
|
||||
|
||||
_this->parsePattern(data->Buf);
|
||||
|
||||
return 0;
|
||||
}, this
|
||||
);
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::End();
|
||||
}
|
||||
virtual void createMenu() override;
|
||||
virtual void createView() override;
|
||||
|
||||
private:
|
||||
char *m_buffer;
|
||||
|
||||
ViewHexEditor *m_hexEditor;
|
||||
std::vector<Highlight> &m_highlights;
|
||||
bool m_windowOpen = true;
|
||||
|
||||
void parsePattern(char *buffer) {
|
||||
static hex::lang::Lexer lexer;
|
||||
static hex::lang::Parser parser;
|
||||
|
||||
this->m_hexEditor->clearHighlights();
|
||||
void setHighlight(u64 offset, size_t size, std::string name, u32 color = 0);
|
||||
void parsePattern(char *buffer);
|
||||
|
||||
auto [lexResult, tokens] = lexer.lex(buffer);
|
||||
|
||||
if (lexResult.failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto [parseResult, ast] = parser.parse(tokens);
|
||||
if (parseResult.failed()) {
|
||||
for(auto &node : ast) delete node;
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto &varNode : this->findNodes<lang::ASTNodeVariableDecl>(lang::ASTNode::Type::VariableDecl, ast)) {
|
||||
if (!varNode->getOffset().has_value())
|
||||
continue;
|
||||
|
||||
u64 offset = varNode->getOffset().value();
|
||||
if (varNode->getVariableType() != lang::Token::TypeToken::Type::CustomType) {
|
||||
this->m_hexEditor->setHighlight(offset, static_cast<u32>(varNode->getVariableType()) >> 4);
|
||||
} else {
|
||||
for (auto &structNode : this->findNodes<lang::ASTNodeStruct>(lang::ASTNode::Type::Struct, ast))
|
||||
if (varNode->getCustomVariableTypeName() == structNode->getName())
|
||||
if (this->highlightStruct(ast, structNode, offset) == -1)
|
||||
this->m_hexEditor->clearHighlights();
|
||||
|
||||
for (auto &usingNode : this->findNodes<lang::ASTNodeTypeDecl>(lang::ASTNode::Type::TypeDecl, ast))
|
||||
if (varNode->getCustomVariableTypeName() == usingNode->getTypeName())
|
||||
if (this->highlightUsingDecls(ast, usingNode, offset) == -1)
|
||||
this->m_hexEditor->clearHighlights();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for(auto &node : ast) delete node;
|
||||
}
|
||||
|
||||
template<std::derived_from<lang::ASTNode> T>
|
||||
std::vector<T*> findNodes(const lang::ASTNode::Type type, const std::vector<lang::ASTNode*> &nodes) const noexcept {
|
||||
std::vector<T*> result;
|
||||
|
||||
for (const auto & node : nodes)
|
||||
if (node->getType() == type)
|
||||
result.push_back(static_cast<T*>(node));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
s32 highlightUsingDecls(std::vector<lang::ASTNode*> &ast, lang::ASTNodeTypeDecl* currTypeDeclNode, u64 offset) {
|
||||
if (currTypeDeclNode->getAssignedType() != lang::Token::TypeToken::Type::CustomType) {
|
||||
size_t size = static_cast<u32>(currTypeDeclNode->getAssignedType()) >> 4;
|
||||
|
||||
this->m_hexEditor->setHighlight(offset, size);
|
||||
offset += size;
|
||||
} else {
|
||||
bool foundType = false;
|
||||
for (auto &structNode : findNodes<lang::ASTNodeStruct>(lang::ASTNode::Type::Struct, ast))
|
||||
if (structNode->getName() == currTypeDeclNode->getAssignedCustomTypeName()) {
|
||||
offset = this->highlightStruct(ast, structNode, offset);
|
||||
foundType = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto &typeDeclNode : findNodes<lang::ASTNodeTypeDecl>(lang::ASTNode::Type::TypeDecl, ast))
|
||||
if (typeDeclNode->getTypeName() == currTypeDeclNode->getAssignedCustomTypeName()) {
|
||||
offset = this->highlightUsingDecls(ast, typeDeclNode, offset);
|
||||
foundType = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!foundType)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
s32 highlightStruct(std::vector<lang::ASTNode*> &ast, lang::ASTNodeStruct* currStructNode, u64 offset) {
|
||||
u64 startOffset = offset;
|
||||
|
||||
for (auto &node : currStructNode->getNodes()) {
|
||||
auto var = static_cast<lang::ASTNodeVariableDecl*>(node);
|
||||
|
||||
if (var->getVariableType() != lang::Token::TypeToken::Type::CustomType) {
|
||||
size_t size = static_cast<u32>(var->getVariableType()) >> 4;
|
||||
|
||||
this->m_hexEditor->setHighlight(offset, size);
|
||||
offset += size;
|
||||
} else {
|
||||
bool foundType = false;
|
||||
for (auto &structNode : findNodes<lang::ASTNodeStruct>(lang::ASTNode::Type::Struct, ast))
|
||||
if (structNode->getName() == var->getCustomVariableTypeName()) {
|
||||
auto size = this->highlightStruct(ast, structNode, offset);
|
||||
|
||||
if (size == -1)
|
||||
return -1;
|
||||
|
||||
offset += size;
|
||||
foundType = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto &typeDeclNode : findNodes<lang::ASTNodeTypeDecl>(lang::ASTNode::Type::TypeDecl, ast))
|
||||
if (typeDeclNode->getTypeName() == var->getCustomVariableTypeName()) {
|
||||
auto size = this->highlightUsingDecls(ast, typeDeclNode, offset);
|
||||
|
||||
if (size == -1)
|
||||
return -1;
|
||||
|
||||
offset = size;
|
||||
foundType = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!foundType)
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return offset - startOffset;
|
||||
}
|
||||
s32 highlightUsingDecls(std::vector<lang::ASTNode*> &ast, lang::ASTNodeTypeDecl* currTypeDeclNode, lang::ASTNodeVariableDecl* currVarDec, u64 offset);
|
||||
s32 highlightStruct(std::vector<lang::ASTNode*> &ast, lang::ASTNodeStruct* currStructNode, u64 offset);
|
||||
};
|
||||
|
||||
}
|
29
include/views/view_pattern_data.hpp
Normal file
29
include/views/view_pattern_data.hpp
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include "imgui.h"
|
||||
#include "views/view.hpp"
|
||||
#include "views/highlight.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <cstdio>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class ViewPatternData : public View {
|
||||
public:
|
||||
ViewPatternData(FILE* &file,std::vector<Highlight> &highlights);
|
||||
virtual ~ViewPatternData();
|
||||
|
||||
virtual void createView() override;
|
||||
virtual void createMenu() override;
|
||||
|
||||
private:
|
||||
FILE* &m_file;
|
||||
std::vector<Highlight> &m_highlights;
|
||||
bool m_windowOpen = true;
|
||||
};
|
||||
|
||||
}
|
@ -18,8 +18,8 @@ namespace hex {
|
||||
void loop();
|
||||
|
||||
template<std::derived_from<View> T, typename ... Args>
|
||||
T* addView(Args& ... args) {
|
||||
this->m_views.emplace_back(new T(args...));
|
||||
T* addView(Args&& ... args) {
|
||||
this->m_views.emplace_back(new T(std::forward<Args>(args)...));
|
||||
|
||||
return static_cast<T*>(this->m_views.back());
|
||||
}
|
||||
|
@ -1,13 +1,24 @@
|
||||
#include "window.hpp"
|
||||
|
||||
#include "views/highlight.hpp"
|
||||
#include "views/view_hexeditor.hpp"
|
||||
#include "views/view_pattern.hpp"
|
||||
#include "views/view_pattern_data.hpp"
|
||||
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
int main() {
|
||||
hex::Window window;
|
||||
|
||||
auto* hexEditor = window.addView<hex::ViewHexEditor>();
|
||||
window.addView<hex::ViewPattern>(hexEditor);
|
||||
// Shared Data
|
||||
std::vector<hex::Highlight> highlights;
|
||||
FILE *file = nullptr;
|
||||
|
||||
// Create views
|
||||
window.addView<hex::ViewHexEditor>(file, highlights);
|
||||
window.addView<hex::ViewPattern>(highlights);
|
||||
window.addView<hex::ViewPatternData>(file, highlights);
|
||||
|
||||
window.loop();
|
||||
|
||||
|
43
source/utils.cpp
Normal file
43
source/utils.cpp
Normal file
@ -0,0 +1,43 @@
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace hex {
|
||||
|
||||
std::optional<std::string> openFileDialog() {
|
||||
HRESULT hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
||||
if (SUCCEEDED(hr)) {
|
||||
IFileOpenDialog *pFileOpen;
|
||||
|
||||
hr = CoCreateInstance(CLSID_FileOpenDialog, nullptr, CLSCTX_ALL, IID_IFileOpenDialog, reinterpret_cast<void**>(&pFileOpen));
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = pFileOpen->Show(nullptr);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
IShellItem *pItem;
|
||||
hr = pFileOpen->GetResult(&pItem);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
PWSTR pszFilePath;
|
||||
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
std::wstring_convert<std::codecvt_utf8<wchar_t>, wchar_t> converter;
|
||||
|
||||
std::string result = converter.to_bytes(pszFilePath);
|
||||
|
||||
CoTaskMemFree(pszFilePath);
|
||||
|
||||
return result;
|
||||
}
|
||||
pItem->Release();
|
||||
}
|
||||
}
|
||||
pFileOpen->Release();
|
||||
}
|
||||
CoUninitialize();
|
||||
}
|
||||
|
||||
return { };
|
||||
}
|
||||
|
||||
}
|
85
source/views/view_hexeditor.cpp
Normal file
85
source/views/view_hexeditor.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include "views/view_hexeditor.hpp"
|
||||
|
||||
namespace hex {
|
||||
|
||||
ViewHexEditor::ViewHexEditor(FILE *&file, std::vector<Highlight> &highlights)
|
||||
: View(), m_file(file), m_highlights(highlights) {
|
||||
|
||||
this->m_memoryEditor.ReadFn = [](const ImU8 *data, size_t off) -> ImU8 {
|
||||
ViewHexEditor *_this = (ViewHexEditor *) data;
|
||||
|
||||
if (_this->m_file == nullptr)
|
||||
return 0x00;
|
||||
|
||||
fseek(_this->m_file, off, SEEK_SET);
|
||||
|
||||
ImU8 byte;
|
||||
fread(&byte, sizeof(ImU8), 1, _this->m_file);
|
||||
|
||||
return byte;
|
||||
};
|
||||
|
||||
this->m_memoryEditor.WriteFn = [](ImU8 *data, size_t off, ImU8 d) -> void {
|
||||
ViewHexEditor *_this = (ViewHexEditor *) data;
|
||||
|
||||
if (_this->m_file == nullptr)
|
||||
return;
|
||||
|
||||
fseek(_this->m_file, off, SEEK_SET);
|
||||
|
||||
fwrite(&d, sizeof(ImU8), 1, _this->m_file);
|
||||
|
||||
};
|
||||
|
||||
this->m_memoryEditor.HighlightFn = [](const ImU8 *data, size_t off, bool next) -> bool {
|
||||
ViewHexEditor *_this = (ViewHexEditor *) data;
|
||||
|
||||
for (auto&[offset, size, color, name] : _this->m_highlights) {
|
||||
if (next && off == (offset + size)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (off >= offset && off < (offset + size)) {
|
||||
_this->m_memoryEditor.HighlightColor = color;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
_this->m_memoryEditor.HighlightColor = 0x50C08080;
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
ViewHexEditor::~ViewHexEditor() {}
|
||||
|
||||
void ViewHexEditor::createView() {
|
||||
this->m_memoryEditor.DrawWindow("Hex Editor", this, this->m_file == nullptr ? 0x00 : this->m_fileSize);
|
||||
}
|
||||
|
||||
void ViewHexEditor::createMenu() {
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
if (ImGui::MenuItem("Open File...")) {
|
||||
auto filePath = openFileDialog();
|
||||
if (filePath.has_value()) {
|
||||
if (this->m_file != nullptr)
|
||||
fclose(this->m_file);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Window")) {
|
||||
ImGui::MenuItem("Hex View", "", &this->m_memoryEditor.Open);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
210
source/views/view_pattern.cpp
Normal file
210
source/views/view_pattern.cpp
Normal file
@ -0,0 +1,210 @@
|
||||
#include <random>
|
||||
#include "views/view_pattern.hpp"
|
||||
|
||||
#include "utils.hpp"
|
||||
|
||||
namespace hex {
|
||||
|
||||
ViewPattern::ViewPattern(std::vector<Highlight> &highlights) : View(), m_highlights(highlights) {
|
||||
this->m_buffer = new char[0xFFFFFF];
|
||||
std::memset(this->m_buffer, 0x00, 0xFFFFFF);
|
||||
}
|
||||
ViewPattern::~ViewPattern() {
|
||||
delete[] this->m_buffer;
|
||||
}
|
||||
|
||||
void ViewPattern::createMenu() {
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
if (ImGui::MenuItem("Load pattern...")) {
|
||||
auto filePath = openFileDialog();
|
||||
if (filePath.has_value()) {
|
||||
FILE *file = fopen(filePath->c_str(), "r+b");
|
||||
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t size = ftell(file);
|
||||
rewind(file);
|
||||
|
||||
if (size > 0xFF'FFFF)
|
||||
return;
|
||||
|
||||
fread(this->m_buffer, size, 1, file);
|
||||
|
||||
fclose(file);
|
||||
|
||||
this->parsePattern(this->m_buffer);
|
||||
}
|
||||
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Window")) {
|
||||
ImGui::MenuItem("Pattern View", "", &this->m_windowOpen);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
void ViewPattern::createView() {
|
||||
if (!this->m_windowOpen)
|
||||
return;
|
||||
|
||||
ImGui::Begin("Pattern", &this->m_windowOpen, ImGuiWindowFlags_None);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
|
||||
|
||||
auto size = ImGui::GetWindowSize();
|
||||
size.y -= 50;
|
||||
ImGui::InputTextMultiline("Pattern", this->m_buffer, 0xFFFF, size, ImGuiInputTextFlags_AllowTabInput | ImGuiInputTextFlags_CallbackEdit,
|
||||
[](ImGuiInputTextCallbackData* data) -> int {
|
||||
auto _this = static_cast<ViewPattern*>(data->UserData);
|
||||
|
||||
_this->parsePattern(data->Buf);
|
||||
|
||||
return 0;
|
||||
}, this
|
||||
);
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
|
||||
void ViewPattern::setHighlight(u64 offset, size_t size, std::string name, u32 color) {
|
||||
if (color == 0)
|
||||
color = std::mt19937(std::random_device()())();
|
||||
|
||||
color &= ~0xFF00'0000;
|
||||
color |= 0x5000'0000;
|
||||
|
||||
this->m_highlights.emplace_back(offset, size, color, name);
|
||||
}
|
||||
|
||||
template<std::derived_from<lang::ASTNode> T>
|
||||
static std::vector<T*> findNodes(const lang::ASTNode::Type type, const std::vector<lang::ASTNode*> &nodes) {
|
||||
std::vector<T*> result;
|
||||
|
||||
for (const auto & node : nodes)
|
||||
if (node->getType() == type)
|
||||
result.push_back(static_cast<T*>(node));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void ViewPattern::parsePattern(char *buffer) {
|
||||
static hex::lang::Lexer lexer;
|
||||
static hex::lang::Parser parser;
|
||||
|
||||
this->m_highlights.clear();
|
||||
|
||||
auto [lexResult, tokens] = lexer.lex(buffer);
|
||||
|
||||
if (lexResult.failed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto [parseResult, ast] = parser.parse(tokens);
|
||||
if (parseResult.failed()) {
|
||||
for(auto &node : ast) delete node;
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto &varNode : findNodes<lang::ASTNodeVariableDecl>(lang::ASTNode::Type::VariableDecl, ast)) {
|
||||
if (!varNode->getOffset().has_value())
|
||||
continue;
|
||||
|
||||
u64 offset = varNode->getOffset().value();
|
||||
if (varNode->getVariableType() != lang::Token::TypeToken::Type::CustomType) {
|
||||
this->setHighlight(offset, static_cast<u32>(varNode->getVariableType()) >> 4, varNode->getVariableName());
|
||||
} else {
|
||||
for (auto &structNode : findNodes<lang::ASTNodeStruct>(lang::ASTNode::Type::Struct, ast))
|
||||
if (varNode->getCustomVariableTypeName() == structNode->getName())
|
||||
if (this->highlightStruct(ast, structNode, offset) == -1)
|
||||
this->m_highlights.clear();
|
||||
|
||||
for (auto &usingNode : findNodes<lang::ASTNodeTypeDecl>(lang::ASTNode::Type::TypeDecl, ast))
|
||||
if (varNode->getCustomVariableTypeName() == usingNode->getTypeName())
|
||||
if (this->highlightUsingDecls(ast, usingNode, varNode, offset) == -1)
|
||||
this->m_highlights.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for(auto &node : ast) delete node;
|
||||
}
|
||||
|
||||
s32 ViewPattern::highlightUsingDecls(std::vector<lang::ASTNode*> &ast, lang::ASTNodeTypeDecl* currTypeDeclNode, lang::ASTNodeVariableDecl* currVarDecl, u64 offset) {
|
||||
if (currTypeDeclNode->getAssignedType() != lang::Token::TypeToken::Type::CustomType) {
|
||||
size_t size = static_cast<u32>(currTypeDeclNode->getAssignedType()) >> 4;
|
||||
|
||||
this->setHighlight(offset, size, currVarDecl->getVariableName());
|
||||
offset += size;
|
||||
} else {
|
||||
bool foundType = false;
|
||||
for (auto &structNode : findNodes<lang::ASTNodeStruct>(lang::ASTNode::Type::Struct, ast))
|
||||
if (structNode->getName() == currTypeDeclNode->getAssignedCustomTypeName()) {
|
||||
offset = this->highlightStruct(ast, structNode, offset);
|
||||
foundType = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto &typeDeclNode : findNodes<lang::ASTNodeTypeDecl>(lang::ASTNode::Type::TypeDecl, ast))
|
||||
if (typeDeclNode->getTypeName() == currTypeDeclNode->getAssignedCustomTypeName()) {
|
||||
offset = this->highlightUsingDecls(ast, typeDeclNode, currVarDecl, offset);
|
||||
foundType = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!foundType)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
s32 ViewPattern::highlightStruct(std::vector<lang::ASTNode*> &ast, lang::ASTNodeStruct* currStructNode, u64 offset) {
|
||||
u64 startOffset = offset;
|
||||
|
||||
for (auto &node : currStructNode->getNodes()) {
|
||||
auto var = static_cast<lang::ASTNodeVariableDecl*>(node);
|
||||
|
||||
if (var->getVariableType() != lang::Token::TypeToken::Type::CustomType) {
|
||||
size_t size = static_cast<u32>(var->getVariableType()) >> 4;
|
||||
|
||||
this->setHighlight(offset, size, var->getVariableName());
|
||||
offset += size;
|
||||
} else {
|
||||
bool foundType = false;
|
||||
for (auto &structNode : findNodes<lang::ASTNodeStruct>(lang::ASTNode::Type::Struct, ast))
|
||||
if (structNode->getName() == var->getCustomVariableTypeName()) {
|
||||
auto size = this->highlightStruct(ast, structNode, offset);
|
||||
|
||||
if (size == -1)
|
||||
return -1;
|
||||
|
||||
offset += size;
|
||||
foundType = true;
|
||||
break;
|
||||
}
|
||||
|
||||
for (auto &typeDeclNode : findNodes<lang::ASTNodeTypeDecl>(lang::ASTNode::Type::TypeDecl, ast))
|
||||
if (typeDeclNode->getTypeName() == var->getCustomVariableTypeName()) {
|
||||
auto size = this->highlightUsingDecls(ast, typeDeclNode, var, offset);
|
||||
|
||||
if (size == -1)
|
||||
return -1;
|
||||
|
||||
offset = size;
|
||||
foundType = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!foundType)
|
||||
return -1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return offset - startOffset;
|
||||
}
|
||||
|
||||
}
|
49
source/views/view_pattern_data.cpp
Normal file
49
source/views/view_pattern_data.cpp
Normal file
@ -0,0 +1,49 @@
|
||||
#include "views/view_pattern_data.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace hex {
|
||||
|
||||
ViewPatternData::ViewPatternData(FILE* &file, std::vector<Highlight> &highlights)
|
||||
: View(), m_file(file), m_highlights(highlights) {
|
||||
|
||||
}
|
||||
|
||||
ViewPatternData::~ViewPatternData() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
void ViewPatternData::createView() {
|
||||
if (!this->m_windowOpen)
|
||||
return;
|
||||
|
||||
if (ImGui::Begin("Pattern Data", &this->m_windowOpen)) {
|
||||
ImGui::BeginChild("##scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav);
|
||||
|
||||
for (auto& [offset, size, color, name] : this->m_highlights) {
|
||||
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)
|
||||
ImGui::LabelText(name.c_str(), "[0x%08lx:0x%08lx] %lu (0x%lx) \"%s\"", offset, offset + size, data, data, buffer.data());
|
||||
else
|
||||
ImGui::LabelText(name.c_str(), "[0x%08lx:0x%08lx] [ ARRAY ]", offset, offset + size);
|
||||
}
|
||||
|
||||
ImGui::EndChild();
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
void ViewPatternData::createMenu() {
|
||||
if (ImGui::BeginMenu("Window")) {
|
||||
ImGui::MenuItem("Data View", "", &this->m_windowOpen);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user