diff --git a/include/views/view_data_processor.hpp b/include/views/view_data_processor.hpp index 7712fff63..fb0d839d5 100644 --- a/include/views/view_data_processor.hpp +++ b/include/views/view_data_processor.hpp @@ -32,6 +32,8 @@ namespace hex { int m_rightClickedId = -1; ImVec2 m_rightClickedCoords; + std::optional m_currNodeError; + void eraseLink(u32 id); void eraseNodes(const std::vector &ids); void processNodes(); diff --git a/plugins/builtin/source/content/data_processor_nodes.cpp b/plugins/builtin/source/content/data_processor_nodes.cpp index eb2bb3681..f6a26cfd6 100644 --- a/plugins/builtin/source/content/data_processor_nodes.cpp +++ b/plugins/builtin/source/content/data_processor_nodes.cpp @@ -127,18 +127,14 @@ namespace hex::plugin::builtin { } void process() override { + this->m_value.reset(); auto input = this->getIntegerOnInput(0); - if (!input.has_value()) { - this->m_value.reset(); - return; - } - - this->m_value = input.value(); + this->m_value = input; } private: - std::optional m_value = 0; + std::optional m_value; }; class NodeDisplayFloat : public dp::Node { @@ -155,18 +151,14 @@ namespace hex::plugin::builtin { } void process() override { + this->m_value.reset(); auto input = this->getFloatOnInput(0); - if (!input.has_value()) { - this->m_value.reset(); - return; - } - - this->m_value = input.value(); + this->m_value = input; } private: - std::optional m_value = 0; + std::optional m_value; }; @@ -177,10 +169,7 @@ namespace hex::plugin::builtin { void process() override { auto input = this->getBufferOnInput(0); - if (!input.has_value()) - return; - - std::vector output = input.value(); + std::vector output = input; for (auto &byte : output) byte = ~byte; @@ -196,13 +185,10 @@ namespace hex::plugin::builtin { auto inputA = this->getBufferOnInput(0); auto inputB = this->getBufferOnInput(1); - if (!inputA.has_value() || !inputB.has_value()) - return; - - std::vector output(std::min(inputA->size(), inputB->size()), 0x00); + std::vector output(std::min(inputA.size(), inputB.size()), 0x00); for (u32 i = 0; i < output.size(); i++) - output[i] = inputA.value()[i] & inputB.value()[i]; + output[i] = inputA[i] & inputB[i]; this->setBufferOnOutput(2, output); } @@ -216,13 +202,10 @@ namespace hex::plugin::builtin { auto inputA = this->getBufferOnInput(0); auto inputB = this->getBufferOnInput(1); - if (!inputA.has_value() || !inputB.has_value()) - return; - - std::vector output(std::min(inputA->size(), inputB->size()), 0x00); + std::vector output(std::min(inputA.size(), inputB.size()), 0x00); for (u32 i = 0; i < output.size(); i++) - output[i] = inputA.value()[i] | inputB.value()[i]; + output[i] = inputA[i] | inputB[i]; this->setBufferOnOutput(2, output); } @@ -236,13 +219,10 @@ namespace hex::plugin::builtin { auto inputA = this->getBufferOnInput(0); auto inputB = this->getBufferOnInput(1); - if (!inputA.has_value() || !inputB.has_value()) - return; - - std::vector output(std::min(inputA->size(), inputB->size()), 0x00); + std::vector output(std::min(inputA.size(), inputB.size()), 0x00); for (u32 i = 0; i < output.size(); i++) - output[i] = inputA.value()[i] ^ inputB.value()[i]; + output[i] = inputA[i] ^ inputB[i]; this->setBufferOnOutput(2, output); } @@ -259,13 +239,10 @@ namespace hex::plugin::builtin { auto address = this->getIntegerOnInput(0); auto size = this->getIntegerOnInput(1); - if (!address.has_value() || !size.has_value()) - return; - std::vector data; - data.resize(size.value()); + data.resize(size); - SharedData::currentProvider->readRaw(address.value(), data.data(), size.value()); + SharedData::currentProvider->readRaw(address, data.data(), size); this->setBufferOnOutput(2, data); } @@ -279,10 +256,7 @@ namespace hex::plugin::builtin { auto address = this->getIntegerOnInput(0); auto data = this->getBufferOnInput(1); - if (!address.has_value() || !data.has_value()) - return; - - this->setOverlayData(address.value(), data.value()); + this->setOverlayData(address, data); } }; @@ -293,11 +267,8 @@ namespace hex::plugin::builtin { void process() override { auto input = this->getIntegerOnInput(0); - if (!input.has_value()) - return; - std::vector output(sizeof(u64), 0x00); - std::memcpy(output.data(), &input.value(), sizeof(u64)); + std::memcpy(output.data(), &input, sizeof(u64)); this->setBufferOnOutput(1, output); } @@ -310,11 +281,8 @@ namespace hex::plugin::builtin { void process() override { auto input = this->getBufferOnInput(0); - if (!input.has_value()) - return; - u64 output; - std::memcpy(&output, input->data(), sizeof(u64)); + std::memcpy(&output, input.data(), sizeof(u64)); this->setIntegerOnOutput(1, output); } @@ -332,13 +300,10 @@ namespace hex::plugin::builtin { auto trueData = this->getBufferOnInput(1); auto falseData = this->getBufferOnInput(2); - if (!cond.has_value() || !trueData.has_value() || !falseData.has_value()) - return; - - if (cond.value() != 0) - this->setBufferOnOutput(3, trueData.value()); + if (cond != 0) + this->setBufferOnOutput(3, trueData); else - this->setBufferOnOutput(3, falseData.value()); + this->setBufferOnOutput(3, falseData); } }; @@ -353,10 +318,7 @@ namespace hex::plugin::builtin { auto inputA = this->getIntegerOnInput(0); auto inputB = this->getIntegerOnInput(1); - if (!inputA.has_value() || !inputB.has_value()) - return; - - this->setIntegerOnOutput(2, inputA.value() == inputB.value()); + this->setIntegerOnOutput(2, inputA == inputB); } }; @@ -368,10 +330,7 @@ namespace hex::plugin::builtin { void process() override { auto input = this->getIntegerOnInput(0); - if (!input.has_value()) - return; - - this->setIntegerOnOutput(1, !input.value()); + this->setIntegerOnOutput(1, !input); } }; @@ -385,10 +344,7 @@ namespace hex::plugin::builtin { auto inputA = this->getIntegerOnInput(0); auto inputB = this->getIntegerOnInput(1); - if (!inputA.has_value() || !inputB.has_value()) - return; - - this->setIntegerOnOutput(2, inputA.value() > inputB.value()); + this->setIntegerOnOutput(2, inputA > inputB); } }; @@ -402,10 +358,7 @@ namespace hex::plugin::builtin { auto inputA = this->getIntegerOnInput(0); auto inputB = this->getIntegerOnInput(1); - if (!inputA.has_value() || !inputB.has_value()) - return; - - this->setIntegerOnOutput(2, inputA.value() < inputB.value()); + this->setIntegerOnOutput(2, inputA < inputB); } }; @@ -419,10 +372,7 @@ namespace hex::plugin::builtin { auto inputA = this->getIntegerOnInput(0); auto inputB = this->getIntegerOnInput(1); - if (!inputA.has_value() || !inputB.has_value()) - return; - - this->setIntegerOnOutput(2, inputA.value() && inputB.value()); + this->setIntegerOnOutput(2, inputA && inputB); } }; @@ -436,10 +386,7 @@ namespace hex::plugin::builtin { auto inputA = this->getIntegerOnInput(0); auto inputB = this->getIntegerOnInput(1); - if (!inputA.has_value() || !inputB.has_value()) - return; - - this->setIntegerOnOutput(2, inputA.value() || inputB.value()); + this->setIntegerOnOutput(2, inputA || inputB); } }; @@ -464,18 +411,18 @@ namespace hex::plugin::builtin { auto nonce = this->getBufferOnInput(2); auto input = this->getBufferOnInput(3); - if (!key.has_value() || !iv.has_value() || !nonce.has_value() || !input.has_value()) - return; + if (key.empty()) + throwNodeError("Key cannot be empty"); - if (key->empty() || input->empty()) - return; + if (input.empty()) + throwNodeError("Input cannot be empty"); std::array ivData = { 0 }, nonceData = { 0 }; - std::copy(iv->begin(), iv->end(), ivData.begin()); - std::copy(nonce->begin(), nonce->end(), nonceData.begin()); + std::copy(iv.begin(), iv.end(), ivData.begin()); + std::copy(nonce.begin(), nonce.end(), nonceData.begin()); - auto output = crypt::aesDecrypt(static_cast(this->m_mode), static_cast(this->m_keyLength), key.value(), nonceData, ivData, input.value()); + auto output = crypt::aesDecrypt(static_cast(this->m_mode), static_cast(this->m_keyLength), key, nonceData, ivData, input); this->setBufferOnOutput(4, output); } @@ -494,10 +441,7 @@ namespace hex::plugin::builtin { void process() override { auto input = this->getBufferOnInput(0); - if (!input.has_value()) - return; - - auto output = crypt::decode64(input.value()); + auto output = crypt::decode64(input); this->setBufferOnOutput(1, output); } @@ -512,19 +456,16 @@ namespace hex::plugin::builtin { void process() override { auto input = this->getBufferOnInput(0); - if (!input.has_value()) - return; - - if (input->size() % 2 != 0) - return; + if (input.size() % 2 != 0) + throwNodeError("Can't decode odd number of hex characters"); std::vector output; - for (u32 i = 0; i < input->size(); i += 2) { - char c1 = tolower(input->at(i)); - char c2 = tolower(input->at(i + 1)); + for (u32 i = 0; i < input.size(); i += 2) { + char c1 = tolower(input[i]); + char c2 = tolower(input[i + 1]); if (!std::isxdigit(c1) || !isxdigit(c2)) - return; + throwNodeError("Can't decode non-hexadecimal character"); u8 value; if (std::isdigit(c1)) diff --git a/plugins/libimhex/include/hex/data_processor/attribute.hpp b/plugins/libimhex/include/hex/data_processor/attribute.hpp index 52c85ec51..b38fee1af 100644 --- a/plugins/libimhex/include/hex/data_processor/attribute.hpp +++ b/plugins/libimhex/include/hex/data_processor/attribute.hpp @@ -36,7 +36,7 @@ namespace hex::dp { [[nodiscard]] Node* getParentNode() { return this->m_parentNode; } - [[nodiscard]] std::vector& getOutputData() { return this->m_outputData; } + [[nodiscard]] std::optional>& getOutputData() { return this->m_outputData; } private: u32 m_id; IOType m_ioType; @@ -45,7 +45,7 @@ namespace hex::dp { std::map m_connectedAttributes; Node *m_parentNode; - std::vector m_outputData; + std::optional> m_outputData; friend class Node; void setParentNode(Node *node) { this->m_parentNode = node; } diff --git a/plugins/libimhex/include/hex/data_processor/node.hpp b/plugins/libimhex/include/hex/data_processor/node.hpp index bddcc6080..1b5ba7e1e 100644 --- a/plugins/libimhex/include/hex/data_processor/node.hpp +++ b/plugins/libimhex/include/hex/data_processor/node.hpp @@ -23,6 +23,14 @@ namespace hex::dp { virtual void drawNode() { } virtual void process() = 0; + + using NodeError = std::pair; + + void resetOutputData() { + for (auto &attribute : this->m_attributes) + attribute.getOutputData().reset(); + } + private: u32 m_id; std::string m_title; @@ -43,49 +51,71 @@ namespace hex::dp { protected: - std::optional> getBufferOnInput(u32 index) { - auto attribute = this->getConnectedInputAttribute(index); - - if (attribute == nullptr || attribute->getType() != Attribute::Type::Buffer) - return { }; - - attribute->getParentNode()->process(); - - auto &outputData = attribute->getOutputData(); - - return outputData; + [[noreturn]] void throwNodeError(std::string_view message) { + throw NodeError(this, message); } - std::optional getIntegerOnInput(u32 index) { + std::vector getBufferOnInput(u32 index) { auto attribute = this->getConnectedInputAttribute(index); - if (attribute == nullptr || attribute->getType() != Attribute::Type::Integer) - return { }; + if (attribute == nullptr) + throwNodeError(hex::format("Nothing connected to input '%s'", this->m_attributes[index].getName().data())); + + if (attribute->getType() != Attribute::Type::Buffer) + throwNodeError("Tried to read buffer from non-buffer attribute"); attribute->getParentNode()->process(); auto &outputData = attribute->getOutputData(); - if (outputData.empty() || outputData.size() < sizeof(u64)) - return { }; - else - return *reinterpret_cast(outputData.data()); + if (!outputData.has_value()) + throw std::runtime_error("No data available at connected attribute"); + + return outputData.value(); } - std::optional getFloatOnInput(u32 index) { + u64 getIntegerOnInput(u32 index) { auto attribute = this->getConnectedInputAttribute(index); - if (attribute == nullptr || attribute->getType() != Attribute::Type::Float) - return { }; + if (attribute == nullptr) + throwNodeError(hex::format("Nothing connected to input '%s'", this->m_attributes[index].getName().data())); + + if (attribute->getType() != Attribute::Type::Integer) + throwNodeError("Tried to read integer from non-integer attribute"); attribute->getParentNode()->process(); auto &outputData = attribute->getOutputData(); - if (outputData.empty() || outputData.size() < sizeof(float)) - return { }; - else - return *reinterpret_cast(outputData.data()); + if (!outputData.has_value()) + throw std::runtime_error("No data available at connected attribute"); + + if (outputData->size() < sizeof(u64)) + throw std::runtime_error("Not enough data provided for integer"); + + return *reinterpret_cast(outputData->data()); + } + + float getFloatOnInput(u32 index) { + auto attribute = this->getConnectedInputAttribute(index); + + if (attribute == nullptr) + throwNodeError(hex::format("Nothing connected to input '%s'", this->m_attributes[index].getName().data())); + + if (attribute->getType() != Attribute::Type::Float) + throwNodeError("Tried to read float from non-float attribute"); + + attribute->getParentNode()->process(); + + auto &outputData = attribute->getOutputData(); + + if (!outputData.has_value()) + throw std::runtime_error("No data available at connected attribute"); + + if (outputData->size() < sizeof(float)) + throw std::runtime_error("Not enough data provided for float"); + + return *reinterpret_cast(outputData->data()); } void setBufferOnOutput(u32 index, std::vector data) { diff --git a/plugins/libimhex/include/hex/providers/provider.hpp b/plugins/libimhex/include/hex/providers/provider.hpp index ba4b8e8b8..6bb7f7a4a 100644 --- a/plugins/libimhex/include/hex/providers/provider.hpp +++ b/plugins/libimhex/include/hex/providers/provider.hpp @@ -17,7 +17,7 @@ namespace hex::prv { constexpr static size_t PageSize = 0x1000'0000; Provider(); - virtual ~Provider() = default; + virtual ~Provider(); virtual bool isAvailable() = 0; virtual bool isReadable() = 0; diff --git a/plugins/libimhex/source/providers/provider.cpp b/plugins/libimhex/source/providers/provider.cpp index 357ce166f..218ea5a02 100644 --- a/plugins/libimhex/source/providers/provider.cpp +++ b/plugins/libimhex/source/providers/provider.cpp @@ -6,7 +6,6 @@ #include #include #include -#include namespace hex::prv { @@ -14,6 +13,11 @@ namespace hex::prv { this->m_patches.emplace_back(); } + Provider::~Provider() { + for (auto &overlay : this->m_overlays) + this->deleteOverlay(overlay); + } + void Provider::read(u64 offset, void *buffer, size_t size) { this->readRaw(offset, buffer, size); } diff --git a/source/views/view_data_processor.cpp b/source/views/view_data_processor.cpp index afdde533d..7ff9b9796 100644 --- a/source/views/view_data_processor.cpp +++ b/source/views/view_data_processor.cpp @@ -35,6 +35,13 @@ namespace hex { imnodes::GetStyle().flags = imnodes::StyleFlags(imnodes::StyleFlags_NodeOutline | imnodes::StyleFlags_GridLines); }); + + View::subscribeEvent(Events::FileLoaded, [this](auto) { + for (auto &node : this->m_nodes) { + node->setCurrentOverlay(nullptr); + } + this->m_dataOverlays.clear(); + }); } ViewDataProcessor::~ViewDataProcessor() { @@ -103,11 +110,20 @@ namespace hex { } } - u32 overlayIndex = 0; - for (auto &endNode : this->m_endNodes) { - (void)endNode->process(); - overlayIndex++; + this->m_currNodeError.reset(); + + try { + for (auto &endNode : this->m_endNodes) { + endNode->resetOutputData(); + endNode->process(); + } + } catch (dp::Node::NodeError &e) { + this->m_currNodeError = e; + } catch (std::runtime_error &e) { + printf("Node implementation bug! %s\n", e.what()); } + + } void ViewDataProcessor::drawContent() { @@ -197,9 +213,25 @@ namespace hex { ImGui::EndPopup(); } + { + int nodeId; + if (imnodes::IsNodeHovered(&nodeId) && this->m_currNodeError.has_value() && this->m_currNodeError->first->getID() == nodeId) { + ImGui::BeginTooltip(); + ImGui::TextUnformatted("Error"); + ImGui::Separator(); + ImGui::TextUnformatted(this->m_currNodeError->second.c_str()); + ImGui::EndTooltip(); + } + } + imnodes::BeginNodeEditor(); for (auto& node : this->m_nodes) { + const bool hasError = this->m_currNodeError.has_value() && this->m_currNodeError->first == node; + + if (hasError) + imnodes::PushColorStyle(imnodes::ColorStyle_NodeOutline, 0xFF0000FF); + imnodes::BeginNode(node->getID()); imnodes::BeginNodeTitleBar(); @@ -229,6 +261,9 @@ namespace hex { } imnodes::EndNode(); + + if (hasError) + imnodes::PopColorStyle(); } for (const auto &link : this->m_links)