diff --git a/plugins/builtin/source/content/main_menu_items.cpp b/plugins/builtin/source/content/main_menu_items.cpp index e12ab4f94..7890725aa 100644 --- a/plugins/builtin/source/content/main_menu_items.cpp +++ b/plugins/builtin/source/content/main_menu_items.cpp @@ -397,6 +397,8 @@ namespace hex::plugin::builtin { provider->close(); if (!provider->open()) ImHexApi::Provider::remove(provider, true); + + EventDataChanged::post(provider); }, noRunningTaskAndValidProvider); diff --git a/plugins/builtin/source/content/ui_items.cpp b/plugins/builtin/source/content/ui_items.cpp index bb49c23b8..b806732b0 100644 --- a/plugins/builtin/source/content/ui_items.cpp +++ b/plugins/builtin/source/content/ui_items.cpp @@ -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()); diff --git a/plugins/diffing/include/content/views/view_diff.hpp b/plugins/diffing/include/content/views/view_diff.hpp index fa50584a1..3132413e2 100644 --- a/plugins/diffing/include/content/views/view_diff.hpp +++ b/plugins/diffing/include/content/views/view_diff.hpp @@ -24,6 +24,7 @@ namespace hex::plugin::diffing { struct Column { ui::HexEditor hexEditor; ContentRegistry::Diffing::DiffTree diffTree; + std::vector differences; int provider = -1; i32 scrollLock = 0; @@ -33,6 +34,8 @@ namespace hex::plugin::diffing { std::function(u64, const u8*, size_t)> createCompareFunction(size_t otherIndex) const; void analyze(prv::Provider *providerA, prv::Provider *providerB); + void reset(); + private: std::array m_columns; diff --git a/plugins/diffing/source/content/diffing_algorithms.cpp b/plugins/diffing/source/content/diffing_algorithms.cpp index 278338719..c4d0643d8 100644 --- a/plugins/diffing/source/content/diffing_algorithms.cpp +++ b/plugins/diffing/source/content/diffing_algorithms.cpp @@ -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(m_windowSize, providerA->getActualSize() - address); auto currWindowSizeB = std::min(m_windowSize, providerB->getActualSize() - address); - std::vector dataA(currWindowSizeA), dataB(currWindowSizeB); + std::vector 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(dataA.data()), dataA.size(), - reinterpret_cast(dataB.data()), dataB.size(), + reinterpret_cast(dataA.data()), commonSize, + reinterpret_cast(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 }; } diff --git a/plugins/diffing/source/content/views/view_diff.cpp b/plugins/diffing/source/content/views/view_diff.cpp index 97f5ac796..38c512a71 100644 --- a/plugins/diffing/source/content/views/view_diff.cpp +++ b/plugins/diffing/source/content/views/view_diff.cpp @@ -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(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 { @@ -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();