1
0
mirror of synced 2024-11-28 09:30:51 +01:00

Added project files

This commit is contained in:
WerWolv 2020-11-30 00:03:12 +01:00
parent 9e8523470d
commit 4878f70e58
12 changed files with 274 additions and 20 deletions

View File

@ -10,6 +10,7 @@ pkg_search_module(CRYPTO REQUIRED libcrypto)
pkg_search_module(CAPSTONE REQUIRED capstone)
find_package(OpenGL REQUIRED)
find_package(LLVM REQUIRED CONFIG)
find_package(nlohmann_json REQUIRED)
llvm_map_components_to_libnames(demangler)
@ -32,6 +33,7 @@ add_executable(ImHex
source/helpers/crypto.cpp
source/helpers/patches.cpp
source/helpers/math_evaluator.cpp
source/helpers/project_file_handler.cpp
source/lang/preprocessor.cpp
source/lang/lexer.cpp
@ -69,9 +71,9 @@ add_executable(ImHex
)
if (WIN32)
target_link_libraries(ImHex libglfw3.a libgcc.a libstdc++.a libmagic.a libgnurx.a libtre.a libintl.a libiconv.a shlwapi.lib libcrypto.a libwinpthread.a libcapstone.a libLLVMDemangle.a)
target_link_libraries(ImHex libglfw3.a libgcc.a libstdc++.a libmagic.a libgnurx.a libtre.a libintl.a libiconv.a shlwapi.lib libcrypto.a libwinpthread.a libcapstone.a libLLVMDemangle.a nlohmann_json::nlohmann_json)
endif (WIN32)
if (UNIX)
target_link_libraries(ImHex libglfw.so libmagic.so libcrypto.so libdl.so libcapstone.so libLLVMDemangle.so)
target_link_libraries(ImHex libglfw.so libmagic.so libcrypto.so libdl.so libcapstone.so libLLVMDemangle.so nlohmann_json::nlohmann_json)
endif (UNIX)

View File

@ -10,11 +10,15 @@ namespace hex {
DataChanged,
PatternChanged,
FileDropped,
WindowClosing,
RegionSelected,
SelectionChangeRequest,
AddBookmark
AddBookmark,
ProjectFileStore,
ProjectFileLoad
};
struct EventHandler {

View File

@ -0,0 +1,46 @@
#pragma once
#include <list>
#include <string>
#include <string_view>
#include "patches.hpp"
#include "utils.hpp"
namespace hex {
class ProjectFile {
public:
ProjectFile() = delete;
static bool load(std::string_view filePath);
static bool store(std::string_view filePath = "");
[[nodiscard]] static bool hasUnsavedChanges() { return ProjectFile::s_hasUnsavedChanged; }
static void markDirty() { if (!ProjectFile::s_currProjectFilePath.empty()) ProjectFile::s_hasUnsavedChanged = true; }
[[nodiscard]] static std::string getProjectFilePath() { return ProjectFile::s_currProjectFilePath; }
[[nodiscard]] static std::string getFilePath() { return ProjectFile::s_filePath; }
static void setFilePath(std::string_view filePath) { ProjectFile::s_hasUnsavedChanged = true; ProjectFile::s_filePath = filePath; }
[[nodiscard]] static std::string getPattern() { return ProjectFile::s_pattern; }
static void setPattern(std::string_view pattern) { ProjectFile::s_hasUnsavedChanged = true; ProjectFile::s_pattern = pattern; }
[[nodiscard]] static const Patches& getPatches() { return ProjectFile::s_patches; }
static void setPatches(const Patches &patches) { ProjectFile::s_hasUnsavedChanged = true; ProjectFile::s_patches = patches; }
[[nodiscard]] static const std::list<Bookmark>& getBookmarks() { return ProjectFile::s_bookmarks; }
static void setBookmarks(const std::list<Bookmark> &bookmarks) { ProjectFile::s_hasUnsavedChanged = true; ProjectFile::s_bookmarks = bookmarks; }
private:
static inline std::string s_currProjectFilePath;
static inline bool s_hasUnsavedChanged = false;
static inline std::string s_filePath;
static inline std::string s_pattern;
static inline Patches s_patches;
static inline std::list<Bookmark> s_bookmarks;
};
}

View File

@ -118,4 +118,11 @@ namespace hex {
u64 address;
size_t size;
};
struct Bookmark {
Region region;
std::vector<char> name;
std::vector<char> comment;
};
}

View File

@ -11,13 +11,6 @@ namespace hex {
namespace prv { class Provider; }
struct Bookmark {
Region region;
std::vector<char> name;
std::vector<char> comment;
};
class ViewBookmarks : public View {
public:
explicit ViewBookmarks(prv::Provider* &dataProvider);

View File

@ -0,0 +1,85 @@
#include "helpers/project_file_handler.hpp"
#include <fstream>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
namespace hex {
void to_json(json& j, const hex::Bookmark& b) {
j = json{ { "address", b.region.address }, { "size", b.region.size }, { "name", b.name.data() }, { "comment", b.comment.data() } };
}
void from_json(const json& j, hex::Bookmark& b) {
std::string name, comment;
j.at("address").get_to(b.region.address);
j.at("size").get_to(b.region.size);
j.at("name").get_to(name);
j.at("comment").get_to(comment);
std::copy(name.begin(), name.end(), std::back_inserter(b.name));
std::copy(comment.begin(), comment.end(), std::back_inserter(b.comment));
}
bool ProjectFile::load(std::string_view filePath) {
ProjectFile::s_hasUnsavedChanged = false;
json projectFileData;
try {
std::ifstream projectFile(filePath.data());
projectFile >> projectFileData;
ProjectFile::s_filePath = projectFileData["filePath"];
ProjectFile::s_pattern = projectFileData["pattern"];
ProjectFile::s_patches = projectFileData["patches"].get<Patches>();
for (auto &element : projectFileData["bookmarks"].items()) {
ProjectFile::s_bookmarks.push_back(element.value().get<Bookmark>());
}
} catch (json::exception &e) {
return false;
} catch (std::ofstream::failure &e) {
return false;
}
ProjectFile::s_currProjectFilePath = filePath;
return true;
}
bool ProjectFile::store(std::string_view filePath) {
ProjectFile::s_hasUnsavedChanged = false;
json projectFileData;
if (filePath.empty())
filePath = ProjectFile::s_currProjectFilePath;
try {
projectFileData["filePath"] = ProjectFile::s_filePath;
projectFileData["pattern"] = ProjectFile::s_pattern;
projectFileData["patches"] = ProjectFile::s_patches;
for (auto &bookmark : ProjectFile::s_bookmarks) {
projectFileData["bookmarks"].push_back(bookmark);
}
std::ofstream projectFile(filePath.data(), std::fstream::trunc);
projectFile << projectFileData;
} catch (json::exception &e) {
return false;
} catch (std::ifstream::failure &e) {
return false;
}
ProjectFile::s_currProjectFilePath = filePath;
return true;
}
}

View File

@ -7,6 +7,7 @@
#include <time.h>
#include "helpers/utils.hpp"
#include "helpers/project_file_handler.hpp"
namespace hex::prv {
@ -22,6 +23,9 @@ namespace hex::prv {
this->m_file = fopen(path.data(), "rb");
this->m_writable = false;
}
if (this->m_file != nullptr)
ProjectFile::setFilePath(path);
}
FileProvider::~FileProvider() {

View File

@ -1,6 +1,7 @@
#include "views/view_bookmarks.hpp"
#include "providers/provider.hpp"
#include "helpers/project_file_handler.hpp"
#include <cstring>
@ -19,11 +20,21 @@ namespace hex {
std::strcpy(bookmark.name.data(), ("Bookmark " + std::to_string(this->m_bookmarks.size() + 1)).c_str());
this->m_bookmarks.push_back(bookmark);
ProjectFile::markDirty();
});
View::subscribeEvent(Events::ProjectFileLoad, [this](const void*) {
this->m_bookmarks = ProjectFile::getBookmarks();
});
View::subscribeEvent(Events::ProjectFileStore, [this](const void*) {
ProjectFile::setBookmarks(this->m_bookmarks);
});
}
ViewBookmarks::~ViewBookmarks() {
View::unsubscribeEvent(Events::AddBookmark);
View::unsubscribeEvent(Events::ProjectFileLoad);
View::unsubscribeEvent(Events::ProjectFileStore);
}
void ViewBookmarks::createView() {
@ -83,8 +94,10 @@ namespace hex {
}
}
if (bookmarkToRemove != this->m_bookmarks.end())
if (bookmarkToRemove != this->m_bookmarks.end()) {
this->m_bookmarks.erase(bookmarkToRemove);
ProjectFile::markDirty();
}
ImGui::EndChild();
}

View File

@ -7,6 +7,7 @@
#include "helpers/crypto.hpp"
#include "helpers/patches.hpp"
#include "helpers/project_file_handler.hpp"
#undef __STRICT_ANSI__
#include <cstdio>
@ -36,6 +37,7 @@ namespace hex {
_this->m_dataProvider->write(off, &d, sizeof(ImU8));
_this->postEvent(Events::DataChanged);
ProjectFile::markDirty();
};
this->m_memoryEditor.HighlightFn = [](const ImU8 *data, size_t off, bool next) -> bool {
@ -76,6 +78,19 @@ namespace hex {
this->m_memoryEditor.DataPreviewAddrEnd = region.address + region.size - 1;
View::postEvent(Events::RegionSelected, &region);
});
View::subscribeEvent(Events::ProjectFileLoad, [this](const void *userData) {
this->openFile(ProjectFile::getFilePath());
});
View::subscribeEvent(Events::WindowClosing, [this](const void *userData) {
auto window = const_cast<GLFWwindow*>(static_cast<const GLFWwindow*>(userData));
if (ProjectFile::hasUnsavedChanges()) {
glfwSetWindowShouldClose(window, GLFW_FALSE);
View::doLater([] { ImGui::OpenPopup("Save Changes"); });
}
});
}
ViewHexEditor::~ViewHexEditor() {
@ -118,6 +133,24 @@ namespace hex {
}
if (ImGui::BeginPopupModal("Save Changes", nullptr, ImGuiWindowFlags_NoResize)) {
constexpr auto Message = "You have unsaved changes made to your Project. Are you sure you want to exit?";
ImGui::NewLine();
if (ImGui::BeginChild("##scrolling", ImVec2(300, 50))) {
ImGui::SetCursorPosX(10);
ImGui::TextWrapped("%s", Message);
ImGui::EndChild();
}
ImGui::SetCursorPosX(40);
if (ImGui::Button("Yes", ImVec2(100, 20)))
std::exit(0);
ImGui::SameLine();
ImGui::SetCursorPosX(160);
if (ImGui::Button("No", ImVec2(100, 20)))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
if (this->m_fileBrowser.showFileDialog("Open File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN)) {
this->openFile(this->m_fileBrowser.selected_path);
@ -138,6 +171,17 @@ namespace hex {
}
if (this->m_fileBrowser.showFileDialog("Open Project", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ImVec2(0, 0), ".hexproj")) {
ProjectFile::load(this->m_fileBrowser.selected_path);
View::postEvent(Events::ProjectFileLoad);
}
if (this->m_fileBrowser.showFileDialog("Save Project", imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, ImVec2(0, 0), ".hexproj")) {
ProjectFile::store(this->m_fileBrowser.selected_path);
}
if (this->m_fileBrowser.showFileDialog("Export File", imgui_addons::ImGuiFileBrowser::DialogMode::SAVE)) {
this->saveToFile(this->m_fileBrowser.selected_path, this->m_dataToSave);
}
@ -199,6 +243,24 @@ namespace hex {
View::doLater([]{ ImGui::OpenPopup("Save As"); });
}
ImGui::Separator();
if (ImGui::MenuItem("Open Project", "")) {
this->getWindowOpenState() = true;
View::doLater([]{ ImGui::OpenPopup("Open Project"); });
}
if (ImGui::MenuItem("Save Project", "", false, this->m_dataProvider != nullptr && this->m_dataProvider->isWritable())) {
View::postEvent(Events::ProjectFileStore);
if (ProjectFile::getProjectFilePath() == "")
View::doLater([] { ImGui::OpenPopup("Save Project"); });
else
ProjectFile::store();
}
ImGui::Separator();
if (ImGui::BeginMenu("Import...")) {
if (ImGui::MenuItem("Base64 File")) {
this->getWindowOpenState() = true;
@ -315,7 +377,7 @@ namespace hex {
for (const auto &[address, value] : this->m_dataProvider->getPatches())
this->m_dataProvider->writeRaw(address, &value, sizeof(u8));
return true;
} else if (mods == GLFW_MOD_CONTROL | GLFW_MOD_SHIFT && key == GLFW_KEY_S) {
} else if (mods == (GLFW_MOD_CONTROL | GLFW_MOD_SHIFT) && key == GLFW_KEY_S) {
ImGui::OpenPopup("Save As");
return true;
} else if (mods == GLFW_MOD_CONTROL && key == GLFW_KEY_F) {
@ -345,8 +407,13 @@ namespace hex {
this->m_dataProvider = new prv::FileProvider(path);
this->m_memoryEditor.ReadOnly = !this->m_dataProvider->isWritable();
if (this->m_dataProvider->isAvailable())
ProjectFile::setFilePath(path);
View::postEvent(Events::FileLoaded);
View::postEvent(Events::DataChanged);
ProjectFile::markDirty();
}
bool ViewHexEditor::saveToFile(std::string path, const std::vector<u8>& data) {

View File

@ -3,6 +3,7 @@
#include "providers/provider.hpp"
#include "helpers/utils.hpp"
#include "helpers/project_file_handler.hpp"
#include <string>
@ -11,11 +12,20 @@ using namespace std::literals::string_literals;
namespace hex {
ViewPatches::ViewPatches(prv::Provider* &dataProvider) : View("Patches"), m_dataProvider(dataProvider) {
View::subscribeEvent(Events::ProjectFileStore, [this](const void*) {
if (this->m_dataProvider != nullptr)
ProjectFile::setPatches(this->m_dataProvider->getPatches());
});
View::subscribeEvent(Events::ProjectFileLoad, [this](const void*) {
if (this->m_dataProvider != nullptr)
this->m_dataProvider->getPatches() = ProjectFile::getPatches();
});
}
ViewPatches::~ViewPatches() {
View::unsubscribeEvent(Events::ProjectFileStore);
View::unsubscribeEvent(Events::ProjectFileLoad);
}
void ViewPatches::createView() {
@ -62,6 +72,7 @@ namespace hex {
if (ImGui::BeginPopup("PatchContextMenu")) {
if (ImGui::MenuItem("Remove")) {
patches.erase(this->m_selectedPatch);
ProjectFile::markDirty();
}
ImGui::EndPopup();
}

View File

@ -5,6 +5,8 @@
#include "lang/lexer.hpp"
#include "lang/validator.hpp"
#include "lang/evaluator.hpp"
#include "helpers/project_file_handler.hpp"
#include "helpers/utils.hpp"
#include <magic.h>
@ -76,9 +78,20 @@ namespace hex {
this->m_textEditor.SetLanguageDefinition(PatternLanguage());
this->m_textEditor.SetShowWhitespaces(false);
View::subscribeEvent(Events::FileLoaded, [this](const void* userData) {
lang::Preprocessor preprocessor;
View::subscribeEvent(Events::ProjectFileStore, [this](const void*) {
ProjectFile::setPattern(this->m_textEditor.GetText());
});
View::subscribeEvent(Events::ProjectFileLoad, [this](const void*) {
this->m_textEditor.SetText(ProjectFile::getPattern());
this->parsePattern(this->m_textEditor.GetText().data());
});
View::subscribeEvent(Events::FileLoaded, [this](const void* userData) {
if (!this->m_textEditor.GetText().empty())
return;
lang::Preprocessor preprocessor;
std::string magicFiles;
std::error_code error;
@ -140,7 +153,8 @@ namespace hex {
}
ViewPattern::~ViewPattern() {
View::unsubscribeEvent(Events::ProjectFileStore);
View::unsubscribeEvent(Events::ProjectFileLoad);
}
void ViewPattern::createMenu() {

View File

@ -107,15 +107,17 @@ namespace hex {
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking;
ImGuiViewport* viewport = ImGui::GetMainViewport();
ImGui::SetNextWindowPos(viewport->GetWorkPos());
ImGui::SetNextWindowSize(viewport->GetWorkSize());
ImGui::SetNextWindowViewport(viewport->ID);
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
windowFlags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
windowFlags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoDocking
| ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse
| ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize
| ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoBringToFrontOnFocus;
if (ImGui::Begin("DockSpace", nullptr, windowFlags)) {
ImGui::PopStyleVar(2);
@ -208,6 +210,7 @@ namespace hex {
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
this->m_window = glfwCreateWindow(1280, 720, "ImHex", nullptr, nullptr);
@ -229,7 +232,12 @@ namespace hex {
View::postEvent(Events::FileDropped, paths[0]);
});
glfwSetWindowSizeLimits(this->m_window, 720, 480, GLFW_DONT_CARE, GLFW_DONT_CARE);
glfwSetWindowCloseCallback(this->m_window, [](GLFWwindow *window) {
View::postEvent(Events::WindowClosing, window);
});
glfwSetWindowSizeLimits(this->m_window, 720, 480, GLFW_DONT_CARE, GLFW_DONT_CARE);
if (gladLoadGL() == 0)
throw std::runtime_error("Failed to initialize OpenGL loader!");