2020-11-19 11:36:52 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <hex.hpp>
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#include "imgui.h"
|
|
|
|
#include "imgui_memory_editor.h"
|
|
|
|
|
|
|
|
#include "providers/provider.hpp"
|
2020-11-28 21:55:52 +01:00
|
|
|
#include "helpers/utils.hpp"
|
2020-11-19 11:36:52 +01:00
|
|
|
|
|
|
|
#include <random>
|
|
|
|
|
|
|
|
namespace hex::lang {
|
|
|
|
|
2020-11-23 13:10:14 +01:00
|
|
|
using namespace ::std::literals::string_literals;
|
|
|
|
|
2020-11-19 11:36:52 +01:00
|
|
|
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:
|
2020-11-20 21:59:27 +01:00
|
|
|
enum class Type { Padding, Unsigned, Signed, Float, Character, String, Struct, Union, Array, Enum };
|
2020-11-19 21:19:03 +01:00
|
|
|
|
|
|
|
PatternData(Type type, u64 offset, size_t size, const std::string &name, u32 color = 0)
|
|
|
|
: m_type(type), m_offset(offset), m_size(size), m_color(color), m_name(name) {
|
2020-11-19 11:36:52 +01:00
|
|
|
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;
|
|
|
|
|
2020-11-19 21:19:03 +01:00
|
|
|
[[nodiscard]] Type getPatternType() const { return this->m_type; }
|
2020-11-19 11:36:52 +01:00
|
|
|
[[nodiscard]] u64 getOffset() const { return this->m_offset; }
|
|
|
|
[[nodiscard]] size_t getSize() const { return this->m_size; }
|
2020-11-21 23:00:09 +01:00
|
|
|
|
2020-11-21 20:19:33 +01:00
|
|
|
[[nodiscard]] const std::string& getName() const { return this->m_name; }
|
2020-11-21 23:00:09 +01:00
|
|
|
void setName(std::string name) { this->m_name = name; }
|
2020-11-19 11:36:52 +01:00
|
|
|
|
|
|
|
[[nodiscard]] u32 getColor() const { return this->m_color; }
|
2020-11-21 20:19:33 +01:00
|
|
|
void setColor(u32 color) { this->m_color = color; }
|
2020-11-19 11:36:52 +01:00
|
|
|
|
|
|
|
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 { };
|
|
|
|
}
|
|
|
|
|
2020-11-19 21:19:03 +01:00
|
|
|
virtual void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) { }
|
2020-11-19 11:36:52 +01:00
|
|
|
|
2020-11-19 21:19:03 +01:00
|
|
|
static bool sortPatternDataTable(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider, lang::PatternData* left, lang::PatternData* right) {
|
|
|
|
if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("name")) {
|
|
|
|
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
|
|
|
return left->getName() > right->getName();
|
|
|
|
else
|
|
|
|
return left->getName() < right->getName();
|
|
|
|
}
|
2020-11-20 00:16:50 +01:00
|
|
|
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("offset")) {
|
2020-11-19 21:19:03 +01:00
|
|
|
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);
|
2020-11-19 11:36:52 +01:00
|
|
|
|
2020-11-19 21:19:03 +01:00
|
|
|
provider->read(left->getOffset(), leftBuffer.data(), left->getSize());
|
|
|
|
provider->read(right->getOffset(), rightBuffer.data(), right->getSize());
|
|
|
|
|
2020-11-22 16:22:02 +01:00
|
|
|
if (PatternData::s_endianess != std::endian::native) {
|
|
|
|
std::reverse(leftBuffer.begin(), leftBuffer.end());
|
|
|
|
std::reverse(rightBuffer.begin(), rightBuffer.end());
|
|
|
|
}
|
|
|
|
|
2020-11-19 21:19:03 +01:00
|
|
|
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();
|
2020-11-19 11:36:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-11-19 21:19:03 +01:00
|
|
|
static void resetPalette() { PatternData::s_paletteOffset = 0; }
|
2020-11-22 16:22:02 +01:00
|
|
|
static void setEndianess(std::endian endianess) { PatternData::s_endianess = endianess; }
|
2020-11-19 21:19:03 +01:00
|
|
|
|
2020-11-19 11:36:52 +01:00
|
|
|
protected:
|
|
|
|
void createDefaultEntry(std::string value) {
|
|
|
|
ImGui::TableNextRow();
|
2020-11-23 22:14:11 +01:00
|
|
|
ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
|
2020-11-19 11:36:52 +01:00
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 22:14:11 +01:00
|
|
|
if (ImGui::Selectable(("##PatternDataLine"s + std::to_string(this->getOffset())).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
2020-11-23 13:10:14 +01:00
|
|
|
Region selectRegion = { this->getOffset(), this->getSize() };
|
|
|
|
View::postEvent(Events::SelectionChangeRequest, &selectRegion);
|
|
|
|
}
|
|
|
|
ImGui::SameLine();
|
2020-11-19 11:36:52 +01:00
|
|
|
ImGui::Text("%s", this->getName().c_str());
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 22:14:11 +01:00
|
|
|
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), 14));
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-20 20:26:19 +01:00
|
|
|
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
2020-11-19 11:36:52 +01:00
|
|
|
ImGui::TableNextColumn();
|
2020-11-19 21:43:03 +01:00
|
|
|
ImGui::Text("0x%04lx", this->getSize());
|
2020-11-19 11:36:52 +01:00
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 15:22:26 +01:00
|
|
|
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->getTypeName().c_str());
|
2020-11-19 11:36:52 +01:00
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::Text("%s", value.c_str());
|
|
|
|
}
|
|
|
|
|
2020-11-22 16:22:02 +01:00
|
|
|
protected:
|
|
|
|
static inline std::endian s_endianess = std::endian::native;
|
|
|
|
|
2020-11-19 11:36:52 +01:00
|
|
|
private:
|
2020-11-19 21:19:03 +01:00
|
|
|
Type m_type;
|
2020-11-19 11:36:52 +01:00
|
|
|
u64 m_offset;
|
|
|
|
size_t m_size;
|
|
|
|
|
|
|
|
u32 m_color;
|
|
|
|
std::string m_name;
|
|
|
|
|
|
|
|
static inline u8 s_paletteOffset = 0;
|
2020-11-22 16:22:02 +01:00
|
|
|
|
2020-11-19 11:36:52 +01:00
|
|
|
};
|
|
|
|
|
2020-11-20 21:59:27 +01:00
|
|
|
class PatternDataPadding : public PatternData {
|
|
|
|
public:
|
|
|
|
PatternDataPadding(u64 offset, size_t size) : PatternData(Type::Padding, offset, size, "", 0x00FFFFFF) { }
|
|
|
|
|
|
|
|
void createEntry(prv::Provider* &provider) override {
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getTypeName() override {
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
};
|
2020-11-19 11:36:52 +01:00
|
|
|
|
2020-11-21 23:00:09 +01:00
|
|
|
class PatternDataPointer : public PatternData {
|
|
|
|
public:
|
|
|
|
PatternDataPointer(u64 offset, size_t size, const std::string &name, PatternData *pointedAt, u32 color = 0)
|
|
|
|
: PatternData(Type::Unsigned, offset, size, name, color), m_pointedAt(pointedAt) {
|
|
|
|
this->m_pointedAt->setName("*" + this->m_pointedAt->getName());
|
|
|
|
}
|
|
|
|
|
|
|
|
void createEntry(prv::Provider* &provider) override {
|
|
|
|
u64 data = 0;
|
|
|
|
provider->read(this->getOffset(), &data, this->getSize());
|
2020-11-22 16:22:02 +01:00
|
|
|
data = hex::changeEndianess(data, this->getSize(), PatternData::s_endianess);
|
2020-11-21 23:00:09 +01:00
|
|
|
|
2020-11-23 13:08:24 +01:00
|
|
|
ImGui::TableNextRow();
|
2020-11-21 23:00:09 +01:00
|
|
|
ImGui::TableNextColumn();
|
|
|
|
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 22:14:11 +01:00
|
|
|
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), 14));
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-21 23:00:09 +01:00
|
|
|
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::Text("0x%04lx", this->getSize());
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 15:22:26 +01:00
|
|
|
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->getTypeName().c_str());
|
2020-11-21 23:00:09 +01:00
|
|
|
ImGui::TableNextColumn();
|
2020-11-22 02:25:25 +01:00
|
|
|
ImGui::Text("*(0x%0*llx)", this->getSize() * 2, data);
|
2020-11-21 23:00:09 +01:00
|
|
|
|
|
|
|
if (open) {
|
|
|
|
this->m_pointedAt->createEntry(provider);
|
|
|
|
|
|
|
|
ImGui::TreePop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual std::optional<u32> highlightBytes(size_t offset) {
|
|
|
|
if (offset >= this->getOffset() && offset < (this->getOffset() + this->getSize()))
|
|
|
|
return this->getColor();
|
|
|
|
else if (auto color = this->m_pointedAt->highlightBytes(offset); color.has_value())
|
|
|
|
return color.value();
|
|
|
|
else
|
|
|
|
return { };
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getTypeName() override {
|
|
|
|
return "Pointer";
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
PatternData *m_pointedAt;
|
|
|
|
};
|
|
|
|
|
2020-11-19 11:36:52 +01:00
|
|
|
class PatternDataUnsigned : public PatternData {
|
|
|
|
public:
|
2020-11-19 21:19:03 +01:00
|
|
|
PatternDataUnsigned(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(Type::Unsigned, offset, size, name, color) { }
|
2020-11-19 11:36:52 +01:00
|
|
|
|
|
|
|
void createEntry(prv::Provider* &provider) override {
|
|
|
|
u64 data = 0;
|
|
|
|
provider->read(this->getOffset(), &data, this->getSize());
|
2020-11-22 16:22:02 +01:00
|
|
|
data = hex::changeEndianess(data, this->getSize(), PatternData::s_endianess);
|
2020-11-19 11:36:52 +01:00
|
|
|
|
2020-11-19 21:43:03 +01:00
|
|
|
this->createDefaultEntry(hex::format("%lu (0x%0*lx)", data, this->getSize() * 2, data));
|
2020-11-19 11:36:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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:
|
2020-11-19 21:19:03 +01:00
|
|
|
PatternDataSigned(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(Type::Signed, offset, size, name, color) { }
|
2020-11-19 11:36:52 +01:00
|
|
|
|
|
|
|
void createEntry(prv::Provider* &provider) override {
|
|
|
|
u64 data = 0;
|
|
|
|
provider->read(this->getOffset(), &data, this->getSize());
|
2020-11-22 16:22:02 +01:00
|
|
|
data = hex::changeEndianess(data, this->getSize(), PatternData::s_endianess);
|
2020-11-19 11:36:52 +01:00
|
|
|
|
|
|
|
s64 signedData = signedData = hex::signExtend(data, this->getSize(), 64);
|
|
|
|
|
2020-11-19 21:30:39 +01:00
|
|
|
this->createDefaultEntry(hex::format("%ld (0x%0*lx)", signedData, this->getSize() * 2, data));
|
2020-11-19 11:36:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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:
|
2020-11-19 21:19:03 +01:00
|
|
|
PatternDataFloat(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(Type::Float, offset, size, name, color) { }
|
2020-11-19 11:36:52 +01:00
|
|
|
|
|
|
|
void createEntry(prv::Provider* &provider) override {
|
|
|
|
double formatData = 0;
|
|
|
|
if (this->getSize() == 4) {
|
|
|
|
float data = 0;
|
|
|
|
provider->read(this->getOffset(), &data, 4);
|
2020-11-22 16:22:02 +01:00
|
|
|
data = hex::changeEndianess(data, 4, PatternData::s_endianess);
|
|
|
|
|
2020-11-19 11:36:52 +01:00
|
|
|
formatData = data;
|
|
|
|
} else if (this->getSize() == 8) {
|
|
|
|
double data = 0;
|
|
|
|
provider->read(this->getOffset(), &data, 8);
|
2020-11-22 16:22:02 +01:00
|
|
|
data = hex::changeEndianess(data, 8, PatternData::s_endianess);
|
|
|
|
|
2020-11-19 11:36:52 +01:00
|
|
|
formatData = data;
|
|
|
|
}
|
|
|
|
|
2020-11-19 21:30:39 +01:00
|
|
|
this->createDefaultEntry(hex::format("%f (0x%0*lx)", formatData, this->getSize() * 2, formatData));
|
2020-11-19 11:36:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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:
|
2020-11-19 21:19:03 +01:00
|
|
|
PatternDataCharacter(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(Type::Character, offset, size, name, color) { }
|
2020-11-19 11:36:52 +01:00
|
|
|
|
|
|
|
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:
|
2020-11-19 21:19:03 +01:00
|
|
|
PatternDataString(u64 offset, size_t size, const std::string &name, u32 color = 0) : PatternData(Type::String, offset, size, name, color) { }
|
2020-11-19 11:36:52 +01:00
|
|
|
|
|
|
|
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)
|
2020-11-19 21:19:03 +01:00
|
|
|
: PatternData(Type::Array, offset, size, name, color), m_entries(entries) { }
|
2020-11-19 11:36:52 +01:00
|
|
|
|
|
|
|
void createEntry(prv::Provider* &provider) override {
|
2020-11-23 13:08:24 +01:00
|
|
|
ImGui::TableNextRow();
|
2020-11-19 11:36:52 +01:00
|
|
|
ImGui::TableNextColumn();
|
|
|
|
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 22:14:11 +01:00
|
|
|
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), 14));
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-20 20:26:19 +01:00
|
|
|
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
2020-11-19 11:36:52 +01:00
|
|
|
ImGui::TableNextColumn();
|
2020-11-19 21:43:03 +01:00
|
|
|
ImGui::Text("0x%04lx", this->getSize());
|
2020-11-19 11:36:52 +01:00
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 15:22:26 +01:00
|
|
|
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->m_entries[0]->getTypeName().c_str());
|
|
|
|
ImGui::SameLine(0, 0);
|
|
|
|
|
|
|
|
ImGui::TextUnformatted("[");
|
|
|
|
ImGui::SameLine(0, 0);
|
|
|
|
ImGui::TextColored(ImColor(0xFF00FF00), "%llu", this->m_entries.size());
|
|
|
|
ImGui::SameLine(0, 0);
|
|
|
|
ImGui::TextUnformatted("]");
|
|
|
|
|
2020-11-19 11:36:52 +01:00
|
|
|
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)
|
2020-11-19 21:19:03 +01:00
|
|
|
: PatternData(Type::Struct, offset, size, name, color), m_structName(structName), m_members(members), m_sortedMembers(members) { }
|
2020-11-19 11:36:52 +01:00
|
|
|
|
|
|
|
void createEntry(prv::Provider* &provider) override {
|
2020-11-23 13:08:24 +01:00
|
|
|
ImGui::TableNextRow();
|
2020-11-19 11:36:52 +01:00
|
|
|
ImGui::TableNextColumn();
|
|
|
|
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 22:14:11 +01:00
|
|
|
ImGui::TableNextColumn();
|
2020-11-20 20:26:19 +01:00
|
|
|
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
2020-11-19 11:36:52 +01:00
|
|
|
ImGui::TableNextColumn();
|
2020-11-19 21:43:03 +01:00
|
|
|
ImGui::Text("0x%04lx", this->getSize());
|
2020-11-19 11:36:52 +01:00
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 15:22:26 +01:00
|
|
|
ImGui::TextColored(ImColor(0xFFD69C56), "struct"); ImGui::SameLine(); ImGui::Text("%s", this->m_structName.c_str());
|
2020-11-19 11:36:52 +01:00
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::Text("%s", "{ ... }");
|
|
|
|
|
|
|
|
if (open) {
|
2020-11-19 21:19:03 +01:00
|
|
|
for (auto &member : this->m_sortedMembers)
|
2020-11-19 11:36:52 +01:00
|
|
|
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 { };
|
|
|
|
}
|
|
|
|
|
2020-11-19 21:19:03 +01:00
|
|
|
void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) override {
|
|
|
|
this->m_sortedMembers = this->m_members;
|
|
|
|
|
|
|
|
std::sort(this->m_sortedMembers.begin(), this->m_sortedMembers.end(), [&sortSpecs, &provider](PatternData *left, PatternData *right) {
|
|
|
|
return PatternData::sortPatternDataTable(sortSpecs, provider, left, right);
|
|
|
|
});
|
|
|
|
|
|
|
|
for (auto &member : this->m_members)
|
|
|
|
member->sort(sortSpecs, provider);
|
|
|
|
}
|
|
|
|
|
2020-11-19 11:36:52 +01:00
|
|
|
std::string getTypeName() override {
|
|
|
|
return "struct " + this->m_structName;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::string m_structName;
|
|
|
|
std::vector<PatternData*> m_members;
|
|
|
|
std::vector<PatternData*> m_sortedMembers;
|
|
|
|
};
|
|
|
|
|
2020-11-20 21:29:28 +01:00
|
|
|
class PatternDataUnion : public PatternData {
|
|
|
|
public:
|
|
|
|
PatternDataUnion(u64 offset, size_t size, const std::string &name, const std::string &unionName, const std::vector<PatternData*> & members, u32 color = 0)
|
|
|
|
: PatternData(Type::Union, offset, size, name, color), m_unionName(unionName), m_members(members), m_sortedMembers(members) { }
|
|
|
|
|
|
|
|
void createEntry(prv::Provider* &provider) override {
|
2020-11-23 13:08:24 +01:00
|
|
|
ImGui::TableNextRow();
|
2020-11-20 21:29:28 +01:00
|
|
|
ImGui::TableNextColumn();
|
|
|
|
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 22:14:11 +01:00
|
|
|
ImGui::TableNextColumn();
|
2020-11-20 21:29:28 +01:00
|
|
|
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::Text("0x%04lx", this->getSize());
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 15:22:26 +01:00
|
|
|
ImGui::TextColored(ImColor(0xFFD69C56), "union"); ImGui::SameLine(); ImGui::Text("%s", this->m_unionName.c_str());
|
|
|
|
|
2020-11-20 21:29:28 +01:00
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::Text("%s", "{ ... }");
|
|
|
|
|
|
|
|
if (open) {
|
|
|
|
for (auto &member : this->m_sortedMembers)
|
|
|
|
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 { };
|
|
|
|
}
|
|
|
|
|
|
|
|
void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) override {
|
|
|
|
this->m_sortedMembers = this->m_members;
|
|
|
|
|
|
|
|
std::sort(this->m_sortedMembers.begin(), this->m_sortedMembers.end(), [&sortSpecs, &provider](PatternData *left, PatternData *right) {
|
|
|
|
return PatternData::sortPatternDataTable(sortSpecs, provider, left, right);
|
|
|
|
});
|
|
|
|
|
|
|
|
for (auto &member : this->m_members)
|
|
|
|
member->sort(sortSpecs, provider);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getTypeName() override {
|
|
|
|
return "union " + this->m_unionName;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::string m_unionName;
|
|
|
|
std::vector<PatternData*> m_members;
|
|
|
|
std::vector<PatternData*> m_sortedMembers;
|
|
|
|
};
|
|
|
|
|
2020-11-19 11:36:52 +01:00
|
|
|
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)
|
2020-11-19 21:19:03 +01:00
|
|
|
: PatternData(Type::Enum, offset, size, name, color), m_enumName(enumName), m_enumValues(enumValues) { }
|
2020-11-19 11:36:52 +01:00
|
|
|
|
|
|
|
void createEntry(prv::Provider* &provider) override {
|
2020-11-19 21:30:12 +01:00
|
|
|
u64 value = 0;
|
|
|
|
provider->read(this->getOffset(), &value, this->getSize());
|
2020-11-22 16:22:02 +01:00
|
|
|
value = hex::changeEndianess(value, this->getSize(), PatternData::s_endianess);
|
2020-11-19 21:30:12 +01:00
|
|
|
|
|
|
|
std::string valueString = this->m_enumName + "::";
|
|
|
|
|
|
|
|
bool foundValue = false;
|
|
|
|
for (auto &[entryValue, entryName] : this->m_enumValues) {
|
|
|
|
if (value == entryValue) {
|
|
|
|
valueString += entryName;
|
|
|
|
foundValue = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!foundValue)
|
|
|
|
valueString += "???";
|
2020-11-19 11:36:52 +01:00
|
|
|
|
2020-11-23 15:22:26 +01:00
|
|
|
ImGui::TableNextRow();
|
|
|
|
ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth);
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
if (ImGui::Selectable(("##PatternDataLine"s + std::to_string(this->getOffset())).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) {
|
|
|
|
Region selectRegion = { this->getOffset(), this->getSize() };
|
|
|
|
View::postEvent(Events::SelectionChangeRequest, &selectRegion);
|
|
|
|
}
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::Text("%s", this->getName().c_str());
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 22:14:11 +01:00
|
|
|
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), 14));
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 15:22:26 +01:00
|
|
|
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::Text("0x%04lx", this->getSize());
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::TextColored(ImColor(0xFFD69C56), "enum"); ImGui::SameLine(); ImGui::Text("%s", this->m_enumName.c_str());
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::Text("%s", hex::format("%s (0x%0*lx)", valueString.c_str(), this->getSize() * 2, value).c_str());
|
2020-11-19 11:36:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
std::string getTypeName() override {
|
|
|
|
return "enum " + this->m_enumName;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::string m_enumName;
|
|
|
|
std::vector<std::pair<u64, std::string>> m_enumValues;
|
|
|
|
};
|
|
|
|
|
2020-11-20 20:26:19 +01:00
|
|
|
class PatternDataBitfield : public PatternData {
|
|
|
|
public:
|
|
|
|
PatternDataBitfield(u64 offset, size_t size, const std::string &name, const std::string &bitfieldName, std::vector<std::pair<std::string, size_t>> fields, u32 color = 0)
|
|
|
|
: PatternData(Type::Enum, offset, size, name, color), m_bitfieldName(bitfieldName), m_fields(fields) { }
|
|
|
|
|
|
|
|
void createEntry(prv::Provider* &provider) override {
|
|
|
|
u64 value = 0;
|
|
|
|
provider->read(this->getOffset(), &value, this->getSize());
|
2020-11-22 16:22:02 +01:00
|
|
|
value = hex::changeEndianess(value, this->getSize(), PatternData::s_endianess);
|
2020-11-20 20:26:19 +01:00
|
|
|
|
2020-11-23 13:08:24 +01:00
|
|
|
ImGui::TableNextRow();
|
2020-11-20 20:26:19 +01:00
|
|
|
ImGui::TableNextColumn();
|
|
|
|
bool open = ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 22:14:11 +01:00
|
|
|
ImGui::TableNextColumn();
|
2020-11-20 20:26:19 +01:00
|
|
|
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::Text("0x%04lx", this->getSize());
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 15:22:26 +01:00
|
|
|
ImGui::TextColored(ImColor(0xFFD69C56), "bitfield"); ImGui::SameLine(); ImGui::Text("%s", this->m_bitfieldName.c_str());
|
2020-11-20 20:26:19 +01:00
|
|
|
ImGui::TableNextColumn();
|
2020-11-20 21:29:28 +01:00
|
|
|
ImGui::Text("{ %llx }", value);
|
2020-11-20 20:26:19 +01:00
|
|
|
|
|
|
|
if (open) {
|
|
|
|
u16 bitOffset = 0;
|
|
|
|
for (auto &[entryName, entrySize] : this->m_fields) {
|
|
|
|
ImGui::TableNextRow();
|
|
|
|
ImGui::TreeNodeEx(this->getName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth);
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::Text("%s", entryName.c_str());
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-23 22:14:11 +01:00
|
|
|
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), 14));
|
|
|
|
ImGui::TableNextColumn();
|
2020-11-20 20:26:19 +01:00
|
|
|
ImGui::Text("0x%08lx : 0x%08lx", this->getOffset() + (bitOffset >> 3), this->getOffset() + ((bitOffset + entrySize) >> 3) - 1);
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
if (entrySize == 1)
|
|
|
|
ImGui::Text("%llu bit", entrySize);
|
|
|
|
else
|
|
|
|
ImGui::Text("%llu bits", entrySize);
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::Text("%s", entryName.c_str());
|
|
|
|
ImGui::TableNextColumn();
|
|
|
|
ImGui::Text("%llx", hex::extract((bitOffset + entrySize) - 1, bitOffset, value));
|
|
|
|
bitOffset += entrySize;
|
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::TreePop();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getTypeName() override {
|
|
|
|
return "bitfield " + this->m_bitfieldName;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::string m_bitfieldName;
|
|
|
|
std::vector<std::pair<std::string, size_t>> m_fields;
|
|
|
|
};
|
|
|
|
|
2020-11-19 11:36:52 +01:00
|
|
|
|
|
|
|
}
|