diff --git a/lib/libimhex/include/hex/api/content_registry.hpp b/lib/libimhex/include/hex/api/content_registry.hpp index cb4af9bae..880d67d11 100644 --- a/lib/libimhex/include/hex/api/content_registry.hpp +++ b/lib/libimhex/include/hex/api/content_registry.hpp @@ -24,6 +24,7 @@ namespace hex { class View; class Shortcut; + class Task; namespace dp { class Node; @@ -1259,6 +1260,7 @@ namespace hex { [[nodiscard]] bool isExperimentEnabled(const std::string &experimentName); } + /* Reports Registry. Allows adding new sections to exported reports */ namespace Reports { namespace impl { @@ -1276,6 +1278,73 @@ namespace hex { void addReportProvider(impl::Callback callback); } + + namespace DataInformation { + + class InformationSection { + public: + InformationSection(const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedDescription = "", bool hasSettings = false) + : m_unlocalizedName(unlocalizedName), m_unlocalizedDescription(unlocalizedDescription), + m_hasSettings(hasSettings) { } + virtual ~InformationSection() = default; + + [[nodiscard]] const UnlocalizedString& getUnlocalizedName() const { return m_unlocalizedName; } + [[nodiscard]] const UnlocalizedString& getUnlocalizedDescription() const { return m_unlocalizedDescription; } + + virtual void process(Task &task, prv::Provider *provider, Region region) = 0; + virtual void reset() = 0; + + virtual void drawSettings() { } + virtual void drawContent() = 0; + + [[nodiscard]] bool isValid() const { return m_valid; } + void markValid(bool valid = true) { m_valid = valid; } + + [[nodiscard]] bool isEnabled() const { return m_enabled; } + void setEnabled(bool enabled) { m_enabled = enabled; } + + [[nodiscard]] bool isAnalyzing() const { return m_analyzing; } + void setAnalyzing(bool analyzing) { m_analyzing = analyzing; } + + virtual void load(const nlohmann::json &data) { + m_enabled = data.value("enabled", true); + } + [[nodiscard]] virtual nlohmann::json store() { + nlohmann::json data; + data["enabled"] = m_enabled.load(); + + return data; + } + + [[nodiscard]] bool hasSettings() const { return m_hasSettings; } + + private: + UnlocalizedString m_unlocalizedName, m_unlocalizedDescription; + bool m_hasSettings; + + std::atomic m_analyzing = false; + std::atomic m_valid = false; + std::atomic m_enabled = true; + }; + + namespace impl { + + using CreateCallback = std::function()>; + + const std::vector& getInformationSectionConstructors(); + void addInformationSectionCreator(const CreateCallback &callback); + + } + + template + void addInformationSection(auto && ...args) { + impl::addInformationSectionCreator([args...] { + return std::make_unique(std::forward(args)...); + }); + } + + } + } } diff --git a/lib/libimhex/include/hex/api/imhex_api.hpp b/lib/libimhex/include/hex/api/imhex_api.hpp index bbc8d5c0a..94d59b266 100644 --- a/lib/libimhex/include/hex/api/imhex_api.hpp +++ b/lib/libimhex/include/hex/api/imhex_api.hpp @@ -19,7 +19,9 @@ struct GLFWwindow; namespace hex { - class AutoResetBase; + namespace impl { + class AutoResetBase; + } namespace prv { class Provider; @@ -409,7 +411,7 @@ namespace hex { bool isWindowResizable(); - void addAutoResetObject(AutoResetBase *object); + void addAutoResetObject(hex::impl::AutoResetBase *object); void cleanup(); } diff --git a/lib/libimhex/include/hex/api/task_manager.hpp b/lib/libimhex/include/hex/api/task_manager.hpp index eedf45627..c3cb387bb 100644 --- a/lib/libimhex/include/hex/api/task_manager.hpp +++ b/lib/libimhex/include/hex/api/task_manager.hpp @@ -31,7 +31,8 @@ namespace hex { * @brief Updates the current process value of the task * @param value Current value */ - void update(u64 value = 0); + void update(u64 value); + void update() const; /** * @brief Sets the maximum value of the task diff --git a/lib/libimhex/include/hex/helpers/auto_reset.hpp b/lib/libimhex/include/hex/helpers/auto_reset.hpp index 9e04aebe7..fff597139 100644 --- a/lib/libimhex/include/hex/helpers/auto_reset.hpp +++ b/lib/libimhex/include/hex/helpers/auto_reset.hpp @@ -5,14 +5,18 @@ namespace hex { - class AutoResetBase { - public: - virtual ~AutoResetBase() = default; - virtual void reset() = 0; - }; + namespace impl { + + class AutoResetBase { + public: + virtual ~AutoResetBase() = default; + virtual void reset() = 0; + }; + + } template - class AutoReset : AutoResetBase { + class AutoReset : public impl::AutoResetBase { public: using Type = T; diff --git a/lib/libimhex/include/hex/helpers/magic.hpp b/lib/libimhex/include/hex/helpers/magic.hpp index de6c3c8bc..fb0578cc3 100644 --- a/lib/libimhex/include/hex/helpers/magic.hpp +++ b/lib/libimhex/include/hex/helpers/magic.hpp @@ -17,13 +17,13 @@ namespace hex::magic { bool compile(); std::string getDescription(const std::vector &data, bool firstEntryOnly = false); - std::string getDescription(prv::Provider *provider, size_t size = 100_KiB, bool firstEntryOnly = false); + std::string getDescription(prv::Provider *provider, u64 address = 0x00, size_t size = 100_KiB, bool firstEntryOnly = false); std::string getMIMEType(const std::vector &data, bool firstEntryOnly = false); - std::string getMIMEType(prv::Provider *provider, size_t size = 100_KiB, bool firstEntryOnly = false); + std::string getMIMEType(prv::Provider *provider, u64 address = 0x00, size_t size = 100_KiB, bool firstEntryOnly = false); std::string getExtensions(const std::vector &data, bool firstEntryOnly = false); - std::string getExtensions(prv::Provider *provider, size_t size = 100_KiB, bool firstEntryOnly = false); + std::string getExtensions(prv::Provider *provider, u64 address = 0x00, size_t size = 100_KiB, bool firstEntryOnly = false); std::string getAppleCreatorType(const std::vector &data, bool firstEntryOnly = false); - std::string getAppleCreatorType(prv::Provider *provider, size_t size = 100_KiB, bool firstEntryOnly = false); + std::string getAppleCreatorType(prv::Provider *provider, u64 address = 0x00, size_t size = 100_KiB, bool firstEntryOnly = false); bool isValidMIMEType(const std::string &mimeType); diff --git a/lib/libimhex/source/api/content_registry.cpp b/lib/libimhex/source/api/content_registry.cpp index f15285395..564b702a7 100644 --- a/lib/libimhex/source/api/content_registry.cpp +++ b/lib/libimhex/source/api/content_registry.cpp @@ -1255,4 +1255,21 @@ namespace hex { } + namespace ContentRegistry::DataInformation { + + namespace impl { + + static AutoReset> s_informationSectionConstructors; + const std::vector& getInformationSectionConstructors() { + return *s_informationSectionConstructors; + } + + void addInformationSectionCreator(const CreateCallback &callback) { + s_informationSectionConstructors->emplace_back(callback); + } + + } + + } + } diff --git a/lib/libimhex/source/api/imhex_api.cpp b/lib/libimhex/source/api/imhex_api.cpp index e5e0221b7..2912dff4b 100644 --- a/lib/libimhex/source/api/imhex_api.cpp +++ b/lib/libimhex/source/api/imhex_api.cpp @@ -471,8 +471,8 @@ namespace hex { return s_windowResizable; } - static std::vector s_autoResetObjects; - void addAutoResetObject(AutoResetBase *object) { + static std::vector s_autoResetObjects; + void addAutoResetObject(hex::impl::AutoResetBase *object) { s_autoResetObjects.emplace_back(object); } diff --git a/lib/libimhex/source/api/task_manager.cpp b/lib/libimhex/source/api/task_manager.cpp index a9c5ba5c2..68b0b7a66 100644 --- a/lib/libimhex/source/api/task_manager.cpp +++ b/lib/libimhex/source/api/task_manager.cpp @@ -72,6 +72,12 @@ namespace hex { throw TaskInterruptor(); } + void Task::update() const { + if (m_shouldInterrupt.load(std::memory_order_relaxed)) [[unlikely]] + throw TaskInterruptor(); + } + + void Task::setMaxValue(u64 value) { m_maxValue = value; } diff --git a/lib/libimhex/source/helpers/magic.cpp b/lib/libimhex/source/helpers/magic.cpp index 48c2fc84f..d772261af 100644 --- a/lib/libimhex/source/helpers/magic.cpp +++ b/lib/libimhex/source/helpers/magic.cpp @@ -113,9 +113,9 @@ namespace hex::magic { return ""; } - std::string getDescription(prv::Provider *provider, size_t size, bool firstEntryOnly) { + std::string getDescription(prv::Provider *provider, u64 address, size_t size, bool firstEntryOnly) { std::vector buffer(std::min(provider->getSize(), size), 0x00); - provider->read(provider->getBaseAddress(), buffer.data(), buffer.size()); + provider->read(provider->getBaseAddress() + address, buffer.data(), buffer.size()); return getDescription(buffer, firstEntryOnly); } @@ -138,16 +138,16 @@ namespace hex::magic { return ""; } - std::string getMIMEType(prv::Provider *provider, size_t size, bool firstEntryOnly) { + std::string getMIMEType(prv::Provider *provider, u64 address, size_t size, bool firstEntryOnly) { std::vector buffer(std::min(provider->getSize(), size), 0x00); - provider->read(provider->getBaseAddress(), buffer.data(), buffer.size()); + provider->read(provider->getBaseAddress() + address, buffer.data(), buffer.size()); return getMIMEType(buffer, firstEntryOnly); } - std::string getExtensions(prv::Provider *provider, size_t size, bool firstEntryOnly) { + std::string getExtensions(prv::Provider *provider, u64 address, size_t size, bool firstEntryOnly) { std::vector buffer(std::min(provider->getSize(), size), 0x00); - provider->read(provider->getBaseAddress(), buffer.data(), buffer.size()); + provider->read(provider->getBaseAddress() + address, buffer.data(), buffer.size()); return getExtensions(buffer, firstEntryOnly); } @@ -170,9 +170,9 @@ namespace hex::magic { return ""; } - std::string getAppleCreatorType(prv::Provider *provider, size_t size, bool firstEntryOnly) { + std::string getAppleCreatorType(prv::Provider *provider, u64 address, size_t size, bool firstEntryOnly) { std::vector buffer(std::min(provider->getSize(), size), 0x00); - provider->read(provider->getBaseAddress(), buffer.data(), buffer.size()); + provider->read(provider->getBaseAddress() + address, buffer.data(), buffer.size()); return getAppleCreatorType(buffer, firstEntryOnly); } diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index 82596c28f..e5c3d3e79 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -46,6 +46,7 @@ add_imhex_plugin( source/content/out_of_box_experience.cpp source/content/minimap_visualizers.cpp source/content/window_decoration.cpp + source/content/data_information_sections.cpp source/content/data_processor_nodes/basic_nodes.cpp source/content/data_processor_nodes/control_nodes.cpp diff --git a/plugins/builtin/include/content/helpers/diagrams.hpp b/plugins/builtin/include/content/helpers/diagrams.hpp index 1ed0354aa..399a117a0 100644 --- a/plugins/builtin/include/content/helpers/diagrams.hpp +++ b/plugins/builtin/include/content/helpers/diagrams.hpp @@ -302,7 +302,7 @@ namespace hex { void draw(ImVec2 size, ImPlotFlags flags, bool updateHandle = false) { if (!m_processing && ImPlot::BeginPlot("##ChunkBasedAnalysis", size, flags)) { - ImPlot::SetupAxes("hex.ui.common.address"_lang, "hex.builtin.view.information.entropy"_lang, + ImPlot::SetupAxes("hex.ui.common.address"_lang, "hex.builtin.information_section.info_analysis.entropy"_lang, ImPlotAxisFlags_Lock | ImPlotAxisFlags_NoHighlight | ImPlotAxisFlags_NoSideSwitch, ImPlotAxisFlags_Lock | ImPlotAxisFlags_NoHighlight | ImPlotAxisFlags_NoSideSwitch); ImPlot::SetupAxisFormat(ImAxis_X1, impl::IntegerAxisFormatter, (void*)("0x%04llX")); @@ -682,7 +682,7 @@ namespace hex { u64 m_endAddress = 0; // Hold the result of the byte distribution analysis - std::array m_valueCounts; + std::array m_valueCounts = { }; std::atomic m_processing = false; }; diff --git a/plugins/builtin/include/content/views/view_information.hpp b/plugins/builtin/include/content/views/view_information.hpp index c88b1fb40..d5c4d411e 100644 --- a/plugins/builtin/include/content/views/view_information.hpp +++ b/plugins/builtin/include/content/views/view_information.hpp @@ -1,64 +1,35 @@ #pragma once -#include +#include #include - -#include "content/helpers/diagrams.hpp" +#include #include -#include - namespace hex::plugin::builtin { class ViewInformation : public View::Window { public: explicit ViewInformation(); - ~ViewInformation() override; + ~ViewInformation() override = default; void drawContent() override; private: - struct AnalysisData { - AnalysisData() = default; - AnalysisData(const AnalysisData&) = default; - - TaskHolder analyzerTask; - - bool dataValid = false; - u32 blockSize = 0; - double averageEntropy = -1.0; - - double highestBlockEntropy = -1.0; - u64 highestBlockEntropyAddress = 0x00; - double lowestBlockEntropy = -1.0; - u64 lowestBlockEntropyAddress = 0x00; - - double plainTextCharacterPercentage = -1.0; - - Region analysisRegion = { 0, 0 }; - Region analyzedRegion = { 0, 0 }; - prv::Provider *analyzedProvider = nullptr; - - std::string dataDescription; - std::string dataMimeType; - std::string dataAppleCreatorType; - std::string dataExtensions; - - std::shared_ptr digram; - std::shared_ptr layeredDistribution; - std::shared_ptr byteDistribution; - std::shared_ptr byteTypesDistribution; - std::shared_ptr chunkBasedEntropy; - - u32 inputChunkSize = 0; - ui::RegionType selectionType = ui::RegionType::EntireData; - }; - - PerProvider m_analysis; - - void analyze(); + struct AnalysisData { + bool valid = false; + + TaskHolder task; + prv::Provider *analyzedProvider = nullptr; + Region analysisRegion = { 0, 0 }; + + ui::RegionType selectionType = ui::RegionType::EntireData; + + std::list> informationSections; + }; + + PerProvider m_analysisData; }; } diff --git a/plugins/builtin/romfs/lang/de_DE.json b/plugins/builtin/romfs/lang/de_DE.json index b208ac2ec..78a875e3a 100644 --- a/plugins/builtin/romfs/lang/de_DE.json +++ b/plugins/builtin/romfs/lang/de_DE.json @@ -837,32 +837,32 @@ "hex.builtin.view.highlight_rules.no_rule": "Erstelle eine neue Regel um sie zu bearbeiten.", "hex.builtin.view.information.analyze": "Seite analysieren", "hex.builtin.view.information.analyzing": "Analysiere...", - "hex.builtin.view.information.apple_type": "Apple Creator / Type Code", - "hex.builtin.view.information.block_size": "Blockgrösse", - "hex.builtin.view.information.block_size.desc": "{0} Blöcke mit {1} Bytes", - "hex.builtin.view.information.byte_types": "Byte Typen", + "hex.builtin.information_section.magic.apple_type": "Apple Creator / Type Code", + "hex.builtin.information_section.info_analysis.block_size": "Blockgrösse", + "hex.builtin.information_section.info_analysis.block_size.desc": "{0} Blöcke mit {1} Bytes", + "hex.builtin.information_section.info_analysis.byte_types": "Byte Typen", "hex.builtin.view.information.control": "Einstellungen", - "hex.builtin.view.information.description": "Beschreibung", - "hex.builtin.view.information.digram": "Diagramm", - "hex.builtin.view.information.distribution": "Byte Verteilung", - "hex.builtin.view.information.encrypted": "Diese Daten sind vermutlich verschlüsselt oder komprimiert!", - "hex.builtin.view.information.entropy": "Entropie", - "hex.builtin.view.information.extension": "Dateiendung", - "hex.builtin.view.information.file_entropy": "Gesammtentropie", - "hex.builtin.view.information.highest_entropy": "Höchste Blockentropie", - "hex.builtin.view.information.info_analysis": "Informationsanalyse", - "hex.builtin.view.information.layered_distribution": "Schichtverteilung", - "hex.builtin.view.information.lowest_entropy": "Tiefste Blockentropie", - "hex.builtin.view.information.magic": "Magic Informationen", + "hex.builtin.information_section.magic.description": "Beschreibung", + "hex.builtin.information_section.info_analysis.digram": "Diagramm", + "hex.builtin.information_section.info_analysis.distribution": "Byte Verteilung", + "hex.builtin.information_section.info_analysis.encrypted": "Diese Daten sind vermutlich verschlüsselt oder komprimiert!", + "hex.builtin.information_section.info_analysis.entropy": "Entropie", + "hex.builtin.information_section.magic.extension": "Dateiendung", + "hex.builtin.information_section.info_analysis.file_entropy": "Gesammtentropie", + "hex.builtin.information_section.info_analysis.highest_entropy": "Höchste Blockentropie", + "hex.builtin.information_section.info_analysis.lowest_entropy": "Informationsanalyse", + "hex.builtin.information_section.info_analysis": "Schichtverteilung", + "hex.builtin.information_section.info_analysis.layered_distribution": "Tiefste Blockentropie", + "hex.builtin.information_section.magic": "Magic Informationen", "hex.builtin.view.information.magic_db_added": "Magic Datenbank hinzugefügt!", - "hex.builtin.view.information.mime": "MIME Typ", + "hex.builtin.information_section.magic.mime": "MIME Typ", "hex.builtin.view.information.name": "Dateninformationen", - "hex.builtin.view.information.octet_stream_text": "Unbekannt", - "hex.builtin.view.information.octet_stream_warning": "application/octet-stream ist ein generischer MIME Typ für Binärdaten. Dies bedeutet, dass der Dateityp nicht zuverlässig erkannt werden konnte.", - "hex.builtin.view.information.plain_text": "Diese Daten sind vermutlich einfacher Text.", - "hex.builtin.view.information.plain_text_percentage": "Klartext Prozentanteil", - "hex.builtin.view.information.provider_information": "Provider Informationen", - "hex.builtin.view.information.region": "Analysierte Region", + "hex.builtin.view.information.not_analyzed": "Noch nicht Analysiert", + "hex.builtin.information_section.magic.octet_stream_text": "Unbekannt", + "hex.builtin.information_section.magic.octet_stream_warning": "application/octet-stream ist ein generischer MIME Typ für Binärdaten. Dies bedeutet, dass der Dateityp nicht zuverlässig erkannt werden konnte.", + "hex.builtin.information_section.info_analysis.plain_text": "Diese Daten sind vermutlich einfacher Text.", + "hex.builtin.information_section.info_analysis.plain_text_percentage": "Klartext Prozentanteil", + "hex.builtin.information_section.provider_information": "Provider Informationen", "hex.builtin.view.logs.component": "Komponent", "hex.builtin.view.logs.log_level": "Log Level", "hex.builtin.view.logs.message": "Nachricht", diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index 9d618cd3c..d577ae651 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -827,32 +827,32 @@ "hex.builtin.view.highlight_rules.menu.edit.rules": "Modify highlight rules...", "hex.builtin.view.information.analyze": "Analyze page", "hex.builtin.view.information.analyzing": "Analyzing...", - "hex.builtin.view.information.apple_type": "Apple Creator / Type Code", - "hex.builtin.view.information.block_size": "Block size", - "hex.builtin.view.information.block_size.desc": "{0} blocks of {1} bytes", - "hex.builtin.view.information.byte_types": "Byte types", + "hex.builtin.information_section.magic.apple_type": "Apple Creator / Type Code", + "hex.builtin.information_section.info_analysis.block_size": "Block size", + "hex.builtin.information_section.info_analysis.block_size.desc": "{0} blocks of {1} bytes", + "hex.builtin.information_section.info_analysis.byte_types": "Byte types", "hex.builtin.view.information.control": "Control", - "hex.builtin.view.information.description": "Description", - "hex.builtin.view.information.digram": "Digram", - "hex.builtin.view.information.distribution": "Byte distribution", - "hex.builtin.view.information.encrypted": "This data is most likely encrypted or compressed!", - "hex.builtin.view.information.entropy": "Entropy", - "hex.builtin.view.information.extension": "File Extension", - "hex.builtin.view.information.file_entropy": "Overall entropy", - "hex.builtin.view.information.highest_entropy": "Highest block entropy", - "hex.builtin.view.information.lowest_entropy": "Lowest block entropy", - "hex.builtin.view.information.info_analysis": "Information analysis", - "hex.builtin.view.information.layered_distribution": "Layered distribution", - "hex.builtin.view.information.magic": "Magic information", + "hex.builtin.information_section.magic.description": "Description", + "hex.builtin.information_section.info_analysis.digram": "Digram", + "hex.builtin.information_section.info_analysis.distribution": "Byte distribution", + "hex.builtin.information_section.info_analysis.encrypted": "This data is most likely encrypted or compressed!", + "hex.builtin.information_section.info_analysis.entropy": "Entropy", + "hex.builtin.information_section.magic.extension": "File Extension", + "hex.builtin.information_section.info_analysis.file_entropy": "Overall entropy", + "hex.builtin.information_section.info_analysis.highest_entropy": "Highest block entropy", + "hex.builtin.information_section.info_analysis.lowest_entropy": "Lowest block entropy", + "hex.builtin.information_section.info_analysis": "Information analysis", + "hex.builtin.information_section.info_analysis.layered_distribution": "Layered distribution", + "hex.builtin.information_section.magic": "Magic information", "hex.builtin.view.information.magic_db_added": "Magic database added!", - "hex.builtin.view.information.mime": "MIME Type", + "hex.builtin.information_section.magic.mime": "MIME Type", "hex.builtin.view.information.name": "Data Information", - "hex.builtin.view.information.octet_stream_text": "Unknown", - "hex.builtin.view.information.octet_stream_warning": "application/octet-stream denotes an unknown data type.\n\nThis means that this data has no MIME type associated with it because it's not in a known format.", - "hex.builtin.view.information.region": "Analyzed region", - "hex.builtin.view.information.plain_text": "This data is most likely plain text.", - "hex.builtin.view.information.plain_text_percentage": "Plain text percentage", - "hex.builtin.view.information.provider_information": "Provider Information", + "hex.builtin.view.information.not_analyzed": "Not yet analyzed", + "hex.builtin.information_section.magic.octet_stream_text": "Unknown", + "hex.builtin.information_section.magic.octet_stream_warning": "application/octet-stream denotes an unknown data type.\n\nThis means that this data has no MIME type associated with it because it's not in a known format.", + "hex.builtin.information_section.info_analysis.plain_text": "This data is most likely plain text.", + "hex.builtin.information_section.info_analysis.plain_text_percentage": "Plain text percentage", + "hex.builtin.information_section.provider_information": "Provider Information", "hex.builtin.view.logs.component": "Component", "hex.builtin.view.logs.log_level": "Log Level", "hex.builtin.view.logs.message": "Message", diff --git a/plugins/builtin/romfs/lang/es_ES.json b/plugins/builtin/romfs/lang/es_ES.json index 20c53113f..ebd6680b1 100644 --- a/plugins/builtin/romfs/lang/es_ES.json +++ b/plugins/builtin/romfs/lang/es_ES.json @@ -833,32 +833,31 @@ "hex.builtin.view.highlight_rules.no_rule": "", "hex.builtin.view.information.analyze": "Analizar página", "hex.builtin.view.information.analyzing": "Analizando...", - "hex.builtin.view.information.apple_type": "", - "hex.builtin.view.information.block_size": "Tamaño de bloque", - "hex.builtin.view.information.block_size.desc": "{0} bloques de {1} bytes", - "hex.builtin.view.information.byte_types": "Tipos de byte", + "hex.builtin.information_section.magic.apple_type": "", + "hex.builtin.information_section.info_analysis.block_size": "Tamaño de bloque", + "hex.builtin.information_section.info_analysis.block_size.desc": "{0} bloques de {1} bytes", + "hex.builtin.information_section.info_analysis.byte_types": "Tipos de byte", "hex.builtin.view.information.control": "Ajustes", - "hex.builtin.view.information.description": "Descripción", - "hex.builtin.view.information.digram": "Digrama", - "hex.builtin.view.information.distribution": "Distribución de bytes", - "hex.builtin.view.information.encrypted": "¡Estos datos están probablemente encriptados o comprimidos!", - "hex.builtin.view.information.entropy": "Entropía", - "hex.builtin.view.information.extension": "", - "hex.builtin.view.information.file_entropy": "Entropía total", - "hex.builtin.view.information.highest_entropy": "Entropía del mayor bloque", - "hex.builtin.view.information.info_analysis": "Análisis de información", - "hex.builtin.view.information.layered_distribution": "Distribución en capas", - "hex.builtin.view.information.lowest_entropy": "Entropía del menor bloque", - "hex.builtin.view.information.magic": "Información del 'magic'", + "hex.builtin.information_section.magic.description": "Descripción", + "hex.builtin.information_section.info_analysis.digram": "Digrama", + "hex.builtin.information_section.info_analysis.distribution": "Distribución de bytes", + "hex.builtin.information_section.info_analysis.encrypted": "¡Estos datos están probablemente encriptados o comprimidos!", + "hex.builtin.information_section.info_analysis.entropy": "Entropía", + "hex.builtin.information_section.magic.extension": "", + "hex.builtin.information_section.info_analysis.file_entropy": "Entropía total", + "hex.builtin.information_section.info_analysis.highest_entropy": "Entropía del mayor bloque", + "hex.builtin.information_section.info_analysis.lowest_entropy": "Entropía del menor bloque", + "hex.builtin.information_section.info_analysis": "Análisis de información", + "hex.builtin.information_section.info_analysis.layered_distribution": "Distribución en capas", + "hex.builtin.information_section.magic": "Información del 'magic'", "hex.builtin.view.information.magic_db_added": "¡Añadida base de datos de 'magic's!", - "hex.builtin.view.information.mime": "Tipo MIME", + "hex.builtin.information_section.magic.mime": "Tipo MIME", "hex.builtin.view.information.name": "Información de Datos:", - "hex.builtin.view.information.octet_stream_text": "", - "hex.builtin.view.information.octet_stream_warning": "", - "hex.builtin.view.information.plain_text": "Estos datos probablemente no están encriptados o comprimidos.", - "hex.builtin.view.information.plain_text_percentage": "Porcentaje de 'plain text'", - "hex.builtin.view.information.provider_information": "Información de Proveedor", - "hex.builtin.view.information.region": "Región analizada", + "hex.builtin.information_section.magic.octet_stream_text": "", + "hex.builtin.information_section.magic.octet_stream_warning": "", + "hex.builtin.information_section.info_analysis.plain_text": "Estos datos probablemente no están encriptados o comprimidos.", + "hex.builtin.information_section.info_analysis.plain_text_percentage": "Porcentaje de 'plain text'", + "hex.builtin.information_section.provider_information": "Información de Proveedor", "hex.builtin.view.logs.component": "", "hex.builtin.view.logs.log_level": "", "hex.builtin.view.logs.message": "", diff --git a/plugins/builtin/romfs/lang/it_IT.json b/plugins/builtin/romfs/lang/it_IT.json index 5f27d4296..40e8ecfd1 100644 --- a/plugins/builtin/romfs/lang/it_IT.json +++ b/plugins/builtin/romfs/lang/it_IT.json @@ -833,31 +833,31 @@ "hex.builtin.view.highlight_rules.no_rule": "", "hex.builtin.view.information.analyze": "Analizza Pagina", "hex.builtin.view.information.analyzing": "Sto analizzando...", - "hex.builtin.view.information.apple_type": "", - "hex.builtin.view.information.block_size": "Dimensione del Blocco", - "hex.builtin.view.information.block_size.desc": "{0} blocchi di {1} bytes", - "hex.builtin.view.information.byte_types": "", + "hex.builtin.information_section.magic.apple_type": "", + "hex.builtin.information_section.info_analysis.block_size": "Dimensione del Blocco", + "hex.builtin.information_section.info_analysis.block_size.desc": "{0} blocchi di {1} bytes", + "hex.builtin.information_section.info_analysis.byte_types": "", "hex.builtin.view.information.control": "Controllo", - "hex.builtin.view.information.description": "Descrizione", - "hex.builtin.view.information.digram": "", - "hex.builtin.view.information.distribution": "Distribuzione dei Byte", - "hex.builtin.view.information.encrypted": "Questi dati sono probabilmente codificati o compressi!", - "hex.builtin.view.information.entropy": "Entropia", - "hex.builtin.view.information.extension": "", - "hex.builtin.view.information.file_entropy": "", - "hex.builtin.view.information.highest_entropy": "Highest block entropy", - "hex.builtin.view.information.info_analysis": "Informazioni dell'analisi", - "hex.builtin.view.information.layered_distribution": "", - "hex.builtin.view.information.lowest_entropy": "", - "hex.builtin.view.information.magic": "Informazione Magica", + "hex.builtin.information_section.magic.description": "Descrizione", + "hex.builtin.information_section.info_analysis.digram": "", + "hex.builtin.information_section.info_analysis.distribution": "Distribuzione dei Byte", + "hex.builtin.information_section.info_analysis.encrypted": "Questi dati sono probabilmente codificati o compressi!", + "hex.builtin.information_section.info_analysis.entropy": "Entropia", + "hex.builtin.information_section.magic.extension": "", + "hex.builtin.information_section.info_analysis.file_entropy": "", + "hex.builtin.information_section.info_analysis.highest_entropy": "Highest block entropy", + "hex.builtin.information_section.info_analysis": "Informazioni dell'analisi", + "hex.builtin.information_section.info_analysis.layered_distribution": "", + "hex.builtin.information_section.info_analysis.lowest_entropy": "", + "hex.builtin.information_section.magic": "Informazione Magica", "hex.builtin.view.information.magic_db_added": "Database magico aggiunto!", - "hex.builtin.view.information.mime": "Tipo di MIME", + "hex.builtin.information_section.magic.mime": "Tipo di MIME", "hex.builtin.view.information.name": "Informazione sui Dati", - "hex.builtin.view.information.octet_stream_text": "", - "hex.builtin.view.information.octet_stream_warning": "", - "hex.builtin.view.information.plain_text": "", - "hex.builtin.view.information.plain_text_percentage": "", - "hex.builtin.view.information.provider_information": "", + "hex.builtin.information_section.magic.octet_stream_text": "", + "hex.builtin.information_section.magic.octet_stream_warning": "", + "hex.builtin.information_section.info_analysis.plain_text": "", + "hex.builtin.information_section.info_analysis.plain_text_percentage": "", + "hex.builtin.information_section.provider_information": "", "hex.builtin.view.information.region": "Regione Analizzata", "hex.builtin.view.logs.component": "", "hex.builtin.view.logs.log_level": "", diff --git a/plugins/builtin/romfs/lang/ja_JP.json b/plugins/builtin/romfs/lang/ja_JP.json index 0d2cf27fa..c8e08edb9 100644 --- a/plugins/builtin/romfs/lang/ja_JP.json +++ b/plugins/builtin/romfs/lang/ja_JP.json @@ -833,31 +833,31 @@ "hex.builtin.view.highlight_rules.no_rule": "", "hex.builtin.view.information.analyze": "表示中のページを解析する", "hex.builtin.view.information.analyzing": "解析中…", - "hex.builtin.view.information.apple_type": "", - "hex.builtin.view.information.block_size": "ブロックサイズ", - "hex.builtin.view.information.block_size.desc": "{0} ブロック/ {1} バイト", - "hex.builtin.view.information.byte_types": "", + "hex.builtin.information_section.magic.apple_type": "", + "hex.builtin.information_section.info_analysis.block_size": "ブロックサイズ", + "hex.builtin.information_section.info_analysis.block_size.desc": "{0} ブロック/ {1} バイト", + "hex.builtin.information_section.info_analysis.byte_types": "", "hex.builtin.view.information.control": "コントロール", - "hex.builtin.view.information.description": "詳細", - "hex.builtin.view.information.digram": "", - "hex.builtin.view.information.distribution": "バイト分布", - "hex.builtin.view.information.encrypted": "暗号化や圧縮を経たデータと推測されます。", - "hex.builtin.view.information.entropy": "エントロピー", - "hex.builtin.view.information.extension": "", - "hex.builtin.view.information.file_entropy": "", - "hex.builtin.view.information.highest_entropy": "最大エントロピーブロック", - "hex.builtin.view.information.info_analysis": "情報の分析", - "hex.builtin.view.information.layered_distribution": "", - "hex.builtin.view.information.lowest_entropy": "", - "hex.builtin.view.information.magic": "Magic情報", + "hex.builtin.information_section.magic.description": "詳細", + "hex.builtin.information_section.info_analysis.digram": "", + "hex.builtin.information_section.info_analysis.distribution": "バイト分布", + "hex.builtin.information_section.info_analysis.encrypted": "暗号化や圧縮を経たデータと推測されます。", + "hex.builtin.information_section.info_analysis.entropy": "エントロピー", + "hex.builtin.information_section.magic.extension": "", + "hex.builtin.information_section.info_analysis.file_entropy": "", + "hex.builtin.information_section.info_analysis.highest_entropy": "最大エントロピーブロック", + "hex.builtin.information_section.info_analysis": "情報の分析", + "hex.builtin.information_section.info_analysis.layered_distribution": "", + "hex.builtin.information_section.info_analysis.lowest_entropy": "", + "hex.builtin.information_section.magic": "Magic情報", "hex.builtin.view.information.magic_db_added": "Magicデータベースが追加されました。", - "hex.builtin.view.information.mime": "MIMEタイプ", + "hex.builtin.information_section.magic.mime": "MIMEタイプ", "hex.builtin.view.information.name": "データ解析", - "hex.builtin.view.information.octet_stream_text": "", - "hex.builtin.view.information.octet_stream_warning": "", - "hex.builtin.view.information.plain_text": "", - "hex.builtin.view.information.plain_text_percentage": "", - "hex.builtin.view.information.provider_information": "", + "hex.builtin.information_section.magic.octet_stream_text": "", + "hex.builtin.information_section.magic.octet_stream_warning": "", + "hex.builtin.information_section.info_analysis.plain_text": "", + "hex.builtin.information_section.info_analysis.plain_text_percentage": "", + "hex.builtin.information_section.provider_information": "", "hex.builtin.view.information.region": "解析する領域", "hex.builtin.view.logs.component": "", "hex.builtin.view.logs.log_level": "", diff --git a/plugins/builtin/romfs/lang/ko_KR.json b/plugins/builtin/romfs/lang/ko_KR.json index 51977c491..b567d996f 100644 --- a/plugins/builtin/romfs/lang/ko_KR.json +++ b/plugins/builtin/romfs/lang/ko_KR.json @@ -833,31 +833,31 @@ "hex.builtin.view.highlight_rules.no_rule": "규칙을 만들어 편집하세요", "hex.builtin.view.information.analyze": "페이지 분석", "hex.builtin.view.information.analyzing": "분석 중...", - "hex.builtin.view.information.apple_type": "", - "hex.builtin.view.information.block_size": "블록 크기", - "hex.builtin.view.information.block_size.desc": "{1}바이트 중 {0}블록", - "hex.builtin.view.information.byte_types": "바이트 유형", + "hex.builtin.information_section.magic.apple_type": "", + "hex.builtin.information_section.info_analysis.block_size": "블록 크기", + "hex.builtin.information_section.info_analysis.block_size.desc": "{1}바이트 중 {0}블록", + "hex.builtin.information_section.info_analysis.byte_types": "바이트 유형", "hex.builtin.view.information.control": "제어", - "hex.builtin.view.information.description": "설명", - "hex.builtin.view.information.digram": "다이어그램", - "hex.builtin.view.information.distribution": "바이트 분포", - "hex.builtin.view.information.encrypted": "이 데이터는 암호화 또는 압축되어 있을 가능성이 높습니다!", - "hex.builtin.view.information.entropy": "엔트로피", - "hex.builtin.view.information.extension": "", - "hex.builtin.view.information.file_entropy": "전체 엔트로피", - "hex.builtin.view.information.highest_entropy": "최고 블록 엔트로피", - "hex.builtin.view.information.info_analysis": "정보 분석", - "hex.builtin.view.information.layered_distribution": "계층화 분포", - "hex.builtin.view.information.lowest_entropy": "최저 블록 엔트로피", - "hex.builtin.view.information.magic": "Magic 정보", + "hex.builtin.information_section.magic.description": "설명", + "hex.builtin.information_section.info_analysis.digram": "다이어그램", + "hex.builtin.information_section.info_analysis.distribution": "바이트 분포", + "hex.builtin.information_section.info_analysis.encrypted": "이 데이터는 암호화 또는 압축되어 있을 가능성이 높습니다!", + "hex.builtin.information_section.info_analysis.entropy": "엔트로피", + "hex.builtin.information_section.magic.extension": "", + "hex.builtin.information_section.info_analysis.file_entropy": "전체 엔트로피", + "hex.builtin.information_section.info_analysis.highest_entropy": "최고 블록 엔트로피", + "hex.builtin.information_section.info_analysis": "정보 분석", + "hex.builtin.information_section.info_analysis.layered_distribution": "계층화 분포", + "hex.builtin.information_section.info_analysis.lowest_entropy": "최저 블록 엔트로피", + "hex.builtin.information_section.magic": "Magic 정보", "hex.builtin.view.information.magic_db_added": "Magic 데이터베이스 추가됨!", - "hex.builtin.view.information.mime": "MIME 유형", + "hex.builtin.information_section.magic.mime": "MIME 유형", "hex.builtin.view.information.name": "데이터 정보", - "hex.builtin.view.information.octet_stream_text": "알 수 없음", - "hex.builtin.view.information.octet_stream_warning": "application/octet-stream은 알 수 없는 데이터 유형을 나타냅니다.\n\n즉, 이 데이터는 알려진 형식이 아니기 때문에 연결된 MIME 유형이 없습니다.", - "hex.builtin.view.information.plain_text": "이 데이터는 일반 텍스트일 가능성이 높습니다.", - "hex.builtin.view.information.plain_text_percentage": "일반 텍스트 비율", - "hex.builtin.view.information.provider_information": "공급자 정보", + "hex.builtin.information_section.magic.octet_stream_text": "알 수 없음", + "hex.builtin.information_section.magic.octet_stream_warning": "application/octet-stream은 알 수 없는 데이터 유형을 나타냅니다.\n\n즉, 이 데이터는 알려진 형식이 아니기 때문에 연결된 MIME 유형이 없습니다.", + "hex.builtin.information_section.info_analysis.plain_text": "이 데이터는 일반 텍스트일 가능성이 높습니다.", + "hex.builtin.information_section.info_analysis.plain_text_percentage": "일반 텍스트 비율", + "hex.builtin.information_section.provider_information": "공급자 정보", "hex.builtin.view.information.region": "분석한 영역", "hex.builtin.view.logs.component": "컴포넌트", "hex.builtin.view.logs.log_level": "로그 수준", diff --git a/plugins/builtin/romfs/lang/pt_BR.json b/plugins/builtin/romfs/lang/pt_BR.json index 138227c8c..a7e7878fc 100644 --- a/plugins/builtin/romfs/lang/pt_BR.json +++ b/plugins/builtin/romfs/lang/pt_BR.json @@ -833,31 +833,31 @@ "hex.builtin.view.highlight_rules.no_rule": "", "hex.builtin.view.information.analyze": "Analisar Pagina", "hex.builtin.view.information.analyzing": "Analizando...", - "hex.builtin.view.information.apple_type": "", - "hex.builtin.view.information.block_size": "Block size", - "hex.builtin.view.information.block_size.desc": "{0} blocks of {1} bytes", - "hex.builtin.view.information.byte_types": "", + "hex.builtin.information_section.magic.apple_type": "", + "hex.builtin.information_section.info_analysis.block_size": "Block size", + "hex.builtin.information_section.info_analysis.block_size.desc": "{0} blocks of {1} bytes", + "hex.builtin.information_section.info_analysis.byte_types": "", "hex.builtin.view.information.control": "Controle", - "hex.builtin.view.information.description": "Descrição", - "hex.builtin.view.information.digram": "", - "hex.builtin.view.information.distribution": "Byte distribution", - "hex.builtin.view.information.encrypted": "Esses dados provavelmente estão criptografados ou compactados!", - "hex.builtin.view.information.entropy": "Entropy", - "hex.builtin.view.information.extension": "", - "hex.builtin.view.information.file_entropy": "", - "hex.builtin.view.information.highest_entropy": "Highest block entropy", - "hex.builtin.view.information.info_analysis": "Análise de Informações", - "hex.builtin.view.information.layered_distribution": "", - "hex.builtin.view.information.lowest_entropy": "", - "hex.builtin.view.information.magic": "Informação Mágica", + "hex.builtin.information_section.magic.description": "Descrição", + "hex.builtin.information_section.info_analysis.digram": "", + "hex.builtin.information_section.info_analysis.distribution": "Byte distribution", + "hex.builtin.information_section.info_analysis.encrypted": "Esses dados provavelmente estão criptografados ou compactados!", + "hex.builtin.information_section.info_analysis.entropy": "Entropy", + "hex.builtin.information_section.magic.extension": "", + "hex.builtin.information_section.info_analysis.file_entropy": "", + "hex.builtin.information_section.info_analysis.highest_entropy": "Highest block entropy", + "hex.builtin.information_section.info_analysis": "Análise de Informações", + "hex.builtin.information_section.info_analysis.layered_distribution": "", + "hex.builtin.information_section.info_analysis.lowest_entropy": "", + "hex.builtin.information_section.magic": "Informação Mágica", "hex.builtin.view.information.magic_db_added": "Magic database added!", - "hex.builtin.view.information.mime": "MIME Type", + "hex.builtin.information_section.magic.mime": "MIME Type", "hex.builtin.view.information.name": "Data Information", - "hex.builtin.view.information.octet_stream_text": "", - "hex.builtin.view.information.octet_stream_warning": "", - "hex.builtin.view.information.plain_text": "", - "hex.builtin.view.information.plain_text_percentage": "", - "hex.builtin.view.information.provider_information": "", + "hex.builtin.information_section.magic.octet_stream_text": "", + "hex.builtin.information_section.magic.octet_stream_warning": "", + "hex.builtin.information_section.info_analysis.plain_text": "", + "hex.builtin.information_section.info_analysis.plain_text_percentage": "", + "hex.builtin.information_section.provider_information": "", "hex.builtin.view.information.region": "Região analizada", "hex.builtin.view.logs.component": "", "hex.builtin.view.logs.log_level": "", diff --git a/plugins/builtin/romfs/lang/zh_CN.json b/plugins/builtin/romfs/lang/zh_CN.json index 17f13c4c2..7f7d8bb74 100644 --- a/plugins/builtin/romfs/lang/zh_CN.json +++ b/plugins/builtin/romfs/lang/zh_CN.json @@ -833,31 +833,31 @@ "hex.builtin.view.highlight_rules.no_rule": "", "hex.builtin.view.information.analyze": "分析", "hex.builtin.view.information.analyzing": "分析中...", - "hex.builtin.view.information.apple_type": "", - "hex.builtin.view.information.block_size": "块大小", - "hex.builtin.view.information.block_size.desc": "{0} 块 × {1} 字节", - "hex.builtin.view.information.byte_types": "字节类型", + "hex.builtin.information_section.magic.apple_type": "", + "hex.builtin.information_section.info_analysis.block_size": "块大小", + "hex.builtin.information_section.info_analysis.block_size.desc": "{0} 块 × {1} 字节", + "hex.builtin.information_section.info_analysis.byte_types": "字节类型", "hex.builtin.view.information.control": "控制", - "hex.builtin.view.information.description": "描述", - "hex.builtin.view.information.digram": "图", - "hex.builtin.view.information.distribution": "字节分布", - "hex.builtin.view.information.encrypted": "此数据似乎经过了加密或压缩!", - "hex.builtin.view.information.entropy": "熵", - "hex.builtin.view.information.extension": "", - "hex.builtin.view.information.file_entropy": "整体熵", - "hex.builtin.view.information.highest_entropy": "最高区块熵", - "hex.builtin.view.information.info_analysis": "信息分析", - "hex.builtin.view.information.layered_distribution": "分层分布", - "hex.builtin.view.information.lowest_entropy": "最低区块熵", - "hex.builtin.view.information.magic": "LibMagic 信息", + "hex.builtin.information_section.magic.description": "描述", + "hex.builtin.information_section.info_analysis.digram": "图", + "hex.builtin.information_section.info_analysis.distribution": "字节分布", + "hex.builtin.information_section.info_analysis.encrypted": "此数据似乎经过了加密或压缩!", + "hex.builtin.information_section.info_analysis.entropy": "熵", + "hex.builtin.information_section.magic.extension": "", + "hex.builtin.information_section.info_analysis.file_entropy": "整体熵", + "hex.builtin.information_section.info_analysis.highest_entropy": "最高区块熵", + "hex.builtin.information_section.info_analysis": "信息分析", + "hex.builtin.information_section.info_analysis.layered_distribution": "分层分布", + "hex.builtin.information_section.info_analysis.lowest_entropy": "最低区块熵", + "hex.builtin.information_section.magic": "LibMagic 信息", "hex.builtin.view.information.magic_db_added": "LibMagic 数据库已添加!", - "hex.builtin.view.information.mime": "MIME 类型", + "hex.builtin.information_section.magic.mime": "MIME 类型", "hex.builtin.view.information.name": "数据信息", - "hex.builtin.view.information.octet_stream_text": "未知", - "hex.builtin.view.information.octet_stream_warning": "application/octet-stream 表示未知的数据类型。\n\n这意味着该数据没有与之关联的 MIME 类型,因为它不是已知的格式。", - "hex.builtin.view.information.plain_text": "此数据很可能是纯文本。", - "hex.builtin.view.information.plain_text_percentage": "纯文本百分比", - "hex.builtin.view.information.provider_information": "提供者信息", + "hex.builtin.information_section.magic.octet_stream_text": "未知", + "hex.builtin.information_section.magic.octet_stream_warning": "application/octet-stream 表示未知的数据类型。\n\n这意味着该数据没有与之关联的 MIME 类型,因为它不是已知的格式。", + "hex.builtin.information_section.info_analysis.plain_text": "此数据很可能是纯文本。", + "hex.builtin.information_section.info_analysis.plain_text_percentage": "纯文本百分比", + "hex.builtin.information_section.provider_information": "提供者信息", "hex.builtin.view.information.region": "已分析区域", "hex.builtin.view.logs.component": "组件", "hex.builtin.view.logs.log_level": "日志等级", diff --git a/plugins/builtin/romfs/lang/zh_TW.json b/plugins/builtin/romfs/lang/zh_TW.json index 9238d5374..2f555e87c 100644 --- a/plugins/builtin/romfs/lang/zh_TW.json +++ b/plugins/builtin/romfs/lang/zh_TW.json @@ -833,31 +833,31 @@ "hex.builtin.view.highlight_rules.no_rule": "", "hex.builtin.view.information.analyze": "分析頁面", "hex.builtin.view.information.analyzing": "正在分析...", - "hex.builtin.view.information.apple_type": "", - "hex.builtin.view.information.block_size": "區塊大小", - "hex.builtin.view.information.block_size.desc": "{0} blocks of {1} bytes", - "hex.builtin.view.information.byte_types": "", + "hex.builtin.information_section.magic.apple_type": "", + "hex.builtin.information_section.info_analysis.block_size": "區塊大小", + "hex.builtin.information_section.info_analysis.block_size.desc": "{0} blocks of {1} bytes", + "hex.builtin.information_section.info_analysis.byte_types": "", "hex.builtin.view.information.control": "控制", - "hex.builtin.view.information.description": "說明", - "hex.builtin.view.information.digram": "", - "hex.builtin.view.information.distribution": "位元組分佈", - "hex.builtin.view.information.encrypted": "此資料很有可能經過加密或壓縮!", - "hex.builtin.view.information.entropy": "熵", - "hex.builtin.view.information.extension": "", - "hex.builtin.view.information.file_entropy": "", - "hex.builtin.view.information.highest_entropy": "Highest block entropy", - "hex.builtin.view.information.info_analysis": "資訊分析", - "hex.builtin.view.information.layered_distribution": "", - "hex.builtin.view.information.lowest_entropy": "", - "hex.builtin.view.information.magic": "Magic information", + "hex.builtin.information_section.magic.description": "說明", + "hex.builtin.information_section.info_analysis.digram": "", + "hex.builtin.information_section.info_analysis.distribution": "位元組分佈", + "hex.builtin.information_section.info_analysis.encrypted": "此資料很有可能經過加密或壓縮!", + "hex.builtin.information_section.info_analysis.entropy": "熵", + "hex.builtin.information_section.magic.extension": "", + "hex.builtin.information_section.info_analysis.file_entropy": "", + "hex.builtin.information_section.info_analysis.highest_entropy": "Highest block entropy", + "hex.builtin.information_section.info_analysis": "資訊分析", + "hex.builtin.information_section.info_analysis.layered_distribution": "", + "hex.builtin.information_section.info_analysis.lowest_entropy": "", + "hex.builtin.information_section.magic": "Magic information", "hex.builtin.view.information.magic_db_added": "Magic database added!", - "hex.builtin.view.information.mime": "MIME 類型", + "hex.builtin.information_section.magic.mime": "MIME 類型", "hex.builtin.view.information.name": "資料資訊", - "hex.builtin.view.information.octet_stream_text": "未知", - "hex.builtin.view.information.octet_stream_warning": "application/octet-stream denotes an unknown data type.\n\nThis means that this data has no MIME type associated with it because it's not in a known format.", - "hex.builtin.view.information.plain_text": "此資料很有可能是純文字。", - "hex.builtin.view.information.plain_text_percentage": "純文字比例", - "hex.builtin.view.information.provider_information": "提供者資訊", + "hex.builtin.information_section.magic.octet_stream_text": "未知", + "hex.builtin.information_section.magic.octet_stream_warning": "application/octet-stream denotes an unknown data type.\n\nThis means that this data has no MIME type associated with it because it's not in a known format.", + "hex.builtin.information_section.info_analysis.plain_text": "此資料很有可能是純文字。", + "hex.builtin.information_section.info_analysis.plain_text_percentage": "純文字比例", + "hex.builtin.information_section.provider_information": "提供者資訊", "hex.builtin.view.information.region": "Analyzed region", "hex.builtin.view.logs.component": "Component", "hex.builtin.view.logs.log_level": "記錄等級", diff --git a/plugins/builtin/source/content/data_information_sections.cpp b/plugins/builtin/source/content/data_information_sections.cpp new file mode 100644 index 000000000..a1b722610 --- /dev/null +++ b/plugins/builtin/source/content/data_information_sections.cpp @@ -0,0 +1,369 @@ +#include +#include +#include + +#include +#include +#include +#include + +namespace hex::plugin::builtin { + + class InformationProvider : public ContentRegistry::DataInformation::InformationSection { + public: + InformationProvider() : InformationSection("hex.builtin.information_section.provider_information") { } + ~InformationProvider() override = default; + + void process(Task &task, prv::Provider *provider, Region region) override { + hex::unused(task); + + m_provider = provider; + m_region = region; + } + + void reset() override { + m_provider = nullptr; + m_region = Region::Invalid(); + } + + void drawContent() override { + if (ImGui::BeginTable("information", 2, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoKeepColumnsVisible)) { + ImGui::TableSetupColumn("type"); + ImGui::TableSetupColumn("value", ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + + for (auto &[name, value] : m_provider->getDataDescription()) { + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted("{}", name); + ImGui::TableNextColumn(); + ImGuiExt::TextFormattedWrapped("{}", value); + } + + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted("{}", "hex.ui.common.region"_lang); + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted("0x{:X} - 0x{:X}", m_region.getStartAddress(), m_region.getEndAddress()); + + ImGui::EndTable(); + } + } + + private: + prv::Provider *m_provider = nullptr; + Region m_region = Region::Invalid(); + }; + + class InformationMagic : public ContentRegistry::DataInformation::InformationSection { + public: + InformationMagic() : InformationSection("hex.builtin.information_section.magic") { } + ~InformationMagic() override = default; + + void process(Task &task, prv::Provider *provider, Region region) override { + magic::compile(); + + task.update(); + + m_dataDescription = magic::getDescription(provider, region.getStartAddress()); + m_dataMimeType = magic::getMIMEType(provider, region.getStartAddress()); + m_dataAppleCreatorType = magic::getAppleCreatorType(provider, region.getStartAddress()); + m_dataExtensions = magic::getExtensions(provider, region.getStartAddress()); + } + + void drawContent() override { + if (!(m_dataDescription.empty() && m_dataMimeType.empty())) { + if (ImGui::BeginTable("magic", 2, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg)) { + ImGui::TableSetupColumn("type"); + ImGui::TableSetupColumn("value", ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + + if (!m_dataDescription.empty()) { + ImGui::TableNextColumn(); + ImGui::TextUnformatted("hex.builtin.information_section.magic.description"_lang); + ImGui::TableNextColumn(); + + if (m_dataDescription == "data") { + ImGuiExt::TextFormattedColored(ImVec4(0.92F, 0.25F, 0.2F, 1.0F), "{} ({})", "hex.builtin.information_section.magic.octet_stream_text"_lang, m_dataDescription); + } else { + ImGuiExt::TextFormattedWrapped("{}", m_dataDescription); + } + } + + if (!m_dataMimeType.empty()) { + ImGui::TableNextColumn(); + ImGui::TextUnformatted("hex.builtin.information_section.magic.mime"_lang); + ImGui::TableNextColumn(); + + if (m_dataMimeType.contains("application/octet-stream")) { + ImGuiExt::TextFormatted("{}", m_dataMimeType); + ImGui::SameLine(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGuiExt::HelpHover("hex.builtin.information_section.magic.octet_stream_warning"_lang); + ImGui::PopStyleVar(); + } else { + ImGuiExt::TextFormatted("{}", m_dataMimeType); + } + } + + if (!m_dataAppleCreatorType.empty()) { + ImGui::TableNextColumn(); + ImGui::TextUnformatted("hex.builtin.information_section.magic.apple_type"_lang); + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted("{}", m_dataAppleCreatorType); + } + + if (!m_dataExtensions.empty()) { + ImGui::TableNextColumn(); + ImGui::TextUnformatted("hex.builtin.information_section.magic.extension"_lang); + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted("{}", m_dataExtensions); + } + + ImGui::EndTable(); + } + + ImGui::NewLine(); + } + } + + void reset() override { + m_dataDescription.clear(); + m_dataMimeType.clear(); + m_dataAppleCreatorType.clear(); + m_dataExtensions.clear(); + } + + private: + std::string m_dataDescription; + std::string m_dataMimeType; + std::string m_dataAppleCreatorType; + std::string m_dataExtensions; + }; + + class InformationByteAnalysis : public ContentRegistry::DataInformation::InformationSection { + public: + InformationByteAnalysis() : InformationSection("hex.builtin.information_section.info_analysis", "", true) { } + ~InformationByteAnalysis() override = default; + + void process(Task &task, prv::Provider *provider, Region region) override { + if (m_inputChunkSize == 0) + m_inputChunkSize = 256; + + m_blockSize = std::max(std::ceil(region.getSize() / 2048.0F), 256); + + m_byteDistribution.reset(); + m_digram.reset(region.getSize()); + m_layeredDistribution.reset(region.getSize()); + m_byteTypesDistribution.reset(region.getStartAddress(), region.getEndAddress(), provider->getBaseAddress(), provider->getActualSize()); + m_chunkBasedEntropy.reset(m_inputChunkSize, region.getStartAddress(), region.getEndAddress(), + provider->getBaseAddress(), provider->getActualSize()); + + // Create a handle to the file + auto reader = prv::ProviderReader(provider); + reader.seek(region.getStartAddress()); + reader.setEndAddress(region.getEndAddress()); + + // Loop over each byte of the selection and update each analysis + // one byte at a time to process the file only once + for (u8 byte : reader) { + m_byteDistribution.update(byte); + m_byteTypesDistribution.update(byte); + m_chunkBasedEntropy.update(byte); + m_layeredDistribution.update(byte); + m_digram.update(byte); + task.update(); + } + + m_averageEntropy = m_chunkBasedEntropy.calculateEntropy(m_byteDistribution.get(), region.getSize()); + m_highestBlockEntropy = m_chunkBasedEntropy.getHighestEntropyBlockValue(); + m_highestBlockEntropyAddress = m_chunkBasedEntropy.getHighestEntropyBlockAddress(); + m_lowestBlockEntropy = m_chunkBasedEntropy.getLowestEntropyBlockValue(); + m_lowestBlockEntropyAddress = m_chunkBasedEntropy.getLowestEntropyBlockAddress(); + m_plainTextCharacterPercentage = m_byteTypesDistribution.getPlainTextCharacterPercentage(); + } + + void reset() override { + m_averageEntropy = -1.0; + m_highestBlockEntropy = -1.0; + m_plainTextCharacterPercentage = -1.0; + } + + void drawSettings() override { + ImGuiExt::InputHexadecimal("hex.builtin.information_section.info_analysis.block_size"_lang, &m_inputChunkSize); + } + + void drawContent() override { + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGui::GetColorU32(ImGuiCol_WindowBg)); + ImPlot::PushStyleColor(ImPlotCol_FrameBg, ImGui::GetColorU32(ImGuiCol_WindowBg)); + + // Display byte distribution analysis + ImGui::TextUnformatted("hex.builtin.information_section.info_analysis.distribution"_lang); + m_byteDistribution.draw( + ImVec2(-1, 0), + ImPlotFlags_NoLegend | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect + ); + + // Display byte types distribution analysis + ImGui::TextUnformatted("hex.builtin.information_section.info_analysis.byte_types"_lang); + m_byteTypesDistribution.draw( + ImVec2(-1, 0), + ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect, + true + ); + + // Display chunk-based entropy analysis + ImGui::TextUnformatted("hex.builtin.information_section.info_analysis.entropy"_lang); + m_chunkBasedEntropy.draw( + ImVec2(-1, 0), + ImPlotFlags_NoLegend | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect, + true + ); + + ImPlot::PopStyleColor(); + ImGui::PopStyleColor(); + + // Entropy information + if (ImGui::BeginTable("entropy_info", 2, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg)) { + ImGui::TableSetupColumn("type"); + ImGui::TableSetupColumn("value", ImGuiTableColumnFlags_WidthStretch); + + ImGui::TableNextRow(); + + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted("{}", "hex.builtin.information_section.info_analysis.block_size"_lang); + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted("hex.builtin.information_section.info_analysis.block_size.desc"_lang, m_chunkBasedEntropy.getSize(), m_chunkBasedEntropy.getChunkSize()); + + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted("{}", "hex.builtin.information_section.info_analysis.file_entropy"_lang); + ImGui::TableNextColumn(); + if (m_averageEntropy < 0) { + ImGui::TextUnformatted("???"); + } else { + auto entropy = std::abs(m_averageEntropy); + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.1F); + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGui::GetColorU32(ImGuiCol_TableRowBgAlt)); + ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImColor::HSV(0.3F - (0.3F * entropy), 0.6F, 0.8F, 1.0F).Value); + ImGui::ProgressBar(entropy, ImVec2(200_scaled, ImGui::GetTextLineHeight()), hex::format("{:.5f}", entropy).c_str()); + ImGui::PopStyleColor(2); + ImGui::PopStyleVar(); + } + + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted("{}", "hex.builtin.information_section.info_analysis.highest_entropy"_lang); + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted("{:.5f} @", m_highestBlockEntropy); + ImGui::SameLine(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + if (ImGui::Button(hex::format("0x{:06X}", m_highestBlockEntropyAddress).c_str())) { + ImHexApi::HexEditor::setSelection(m_highestBlockEntropyAddress, m_inputChunkSize); + } + ImGui::PopStyleColor(); + ImGui::PopStyleVar(); + + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted("{}", "hex.builtin.information_section.info_analysis.lowest_entropy"_lang); + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted("{:.5f} @", m_lowestBlockEntropy); + ImGui::SameLine(); + ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); + ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); + if (ImGui::Button(hex::format("0x{:06X}", m_lowestBlockEntropyAddress).c_str())) { + ImHexApi::HexEditor::setSelection(m_lowestBlockEntropyAddress, m_inputChunkSize); + } + ImGui::PopStyleColor(); + ImGui::PopStyleVar(); + + ImGui::TableNextColumn(); + ImGuiExt::TextFormatted("{}", "hex.builtin.information_section.info_analysis.plain_text_percentage"_lang); + ImGui::TableNextColumn(); + + if (m_plainTextCharacterPercentage < 0) { + ImGui::TextUnformatted("???"); + } else { + ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.1F); + ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGui::GetColorU32(ImGuiCol_TableRowBgAlt)); + ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImColor::HSV(0.3F * (m_plainTextCharacterPercentage / 100.0F), 0.8F, 0.6F, 1.0F).Value); + ImGui::ProgressBar(m_plainTextCharacterPercentage / 100.0F, ImVec2(200_scaled, ImGui::GetTextLineHeight())); + ImGui::PopStyleColor(2); + ImGui::PopStyleVar(); + } + + ImGui::EndTable(); + } + + // General information + if (ImGui::BeginTable("info", 1, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg)) { + ImGui::TableSetupColumn("value", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableNextRow(); + + if (m_averageEntropy > 0.83 && m_highestBlockEntropy > 0.9) { + ImGui::TableNextColumn(); + ImGuiExt::TextFormattedColored(ImVec4(0.92F, 0.25F, 0.2F, 1.0F), "{}", "hex.builtin.information_section.info_analysis.encrypted"_lang); + } + + if (m_plainTextCharacterPercentage > 95) { + ImGui::TableNextColumn(); + ImGuiExt::TextFormattedColored(ImVec4(0.92F, 0.25F, 0.2F, 1.0F), "{}", "hex.builtin.information_section.info_analysis.plain_text"_lang); + } + + ImGui::EndTable(); + } + + auto availableWidth = ImGui::GetContentRegionAvail().x; + ImGui::BeginGroup(); + { + ImGui::TextUnformatted("hex.builtin.information_section.info_analysis.digram"_lang); + m_digram.draw({ availableWidth, availableWidth }); + } + ImGui::EndGroup(); + + ImGui::BeginGroup(); + { + ImGui::TextUnformatted("hex.builtin.information_section.info_analysis.layered_distribution"_lang); + m_layeredDistribution.draw({ availableWidth, availableWidth }); + } + ImGui::EndGroup(); + } + + void load(const nlohmann::json &data) override { + InformationSection::load(data); + + m_inputChunkSize = data.value("block_size", 0); + } + + nlohmann::json store() override { + auto result = InformationSection::store(); + result["block_size"] = m_inputChunkSize; + + return result; + } + + private: + u32 m_inputChunkSize = 0; + + u32 m_blockSize = 0; + double m_averageEntropy = -1.0; + + double m_highestBlockEntropy = -1.0; + u64 m_highestBlockEntropyAddress = 0x00; + double m_lowestBlockEntropy = -1.0; + u64 m_lowestBlockEntropyAddress = 0x00; + double m_plainTextCharacterPercentage = -1.0; + + DiagramDigram m_digram; + DiagramLayeredDistribution m_layeredDistribution; + DiagramByteDistribution m_byteDistribution; + DiagramByteTypesDistribution m_byteTypesDistribution; + DiagramChunkBasedEntropyAnalysis m_chunkBasedEntropy; + }; + + void registerDataInformationSections() { + ContentRegistry::DataInformation::addInformationSection(); + ContentRegistry::DataInformation::addInformationSection(); + ContentRegistry::DataInformation::addInformationSection(); + } + +} diff --git a/plugins/builtin/source/content/file_handlers.cpp b/plugins/builtin/source/content/file_handlers.cpp index bc0e3a749..5bbb27e55 100644 --- a/plugins/builtin/source/content/file_handlers.cpp +++ b/plugins/builtin/source/content/file_handlers.cpp @@ -1,6 +1,7 @@ #include #include +#include namespace hex::plugin::builtin { @@ -18,6 +19,17 @@ namespace hex::plugin::builtin { return false; }); + + ContentRegistry::FileHandler::add({ ".mgc" }, [](const auto &path) { + for (const auto &destPath : fs::getDefaultPaths(fs::ImHexPath::Magic)) { + if (wolv::io::fs::copyFile(path, destPath / path.filename(), std::fs::copy_options::overwrite_existing)) { + ui::ToastInfo::open("hex.builtin.view.information.magic_db_added"_lang); + return true; + } + } + + return false; + }); } } \ No newline at end of file diff --git a/plugins/builtin/source/content/views/view_information.cpp b/plugins/builtin/source/content/views/view_information.cpp index 15e3fdf4d..a6557e198 100644 --- a/plugins/builtin/source/content/views/view_information.cpp +++ b/plugins/builtin/source/content/views/view_information.cpp @@ -4,16 +4,9 @@ #include #include -#include -#include #include -#include -#include - -#include - #include namespace hex::plugin::builtin { @@ -21,153 +14,53 @@ namespace hex::plugin::builtin { using namespace hex::literals; ViewInformation::ViewInformation() : View::Window("hex.builtin.view.information.name", ICON_VS_GRAPH_LINE) { - EventDataChanged::subscribe(this, [this](prv::Provider *provider) { - auto &analysis = m_analysis.get(provider); + m_analysisData.setOnCreateCallback([](prv::Provider *provider, AnalysisData &data) { + data.analyzedProvider = provider; - analysis.dataValid = false; - analysis.plainTextCharacterPercentage = -1.0; - analysis.averageEntropy = -1.0; - analysis.highestBlockEntropy = -1.0; - analysis.blockSize = 0; - analysis.dataMimeType.clear(); - analysis.dataDescription.clear(); - analysis.dataAppleCreatorType.clear(); - analysis.dataExtensions.clear(); - analysis.analyzedRegion = { 0, 0 }; - }); - - EventRegionSelected::subscribe(this, [this](ImHexApi::HexEditor::ProviderRegion region) { - auto &analysis = m_analysis.get(region.getProvider()); - - // Set the position of the diagram relative to the place where - // the user clicked inside the hex editor view - if (analysis.blockSize != 0) { - analysis.byteTypesDistribution->setHandlePosition(region.getStartAddress()); - analysis.chunkBasedEntropy->setHandlePosition(region.getStartAddress()); - } - }); - - ContentRegistry::FileHandler::add({ ".mgc" }, [](const auto &path) { - for (const auto &destPath : fs::getDefaultPaths(fs::ImHexPath::Magic)) { - if (wolv::io::fs::copyFile(path, destPath / path.filename(), std::fs::copy_options::overwrite_existing)) { - ui::ToastInfo::open("hex.builtin.view.information.magic_db_added"_lang); - return true; - } + for (const auto &informationSectionConstructor : ContentRegistry::DataInformation::impl::getInformationSectionConstructors()) { + data.informationSections.push_back(informationSectionConstructor()); } - - return false; - }); - - m_analysis.setOnCreateCallback([](prv::Provider *provider, AnalysisData &analysis) { - analysis.dataValid = false; - analysis.blockSize = 0; - analysis.averageEntropy = -1.0; - - analysis.lowestBlockEntropy = -1.0; - analysis.highestBlockEntropy = -1.0; - analysis.lowestBlockEntropyAddress = 0x00; - analysis.highestBlockEntropyAddress = 0x00; - - analysis.plainTextCharacterPercentage = -1.0; - - analysis.analysisRegion = { 0, 0 }; - analysis.analyzedRegion = { 0, 0 }; - analysis.analyzedProvider = provider; - - analysis.inputChunkSize = 0; - analysis.selectionType = ui::RegionType::EntireData; - - analysis.digram = std::make_shared(); - analysis.layeredDistribution = std::make_shared(); - analysis.byteDistribution = std::make_shared(); - analysis.byteTypesDistribution = std::make_shared(); - analysis.chunkBasedEntropy = std::make_shared(); - }); - } - - ViewInformation::~ViewInformation() { - EventDataChanged::unsubscribe(this); - EventRegionSelected::unsubscribe(this); - EventProviderOpened::unsubscribe(this); } void ViewInformation::analyze() { AchievementManager::unlockAchievement("hex.builtin.achievement.misc", "hex.builtin.achievement.misc.analyze_file.name"); auto provider = ImHexApi::Provider::get(); + auto &analysis = m_analysisData.get(provider); - m_analysis.get(provider).analyzerTask = TaskManager::createTask("hex.builtin.view.information.analyzing", 0, [this, provider](auto &task) { - auto &analysis = m_analysis.get(provider); - const auto ®ion = analysis.analysisRegion; + // Reset all sections + for (const auto §ion : analysis.informationSections) { + section->reset(); + section->markValid(false); + } - analysis.analyzedProvider = provider; + // Run analyzers for each section + analysis.task = TaskManager::createTask("hex.builtin.view.information.analyzing"_lang, analysis.informationSections.size(), [provider, &analysis](Task &task) { + u32 progress = 0; + for (const auto §ion : analysis.informationSections) { + // Only process the section if it is enabled + if (section->isEnabled()) { + // Set the section as analyzing so a spinner can be drawn + section->setAnalyzing(true); + ON_SCOPE_EXIT { section->setAnalyzing(false); }; - if ((region.getStartAddress() >= region.getEndAddress()) || (region.getEndAddress() > provider->getActualSize())) { - analysis.analyzedRegion = { provider->getBaseAddress(), provider->getActualSize() }; - } + try { + // Process the section + section->process(task, provider, analysis.analysisRegion); - if (analysis.inputChunkSize == 0) { - analysis.inputChunkSize = 256; - } - - task.setMaxValue(analysis.analyzedRegion.getSize()); - - { - magic::compile(); - - analysis.dataDescription = magic::getDescription(provider); - analysis.dataMimeType = magic::getMIMEType(provider); - analysis.dataAppleCreatorType = magic::getAppleCreatorType(provider); - analysis.dataExtensions = magic::getExtensions(provider); - } - - { - analysis.blockSize = std::max(std::ceil(provider->getActualSize() / 2048.0F), 256); - - analysis.averageEntropy = -1.0; - analysis.highestBlockEntropy = -1.0; - analysis.plainTextCharacterPercentage = -1.0; - - // Setup / start each analysis - - analysis.byteDistribution->reset(); - analysis.digram->reset(region.getSize()); - analysis.layeredDistribution->reset(region.getSize()); - analysis.byteTypesDistribution->reset(region.getStartAddress(), region.getEndAddress(), provider->getBaseAddress(), provider->getActualSize()); - analysis.chunkBasedEntropy->reset(analysis.inputChunkSize, region.getStartAddress(), region.getEndAddress(), - provider->getBaseAddress(), provider->getActualSize()); - - // Create a handle to the file - auto reader = prv::ProviderReader(provider); - reader.seek(region.getStartAddress()); - reader.setEndAddress(region.getEndAddress()); - - analysis.analyzedRegion = region; - - u64 count = 0; - - // Loop over each byte of the selection and update each analysis - // one byte at a time to process the file only once - for (u8 byte : reader) { - analysis.byteDistribution->update(byte); - analysis.byteTypesDistribution->update(byte); - analysis.chunkBasedEntropy->update(byte); - analysis.layeredDistribution->update(byte); - analysis.digram->update(byte); - ++count; - task.update(count); + // Mark the section as valid + section->markValid(); + } catch (const std::exception &e) { + // Show a toast with the error if the section failed to process + ui::ToastError::open(hex::format("hex.builtin.view.information.error_processing_section"_lang, Lang(section->getUnlocalizedName()), e.what())); + } } - analysis.averageEntropy = analysis.chunkBasedEntropy->calculateEntropy(analysis.byteDistribution->get(), analysis.analyzedRegion.getSize()); - analysis.highestBlockEntropy = analysis.chunkBasedEntropy->getHighestEntropyBlockValue(); - analysis.highestBlockEntropyAddress = analysis.chunkBasedEntropy->getHighestEntropyBlockAddress(); - analysis.lowestBlockEntropy = analysis.chunkBasedEntropy->getLowestEntropyBlockValue(); - analysis.lowestBlockEntropyAddress = analysis.chunkBasedEntropy->getLowestEntropyBlockAddress(); - analysis.plainTextCharacterPercentage = analysis.byteTypesDistribution->getPlainTextCharacterPercentage(); + // Update the task progress + progress += 1; + task.update(progress); } - - analysis.dataValid = true; }); } @@ -176,25 +69,52 @@ namespace hex::plugin::builtin { auto provider = ImHexApi::Provider::get(); if (ImHexApi::Provider::isValid() && provider->isReadable()) { - auto &analysis = m_analysis.get(provider); + auto &analysis = m_analysisData.get(provider); - ImGui::BeginDisabled(analysis.analyzerTask.isRunning()); + // Draw settings window + ImGui::BeginDisabled(analysis.task.isRunning()); ImGuiExt::BeginSubWindow("hex.ui.common.settings"_lang); { - if (ImGui::BeginTable("SettingsTable", 2, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingFixedSame, ImVec2(ImGui::GetContentRegionAvail().x, 0))) { - ImGui::TableSetupColumn("Left", ImGuiTableColumnFlags_WidthStretch, 0.5F); - ImGui::TableSetupColumn("Right", ImGuiTableColumnFlags_WidthStretch, 0.5F); + // Create a table so we can draw global settings on the left and section specific settings on the right + if (ImGui::BeginTable("SettingsTable", 2, ImGuiTableFlags_BordersInner | ImGuiTableFlags_SizingStretchProp, ImVec2(ImGui::GetContentRegionAvail().x, 0))) { + ImGui::TableSetupColumn("Left", ImGuiTableColumnFlags_WidthStretch, 0.3F); + ImGui::TableSetupColumn("Right", ImGuiTableColumnFlags_WidthStretch, 0.7F); + ImGui::TableNextRow(); + + // Draw global settings ImGui::TableNextColumn(); ui::regionSelectionPicker(&analysis.analysisRegion, provider, &analysis.selectionType, false); + // Draw analyzed section names ImGui::TableNextColumn(); - ImGuiExt::InputHexadecimal("hex.builtin.view.information.block_size"_lang, &analysis.inputChunkSize); + if (ImGui::BeginTable("AnalyzedSections", 1, ImGuiTableFlags_BordersInnerH, ImVec2(ImGui::GetContentRegionAvail().x, ImGui::GetTextLineHeightWithSpacing() * 5))) { + for (const auto §ion : analysis.informationSections | std::views::reverse) { + if (section->isEnabled() && (section->isValid() || section->isAnalyzing())) { + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::BeginDisabled(); + { + ImGui::TextUnformatted(Lang(section->getUnlocalizedName())); + + if (section->isAnalyzing()) { + ImGui::SameLine(); + ImGuiExt::TextSpinner(""); + } + } + ImGui::EndDisabled(); + } + } + + ImGui::EndTable(); + } ImGui::EndTable(); } ImGui::NewLine(); + // Draw the analyze button ImGui::SetCursorPosX(50_scaled); if (ImGuiExt::DimmedButton("hex.builtin.view.information.analyze"_lang, ImVec2(ImGui::GetContentRegionAvail().x - 50_scaled, 0))) this->analyze(); @@ -202,238 +122,89 @@ namespace hex::plugin::builtin { ImGuiExt::EndSubWindow(); ImGui::EndDisabled(); - if (analysis.analyzerTask.isRunning()) { + // Draw the analyzing spinner + if (analysis.task.isRunning()) { ImGuiExt::TextSpinner("hex.builtin.view.information.analyzing"_lang); } else { ImGui::NewLine(); } - if (!analysis.analyzerTask.isRunning() && analysis.dataValid && analysis.analyzedProvider != nullptr) { - - // Provider information - ImGuiExt::Header("hex.builtin.view.information.provider_information"_lang, true); - - if (ImGui::BeginTable("information", 2, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoKeepColumnsVisible)) { - ImGui::TableSetupColumn("type"); - ImGui::TableSetupColumn("value", ImGuiTableColumnFlags_WidthStretch); - - ImGui::TableNextRow(); - - for (auto &[name, value] : analysis.analyzedProvider->getDataDescription()) { - ImGui::TableNextColumn(); - ImGuiExt::TextFormatted("{}", name); - ImGui::TableNextColumn(); - ImGuiExt::TextFormattedWrapped("{}", value); - } - + if (analysis.analyzedProvider != nullptr) { + for (const auto §ion : analysis.informationSections) { ImGui::TableNextColumn(); - ImGuiExt::TextFormatted("{}", "hex.builtin.view.information.region"_lang); - ImGui::TableNextColumn(); - ImGuiExt::TextFormatted("0x{:X} - 0x{:X}", analysis.analyzedRegion.getStartAddress(), analysis.analyzedRegion.getEndAddress()); + ImGui::PushID(section.get()); - ImGui::EndTable(); - } + bool enabled = section->isEnabled(); - // Magic information - if (!(analysis.dataDescription.empty() && analysis.dataMimeType.empty())) { - ImGuiExt::Header("hex.builtin.view.information.magic"_lang); + ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f); + if (ImGui::BeginChild(Lang(section->getUnlocalizedName()), ImVec2(0, 0), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY, ImGuiWindowFlags_MenuBar)) { + if (ImGui::BeginMenuBar()) { - if (ImGui::BeginTable("magic", 2, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg)) { - ImGui::TableSetupColumn("type"); - ImGui::TableSetupColumn("value", ImGuiTableColumnFlags_WidthStretch); - - ImGui::TableNextRow(); - - if (!analysis.dataDescription.empty()) { - ImGui::TableNextColumn(); - ImGui::TextUnformatted("hex.builtin.view.information.description"_lang); - ImGui::TableNextColumn(); - - if (analysis.dataDescription == "data") { - ImGuiExt::TextFormattedColored(ImVec4(0.92F, 0.25F, 0.2F, 1.0F), "{} ({})", "hex.builtin.view.information.octet_stream_text"_lang, analysis.dataDescription); - } else { - ImGuiExt::TextFormattedWrapped("{}", analysis.dataDescription); - } - } - - if (!analysis.dataMimeType.empty()) { - ImGui::TableNextColumn(); - ImGui::TextUnformatted("hex.builtin.view.information.mime"_lang); - ImGui::TableNextColumn(); - - if (analysis.dataMimeType.contains("application/octet-stream")) { - ImGuiExt::TextFormatted("{}", analysis.dataMimeType); - ImGui::SameLine(); + // Draw the enable checkbox of the section + // This is specifically split out so the checkbox does not get disabled when the section is disabled + ImGui::BeginGroup(); + { + ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetStyle().FramePadding.y); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - ImGuiExt::HelpHover("hex.builtin.view.information.octet_stream_warning"_lang); + { + if (ImGui::Checkbox("##enabled", &enabled)) { + section->setEnabled(enabled); + } + } ImGui::PopStyleVar(); - } else { - ImGuiExt::TextFormatted("{}", analysis.dataMimeType); } + ImGui::EndGroup(); + + ImGui::SameLine(); + + // Draw the rest of the section header + ImGui::BeginDisabled(!enabled); + { + ImGui::TextUnformatted(Lang(section->getUnlocalizedName())); + ImGui::SameLine(); + if (auto description = section->getUnlocalizedDescription(); !description.empty()) { + ImGui::SameLine(); + ImGuiExt::HelpHover(Lang(description)); + } + + // Draw settings gear on the right + if (section->hasSettings()) { + ImGui::SameLine(0, ImGui::GetContentRegionAvail().x - ImGui::CalcTextSize(ICON_VS_SETTINGS_GEAR).x); + if (ImGuiExt::DimmedIconButton(ICON_VS_SETTINGS_GEAR, ImGui::GetStyleColorVec4(ImGuiCol_Text))) { + ImGui::OpenPopup("SectionSettings"); + } + + if (ImGui::BeginPopup("SectionSettings")) { + ImGuiExt::Header("hex.ui.common.settings"_lang, true); + section->drawSettings(); + ImGui::EndPopup(); + } + } + } + ImGui::EndDisabled(); + + ImGui::EndMenuBar(); } - if (!analysis.dataAppleCreatorType.empty()) { - ImGui::TableNextColumn(); - ImGui::TextUnformatted("hex.builtin.view.information.apple_type"_lang); - ImGui::TableNextColumn(); - ImGuiExt::TextFormatted("{}", analysis.dataAppleCreatorType); + // Draw the section content + ImGui::BeginDisabled(!enabled); + { + if (section->isValid()) + section->drawContent(); + else if (section->isAnalyzing()) + ImGuiExt::TextSpinner("hex.builtin.view.information.analyzing"_lang); + else + ImGuiExt::TextFormattedCenteredHorizontal("hex.builtin.view.information.not_analyzed"_lang); } - - if (!analysis.dataExtensions.empty()) { - ImGui::TableNextColumn(); - ImGui::TextUnformatted("hex.builtin.view.information.extension"_lang); - ImGui::TableNextColumn(); - ImGuiExt::TextFormatted("{}", analysis.dataExtensions); - } - - ImGui::EndTable(); + ImGui::EndDisabled(); } + ImGui::EndChild(); + ImGui::PopStyleVar(); + + ImGui::PopID(); ImGui::NewLine(); } - - // Information analysis - if (analysis.analyzedRegion.getSize() > 0) { - - ImGuiExt::Header("hex.builtin.view.information.info_analysis"_lang); - - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGui::GetColorU32(ImGuiCol_WindowBg)); - ImPlot::PushStyleColor(ImPlotCol_FrameBg, ImGui::GetColorU32(ImGuiCol_WindowBg)); - - // Display byte distribution analysis - ImGui::TextUnformatted("hex.builtin.view.information.distribution"_lang); - analysis.byteDistribution->draw( - ImVec2(-1, 0), - ImPlotFlags_NoLegend | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect - ); - - // Display byte types distribution analysis - ImGui::TextUnformatted("hex.builtin.view.information.byte_types"_lang); - analysis.byteTypesDistribution->draw( - ImVec2(-1, 0), - ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect, - true - ); - - // Display chunk-based entropy analysis - ImGui::TextUnformatted("hex.builtin.view.information.entropy"_lang); - analysis.chunkBasedEntropy->draw( - ImVec2(-1, 0), - ImPlotFlags_NoLegend | ImPlotFlags_NoMenus | ImPlotFlags_NoBoxSelect, - true - ); - - ImPlot::PopStyleColor(); - ImGui::PopStyleColor(); - - ImGui::NewLine(); - } - - // Entropy information - if (ImGui::BeginTable("entropy_info", 2, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg)) { - ImGui::TableSetupColumn("type"); - ImGui::TableSetupColumn("value", ImGuiTableColumnFlags_WidthStretch); - - ImGui::TableNextRow(); - - ImGui::TableNextColumn(); - ImGuiExt::TextFormatted("{}", "hex.builtin.view.information.block_size"_lang); - ImGui::TableNextColumn(); - ImGuiExt::TextFormatted("hex.builtin.view.information.block_size.desc"_lang, analysis.chunkBasedEntropy->getSize(), analysis.chunkBasedEntropy->getChunkSize()); - - ImGui::TableNextColumn(); - ImGuiExt::TextFormatted("{}", "hex.builtin.view.information.file_entropy"_lang); - ImGui::TableNextColumn(); - if (analysis.averageEntropy < 0) { - ImGui::TextUnformatted("???"); - } else { - auto entropy = std::abs(analysis.averageEntropy); - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.1F); - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGui::GetColorU32(ImGuiCol_TableRowBgAlt)); - ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImColor::HSV(0.3F - (0.3F * entropy), 0.6F, 0.8F, 1.0F).Value); - ImGui::ProgressBar(entropy, ImVec2(200_scaled, ImGui::GetTextLineHeight()), hex::format("{:.5f}", entropy).c_str()); - ImGui::PopStyleColor(2); - ImGui::PopStyleVar(); - } - - ImGui::TableNextColumn(); - ImGuiExt::TextFormatted("{}", "hex.builtin.view.information.highest_entropy"_lang); - ImGui::TableNextColumn(); - ImGuiExt::TextFormatted("{:.5f} @", analysis.highestBlockEntropy); - ImGui::SameLine(); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); - if (ImGui::Button(hex::format("0x{:06X}", analysis.highestBlockEntropyAddress).c_str())) { - ImHexApi::HexEditor::setSelection(analysis.highestBlockEntropyAddress, analysis.inputChunkSize); - } - ImGui::PopStyleColor(); - ImGui::PopStyleVar(); - - ImGui::TableNextColumn(); - ImGuiExt::TextFormatted("{}", "hex.builtin.view.information.lowest_entropy"_lang); - ImGui::TableNextColumn(); - ImGuiExt::TextFormatted("{:.5f} @", analysis.lowestBlockEntropy); - ImGui::SameLine(); - ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); - ImGui::PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); - if (ImGui::Button(hex::format("0x{:06X}", analysis.lowestBlockEntropyAddress).c_str())) { - ImHexApi::HexEditor::setSelection(analysis.lowestBlockEntropyAddress, analysis.inputChunkSize); - } - ImGui::PopStyleColor(); - ImGui::PopStyleVar(); - - ImGui::TableNextColumn(); - ImGuiExt::TextFormatted("{}", "hex.builtin.view.information.plain_text_percentage"_lang); - ImGui::TableNextColumn(); - if (analysis.plainTextCharacterPercentage < 0) { - ImGui::TextUnformatted("???"); - } else { - ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.1F); - ImGui::PushStyleColor(ImGuiCol_FrameBg, ImGui::GetColorU32(ImGuiCol_TableRowBgAlt)); - ImGui::PushStyleColor(ImGuiCol_PlotHistogram, ImColor::HSV(0.3F * (analysis.plainTextCharacterPercentage / 100.0F), 0.8F, 0.6F, 1.0F).Value); - ImGui::ProgressBar(analysis.plainTextCharacterPercentage / 100.0F, ImVec2(200_scaled, ImGui::GetTextLineHeight())); - ImGui::PopStyleColor(2); - ImGui::PopStyleVar(); - } - - ImGui::EndTable(); - } - - ImGui::NewLine(); - - // General information - if (ImGui::BeginTable("info", 1, ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg)) { - ImGui::TableSetupColumn("value", ImGuiTableColumnFlags_WidthStretch); - ImGui::TableNextRow(); - - if (analysis.averageEntropy > 0.83 && analysis.highestBlockEntropy > 0.9) { - ImGui::TableNextColumn(); - ImGuiExt::TextFormattedColored(ImVec4(0.92F, 0.25F, 0.2F, 1.0F), "{}", "hex.builtin.view.information.encrypted"_lang); - } - - if (analysis.plainTextCharacterPercentage > 95) { - ImGui::TableNextColumn(); - ImGuiExt::TextFormattedColored(ImVec4(0.92F, 0.25F, 0.2F, 1.0F), "{}", "hex.builtin.view.information.plain_text"_lang); - } - - ImGui::EndTable(); - } - - ImGui::BeginGroup(); - { - ImGui::TextUnformatted("hex.builtin.view.information.digram"_lang); - analysis.digram->draw(scaled(ImVec2(300, 300))); - } - ImGui::EndGroup(); - - ImGui::SameLine(); - - ImGui::BeginGroup(); - { - ImGui::TextUnformatted("hex.builtin.view.information.layered_distribution"_lang); - analysis.layeredDistribution->draw(scaled(ImVec2(300, 300))); - } - ImGui::EndGroup(); } } } diff --git a/plugins/builtin/source/plugin_builtin.cpp b/plugins/builtin/source/plugin_builtin.cpp index 69115e3e2..c9f0f9afe 100644 --- a/plugins/builtin/source/plugin_builtin.cpp +++ b/plugins/builtin/source/plugin_builtin.cpp @@ -40,6 +40,7 @@ namespace hex::plugin::builtin { void registerAchievements(); void registerReportGenerators(); void registerTutorials(); + void registerDataInformationSections(); void loadWorkspaces(); void addWindowDecoration(); @@ -112,6 +113,7 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") { registerAchievements(); registerReportGenerators(); registerTutorials(); + registerDataInformationSections(); loadWorkspaces(); addWindowDecoration(); createWelcomeScreen();