mirror of https://github.com/WerWolv/ImHex.git
fix: Processing and drawing of diffs
This commit is contained in:
parent
5cfcca0bc4
commit
0aae605ac4
|
@ -397,6 +397,8 @@ namespace hex::plugin::builtin {
|
|||
provider->close();
|
||||
if (!provider->open())
|
||||
ImHexApi::Provider::remove(provider, true);
|
||||
|
||||
EventDataChanged::post(provider);
|
||||
}, noRunningTaskAndValidProvider);
|
||||
|
||||
|
||||
|
|
|
@ -187,7 +187,7 @@ namespace hex::plugin::builtin {
|
|||
if (progress < 0)
|
||||
progressString = "";
|
||||
else
|
||||
progressString = hex::format("[ {}/{} ({:.1f}%) ] ", frontTask->getValue(), frontTask->getMaxValue(), progress * 100.0F);
|
||||
progressString = hex::format("[ {}/{} ({:.1f}%) ] ", frontTask->getValue(), frontTask->getMaxValue(), std::min(progress, 1.0F) * 100.0F);
|
||||
|
||||
ImGuiExt::InfoTooltip(hex::format("{}{}", progressString, Lang(frontTask->getUnlocalizedName())).c_str());
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ namespace hex::plugin::diffing {
|
|||
struct Column {
|
||||
ui::HexEditor hexEditor;
|
||||
ContentRegistry::Diffing::DiffTree diffTree;
|
||||
std::vector<ContentRegistry::Diffing::DiffTree::Data> differences;
|
||||
|
||||
int provider = -1;
|
||||
i32 scrollLock = 0;
|
||||
|
@ -33,6 +34,8 @@ namespace hex::plugin::diffing {
|
|||
std::function<std::optional<color_t>(u64, const u8*, size_t)> createCompareFunction(size_t otherIndex) const;
|
||||
void analyze(prv::Provider *providerA, prv::Provider *providerB);
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
std::array<Column, 2> m_columns;
|
||||
|
||||
|
|
|
@ -88,31 +88,45 @@ namespace hex::plugin::diffing {
|
|||
edlibConfig.mode = EdlibAlignMode::EDLIB_MODE_NW;
|
||||
edlibConfig.task = EdlibAlignTask::EDLIB_TASK_PATH;
|
||||
|
||||
const auto windowStart = std::min(providerA->getBaseAddress(), providerB->getBaseAddress());
|
||||
const auto windowEnd = std::max(providerA->getBaseAddress() + providerA->getActualSize(), providerB->getBaseAddress() + providerB->getActualSize());
|
||||
const auto providerAStart = providerA->getBaseAddress();
|
||||
const auto providerBStart = providerB->getBaseAddress();
|
||||
const auto providerAEnd = providerAStart + providerA->getActualSize();
|
||||
const auto providerBEnd = providerBStart + providerB->getActualSize();
|
||||
|
||||
const auto windowStart = std::max(providerAStart, providerBStart);
|
||||
const auto windowEnd = std::min(providerAEnd, providerBEnd);
|
||||
|
||||
auto &task = TaskManager::getCurrentTask();
|
||||
|
||||
if (providerAStart > providerBStart) {
|
||||
differencesA.insert({ providerBStart, providerAStart }, DifferenceType::Deletion);
|
||||
differencesB.insert({ providerBStart, providerAStart }, DifferenceType::Deletion);
|
||||
} else if (providerAStart < providerBStart) {
|
||||
differencesA.insert({ providerAStart, providerBStart }, DifferenceType::Insertion);
|
||||
differencesB.insert({ providerAStart, providerBStart }, DifferenceType::Insertion);
|
||||
}
|
||||
|
||||
for (u64 address = windowStart; address < windowEnd; address += m_windowSize) {
|
||||
if (task.wasInterrupted())
|
||||
break;
|
||||
|
||||
auto currWindowSizeA = std::min<u64>(m_windowSize, providerA->getActualSize() - address);
|
||||
auto currWindowSizeB = std::min<u64>(m_windowSize, providerB->getActualSize() - address);
|
||||
std::vector<u8> dataA(currWindowSizeA), dataB(currWindowSizeB);
|
||||
std::vector<u8> dataA(currWindowSizeA, 0x00), dataB(currWindowSizeB, 0x00);
|
||||
|
||||
providerA->read(address, dataA.data(), dataA.size());
|
||||
providerB->read(address, dataB.data(), dataB.size());
|
||||
|
||||
const auto commonSize = std::min(dataA.size(), dataB.size());
|
||||
EdlibAlignResult result = edlibAlign(
|
||||
reinterpret_cast<const char*>(dataA.data()), dataA.size(),
|
||||
reinterpret_cast<const char*>(dataB.data()), dataB.size(),
|
||||
reinterpret_cast<const char*>(dataA.data()), commonSize,
|
||||
reinterpret_cast<const char*>(dataB.data()), commonSize,
|
||||
edlibConfig
|
||||
);
|
||||
|
||||
auto currentOperation = DifferenceType(0xFF);
|
||||
Region regionA = {}, regionB = {};
|
||||
u64 currentAddressA = 0x00, currentAddressB = 0x00;
|
||||
u64 currentAddressA = address, currentAddressB = address;
|
||||
|
||||
const auto insertDifference = [&] {
|
||||
switch (currentOperation) {
|
||||
|
@ -166,6 +180,13 @@ namespace hex::plugin::diffing {
|
|||
task.update(address);
|
||||
}
|
||||
|
||||
if (providerAEnd > providerBEnd) {
|
||||
differencesA.insert({ providerBEnd, providerAEnd }, DifferenceType::Insertion);
|
||||
differencesB.insert({ providerBEnd, providerAEnd }, DifferenceType::Insertion);
|
||||
} else if (providerAEnd < providerBEnd) {
|
||||
differencesA.insert({ providerAEnd, providerBEnd }, DifferenceType::Deletion);
|
||||
differencesB.insert({ providerAEnd, providerBEnd }, DifferenceType::Deletion);
|
||||
}
|
||||
|
||||
return { differencesA, differencesB };
|
||||
}
|
||||
|
|
|
@ -15,12 +15,10 @@ namespace hex::plugin::diffing {
|
|||
ViewDiff::ViewDiff() : View::Window("hex.diffing.view.diff.name", ICON_VS_DIFF_SIDEBYSIDE) {
|
||||
// Clear the selected diff providers when a provider is closed
|
||||
EventProviderClosed::subscribe(this, [this](prv::Provider *) {
|
||||
for (auto &column : m_columns) {
|
||||
column.provider = -1;
|
||||
column.hexEditor.setSelectionUnchecked(std::nullopt, std::nullopt);
|
||||
column.diffTree.clear();
|
||||
}
|
||||
|
||||
this->reset();
|
||||
});
|
||||
EventDataChanged::subscribe(this, [this](prv::Provider *) {
|
||||
m_analyzed = false;
|
||||
});
|
||||
|
||||
// Set the background highlight callbacks for the two hex editor columns
|
||||
|
@ -30,6 +28,7 @@ namespace hex::plugin::diffing {
|
|||
|
||||
ViewDiff::~ViewDiff() {
|
||||
EventProviderClosed::unsubscribe(this);
|
||||
EventDataChanged::unsubscribe(this);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -93,19 +92,37 @@ namespace hex::plugin::diffing {
|
|||
}
|
||||
|
||||
void ViewDiff::analyze(prv::Provider *providerA, prv::Provider *providerB) {
|
||||
auto commonSize = std::min(providerA->getActualSize(), providerB->getActualSize());
|
||||
auto commonSize = std::max(providerA->getActualSize(), providerB->getActualSize());
|
||||
m_diffTask = TaskManager::createTask("Diffing...", commonSize, [this, providerA, providerB](Task &) {
|
||||
auto differences = m_algorithm->analyze(providerA, providerB);
|
||||
|
||||
// Move the calculated differences over so they can be displayed
|
||||
for (size_t i = 0; i < m_columns.size(); i++) {
|
||||
auto &column = m_columns[i];
|
||||
auto &provider = ImHexApi::Provider::getProviders()[column.provider];
|
||||
|
||||
column.differences = differences[i].overlapping({ provider->getBaseAddress(), provider->getBaseAddress() + provider->getActualSize() });
|
||||
std::ranges::sort(
|
||||
column.differences,
|
||||
std::less(),
|
||||
[](const auto &a) { return a.interval; }
|
||||
);
|
||||
|
||||
column.diffTree = std::move(differences[i]);
|
||||
}
|
||||
m_analyzed = true;
|
||||
});
|
||||
}
|
||||
|
||||
void ViewDiff::reset() {
|
||||
for (auto &column : m_columns) {
|
||||
column.provider = -1;
|
||||
column.hexEditor.setSelectionUnchecked(std::nullopt, std::nullopt);
|
||||
column.diffTree.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::function<std::optional<color_t>(u64, const u8*, size_t)> ViewDiff::createCompareFunction(size_t otherIndex) const {
|
||||
const auto currIndex = otherIndex == 0 ? 1 : 0;
|
||||
return [=, this](u64 address, const u8 *, size_t size) -> std::optional<color_t> {
|
||||
|
@ -265,45 +282,33 @@ namespace hex::plugin::diffing {
|
|||
if (m_analyzed) {
|
||||
ImGuiListClipper clipper;
|
||||
|
||||
auto &diffTreeA = m_columns[0].diffTree;
|
||||
auto &diffTreeB = m_columns[1].diffTree;
|
||||
clipper.Begin(int(diffTreeA.size()));
|
||||
auto &differencesA = m_columns[0].differences;
|
||||
auto &differencesB = m_columns[1].differences;
|
||||
clipper.Begin(int(std::min(differencesA.size(), differencesB.size())));
|
||||
|
||||
auto diffIterA = diffTreeA.begin();
|
||||
auto diffIterB = diffTreeB.begin();
|
||||
while (clipper.Step()) {
|
||||
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
|
||||
ImGui::TableNextRow();
|
||||
|
||||
// Prevent the list from trying to access non-existing diffs
|
||||
if (size_t(i) >= diffTreeA.size())
|
||||
break;
|
||||
|
||||
ImGui::PushID(i);
|
||||
|
||||
const auto &[startA, restA] = *diffIterA;
|
||||
const auto &[endA, typeA] = restA;
|
||||
|
||||
const auto &[startB, restB] = *diffIterB;
|
||||
const auto &[endB, typeB] = restB;
|
||||
|
||||
std::advance(diffIterA, 1);
|
||||
std::advance(diffIterB, 1);
|
||||
const auto &[regionA, typeA] = differencesA[i];
|
||||
const auto &[regionB, typeB] = differencesB[i];
|
||||
|
||||
// Draw a clickable row for each difference that will select the difference in both hex editors
|
||||
|
||||
// Draw start address
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(hex::format("0x{:02X}", startA).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) {
|
||||
a.hexEditor.setSelection({ startA, ((endA - startA) + 1) });
|
||||
if (ImGui::Selectable(hex::format("0x{:02X}", regionA.start).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) {
|
||||
a.hexEditor.setSelection({ regionA.start, ((regionA.end - regionA.start) + 1) });
|
||||
a.hexEditor.jumpToSelection();
|
||||
b.hexEditor.setSelection({ startB, ((endB - startB) + 1) });
|
||||
b.hexEditor.setSelection({ regionB.start, ((regionB.end - regionB.start) + 1) });
|
||||
b.hexEditor.jumpToSelection();
|
||||
}
|
||||
|
||||
// Draw end address
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(hex::format("0x{:02X}", endA).c_str());
|
||||
ImGui::TextUnformatted(hex::format("0x{:02X}", regionA.start).c_str());
|
||||
|
||||
// Draw difference type
|
||||
ImGui::TableNextColumn();
|
||||
|
|
Loading…
Reference in New Issue