From 5c13cf9dbfe1f84e7054c5eed6a0a3dfdc4ea80e Mon Sep 17 00:00:00 2001 From: WerWolv Date: Wed, 10 Aug 2022 09:26:48 +0200 Subject: [PATCH] sys: Added support for providers with unreadable regions --- lib/external/pattern_language | 2 +- lib/libimhex/include/hex/helpers/types.hpp | 12 +++++-- .../include/hex/providers/provider.hpp | 2 ++ lib/libimhex/source/api/content_registry.cpp | 8 +++-- lib/libimhex/source/providers/provider.cpp | 32 ++++++++++++++++++ .../content/providers/null_provider.hpp | 33 +++++++++++++++++++ plugins/builtin/source/content/providers.cpp | 8 ++--- .../source/content/views/view_hex_editor.cpp | 32 +++++++++++++----- 8 files changed, 111 insertions(+), 18 deletions(-) create mode 100644 plugins/builtin/include/content/providers/null_provider.hpp diff --git a/lib/external/pattern_language b/lib/external/pattern_language index f1c58564f..15f42da03 160000 --- a/lib/external/pattern_language +++ b/lib/external/pattern_language @@ -1 +1 @@ -Subproject commit f1c58564f32b23e52a57ef2c1263223b3b773ddf +Subproject commit 15f42da03ff501d5e1c66794a508ef9a452236e3 diff --git a/lib/libimhex/include/hex/helpers/types.hpp b/lib/libimhex/include/hex/helpers/types.hpp index dafc5dd2f..01d2d45a3 100644 --- a/lib/libimhex/include/hex/helpers/types.hpp +++ b/lib/libimhex/include/hex/helpers/types.hpp @@ -21,11 +21,11 @@ namespace hex { size_t size; [[nodiscard]] constexpr bool isWithin(const Region &other) const { - return (this->getStartAddress() >= other.getStartAddress()) && (this->getEndAddress() <= other.getEndAddress()); + return (this->getStartAddress() >= other.getStartAddress()) && (this->getEndAddress() <= other.getEndAddress()) && *this != Invalid() && other != Invalid(); } [[nodiscard]] constexpr bool overlaps(const Region &other) const { - return (this->getEndAddress() >= other.getStartAddress()) && (this->getStartAddress() < other.getEndAddress()); + return (this->getEndAddress() >= other.getStartAddress()) && (this->getStartAddress() < other.getEndAddress()) && *this != Invalid() && other != Invalid(); } [[nodiscard]] constexpr u64 getStartAddress() const { @@ -39,6 +39,14 @@ namespace hex { [[nodiscard]] constexpr size_t getSize() const { return this->size; } + + constexpr bool operator==(const Region &other) const { + return this->address == other.address && this->size == other.size; + } + + constexpr static Region Invalid() { + return { 0, 0 }; + } }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/providers/provider.hpp b/lib/libimhex/include/hex/providers/provider.hpp index 2cc2fdf5c..f9aa967bf 100644 --- a/lib/libimhex/include/hex/providers/provider.hpp +++ b/lib/libimhex/include/hex/providers/provider.hpp @@ -99,6 +99,8 @@ namespace hex::prv { void markDirty(bool dirty = true) { this->m_dirty = dirty; } [[nodiscard]] bool isDirty() const { return this->m_dirty; } + virtual std::pair getRegionValidity(u64 address) const; + protected: u32 m_currPage = 0; u64 m_baseAddress = 0; diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index c7201bd5f..e8b296df6 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -244,9 +244,11 @@ namespace hex { std::unique_ptr createDefaultRuntime(prv::Provider *provider) { auto runtime = std::make_unique(); - runtime->setDataSource([provider](u64 offset, u8 *buffer, size_t size) { - provider->read(offset, buffer, size); - }, 0, 0); + if (provider != nullptr) { + runtime->setDataSource([provider](u64 offset, u8 *buffer, size_t size) { + provider->read(offset, buffer, size); + }, provider->getBaseAddress(), provider->getActualSize()); + } runtime->setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude)); diff --git a/lib/libimhex/source/providers/provider.cpp b/lib/libimhex/source/providers/provider.cpp index 749946ce0..610317558 100644 --- a/lib/libimhex/source/providers/provider.cpp +++ b/lib/libimhex/source/providers/provider.cpp @@ -254,4 +254,36 @@ namespace hex::prv { this->m_currPage = settings["currPage"]; } + std::pair Provider::getRegionValidity(u64 address) const { + if (address > this->getActualSize()) + return { Region::Invalid(), false }; + + bool insideValidRegion = false; + + std::optional nextRegionAddress; + for (const auto &overlay : this->m_overlays) { + Region overlayRegion = { overlay->getAddress(), overlay->getSize() }; + if (!nextRegionAddress.has_value() || overlay->getAddress() < nextRegionAddress) { + nextRegionAddress = overlayRegion.getStartAddress(); + } + + if (Region { address, 1 }.overlaps(overlayRegion)) { + insideValidRegion = true; + } + } + + for (const auto &[patchAddress, value] : this->m_patches.back()) { + if (!nextRegionAddress.has_value() || patchAddress < nextRegionAddress) + nextRegionAddress = patchAddress; + + if (address == patchAddress) + insideValidRegion = true; + } + + if (!nextRegionAddress.has_value()) + return { Region { address, this->getActualSize() - address }, true }; + else + return { Region { address, *nextRegionAddress - address }, insideValidRegion }; + } + } diff --git a/plugins/builtin/include/content/providers/null_provider.hpp b/plugins/builtin/include/content/providers/null_provider.hpp new file mode 100644 index 000000000..37cf92002 --- /dev/null +++ b/plugins/builtin/include/content/providers/null_provider.hpp @@ -0,0 +1,33 @@ +#pragma once + +#include + +namespace hex::plugin::builtin::prv { + + class NullProvider : public hex::prv::Provider { + public: + explicit NullProvider() = default; + ~NullProvider() override = default; + + [[nodiscard]] bool isAvailable() const override { return true; } + [[nodiscard]] bool isReadable() const override { return true; } + [[nodiscard]] bool isWritable() const override { return false; } + [[nodiscard]] bool isResizable() const override { return false; } + [[nodiscard]] bool isSavable() const override { return false; } + + void readRaw(u64 offset, void *buffer, size_t size) override { hex::unused(offset, buffer, size); } + void writeRaw(u64 offset, const void *buffer, size_t size) override { hex::unused(offset, buffer, size); } + [[nodiscard]] size_t getActualSize() const override { return 0x00; } + + [[nodiscard]] std::string getName() const override { return "None"; } + [[nodiscard]] std::vector> getDataInformation() const override { return { }; } + + void loadSettings(const nlohmann::json &settings) override { hex::unused(settings); } + [[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override { return settings; } + + [[nodiscard]] std::string getTypeName() const override { + return "hex.builtin.provider.null"; + } + }; + +} \ No newline at end of file diff --git a/plugins/builtin/source/content/providers.cpp b/plugins/builtin/source/content/providers.cpp index 200eff78b..3fe423a02 100644 --- a/plugins/builtin/source/content/providers.cpp +++ b/plugins/builtin/source/content/providers.cpp @@ -2,6 +2,7 @@ #include "content/providers/gdb_provider.hpp" #include "content/providers/file_provider.hpp" +#include "content/providers/null_provider.hpp" #include "content/providers/disk_provider.hpp" #include @@ -13,8 +14,9 @@ namespace hex::plugin::builtin { void registerProviders() { ContentRegistry::Provider::add(false); - ContentRegistry::Provider::add(); + ContentRegistry::Provider::add(false); ContentRegistry::Provider::add(); + ContentRegistry::Provider::add(); ProjectFile::registerHandler({ .basePath = "providers", @@ -53,9 +55,7 @@ namespace hex::plugin::builtin { } tar.write(basePath / "providers.json", - nlohmann::json({ - {"providers", providerIds} - }).dump(4) + nlohmann::json({ {"providers", providerIds } }).dump(4) ); return true; diff --git a/plugins/builtin/source/content/views/view_hex_editor.cpp b/plugins/builtin/source/content/views/view_hex_editor.cpp index b66dc66bc..974a10680 100644 --- a/plugins/builtin/source/content/views/view_hex_editor.cpp +++ b/plugins/builtin/source/content/views/view_hex_editor.cpp @@ -728,6 +728,16 @@ namespace hex::plugin::builtin { if (ImHexApi::Provider::isValid()) { auto provider = ImHexApi::Provider::get(); + std::pair validRegion = { Region::Invalid(), false }; + const auto isCurrRegionValid = [&validRegion, &provider](u64 address){ + auto &[currRegion, currRegionValid] = validRegion; + if (!Region{ address, 1 }.isWithin(currRegion)) { + validRegion = provider->getRegionValidity(address); + } + + return currRegionValid; + }; + ImGuiListClipper clipper; clipper.Begin(std::ceil(provider->getSize() / (long double)(this->m_bytesPerRow)), CharacterSize.y); @@ -735,7 +745,7 @@ namespace hex::plugin::builtin { this->m_visibleRowCount = clipper.DisplayEnd - clipper.DisplayStart; // Loop over rows - for (i128 y = clipper.DisplayStart; y < u64(clipper.DisplayEnd); y++) { + for (u64 y = u64(clipper.DisplayStart); y < u64(clipper.DisplayEnd); y++) { // Draw address column ImGui::TableNextRow(); @@ -800,13 +810,14 @@ namespace hex::plugin::builtin { if (x < std::ceil(float(validBytes) / bytesPerCell)) { auto cellStartPos = getCellPosition(); auto cellSize = (CharacterSize * ImVec2(this->m_currDataVisualizer->getMaxCharsPerCell(), 1) + (ImVec2(3, 2) * ImGui::GetStyle().CellPadding) - ImVec2(1, 0) * ImGui::GetStyle().CellPadding) + ImVec2(1, 0); + auto maxCharsPerCell = this->m_currDataVisualizer->getMaxCharsPerCell(); auto [foregroundColor, backgroundColor] = cellColors[x]; if (isColumnSeparatorColumn(x + 1, columnCount) && selectionMax != x + y * columnCount) { cellSize.x += SeparatorColumWidth + 1; } - if (y == clipper.DisplayStart) + if (y == u64(clipper.DisplayStart)) cellSize.y -= (ImGui::GetStyle().CellPadding.y + 1); // Draw highlights and selection @@ -830,8 +841,11 @@ namespace hex::plugin::builtin { // Draw cell content ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - ImGui::PushItemWidth((CharacterSize * this->m_currDataVisualizer->getMaxCharsPerCell()).x); - this->drawCell(byteAddress, &bytes[x * bytesPerCell], bytesPerCell, cellHovered); + ImGui::PushItemWidth((CharacterSize * maxCharsPerCell).x); + if (isCurrRegionValid(byteAddress)) + this->drawCell(byteAddress, &bytes[x * bytesPerCell], bytesPerCell, cellHovered); + else + ImGui::TextFormatted("{}", std::string(maxCharsPerCell, '?')); ImGui::PopItemWidth(); ImGui::PopStyleVar(); @@ -875,7 +889,9 @@ namespace hex::plugin::builtin { this->drawSelectionFrame(x, y, byteAddress, 1, cellStartPos, cellSize); } - if (std::isprint(bytes[x])) + if (!isCurrRegionValid(byteAddress)) + ImGui::TextFormatted("?"); + else if (std::isprint(bytes[x])) ImGui::TextFormatted("{:c}", bytes[x]); else ImGui::TextDisabled("."); @@ -917,7 +933,7 @@ namespace hex::plugin::builtin { const auto x = address % this->m_bytesPerRow; - if (x < validBytes) { + if (x < validBytes && isCurrRegionValid(address)) { auto [foregroundColor, backgroundColor] = cellColors[x / bytesPerCell]; // Draw highlights and selection @@ -951,13 +967,13 @@ namespace hex::plugin::builtin { if ((ImGui::IsMouseDown(ImGuiMouseButton_Left) && this->m_selectionStart != this->m_selectionEnd)) { auto fractionPerLine = 1.0 / (this->m_visibleRowCount + 1); - if (y == clipper.DisplayStart + 2) { + if (y == u64(clipper.DisplayStart + 2)) { if (i128(this->m_selectionEnd - provider->getBaseAddress() - provider->getCurrentPageAddress()) <= (i64(clipper.DisplayStart + 2) * this->m_bytesPerRow)) { this->m_shouldScrollToSelection = false; ImGui::SetScrollHereY(fractionPerLine * 4); } - } else if (y == (clipper.DisplayEnd - 2)) { + } else if (y == u64(clipper.DisplayEnd - 2)) { if (i128(this->m_selectionEnd - provider->getBaseAddress() - provider->getCurrentPageAddress()) >= (i64(clipper.DisplayEnd - 2) * this->m_bytesPerRow)) { this->m_shouldScrollToSelection = false; ImGui::SetScrollHereY(fractionPerLine * (this->m_visibleRowCount - 1));