diff --git a/include/views/view_hexeditor.hpp b/include/views/view_hexeditor.hpp index 38eb1c153..dcf2c14af 100644 --- a/include/views/view_hexeditor.hpp +++ b/include/views/view_hexeditor.hpp @@ -67,6 +67,7 @@ namespace hex { enum class Language { C, Cpp, CSharp, Rust, Python, Java, JavaScript }; void copyBytes(); + void pasteBytes(); void copyString(); void copyLanguageArray(Language language); void copyHexView(); diff --git a/plugins/builtin/source/lang/de_DE.cpp b/plugins/builtin/source/lang/de_DE.cpp index 952bb6c08..9a114b982 100644 --- a/plugins/builtin/source/lang/de_DE.cpp +++ b/plugins/builtin/source/lang/de_DE.cpp @@ -186,9 +186,9 @@ namespace hex::plugin::builtin { { "hex.view.hexeditor.error.open", "Öffnen der Datei fehlgeschlagen!" }, { "hex.view.hexeditor.menu.edit.undo", "Rückgängig" }, { "hex.view.hexeditor.menu.edit.redo", "Wiederholen" }, - { "hex.view.hexeditor.menu.edit.copy", "Kopieren als..." }, - { "hex.view.hexeditor.copy.bytes", "Bytes" }, - { "hex.view.hexeditor.copy.hex", "Hex String" }, + { "hex.view.hexeditor.menu.edit.copy", "Kopieren" }, + { "hex.view.hexeditor.menu.edit.copy_as", "Kopieren als..." }, + { "hex.view.hexeditor.copy.hex", "String" }, { "hex.view.hexeditor.copy.c", "C Array" }, { "hex.view.hexeditor.copy.cpp", "C++ Array" }, { "hex.view.hexeditor.copy.csharp", "C# Array" }, @@ -198,6 +198,7 @@ namespace hex::plugin::builtin { { "hex.view.hexeditor.copy.js", "JavaScript Array" }, { "hex.view.hexeditor.copy.ascii", "ASCII Art" }, { "hex.view.hexeditor.copy.html", "HTML" }, + { "hex.view.hexeditor.menu.edit.paste", "Einfügen" }, { "hex.view.hexeditor.menu.edit.bookmark", "Lesezeichen erstellen" }, { "hex.view.hexeditor.menu.edit.set_base", "Basisadresse setzen" }, diff --git a/plugins/builtin/source/lang/en_US.cpp b/plugins/builtin/source/lang/en_US.cpp index 106f4d16f..231910821 100644 --- a/plugins/builtin/source/lang/en_US.cpp +++ b/plugins/builtin/source/lang/en_US.cpp @@ -186,9 +186,9 @@ namespace hex::plugin::builtin { { "hex.view.hexeditor.error.open", "Failed to open file!" }, { "hex.view.hexeditor.menu.edit.undo", "Undo" }, { "hex.view.hexeditor.menu.edit.redo", "Redo" }, - { "hex.view.hexeditor.menu.edit.copy", "Copy as..." }, - { "hex.view.hexeditor.copy.bytes", "Bytes" }, - { "hex.view.hexeditor.copy.hex", "Hex String" }, + { "hex.view.hexeditor.menu.edit.copy", "Copy" }, + { "hex.view.hexeditor.menu.edit.copy_as", "Copy as..." }, + { "hex.view.hexeditor.copy.hex", "String" }, { "hex.view.hexeditor.copy.c", "C Array" }, { "hex.view.hexeditor.copy.cpp", "C++ Array" }, { "hex.view.hexeditor.copy.csharp", "C# Array" }, @@ -198,6 +198,7 @@ namespace hex::plugin::builtin { { "hex.view.hexeditor.copy.js", "JavaScript Array" }, { "hex.view.hexeditor.copy.ascii", "ASCII Art" }, { "hex.view.hexeditor.copy.html", "HTML" }, + { "hex.view.hexeditor.menu.edit.paste", "Paste" }, { "hex.view.hexeditor.menu.edit.bookmark", "Create bookmark" }, { "hex.view.hexeditor.menu.edit.set_base", "Set base address" }, diff --git a/plugins/builtin/source/lang/it_IT.cpp b/plugins/builtin/source/lang/it_IT.cpp index 384e0ce8e..5f1cac6e5 100644 --- a/plugins/builtin/source/lang/it_IT.cpp +++ b/plugins/builtin/source/lang/it_IT.cpp @@ -186,9 +186,9 @@ namespace hex::plugin::builtin { { "hex.view.hexeditor.error.open", "Impossibile aprire il File!" }, { "hex.view.hexeditor.menu.edit.undo", "Annulla" }, { "hex.view.hexeditor.menu.edit.redo", "Ripeti" }, - { "hex.view.hexeditor.menu.edit.copy", "Copia come..." }, - { "hex.view.hexeditor.copy.bytes", "Bytes" }, - { "hex.view.hexeditor.copy.hex", "Stringa esadecimale" }, + { "hex.view.hexeditor.menu.edit.copy", "Copia" }, + { "hex.view.hexeditor.menu.edit.copy_as", "Copia come..." }, + { "hex.view.hexeditor.copy.hex", "Stringa" }, { "hex.view.hexeditor.copy.c", "C Array" }, { "hex.view.hexeditor.copy.cpp", "C++ Array" }, { "hex.view.hexeditor.copy.csharp", "C# Array" }, @@ -198,6 +198,7 @@ namespace hex::plugin::builtin { { "hex.view.hexeditor.copy.js", "JavaScript Array" }, { "hex.view.hexeditor.copy.ascii", "ASCII Art" }, { "hex.view.hexeditor.copy.html", "HTML" }, + { "hex.view.hexeditor.menu.edit.paste", "Incolla" }, { "hex.view.hexeditor.menu.edit.bookmark", "Crea segnalibro" }, { "hex.view.hexeditor.menu.edit.set_base", "Imposta indirizzo di base" }, diff --git a/source/views/view_hexeditor.cpp b/source/views/view_hexeditor.cpp index 6299b8b26..fcb489f8e 100644 --- a/source/views/view_hexeditor.cpp +++ b/source/views/view_hexeditor.cpp @@ -555,12 +555,15 @@ namespace hex { } else if (mods == GLFW_MOD_CONTROL && key == 'O') { View::doLater([]{ ImGui::OpenPopup("hex.view.hexeditor.open_file"_lang); }); return true; - } else if (mods == (GLFW_MOD_CONTROL | GLFW_MOD_ALT) && key == 'C') { + } else if (mods == GLFW_MOD_CONTROL && key == 'C') { this->copyBytes(); return true; } else if (mods == (GLFW_MOD_CONTROL | GLFW_MOD_SHIFT) && key == 'C') { this->copyString(); return true; + } else if (mods == GLFW_MOD_CONTROL && key == 'V') { + this->pasteBytes(); + return true; } return false; @@ -646,6 +649,46 @@ namespace hex { ImGui::SetClipboardText(str.c_str()); } + void ViewHexEditor::pasteBytes() { + auto provider = SharedData::currentProvider; + + 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); + + std::string clipboard = ImGui::GetClipboardText(); + + // Check for non-hex characters + bool isValidHexString = std::find_if(clipboard.begin(), clipboard.end(), [](char c) { + return !std::isxdigit(c) && !std::isspace(c); + }) == clipboard.end(); + + if (!isValidHexString) return; + + // Remove all whitespace + std::erase_if(clipboard, [](char c) { return std::isspace(c); }); + + // Only paste whole bytes + if (clipboard.length() % 2 != 0) return; + + // Convert hex string to bytes + std::vector buffer(clipboard.length() / 2, 0x00); + u32 stringIndex = 0; + for (u8 &byte : buffer) { + for (u8 i = 0; i < 2; i++) { + byte <<= 4; + + char c = clipboard[stringIndex]; + + if (c >= '0' && c <= '9') byte |= (c - '0'); + else if (c >= 'a' && c <= 'f') byte |= (c - 'a') + 0xA; + else if (c >= 'A' && c <= 'F') byte |= (c - 'A') + 0xA; + } + } + + // Write bytes + provider->write(start - provider->getBaseAddress(), buffer.data(), std::min(end - start + 1, buffer.size())); + } + void ViewHexEditor::copyString() { auto provider = SharedData::currentProvider; @@ -1104,9 +1147,14 @@ R"( if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.redo"_lang, "CTRL + Y", false, SharedData::currentProvider != nullptr)) SharedData::currentProvider->redo(); - if (ImGui::BeginMenu("hex.view.hexeditor.menu.edit.copy"_lang, this->m_memoryEditor.DataPreviewAddr != -1 && this->m_memoryEditor.DataPreviewAddrEnd != -1)) { - if (ImGui::MenuItem("hex.view.hexeditor.copy.bytes"_lang, "CTRL + ALT + C")) - this->copyBytes(); + ImGui::Separator(); + + bool bytesSelected = this->m_memoryEditor.DataPreviewAddr != -1 && this->m_memoryEditor.DataPreviewAddrEnd != -1; + + if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.copy"_lang, "CTRL + C", false, bytesSelected)) + this->copyBytes(); + + if (ImGui::BeginMenu("hex.view.hexeditor.menu.edit.copy_as"_lang, bytesSelected)) { if (ImGui::MenuItem("hex.view.hexeditor.copy.hex"_lang, "CTRL + SHIFT + C")) this->copyString(); @@ -1137,6 +1185,11 @@ R"( ImGui::EndMenu(); } + if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.paste"_lang, "CTRL + V", false, bytesSelected)) + this->pasteBytes(); + + ImGui::Separator(); + if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.bookmark"_lang, nullptr, false, this->m_memoryEditor.DataPreviewAddr != -1 && this->m_memoryEditor.DataPreviewAddrEnd != -1)) { auto base = SharedData::currentProvider->getBaseAddress();