2021-12-07 22:47:41 +01:00
|
|
|
#include "content/views/view_hexeditor.hpp"
|
2020-11-10 21:31:04 +01:00
|
|
|
|
2021-01-20 20:16:24 +01:00
|
|
|
#include <hex/api/imhex_api.hpp>
|
2021-09-06 20:35:38 +02:00
|
|
|
#include <hex/providers/provider.hpp>
|
2021-02-03 11:54:41 +01:00
|
|
|
#include <hex/helpers/crypto.hpp>
|
2021-09-08 15:18:24 +02:00
|
|
|
#include <hex/helpers/file.hpp>
|
2022-01-13 14:34:19 +01:00
|
|
|
#include <hex/helpers/paths.hpp>
|
2021-12-07 22:47:41 +01:00
|
|
|
#include <hex/helpers/patches.hpp>
|
|
|
|
#include <hex/helpers/project_file_handler.hpp>
|
|
|
|
#include <hex/helpers/loader_script_handler.hpp>
|
2020-11-24 02:00:22 +01:00
|
|
|
|
2022-01-13 14:34:19 +01:00
|
|
|
#include <hex/pattern_language/pattern_data.hpp>
|
|
|
|
#include <content/providers/file_provider.hpp>
|
|
|
|
|
|
|
|
|
2021-08-29 14:18:45 +02:00
|
|
|
#include <GLFW/glfw3.h>
|
|
|
|
|
|
|
|
#include <nlohmann/json.hpp>
|
|
|
|
|
2020-11-24 02:00:22 +01:00
|
|
|
#undef __STRICT_ANSI__
|
|
|
|
#include <cstdio>
|
|
|
|
|
2022-01-09 21:27:59 +01:00
|
|
|
#include <thread>
|
2021-03-29 22:44:23 +02:00
|
|
|
#include <filesystem>
|
|
|
|
|
2021-07-27 21:07:36 +02:00
|
|
|
#if defined(OS_WINDOWS)
|
|
|
|
#include <windows.h>
|
|
|
|
#else
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
namespace hex::plugin::builtin {
|
2020-11-10 21:31:04 +01:00
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
ViewHexEditor::ViewHexEditor() : View("hex.builtin.view.hexeditor.name"_lang) {
|
2020-11-10 21:31:04 +01:00
|
|
|
|
2021-02-17 14:47:25 +01:00
|
|
|
this->m_searchStringBuffer.resize(0xFFF, 0x00);
|
|
|
|
this->m_searchHexBuffer.resize(0xFFF, 0x00);
|
|
|
|
|
2022-01-13 14:34:19 +01:00
|
|
|
ContentRegistry::FileHandler::add({ ".hexproj" }, [](const auto &path) {
|
|
|
|
return ProjectFile::load(path.string());
|
|
|
|
});
|
|
|
|
|
2020-11-10 21:31:04 +01:00
|
|
|
this->m_memoryEditor.ReadFn = [](const ImU8 *data, size_t off) -> ImU8 {
|
2021-09-21 02:29:54 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
2020-12-27 15:39:06 +01:00
|
|
|
if (!provider->isAvailable() || !provider->isReadable())
|
2020-11-10 21:31:04 +01:00
|
|
|
return 0x00;
|
|
|
|
|
|
|
|
ImU8 byte;
|
2021-12-09 21:10:24 +01:00
|
|
|
provider->read(off + provider->getBaseAddress() + provider->getCurrentPageAddress(), &byte, sizeof(ImU8));
|
2020-11-10 21:31:04 +01:00
|
|
|
|
|
|
|
return byte;
|
|
|
|
};
|
|
|
|
|
|
|
|
this->m_memoryEditor.WriteFn = [](ImU8 *data, size_t off, ImU8 d) -> void {
|
2021-09-21 02:29:54 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
2020-12-27 15:39:06 +01:00
|
|
|
if (!provider->isAvailable() || !provider->isWritable())
|
2020-11-10 21:31:04 +01:00
|
|
|
return;
|
|
|
|
|
2021-12-09 21:10:24 +01:00
|
|
|
provider->write(off + provider->getBaseAddress() + provider->getCurrentPageAddress(), &d, sizeof(ImU8));
|
2021-03-27 11:36:36 +01:00
|
|
|
EventManager::post<EventDataChanged>();
|
2020-11-30 00:03:12 +01:00
|
|
|
ProjectFile::markDirty();
|
2020-11-10 21:31:04 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
this->m_memoryEditor.HighlightFn = [](const ImU8 *data, size_t off, bool next) -> bool {
|
|
|
|
ViewHexEditor *_this = (ViewHexEditor *) data;
|
|
|
|
|
2021-01-03 02:37:37 +01:00
|
|
|
std::optional<u32> currColor, prevColor;
|
2021-01-13 14:11:23 +01:00
|
|
|
|
2021-12-09 21:10:24 +01:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
|
|
|
|
|
|
|
off += provider->getBaseAddress() + provider->getCurrentPageAddress();
|
2021-02-17 14:57:32 +01:00
|
|
|
|
2021-03-29 23:07:18 +02:00
|
|
|
u32 alpha = static_cast<u32>(_this->m_highlightAlpha) << 24;
|
|
|
|
|
2021-02-24 21:42:18 +01:00
|
|
|
for (const auto &[region, name, comment, color, locked] : ImHexApi::Bookmarks::getEntries()) {
|
2021-01-13 14:11:23 +01:00
|
|
|
if (off >= region.address && off < (region.address + region.size))
|
2021-03-29 23:07:18 +02:00
|
|
|
currColor = (color & 0x00FFFFFF) | alpha;
|
2021-01-13 14:11:23 +01:00
|
|
|
if ((off - 1) >= region.address && (off - 1) < (region.address + region.size))
|
2021-03-29 23:07:18 +02:00
|
|
|
prevColor = (color & 0x00FFFFFF) | alpha;
|
2021-01-13 14:11:23 +01:00
|
|
|
}
|
|
|
|
|
2022-01-12 22:02:47 +01:00
|
|
|
{
|
|
|
|
for (const auto &pattern : SharedData::patternData) {
|
|
|
|
auto child = pattern->getPattern(off);
|
|
|
|
if (child != nullptr) {
|
|
|
|
auto color = (child->getColor() & 0x00FFFFFF) | alpha;
|
|
|
|
currColor = currColor.has_value() ? ImAlphaBlendColors(color, currColor.value()) : color;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for (const auto &pattern : SharedData::patternData) {
|
|
|
|
auto child = pattern->getPattern(off - 1);
|
|
|
|
if (child != nullptr) {
|
|
|
|
auto color = (child->getColor() & 0x00FFFFFF) | alpha;
|
|
|
|
prevColor = prevColor.has_value() ? ImAlphaBlendColors(color, currColor.value()) : color;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2021-01-20 18:10:40 +01:00
|
|
|
}
|
2021-01-03 02:37:37 +01:00
|
|
|
|
|
|
|
if (next && prevColor != currColor) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-01-20 18:10:40 +01:00
|
|
|
if (currColor.has_value() && (currColor.value() & 0x00FFFFFF) != 0x00) {
|
2021-03-29 23:07:18 +02:00
|
|
|
_this->m_memoryEditor.HighlightColor = (currColor.value() & 0x00FFFFFF) | alpha;
|
2021-01-03 02:37:37 +01:00
|
|
|
return true;
|
2020-11-10 21:31:04 +01:00
|
|
|
}
|
|
|
|
|
2020-11-19 22:34:56 +01:00
|
|
|
_this->m_memoryEditor.HighlightColor = 0x60C08080;
|
2020-11-10 21:31:04 +01:00
|
|
|
return false;
|
|
|
|
};
|
2020-11-17 13:58:50 +01:00
|
|
|
|
2021-02-17 14:57:32 +01:00
|
|
|
this->m_memoryEditor.HoverFn = [](const ImU8 *data, size_t off) {
|
2021-01-13 16:45:31 +01:00
|
|
|
bool tooltipShown = false;
|
|
|
|
|
2021-09-21 02:29:54 +02:00
|
|
|
off += ImHexApi::Provider::get()->getBaseAddress();
|
2021-02-17 14:57:32 +01:00
|
|
|
|
2021-02-24 21:42:18 +01:00
|
|
|
for (const auto &[region, name, comment, color, locked] : ImHexApi::Bookmarks::getEntries()) {
|
2021-02-17 14:57:32 +01:00
|
|
|
if (off >= region.address && off < (region.address + region.size)) {
|
2021-01-13 16:45:31 +01:00
|
|
|
if (!tooltipShown) {
|
|
|
|
ImGui::BeginTooltip();
|
|
|
|
tooltipShown = true;
|
|
|
|
}
|
|
|
|
ImGui::ColorButton(name.data(), ImColor(color).Value);
|
|
|
|
ImGui::SameLine(0, 10);
|
|
|
|
ImGui::TextUnformatted(name.data());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (tooltipShown)
|
|
|
|
ImGui::EndTooltip();
|
|
|
|
};
|
|
|
|
|
2021-02-14 01:11:55 +01:00
|
|
|
this->m_memoryEditor.DecodeFn = [](const ImU8 *data, size_t addr) -> MemoryEditor::DecodeData {
|
|
|
|
ViewHexEditor *_this = (ViewHexEditor *) data;
|
|
|
|
|
|
|
|
if (_this->m_currEncodingFile.getLongestSequence() == 0)
|
|
|
|
return { ".", 1, 0xFFFF8000 };
|
|
|
|
|
2021-09-21 02:29:54 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
2021-02-14 01:11:55 +01:00
|
|
|
size_t size = std::min<size_t>(_this->m_currEncodingFile.getLongestSequence(), provider->getActualSize() - addr);
|
|
|
|
|
|
|
|
std::vector<u8> buffer(size);
|
2021-12-09 21:10:24 +01:00
|
|
|
provider->read(addr + provider->getBaseAddress() + provider->getCurrentPageAddress(), buffer.data(), size);
|
2021-02-14 01:11:55 +01:00
|
|
|
|
|
|
|
auto [decoded, advance] = _this->m_currEncodingFile.getEncodingFor(buffer);
|
|
|
|
|
|
|
|
ImColor color;
|
|
|
|
if (decoded.length() == 1 && std::isalnum(decoded[0])) color = 0xFFFF8000;
|
|
|
|
else if (decoded.length() == 1 && advance == 1) color = 0xFF0000FF;
|
|
|
|
else if (decoded.length() > 1 && advance == 1) color = 0xFF00FFFF;
|
|
|
|
else if (advance > 1) color = 0xFFFFFFFF;
|
|
|
|
else color = 0xFFFF8000;
|
|
|
|
|
|
|
|
return { std::string(decoded), advance, color };
|
|
|
|
};
|
|
|
|
|
2021-12-23 15:11:38 +01:00
|
|
|
registerEvents();
|
|
|
|
registerShortcuts();
|
2020-11-10 21:31:04 +01:00
|
|
|
}
|
|
|
|
|
2020-11-12 09:38:52 +01:00
|
|
|
ViewHexEditor::~ViewHexEditor() {
|
2021-09-08 15:18:24 +02:00
|
|
|
EventManager::unsubscribe<RequestOpenFile>(this);
|
2021-03-27 11:36:36 +01:00
|
|
|
EventManager::unsubscribe<RequestSelectionChange>(this);
|
|
|
|
EventManager::unsubscribe<EventProjectFileLoad>(this);
|
|
|
|
EventManager::unsubscribe<EventWindowClosing>(this);
|
|
|
|
EventManager::unsubscribe<RequestOpenWindow>(this);
|
2021-03-29 23:07:18 +02:00
|
|
|
EventManager::unsubscribe<EventSettingsChanged>(this);
|
2020-11-12 09:38:52 +01:00
|
|
|
}
|
2020-11-10 21:31:04 +01:00
|
|
|
|
2020-12-22 18:10:01 +01:00
|
|
|
void ViewHexEditor::drawContent() {
|
2021-09-21 02:29:54 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
2020-12-27 15:39:06 +01:00
|
|
|
|
2021-09-21 02:29:54 +02:00
|
|
|
size_t dataSize = (!ImHexApi::Provider::isValid() || !provider->isReadable()) ? 0x00 : provider->getSize();
|
2020-11-12 09:38:52 +01:00
|
|
|
|
2021-12-09 21:10:24 +01:00
|
|
|
this->m_memoryEditor.DrawWindow(View::toWindowName("hex.builtin.view.hexeditor.name").c_str(), &this->getWindowOpenState(), this, dataSize, dataSize == 0 ? 0x00 : provider->getBaseAddress() + provider->getCurrentPageAddress());
|
2020-11-12 09:38:52 +01:00
|
|
|
|
|
|
|
if (dataSize != 0x00) {
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::Begin(View::toWindowName("hex.builtin.view.hexeditor.name").c_str())) {
|
2020-11-22 19:43:35 +01:00
|
|
|
|
2021-01-30 22:39:06 +01:00
|
|
|
if (ImGui::IsMouseReleased(ImGuiMouseButton_Right) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows))
|
2021-02-11 23:09:45 +01:00
|
|
|
ImGui::OpenPopup("hex.menu.edit"_lang);
|
2020-11-22 19:43:35 +01:00
|
|
|
|
2021-02-11 23:09:45 +01:00
|
|
|
if (ImGui::BeginPopup("hex.menu.edit"_lang)) {
|
2021-01-10 23:59:36 +01:00
|
|
|
this->drawEditPopup();
|
|
|
|
ImGui::EndPopup();
|
|
|
|
}
|
2020-11-22 19:43:35 +01:00
|
|
|
|
2021-09-20 23:40:36 +02:00
|
|
|
if (provider->getPageCount() > 1) {
|
2022-01-11 23:05:02 +01:00
|
|
|
ImGui::NewLine();
|
2021-12-07 22:47:41 +01:00
|
|
|
|
2022-01-11 23:48:18 +01:00
|
|
|
auto linePos = ImGui::GetCursorPosY() - 15_scaled;
|
2020-11-22 19:43:35 +01:00
|
|
|
|
2022-01-11 23:05:02 +01:00
|
|
|
ImGui::SetCursorPosY(linePos);
|
2020-11-22 19:43:35 +01:00
|
|
|
|
2021-09-20 23:40:36 +02:00
|
|
|
if (ImGui::ArrowButton("prevPage", ImGuiDir_Left)) {
|
|
|
|
provider->setCurrentPage(provider->getCurrentPage() - 1);
|
|
|
|
|
|
|
|
EventManager::post<EventRegionSelected>(Region { std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd), 1 });
|
|
|
|
}
|
2021-01-10 23:59:36 +01:00
|
|
|
|
2021-09-20 23:40:36 +02:00
|
|
|
ImGui::SameLine();
|
2021-01-10 23:59:36 +01:00
|
|
|
|
2021-09-20 23:40:36 +02:00
|
|
|
if (ImGui::ArrowButton("nextPage", ImGuiDir_Right)) {
|
|
|
|
provider->setCurrentPage(provider->getCurrentPage() + 1);
|
2020-11-22 19:43:35 +01:00
|
|
|
|
2021-09-20 23:40:36 +02:00
|
|
|
EventManager::post<EventRegionSelected>(Region { std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd), 1 });
|
|
|
|
}
|
2022-01-11 23:05:02 +01:00
|
|
|
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
|
|
|
ImGui::SameLine();
|
|
|
|
ImGui::SetCursorPosY(linePos);
|
|
|
|
|
|
|
|
ImGui::TextFormatted("hex.builtin.view.hexeditor.page"_lang, provider->getCurrentPage() + 1, provider->getPageCount());
|
2021-01-10 23:59:36 +01:00
|
|
|
}
|
2021-09-20 23:40:36 +02:00
|
|
|
|
2021-09-28 12:34:55 +02:00
|
|
|
this->drawSearchPopup();
|
|
|
|
this->drawGotoPopup();
|
|
|
|
|
2021-01-10 23:59:36 +01:00
|
|
|
}
|
2020-11-22 19:43:35 +01:00
|
|
|
ImGui::End();
|
2020-11-12 09:38:52 +01:00
|
|
|
}
|
2021-02-07 14:29:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void save() {
|
2021-09-21 02:29:54 +02:00
|
|
|
ImHexApi::Provider::get()->save();
|
2021-02-07 14:29:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static void saveAs() {
|
2021-12-07 22:47:41 +01:00
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.save_as"_lang, DialogMode::Save, { }, [](auto path) {
|
2021-09-21 02:29:54 +02:00
|
|
|
ImHexApi::Provider::get()->saveAs(path);
|
2021-02-07 14:29:13 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void ViewHexEditor::drawAlwaysVisible() {
|
2021-09-21 02:29:54 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
2020-11-24 02:59:49 +01:00
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginPopupModal("hex.builtin.view.hexeditor.exit_application.title"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
2020-11-30 00:03:12 +01:00
|
|
|
ImGui::NewLine();
|
2021-12-07 22:47:41 +01:00
|
|
|
ImGui::TextUnformatted("hex.builtin.view.hexeditor.exit_application.desc"_lang);
|
2020-12-11 14:24:42 +01:00
|
|
|
ImGui::NewLine();
|
|
|
|
|
2021-03-27 11:36:36 +01:00
|
|
|
confirmButtons("hex.common.yes"_lang, "hex.common.no"_lang, [] {
|
2021-08-21 13:55:21 +02:00
|
|
|
ImHexApi::Common::closeImHex(true);
|
2021-03-27 11:36:36 +01:00
|
|
|
},
|
|
|
|
[] {
|
|
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
});
|
2021-01-14 17:01:44 +01:00
|
|
|
|
|
|
|
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape)))
|
|
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
|
2020-11-30 00:03:12 +01:00
|
|
|
ImGui::EndPopup();
|
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginPopupModal("hex.builtin.view.hexeditor.script.title"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
2020-12-11 14:24:42 +01:00
|
|
|
ImGui::SetCursorPosX(10);
|
2022-01-15 14:14:53 +01:00
|
|
|
ImGui::TextFormattedWrapped("{}", static_cast<const char *>("hex.builtin.view.hexeditor.script.desc"_lang));
|
2020-12-01 02:21:40 +01:00
|
|
|
|
|
|
|
ImGui::NewLine();
|
|
|
|
ImGui::InputText("##nolabel", this->m_loaderScriptScriptPath.data(), this->m_loaderScriptScriptPath.length(), ImGuiInputTextFlags_ReadOnly);
|
|
|
|
ImGui::SameLine();
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::Button("hex.builtin.view.hexeditor.script.script"_lang)) {
|
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.script.script.title"_lang, DialogMode::Open, { { "Python Script", "py" } }, [this](auto path) {
|
2021-01-27 00:44:10 +01:00
|
|
|
this->m_loaderScriptScriptPath = path;
|
|
|
|
});
|
|
|
|
}
|
2020-12-01 02:21:40 +01:00
|
|
|
ImGui::InputText("##nolabel", this->m_loaderScriptFilePath.data(), this->m_loaderScriptFilePath.length(), ImGuiInputTextFlags_ReadOnly);
|
|
|
|
ImGui::SameLine();
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::Button("hex.builtin.view.hexeditor.script.file"_lang)) {
|
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.script.file.title"_lang, DialogMode::Open, { }, [this](auto path) {
|
2021-01-27 00:44:10 +01:00
|
|
|
this->m_loaderScriptFilePath = path;
|
|
|
|
});
|
|
|
|
}
|
2021-01-14 17:01:44 +01:00
|
|
|
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape)))
|
|
|
|
ImGui::CloseCurrentPopup();
|
2020-12-01 02:21:40 +01:00
|
|
|
|
|
|
|
ImGui::NewLine();
|
|
|
|
|
2021-02-11 23:09:45 +01:00
|
|
|
confirmButtons("hex.common.load"_lang, "hex.common.cancel"_lang,
|
2021-04-13 08:41:59 +02:00
|
|
|
[this, &provider] {
|
|
|
|
if (!this->m_loaderScriptScriptPath.empty() && !this->m_loaderScriptFilePath.empty()) {
|
2021-09-08 15:18:24 +02:00
|
|
|
EventManager::post<RequestOpenFile>(this->m_loaderScriptFilePath);
|
2021-04-13 08:41:59 +02:00
|
|
|
LoaderScript::setFilePath(this->m_loaderScriptFilePath);
|
|
|
|
LoaderScript::setDataProvider(provider);
|
|
|
|
LoaderScript::processFile(this->m_loaderScriptScriptPath);
|
|
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
[] {
|
|
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
}
|
2020-12-11 14:24:42 +01:00
|
|
|
);
|
|
|
|
|
2020-12-01 02:21:40 +01:00
|
|
|
ImGui::EndPopup();
|
2020-12-11 14:24:42 +01:00
|
|
|
|
2020-12-01 02:21:40 +01:00
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginPopupModal("hex.builtin.view.hexeditor.menu.edit.set_base"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
2021-02-11 23:09:45 +01:00
|
|
|
ImGui::InputText("hex.common.address"_lang, this->m_baseAddressBuffer, 16, ImGuiInputTextFlags_CharsHexadecimal);
|
2021-01-11 13:50:04 +01:00
|
|
|
ImGui::NewLine();
|
|
|
|
|
2021-02-11 23:09:45 +01:00
|
|
|
confirmButtons("hex.common.set"_lang, "hex.common.cancel"_lang,
|
2021-02-07 14:29:13 +01:00
|
|
|
[this, &provider]{
|
|
|
|
provider->setBaseAddress(strtoull(this->m_baseAddressBuffer, nullptr, 16));
|
|
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
}, []{
|
|
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
});
|
2021-01-11 13:50:04 +01:00
|
|
|
|
2021-01-14 17:01:44 +01:00
|
|
|
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape)))
|
2021-01-11 13:50:04 +01:00
|
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
|
|
|
|
ImGui::EndPopup();
|
|
|
|
}
|
2021-07-27 21:07:36 +02:00
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginPopupModal("hex.builtin.view.hexeditor.menu.edit.resize"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
2021-07-27 21:07:36 +02:00
|
|
|
ImGui::InputScalar("hex.common.size"_lang, ImGuiDataType_U64, &this->m_resizeSize, nullptr, nullptr, "0x%016llx", ImGuiInputTextFlags_CharsHexadecimal);
|
|
|
|
ImGui::NewLine();
|
|
|
|
|
|
|
|
confirmButtons("hex.common.set"_lang, "hex.common.cancel"_lang,
|
|
|
|
[this, &provider]{
|
|
|
|
provider->resize(this->m_resizeSize);
|
|
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
}, []{
|
|
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
});
|
|
|
|
|
|
|
|
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape)))
|
|
|
|
ImGui::CloseCurrentPopup();
|
|
|
|
|
|
|
|
ImGui::EndPopup();
|
|
|
|
}
|
2021-01-27 00:44:10 +01:00
|
|
|
}
|
2021-01-11 13:50:04 +01:00
|
|
|
|
2020-12-22 18:10:01 +01:00
|
|
|
void ViewHexEditor::drawMenu() {
|
2021-09-21 02:29:54 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
|
|
|
bool providerValid = ImHexApi::Provider::isValid();
|
2020-11-24 02:00:22 +01:00
|
|
|
|
2021-02-11 23:09:45 +01:00
|
|
|
if (ImGui::BeginMenu("hex.menu.file"_lang)) {
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.open_file"_lang, "CTRL + O")) {
|
2021-01-27 00:44:10 +01:00
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) {
|
2021-09-08 15:18:24 +02:00
|
|
|
EventManager::post<RequestOpenFile>(path);
|
2021-01-27 00:44:10 +01:00
|
|
|
});
|
2020-11-24 02:00:22 +01:00
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginMenu("hex.builtin.view.hexeditor.menu.file.open_recent"_lang, !SharedData::recentFilePaths.empty())) {
|
2021-04-13 08:41:59 +02:00
|
|
|
for (auto &path : SharedData::recentFilePaths) {
|
2022-01-13 14:34:19 +01:00
|
|
|
if (ImGui::MenuItem(fs::path(path).filename().string().c_str())) {
|
2021-09-08 15:18:24 +02:00
|
|
|
EventManager::post<RequestOpenFile>(path);
|
2021-04-13 08:41:59 +02:00
|
|
|
}
|
2021-12-12 11:53:56 +01:00
|
|
|
}
|
|
|
|
|
2022-01-08 23:17:47 +01:00
|
|
|
ImGui::Separator();
|
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.clear_recent"_lang)) {
|
|
|
|
SharedData::recentFilePaths.clear();
|
|
|
|
ContentRegistry::Settings::write(
|
|
|
|
"hex.builtin.setting.imhex",
|
|
|
|
"hex.builtin.setting.imhex.recent_files",
|
|
|
|
std::vector<std::string>{});
|
|
|
|
}
|
|
|
|
|
2021-12-12 11:53:56 +01:00
|
|
|
ImGui::EndMenu();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ImGui::BeginMenu("hex.builtin.view.hexeditor.menu.file.open_other"_lang)) {
|
|
|
|
|
|
|
|
for (const auto &unlocalizedProviderName : ContentRegistry::Provider::getEntries()) {
|
|
|
|
if (ImGui::MenuItem(LangEntry(unlocalizedProviderName))) {
|
|
|
|
EventManager::post<RequestCreateProvider>(unlocalizedProviderName, nullptr);
|
|
|
|
}
|
2021-04-13 08:41:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndMenu();
|
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.save"_lang, "CTRL + S", false, providerValid && provider->isWritable())) {
|
2021-01-27 00:44:10 +01:00
|
|
|
save();
|
2020-11-27 13:45:56 +01:00
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.save_as"_lang, "CTRL + SHIFT + S", false, providerValid && provider->isWritable())) {
|
2021-01-27 00:44:10 +01:00
|
|
|
saveAs();
|
2020-11-27 13:45:56 +01:00
|
|
|
}
|
|
|
|
|
2021-12-12 21:46:48 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.close"_lang, "", false, providerValid)) {
|
2021-03-29 22:44:35 +02:00
|
|
|
EventManager::post<EventFileUnloaded>();
|
2021-09-21 02:29:54 +02:00
|
|
|
ImHexApi::Provider::remove(ImHexApi::Provider::get());
|
2021-09-22 12:58:49 +02:00
|
|
|
providerValid = false;
|
2021-03-29 22:44:35 +02:00
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.quit"_lang, "", false)) {
|
2021-09-10 21:48:51 +02:00
|
|
|
ImHexApi::Common::closeImHex();
|
|
|
|
}
|
|
|
|
|
2020-11-30 00:03:12 +01:00
|
|
|
ImGui::Separator();
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.open_project"_lang, "")) {
|
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.menu.file.open_project"_lang, DialogMode::Open, { { "Project File", "hexproj" } }, [this](auto path) {
|
2021-01-27 00:44:10 +01:00
|
|
|
ProjectFile::load(path);
|
|
|
|
});
|
2020-11-30 00:03:12 +01:00
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.save_project"_lang, "", false, providerValid && provider->isWritable())) {
|
2021-01-27 00:44:10 +01:00
|
|
|
if (ProjectFile::getProjectFilePath() == "") {
|
2021-12-07 22:47:41 +01:00
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.save_project"_lang, DialogMode::Save, { { "Project File", "hexproj" } }, [](auto path) {
|
2021-07-31 18:05:21 +02:00
|
|
|
if (path.ends_with(".hexproj")) {
|
|
|
|
ProjectFile::store(path);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ProjectFile::store(path + ".hexproj");
|
|
|
|
}
|
2021-01-27 00:44:10 +01:00
|
|
|
});
|
|
|
|
}
|
2020-11-30 00:03:12 +01:00
|
|
|
else
|
|
|
|
ProjectFile::store();
|
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.load_encoding_file"_lang)) {
|
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.load_enconding_file"_lang, DialogMode::Open, { }, [this](auto path) {
|
2021-02-14 01:11:55 +01:00
|
|
|
this->m_currEncodingFile = EncodingFile(EncodingFile::Type::Thingy, path);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2020-11-30 00:03:12 +01:00
|
|
|
ImGui::Separator();
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginMenu("hex.builtin.view.hexeditor.menu.file.import"_lang)) {
|
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.import.base64"_lang)) {
|
2021-01-27 00:44:10 +01:00
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.menu.file.import.base64"_lang, DialogMode::Open, { }, [this](auto path) {
|
2021-01-27 00:44:10 +01:00
|
|
|
std::vector<u8> base64;
|
|
|
|
this->loadFromFile(path, base64);
|
|
|
|
|
|
|
|
if (!base64.empty()) {
|
2021-02-02 23:11:23 +01:00
|
|
|
this->m_dataToSave = crypt::decode64(base64);
|
2021-01-27 00:44:10 +01:00
|
|
|
|
|
|
|
if (this->m_dataToSave.empty())
|
2021-12-07 22:47:41 +01:00
|
|
|
View::showErrorPopup("hex.builtin.view.hexeditor.base64.import_error"_lang);
|
2021-01-27 00:44:10 +01:00
|
|
|
else
|
2021-12-07 22:47:41 +01:00
|
|
|
ImGui::OpenPopup("hex.builtin.view.hexeditor.save_data"_lang);
|
2021-01-27 00:44:10 +01:00
|
|
|
this->getWindowOpenState() = true;
|
2021-12-07 22:47:41 +01:00
|
|
|
} else View::showErrorPopup("hex.builtin.view.hexeditor.file_open_error"_lang);
|
2021-01-27 00:44:10 +01:00
|
|
|
});
|
2020-11-24 02:00:22 +01:00
|
|
|
}
|
|
|
|
|
2020-11-29 15:09:36 +01:00
|
|
|
ImGui::Separator();
|
|
|
|
|
2022-01-09 21:27:59 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.import.ips"_lang, nullptr, false, !this->m_processingImportExport)) {
|
2021-01-27 00:44:10 +01:00
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) {
|
2022-01-09 21:27:59 +01:00
|
|
|
this->m_processingImportExport = true;
|
|
|
|
std::thread([this, path] {
|
|
|
|
auto task = ImHexApi::Tasks::createTask("hex.builtin.view.hexeditor.processing", 0);
|
|
|
|
|
|
|
|
auto patchData = File(path, File::Mode::Read).readBytes();
|
|
|
|
auto patch = hex::loadIPSPatch(patchData);
|
|
|
|
|
|
|
|
task.setMaxValue(patch.size());
|
|
|
|
|
|
|
|
auto provider = ImHexApi::Provider::get();
|
|
|
|
|
|
|
|
u64 progress = 0;
|
|
|
|
for (auto &[address, value] : patch) {
|
|
|
|
provider->addPatch(address, &value, 1);
|
|
|
|
progress++;
|
|
|
|
task.update(progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
provider->createUndoPoint();
|
|
|
|
this->m_processingImportExport = false;
|
|
|
|
}).detach();
|
2021-01-27 00:44:10 +01:00
|
|
|
|
|
|
|
this->getWindowOpenState() = true;
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2020-11-29 15:09:36 +01:00
|
|
|
}
|
|
|
|
|
2022-01-09 21:27:59 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.import.ips32"_lang, nullptr, false, !this->m_processingImportExport)) {
|
2021-12-07 22:47:41 +01:00
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) {
|
2022-01-09 21:27:59 +01:00
|
|
|
this->m_processingImportExport = true;
|
|
|
|
std::thread([this, path] {
|
|
|
|
auto task = ImHexApi::Tasks::createTask("hex.builtin.view.hexeditor.processing", 0);
|
|
|
|
|
|
|
|
auto patchData = File(path, File::Mode::Read).readBytes();
|
|
|
|
auto patch = hex::loadIPS32Patch(patchData);
|
|
|
|
|
|
|
|
task.setMaxValue(patch.size());
|
|
|
|
|
|
|
|
auto provider = ImHexApi::Provider::get();
|
|
|
|
|
|
|
|
u64 progress = 0;
|
|
|
|
for (auto &[address, value] : patch) {
|
|
|
|
provider->addPatch(address, &value, 1);
|
|
|
|
progress++;
|
|
|
|
task.update(progress);
|
|
|
|
}
|
|
|
|
|
|
|
|
provider->createUndoPoint();
|
|
|
|
this->m_processingImportExport = false;
|
|
|
|
}).detach();
|
2021-01-27 00:44:10 +01:00
|
|
|
|
|
|
|
this->getWindowOpenState() = true;
|
|
|
|
});
|
2020-11-29 15:09:36 +01:00
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.import.script"_lang)) {
|
2020-12-01 02:21:40 +01:00
|
|
|
this->m_loaderScriptFilePath.clear();
|
|
|
|
this->m_loaderScriptScriptPath.clear();
|
2021-12-07 22:47:41 +01:00
|
|
|
View::doLater([]{ ImGui::OpenPopup("hex.builtin.view.hexeditor.script.title"_lang); });
|
2020-12-01 02:21:40 +01:00
|
|
|
}
|
|
|
|
|
2020-11-24 02:00:22 +01:00
|
|
|
ImGui::EndMenu();
|
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginMenu("hex.builtin.view.hexeditor.menu.file.export"_lang, providerValid && provider->isWritable())) {
|
2022-01-09 21:27:59 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.export.ips"_lang, nullptr, false, !this->m_processingImportExport)) {
|
2020-12-27 15:39:06 +01:00
|
|
|
Patches patches = provider->getPatches();
|
2020-11-27 09:09:48 +01:00
|
|
|
if (!patches.contains(0x00454F45) && patches.contains(0x00454F46)) {
|
|
|
|
u8 value = 0;
|
2020-12-27 15:39:06 +01:00
|
|
|
provider->read(0x00454F45, &value, sizeof(u8));
|
2020-11-27 09:09:48 +01:00
|
|
|
patches[0x00454F45] = value;
|
|
|
|
}
|
|
|
|
|
2022-01-09 21:27:59 +01:00
|
|
|
this->m_processingImportExport = true;
|
|
|
|
std::thread([this, patches]{
|
|
|
|
auto task = ImHexApi::Tasks::createTask("hex.builtin.view.hexeditor.processing", 0);
|
|
|
|
|
|
|
|
this->m_dataToSave = generateIPSPatch(patches);
|
|
|
|
this->m_processingImportExport = false;
|
|
|
|
|
|
|
|
View::doLater([this]{
|
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.menu.file.export.title"_lang, DialogMode::Save, { }, [this](auto path) {
|
|
|
|
this->saveToFile(path, this->m_dataToSave);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}).detach();
|
2020-11-27 09:09:48 +01:00
|
|
|
}
|
2022-01-09 21:27:59 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.export.ips32"_lang, nullptr, false, !this->m_processingImportExport)) {
|
2020-12-27 15:39:06 +01:00
|
|
|
Patches patches = provider->getPatches();
|
2020-11-27 09:09:48 +01:00
|
|
|
if (!patches.contains(0x00454F45) && patches.contains(0x45454F46)) {
|
|
|
|
u8 value = 0;
|
2020-12-27 15:39:06 +01:00
|
|
|
provider->read(0x45454F45, &value, sizeof(u8));
|
2020-11-27 09:09:48 +01:00
|
|
|
patches[0x45454F45] = value;
|
|
|
|
}
|
|
|
|
|
2022-01-09 21:27:59 +01:00
|
|
|
this->m_processingImportExport = true;
|
|
|
|
std::thread([this, patches]{
|
|
|
|
auto task = ImHexApi::Tasks::createTask("hex.builtin.view.hexeditor.processing", 0);
|
|
|
|
|
|
|
|
this->m_dataToSave = generateIPS32Patch(patches);
|
|
|
|
this->m_processingImportExport = false;
|
|
|
|
|
|
|
|
View::doLater([this]{
|
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.menu.file.export.title"_lang, DialogMode::Save, { }, [this](auto path) {
|
|
|
|
this->saveToFile(path, this->m_dataToSave);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}).detach();
|
2020-11-27 09:09:48 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndMenu();
|
|
|
|
}
|
|
|
|
|
2020-11-27 13:45:56 +01:00
|
|
|
|
|
|
|
|
2020-11-24 02:00:22 +01:00
|
|
|
ImGui::Separator();
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.search"_lang, "CTRL + F")) {
|
2020-11-29 01:17:54 +01:00
|
|
|
this->getWindowOpenState() = true;
|
2021-12-07 22:47:41 +01:00
|
|
|
ImGui::OpenPopupInWindow(View::toWindowName("hex.builtin.view.hexeditor.name").c_str(), "hex.builtin.view.hexeditor.menu.file.search"_lang);
|
2020-11-24 02:00:22 +01:00
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.file.goto"_lang, "CTRL + G")) {
|
2020-11-29 01:17:54 +01:00
|
|
|
this->getWindowOpenState() = true;
|
2021-12-07 22:47:41 +01:00
|
|
|
ImGui::OpenPopupInWindow(View::toWindowName("hex.builtin.view.hexeditor.name").c_str(), "hex.builtin.view.hexeditor.menu.file.goto"_lang);
|
2020-11-24 02:00:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndMenu();
|
|
|
|
}
|
|
|
|
|
2021-02-11 23:09:45 +01:00
|
|
|
if (ImGui::BeginMenu("hex.menu.edit"_lang)) {
|
2021-01-10 23:59:36 +01:00
|
|
|
this->drawEditPopup();
|
2020-11-24 02:00:22 +01:00
|
|
|
ImGui::EndMenu();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
bool ViewHexEditor::createFile(const std::string &path) {
|
2021-07-27 21:07:36 +02:00
|
|
|
#if defined(OS_WINDOWS)
|
|
|
|
std::wstring widePath;
|
|
|
|
{
|
|
|
|
auto length = path.length() + 1;
|
|
|
|
auto wideLength = MultiByteToWideChar(CP_UTF8, 0, path.data(), length, 0, 0);
|
|
|
|
auto buffer = new wchar_t[wideLength];
|
|
|
|
MultiByteToWideChar(CP_UTF8, 0, path.data(), length, buffer, wideLength);
|
|
|
|
widePath = buffer;
|
|
|
|
delete[] buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto handle = ::CreateFileW(widePath.data(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
|
|
|
|
|
|
|
|
if (handle == INVALID_HANDLE_VALUE)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
::SetFilePointer(handle, 1, nullptr, FILE_BEGIN);
|
|
|
|
::SetEndOfFile(handle);
|
|
|
|
::CloseHandle(handle);
|
|
|
|
#else
|
2021-07-27 21:49:17 +02:00
|
|
|
auto handle = ::open(path.data(), O_RDWR | O_CREAT, 0644);
|
2021-07-27 21:07:36 +02:00
|
|
|
if (handle == -1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
lseek(handle, 0, SEEK_SET);
|
|
|
|
write(handle, "", 1);
|
|
|
|
|
|
|
|
close(handle);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2020-11-24 02:00:22 +01:00
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
void ViewHexEditor::openFile(const std::string &path) {
|
2021-12-07 22:47:41 +01:00
|
|
|
hex::prv::Provider *provider = nullptr;
|
|
|
|
EventManager::post<RequestCreateProvider>("hex.builtin.provider.file", &provider);
|
|
|
|
|
2021-12-12 00:41:44 +01:00
|
|
|
if (auto fileProvider = dynamic_cast<prv::FileProvider*>(provider)) {
|
|
|
|
fileProvider->setPath(path);
|
|
|
|
if (!fileProvider->open()) {
|
|
|
|
View::showErrorPopup("hex.builtin.view.hexeditor.error.open"_lang);
|
2021-12-12 21:46:48 +01:00
|
|
|
ImHexApi::Provider::remove(provider);
|
|
|
|
|
2021-12-12 00:41:44 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2020-12-27 15:39:06 +01:00
|
|
|
|
2021-01-31 00:05:07 +01:00
|
|
|
if (!provider->isWritable()) {
|
|
|
|
this->m_memoryEditor.ReadOnly = true;
|
2021-12-07 22:47:41 +01:00
|
|
|
View::showErrorPopup("hex.builtin.view.hexeditor.error.read_only"_lang);
|
2021-01-31 00:05:07 +01:00
|
|
|
} else {
|
|
|
|
this->m_memoryEditor.ReadOnly = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!provider->isAvailable()) {
|
2021-12-07 22:47:41 +01:00
|
|
|
View::showErrorPopup("hex.builtin.view.hexeditor.error.open"_lang);
|
2021-09-21 02:29:54 +02:00
|
|
|
ImHexApi::Provider::remove(provider);
|
2021-02-14 01:11:55 +01:00
|
|
|
|
2021-01-31 00:05:07 +01:00
|
|
|
return;
|
|
|
|
}
|
2020-11-30 00:03:12 +01:00
|
|
|
|
2021-01-31 00:05:07 +01:00
|
|
|
ProjectFile::setFilePath(path);
|
2020-11-30 00:03:12 +01:00
|
|
|
|
2020-12-05 22:10:03 +01:00
|
|
|
this->getWindowOpenState() = true;
|
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
EventManager::post<EventFileLoaded>(path);
|
2021-03-27 11:36:36 +01:00
|
|
|
EventManager::post<EventDataChanged>();
|
2022-01-12 22:02:47 +01:00
|
|
|
|
|
|
|
{
|
|
|
|
std::vector<pl::PatternData*> patterns;
|
|
|
|
EventManager::post<EventPatternChanged>(patterns);
|
|
|
|
}
|
2020-11-17 13:58:50 +01:00
|
|
|
}
|
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
bool ViewHexEditor::saveToFile(const std::string &path, const std::vector<u8>& data) {
|
|
|
|
File(path, File::Mode::Create).write(data);
|
2020-11-24 02:00:22 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
bool ViewHexEditor::loadFromFile(const std::string &path, std::vector<u8>& data) {
|
|
|
|
data = File(path, File::Mode::Read).readBytes();
|
2020-11-24 02:00:22 +01:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
void ViewHexEditor::copyBytes() const {
|
2021-09-21 02:29:54 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
2020-12-27 15:39:06 +01:00
|
|
|
|
2020-11-17 02:36:12 +01:00
|
|
|
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;
|
2020-11-16 00:07:42 +01:00
|
|
|
|
|
|
|
std::vector<u8> buffer(copySize, 0x00);
|
2021-12-09 21:10:24 +01:00
|
|
|
provider->read(start + provider->getBaseAddress() + provider->getCurrentPageAddress(), buffer.data(), buffer.size());
|
2020-11-16 00:07:42 +01:00
|
|
|
|
|
|
|
std::string str;
|
|
|
|
for (const auto &byte : buffer)
|
2021-03-03 19:58:22 +01:00
|
|
|
str += hex::format("{0:02X} ", byte);
|
2020-11-16 00:07:42 +01:00
|
|
|
str.pop_back();
|
|
|
|
|
|
|
|
ImGui::SetClipboardText(str.c_str());
|
|
|
|
}
|
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
void ViewHexEditor::pasteBytes() const {
|
2021-09-21 02:29:54 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
2021-04-16 17:01:01 +02:00
|
|
|
|
|
|
|
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<u8> 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;
|
2021-04-16 19:44:22 +02:00
|
|
|
|
|
|
|
stringIndex++;
|
2021-04-16 17:01:01 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Write bytes
|
2021-12-09 21:10:24 +01:00
|
|
|
provider->read(start + provider->getBaseAddress() + provider->getCurrentPageAddress(), buffer.data(), std::min(end - start + 1, buffer.size()));
|
2021-04-16 17:01:01 +02:00
|
|
|
}
|
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
void ViewHexEditor::copyString() const {
|
2021-09-21 02:29:54 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
2020-12-27 15:39:06 +01:00
|
|
|
|
2020-11-17 02:36:12 +01:00
|
|
|
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;
|
2020-11-16 00:07:42 +01:00
|
|
|
|
2020-11-23 03:00:46 +01:00
|
|
|
std::string buffer(copySize, 0x00);
|
2022-01-13 00:27:31 +01:00
|
|
|
buffer.reserve(copySize);
|
2021-12-09 21:10:24 +01:00
|
|
|
provider->read(start + provider->getBaseAddress() + provider->getCurrentPageAddress(), buffer.data(), copySize);
|
2020-11-16 00:07:42 +01:00
|
|
|
|
|
|
|
ImGui::SetClipboardText(buffer.c_str());
|
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
static std::vector<std::pair<u64, u64>> findString(hex::prv::Provider* &provider, std::string string) {
|
2020-11-15 23:04:46 +01:00
|
|
|
std::vector<std::pair<u64, u64>> results;
|
|
|
|
|
|
|
|
u32 foundCharacters = 0;
|
|
|
|
|
|
|
|
std::vector<u8> buffer(1024, 0x00);
|
|
|
|
size_t dataSize = provider->getSize();
|
|
|
|
for (u64 offset = 0; offset < dataSize; offset += 1024) {
|
2020-12-06 13:48:56 +01:00
|
|
|
size_t usedBufferSize = std::min(u64(buffer.size()), dataSize - offset);
|
2021-12-09 21:10:24 +01:00
|
|
|
provider->read(offset + provider->getBaseAddress() + provider->getCurrentPageAddress(), buffer.data(), usedBufferSize);
|
2020-11-15 23:04:46 +01:00
|
|
|
|
|
|
|
for (u64 i = 0; i < usedBufferSize; i++) {
|
|
|
|
if (buffer[i] == string[foundCharacters])
|
|
|
|
foundCharacters++;
|
|
|
|
else
|
|
|
|
foundCharacters = 0;
|
|
|
|
|
|
|
|
if (foundCharacters == string.size()) {
|
2021-09-28 12:34:55 +02:00
|
|
|
results.emplace_back(offset + i - foundCharacters + 1, offset + i);
|
2020-11-15 23:04:46 +01:00
|
|
|
foundCharacters = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
static std::vector<std::pair<u64, u64>> findHex(hex::prv::Provider* &provider, std::string string) {
|
2020-11-15 23:04:46 +01:00
|
|
|
std::vector<std::pair<u64, u64>> results;
|
|
|
|
|
|
|
|
if ((string.size() % 2) == 1)
|
|
|
|
string = "0" + string;
|
|
|
|
|
|
|
|
std::vector<u8> hex;
|
|
|
|
hex.reserve(string.size() / 2);
|
|
|
|
|
|
|
|
for (u32 i = 0; i < string.size(); i += 2) {
|
|
|
|
char byte[3] = { string[i], string[i + 1], 0 };
|
|
|
|
hex.push_back(strtoul(byte, nullptr, 16));
|
|
|
|
}
|
|
|
|
|
|
|
|
u32 foundCharacters = 0;
|
|
|
|
|
|
|
|
std::vector<u8> buffer(1024, 0x00);
|
|
|
|
size_t dataSize = provider->getSize();
|
|
|
|
for (u64 offset = 0; offset < dataSize; offset += 1024) {
|
2020-12-06 13:48:56 +01:00
|
|
|
size_t usedBufferSize = std::min(u64(buffer.size()), dataSize - offset);
|
2021-12-09 21:10:24 +01:00
|
|
|
provider->read(offset + provider->getBaseAddress() + provider->getCurrentPageAddress(), buffer.data(), usedBufferSize);
|
2020-11-15 23:04:46 +01:00
|
|
|
|
|
|
|
for (u64 i = 0; i < usedBufferSize; i++) {
|
|
|
|
if (buffer[i] == hex[foundCharacters])
|
|
|
|
foundCharacters++;
|
|
|
|
else
|
|
|
|
foundCharacters = 0;
|
|
|
|
|
|
|
|
if (foundCharacters == hex.size()) {
|
2021-09-28 12:34:55 +02:00
|
|
|
results.emplace_back(offset + i - foundCharacters + 1, offset + i);
|
2020-11-15 23:04:46 +01:00
|
|
|
foundCharacters = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return results;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-11-12 09:38:52 +01:00
|
|
|
void ViewHexEditor::drawSearchPopup() {
|
2020-11-15 23:04:46 +01:00
|
|
|
static auto InputCallback = [](ImGuiInputTextCallbackData* data) -> int {
|
|
|
|
auto _this = static_cast<ViewHexEditor*>(data->UserData);
|
2021-09-21 02:29:54 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
2020-11-12 09:38:52 +01:00
|
|
|
|
2020-12-27 15:39:06 +01:00
|
|
|
*_this->m_lastSearchBuffer = _this->m_searchFunction(provider, data->Buf);
|
2020-11-15 23:04:46 +01:00
|
|
|
_this->m_lastSearchIndex = 0;
|
2020-11-11 14:42:01 +01:00
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
if (!_this->m_lastSearchBuffer->empty())
|
2021-04-16 21:50:15 +02:00
|
|
|
_this->m_memoryEditor.GotoAddrAndSelect((*_this->m_lastSearchBuffer)[0].first, (*_this->m_lastSearchBuffer)[0].second);
|
2020-11-11 14:42:01 +01:00
|
|
|
|
2020-11-15 23:04:46 +01:00
|
|
|
return 0;
|
|
|
|
};
|
2020-11-11 14:42:01 +01:00
|
|
|
|
2020-11-15 23:04:46 +01:00
|
|
|
static auto Find = [this](char *buffer) {
|
2021-09-21 02:29:54 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
2020-12-27 15:39:06 +01:00
|
|
|
|
|
|
|
*this->m_lastSearchBuffer = this->m_searchFunction(provider, buffer);
|
2020-11-15 23:04:46 +01:00
|
|
|
this->m_lastSearchIndex = 0;
|
2020-11-11 14:42:01 +01:00
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
if (!this->m_lastSearchBuffer->empty())
|
2021-04-16 21:50:15 +02:00
|
|
|
this->m_memoryEditor.GotoAddrAndSelect((*this->m_lastSearchBuffer)[0].first, (*this->m_lastSearchBuffer)[0].second);
|
2020-11-15 23:04:46 +01:00
|
|
|
};
|
2020-11-11 14:42:01 +01:00
|
|
|
|
2020-11-15 23:04:46 +01:00
|
|
|
static auto FindNext = [this]() {
|
2021-09-08 15:18:24 +02:00
|
|
|
if (!this->m_lastSearchBuffer->empty()) {
|
2020-11-15 23:04:46 +01:00
|
|
|
++this->m_lastSearchIndex %= this->m_lastSearchBuffer->size();
|
2021-04-16 21:50:15 +02:00
|
|
|
this->m_memoryEditor.GotoAddrAndSelect((*this->m_lastSearchBuffer)[this->m_lastSearchIndex].first,
|
2020-11-15 23:04:46 +01:00
|
|
|
(*this->m_lastSearchBuffer)[this->m_lastSearchIndex].second);
|
2020-11-11 14:42:01 +01:00
|
|
|
}
|
2020-11-15 23:04:46 +01:00
|
|
|
};
|
2020-11-11 14:42:01 +01:00
|
|
|
|
2020-11-15 23:04:46 +01:00
|
|
|
static auto FindPrevious = [this]() {
|
2021-09-08 15:18:24 +02:00
|
|
|
if (!this->m_lastSearchBuffer->empty()) {
|
2020-11-15 23:04:46 +01:00
|
|
|
this->m_lastSearchIndex--;
|
2020-11-11 14:42:01 +01:00
|
|
|
|
2020-11-15 23:04:46 +01:00
|
|
|
if (this->m_lastSearchIndex < 0)
|
|
|
|
this->m_lastSearchIndex = this->m_lastSearchBuffer->size() - 1;
|
|
|
|
|
|
|
|
this->m_lastSearchIndex %= this->m_lastSearchBuffer->size();
|
|
|
|
|
2021-04-16 21:50:15 +02:00
|
|
|
this->m_memoryEditor.GotoAddrAndSelect((*this->m_lastSearchBuffer)[this->m_lastSearchIndex].first,
|
2020-11-15 23:04:46 +01:00
|
|
|
(*this->m_lastSearchBuffer)[this->m_lastSearchIndex].second);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2021-09-28 12:34:55 +02:00
|
|
|
|
|
|
|
ImGui::SetNextWindowPos(ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMin() - ImGui::GetStyle().WindowPadding);
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginPopup("hex.builtin.view.hexeditor.menu.file.search"_lang)) {
|
2020-11-15 23:04:46 +01:00
|
|
|
if (ImGui::BeginTabBar("searchTabs")) {
|
2021-02-17 14:47:25 +01:00
|
|
|
std::vector<char> *currBuffer = nullptr;
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginTabItem("hex.builtin.view.hexeditor.search.string"_lang)) {
|
2020-11-15 23:04:46 +01:00
|
|
|
this->m_searchFunction = findString;
|
|
|
|
this->m_lastSearchBuffer = &this->m_lastStringSearch;
|
2021-02-17 14:47:25 +01:00
|
|
|
currBuffer = &this->m_searchStringBuffer;
|
2020-11-15 23:04:46 +01:00
|
|
|
|
2021-02-17 14:47:25 +01:00
|
|
|
ImGui::InputText("##nolabel", currBuffer->data(), currBuffer->size(), ImGuiInputTextFlags_CallbackCompletion,
|
2020-11-15 23:04:46 +01:00
|
|
|
InputCallback, this);
|
|
|
|
ImGui::EndTabItem();
|
2020-11-11 14:42:01 +01:00
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginTabItem("hex.builtin.view.hexeditor.search.hex"_lang)) {
|
2020-11-15 23:04:46 +01:00
|
|
|
this->m_searchFunction = findHex;
|
|
|
|
this->m_lastSearchBuffer = &this->m_lastHexSearch;
|
2021-02-17 14:47:25 +01:00
|
|
|
currBuffer = &this->m_searchHexBuffer;
|
2020-11-15 23:04:46 +01:00
|
|
|
|
2021-02-17 14:47:25 +01:00
|
|
|
ImGui::InputText("##nolabel", currBuffer->data(), currBuffer->size(),
|
2020-11-15 23:04:46 +01:00
|
|
|
ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CallbackCompletion,
|
|
|
|
InputCallback, this);
|
|
|
|
ImGui::EndTabItem();
|
|
|
|
}
|
2020-11-11 14:42:01 +01:00
|
|
|
|
2021-02-17 14:47:25 +01:00
|
|
|
if (currBuffer != nullptr) {
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::Button("hex.builtin.view.hexeditor.search.find"_lang))
|
2021-02-17 14:47:25 +01:00
|
|
|
Find(currBuffer->data());
|
2020-11-11 14:42:01 +01:00
|
|
|
|
2021-09-08 15:18:24 +02:00
|
|
|
if (!this->m_lastSearchBuffer->empty()) {
|
2021-12-07 22:47:41 +01:00
|
|
|
if ((ImGui::Button("hex.builtin.view.hexeditor.search.find_next"_lang)))
|
2021-02-17 14:47:25 +01:00
|
|
|
FindNext();
|
2020-11-11 14:42:01 +01:00
|
|
|
|
2021-02-17 14:47:25 +01:00
|
|
|
ImGui::SameLine();
|
2020-11-11 14:42:01 +01:00
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if ((ImGui::Button("hex.builtin.view.hexeditor.search.find_prev"_lang)))
|
2021-02-17 14:47:25 +01:00
|
|
|
FindPrevious();
|
|
|
|
}
|
2020-11-11 14:42:01 +01:00
|
|
|
}
|
2020-11-15 23:04:46 +01:00
|
|
|
|
|
|
|
ImGui::EndTabBar();
|
2020-11-11 14:42:01 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndPopup();
|
|
|
|
}
|
2020-11-10 21:31:04 +01:00
|
|
|
}
|
|
|
|
|
2020-11-12 09:38:52 +01:00
|
|
|
void ViewHexEditor::drawGotoPopup() {
|
2021-09-21 02:29:54 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
2021-04-16 19:44:52 +02:00
|
|
|
auto baseAddress = provider->getBaseAddress();
|
|
|
|
auto dataSize = provider->getActualSize();
|
2020-12-27 15:39:06 +01:00
|
|
|
|
2021-09-28 12:34:55 +02:00
|
|
|
ImGui::SetNextWindowPos(ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMin() - ImGui::GetStyle().WindowPadding);
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginPopup("hex.builtin.view.hexeditor.menu.file.goto"_lang)) {
|
2020-11-19 23:24:34 +01:00
|
|
|
if (ImGui::BeginTabBar("gotoTabs")) {
|
2021-04-16 19:44:52 +02:00
|
|
|
u64 newOffset = 0;
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginTabItem("hex.builtin.view.hexeditor.goto.offset.absolute"_lang)) {
|
2021-04-16 19:44:52 +02:00
|
|
|
ImGui::InputScalar("hex", ImGuiDataType_U64, &this->m_gotoAddress, nullptr, nullptr, "%llx", ImGuiInputTextFlags_CharsHexadecimal);
|
2020-11-10 21:31:04 +01:00
|
|
|
|
2021-04-16 19:44:52 +02:00
|
|
|
if (this->m_gotoAddress < baseAddress || this->m_gotoAddress > baseAddress + dataSize)
|
|
|
|
this->m_gotoAddress = baseAddress;
|
2020-11-10 21:31:04 +01:00
|
|
|
|
2020-11-19 23:24:34 +01:00
|
|
|
newOffset = this->m_gotoAddress;
|
|
|
|
|
|
|
|
ImGui::EndTabItem();
|
|
|
|
}
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginTabItem("hex.builtin.view.hexeditor.goto.offset.begin"_lang)) {
|
2021-04-16 19:44:52 +02:00
|
|
|
ImGui::InputScalar("hex", ImGuiDataType_U64, &this->m_gotoAddress, nullptr, nullptr, "%llx", ImGuiInputTextFlags_CharsHexadecimal);
|
|
|
|
|
|
|
|
if (this->m_gotoAddress < 0 || this->m_gotoAddress > dataSize)
|
|
|
|
this->m_gotoAddress = 0;
|
|
|
|
|
|
|
|
newOffset = this->m_gotoAddress + baseAddress;
|
|
|
|
|
|
|
|
ImGui::EndTabItem();
|
|
|
|
}
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginTabItem("hex.builtin.view.hexeditor.goto.offset.current"_lang)) {
|
2021-04-16 19:44:52 +02:00
|
|
|
ImGui::InputScalar("dec", ImGuiDataType_S64, &this->m_gotoAddress, nullptr, nullptr, "%lld", ImGuiInputTextFlags_CharsDecimal);
|
2020-11-19 23:24:34 +01:00
|
|
|
|
2021-04-16 19:44:52 +02:00
|
|
|
s64 currSelectionOffset = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
|
2020-11-19 23:24:34 +01:00
|
|
|
|
2021-04-16 19:44:52 +02:00
|
|
|
if (currSelectionOffset + this->m_gotoAddress < 0)
|
|
|
|
this->m_gotoAddress = -currSelectionOffset;
|
|
|
|
else if (currSelectionOffset + this->m_gotoAddress > dataSize)
|
|
|
|
this->m_gotoAddress = dataSize - currSelectionOffset;
|
2020-11-19 23:24:34 +01:00
|
|
|
|
2021-04-16 19:44:52 +02:00
|
|
|
newOffset = currSelectionOffset + this->m_gotoAddress + baseAddress;
|
2020-11-19 23:24:34 +01:00
|
|
|
|
|
|
|
ImGui::EndTabItem();
|
|
|
|
}
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginTabItem("hex.builtin.view.hexeditor.goto.offset.end"_lang)) {
|
2021-04-16 19:44:52 +02:00
|
|
|
ImGui::InputScalar("hex", ImGuiDataType_U64, &this->m_gotoAddress, nullptr, nullptr, "%llx", ImGuiInputTextFlags_CharsHexadecimal);
|
2020-11-19 23:24:34 +01:00
|
|
|
|
2021-04-16 19:44:52 +02:00
|
|
|
if (this->m_gotoAddress < 0 || this->m_gotoAddress > dataSize)
|
|
|
|
this->m_gotoAddress = 0;
|
2020-11-19 23:24:34 +01:00
|
|
|
|
2021-04-16 19:44:52 +02:00
|
|
|
newOffset = (baseAddress + dataSize) - this->m_gotoAddress - 1;
|
2020-11-19 23:24:34 +01:00
|
|
|
|
|
|
|
ImGui::EndTabItem();
|
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::Button("hex.builtin.view.hexeditor.menu.file.goto"_lang)) {
|
|
|
|
provider->setCurrentPage(std::floor(double(newOffset - baseAddress) / hex::prv::Provider::PageSize));
|
2021-04-16 19:44:52 +02:00
|
|
|
EventManager::post<RequestSelectionChange>(Region { newOffset, 1 });
|
2020-11-19 23:24:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
ImGui::EndTabBar();
|
2020-11-10 21:31:04 +01:00
|
|
|
}
|
|
|
|
|
2020-11-12 09:38:52 +01:00
|
|
|
ImGui::EndPopup();
|
2020-11-11 14:42:01 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-10 23:59:36 +01:00
|
|
|
void ViewHexEditor::drawEditPopup() {
|
2021-09-21 02:29:54 +02:00
|
|
|
auto provider = ImHexApi::Provider::get();
|
|
|
|
bool providerValid = ImHexApi::Provider::isValid();
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.edit.undo"_lang, "CTRL + Z", false, providerValid))
|
2021-09-21 02:29:54 +02:00
|
|
|
provider->undo();
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.edit.redo"_lang, "CTRL + Y", false, providerValid))
|
2021-09-21 02:29:54 +02:00
|
|
|
provider->redo();
|
2021-03-26 21:43:24 +01:00
|
|
|
|
2021-04-16 17:01:01 +02:00
|
|
|
ImGui::Separator();
|
|
|
|
|
|
|
|
bool bytesSelected = this->m_memoryEditor.DataPreviewAddr != -1 && this->m_memoryEditor.DataPreviewAddrEnd != -1;
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.edit.copy"_lang, "CTRL + C", false, bytesSelected))
|
2021-04-16 17:01:01 +02:00
|
|
|
this->copyBytes();
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::BeginMenu("hex.builtin.view.hexeditor.menu.edit.copy_as"_lang, bytesSelected)) {
|
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.copy.hex"_lang, "CTRL + SHIFT + C"))
|
2021-01-10 23:59:36 +01:00
|
|
|
this->copyString();
|
|
|
|
|
|
|
|
ImGui::Separator();
|
|
|
|
|
2022-01-13 00:27:31 +01:00
|
|
|
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);
|
2021-01-10 23:59:36 +01:00
|
|
|
|
2022-01-13 00:27:31 +01:00
|
|
|
size_t copySize = (end - start) + 1;
|
2021-01-10 23:59:36 +01:00
|
|
|
|
2022-01-13 00:27:31 +01:00
|
|
|
ImGui::SetClipboardText(callback(provider, start + provider->getBaseAddress() + provider->getCurrentPageAddress(), copySize).c_str());
|
|
|
|
}
|
|
|
|
}
|
2021-01-10 23:59:36 +01:00
|
|
|
|
|
|
|
ImGui::EndMenu();
|
|
|
|
}
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.edit.paste"_lang, "CTRL + V", false, bytesSelected))
|
2021-04-16 17:01:01 +02:00
|
|
|
this->pasteBytes();
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.edit.select_all"_lang, "CTRL + A", false, providerValid))
|
2021-09-21 02:29:54 +02:00
|
|
|
EventManager::post<RequestSelectionChange>(Region { provider->getBaseAddress(), provider->getActualSize() });
|
2021-07-29 21:09:18 +02:00
|
|
|
|
2021-04-16 17:01:01 +02:00
|
|
|
ImGui::Separator();
|
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.edit.bookmark"_lang, nullptr, false, this->m_memoryEditor.DataPreviewAddr != -1 && this->m_memoryEditor.DataPreviewAddrEnd != -1)) {
|
2021-09-21 02:29:54 +02:00
|
|
|
auto base = ImHexApi::Provider::get()->getBaseAddress();
|
2021-02-17 14:57:32 +01:00
|
|
|
|
|
|
|
size_t start = base + std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
|
|
|
|
size_t end = base + std::max(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
|
2021-01-10 23:59:36 +01:00
|
|
|
|
2021-01-20 20:16:24 +01:00
|
|
|
ImHexApi::Bookmarks::add(start, end - start + 1, { }, { });
|
2021-01-10 23:59:36 +01:00
|
|
|
}
|
2021-01-11 13:50:04 +01:00
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.edit.set_base"_lang, nullptr, false, providerValid && provider->isReadable())) {
|
2021-01-20 20:16:24 +01:00
|
|
|
std::memset(this->m_baseAddressBuffer, 0x00, sizeof(this->m_baseAddressBuffer));
|
2021-12-07 22:47:41 +01:00
|
|
|
View::doLater([]{ ImGui::OpenPopup("hex.builtin.view.hexeditor.menu.edit.set_base"_lang); });
|
2021-01-11 13:50:04 +01:00
|
|
|
}
|
2021-07-27 21:07:36 +02:00
|
|
|
|
2021-12-07 22:47:41 +01:00
|
|
|
if (ImGui::MenuItem("hex.builtin.view.hexeditor.menu.edit.resize"_lang, nullptr, false, providerValid && provider->isResizable())) {
|
2021-09-13 17:26:30 +02:00
|
|
|
View::doLater([this]{
|
2021-09-21 02:29:54 +02:00
|
|
|
this->m_resizeSize = ImHexApi::Provider::get()->getActualSize();
|
2021-12-07 22:47:41 +01:00
|
|
|
ImGui::OpenPopup("hex.builtin.view.hexeditor.menu.edit.resize"_lang);
|
2021-07-27 21:07:36 +02:00
|
|
|
});
|
|
|
|
}
|
2021-01-10 23:59:36 +01:00
|
|
|
}
|
|
|
|
|
2021-12-23 15:11:38 +01:00
|
|
|
void ViewHexEditor::registerEvents() {
|
|
|
|
EventManager::subscribe<RequestOpenFile>(this, [this](const std::string &filePath) {
|
|
|
|
this->openFile(filePath);
|
|
|
|
this->getWindowOpenState() = true;
|
|
|
|
});
|
|
|
|
|
|
|
|
EventManager::subscribe<RequestSelectionChange>(this, [this](Region region) {
|
|
|
|
auto provider = ImHexApi::Provider::get();
|
|
|
|
auto page = provider->getPageOfAddress(region.address);
|
|
|
|
|
|
|
|
if (!page.has_value())
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (region.size != 0) {
|
|
|
|
provider->setCurrentPage(page.value());
|
|
|
|
u64 start = region.address - provider->getBaseAddress() - provider->getCurrentPageAddress();
|
|
|
|
this->m_memoryEditor.GotoAddrAndSelect(start, start + region.size - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
EventManager::post<EventRegionSelected>(Region { this->m_memoryEditor.DataPreviewAddr, (this->m_memoryEditor.DataPreviewAddrEnd - this->m_memoryEditor.DataPreviewAddr) + 1});
|
|
|
|
});
|
|
|
|
|
|
|
|
EventManager::subscribe<EventProjectFileLoad>(this, []() {
|
|
|
|
EventManager::post<RequestOpenFile>(ProjectFile::getFilePath());
|
|
|
|
});
|
|
|
|
|
|
|
|
EventManager::subscribe<EventWindowClosing>(this, [](GLFWwindow *window) {
|
|
|
|
if (ProjectFile::hasUnsavedChanges()) {
|
|
|
|
glfwSetWindowShouldClose(window, GLFW_FALSE);
|
|
|
|
View::doLater([] { ImGui::OpenPopup("hex.builtin.view.hexeditor.exit_application.title"_lang); });
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
EventManager::subscribe<RequestOpenWindow>(this, [this](std::string name) {
|
|
|
|
if (name == "Create File") {
|
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.create_file"_lang, DialogMode::Save, { }, [this](auto path) {
|
|
|
|
if (!this->createFile(path)) {
|
|
|
|
View::showErrorPopup("hex.builtin.view.hexeditor.error.create"_lang);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
EventManager::post<RequestOpenFile>(path);
|
|
|
|
this->getWindowOpenState() = true;
|
|
|
|
});
|
|
|
|
} else if (name == "Open File") {
|
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [this](auto path) {
|
|
|
|
EventManager::post<RequestOpenFile>(path);
|
|
|
|
this->getWindowOpenState() = true;
|
|
|
|
});
|
|
|
|
} else if (name == "Open Project") {
|
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.open_project"_lang, DialogMode::Open, { { "Project File", "hexproj" } }, [this](auto path) {
|
|
|
|
ProjectFile::load(path);
|
|
|
|
this->getWindowOpenState() = true;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
EventManager::subscribe<EventSettingsChanged>(this, [this] {
|
|
|
|
{
|
|
|
|
auto alpha = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.highlight_alpha");
|
|
|
|
|
|
|
|
if (alpha.is_number())
|
|
|
|
this->m_highlightAlpha = alpha;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
auto columnCount = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.column_count");
|
|
|
|
|
|
|
|
if (columnCount.is_number())
|
|
|
|
this->m_memoryEditor.Cols = static_cast<int>(columnCount);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
auto hexii = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.hexii");
|
|
|
|
|
|
|
|
if (hexii.is_number())
|
|
|
|
this->m_memoryEditor.OptShowHexII = static_cast<int>(hexii);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
auto ascii = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.ascii");
|
|
|
|
|
|
|
|
if (ascii.is_number())
|
|
|
|
this->m_memoryEditor.OptShowAscii = static_cast<int>(ascii);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
auto advancedDecoding = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.advanced_decoding");
|
|
|
|
|
|
|
|
if (advancedDecoding.is_number())
|
|
|
|
this->m_memoryEditor.OptShowAdvancedDecoding = static_cast<int>(advancedDecoding);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
auto greyOutZeros = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.grey_zeros");
|
|
|
|
|
|
|
|
if (greyOutZeros.is_number())
|
|
|
|
this->m_memoryEditor.OptGreyOutZeroes = static_cast<int>(greyOutZeros);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
auto upperCaseHex = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.uppercase_hex");
|
|
|
|
|
|
|
|
if (upperCaseHex.is_number())
|
|
|
|
this->m_memoryEditor.OptUpperCaseHex = static_cast<int>(upperCaseHex);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
auto showExtraInfo = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.extra_info");
|
|
|
|
|
|
|
|
if (showExtraInfo.is_number())
|
|
|
|
this->m_memoryEditor.OptShowExtraInfo = static_cast<int>(showExtraInfo);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
EventManager::subscribe<QuerySelection>(this, [this](auto ®ion) {
|
|
|
|
u64 address = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
|
|
|
|
size_t size = std::abs(s64(this->m_memoryEditor.DataPreviewAddrEnd) - s64(this->m_memoryEditor.DataPreviewAddr)) + 1;
|
|
|
|
|
|
|
|
region = Region { address, size };
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
void ViewHexEditor::registerShortcuts() {
|
|
|
|
ShortcutManager::addGlobalShortcut(CTRL + Keys::S, [] {
|
|
|
|
save();
|
|
|
|
});
|
|
|
|
|
|
|
|
ShortcutManager::addGlobalShortcut(CTRL + SHIFT + Keys::S, [] {
|
|
|
|
saveAs();
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
ShortcutManager::addShortcut(this, CTRL + Keys::Z, [] {
|
|
|
|
if (ImHexApi::Provider::isValid())
|
|
|
|
ImHexApi::Provider::get()->undo();
|
|
|
|
});
|
|
|
|
|
|
|
|
ShortcutManager::addShortcut(this, CTRL + Keys::Y, [] {
|
|
|
|
if (ImHexApi::Provider::isValid())
|
|
|
|
ImHexApi::Provider::get()->redo();
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
ShortcutManager::addShortcut(this, CTRL + Keys::F, [] {
|
|
|
|
ImGui::OpenPopupInWindow(View::toWindowName("hex.builtin.view.hexeditor.name").c_str(), "hex.builtin.view.hexeditor.menu.file.search"_lang);
|
|
|
|
});
|
|
|
|
|
|
|
|
ShortcutManager::addShortcut(this, CTRL + Keys::G, [] {
|
|
|
|
ImGui::OpenPopupInWindow(View::toWindowName("hex.builtin.view.hexeditor.name").c_str(), "hex.builtin.view.hexeditor.menu.file.goto"_lang);
|
|
|
|
});
|
|
|
|
|
|
|
|
ShortcutManager::addShortcut(this, CTRL + Keys::O, [] {
|
|
|
|
hex::openFileBrowser("hex.builtin.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [](auto path) {
|
|
|
|
EventManager::post<RequestOpenFile>(path);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
|
|
ShortcutManager::addShortcut(this, CTRL + Keys::C, [this] {
|
|
|
|
this->copyBytes();
|
|
|
|
});
|
|
|
|
|
|
|
|
ShortcutManager::addShortcut(this, CTRL + SHIFT + Keys::C, [this] {
|
|
|
|
this->copyString();
|
|
|
|
});
|
|
|
|
|
|
|
|
ShortcutManager::addShortcut(this, CTRL + Keys::V, [this] {
|
|
|
|
this->pasteBytes();
|
|
|
|
});
|
|
|
|
|
|
|
|
ShortcutManager::addShortcut(this, CTRL + Keys::A, [this] {
|
|
|
|
auto provider = ImHexApi::Provider::get();
|
|
|
|
EventManager::post<RequestSelectionChange>(Region { provider->getBaseAddress(), provider->getActualSize() });
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2020-11-10 21:31:04 +01:00
|
|
|
}
|