From e3ae1698332e29244958ce3cf5dbff82d0bec854 Mon Sep 17 00:00:00 2001 From: iTrooz Date: Wed, 5 Jul 2023 20:49:57 +0200 Subject: [PATCH] impr: Separate the behaviour of being savable and being dumpable for provider (#1183) ### Problem description Currently, the providers use the method `isSavable()` to determine both if they can use "Save" or "Save as". This behaviour is problematic because some providers may need to be saveable but not saveable as: for example the view provider. The original provider may not allow to be saved. ### Implementation description I separate these two behaviour by creating another function: `isDumpable()`, that return true by default but can be overridden by the provider to return false, if the provider should not be dumped in any way. ### Additional things While I was at it, I also marked "export" operations as needing the "dumpable" flag. That way, we can't accidentally export the whole address space of a process as base64. I also added documentation for these some functions in Provider --- .../include/hex/providers/provider.hpp | 19 +++++++++++++++++++ lib/libimhex/source/providers/provider.cpp | 4 ++++ .../content/providers/view_provider.hpp | 8 +++++++- .../source/content/main_menu_items.cpp | 14 +++++++++++--- .../source/content/views/view_hex_editor.cpp | 4 ++-- .../providers/process_memory_provider.hpp | 1 + 6 files changed, 44 insertions(+), 6 deletions(-) diff --git a/lib/libimhex/include/hex/providers/provider.hpp b/lib/libimhex/include/hex/providers/provider.hpp index 2ebf581bb..fbc462a1b 100644 --- a/lib/libimhex/include/hex/providers/provider.hpp +++ b/lib/libimhex/include/hex/providers/provider.hpp @@ -38,10 +38,29 @@ namespace hex::prv { [[nodiscard]] virtual bool isAvailable() const = 0; [[nodiscard]] virtual bool isReadable() const = 0; + + /** + * @brief Controls if the user can write data to this specific provider. + * This may be false for e.g. a file opened in read-only + */ [[nodiscard]] virtual bool isWritable() const = 0; [[nodiscard]] virtual bool isResizable() const = 0; + + /** + * @brief Controls whether the provider can be saved ("saved", not "saved as") + * This is mainly used by providers that aren't buffered, and so don't need to be saved + * This function will usually return false for providers that aren't writable, but this isn't guaranted + */ [[nodiscard]] virtual bool isSavable() const = 0; + /** + * @brief Controls whether we can dump data from this provider (e.g. "save as", or "export -> .."). + * Typically disabled for process with sparse data, like the Process memory provider + * where the virtual address space is several TiBs large. + * Default implementation returns true. + */ + [[nodiscard]] virtual bool isDumpable() const; + /** * @brief Read data from this provider, applying overlays and patches * @param offset offset to start reading the data diff --git a/lib/libimhex/source/providers/provider.cpp b/lib/libimhex/source/providers/provider.cpp index cd2d178e6..57e302f93 100644 --- a/lib/libimhex/source/providers/provider.cpp +++ b/lib/libimhex/source/providers/provider.cpp @@ -356,4 +356,8 @@ namespace hex::prv { return 0; } + [[nodiscard]] bool Provider::isDumpable() const { + return true; + } + } diff --git a/plugins/builtin/include/content/providers/view_provider.hpp b/plugins/builtin/include/content/providers/view_provider.hpp index 5866f8de9..5d9ae8b38 100644 --- a/plugins/builtin/include/content/providers/view_provider.hpp +++ b/plugins/builtin/include/content/providers/view_provider.hpp @@ -38,7 +38,13 @@ namespace hex::plugin::builtin { return this->m_provider->isWritable(); } [[nodiscard]] bool isResizable() const override { return true; } - [[nodiscard]] bool isSavable() const override { return true; } + + [[nodiscard]] bool isSavable() const override { + if (this->m_provider == nullptr) + return false; + else + return this->m_provider->isSavable(); + } void save() override { this->m_provider->save(); diff --git a/plugins/builtin/source/content/main_menu_items.cpp b/plugins/builtin/source/content/main_menu_items.cpp index 6c4bb0dc8..1fee6e06d 100644 --- a/plugins/builtin/source/content/main_menu_items.cpp +++ b/plugins/builtin/source/content/main_menu_items.cpp @@ -285,6 +285,13 @@ namespace hex::plugin::builtin { } + /** + * @brief returns true if there is a currently selected provider, and it is possibl to dump data from it + */ + bool isProviderDumpable() { + auto provider = ImHexApi::Provider::get(); + return ImHexApi::Provider::isValid() && provider->isDumpable(); + } static void createFileMenu() { @@ -368,12 +375,13 @@ namespace hex::plugin::builtin { } /* Export */ + /* Only make them accessible if the current provider is dumpable */ { /* Base 64 */ ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.export", "hex.builtin.menu.file.export.base64" }, 6000, Shortcut::None, exportBase64, - ImHexApi::Provider::isValid); + isProviderDumpable); ContentRegistry::Interface::addMenuItemSeparator({ "hex.builtin.menu.file", "hex.builtin.menu.file.export" }, 6050); @@ -381,13 +389,13 @@ namespace hex::plugin::builtin { ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.export", "hex.builtin.menu.file.export.ips" }, 6100, Shortcut::None, exportIPSPatch, - ImHexApi::Provider::isValid); + isProviderDumpable); /* IPS32 */ ContentRegistry::Interface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.export", "hex.builtin.menu.file.export.ips32" }, 6150, Shortcut::None, exportIPS32Patch, - ImHexApi::Provider::isValid); + isProviderDumpable); } ContentRegistry::Interface::addMenuItemSeparator({ "hex.builtin.menu.file" }, 10000); diff --git a/plugins/builtin/source/content/views/view_hex_editor.cpp b/plugins/builtin/source/content/views/view_hex_editor.cpp index b2adbbc1b..f8c8630a6 100644 --- a/plugins/builtin/source/content/views/view_hex_editor.cpp +++ b/plugins/builtin/source/content/views/view_hex_editor.cpp @@ -960,7 +960,7 @@ namespace hex::plugin::builtin { auto provider = ImHexApi::Provider::get(); bool providerValid = ImHexApi::Provider::isValid(); - return providerValid && provider->isWritable(); + return providerValid && provider->isWritable() && provider->isSavable() && provider->isDirty(); }); /* Save As */ @@ -971,7 +971,7 @@ namespace hex::plugin::builtin { auto provider = ImHexApi::Provider::get(); bool providerValid = ImHexApi::Provider::isValid(); - return providerValid && provider->isWritable(); + return providerValid && provider->isDumpable(); }); /* Load Encoding File */ diff --git a/plugins/windows/include/content/providers/process_memory_provider.hpp b/plugins/windows/include/content/providers/process_memory_provider.hpp index 33791cf1f..7f3a8e90c 100644 --- a/plugins/windows/include/content/providers/process_memory_provider.hpp +++ b/plugins/windows/include/content/providers/process_memory_provider.hpp @@ -27,6 +27,7 @@ namespace hex::plugin::windows { [[nodiscard]] bool isWritable() const override { return true; } [[nodiscard]] bool isResizable() const override { return false; } [[nodiscard]] bool isSavable() const override { return false; } + [[nodiscard]] bool isDumpable() const override { return false; } void read(u64 address, void *buffer, size_t size, bool) override { this->readRaw(address, buffer, size); } void write(u64 address, const void *buffer, size_t size) override { this->writeRaw(address, buffer, size); }