diff --git a/lib/libimhex/include/hex/pattern_language/pattern_drawer.hpp b/lib/libimhex/include/hex/pattern_language/pattern_drawer.hpp new file mode 100644 index 000000000..69225a0bb --- /dev/null +++ b/lib/libimhex/include/hex/pattern_language/pattern_drawer.hpp @@ -0,0 +1,470 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +namespace { + constexpr static auto DisplayEndDefault = 50u; + constexpr static auto DisplayEndStep = 50u; + + template + concept ArrayPattern = requires(T pattern, std::function fn) { + { pattern.forEachArrayEntry(fn) } -> std::same_as; + }; +}; + +namespace hex::pl { + + class PatternDrawer : public PatternVisitor + { + public: + PatternDrawer() + : m_provider{nullptr} + { } + + void setProvider(prv::Provider *provider) { + m_provider = provider; + } + + void visit(PatternArrayDynamic& pattern) override { + this->drawArray(pattern); + } + + void visit(PatternArrayStatic& pattern) override { + this->drawArray(pattern); + } + + void visit(PatternBitfieldField& pattern) override { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + this->drawNameColumn(pattern); + this->makeSelectable(pattern); + this->drawColorColumn(pattern); + + auto byteAddr = pattern.getOffset() + pattern.getBitOffset() / 8; + auto firstBitIdx = pattern.getBitOffset() % 8; + auto lastBitIdx = firstBitIdx + (pattern.getBitSize() - 1) % 8; + if (firstBitIdx == lastBitIdx) + ImGui::TextFormatted("0x{0:08X} bit {1}", byteAddr, firstBitIdx); + else + ImGui::TextFormatted("0x{0:08X} bits {1} - {2}", byteAddr, firstBitIdx, lastBitIdx); + ImGui::TableNextColumn(); + if (pattern.getBitSize() == 1) + ImGui::TextFormatted("{0} bit", pattern.getBitSize()); + else + ImGui::TextFormatted("{0} bits", pattern.getBitSize()); + ImGui::TableNextColumn(); + ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "bits"); + ImGui::TableNextColumn(); + + u64 extractedValue = pattern.getValue(m_provider); + ImGui::TextFormatted("{}", pattern.formatDisplayValue(hex::format("{0} (0x{1:X})", extractedValue, extractedValue), &pattern)); + } + + void visit(PatternBitfield& pattern) override { + std::vector value = pattern.getValue(m_provider); + + bool open = true; + if (!pattern.isInlined()) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + open = this->createTreeNode(pattern); + ImGui::TableNextColumn(); + this->makeSelectable(pattern); + this->drawCommentTooltip(pattern); + ImGui::TableNextColumn(); + this->drawOffsetColumn(pattern); + this->drawSizeColumn(pattern); + this->drawTypenameColumn(pattern, "bitfield"); + + std::string valueString = "{ "; + for (auto i : value) + valueString += hex::format("{0:02X} ", i); + valueString += "}"; + + ImGui::TextFormatted("{}", pattern.formatDisplayValue(valueString, &pattern)); + } else { + ImGui::SameLine(); + ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf); + } + + if (open) { + pattern.forEachMember([&] (auto &field) { + this->draw(field); + }); + + ImGui::TreePop(); + } + } + + void visit(PatternBoolean& pattern) override { + u8 boolean = pattern.getValue(m_provider); + + if (boolean == 0) + this->createDefaultEntry(pattern, "false", false); + else if (boolean == 1) + this->createDefaultEntry(pattern, "true", true); + else + this->createDefaultEntry(pattern, "true*", true); + } + + void visit(PatternCharacter& pattern) override { + char character = pattern.getValue(m_provider); + this->createDefaultEntry(pattern, hex::format("'{0}'", character), character); + } + + void visit(PatternEnum& pattern) override { + u64 value = pattern.getValue(m_provider); + + std::string valueString = pattern.getTypeName() + "::"; + + bool foundValue = false; + for (auto &[entryValueLiteral, entryName] : pattern.getEnumValues()) { + auto visitor = overloaded { + [&, name = entryName](auto &entryValue) { + if (value == entryValue) { + valueString += name; + foundValue = true; + return true; + } + + return false; + }, + [](const std::string &) { return false; }, + [](Pattern *) { return false; }, + }; + + bool matches = std::visit(visitor, entryValueLiteral); + if (matches) + break; + } + + if (!foundValue) + valueString += "???"; + + ImGui::TableNextRow(); + this->createLeafNode(pattern); + this->drawCommentTooltip(pattern); + ImGui::TableNextColumn(); + this->makeSelectable(pattern); + ImGui::SameLine(); + this->drawNameColumn(pattern); + this->drawColorColumn(pattern); + this->drawOffsetColumn(pattern); + this->drawSizeColumn(pattern); + this->drawTypenameColumn(pattern, "enum"); + ImGui::TextFormatted("{}", pattern.formatDisplayValue(hex::format("{} (0x{:0{}X})", valueString.c_str(), value, pattern.getSize() * 2), &pattern)); + } + + void visit(PatternFloat& pattern) override { + if (pattern.getSize() == 4) { + float f32 = pattern.getValue(m_provider); + u32 data = *reinterpret_cast(&f32); + this->createDefaultEntry(pattern, hex::format("{:e} (0x{:0{}X})", f32, data, pattern.getSize() * 2), f32); + } else if (pattern.getSize() == 8) { + double f64 = pattern.getValue(m_provider); + u64 data = *reinterpret_cast(&f64); + this->createDefaultEntry(pattern, hex::format("{:e} (0x{:0{}X})", f64, data, pattern.getSize() * 2), f64); + } + } + + void visit(PatternPadding& pattern) override { + // Do nothing + } + + void visit(PatternPointer& pattern) override { + u64 data = pattern.getValue(m_provider); + + bool open = true; + + if (!pattern.isInlined()) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + open = this->createTreeNode(pattern); + ImGui::TableNextColumn(); + this->makeSelectable(pattern); + this->drawCommentTooltip(pattern); + ImGui::SameLine(0, 0); + this->drawColorColumn(pattern); + this->drawOffsetColumn(pattern); + this->drawSizeColumn(pattern); + ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{}", pattern.getFormattedName()); + ImGui::TableNextColumn(); + ImGui::TextFormatted("{}", pattern.formatDisplayValue(hex::format("*(0x{0:X})", data), u128(data))); + } else { + ImGui::SameLine(); + ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf); + } + + if (open) { + pattern.getPointedAtPattern()->accept(*this); + + ImGui::TreePop(); + } + } + + void visit(PatternSigned& pattern) override { + i128 data = pattern.getValue(m_provider); + this->createDefaultEntry(pattern, hex::format("{:d} (0x{:0{}X})", data, data, 1 * 2), data); + } + + void visit(PatternString& pattern) override { + auto size = std::min(pattern.getSize(), 0x7F); + + if (size == 0) + return; + + std::string displayString = pattern.getValue(m_provider, size); + this->createDefaultEntry(pattern, hex::format("\"{0}\" {1}", displayString, size > pattern.getSize() ? "(truncated)" : ""), displayString); + } + + void visit(PatternStruct& pattern) override { + bool open = true; + + if (!pattern.isInlined()) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + open = this->createTreeNode(pattern); + ImGui::TableNextColumn(); + this->makeSelectable(pattern); + this->drawCommentTooltip(pattern); + ImGui::TableNextColumn(); + this->drawOffsetColumn(pattern); + this->drawSizeColumn(pattern); + this->drawTypenameColumn(pattern, "struct"); + ImGui::TextFormatted("{}", pattern.formatDisplayValue("{ ... }", &pattern)); + } else { + ImGui::SameLine(); + ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf); + } + + if (open) { + pattern.forEachMember([&](auto &member){ + this->draw(member); + }); + + ImGui::TreePop(); + } + } + + void visit(PatternUnion& pattern) override { + bool open = true; + + if (!pattern.isInlined()) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + open = this->createTreeNode(pattern); + ImGui::TableNextColumn(); + this->makeSelectable(pattern); + this->drawCommentTooltip(pattern); + ImGui::TableNextColumn(); + this->drawOffsetColumn(pattern); + this->drawSizeColumn(pattern); + this->drawTypenameColumn(pattern, "union"); + ImGui::TextFormatted("{}", pattern.formatDisplayValue("{ ... }", &pattern)); + } else { + ImGui::SameLine(); + ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf); + } + + if (open) { + pattern.forEachMember([&](auto &member) { + this->draw(member); + }); + + ImGui::TreePop(); + } + } + + void visit(PatternUnsigned& pattern) override { + u128 data = pattern.getValue(m_provider); + this->createDefaultEntry(pattern, hex::format("{:d} (0x{:0{}X})", data, data, pattern.getSize() * 2), data); + } + + void visit(PatternWideCharacter& pattern) override { + char16_t character = pattern.getValue(m_provider); + u128 literal = character; + auto str = std::wstring_convert, char16_t> {}.to_bytes(character); + this->createDefaultEntry(pattern, hex::format("'{0}'", str), literal); + } + + void visit(PatternWideString& pattern) override { + auto size = std::min(pattern.getSize(), 0x100); + + if (size == 0) + return; + + std::string utf8String = pattern.getValue(m_provider, size); + + this->createDefaultEntry(pattern, hex::format("\"{0}\" {1}", utf8String, size > pattern.getSize() ? "(truncated)" : ""), utf8String); + } + + private: + void createDefaultEntry(const Pattern &pattern, const std::string &value, Token::Literal &&literal) const { + ImGui::TableNextRow(); + this->createLeafNode(pattern); + ImGui::TableNextColumn(); + + ImGui::PushID(pattern.getOffset()); + ImGui::PushID(pattern.getVariableName().c_str()); + this->makeSelectable(pattern); + ImGui::PopID(); + ImGui::PopID(); + + this->drawCommentTooltip(pattern); + ImGui::SameLine(); + this->drawNameColumn(pattern); + this->drawColorColumn(pattern); + this->drawOffsetColumn(pattern); + this->drawSizeColumn(pattern); + ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{}", pattern.getTypeName().empty() ? pattern.getFormattedName() : pattern.getTypeName()); + ImGui::TableNextColumn(); + ImGui::TextFormatted("{}", pattern.formatDisplayValue(value, literal)); + } + + void makeSelectable(const Pattern &pattern) const { + if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(&pattern))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) { + ImHexApi::HexEditor::setSelection(pattern.getOffset(), pattern.getSize()); + } + } + + void drawCommentTooltip(const Pattern &pattern) const { + if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && pattern.getComment().has_value()) { + ImGui::BeginTooltip(); + ImGui::TextUnformatted(pattern.getComment()->c_str()); + ImGui::EndTooltip(); + } + } + + void draw(Pattern& pattern) { + if (pattern.isHidden()) + return; + + pattern.accept(*this); + } + + template + void drawArray(T& pattern) { + if (pattern.getEntryCount() == 0) + return; + + bool open = true; + if (!pattern.isInlined()) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + open = this->createTreeNode(pattern); + ImGui::TableNextColumn(); + if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(&pattern))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) { + ImHexApi::HexEditor::setSelection(pattern.getOffset(), pattern.getSize()); + } + this->drawCommentTooltip(pattern); + ImGui::TableNextColumn(); + this->drawOffsetColumn(pattern); + this->drawSizeColumn(pattern); + ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{0}", pattern.getTypeName()); + ImGui::SameLine(0, 0); + + ImGui::TextUnformatted("["); + ImGui::SameLine(0, 0); + ImGui::TextFormattedColored(ImColor(0xFF00FF00), "{0}", pattern.getEntryCount()); + ImGui::SameLine(0, 0); + ImGui::TextUnformatted("]"); + + ImGui::TableNextColumn(); + ImGui::TextFormatted("{}", pattern.formatDisplayValue("{ ... }", &pattern)); + } else { + ImGui::SameLine(); + ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf); + } + + auto& displayEnd = this->getDisplayEnd(pattern); + if (open) { + pattern.forEachArrayEntry([&] (u64 idx, auto &entry){ + u64 lastVisible = displayEnd - 1; + if (idx < lastVisible) { + this->draw(entry); + } else if (idx == lastVisible) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::Selectable("... (Double-click to see more items)", false, ImGuiSelectableFlags_SpanAllColumns); + if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) + displayEnd += DisplayEndStep; + } + }); + + ImGui::TreePop(); + } else { + displayEnd = DisplayEndDefault; + } + } + + void createLeafNode(const Pattern& pattern) const { + ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_Leaf | + ImGuiTreeNodeFlags_NoTreePushOnOpen | + ImGuiTreeNodeFlags_SpanFullWidth | + ImGuiTreeNodeFlags_AllowItemOverlap); + } + + bool createTreeNode(const Pattern& pattern) const { + return ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); + } + + void drawTypenameColumn(const Pattern& pattern, const std::string& pattern_name) const { + ImGui::TextFormattedColored(ImColor(0xFFD69C56), pattern_name); + ImGui::SameLine(); + ImGui::TextUnformatted(pattern.getTypeName().c_str()); + ImGui::TableNextColumn(); + } + + void drawNameColumn(const Pattern& pattern) const { + ImGui::TextUnformatted(pattern.getDisplayName().c_str()); + ImGui::TableNextColumn(); + } + + void drawColorColumn(const Pattern& pattern) const { + ImGui::ColorButton("color", ImColor(pattern.getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight())); + ImGui::TableNextColumn(); + } + + void drawOffsetColumn(const Pattern& pattern) const { + ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", pattern.getOffset(), pattern.getOffset() + pattern.getSize() - (pattern.getSize() == 0 ? 0 : 1)); + ImGui::TableNextColumn(); + } + + void drawSizeColumn(const Pattern& pattern) const { + ImGui::TextFormatted("0x{0:04X}", pattern.getSize()); + ImGui::TableNextColumn(); + } + + u64& getDisplayEnd(const Pattern& pattern) { + auto it = m_displayEnd.find(&pattern); + if (it != m_displayEnd.end()) { + return it->second; + } + + auto [inserted, success] = m_displayEnd.emplace(&pattern, DisplayEndDefault); + return inserted->second; + } + + private: + prv::Provider *m_provider; + std::map m_displayEnd; + }; +}; \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/pattern_visitor.hpp b/lib/libimhex/include/hex/pattern_language/pattern_visitor.hpp new file mode 100644 index 000000000..602ef19d6 --- /dev/null +++ b/lib/libimhex/include/hex/pattern_language/pattern_visitor.hpp @@ -0,0 +1,44 @@ +#pragma once + +namespace hex::pl { + + class PatternArrayDynamic; + class PatternArrayStatic; + class PatternBitfield; + class PatternBitfieldField; + class PatternBoolean; + class PatternCharacter; + class PatternEnum; + class PatternFloat; + class PatternPadding; + class PatternPointer; + class PatternSigned; + class PatternString; + class PatternStruct; + class PatternUnion; + class PatternUnsigned; + class PatternWideCharacter; + class PatternWideString; + + class PatternVisitor + { + public: + virtual void visit(PatternArrayDynamic& pattern) = 0; + virtual void visit(PatternArrayStatic& pattern) = 0; + virtual void visit(PatternBitfield& pattern) = 0; + virtual void visit(PatternBitfieldField& pattern) = 0; + virtual void visit(PatternBoolean& pattern) = 0; + virtual void visit(PatternCharacter& pattern) = 0; + virtual void visit(PatternEnum& pattern) = 0; + virtual void visit(PatternFloat& pattern) = 0; + virtual void visit(PatternPadding& pattern) = 0; + virtual void visit(PatternPointer& pattern) = 0; + virtual void visit(PatternSigned& pattern) = 0; + virtual void visit(PatternString& pattern) = 0; + virtual void visit(PatternStruct& pattern) = 0; + virtual void visit(PatternUnion& pattern) = 0; + virtual void visit(PatternUnsigned& pattern) = 0; + virtual void visit(PatternWideCharacter& pattern) = 0; + virtual void visit(PatternWideString& pattern) = 0; + }; +}; \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern.hpp index 24fdc5589..0ef77e53b 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include @@ -107,7 +108,6 @@ namespace hex::pl { [[nodiscard]] const auto &getFormatterFunction() const { return this->m_formatterFunction; } void setFormatterFunction(const ContentRegistry::PatternLanguage::Function &function) { this->m_formatterFunction = function; } - virtual void createEntry(prv::Provider *&provider) = 0; [[nodiscard]] virtual std::string getFormattedName() const = 0; [[nodiscard]] virtual const Pattern *getPattern(u64 offset) const { @@ -179,12 +179,6 @@ namespace hex::pl { return false; } - void draw(prv::Provider *provider) { - if (isHidden()) return; - - this->createEntry(provider); - } - void setHidden(bool hidden) { this->m_hidden = hidden; } @@ -250,42 +244,7 @@ namespace hex::pl { this->m_cachedDisplayValue.reset(); } - protected: - void createDefaultEntry(const std::string &value, Token::Literal &&literal) const { - ImGui::TableNextRow(); - ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap); - ImGui::TableNextColumn(); - - ImGui::PushID(this->getOffset()); - ImGui::PushID(this->getVariableName().c_str()); - if (ImGui::Selectable("##PatternLine", false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) { - ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize()); - } - ImGui::PopID(); - ImGui::PopID(); - - this->drawCommentTooltip(); - ImGui::SameLine(); - ImGui::TextUnformatted(this->getDisplayName().c_str()); - ImGui::TableNextColumn(); - ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight())); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), this->getOffset() + this->getSize() - 1); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:04X}", this->getSize()); - ImGui::TableNextColumn(); - ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{}", this->getTypeName().empty() ? this->getFormattedName() : this->getTypeName()); - ImGui::TableNextColumn(); - ImGui::TextFormatted("{}", formatDisplayValue(value, literal)); - } - - void drawCommentTooltip() const { - if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && this->getComment().has_value()) { - ImGui::BeginTooltip(); - ImGui::TextUnformatted(this->getComment()->c_str()); - ImGui::EndTooltip(); - } - } + virtual void accept(PatternVisitor &v) = 0; protected: std::optional m_endian; diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_array_dynamic.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_array_dynamic.hpp index f90cd121a..6f7333262 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_array_dynamic.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_array_dynamic.hpp @@ -29,63 +29,6 @@ namespace hex::pl { entry->setColor(color); } - void createEntry(prv::Provider *&provider) override { - if (this->m_entries.empty()) - return; - - bool open = true; - if (!this->isInlined()) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); - ImGui::TableNextColumn(); - if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(this))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) { - ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize()); - } - this->drawCommentTooltip(); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), this->getOffset() + this->getSize() - 1); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:04X}", this->getSize()); - ImGui::TableNextColumn(); - ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{0}", this->m_entries[0]->getTypeName()); - ImGui::SameLine(0, 0); - - ImGui::TextUnformatted("["); - ImGui::SameLine(0, 0); - ImGui::TextFormattedColored(ImColor(0xFF00FF00), "{0}", this->m_entries.size()); - ImGui::SameLine(0, 0); - ImGui::TextUnformatted("]"); - - ImGui::TableNextColumn(); - ImGui::TextFormatted("{}", this->formatDisplayValue("{ ... }", this)); - } else { - ImGui::SameLine(); - ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf); - } - - if (open) { - for (u64 i = 0; i < this->m_entries.size(); i++) { - this->m_entries[i]->draw(provider); - - if (i >= (this->m_displayEnd - 1)) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - - ImGui::Selectable("... (Double-click to see more items)", false, ImGuiSelectableFlags_SpanAllColumns); - if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) - this->m_displayEnd += 50; - - break; - } - } - - ImGui::TreePop(); - } else { - this->m_displayEnd = 50; - } - } - void getHighlightedAddresses(std::map &highlight) const override { for (auto &entry : this->m_entries) { entry->getHighlightedAddresses(highlight); @@ -96,6 +39,10 @@ namespace hex::pl { return this->m_entries[0]->getTypeName() + "[" + std::to_string(this->m_entries.size()) + "]"; } + [[nodiscard]] std::string getTypeName() const { + return this->m_entries[0]->getTypeName(); + } + void setOffset(u64 offset) override { for (auto &entry : this->m_entries) entry->setOffset(entry->getOffset() - this->getOffset() + offset); @@ -103,10 +50,19 @@ namespace hex::pl { Pattern::setOffset(offset); } + [[nodiscard]] size_t getEntryCount() const { + return this->m_entries.size(); + } + [[nodiscard]] const auto &getEntries() { return this->m_entries; } + void forEachArrayEntry(const std::function& fn) { + for (u64 i = 0; i < this->m_entries.size(); i++) + fn(i, *this->m_entries[i]); + } + void setEntries(std::vector> &&entries) { this->m_entries = std::move(entries); @@ -151,9 +107,12 @@ namespace hex::pl { Pattern::setEndian(endian); } + void accept(PatternVisitor &v) override { + v.visit(*this); + } + private: std::vector> m_entries; - u64 m_displayEnd = 50; }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_array_static.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_array_static.hpp index 48e973a51..e2c040d2a 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_array_static.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_array_static.hpp @@ -19,65 +19,12 @@ namespace hex::pl { return std::unique_ptr(new PatternArrayStatic(*this)); } - void createEntry(prv::Provider *&provider) override { - if (this->getEntryCount() == 0) - return; - - bool open = true; - - if (!this->isInlined()) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); - ImGui::TableNextColumn(); - if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(this))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) { - ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize()); - } - this->drawCommentTooltip(); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), this->getOffset() + this->getSize() - 1); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:04X}", this->getSize()); - ImGui::TableNextColumn(); - ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{0}", this->m_template->getTypeName().c_str()); - ImGui::SameLine(0, 0); - - ImGui::TextUnformatted("["); - ImGui::SameLine(0, 0); - ImGui::TextFormattedColored(ImColor(0xFF00FF00), "{0}", this->m_entryCount); - ImGui::SameLine(0, 0); - ImGui::TextUnformatted("]"); - - ImGui::TableNextColumn(); - ImGui::TextFormatted("{}", this->formatDisplayValue("{ ... }", this)); - } else { - ImGui::SameLine(); - ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf); - } - - if (open) { - auto entry = this->m_template->clone(); - for (u64 index = 0; index < this->m_entryCount; index++) { - entry->clearFormatCache(); - entry->setVariableName(hex::format("[{0}]", index)); - entry->setOffset(this->getOffset() + index * this->m_template->getSize()); - entry->draw(provider); - - if (index >= (this->m_displayEnd - 1)) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - - ImGui::Selectable("... (Double-click to see more items)", false, ImGuiSelectableFlags_SpanAllColumns); - if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) - this->m_displayEnd += 50; - - break; - } - } - - ImGui::TreePop(); - } else { - this->m_displayEnd = 50; + void forEachArrayEntry(const std::function& fn) { + auto entry = std::shared_ptr(this->m_template->clone()); + for (u64 index = 0; index < this->m_entryCount; index++) { + entry->setVariableName(hex::format("[{0}]", index)); + entry->setOffset(this->getOffset() + index * this->m_template->getSize()); + fn(index, *entry); } } @@ -105,6 +52,10 @@ namespace hex::pl { return this->m_template->getTypeName() + "[" + std::to_string(this->m_entryCount) + "]"; } + [[nodiscard]] std::string getTypeName() const { + return this->m_template->getTypeName(); + } + [[nodiscard]] const std::shared_ptr &getTemplate() const { return this->m_template; } @@ -155,11 +106,14 @@ namespace hex::pl { Pattern::setEndian(endian); } + void accept(PatternVisitor &v) override { + v.visit(*this); + } + private: std::shared_ptr m_template = nullptr; mutable std::unique_ptr m_highlightTemplate = nullptr; size_t m_entryCount = 0; - u64 m_displayEnd = 50; }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_bitfield.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_bitfield.hpp index 71050d22e..4a3fd4148 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_bitfield.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_bitfield.hpp @@ -14,41 +14,16 @@ namespace hex::pl { return std::unique_ptr(new PatternBitfieldField(*this)); } - void createEntry(prv::Provider *&provider) override { + u64 getValue(prv::Provider *&provider) { std::vector value(this->m_bitField->getSize(), 0); provider->read(this->m_bitField->getOffset(), &value[0], value.size()); if (this->m_bitField->getEndian() != std::endian::native) std::reverse(value.begin(), value.end()); - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextUnformatted(this->getDisplayName().c_str()); - ImGui::SameLine(); - if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(this))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) { - ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize()); - } - ImGui::TableNextColumn(); - ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight())); - ImGui::TableNextColumn(); - if (this->m_bitSize == 1) - ImGui::TextFormatted("0x{0:08X} bit {1}", this->getOffset() + this->m_bitOffset / 8, (this->m_bitOffset + (this->m_bitSize - 1)) % 8); - else - ImGui::TextFormatted("0x{0:08X} bits {1} - {2}", this->getOffset() + this->m_bitOffset / 8, this->m_bitOffset % 8, this->m_bitOffset % 8 + (this->m_bitSize - 1) % 8); - ImGui::TableNextColumn(); - if (this->m_bitSize == 1) - ImGui::TextFormatted("{0} bit", this->m_bitSize); - else - ImGui::TextFormatted("{0} bits", this->m_bitSize); - ImGui::TableNextColumn(); - ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "bits"); - ImGui::TableNextColumn(); - { - u8 numBytes = (this->m_bitSize / 8) + 1; + u8 numBytes = (this->m_bitSize / 8) + 1; - u64 extractedValue = hex::extract(this->m_bitOffset + (this->m_bitSize - 1), this->m_bitOffset, value); - ImGui::TextFormatted("{}", this->formatDisplayValue(hex::format("{0} (0x{1:X})", extractedValue, extractedValue), this)); - } + return hex::extract(this->m_bitOffset + (this->m_bitSize - 1), this->m_bitOffset, value); } [[nodiscard]] std::string getFormattedName() const override { @@ -71,6 +46,10 @@ namespace hex::pl { return this->m_bitOffset == otherBitfieldField.m_bitOffset && this->m_bitSize == otherBitfieldField.m_bitSize; } + void accept(PatternVisitor &v) override { + v.visit(*this); + } + private: u8 m_bitOffset, m_bitSize; Pattern *m_bitField; @@ -92,52 +71,19 @@ namespace hex::pl { return std::unique_ptr(new PatternBitfield(*this)); } - void createEntry(prv::Provider *&provider) override { + std::vector getValue(prv::Provider *&provider) const { std::vector value(this->getSize(), 0); provider->read(this->getOffset(), &value[0], value.size()); - if (this->m_endian == std::endian::little) + if (this->getEndian() == std::endian::little) std::reverse(value.begin(), value.end()); - bool open = true; - if (!this->isInlined()) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); - ImGui::TableNextColumn(); - if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(this))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) { - ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize()); - } - this->drawCommentTooltip(); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), this->getOffset() + this->getSize() - 1); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:04X}", this->getSize()); - ImGui::TableNextColumn(); - ImGui::TextFormattedColored(ImColor(0xFFD69C56), "bitfield"); - ImGui::SameLine(); - ImGui::TextUnformatted(Pattern::getTypeName().c_str()); - ImGui::TableNextColumn(); - - std::string valueString = "{ "; - for (auto i : value) - valueString += hex::format("{0:02X} ", i); - valueString += "}"; - - ImGui::TextFormatted("{}", this->formatDisplayValue(valueString, this)); - } else { - ImGui::SameLine(); - ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf); - } - - if (open) { - - for (auto &field : this->m_fields) - field->draw(provider); - - ImGui::TreePop(); - } + return value; + } + void forEachMember(const std::function& fn) { + for (auto &field : this->m_fields) + fn(*field); } void setOffset(u64 offset) override { @@ -186,6 +132,10 @@ namespace hex::pl { return true; } + void accept(PatternVisitor &v) override { + v.visit(*this); + } + private: std::vector> m_fields; }; diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_boolean.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_boolean.hpp index 70a65f92c..271b4f58f 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_boolean.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_boolean.hpp @@ -13,16 +13,10 @@ namespace hex::pl { return std::unique_ptr(new PatternBoolean(*this)); } - void createEntry(prv::Provider *&provider) override { + u8 getValue(prv::Provider *&provider) { u8 boolean; provider->read(this->getOffset(), &boolean, 1); - - if (boolean == 0) - this->createDefaultEntry("false", false); - else if (boolean == 1) - this->createDefaultEntry("true", true); - else - this->createDefaultEntry("true*", true); + return boolean; } [[nodiscard]] std::string getFormattedName() const override { @@ -30,6 +24,10 @@ namespace hex::pl { } [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } + + void accept(PatternVisitor &v) override { + v.visit(*this); + } }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_character.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_character.hpp index ceade03eb..2ac1cb33b 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_character.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_character.hpp @@ -13,11 +13,10 @@ namespace hex::pl { return std::unique_ptr(new PatternCharacter(*this)); } - void createEntry(prv::Provider *&provider) override { + char getValue(prv::Provider *&provider) { char character; provider->read(this->getOffset(), &character, 1); - - this->createDefaultEntry(hex::format("'{0}'", character), character); + return character; } [[nodiscard]] std::string getFormattedName() const override { @@ -25,6 +24,10 @@ namespace hex::pl { } [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } + + void accept(PatternVisitor &v) override { + v.visit(*this); + } }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_enum.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_enum.hpp index 1a0dfe343..609a14113 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_enum.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_enum.hpp @@ -14,66 +14,28 @@ namespace hex::pl { return std::unique_ptr(new PatternEnum(*this)); } - void createEntry(prv::Provider *&provider) override { + u64 getValue(prv::Provider *&provider) { u64 value = 0; provider->read(this->getOffset(), &value, this->getSize()); - value = hex::changeEndianess(value, this->getSize(), this->getEndian()); - - std::string valueString = Pattern::getTypeName() + "::"; - - bool foundValue = false; - for (auto &[entryValueLiteral, entryName] : this->m_enumValues) { - bool matches = std::visit(overloaded { - [&, name = entryName](auto &&entryValue) { - if (value == entryValue) { - valueString += name; - foundValue = true; - return true; - } - - return false; - }, - [](std::string &) { return false; }, - [](Pattern *) { return false; } }, - entryValueLiteral); - if (matches) - break; - } - - if (!foundValue) - valueString += "???"; - - ImGui::TableNextRow(); - ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap); - this->drawCommentTooltip(); - ImGui::TableNextColumn(); - if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(this))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) { - ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize()); - } - ImGui::SameLine(); - ImGui::TextUnformatted(this->getDisplayName().c_str()); - ImGui::TableNextColumn(); - ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight())); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), this->getOffset() + this->getSize() - 1); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:04X}", this->getSize()); - ImGui::TableNextColumn(); - ImGui::TextFormattedColored(ImColor(0xFFD69C56), "enum"); - ImGui::SameLine(); - ImGui::TextUnformatted(Pattern::getTypeName().c_str()); - ImGui::TableNextColumn(); - ImGui::TextFormatted("{}", this->formatDisplayValue(hex::format("{} (0x{:0{}X})", valueString.c_str(), value, this->getSize() * 2), this)); + return hex::changeEndianess(value, this->getSize(), this->getEndian()); } [[nodiscard]] std::string getFormattedName() const override { return "enum " + Pattern::getTypeName(); } + [[nodiscard]] std::string getTypeName() const { + return Pattern::getTypeName(); + } + void setEnumValues(const std::vector> &enumValues) { this->m_enumValues = enumValues; } + const auto& getEnumValues() const { + return this->m_enumValues; + } + [[nodiscard]] bool operator==(const Pattern &other) const override { if (!areCommonPropertiesEqual(other)) return false; @@ -90,6 +52,10 @@ namespace hex::pl { return true; } + void accept(PatternVisitor &v) override { + v.visit(*this); + } + private: std::vector> m_enumValues; }; diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_float.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_float.hpp index b00e3d15c..2cd7d3848 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_float.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_float.hpp @@ -13,19 +13,20 @@ namespace hex::pl { return std::unique_ptr(new PatternFloat(*this)); } - void createEntry(prv::Provider *&provider) override { + double getValue(prv::Provider *&provider) { if (this->getSize() == 4) { u32 data = 0; provider->read(this->getOffset(), &data, 4); data = hex::changeEndianess(data, 4, this->getEndian()); - - this->createDefaultEntry(hex::format("{:e} (0x{:0{}X})", *reinterpret_cast(&data), data, this->getSize() * 2), *reinterpret_cast(&data)); + return *reinterpret_cast(&data); } else if (this->getSize() == 8) { u64 data = 0; provider->read(this->getOffset(), &data, 8); data = hex::changeEndianess(data, 8, this->getEndian()); - - this->createDefaultEntry(hex::format("{:e} (0x{:0{}X})", *reinterpret_cast(&data), data, this->getSize() * 2), *reinterpret_cast(&data)); + return *reinterpret_cast(&data); + } else { + assert(false); + return std::numeric_limits::quiet_NaN(); } } @@ -41,6 +42,10 @@ namespace hex::pl { } [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } + + void accept(PatternVisitor &v) override { + v.visit(*this); + } }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_padding.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_padding.hpp index 534f0c879..033d25143 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_padding.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_padding.hpp @@ -12,14 +12,15 @@ namespace hex::pl { return std::unique_ptr(new PatternPadding(*this)); } - void createEntry(prv::Provider *&provider) override { - } - [[nodiscard]] std::string getFormattedName() const override { return ""; } [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } + + void accept(PatternVisitor &v) override { + v.visit(*this); + } }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_pointer.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_pointer.hpp index 4213d1474..3ad94a652 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_pointer.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_pointer.hpp @@ -19,42 +19,10 @@ namespace hex::pl { return std::unique_ptr(new PatternPointer(*this)); } - void createEntry(prv::Provider *&provider) override { + u64 getValue(prv::Provider *&provider) { u64 data = 0; provider->read(this->getOffset(), &data, this->getSize()); - data = hex::changeEndianess(data, this->getSize(), this->getEndian()); - - bool open = true; - - if (!this->isInlined()) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); - ImGui::TableNextColumn(); - if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(this))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) { - ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize()); - } - this->drawCommentTooltip(); - ImGui::SameLine(0, 0); - ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight())); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), this->getOffset() + this->getSize() - 1); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:04X}", this->getSize()); - ImGui::TableNextColumn(); - ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{}", this->getFormattedName()); - ImGui::TableNextColumn(); - ImGui::TextFormatted("{}", formatDisplayValue(hex::format("*(0x{0:X})", data), u128(data))); - } else { - ImGui::SameLine(); - ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf); - } - - if (open) { - this->m_pointedAt->createEntry(provider); - - ImGui::TreePop(); - } + return hex::changeEndianess(data, this->getSize(), this->getEndian()); } void getHighlightedAddresses(std::map &highlight) const override { @@ -135,6 +103,10 @@ namespace hex::pl { Pattern::setEndian(endian); } + void accept(PatternVisitor &v) override { + v.visit(*this); + } + private: std::unique_ptr m_pointedAt; u64 m_pointedAtAddress = 0; diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_signed.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_signed.hpp index 570a8963e..7f46b84e4 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_signed.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_signed.hpp @@ -13,13 +13,12 @@ namespace hex::pl { return std::unique_ptr(new PatternSigned(*this)); } - void createEntry(prv::Provider *&provider) override { + i128 getValue(prv::Provider *&provider) { i128 data = 0; provider->read(this->getOffset(), &data, this->getSize()); data = hex::changeEndianess(data, this->getSize(), this->getEndian()); - data = hex::signExtend(this->getSize() * 8, data); - this->createDefaultEntry(hex::format("{:d} (0x{:0{}X})", data, data, 1 * 2), data); + return hex::signExtend(this->getSize() * 8, data); } [[nodiscard]] std::string getFormattedName() const override { @@ -40,6 +39,10 @@ namespace hex::pl { } [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } + + void accept(PatternVisitor &v) override { + v.visit(*this); + } }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_string.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_string.hpp index ebecfa17f..e3b23adae 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_string.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_string.hpp @@ -13,17 +13,14 @@ namespace hex::pl { return std::unique_ptr(new PatternString(*this)); } - void createEntry(prv::Provider *&provider) override { - auto size = std::min(this->getSize(), 0x7F); - - if (size == 0) - return; + std::string getValue(prv::Provider *&provider) { + return this->getValue(provider, this->getSize()); + } + std::string getValue(prv::Provider *&provider, size_t size) { std::vector buffer(size, 0x00); provider->read(this->getOffset(), buffer.data(), size); - - auto displayString = hex::encodeByteString(buffer); - this->createDefaultEntry(hex::format("\"{0}\" {1}", displayString, size > this->getSize() ? "(truncated)" : ""), displayString); + return hex::encodeByteString(buffer); } [[nodiscard]] std::string getFormattedName() const override { @@ -42,6 +39,10 @@ namespace hex::pl { } [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } + + void accept(PatternVisitor &v) override { + v.visit(*this); + } }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_struct.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_struct.hpp index 85cb47001..bfbf80e87 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_struct.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_struct.hpp @@ -24,47 +24,17 @@ namespace hex::pl { return std::unique_ptr(new PatternStruct(*this)); } - void createEntry(prv::Provider *&provider) override { - bool open = true; - - if (!this->isInlined()) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); - ImGui::TableNextColumn(); - if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(this))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) { - ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize()); - } - this->drawCommentTooltip(); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), this->getOffset() + this->getSize() - (this->getSize() == 0 ? 0 : 1)); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:04X}", this->getSize()); - ImGui::TableNextColumn(); - ImGui::TextFormattedColored(ImColor(0xFFD69C56), "struct"); - ImGui::SameLine(); - ImGui::TextUnformatted(this->getTypeName().c_str()); - ImGui::TableNextColumn(); - ImGui::TextFormatted("{}", this->formatDisplayValue("{ ... }", this)); - } else { - ImGui::SameLine(); - ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf); - } - - if (open) { - for (auto &member : this->m_sortedMembers) - member->draw(provider); - - ImGui::TreePop(); - } - } - void getHighlightedAddresses(std::map &highlight) const override { for (auto &member : this->m_members) { member->getHighlightedAddresses(highlight); } } + void forEachMember(const std::function& fn) { + for (auto &member : this->m_sortedMembers) + fn(*member); + } + void setOffset(u64 offset) override { for (auto &member : this->m_members) member->setOffset(member->getOffset() - this->getOffset() + offset); @@ -151,6 +121,10 @@ namespace hex::pl { Pattern::setEndian(endian); } + void accept(PatternVisitor &v) override { + v.visit(*this); + } + private: std::vector> m_members; std::vector m_sortedMembers; diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_union.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_union.hpp index dc2b10c7c..963cd01d2 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_union.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_union.hpp @@ -24,40 +24,9 @@ namespace hex::pl { return std::unique_ptr(new PatternUnion(*this)); } - void createEntry(prv::Provider *&provider) override { - bool open = true; - - if (!this->isInlined()) { - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth); - ImGui::TableNextColumn(); - if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(this))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) { - ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize()); - } - this->drawCommentTooltip(); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), std::max(this->getOffset() + this->getSize() - (this->getSize() == 0 ? 0 : 1), u64(0))); - ImGui::TableNextColumn(); - ImGui::TextFormatted("0x{0:04X}", this->getSize()); - ImGui::TableNextColumn(); - ImGui::TextFormattedColored(ImColor(0xFFD69C56), "union"); - ImGui::SameLine(); - ImGui::TextUnformatted(Pattern::getTypeName().c_str()); - - ImGui::TableNextColumn(); - ImGui::TextFormatted("{}", this->formatDisplayValue("{ ... }", this)); - } else { - ImGui::SameLine(); - ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf); - } - - if (open) { - for (auto &member : this->m_sortedMembers) - member->draw(provider); - - ImGui::TreePop(); - } + void forEachMember(const std::function& fn) { + for (auto &member : this->m_sortedMembers) + fn(*member); } void getHighlightedAddresses(std::map &highlight) const override { @@ -96,7 +65,10 @@ namespace hex::pl { [[nodiscard]] std::string getFormattedName() const override { return "union " + Pattern::getTypeName(); - ; + } + + [[nodiscard]] std::string getTypeName() const { + return Pattern::getTypeName(); } [[nodiscard]] const auto &getMembers() const { @@ -152,6 +124,10 @@ namespace hex::pl { Pattern::setEndian(endian); } + void accept(PatternVisitor &v) override { + v.visit(*this); + } + private: std::vector> m_members; std::vector m_sortedMembers; diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_unsigned.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_unsigned.hpp index 6ad941ce2..098733407 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_unsigned.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_unsigned.hpp @@ -13,12 +13,10 @@ namespace hex::pl { return std::unique_ptr(new PatternUnsigned(*this)); } - void createEntry(prv::Provider *&provider) override { + u128 getValue(prv::Provider *&provider) { u128 data = 0; provider->read(this->getOffset(), &data, this->getSize()); - data = hex::changeEndianess(data, this->getSize(), this->getEndian()); - - this->createDefaultEntry(hex::format("{:d} (0x{:0{}X})", data, data, this->getSize() * 2), data); + return hex::changeEndianess(data, this->getSize(), this->getEndian()); } [[nodiscard]] std::string getFormattedName() const override { @@ -39,6 +37,10 @@ namespace hex::pl { } [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } + + void accept(PatternVisitor &v) override { + v.visit(*this); + } }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_wide_character.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_wide_character.hpp index 13c5d322a..2e224b0c7 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_wide_character.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_wide_character.hpp @@ -15,13 +15,10 @@ namespace hex::pl { return std::unique_ptr(new PatternWideCharacter(*this)); } - void createEntry(prv::Provider *&provider) override { + char16_t getValue(prv::Provider *&provider) { char16_t character; provider->read(this->getOffset(), &character, 2); - character = hex::changeEndianess(character, this->getEndian()); - - u128 literal = character; - this->createDefaultEntry(hex::format("'{0}'", std::wstring_convert, char16_t> {}.to_bytes(character)), literal); + return hex::changeEndianess(character, this->getEndian()); } [[nodiscard]] std::string getFormattedName() const override { @@ -37,6 +34,10 @@ namespace hex::pl { } [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } + + void accept(PatternVisitor &v) override { + v.visit(*this); + } }; } \ No newline at end of file diff --git a/lib/libimhex/include/hex/pattern_language/patterns/pattern_wide_string.hpp b/lib/libimhex/include/hex/pattern_language/patterns/pattern_wide_string.hpp index 8ebae7a6f..3754e97e0 100644 --- a/lib/libimhex/include/hex/pattern_language/patterns/pattern_wide_string.hpp +++ b/lib/libimhex/include/hex/pattern_language/patterns/pattern_wide_string.hpp @@ -15,26 +15,22 @@ namespace hex::pl { return std::unique_ptr(new PatternWideString(*this)); } - void createEntry(prv::Provider *&provider) override { - auto size = std::min(this->getSize(), 0x100); - - if (size == 0) - return; + std::string getValue(prv::Provider *&provider) { + return this->getValue(provider, this->getSize()); + } + std::string getValue(prv::Provider *&provider, size_t size) { std::u16string buffer(this->getSize() / sizeof(char16_t), 0x00); provider->read(this->getOffset(), buffer.data(), size); for (auto &c : buffer) c = hex::changeEndianess(c, 2, this->getEndian()); - buffer.erase(std::remove_if(buffer.begin(), buffer.end(), [](auto c) { - return c == 0x00; - }), - buffer.end()); + auto it = std::remove_if(buffer.begin(), buffer.end(), + [](auto c) { return c == 0x00; }); + buffer.erase(it, buffer.end()); - auto utf8String = std::wstring_convert, char16_t> {}.to_bytes(buffer); - - this->createDefaultEntry(hex::format("\"{0}\" {1}", utf8String, size > this->getSize() ? "(truncated)" : ""), utf8String); + return std::wstring_convert, char16_t> {}.to_bytes(buffer); } [[nodiscard]] std::string getFormattedName() const override { @@ -56,6 +52,10 @@ namespace hex::pl { } [[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual(other); } + + void accept(PatternVisitor &v) override { + v.visit(*this); + } }; } \ No newline at end of file diff --git a/plugins/builtin/include/content/views/view_pattern_data.hpp b/plugins/builtin/include/content/views/view_pattern_data.hpp index 60ea27957..284761e64 100644 --- a/plugins/builtin/include/content/views/view_pattern_data.hpp +++ b/plugins/builtin/include/content/views/view_pattern_data.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -20,6 +21,7 @@ namespace hex::plugin::builtin { private: std::map>> m_sortedPatterns; + hex::pl::PatternDrawer m_drawer; }; } \ No newline at end of file diff --git a/plugins/builtin/source/content/views/view_pattern_data.cpp b/plugins/builtin/source/content/views/view_pattern_data.cpp index 8c66ff241..c1ca90ce2 100644 --- a/plugins/builtin/source/content/views/view_pattern_data.cpp +++ b/plugins/builtin/source/content/views/view_pattern_data.cpp @@ -61,8 +61,9 @@ namespace hex::plugin::builtin { ImGui::TableHeadersRow(); if (!sortedPatterns.empty()) { + m_drawer.setProvider(provider); for (auto &patterns : sortedPatterns) - patterns->draw(provider); + patterns->accept(m_drawer); } ImGui::EndTable();