diff --git a/lib/external/pattern_language b/lib/external/pattern_language index 86e4a8d4c..7d8d90fb2 160000 --- a/lib/external/pattern_language +++ b/lib/external/pattern_language @@ -1 +1 @@ -Subproject commit 86e4a8d4c0934412cf69713516a96f268f1d7e6d +Subproject commit 7d8d90fb2a421d0f47b3566584c976f061afe5ee diff --git a/lib/libimhex/CMakeLists.txt b/lib/libimhex/CMakeLists.txt index 0e9445a1e..e7c679b1e 100644 --- a/lib/libimhex/CMakeLists.txt +++ b/lib/libimhex/CMakeLists.txt @@ -70,4 +70,4 @@ elseif (APPLE) endif () target_link_libraries(libimhex PRIVATE ${FMT_LIBRARIES}) -target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} libpl ${MINIAUDIO_LIBRARIES} libwolv-utils libwolv-io libwolv-hash libwolv-net libwolv-containers) +target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} libpl libpl-gen ${MINIAUDIO_LIBRARIES} libwolv-utils libwolv-io libwolv-hash libwolv-net libwolv-containers) diff --git a/plugins/builtin/include/ui/pattern_drawer.hpp b/plugins/builtin/include/ui/pattern_drawer.hpp index dd01e5556..665f42526 100644 --- a/plugins/builtin/include/ui/pattern_drawer.hpp +++ b/plugins/builtin/include/ui/pattern_drawer.hpp @@ -2,15 +2,20 @@ #include #include + +#include + #include namespace hex::plugin::builtin::ui { class PatternDrawer : public pl::PatternVisitor { public: - PatternDrawer() = default; + PatternDrawer() { + this->m_formatters = pl::gen::fmt::createFormatters(); + } - void draw(const std::vector> &patterns, float height = 0.0F); + void draw(const std::vector> &patterns, pl::PatternLanguage *runtime = nullptr, float height = 0.0F); enum class TreeStyle { Default = 0, @@ -87,5 +92,7 @@ namespace hex::plugin::builtin::ui { bool m_favoritesUpdated = false; std::function m_selectionCallback = [](Region) { }; + + pl::gen::fmt::FormatterArray m_formatters; }; } \ No newline at end of file diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index a7307e516..2e133c37b 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -366,6 +366,7 @@ "hex.builtin.nodes.visualizer.layered_dist.header": "Layered Distribution", "hex.builtin.pattern_drawer.color": "Color", "hex.builtin.pattern_drawer.double_click": "Double-click to see more items", + "hex.builtin.pattern_drawer.export": "Export Patterns as...", "hex.builtin.pattern_drawer.favorites": "Favorites", "hex.builtin.pattern_drawer.local": "Local", "hex.builtin.pattern_drawer.offset": "Offset", diff --git a/plugins/builtin/source/content/views/view_pattern_data.cpp b/plugins/builtin/source/content/views/view_pattern_data.cpp index c83c20373..72bcef65c 100644 --- a/plugins/builtin/source/content/views/view_pattern_data.cpp +++ b/plugins/builtin/source/content/views/view_pattern_data.cpp @@ -44,7 +44,7 @@ namespace hex::plugin::builtin { this->m_shouldReset = false; } - this->m_patternDrawer.draw(runtime.getPatterns()); + this->m_patternDrawer.draw(runtime.getPatterns(), &runtime); } } } diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index 6d8685125..a9e4f6ce8 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -484,7 +484,7 @@ namespace hex::plugin::builtin { }(); if (*this->m_executionDone) - patternDrawer.draw(patterns, 150_scaled); + patternDrawer.draw(patterns, &runtime, 150_scaled); }; } diff --git a/plugins/builtin/source/ui/pattern_drawer.cpp b/plugins/builtin/source/ui/pattern_drawer.cpp index 81e319f13..05ae623b9 100644 --- a/plugins/builtin/source/ui/pattern_drawer.cpp +++ b/plugins/builtin/source/ui/pattern_drawer.cpp @@ -988,7 +988,7 @@ namespace hex::plugin::builtin::ui { } } - void PatternDrawer::draw(const std::vector> &patterns, float height) { + void PatternDrawer::draw(const std::vector> &patterns, pl::PatternLanguage *runtime, float height) { const auto treeStyleButton = [this](auto icon, TreeStyle style, const char *tooltip) { bool pushed = false; @@ -1010,7 +1010,7 @@ namespace hex::plugin::builtin::ui { this->resetEditing(); } - ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetTextLineHeightWithSpacing() * 5.5); + ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetTextLineHeightWithSpacing() * 7.5); if (ImGui::InputTextIcon("##Search", ICON_VS_FILTER, this->m_filterText)) { this->m_filter = parseRValueFilter(this->m_filterText); } @@ -1024,6 +1024,37 @@ namespace hex::plugin::builtin::ui { ImGui::SameLine(0, 0); treeStyleButton(ICON_VS_LIST_FLAT, TreeStyle::Flattened, "hex.builtin.pattern_drawer.tree_style.flattened"_lang); + ImGui::SameLine(0, 15_scaled); + + const auto startPos = ImGui::GetCursorPos(); + + ImGui::BeginDisabled(runtime == nullptr); + if (ImGui::DimmedIconButton(ICON_VS_EXPORT, ImGui::GetStyleColorVec4(ImGuiCol_Text))) { + ImGui::OpenPopup("ExportPatterns"); + } + ImGui::EndDisabled(); + + ImGui::InfoTooltip("hex.builtin.pattern_drawer.export"_lang); + + ImGui::SetNextWindowPos(ImGui::GetWindowPos() + ImVec2(startPos.x, ImGui::GetCursorPosY())); + if (ImGui::BeginPopup("ExportPatterns")) { + for (const auto &formatter : this->m_formatters) { + const auto &name = formatter->getName(); + const auto &extension = formatter->getFileExtension(); + + if (ImGui::MenuItem(name.c_str())) { + + fs::openFileBrowser(fs::DialogMode::Save, { { name.c_str(), extension.c_str() } }, [&](const std::fs::path &path) { + auto result = formatter->format(*runtime); + + wolv::io::File output(path, wolv::io::File::Mode::Create); + output.writeVector(result); + }); + } + } + ImGui::EndPopup(); + } + if (!this->m_favoritesUpdated) { this->m_favoritesUpdated = true;