diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index 85e1aff1a..e3acd6e54 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -43,6 +43,14 @@ add_imhex_plugin( source/content/achievements.cpp source/content/file_extraction.cpp + source/content/dpn/basic_nodes.cpp + source/content/dpn/control_nodes.cpp + source/content/dpn/decode_nodes.cpp + source/content/dpn/logic_nodes.cpp + source/content/dpn/math_nodes.cpp + source/content/dpn/other_nodes.cpp + source/content/dpn/visual_nodes.cpp + source/content/providers/file_provider.cpp source/content/providers/gdb_provider.cpp source/content/providers/disk_provider.cpp diff --git a/plugins/builtin/include/content/data_processor_nodes.hpp b/plugins/builtin/include/content/data_processor_nodes.hpp new file mode 100644 index 000000000..1ea5de1f1 --- /dev/null +++ b/plugins/builtin/include/content/data_processor_nodes.hpp @@ -0,0 +1,13 @@ +#include + +namespace hex::plugin::builtin { + + void registerBasicDataProcessorNodes(); + void registerVisualDataProcessorNodes(); + void registerLogicDataProcessorNodes(); + void registerControlDataProcessorNodes(); + void registerDecodeDataProcessorNodes(); + void registerMathDataProcessorNodes(); + void registerOtherDataProcessorNodes(); + +} \ No newline at end of file diff --git a/plugins/builtin/include/content/helpers/diagrams.hpp b/plugins/builtin/include/content/helpers/diagrams.hpp index 94100796c..10f8f7d27 100644 --- a/plugins/builtin/include/content/helpers/diagrams.hpp +++ b/plugins/builtin/include/content/helpers/diagrams.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include diff --git a/plugins/builtin/source/content/data_processor_nodes.cpp b/plugins/builtin/source/content/data_processor_nodes.cpp index 67ce99cf2..b14649899 100644 --- a/plugins/builtin/source/content/data_processor_nodes.cpp +++ b/plugins/builtin/source/content/data_processor_nodes.cpp @@ -1,1404 +1,15 @@ -#include -#include -#include - -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include +#include namespace hex::plugin::builtin { - class NodeNullptr : public dp::Node { - public: - NodeNullptr() : Node("hex.builtin.nodes.constants.nullptr.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "") }) { } - - void process() override { - this->setBufferOnOutput(0, {}); - } - }; - - class NodeBuffer : public dp::Node { - public: - NodeBuffer() : Node("hex.builtin.nodes.constants.buffer.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "") }) { } - - void drawNode() override { - constexpr static int StepSize = 1, FastStepSize = 10; - - ImGui::PushItemWidth(100_scaled); - ImGui::InputScalar("hex.builtin.nodes.constants.buffer.size"_lang, ImGuiDataType_U32, &this->m_size, &StepSize, &FastStepSize); - ImGui::PopItemWidth(); - } - - void process() override { - if (this->m_buffer.size() != this->m_size) - this->m_buffer.resize(this->m_size, 0x00); - - this->setBufferOnOutput(0, this->m_buffer); - } - - void store(nlohmann::json &j) const override { - j = nlohmann::json::object(); - - j["size"] = this->m_size; - j["data"] = this->m_buffer; - } - - void load(const nlohmann::json &j) override { - this->m_size = j.at("size"); - this->m_buffer = j.at("data").get>(); - } - - private: - u32 m_size = 1; - std::vector m_buffer; - }; - - class NodeString : public dp::Node { - public: - NodeString() : Node("hex.builtin.nodes.constants.string.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "") }) { - - } - - void drawNode() override { - ImGui::InputTextMultiline("##string", this->m_value, ImVec2(150_scaled, 0), ImGuiInputTextFlags_AllowTabInput); - } - - void process() override { - this->setBufferOnOutput(0, hex::decodeByteString(this->m_value)); - } - - void store(nlohmann::json &j) const override { - j = nlohmann::json::object(); - - j["data"] = this->m_value; - } - - void load(const nlohmann::json &j) override { - this->m_value = j.at("data").get(); - } - - private: - std::string m_value; - }; - - class NodeInteger : public dp::Node { - public: - NodeInteger() : Node("hex.builtin.nodes.constants.int.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "") }) { } - - void drawNode() override { - ImGui::PushItemWidth(100_scaled); - ImGui::InputHexadecimal("##integer_value", &this->m_value); - ImGui::PopItemWidth(); - } - - void process() override { - this->setIntegerOnOutput(0, this->m_value); - } - - void store(nlohmann::json &j) const override { - j = nlohmann::json::object(); - - j["data"] = this->m_value; - } - - void load(const nlohmann::json &j) override { - this->m_value = j.at("data"); - } - - private: - u64 m_value = 0; - }; - - class NodeFloat : public dp::Node { - public: - NodeFloat() : Node("hex.builtin.nodes.constants.float.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Float, "") }) { } - - void drawNode() override { - ImGui::PushItemWidth(100_scaled); - ImGui::InputScalar("##floatValue", ImGuiDataType_Float, &this->m_value, nullptr, nullptr, "%f", ImGuiInputTextFlags_CharsDecimal); - ImGui::PopItemWidth(); - } - - void process() override { - this->setFloatOnOutput(0, this->m_value); - } - - void store(nlohmann::json &j) const override { - j = nlohmann::json::object(); - - j["data"] = this->m_value; - } - - void load(const nlohmann::json &j) override { - this->m_value = j.at("data"); - } - - private: - float m_value = 0; - }; - - class NodeRGBA8 : public dp::Node { - public: - NodeRGBA8() : Node("hex.builtin.nodes.constants.rgba8.header", - { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.constants.rgba8.output.r"), - dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.constants.rgba8.output.g"), - dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.constants.rgba8.output.b"), - dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.constants.rgba8.output.a") }) { } - - void drawNode() override { - ImGui::PushItemWidth(200_scaled); - ImGui::ColorPicker4("##colorPicker", &this->m_color.Value.x, ImGuiColorEditFlags_AlphaBar); - ImGui::PopItemWidth(); - } - - void process() override { - this->setBufferOnOutput(0, wolv::util::toBytes(u8(this->m_color.Value.x * 0xFF))); - this->setBufferOnOutput(1, wolv::util::toBytes(u8(this->m_color.Value.y * 0xFF))); - this->setBufferOnOutput(2, wolv::util::toBytes(u8(this->m_color.Value.z * 0xFF))); - this->setBufferOnOutput(3, wolv::util::toBytes(u8(this->m_color.Value.w * 0xFF))); - } - - void store(nlohmann::json &j) const override { - j = nlohmann::json::object(); - - j["data"] = nlohmann::json::object(); - j["data"]["r"] = this->m_color.Value.x; - j["data"]["g"] = this->m_color.Value.y; - j["data"]["b"] = this->m_color.Value.z; - j["data"]["a"] = this->m_color.Value.w; - } - - void load(const nlohmann::json &j) override { - const auto &color = j.at("data"); - this->m_color = ImVec4(color.at("r"), color.at("g"), color.at("b"), color.at("a")); - } - - private: - ImColor m_color; - }; - - class NodeComment : public dp::Node { - public: - NodeComment() : Node("hex.builtin.nodes.constants.comment.header", {}) { - - } - - void drawNode() override { - ImGui::InputTextMultiline("##string", this->m_comment, scaled(ImVec2(150, 100))); - } - - void process() override { - } - - void store(nlohmann::json &j) const override { - j = nlohmann::json::object(); - - j["comment"] = this->m_comment; - } - - void load(const nlohmann::json &j) override { - this->m_comment = j["comment"].get(); - } - - private: - std::string m_comment; - }; - - - class NodeDisplayInteger : public dp::Node { - public: - NodeDisplayInteger() : Node("hex.builtin.nodes.display.int.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input") }) { } - - void drawNode() override { - ImGui::PushItemWidth(150_scaled); - if (this->m_value.has_value()) - ImGui::TextFormatted("0x{0:X}", this->m_value.value()); - else - ImGui::TextUnformatted("???"); - ImGui::PopItemWidth(); - } - - void process() override { - this->m_value.reset(); - const auto &input = this->getIntegerOnInput(0); - - this->m_value = input; - } - - private: - std::optional m_value; - }; - - class NodeDisplayFloat : public dp::Node { - public: - NodeDisplayFloat() : Node("hex.builtin.nodes.display.float.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Float, "hex.builtin.nodes.common.input") }) { } - - void drawNode() override { - ImGui::PushItemWidth(150_scaled); - if (this->m_value.has_value()) - ImGui::TextFormatted("{0}", this->m_value.value()); - else - ImGui::TextUnformatted("???"); - ImGui::PopItemWidth(); - } - - void process() override { - this->m_value.reset(); - const auto &input = this->getFloatOnInput(0); - - this->m_value = input; - } - - private: - std::optional m_value; - }; - - class NodeDisplayBuffer : public dp::Node { - public: - NodeDisplayBuffer() : Node("hex.builtin.nodes.display.buffer.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { } - - void drawNode() override { - static const std::string Header = " Address 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F "; - - if (ImGui::BeginChild("##hex_view", scaled(ImVec2(ImGui::CalcTextSize(Header.c_str()).x, 200)), true)) { - ImGui::TextUnformatted(Header.c_str()); - - auto size = this->m_buffer.size(); - ImGuiListClipper clipper; - - clipper.Begin((size + 0x0F) / 0x10); - - while (clipper.Step()) - for (auto y = clipper.DisplayStart; y < clipper.DisplayEnd; y++) { - auto lineSize = ((size - y * 0x10) < 0x10) ? size % 0x10 : 0x10; - - std::string line = hex::format(" {:08X}: ", y * 0x10); - for (u32 x = 0; x < 0x10; x++) { - if (x < lineSize) - line += hex::format("{:02X} ", this->m_buffer[y * 0x10 + x]); - else - line += " "; - - if (x == 7) line += " "; - } - - line += " "; - - for (u32 x = 0; x < lineSize; x++) { - auto c = char(this->m_buffer[y * 0x10 + x]); - if (std::isprint(c)) - line += c; - else - line += "."; - } - - ImGui::TextUnformatted(line.c_str()); - } - clipper.End(); - } - ImGui::EndChild(); - } - - void process() override { - this->m_buffer = this->getBufferOnInput(0); - } - - private: - std::vector m_buffer; - }; - - class NodeDisplayString : public dp::Node { - public: - NodeDisplayString() : Node("hex.builtin.nodes.display.string.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { } - - void drawNode() override { - constexpr static auto LineLength = 50; - if (ImGui::BeginChild("##string_view", scaled(ImVec2(ImGui::CalcTextSize(" ").x * (LineLength + 4), 150)), true)) { - std::string_view string = this->m_value; - - ImGuiListClipper clipper; - clipper.Begin((string.length() + (LineLength - 1)) / LineLength); - - while (clipper.Step()) - for (auto i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - auto line = string.substr(i * LineLength, LineLength); - ImGui::TextUnformatted(""); - ImGui::SameLine(); - ImGui::TextUnformatted(line.data(), line.data() + line.length()); - } - - clipper.End(); - } - ImGui::EndChild(); - } - - void process() override { - const auto &input = this->getBufferOnInput(0); - - this->m_value = hex::encodeByteString(input); - } - - private: - std::string m_value; - }; - - - class NodeBitwiseNOT : public dp::Node { - public: - NodeBitwiseNOT() : Node("hex.builtin.nodes.bitwise.not.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &input = this->getBufferOnInput(0); - - std::vector output = input; - for (auto &byte : output) - byte = ~byte; - - this->setBufferOnOutput(1, output); - } - }; - - class NodeBitwiseShiftLeft : public dp::Node { - public: - NodeBitwiseShiftLeft() : Node("hex.builtin.nodes.bitwise.shift_left.header", { - dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), - dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.amount"), - dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") - }) { } - - void process() override { - const auto &input = this->getBufferOnInput(0); - const auto &amount = this->getIntegerOnInput(1); - - std::vector output = input; - - for (u32 i = 0; i < amount; i += 1) { - u8 prevByte = 0x00; - for (auto &byte : output) { - auto startValue = byte; - - byte <<= 1; - byte |= (prevByte & 0x80) >> 7; - prevByte = startValue; - } - } - - this->setBufferOnOutput(2, output); - } - }; - - class NodeBitwiseShiftRight : public dp::Node { - public: - NodeBitwiseShiftRight() : Node("hex.builtin.nodes.bitwise.shift_right.header", { - dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), - dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.amount"), - dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") - }) { } - - void process() override { - const auto &input = this->getBufferOnInput(0); - const auto &amount = this->getIntegerOnInput(1); - - std::vector output = input; - - for (u32 i = 0; i < amount; i += 1) { - u8 prevByte = 0x00; - for (auto &byte : output | std::views::reverse) { - auto startValue = byte; - byte >>= 1; - byte |= (prevByte & 0x01) << 7; - prevByte = startValue; - } - } - - this->setBufferOnOutput(2, output); - } - }; - - class NodeBitwiseADD : public dp::Node { - public: - NodeBitwiseADD() : Node("hex.builtin.nodes.bitwise.add.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &inputA = this->getBufferOnInput(0); - const auto &inputB = this->getBufferOnInput(1); - - std::vector output(std::min(inputA.size(), inputB.size()), 0x00); - - for (u32 i = 0; i < output.size(); i++) - output[i] = inputA[i] + inputB[i]; - - this->setBufferOnOutput(2, output); - } - }; - - class NodeBitwiseAND : public dp::Node { - public: - NodeBitwiseAND() : Node("hex.builtin.nodes.bitwise.and.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &inputA = this->getBufferOnInput(0); - const auto &inputB = this->getBufferOnInput(1); - - std::vector output(std::min(inputA.size(), inputB.size()), 0x00); - - for (u32 i = 0; i < output.size(); i++) - output[i] = inputA[i] & inputB[i]; - - this->setBufferOnOutput(2, output); - } - }; - - class NodeBitwiseOR : public dp::Node { - public: - NodeBitwiseOR() : Node("hex.builtin.nodes.bitwise.or.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &inputA = this->getBufferOnInput(0); - const auto &inputB = this->getBufferOnInput(1); - - std::vector output(std::min(inputA.size(), inputB.size()), 0x00); - - for (u32 i = 0; i < output.size(); i++) - output[i] = inputA[i] | inputB[i]; - - this->setBufferOnOutput(2, output); - } - }; - - class NodeBitwiseXOR : public dp::Node { - public: - NodeBitwiseXOR() : Node("hex.builtin.nodes.bitwise.xor.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &inputA = this->getBufferOnInput(0); - const auto &inputB = this->getBufferOnInput(1); - - std::vector output(std::min(inputA.size(), inputB.size()), 0x00); - - for (u32 i = 0; i < output.size(); i++) - output[i] = inputA[i] ^ inputB[i]; - - this->setBufferOnOutput(2, output); - } - }; - - class NodeReadData : public dp::Node { - public: - NodeReadData() : Node("hex.builtin.nodes.data_access.read.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.read.address"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.read.size"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.data_access.read.data") }) { } - - void process() override { - const auto &address = this->getIntegerOnInput(0); - const auto &size = this->getIntegerOnInput(1); - - std::vector data; - data.resize(size); - - ImHexApi::Provider::get()->readRaw(address, data.data(), size); - - this->setBufferOnOutput(2, data); - } - }; - - class NodeWriteData : public dp::Node { - public: - NodeWriteData() : Node("hex.builtin.nodes.data_access.write.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.write.address"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.data_access.write.data") }) { } - - void process() override { - const auto &address = this->getIntegerOnInput(0); - const auto &data = this->getBufferOnInput(1); - - if (!data.empty()) { - AchievementManager::unlockAchievement("hex.builtin.achievement.data_processor", "hex.builtin.achievement.data_processor.modify_data.name"); - } - - this->setOverlayData(address, data); - } - }; - - class NodeDataSize : public dp::Node { - public: - NodeDataSize() : Node("hex.builtin.nodes.data_access.size.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.size.size") }) { } - - void process() override { - auto size = ImHexApi::Provider::get()->getActualSize(); - - this->setIntegerOnOutput(0, size); - } - }; - - class NodeDataSelection : public dp::Node { - public: - NodeDataSelection() : Node("hex.builtin.nodes.data_access.selection.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.selection.address"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.selection.size") }) { - EventManager::subscribe(this, [this](const auto ®ion) { - this->m_address = region.address; - this->m_size = region.size; - }); - } - - ~NodeDataSelection() override { - EventManager::unsubscribe(this); - } - - void process() override { - this->setIntegerOnOutput(0, this->m_address); - this->setIntegerOnOutput(1, this->m_size); - } - - private: - u64 m_address = 0; - size_t m_size = 0; - }; - - class NodeCastIntegerToBuffer : public dp::Node { - public: - NodeCastIntegerToBuffer() : Node("hex.builtin.nodes.casting.int_to_buffer.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &input = this->getIntegerOnInput(0); - - std::vector output(sizeof(input), 0x00); - std::memcpy(output.data(), &input, sizeof(input)); - - this->setBufferOnOutput(1, output); - } - }; - - class NodeCastBufferToInteger : public dp::Node { - public: - NodeCastBufferToInteger() : Node("hex.builtin.nodes.casting.buffer_to_int.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &input = this->getBufferOnInput(0); - - i128 output = 0; - if (input.empty() || input.size() > sizeof(output)) - throwNodeError("Buffer is empty or bigger than 128 bits"); - - std::memcpy(&output, input.data(), input.size()); - - this->setIntegerOnOutput(1, output); - } - }; - - class NodeCastFloatToBuffer : public dp::Node { - public: - NodeCastFloatToBuffer() : Node("hex.builtin.nodes.casting.float_to_buffer.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Float, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &input = this->getFloatOnInput(0); - - std::vector output(sizeof(input), 0x00); - std::memcpy(output.data(), &input, sizeof(input)); - - this->setBufferOnOutput(1, output); - } - }; - - class NodeCastBufferToFloat : public dp::Node { - public: - NodeCastBufferToFloat() : Node("hex.builtin.nodes.casting.buffer_to_float.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Float, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &input = this->getBufferOnInput(0); - - double output = 0; - if (input.empty() || input.size() != sizeof(output)) - throwNodeError("Buffer is empty or not the right size to fit a float"); - - std::memcpy(&output, input.data(), input.size()); - - this->setFloatOnOutput(1, output); - } - }; - - class NodeArithmeticAdd : public dp::Node { - public: - NodeArithmeticAdd() : Node("hex.builtin.nodes.arithmetic.add.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &inputA = this->getIntegerOnInput(0); - const auto &inputB = this->getIntegerOnInput(1); - - auto output = inputA + inputB; - - this->setIntegerOnOutput(2, output); - } - }; - - class NodeArithmeticSubtract : public dp::Node { - public: - NodeArithmeticSubtract() : Node("hex.builtin.nodes.arithmetic.sub.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &inputA = this->getIntegerOnInput(0); - const auto &inputB = this->getIntegerOnInput(1); - - auto output = inputA - inputB; - - this->setIntegerOnOutput(2, output); - } - }; - - class NodeArithmeticMultiply : public dp::Node { - public: - NodeArithmeticMultiply() : Node("hex.builtin.nodes.arithmetic.mul.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &inputA = this->getIntegerOnInput(0); - const auto &inputB = this->getIntegerOnInput(1); - - auto output = inputA * inputB; - - this->setIntegerOnOutput(2, output); - } - }; - - class NodeArithmeticDivide : public dp::Node { - public: - NodeArithmeticDivide() : Node("hex.builtin.nodes.arithmetic.div.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &inputA = this->getIntegerOnInput(0); - const auto &inputB = this->getIntegerOnInput(1); - - if (inputB == 0) - throwNodeError("Division by zero"); - - auto output = inputA / inputB; - - this->setIntegerOnOutput(2, output); - } - }; - - class NodeArithmeticModulus : public dp::Node { - public: - NodeArithmeticModulus() : Node("hex.builtin.nodes.arithmetic.mod.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &inputA = this->getIntegerOnInput(0); - const auto &inputB = this->getIntegerOnInput(1); - - if (inputB == 0) - throwNodeError("Division by zero"); - - auto output = inputA % inputB; - - this->setIntegerOnOutput(2, output); - } - }; - - class NodeArithmeticAverage : public dp::Node { - public: - NodeArithmeticAverage() : Node("hex.builtin.nodes.arithmetic.average.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Float, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &input = this->getBufferOnInput(0); - - double output = std::reduce(input.begin(), input.end(), double(0)) / double(input.size()); - - this->setFloatOnOutput(1, output); - } - }; - - class NodeArithmeticMedian : public dp::Node { - public: - NodeArithmeticMedian() : Node("hex.builtin.nodes.arithmetic.median.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Float, "hex.builtin.nodes.common.output") }) { } - - void process() override { - auto input = this->getBufferOnInput(0); - - u64 medianIndex = input.size() / 2; - std::nth_element(input.begin(), input.begin() + medianIndex, input.end()); - i128 median = 0; - - if (input.size() % 2 == 0) { - std::nth_element(input.begin(), input.begin() + medianIndex - 1, input.end()); - median = (input[medianIndex] + input[medianIndex - 1]) / 2; - } else { - median = input[medianIndex]; - } - - this->setFloatOnOutput(1, median); - } - }; - - class NodeArithmeticCeil : public dp::Node { - public: - NodeArithmeticCeil() : Node("hex.builtin.nodes.arithmetic.ceil.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Float, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Float, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &input = this->getFloatOnInput(0); - - this->setFloatOnOutput(1, std::ceil(input)); - } - }; - - class NodeArithmeticFloor : public dp::Node { - public: - NodeArithmeticFloor() : Node("hex.builtin.nodes.arithmetic.floor.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Float, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Float, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &input = this->getFloatOnInput(0); - - this->setFloatOnOutput(1, std::floor(input)); - } - }; - - class NodeArithmeticRound : public dp::Node { - public: - NodeArithmeticRound() : Node("hex.builtin.nodes.arithmetic.round.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Float, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Float, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &input = this->getFloatOnInput(0); - - this->setFloatOnOutput(1, std::round(input)); - } - }; - - class NodeBufferCombine : public dp::Node { - public: - NodeBufferCombine() : Node("hex.builtin.nodes.buffer.combine.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &inputA = this->getBufferOnInput(0); - const auto &inputB = this->getBufferOnInput(1); - - auto output = inputA; - std::copy(inputB.begin(), inputB.end(), std::back_inserter(output)); - - this->setBufferOnOutput(2, output); - } - }; - - class NodeBufferSlice : public dp::Node { - public: - NodeBufferSlice() : Node("hex.builtin.nodes.buffer.slice.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.buffer.slice.input.buffer"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.buffer.slice.input.from"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.buffer.slice.input.to"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &input = this->getBufferOnInput(0); - const auto &from = this->getIntegerOnInput(1); - const auto &to = this->getIntegerOnInput(2); - - if (from < 0 || static_cast(from) >= input.size()) - throwNodeError("'from' input out of range"); - if (to < 0 || static_cast(to) >= input.size()) - throwNodeError("'to' input out of range"); - if (to <= from) - throwNodeError("'to' input needs to be greater than 'from' input"); - - this->setBufferOnOutput(3, std::vector(input.begin() + u64(from), input.begin() + u64(to))); - } - }; - - class NodeBufferRepeat : public dp::Node { - public: - NodeBufferRepeat() : Node("hex.builtin.nodes.buffer.repeat.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.buffer.repeat.input.buffer"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.buffer.repeat.input.count"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &buffer = this->getBufferOnInput(0); - const auto &count = this->getIntegerOnInput(1); - - std::vector output; - output.resize(buffer.size() * count); - - for (u32 i = 0; i < count; i++) - std::copy(buffer.begin(), buffer.end(), output.begin() + buffer.size() * i); - - this->setBufferOnOutput(2, output); - } - }; - - class NodeBufferPatch : public dp::Node { - public: - NodeBufferPatch() : Node("hex.builtin.nodes.buffer.patch.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.buffer.patch.input.patch"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.common.address"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - auto buffer = this->getBufferOnInput(0); - const auto &patch = this->getBufferOnInput(1); - const auto &address = this->getIntegerOnInput(2); - - if (address < 0 || static_cast(address) >= buffer.size()) - throwNodeError("Address out of range"); - - if (address + patch.size() > buffer.size()) - buffer.resize(address + patch.size()); - - std::copy(patch.begin(), patch.end(), buffer.begin() + address); - - this->setBufferOnOutput(3, buffer); - } - }; - - class NodeBufferSize : public dp::Node { - public: - NodeBufferSize() : Node("hex.builtin.nodes.buffer.size.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.buffer.size.output") }) { } - - void process() override { - const auto &buffer = this->getBufferOnInput(0); - - this->setIntegerOnOutput(1, buffer.size()); - } - }; - - class NodeIf : public dp::Node { - public: - NodeIf() : Node("hex.builtin.nodes.control_flow.if.header", - { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.control_flow.if.condition"), - dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.control_flow.if.true"), - dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.control_flow.if.false"), - dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &cond = this->getIntegerOnInput(0); - const auto &trueData = this->getBufferOnInput(1); - const auto &falseData = this->getBufferOnInput(2); - - if (cond != 0) - this->setBufferOnOutput(3, trueData); - else - this->setBufferOnOutput(3, falseData); - } - }; - - class NodeEquals : public dp::Node { - public: - NodeEquals() : Node("hex.builtin.nodes.control_flow.equals.header", - { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), - dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), - dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &inputA = this->getIntegerOnInput(0); - const auto &inputB = this->getIntegerOnInput(1); - - this->setIntegerOnOutput(2, inputA == inputB); - } - }; - - class NodeNot : public dp::Node { - public: - NodeNot() : Node("hex.builtin.nodes.control_flow.not.header", - { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input"), - dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &input = this->getIntegerOnInput(0); - - this->setIntegerOnOutput(1, !input); - } - }; - - class NodeGreaterThan : public dp::Node { - public: - NodeGreaterThan() : Node("hex.builtin.nodes.control_flow.gt.header", - { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), - dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), - dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &inputA = this->getIntegerOnInput(0); - const auto &inputB = this->getIntegerOnInput(1); - - this->setIntegerOnOutput(2, inputA > inputB); - } - }; - - class NodeLessThan : public dp::Node { - public: - NodeLessThan() : Node("hex.builtin.nodes.control_flow.lt.header", - { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), - dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), - dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &inputA = this->getIntegerOnInput(0); - const auto &inputB = this->getIntegerOnInput(1); - - this->setIntegerOnOutput(2, inputA < inputB); - } - }; - - class NodeBoolAND : public dp::Node { - public: - NodeBoolAND() : Node("hex.builtin.nodes.control_flow.and.header", - { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), - dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), - dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &inputA = this->getIntegerOnInput(0); - const auto &inputB = this->getIntegerOnInput(1); - - this->setIntegerOnOutput(2, inputA && inputB); - } - }; - - class NodeBoolOR : public dp::Node { - public: - NodeBoolOR() : Node("hex.builtin.nodes.control_flow.or.header", - { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), - dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), - dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &inputA = this->getIntegerOnInput(0); - const auto &inputB = this->getIntegerOnInput(1); - - this->setIntegerOnOutput(2, inputA || inputB); - } - }; - - class NodeCryptoAESDecrypt : public dp::Node { - public: - NodeCryptoAESDecrypt() : Node("hex.builtin.nodes.crypto.aes.header", - { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.crypto.aes.key"), - dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.crypto.aes.iv"), - dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.crypto.aes.nonce"), - dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), - dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void drawNode() override { - ImGui::PushItemWidth(100_scaled); - ImGui::Combo("hex.builtin.nodes.crypto.aes.mode"_lang, &this->m_mode, "ECB\0CBC\0CFB128\0CTR\0GCM\0CCM\0OFB\0"); - ImGui::Combo("hex.builtin.nodes.crypto.aes.key_length"_lang, &this->m_keyLength, "128 Bits\000192 Bits\000256 Bits\000"); - ImGui::PopItemWidth(); - } - - void process() override { - const auto &key = this->getBufferOnInput(0); - const auto &iv = this->getBufferOnInput(1); - const auto &nonce = this->getBufferOnInput(2); - const auto &input = this->getBufferOnInput(3); - - if (key.empty()) - throwNodeError("Key cannot be empty"); - - 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()); - - auto output = crypt::aesDecrypt(static_cast(this->m_mode), static_cast(this->m_keyLength), key, nonceData, ivData, input); - - this->setBufferOnOutput(4, output); - } - - void store(nlohmann::json &j) const override { - j = nlohmann::json::object(); - - j["data"] = nlohmann::json::object(); - j["data"]["mode"] = this->m_mode; - j["data"]["key_length"] = this->m_keyLength; - } - - void load(const nlohmann::json &j) override { - this->m_mode = j["data"]["mode"]; - this->m_keyLength = j["data"]["key_length"]; - } - - private: - int m_mode = 0; - int m_keyLength = 0; - }; - - class NodeDecodingBase64 : public dp::Node { - public: - NodeDecodingBase64() : Node("hex.builtin.nodes.decoding.base64.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - const auto &input = this->getBufferOnInput(0); - - auto output = crypt::decode64(input); - - this->setBufferOnOutput(1, output); - } - }; - - class NodeDecodingHex : public dp::Node { - public: - NodeDecodingHex() : Node("hex.builtin.nodes.decoding.hex.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - auto input = this->getBufferOnInput(0); - - std::erase_if(input, [](u8 c) { return std::isspace(c); }); - - 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 = static_cast(std::tolower(input[i])); - char c2 = static_cast(std::tolower(input[i + 1])); - - if (!std::isxdigit(c1) || !isxdigit(c2)) - throwNodeError("Can't decode non-hexadecimal character"); - - u8 value; - if (std::isdigit(c1)) - value = (c1 - '0') << 4; - else - value = ((c1 - 'a') + 0x0A) << 4; - - if (std::isdigit(c2)) - value |= c2 - '0'; - else - value |= (c2 - 'a') + 0x0A; - - output.push_back(value); - } - - this->setBufferOnOutput(1, output); - } - }; - - class NodeVisualizerDigram : public dp::Node { - public: - NodeVisualizerDigram() : Node("hex.builtin.nodes.visualizer.digram.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { } - - void drawNode() override { - this->m_digram.draw(scaled({ 200, 200 })); - - if (ImGui::IsItemHovered() && ImGui::IsKeyDown(ImGuiKey_LeftShift)) { - ImGui::BeginTooltip(); - this->m_digram.draw(scaled({ 600, 600 })); - ImGui::EndTooltip(); - } - } - - void process() override { - this->m_digram.process(this->getBufferOnInput(0)); - } - - private: - DiagramDigram m_digram; - }; - - class NodeVisualizerLayeredDistribution : public dp::Node { - public: - NodeVisualizerLayeredDistribution() : Node("hex.builtin.nodes.visualizer.layered_dist.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { } - - void drawNode() override { - this->m_layeredDistribution.draw(scaled({ 200, 200 })); - if (ImGui::IsItemHovered() && ImGui::IsKeyDown(ImGuiKey_LeftShift)) { - ImGui::BeginTooltip(); - this->m_layeredDistribution.draw(scaled({ 600, 600 })); - ImGui::EndTooltip(); - } - } - - void process() override { - this->m_layeredDistribution.process(this->getBufferOnInput(0)); - } - - private: - DiagramLayeredDistribution m_layeredDistribution; - }; - - class NodeVisualizerImage : public dp::Node { - public: - NodeVisualizerImage() : Node("hex.builtin.nodes.visualizer.image.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { } - - void drawNode() override { - ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.getAspectRatio() * 200, 200))); - if (ImGui::IsItemHovered() && ImGui::IsKeyDown(ImGuiKey_LeftShift)) { - ImGui::BeginTooltip(); - ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.getAspectRatio() * 600, 600))); - ImGui::EndTooltip(); - } - } - - void process() override { - const auto &rawData = this->getBufferOnInput(0); - - this->m_texture = ImGui::Texture(rawData.data(), rawData.size()); - } - - private: - ImGui::Texture m_texture; - }; - - class NodeVisualizerImageRGBA : public dp::Node { - public: - NodeVisualizerImageRGBA() : Node("hex.builtin.nodes.visualizer.image_rgba.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.width"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.height") }) { } - - void drawNode() override { - ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.getAspectRatio() * 200, 200))); - if (ImGui::IsItemHovered() && ImGui::IsKeyDown(ImGuiKey_LeftShift)) { - ImGui::BeginTooltip(); - ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.getAspectRatio() * 600, 600))); - ImGui::EndTooltip(); - } - } - - void process() override { - this->m_texture = { }; - - const auto &rawData = this->getBufferOnInput(0); - const auto &width = this->getIntegerOnInput(1); - const auto &height = this->getIntegerOnInput(2); - - const size_t requiredBytes = width * height * 4; - if (requiredBytes > rawData.size()) - throwNodeError(hex::format("Image requires at least {} bytes of data, but only {} bytes are available", requiredBytes, rawData.size())); - - this->m_texture = ImGui::Texture(rawData.data(), rawData.size(), width, height); - } - - private: - ImGui::Texture m_texture; - }; - - class NodeVisualizerByteDistribution : public dp::Node { - public: - NodeVisualizerByteDistribution() : Node("hex.builtin.nodes.visualizer.byte_distribution.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { } - - void drawNode() override { - drawPlot(scaled({ 400, 300 })); - - if (ImGui::IsItemHovered() && ImGui::IsKeyDown(ImGuiKey_LeftShift)) { - ImGui::BeginTooltip(); - drawPlot(scaled({ 700, 550 })); - ImGui::EndTooltip(); - } - } - - void drawPlot(const ImVec2 &viewSize) { - if (ImPlot::BeginPlot("##distribution", viewSize, ImPlotFlags_NoLegend | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect)) { - ImPlot::SetupAxes("Address", "Count", ImPlotAxisFlags_Lock, ImPlotAxisFlags_Lock); - ImPlot::SetupAxisScale(ImAxis_Y1, ImPlotScale_Log10); - ImPlot::SetupAxesLimits(0, 256, 1, double(*std::max_element(this->m_counts.begin(), this->m_counts.end())) * 1.1F, ImGuiCond_Always); - - static auto x = [] { - std::array result { 0 }; - std::iota(result.begin(), result.end(), 0); - return result; - }(); - - - ImPlot::PlotBars("##bytes", x.data(), this->m_counts.data(), x.size(), 1); - - ImPlot::EndPlot(); - } - } - - void process() override { - const auto &buffer = this->getBufferOnInput(0); - - this->m_counts.fill(0x00); - for (const auto &byte : buffer) { - this->m_counts[byte]++; - } - } - - private: - std::array m_counts = { 0 }; - }; - - - class NodePatternLanguageOutVariable : public dp::Node { - public: - NodePatternLanguageOutVariable() : Node("hex.builtin.nodes.pattern_language.out_var.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void drawNode() override { - ImGui::PushItemWidth(100_scaled); - ImGui::InputText("##name", this->m_name); - ImGui::PopItemWidth(); - } - - void process() override { - auto lock = std::scoped_lock(ContentRegistry::PatternLanguage::getRuntimeLock()); - auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); - - const auto &outVars = runtime.getOutVariables(); - - if (outVars.contains(this->m_name)) { - std::visit(wolv::util::overloaded { - [](const std::string &) {}, - [](pl::ptrn::Pattern *) {}, - [this](auto &&value) { - std::vector buffer(std::min(sizeof(value), 8)); - std::memcpy(buffer.data(), &value, buffer.size()); - - this->setBufferOnOutput(0, buffer); - } - }, outVars.at(this->m_name)); - } else { - throwNodeError(hex::format("Out variable '{}' has not been defined!", this->m_name)); - } - } - - void store(nlohmann::json &j) const override { - j = nlohmann::json::object(); - - j["name"] = this->m_name; - } - - void load(const nlohmann::json &j) override { - this->m_name = j["name"].get(); - } - - private: - std::string m_name; - }; - - class NodeBufferByteSwap : public dp::Node { - public: - NodeBufferByteSwap() : Node("hex.builtin.nodes.buffer.byte_swap.header", {dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - auto data = this->getBufferOnInput(0); - std::reverse(data.begin(), data.end()); - this->setBufferOnOutput(1, data); - } - - }; - - class NodeBitwiseSwap : public dp::Node { - public: - NodeBitwiseSwap() : Node("hex.builtin.nodes.bitwise.swap.header", {dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } - - void process() override { - // Table contains reversed nibble entries - static constexpr std::array BitFlipLookup = { - 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE, - 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF, }; - auto data = this->getBufferOnInput(0); - - for (u8 &b : data) - b = BitFlipLookup[b & 0xf] << 4 | BitFlipLookup[b >> 4]; - - std::reverse(data.begin(), data.end()); - this->setBufferOnOutput(1, data); - } - - }; - - class NodeDisplayBits : public dp::Node { - public: - NodeDisplayBits() : Node("hex.builtin.nodes.display.bits.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { } - - void drawNode() override { - ImGui::PushItemWidth(100_scaled); - ImGui::Text("%s", this->m_display.c_str()); - ImGui::PopItemWidth(); - } - - void process() override { - const auto &buffer = this->getBufferOnInput(0); - // Display bits in groups of 4 bits - std::string display; - display.reserve(buffer.size() * 9 + 2); // 8 bits + 1 space at beginning + 1 space every 4 bits - for (const auto &byte : buffer) { - for (size_t i = 0; i < 8; i++) { - if (i % 4 == 0) { - display += ' '; - } - display += (byte & (1 << i)) != 0 ? '1' : '0'; - } - } - this->m_display = wolv::util::trim(display); - } - - private: - std::string m_display = "???"; - }; - void registerDataProcessorNodes() { - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.int"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.float"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.nullptr"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.buffer"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.string"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.rgba8"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.comment"); - - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.display", "hex.builtin.nodes.display.int"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.display", "hex.builtin.nodes.display.float"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.display", "hex.builtin.nodes.display.buffer"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.display", "hex.builtin.nodes.display.string"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.display", "hex.builtin.nodes.display.bits"); - - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.data_access", "hex.builtin.nodes.data_access.read"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.data_access", "hex.builtin.nodes.data_access.write"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.data_access", "hex.builtin.nodes.data_access.size"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.data_access", "hex.builtin.nodes.data_access.selection"); - - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.casting", "hex.builtin.nodes.casting.int_to_buffer"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.casting", "hex.builtin.nodes.casting.buffer_to_int"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.casting", "hex.builtin.nodes.casting.float_to_buffer"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.casting", "hex.builtin.nodes.casting.buffer_to_float"); - - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.add"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.sub"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.mul"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.div"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.mod"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.average"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.median"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.ceil"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.floor"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.round"); - - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.buffer", "hex.builtin.nodes.buffer.combine"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.buffer", "hex.builtin.nodes.buffer.slice"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.buffer", "hex.builtin.nodes.buffer.repeat"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.buffer", "hex.builtin.nodes.buffer.patch"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.buffer", "hex.builtin.nodes.buffer.size"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.buffer", "hex.builtin.nodes.buffer.byte_swap"); - - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.control_flow", "hex.builtin.nodes.control_flow.if"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.control_flow", "hex.builtin.nodes.control_flow.equals"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.control_flow", "hex.builtin.nodes.control_flow.not"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.control_flow", "hex.builtin.nodes.control_flow.gt"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.control_flow", "hex.builtin.nodes.control_flow.lt"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.control_flow", "hex.builtin.nodes.control_flow.and"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.control_flow", "hex.builtin.nodes.control_flow.or"); - - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.add"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.and"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.or"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.xor"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.not"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.shift_left"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.shift_right"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.swap"); - - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.decoding", "hex.builtin.nodes.decoding.base64"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.decoding", "hex.builtin.nodes.decoding.hex"); - - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.crypto", "hex.builtin.nodes.crypto.aes"); - - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.digram"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.layered_dist"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.image"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.image_rgba"); - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.byte_distribution"); - - ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.pattern_language", "hex.builtin.nodes.pattern_language.out_var"); + registerBasicDataProcessorNodes(); + registerVisualDataProcessorNodes(); + registerLogicDataProcessorNodes(); + registerControlDataProcessorNodes(); + registerDecodeDataProcessorNodes(); + registerMathDataProcessorNodes(); + registerOtherDataProcessorNodes(); } - + } \ No newline at end of file diff --git a/plugins/builtin/source/content/dpn/basic_nodes.cpp b/plugins/builtin/source/content/dpn/basic_nodes.cpp new file mode 100644 index 000000000..075c10d03 --- /dev/null +++ b/plugins/builtin/source/content/dpn/basic_nodes.cpp @@ -0,0 +1,221 @@ +#include +#include +#include +#include +#include + +#include + +#include + +#include + +namespace hex::plugin::builtin { + + class NodeNullptr : public dp::Node { + public: + NodeNullptr() : Node("hex.builtin.nodes.constants.nullptr.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "") }) { } + + void process() override { + this->setBufferOnOutput(0, {}); + } + }; + + class NodeBuffer : public dp::Node { + public: + NodeBuffer() : Node("hex.builtin.nodes.constants.buffer.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "") }) { } + + void drawNode() override { + constexpr static int StepSize = 1, FastStepSize = 10; + + ImGui::PushItemWidth(100_scaled); + ImGui::InputScalar("hex.builtin.nodes.constants.buffer.size"_lang, ImGuiDataType_U32, &this->m_size, &StepSize, &FastStepSize); + ImGui::PopItemWidth(); + } + + void process() override { + if (this->m_buffer.size() != this->m_size) + this->m_buffer.resize(this->m_size, 0x00); + + this->setBufferOnOutput(0, this->m_buffer); + } + + void store(nlohmann::json &j) const override { + j = nlohmann::json::object(); + + j["size"] = this->m_size; + j["data"] = this->m_buffer; + } + + void load(const nlohmann::json &j) override { + this->m_size = j.at("size"); + this->m_buffer = j.at("data").get>(); + } + + private: + u32 m_size = 1; + std::vector m_buffer; + }; + + class NodeString : public dp::Node { + public: + NodeString() : Node("hex.builtin.nodes.constants.string.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "") }) { + + } + + void drawNode() override { + ImGui::InputTextMultiline("##string", this->m_value, ImVec2(150_scaled, 0), ImGuiInputTextFlags_AllowTabInput); + } + + void process() override { + this->setBufferOnOutput(0, hex::decodeByteString(this->m_value)); + } + + void store(nlohmann::json &j) const override { + j = nlohmann::json::object(); + + j["data"] = this->m_value; + } + + void load(const nlohmann::json &j) override { + this->m_value = j.at("data").get(); + } + + private: + std::string m_value; + }; + + class NodeInteger : public dp::Node { + public: + NodeInteger() : Node("hex.builtin.nodes.constants.int.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "") }) { } + + void drawNode() override { + ImGui::PushItemWidth(100_scaled); + ImGui::InputHexadecimal("##integer_value", &this->m_value); + ImGui::PopItemWidth(); + } + + void process() override { + this->setIntegerOnOutput(0, this->m_value); + } + + void store(nlohmann::json &j) const override { + j = nlohmann::json::object(); + + j["data"] = this->m_value; + } + + void load(const nlohmann::json &j) override { + this->m_value = j.at("data"); + } + + private: + u64 m_value = 0; + }; + + class NodeFloat : public dp::Node { + public: + NodeFloat() : Node("hex.builtin.nodes.constants.float.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Float, "") }) { } + + void drawNode() override { + ImGui::PushItemWidth(100_scaled); + ImGui::InputScalar("##floatValue", ImGuiDataType_Float, &this->m_value, nullptr, nullptr, "%f", ImGuiInputTextFlags_CharsDecimal); + ImGui::PopItemWidth(); + } + + void process() override { + this->setFloatOnOutput(0, this->m_value); + } + + void store(nlohmann::json &j) const override { + j = nlohmann::json::object(); + + j["data"] = this->m_value; + } + + void load(const nlohmann::json &j) override { + this->m_value = j.at("data"); + } + + private: + float m_value = 0; + }; + + class NodeRGBA8 : public dp::Node { + public: + NodeRGBA8() : Node("hex.builtin.nodes.constants.rgba8.header", + { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.constants.rgba8.output.r"), + dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.constants.rgba8.output.g"), + dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.constants.rgba8.output.b"), + dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.constants.rgba8.output.a") }) { } + + void drawNode() override { + ImGui::PushItemWidth(200_scaled); + ImGui::ColorPicker4("##colorPicker", &this->m_color.Value.x, ImGuiColorEditFlags_AlphaBar); + ImGui::PopItemWidth(); + } + + void process() override { + this->setBufferOnOutput(0, wolv::util::toBytes(u8(this->m_color.Value.x * 0xFF))); + this->setBufferOnOutput(1, wolv::util::toBytes(u8(this->m_color.Value.y * 0xFF))); + this->setBufferOnOutput(2, wolv::util::toBytes(u8(this->m_color.Value.z * 0xFF))); + this->setBufferOnOutput(3, wolv::util::toBytes(u8(this->m_color.Value.w * 0xFF))); + } + + void store(nlohmann::json &j) const override { + j = nlohmann::json::object(); + + j["data"] = nlohmann::json::object(); + j["data"]["r"] = this->m_color.Value.x; + j["data"]["g"] = this->m_color.Value.y; + j["data"]["b"] = this->m_color.Value.z; + j["data"]["a"] = this->m_color.Value.w; + } + + void load(const nlohmann::json &j) override { + const auto &color = j.at("data"); + this->m_color = ImVec4(color.at("r"), color.at("g"), color.at("b"), color.at("a")); + } + + private: + ImColor m_color; + }; + + class NodeComment : public dp::Node { + public: + NodeComment() : Node("hex.builtin.nodes.constants.comment.header", {}) { + + } + + void drawNode() override { + ImGui::InputTextMultiline("##string", this->m_comment, scaled(ImVec2(150, 100))); + } + + void process() override { + } + + void store(nlohmann::json &j) const override { + j = nlohmann::json::object(); + + j["comment"] = this->m_comment; + } + + void load(const nlohmann::json &j) override { + this->m_comment = j["comment"].get(); + } + + private: + std::string m_comment; + }; + + void registerBasicDataProcessorNodes() { + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.int"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.float"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.nullptr"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.buffer"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.string"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.rgba8"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.constants", "hex.builtin.nodes.constants.comment"); + } + +} diff --git a/plugins/builtin/source/content/dpn/control_nodes.cpp b/plugins/builtin/source/content/dpn/control_nodes.cpp new file mode 100644 index 000000000..43546f5ff --- /dev/null +++ b/plugins/builtin/source/content/dpn/control_nodes.cpp @@ -0,0 +1,124 @@ +#include +#include + +namespace hex::plugin::builtin { + + class NodeIf : public dp::Node { + public: + NodeIf() : Node("hex.builtin.nodes.control_flow.if.header", + { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.control_flow.if.condition"), + dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.control_flow.if.true"), + dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.control_flow.if.false"), + dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &cond = this->getIntegerOnInput(0); + const auto &trueData = this->getBufferOnInput(1); + const auto &falseData = this->getBufferOnInput(2); + + if (cond != 0) + this->setBufferOnOutput(3, trueData); + else + this->setBufferOnOutput(3, falseData); + } + }; + + class NodeEquals : public dp::Node { + public: + NodeEquals() : Node("hex.builtin.nodes.control_flow.equals.header", + { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), + dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), + dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &inputA = this->getIntegerOnInput(0); + const auto &inputB = this->getIntegerOnInput(1); + + this->setIntegerOnOutput(2, inputA == inputB); + } + }; + + class NodeNot : public dp::Node { + public: + NodeNot() : Node("hex.builtin.nodes.control_flow.not.header", + { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input"), + dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &input = this->getIntegerOnInput(0); + + this->setIntegerOnOutput(1, !input); + } + }; + + class NodeGreaterThan : public dp::Node { + public: + NodeGreaterThan() : Node("hex.builtin.nodes.control_flow.gt.header", + { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), + dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), + dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &inputA = this->getIntegerOnInput(0); + const auto &inputB = this->getIntegerOnInput(1); + + this->setIntegerOnOutput(2, inputA > inputB); + } + }; + + class NodeLessThan : public dp::Node { + public: + NodeLessThan() : Node("hex.builtin.nodes.control_flow.lt.header", + { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), + dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), + dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &inputA = this->getIntegerOnInput(0); + const auto &inputB = this->getIntegerOnInput(1); + + this->setIntegerOnOutput(2, inputA < inputB); + } + }; + + class NodeBoolAND : public dp::Node { + public: + NodeBoolAND() : Node("hex.builtin.nodes.control_flow.and.header", + { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), + dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), + dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &inputA = this->getIntegerOnInput(0); + const auto &inputB = this->getIntegerOnInput(1); + + this->setIntegerOnOutput(2, inputA && inputB); + } + }; + + class NodeBoolOR : public dp::Node { + public: + NodeBoolOR() : Node("hex.builtin.nodes.control_flow.or.header", + { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), + dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), + dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &inputA = this->getIntegerOnInput(0); + const auto &inputB = this->getIntegerOnInput(1); + + this->setIntegerOnOutput(2, inputA || inputB); + } + }; + + void registerControlDataProcessorNodes() { + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.control_flow", "hex.builtin.nodes.control_flow.if"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.control_flow", "hex.builtin.nodes.control_flow.equals"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.control_flow", "hex.builtin.nodes.control_flow.not"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.control_flow", "hex.builtin.nodes.control_flow.gt"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.control_flow", "hex.builtin.nodes.control_flow.lt"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.control_flow", "hex.builtin.nodes.control_flow.and"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.control_flow", "hex.builtin.nodes.control_flow.or"); + } + +} diff --git a/plugins/builtin/source/content/dpn/decode_nodes.cpp b/plugins/builtin/source/content/dpn/decode_nodes.cpp new file mode 100644 index 000000000..71862a0ac --- /dev/null +++ b/plugins/builtin/source/content/dpn/decode_nodes.cpp @@ -0,0 +1,124 @@ +#include +#include +#include +#include +#include + +#include + +namespace hex::plugin::builtin { + + class NodeCryptoAESDecrypt : public dp::Node { + public: + NodeCryptoAESDecrypt() : Node("hex.builtin.nodes.crypto.aes.header", + { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.crypto.aes.key"), + dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.crypto.aes.iv"), + dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.crypto.aes.nonce"), + dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), + dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void drawNode() override { + ImGui::PushItemWidth(100_scaled); + ImGui::Combo("hex.builtin.nodes.crypto.aes.mode"_lang, &this->m_mode, "ECB\0CBC\0CFB128\0CTR\0GCM\0CCM\0OFB\0"); + ImGui::Combo("hex.builtin.nodes.crypto.aes.key_length"_lang, &this->m_keyLength, "128 Bits\000192 Bits\000256 Bits\000"); + ImGui::PopItemWidth(); + } + + void process() override { + const auto &key = this->getBufferOnInput(0); + const auto &iv = this->getBufferOnInput(1); + const auto &nonce = this->getBufferOnInput(2); + const auto &input = this->getBufferOnInput(3); + + if (key.empty()) + throwNodeError("Key cannot be empty"); + + 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()); + + auto output = crypt::aesDecrypt(static_cast(this->m_mode), static_cast(this->m_keyLength), key, nonceData, ivData, input); + + this->setBufferOnOutput(4, output); + } + + void store(nlohmann::json &j) const override { + j = nlohmann::json::object(); + + j["data"] = nlohmann::json::object(); + j["data"]["mode"] = this->m_mode; + j["data"]["key_length"] = this->m_keyLength; + } + + void load(const nlohmann::json &j) override { + this->m_mode = j["data"]["mode"]; + this->m_keyLength = j["data"]["key_length"]; + } + + private: + int m_mode = 0; + int m_keyLength = 0; + }; + + class NodeDecodingBase64 : public dp::Node { + public: + NodeDecodingBase64() : Node("hex.builtin.nodes.decoding.base64.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &input = this->getBufferOnInput(0); + + auto output = crypt::decode64(input); + + this->setBufferOnOutput(1, output); + } + }; + + class NodeDecodingHex : public dp::Node { + public: + NodeDecodingHex() : Node("hex.builtin.nodes.decoding.hex.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + auto input = this->getBufferOnInput(0); + + std::erase_if(input, [](u8 c) { return std::isspace(c); }); + + 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 = static_cast(std::tolower(input[i])); + char c2 = static_cast(std::tolower(input[i + 1])); + + if (!std::isxdigit(c1) || !isxdigit(c2)) + throwNodeError("Can't decode non-hexadecimal character"); + + u8 value; + if (std::isdigit(c1)) + value = (c1 - '0') << 4; + else + value = ((c1 - 'a') + 0x0A) << 4; + + if (std::isdigit(c2)) + value |= c2 - '0'; + else + value |= (c2 - 'a') + 0x0A; + + output.push_back(value); + } + + this->setBufferOnOutput(1, output); + } + }; + + void registerDecodeDataProcessorNodes() { + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.decoding", "hex.builtin.nodes.decoding.base64"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.decoding", "hex.builtin.nodes.decoding.hex"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.crypto", "hex.builtin.nodes.crypto.aes"); + } + +} diff --git a/plugins/builtin/source/content/dpn/logic_nodes.cpp b/plugins/builtin/source/content/dpn/logic_nodes.cpp new file mode 100644 index 000000000..f6c49b5c3 --- /dev/null +++ b/plugins/builtin/source/content/dpn/logic_nodes.cpp @@ -0,0 +1,180 @@ +#include +#include +#include + +#include + +namespace hex::plugin::builtin { + + class NodeBitwiseNOT : public dp::Node { + public: + NodeBitwiseNOT() : Node("hex.builtin.nodes.bitwise.not.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &input = this->getBufferOnInput(0); + + std::vector output = input; + for (auto &byte : output) + byte = ~byte; + + this->setBufferOnOutput(1, output); + } + }; + + class NodeBitwiseShiftLeft : public dp::Node { + public: + NodeBitwiseShiftLeft() : Node("hex.builtin.nodes.bitwise.shift_left.header", { + dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), + dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.amount"), + dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") + }) { } + + void process() override { + const auto &input = this->getBufferOnInput(0); + const auto &amount = this->getIntegerOnInput(1); + + std::vector output = input; + + for (u32 i = 0; i < amount; i += 1) { + u8 prevByte = 0x00; + for (auto &byte : output) { + auto startValue = byte; + + byte <<= 1; + byte |= (prevByte & 0x80) >> 7; + prevByte = startValue; + } + } + + this->setBufferOnOutput(2, output); + } + }; + + class NodeBitwiseShiftRight : public dp::Node { + public: + NodeBitwiseShiftRight() : Node("hex.builtin.nodes.bitwise.shift_right.header", { + dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), + dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.amount"), + dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") + }) { } + + void process() override { + const auto &input = this->getBufferOnInput(0); + const auto &amount = this->getIntegerOnInput(1); + + std::vector output = input; + + for (u32 i = 0; i < amount; i += 1) { + u8 prevByte = 0x00; + for (auto &byte : output | std::views::reverse) { + auto startValue = byte; + byte >>= 1; + byte |= (prevByte & 0x01) << 7; + prevByte = startValue; + } + } + + this->setBufferOnOutput(2, output); + } + }; + + class NodeBitwiseADD : public dp::Node { + public: + NodeBitwiseADD() : Node("hex.builtin.nodes.bitwise.add.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &inputA = this->getBufferOnInput(0); + const auto &inputB = this->getBufferOnInput(1); + + std::vector output(std::min(inputA.size(), inputB.size()), 0x00); + + for (u32 i = 0; i < output.size(); i++) + output[i] = inputA[i] + inputB[i]; + + this->setBufferOnOutput(2, output); + } + }; + + class NodeBitwiseAND : public dp::Node { + public: + NodeBitwiseAND() : Node("hex.builtin.nodes.bitwise.and.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &inputA = this->getBufferOnInput(0); + const auto &inputB = this->getBufferOnInput(1); + + std::vector output(std::min(inputA.size(), inputB.size()), 0x00); + + for (u32 i = 0; i < output.size(); i++) + output[i] = inputA[i] & inputB[i]; + + this->setBufferOnOutput(2, output); + } + }; + + class NodeBitwiseOR : public dp::Node { + public: + NodeBitwiseOR() : Node("hex.builtin.nodes.bitwise.or.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &inputA = this->getBufferOnInput(0); + const auto &inputB = this->getBufferOnInput(1); + + std::vector output(std::min(inputA.size(), inputB.size()), 0x00); + + for (u32 i = 0; i < output.size(); i++) + output[i] = inputA[i] | inputB[i]; + + this->setBufferOnOutput(2, output); + } + }; + + class NodeBitwiseXOR : public dp::Node { + public: + NodeBitwiseXOR() : Node("hex.builtin.nodes.bitwise.xor.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &inputA = this->getBufferOnInput(0); + const auto &inputB = this->getBufferOnInput(1); + + std::vector output(std::min(inputA.size(), inputB.size()), 0x00); + + for (u32 i = 0; i < output.size(); i++) + output[i] = inputA[i] ^ inputB[i]; + + this->setBufferOnOutput(2, output); + } + }; + + class NodeBitwiseSwap : public dp::Node { + public: + NodeBitwiseSwap() : Node("hex.builtin.nodes.bitwise.swap.header", {dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + // Table contains reversed nibble entries + static constexpr std::array BitFlipLookup = { + 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE, + 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF, }; + auto data = this->getBufferOnInput(0); + + for (u8 &b : data) + b = BitFlipLookup[b & 0xf] << 4 | BitFlipLookup[b >> 4]; + + std::reverse(data.begin(), data.end()); + this->setBufferOnOutput(1, data); + } + + }; + + void registerLogicDataProcessorNodes() { + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.add"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.and"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.or"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.xor"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.not"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.shift_left"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.shift_right"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.bitwise", "hex.builtin.nodes.bitwise.swap"); + } + +} \ No newline at end of file diff --git a/plugins/builtin/source/content/dpn/math_nodes.cpp b/plugins/builtin/source/content/dpn/math_nodes.cpp new file mode 100644 index 000000000..7e5b41116 --- /dev/null +++ b/plugins/builtin/source/content/dpn/math_nodes.cpp @@ -0,0 +1,167 @@ +#include +#include + +#include +#include +#include + +namespace hex::plugin::builtin { + + class NodeArithmeticAdd : public dp::Node { + public: + NodeArithmeticAdd() : Node("hex.builtin.nodes.arithmetic.add.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &inputA = this->getIntegerOnInput(0); + const auto &inputB = this->getIntegerOnInput(1); + + auto output = inputA + inputB; + + this->setIntegerOnOutput(2, output); + } + }; + + class NodeArithmeticSubtract : public dp::Node { + public: + NodeArithmeticSubtract() : Node("hex.builtin.nodes.arithmetic.sub.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &inputA = this->getIntegerOnInput(0); + const auto &inputB = this->getIntegerOnInput(1); + + auto output = inputA - inputB; + + this->setIntegerOnOutput(2, output); + } + }; + + class NodeArithmeticMultiply : public dp::Node { + public: + NodeArithmeticMultiply() : Node("hex.builtin.nodes.arithmetic.mul.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &inputA = this->getIntegerOnInput(0); + const auto &inputB = this->getIntegerOnInput(1); + + auto output = inputA * inputB; + + this->setIntegerOnOutput(2, output); + } + }; + + class NodeArithmeticDivide : public dp::Node { + public: + NodeArithmeticDivide() : Node("hex.builtin.nodes.arithmetic.div.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &inputA = this->getIntegerOnInput(0); + const auto &inputB = this->getIntegerOnInput(1); + + if (inputB == 0) + throwNodeError("Division by zero"); + + auto output = inputA / inputB; + + this->setIntegerOnOutput(2, output); + } + }; + + class NodeArithmeticModulus : public dp::Node { + public: + NodeArithmeticModulus() : Node("hex.builtin.nodes.arithmetic.mod.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &inputA = this->getIntegerOnInput(0); + const auto &inputB = this->getIntegerOnInput(1); + + if (inputB == 0) + throwNodeError("Division by zero"); + + auto output = inputA % inputB; + + this->setIntegerOnOutput(2, output); + } + }; + + class NodeArithmeticAverage : public dp::Node { + public: + NodeArithmeticAverage() : Node("hex.builtin.nodes.arithmetic.average.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Float, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &input = this->getBufferOnInput(0); + + double output = std::reduce(input.begin(), input.end(), double(0)) / double(input.size()); + + this->setFloatOnOutput(1, output); + } + }; + + class NodeArithmeticMedian : public dp::Node { + public: + NodeArithmeticMedian() : Node("hex.builtin.nodes.arithmetic.median.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Float, "hex.builtin.nodes.common.output") }) { } + + void process() override { + auto input = this->getBufferOnInput(0); + + u64 medianIndex = input.size() / 2; + std::nth_element(input.begin(), input.begin() + medianIndex, input.end()); + i128 median = 0; + + if (input.size() % 2 == 0) { + std::nth_element(input.begin(), input.begin() + medianIndex - 1, input.end()); + median = (input[medianIndex] + input[medianIndex - 1]) / 2; + } else { + median = input[medianIndex]; + } + + this->setFloatOnOutput(1, median); + } + }; + + class NodeArithmeticCeil : public dp::Node { + public: + NodeArithmeticCeil() : Node("hex.builtin.nodes.arithmetic.ceil.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Float, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Float, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &input = this->getFloatOnInput(0); + + this->setFloatOnOutput(1, std::ceil(input)); + } + }; + + class NodeArithmeticFloor : public dp::Node { + public: + NodeArithmeticFloor() : Node("hex.builtin.nodes.arithmetic.floor.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Float, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Float, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &input = this->getFloatOnInput(0); + + this->setFloatOnOutput(1, std::floor(input)); + } + }; + + class NodeArithmeticRound : public dp::Node { + public: + NodeArithmeticRound() : Node("hex.builtin.nodes.arithmetic.round.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Float, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Float, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &input = this->getFloatOnInput(0); + + this->setFloatOnOutput(1, std::round(input)); + } + }; + + void registerMathDataProcessorNodes() { + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.add"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.sub"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.mul"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.div"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.mod"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.average"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.median"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.ceil"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.floor"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.arithmetic", "hex.builtin.nodes.arithmetic.round"); + } + +} \ No newline at end of file diff --git a/plugins/builtin/source/content/dpn/other_nodes.cpp b/plugins/builtin/source/content/dpn/other_nodes.cpp new file mode 100644 index 000000000..c413c779c --- /dev/null +++ b/plugins/builtin/source/content/dpn/other_nodes.cpp @@ -0,0 +1,457 @@ +#include +#include +#include +#include +#include +#include + +#include + +#include + +namespace hex::plugin::builtin { + + class NodeReadData : public dp::Node { + public: + NodeReadData() : Node("hex.builtin.nodes.data_access.read.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.read.address"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.read.size"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.data_access.read.data") }) { } + + void process() override { + const auto &address = this->getIntegerOnInput(0); + const auto &size = this->getIntegerOnInput(1); + + std::vector data; + data.resize(size); + + ImHexApi::Provider::get()->readRaw(address, data.data(), size); + + this->setBufferOnOutput(2, data); + } + }; + + class NodeWriteData : public dp::Node { + public: + NodeWriteData() : Node("hex.builtin.nodes.data_access.write.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.write.address"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.data_access.write.data") }) { } + + void process() override { + const auto &address = this->getIntegerOnInput(0); + const auto &data = this->getBufferOnInput(1); + + if (!data.empty()) { + AchievementManager::unlockAchievement("hex.builtin.achievement.data_processor", "hex.builtin.achievement.data_processor.modify_data.name"); + } + + this->setOverlayData(address, data); + } + }; + + class NodeDataSize : public dp::Node { + public: + NodeDataSize() : Node("hex.builtin.nodes.data_access.size.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.size.size") }) { } + + void process() override { + auto size = ImHexApi::Provider::get()->getActualSize(); + + this->setIntegerOnOutput(0, size); + } + }; + + class NodeDataSelection : public dp::Node { + public: + NodeDataSelection() : Node("hex.builtin.nodes.data_access.selection.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.selection.address"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.data_access.selection.size") }) { + EventManager::subscribe(this, [this](const auto ®ion) { + this->m_address = region.address; + this->m_size = region.size; + }); + } + + ~NodeDataSelection() override { + EventManager::unsubscribe(this); + } + + void process() override { + this->setIntegerOnOutput(0, this->m_address); + this->setIntegerOnOutput(1, this->m_size); + } + + private: + u64 m_address = 0; + size_t m_size = 0; + }; + + class NodeCastIntegerToBuffer : public dp::Node { + public: + NodeCastIntegerToBuffer() : Node("hex.builtin.nodes.casting.int_to_buffer.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &input = this->getIntegerOnInput(0); + + std::vector output(sizeof(input), 0x00); + std::memcpy(output.data(), &input, sizeof(input)); + + this->setBufferOnOutput(1, output); + } + }; + + class NodeCastBufferToInteger : public dp::Node { + public: + NodeCastBufferToInteger() : Node("hex.builtin.nodes.casting.buffer_to_int.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &input = this->getBufferOnInput(0); + + i128 output = 0; + if (input.empty() || input.size() > sizeof(output)) + throwNodeError("Buffer is empty or bigger than 128 bits"); + + std::memcpy(&output, input.data(), input.size()); + + this->setIntegerOnOutput(1, output); + } + }; + + class NodeCastFloatToBuffer : public dp::Node { + public: + NodeCastFloatToBuffer() : Node("hex.builtin.nodes.casting.float_to_buffer.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Float, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &input = this->getFloatOnInput(0); + + std::vector output(sizeof(input), 0x00); + std::memcpy(output.data(), &input, sizeof(input)); + + this->setBufferOnOutput(1, output); + } + }; + + class NodeCastBufferToFloat : public dp::Node { + public: + NodeCastBufferToFloat() : Node("hex.builtin.nodes.casting.buffer_to_float.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Float, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &input = this->getBufferOnInput(0); + + double output = 0; + if (input.empty() || input.size() != sizeof(output)) + throwNodeError("Buffer is empty or not the right size to fit a float"); + + std::memcpy(&output, input.data(), input.size()); + + this->setFloatOnOutput(1, output); + } + }; + + class NodeBufferCombine : public dp::Node { + public: + NodeBufferCombine() : Node("hex.builtin.nodes.buffer.combine.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.a"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input.b"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &inputA = this->getBufferOnInput(0); + const auto &inputB = this->getBufferOnInput(1); + + auto output = inputA; + std::copy(inputB.begin(), inputB.end(), std::back_inserter(output)); + + this->setBufferOnOutput(2, output); + } + }; + + class NodeBufferSlice : public dp::Node { + public: + NodeBufferSlice() : Node("hex.builtin.nodes.buffer.slice.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.buffer.slice.input.buffer"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.buffer.slice.input.from"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.buffer.slice.input.to"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &input = this->getBufferOnInput(0); + const auto &from = this->getIntegerOnInput(1); + const auto &to = this->getIntegerOnInput(2); + + if (from < 0 || static_cast(from) >= input.size()) + throwNodeError("'from' input out of range"); + if (to < 0 || static_cast(to) >= input.size()) + throwNodeError("'to' input out of range"); + if (to <= from) + throwNodeError("'to' input needs to be greater than 'from' input"); + + this->setBufferOnOutput(3, std::vector(input.begin() + u64(from), input.begin() + u64(to))); + } + }; + + class NodeBufferRepeat : public dp::Node { + public: + NodeBufferRepeat() : Node("hex.builtin.nodes.buffer.repeat.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.buffer.repeat.input.buffer"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.buffer.repeat.input.count"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + const auto &buffer = this->getBufferOnInput(0); + const auto &count = this->getIntegerOnInput(1); + + std::vector output; + output.resize(buffer.size() * count); + + for (u32 i = 0; i < count; i++) + std::copy(buffer.begin(), buffer.end(), output.begin() + buffer.size() * i); + + this->setBufferOnOutput(2, output); + } + }; + + class NodeBufferPatch : public dp::Node { + public: + NodeBufferPatch() : Node("hex.builtin.nodes.buffer.patch.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.buffer.patch.input.patch"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.common.address"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + auto buffer = this->getBufferOnInput(0); + const auto &patch = this->getBufferOnInput(1); + const auto &address = this->getIntegerOnInput(2); + + if (address < 0 || static_cast(address) >= buffer.size()) + throwNodeError("Address out of range"); + + if (address + patch.size() > buffer.size()) + buffer.resize(address + patch.size()); + + std::copy(patch.begin(), patch.end(), buffer.begin() + address); + + this->setBufferOnOutput(3, buffer); + } + }; + + class NodeBufferSize : public dp::Node { + public: + NodeBufferSize() : Node("hex.builtin.nodes.buffer.size.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Integer, "hex.builtin.nodes.buffer.size.output") }) { } + + void process() override { + const auto &buffer = this->getBufferOnInput(0); + + this->setIntegerOnOutput(1, buffer.size()); + } + }; + + class NodeVisualizerDigram : public dp::Node { + public: + NodeVisualizerDigram() : Node("hex.builtin.nodes.visualizer.digram.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { } + + void drawNode() override { + this->m_digram.draw(scaled({ 200, 200 })); + + if (ImGui::IsItemHovered() && ImGui::IsKeyDown(ImGuiKey_LeftShift)) { + ImGui::BeginTooltip(); + this->m_digram.draw(scaled({ 600, 600 })); + ImGui::EndTooltip(); + } + } + + void process() override { + this->m_digram.process(this->getBufferOnInput(0)); + } + + private: + DiagramDigram m_digram; + }; + + class NodeVisualizerLayeredDistribution : public dp::Node { + public: + NodeVisualizerLayeredDistribution() : Node("hex.builtin.nodes.visualizer.layered_dist.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { } + + void drawNode() override { + this->m_layeredDistribution.draw(scaled({ 200, 200 })); + if (ImGui::IsItemHovered() && ImGui::IsKeyDown(ImGuiKey_LeftShift)) { + ImGui::BeginTooltip(); + this->m_layeredDistribution.draw(scaled({ 600, 600 })); + ImGui::EndTooltip(); + } + } + + void process() override { + this->m_layeredDistribution.process(this->getBufferOnInput(0)); + } + + private: + DiagramLayeredDistribution m_layeredDistribution; + }; + + class NodeVisualizerImage : public dp::Node { + public: + NodeVisualizerImage() : Node("hex.builtin.nodes.visualizer.image.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { } + + void drawNode() override { + ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.getAspectRatio() * 200, 200))); + if (ImGui::IsItemHovered() && ImGui::IsKeyDown(ImGuiKey_LeftShift)) { + ImGui::BeginTooltip(); + ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.getAspectRatio() * 600, 600))); + ImGui::EndTooltip(); + } + } + + void process() override { + const auto &rawData = this->getBufferOnInput(0); + + this->m_texture = ImGui::Texture(rawData.data(), rawData.size()); + } + + private: + ImGui::Texture m_texture; + }; + + class NodeVisualizerImageRGBA : public dp::Node { + public: + NodeVisualizerImageRGBA() : Node("hex.builtin.nodes.visualizer.image_rgba.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.width"), dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.height") }) { } + + void drawNode() override { + ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.getAspectRatio() * 200, 200))); + if (ImGui::IsItemHovered() && ImGui::IsKeyDown(ImGuiKey_LeftShift)) { + ImGui::BeginTooltip(); + ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.getAspectRatio() * 600, 600))); + ImGui::EndTooltip(); + } + } + + void process() override { + this->m_texture = { }; + + const auto &rawData = this->getBufferOnInput(0); + const auto &width = this->getIntegerOnInput(1); + const auto &height = this->getIntegerOnInput(2); + + const size_t requiredBytes = width * height * 4; + if (requiredBytes > rawData.size()) + throwNodeError(hex::format("Image requires at least {} bytes of data, but only {} bytes are available", requiredBytes, rawData.size())); + + this->m_texture = ImGui::Texture(rawData.data(), rawData.size(), width, height); + } + + private: + ImGui::Texture m_texture; + }; + + class NodeVisualizerByteDistribution : public dp::Node { + public: + NodeVisualizerByteDistribution() : Node("hex.builtin.nodes.visualizer.byte_distribution.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { } + + void drawNode() override { + drawPlot(scaled({ 400, 300 })); + + if (ImGui::IsItemHovered() && ImGui::IsKeyDown(ImGuiKey_LeftShift)) { + ImGui::BeginTooltip(); + drawPlot(scaled({ 700, 550 })); + ImGui::EndTooltip(); + } + } + + void drawPlot(const ImVec2 &viewSize) { + if (ImPlot::BeginPlot("##distribution", viewSize, ImPlotFlags_NoLegend | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect)) { + ImPlot::SetupAxes("Address", "Count", ImPlotAxisFlags_Lock, ImPlotAxisFlags_Lock); + ImPlot::SetupAxisScale(ImAxis_Y1, ImPlotScale_Log10); + ImPlot::SetupAxesLimits(0, 256, 1, double(*std::max_element(this->m_counts.begin(), this->m_counts.end())) * 1.1F, ImGuiCond_Always); + + static auto x = [] { + std::array result { 0 }; + std::iota(result.begin(), result.end(), 0); + return result; + }(); + + + ImPlot::PlotBars("##bytes", x.data(), this->m_counts.data(), x.size(), 1); + + ImPlot::EndPlot(); + } + } + + void process() override { + const auto &buffer = this->getBufferOnInput(0); + + this->m_counts.fill(0x00); + for (const auto &byte : buffer) { + this->m_counts[byte]++; + } + } + + private: + std::array m_counts = { 0 }; + }; + + + class NodePatternLanguageOutVariable : public dp::Node { + public: + NodePatternLanguageOutVariable() : Node("hex.builtin.nodes.pattern_language.out_var.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void drawNode() override { + ImGui::PushItemWidth(100_scaled); + ImGui::InputText("##name", this->m_name); + ImGui::PopItemWidth(); + } + + void process() override { + auto lock = std::scoped_lock(ContentRegistry::PatternLanguage::getRuntimeLock()); + auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); + + const auto &outVars = runtime.getOutVariables(); + + if (outVars.contains(this->m_name)) { + std::visit(wolv::util::overloaded { + [](const std::string &) {}, + [](pl::ptrn::Pattern *) {}, + [this](auto &&value) { + std::vector buffer(std::min(sizeof(value), 8)); + std::memcpy(buffer.data(), &value, buffer.size()); + + this->setBufferOnOutput(0, buffer); + } + }, outVars.at(this->m_name)); + } else { + throwNodeError(hex::format("Out variable '{}' has not been defined!", this->m_name)); + } + } + + void store(nlohmann::json &j) const override { + j = nlohmann::json::object(); + + j["name"] = this->m_name; + } + + void load(const nlohmann::json &j) override { + this->m_name = j["name"].get(); + } + + private: + std::string m_name; + }; + + class NodeBufferByteSwap : public dp::Node { + public: + NodeBufferByteSwap() : Node("hex.builtin.nodes.buffer.byte_swap.header", {dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input"), dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.output") }) { } + + void process() override { + auto data = this->getBufferOnInput(0); + std::reverse(data.begin(), data.end()); + this->setBufferOnOutput(1, data); + } + + }; + + void registerOtherDataProcessorNodes() { + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.data_access", "hex.builtin.nodes.data_access.read"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.data_access", "hex.builtin.nodes.data_access.write"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.data_access", "hex.builtin.nodes.data_access.size"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.data_access", "hex.builtin.nodes.data_access.selection"); + + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.casting", "hex.builtin.nodes.casting.int_to_buffer"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.casting", "hex.builtin.nodes.casting.buffer_to_int"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.casting", "hex.builtin.nodes.casting.float_to_buffer"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.casting", "hex.builtin.nodes.casting.buffer_to_float"); + + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.buffer", "hex.builtin.nodes.buffer.combine"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.buffer", "hex.builtin.nodes.buffer.slice"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.buffer", "hex.builtin.nodes.buffer.repeat"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.buffer", "hex.builtin.nodes.buffer.patch"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.buffer", "hex.builtin.nodes.buffer.size"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.buffer", "hex.builtin.nodes.buffer.byte_swap"); + + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.digram"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.layered_dist"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.image"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.image_rgba"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.visualizer", "hex.builtin.nodes.visualizer.byte_distribution"); + + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.pattern_language", "hex.builtin.nodes.pattern_language.out_var"); + } + +} diff --git a/plugins/builtin/source/content/dpn/visual_nodes.cpp b/plugins/builtin/source/content/dpn/visual_nodes.cpp new file mode 100644 index 000000000..387fbc51d --- /dev/null +++ b/plugins/builtin/source/content/dpn/visual_nodes.cpp @@ -0,0 +1,184 @@ +#include +#include +#include +#include +#include + +namespace hex::plugin::builtin { + + class NodeDisplayInteger : public dp::Node { + public: + NodeDisplayInteger() : Node("hex.builtin.nodes.display.int.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Integer, "hex.builtin.nodes.common.input") }) { } + + void drawNode() override { + ImGui::PushItemWidth(150_scaled); + if (this->m_value.has_value()) + ImGui::TextFormatted("0x{0:X}", this->m_value.value()); + else + ImGui::TextUnformatted("???"); + ImGui::PopItemWidth(); + } + + void process() override { + this->m_value.reset(); + const auto &input = this->getIntegerOnInput(0); + + this->m_value = input; + } + + private: + std::optional m_value; + }; + + class NodeDisplayFloat : public dp::Node { + public: + NodeDisplayFloat() : Node("hex.builtin.nodes.display.float.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Float, "hex.builtin.nodes.common.input") }) { } + + void drawNode() override { + ImGui::PushItemWidth(150_scaled); + if (this->m_value.has_value()) + ImGui::TextFormatted("{0}", this->m_value.value()); + else + ImGui::TextUnformatted("???"); + ImGui::PopItemWidth(); + } + + void process() override { + this->m_value.reset(); + const auto &input = this->getFloatOnInput(0); + + this->m_value = input; + } + + private: + std::optional m_value; + }; + + class NodeDisplayBuffer : public dp::Node { + public: + NodeDisplayBuffer() : Node("hex.builtin.nodes.display.buffer.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { } + + void drawNode() override { + static const std::string Header = " Address 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F "; + + if (ImGui::BeginChild("##hex_view", scaled(ImVec2(ImGui::CalcTextSize(Header.c_str()).x, 200)), true)) { + ImGui::TextUnformatted(Header.c_str()); + + auto size = this->m_buffer.size(); + ImGuiListClipper clipper; + + clipper.Begin((size + 0x0F) / 0x10); + + while (clipper.Step()) + for (auto y = clipper.DisplayStart; y < clipper.DisplayEnd; y++) { + auto lineSize = ((size - y * 0x10) < 0x10) ? size % 0x10 : 0x10; + + std::string line = hex::format(" {:08X}: ", y * 0x10); + for (u32 x = 0; x < 0x10; x++) { + if (x < lineSize) + line += hex::format("{:02X} ", this->m_buffer[y * 0x10 + x]); + else + line += " "; + + if (x == 7) line += " "; + } + + line += " "; + + for (u32 x = 0; x < lineSize; x++) { + auto c = char(this->m_buffer[y * 0x10 + x]); + if (std::isprint(c)) + line += c; + else + line += "."; + } + + ImGui::TextUnformatted(line.c_str()); + } + clipper.End(); + } + ImGui::EndChild(); + } + + void process() override { + this->m_buffer = this->getBufferOnInput(0); + } + + private: + std::vector m_buffer; + }; + + class NodeDisplayString : public dp::Node { + public: + NodeDisplayString() : Node("hex.builtin.nodes.display.string.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { } + + void drawNode() override { + constexpr static auto LineLength = 50; + if (ImGui::BeginChild("##string_view", scaled(ImVec2(ImGui::CalcTextSize(" ").x * (LineLength + 4), 150)), true)) { + std::string_view string = this->m_value; + + ImGuiListClipper clipper; + clipper.Begin((string.length() + (LineLength - 1)) / LineLength); + + while (clipper.Step()) + for (auto i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { + auto line = string.substr(i * LineLength, LineLength); + ImGui::TextUnformatted(""); + ImGui::SameLine(); + ImGui::TextUnformatted(line.data(), line.data() + line.length()); + } + + clipper.End(); + } + ImGui::EndChild(); + } + + void process() override { + const auto &input = this->getBufferOnInput(0); + + this->m_value = hex::encodeByteString(input); + } + + private: + std::string m_value; + }; + + class NodeDisplayBits : public dp::Node { + public: + NodeDisplayBits() : Node("hex.builtin.nodes.display.bits.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { } + + void drawNode() override { + ImGui::PushItemWidth(100_scaled); + ImGui::Text("%s", this->m_display.c_str()); + ImGui::PopItemWidth(); + } + + void process() override { + const auto &buffer = this->getBufferOnInput(0); + // Display bits in groups of 4 bits + std::string display; + display.reserve(buffer.size() * 9 + 2); // 8 bits + 1 space at beginning + 1 space every 4 bits + for (const auto &byte : buffer) { + for (size_t i = 0; i < 8; i++) { + if (i % 4 == 0) { + display += ' '; + } + display += (byte & (1 << i)) != 0 ? '1' : '0'; + } + } + this->m_display = wolv::util::trim(display); + } + + private: + std::string m_display = "???"; + }; + + void registerVisualDataProcessorNodes() { + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.display", "hex.builtin.nodes.display.int"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.display", "hex.builtin.nodes.display.float"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.display", "hex.builtin.nodes.display.buffer"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.display", "hex.builtin.nodes.display.string"); + ContentRegistry::DataProcessorNode::add("hex.builtin.nodes.display", "hex.builtin.nodes.display.bits"); + } + +}