diff --git a/plugins/builtin/include/content/providers/intel_hex_provider.hpp b/plugins/builtin/include/content/providers/intel_hex_provider.hpp index 4fce281da..afbee08bb 100644 --- a/plugins/builtin/include/content/providers/intel_hex_provider.hpp +++ b/plugins/builtin/include/content/providers/intel_hex_provider.hpp @@ -2,14 +2,25 @@ #include #include +#include #include +#include namespace hex::plugin::builtin { + struct MemoryRegion { + Region region; + std::string name; + + constexpr bool operator<(const MemoryRegion &other) const { + return this->region.getStartAddress() < other.region.getStartAddress(); + } + }; class IntelHexProvider : public hex::prv::Provider, public hex::prv::IProviderDataDescription, - public hex::prv::IProviderFilePicker { + public hex::prv::IProviderFilePicker, + public hex::prv::IProviderSidebarInterface { public: IntelHexProvider() = default; ~IntelHexProvider() override = default; @@ -21,11 +32,13 @@ namespace hex::plugin::builtin { [[nodiscard]] bool isSavable() const override { return false; } void setBaseAddress(u64 address) override; + void drawSidebarInterface() override; void readRaw(u64 offset, void *buffer, size_t size) override; void writeRaw(u64 offset, const void *buffer, size_t size) override; [[nodiscard]] u64 getActualSize() const override; - + void processMemoryRegions(wolv::util::Expected>, std::string> data); + static bool memoryRegionFilter(const std::string &search, const MemoryRegion &memoryRegion); bool open() override; void close() override; @@ -52,7 +65,8 @@ namespace hex::plugin::builtin { size_t m_dataSize = 0x00; wolv::container::IntervalTree> m_data; + ui::SearchableWidget m_regionSearchWidget = ui::SearchableWidget(memoryRegionFilter); + std::vector m_memoryRegions; std::fs::path m_sourceFilePath; }; - -} \ No newline at end of file +} diff --git a/plugins/builtin/source/content/providers/intel_hex_provider.cpp b/plugins/builtin/source/content/providers/intel_hex_provider.cpp index d92916b49..d7e5dd680 100644 --- a/plugins/builtin/source/content/providers/intel_hex_provider.cpp +++ b/plugins/builtin/source/content/providers/intel_hex_provider.cpp @@ -2,9 +2,13 @@ #include +#include #include -#include #include +#include +#include +#include +#include #include @@ -194,6 +198,53 @@ namespace hex::plugin::builtin { return m_dataSize; } + void IntelHexProvider::processMemoryRegions(wolv::util::Expected>, std::string> data) { + std::optional maxAddress; + bool firstAddress = true; + u64 regionStartAddr = 0; + u32 prevAddrEnd = 0; + u32 blockIdx = 0; + u64 blockSize = 0; + + for (auto &[address, bytes] : data.value()) { + auto endAddress = (address + bytes.size()) - 1; + if (firstAddress) { + regionStartAddr = address; + firstAddress = false; + } else { + if (address > (prevAddrEnd + 1)) { + m_memoryRegions.emplace_back(Region(regionStartAddr, blockSize), fmt::format("Block {}", blockIdx)); + regionStartAddr = address; + blockSize = 0; + blockIdx++; + } + } + blockSize += bytes.size(); + prevAddrEnd = endAddress; + + m_data.emplace({ address, endAddress }, std::move(bytes)); + if (endAddress > maxAddress) + maxAddress = endAddress; + } + + if (blockSize > 0) { + m_memoryRegions.emplace_back(Region(regionStartAddr, blockSize), fmt::format("Block {}", blockIdx)); + } + + if (maxAddress.has_value()) + m_dataSize = *maxAddress + 1; + else + m_dataSize = 0x00; + + m_dataValid = true; + + TaskManager::doLater([this] { + // Jump to first region after loading all regions + auto [region, _] = m_memoryRegions.front(); + ImHexApi::HexEditor::setSelection(region.getStartAddress(), 1); + }); + } + bool IntelHexProvider::open() { auto file = wolv::io::File(m_sourceFilePath, wolv::io::File::Mode::Read); if (!file.isValid()) { @@ -206,22 +257,7 @@ namespace hex::plugin::builtin { this->setErrorMessage(data.error()); return false; } - - std::optional maxAddress; - for (auto &[address, bytes] : data.value()) { - auto endAddress = (address + bytes.size()) - 1; - m_data.emplace({ address, endAddress }, std::move(bytes)); - - if (endAddress > maxAddress) - maxAddress = endAddress; - } - - if (maxAddress.has_value()) - m_dataSize = *maxAddress + 1; - else - m_dataSize = 0x00; - - m_dataValid = true; + processMemoryRegions(data); return true; } @@ -285,6 +321,62 @@ namespace hex::plugin::builtin { return { Region { closestInterval.start, (closestInterval.end - closestInterval.start) + 1}, Provider::getRegionValidity(address).second }; } + bool IntelHexProvider::memoryRegionFilter(const std::string& search, const MemoryRegion& memoryRegion) { + std::string startAddr = fmt::format("{:#x}", memoryRegion.region.getStartAddress()); + std::string endAddr = fmt::format("{:#x}", memoryRegion.region.getEndAddress()); + + return hex::containsIgnoreCase(startAddr, search) || + hex::containsIgnoreCase(endAddr, search); + } + + void IntelHexProvider::drawSidebarInterface() { + ImGuiExt::Header("hex.builtin.provider.process_memory.memory_regions"_lang, true); + + auto availableX = ImGui::GetContentRegionAvail().x; + ImGui::PushItemWidth(availableX); + const auto &filtered = m_regionSearchWidget.draw(m_memoryRegions); + ImGui::PopItemWidth(); + + auto availableY = ImGui::GetContentRegionAvail().y; + if (ImGui::BeginTable("##module_table", 3, + ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | + ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollY, + ImVec2(availableX, availableY))) { + ImGui::TableSetupColumn("hex.ui.common.region"_lang); + ImGui::TableSetupColumn("hex.ui.common.size"_lang); + ImGui::TableSetupColumn("hex.ui.common.name"_lang); + ImGui::TableSetupScrollFreeze(0, 1); + + ImGui::TableHeadersRow(); + + for (const auto &memoryRegion : filtered) { + ImGui::PushID(&memoryRegion); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGuiExt::TextFormatted("0x{0:08X} - 0x{1:08X}", + memoryRegion->region.getStartAddress(), memoryRegion->region.getEndAddress()); + + ImGui::TableNextColumn(); + ImGui::TextUnformatted(hex::toByteString(memoryRegion->region.getSize()).c_str()); + + + ImGui::TableNextColumn(); + if (ImGui::Selectable(memoryRegion->name.c_str(), + false, + ImGuiSelectableFlags_SpanAllColumns)) { + ImHexApi::HexEditor::setSelection( + memoryRegion->region.getStartAddress(), 1); + } + + ImGui::PopID(); + } + + ImGui::EndTable(); + } + } + void IntelHexProvider::loadSettings(const nlohmann::json &settings) { Provider::loadSettings(settings); diff --git a/plugins/builtin/source/content/providers/motorola_srec_provider.cpp b/plugins/builtin/source/content/providers/motorola_srec_provider.cpp index 7819b8d35..60ada419d 100644 --- a/plugins/builtin/source/content/providers/motorola_srec_provider.cpp +++ b/plugins/builtin/source/content/providers/motorola_srec_provider.cpp @@ -1,9 +1,8 @@ #include "content/providers/motorola_srec_provider.hpp" - #include -#include #include +#include #include #include @@ -183,22 +182,7 @@ namespace hex::plugin::builtin { this->setErrorMessage(data.error()); return false; } - - std::optional maxAddress; - for (auto &[address, bytes] : data.value()) { - auto endAddress = (address + bytes.size()) - 1; - m_data.emplace({ address, endAddress }, std::move(bytes)); - - if (endAddress > maxAddress) - maxAddress = endAddress; - } - - if (maxAddress.has_value()) - m_dataSize = *maxAddress + 1; - else - m_dataSize = 0x00; - - m_dataValid = true; + processMemoryRegions(data); return true; }