2022-01-13 00:27:31 +01:00
|
|
|
#include <hex/api/content_registry.hpp>
|
2023-08-06 21:33:15 +02:00
|
|
|
#include <hex/api/achievement_manager.hpp>
|
2022-01-13 00:27:31 +01:00
|
|
|
|
|
|
|
#include <hex/providers/provider.hpp>
|
2022-09-09 20:13:49 +02:00
|
|
|
#include <hex/providers/buffered_reader.hpp>
|
2023-11-22 08:26:31 +01:00
|
|
|
|
2022-01-13 00:27:31 +01:00
|
|
|
#include <hex/helpers/fmt.hpp>
|
2022-09-13 23:48:47 +02:00
|
|
|
#include <hex/helpers/crypto.hpp>
|
2023-11-22 08:26:31 +01:00
|
|
|
#include <hex/helpers/utils.hpp>
|
2022-01-13 00:27:31 +01:00
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
#include <content/export_formatters/export_formatter_csv.hpp>
|
|
|
|
#include <content/export_formatters/export_formatter_tsv.hpp>
|
|
|
|
#include <content/export_formatters/export_formatter_json.hpp>
|
|
|
|
|
2022-01-13 00:27:31 +01:00
|
|
|
namespace hex::plugin::builtin {
|
|
|
|
|
2023-10-26 17:13:59 +02:00
|
|
|
static std::string formatLanguageArray(prv::Provider *provider, u64 offset, size_t size, const std::string &start, const std::string &byteFormat, const std::string &end, bool removeFinalDelimiter= false) {
|
2022-09-09 20:13:49 +02:00
|
|
|
constexpr static auto NewLineIndent = "\n ";
|
|
|
|
constexpr static auto LineLength = 16;
|
2022-01-13 00:27:31 +01:00
|
|
|
|
2022-09-09 20:13:49 +02:00
|
|
|
std::string result;
|
|
|
|
result.reserve(start.size() + hex::format(byteFormat, 0x00).size() * size + + std::string(NewLineIndent).size() / LineLength + end.size());
|
2022-01-13 00:27:31 +01:00
|
|
|
|
2022-09-09 20:13:49 +02:00
|
|
|
result += start;
|
2022-01-13 00:27:31 +01:00
|
|
|
|
2023-03-12 18:27:29 +01:00
|
|
|
auto reader = prv::ProviderReader(provider);
|
2022-09-09 20:13:49 +02:00
|
|
|
reader.seek(offset);
|
2022-09-16 08:30:28 +02:00
|
|
|
reader.setEndAddress(offset + size - 1);
|
2022-01-13 00:27:31 +01:00
|
|
|
|
2022-09-13 23:48:47 +02:00
|
|
|
u64 index = 0x00;
|
2022-09-09 20:13:49 +02:00
|
|
|
for (u8 byte : reader) {
|
2022-09-13 23:48:47 +02:00
|
|
|
if ((index % LineLength) == 0x00)
|
2022-09-09 20:13:49 +02:00
|
|
|
result += NewLineIndent;
|
|
|
|
|
|
|
|
result += hex::format(byteFormat, byte);
|
|
|
|
|
2022-09-13 23:48:47 +02:00
|
|
|
index++;
|
2022-09-09 20:13:49 +02:00
|
|
|
}
|
2022-01-13 00:27:31 +01:00
|
|
|
|
2023-10-26 17:13:59 +02:00
|
|
|
// Remove trailing delimiter if required
|
|
|
|
if (removeFinalDelimiter && size > 0) {
|
2022-01-24 20:53:17 +01:00
|
|
|
result.pop_back();
|
|
|
|
result.pop_back();
|
2022-01-13 00:27:31 +01:00
|
|
|
}
|
|
|
|
|
2022-09-09 20:13:49 +02:00
|
|
|
result += "\n" + end;
|
2022-01-13 00:27:31 +01:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
void registerDataFormatters() {
|
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
ContentRegistry::DataFormatter::addExportMenuEntry("hex.builtin.view.hex_editor.copy.c", [](prv::Provider *provider, u64 offset, size_t size) {
|
2022-01-24 20:53:17 +01:00
|
|
|
return formatLanguageArray(provider, offset, size, hex::format("const uint8_t data[{0}] = {{", size), "0x{0:02X}, ", "};");
|
2022-01-13 00:27:31 +01:00
|
|
|
});
|
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
ContentRegistry::DataFormatter::addExportMenuEntry("hex.builtin.view.hex_editor.copy.cpp", [](prv::Provider *provider, u64 offset, size_t size) {
|
2023-08-06 21:33:15 +02:00
|
|
|
AchievementManager::unlockAchievement("hex.builtin.achievement.hex_editor", "hex.builtin.achievement.hex_editor.copy_as.name");
|
|
|
|
|
2022-01-24 20:53:17 +01:00
|
|
|
return formatLanguageArray(provider, offset, size, hex::format("constexpr std::array<uint8_t, {0}> data = {{", size), "0x{0:02X}, ", "};");
|
2022-01-13 00:27:31 +01:00
|
|
|
});
|
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
ContentRegistry::DataFormatter::addExportMenuEntry("hex.builtin.view.hex_editor.copy.java", [](prv::Provider *provider, u64 offset, size_t size) {
|
2022-01-24 20:53:17 +01:00
|
|
|
return formatLanguageArray(provider, offset, size, "final byte[] data = {", "0x{0:02X}, ", "};");
|
2022-01-13 00:27:31 +01:00
|
|
|
});
|
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
ContentRegistry::DataFormatter::addExportMenuEntry("hex.builtin.view.hex_editor.copy.csharp", [](prv::Provider *provider, u64 offset, size_t size) {
|
2022-01-24 20:53:17 +01:00
|
|
|
return formatLanguageArray(provider, offset, size, "const byte[] data = {", "0x{0:02X}, ", "};");
|
2022-01-13 00:27:31 +01:00
|
|
|
});
|
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
ContentRegistry::DataFormatter::addExportMenuEntry("hex.builtin.view.hex_editor.copy.rust", [](prv::Provider *provider, u64 offset, size_t size) {
|
2022-01-24 20:53:17 +01:00
|
|
|
return formatLanguageArray(provider, offset, size, hex::format("let data: [u8; 0x{0:02X}] = [", size), "0x{0:02X}, ", "];");
|
2022-01-13 00:27:31 +01:00
|
|
|
});
|
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
ContentRegistry::DataFormatter::addExportMenuEntry("hex.builtin.view.hex_editor.copy.python", [](prv::Provider *provider, u64 offset, size_t size) {
|
2022-09-18 15:05:56 +02:00
|
|
|
return formatLanguageArray(provider, offset, size, "data = bytes([", "0x{0:02X}, ", "])");
|
2022-01-13 00:27:31 +01:00
|
|
|
});
|
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
ContentRegistry::DataFormatter::addExportMenuEntry("hex.builtin.view.hex_editor.copy.js", [](prv::Provider *provider, u64 offset, size_t size) {
|
2022-01-24 20:53:17 +01:00
|
|
|
return formatLanguageArray(provider, offset, size, "const data = new Uint8Array([", "0x{0:02X}, ", "]);");
|
2022-01-13 00:27:31 +01:00
|
|
|
});
|
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
ContentRegistry::DataFormatter::addExportMenuEntry("hex.builtin.view.hex_editor.copy.lua", [](prv::Provider *provider, u64 offset, size_t size) {
|
2022-09-13 23:48:47 +02:00
|
|
|
return formatLanguageArray(provider, offset, size, "data = {", "0x{0:02X}, ", "}");
|
|
|
|
});
|
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
ContentRegistry::DataFormatter::addExportMenuEntry("hex.builtin.view.hex_editor.copy.go", [](prv::Provider *provider, u64 offset, size_t size) {
|
2023-10-26 17:13:59 +02:00
|
|
|
return formatLanguageArray(provider, offset, size, "data := [...]byte{", "0x{0:02X}, ", "}", false);
|
2022-09-13 23:48:47 +02:00
|
|
|
});
|
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
ContentRegistry::DataFormatter::addExportMenuEntry("hex.builtin.view.hex_editor.copy.crystal", [](prv::Provider *provider, u64 offset, size_t size) {
|
2022-09-13 23:48:47 +02:00
|
|
|
return formatLanguageArray(provider, offset, size, "data = [", "0x{0:02X}, ", "] of UInt8");
|
|
|
|
});
|
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
ContentRegistry::DataFormatter::addExportMenuEntry("hex.builtin.view.hex_editor.copy.swift", [](prv::Provider *provider, u64 offset, size_t size) {
|
2022-09-13 23:48:47 +02:00
|
|
|
return formatLanguageArray(provider, offset, size, "let data: [Uint8] = [", "0x{0:02X}, ", "]");
|
|
|
|
});
|
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
ContentRegistry::DataFormatter::addExportMenuEntry("hex.builtin.view.hex_editor.copy.pascal", [](prv::Provider *provider, u64 offset, size_t size) {
|
2022-09-13 23:48:47 +02:00
|
|
|
return formatLanguageArray(provider, offset, size, hex::format("data: array[0..{0}] of Byte = (", size - 1), "${0:02X}, ", ")");
|
|
|
|
});
|
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
ContentRegistry::DataFormatter::addExportMenuEntry("hex.builtin.view.hex_editor.copy.base64", [](prv::Provider *provider, u64 offset, size_t size) {
|
2022-09-13 23:48:47 +02:00
|
|
|
std::vector<u8> data(size, 0x00);
|
|
|
|
provider->read(offset, data.data(), size);
|
|
|
|
|
|
|
|
auto result = crypt::encode64(data);
|
|
|
|
|
|
|
|
return std::string(result.begin(), result.end());
|
|
|
|
});
|
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
ContentRegistry::DataFormatter::addExportMenuEntry("hex.builtin.view.hex_editor.copy.hex_view", [](prv::Provider *provider, u64 offset, size_t size) {
|
2023-11-22 08:26:31 +01:00
|
|
|
return hex::generateHexView(offset, size, provider);
|
2022-01-13 00:27:31 +01:00
|
|
|
});
|
|
|
|
|
2024-06-18 22:57:55 +02:00
|
|
|
ContentRegistry::DataFormatter::addExportMenuEntry("hex.builtin.view.hex_editor.copy.html", [](prv::Provider *provider, u64 offset, size_t size) {
|
2022-01-13 00:27:31 +01:00
|
|
|
std::string result =
|
2022-01-24 20:53:17 +01:00
|
|
|
"<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"
|
2023-11-09 14:42:29 +01:00
|
|
|
" .zerobyte { color:#808080 }\n"
|
2022-01-24 20:53:17 +01:00
|
|
|
" </style>\n\n"
|
|
|
|
" <code>\n"
|
2022-09-09 20:13:49 +02:00
|
|
|
" <span class=\"offsetheader\">Hex View  00 01 02 03 04 05 06 07  08 09 0A 0B 0C 0D 0E 0F</span>";
|
2022-01-13 00:27:31 +01:00
|
|
|
|
2023-03-12 18:27:29 +01:00
|
|
|
auto reader = prv::ProviderReader(provider);
|
2022-09-09 20:13:49 +02:00
|
|
|
reader.seek(offset);
|
2022-09-16 08:30:28 +02:00
|
|
|
reader.setEndAddress((offset + size) - 1);
|
2022-01-13 00:27:31 +01:00
|
|
|
|
2022-09-09 20:13:49 +02:00
|
|
|
u64 address = offset & ~u64(0x0F);
|
|
|
|
std::string asciiRow;
|
|
|
|
for (u8 byte : reader) {
|
|
|
|
if ((address % 0x10) == 0) {
|
|
|
|
result += hex::format(" {}", asciiRow);
|
|
|
|
result += hex::format("<br>\n <span class=\"offsetcolumn\">{0:08X}</span>  <span class=\"hexcolumn\">", address);
|
2022-01-13 00:27:31 +01:00
|
|
|
|
2022-09-09 20:13:49 +02:00
|
|
|
asciiRow.clear();
|
2022-01-13 00:27:31 +01:00
|
|
|
|
2022-09-09 20:13:49 +02:00
|
|
|
if (address == (offset & ~u64(0x0F))) {
|
|
|
|
for (u64 i = 0; i < (offset - address); i++) {
|
|
|
|
result += "   ";
|
|
|
|
asciiRow += " ";
|
2022-01-13 00:27:31 +01:00
|
|
|
}
|
2022-09-09 20:13:49 +02:00
|
|
|
address = offset;
|
2022-01-13 00:27:31 +01:00
|
|
|
}
|
|
|
|
|
2022-09-09 20:13:49 +02:00
|
|
|
result += "</span>";
|
2022-01-13 00:27:31 +01:00
|
|
|
}
|
2022-09-09 20:13:49 +02:00
|
|
|
|
2023-11-09 14:42:29 +01:00
|
|
|
std::string tagStart, tagEnd;
|
|
|
|
if (byte == 0x00) {
|
|
|
|
tagStart = "<span class=\"zerobyte\">";
|
|
|
|
tagEnd = "</span>";
|
|
|
|
}
|
|
|
|
|
|
|
|
result += hex::format("{0}{2:02X}{1} ", tagStart, tagEnd, byte);
|
2022-09-09 20:13:49 +02:00
|
|
|
asciiRow += std::isprint(byte) ? char(byte) : '.';
|
|
|
|
if ((address % 0x10) == 0x07)
|
|
|
|
result += " ";
|
|
|
|
|
|
|
|
address++;
|
2022-01-13 00:27:31 +01:00
|
|
|
}
|
|
|
|
|
2023-11-09 14:42:29 +01:00
|
|
|
if (address % 0x10 != 0x00)
|
|
|
|
for (u32 i = 0; i < (0x10 - (address % 0x10)); i++)
|
|
|
|
result += "   ";
|
2022-09-09 20:13:49 +02:00
|
|
|
result += asciiRow;
|
|
|
|
|
2022-01-13 00:27:31 +01:00
|
|
|
result +=
|
2022-09-09 20:13:49 +02:00
|
|
|
"\n </code>\n"
|
2022-01-24 20:53:17 +01:00
|
|
|
"</div>\n";
|
2022-01-13 00:27:31 +01:00
|
|
|
|
|
|
|
return result;
|
|
|
|
});
|
2024-06-18 22:57:55 +02:00
|
|
|
|
|
|
|
ContentRegistry::DataFormatter::addFindExportFormatter("csv", "csv", [](const std::vector<ContentRegistry::DataFormatter::impl::FindOccurrence>& occurrences, const auto &transformFunc) {
|
|
|
|
export_fmt::ExportFormatterCsv formatter;
|
|
|
|
return formatter.format(occurrences, transformFunc);
|
|
|
|
});
|
|
|
|
|
|
|
|
ContentRegistry::DataFormatter::addFindExportFormatter("tsv", "tsv", [](const std::vector<ContentRegistry::DataFormatter::impl::FindOccurrence>& occurrences, const auto &transformFunc) {
|
|
|
|
export_fmt::ExportFormatterTsv formatter;
|
|
|
|
return formatter.format(occurrences, transformFunc);
|
|
|
|
});
|
|
|
|
|
|
|
|
ContentRegistry::DataFormatter::addFindExportFormatter("json", "json", [](const std::vector<ContentRegistry::DataFormatter::impl::FindOccurrence>& occurrences, const auto &transformFunc) {
|
|
|
|
export_fmt::ExportFormatterJson formatter;
|
|
|
|
return formatter.format(occurrences, transformFunc);
|
|
|
|
});
|
2022-01-13 00:27:31 +01:00
|
|
|
}
|
|
|
|
|
2023-11-22 08:26:31 +01:00
|
|
|
}
|