mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-04-01 21:17:44 -05:00
build: Switch to better interval tree implementation
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <IntervalTree.h>
|
||||
#include <IITree.h>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
@@ -44,7 +44,7 @@ namespace hex::plugin::builtin {
|
||||
protected:
|
||||
bool m_dataValid = false;
|
||||
size_t m_dataSize = 0x00;
|
||||
interval_tree::IntervalTree<u64, std::vector<u8>> m_data;
|
||||
IITree<u64, std::vector<u8>> m_data;
|
||||
|
||||
std::fs::path m_sourceFilePath;
|
||||
};
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
#include "ui/hex_editor.hpp"
|
||||
|
||||
#include <IntervalTree.h>
|
||||
#include <IITree.h>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
#include <IntervalTree.h>
|
||||
#include <IITree.h>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
@@ -94,11 +94,11 @@ namespace hex::plugin::builtin {
|
||||
|
||||
} m_searchSettings, m_decodeSettings;
|
||||
|
||||
using OccurrenceTree = interval_tree::IntervalTree<u64, Occurrence>;
|
||||
using OccurrenceTree = IITree<u64, Occurrence>;
|
||||
|
||||
std::map<prv::Provider*, std::vector<Occurrence>> m_foundOccurrences, m_sortedOccurrences;
|
||||
std::map<prv::Provider*, OccurrenceTree> m_occurrenceTree;
|
||||
std::map<prv::Provider*, std::string> m_currFilter;
|
||||
PerProvider<std::vector<Occurrence>> m_foundOccurrences, m_sortedOccurrences;
|
||||
PerProvider<OccurrenceTree> m_occurrenceTree;
|
||||
PerProvider<std::string> m_currFilter;
|
||||
|
||||
TaskHolder m_searchTask, m_filterTask;
|
||||
bool m_settingsValid = false;
|
||||
|
||||
@@ -161,26 +161,37 @@ namespace hex::plugin::builtin {
|
||||
void IntelHexProvider::setBaseAddress(u64 address) {
|
||||
auto oldBase = this->getBaseAddress();
|
||||
|
||||
auto intervals = this->m_data.findOverlapping(oldBase, oldBase + this->getActualSize());
|
||||
std::vector<size_t> indices;
|
||||
this->m_data.overlap(oldBase, oldBase + this->getActualSize(), indices);
|
||||
|
||||
for (auto &interval : intervals) {
|
||||
interval.start = (interval.start - oldBase) + address;
|
||||
interval.stop = (interval.stop - oldBase) + address;
|
||||
IITree<u64, std::vector<u8>> intervals;
|
||||
for (auto &index : indices) {
|
||||
intervals.add(
|
||||
(this->m_data.start(index) - oldBase) + address,
|
||||
(this->m_data.end(index) - oldBase) + address,
|
||||
this->m_data.data(index)
|
||||
);
|
||||
}
|
||||
|
||||
this->m_data = std::move(intervals);
|
||||
this->m_data.index();
|
||||
|
||||
Provider::setBaseAddress(address);
|
||||
}
|
||||
|
||||
void IntelHexProvider::readRaw(u64 offset, void *buffer, size_t size) {
|
||||
auto intervals = this->m_data.findOverlapping(offset, (offset + size) - 1);
|
||||
std::vector<size_t> indices;
|
||||
this->m_data.overlap(offset, (offset + size) - 1, indices);
|
||||
|
||||
std::memset(buffer, 0x00, size);
|
||||
auto bytes = reinterpret_cast<u8*>(buffer);
|
||||
for (const auto &interval : intervals) {
|
||||
for (u32 i = std::max(interval.start, offset); i <= interval.stop && (i - offset) < size; i++) {
|
||||
bytes[i - offset] = interval.value[i - interval.start];
|
||||
for (const auto &index : indices) {
|
||||
auto start = this->m_data.start(index);
|
||||
auto end = this->m_data.end(index);
|
||||
auto data = this->m_data.data(index);
|
||||
|
||||
for (u32 i = std::max(start, offset); i <= end && (i - offset) < size; i++) {
|
||||
bytes[i - offset] = data[i - start];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -203,15 +214,15 @@ namespace hex::plugin::builtin {
|
||||
return false;
|
||||
|
||||
u64 maxAddress = 0x00;
|
||||
decltype(this->m_data)::interval_vector intervals;
|
||||
for (auto &[address, bytes] : data) {
|
||||
auto endAddress = (address + bytes.size()) - 1;
|
||||
intervals.emplace_back(address, endAddress, std::move(bytes));
|
||||
this->m_data.add(address, endAddress, std::move(bytes));
|
||||
|
||||
if (endAddress > maxAddress)
|
||||
maxAddress = endAddress;
|
||||
}
|
||||
this->m_data = std::move(intervals);
|
||||
this->m_data.index();
|
||||
|
||||
this->m_dataSize = maxAddress + 1;
|
||||
this->m_dataValid = true;
|
||||
|
||||
@@ -254,17 +265,22 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
std::pair<Region, bool> IntelHexProvider::getRegionValidity(u64 address) const {
|
||||
auto intervals = this->m_data.findOverlapping(address, address);
|
||||
if (intervals.empty()) {
|
||||
std::vector<size_t> indices;
|
||||
this->m_data.overlap(address, address, indices);
|
||||
if (indices.empty()) {
|
||||
return Provider::getRegionValidity(address);
|
||||
}
|
||||
|
||||
auto closestInterval = intervals.front();
|
||||
for (const auto &interval : intervals) {
|
||||
if (interval.start < closestInterval.start)
|
||||
closestInterval = interval;
|
||||
auto closestIndex = indices.front();
|
||||
for (const auto &index : indices) {
|
||||
if (this->m_data.start(index) < this->m_data.start(closestIndex))
|
||||
closestIndex = index;
|
||||
}
|
||||
return { Region { closestInterval.start, (closestInterval.stop - closestInterval.start) + 1}, true };
|
||||
|
||||
auto start = this->m_data.start(closestIndex);
|
||||
auto end = this->m_data.end(closestIndex);
|
||||
|
||||
return { Region { start, (end - start) + 1 }, true };
|
||||
}
|
||||
|
||||
void IntelHexProvider::loadSettings(const nlohmann::json &settings) {
|
||||
|
||||
@@ -180,15 +180,15 @@ namespace hex::plugin::builtin {
|
||||
return false;
|
||||
|
||||
u64 maxAddress = 0x00;
|
||||
decltype(this->m_data)::interval_vector intervals;
|
||||
for (auto &[address, bytes] : data) {
|
||||
auto endAddress = (address + bytes.size()) - 1;
|
||||
intervals.emplace_back(address, endAddress, std::move(bytes));
|
||||
this->m_data.add(address, endAddress, std::move(bytes));
|
||||
|
||||
if (endAddress > maxAddress)
|
||||
maxAddress = endAddress;
|
||||
}
|
||||
this->m_data = std::move(intervals);
|
||||
this->m_data.index();
|
||||
|
||||
this->m_dataSize = maxAddress + 1;
|
||||
this->m_dataValid = true;
|
||||
|
||||
|
||||
@@ -22,9 +22,8 @@ namespace hex::plugin::builtin {
|
||||
if (this->m_searchTask.isRunning())
|
||||
return { };
|
||||
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
if (!this->m_occurrenceTree[provider].findOverlapping(address, address).empty())
|
||||
std::vector<size_t> occurrences;
|
||||
if (this->m_occurrenceTree->overlap(address, address, occurrences))
|
||||
return HighlightColor();
|
||||
else
|
||||
return std::nullopt;
|
||||
@@ -36,10 +35,8 @@ namespace hex::plugin::builtin {
|
||||
if (this->m_searchTask.isRunning())
|
||||
return;
|
||||
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
auto occurrences = this->m_occurrenceTree[provider].findOverlapping(address, address);
|
||||
if (occurrences.empty())
|
||||
std::vector<size_t> occurrences;
|
||||
if (!this->m_occurrenceTree->overlap(address, address, occurrences))
|
||||
return;
|
||||
|
||||
ImGui::BeginTooltip();
|
||||
@@ -51,7 +48,10 @@ namespace hex::plugin::builtin {
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
{
|
||||
const auto value = this->decodeValue(ImHexApi::Provider::get(), occurrence.value, 256);
|
||||
auto start = this->m_occurrenceTree->start(occurrence);
|
||||
auto end = this->m_occurrenceTree->end(occurrence) - 1;
|
||||
const auto &bytes = this->m_occurrenceTree->data(occurrence);
|
||||
const auto value = this->decodeValue(ImHexApi::Provider::get(), bytes, 256);
|
||||
|
||||
ImGui::ColorButton("##color", ImColor(HighlightColor()));
|
||||
ImGui::SameLine(0, 10);
|
||||
@@ -65,7 +65,7 @@ namespace hex::plugin::builtin {
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}: ", "hex.builtin.common.region"_lang);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("[ 0x{:08X} - 0x{:08X} ]", occurrence.value.region.getStartAddress(), occurrence.value.region.getEndAddress());
|
||||
ImGui::TextFormatted("[ 0x{:08X} - 0x{:08X} ]", start, end);
|
||||
|
||||
auto demangledValue = llvm::demangle(value);
|
||||
|
||||
@@ -494,28 +494,27 @@ namespace hex::plugin::builtin {
|
||||
switch (settings.mode) {
|
||||
using enum SearchSettings::Mode;
|
||||
case Strings:
|
||||
this->m_foundOccurrences[provider] = searchStrings(task, provider, searchRegion, settings.strings);
|
||||
this->m_foundOccurrences.get(provider) = searchStrings(task, provider, searchRegion, settings.strings);
|
||||
break;
|
||||
case Sequence:
|
||||
this->m_foundOccurrences[provider] = searchSequence(task, provider, searchRegion, settings.bytes);
|
||||
this->m_foundOccurrences.get(provider) = searchSequence(task, provider, searchRegion, settings.bytes);
|
||||
break;
|
||||
case Regex:
|
||||
this->m_foundOccurrences[provider] = searchRegex(task, provider, searchRegion, settings.regex);
|
||||
this->m_foundOccurrences.get(provider) = searchRegex(task, provider, searchRegion, settings.regex);
|
||||
break;
|
||||
case BinaryPattern:
|
||||
this->m_foundOccurrences[provider] = searchBinaryPattern(task, provider, searchRegion, settings.binaryPattern);
|
||||
this->m_foundOccurrences.get(provider) = searchBinaryPattern(task, provider, searchRegion, settings.binaryPattern);
|
||||
break;
|
||||
case Value:
|
||||
this->m_foundOccurrences[provider] = searchValue(task, provider, searchRegion, settings.value);
|
||||
this->m_foundOccurrences.get(provider) = searchValue(task, provider, searchRegion, settings.value);
|
||||
break;
|
||||
}
|
||||
|
||||
this->m_sortedOccurrences[provider] = this->m_foundOccurrences[provider];
|
||||
this->m_sortedOccurrences.get(provider) = this->m_foundOccurrences.get(provider);
|
||||
|
||||
OccurrenceTree::interval_vector intervals;
|
||||
for (const auto &occurrence : this->m_foundOccurrences[provider])
|
||||
intervals.emplace_back(occurrence.region.getStartAddress(), occurrence.region.getEndAddress(), occurrence);
|
||||
this->m_occurrenceTree[provider] = std::move(intervals);
|
||||
for (const auto &occurrence : this->m_foundOccurrences.get(provider))
|
||||
this->m_occurrenceTree->add(occurrence.region.getStartAddress(), occurrence.region.getEndAddress() + 1, occurrence);
|
||||
this->m_occurrenceTree->index();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -800,14 +799,14 @@ namespace hex::plugin::builtin {
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SameLine();
|
||||
ImGui::TextFormatted("hex.builtin.view.find.search.entries"_lang, this->m_foundOccurrences[provider].size());
|
||||
ImGui::TextFormatted("hex.builtin.view.find.search.entries"_lang, this->m_foundOccurrences->size());
|
||||
|
||||
ImGui::BeginDisabled(this->m_foundOccurrences[provider].empty());
|
||||
ImGui::BeginDisabled(this->m_foundOccurrences->empty());
|
||||
{
|
||||
if (ImGui::Button("hex.builtin.view.find.search.reset"_lang)) {
|
||||
this->m_foundOccurrences[provider].clear();
|
||||
this->m_sortedOccurrences[provider].clear();
|
||||
this->m_occurrenceTree[provider].clear();
|
||||
this->m_foundOccurrences->clear();
|
||||
this->m_sortedOccurrences->clear();
|
||||
*this->m_occurrenceTree = {};
|
||||
}
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
@@ -818,25 +817,25 @@ namespace hex::plugin::builtin {
|
||||
ImGui::Separator();
|
||||
ImGui::NewLine();
|
||||
|
||||
auto &currOccurrences = this->m_sortedOccurrences[provider];
|
||||
auto &currOccurrences = *this->m_sortedOccurrences;
|
||||
|
||||
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
auto prevFilterLength = this->m_currFilter[provider].length();
|
||||
if (ImGui::InputTextWithHint("##filter", "hex.builtin.common.filter"_lang, this->m_currFilter[provider])) {
|
||||
if (prevFilterLength > this->m_currFilter[provider].length())
|
||||
this->m_sortedOccurrences[provider] = this->m_foundOccurrences[provider];
|
||||
auto prevFilterLength = this->m_currFilter->length();
|
||||
if (ImGui::InputTextWithHint("##filter", "hex.builtin.common.filter"_lang, *this->m_currFilter)) {
|
||||
if (prevFilterLength > this->m_currFilter->length())
|
||||
*this->m_sortedOccurrences = *this->m_foundOccurrences;
|
||||
|
||||
if (this->m_filterTask.isRunning())
|
||||
this->m_filterTask.interrupt();
|
||||
|
||||
if (!this->m_currFilter[provider].empty()) {
|
||||
if (!this->m_currFilter->empty()) {
|
||||
this->m_filterTask = TaskManager::createTask("Filtering", currOccurrences.size(), [this, provider, &currOccurrences](Task &task) {
|
||||
u64 progress = 0;
|
||||
currOccurrences.erase(std::remove_if(currOccurrences.begin(), currOccurrences.end(), [this, provider, &task, &progress](const auto ®ion) {
|
||||
task.update(progress);
|
||||
progress += 1;
|
||||
|
||||
return !hex::containsIgnoreCase(this->decodeValue(provider, region), this->m_currFilter[provider]);
|
||||
return !hex::containsIgnoreCase(this->decodeValue(provider, region), this->m_currFilter.get(provider));
|
||||
}), currOccurrences.end());
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
auto selection = ImHexApi::HexEditor::getSelection();
|
||||
|
||||
if (ImGui::GetIO().KeyShift) {
|
||||
if (selection.has_value() && ImGui::GetIO().KeyShift) {
|
||||
auto &hashFunctions = this->m_hashFunctions.get(selection->getProvider());
|
||||
if (!hashFunctions.empty() && selection.has_value() && selection->overlaps(Region { address, size })) {
|
||||
ImGui::BeginTooltip();
|
||||
|
||||
Reference in New Issue
Block a user