From 91160b431140374e09b799a1a11b22e8bd1590c0 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Fri, 9 Sep 2022 20:13:49 +0200 Subject: [PATCH] fix: Copy as... function sometimes producing invalid results Fixes #738 --- .../source/content/data_formatters.cpp | 152 +++++++++--------- .../source/content/views/view_hex_editor.cpp | 19 ++- 2 files changed, 91 insertions(+), 80 deletions(-) diff --git a/plugins/builtin/source/content/data_formatters.cpp b/plugins/builtin/source/content/data_formatters.cpp index 5ab3a83b8..c3900200b 100644 --- a/plugins/builtin/source/content/data_formatters.cpp +++ b/plugins/builtin/source/content/data_formatters.cpp @@ -1,34 +1,40 @@ #include #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 "; + constexpr static auto NewLineIndent = "\n "; + constexpr static auto LineLength = 16; - std::string result = start; + std::string result; + result.reserve(start.size() + hex::format(byteFormat, 0x00).size() * size + + std::string(NewLineIndent).size() / LineLength + end.size()); - 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); + result += start; - for (u32 j = 0; j < readSize; j++) { - if (j % 0x10 == 0) - result += NewLineIndent; + auto reader = prv::BufferedReader(provider); + reader.seek(offset); + reader.setEndAddress(offset + size); - result += hex::format(byteFormat, buffer[j]); - } + for (u8 byte : reader) { + if ((offset % LineLength) == 0x00) + result += NewLineIndent; - // Remove trailing comma + result += hex::format(byteFormat, byte); + + offset++; + } + + // Remove trailing comma + if (provider->getActualSize() > 0) { result.pop_back(); result.pop_back(); } - result += "\n"; - result += end; + result += "\n" + end; return result; } @@ -64,44 +70,46 @@ namespace hex::plugin::builtin { }); ContentRegistry::DataFormatter::add("hex.builtin.view.hex_editor.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"; + constexpr static auto HeaderLine = "Hex View 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"; + std::string result; + result.reserve(std::string(HeaderLine).size() * size / 0x10); - 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); + result += HeaderLine; - const auto end = (offset + readSize) - 1; + auto reader = prv::BufferedReader(provider); + reader.seek(offset); + reader.setEndAddress((offset + size) - 1); - for (u32 col = offset >> 4; col <= (end >> 4); col++) { - result += hex::format("{0:08X} ", col << 4); - for (u64 i = 0; i < 16; i++) { + u64 address = offset & ~u64(0x0F); + std::string asciiRow; + for (u8 byte : reader) { + if ((address % 0x10) == 0) { + result += hex::format(" {}", asciiRow); + result += hex::format("\n{0:08X} ", address); - if ((col == (offset >> 4) && i < (offset & 0xF)) || (col == (end >> 4) && i > (end & 0xF))) + asciiRow.clear(); + + if (address == (offset & ~u64(0x0F))) { + for (u64 i = 0; i < (offset - address); i++) { result += " "; - else - result += hex::format("{0:02X} ", buffer[((col << 4) - offset) + i]); - - if ((i & 0xF) == 0x7) - result += " "; + asciiRow += " "; + } + address = offset; } + } + result += hex::format("{0:02X} ", byte); + asciiRow += std::isprint(byte) ? char(byte) : '.'; + if ((address % 0x10) == 0x07) 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"; - } + address++; } + + for (u32 i = 0; i < (0x10 - (address % 0x10)); i++) + result += " "; + result += hex::format(" {}", asciiRow); + return result; }); @@ -115,48 +123,46 @@ namespace hex::plugin::builtin { " .textcolumn { color:#000000 }\n" " \n\n" " \n" - " Hex View  00 01 02 03 04 05 06 07  08 09 0A 0B 0C 0D 0E 0F
\n"; + " Hex View  00 01 02 03 04 05 06 07  08 09 0A 0B 0C 0D 0E 0F"; + auto reader = prv::BufferedReader(provider); + reader.seek(offset); + reader.setEndAddress(offset + size); - 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); + u64 address = offset & ~u64(0x0F); + std::string asciiRow; + for (u8 byte : reader) { + if ((address % 0x10) == 0) { + result += hex::format(" {}", asciiRow); + result += hex::format("
\n {0:08X}  ", address); - const auto end = (offset + readSize) - 1; + asciiRow.clear(); - 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); + if (address == (offset & ~u64(0x0F))) { + for (u64 i = 0; i < (offset - address); i++) { + result += "   "; + asciiRow += " "; } + address = offset; } - result += "
\n"; + result += "
"; } + + result += hex::format("{0:02X} ", byte); + asciiRow += std::isprint(byte) ? char(byte) : '.'; + if ((address % 0x10) == 0x07) + result += " "; + + address++; } + for (u32 i = 0; i < (0x10 - (address % 0x10)); i++) + result += "   "; + result += asciiRow; + result += - "
\n" + "\n \n" "\n"; return result; diff --git a/plugins/builtin/source/content/views/view_hex_editor.cpp b/plugins/builtin/source/content/views/view_hex_editor.cpp index fc36d666b..6ea2dcc0a 100644 --- a/plugins/builtin/source/content/views/view_hex_editor.cpp +++ b/plugins/builtin/source/content/views/view_hex_editor.cpp @@ -1175,17 +1175,22 @@ namespace hex::plugin::builtin { } static void copyBytes(const Region &selection) { + constexpr static auto Format = "{0:02X} "; + auto provider = ImHexApi::Provider::get(); - std::vector buffer(selection.size, 0x00); - provider->read(selection.getStartAddress() + provider->getBaseAddress() + provider->getCurrentPageAddress(), buffer.data(), buffer.size()); + auto reader = prv::BufferedReader(provider); + reader.seek(selection.getStartAddress() + provider->getBaseAddress() + provider->getCurrentPageAddress()); + reader.setEndAddress(selection.getEndAddress() + provider->getBaseAddress() + provider->getCurrentPageAddress()); - std::string str; - for (const auto &byte : buffer) - str += hex::format("{0:02X} ", byte); - str.pop_back(); + std::string result; + result.reserve(fmt::format(Format, 0x00).size() * selection.getSize()); - ImGui::SetClipboardText(str.c_str()); + for (const auto &byte : reader) + result += fmt::format(Format, byte); + result.pop_back(); + + ImGui::SetClipboardText(result.c_str()); } static void pasteBytes(const Region &selection) {