1
0
mirror of synced 2024-11-12 02:00:52 +01:00

Completely rewrite highlight and pattern evaluator

This commit is contained in:
WerWolv 2020-11-19 11:36:52 +01:00
parent 0889764bcc
commit 6fffc589bf
15 changed files with 720 additions and 570 deletions

View File

@ -24,6 +24,7 @@ add_executable(ImHex
source/lang/lexer.cpp
source/lang/parser.cpp
source/lang/validator.cpp
source/lang/evaluator.cpp
source/provider/file_provider.cpp

View File

@ -0,0 +1,32 @@
#pragma once
#include <hex.hpp>
#include "lang/pattern_data.hpp"
#include "ast_node.hpp"
#include <string>
#include <unordered_map>
#include <vector>
namespace hex::lang {
class Evaluator {
public:
Evaluator();
std::pair<Result, std::vector<PatternData*>> evaluate(const std::vector<ASTNode*>& ast);
private:
std::unordered_map<std::string, ASTNode*> m_types;
std::pair<PatternData*, size_t> createStructPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createEnumPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createArrayPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createStringPattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createCustomTypePattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
std::pair<PatternData*, size_t> createBuiltInTypePattern(ASTNodeVariableDecl *varDeclNode, u64 offset);
};
}

View File

@ -0,0 +1,389 @@
#pragma once
#include <hex.hpp>
#include <string>
#include "imgui.h"
#include "imgui_memory_editor.h"
#include "providers/provider.hpp"
#include "utils.hpp"
#include <random>
namespace hex::lang {
namespace {
std::string makeDisplayable(u8 *data, size_t size) {
std::string result;
for (u8* c = data; c < (data + size); c++) {
if (iscntrl(*c) || *c > 0x7F)
result += " ";
else
result += *c;
}
return result;
}
}
class PatternData {
public:
PatternData(u64 offset, size_t size, const std::string &name, u32 color = 0)
: m_offset(offset), m_size(size), m_color(color), m_name(name) {
constexpr u32 Palette[] = { 0x50b4771f, 0x500e7fff, 0x502ca02c, 0x502827d6, 0x50bd6794, 0x504b568c, 0x50c277e3, 0x507f7f7f, 0x5022bdbc, 0x50cfbe17 };
if (color != 0)
return;
this->m_color = Palette[PatternData::s_paletteOffset++];
if (PatternData::s_paletteOffset >= (sizeof(Palette) / sizeof(u32)))
PatternData::s_paletteOffset = 0;
}
virtual ~PatternData() = default;
[[nodiscard]] u64 getOffset() const { return this->m_offset; }
[[nodiscard]] size_t getSize() const { return this->m_size; }
[[nodiscard]] u32 getColor() const { return this->m_color; }
[[nodiscard]] const std::string& getName() const { return this->m_name; }
virtual void createEntry(prv::Provider* &provider) = 0;
virtual std::string getTypeName() = 0;
virtual std::optional<u32> highlightBytes(size_t offset) {
if (offset >= this->getOffset() && offset < (this->getOffset() + this->getSize()))
return this->getColor();
else
return { };
}
static void resetPalette() { PatternData::s_paletteOffset = 0; }
static bool beginPatternDataTable(prv::Provider* &provider, const std::vector<lang::PatternData*> &patterns, std::vector<lang::PatternData*> &sortedPatterns) {
if (ImGui::BeginTable("##patterndatatable", 6, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg)) {
ImGui::TableSetupColumn("Color", 0, -1, ImGui::GetID("color"));
ImGui::TableSetupColumn("Name", 0, -1, ImGui::GetID("name"));
ImGui::TableSetupColumn("Position", 0, -1, ImGui::GetID("position"));
ImGui::TableSetupColumn("Size", 0, -1, ImGui::GetID("size"));
ImGui::TableSetupColumn("Type", 0, -1, ImGui::GetID("type"));
ImGui::TableSetupColumn("Value", 0, -1, ImGui::GetID("value"));
auto sortSpecs = ImGui::TableGetSortSpecs();
if (sortSpecs->SpecsDirty || sortedPatterns.empty()) {
sortedPatterns = patterns;
std::sort(sortedPatterns.begin(), sortedPatterns.end(), [&sortSpecs, &provider](lang::PatternData* left, lang::PatternData* right) -> bool {
if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("name")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return left->getName() > right->getName();
else
return left->getName() < right->getName();
}
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("position")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return left->getOffset() > right->getOffset();
else
return left->getOffset() < right->getOffset();
}
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("size")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return left->getSize() > right->getSize();
else
return left->getSize() < right->getSize();
}
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("value")) {
size_t biggerSize = std::max(left->getSize(), right->getSize());
std::vector<u8> leftBuffer(biggerSize, 0x00), rightBuffer(biggerSize, 0x00);
provider->read(left->getOffset(), leftBuffer.data(), left->getSize());
provider->read(right->getOffset(), rightBuffer.data(), right->getSize());
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return leftBuffer > rightBuffer;
else
return leftBuffer < rightBuffer;
}
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("type")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return left->getTypeName() > right->getTypeName();
else
return left->getTypeName() < right->getTypeName();
}
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("color")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return left->getColor() > right->getColor();
else
return left->getColor() < right->getColor();
}
return false;
});
sortSpecs->SpecsDirty = false;
}
ImGui::TableHeadersRow();
return true;
}
return false;
}
protected:
void createDefaultEntry(std::string value) {
ImGui::TableNextRow();
ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip);
ImGui::TableNextColumn();
ImGui::Text("%s", this->getName().c_str());
ImGui::TableNextColumn();
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize());
ImGui::TableNextColumn();
ImGui::Text("0x%08lx", this->getSize());
ImGui::TableNextColumn();
ImGui::Text("%s", this->getTypeName().c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", value.c_str());
}
private:
u64 m_offset;
size_t m_size;
u32 m_color;
std::string m_name;
static inline u8 s_paletteOffset = 0;
};
class PatternDataUnsigned : public PatternData {
public:
PatternDataUnsigned(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(offset, size, name, color) { }
void createEntry(prv::Provider* &provider) override {
u64 data = 0;
provider->read(this->getOffset(), &data, this->getSize());
this->createDefaultEntry(hex::format("%lu (0x%08lx)", data, data));
}
std::string getTypeName() override {
switch (this->getSize()) {
case 1: return "u8";
case 2: return "u16";
case 4: return "u32";
case 8: return "u64";
case 16: return "u128";
default: return "Unsigned data";
}
}
};
class PatternDataSigned : public PatternData {
public:
PatternDataSigned(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(offset, size, name, color) { }
void createEntry(prv::Provider* &provider) override {
u64 data = 0;
provider->read(this->getOffset(), &data, this->getSize());
s64 signedData = signedData = hex::signExtend(data, this->getSize(), 64);
this->createDefaultEntry(hex::format("%ld (0x%08lx)", signedData, data));
}
std::string getTypeName() override {
switch (this->getSize()) {
case 1: return "s8";
case 2: return "s16";
case 4: return "s32";
case 8: return "s64";
case 16: return "s128";
default: return "Signed data";
}
}
};
class PatternDataFloat : public PatternData {
public:
PatternDataFloat(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(offset, size, name, color) { }
void createEntry(prv::Provider* &provider) override {
double formatData = 0;
if (this->getSize() == 4) {
float data = 0;
provider->read(this->getOffset(), &data, 4);
formatData = data;
} else if (this->getSize() == 8) {
double data = 0;
provider->read(this->getOffset(), &data, 8);
formatData = data;
}
this->createDefaultEntry(hex::format("%f (0x%08lx)", formatData, formatData));
}
std::string getTypeName() override {
switch (this->getSize()) {
case 4: return "float";
case 8: return "double";
default: return "Floating point data";
}
}
};
class PatternDataCharacter : public PatternData {
public:
PatternDataCharacter(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(offset, size, name, color) { }
void createEntry(prv::Provider* &provider) override {
char character;
provider->read(this->getOffset(), &character, 1);
this->createDefaultEntry(hex::format("'%c'", character));
}
std::string getTypeName() override {
return "Character";
}
};
class PatternDataString : public PatternData {
public:
PatternDataString(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(offset, size, name, color) { }
void createEntry(prv::Provider* &provider) override {
std::vector<u8> buffer(this->getSize() + 1, 0x00);
provider->read(this->getOffset(), buffer.data(), this->getSize());
buffer[this->getSize()] = '\0';
this->createDefaultEntry(hex::format("\"%s\"", makeDisplayable(buffer.data(), this->getSize()).c_str()));
}
std::string getTypeName() override {
return "String";
}
};
class PatternDataArray : public PatternData {
public:
PatternDataArray(u64 offset, size_t size, const std::string &name, const std::vector<PatternData*> & entries, u32 color = 0)
: PatternData(offset, size, name, color), m_entries(entries) { }
void createEntry(prv::Provider* &provider) override {
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip);
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize());
ImGui::TableNextColumn();
ImGui::Text("0x%08lx", this->getSize());
ImGui::TableNextColumn();
ImGui::Text("%s", this->getTypeName().c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", "{ ... }");
if (open) {
for (auto &member : this->m_entries)
member->createEntry(provider);
ImGui::TreePop();
}
}
std::optional<u32> highlightBytes(size_t offset) override{
for (auto &entry : this->m_entries) {
if (auto color = entry->highlightBytes(offset); color.has_value())
return color.value();
}
return { };
}
std::string getTypeName() override {
return this->m_entries[0]->getTypeName() + "[" + std::to_string(this->m_entries.size()) + "]";
}
private:
std::vector<PatternData*> m_entries;
};
class PatternDataStruct : public PatternData {
public:
PatternDataStruct(u64 offset, size_t size, const std::string &name, const std::string &structName, const std::vector<PatternData*> & members, u32 color = 0)
: PatternData(offset, size, name, color), m_structName(structName), m_members(members) { }
void createEntry(prv::Provider* &provider) override {
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_AlphaPreview);
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::TableNextColumn();
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize());
ImGui::TableNextColumn();
ImGui::Text("0x%08lx", this->getSize());
ImGui::TableNextColumn();
ImGui::Text("%s", this->getTypeName().c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", "{ ... }");
if (open) {
for (auto &member : this->m_members)
member->createEntry(provider);
ImGui::TreePop();
}
}
std::optional<u32> highlightBytes(size_t offset) override{
for (auto &member : this->m_members) {
if (auto color = member->highlightBytes(offset); color.has_value())
return color.value();
}
return { };
}
std::string getTypeName() override {
return "struct " + this->m_structName;
}
private:
std::string m_structName;
std::vector<PatternData*> m_members;
std::vector<PatternData*> m_sortedMembers;
};
class PatternDataEnum : public PatternData {
public:
PatternDataEnum(u64 offset, size_t size, const std::string &name, const std::string &enumName, std::vector<std::pair<u64, std::string>> enumValues, u32 color = 0)
: PatternData(offset, size, name, color), m_enumName(enumName), m_enumValues(enumValues) { }
void createEntry(prv::Provider* &provider) override {
}
std::string getTypeName() override {
return "enum " + this->m_enumName;
}
private:
std::string m_enumName;
std::vector<std::pair<u64, std::string>> m_enumValues;
};
}

View File

@ -9,5 +9,6 @@ namespace hex::lang {
constexpr Result ResultPreprocessingError(1, 1);
constexpr Result ResultLexicalError(2, 1);
constexpr Result ResultParseError(3, 1);
constexpr Result ResultEvaluatorError(4, 1);
}

View File

@ -3,9 +3,10 @@
#include <hex.hpp>
#include <array>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <memory>
#include <vector>
#include "lang/token.hpp"
@ -75,4 +76,16 @@ namespace hex {
}
class ScopeExit {
public:
ScopeExit(std::function<void()> func) : m_func(func) {}
~ScopeExit() { if (this->m_func != nullptr) this->m_func(); }
void release() {
this->m_func = nullptr;
}
private:
std::function<void()> m_func;
};
}

View File

@ -1,200 +0,0 @@
#pragma once
#include <hex.hpp>
#include <string>
#include "providers/provider.hpp"
#include "utils.hpp"
#include <random>
namespace hex {
namespace {
std::string makeDisplayable(u8 *data, size_t size) {
std::string result;
for (u8* c = data; c < (data + size); c++) {
if (iscntrl(*c) || *c > 0x7F)
result += " ";
else
result += *c;
}
return result;
}
}
class PatternData {
public:
PatternData(u64 offset, size_t size, const std::string &name, u32 color = 0)
: m_offset(offset), m_size(size), m_color(color), m_name(name) {
constexpr u32 Palette[] = { 0x50b4771f, 0x500e7fff, 0x502ca02c, 0x502827d6, 0x50bd6794, 0x504b568c, 0x50c277e3, 0x507f7f7f, 0x5022bdbc, 0x50cfbe17 };
this->m_color = Palette[PatternData::s_paletteOffset++];
if (PatternData::s_paletteOffset >= (sizeof(Palette) / sizeof(u32)))
PatternData::s_paletteOffset = 0;
}
virtual ~PatternData() = default;
[[nodiscard]] u64 getOffset() const { return this->m_offset; }
[[nodiscard]] size_t getSize() const { return this->m_size; }
[[nodiscard]] u32 getColor() const { return this->m_color; }
[[nodiscard]] const std::string& getName() const { return this->m_name; }
virtual std::string format(prv::Provider* &provider) = 0;
virtual std::string getTypeName() = 0;
static void resetPalette() { PatternData::s_paletteOffset = 0; }
private:
u64 m_offset;
size_t m_size;
u32 m_color;
std::string m_name;
static inline u8 s_paletteOffset = 0;
};
class PatternDataUnsigned : public PatternData {
public:
PatternDataUnsigned(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(offset, size, name, color) { }
std::string format(prv::Provider* &provider) override {
u64 data = 0;
provider->read(this->getOffset(), &data, this->getSize());
return hex::format("%lu (0x%08lx)", data, data);
}
std::string getTypeName() override {
switch (this->getSize()) {
case 1: return "u8";
case 2: return "u16";
case 4: return "u32";
case 8: return "u64";
case 16: return "u128";
default: return "Unsigned data";
}
}
};
class PatternDataSigned : public PatternData {
public:
PatternDataSigned(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(offset, size, name, color) { }
std::string format(prv::Provider* &provider) override {
u64 data = 0;
provider->read(this->getOffset(), &data, this->getSize());
s64 signedData = signedData = hex::signExtend(data, this->getSize(), 64);
return hex::format("%ld (0x%08lx)", signedData, data);
}
std::string getTypeName() override {
switch (this->getSize()) {
case 1: return "s8";
case 2: return "s16";
case 4: return "s32";
case 8: return "s64";
case 16: return "s128";
default: return "Signed data";
}
}
};
class PatternDataFloat : public PatternData {
public:
PatternDataFloat(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(offset, size, name, color) { }
std::string format(prv::Provider* &provider) override {
double formatData = 0;
if (this->getSize() == 4) {
float data = 0;
provider->read(this->getOffset(), &data, 4);
formatData = data;
} else if (this->getSize() == 8) {
double data = 0;
provider->read(this->getOffset(), &data, 8);
formatData = data;
}
return hex::format("%f (0x%08lx)", formatData, formatData);
}
std::string getTypeName() override {
switch (this->getSize()) {
case 4: return "float";
case 8: return "double";
default: return "Floating point data";
}
}
};
class PatternDataCharacter : public PatternData {
public:
PatternDataCharacter(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(offset, size, name, color) { }
std::string format(prv::Provider* &provider) override {
char character;
provider->read(this->getOffset(), &character, 1);
return hex::format("'%c'", character);
}
std::string getTypeName() override {
return "Character";
}
};
class PatternDataString : public PatternData {
public:
PatternDataString(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(offset, size, name, color) { }
std::string format(prv::Provider* &provider) override {
std::vector<u8> buffer(this->getSize() + 1, 0x00);
provider->read(this->getOffset(), buffer.data(), this->getSize());
buffer[this->getSize()] = '\0';
return hex::format("\"%s\"", makeDisplayable(buffer.data(), this->getSize()).c_str());
}
std::string getTypeName() override {
return "String";
}
};
class PatternDataEnum : public PatternData {
public:
PatternDataEnum(u64 offset, size_t size, const std::string &name, const std::string &enumName, std::vector<std::pair<u64, std::string>> enumValues, u32 color = 0)
: PatternData(offset, size, name, color), m_enumName(enumName), m_enumValues(enumValues) { }
std::string format(prv::Provider* &provider) override {
u64 value = 0;
provider->read(this->getOffset(), &value, this->getSize());
for (auto [enumValue, name] : this->m_enumValues) {
if (value == enumValue)
return hex::format("%lu (0x%08lx) : %s::%s", value, value, this->m_enumName.c_str(), name.c_str());
}
return hex::format("%lu (0x%08lx) : %s::???", value, value, this->m_enumName.c_str());
}
std::string getTypeName() override {
return "enum " + this->m_enumName;
}
private:
std::string m_enumName;
std::vector<std::pair<u64, std::string>> m_enumValues;
};
}

View File

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

View File

@ -10,7 +10,7 @@
#include <random>
#include <vector>
#include "views/pattern_data.hpp"
#include "lang/pattern_data.hpp"
namespace hex {
@ -20,7 +20,7 @@ namespace hex {
class ViewHexEditor : public View {
public:
ViewHexEditor(prv::Provider* &dataProvider, std::vector<hex::PatternData*> &patternData);
ViewHexEditor(prv::Provider* &dataProvider, std::vector<lang::PatternData*> &patternData);
~ViewHexEditor() override;
void createView() override;
@ -32,7 +32,7 @@ namespace hex {
imgui_addons::ImGuiFileBrowser m_fileBrowser;
prv::Provider* &m_dataProvider;
std::vector<hex::PatternData*> &m_patternData;
std::vector<lang::PatternData*> &m_patternData;
char m_searchStringBuffer[0xFFFF] = { 0 };
char m_searchHexBuffer[0xFFFF] = { 0 };

View File

@ -3,7 +3,7 @@
#include "lang/ast_node.hpp"
#include "views/view.hpp"
#include "views/pattern_data.hpp"
#include "lang/pattern_data.hpp"
#include "providers/provider.hpp"
@ -17,7 +17,7 @@ namespace hex {
class ViewPattern : public View {
public:
explicit ViewPattern(prv::Provider* &dataProvider, std::vector<hex::PatternData*> &patternData);
explicit ViewPattern(prv::Provider* &dataProvider, std::vector<lang::PatternData*> &patternData);
~ViewPattern() override;
void createMenu() override;
@ -26,20 +26,14 @@ namespace hex {
private:
char *m_buffer = nullptr;
std::vector<hex::PatternData*> &m_patternData;
std::vector<lang::PatternData*> &m_patternData;
prv::Provider* &m_dataProvider;
bool m_windowOpen = true;
imgui_addons::ImGuiFileBrowser m_fileBrowser;
void addPatternData(PatternData *patternData);
void clearPatternData();
void parsePattern(char *buffer);
s32 highlightUsingDecls(std::vector<lang::ASTNode*> &ast, lang::ASTNodeTypeDecl* currTypeDeclNode, lang::ASTNodeVariableDecl* currVarDec, u64 offset, std::string name);
s32 highlightStruct(std::vector<lang::ASTNode*> &ast, lang::ASTNodeStruct* currStructNode, u64 offset, std::string name);
s32 highlightEnum(std::vector<lang::ASTNode*> &ast, lang::ASTNodeEnum* currEnumNode, u64 offset, std::string name);
};
}

View File

@ -4,7 +4,7 @@
#include "imgui.h"
#include "views/view.hpp"
#include "views/pattern_data.hpp"
#include "lang/pattern_data.hpp"
#include <vector>
#include <tuple>
@ -16,7 +16,7 @@ namespace hex {
class ViewPatternData : public View {
public:
ViewPatternData(prv::Provider* &dataProvider, std::vector<hex::PatternData*> &patternData);
ViewPatternData(prv::Provider* &dataProvider, std::vector<lang::PatternData*> &patternData);
~ViewPatternData() override;
void createView() override;
@ -24,8 +24,8 @@ namespace hex {
private:
prv::Provider* &m_dataProvider;
std::vector<hex::PatternData*> &m_patternData;
std::vector<hex::PatternData*> m_sortedPatternData;
std::vector<lang::PatternData*> &m_patternData;
std::vector<lang::PatternData*> m_sortedPatternData;
bool m_windowOpen = true;
};

248
source/lang/evaluator.cpp Normal file
View File

@ -0,0 +1,248 @@
#include "lang/evaluator.hpp"
#include <unordered_map>
namespace hex::lang {
Evaluator::Evaluator() {
}
std::pair<PatternData*, size_t> Evaluator::createStructPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) {
std::vector<PatternData*> members;
auto structNode = static_cast<ASTNodeStruct*>(this->m_types[varDeclNode->getCustomVariableTypeName()]);
if (structNode == nullptr)
return { nullptr, 0 };
size_t structSize = 0;
for (const auto &node : structNode->getNodes()) {
const auto &member = static_cast<ASTNodeVariableDecl*>(node);
const auto typeDeclNode = static_cast<ASTNodeTypeDecl*>(this->m_types[member->getCustomVariableTypeName()]);
if (typeDeclNode == nullptr)
return { nullptr, 0 };
if (member->getVariableType() == Token::TypeToken::Type::Signed8Bit && member->getArraySize() > 1) {
const auto &[pattern, size] = this->createStringPattern(member, offset + structSize);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
structSize += size;
} else if (member->getVariableType() == Token::TypeToken::Type::CustomType
&& typeDeclNode->getAssignedType() == Token::TypeToken::Type::Signed8Bit
&& member->getArraySize() > 1) {
const auto &[pattern, size] = this->createStringPattern(member, offset + structSize);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
structSize += size;
}
else if (member->getArraySize() > 1) {
const auto &[pattern, size] = this->createArrayPattern(member, offset + structSize);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
structSize += size;
}
else if (member->getVariableType() != Token::TypeToken::Type::CustomType) {
const auto &[pattern, size] = this->createBuiltInTypePattern(member, offset + structSize);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
structSize += size;
}
else {
const auto &[pattern, size] = this->createCustomTypePattern(member, offset + structSize);
if (pattern == nullptr)
return { nullptr, 0 };
members.push_back(pattern);
structSize += size;
}
}
return { new PatternDataStruct(offset, structSize, varDeclNode->getVariableName(), structNode->getName(), members, 0x00FFFFFF), structSize };
}
std::pair<PatternData*, size_t> Evaluator::createEnumPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) {
std::vector<std::pair<u64, std::string>> enumValues;
auto *enumType = static_cast<ASTNodeEnum*>(this->m_types[varDeclNode->getCustomVariableTypeName()]);
if (enumType == nullptr)
return { nullptr, 0 };
size_t size = getTypeSize(enumType->getUnderlyingType());
return { new PatternDataEnum(offset, size, varDeclNode->getVariableName(), enumType->getName(), enumType->getValues()), size };
}
std::pair<PatternData*, size_t> Evaluator::createArrayPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) {
std::vector<PatternData*> entries;
size_t arraySize = 0;
for (u32 i = 0; i < varDeclNode->getArraySize(); i++) {
ASTNodeVariableDecl *nonArrayVarDeclNode = new ASTNodeVariableDecl(varDeclNode->getVariableType(), "[" + std::to_string(i) + "]", varDeclNode->getCustomVariableTypeName(), varDeclNode->getOffset(), 1);
if (varDeclNode->getVariableType() != Token::TypeToken::Type::CustomType) {
const auto &[pattern, size] = this->createBuiltInTypePattern(nonArrayVarDeclNode, offset + arraySize);
if (pattern == nullptr)
return { nullptr, 0 };
entries.push_back(pattern);
arraySize += size;
} else {
const auto &[pattern, size] = this->createCustomTypePattern(nonArrayVarDeclNode, offset + arraySize);
if (pattern == nullptr)
return { nullptr, 0 };
entries.push_back(pattern);
arraySize += size;
}
delete nonArrayVarDeclNode;
}
return { new PatternDataArray(offset, arraySize, varDeclNode->getVariableName(), entries, 0x00FFFFFF), arraySize };
}
std::pair<PatternData*, size_t> Evaluator::createStringPattern(ASTNodeVariableDecl *varDeclNode, u64 offset) {
size_t arraySize = varDeclNode->getArraySize();
return { new PatternDataString(offset, arraySize, varDeclNode->getVariableName()), arraySize };
}
std::pair<PatternData*, size_t> Evaluator::createCustomTypePattern(ASTNodeVariableDecl *varDeclNode, u64 offset) {
auto &currType = this->m_types[varDeclNode->getCustomVariableTypeName()];
if (currType == nullptr)
return { nullptr, 0 };
switch (currType->getType()) {
case ASTNode::Type::Struct:
return this->createStructPattern(varDeclNode, offset);
case ASTNode::Type::Enum:
return this->createEnumPattern(varDeclNode, offset);
case ASTNode::Type::TypeDecl:
return this->createBuiltInTypePattern(varDeclNode, offset);
}
return { nullptr, 0 };
}
std::pair<PatternData*, size_t> Evaluator::createBuiltInTypePattern(ASTNodeVariableDecl *varDeclNode, u64 offset) {
auto type = varDeclNode->getVariableType();
if (type == Token::TypeToken::Type::CustomType) {
const auto &currType = static_cast<ASTNodeTypeDecl*>(this->m_types[varDeclNode->getCustomVariableTypeName()]);
if (currType == nullptr)
return { nullptr, 0 };
type = currType->getAssignedType();
}
size_t typeSize = getTypeSize(type);
size_t arraySize = varDeclNode->getArraySize();
if (isSigned(type)) {
if (typeSize == 1 && arraySize == 1)
return { new PatternDataCharacter(offset, typeSize, varDeclNode->getVariableName()), 1 };
else if (arraySize > 1)
return createArrayPattern(varDeclNode, offset);
else
return { new PatternDataSigned(offset, typeSize, varDeclNode->getVariableName()), typeSize * arraySize };
} else if (isUnsigned(varDeclNode->getVariableType())) {
if (arraySize > 1)
return createArrayPattern(varDeclNode, offset);
else
return { new PatternDataUnsigned(offset, typeSize, varDeclNode->getVariableName()), typeSize * arraySize };
} else if (isFloatingPoint(varDeclNode->getVariableType())) {
if (arraySize > 1)
return createArrayPattern(varDeclNode, offset);
else
return { new PatternDataFloat(offset, typeSize, varDeclNode->getVariableName()), typeSize * arraySize };
}
return { nullptr, 0 };
}
std::pair<Result, std::vector<PatternData*>> Evaluator::evaluate(const std::vector<ASTNode *> &ast) {
// Evaluate types
for (const auto &node : ast) {
switch(node->getType()) {
case ASTNode::Type::Struct:
{
auto *structNode = static_cast<ASTNodeStruct*>(node);
this->m_types.emplace(structNode->getName(), structNode);
}
break;
case ASTNode::Type::Enum:
{
auto *enumNode = static_cast<ASTNodeEnum*>(node);
this->m_types.emplace(enumNode->getName(), enumNode);
}
break;
case ASTNode::Type::TypeDecl:
{
auto *typeDeclNode = static_cast<ASTNodeTypeDecl*>(node);
if (typeDeclNode->getAssignedType() == Token::TypeToken::Type::CustomType)
this->m_types.emplace(typeDeclNode->getTypeName(), this->m_types[typeDeclNode->getAssignedCustomTypeName()]);
else
this->m_types.emplace(typeDeclNode->getTypeName(), typeDeclNode);
}
break;
case ASTNode::Type::VariableDecl: break;
case ASTNode::Type::Scope: break;
}
}
// Evaluate variable declarations
std::vector<PatternData*> variables;
for (const auto &node : ast) {
if (node->getType() != ASTNode::Type::VariableDecl)
continue;
auto *varDeclNode = static_cast<ASTNodeVariableDecl*>(node);
if (varDeclNode->getVariableType() == Token::TypeToken::Type::Signed8Bit && varDeclNode->getArraySize() > 1) {
const auto &[pattern, _] = createStringPattern(varDeclNode, varDeclNode->getOffset().value());
variables.push_back(pattern);
}
else if (varDeclNode->getArraySize() > 1) {
const auto &[pattern, _] = this->createArrayPattern(varDeclNode, varDeclNode->getOffset().value());
variables.push_back(pattern);
} else if (varDeclNode->getVariableType() != Token::TypeToken::Type::CustomType) {
const auto &[pattern, _] = this->createBuiltInTypePattern(varDeclNode, varDeclNode->getOffset().value());
variables.push_back(pattern);
} else {
const auto &[pattern, _] = this->createCustomTypePattern(varDeclNode, varDeclNode->getOffset().value());
variables.push_back(pattern);
}
}
for (const auto &var : variables)
if (var == nullptr)
return { ResultEvaluatorError, { } };
return { ResultSuccess, variables };
}
}

View File

@ -1,6 +1,6 @@
#include "window.hpp"
#include "views/pattern_data.hpp"
#include "lang/pattern_data.hpp"
#include "views/view_hexeditor.hpp"
#include "views/view_pattern.hpp"
#include "views/view_pattern_data.hpp"
@ -18,7 +18,7 @@ int main() {
hex::Window window;
// Shared Data
std::vector<hex::PatternData*> patternData;
std::vector<hex::lang::PatternData*> patternData;
hex::prv::Provider *dataProvider = nullptr;
// Create views

View File

@ -7,7 +7,7 @@
namespace hex {
ViewHexEditor::ViewHexEditor(prv::Provider* &dataProvider, std::vector<hex::PatternData*> &patternData)
ViewHexEditor::ViewHexEditor(prv::Provider* &dataProvider, std::vector<lang::PatternData*> &patternData)
: View(), m_dataProvider(dataProvider), m_patternData(patternData) {
this->m_memoryEditor.ReadFn = [](const ImU8 *data, size_t off) -> ImU8 {
@ -36,12 +36,12 @@ namespace hex {
ViewHexEditor *_this = (ViewHexEditor *) data;
for (auto& pattern : _this->m_patternData) {
if (next && off == (pattern->getOffset() + pattern->getSize())) {
if (next && pattern->highlightBytes(off - 1) != pattern->highlightBytes(off)) {
return false;
}
if (off >= pattern->getOffset() && off < (pattern->getOffset() + pattern->getSize())) {
_this->m_memoryEditor.HighlightColor = pattern->getColor();
if (auto color = pattern->highlightBytes(off); color.has_value()) {
_this->m_memoryEditor.HighlightColor = color.value();
return true;
}
}

View File

@ -4,11 +4,12 @@
#include "lang/parser.hpp"
#include "lang/lexer.hpp"
#include "lang/validator.hpp"
#include "lang/evaluator.hpp"
#include "utils.hpp"
namespace hex {
ViewPattern::ViewPattern(prv::Provider* &dataProvider, std::vector<hex::PatternData*> &patternData)
ViewPattern::ViewPattern(prv::Provider* &dataProvider, std::vector<lang::PatternData*> &patternData)
: View(), m_dataProvider(dataProvider), m_patternData(patternData) {
this->m_buffer = new char[0xFF'FFFF];
@ -84,16 +85,12 @@ namespace hex {
}
void ViewPattern::addPatternData(PatternData *patternData) {
this->m_patternData.push_back(patternData);
}
void ViewPattern::clearPatternData() {
for (auto &data : this->m_patternData)
delete data;
this->m_patternData.clear();
PatternData::resetPalette();
lang::PatternData::resetPalette();
}
template<std::derived_from<lang::ASTNode> T>
@ -108,10 +105,11 @@ namespace hex {
}
void ViewPattern::parsePattern(char *buffer) {
static hex::lang::Preprocessor preprocessor;
static hex::lang::Lexer lexer;
static hex::lang::Parser parser;
static hex::lang::Validator validator;
hex::lang::Preprocessor preprocessor;
hex::lang::Lexer lexer;
hex::lang::Parser parser;
hex::lang::Validator validator;
hex::lang::Evaluator evaluator;
this->clearPatternData();
this->postEvent(Events::PatternChanged);
@ -127,275 +125,23 @@ namespace hex {
auto [parseResult, ast] = parser.parse(tokens);
if (parseResult.failed()) {
for(auto &node : ast) delete node;
return;
}
hex::ScopeExit deleteAst([&ast]{ for(auto &node : ast) delete node; });
auto validatorResult = validator.validate(ast);
if (!validatorResult) {
for(auto &node : ast) delete node;
return;
}
for (auto &varNode : findNodes<lang::ASTNodeVariableDecl>(lang::ASTNode::Type::VariableDecl, ast)) {
if (!varNode->getOffset().has_value())
continue;
u64 offset = varNode->getOffset().value();
if (varNode->getVariableType() != lang::Token::TypeToken::Type::CustomType) {
size_t size = getTypeSize(varNode->getVariableType()) * varNode->getArraySize();
if (isUnsigned(varNode->getVariableType()))
this->addPatternData(new PatternDataUnsigned(offset, size, varNode->getVariableName()));
else if (isSigned(varNode->getVariableType())) {
if (getTypeSize(varNode->getVariableType()) == 1 && varNode->getArraySize() == 1)
this->addPatternData(new PatternDataCharacter(offset, size, varNode->getVariableName()));
else if (getTypeSize(varNode->getVariableType()) == 1 && varNode->getArraySize() > 1)
this->addPatternData(new PatternDataString(offset, size, varNode->getVariableName()));
else
this->addPatternData(new PatternDataSigned(offset, size, varNode->getVariableName()));
}
else if (isFloatingPoint(varNode->getVariableType()))
this->addPatternData(new PatternDataFloat(offset, size, varNode->getVariableName()));
} else {
for (auto &structNode : findNodes<lang::ASTNodeStruct>(lang::ASTNode::Type::Struct, ast)) {
if (varNode->getCustomVariableTypeName() == structNode->getName()) {
for (u32 i = 0; i < varNode->getArraySize(); i++) {
std::string name = varNode->getVariableName();
if (varNode->getArraySize() > 1)
name += "[" + std::to_string(varNode->getArraySize()) + "]";
if (size_t size = this->highlightStruct(ast, structNode, offset, name); size == -1)
this->clearPatternData();
else
offset += size;
}
}
}
for (auto &enumNode : findNodes<lang::ASTNodeEnum>(lang::ASTNode::Type::Enum, ast)) {
if (varNode->getCustomVariableTypeName() == enumNode->getName()) {
for (u32 i = 0; i < varNode->getArraySize(); i++) {
std::string name = varNode->getVariableName();
if (varNode->getArraySize() > 1)
name += "[" + std::to_string(varNode->getArraySize()) + "]";
if (size_t size = this->highlightEnum(ast, enumNode, offset, name); size == -1)
this->clearPatternData();
else
offset += size;
}
}
}
for (auto &usingNode : findNodes<lang::ASTNodeTypeDecl>(lang::ASTNode::Type::TypeDecl, ast)) {
if (varNode->getCustomVariableTypeName() == usingNode->getTypeName()) {
for (u32 i = 0; i < varNode->getArraySize(); i++) {
std::string name = varNode->getVariableName();
if (varNode->getArraySize() > 1)
name += "[" + std::to_string(varNode->getArraySize()) + "]";
if (size_t size = this->highlightUsingDecls(ast, usingNode, varNode, offset, name); size == -1)
this->clearPatternData();
else
offset += size;
}
}
}
}
auto [evaluateResult, patternData] = evaluator.evaluate(ast);
if (evaluateResult.failed()) {
return;
}
this->m_patternData = patternData;
for(auto &node : ast) delete node;
this->postEvent(Events::PatternChanged);
}
s32 ViewPattern::highlightUsingDecls(std::vector<lang::ASTNode*> &ast, lang::ASTNodeTypeDecl* currTypeDeclNode, lang::ASTNodeVariableDecl* currVarDecl, u64 offset, std::string name) {
u64 startOffset = offset;
if (currTypeDeclNode->getAssignedType() != lang::Token::TypeToken::Type::CustomType) {
size_t size = (static_cast<u32>(currTypeDeclNode->getAssignedType()) >> 4);
if (isUnsigned(currTypeDeclNode->getAssignedType()))
this->addPatternData(new PatternDataUnsigned(offset, size, name));
else if (isSigned(currTypeDeclNode->getAssignedType()))
this->addPatternData(new PatternDataSigned(offset, size, name));
else if (isFloatingPoint(currTypeDeclNode->getAssignedType()))
this->addPatternData(new PatternDataFloat(offset, size, name));
offset += size;
} else {
bool foundType = false;
for (auto &structNode : findNodes<lang::ASTNodeStruct>(lang::ASTNode::Type::Struct, ast)) {
if (structNode->getName() == currTypeDeclNode->getAssignedCustomTypeName()) {
for (size_t i = 0; i < currVarDecl->getArraySize(); i++) {
size_t size = this->highlightStruct(ast, structNode, offset, name);
if (size == -1)
return -1;
offset += size;
}
foundType = true;
break;
}
}
for (auto &enumNode : findNodes<lang::ASTNodeEnum>(lang::ASTNode::Type::Enum, ast)) {
if (enumNode->getName() == currTypeDeclNode->getAssignedCustomTypeName()) {
for (size_t i = 0; i < currVarDecl->getArraySize(); i++) {
size_t size = this->highlightEnum(ast, enumNode, offset, name);
if (size == -1)
return -1;
offset += size;
}
foundType = true;
break;
}
}
for (auto &typeDeclNode : findNodes<lang::ASTNodeTypeDecl>(lang::ASTNode::Type::TypeDecl, ast)) {
if (typeDeclNode->getTypeName() == currTypeDeclNode->getAssignedCustomTypeName()) {
for (size_t i = 0; i < currVarDecl->getArraySize(); i++) {
size_t size = this->highlightUsingDecls(ast, typeDeclNode, currVarDecl, offset, name);
if (size == -1)
return -1;
offset += size;
}
foundType = true;
break;
}
}
if (!foundType)
return -1;
}
return offset - startOffset;
}
s32 ViewPattern::highlightStruct(std::vector<lang::ASTNode*> &ast, lang::ASTNodeStruct* currStructNode, u64 offset, std::string name) {
u64 startOffset = offset;
for (auto &node : currStructNode->getNodes()) {
auto varNode = static_cast<lang::ASTNodeVariableDecl*>(node);
if (varNode->getVariableType() != lang::Token::TypeToken::Type::CustomType) {
size_t size = (static_cast<u32>(varNode->getVariableType()) >> 4);
for (size_t i = 0; i < varNode->getArraySize(); i++) {
std::string memberName = name + "." + varNode->getVariableName();
if (varNode->getArraySize() > 1)
memberName += "[" + std::to_string(i) + "]";
if (isUnsigned(varNode->getVariableType()))
this->addPatternData(new PatternDataUnsigned(offset, size, memberName));
else if (isSigned(varNode->getVariableType())) {
if (getTypeSize(varNode->getVariableType()) == 1 && varNode->getArraySize() == 1)
this->addPatternData(new PatternDataCharacter(offset, size, memberName));
else if (getTypeSize(varNode->getVariableType()) == 1 && varNode->getArraySize() > 1) {
this->addPatternData(new PatternDataString(offset, size * varNode->getArraySize(), name + "." + varNode->getVariableName()));
offset += size * varNode->getArraySize();
break;
}
else
this->addPatternData(new PatternDataSigned(offset, size, memberName));
}
else if (isFloatingPoint(varNode->getVariableType()))
this->addPatternData(new PatternDataFloat(offset, size, memberName));
offset += size;
}
} else {
bool foundType = false;
for (auto &structNode : findNodes<lang::ASTNodeStruct>(lang::ASTNode::Type::Struct, ast)) {
if (structNode->getName() == varNode->getCustomVariableTypeName()) {
for (size_t i = 0; i < varNode->getArraySize(); i++) {
std::string memberName = name + "." + varNode->getVariableName();
if (varNode->getArraySize() > 1)
memberName += "[" + std::to_string(i) + "]";
size_t size = this->highlightStruct(ast, structNode, offset, memberName);
if (size == -1)
return -1;
offset += size;
}
foundType = true;
break;
}
}
for (auto &enumNode : findNodes<lang::ASTNodeEnum>(lang::ASTNode::Type::Enum, ast)) {
if (enumNode->getName() == varNode->getCustomVariableTypeName()) {
for (size_t i = 0; i < varNode->getArraySize(); i++) {
std::string memberName = name + "." + varNode->getVariableName();
if (varNode->getArraySize() > 1)
memberName += "[" + std::to_string(i) + "]";
size_t size = this->highlightEnum(ast, enumNode, offset, memberName);
if (size == -1)
return -1;
offset += size;
}
foundType = true;
break;
}
}
for (auto &typeDeclNode : findNodes<lang::ASTNodeTypeDecl>(lang::ASTNode::Type::TypeDecl, ast)) {
if (typeDeclNode->getTypeName() == varNode->getCustomVariableTypeName()) {
for (size_t i = 0; i < varNode->getArraySize(); i++) {
std::string memberName = name + "." + varNode->getVariableName();
if (varNode->getArraySize() > 1)
memberName += "[" + std::to_string(i) + "]";
size_t size = this->highlightUsingDecls(ast, typeDeclNode, varNode, offset, memberName);
if (size == -1)
return -1;
offset += size;
}
foundType = true;
break;
}
}
if (!foundType)
return -1;
}
}
return offset - startOffset;
}
s32 ViewPattern::highlightEnum(std::vector<lang::ASTNode*> &ast, lang::ASTNodeEnum* currEnumNode, u64 offset, std::string name) {
if (!isUnsigned(currEnumNode->getUnderlyingType()))
return -1;
s32 size = static_cast<u32>(currEnumNode->getUnderlyingType()) >> 4;
if (size > 8)
return -1;
this->addPatternData(new PatternDataEnum(offset, size, name, currEnumNode->getName(), currEnumNode->getValues()));
return size;
}
}

View File

@ -1,10 +1,11 @@
#include "views/view_pattern_data.hpp"
#include "providers/provider.hpp"
#include "lang/pattern_data.hpp"
namespace hex {
ViewPatternData::ViewPatternData(prv::Provider* &dataProvider, std::vector<hex::PatternData*> &patternData)
ViewPatternData::ViewPatternData(prv::Provider* &dataProvider, std::vector<lang::PatternData*> &patternData)
: View(), m_dataProvider(dataProvider), m_patternData(patternData) {
this->subscribeEvent(Events::PatternChanged, [this](auto data) {
@ -25,85 +26,10 @@ namespace hex {
if (this->m_dataProvider != nullptr && this->m_dataProvider->isReadable()) {
if (ImGui::BeginTable("##patterndatatable", 6, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg)) {
ImGui::TableSetupColumn("Color", 0, -1, ImGui::GetID("color"));
ImGui::TableSetupColumn("Name", 0, -1, ImGui::GetID("name"));
ImGui::TableSetupColumn("Position", 0, -1, ImGui::GetID("position"));
ImGui::TableSetupColumn("Size", 0, -1, ImGui::GetID("size"));
ImGui::TableSetupColumn("Type", 0, -1, ImGui::GetID("type"));
ImGui::TableSetupColumn("Value", 0, -1, ImGui::GetID("value"));
auto sortSpecs = ImGui::TableGetSortSpecs();
if (sortSpecs->SpecsDirty || this->m_sortedPatternData.empty()) {
this->m_sortedPatternData = this->m_patternData;
std::sort(this->m_sortedPatternData.begin(), this->m_sortedPatternData.end(), [this, &sortSpecs](PatternData* left, PatternData* right) -> bool {
if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("name")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return left->getName() > right->getName();
else
return left->getName() < right->getName();
}
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("position")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return left->getOffset() > right->getOffset();
else
return left->getOffset() < right->getOffset();
}
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("size")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return left->getSize() > right->getSize();
else
return left->getSize() < right->getSize();
}
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("value")) {
size_t biggerSize = std::max(left->getSize(), right->getSize());
std::vector<u8> leftBuffer(biggerSize, 0x00), rightBuffer(biggerSize, 0x00);
this->m_dataProvider->read(left->getOffset(), leftBuffer.data(), left->getSize());
this->m_dataProvider->read(right->getOffset(), rightBuffer.data(), right->getSize());
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return leftBuffer > rightBuffer;
else
return leftBuffer < rightBuffer;
}
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("type")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return left->getTypeName() > right->getTypeName();
else
return left->getTypeName() < right->getTypeName();
}
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("color")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return left->getColor() > right->getColor();
else
return left->getColor() < right->getColor();
}
return false;
});
sortSpecs->SpecsDirty = false;
}
ImGui::TableHeadersRow();
if (lang::PatternData::beginPatternDataTable(this->m_dataProvider, this->m_patternData, this->m_sortedPatternData)) {
u32 rowCount = 0;
for (auto& patternData : this->m_sortedPatternData) {
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(patternData->getColor()), ImGuiColorEditFlags_NoTooltip);
ImGui::TableNextColumn();
ImGui::Text("%s", patternData->getName().c_str());
ImGui::TableNextColumn();
ImGui::Text("0x%08lx : 0x%08lx", patternData->getOffset(), patternData->getOffset() + patternData->getSize());
ImGui::TableNextColumn();
ImGui::Text("0x%08lx", patternData->getSize());
ImGui::TableNextColumn();
ImGui::Text("%s", patternData->getTypeName().c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", patternData->format(this->m_dataProvider).c_str());
patternData->createEntry(this->m_dataProvider);
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, ((rowCount % 2) == 0) ? 0xFF101010 : 0xFF303030);
rowCount++;
}