diff --git a/plugins/disassembler/include/content/views/view_disassembler.hpp b/plugins/disassembler/include/content/views/view_disassembler.hpp index 3a29f190a..ec87d974c 100644 --- a/plugins/disassembler/include/content/views/view_disassembler.hpp +++ b/plugins/disassembler/include/content/views/view_disassembler.hpp @@ -41,6 +41,7 @@ namespace hex::plugin::disasm { std::vector m_disassembly; void disassemble(); + void exportToFile(); }; } \ No newline at end of file diff --git a/plugins/disassembler/romfs/lang/de_DE.json b/plugins/disassembler/romfs/lang/de_DE.json index 187cd2d39..7257f25a4 100644 --- a/plugins/disassembler/romfs/lang/de_DE.json +++ b/plugins/disassembler/romfs/lang/de_DE.json @@ -17,6 +17,8 @@ "hex.disassembler.view.disassembler.bpf.classic": "Classic", "hex.disassembler.view.disassembler.bpf.extended": "Extended", "hex.disassembler.view.disassembler.disassemble": "Disassemble", + "hex.disassembler.view.disassembler.export": "Exportieren", + "hex.disassembler.view.disassembler.export.popup.error": "Der Export zur ASM-Datei ist fehlgeschlagen.", "hex.disassembler.view.disassembler.disassembling": "Disassemblen...", "hex.disassembler.view.disassembler.disassembly.address": "Adresse", "hex.disassembler.view.disassembler.disassembly.bytes": "Byte", diff --git a/plugins/disassembler/romfs/lang/en_US.json b/plugins/disassembler/romfs/lang/en_US.json index d380fe47b..ef44b96c5 100644 --- a/plugins/disassembler/romfs/lang/en_US.json +++ b/plugins/disassembler/romfs/lang/en_US.json @@ -17,6 +17,8 @@ "hex.disassembler.view.disassembler.bpf.classic": "Classic", "hex.disassembler.view.disassembler.bpf.extended": "Extended", "hex.disassembler.view.disassembler.disassemble": "Disassemble", + "hex.disassembler.view.disassembler.export": "Export instructions as...", + "hex.disassembler.view.disassembler.export.popup.error": "Failed to export to ASM file!", "hex.disassembler.view.disassembler.disassembling": "Disassembling...", "hex.disassembler.view.disassembler.disassembly.address": "Address", "hex.disassembler.view.disassembler.disassembly.bytes": "Byte", diff --git a/plugins/disassembler/source/content/views/view_disassembler.cpp b/plugins/disassembler/source/content/views/view_disassembler.cpp index 19904b202..2727df2f1 100644 --- a/plugins/disassembler/source/content/views/view_disassembler.cpp +++ b/plugins/disassembler/source/content/views/view_disassembler.cpp @@ -6,6 +6,7 @@ #include #include +#include using namespace std::literals::string_literals; @@ -92,6 +93,36 @@ namespace hex::plugin::disasm { }); } + void ViewDisassembler::exportToFile() { + TaskManager::createTask("hex.ui.common.processing"_lang, TaskManager::NoProgress, [this](auto &) { + TaskManager::doLater([this] { + fs::openFileBrowser(fs::DialogMode::Save, {}, [this](const std::fs::path &path) { + auto p = path; + if (p.extension() != ".asm") + p.replace_filename(hex::format("{}{}", p.filename().string(), ".asm")); + auto file = wolv::io::File(p, wolv::io::File::Mode::Create); + + if (!file.isValid()) { + ui::ToastError::open("hex.disassembler.view.disassembler.export.popup.error"_lang); + return; + } + + // As disassembly code can be quite long, we prefer writing each disassembled instruction to file + for (const Disassembly& d : m_disassembly) { + // We test for a "bugged" case that should never happen - the instruction should always have a mnemonic + if (d.mnemonic.empty()) + continue; + + if (d.operators.empty()) + file.writeString(hex::format("{}\n", d.mnemonic)); + else + file.writeString(hex::format("{} {}\n", d.mnemonic, d.operators)); + } + }); + }); + }); + } + void ViewDisassembler::drawContent() { auto provider = ImHexApi::Provider::get(); if (ImHexApi::Provider::isValid() && provider->isReadable()) { @@ -390,9 +421,18 @@ namespace hex::plugin::disasm { } ImGui::EndDisabled(); + // Draw export to file icon button + ImGui::SameLine(); + ImGui::BeginDisabled(m_disassemblerTask.isRunning() || m_disassembly.empty()); + { + if (ImGuiExt::DimmedIconButton(ICON_VS_EXPORT, ImGui::GetStyleColorVec4(ImGuiCol_Text))) + this->exportToFile(); + } + ImGui::EndDisabled(); + ImGuiExt::InfoTooltip("hex.disassembler.view.disassembler.export"_lang); + // Draw a spinner if the disassembler is running if (m_disassemblerTask.isRunning()) { - ImGui::SameLine(); ImGuiExt::TextSpinner("hex.disassembler.view.disassembler.disassembling"_lang); }