1
0
mirror of synced 2025-02-17 18:59:21 +01:00

patterns: Add optimization for arrays of statically sized types

This commit is contained in:
WerWolv 2021-09-06 20:35:38 +02:00
parent 6879cf765f
commit ee7c6a91a7
13 changed files with 330 additions and 65 deletions

View File

@ -4,7 +4,6 @@
#include <hex/views/view.hpp>
#include <imgui.h>
#include <hex/lang/pattern_data.hpp>
#include <vector>
#include <tuple>

View File

@ -4,7 +4,6 @@
#include <imgui.h>
#include <hex/views/view.hpp>
#include <hex/lang/pattern_data.hpp>
#include <vector>
#include <tuple>

View File

@ -10,8 +10,6 @@
#include <random>
#include <vector>
#include <hex/lang/pattern_data.hpp>
namespace hex {
namespace prv { class Provider; }

View File

@ -4,7 +4,6 @@
#include <imgui.h>
#include <hex/views/view.hpp>
#include <hex/lang/pattern_data.hpp>
#include <vector>
#include <tuple>
@ -13,6 +12,7 @@
namespace hex {
namespace prv { class Provider; }
namespace lang { class PatternData; }
class ViewPatternData : public View {
public:

View File

@ -82,6 +82,8 @@ namespace hex::lang {
PatternData* evaluateType(ASTNodeTypeDecl *node);
PatternData* evaluateVariable(ASTNodeVariableDecl *node);
PatternData* evaluateArray(ASTNodeArrayVariableDecl *node);
PatternData* evaluateStaticArray(ASTNodeArrayVariableDecl *node);
PatternData* evaluateDynamicArray(ASTNodeArrayVariableDecl *node);
PatternData* evaluatePointer(ASTNodePointerVariableDecl *node);
};

View File

@ -55,12 +55,15 @@ namespace hex::lang {
if (SharedData::patternPaletteOffset >= (sizeof(Palette) / sizeof(u32)))
SharedData::patternPaletteOffset = 0;
}
PatternData(const PatternData &other) = default;
virtual ~PatternData() = default;
virtual PatternData* clone() = 0;
[[nodiscard]] u64 getOffset() const { return this->m_offset; }
void setOffset(u64 offset) { this->m_offset = offset; }
virtual void setOffset(u64 offset) { this->m_offset = offset; }
[[nodiscard]] size_t getSize() const { return this->m_size; }
void setSize(size_t size) { this->m_size = size; }
@ -104,6 +107,10 @@ namespace hex::lang {
return this->m_highlightedAddresses;
}
virtual void clearHighlightedAddresses() {
this->m_highlightedAddresses.clear();
}
virtual void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) { }
static bool sortPatternDataTable(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider, lang::PatternData* left, lang::PatternData* right) {
@ -253,7 +260,7 @@ namespace hex::lang {
: PatternData(offset, size, color), m_pointedAt(nullptr) {
}
PatternDataPointer(const PatternDataPointer &other) : PatternData(other.getOffset(), other.getSize(), other.getColor()) {
PatternDataPointer(const PatternDataPointer &other) : PatternData(other) {
this->m_pointedAt = other.m_pointedAt->clone();
}
@ -577,13 +584,13 @@ namespace hex::lang {
}
};
class PatternDataArray : public PatternData {
class PatternDataDynamicArray : public PatternData {
public:
PatternDataArray(u64 offset, size_t size, u32 color = 0)
PatternDataDynamicArray(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) {
}
PatternDataArray(const PatternDataArray &other) : PatternData(other.getOffset(), other.getSize(), other.getColor()) {
PatternDataDynamicArray(const PatternDataDynamicArray &other) : PatternData(other) {
std::vector<PatternData*> entries;
for (const auto &entry : other.m_entries)
entries.push_back(entry->clone());
@ -591,13 +598,21 @@ namespace hex::lang {
this->setEntries(entries);
}
~PatternDataArray() override {
~PatternDataDynamicArray() override {
for (const auto &entry : this->m_entries)
delete entry;
}
PatternData* clone() override {
return new PatternDataArray(*this);
return new PatternDataDynamicArray(*this);
}
void setOffset(u64 offset) override {
for (auto &entry : this->m_entries) {
entry->setOffset(offset + (entry->getOffset() - this->getOffset()));
}
PatternData::setOffset(offset);
}
void createEntry(prv::Provider* &provider) override {
@ -654,6 +669,12 @@ namespace hex::lang {
return this->m_highlightedAddresses;
}
void clearHighlightedAddresses() override {
for (auto &entry : this->m_entries)
entry->clearHighlightedAddresses();
PatternData::clearHighlightedAddresses();
}
[[nodiscard]] std::string getFormattedName() const override {
return this->m_entries[0]->getTypeName() + "[" + std::to_string(this->m_entries.size()) + "]";
}
@ -675,14 +696,137 @@ namespace hex::lang {
std::vector<PatternData*> m_entries;
};
class PatternDataStaticArray : public PatternData {
public:
PatternDataStaticArray(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) {
}
PatternDataStaticArray(const PatternDataStaticArray &other) : PatternData(other) {
this->setEntries(other.getTemplate()->clone(), other.getEntryCount());
}
~PatternDataStaticArray() override {
delete this->m_template;
}
PatternData* clone() override {
return new PatternDataStaticArray(*this);
}
void createEntry(prv::Provider* &provider) override {
if (this->getEntryCount() == 0)
return;
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
this->drawCommentTooltip();
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
ImGui::TableNextColumn();
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04llX", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->m_template->getTypeName().c_str());
ImGui::SameLine(0, 0);
ImGui::TextUnformatted("[");
ImGui::SameLine(0, 0);
ImGui::TextColored(ImColor(0xFF00FF00), "%llu", this->m_entryCount);
ImGui::SameLine(0, 0);
ImGui::TextUnformatted("]");
ImGui::TableNextColumn();
ImGui::Text("%s", "{ ... }");
if (open) {
auto entry = 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());
entry->draw(provider);
}
delete entry;
ImGui::TreePop();
}
}
std::optional<u32> highlightBytes(size_t offset) override{
auto entry = this->m_template->clone();
for (u64 address = this->getOffset(); address < this->getOffset() + this->getSize(); address += this->m_template->getSize()) {
entry->setOffset(address);
if (auto color = entry->highlightBytes(offset); color.has_value())
return color.value();
}
delete entry;
return { };
}
std::map<u64, u32> getHighlightedAddresses() override {
if (this->m_highlightedAddresses.empty()) {
auto entry = this->m_template->clone();
for (u64 address = this->getOffset(); address < this->getOffset() + this->getSize(); address += this->m_template->getSize()) {
entry->setOffset(address);
entry->clearHighlightedAddresses();
this->m_highlightedAddresses.merge(entry->getHighlightedAddresses());
}
delete entry;
}
return this->m_highlightedAddresses;
}
void clearHighlightedAddresses() override {
this->m_template->clearHighlightedAddresses();
PatternData::clearHighlightedAddresses();
}
[[nodiscard]] std::string getFormattedName() const override {
return this->m_template->getTypeName() + "[" + std::to_string(this->m_entryCount) + "]";
}
[[nodiscard]] PatternData* getTemplate() const {
return this->m_template;
}
[[nodiscard]] size_t getEntryCount() const {
return this->m_entryCount;
}
void setEntryCount(size_t count) {
this->m_entryCount = count;
}
void setEntries(PatternData* templ, size_t count) {
this->m_template = templ;
this->m_entryCount = count;
this->m_template->setColor(this->getColor());
this->m_template->setParent(this);
}
private:
PatternData *m_template;
size_t m_entryCount;
};
class PatternDataStruct : public PatternData {
public:
PatternDataStruct(u64 offset, size_t size, u32 color = 0) : PatternData(offset, size, color){
}
PatternDataStruct(const PatternDataStruct &other) : PatternData(other.getOffset(), other.getSize(), other.getColor()) {
PatternDataStruct(const PatternDataStruct &other) : PatternData(other) {
for (const auto &member : other.m_members)
this->m_members.push_back(member->clone());
this->m_sortedMembers = this->m_members;
}
~PatternDataStruct() override {
@ -694,6 +838,14 @@ namespace hex::lang {
return new PatternDataStruct(*this);
}
void setOffset(u64 offset) override {
for (auto &member : this->m_members) {
member->setOffset(offset + (member->getOffset() - this->getOffset()));
}
PatternData::setOffset(offset);
}
void createEntry(prv::Provider* &provider) override {
ImGui::TableNextRow();
ImGui::TableNextColumn();
@ -737,6 +889,12 @@ namespace hex::lang {
return this->m_highlightedAddresses;
}
void clearHighlightedAddresses() override {
for (auto &member : this->m_members)
member->clearHighlightedAddresses();
PatternData::clearHighlightedAddresses();
}
void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) override {
this->m_sortedMembers = this->m_members;
@ -780,9 +938,10 @@ namespace hex::lang {
}
PatternDataUnion(const PatternDataUnion &other) : PatternData(other.getOffset(), other.getSize(), other.getColor()) {
PatternDataUnion(const PatternDataUnion &other) : PatternData(other) {
for (const auto &member : other.m_members)
this->m_members.push_back(member->clone());
this->m_sortedMembers = this->m_members;
}
~PatternDataUnion() override {
@ -794,6 +953,14 @@ namespace hex::lang {
return new PatternDataUnion(*this);
}
void setOffset(u64 offset) override {
for (auto &member : this->m_members) {
member->setOffset(offset + (member->getOffset() - this->getOffset()));
}
PatternData::setOffset(offset);
}
void createEntry(prv::Provider* &provider) override {
ImGui::TableNextRow();
ImGui::TableNextColumn();
@ -838,6 +1005,12 @@ namespace hex::lang {
return this->m_highlightedAddresses;
}
void clearHighlightedAddresses() override {
for (auto &member : this->m_members)
member->clearHighlightedAddresses();
PatternData::clearHighlightedAddresses();
}
void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) override {
this->m_sortedMembers = this->m_members;

View File

@ -61,8 +61,12 @@ namespace hex::lang {
else if (auto bitfieldPattern = dynamic_cast<PatternDataBitfield*>(currPattern); bitfieldPattern != nullptr) {
currMembers = bitfieldPattern->getFields();
}
else if (auto arrayPattern = dynamic_cast<PatternDataArray*>(currPattern); arrayPattern != nullptr) {
currMembers = arrayPattern->getEntries();
else if (auto dynamicArrayPattern = dynamic_cast<PatternDataDynamicArray*>(currPattern); dynamicArrayPattern != nullptr) {
currMembers = dynamicArrayPattern->getEntries();
continue;
}
else if (auto staticArrayPattern = dynamic_cast<PatternDataStaticArray*>(currPattern); staticArrayPattern != nullptr) {
currMembers = { staticArrayPattern->getTemplate() };
continue;
}
else
@ -84,15 +88,30 @@ namespace hex::lang {
ON_SCOPE_EXIT { delete arrayIndexNode; };
if (currPattern != nullptr) {
if (auto arrayPattern = dynamic_cast<PatternDataArray*>(currPattern); arrayPattern != nullptr) {
if (auto dynamicArrayPattern = dynamic_cast<PatternDataDynamicArray*>(currPattern); dynamicArrayPattern != nullptr) {
std::visit([this](auto &&arrayIndex) {
if (std::is_floating_point_v<decltype(arrayIndex)>)
this->getConsole().abortEvaluation("cannot use float to index into array");
}, arrayIndexNode->getValue());
std::visit([&](auto &&arrayIndex){
if (arrayIndex >= 0 && arrayIndex < arrayPattern->getEntries().size())
currPattern = arrayPattern->getEntries()[arrayIndex];
if (arrayIndex >= 0 && arrayIndex < dynamicArrayPattern->getEntries().size())
currPattern = dynamicArrayPattern->getEntries()[arrayIndex];
else
this->getConsole().abortEvaluation(hex::format("tried to access out of bounds index {} of '{}'", arrayIndex, currPattern->getVariableName()));
}, arrayIndexNode->getValue());
} else if (auto staticArrayPattern = dynamic_cast<PatternDataStaticArray*>(currPattern); staticArrayPattern != nullptr) {
std::visit([this](auto &&arrayIndex) {
if (std::is_floating_point_v<decltype(arrayIndex)>)
this->getConsole().abortEvaluation("cannot use float to index into array");
}, arrayIndexNode->getValue());
std::visit([&](auto &&arrayIndex){
if (arrayIndex >= 0 && arrayIndex < staticArrayPattern->getEntryCount()) {
currPattern = staticArrayPattern->getTemplate();
currPattern->setOffset(staticArrayPattern->getOffset() + arrayIndex * staticArrayPattern->getSize());
}
else
this->getConsole().abortEvaluation(hex::format("tried to access out of bounds index {} of '{}'", arrayIndex, currPattern->getVariableName()));
}, arrayIndexNode->getValue());
@ -960,7 +979,6 @@ namespace hex::lang {
}
PatternData* Evaluator::evaluateArray(ASTNodeArrayVariableDecl *node) {
// Evaluate placement of array
if (auto offset = dynamic_cast<ASTNodeNumericExpression*>(node->getPlacementOffset()); offset != nullptr) {
auto valueNode = evaluateMathematicalExpression(offset);
@ -982,6 +1000,112 @@ namespace hex::lang {
return nullptr;
}
auto type = static_cast<ASTNodeTypeDecl*>(node->getType())->getType();
if (dynamic_cast<ASTNodeBuiltinType*>(type) != nullptr)
return this->evaluateStaticArray(node);
auto attributes = dynamic_cast<Attributable*>(type)->getAttributes();
bool isStaticType = std::any_of(attributes.begin(), attributes.end(), [](ASTNodeAttribute *attribute) {
return attribute->getAttribute() == "static" && !attribute->getValue().has_value();
});
if (isStaticType)
return this->evaluateStaticArray(node);
else
return this->evaluateDynamicArray(node);
}
PatternData* Evaluator::evaluateStaticArray(ASTNodeArrayVariableDecl *node) {
std::optional<u32> color;
size_t arraySize = 0;
auto startOffset = this->m_currOffset;
PatternData *templatePattern;
if (auto typeDecl = dynamic_cast<ASTNodeTypeDecl*>(node->getType()); typeDecl != nullptr)
templatePattern = this->evaluateType(typeDecl);
else if (auto builtinTypeDecl = dynamic_cast<ASTNodeBuiltinType*>(node->getType()); builtinTypeDecl != nullptr)
templatePattern = this->evaluateBuiltinType(builtinTypeDecl);
else
this->getConsole().abortEvaluation("ASTNodeVariableDecl had an invalid type. This is a bug!");
auto entrySize = this->m_currOffset - startOffset;
ON_SCOPE_EXIT { delete templatePattern; };
auto sizeNode = node->getSize();
if (auto numericExpression = dynamic_cast<ASTNodeNumericExpression*>(sizeNode); numericExpression != nullptr) {
// Parse explicit size of array
auto valueNode = this->evaluateMathematicalExpression(numericExpression);
ON_SCOPE_EXIT { delete valueNode; };
arraySize = std::visit([this] (auto &&value) {
using Type = std::remove_cvref_t<decltype(value)>;
if constexpr (std::is_floating_point_v<Type>)
this->getConsole().abortEvaluation("bitfield entry size must be an integer value");
return static_cast<u64>(value);
}, valueNode->getValue());
} else if (auto whileLoopExpression = dynamic_cast<ASTNodeWhileStatement*>(sizeNode); whileLoopExpression != nullptr) {
// Parse while loop based size of array
auto conditionNode = this->evaluateMathematicalExpression(static_cast<ASTNodeNumericExpression*>(whileLoopExpression->getCondition()));
ON_SCOPE_EXIT { delete conditionNode; };
while (std::visit([](auto &&value) { return value != 0; }, conditionNode->getValue())) {
arraySize++;
delete conditionNode;
conditionNode = this->evaluateMathematicalExpression(static_cast<ASTNodeNumericExpression*>(whileLoopExpression->getCondition()));
}
} else {
// Parse unsized array
if (auto typeDecl = dynamic_cast<ASTNodeTypeDecl*>(node->getType()); typeDecl != nullptr) {
if (auto builtinType = dynamic_cast<ASTNodeBuiltinType*>(typeDecl->getType()); builtinType != nullptr) {
std::vector<u8> bytes(Token::getTypeSize(builtinType->getType()), 0x00);
u64 offset = startOffset;
do {
this->m_provider->read(offset, bytes.data(), bytes.size());
offset += bytes.size();
arraySize++;
} while (!std::all_of(bytes.begin(), bytes.end(), [](u8 byte){ return byte == 0x00; }) && offset < this->m_provider->getSize());
}
}
}
if (auto typeDecl = dynamic_cast<ASTNodeTypeDecl*>(node->getType()); typeDecl != nullptr) {
if (auto builtinType = dynamic_cast<ASTNodeBuiltinType *>(typeDecl->getType()); builtinType != nullptr) {
if (builtinType->getType() == Token::ValueType::Padding)
return new PatternDataPadding(startOffset, entrySize * arraySize);
}
}
PatternData *pattern;
if (dynamic_cast<PatternDataCharacter*>(templatePattern) != nullptr)
pattern = new PatternDataString(startOffset, entrySize * arraySize, color.value_or(0));
else if (dynamic_cast<PatternDataCharacter16*>(templatePattern) != nullptr)
pattern = new PatternDataString16(startOffset, entrySize * arraySize, color.value_or(0));
else {
auto arrayPattern = new PatternDataStaticArray(startOffset, entrySize * arraySize, color.value_or(0));
arrayPattern->setTypeName(templatePattern->getTypeName());
arrayPattern->setEntries(templatePattern->clone(), arraySize);
pattern = arrayPattern;
}
pattern->setVariableName(node->getName().data());
pattern->setEndian(this->getCurrentEndian());
this->m_currOffset = startOffset + entrySize * arraySize;
return this->evaluateAttributes(node, pattern);
}
PatternData* Evaluator::evaluateDynamicArray(ASTNodeArrayVariableDecl *node) {
auto startOffset = this->m_currOffset;
std::vector<PatternData*> entries;
@ -991,8 +1115,6 @@ namespace hex::lang {
PatternData *entry;
if (auto typeDecl = dynamic_cast<ASTNodeTypeDecl*>(node->getType()); typeDecl != nullptr)
entry = this->evaluateType(typeDecl);
else if (auto builtinTypeDecl = dynamic_cast<ASTNodeBuiltinType*>(node->getType()); builtinTypeDecl != nullptr)
entry = this->evaluateBuiltinType(builtinTypeDecl);
else
this->getConsole().abortEvaluation("ASTNodeVariableDecl had an invalid type. This is a bug!");
@ -1042,23 +1164,6 @@ namespace hex::lang {
delete conditionNode;
conditionNode = this->evaluateMathematicalExpression(static_cast<ASTNodeNumericExpression*>(whileLoopExpression->getCondition()));
}
} else {
// Parse unsized array
if (auto typeDecl = dynamic_cast<ASTNodeTypeDecl*>(node->getType()); typeDecl != nullptr) {
if (auto builtinType = dynamic_cast<ASTNodeBuiltinType*>(typeDecl->getType()); builtinType != nullptr) {
std::vector<u8> bytes(Token::getTypeSize(builtinType->getType()), 0x00);
u64 offset = startOffset;
u64 index = 0;
do {
this->m_provider->read(offset, bytes.data(), bytes.size());
offset += bytes.size();
addEntry(index);
index++;
} while (!std::all_of(bytes.begin(), bytes.end(), [](u8 byte){ return byte == 0x00; }) && offset < this->m_provider->getSize());
}
}
}
auto deleteEntries = SCOPE_GUARD {
@ -1066,31 +1171,13 @@ namespace hex::lang {
delete entry;
};
if (auto typeDecl = dynamic_cast<ASTNodeTypeDecl*>(node->getType()); typeDecl != nullptr) {
if (auto builtinType = dynamic_cast<ASTNodeBuiltinType *>(typeDecl->getType()); builtinType != nullptr) {
if (builtinType->getType() == Token::ValueType::Padding)
return new PatternDataPadding(startOffset, this->m_currOffset - startOffset);
}
}
if (node->getSize() == nullptr)
this->getConsole().abortEvaluation("no bounds provided for array");
auto pattern = new PatternDataDynamicArray(startOffset, (this->m_currOffset - startOffset), color.value_or(0));
PatternData *pattern;
if (entries.empty())
pattern = new PatternDataPadding(startOffset, 0);
else if (dynamic_cast<PatternDataCharacter*>(entries[0]) != nullptr)
pattern = new PatternDataString(startOffset, (this->m_currOffset - startOffset), color.value_or(0));
else if (dynamic_cast<PatternDataCharacter16*>(entries[0]) != nullptr)
pattern = new PatternDataString16(startOffset, (this->m_currOffset - startOffset), color.value_or(0));
else {
if (node->getSize() == nullptr)
this->getConsole().abortEvaluation("no bounds provided for array");
auto arrayPattern = new PatternDataArray(startOffset, (this->m_currOffset - startOffset), color.value_or(0));
arrayPattern->setEntries(entries);
deleteEntries.release();
pattern = arrayPattern;
}
deleteEntries.release();
pattern->setEntries(entries);
pattern->setVariableName(node->getName().data());
pattern->setEndian(this->getCurrentEndian());

View File

@ -7,12 +7,13 @@
#include <hex/lang/parser.hpp>
#include <hex/lang/validator.hpp>
#include <hex/lang/evaluator.hpp>
#include <hex/lang/pattern_data.hpp>
#include <unistd.h>
namespace hex::lang {
class PatternData;
PatternLanguage::PatternLanguage() {
this->m_preprocessor = new Preprocessor();
this->m_lexer = new Lexer();

View File

@ -5,6 +5,7 @@
#include <hex/helpers/net.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/lang/pattern_data.hpp>
#include <fontawesome_font.h>
#include <codicons_font.h>

View File

@ -1,6 +1,6 @@
#include "views/view_command_palette.hpp"
#include <GLFW/glfw3.h>
#include <cstring>
namespace hex {

View File

@ -3,6 +3,9 @@
#include <imgui_imhex_extensions.h>
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/utils.hpp>
namespace hex {
ViewHelp::ViewHelp() : View("hex.view.help.about.name") {

View File

@ -1,8 +1,9 @@
#include "views/view_hexeditor.hpp"
#include <hex/providers/provider.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/providers/provider.hpp>
#include <hex/helpers/crypto.hpp>
#include <hex/lang/pattern_data.hpp>
#include "providers/file_provider.hpp"
#include "helpers/patches.hpp"

View File

@ -4,6 +4,7 @@
#include <hex/lang/preprocessor.hpp>
#include <hex/lang/pattern_data.hpp>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/magic.hpp>
#include <hex/helpers/literals.hpp>