mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-04-02 05:27:41 -05:00
api: Move copy-as data formatting code to builtin-plugin, add api for it
This commit is contained in:
189
plugins/builtin/source/content/data_formatters.cpp
Normal file
189
plugins/builtin/source/content/data_formatters.cpp
Normal file
@@ -0,0 +1,189 @@
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
|
||||
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<u8> buffer(0x1'0000, 0x00);
|
||||
for (u64 i = 0; i < size; i += buffer.size()) {
|
||||
size_t readSize = std::min<u64>(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<uint8_t, {0}> 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<u8> buffer(0x1'0000, 0x00);
|
||||
for (u64 byte = 0; byte < size; byte += buffer.size()) {
|
||||
size_t readSize = std::min<u64>(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 =
|
||||
"<div>\n"
|
||||
" <style type=\"text/css\">\n"
|
||||
" .offsetheader { color:#0000A0; line-height:200% }\n"
|
||||
" .offsetcolumn { color:#0000A0 }\n"
|
||||
" .hexcolumn { color:#000000 }\n"
|
||||
" .textcolumn { color:#000000 }\n"
|
||||
" </style>\n\n"
|
||||
" <code>\n"
|
||||
" <span class=\"offsetheader\">Hex View  00 01 02 03 04 05 06 07  08 09 0A 0B 0C 0D 0E 0F</span><br>\n";
|
||||
|
||||
|
||||
std::vector<u8> buffer(0x1'0000, 0x00);
|
||||
for (u64 byte = 0; byte < size; byte += buffer.size()) {
|
||||
size_t readSize = std::min<u64>(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(" <span class=\"offsetcolumn\">{0:08X}</span>  <span class=\"hexcolumn\">", 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 += "</span>  <span class=\"textcolumn\">";
|
||||
|
||||
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 += "</span><br>\n";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
result +=
|
||||
" </code>\n"
|
||||
"</div>\n";
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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<u8> 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<unsigned char, " + std::to_string(buffer.size()) + "> 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<u8> 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<u8> buffer(copySize, 0x00);
|
||||
provider->read(start + provider->getBaseAddress() + provider->getCurrentPageAddress(), buffer.data(), buffer.size());
|
||||
|
||||
std::string str =
|
||||
R"(
|
||||
<div>
|
||||
<style type="text/css">
|
||||
.offsetheader { color:#0000A0; line-height:200% }
|
||||
.offsetcolumn { color:#0000A0 }
|
||||
.hexcolumn { color:#000000 }
|
||||
.textcolumn { color:#000000 }
|
||||
</style>
|
||||
|
||||
<code>
|
||||
<span class="offsetheader">Hex View  00 01 02 03 04 05 06 07  08 09 0A 0B 0C 0D 0E 0F</span><br/>
|
||||
)";
|
||||
|
||||
|
||||
for (u32 col = start >> 4; col <= (end >> 4); col++) {
|
||||
str += hex::format(" <span class=\"offsetcolumn\">{0:08X}</span>  <span class=\"hexcolumn\">", 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 += "</span>  <span class=\"textcolumn\">";
|
||||
|
||||
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 += "</span><br/>\n";
|
||||
}
|
||||
|
||||
str +=
|
||||
R"(
|
||||
</code>
|
||||
</div>
|
||||
)";
|
||||
|
||||
|
||||
ImGui::SetClipboardText(str.c_str());
|
||||
}
|
||||
|
||||
static std::vector<std::pair<u64, u64>> findString(hex::prv::Provider* &provider, std::string string) {
|
||||
std::vector<std::pair<u64, u64>> 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();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user