diff --git a/plugins/builtin/include/content/views/view_data_inspector.hpp b/plugins/builtin/include/content/views/view_data_inspector.hpp index 95989dd40..fd0d9ac63 100644 --- a/plugins/builtin/include/content/views/view_data_inspector.hpp +++ b/plugins/builtin/include/content/views/view_data_inspector.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include #include @@ -67,9 +68,8 @@ namespace hex::plugin::builtin { bool m_reverse = false; ui::VisualizerDrawer m_visualizerDrawer; - u64 m_startAddress = 0; + ImHexApi::HexEditor::ProviderRegion m_selectedRegion; size_t m_validBytes = 0; - prv::Provider *m_selectedProvider = nullptr; std::atomic m_dataValid = false; pl::PatternLanguage m_runtime; diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index 05d468987..de0f16aee 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -525,6 +525,7 @@ "hex.builtin.setting.general.show_tips": "Show tips on startup", "hex.builtin.setting.general.sync_pattern_source": "Sync pattern source code between open data sources", "hex.builtin.setting.general.upload_crash_logs": "Upload crash reports", + "hex.builtin.setting.general.data_inspector_exact_size_only": "Only show data inspector rows that match selection size", "hex.builtin.setting.hex_editor": "Hex Editor", "hex.builtin.setting.hex_editor.byte_padding": "Extra byte cell padding", "hex.builtin.setting.hex_editor.bytes_per_row": "Bytes per row", diff --git a/plugins/builtin/source/content/data_inspector.cpp b/plugins/builtin/source/content/data_inspector.cpp index 3b8159527..a7711865a 100644 --- a/plugins/builtin/source/content/data_inspector.cpp +++ b/plugins/builtin/source/content/data_inspector.cpp @@ -535,7 +535,7 @@ namespace hex::plugin::builtin { constexpr static auto MaxStringLength = 64; - ContentRegistry::DataInspector::add("hex.builtin.inspector.string", 1, + ContentRegistry::DataInspector::add("hex.builtin.inspector.string", 1, 512, [](auto buffer, auto endian, auto style) { std::ignore = buffer; std::ignore = endian; @@ -566,7 +566,7 @@ namespace hex::plugin::builtin { }) ); - ContentRegistry::DataInspector::add("hex.builtin.inspector.wstring", sizeof(wchar_t), + ContentRegistry::DataInspector::add("hex.builtin.inspector.wstring", sizeof(wchar_t), 512, [](auto buffer, auto endian, auto style) { std::ignore = buffer; std::ignore = endian; @@ -612,7 +612,7 @@ namespace hex::plugin::builtin { }) ); - ContentRegistry::DataInspector::add("hex.builtin.inspector.string16", sizeof(char16_t), + ContentRegistry::DataInspector::add("hex.builtin.inspector.string16", sizeof(char16_t), 512, [](auto buffer, auto endian, auto style) { std::ignore = buffer; std::ignore = endian; @@ -658,7 +658,7 @@ namespace hex::plugin::builtin { }) ); - ContentRegistry::DataInspector::add("hex.builtin.inspector.string32", sizeof(char32_t), + ContentRegistry::DataInspector::add("hex.builtin.inspector.string32", sizeof(char32_t), 512, [](auto buffer, auto endian, auto style) { std::ignore = buffer; std::ignore = endian; @@ -704,7 +704,7 @@ namespace hex::plugin::builtin { }) ); - ContentRegistry::DataInspector::add("hex.builtin.inspector.custom_encoding", 1, [encodingFile = EncodingFile()](const std::vector &, std::endian, Style) mutable { + ContentRegistry::DataInspector::add("hex.builtin.inspector.custom_encoding", 1, 512, [encodingFile = EncodingFile()](const std::vector &, std::endian, Style) mutable { std::string value, copyValue; if (encodingFile.valid()) { diff --git a/plugins/builtin/source/content/settings_entries.cpp b/plugins/builtin/source/content/settings_entries.cpp index b32ad40d2..9822b938e 100644 --- a/plugins/builtin/source/content/settings_entries.cpp +++ b/plugins/builtin/source/content/settings_entries.cpp @@ -754,6 +754,8 @@ for (const auto &path : m_paths) { .setTooltip("hex.builtin.setting.general.max_mem_file_size.desc"); ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.patterns", "hex.builtin.setting.general.pattern_data_max_filter_items", 128, 32, 1024); + ContentRegistry::Settings::add("hex.builtin.setting.general", "", "hex.builtin.setting.general.data_inspector_exact_size_only", false); + auto suggestPatterns = ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.patterns", "hex.builtin.setting.general.suggest_patterns", true); ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.patterns", "hex.builtin.setting.general.auto_apply_patterns", false).setEnabledCallback([=] { return static_cast(suggestPatterns.getWidget()).isChecked(); diff --git a/plugins/builtin/source/content/views/view_data_inspector.cpp b/plugins/builtin/source/content/views/view_data_inspector.cpp index 16220286c..c09281e87 100644 --- a/plugins/builtin/source/content/views/view_data_inspector.cpp +++ b/plugins/builtin/source/content/views/view_data_inspector.cpp @@ -26,6 +26,7 @@ namespace hex::plugin::builtin { + static ContentRegistry::Settings::SettingsVariable onlyShowExactSizeMatchEntries = false; using NumberDisplayStyle = ContentRegistry::DataInspector::NumberDisplayStyle; ViewDataInspector::ViewDataInspector() : View::Window("hex.builtin.view.data_inspector.name", ICON_VS_INSPECT) { @@ -34,11 +35,10 @@ namespace hex::plugin::builtin { // Save current selection if (!ImHexApi::Provider::isValid() || region == Region::Invalid()) { m_validBytes = 0; - m_selectedProvider = nullptr; + m_selectedRegion = { Region::Invalid(), nullptr }; } else { m_validBytes = u64((region.getProvider()->getBaseAddress() + region.getProvider()->getActualSize()) - region.address); - m_startAddress = region.address; - m_selectedProvider = region.getProvider(); + m_selectedRegion = region; } // Invalidate inspector rows @@ -46,12 +46,12 @@ namespace hex::plugin::builtin { }); EventDataChanged::subscribe(this, [this](const auto &provider) { - if (provider == m_selectedProvider) + if (provider == m_selectedRegion.getProvider()) m_shouldInvalidate = true; }); EventProviderClosed::subscribe(this, [this](const auto*) { - m_selectedProvider = nullptr; + m_selectedRegion = { Region::Invalid(), nullptr }; }); ContentRegistry::Settings::onChange("hex.builtin.setting.data_inspector", "hex.builtin.setting.data_inspector.hidden_rows", [this](const ContentRegistry::Settings::SettingsValue &value) { @@ -101,17 +101,30 @@ namespace hex::plugin::builtin { void ViewDataInspector::updateInspectorRowsTask() { m_workData.clear(); - if (m_selectedProvider == nullptr) + if (m_selectedRegion.getProvider() == nullptr) return; // Decode bytes using registered inspectors - for (auto &entry : ContentRegistry::DataInspector::impl::getEntries()) { + for (const auto &entry : ContentRegistry::DataInspector::impl::getEntries()) { if (m_validBytes < entry.requiredSize) continue; + // If the setting is enabled, skip all entries that don't match the exact selection size + if (onlyShowExactSizeMatchEntries) { + const auto selectedBytes = m_selectedRegion.getSize(); + + if (entry.requiredSize != entry.maxSize) { + if (selectedBytes < entry.requiredSize || selectedBytes > entry.maxSize) + continue; + } else { + if (selectedBytes != entry.requiredSize) + continue; + } + } + // Try to read as many bytes as requested and possible std::vector buffer(m_validBytes > entry.maxSize ? entry.maxSize : m_validBytes); - m_selectedProvider->read(m_startAddress, buffer.data(), buffer.size()); + m_selectedRegion.getProvider()->read(m_selectedRegion.getStartAddress(), buffer.data(), buffer.size()); preprocessBytes(buffer); @@ -133,7 +146,7 @@ namespace hex::plugin::builtin { } void ViewDataInspector::inspectorReadFunction(u64 offset, u8 *buffer, size_t size) { - m_selectedProvider->read(offset, buffer, size); + m_selectedRegion.getProvider()->read(offset, buffer, size); preprocessBytes({ buffer, size }); } @@ -144,11 +157,13 @@ namespace hex::plugin::builtin { { "numberDisplayStyle", u128(u64(m_numberDisplayStyle)) } }; + const auto provider = m_selectedRegion.getProvider(); + // Setup a new pattern language runtime - ContentRegistry::PatternLanguage::configureRuntime(m_runtime, m_selectedProvider); + ContentRegistry::PatternLanguage::configureRuntime(m_runtime, provider); // Setup the runtime to read from the selected provider - m_runtime.setDataSource(m_selectedProvider->getBaseAddress(), m_selectedProvider->getActualSize(), [this](u64 offset, u8 *buffer, size_t size) { + m_runtime.setDataSource(provider->getBaseAddress(), provider->getActualSize(), [this](u64 offset, u8 *buffer, size_t size) { this->inspectorReadFunction(offset, buffer, size); }); @@ -159,7 +174,7 @@ namespace hex::plugin::builtin { m_runtime.setDefaultEndian(m_endian); // Set start address to the selected address - m_runtime.setStartAddress(m_startAddress); + m_runtime.setStartAddress(m_selectedRegion.getStartAddress()); // Loop over all files in the inspectors folder and execute them for (const auto &folderPath : paths::Inspectors.read()) { @@ -289,14 +304,16 @@ namespace hex::plugin::builtin { u64 requiredSize = selectedEntryIt == m_cachedData.end() ? 0x00 : selectedEntryIt->requiredSize; - bool noData = m_selectedProvider == nullptr || !m_selectedProvider->isReadable() || m_validBytes <= 0; + const auto provider = m_selectedRegion.getProvider(); + + bool noData = provider == nullptr || !provider->isReadable() || m_validBytes <= 0; ImGui::BeginDisabled(noData || !selection.has_value() || !m_selectedEntryName.has_value()); { const auto buttonSizeSmall = ImVec2(ImGui::GetTextLineHeightWithSpacing() * 1.5F, 0); const auto buttonSize = ImVec2((ImGui::GetContentRegionAvail().x / 2) - buttonSizeSmall.x - ImGui::GetStyle().FramePadding.x * 3, 0); - const auto baseAddress = noData ? 0x00 : m_selectedProvider->getBaseAddress(); - const auto providerSize = noData ? 0x00 : m_selectedProvider->getActualSize(); + const auto baseAddress = noData ? 0x00 : provider->getBaseAddress(); + const auto providerSize = noData ? 0x00 : provider->getActualSize(); const auto providerEndAddress = baseAddress + providerSize; ImGui::BeginDisabled(!selection.has_value() || providerSize < requiredSize || selection->getStartAddress() < baseAddress + requiredSize); @@ -338,7 +355,7 @@ namespace hex::plugin::builtin { ImGuiTableColumnFlags_WidthStretch); if (m_tableEditingModeEnabled) - ImGui::TableSetupColumn("##favorite", ImGuiTableColumnFlags_WidthFixed, ImGui::GetTextLineHeight()); + ImGui::TableSetupColumn("##editing", ImGuiTableColumnFlags_WidthFixed, ImGui::GetTextLineHeight()); ImGui::TableHeadersRow(); @@ -476,7 +493,7 @@ namespace hex::plugin::builtin { } // Enter editing mode when double-clicking the row - const bool editable = entry.editingFunction.has_value() && m_selectedProvider->isWritable(); + const bool editable = entry.editingFunction.has_value() && m_selectedRegion.getProvider()->isWritable(); if (ImGui::IsItemHovered()) { if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && editable) { entry.editing = true; @@ -515,7 +532,7 @@ namespace hex::plugin::builtin { preprocessBytes(*bytes); // Write those bytes to the selected provider at the current address - m_selectedProvider->write(m_startAddress, bytes->data(), bytes->size()); + m_selectedRegion.getProvider()->write(m_selectedRegion.getStartAddress(), bytes->data(), bytes->size()); // Disable editing mode m_editingValue.clear();