From 6a8611d98de6eab1a357c7a3e46133c3613b97c4 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Fri, 21 Oct 2022 12:01:28 +0200 Subject: [PATCH] ux: Make New File command create a new file in memory Closes #792 --- plugins/builtin/CMakeLists.txt | 1 + .../providers/memory_file_provider.hpp | 48 +++++++ .../source/content/main_menu_items.cpp | 6 +- plugins/builtin/source/content/providers.cpp | 2 + .../content/providers/file_provider.cpp | 1 + .../providers/memory_file_provider.cpp | 130 ++++++++++++++++++ plugins/builtin/source/content/ui_items.cpp | 10 +- .../builtin/source/content/welcome_screen.cpp | 9 +- plugins/builtin/source/lang/de_DE.cpp | 2 + plugins/builtin/source/lang/en_US.cpp | 2 + plugins/builtin/source/lang/it_IT.cpp | 2 + plugins/builtin/source/lang/ja_JP.cpp | 2 + plugins/builtin/source/lang/ko_KR.cpp | 2 + plugins/builtin/source/lang/pt_BR.cpp | 2 + plugins/builtin/source/lang/zh_CN.cpp | 2 + plugins/builtin/source/lang/zh_TW.cpp | 2 + 16 files changed, 218 insertions(+), 5 deletions(-) create mode 100644 plugins/builtin/include/content/providers/memory_file_provider.hpp create mode 100644 plugins/builtin/source/content/providers/memory_file_provider.cpp diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index 5248367e8..3192f9bcd 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -30,6 +30,7 @@ add_library(${PROJECT_NAME} SHARED source/content/providers/disk_provider.cpp source/content/providers/intel_hex_provider.cpp source/content/providers/motorola_srec_provider.cpp + source/content/providers/memory_file_provider.cpp source/content/views/view_hex_editor.cpp source/content/views/view_pattern_editor.cpp diff --git a/plugins/builtin/include/content/providers/memory_file_provider.hpp b/plugins/builtin/include/content/providers/memory_file_provider.hpp new file mode 100644 index 000000000..b85cdc741 --- /dev/null +++ b/plugins/builtin/include/content/providers/memory_file_provider.hpp @@ -0,0 +1,48 @@ +#pragma once + +#include + +namespace hex::plugin::builtin::prv { + + class MemoryFileProvider : public hex::prv::Provider { + public: + explicit MemoryFileProvider() = default; + ~MemoryFileProvider() override = default; + + [[nodiscard]] bool isAvailable() const override { return true; } + [[nodiscard]] bool isReadable() const override { return true; } + [[nodiscard]] bool isWritable() const override { return true; } + [[nodiscard]] bool isResizable() const override { return true; } + [[nodiscard]] bool isSavable() const override { return true; } + + [[nodiscard]] bool open() override; + void close() override { } + + void readRaw(u64 offset, void *buffer, size_t size) override; + void writeRaw(u64 offset, const void *buffer, size_t size) override; + [[nodiscard]] size_t getActualSize() const override { return this->m_data.size(); } + + void resize(size_t newSize) override; + void insert(u64 offset, size_t size) override; + void remove(u64 offset, size_t size) override; + + void save() override; + void saveAs(const std::fs::path &path) override; + + [[nodiscard]] std::string getName() const override { return "hex.builtin.provider.mem_file.unsaved"; } + [[nodiscard]] std::vector> getDataInformation() const override { return { }; } + + [[nodiscard]] std::string getTypeName() const override { + return "hex.builtin.provider.mem_file"; + } + + [[nodiscard]] std::pair getRegionValidity(u64 address) const override; + + void loadSettings(const nlohmann::json &settings) override { hex::unused(settings); } + [[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override { return settings; } + + private: + std::vector m_data; + }; + +} \ No newline at end of file diff --git a/plugins/builtin/source/content/main_menu_items.cpp b/plugins/builtin/source/content/main_menu_items.cpp index ca248b5cc..8fa298446 100644 --- a/plugins/builtin/source/content/main_menu_items.cpp +++ b/plugins/builtin/source/content/main_menu_items.cpp @@ -21,7 +21,11 @@ namespace hex::plugin::builtin { bool taskRunning = TaskManager::getRunningTaskCount() > 0; if (ImGui::MenuItem("hex.builtin.menu.file.create_file"_lang, "CTRL + N", false, !taskRunning)) { - EventManager::post("Create File"); + auto newProvider = hex::ImHexApi::Provider::createProvider("hex.builtin.provider.mem_file", true); + if (newProvider != nullptr && !newProvider->open()) + hex::ImHexApi::Provider::remove(newProvider); + else + EventManager::post(newProvider); } if (ImGui::MenuItem("hex.builtin.menu.file.open_file"_lang, "CTRL + O", false, !taskRunning)) { diff --git a/plugins/builtin/source/content/providers.cpp b/plugins/builtin/source/content/providers.cpp index 5cd48cb36..88c35ef30 100644 --- a/plugins/builtin/source/content/providers.cpp +++ b/plugins/builtin/source/content/providers.cpp @@ -6,6 +6,7 @@ #include "content/providers/disk_provider.hpp" #include "content/providers/intel_hex_provider.hpp" #include "content/providers/motorola_srec_provider.hpp" +#include "content/providers/memory_file_provider.hpp" #include #include @@ -21,6 +22,7 @@ namespace hex::plugin::builtin { ContentRegistry::Provider::add(); ContentRegistry::Provider::add(); ContentRegistry::Provider::add(); + ContentRegistry::Provider::add(false); ProjectFile::registerHandler({ .basePath = "providers", diff --git a/plugins/builtin/source/content/providers/file_provider.cpp b/plugins/builtin/source/content/providers/file_provider.cpp index bf0642be8..3207cb899 100644 --- a/plugins/builtin/source/content/providers/file_provider.cpp +++ b/plugins/builtin/source/content/providers/file_provider.cpp @@ -145,6 +145,7 @@ namespace hex::plugin::builtin::prv { this->resize(newSize); Provider::insert(offset, size); + Provider::remove(offset, size); } size_t FileProvider::getActualSize() const { diff --git a/plugins/builtin/source/content/providers/memory_file_provider.cpp b/plugins/builtin/source/content/providers/memory_file_provider.cpp new file mode 100644 index 000000000..22a568b64 --- /dev/null +++ b/plugins/builtin/source/content/providers/memory_file_provider.cpp @@ -0,0 +1,130 @@ +#include "content/providers/memory_file_provider.hpp" +#include "content/providers/file_provider.hpp" + +#include + +#include +#include +#include +#include + +namespace hex::plugin::builtin::prv { + + bool MemoryFileProvider::open() { + this->m_data.resize(1); + this->markDirty(); + return true; + } + + void MemoryFileProvider::readRaw(u64 offset, void *buffer, size_t size) { + if ((offset + size) > this->getActualSize() || buffer == nullptr || size == 0) + return; + + std::memcpy(buffer, &this->m_data.front() + offset, size); + } + + void MemoryFileProvider::writeRaw(u64 offset, const void *buffer, size_t size) { + if ((offset + size) > this->getActualSize() || buffer == nullptr || size == 0) + return; + + std::memcpy(&this->m_data.front() + offset, buffer, size); + } + + void MemoryFileProvider::save() { + fs::openFileBrowser(fs::DialogMode::Save, { }, [this](const std::fs::path &path) { + if (path.empty()) + return; + + this->saveAs(path); + + auto newProvider = hex::ImHexApi::Provider::createProvider("hex.builtin.provider.file", true); + + if (auto fileProvider = dynamic_cast(newProvider); fileProvider != nullptr && (fileProvider->setPath(path), !fileProvider->open())) + ImHexApi::Provider::remove(newProvider); + else { + fileProvider->markDirty(false); + EventManager::post(newProvider); + ImHexApi::Provider::remove(this, true); + } + }); + } + + void MemoryFileProvider::saveAs(const std::fs::path &path) { + fs::File file(path, fs::File::Mode::Create); + + if (file.isValid()) { + auto provider = ImHexApi::Provider::get(); + + std::vector buffer(std::min(0xFF'FFFF, provider->getActualSize()), 0x00); + size_t bufferSize = buffer.size(); + + for (u64 offset = 0; offset < provider->getActualSize(); offset += bufferSize) { + if (bufferSize > provider->getActualSize() - offset) + bufferSize = provider->getActualSize() - offset; + + provider->read(offset + this->getBaseAddress(), buffer.data(), bufferSize); + file.write(buffer); + } + } + } + + void MemoryFileProvider::resize(size_t newSize) { + this->m_data.resize(newSize); + + Provider::resize(newSize); + } + + void MemoryFileProvider::insert(u64 offset, size_t size) { + auto oldSize = this->getActualSize(); + this->resize(oldSize + size); + + std::vector buffer(0x1000); + const std::vector zeroBuffer(0x1000); + + auto position = oldSize; + while (position > offset) { + const auto readSize = std::min(position - offset, buffer.size()); + + position -= readSize; + + this->readRaw(position, buffer.data(), readSize); + this->writeRaw(position, zeroBuffer.data(), readSize); + this->writeRaw(position + size, buffer.data(), readSize); + } + + Provider::insert(offset, size); + } + + void MemoryFileProvider::remove(u64 offset, size_t size) { + auto oldSize = this->getActualSize(); + this->resize(oldSize + size); + + std::vector buffer(0x1000); + + const auto newSize = oldSize - size; + auto position = offset; + while (position < newSize) { + const auto readSize = std::min(newSize - position, buffer.size()); + + this->readRaw(position + size, buffer.data(), readSize); + this->writeRaw(position, buffer.data(), readSize); + + position += readSize; + } + + this->resize(newSize); + + Provider::insert(offset, size); + Provider::remove(offset, size); + } + + std::pair MemoryFileProvider::getRegionValidity(u64 address) const { + address -= this->getBaseAddress(); + + if (address < this->getActualSize()) + return { Region { this->getBaseAddress() + address, this->getActualSize() - address }, true }; + else + return { Region::Invalid(), false }; + } + +} diff --git a/plugins/builtin/source/content/ui_items.cpp b/plugins/builtin/source/content/ui_items.cpp index 52c355249..59a5a61ad 100644 --- a/plugins/builtin/source/content/ui_items.cpp +++ b/plugins/builtin/source/content/ui_items.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -303,8 +304,13 @@ namespace hex::plugin::builtin { ImGui::BeginDisabled(tasksRunning); { // Create new file - if (ImGui::ToolBarButton(ICON_VS_FILE, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGray))) - EventManager::post("Create File"); + if (ImGui::ToolBarButton(ICON_VS_FILE, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGray))) { + auto newProvider = hex::ImHexApi::Provider::createProvider("hex.builtin.provider.mem_file", true); + if (newProvider != nullptr && !newProvider->open()) + hex::ImHexApi::Provider::remove(newProvider); + else + EventManager::post(newProvider); + } // Open file if (ImGui::ToolBarButton(ICON_VS_FOLDER_OPENED, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBrown))) diff --git a/plugins/builtin/source/content/welcome_screen.cpp b/plugins/builtin/source/content/welcome_screen.cpp index 8eb45e711..fcd8c8259 100644 --- a/plugins/builtin/source/content/welcome_screen.cpp +++ b/plugins/builtin/source/content/welcome_screen.cpp @@ -208,8 +208,13 @@ namespace hex::plugin::builtin { ImGui::UnderlinedText("hex.builtin.welcome.header.start"_lang); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 5_scaled); { - if (ImGui::IconHyperlink(ICON_VS_NEW_FILE, "hex.builtin.welcome.start.create_file"_lang)) - EventManager::post("Create File"); + if (ImGui::IconHyperlink(ICON_VS_NEW_FILE, "hex.builtin.welcome.start.create_file"_lang)) { + auto newProvider = hex::ImHexApi::Provider::createProvider("hex.builtin.provider.mem_file", true); + if (newProvider != nullptr && !newProvider->open()) + hex::ImHexApi::Provider::remove(newProvider); + else + EventManager::post(newProvider); + } if (ImGui::IconHyperlink(ICON_VS_GO_TO_FILE, "hex.builtin.welcome.start.open_file"_lang)) EventManager::post("Open File"); if (ImGui::IconHyperlink(ICON_VS_NOTEBOOK, "hex.builtin.welcome.start.open_project"_lang)) diff --git a/plugins/builtin/source/lang/de_DE.cpp b/plugins/builtin/source/lang/de_DE.cpp index e99dec985..1786ab310 100644 --- a/plugins/builtin/source/lang/de_DE.cpp +++ b/plugins/builtin/source/lang/de_DE.cpp @@ -833,6 +833,8 @@ namespace hex::plugin::builtin { { "hex.builtin.provider.intel_hex.name", "Intel Hex {0}" }, { "hex.builtin.provider.motorola_srec", "Motorola SREC Provider" }, { "hex.builtin.provider.motorola_srec.name", "Motorola SREC {0}" }, + { "hex.builtin.provider.mem_file", "RAM Datei" }, + { "hex.builtin.provider.mem_file.unsaved", "Ungespeicherte Datei" }, { "hex.builtin.layouts.default", "Standard" }, diff --git a/plugins/builtin/source/lang/en_US.cpp b/plugins/builtin/source/lang/en_US.cpp index f3f9eac71..7af7531e0 100644 --- a/plugins/builtin/source/lang/en_US.cpp +++ b/plugins/builtin/source/lang/en_US.cpp @@ -837,6 +837,8 @@ namespace hex::plugin::builtin { { "hex.builtin.provider.intel_hex.name", "Intel Hex {0}" }, { "hex.builtin.provider.motorola_srec", "Motorola SREC Provider" }, { "hex.builtin.provider.motorola_srec.name", "Motorola SREC {0}" }, + { "hex.builtin.provider.mem_file", "Memory File" }, + { "hex.builtin.provider.mem_file.unsaved", "Unsaved File" }, { "hex.builtin.layouts.default", "Default" }, diff --git a/plugins/builtin/source/lang/it_IT.cpp b/plugins/builtin/source/lang/it_IT.cpp index 655aa0f65..c6f6c9264 100644 --- a/plugins/builtin/source/lang/it_IT.cpp +++ b/plugins/builtin/source/lang/it_IT.cpp @@ -842,6 +842,8 @@ namespace hex::plugin::builtin { // { "hex.builtin.provider.intel_hex.name", "Intel Hex {0}" }, //{ "hex.builtin.provider.motorola_srec", "Motorola SREC Provider" }, // { "hex.builtin.provider.motorola_srec.name", "Motorola SREC {0}" }, + //{ "hex.builtin.provider.mem_file", "Memory File" }, + // { "hex.builtin.provider.mem_file.unsaved", "Unsaved File" }, { "hex.builtin.layouts.default", "Default" }, diff --git a/plugins/builtin/source/lang/ja_JP.cpp b/plugins/builtin/source/lang/ja_JP.cpp index 117752142..fd2f0557e 100644 --- a/plugins/builtin/source/lang/ja_JP.cpp +++ b/plugins/builtin/source/lang/ja_JP.cpp @@ -839,6 +839,8 @@ namespace hex::plugin::builtin { // { "hex.builtin.provider.intel_hex.name", "Intel Hex {0}" }, //{ "hex.builtin.provider.motorola_srec", "Motorola SREC Provider" }, // { "hex.builtin.provider.motorola_srec.name", "Motorola SREC {0}" }, + //{ "hex.builtin.provider.mem_file", "Memory File" }, + // { "hex.builtin.provider.mem_file.unsaved", "Unsaved File" }, { "hex.builtin.layouts.default", "標準" }, diff --git a/plugins/builtin/source/lang/ko_KR.cpp b/plugins/builtin/source/lang/ko_KR.cpp index 6d61f7250..cc3be403b 100644 --- a/plugins/builtin/source/lang/ko_KR.cpp +++ b/plugins/builtin/source/lang/ko_KR.cpp @@ -836,6 +836,8 @@ namespace hex::plugin::builtin { { "hex.builtin.provider.intel_hex.name", "Intel Hex {0}" }, { "hex.builtin.provider.motorola_srec", "Motorola SREC 공급자" }, { "hex.builtin.provider.motorola_srec.name", "Motorola SREC {0}" }, + //{ "hex.builtin.provider.mem_file", "Memory File" }, + // { "hex.builtin.provider.mem_file.unsaved", "Unsaved File" }, { "hex.builtin.layouts.default", "기본 값" }, diff --git a/plugins/builtin/source/lang/pt_BR.cpp b/plugins/builtin/source/lang/pt_BR.cpp index bf456f602..4ead260e8 100644 --- a/plugins/builtin/source/lang/pt_BR.cpp +++ b/plugins/builtin/source/lang/pt_BR.cpp @@ -835,6 +835,8 @@ namespace hex::plugin::builtin { // { "hex.builtin.provider.intel_hex.name", "Intel Hex {0}" }, //{ "hex.builtin.provider.motorola_srec", "Motorola SREC Provider" }, // { "hex.builtin.provider.motorola_srec.name", "Motorola SREC {0}" }, + //{ "hex.builtin.provider.mem_file", "Memory File" }, + // { "hex.builtin.provider.mem_file.unsaved", "Unsaved File" }, { "hex.builtin.layouts.default", "Default" }, diff --git a/plugins/builtin/source/lang/zh_CN.cpp b/plugins/builtin/source/lang/zh_CN.cpp index 740624e2b..c7dd09eea 100644 --- a/plugins/builtin/source/lang/zh_CN.cpp +++ b/plugins/builtin/source/lang/zh_CN.cpp @@ -838,6 +838,8 @@ namespace hex::plugin::builtin { { "hex.builtin.provider.intel_hex.name", "Intel Hex {0}" }, { "hex.builtin.provider.motorola_srec", "Motorola SREC" }, { "hex.builtin.provider.motorola_srec.name", "Motorola SREC {0}" }, + //{ "hex.builtin.provider.mem_file", "Memory File" }, + // { "hex.builtin.provider.mem_file.unsaved", "Unsaved File" }, { "hex.builtin.layouts.default", "默认" }, diff --git a/plugins/builtin/source/lang/zh_TW.cpp b/plugins/builtin/source/lang/zh_TW.cpp index c3cc47330..ae0570bef 100644 --- a/plugins/builtin/source/lang/zh_TW.cpp +++ b/plugins/builtin/source/lang/zh_TW.cpp @@ -835,6 +835,8 @@ namespace hex::plugin::builtin { // { "hex.builtin.provider.intel_hex.name", "Intel Hex {0}" }, //{ "hex.builtin.provider.motorola_srec", "Motorola SREC Provider" }, // { "hex.builtin.provider.motorola_srec.name", "Motorola SREC {0}" }, + //{ "hex.builtin.provider.mem_file", "Memory File" }, + // { "hex.builtin.provider.mem_file.unsaved", "Unsaved File" }, { "hex.builtin.layouts.default", "預設" },