From c1b4c4e42ad90c96a8a2896836163c876c16d4b2 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Sun, 6 Feb 2022 14:44:03 +0100 Subject: [PATCH] nodes: Added layered distribution visualizer --- .../source/content/data_processor_nodes.cpp | 93 ++++++++++++++++++- plugins/builtin/source/lang/de_DE.cpp | 2 + plugins/builtin/source/lang/en_US.cpp | 4 +- plugins/builtin/source/lang/it_IT.cpp | 2 + plugins/builtin/source/lang/zh_CN.cpp | 2 + 5 files changed, 98 insertions(+), 5 deletions(-) diff --git a/plugins/builtin/source/content/data_processor_nodes.cpp b/plugins/builtin/source/content/data_processor_nodes.cpp index 7710ee0eb..c82ab4dfa 100644 --- a/plugins/builtin/source/content/data_processor_nodes.cpp +++ b/plugins/builtin/source/content/data_processor_nodes.cpp @@ -836,6 +836,89 @@ namespace hex::plugin::builtin { size_t m_highestCount = 0; }; + 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 { + const auto viewSize = scaled({ 200, 200 }); + ImGui::PushStyleColor(ImGuiCol_ChildBg, ImU32(ImColor(0, 0, 0))); + if (ImGui::BeginChild("##visualizer", viewSize, true)) { + auto drawList = ImGui::GetWindowDrawList(); + + float xStep = (viewSize.x * 0.95F) / 0xFF; + float yStep = (viewSize.y * 0.95F) / 0xFF; + + for (size_t i = 0; i < ((this->m_buffer.size() == 0) ? 0 : this->m_buffer.size()); i++) { + const auto &[x, y] = std::pair { this->m_buffer[i] * xStep, yStep * ((float(i) / this->m_buffer.size()) * 0xFF) }; + + auto color = ImLerp(ImColor(0xFF, 0x6D, 0x01).Value, ImColor(0x01, 0x93, 0xFF).Value, float(i) / this->m_buffer.size()); + color.w = this->m_opacityBuffer[i]; + + auto pos = ImGui::GetWindowPos() + ImVec2(viewSize.x * 0.025F, viewSize.y * 0.025F) + ImVec2(x, y); + drawList->AddRectFilled(pos, pos + ImVec2(xStep, yStep), ImColor(color)); + } + } + ImGui::EndChild(); + ImGui::PopStyleColor(); + } + + void process() override { + constexpr static auto SampleSize = 0x9000; + const static size_t SequenceCount = std::ceil(std::sqrt(SampleSize)); + + this->m_buffer.clear(); + + auto buffer = this->getBufferOnInput(0); + if (buffer.size() < SampleSize) + this->m_buffer = buffer; + else { + std::random_device randomDevice; + std::mt19937_64 random(randomDevice()); + + std::map> orderedData; + for (u32 i = 0; i < SequenceCount; i++) { + ssize_t offset = random() % buffer.size(); + + std::vector sequence; + sequence.reserve(SampleSize); + std::copy(buffer.begin() + offset, buffer.begin() + offset + std::min(SequenceCount, buffer.size() - offset), std::back_inserter(sequence)); + + orderedData.insert({ offset, sequence }); + } + + this->m_buffer.reserve(SampleSize); + + u64 lastEnd = 0x00; + for (const auto &[offset, sequence] : orderedData) { + if (offset < lastEnd) + this->m_buffer.resize(this->m_buffer.size() - (lastEnd - offset)); + + std::copy(sequence.begin(), sequence.end(), std::back_inserter(this->m_buffer)); + lastEnd = offset + sequence.size(); + } + } + + this->m_opacityBuffer.resize(this->m_buffer.size()); + + std::map heatMap; + for (size_t i = 0; i < (this->m_buffer.empty() ? 0 : this->m_buffer.size() - 1); i++) { + auto count = ++heatMap[this->m_buffer[i] << 8 | heatMap[i + 1]]; + + this->m_highestCount = std::max(this->m_highestCount, count); + } + + for (size_t i = 0; i < (this->m_buffer.empty() ? 0 : this->m_buffer.size() - 1); i++) { + this->m_opacityBuffer[i] = std::min(0.2F + (float(heatMap[this->m_buffer[i] << 8 | this->m_buffer[i + 1]]) / float(this->m_highestCount / 1000)), 1.0F); + } + } + + private: + std::vector m_buffer; + std::vector m_opacityBuffer; + size_t m_highestCount = 0; + }; + 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") }) { } @@ -863,14 +946,15 @@ namespace hex::plugin::builtin { void drawNode() override { ImPlot::SetNextPlotLimits(0, 256, 0.5, float(*std::max_element(this->m_counts.begin(), this->m_counts.end())) * 1.1F, ImGuiCond_Always); - if (ImPlot::BeginPlot("##distribution", nullptr, nullptr, scaled(ImVec2(300, 200)), ImPlotFlags_NoLegend | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect, ImPlotAxisFlags_Lock, ImPlotAxisFlags_Lock | ImPlotAxisFlags_LogScale, ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoTickLabels, ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoTickLabels)) { - constexpr static auto x = [] { + if (ImPlot::BeginPlot("##distribution", "Address", "Count", scaled(ImVec2(400, 300)), ImPlotFlags_NoLegend | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect, ImPlotAxisFlags_Lock, ImPlotAxisFlags_Lock | ImPlotAxisFlags_LogScale, ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoTickLabels, ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoTickLabels)) { + 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(), 0.67); + + ImPlot::PlotBars("##bytes", x.data(), this->m_counts.data(), x.size(), 1); ImPlot::EndPlot(); } @@ -881,7 +965,7 @@ namespace hex::plugin::builtin { this->m_counts.fill(0x00); for (const auto &byte : buffer) { - m_counts[byte]++; + this->m_counts[byte]++; } } @@ -937,6 +1021,7 @@ namespace hex::plugin::builtin { 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.byte_distribution"); } diff --git a/plugins/builtin/source/lang/de_DE.cpp b/plugins/builtin/source/lang/de_DE.cpp index f50afd641..73db8d392 100644 --- a/plugins/builtin/source/lang/de_DE.cpp +++ b/plugins/builtin/source/lang/de_DE.cpp @@ -542,6 +542,8 @@ namespace hex::plugin::builtin { { "hex.builtin.nodes.visualizer", "Visualisierung" }, { "hex.builtin.nodes.visualizer.digram", "Digram" }, { "hex.builtin.nodes.visualizer.digram.header", "Digram" }, + { "hex.builtin.nodes.visualizer.layered_dist", "Geschichtete Verteilung" }, + { "hex.builtin.nodes.visualizer.layered_dist.header", "Geschichtete Verteilung" }, { "hex.builtin.nodes.visualizer.image", "Bild" }, { "hex.builtin.nodes.visualizer.image.header", "Bild" }, { "hex.builtin.nodes.visualizer.byte_distribution", "Byteverteilung" }, diff --git a/plugins/builtin/source/lang/en_US.cpp b/plugins/builtin/source/lang/en_US.cpp index ca472ba47..3eed18b59 100644 --- a/plugins/builtin/source/lang/en_US.cpp +++ b/plugins/builtin/source/lang/en_US.cpp @@ -544,7 +544,9 @@ namespace hex::plugin::builtin { { "hex.builtin.nodes.visualizer", "Visualizers" }, { "hex.builtin.nodes.visualizer.digram", "Digram" }, - { "hex.builtin.nodes.visualizer.digram.header", "Digram Visualizer" }, + { "hex.builtin.nodes.visualizer.digram.header", "Digram" }, + { "hex.builtin.nodes.visualizer.layered_dist", "Layered Distribution" }, + { "hex.builtin.nodes.visualizer.layered_dist.header", "Layered Distribution" }, { "hex.builtin.nodes.visualizer.image", "Image" }, { "hex.builtin.nodes.visualizer.image.header", "Image Visualizer" }, { "hex.builtin.nodes.visualizer.byte_distribution", "Byte Distribution" }, diff --git a/plugins/builtin/source/lang/it_IT.cpp b/plugins/builtin/source/lang/it_IT.cpp index bd7981472..bb612060a 100644 --- a/plugins/builtin/source/lang/it_IT.cpp +++ b/plugins/builtin/source/lang/it_IT.cpp @@ -543,6 +543,8 @@ namespace hex::plugin::builtin { //{ "hex.builtin.nodes.visualizer", "Visualizers" }, //{ "hex.builtin.nodes.visualizer.digram", "Digram" }, //{ "hex.builtin.nodes.visualizer.digram.header", "Digram Visualizer" }, + //{ "hex.builtin.nodes.visualizer.layered_dist", "Layered Distribution" }, + //{ "hex.builtin.nodes.visualizer.layered_dist.header", "Layered Distribution" }, //{ "hex.builtin.nodes.visualizer.image", "Image" }, //{ "hex.builtin.nodes.visualizer.image.header", "Image Visualizer" }, //{ "hex.builtin.nodes.visualizer.byte_distribution", "Byte Distribution" }, diff --git a/plugins/builtin/source/lang/zh_CN.cpp b/plugins/builtin/source/lang/zh_CN.cpp index 0248647ad..1ee5bd34c 100644 --- a/plugins/builtin/source/lang/zh_CN.cpp +++ b/plugins/builtin/source/lang/zh_CN.cpp @@ -538,6 +538,8 @@ namespace hex::plugin::builtin { //{ "hex.builtin.nodes.visualizer", "Visualizers" }, //{ "hex.builtin.nodes.visualizer.digram", "Digram" }, //{ "hex.builtin.nodes.visualizer.digram.header", "Digram Visualizer" }, + //{ "hex.builtin.nodes.visualizer.layered_dist", "Layered Distribution" }, + //{ "hex.builtin.nodes.visualizer.layered_dist.header", "Layered Distribution" }, //{ "hex.builtin.nodes.visualizer.image", "Image" }, //{ "hex.builtin.nodes.visualizer.image.header", "Image Visualizer" }, //{ "hex.builtin.nodes.visualizer.byte_distribution", "Byte Distribution" },