mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-27 23:37:05 -05:00
feat: Added Hex Editor "Decode as Encoding" option
This commit is contained in:
@@ -27,10 +27,11 @@ namespace hex {
|
||||
EncodingFile& operator=(const EncodingFile &other);
|
||||
EncodingFile& operator=(EncodingFile &&other) noexcept;
|
||||
|
||||
[[nodiscard]] std::pair<std::string_view, size_t> getEncodingFor(std::span<u8> buffer) const;
|
||||
[[nodiscard]] std::pair<std::string_view, size_t> getEncodingFor(std::span<const u8> buffer) const;
|
||||
[[nodiscard]] u64 getEncodingLengthFor(std::span<u8> buffer) const;
|
||||
[[nodiscard]] u64 getShortestSequence() const { return m_shortestSequence; }
|
||||
[[nodiscard]] u64 getLongestSequence() const { return m_longestSequence; }
|
||||
[[nodiscard]] std::string decodeAll(std::span<const u8> buffer) const;
|
||||
|
||||
[[nodiscard]] bool valid() const { return m_valid; }
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ namespace hex {
|
||||
|
||||
|
||||
|
||||
std::pair<std::string_view, size_t> EncodingFile::getEncodingFor(std::span<u8> buffer) const {
|
||||
std::pair<std::string_view, size_t> EncodingFile::getEncodingFor(std::span<const u8> buffer) const {
|
||||
for (auto riter = m_mapping->crbegin(); riter != m_mapping->crend(); ++riter) {
|
||||
const auto &[size, mapping] = *riter;
|
||||
|
||||
@@ -116,6 +116,19 @@ namespace hex {
|
||||
return 1;
|
||||
}
|
||||
|
||||
std::string EncodingFile::decodeAll(std::span<const u8> buffer) const {
|
||||
std::string result;
|
||||
|
||||
while (!buffer.empty()) {
|
||||
const auto [character, size] = getEncodingFor(buffer);
|
||||
result += character;
|
||||
buffer = buffer.subspan(size);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
void EncodingFile::parse(const std::string &content) {
|
||||
m_tableContent = content;
|
||||
for (const auto &line : wolv::util::splitString(m_tableContent, "\n")) {
|
||||
|
||||
@@ -26,6 +26,9 @@ namespace hex::plugin::builtin {
|
||||
[[nodiscard]] virtual bool canBePinned() const { return false; }
|
||||
[[nodiscard]] bool isPinned() const { return m_isPinned; }
|
||||
void setPinned(const bool pinned) { m_isPinned = pinned; }
|
||||
|
||||
[[nodiscard]] virtual ImGuiWindowFlags getFlags() const { return ImGuiWindowFlags_AlwaysAutoResize; }
|
||||
|
||||
private:
|
||||
bool m_isPinned = false;
|
||||
};
|
||||
|
||||
@@ -877,6 +877,8 @@
|
||||
"hex.builtin.view.hex_editor.menu.edit.select_all": "Select all",
|
||||
"hex.builtin.view.hex_editor.menu.edit.set_base": "Set Base Address...",
|
||||
"hex.builtin.view.hex_editor.menu.edit.set_page_size": "Set Page Size...",
|
||||
"hex.builtin.view.hex_editor.menu.edit.decode_as_text": "Decode as Encoding",
|
||||
"hex.builtin.view.hex_editor.menu.edit.decoded_string.popup.title": "Decoded Text",
|
||||
"hex.builtin.view.hex_editor.menu.file.goto": "Go to address...",
|
||||
"hex.builtin.view.hex_editor.menu.file.skip_until": "Skip Until",
|
||||
"hex.builtin.view.hex_editor.menu.file.skip_until.previous_differing_byte": "Previous Differing Byte",
|
||||
|
||||
@@ -689,14 +689,7 @@ namespace hex::plugin::builtin {
|
||||
std::vector<u8> stringBuffer(std::min<size_t>(currSelection->size, 0x1000), 0x00);
|
||||
ImHexApi::Provider::get()->read(currSelection->address, stringBuffer.data(), stringBuffer.size());
|
||||
|
||||
u64 offset = 0;
|
||||
while (offset < stringBuffer.size()) {
|
||||
const auto [character, size] = encodingFile.getEncodingFor(std::span(stringBuffer).subspan(offset));
|
||||
value += character;
|
||||
offset += size;
|
||||
}
|
||||
copyValue = value;
|
||||
|
||||
copyValue = value = encodingFile.decodeAll(stringBuffer);
|
||||
|
||||
if (value.size() > MaxStringLength) {
|
||||
value.resize(MaxStringLength);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <content/popups/hex_editor/popup_hex_editor_find.hpp>
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
#include <hex/helpers/menu_items.hpp>
|
||||
#include <ui/text_editor.hpp>
|
||||
#include <wolv/literals.hpp>
|
||||
|
||||
using namespace std::literals::string_literals;
|
||||
@@ -545,6 +546,46 @@ namespace hex::plugin::builtin {
|
||||
std::function<void(const Region &selection, bool selectionCheck)> m_pasteCallback;
|
||||
};
|
||||
|
||||
class PopupDecodedString final : public ViewHexEditor::Popup {
|
||||
public:
|
||||
explicit PopupDecodedString(std::string decodedString) : m_decodedString(std::move(decodedString)) {
|
||||
}
|
||||
|
||||
void draw(ViewHexEditor *) override {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2());
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0F);
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4());
|
||||
|
||||
auto text = wolv::util::trim(wolv::util::wrapMonospacedString(
|
||||
m_decodedString,
|
||||
ImGui::CalcTextSize("M").x,
|
||||
std::max(100_scaled, ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ScrollbarSize - ImGui::GetStyle().FrameBorderSize)
|
||||
));
|
||||
|
||||
ImGui::InputTextMultiline(
|
||||
"##",
|
||||
text.data(),
|
||||
text.size() + 1,
|
||||
ImGui::GetContentRegionAvail(),
|
||||
ImGuiInputTextFlags_ReadOnly | ImGuiInputTextFlags_NoHorizontalScroll
|
||||
);
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleVar(2);
|
||||
}
|
||||
|
||||
[[nodiscard]] UnlocalizedString getTitle() const override {
|
||||
return "hex.builtin.view.hex_editor.menu.edit.decoded_string.popup.title";
|
||||
}
|
||||
|
||||
[[nodiscard]] bool canBePinned() const override { return true; }
|
||||
[[nodiscard]] ImGuiWindowFlags getFlags() const override { return ImGuiWindowFlags_None; }
|
||||
|
||||
private:
|
||||
std::string m_decodedString;
|
||||
ui::TextEditor m_editor;
|
||||
};
|
||||
|
||||
/* Hex Editor */
|
||||
|
||||
ViewHexEditor::ViewHexEditor() : View::Window("hex.builtin.view.hex_editor.name", ICON_VS_FILE_BINARY) {
|
||||
@@ -711,7 +752,7 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
if (m_currPopup != nullptr) {
|
||||
if (ImGui::Begin(fmt::format("##{}", m_currPopup->getTitle().get()).c_str(), &open, ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking)) {
|
||||
if (ImGui::Begin(fmt::format("##{}", m_currPopup->getTitle().get()).c_str(), &open, m_currPopup->getFlags() | ImGuiWindowFlags_NoDocking)) {
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
|
||||
this->closePopup();
|
||||
} else {
|
||||
@@ -1666,6 +1707,32 @@ namespace hex::plugin::builtin {
|
||||
},
|
||||
[] { return ImHexApi::HexEditor::isSelectionValid() && ImHexApi::Provider::isValid(); },
|
||||
this);
|
||||
|
||||
/* Decode as Text */
|
||||
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.hex_editor.menu.edit.decode_as_text" }, ICON_VS_CHAT_SPARKLE, 1960, Shortcut::None,
|
||||
[this] {
|
||||
const auto selection = ImHexApi::HexEditor::getSelection();
|
||||
|
||||
TaskManager::createTask("", TaskManager::NoProgress, [this, selection] {
|
||||
const auto &customEncoding = this->m_hexEditor.getCustomEncoding();
|
||||
if (!customEncoding.has_value())
|
||||
return;
|
||||
|
||||
std::vector<u8> buffer(selection->getSize());
|
||||
selection->getProvider()->read(selection->getStartAddress(), buffer.data(), buffer.size());
|
||||
|
||||
auto decodedString = customEncoding->decodeAll(buffer);
|
||||
TaskManager::doLater([this, decodedString = std::move(decodedString)]() mutable {
|
||||
this->openPopup<PopupDecodedString>(std::move(decodedString));
|
||||
});
|
||||
});
|
||||
},
|
||||
[this] {
|
||||
return ImHexApi::HexEditor::isSelectionValid() &&
|
||||
ImHexApi::Provider::isValid() &&
|
||||
this->m_hexEditor.getCustomEncoding().has_value();
|
||||
},
|
||||
this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user