diff --git a/include/views/view_entropy.hpp b/include/views/view_entropy.hpp new file mode 100644 index 000000000..a7a0db042 --- /dev/null +++ b/include/views/view_entropy.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "views/view.hpp" + +#include + +namespace hex { + + namespace prv { class Provider; } + + class ViewEntropy : public View { + public: + explicit ViewEntropy(prv::Provider* &dataProvider); + ~ViewEntropy() override; + + void createView() override; + void createMenu() override; + + private: + prv::Provider* &m_dataProvider; + bool m_windowOpen = true; + + double m_entropy = 0; + float m_valueCounts[256] = { 0 }; + bool m_shouldInvalidate = true; + }; + +} \ No newline at end of file diff --git a/source/main.cpp b/source/main.cpp index 30e56e2f2..d0dbfdaa0 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -5,6 +5,7 @@ #include "views/view_pattern.hpp" #include "views/view_pattern_data.hpp" #include "views/view_hashes.hpp" +#include "views/view_entropy.hpp" #include "providers/provider.hpp" @@ -22,6 +23,7 @@ int main() { window.addView(highlights); window.addView(dataProvider, highlights); window.addView(dataProvider); + window.addView(dataProvider); window.loop(); diff --git a/source/views/view_entropy.cpp b/source/views/view_entropy.cpp new file mode 100644 index 000000000..2cab40042 --- /dev/null +++ b/source/views/view_entropy.cpp @@ -0,0 +1,84 @@ +#include "views/view_entropy.hpp" + +#include "providers/provider.hpp" + +#include "utils.hpp" + +#include +#include +#include + +namespace hex { + + ViewEntropy::ViewEntropy(prv::Provider* &dataProvider) : View(), m_dataProvider(dataProvider) { + + } + + ViewEntropy::~ViewEntropy() { + + } + + + void ViewEntropy::createView() { + if (!this->m_windowOpen) + return; + + if (ImGui::Begin("Entropy", &this->m_windowOpen)) { + ImGui::BeginChild("##scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav); + + if (this->m_dataProvider != nullptr && this->m_dataProvider->isReadable()) { + if (this->m_shouldInvalidate) { + std::vector buffer(512, 0x00); + std::memset(this->m_valueCounts, 0x00, sizeof(this->m_valueCounts)); + + for (u64 i = 0; i < this->m_dataProvider->getSize(); i += 512) { + this->m_dataProvider->read(i, buffer.data(), std::min(512ULL, this->m_dataProvider->getSize() - i)); + + for (u16 j = 0; j < 512; j++) + this->m_valueCounts[buffer[j]]++; + } + + size_t numBytes = this->m_dataProvider->getSize(); + this->m_entropy = 0; + for (u16 i = 0; i < 256; i++) { + this->m_valueCounts[i] /= numBytes; + + if (this->m_valueCounts[i] > 0) + this->m_entropy -= this->m_valueCounts[i] * std::log2(this->m_valueCounts[i]); + } + + this->m_entropy /= 8; + + this->m_shouldInvalidate = false; + } + + ImGui::LabelText("Entropy", "%.8f", this->m_entropy); + + if (this->m_entropy > 0.99) + ImGui::TextUnformatted("This file is most likely encrypted or compressed!"); + + ImGui::Separator(); + ImGui::NewLine(); + ImGui::PlotHistogram("Byte Distribution", this->m_valueCounts, 256, 0, nullptr, FLT_MAX, FLT_MAX, ImVec2(0, 100)); + + ImGui::NewLine(); + ImGui::Separator(); + ImGui::NewLine(); + + if (ImGui::Button("Invalidate")) + this->m_shouldInvalidate = true; + } + + ImGui::EndChild(); + } + ImGui::End(); + } + + void ViewEntropy::createMenu() { + if (ImGui::BeginMenu("View")) { + ImGui::MenuItem("Entropy View", "", &this->m_windowOpen); + ImGui::EndMenu(); + } + } + +} \ No newline at end of file