sys: Added support for providers with unreadable regions
This commit is contained in:
parent
19a0dc80db
commit
5c13cf9dbf
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
@ -1 +1 @@
|
||||
Subproject commit f1c58564f32b23e52a57ef2c1263223b3b773ddf
|
||||
Subproject commit 15f42da03ff501d5e1c66794a508ef9a452236e3
|
@ -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 };
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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<Region, bool> getRegionValidity(u64 address) const;
|
||||
|
||||
protected:
|
||||
u32 m_currPage = 0;
|
||||
u64 m_baseAddress = 0;
|
||||
|
@ -244,9 +244,11 @@ namespace hex {
|
||||
std::unique_ptr<pl::PatternLanguage> createDefaultRuntime(prv::Provider *provider) {
|
||||
auto runtime = std::make_unique<pl::PatternLanguage>();
|
||||
|
||||
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));
|
||||
|
||||
|
@ -254,4 +254,36 @@ namespace hex::prv {
|
||||
this->m_currPage = settings["currPage"];
|
||||
}
|
||||
|
||||
std::pair<Region, bool> Provider::getRegionValidity(u64 address) const {
|
||||
if (address > this->getActualSize())
|
||||
return { Region::Invalid(), false };
|
||||
|
||||
bool insideValidRegion = false;
|
||||
|
||||
std::optional<u64> 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 };
|
||||
}
|
||||
|
||||
}
|
||||
|
33
plugins/builtin/include/content/providers/null_provider.hpp
Normal file
33
plugins/builtin/include/content/providers/null_provider.hpp
Normal file
@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
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<std::pair<std::string, std::string>> 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";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
@ -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 <hex/api/project_file_manager.hpp>
|
||||
@ -13,8 +14,9 @@ namespace hex::plugin::builtin {
|
||||
void registerProviders() {
|
||||
|
||||
ContentRegistry::Provider::add<prv::FileProvider>(false);
|
||||
ContentRegistry::Provider::add<prv::GDBProvider>();
|
||||
ContentRegistry::Provider::add<prv::NullProvider>(false);
|
||||
ContentRegistry::Provider::add<prv::DiskProvider>();
|
||||
ContentRegistry::Provider::add<prv::GDBProvider>();
|
||||
|
||||
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;
|
||||
|
@ -728,6 +728,16 @@ namespace hex::plugin::builtin {
|
||||
if (ImHexApi::Provider::isValid()) {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
std::pair<Region, bool> 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));
|
||||
|
Loading…
x
Reference in New Issue
Block a user