diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index 76513d7c8..504b6e7c6 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -15,6 +15,7 @@ add_library(${PROJECT_NAME} SHARED source/content/ui_items.cpp source/content/providers.cpp source/content/views.cpp + source/content/data_formatters.cpp source/content/providers/file_provider.cpp source/content/providers/gdb_provider.cpp diff --git a/plugins/builtin/include/content/views/view_hexeditor.hpp b/plugins/builtin/include/content/views/view_hexeditor.hpp index 7f7e379e9..e8f51aca9 100644 --- a/plugins/builtin/include/content/views/view_hexeditor.hpp +++ b/plugins/builtin/include/content/views/view_hexeditor.hpp @@ -68,9 +68,6 @@ namespace hex::plugin::builtin { void copyBytes() const; void pasteBytes() const; void copyString() const; - void copyLanguageArray(Language language) const; - void copyHexView() const; - void copyHexViewHTML() const; void registerEvents(); void registerShortcuts(); diff --git a/plugins/builtin/source/content/data_formatters.cpp b/plugins/builtin/source/content/data_formatters.cpp new file mode 100644 index 000000000..637d3546f --- /dev/null +++ b/plugins/builtin/source/content/data_formatters.cpp @@ -0,0 +1,189 @@ +#include + +#include +#include + +namespace hex::plugin::builtin { + + static std::string formatLanguageArray(prv::Provider *provider, u64 offset, size_t size, const std::string &start, const std::string &byteFormat, const std::string &end) { + constexpr auto NewLineIndent = "\n "; + + std::string result = start; + + std::vector buffer(0x1'0000, 0x00); + for (u64 i = 0; i < size; i += buffer.size()) { + size_t readSize = std::min(buffer.size(), size - i); + provider->read(offset, buffer.data(), readSize); + + for (u32 j = 0; j < readSize; j++) { + if (j % 0x10 == 0) + result += NewLineIndent; + + result += hex::format(byteFormat, buffer[j]); + } + + // Remove trailing comma + result.pop_back(); result.pop_back(); + } + + result += "\n"; + result += end; + + return result; + } + + void registerDataFormatters() { + + ContentRegistry::DataFormatter::add("hex.builtin.view.hexeditor.copy.c", [](prv::Provider *provider, u64 offset, size_t size) { + return formatLanguageArray(provider, offset, size, + hex::format("const uint8_t data[{0}] = {{", size), + "0x{0:02X}, ", + "};"); + }); + + ContentRegistry::DataFormatter::add("hex.builtin.view.hexeditor.copy.cpp", [](prv::Provider *provider, u64 offset, size_t size) { + return formatLanguageArray(provider, offset, size, + hex::format("constexpr std::array data = {{", size), + "0x{0:02X}, ", + "};"); + }); + + ContentRegistry::DataFormatter::add("hex.builtin.view.hexeditor.copy.java", [](prv::Provider *provider, u64 offset, size_t size) { + return formatLanguageArray(provider, offset, size, + "final byte[] data = {", + "0x{0:02X}, ", + "};"); + }); + + ContentRegistry::DataFormatter::add("hex.builtin.view.hexeditor.copy.csharp", [](prv::Provider *provider, u64 offset, size_t size) { + return formatLanguageArray(provider, offset, size, + "const byte[] data = {", + "0x{0:02X}, ", + "};"); + }); + + ContentRegistry::DataFormatter::add("hex.builtin.view.hexeditor.copy.rust", [](prv::Provider *provider, u64 offset, size_t size) { + return formatLanguageArray(provider, offset, size, + hex::format("let data: [u8; 0x{0:02X}] = [", size), + "0x{0:02X}, ", + "];"); + }); + + ContentRegistry::DataFormatter::add("hex.builtin.view.hexeditor.copy.python", [](prv::Provider *provider, u64 offset, size_t size) { + return formatLanguageArray(provider, offset, size, + "data = bytes([", + "0x{0:02X}, ", + "]);"); + }); + + ContentRegistry::DataFormatter::add("hex.builtin.view.hexeditor.copy.js", [](prv::Provider *provider, u64 offset, size_t size) { + return formatLanguageArray(provider, offset, size, + "const data = new Uint8Array([", + "0x{0:02X}, ", + "]);"); + }); + + ContentRegistry::DataFormatter::add("hex.builtin.view.hexeditor.copy.ascii", [](prv::Provider *provider, u64 offset, size_t size) { + std::string result = "Hex View 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n\n"; + + std::vector buffer(0x1'0000, 0x00); + for (u64 byte = 0; byte < size; byte += buffer.size()) { + size_t readSize = std::min(buffer.size(), size - byte); + provider->read(offset, buffer.data(), readSize); + + const auto end = (offset + readSize) - 1; + + for (u32 col = offset >> 4; col <= (end >> 4); col++) { + result += hex::format("{0:08X} ", col << 4); + for (u64 i = 0 ; i < 16; i++) { + + if (col == (offset >> 4) && i < (offset & 0xF) || col == (end >> 4) && i > (end & 0xF)) + result += " "; + else + result += hex::format("{0:02X} ", buffer[((col << 4) - offset) + i]); + + if ((i & 0xF) == 0x7) + result += " "; + } + + result += " "; + + for (u64 i = 0 ; i < 16; i++) { + + if (col == (offset >> 4) && i < (offset & 0xF) || col == (end >> 4) && i > (end & 0xF)) + result += " "; + else { + u8 c = buffer[((col << 4) - offset) + i]; + char displayChar = (c < 32 || c >= 128) ? '.' : c; + result += hex::format("{0}", displayChar); + } + } + + result += "\n"; + } + + } + return result; + }); + + ContentRegistry::DataFormatter::add("hex.builtin.view.hexeditor.copy.html", [](prv::Provider *provider, u64 offset, size_t size) { + std::string result = + "
\n" + " \n\n" + " \n" + " Hex View  00 01 02 03 04 05 06 07  08 09 0A 0B 0C 0D 0E 0F
\n"; + + + std::vector buffer(0x1'0000, 0x00); + for (u64 byte = 0; byte < size; byte += buffer.size()) { + size_t readSize = std::min(buffer.size(), size - byte); + provider->read(offset, buffer.data(), readSize); + + const auto end = (offset + readSize) - 1; + + for (u32 col = offset >> 4; col <= (end >> 4); col++) { + result += hex::format(" {0:08X}  ", col << 4); + for (u64 i = 0 ; i < 16; i++) { + + if (col == (offset >> 4) && i < (offset & 0xF) || col == (end >> 4) && i > (end & 0xF)) + result += "   "; + else + result += hex::format("{0:02X} ", buffer[((col << 4) - offset) + i]); + + if ((i & 0xF) == 0x7) + result += " "; + } + + result += "  "; + + for (u64 i = 0 ; i < 16; i++) { + + if (col == (offset >> 4) && i < (offset & 0xF) || col == (end >> 4) && i > (end & 0xF)) + result += " "; + else { + u8 c = buffer[((col << 4) - offset) + i]; + char displayChar = (c < 32 || c >= 128) ? '.' : c; + result += hex::format("{0}", displayChar); + } + } + + result += "
\n"; + } + + } + + result += + "
\n" + "
\n"; + + return result; + }); + + } + +} \ No newline at end of file diff --git a/plugins/builtin/source/content/views/view_hexeditor.cpp b/plugins/builtin/source/content/views/view_hexeditor.cpp index 3d92aa380..11c2c26ee 100644 --- a/plugins/builtin/source/content/views/view_hexeditor.cpp +++ b/plugins/builtin/source/content/views/view_hexeditor.cpp @@ -741,226 +741,12 @@ namespace hex::plugin::builtin { size_t copySize = (end - start) + 1; std::string buffer(copySize, 0x00); - buffer.reserve(copySize + 1); + buffer.reserve(copySize); provider->read(start + provider->getBaseAddress() + provider->getCurrentPageAddress(), buffer.data(), copySize); ImGui::SetClipboardText(buffer.c_str()); } - void ViewHexEditor::copyLanguageArray(Language language) const { - auto provider = ImHexApi::Provider::get(); - - size_t start = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd); - size_t end = std::max(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd); - - size_t copySize = (end - start) + 1; - - std::vector buffer(copySize, 0x00); - provider->read(start + provider->getBaseAddress() + provider->getCurrentPageAddress(), buffer.data(), buffer.size()); - - std::string str; - switch (language) { - case Language::C: - str += "const unsigned char data[" + std::to_string(buffer.size()) + "] = { "; - - for (const auto &byte : buffer) - str += hex::format("0x{0:02X}, ", byte); - - // Remove trailing comma - str.pop_back(); - str.pop_back(); - - str += " };"; - break; - case Language::Cpp: - str += "constexpr std::array data = { "; - - for (const auto &byte : buffer) - str += hex::format("0x{0:02X}, ", byte); - - // Remove trailing comma - str.pop_back(); - str.pop_back(); - - str += " };"; - break; - case Language::Java: - str += "final byte[] data = { "; - - for (const auto &byte : buffer) - str += hex::format("0x{0:02X}, ", byte); - - // Remove trailing comma - str.pop_back(); - str.pop_back(); - - str += " };"; - break; - case Language::CSharp: - str += "const byte[] data = { "; - - for (const auto &byte : buffer) - str += hex::format("0x{0:02X}, ", byte); - - // Remove trailing comma - str.pop_back(); - str.pop_back(); - - str += " };"; - break; - case Language::Rust: - str += "let data: [u8; " + std::to_string(buffer.size()) + "] = [ "; - - for (const auto &byte : buffer) - str += hex::format("0x{0:02X}, ", byte); - - // Remove trailing comma - str.pop_back(); - str.pop_back(); - - str += " ];"; - break; - case Language::Python: - str += "data = bytes([ "; - - for (const auto &byte : buffer) - str += hex::format("0x{0:02X}, ", byte); - - // Remove trailing comma - str.pop_back(); - str.pop_back(); - - str += " ]);"; - break; - case Language::JavaScript: - str += "const data = new Uint8Array([ "; - - for (const auto &byte : buffer) - str += hex::format("0x{0:02X}, ", byte); - - // Remove trailing comma - str.pop_back(); - str.pop_back(); - - str += " ]);"; - break; - } - - ImGui::SetClipboardText(str.c_str()); - } - - void ViewHexEditor::copyHexView() const { - auto provider = ImHexApi::Provider::get(); - - size_t start = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd); - size_t end = std::max(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd); - - size_t copySize = (end - start) + 1; - - std::vector buffer(copySize, 0x00); - provider->read(start + provider->getBaseAddress() + provider->getCurrentPageAddress(), buffer.data(), buffer.size()); - - std::string str = "Hex View 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n\n"; - - - for (u32 col = start >> 4; col <= (end >> 4); col++) { - str += hex::format("{0:08X} ", col << 4); - for (u64 i = 0 ; i < 16; i++) { - - if (col == (start >> 4) && i < (start & 0xF) || col == (end >> 4) && i > (end & 0xF)) - str += " "; - else - str += hex::format("{0:02X} ", buffer[((col << 4) - start) + i]); - - if ((i & 0xF) == 0x7) - str += " "; - } - - str += " "; - - for (u64 i = 0 ; i < 16; i++) { - - if (col == (start >> 4) && i < (start & 0xF) || col == (end >> 4) && i > (end & 0xF)) - str += " "; - else { - u8 c = buffer[((col << 4) - start) + i]; - char displayChar = (c < 32 || c >= 128) ? '.' : c; - str += hex::format("{0}", displayChar); - } - } - - str += "\n"; - } - - - ImGui::SetClipboardText(str.c_str()); - } - - void ViewHexEditor::copyHexViewHTML() const { - auto provider = ImHexApi::Provider::get(); - - size_t start = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd); - size_t end = std::max(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd); - - size_t copySize = (end - start) + 1; - - std::vector buffer(copySize, 0x00); - provider->read(start + provider->getBaseAddress() + provider->getCurrentPageAddress(), buffer.data(), buffer.size()); - - std::string str = -R"( -
- - - - Hex View  00 01 02 03 04 05 06 07  08 09 0A 0B 0C 0D 0E 0F
-)"; - - - for (u32 col = start >> 4; col <= (end >> 4); col++) { - str += hex::format(" {0:08X}  ", col << 4); - for (u64 i = 0 ; i < 16; i++) { - - if (col == (start >> 4) && i < (start & 0xF) || col == (end >> 4) && i > (end & 0xF)) - str += "   "; - else - str += hex::format("{0:02X} ", buffer[((col << 4) - start) + i]); - - if ((i & 0xF) == 0x7) - str += " "; - } - - str += "  "; - - for (u64 i = 0 ; i < 16; i++) { - - if (col == (start >> 4) && i < (start & 0xF) || col == (end >> 4) && i > (end & 0xF)) - str += " "; - else { - u8 c = buffer[((col << 4) - start) + i]; - char displayChar = (c < 32 || c >= 128) ? '.' : c; - str += hex::format("{0}", displayChar); - } - } - - str += "
\n"; - } - - str += -R"( -
-
-)"; - - - ImGui::SetClipboardText(str.c_str()); - } - static std::vector> findString(hex::prv::Provider* &provider, std::string string) { std::vector> results; @@ -1208,27 +994,16 @@ R"( ImGui::Separator(); - if (ImGui::MenuItem("hex.builtin.view.hexeditor.copy.c"_lang)) - this->copyLanguageArray(Language::C); - if (ImGui::MenuItem("hex.builtin.view.hexeditor.copy.cpp"_lang)) - this->copyLanguageArray(Language::Cpp); - if (ImGui::MenuItem("hex.builtin.view.hexeditor.copy.csharp"_lang)) - this->copyLanguageArray(Language::CSharp); - if (ImGui::MenuItem("hex.builtin.view.hexeditor.copy.rust"_lang)) - this->copyLanguageArray(Language::Rust); - if (ImGui::MenuItem("hex.builtin.view.hexeditor.copy.python"_lang)) - this->copyLanguageArray(Language::Python); - if (ImGui::MenuItem("hex.builtin.view.hexeditor.copy.java"_lang)) - this->copyLanguageArray(Language::Java); - if (ImGui::MenuItem("hex.builtin.view.hexeditor.copy.js"_lang)) - this->copyLanguageArray(Language::JavaScript); + for (const auto&[unlocalizedName, callback] : ContentRegistry::DataFormatter::getEntries()) { + if (ImGui::MenuItem(LangEntry(unlocalizedName))) { + size_t start = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd); + size_t end = std::max(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd); - ImGui::Separator(); + size_t copySize = (end - start) + 1; - if (ImGui::MenuItem("hex.builtin.view.hexeditor.copy.ascii"_lang)) - this->copyHexView(); - if (ImGui::MenuItem("hex.builtin.view.hexeditor.copy.html"_lang)) - this->copyHexViewHTML(); + ImGui::SetClipboardText(callback(provider, start + provider->getBaseAddress() + provider->getCurrentPageAddress(), copySize).c_str()); + } + } ImGui::EndMenu(); } diff --git a/plugins/builtin/source/plugin_builtin.cpp b/plugins/builtin/source/plugin_builtin.cpp index 950a8db6f..05ba086e2 100644 --- a/plugins/builtin/source/plugin_builtin.cpp +++ b/plugins/builtin/source/plugin_builtin.cpp @@ -12,6 +12,7 @@ namespace hex::plugin::builtin { void registerSettings(); void registerDataProcessorNodes(); void registerProviders(); + void registerDataFormatters(); void addFooterItems(); void addToolbarItems(); @@ -35,6 +36,7 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") { registerSettings(); registerDataProcessorNodes(); registerProviders(); + registerDataFormatters(); addFooterItems(); addToolbarItems(); diff --git a/plugins/libimhex/include/hex/api/content_registry.hpp b/plugins/libimhex/include/hex/api/content_registry.hpp index 15f044f27..183acd1cc 100644 --- a/plugins/libimhex/include/hex/api/content_registry.hpp +++ b/plugins/libimhex/include/hex/api/content_registry.hpp @@ -253,6 +253,24 @@ namespace hex { const std::vector& getEntries(); } + + namespace DataFormatter { + + namespace impl { + + using Callback = std::function; + struct Entry { + std::string unlocalizedName; + Callback callback; + }; + + } + + void add(const std::string &unlocalizedName, const impl::Callback &callback); + + std::vector& getEntries(); + + } }; } \ No newline at end of file diff --git a/plugins/libimhex/include/hex/helpers/shared_data.hpp b/plugins/libimhex/include/hex/helpers/shared_data.hpp index 60664f616..43f937570 100644 --- a/plugins/libimhex/include/hex/helpers/shared_data.hpp +++ b/plugins/libimhex/include/hex/helpers/shared_data.hpp @@ -91,6 +91,8 @@ namespace hex { static u32 dataProcessorLinkIdCounter; static u32 dataProcessorAttrIdCounter; + static std::vector dataFormatters; + static std::list recentFilePaths; static int mainArgc; diff --git a/plugins/libimhex/source/api/content_registry.cpp b/plugins/libimhex/source/api/content_registry.cpp index cfcc1b8bd..1b7d18cb8 100644 --- a/plugins/libimhex/source/api/content_registry.cpp +++ b/plugins/libimhex/source/api/content_registry.cpp @@ -288,4 +288,19 @@ namespace hex { const std::vector &ContentRegistry::Provider::getEntries() { return SharedData::providerNames; } + + + + /* Data Formatters */ + + void ContentRegistry::DataFormatter::add(const std::string &unlocalizedName, const impl::Callback &callback) { + ContentRegistry::DataFormatter::getEntries().push_back({ + unlocalizedName, + callback + }); + } + + std::vector &ContentRegistry::DataFormatter::getEntries() { + return SharedData::dataFormatters; + } } \ No newline at end of file diff --git a/plugins/libimhex/source/helpers/shared_data.cpp b/plugins/libimhex/source/helpers/shared_data.cpp index 143277f0d..445bdc614 100644 --- a/plugins/libimhex/source/helpers/shared_data.cpp +++ b/plugins/libimhex/source/helpers/shared_data.cpp @@ -41,6 +41,8 @@ namespace hex { u32 SharedData::dataProcessorLinkIdCounter = 1; u32 SharedData::dataProcessorAttrIdCounter = 1; + std::vector SharedData::dataFormatters; + std::list SharedData::recentFilePaths; int SharedData::mainArgc;