build: More repo cleanup, move libimhex and external libs to /lib folder

This commit is contained in:
WerWolv
2022-01-16 14:20:52 +01:00
parent a5a1ae6725
commit 40d7e4aa6e
232 changed files with 62 additions and 75 deletions

View File

@@ -0,0 +1,29 @@
#pragma once
#include <cstdint>
#include <cstddef>
constexpr static const auto ImHexApiURL = "https://api.werwolv.net/imhex";
constexpr static const auto GitHubApiURL = "https://api.github.com/repos/WerWolv/ImHex";
using u8 = std::uint8_t;
using u16 = std::uint16_t;
using u32 = std::uint32_t;
using u64 = std::uint64_t;
using u128 = __uint128_t;
using s8 = std::int8_t;
using s16 = std::int16_t;
using s32 = std::int32_t;
using s64 = std::int64_t;
using s128 = __int128_t;
namespace hex {
struct Region {
u64 address;
size_t size;
};
}

View File

@@ -0,0 +1,296 @@
#pragma once
#include <hex.hpp>
#include <hex/helpers/concepts.hpp>
#include <hex/helpers/paths.hpp>
#include <hex/pattern_language/token.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/api/event.hpp>
#include <functional>
#include <map>
#include <string>
#include <string_view>
#include <vector>
#include <nlohmann/json_fwd.hpp>
namespace hex {
class View;
class LanguageDefinition;
namespace pl { class Evaluator; }
namespace dp { class Node; }
namespace prv { class Provider; }
/*
The Content Registry is the heart of all features in ImHex that are in some way extendable by Plugins.
It allows you to add/register new content that will be picked up and used by the ImHex core or by other
plugins when needed.
*/
namespace ContentRegistry {
/* Settings Registry. Allows adding of new entries into the ImHex preferences window. */
namespace Settings {
using Callback = std::function<bool(const std::string&, nlohmann::json&)>;
struct Entry {
std::string name;
Callback callback;
};
void load();
void store();
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, s64 defaultValue, const Callback &callback);
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback);
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, s64 value);
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value);
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string>& value);
s64 read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, s64 defaultValue);
std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue);
std::vector<std::string> read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string>& defaultValue = { });
std::map<std::string, std::vector<Entry>>& getEntries();
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName);
nlohmann::json& getSettingsData();
}
/* Command Palette Command Registry. Allows adding of new commands to the command palette */
namespace CommandPaletteCommands {
enum class Type : u32 {
SymbolCommand,
KeywordCommand
};
using DisplayCallback = std::function<std::string(std::string)>;
using ExecuteCallback = std::function<void(std::string)>;
struct Entry {
Type type;
std::string command;
std::string unlocalizedDescription;
DisplayCallback displayCallback;
ExecuteCallback executeCallback;
};
void add(Type type, const std::string &command, const std::string &unlocalizedDescription, const DisplayCallback &displayCallback, const ExecuteCallback &executeCallback = [](auto){});
std::vector<Entry>& getEntries();
}
/* Pattern Language Function Registry. Allows adding of new functions that may be used inside the pattern language */
namespace PatternLanguage {
constexpr static u32 UnlimitedParameters = 0xFFFF'FFFF;
constexpr static u32 MoreParametersThan = 0x8000'0000;
constexpr static u32 LessParametersThan = 0x4000'0000;
constexpr static u32 NoParameters = 0x0000'0000;
using Namespace = std::vector<std::string>;
using Callback = std::function<std::optional<hex::pl::Token::Literal>(hex::pl::Evaluator*, const std::vector<hex::pl::Token::Literal>&)>;
struct Function {
u32 parameterCount;
Callback func;
bool dangerous;
};
void addFunction(const Namespace &ns, const std::string &name, u32 parameterCount, const Callback &func);
void addDangerousFunction(const Namespace &ns, const std::string &name, u32 parameterCount, const Callback &func);
std::map<std::string, ContentRegistry::PatternLanguage::Function>& getFunctions();
}
/* View Registry. Allows adding of new windows */
namespace Views {
namespace impl {
void add(View *view);
}
template<hex::derived_from<View> T, typename ... Args>
void add(Args&& ... args) {
return impl::add(new T(std::forward<Args>(args)...));
}
std::vector<View*>& getEntries();
}
/* Tools Registry. Allows adding new entries to the tools window */
namespace Tools {
namespace impl {
using Callback = std::function<void()>;
struct Entry {
std::string name;
Callback function;
};
}
void add(const std::string &unlocalizedName, const impl::Callback &function);
std::vector<impl::Entry>& getEntries();
}
/* Data Inspector Registry. Allows adding of new types to the data inspector */
namespace DataInspector {
enum class NumberDisplayStyle {
Decimal,
Hexadecimal,
Octal
};
namespace impl {
using DisplayFunction = std::function<std::string()>;
using GeneratorFunction = std::function<DisplayFunction(const std::vector<u8>&, std::endian, NumberDisplayStyle)>;
struct Entry {
std::string unlocalizedName;
size_t requiredSize;
impl::GeneratorFunction generatorFunction;
};
}
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction function);
std::vector<impl::Entry>& getEntries();
}
/* Data Processor Node Registry. Allows adding new processor nodes to be used in the data processor */
namespace DataProcessorNode {
namespace impl {
using CreatorFunction = std::function<dp::Node*()>;
struct Entry {
std::string category;
std::string name;
CreatorFunction creatorFunction;
};
void add(const Entry &entry);
}
template<hex::derived_from<dp::Node> T, typename ... Args>
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, Args&& ... args) {
add(impl::Entry{ unlocalizedCategory.c_str(), unlocalizedName.c_str(),
[=]{
auto node = new T(std::forward<Args>(args)...);
node->setUnlocalizedName(unlocalizedName);
return node;
}
});
}
void addSeparator();
std::vector<impl::Entry>& getEntries();
}
/* Language Registry. Allows together with the LangEntry class and the _lang user defined literal to add new languages */
namespace Language {
void registerLanguage(const std::string &name, const std::string &languageCode);
void addLocalizations(const std::string &languageCode, const LanguageDefinition &definition);
std::map<std::string, std::string>& getLanguages();
std::map<std::string, std::vector<LanguageDefinition>>& getLanguageDefinitions();
}
/* Interface Registry. Allows adding new items to various interfaces */
namespace Interface {
using DrawCallback = std::function<void()>;
void addWelcomeScreenEntry(const DrawCallback &function);
void addFooterItem(const DrawCallback &function);
void addToolbarItem(const DrawCallback &function);
std::vector<DrawCallback>& getWelcomeScreenEntries();
std::vector<DrawCallback>& getFooterItems();
std::vector<DrawCallback>& getToolbarItems();
}
/* Provider Registry. Allows adding new data providers to be created from the UI */
namespace Provider {
namespace impl {
void addProviderName(const std::string &unlocalizedName);
}
template<hex::derived_from<hex::prv::Provider> T>
void add(const std::string &unlocalizedName, bool addToList = true) {
(void) EventManager::subscribe<RequestCreateProvider>([expectedName = unlocalizedName](const std::string &name, hex::prv::Provider **provider){
if (name != expectedName) return;
auto newProvider = new T();
hex::ImHexApi::Provider::add(newProvider);
if (provider != nullptr)
*provider = newProvider;
});
if (addToList)
impl::addProviderName(unlocalizedName);
}
const std::vector<std::string>& getEntries();
}
namespace DataFormatter {
namespace impl {
using Callback = std::function<std::string(prv::Provider *provider, u64 address, size_t size)>;
struct Entry {
std::string unlocalizedName;
Callback callback;
};
}
void add(const std::string &unlocalizedName, const impl::Callback &callback);
std::vector<impl::Entry>& getEntries();
}
namespace FileHandler {
namespace impl {
using Callback = std::function<bool(fs::path)>;
struct Entry {
std::vector<std::string> extensions;
Callback callback;
};
}
void add(const std::vector<std::string> &extensions, const impl::Callback &callback);
std::vector<impl::Entry>& getEntries();
}
};
}

View File

@@ -0,0 +1,128 @@
#pragma once
#include <hex.hpp>
#include <list>
#include <map>
#include <string_view>
#include <functional>
#include <hex/api/imhex_api.hpp>
#include <hex/helpers/paths.hpp>
#define EVENT_DEF(event_name, ...) \
struct event_name final : public hex::Event<__VA_ARGS__> { \
constexpr static auto id = [] { return hex::EventId(); }(); \
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
}
class GLFWwindow;
namespace hex {
class EventId {
public:
explicit constexpr EventId(const char *func = __builtin_FUNCTION(), u32 line = __builtin_LINE()) {
this->m_hash = line ^ 123456789;
for (auto c : std::string_view(func)) {
this->m_hash = (this->m_hash >> 5) | (this->m_hash << 27);
this->m_hash ^= c;
}
}
constexpr bool operator ==(const EventId &rhs) const = default;
private:
u32 m_hash;
};
struct EventBase {
EventBase() noexcept = default;
};
template<typename ... Params>
struct Event : public EventBase {
using Callback = std::function<void(Params...)>;
explicit Event(Callback func) noexcept : m_func(std::move(func)) {}
void operator()(Params... params) const noexcept {
this->m_func(params...);
}
private:
Callback m_func;
};
class EventManager {
public:
using EventList = std::list<std::pair<EventId, EventBase*>>;
template<typename E>
[[nodiscard]] static EventList::iterator subscribe(typename E::Callback function) {
return s_events.insert(s_events.end(), std::make_pair(E::id, new E(function)));
}
template<typename E>
static void subscribe(void *token, typename E::Callback function) {
s_tokenStore.insert(std::make_pair(token, subscribe<E>(function)));
}
static void unsubscribe(EventList::iterator iter) noexcept {
s_events.remove(*iter);
}
template<typename E>
static void unsubscribe(void *token) noexcept {
auto iter = std::find_if(s_tokenStore.begin(), s_tokenStore.end(), [&](auto &item){
return item.first == token && item.second->first == E::id;
});
if (iter != s_tokenStore.end()) {
s_events.remove(*iter->second);
}
}
template<typename E>
static void post(auto&& ... args) noexcept {
for (const auto &[id, event] : s_events) {
if (id == E::id)
(*reinterpret_cast<E *>(event))(std::forward<decltype(args)>(args)...);
}
}
private:
static std::map<void*, EventList::iterator> s_tokenStore;
static EventList s_events;
};
namespace pl { class PatternData; }
/* Default Events */
EVENT_DEF(EventFileLoaded, fs::path);
EVENT_DEF(EventFileUnloaded);
EVENT_DEF(EventDataChanged);
EVENT_DEF(EventPatternChanged, std::vector<pl::PatternData*>&);
EVENT_DEF(EventWindowClosing, GLFWwindow*);
EVENT_DEF(EventRegionSelected, Region);
EVENT_DEF(EventProjectFileStore);
EVENT_DEF(EventProjectFileLoad);
EVENT_DEF(EventSettingsChanged);
EVENT_DEF(EventAbnormalTermination, int);
EVENT_DEF(EventOSThemeChanged);
EVENT_DEF(EventProviderCreated, prv::Provider*);
EVENT_DEF(RequestOpenWindow, std::string);
EVENT_DEF(RequestSelectionChange, Region);
EVENT_DEF(RequestAddBookmark, ImHexApi::Bookmarks::Entry);
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
EVENT_DEF(RequestChangeWindowTitle, std::string);
EVENT_DEF(RequestCloseImHex, bool);
EVENT_DEF(RequestOpenFile, fs::path);
EVENT_DEF(RequestChangeTheme, u32);
EVENT_DEF(RequestOpenPopup, std::string);
EVENT_DEF(RequestCreateProvider, std::string, hex::prv::Provider **);
EVENT_DEF(QuerySelection, Region&);
}

View File

@@ -0,0 +1,67 @@
#pragma once
#include <hex.hpp>
#include <list>
#include <vector>
#include <string>
#include <hex/helpers/concepts.hpp>
#include <hex/api/task.hpp>
#include <hex/api/keybinding.hpp>
namespace hex {
namespace prv { class Provider; }
namespace ImHexApi {
namespace Common {
void closeImHex(bool noQuestions = false);
void restartImHex();
};
namespace Bookmarks {
struct Entry {
Region region;
std::vector<char> name;
std::vector<char> comment;
u32 color;
bool locked;
};
void add(Region region, const std::string &name, const std::string &comment, u32 color = 0x00000000);
void add(u64 addr, size_t size, const std::string &name, const std::string &comment, u32 color = 0x00000000);
std::list<Entry>& getEntries();
};
namespace Provider {
prv::Provider* get();
const std::vector<prv::Provider*>& getProviders();
bool isValid();
void add(prv::Provider *provider);
template<hex::derived_from<prv::Provider> T>
void add(auto&& ... args) {
add(new T(std::forward<decltype(args)>(args)...));
}
void remove(prv::Provider *provider);
};
namespace Tasks {
Task createTask(const std::string &unlocalizedName, u64 maxValue);
}
};
}

View File

@@ -0,0 +1,190 @@
#pragma once
#include <hex.hpp>
#include <GLFW/glfw3.h>
#include <functional>
#include <map>
#include <set>
struct ImGuiWindow;
namespace hex {
struct View;
enum class Keys {
Space = GLFW_KEY_SPACE,
Apostrophe = GLFW_KEY_APOSTROPHE,
Comma = GLFW_KEY_COMMA,
Minus = GLFW_KEY_MINUS,
Period = GLFW_KEY_PERIOD,
Slash = GLFW_KEY_SLASH,
Num0 = GLFW_KEY_0,
Num1 = GLFW_KEY_1,
Num2 = GLFW_KEY_2,
Num3 = GLFW_KEY_3,
Num4 = GLFW_KEY_4,
Num5 = GLFW_KEY_5,
Num6 = GLFW_KEY_6,
Num7 = GLFW_KEY_7,
Num8 = GLFW_KEY_8,
Num9 = GLFW_KEY_9,
Semicolon = GLFW_KEY_SEMICOLON,
Equals = GLFW_KEY_EQUAL,
A = GLFW_KEY_A,
B = GLFW_KEY_B,
C = GLFW_KEY_C,
D = GLFW_KEY_D,
E = GLFW_KEY_E,
F = GLFW_KEY_F,
G = GLFW_KEY_G,
H = GLFW_KEY_H,
I = GLFW_KEY_I,
J = GLFW_KEY_J,
K = GLFW_KEY_K,
L = GLFW_KEY_L,
M = GLFW_KEY_M,
N = GLFW_KEY_N,
O = GLFW_KEY_O,
P = GLFW_KEY_P,
Q = GLFW_KEY_Q,
R = GLFW_KEY_R,
S = GLFW_KEY_S,
T = GLFW_KEY_T,
U = GLFW_KEY_U,
V = GLFW_KEY_V,
W = GLFW_KEY_W,
X = GLFW_KEY_X,
Y = GLFW_KEY_Y,
Z = GLFW_KEY_Z,
LeftBracket = GLFW_KEY_LEFT_BRACKET,
Backslash = GLFW_KEY_BACKSLASH,
RightBracket = GLFW_KEY_RIGHT_BRACKET,
GraveAccent = GLFW_KEY_GRAVE_ACCENT,
World1 = GLFW_KEY_WORLD_1,
World2 = GLFW_KEY_WORLD_2,
Escape = GLFW_KEY_ESCAPE,
Enter = GLFW_KEY_ENTER,
Tab = GLFW_KEY_TAB,
Backspace = GLFW_KEY_BACKSPACE,
Insert = GLFW_KEY_INSERT,
Delete = GLFW_KEY_DELETE,
Right = GLFW_KEY_RIGHT,
Left = GLFW_KEY_LEFT,
Down = GLFW_KEY_DOWN,
Up = GLFW_KEY_UP,
PageUp = GLFW_KEY_PAGE_UP,
PageDown = GLFW_KEY_PAGE_DOWN,
Home = GLFW_KEY_HOME,
End = GLFW_KEY_END,
CapsLock = GLFW_KEY_CAPS_LOCK,
ScrollLock = GLFW_KEY_SCROLL_LOCK,
NumLock = GLFW_KEY_NUM_LOCK,
PrintScreen = GLFW_KEY_PRINT_SCREEN,
Pause = GLFW_KEY_PAUSE,
F1 = GLFW_KEY_F1,
F2 = GLFW_KEY_F2,
F3 = GLFW_KEY_F3,
F4 = GLFW_KEY_F4,
F5 = GLFW_KEY_F5,
F6 = GLFW_KEY_F6,
F7 = GLFW_KEY_F7,
F8 = GLFW_KEY_F8,
F9 = GLFW_KEY_F9,
F10 = GLFW_KEY_F10,
F11 = GLFW_KEY_F11,
F12 = GLFW_KEY_F12,
F13 = GLFW_KEY_F13,
F14 = GLFW_KEY_F14,
F15 = GLFW_KEY_F15,
F16 = GLFW_KEY_F16,
F17 = GLFW_KEY_F17,
F18 = GLFW_KEY_F18,
F19 = GLFW_KEY_F19,
F20 = GLFW_KEY_F20,
F21 = GLFW_KEY_F21,
F22 = GLFW_KEY_F22,
F23 = GLFW_KEY_F23,
F24 = GLFW_KEY_F24,
F25 = GLFW_KEY_F25,
KeyPad0 = GLFW_KEY_KP_0,
KeyPad1 = GLFW_KEY_KP_1,
KeyPad2 = GLFW_KEY_KP_2,
KeyPad3 = GLFW_KEY_KP_3,
KeyPad4 = GLFW_KEY_KP_4,
KeyPad5 = GLFW_KEY_KP_5,
KeyPad6 = GLFW_KEY_KP_6,
KeyPad7 = GLFW_KEY_KP_7,
KeyPad8 = GLFW_KEY_KP_8,
KeyPad9 = GLFW_KEY_KP_9,
KeyPadDecimal = GLFW_KEY_KP_DECIMAL,
KeyPadDivide = GLFW_KEY_KP_DIVIDE,
KeyPadMultiply = GLFW_KEY_KP_MULTIPLY,
KeyPadSubtract = GLFW_KEY_KP_SUBTRACT,
KeyPadAdd = GLFW_KEY_KP_ADD,
KeyPadEnter = GLFW_KEY_KP_ENTER,
KeyPadEqual = GLFW_KEY_KP_EQUAL,
Menu = GLFW_KEY_MENU,
};
class Key {
public:
constexpr Key(Keys key) :m_key(static_cast<u32>(key)) { }
auto operator<=>(const Key&) const = default;
private:
u32 m_key;
};
class Shortcut {
public:
Shortcut operator+(const Key &other) const {
Shortcut result = *this;
result.m_keys.insert(other);
return result;
}
Shortcut& operator+=(const Key &other) {
this->m_keys.insert(other);
return *this;
}
bool operator<(const Shortcut &other) const {
return this->m_keys < other.m_keys;
}
bool operator==(const Shortcut &other) const {
return this->m_keys == other.m_keys;
}
private:
friend Shortcut operator+(const Key &lhs, const Key &rhs);
std::set<Key> m_keys;
};
inline Shortcut operator+(const Key &lhs, const Key &rhs) {
Shortcut result;
result.m_keys = { lhs, rhs };
return result;
}
static constexpr auto CTRL = Key(static_cast<Keys>(0x1000'0000));
static constexpr auto ALT = Key(static_cast<Keys>(0x2000'0000));
static constexpr auto SHIFT = Key(static_cast<Keys>(0x3000'0000));
static constexpr auto SUPER = Key(static_cast<Keys>(0x4000'0000));
class ShortcutManager {
public:
static void addGlobalShortcut(const Shortcut &shortcut, const std::function<void()> &callback);
static void addShortcut(View *view, const Shortcut &shortcut, const std::function<void()> &callback);
static void process(View *currentView, bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode);
};
}

View File

@@ -0,0 +1,32 @@
#pragma once
#include <hex.hpp>
#include <string>
namespace hex {
class Task {
public:
Task(const std::string& unlocalizedName, u64 maxValue);
~Task();
void setMaxValue(u64 maxValue);
void update(u64 currValue);
void finish();
[[nodiscard]]
double getProgress() const;
[[nodiscard]]
const std::string& getName() const;
[[nodiscard]]
bool isPending() const;
private:
std::string m_name;
u64 m_maxValue, m_currValue;
};
}

View File

@@ -0,0 +1,57 @@
#pragma once
#include <hex.hpp>
#include <optional>
#include <string>
#include <string_view>
#include <map>
#include <vector>
namespace hex::dp {
class Node;
class Attribute {
public:
enum class Type {
Integer,
Float,
Buffer
};
enum class IOType {
In, Out
};
Attribute(IOType ioType, Type type, std::string unlocalizedName);
~Attribute();
[[nodiscard]] u32 getID() const { return this->m_id; }
void setID(u32 id) { this->m_id = id; }
[[nodiscard]] IOType getIOType() const { return this->m_ioType; }
[[nodiscard]] Type getType() const { return this->m_type; }
[[nodiscard]] const std::string& getUnlocalizedName() const { return this->m_unlocalizedName; }
void addConnectedAttribute(u32 linkId, Attribute *to) { this->m_connectedAttributes.insert({ linkId, to }); }
void removeConnectedAttribute(u32 linkId) { this->m_connectedAttributes.erase(linkId); }
[[nodiscard]] std::map<u32, Attribute*>& getConnectedAttributes() { return this->m_connectedAttributes; }
[[nodiscard]] Node* getParentNode() { return this->m_parentNode; }
[[nodiscard]] std::optional<std::vector<u8>>& getOutputData() { return this->m_outputData; }
private:
u32 m_id;
IOType m_ioType;
Type m_type;
std::string m_unlocalizedName;
std::map<u32, Attribute*> m_connectedAttributes;
Node *m_parentNode = nullptr;
std::optional<std::vector<u8>> m_outputData;
friend class Node;
void setParentNode(Node *node) { this->m_parentNode = node; }
};
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include <hex.hpp>
namespace hex::dp {
class Link {
public:
Link(u32 from, u32 to);
[[nodiscard]] u32 getID() const { return this->m_id; }
void setID(u32 id) { this->m_id = id; }
[[nodiscard]] u32 getFromID() const { return this->m_from; }
[[nodiscard]] u32 getToID() const { return this->m_to; }
private:
u32 m_id;
u32 m_from, m_to;
};
}

View File

@@ -0,0 +1,95 @@
#pragma once
#include <hex.hpp>
#include <hex/data_processor/attribute.hpp>
#include <set>
#include <string_view>
#include <vector>
#include <nlohmann/json_fwd.hpp>
namespace hex::prv { class Provider; class Overlay; }
namespace hex::dp {
class Node {
public:
Node(std::string unlocalizedTitle, std::vector<Attribute> attributes);
virtual ~Node() = default;
[[nodiscard]] u32 getID() const { return this->m_id; }
void setID(u32 id) { this->m_id = id; }
[[nodiscard]] const std::string& getUnlocalizedName() const { return this->m_unlocalizedName; }
void setUnlocalizedName(const std::string &unlocalizedName) { this->m_unlocalizedName = unlocalizedName; }
[[nodiscard]] const std::string& getUnlocalizedTitle() const { return this->m_unlocalizedTitle; }
[[nodiscard]] std::vector<Attribute>& getAttributes() { return this->m_attributes; }
void setCurrentOverlay(prv::Overlay *overlay) {
this->m_overlay = overlay;
}
virtual void drawNode() { }
virtual void process() = 0;
virtual void store(nlohmann::json &j) { }
virtual void load(nlohmann::json &j) { }
using NodeError = std::pair<Node*, std::string>;
void resetOutputData() {
for (auto &attribute : this->m_attributes)
attribute.getOutputData().reset();
}
void resetProcessedInputs() {
this->m_processedInputs.clear();
}
private:
u32 m_id;
std::string m_unlocalizedTitle, m_unlocalizedName;
std::vector<Attribute> m_attributes;
std::set<u32> m_processedInputs;
prv::Overlay *m_overlay = nullptr;
Attribute* getConnectedInputAttribute(u32 index) {
if (index >= this->getAttributes().size())
throw std::runtime_error("Attribute index out of bounds!");
auto &connectedAttribute = this->getAttributes()[index].getConnectedAttributes();
if (connectedAttribute.empty())
return nullptr;
return connectedAttribute.begin()->second;
}
void markInputProcessed(u32 index) {
const auto &[iter, inserted] = this->m_processedInputs.insert(index);
if (!inserted)
throwNodeError("Recursion detected!");
}
protected:
[[noreturn]] void throwNodeError(const std::string &message) {
throw NodeError(this, message);
}
std::vector<u8> getBufferOnInput(u32 index);
u64 getIntegerOnInput(u32 index);
float getFloatOnInput(u32 index);
void setBufferOnOutput(u32 index, std::vector<u8> data);
void setIntegerOnOutput(u32 index, u64 integer);
void setFloatOnOutput(u32 index, float floatingPoint);
void setOverlayData(u64 address, const std::vector<u8> &data);
};
}

View File

@@ -0,0 +1,162 @@
#pragma once
#include <hex.hpp>
#include <type_traits>
namespace hex {
template<typename>
struct is_integral_helper : public std::false_type { };
template<>
struct is_integral_helper<u8> : public std::true_type { };
template<>
struct is_integral_helper<s8> : public std::true_type { };
template<>
struct is_integral_helper<u16> : public std::true_type { };
template<>
struct is_integral_helper<s16> : public std::true_type { };
template<>
struct is_integral_helper<u32> : public std::true_type { };
template<>
struct is_integral_helper<s32> : public std::true_type { };
template<>
struct is_integral_helper<u64> : public std::true_type { };
template<>
struct is_integral_helper<s64> : public std::true_type { };
template<>
struct is_integral_helper<u128> : public std::true_type { };
template<>
struct is_integral_helper<s128> : public std::true_type { };
template<>
struct is_integral_helper<bool> : public std::true_type { };
template<>
struct is_integral_helper<char> : public std::true_type { };
template<>
struct is_integral_helper<char8_t> : public std::true_type { };
template<>
struct is_integral_helper<char16_t> : public std::true_type { };
template<>
struct is_integral_helper<char32_t> : public std::true_type { };
template<>
struct is_integral_helper<wchar_t> : public std::true_type { };
template<typename T>
struct is_integral : public is_integral_helper<std::remove_cvref_t<T>>::type { };
template<typename>
struct is_signed_helper : public std::false_type { };
template<>
struct is_signed_helper<s8> : public std::true_type { };
template<>
struct is_signed_helper<s16> : public std::true_type { };
template<>
struct is_signed_helper<s32> : public std::true_type { };
template<>
struct is_signed_helper<s64> : public std::true_type { };
template<>
struct is_signed_helper<s128> : public std::true_type { };
template<>
struct is_signed_helper<char> : public std::true_type { };
template<>
struct is_signed_helper<float> : public std::true_type { };
template<>
struct is_signed_helper<double> : public std::true_type { };
template<>
struct is_signed_helper<long double> : public std::true_type { };
template<typename T>
struct is_signed : public is_signed_helper<std::remove_cvref_t<T>>::type { };
template<typename>
struct is_floating_point_helper : public std::false_type { };
template<>
struct is_floating_point_helper<float> : public std::true_type { };
template<>
struct is_floating_point_helper<double> : public std::true_type { };
template<>
struct is_floating_point_helper<long double> : public std::true_type { };
template<typename T>
struct is_floating_point : public is_floating_point_helper<std::remove_cvref_t<T>>::type { };
}
#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 12000
#if __has_include(<concepts>)
// Make sure we break when derived_from is implemented in libc++. Then we can fix a compatibility version above
#include <concepts>
#endif
// libcxx 12 still doesn't have many default concepts implemented, as a result we need to define it ourself using clang built-ins.
// [concept.derived] (patch from https://reviews.llvm.org/D74292)
namespace hex {
template<class _Dp, class _Bp>
concept derived_from =
__is_base_of(_Bp, _Dp) && __is_convertible_to(const volatile _Dp*, const volatile _Bp*);
}
#else
// Assume supported
#include <concepts>
namespace hex {
using std::derived_from;
}
#endif
// [concepts.arithmetic]
namespace hex {
template<class T>
concept integral = hex::is_integral<T>::value;
template<class T>
concept signed_integral = integral<T> && hex::is_signed<T>::value;
template<class T>
concept unsigned_integral = integral<T> && !signed_integral<T>;
template<class T>
concept floating_point = std::is_floating_point<T>::value;
}
namespace hex {
template<typename T>
struct always_false : std::false_type {};
template<typename T, size_t Size>
concept has_size = sizeof(T) == Size;
}

View File

@@ -0,0 +1,58 @@
#pragma once
#include <hex.hpp>
#include <array>
#include <optional>
#include <string>
#include <vector>
namespace hex::prv { class Provider; }
namespace hex::crypt {
void initialize();
void exit();
u16 crc8(prv::Provider* &data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut);
u16 crc16(prv::Provider* &data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut);
u32 crc32(prv::Provider* &data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut);
std::array<u8, 16> md5(prv::Provider* &data, u64 offset, size_t size);
std::array<u8, 20> sha1(prv::Provider* &data, u64 offset, size_t size);
std::array<u8, 28> sha224(prv::Provider* &data, u64 offset, size_t size);
std::array<u8, 32> sha256(prv::Provider* &data, u64 offset, size_t size);
std::array<u8, 48> sha384(prv::Provider* &data, u64 offset, size_t size);
std::array<u8, 64> sha512(prv::Provider* &data, u64 offset, size_t size);
std::array<u8, 16> md5(const std::vector<u8> &data);
std::array<u8, 20> sha1(const std::vector<u8> &data);
std::array<u8, 28> sha224(const std::vector<u8> &data);
std::array<u8, 32> sha256(const std::vector<u8> &data);
std::array<u8, 48> sha384(const std::vector<u8> &data);
std::array<u8, 64> sha512(const std::vector<u8> &data);
std::vector<u8> decode64(const std::vector<u8> &input);
std::vector<u8> encode64(const std::vector<u8> &input);
std::vector<u8> decode16(const std::string &input);
std::string encode16(const std::vector<u8> &input);
enum class AESMode : u8 {
ECB = 0,
CBC = 1,
CFB128 = 2,
CTR = 3,
GCM = 4,
CCM = 5,
OFB = 6,
XTS = 7
};
enum class KeyLength : u8 {
Key128Bits = 0,
Key192Bits = 1,
Key256Bits = 2
};
std::vector<u8> aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input);
}

View File

@@ -0,0 +1,62 @@
#pragma once
#if __has_include(<capstone/capstone.h>)
#include <capstone/capstone.h>
#else
#include <capstone.h>
#endif
#include <hex.hpp>
namespace hex {
enum class Architecture : s32 {
ARM,
ARM64,
MIPS,
X86,
PPC,
SPARC,
SYSZ,
XCORE,
M68K,
TMS320C64X,
M680X,
EVM,
MOS65XX,
WASM,
BPF,
RISCV,
MAX,
MIN = ARM
};
class Disassembler {
public:
static constexpr cs_arch toCapstoneArchictecture(Architecture architecture) {
return static_cast<cs_arch>(architecture);
}
static inline bool isSupported(Architecture architecture) {
return cs_support(toCapstoneArchictecture(architecture));
}
constexpr static const char * const ArchitectureNames[] = { "ARM32", "ARM64", "MIPS", "x86", "PowerPC", "Sparc", "SystemZ", "XCore", "68K", "TMS320C64x", "680X", "Ethereum", "MOS65XX", "WebAssembly", "Berkeley Packet Filter", "RISC-V" };
static inline s32 getArchitectureSupportedCount() {
static s32 supportedCount = -1;
if (supportedCount != -1) {
return supportedCount;
}
for (supportedCount = static_cast<s32>(Architecture::MIN); supportedCount < static_cast<s32>(Architecture::MAX); supportedCount++) {
if (!cs_support(supportedCount)) {
break;
}
}
return supportedCount;
}
};
}

View File

@@ -0,0 +1,36 @@
#pragma once
#include <hex.hpp>
#include <map>
#include <string_view>
#include <vector>
#include <hex/helpers/paths.hpp>
namespace hex {
class EncodingFile {
public:
enum class Type {
Thingy
};
EncodingFile() = default;
EncodingFile(Type type, const fs::path &path);
[[nodiscard]] std::pair<std::string_view, size_t> getEncodingFor(const std::vector<u8> &buffer) const;
[[nodiscard]] size_t getLongestSequence() const { return this->m_longestSequence; }
[[nodiscard]] bool valid() const { return this->m_valid; }
private:
void parseThingyFile(std::ifstream &content);
bool m_valid = false;
std::map<u32, std::map<std::vector<u8>, std::string>> m_mapping;
size_t m_longestSequence = 0;
};
}

View File

@@ -0,0 +1,63 @@
#pragma once
#include <hex.hpp>
#include <cstdio>
#include <string>
#include <vector>
#include <hex/helpers/paths.hpp>
#if defined(OS_MACOS)
#define off64_t off_t
#define fopen64 fopen
#define fseeko64 fseek
#define ftello64 ftell
#define ftruncate64 ftruncate
#endif
namespace hex {
class File {
public:
enum class Mode {
Read,
Write,
Create
};
explicit File(const fs::path &path, Mode mode);
File();
File(const File&) = delete;
File(File &&other) noexcept;
~File();
[[nodiscard]] bool isValid() const { return this->m_file != nullptr; }
void seek(u64 offset);
void close();
size_t readBuffer(u8 *buffer, size_t size);
std::vector<u8> readBytes(size_t numBytes = 0);
std::string readString(size_t numBytes = 0);
void write(const u8 *buffer, size_t size);
void write(const std::vector<u8> &bytes);
void write(const std::string &string);
[[nodiscard]] size_t getSize() const;
void setSize(u64 size);
void flush();
void remove();
auto getHandle() { return this->m_file; }
const fs::path& getPath() { return this->m_path; }
private:
FILE *m_file;
fs::path m_path;
};
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include <string_view>
#include <fmt/format.h>
#include <fmt/chrono.h>
namespace hex {
template<typename ... Args>
inline std::string format(std::string_view format, Args ... args) {
return fmt::format(fmt::runtime(format), args...);
}
template<typename ... Args>
inline void print(std::string_view format, Args ... args) {
fmt::print(fmt::runtime(format), args...);
}
}

View File

@@ -0,0 +1,57 @@
#pragma once
#include <initializer_list>
#include <map>
#include <string>
#include <string_view>
namespace hex {
class LanguageDefinition {
public:
LanguageDefinition(std::initializer_list<std::pair<std::string, std::string>> entries);
const std::map<std::string, std::string>& getEntries() const;
private:
std::map<std::string, std::string> m_entries;
};
class LangEntry {
public:
explicit LangEntry(const char *unlocalizedString);
explicit LangEntry(const std::string &unlocalizedString);
explicit LangEntry(std::string_view unlocalizedString);
operator std::string() const;
operator std::string_view() const;
operator const char*() const;
[[nodiscard]] std::string_view get() const;
static void loadLanguage(std::string_view language);
static const std::map<std::string, std::string>& getSupportedLanguages();
private:
std::string m_unlocalizedString;
};
std::string operator+(const std::string &&left, const LangEntry &&right);
std::string operator+(const LangEntry &&left, const std::string &&right);
std::string operator+(const std::string_view &&left, const LangEntry &&right);
std::string operator+(const LangEntry &&left, const std::string_view &&right);
std::string operator+(const char *left, const LangEntry &&right);
std::string operator+(const LangEntry &&left, const char *right);
std::string operator+(const LangEntry &&left, const LangEntry &&right);
namespace lang_literals {
inline LangEntry operator""_lang(const char *string, size_t) {
return LangEntry(string);
}
}
}

View File

@@ -0,0 +1,23 @@
#pragma once
namespace hex::literals {
/* Byte literals */
constexpr static inline unsigned long long operator ""_Bytes(unsigned long long bytes) noexcept {
return bytes;
}
constexpr static inline unsigned long long operator ""_KiB(unsigned long long kiB) noexcept {
return operator ""_Bytes(kiB * 1024);
}
constexpr static inline unsigned long long operator ""_MiB(unsigned long long MiB) noexcept {
return operator ""_KiB(MiB * 1024);
}
constexpr static inline unsigned long long operator ""_GiB(unsigned long long GiB) noexcept {
return operator ""_MiB(GiB * 1024);
}
}

View File

@@ -0,0 +1,35 @@
#pragma once
#include <string>
#include <string_view>
#include <hex/helpers/paths.hpp>
struct _object;
typedef struct _object PyObject;
namespace hex {
namespace prv { class Provider; }
class LoaderScript {
public:
LoaderScript() = delete;
static bool processFile(const fs::path &scriptPath);
static void setFilePath(const fs::path &filePath) { LoaderScript::s_filePath = filePath; }
static void setDataProvider(prv::Provider* provider) { LoaderScript::s_dataProvider = provider; }
private:
static inline fs::path s_filePath;
static inline prv::Provider* s_dataProvider;
static PyObject* Py_getFilePath(PyObject *self, PyObject *args);
static PyObject* Py_addPatch(PyObject *self, PyObject *args);
static PyObject* Py_addBookmark(PyObject *self, PyObject *args);
static PyObject* Py_addStruct(PyObject *self, PyObject *args);
static PyObject* Py_addUnion(PyObject *self, PyObject *args);
};
}

View File

@@ -0,0 +1,40 @@
#pragma once
#include <fmt/core.h>
#include <fmt/color.h>
namespace hex::log {
void debug(const std::string &fmt, auto ... args) {
#if defined(DEBUG)
fmt::print(fg(fmt::color::green_yellow) | fmt::emphasis::bold, "[DEBUG] ");
fmt::print(fmt::runtime(fmt), args...);
fmt::print("\n");
#endif
}
void info(const std::string &fmt, auto ... args) {
fmt::print(fg(fmt::color::cadet_blue) | fmt::emphasis::bold, "[INFO] ");
fmt::print(fmt::runtime(fmt), args...);
fmt::print("\n");
}
void warn(const std::string &fmt, auto ... args) {
fmt::print(fg(fmt::color::orange) | fmt::emphasis::bold, "[WARN] ");
fmt::print(fmt::runtime(fmt), args...);
fmt::print("\n");
}
void error(const std::string &fmt, auto ... args) {
fmt::print(fg(fmt::color::red) | fmt::emphasis::bold, "[ERROR] ");
fmt::print(fmt::runtime(fmt), args...);
fmt::print("\n");
}
void fatal(const std::string &fmt, auto ... args) {
fmt::print(fg(fmt::color::purple) | fmt::emphasis::bold, "[FATAL] ");
fmt::print(fmt::runtime(fmt), args...);
fmt::print("\n");
}
}

View File

@@ -0,0 +1,22 @@
#pragma once
#include <hex.hpp>
#include <hex/helpers/literals.hpp>
#include <string>
#include <vector>
namespace hex::prv { class Provider; }
namespace hex::magic {
using namespace hex::literals;
bool compile();
std::string getDescription(const std::vector<u8> &data);
std::string getDescription(prv::Provider *provider, size_t size = 5_MiB);
std::string getMIMEType(const std::vector<u8> &data);
std::string getMIMEType(prv::Provider *provider, size_t size = 5_MiB);
}

View File

@@ -0,0 +1,66 @@
#pragma once
#include <hex.hpp>
#include <cstring>
#include <future>
#include <optional>
#include <string>
#include <filesystem>
#include <atomic>
#include <nlohmann/json_fwd.hpp>
#include <curl/system.h>
#include <hex/helpers/paths.hpp>
using CURL = void;
struct curl_slist;
namespace hex {
template<typename T>
struct Response {
s32 code;
T body;
};
template<>
struct Response<void> {
s32 code;
};
class Net {
public:
Net();
~Net();
std::future<Response<std::string>> getString(const std::string &url, u32 timeout = 2000);
std::future<Response<nlohmann::json>> getJson(const std::string &url, u32 timeout = 2000);
std::future<Response<std::string>> uploadFile(const std::string &url, const fs::path &filePath, u32 timeout = 2000);
std::future<Response<void>> downloadFile(const std::string &url, const fs::path &filePath, u32 timeout = 2000);
[[nodiscard]]
std::string encode(const std::string &input);
[[nodiscard]]
float getProgress() const { return this->m_progress; }
void cancel() { this->m_shouldCancel = true; }
private:
void setCommonSettings(std::string &response, const std::string &url, u32 timeout = 2000, const std::map<std::string, std::string> &extraHeaders = { }, const std::string &body = { });
std::optional<s32> execute();
friend int progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow);
private:
CURL *m_ctx;
curl_slist *m_headers = nullptr;
std::mutex m_transmissionActive;
float m_progress = 0.0F;
bool m_shouldCancel = false;
};
}

View File

@@ -0,0 +1,17 @@
#pragma once
#include <hex.hpp>
#include <map>
#include <vector>
namespace hex {
using Patches = std::map<u64, u8>;
std::vector<u8> generateIPSPatch(const Patches &patches);
std::vector<u8> generateIPS32Patch(const Patches &patches);
Patches loadIPSPatch(const std::vector<u8> &ipsPatch);
Patches loadIPS32Patch(const std::vector<u8> &ipsPatch);
}

View File

@@ -0,0 +1,27 @@
#pragma once
#include <string>
#include <vector>
#include <filesystem>
namespace hex {
namespace fs = std::filesystem;
enum class ImHexPath {
Patterns,
PatternsInclude,
Magic,
Python,
Plugins,
Yara,
Config,
Resources,
Constants
};
std::string getExecutablePath();
std::vector<fs::path> getPath(ImHexPath path, bool listNonExisting = false);
}

View File

@@ -0,0 +1,10 @@
#pragma once
#if defined(OS_MACOS)
#include <hex/helpers/paths.hpp>
namespace hex {
std::string getMacExecutableDirectoryPath();
std::string getMacApplicationSupportDirectoryPath();
}
#endif

View File

@@ -0,0 +1,105 @@
#pragma once
#include <list>
#include <string>
#include <string_view>
#include "patches.hpp"
#include <hex/api/imhex_api.hpp>
#include <hex/api/event.hpp>
#include <hex/helpers/paths.hpp>
namespace hex {
class ProjectFile {
public:
ProjectFile() = delete;
static bool load(const fs::path &filePath);
static bool store(fs::path filePath = { });
[[nodiscard]] static bool hasUnsavedChanges() {
return ProjectFile::s_hasUnsavedChanged;
}
static void markDirty() {
bool setWindowTitle = !hasUnsavedChanges();
ProjectFile::s_hasUnsavedChanged = true;
if (setWindowTitle)
EventManager::post<RequestChangeWindowTitle>(fs::path(getFilePath()).filename().string());
}
[[nodiscard]] static const fs::path& getProjectFilePath() {
return ProjectFile::s_currProjectFilePath;
}
static void clearProjectFilePath() {
ProjectFile::s_currProjectFilePath.clear();
}
[[nodiscard]] static const fs::path& getFilePath() {
return ProjectFile::s_filePath;
}
static void setFilePath(const fs::path &filePath) {
ProjectFile::s_filePath = filePath;
EventManager::post<RequestChangeWindowTitle>(filePath.filename().string());
}
[[nodiscard]] static const std::string& getPattern() {
return ProjectFile::s_pattern;
}
static void setPattern(const std::string &pattern) {
markDirty();
ProjectFile::s_pattern = pattern;
}
[[nodiscard]] static const Patches& getPatches() {
return ProjectFile::s_patches;
}
static void setPatches(const Patches &patches) {
markDirty();
ProjectFile::s_patches = patches;
}
[[nodiscard]] static const std::list<ImHexApi::Bookmarks::Entry>& getBookmarks() {
return ProjectFile::s_bookmarks;
}
static void setBookmarks(const std::list<ImHexApi::Bookmarks::Entry> &bookmarks) {
markDirty();
ProjectFile::s_bookmarks = bookmarks;
}
[[nodiscard]] static const std::string& getDataProcessorContent() {
return ProjectFile::s_dataProcessorContent;
}
static void setDataProcessorContent(const std::string &json) {
markDirty();
ProjectFile::s_dataProcessorContent = json;
}
private:
static fs::path s_currProjectFilePath;
static bool s_hasUnsavedChanged;
static fs::path s_filePath;
static std::string s_pattern;
static Patches s_patches;
static std::list<ImHexApi::Bookmarks::Entry> s_bookmarks;
static std::string s_dataProcessorContent;
};
}

View File

@@ -0,0 +1,115 @@
#pragma once
#include <any>
#include <functional>
#include <list>
#include <map>
#include <memory>
#include <mutex>
#include <vector>
#include <hex/api/content_registry.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/api/task.hpp>
#include <hex/views/view.hpp>
#include <imgui.h>
#include <nlohmann/json_fwd.hpp>
namespace hex { class SharedData; }
namespace hex::plugin::internal {
void initializePlugin(SharedData &sharedData);
}
namespace hex {
namespace prv { class Provider; }
namespace dp { class Node; }
namespace pl { class PatternData; }
class View;
class SharedData {
SharedData() = default;
public:
SharedData(const SharedData&) = delete;
SharedData(SharedData&&) = delete;
friend class Window;
template<typename T>
static T& getVariable(std::string variableName) {
return std::any_cast<T&>(SharedData::sharedVariables[variableName]);
}
template<typename T>
static void setVariable(std::string variableName, T value) {
SharedData::sharedVariables[variableName] = value;
}
static void clearVariables() {
SharedData::sharedVariables.clear();
}
public:
static std::vector<std::function<void()>> deferredCalls;
static std::vector<prv::Provider*> providers;
static u32 currentProvider;
static std::map<std::string, std::vector<ContentRegistry::Settings::Entry>> settingsEntries;
static nlohmann::json settingsJson;
static std::vector<ContentRegistry::CommandPaletteCommands::Entry> commandPaletteCommands;
static std::map<std::string, ContentRegistry::PatternLanguage::Function> patternLanguageFunctions;
static std::vector<View*> views;
static std::vector<ContentRegistry::Tools::impl::Entry> toolsEntries;
static std::vector<ContentRegistry::DataInspector::impl::Entry> dataInspectorEntries;
static u32 patternPaletteOffset;
static std::string popupMessage;
static std::list<ImHexApi::Bookmarks::Entry> bookmarkEntries;
static std::vector<pl::PatternData*> patternData;
static std::map<std::string, std::string> languageNames;
static std::map<std::string, std::vector<LanguageDefinition>> languageDefinitions;
static std::map<std::string, std::string> loadedLanguageStrings;
static std::vector<ContentRegistry::Interface::DrawCallback> welcomeScreenEntries;
static std::vector<ContentRegistry::Interface::DrawCallback> footerItems;
static std::vector<ContentRegistry::Interface::DrawCallback> toolbarItems;
static std::map<Shortcut, std::function<void()>> globalShortcuts;
static std::mutex tasksMutex;
static std::list<Task*> runningTasks;
static std::vector<std::string> providerNames;
static std::vector<ContentRegistry::DataProcessorNode::impl::Entry> dataProcessorNodes;
static u32 dataProcessorNodeIdCounter;
static u32 dataProcessorLinkIdCounter;
static u32 dataProcessorAttrIdCounter;
static std::vector<ContentRegistry::DataFormatter::impl::Entry> dataFormatters;
static std::vector<ContentRegistry::FileHandler::impl::Entry> fileHandlers;
static std::list<fs::path> recentFilePaths;
static int mainArgc;
static char **mainArgv;
static char **mainEnvp;
static ImFontAtlas *fontAtlas;
static ImFontConfig fontConfig;
static ImVec2 windowPos;
static ImVec2 windowSize;
static float globalScale;
static float fontScale;
private:
static std::map<std::string, std::any> sharedVariables;
};
}

View File

@@ -0,0 +1,55 @@
#pragma once
#include <hex.hpp>
#include <string>
#include <vector>
#if defined(OS_WINDOWS)
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#define SOCKET_NONE INVALID_SOCKET
#else
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/ip.h>
#include <arpa/inet.h>
#define SOCKET_NONE -1
#endif
namespace hex {
class Socket {
public:
Socket() = default;
Socket(const Socket&) = delete;
Socket(Socket &&other);
Socket(const std::string &address, u16 port);
~Socket();
void connect(const std::string &address, u16 port);
void disconnect();
[[nodiscard]]
bool isConnected() const;
std::string readString(size_t size = 0x1000) const;
std::vector<u8> readBytes(size_t size = 0x1000) const;
void writeString(const std::string &string) const;
void writeBytes(const std::vector<u8> &bytes) const;
private:
bool m_connected = false;
#if defined(OS_WINDOWS)
SOCKET m_socket = SOCKET_NONE;
#else
int m_socket = SOCKET_NONE;
#endif
};
}

View File

@@ -0,0 +1,329 @@
#pragma once
#include <hex.hpp>
#include <hex/helpers/concepts.hpp>
#include <hex/helpers/paths.hpp>
#include <array>
#include <bit>
#include <cstring>
#include <cctype>
#include <functional>
#include <limits>
#include <memory>
#include <optional>
#include <string>
#include <type_traits>
#include <variant>
#include <vector>
#include <nfd.hpp>
#define TOKEN_CONCAT_IMPL(x, y) x ## y
#define TOKEN_CONCAT(x, y) TOKEN_CONCAT_IMPL(x, y)
#define ANONYMOUS_VARIABLE(prefix) TOKEN_CONCAT(prefix, __COUNTER__)
struct ImVec2;
namespace hex {
long double operator""_scaled(long double value);
long double operator""_scaled(unsigned long long value);
ImVec2 scaled(const ImVec2 &vector);
std::string to_string(u128 value);
std::string to_string(s128 value);
std::string toByteString(u64 bytes);
std::string makePrintable(u8 c);
void runCommand(const std::string &command);
void openWebpage(std::string url);
[[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const hex::unsigned_integral auto &value) {
using ValueType = std::remove_cvref_t<decltype(value)>;
ValueType mask = (std::numeric_limits<ValueType>::max() >> (((sizeof(value) * 8) - 1) - (from - to))) << to;
return (value & mask) >> to;
}
[[nodiscard]] inline u64 extract(u32 from, u32 to, const std::vector<u8> &bytes) {
u8 index = 0;
while(from > 32 && to > 32) {
if (from - 8 < 0 || to - 8 < 0)
return 0;
from -= 8;
to -= 8;
index++;
}
u64 value = 0;
std::memcpy(&value, &bytes[index], std::min(sizeof(value), bytes.size() - index));
u64 mask = (std::numeric_limits<u64>::max() >> (64 - (from + 1)));
return (value & mask) >> to;
}
constexpr inline s128 signExtend(size_t numBits, s128 value) {
s128 mask = 1U << (numBits - 1);
return (value ^ mask) - mask;
}
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
template<size_t Size>
struct SizeTypeImpl { };
template<> struct SizeTypeImpl<1> { using Type = u8; };
template<> struct SizeTypeImpl<2> { using Type = u16; };
template<> struct SizeTypeImpl<4> { using Type = u32; };
template<> struct SizeTypeImpl<8> { using Type = u64; };
template<> struct SizeTypeImpl<16> { using Type = u128; };
template<size_t Size>
using SizeType = typename SizeTypeImpl<Size>::Type;
template<typename T>
constexpr T changeEndianess(const T &value, std::endian endian) {
if (endian == std::endian::native)
return value;
constexpr auto Size = sizeof(T);
SizeType<Size> unswapped;
std::memcpy(&unswapped, &value, Size);
SizeType<Size> swapped;
if constexpr (!std::has_single_bit(Size) || Size > 16)
static_assert(always_false<T>::value, "Invalid type provided!");
switch (Size) {
case 1: swapped = unswapped; break;
case 2: swapped = __builtin_bswap16(unswapped); break;
case 4: swapped = __builtin_bswap32(unswapped); break;
case 8: swapped = __builtin_bswap64(unswapped); break;
case 16: swapped = (u128(__builtin_bswap64(unswapped & 0xFFFF'FFFF'FFFF'FFFF)) << 64) | __builtin_bswap64(u128(unswapped) >> 64); break;
default: __builtin_unreachable();
}
T result;
std::memcpy(&result, &swapped, Size);
return result;
}
[[nodiscard]]
constexpr u128 bitmask(u8 bits) {
return u128(-1) >> (128 - bits);
}
template<typename T>
constexpr T changeEndianess(T value, size_t size, std::endian endian) {
if (endian == std::endian::native)
return value;
u128 unswapped = 0;
std::memcpy(&unswapped, &value, size);
u128 swapped;
switch (size) {
case 1: swapped = unswapped; break;
case 2: swapped = __builtin_bswap16(unswapped); break;
case 4: swapped = __builtin_bswap32(unswapped); break;
case 8: swapped = __builtin_bswap64(unswapped); break;
case 16: swapped = (u128(__builtin_bswap64(unswapped & 0xFFFF'FFFF'FFFF'FFFF)) << 64) | __builtin_bswap64(u128(unswapped) >> 64); break;
default: __builtin_unreachable();
}
T result = 0;
std::memcpy(&result, &swapped, size);
return result;
}
template< class T >
constexpr T bit_width(T x) noexcept {
return std::numeric_limits<T>::digits - std::countl_zero(x);
}
template<typename T>
constexpr T bit_ceil(T x) noexcept {
if (x <= 1u)
return T(1);
return T(1) << bit_width(T(x - 1));
}
std::vector<std::string> splitString(const std::string &string, const std::string &delimiter);
std::string combineStrings(const std::vector<std::string> &strings, const std::string &delimiter = "");
std::string toEngineeringString(double value);
template<typename T>
std::vector<u8> toBytes(T value) {
std::vector<u8> bytes(sizeof(T));
std::memcpy(bytes.data(), &value, sizeof(T));
return bytes;
}
inline std::vector<u8> parseByteString(const std::string &string) {
auto byteString = std::string(string);
byteString.erase(std::remove(byteString.begin(), byteString.end(), ' '), byteString.end());
if ((byteString.length() % 2) != 0) return { };
std::vector<u8> result;
for (u32 i = 0; i < byteString.length(); i += 2) {
if (!std::isxdigit(byteString[i]) || !std::isxdigit(byteString[i + 1]))
return { };
result.push_back(std::strtoul(byteString.substr(i, 2).c_str(), nullptr, 16));
}
return result;
}
inline std::string toBinaryString(hex::unsigned_integral auto number) {
if (number == 0) return "0";
std::string result;
for (s16 bit = hex::bit_width(number) - 1; bit >= 0; bit--)
result += (number & (0b1 << bit)) == 0 ? '0' : '1';
return result;
}
inline void trimLeft(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch) && ch >= 0x20;
}));
}
inline void trimRight(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch) && ch >= 0x20;
}).base(), s.end());
}
inline void trim(std::string &s) {
trimLeft(s);
trimRight(s);
}
enum class DialogMode {
Open,
Save,
Folder
};
void openFileBrowser(const std::string &title, DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(fs::path)> &callback, const std::string &defaultPath = {});
float float16ToFloat32(u16 float16);
inline bool equalsIgnoreCase(const std::string &left, const std::string &right) {
return std::equal(left.begin(), left.end(), right.begin(), right.end(), [](char a, char b) {
return tolower(a) == tolower(b);
});
}
inline bool containsIgnoreCase(const std::string &a, const std::string &b) {
auto iter = std::search(a.begin(), a.end(), b.begin(), b.end(), [](char ch1, char ch2) {
return std::toupper(ch1) == std::toupper(ch2);
});
return iter != a.end();
}
template<typename T, typename ... VariantTypes>
T get_or(const std::variant<VariantTypes...> &variant, T alt) {
const T *value = std::get_if<T>(&variant);
if (value == nullptr)
return alt;
else
return *value;
}
bool isProcessElevated();
namespace scope_guard {
#define SCOPE_GUARD ::hex::scope_guard::ScopeGuardOnExit() + [&]()
#define ON_SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_) = SCOPE_GUARD
template<class F>
class ScopeGuard {
private:
F m_func;
bool m_active;
public:
constexpr ScopeGuard(F func) : m_func(std::move(func)), m_active(true) { }
~ScopeGuard() { if (this->m_active) { this->m_func(); } }
void release() { this->m_active = false; }
ScopeGuard(ScopeGuard &&other) noexcept : m_func(std::move(other.m_func)), m_active(other.m_active) {
other.cancel();
}
ScopeGuard& operator=(ScopeGuard &&) = delete;
};
enum class ScopeGuardOnExit { };
template <typename F>
constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F&& f) {
return ScopeGuard<F>(std::forward<F>(f));
}
}
namespace first_time_exec {
#define FIRST_TIME static auto ANONYMOUS_VARIABLE(FIRST_TIME_) = ::hex::first_time_exec::FirstTimeExecutor() + [&]()
template<class F>
class FirstTimeExecute {
public:
constexpr FirstTimeExecute(F func) { func(); }
FirstTimeExecute& operator=(FirstTimeExecute &&) = delete;
};
enum class FirstTimeExecutor { };
template <typename F>
constexpr FirstTimeExecute<F> operator+(FirstTimeExecutor, F&& f) {
return FirstTimeExecute<F>(std::forward<F>(f));
}
}
namespace final_cleanup {
#define FINAL_CLEANUP static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]()
template<class F>
class FinalCleanupExecute {
F m_func;
public:
constexpr FinalCleanupExecute(F func) : m_func(func) { }
constexpr ~FinalCleanupExecute() { this->m_func(); }
FinalCleanupExecute& operator=(FinalCleanupExecute &&) = delete;
};
enum class FinalCleanupExecutor { };
template <typename F>
constexpr FinalCleanupExecute<F> operator+(FinalCleanupExecutor, F&& f) {
return FinalCleanupExecute<F>(std::forward<F>(f));
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,263 @@
#pragma once
#include <atomic>
#include <bit>
#include <map>
#include <optional>
#include <vector>
#include <hex/pattern_language/log_console.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/concepts.hpp>
namespace hex::prv { class Provider; }
namespace hex::pl {
enum class DangerousFunctionPermission {
Ask,
Deny,
Allow
};
enum class ControlFlowStatement {
None,
Continue,
Break,
Return
};
class PatternData;
class PatternCreationLimiter;
class ASTNode;
class Evaluator {
public:
Evaluator() = default;
std::optional<std::vector<PatternData*>> evaluate(const std::vector<ASTNode*> &ast);
[[nodiscard]]
LogConsole& getConsole() {
return this->m_console;
}
struct Scope { PatternData *parent; std::vector<PatternData*>* scope; };
void pushScope(PatternData *parent, std::vector<PatternData*> &scope) {
if (this->m_scopes.size() > this->getEvaluationDepth())
LogConsole::abortEvaluation(hex::format("evaluation depth exceeded set limit of {}", this->getEvaluationDepth()));
this->handleAbort();
this->m_scopes.push_back({ parent, &scope });
}
void popScope() {
this->m_scopes.pop_back();
}
const Scope& getScope(s32 index) {
return this->m_scopes[this->m_scopes.size() - 1 + index];
}
const Scope& getGlobalScope() {
return this->m_scopes.front();
}
size_t getScopeCount() {
return this->m_scopes.size();
}
bool isGlobalScope() {
return this->m_scopes.size() == 1;
}
void setProvider(prv::Provider *provider) {
this->m_provider = provider;
}
void setInVariables(const std::map<std::string, Token::Literal> &inVariables) {
this->m_inVariables = inVariables;
}
[[nodiscard]]
std::map<std::string, Token::Literal> getOutVariables() const {
std::map<std::string, Token::Literal> result;
for (const auto &[name, offset] : this->m_outVariables) {
result.insert({ name, this->getStack()[offset] });
}
return result;
}
[[nodiscard]]
prv::Provider *getProvider() const {
return this->m_provider;
}
void setDefaultEndian(std::endian endian) {
this->m_defaultEndian = endian;
}
[[nodiscard]]
std::endian getDefaultEndian() const {
return this->m_defaultEndian;
}
void setEvaluationDepth(u64 evalDepth) {
this->m_evalDepth = evalDepth;
}
[[nodiscard]]
u64 getEvaluationDepth() const {
return this->m_evalDepth;
}
void setArrayLimit(u64 arrayLimit) {
this->m_arrayLimit = arrayLimit;
}
[[nodiscard]]
u64 getArrayLimit() const {
return this->m_arrayLimit;
}
void setPatternLimit(u64 limit) {
this->m_patternLimit = limit;
}
[[nodiscard]]
u64 getPatternLimit() {
return this->m_patternLimit;
}
[[nodiscard]]
u64 getPatternCount() {
return this->m_currPatternCount;
}
void setLoopLimit(u64 limit) {
this->m_loopLimit = limit;
}
[[nodiscard]]
u64 getLoopLimit() {
return this->m_loopLimit;
}
u64& dataOffset() { return this->m_currOffset; }
bool addCustomFunction(const std::string &name, u32 numParams, const ContentRegistry::PatternLanguage::Callback &function) {
const auto [iter, inserted] = this->m_customFunctions.insert({ name, { numParams, function } });
return inserted;
}
[[nodiscard]]
const std::map<std::string, ContentRegistry::PatternLanguage::Function>& getCustomFunctions() const {
return this->m_customFunctions;
}
[[nodiscard]]
std::vector<Token::Literal>& getStack() {
return this->m_stack;
}
[[nodiscard]]
const std::vector<Token::Literal>& getStack() const {
return this->m_stack;
}
void createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value = std::nullopt, bool outVariable = false);
void setVariable(const std::string &name, const Token::Literal& value);
void abort() {
this->m_aborted = true;
}
void handleAbort() {
if (this->m_aborted)
LogConsole::abortEvaluation("evaluation aborted by user");
}
[[nodiscard]]
std::optional<Token::Literal> getEnvVariable(const std::string &name) const {
if (this->m_envVariables.contains(name))
return this->m_envVariables.at(name);
else
return std::nullopt;
}
void setEnvVariable(const std::string &name, const Token::Literal &value) {
this->m_envVariables[name] = value;
}
[[nodiscard]]
bool hasDangerousFunctionBeenCalled() const {
return this->m_dangerousFunctionCalled;
}
void dangerousFunctionCalled() {
this->m_dangerousFunctionCalled = true;
}
void allowDangerousFunctions(bool allow) {
this->m_allowDangerousFunctions = allow ? DangerousFunctionPermission::Allow : DangerousFunctionPermission::Deny;
this->m_dangerousFunctionCalled = false;
}
[[nodiscard]]
DangerousFunctionPermission getDangerousFunctionPermission() const {
return this->m_allowDangerousFunctions;
}
void setCurrentControlFlowStatement(ControlFlowStatement statement) {
this->m_currControlFlowStatement = statement;
}
[[nodiscard]]
ControlFlowStatement getCurrentControlFlowStatement() const {
return this->m_currControlFlowStatement;
}
private:
void patternCreated();
void patternDestroyed();
private:
u64 m_currOffset;
prv::Provider *m_provider = nullptr;
LogConsole m_console;
std::endian m_defaultEndian = std::endian::native;
u64 m_evalDepth;
u64 m_arrayLimit;
u64 m_patternLimit;
u64 m_loopLimit;
u64 m_currPatternCount;
std::atomic<bool> m_aborted;
std::vector<Scope> m_scopes;
std::map<std::string, ContentRegistry::PatternLanguage::Function> m_customFunctions;
std::vector<ASTNode*> m_customFunctionDefinitions;
std::vector<Token::Literal> m_stack;
std::map<std::string, Token::Literal> m_envVariables;
std::map<std::string, Token::Literal> m_inVariables;
std::map<std::string, size_t> m_outVariables;
std::atomic<bool> m_dangerousFunctionCalled = false;
std::atomic<DangerousFunctionPermission> m_allowDangerousFunctions = DangerousFunctionPermission::Ask;
ControlFlowStatement m_currControlFlowStatement;
friend class PatternCreationLimiter;
};
}

View File

@@ -0,0 +1,30 @@
#pragma once
#include <hex.hpp>
#include <hex/pattern_language/token.hpp>
#include <optional>
#include <string>
#include <vector>
namespace hex::pl {
class Lexer {
public:
using LexerError = std::pair<u32, std::string>;
Lexer() = default;
std::optional<std::vector<Token>> lex(const std::string& code);
const std::optional<LexerError>& getError() { return this->m_error; }
private:
std::optional<LexerError> m_error;
[[noreturn]] void throwLexerError(const std::string &error, u32 lineNumber) const {
throw LexerError(lineNumber, "Lexer: " + error);
}
};
}

View File

@@ -0,0 +1,49 @@
#pragma once
#include <hex.hpp>
#include <optional>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
namespace hex::pl {
class ASTNode;
class LogConsole {
public:
enum Level {
Debug,
Info,
Warning,
Error
};
[[nodiscard]]
const auto& getLog() const { return this->m_consoleLog; }
using EvaluateError = std::pair<u32, std::string>;
void log(Level level, const std::string &message);
[[noreturn]]
static void abortEvaluation(const std::string &message);
[[noreturn]]
static void abortEvaluation(const std::string &message, const ASTNode *node);
void clear();
void setHardError(const EvaluateError &error) { this->m_lastHardError = error; }
[[nodiscard]]
const std::optional<EvaluateError>& getLastHardError() { return this->m_lastHardError; };
private:
std::vector<std::pair<Level, std::string>> m_consoleLog;
std::optional<EvaluateError> m_lastHardError;
};
}

View File

@@ -0,0 +1,254 @@
#pragma once
#include <hex.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/pattern_language/token.hpp>
#include <hex/pattern_language/ast_node.hpp>
#include <unordered_map>
#include <stdexcept>
#include <utility>
#include <vector>
namespace hex::pl {
class Parser {
public:
using TokenIter = std::vector<Token>::const_iterator;
using ParseError = std::pair<u32, std::string>;
Parser() = default;
~Parser() = default;
std::optional<std::vector<ASTNode*>> parse(const std::vector<Token> &tokens);
const std::optional<ParseError>& getError() { return this->m_error; }
private:
std::optional<ParseError> m_error;
TokenIter m_curr;
TokenIter m_originalPosition;
std::unordered_map<std::string, ASTNode*> m_types;
std::vector<TokenIter> m_matchedOptionals;
std::vector<std::vector<std::string>> m_currNamespace;
u32 getLineNumber(s32 index) const {
return this->m_curr[index].lineNumber;
}
auto* create(auto *node) {
node->setLineNumber(this->getLineNumber(-1));
return node;
}
template<typename T>
const T& getValue(s32 index) const {
auto value = std::get_if<T>(&this->m_curr[index].value);
if (value == nullptr)
throwParseError("failed to decode token. Invalid type.", getLineNumber(index));
return *value;
}
Token::Type getType(s32 index) const {
return this->m_curr[index].type;
}
std::string getNamespacePrefixedName(const std::string &name) {
std::string result;
for (const auto &part : this->m_currNamespace.back()) {
result += part + "::";
}
result += name;
return result;
}
ASTNode* parseFunctionCall();
ASTNode* parseStringLiteral();
std::string parseNamespaceResolution();
ASTNode* parseScopeResolution();
ASTNode* parseRValue(ASTNodeRValue::Path &path);
ASTNode* parseFactor();
ASTNode* parseCastExpression();
ASTNode* parseUnaryExpression();
ASTNode* parseMultiplicativeExpression();
ASTNode* parseAdditiveExpression();
ASTNode* parseShiftExpression();
ASTNode* parseRelationExpression();
ASTNode* parseEqualityExpression();
ASTNode* parseBinaryAndExpression();
ASTNode* parseBinaryXorExpression();
ASTNode* parseBinaryOrExpression();
ASTNode* parseBooleanAnd();
ASTNode* parseBooleanXor();
ASTNode* parseBooleanOr();
ASTNode* parseTernaryConditional();
ASTNode* parseMathematicalExpression();
ASTNode* parseFunctionDefinition();
ASTNode* parseFunctionVariableDecl();
ASTNode* parseFunctionStatement();
ASTNode* parseFunctionVariableAssignment();
ASTNode* parseFunctionControlFlowStatement();
std::vector<ASTNode*> parseStatementBody();
ASTNode* parseFunctionConditional();
ASTNode* parseFunctionWhileLoop();
ASTNode* parseFunctionForLoop();
void parseAttribute(Attributable *currNode);
ASTNode* parseConditional();
ASTNode* parseWhileStatement();
ASTNodeTypeDecl* parseType(bool allowFunctionTypes = false);
ASTNode* parseUsingDeclaration();
ASTNode* parsePadding();
ASTNode* parseMemberVariable(ASTNodeTypeDecl *type);
ASTNode* parseMemberArrayVariable(ASTNodeTypeDecl *type);
ASTNode* parseMemberPointerVariable(ASTNodeTypeDecl *type);
ASTNode* parseMember();
ASTNode* parseStruct();
ASTNode* parseUnion();
ASTNode* parseEnum();
ASTNode* parseBitfield();
ASTNode* parseVariablePlacement(ASTNodeTypeDecl *type);
ASTNode* parseArrayVariablePlacement(ASTNodeTypeDecl *type);
ASTNode* parsePointerVariablePlacement(ASTNodeTypeDecl *type);
ASTNode* parsePlacement();
std::vector<ASTNode*> parseNamespace();
std::vector<ASTNode*> parseStatements();
ASTNodeTypeDecl* addType(const std::string &name, ASTNode *node, std::optional<std::endian> endian = std::nullopt);
std::vector<ASTNode*> parseTillToken(Token::Type endTokenType, const auto value) {
std::vector<ASTNode*> program;
auto guard = SCOPE_GUARD {
for (auto &node : program)
delete node;
};
while (this->m_curr->type != endTokenType || (*this->m_curr) != value) {
for (auto statement : parseStatements())
program.push_back(statement);
}
this->m_curr++;
guard.release();
return program;
}
[[noreturn]] void throwParseError(const std::string &error, s32 token = -1) const {
throw ParseError(this->m_curr[token].lineNumber, "Parser: " + error);
}
/* Token consuming */
enum class Setting{ };
constexpr static auto Normal = static_cast<Setting>(0);
constexpr static auto Not = static_cast<Setting>(1);
bool begin() {
this->m_originalPosition = this->m_curr;
this->m_matchedOptionals.clear();
return true;
}
void reset() {
this->m_curr = this->m_originalPosition;
}
template<Setting S = Normal>
bool sequence() {
if constexpr (S == Normal)
return true;
else if constexpr (S == Not)
return false;
else
__builtin_unreachable();
}
template<Setting S = Normal>
bool sequence(Token::Type type, auto value, auto ... args) {
if constexpr (S == Normal) {
if (!peek(type, value)) {
reset();
return false;
}
this->m_curr++;
if (!sequence<Normal>(args...)) {
reset();
return false;
}
return true;
} else if constexpr (S == Not) {
if (!peek(type, value))
return true;
this->m_curr++;
if (!sequence<Normal>(args...))
return true;
reset();
return false;
} else
__builtin_unreachable();
}
template<Setting S = Normal>
bool oneOf() {
if constexpr (S == Normal)
return false;
else if constexpr (S == Not)
return true;
else
__builtin_unreachable();
}
template<Setting S = Normal>
bool oneOf(Token::Type type, auto value, auto ... args) {
if constexpr (S == Normal)
return sequence<Normal>(type, value) || oneOf(args...);
else if constexpr (S == Not)
return sequence<Not>(type, value) && oneOf(args...);
else
__builtin_unreachable();
}
bool variant(Token::Type type1, auto value1, Token::Type type2, auto value2) {
if (!peek(type1, value1)) {
if (!peek(type2, value2)) {
reset();
return false;
}
}
this->m_curr++;
return true;
}
bool optional(Token::Type type, auto value) {
if (peek(type, value)) {
this->m_matchedOptionals.push_back(this->m_curr);
this->m_curr++;
}
return true;
}
bool peek(Token::Type type, auto value, s32 index = 0) {
return this->m_curr[index].type == type && this->m_curr[index] == value;
}
};
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,72 @@
#pragma once
#include <hex.hpp>
#include <bit>
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include <hex/pattern_language/log_console.hpp>
#include <hex/pattern_language/token.hpp>
namespace hex::prv { class Provider; }
namespace hex::pl {
class Preprocessor;
class Lexer;
class Parser;
class Validator;
class Evaluator;
class PatternData;
class ASTNode;
class PatternLanguage {
public:
PatternLanguage();
~PatternLanguage();
[[nodiscard]]
std::optional<std::vector<ASTNode*>> parseString(const std::string &code);
[[nodiscard]]
std::optional<std::vector<PatternData*>> executeString(prv::Provider *provider, const std::string &string, const std::map<std::string, Token::Literal> &envVars = { }, const std::map<std::string, Token::Literal> &inVariables = { });
[[nodiscard]]
std::optional<std::vector<PatternData*>> executeFile(prv::Provider *provider, const fs::path &path, const std::map<std::string, Token::Literal> &envVars = { }, const std::map<std::string, Token::Literal> &inVariables = { });
[[nodiscard]]
const std::vector<ASTNode*>& getCurrentAST() const;
void abort();
[[nodiscard]]
const std::vector<std::pair<LogConsole::Level, std::string>>& getConsoleLog();
[[nodiscard]]
const std::optional<std::pair<u32, std::string>>& getError();
[[nodiscard]]
std::map<std::string, Token::Literal> getOutVariables() const;
[[nodiscard]]
u32 getCreatedPatternCount();
[[nodiscard]]
u32 getMaximumPatternCount();
[[nodiscard]]
bool hasDangerousFunctionBeenCalled() const;
void allowDangerousFunctions(bool allow);
private:
Preprocessor *m_preprocessor;
Lexer *m_lexer;
Parser *m_parser;
Validator *m_validator;
Evaluator *m_evaluator;
std::vector<ASTNode*> m_currAST;
std::optional<std::pair<u32, std::string>> m_currError;
};
}

View File

@@ -0,0 +1,40 @@
#pragma once
#include <hex.hpp>
#include <functional>
#include <optional>
#include <set>
#include <string>
#include <unordered_map>
#include <utility>
namespace hex::pl {
class Preprocessor {
public:
Preprocessor();
std::optional<std::string> preprocess(const std::string& code, bool initialRun = true);
void addPragmaHandler(const std::string &pragmaType, const std::function<bool(const std::string&)> &function);
void addDefaultPragmaHandlers();
const std::pair<u32, std::string>& getError() { return this->m_error; }
private:
using PreprocessorError = std::pair<u32, std::string>;
[[noreturn]] void throwPreprocessorError(const std::string &error, u32 lineNumber) const {
throw PreprocessorError(lineNumber, "Preprocessor: " + error);
}
std::unordered_map<std::string, std::function<bool(std::string)>> m_pragmaHandlers;
std::set<std::tuple<std::string, std::string, u32>> m_defines;
std::set<std::tuple<std::string, std::string, u32>> m_pragmas;
std::pair<u32, std::string> m_error;
};
}

View File

@@ -0,0 +1,348 @@
#pragma once
#include <hex.hpp>
#include <utility>
#include <string>
#include <variant>
#include <hex/helpers/utils.hpp>
namespace hex::pl {
class PatternData;
class Token {
public:
enum class Type : u64 {
Keyword,
ValueType,
Operator,
Integer,
String,
Identifier,
Separator
};
enum class Keyword {
Struct,
Union,
Using,
Enum,
Bitfield,
LittleEndian,
BigEndian,
If,
Else,
Parent,
This,
While,
For,
Function,
Return,
Namespace,
In,
Out,
Break,
Continue
};
enum class Operator {
AtDeclaration,
Assignment,
Inherit,
Plus,
Minus,
Star,
Slash,
Percent,
ShiftLeft,
ShiftRight,
BitOr,
BitAnd,
BitXor,
BitNot,
BoolEquals,
BoolNotEquals,
BoolGreaterThan,
BoolLessThan,
BoolGreaterThanOrEquals,
BoolLessThanOrEquals,
BoolAnd,
BoolOr,
BoolXor,
BoolNot,
TernaryConditional,
Dollar,
AddressOf,
SizeOf,
ScopeResolution
};
enum class ValueType {
Unsigned8Bit = 0x10,
Signed8Bit = 0x11,
Unsigned16Bit = 0x20,
Signed16Bit = 0x21,
Unsigned32Bit = 0x40,
Signed32Bit = 0x41,
Unsigned64Bit = 0x80,
Signed64Bit = 0x81,
Unsigned128Bit = 0x100,
Signed128Bit = 0x101,
Character = 0x13,
Character16 = 0x23,
Boolean = 0x14,
Float = 0x42,
Double = 0x82,
String = 0x15,
Auto = 0x16,
CustomType = 0x00,
Padding = 0x1F,
Unsigned = 0xFF00,
Signed = 0xFF01,
FloatingPoint = 0xFF02,
Integer = 0xFF03,
Any = 0xFFFF
};
enum class Separator {
RoundBracketOpen,
RoundBracketClose,
CurlyBracketOpen,
CurlyBracketClose,
SquareBracketOpen,
SquareBracketClose,
Comma,
Dot,
EndOfExpression,
EndOfProgram
};
struct Identifier {
explicit Identifier(std::string identifier) : m_identifier(std::move(identifier)) { }
[[nodiscard]]
const std::string &get() const { return this->m_identifier; }
auto operator<=>(const Identifier&) const = default;
bool operator==(const Identifier&) const = default;
private:
std::string m_identifier;
};
using Literal = std::variant<char, bool, u128, s128, double, std::string, PatternData*>;
using ValueTypes = std::variant<Keyword, Identifier, Operator, Literal, ValueType, Separator>;
Token(Type type, auto value, u32 lineNumber) : type(type), value(value), lineNumber(lineNumber) {
}
[[nodiscard]] constexpr static inline bool isUnsigned(const ValueType type) {
return (static_cast<u32>(type) & 0x0F) == 0x00;
}
[[nodiscard]] constexpr static inline bool isSigned(const ValueType type) {
return (static_cast<u32>(type) & 0x0F) == 0x01;
}
[[nodiscard]] constexpr static inline bool isFloatingPoint(const ValueType type) {
return (static_cast<u32>(type) & 0x0F) == 0x02;
}
[[nodiscard]] constexpr static inline u32 getTypeSize(const ValueType type) {
return static_cast<u32>(type) >> 4;
}
static u128 literalToUnsigned(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](std::string) -> u128 { throw std::string("expected integral type, got string"); },
[](PatternData*) -> u128 { throw std::string("expected integral type, got custom type"); },
[](auto &&value) -> u128 { return value; }
},
literal);
}
static s128 literalToSigned(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](std::string) -> s128 { throw std::string("expected integral type, got string"); },
[](PatternData*) -> s128 { throw std::string("expected integral type, got custom type"); },
[](auto &&value) -> s128 { return value; }
},
literal);
}
static double literalToFloatingPoint(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](std::string) -> double { throw std::string("expected integral type, got string"); },
[](PatternData*) -> double { throw std::string("expected integral type, got custom type"); },
[](auto &&value) -> double { return value; }
},
literal);
}
static bool literalToBoolean(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](std::string) -> bool { throw std::string("expected integral type, got string"); },
[](PatternData*) -> bool { throw std::string("expected integral type, got custom type"); },
[](auto &&value) -> bool { return value != 0; }
},
literal);
}
static std::string literalToString(const pl::Token::Literal &literal, bool cast) {
if (!cast && std::get_if<std::string>(&literal) == nullptr)
throw std::string("expected string type, got integral");
return std::visit(overloaded {
[](std::string value) -> std::string { return value; },
[](u128 value) -> std::string { return std::to_string(u64(value)); },
[](s128 value) -> std::string { return std::to_string(s64(value)); },
[](bool value) -> std::string { return value ? "true" : "false"; },
[](char value) -> std::string { return std::string() + value; },
[](PatternData*) -> std::string { throw std::string("expected integral type, got custom type"); },
[](auto &&value) -> std::string { return std::to_string(value); }
},
literal);
}
[[nodiscard]] constexpr static auto getTypeName(const pl::Token::ValueType type) {
switch (type) {
case ValueType::Signed8Bit: return "s8";
case ValueType::Signed16Bit: return "s16";
case ValueType::Signed32Bit: return "s32";
case ValueType::Signed64Bit: return "s64";
case ValueType::Signed128Bit: return "s128";
case ValueType::Unsigned8Bit: return "u8";
case ValueType::Unsigned16Bit: return "u16";
case ValueType::Unsigned32Bit: return "u32";
case ValueType::Unsigned64Bit: return "u64";
case ValueType::Unsigned128Bit: return "u128";
case ValueType::Float: return "float";
case ValueType::Double: return "double";
case ValueType::Character: return "char";
case ValueType::Character16: return "char16";
case ValueType::Padding: return "padding";
case ValueType::String: return "str";
default: return "< ??? >";
}
}
bool operator==(const ValueTypes &other) const {
if (this->type == Type::Integer || this->type == Type::Identifier || this->type == Type::String)
return true;
else if (this->type == Type::ValueType) {
auto otherValueType = std::get_if<ValueType>(&other);
auto valueType = std::get_if<ValueType>(&this->value);
if (otherValueType == nullptr) return false;
if (valueType == nullptr) return false;
if (*otherValueType == *valueType)
return true;
else if (*otherValueType == ValueType::Any)
return *valueType != ValueType::CustomType && *valueType != ValueType::Padding;
else if (*otherValueType == ValueType::Unsigned)
return isUnsigned(*valueType);
else if (*otherValueType == ValueType::Signed)
return isSigned(*valueType);
else if (*otherValueType == ValueType::FloatingPoint)
return isFloatingPoint(*valueType);
else if (*otherValueType == ValueType::Integer)
return isUnsigned(*valueType) || isSigned(*valueType);
}
else
return other == this->value;
return false;
}
bool operator!=(const ValueTypes &other) const {
return !operator==(other);
}
Type type;
ValueTypes value;
u32 lineNumber;
};
}
#define COMPONENT(type, value) hex::pl::Token::Type::type, hex::pl::Token::type::value
#define KEYWORD_STRUCT COMPONENT(Keyword, Struct)
#define KEYWORD_UNION COMPONENT(Keyword, Union)
#define KEYWORD_USING COMPONENT(Keyword, Using)
#define KEYWORD_ENUM COMPONENT(Keyword, Enum)
#define KEYWORD_BITFIELD COMPONENT(Keyword, Bitfield)
#define KEYWORD_LE COMPONENT(Keyword, LittleEndian)
#define KEYWORD_BE COMPONENT(Keyword, BigEndian)
#define KEYWORD_IF COMPONENT(Keyword, If)
#define KEYWORD_ELSE COMPONENT(Keyword, Else)
#define KEYWORD_PARENT COMPONENT(Keyword, Parent)
#define KEYWORD_THIS COMPONENT(Keyword, This)
#define KEYWORD_WHILE COMPONENT(Keyword, While)
#define KEYWORD_FOR COMPONENT(Keyword, For)
#define KEYWORD_FUNCTION COMPONENT(Keyword, Function)
#define KEYWORD_RETURN COMPONENT(Keyword, Return)
#define KEYWORD_NAMESPACE COMPONENT(Keyword, Namespace)
#define KEYWORD_IN COMPONENT(Keyword, In)
#define KEYWORD_OUT COMPONENT(Keyword, Out)
#define KEYWORD_BREAK COMPONENT(Keyword, Break)
#define KEYWORD_CONTINUE COMPONENT(Keyword, Continue)
#define INTEGER hex::pl::Token::Type::Integer, hex::pl::Token::Literal(u128(0))
#define IDENTIFIER hex::pl::Token::Type::Identifier, ""
#define STRING hex::pl::Token::Type::String, hex::pl::Token::Literal("")
#define OPERATOR_AT COMPONENT(Operator, AtDeclaration)
#define OPERATOR_ASSIGNMENT COMPONENT(Operator, Assignment)
#define OPERATOR_INHERIT COMPONENT(Operator, Inherit)
#define OPERATOR_PLUS COMPONENT(Operator, Plus)
#define OPERATOR_MINUS COMPONENT(Operator, Minus)
#define OPERATOR_STAR COMPONENT(Operator, Star)
#define OPERATOR_SLASH COMPONENT(Operator, Slash)
#define OPERATOR_PERCENT COMPONENT(Operator, Percent)
#define OPERATOR_SHIFTLEFT COMPONENT(Operator, ShiftLeft)
#define OPERATOR_SHIFTRIGHT COMPONENT(Operator, ShiftRight)
#define OPERATOR_BITOR COMPONENT(Operator, BitOr)
#define OPERATOR_BITAND COMPONENT(Operator, BitAnd)
#define OPERATOR_BITXOR COMPONENT(Operator, BitXor)
#define OPERATOR_BITNOT COMPONENT(Operator, BitNot)
#define OPERATOR_BOOLEQUALS COMPONENT(Operator, BoolEquals)
#define OPERATOR_BOOLNOTEQUALS COMPONENT(Operator, BoolNotEquals)
#define OPERATOR_BOOLGREATERTHAN COMPONENT(Operator, BoolGreaterThan)
#define OPERATOR_BOOLLESSTHAN COMPONENT(Operator, BoolLessThan)
#define OPERATOR_BOOLGREATERTHANOREQUALS COMPONENT(Operator, BoolGreaterThanOrEquals)
#define OPERATOR_BOOLLESSTHANOREQUALS COMPONENT(Operator, BoolLessThanOrEquals)
#define OPERATOR_BOOLAND COMPONENT(Operator, BoolAnd)
#define OPERATOR_BOOLOR COMPONENT(Operator, BoolOr)
#define OPERATOR_BOOLXOR COMPONENT(Operator, BoolXor)
#define OPERATOR_BOOLNOT COMPONENT(Operator, BoolNot)
#define OPERATOR_TERNARYCONDITIONAL COMPONENT(Operator, TernaryConditional)
#define OPERATOR_DOLLAR COMPONENT(Operator, Dollar)
#define OPERATOR_ADDRESSOF COMPONENT(Operator, AddressOf)
#define OPERATOR_SIZEOF COMPONENT(Operator, SizeOf)
#define OPERATOR_SCOPERESOLUTION COMPONENT(Operator, ScopeResolution)
#define VALUETYPE_CUSTOMTYPE COMPONENT(ValueType, CustomType)
#define VALUETYPE_PADDING COMPONENT(ValueType, Padding)
#define VALUETYPE_UNSIGNED COMPONENT(ValueType, Unsigned)
#define VALUETYPE_SIGNED COMPONENT(ValueType, Signed)
#define VALUETYPE_FLOATINGPOINT COMPONENT(ValueType, FloatingPoint)
#define VALUETYPE_INTEGER COMPONENT(ValueType, Integer)
#define VALUETYPE_ANY COMPONENT(ValueType, Any)
#define SEPARATOR_ROUNDBRACKETOPEN COMPONENT(Separator, RoundBracketOpen)
#define SEPARATOR_ROUNDBRACKETCLOSE COMPONENT(Separator, RoundBracketClose)
#define SEPARATOR_CURLYBRACKETOPEN COMPONENT(Separator, CurlyBracketOpen)
#define SEPARATOR_CURLYBRACKETCLOSE COMPONENT(Separator, CurlyBracketClose)
#define SEPARATOR_SQUAREBRACKETOPEN COMPONENT(Separator, SquareBracketOpen)
#define SEPARATOR_SQUAREBRACKETCLOSE COMPONENT(Separator, SquareBracketClose)
#define SEPARATOR_COMMA COMPONENT(Separator, Comma)
#define SEPARATOR_DOT COMPONENT(Separator, Dot)
#define SEPARATOR_ENDOFEXPRESSION COMPONENT(Separator, EndOfExpression)
#define SEPARATOR_ENDOFPROGRAM COMPONENT(Separator, EndOfProgram)

View File

@@ -0,0 +1,31 @@
#pragma once
#include <hex.hpp>
#include <string>
#include <vector>
namespace hex::pl {
class ASTNode;
class Validator {
public:
Validator();
bool validate(const std::vector<ASTNode*>& ast);
const std::pair<u32, std::string>& getError() { return this->m_error; }
private:
std::pair<u32, std::string> m_error;
using ValidatorError = std::pair<u32, std::string>;
[[noreturn]] void throwValidateError(std::string_view error, u32 lineNumber) const {
throw ValidatorError(lineNumber, error);
}
};
}

View File

@@ -0,0 +1,20 @@
#pragma once
#include <imgui.h>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui_internal.h>
#include <hex.hpp>
#define IMHEX_PLUGIN_SETUP(name, author, description) IMHEX_PLUGIN_SETUP_IMPL(IMHEX_PLUGIN_NAME, name, author, description)
#define IMHEX_PLUGIN_SETUP_IMPL(namespaceName, name, author, description) \
namespace hex::plugin::namespaceName::internal { \
[[gnu::visibility("default")]] void initializePlugin(); \
\
[[gnu::visibility("default")]] const char* getPluginName() { return name; } \
[[gnu::visibility("default")]] const char* getPluginAuthor() { return author; } \
[[gnu::visibility("default")]] const char* getPluginDescription() { return description; } \
[[gnu::visibility("default")]] void setImGuiContext(ImGuiContext *ctx) { ImGui::SetCurrentContext(ctx); GImGui = ctx; } \
} \
void hex::plugin::namespaceName::internal::initializePlugin()

View File

@@ -0,0 +1,24 @@
#pragma once
#include <hex.hpp>
#include <vector>
namespace hex::prv {
class Overlay {
public:
Overlay() { }
void setAddress(u64 address) { this->m_address = address; }
[[nodiscard]] u64 getAddress() const { return this->m_address; }
[[nodiscard]] u64 getSize() const { return this->m_data.size(); }
[[nodiscard]] std::vector<u8>& getData() { return this->m_data; }
private:
u64 m_address = 0;
std::vector<u8> m_data;
};
}

View File

@@ -0,0 +1,89 @@
#pragma once
#include <hex.hpp>
#include <map>
#include <optional>
#include <string>
#include <vector>
#include <hex/helpers/shared_data.hpp>
#include <hex/providers/overlay.hpp>
namespace hex::prv {
class Provider {
public:
constexpr static size_t PageSize = 0x1000'0000;
Provider();
virtual ~Provider();
[[nodiscard]] virtual bool isAvailable() const = 0;
[[nodiscard]] virtual bool isReadable() const = 0;
[[nodiscard]] virtual bool isWritable() const = 0;
[[nodiscard]] virtual bool isResizable() const = 0;
[[nodiscard]] virtual bool isSavable() const = 0;
virtual void read(u64 offset, void *buffer, size_t size, bool overlays = true);
virtual void write(u64 offset, const void *buffer, size_t size);
virtual void resize(ssize_t newSize);
virtual void save();
virtual void saveAs(const fs::path &path);
virtual void readRaw(u64 offset, void *buffer, size_t size) = 0;
virtual void writeRaw(u64 offset, const void *buffer, size_t size) = 0;
[[nodiscard]] virtual size_t getActualSize() const = 0;
void applyOverlays(u64 offset, void *buffer, size_t size);
[[nodiscard]] std::map<u64, u8>& getPatches();
[[nodiscard]] const std::map<u64, u8>& getPatches() const;
void applyPatches();
[[nodiscard]] Overlay* newOverlay();
void deleteOverlay(Overlay *overlay);
[[nodiscard]] const std::list<Overlay*>& getOverlays();
[[nodiscard]] u32 getPageCount() const;
[[nodiscard]] u32 getCurrentPage() const;
void setCurrentPage(u32 page);
virtual void setBaseAddress(u64 address);
[[nodiscard]] virtual u64 getBaseAddress() const;
[[nodiscard]] virtual u64 getCurrentPageAddress() const;
[[nodiscard]] virtual size_t getSize() const;
[[nodiscard]] virtual std::optional<u32> getPageOfAddress(u64 address) const;
[[nodiscard]] virtual std::string getName() const = 0;
[[nodiscard]] virtual std::vector<std::pair<std::string, std::string>> getDataInformation() const = 0;
[[nodiscard]] virtual bool open() = 0;
virtual void close() = 0;
void addPatch(u64 offset, const void *buffer, size_t size, bool createUndo = false);
void createUndoPoint();
void undo();
void redo();
[[nodiscard]] bool canUndo() const;
[[nodiscard]] bool canRedo() const;
[[nodiscard]] virtual bool hasLoadInterface() const;
[[nodiscard]] virtual bool hasInterface() const;
virtual void drawLoadInterface();
virtual void drawInterface();
protected:
u32 m_currPage = 0;
u64 m_baseAddress = 0;
u32 m_patchTreeOffset = 0;
std::list<std::map<u64, u8>> m_patches;
std::list<Overlay*> m_overlays;
};
}

View File

@@ -0,0 +1,108 @@
#pragma once
#include <functional>
#include <imgui.h>
#include <hex/helpers/fmt.hpp>
enum ImGuiCustomCol {
ImGuiCustomCol_DescButton,
ImGuiCustomCol_DescButtonHovered,
ImGuiCustomCol_DescButtonActive,
ImGuiCustomCol_ToolbarGray,
ImGuiCustomCol_ToolbarRed,
ImGuiCustomCol_ToolbarYellow,
ImGuiCustomCol_ToolbarGreen,
ImGuiCustomCol_ToolbarBlue,
ImGuiCustomCol_ToolbarPurple,
ImGuiCustomCol_ToolbarBrown,
ImGuiCustomCol_Highlight,
ImGuiCustomCol_COUNT
};
namespace ImGui {
struct Texture {
ImTextureID textureId;
int width, height;
[[nodiscard]]
constexpr bool valid() const noexcept {
return this->textureId != nullptr;
}
[[nodiscard]]
constexpr operator ImTextureID() {
return this->textureId;
}
[[nodiscard]]
auto size() const noexcept {
return ImVec2(this->width, this->height);
}
};
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data);
bool IconHyperlink(const char *icon, const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
bool Hyperlink(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
bool BulletHyperlink(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
bool DescriptionButton(const char* label, const char* description, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
void UnderlinedText(const char* label, ImColor color = ImGui::GetStyleColorVec4(ImGuiCol_Text), const ImVec2& size_arg = ImVec2(0, 0));
void Disabled(const std::function<void()> &widgets, bool disabled);
void TextSpinner(const char* label);
void Header(const char *label, bool firstEntry = false);
void HeaderColored(const char *label, ImColor color, bool firstEntry);
void InfoTooltip(const char *text);
bool TitleBarButton(const char* label, ImVec2 size_arg);
bool ToolBarButton(const char* symbol, ImVec4 color);
bool IconButton(const char* symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0));
inline bool HasSecondPassed() {
return static_cast<ImU32>(ImGui::GetTime() * 100) % 100 <= static_cast<ImU32>(ImGui::GetIO().DeltaTime * 100);
}
Texture LoadImageFromPath(const char *path);
Texture LoadImageFromMemory(const ImU8 *buffer, int size);
void UnloadImage(Texture &texture);
void OpenPopupInWindow(const char *window_name, const char *popup_name);
struct ImHexCustomData {
ImVec4 Colors[ImGuiCustomCol_COUNT];
};
ImU32 GetCustomColorU32(ImGuiCustomCol idx, float alpha_mul = 1.0F);
ImVec4 GetCustomColorVec4(ImGuiCustomCol idx, float alpha_mul = 1.0F);
void StyleCustomColorsDark();
void StyleCustomColorsLight();
void StyleCustomColorsClassic();
void SmallProgressBar(float fraction, float yOffset = 0.0F);
void TextFormatted(const std::string &fmt, auto&& ... args) {
ImGui::TextUnformatted(hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
}
void TextFormattedColored(ImColor color, const std::string &fmt, auto&& ... args) {
ImGui::TextColored(color, "%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
}
void TextFormattedDisabled(const std::string &fmt, auto&& ... args) {
ImGui::TextDisabled("%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
}
void TextFormattedWrapped(const std::string &fmt, auto&& ... args) {
ImGui::TextWrapped("%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
}
}

View File

@@ -0,0 +1,72 @@
#pragma once
#include <hex.hpp>
#include <imgui.h>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui_internal.h>
#include <hex/ui/imgui_imhex_extensions.h>
#include <fontawesome_font.h>
#include <codicons_font.h>
#include <hex/api/imhex_api.hpp>
#include <hex/api/event.hpp>
#include <hex/providers/provider.hpp>
#include <hex/helpers/lang.hpp>
#include <functional>
#include <string>
#include <vector>
namespace hex {
using namespace hex::lang_literals;
class View {
public:
explicit View(std::string unlocalizedViewName);
virtual ~View() = default;
virtual void drawContent() = 0;
virtual void drawAlwaysVisible() { }
virtual void drawMenu();
virtual bool isAvailable() const;
virtual bool shouldProcess() const { return this->isAvailable() && this->getWindowOpenState(); }
static void doLater(std::function<void()> &&function);
static std::vector<std::function<void()>>& getDeferedCalls();
static void drawCommonInterfaces();
static void showMessagePopup(const std::string &message);
static void showErrorPopup(const std::string &errorMessage);
static void showFatalPopup(const std::string &errorMessage);
virtual bool hasViewMenuItemEntry() const;
virtual ImVec2 getMinSize() const;
virtual ImVec2 getMaxSize() const;
bool& getWindowOpenState();
const bool& getWindowOpenState() const;
[[nodiscard]] const std::string& getUnlocalizedName() const;
static void confirmButtons(const std::string &textLeft, const std::string &textRight, const std::function<void()> &leftButtonFn, const std::function<void()> &rightButtonFn);
static void discardNavigationRequests();
static inline std::string toWindowName(const std::string &unlocalizedName) {
return LangEntry(unlocalizedName) + "###" + unlocalizedName;
}
private:
std::string m_unlocalizedViewName;
bool m_windowOpen = false;
std::map<Shortcut, std::function<void()>> m_shortcuts;
friend class ShortcutManager;
};
}