1
0
mirror of synced 2024-11-15 11:33:23 +01:00
ImHex/source/views/view_hexeditor.cpp

1075 lines
40 KiB
C++
Raw Normal View History

2020-11-10 21:31:04 +01:00
#include "views/view_hexeditor.hpp"
#include <hex/providers/provider.hpp>
2021-01-20 20:16:24 +01:00
#include <hex/api/imhex_api.hpp>
#include "providers/file_provider.hpp"
2020-11-11 14:42:01 +01:00
#include <GLFW/glfw3.h>
#include "helpers/crypto.hpp"
#include "helpers/patches.hpp"
2020-11-30 00:03:12 +01:00
#include "helpers/project_file_handler.hpp"
2020-12-01 02:21:40 +01:00
#include "helpers/loader_script_handler.hpp"
#undef __STRICT_ANSI__
#include <cstdio>
2020-11-10 21:31:04 +01:00
namespace hex {
2021-01-20 20:16:24 +01:00
ViewHexEditor::ViewHexEditor(std::vector<lang::PatternData*> &patternData)
: View("Hex Editor"), m_patternData(patternData) {
2020-11-10 21:31:04 +01:00
this->m_memoryEditor.ReadFn = [](const ImU8 *data, size_t off) -> ImU8 {
auto provider = SharedData::currentProvider;
if (!provider->isAvailable() || !provider->isReadable())
2020-11-10 21:31:04 +01:00
return 0x00;
ImU8 byte;
provider->read(off, &byte, sizeof(ImU8));
2020-11-10 21:31:04 +01:00
for (auto &overlay : SharedData::currentProvider->getOverlays()) {
auto overlayAddress = overlay->getAddress();
if (off >= overlayAddress && off < overlayAddress + overlay->getSize())
byte = overlay->getData()[off - overlayAddress];
}
2020-11-10 21:31:04 +01:00
return byte;
};
this->m_memoryEditor.WriteFn = [](ImU8 *data, size_t off, ImU8 d) -> void {
auto provider = SharedData::currentProvider;
if (!provider->isAvailable() || !provider->isWritable())
2020-11-10 21:31:04 +01:00
return;
provider->write(off, &d, sizeof(ImU8));
View::postEvent(Events::DataChanged);
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;
std::optional<u32> currColor, prevColor;
2021-01-20 20:16:24 +01:00
for (const auto &[region, name, comment, color] : ImHexApi::Bookmarks::getEntries()) {
if (off >= region.address && off < (region.address + region.size))
2021-01-20 18:10:40 +01:00
currColor = (color & 0x00FFFFFF) | 0x80000000;
if ((off - 1) >= region.address && (off - 1) < (region.address + region.size))
2021-01-20 18:10:40 +01:00
prevColor = (color & 0x00FFFFFF) | 0x80000000;
}
2021-01-20 18:10:40 +01:00
if (_this->m_highlightedBytes.contains(off)) {
auto color = (_this->m_highlightedBytes[off] & 0x00FFFFFF) | 0x80000000;
currColor = currColor.has_value() ? ImAlphaBlendColors(color, currColor.value()) : color;
}
if (_this->m_highlightedBytes.contains(off - 1)) {
auto color = (_this->m_highlightedBytes[off - 1] & 0x00FFFFFF) | 0x80000000;
prevColor = prevColor.has_value() ? ImAlphaBlendColors(color, prevColor.value()) : color;
}
if (next && prevColor != currColor) {
return false;
}
2021-01-20 18:10:40 +01:00
if (currColor.has_value() && (currColor.value() & 0x00FFFFFF) != 0x00) {
_this->m_memoryEditor.HighlightColor = (currColor.value() & 0x00FFFFFF) | 0x40000000;
return true;
2020-11-10 21:31:04 +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
this->m_memoryEditor.HoverFn = [](const ImU8 *data, size_t addr) {
bool tooltipShown = false;
2021-01-20 20:16:24 +01:00
for (const auto &[region, name, comment, color] : ImHexApi::Bookmarks::getEntries()) {
if (addr >= region.address && addr < (region.address + region.size)) {
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-01-21 10:53:12 +01:00
View::subscribeEvent(Events::FileDropped, [this](auto userData) {
auto filePath = std::any_cast<const char*>(userData);
2020-11-17 13:58:50 +01:00
if (filePath != nullptr)
this->openFile(filePath);
});
2021-01-21 10:53:12 +01:00
View::subscribeEvent(Events::SelectionChangeRequest, [this](auto userData) {
const Region &region = std::any_cast<Region>(userData);
auto provider = SharedData::currentProvider;
auto page = provider->getPageOfAddress(region.address);
if (!page.has_value())
return;
provider->setCurrentPage(page.value());
this->m_memoryEditor.GotoAddr = region.address;
this->m_memoryEditor.DataPreviewAddr = region.address;
this->m_memoryEditor.DataPreviewAddrEnd = region.address + region.size - 1;
2021-01-21 10:53:12 +01:00
View::postEvent(Events::RegionSelected, region);
});
2020-11-30 00:03:12 +01:00
2021-01-21 10:53:12 +01:00
View::subscribeEvent(Events::ProjectFileLoad, [this](auto) {
2020-11-30 00:03:12 +01:00
this->openFile(ProjectFile::getFilePath());
});
2021-01-21 10:53:12 +01:00
View::subscribeEvent(Events::WindowClosing, [this](auto userData) {
auto window = std::any_cast<GLFWwindow*>(userData);
2020-11-30 00:03:12 +01:00
if (ProjectFile::hasUnsavedChanges()) {
glfwSetWindowShouldClose(window, GLFW_FALSE);
View::doLater([] { ImGui::OpenPopup("Save Changes"); });
}
});
2021-01-21 10:53:12 +01:00
View::subscribeEvent(Events::PatternChanged, [this](auto) {
this->m_highlightedBytes.clear();
for (const auto &pattern : this->m_patternData)
this->m_highlightedBytes.merge(pattern->getHighlightedAddresses());
});
View::subscribeEvent(Events::OpenWindow, [this](auto name) {
if (std::any_cast<const char*>(name) == std::string("Open File")) {
View::openFileBrowser("Open File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) {
this->openFile(path);
this->getWindowOpenState() = true;
});
} else if (std::any_cast<const char*>(name) == std::string("Open Project")) {
View::openFileBrowser("Open Project", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ".hexproj", [this](auto path) {
ProjectFile::load(path);
View::postEvent(Events::ProjectFileLoad);
this->getWindowOpenState() = true;
});
}
});
2020-11-10 21:31:04 +01:00
}
ViewHexEditor::~ViewHexEditor() {
}
2020-11-10 21:31:04 +01:00
void ViewHexEditor::drawContent() {
auto provider = SharedData::currentProvider;
size_t dataSize = (provider == nullptr || !provider->isReadable()) ? 0x00 : provider->getSize();
this->m_memoryEditor.DrawWindow("Hex Editor", &this->getWindowOpenState(), this, dataSize, dataSize == 0 ? 0x00 : provider->getBaseAddress());
if (dataSize != 0x00) {
if (ImGui::Begin("Hex Editor")) {
if (ImGui::IsMouseReleased(ImGuiMouseButton_Right) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows))
ImGui::OpenPopup("Edit");
if (ImGui::BeginPopup("Edit")) {
this->drawEditPopup();
ImGui::EndPopup();
}
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
ImGui::Text("Page %d / %d", provider->getCurrentPage() + 1, provider->getPageCount());
ImGui::SameLine();
if (ImGui::ArrowButton("prevPage", ImGuiDir_Left)) {
provider->setCurrentPage(provider->getCurrentPage() - 1);
Region dataPreview = { std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd), 1 };
2021-01-21 10:53:12 +01:00
View::postEvent(Events::RegionSelected, dataPreview);
}
ImGui::SameLine();
if (ImGui::ArrowButton("nextPage", ImGuiDir_Right)) {
provider->setCurrentPage(provider->getCurrentPage() + 1);
Region dataPreview = { std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd), 1 };
2021-01-21 10:53:12 +01:00
View::postEvent(Events::RegionSelected, dataPreview);
}
}
ImGui::End();
this->drawSearchPopup();
this->drawGotoPopup();
}
Proper DPI scaling and basic custom font (#85) * add glm to arch deps After running got `None of the required 'glm' found`. This fixes that * dist/fedora: Include file magic headers Due to differences in package names between Deb based systems, Arch Linux, and RPM based systems the package containing the development headers for file were missing from the Fedora dependencies script. This includes the package `file-devel`, which is the package which resolves the issue. In Fedora, one can identify the package providing a specific file using the verb "whatprovides" with the command dnf, e.g.: [~]$ dnf whatprovides /usr/include/magic.h Last metadata expiration check: 4 days, 0:23:05 ago on Fri 04 Dec 2020 09:06:53 AM PST. file-devel-5.39-3.fc33.i686 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : @System Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h If one is unsure of the specific path, globbing may be used (but must be quoted): dnf whatprovides "*/magic.h" Resolves #48 * dist: Prevent already installed packages in ArchLinux and MSYS2. Use --needed option with pacman to prevent it. * Add script to install dependencies on Debian/Ubuntu. Tested with Xubuntu 20.04 and Debian testing (in today's Docker image bitnami/minideb). Update README.md. * ci: rework (#31) * Support non standard LLVM library names (#86) This fix openSUSE and Gentoo issue mentioned in https://github.com/WerWolv/ImHex/issues/37#issuecomment-739503138. (tested on openSUSE tumbleweed via Docker) I also took the liberty of renaming llvm_lib to llvm_demangle_lib to be more specific in the ``CMakeLists.txt``. * Implement proper DPI handling * Implement basic custom font support * Fix building on windows * Hopefully fix fonts on Windows * Fix several scaling issues * Replace font renderer with freetype * Updated CI and dependency scripts * Rebuild default font atlas * Correct platform detection macro for mingw * Fixed PKGBUILD Co-authored-by: brockelmore <31553173+brockelmore@users.noreply.github.com> Co-authored-by: Brian 'Redbeard' Harrington <redbeard@dead-city.org> Co-authored-by: Biswapriyo Nath <nathbappai@gmail.com> Co-authored-by: Stéphane Gourichon <stephane.gourichon@fidergo.fr> Co-authored-by: umarcor <38422348+umarcor@users.noreply.github.com> Co-authored-by: Mary <me@thog.eu> Co-authored-by: WerWolv <werwolv98@gmail.com>
2020-12-11 14:24:42 +01:00
if (ImGui::BeginPopupModal("Save Changes", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
constexpr auto Message = "You have unsaved changes made to your Project.\nAre you sure you want to exit?";
2020-11-30 00:03:12 +01:00
ImGui::NewLine();
Proper DPI scaling and basic custom font (#85) * add glm to arch deps After running got `None of the required 'glm' found`. This fixes that * dist/fedora: Include file magic headers Due to differences in package names between Deb based systems, Arch Linux, and RPM based systems the package containing the development headers for file were missing from the Fedora dependencies script. This includes the package `file-devel`, which is the package which resolves the issue. In Fedora, one can identify the package providing a specific file using the verb "whatprovides" with the command dnf, e.g.: [~]$ dnf whatprovides /usr/include/magic.h Last metadata expiration check: 4 days, 0:23:05 ago on Fri 04 Dec 2020 09:06:53 AM PST. file-devel-5.39-3.fc33.i686 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : @System Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h If one is unsure of the specific path, globbing may be used (but must be quoted): dnf whatprovides "*/magic.h" Resolves #48 * dist: Prevent already installed packages in ArchLinux and MSYS2. Use --needed option with pacman to prevent it. * Add script to install dependencies on Debian/Ubuntu. Tested with Xubuntu 20.04 and Debian testing (in today's Docker image bitnami/minideb). Update README.md. * ci: rework (#31) * Support non standard LLVM library names (#86) This fix openSUSE and Gentoo issue mentioned in https://github.com/WerWolv/ImHex/issues/37#issuecomment-739503138. (tested on openSUSE tumbleweed via Docker) I also took the liberty of renaming llvm_lib to llvm_demangle_lib to be more specific in the ``CMakeLists.txt``. * Implement proper DPI handling * Implement basic custom font support * Fix building on windows * Hopefully fix fonts on Windows * Fix several scaling issues * Replace font renderer with freetype * Updated CI and dependency scripts * Rebuild default font atlas * Correct platform detection macro for mingw * Fixed PKGBUILD Co-authored-by: brockelmore <31553173+brockelmore@users.noreply.github.com> Co-authored-by: Brian 'Redbeard' Harrington <redbeard@dead-city.org> Co-authored-by: Biswapriyo Nath <nathbappai@gmail.com> Co-authored-by: Stéphane Gourichon <stephane.gourichon@fidergo.fr> Co-authored-by: umarcor <38422348+umarcor@users.noreply.github.com> Co-authored-by: Mary <me@thog.eu> Co-authored-by: WerWolv <werwolv98@gmail.com>
2020-12-11 14:24:42 +01:00
ImGui::TextUnformatted(Message);
ImGui::NewLine();
confirmButtons("Yes", "No", [] { View::postEvent(Events::CloseImHex); }, [] { ImGui::CloseCurrentPopup(); });
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape)))
ImGui::CloseCurrentPopup();
2020-11-30 00:03:12 +01:00
ImGui::EndPopup();
}
Proper DPI scaling and basic custom font (#85) * add glm to arch deps After running got `None of the required 'glm' found`. This fixes that * dist/fedora: Include file magic headers Due to differences in package names between Deb based systems, Arch Linux, and RPM based systems the package containing the development headers for file were missing from the Fedora dependencies script. This includes the package `file-devel`, which is the package which resolves the issue. In Fedora, one can identify the package providing a specific file using the verb "whatprovides" with the command dnf, e.g.: [~]$ dnf whatprovides /usr/include/magic.h Last metadata expiration check: 4 days, 0:23:05 ago on Fri 04 Dec 2020 09:06:53 AM PST. file-devel-5.39-3.fc33.i686 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : @System Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h If one is unsure of the specific path, globbing may be used (but must be quoted): dnf whatprovides "*/magic.h" Resolves #48 * dist: Prevent already installed packages in ArchLinux and MSYS2. Use --needed option with pacman to prevent it. * Add script to install dependencies on Debian/Ubuntu. Tested with Xubuntu 20.04 and Debian testing (in today's Docker image bitnami/minideb). Update README.md. * ci: rework (#31) * Support non standard LLVM library names (#86) This fix openSUSE and Gentoo issue mentioned in https://github.com/WerWolv/ImHex/issues/37#issuecomment-739503138. (tested on openSUSE tumbleweed via Docker) I also took the liberty of renaming llvm_lib to llvm_demangle_lib to be more specific in the ``CMakeLists.txt``. * Implement proper DPI handling * Implement basic custom font support * Fix building on windows * Hopefully fix fonts on Windows * Fix several scaling issues * Replace font renderer with freetype * Updated CI and dependency scripts * Rebuild default font atlas * Correct platform detection macro for mingw * Fixed PKGBUILD Co-authored-by: brockelmore <31553173+brockelmore@users.noreply.github.com> Co-authored-by: Brian 'Redbeard' Harrington <redbeard@dead-city.org> Co-authored-by: Biswapriyo Nath <nathbappai@gmail.com> Co-authored-by: Stéphane Gourichon <stephane.gourichon@fidergo.fr> Co-authored-by: umarcor <38422348+umarcor@users.noreply.github.com> Co-authored-by: Mary <me@thog.eu> Co-authored-by: WerWolv <werwolv98@gmail.com>
2020-12-11 14:24:42 +01:00
if (ImGui::BeginPopupModal("Load File with Loader Script", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
2020-12-01 02:21:40 +01:00
constexpr auto Message = "Load a file using a Python loader script.";
Proper DPI scaling and basic custom font (#85) * add glm to arch deps After running got `None of the required 'glm' found`. This fixes that * dist/fedora: Include file magic headers Due to differences in package names between Deb based systems, Arch Linux, and RPM based systems the package containing the development headers for file were missing from the Fedora dependencies script. This includes the package `file-devel`, which is the package which resolves the issue. In Fedora, one can identify the package providing a specific file using the verb "whatprovides" with the command dnf, e.g.: [~]$ dnf whatprovides /usr/include/magic.h Last metadata expiration check: 4 days, 0:23:05 ago on Fri 04 Dec 2020 09:06:53 AM PST. file-devel-5.39-3.fc33.i686 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : @System Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h If one is unsure of the specific path, globbing may be used (but must be quoted): dnf whatprovides "*/magic.h" Resolves #48 * dist: Prevent already installed packages in ArchLinux and MSYS2. Use --needed option with pacman to prevent it. * Add script to install dependencies on Debian/Ubuntu. Tested with Xubuntu 20.04 and Debian testing (in today's Docker image bitnami/minideb). Update README.md. * ci: rework (#31) * Support non standard LLVM library names (#86) This fix openSUSE and Gentoo issue mentioned in https://github.com/WerWolv/ImHex/issues/37#issuecomment-739503138. (tested on openSUSE tumbleweed via Docker) I also took the liberty of renaming llvm_lib to llvm_demangle_lib to be more specific in the ``CMakeLists.txt``. * Implement proper DPI handling * Implement basic custom font support * Fix building on windows * Hopefully fix fonts on Windows * Fix several scaling issues * Replace font renderer with freetype * Updated CI and dependency scripts * Rebuild default font atlas * Correct platform detection macro for mingw * Fixed PKGBUILD Co-authored-by: brockelmore <31553173+brockelmore@users.noreply.github.com> Co-authored-by: Brian 'Redbeard' Harrington <redbeard@dead-city.org> Co-authored-by: Biswapriyo Nath <nathbappai@gmail.com> Co-authored-by: Stéphane Gourichon <stephane.gourichon@fidergo.fr> Co-authored-by: umarcor <38422348+umarcor@users.noreply.github.com> Co-authored-by: Mary <me@thog.eu> Co-authored-by: WerWolv <werwolv98@gmail.com>
2020-12-11 14:24:42 +01:00
ImGui::SetCursorPosX(10);
ImGui::TextWrapped(Message);
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-01-27 00:44:10 +01:00
if (ImGui::Button("Script")) {
View::openFileBrowser("Loader Script: Open Script", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ".py", [this](auto path) {
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-01-27 00:44:10 +01:00
if (ImGui::Button("File")) {
View::openFileBrowser("Loader Script: Open File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) {
this->m_loaderScriptFilePath = path;
});
}
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape)))
ImGui::CloseCurrentPopup();
2020-12-01 02:21:40 +01:00
ImGui::NewLine();
Proper DPI scaling and basic custom font (#85) * add glm to arch deps After running got `None of the required 'glm' found`. This fixes that * dist/fedora: Include file magic headers Due to differences in package names between Deb based systems, Arch Linux, and RPM based systems the package containing the development headers for file were missing from the Fedora dependencies script. This includes the package `file-devel`, which is the package which resolves the issue. In Fedora, one can identify the package providing a specific file using the verb "whatprovides" with the command dnf, e.g.: [~]$ dnf whatprovides /usr/include/magic.h Last metadata expiration check: 4 days, 0:23:05 ago on Fri 04 Dec 2020 09:06:53 AM PST. file-devel-5.39-3.fc33.i686 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : @System Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h If one is unsure of the specific path, globbing may be used (but must be quoted): dnf whatprovides "*/magic.h" Resolves #48 * dist: Prevent already installed packages in ArchLinux and MSYS2. Use --needed option with pacman to prevent it. * Add script to install dependencies on Debian/Ubuntu. Tested with Xubuntu 20.04 and Debian testing (in today's Docker image bitnami/minideb). Update README.md. * ci: rework (#31) * Support non standard LLVM library names (#86) This fix openSUSE and Gentoo issue mentioned in https://github.com/WerWolv/ImHex/issues/37#issuecomment-739503138. (tested on openSUSE tumbleweed via Docker) I also took the liberty of renaming llvm_lib to llvm_demangle_lib to be more specific in the ``CMakeLists.txt``. * Implement proper DPI handling * Implement basic custom font support * Fix building on windows * Hopefully fix fonts on Windows * Fix several scaling issues * Replace font renderer with freetype * Updated CI and dependency scripts * Rebuild default font atlas * Correct platform detection macro for mingw * Fixed PKGBUILD Co-authored-by: brockelmore <31553173+brockelmore@users.noreply.github.com> Co-authored-by: Brian 'Redbeard' Harrington <redbeard@dead-city.org> Co-authored-by: Biswapriyo Nath <nathbappai@gmail.com> Co-authored-by: Stéphane Gourichon <stephane.gourichon@fidergo.fr> Co-authored-by: umarcor <38422348+umarcor@users.noreply.github.com> Co-authored-by: Mary <me@thog.eu> Co-authored-by: WerWolv <werwolv98@gmail.com>
2020-12-11 14:24:42 +01:00
confirmButtons("Load", "Cancel",
[this, &provider] {
Proper DPI scaling and basic custom font (#85) * add glm to arch deps After running got `None of the required 'glm' found`. This fixes that * dist/fedora: Include file magic headers Due to differences in package names between Deb based systems, Arch Linux, and RPM based systems the package containing the development headers for file were missing from the Fedora dependencies script. This includes the package `file-devel`, which is the package which resolves the issue. In Fedora, one can identify the package providing a specific file using the verb "whatprovides" with the command dnf, e.g.: [~]$ dnf whatprovides /usr/include/magic.h Last metadata expiration check: 4 days, 0:23:05 ago on Fri 04 Dec 2020 09:06:53 AM PST. file-devel-5.39-3.fc33.i686 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : @System Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h If one is unsure of the specific path, globbing may be used (but must be quoted): dnf whatprovides "*/magic.h" Resolves #48 * dist: Prevent already installed packages in ArchLinux and MSYS2. Use --needed option with pacman to prevent it. * Add script to install dependencies on Debian/Ubuntu. Tested with Xubuntu 20.04 and Debian testing (in today's Docker image bitnami/minideb). Update README.md. * ci: rework (#31) * Support non standard LLVM library names (#86) This fix openSUSE and Gentoo issue mentioned in https://github.com/WerWolv/ImHex/issues/37#issuecomment-739503138. (tested on openSUSE tumbleweed via Docker) I also took the liberty of renaming llvm_lib to llvm_demangle_lib to be more specific in the ``CMakeLists.txt``. * Implement proper DPI handling * Implement basic custom font support * Fix building on windows * Hopefully fix fonts on Windows * Fix several scaling issues * Replace font renderer with freetype * Updated CI and dependency scripts * Rebuild default font atlas * Correct platform detection macro for mingw * Fixed PKGBUILD Co-authored-by: brockelmore <31553173+brockelmore@users.noreply.github.com> Co-authored-by: Brian 'Redbeard' Harrington <redbeard@dead-city.org> Co-authored-by: Biswapriyo Nath <nathbappai@gmail.com> Co-authored-by: Stéphane Gourichon <stephane.gourichon@fidergo.fr> Co-authored-by: umarcor <38422348+umarcor@users.noreply.github.com> Co-authored-by: Mary <me@thog.eu> Co-authored-by: WerWolv <werwolv98@gmail.com>
2020-12-11 14:24:42 +01:00
if (!this->m_loaderScriptScriptPath.empty() && !this->m_loaderScriptFilePath.empty()) {
this->openFile(this->m_loaderScriptFilePath);
LoaderScript::setFilePath(this->m_loaderScriptFilePath);
LoaderScript::setDataProvider(provider);
Proper DPI scaling and basic custom font (#85) * add glm to arch deps After running got `None of the required 'glm' found`. This fixes that * dist/fedora: Include file magic headers Due to differences in package names between Deb based systems, Arch Linux, and RPM based systems the package containing the development headers for file were missing from the Fedora dependencies script. This includes the package `file-devel`, which is the package which resolves the issue. In Fedora, one can identify the package providing a specific file using the verb "whatprovides" with the command dnf, e.g.: [~]$ dnf whatprovides /usr/include/magic.h Last metadata expiration check: 4 days, 0:23:05 ago on Fri 04 Dec 2020 09:06:53 AM PST. file-devel-5.39-3.fc33.i686 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : @System Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h If one is unsure of the specific path, globbing may be used (but must be quoted): dnf whatprovides "*/magic.h" Resolves #48 * dist: Prevent already installed packages in ArchLinux and MSYS2. Use --needed option with pacman to prevent it. * Add script to install dependencies on Debian/Ubuntu. Tested with Xubuntu 20.04 and Debian testing (in today's Docker image bitnami/minideb). Update README.md. * ci: rework (#31) * Support non standard LLVM library names (#86) This fix openSUSE and Gentoo issue mentioned in https://github.com/WerWolv/ImHex/issues/37#issuecomment-739503138. (tested on openSUSE tumbleweed via Docker) I also took the liberty of renaming llvm_lib to llvm_demangle_lib to be more specific in the ``CMakeLists.txt``. * Implement proper DPI handling * Implement basic custom font support * Fix building on windows * Hopefully fix fonts on Windows * Fix several scaling issues * Replace font renderer with freetype * Updated CI and dependency scripts * Rebuild default font atlas * Correct platform detection macro for mingw * Fixed PKGBUILD Co-authored-by: brockelmore <31553173+brockelmore@users.noreply.github.com> Co-authored-by: Brian 'Redbeard' Harrington <redbeard@dead-city.org> Co-authored-by: Biswapriyo Nath <nathbappai@gmail.com> Co-authored-by: Stéphane Gourichon <stephane.gourichon@fidergo.fr> Co-authored-by: umarcor <38422348+umarcor@users.noreply.github.com> Co-authored-by: Mary <me@thog.eu> Co-authored-by: WerWolv <werwolv98@gmail.com>
2020-12-11 14:24:42 +01:00
LoaderScript::processFile(this->m_loaderScriptScriptPath);
ImGui::CloseCurrentPopup();
}
},
[] {
2020-12-01 02:21:40 +01:00
ImGui::CloseCurrentPopup();
}
Proper DPI scaling and basic custom font (#85) * add glm to arch deps After running got `None of the required 'glm' found`. This fixes that * dist/fedora: Include file magic headers Due to differences in package names between Deb based systems, Arch Linux, and RPM based systems the package containing the development headers for file were missing from the Fedora dependencies script. This includes the package `file-devel`, which is the package which resolves the issue. In Fedora, one can identify the package providing a specific file using the verb "whatprovides" with the command dnf, e.g.: [~]$ dnf whatprovides /usr/include/magic.h Last metadata expiration check: 4 days, 0:23:05 ago on Fri 04 Dec 2020 09:06:53 AM PST. file-devel-5.39-3.fc33.i686 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : @System Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h If one is unsure of the specific path, globbing may be used (but must be quoted): dnf whatprovides "*/magic.h" Resolves #48 * dist: Prevent already installed packages in ArchLinux and MSYS2. Use --needed option with pacman to prevent it. * Add script to install dependencies on Debian/Ubuntu. Tested with Xubuntu 20.04 and Debian testing (in today's Docker image bitnami/minideb). Update README.md. * ci: rework (#31) * Support non standard LLVM library names (#86) This fix openSUSE and Gentoo issue mentioned in https://github.com/WerWolv/ImHex/issues/37#issuecomment-739503138. (tested on openSUSE tumbleweed via Docker) I also took the liberty of renaming llvm_lib to llvm_demangle_lib to be more specific in the ``CMakeLists.txt``. * Implement proper DPI handling * Implement basic custom font support * Fix building on windows * Hopefully fix fonts on Windows * Fix several scaling issues * Replace font renderer with freetype * Updated CI and dependency scripts * Rebuild default font atlas * Correct platform detection macro for mingw * Fixed PKGBUILD Co-authored-by: brockelmore <31553173+brockelmore@users.noreply.github.com> Co-authored-by: Brian 'Redbeard' Harrington <redbeard@dead-city.org> Co-authored-by: Biswapriyo Nath <nathbappai@gmail.com> Co-authored-by: Stéphane Gourichon <stephane.gourichon@fidergo.fr> Co-authored-by: umarcor <38422348+umarcor@users.noreply.github.com> Co-authored-by: Mary <me@thog.eu> Co-authored-by: WerWolv <werwolv98@gmail.com>
2020-12-11 14:24:42 +01:00
);
2020-12-01 02:21:40 +01:00
ImGui::EndPopup();
Proper DPI scaling and basic custom font (#85) * add glm to arch deps After running got `None of the required 'glm' found`. This fixes that * dist/fedora: Include file magic headers Due to differences in package names between Deb based systems, Arch Linux, and RPM based systems the package containing the development headers for file were missing from the Fedora dependencies script. This includes the package `file-devel`, which is the package which resolves the issue. In Fedora, one can identify the package providing a specific file using the verb "whatprovides" with the command dnf, e.g.: [~]$ dnf whatprovides /usr/include/magic.h Last metadata expiration check: 4 days, 0:23:05 ago on Fri 04 Dec 2020 09:06:53 AM PST. file-devel-5.39-3.fc33.i686 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : @System Matched from: Filename : /usr/include/magic.h file-devel-5.39-3.fc33.x86_64 : Libraries and header files for file development Repo : fedora Matched from: Filename : /usr/include/magic.h If one is unsure of the specific path, globbing may be used (but must be quoted): dnf whatprovides "*/magic.h" Resolves #48 * dist: Prevent already installed packages in ArchLinux and MSYS2. Use --needed option with pacman to prevent it. * Add script to install dependencies on Debian/Ubuntu. Tested with Xubuntu 20.04 and Debian testing (in today's Docker image bitnami/minideb). Update README.md. * ci: rework (#31) * Support non standard LLVM library names (#86) This fix openSUSE and Gentoo issue mentioned in https://github.com/WerWolv/ImHex/issues/37#issuecomment-739503138. (tested on openSUSE tumbleweed via Docker) I also took the liberty of renaming llvm_lib to llvm_demangle_lib to be more specific in the ``CMakeLists.txt``. * Implement proper DPI handling * Implement basic custom font support * Fix building on windows * Hopefully fix fonts on Windows * Fix several scaling issues * Replace font renderer with freetype * Updated CI and dependency scripts * Rebuild default font atlas * Correct platform detection macro for mingw * Fixed PKGBUILD Co-authored-by: brockelmore <31553173+brockelmore@users.noreply.github.com> Co-authored-by: Brian 'Redbeard' Harrington <redbeard@dead-city.org> Co-authored-by: Biswapriyo Nath <nathbappai@gmail.com> Co-authored-by: Stéphane Gourichon <stephane.gourichon@fidergo.fr> Co-authored-by: umarcor <38422348+umarcor@users.noreply.github.com> Co-authored-by: Mary <me@thog.eu> Co-authored-by: WerWolv <werwolv98@gmail.com>
2020-12-11 14:24:42 +01:00
2020-12-01 02:21:40 +01:00
}
if (ImGui::BeginPopupModal("Set base address", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::InputText("Address", this->m_baseAddressBuffer, 16, ImGuiInputTextFlags_CharsHexadecimal);
ImGui::NewLine();
confirmButtons("Set", "Cancel",
[this, &provider]{
provider->setBaseAddress(strtoull(this->m_baseAddressBuffer, nullptr, 16));
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-27 00:44:10 +01:00
static void save() {
auto provider = SharedData::currentProvider;
for (const auto &[address, value] : provider->getPatches())
provider->writeRaw(address, &value, sizeof(u8));
}
2021-01-27 00:44:10 +01:00
static void saveAs() {
View::openFileBrowser("Save As", imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, "*.*", [](auto path) {
FILE *file = fopen(path.c_str(), "wb");
if (file != nullptr) {
std::vector<u8> buffer(0xFF'FFFF, 0x00);
size_t bufferSize = buffer.size();
fseek(file, 0, SEEK_SET);
2021-01-27 00:44:10 +01:00
auto provider = SharedData::currentProvider;
for (u64 offset = 0; offset < provider->getActualSize(); offset += bufferSize) {
if (bufferSize > provider->getActualSize() - offset)
bufferSize = provider->getActualSize() - offset;
provider->read(offset, buffer.data(), bufferSize);
fwrite(buffer.data(), 1, bufferSize, file);
}
fclose(file);
}
2021-01-27 00:44:10 +01:00
});
};
void ViewHexEditor::drawMenu() {
auto provider = SharedData::currentProvider;
if (ImGui::BeginMenu("File")) {
if (ImGui::MenuItem("Open File...", "CTRL + O")) {
2021-01-27 00:44:10 +01:00
View::openFileBrowser("Open File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) {
this->openFile(path);
this->getWindowOpenState() = true;
});
}
if (ImGui::MenuItem("Save", "CTRL + S", false, provider != nullptr && provider->isWritable())) {
2021-01-27 00:44:10 +01:00
save();
}
if (ImGui::MenuItem("Save As...", "CTRL + SHIFT + S", false, provider != nullptr && provider->isWritable())) {
2021-01-27 00:44:10 +01:00
saveAs();
}
2020-11-30 00:03:12 +01:00
ImGui::Separator();
if (ImGui::MenuItem("Open Project", "")) {
2021-01-27 00:44:10 +01:00
View::openFileBrowser("Open Project", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, ".hexproj", [this](auto path) {
ProjectFile::load(path);
View::postEvent(Events::ProjectFileLoad);
this->getWindowOpenState() = true;
});
2020-11-30 00:03:12 +01:00
}
if (ImGui::MenuItem("Save Project", "", false, provider != nullptr && provider->isWritable())) {
2020-11-30 00:03:12 +01:00
View::postEvent(Events::ProjectFileStore);
2021-01-27 00:44:10 +01:00
if (ProjectFile::getProjectFilePath() == "") {
View::openFileBrowser("Save Project", imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, ".hexproj", [](auto path) {
ProjectFile::store(path);
});
}
2020-11-30 00:03:12 +01:00
else
ProjectFile::store();
}
ImGui::Separator();
if (ImGui::BeginMenu("Import...")) {
if (ImGui::MenuItem("Base64 File")) {
2021-01-27 00:44:10 +01:00
View::openFileBrowser("Open Base64 File", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) {
std::vector<u8> base64;
this->loadFromFile(path, base64);
if (!base64.empty()) {
this->m_dataToSave = crypt::decode64(base64);
2021-01-27 00:44:10 +01:00
if (this->m_dataToSave.empty())
View::showErrorPopup("File is not in a valid Base64 format!");
else
ImGui::OpenPopup("Save Data");
this->getWindowOpenState() = true;
} else View::showErrorPopup("Failed to open file!");
});
}
ImGui::Separator();
if (ImGui::MenuItem("IPS Patch")) {
2021-01-27 00:44:10 +01:00
View::openFileBrowser("Apply IPS Patch", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) {
auto patchData = hex::readFile(path);
auto patch = hex::loadIPSPatch(patchData);
for (auto &[address, value] : patch) {
SharedData::currentProvider->write(address, &value, 1);
}
this->getWindowOpenState() = true;
});
}
if (ImGui::MenuItem("IPS32 Patch")) {
2021-01-27 00:44:10 +01:00
View::openFileBrowser("Apply IPS32 Patch", imgui_addons::ImGuiFileBrowser::DialogMode::OPEN, "*.*", [this](auto path) {
auto patchData = hex::readFile(path);
auto patch = hex::loadIPS32Patch(patchData);
for (auto &[address, value] : patch) {
SharedData::currentProvider->write(address, &value, 1);
}
this->getWindowOpenState() = true;
});
}
2020-12-01 02:21:40 +01:00
if (ImGui::MenuItem("File with Loader Script")) {
this->m_loaderScriptFilePath.clear();
this->m_loaderScriptScriptPath.clear();
View::doLater([]{ ImGui::OpenPopup("Load File with Loader Script"); });
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Export...", provider != nullptr && provider->isWritable())) {
if (ImGui::MenuItem("IPS Patch")) {
Patches patches = provider->getPatches();
if (!patches.contains(0x00454F45) && patches.contains(0x00454F46)) {
u8 value = 0;
provider->read(0x00454F45, &value, sizeof(u8));
patches[0x00454F45] = value;
}
this->m_dataToSave = generateIPSPatch(patches);
2021-01-27 00:44:10 +01:00
View::openFileBrowser("Export File", imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, "*.*", [this](auto path) {
this->saveToFile(path, this->m_dataToSave);
});
}
if (ImGui::MenuItem("IPS32 Patch")) {
Patches patches = provider->getPatches();
if (!patches.contains(0x00454F45) && patches.contains(0x45454F46)) {
u8 value = 0;
provider->read(0x45454F45, &value, sizeof(u8));
patches[0x45454F45] = value;
}
this->m_dataToSave = generateIPS32Patch(patches);
2021-01-27 00:44:10 +01:00
View::openFileBrowser("Export File", imgui_addons::ImGuiFileBrowser::DialogMode::SAVE, "*.*", [this](auto path) {
this->saveToFile(path, this->m_dataToSave);
});
}
ImGui::EndMenu();
}
ImGui::Separator();
if (ImGui::MenuItem("Search", "CTRL + F")) {
this->getWindowOpenState() = true;
View::doLater([]{ ImGui::OpenPopup("Search"); });
}
if (ImGui::MenuItem("Goto", "CTRL + G")) {
this->getWindowOpenState() = true;
View::doLater([]{ ImGui::OpenPopup("Goto"); });
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Edit")) {
this->drawEditPopup();
ImGui::EndMenu();
}
}
bool ViewHexEditor::handleShortcut(int key, int mods) {
if (mods == GLFW_MOD_CONTROL && key == GLFW_KEY_S) {
2021-01-27 00:44:10 +01:00
save();
return true;
2020-11-30 00:03:12 +01:00
} else if (mods == (GLFW_MOD_CONTROL | GLFW_MOD_SHIFT) && key == GLFW_KEY_S) {
2021-01-27 00:44:10 +01:00
saveAs();
return true;
} else if (mods == GLFW_MOD_CONTROL && key == GLFW_KEY_F) {
View::doLater([]{ ImGui::OpenPopup("Search"); });
return true;
} else if (mods == GLFW_MOD_CONTROL && key == GLFW_KEY_G) {
View::doLater([]{ ImGui::OpenPopup("Goto"); });
return true;
} else if (mods == GLFW_MOD_CONTROL && key == GLFW_KEY_O) {
View::doLater([]{ ImGui::OpenPopup("Open File"); });
return true;
} else if (mods == (GLFW_MOD_CONTROL | GLFW_MOD_ALT) && key == GLFW_KEY_C) {
this->copyBytes();
return true;
} else if (mods == (GLFW_MOD_CONTROL | GLFW_MOD_SHIFT) && key == GLFW_KEY_C) {
this->copyString();
return true;
}
return false;
}
2020-11-17 13:58:50 +01:00
void ViewHexEditor::openFile(std::string path) {
auto& provider = SharedData::currentProvider;
if (provider != nullptr)
delete provider;
2020-11-17 13:58:50 +01:00
provider = new prv::FileProvider(path);
if (!provider->isWritable()) {
this->m_memoryEditor.ReadOnly = true;
View::showErrorPopup("Couldn't get write access. File opened in read-only mode.");
} else {
this->m_memoryEditor.ReadOnly = false;
}
if (!provider->isAvailable()) {
View::showErrorPopup("Failed to open file!");
return;
}
2020-11-30 00:03:12 +01:00
ProjectFile::setFilePath(path);
2020-11-30 00:03:12 +01:00
this->getWindowOpenState() = true;
View::postEvent(Events::FileLoaded, path);
2020-11-17 13:58:50 +01:00
View::postEvent(Events::DataChanged);
View::postEvent(Events::PatternChanged);
2020-11-17 13:58:50 +01:00
}
bool ViewHexEditor::saveToFile(std::string path, const std::vector<u8>& data) {
FILE *file = fopen(path.c_str(), "wb");
if (file == nullptr)
return false;
fwrite(data.data(), 1, data.size(), file);
fclose(file);
return true;
}
bool ViewHexEditor::loadFromFile(std::string path, std::vector<u8>& data) {
FILE *file = fopen(path.c_str(), "rb");
if (file == nullptr)
return false;
fseek(file, 0, SEEK_END);
size_t size = ftello64(file);
rewind(file);
data.resize(size);
fread(data.data(), 1, data.size(), file);
fclose(file);
return true;
}
2020-11-16 00:07:42 +01:00
void ViewHexEditor::copyBytes() {
auto provider = SharedData::currentProvider;
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);
provider->read(start, buffer.data(), buffer.size());
2020-11-16 00:07:42 +01:00
std::string str;
for (const auto &byte : buffer)
2020-11-20 15:15:43 +01:00
str += hex::format("%02X ", byte);
2020-11-16 00:07:42 +01:00
str.pop_back();
ImGui::SetClipboardText(str.c_str());
}
void ViewHexEditor::copyString() {
auto provider = SharedData::currentProvider;
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::string buffer(copySize, 0x00);
2020-11-16 00:07:42 +01:00
buffer.reserve(copySize + 1);
provider->read(start, buffer.data(), copySize);
2020-11-16 00:07:42 +01:00
ImGui::SetClipboardText(buffer.c_str());
}
void ViewHexEditor::copyLanguageArray(Language language) {
auto provider = SharedData::currentProvider;
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, 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)
2020-11-20 15:15:43 +01:00
str += hex::format("0x%02X, ", byte);
// Remove trailing comma
str.pop_back();
str.pop_back();
str += " };";
break;
case Language::Cpp:
2020-11-20 11:58:40 +01:00
str += "constexpr std::array<unsigned char, " + std::to_string(buffer.size()) + "> data = { ";
for (const auto &byte : buffer)
2020-11-20 15:15:43 +01:00
str += hex::format("0x%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)
2020-11-20 15:15:43 +01:00
str += hex::format("0x%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)
2020-11-20 15:15:43 +01:00
str += hex::format("0x%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)
2020-11-20 15:15:43 +01:00
str += hex::format("0x%02X, ", byte);
// Remove trailing comma
str.pop_back();
str.pop_back();
str += " ];";
break;
case Language::Python:
str += "data = bytes([ ";
for (const auto &byte : buffer)
2020-11-20 15:15:43 +01:00
str += hex::format("0x%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)
2020-11-20 15:15:43 +01:00
str += hex::format("0x%02X, ", byte);
// Remove trailing comma
str.pop_back();
str.pop_back();
str += " ]);";
break;
}
ImGui::SetClipboardText(str.c_str());
}
2020-11-20 13:25:55 +01:00
void ViewHexEditor::copyHexView() {
auto provider = SharedData::currentProvider;
2020-11-20 13:25:55 +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;
std::vector<u8> buffer(copySize, 0x00);
provider->read(start, buffer.data(), buffer.size());
2020-11-20 13:25:55 +01:00
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++) {
2020-11-20 15:15:43 +01:00
str += hex::format("%08lX ", col << 4);
2020-11-20 13:25:55 +01:00
for (u64 i = 0 ; i < 16; i++) {
if (col == (start >> 4) && i < (start & 0xF) || col == (end >> 4) && i > (end & 0xF))
str += " ";
else
2020-11-20 15:15:43 +01:00
str += hex::format("%02lX ", buffer[((col << 4) - start) + i]);
2020-11-20 13:25:55 +01:00
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("%c", displayChar);
}
}
str += "\n";
}
ImGui::SetClipboardText(str.c_str());
}
2020-11-20 15:15:43 +01:00
void ViewHexEditor::copyHexViewHTML() {
auto provider = SharedData::currentProvider;
2020-11-20 15:15:43 +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;
std::vector<u8> buffer(copySize, 0x00);
provider->read(start, buffer.data(), buffer.size());
2020-11-20 15:15:43 +01:00
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&nbsp&nbsp00 01 02 03 04 05 06 07&nbsp 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\">%08lX</span>&nbsp&nbsp<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 += "&nbsp&nbsp ";
else
str += hex::format("%02lX ", buffer[((col << 4) - start) + i]);
if ((i & 0xF) == 0x7)
str += "&nbsp";
}
str += "</span>&nbsp&nbsp<span class=\"textcolumn\">";
for (u64 i = 0 ; i < 16; i++) {
if (col == (start >> 4) && i < (start & 0xF) || col == (end >> 4) && i > (end & 0xF))
str += "&nbsp";
else {
u8 c = buffer[((col << 4) - start) + i];
char displayChar = (c < 32 || c >= 128) ? '.' : c;
str += hex::format("%c", displayChar);
}
}
str += "</span><br/>\n";
}
str +=
R"(
</code>
</div>
)";
ImGui::SetClipboardText(str.c_str());
}
2020-11-15 23:04:46 +01:00
static std::vector<std::pair<u64, u64>> findString(prv::Provider* &provider, std::string string) {
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) {
size_t usedBufferSize = std::min(u64(buffer.size()), dataSize - offset);
2020-11-15 23:04:46 +01:00
provider->read(offset, buffer.data(), usedBufferSize);
for (u64 i = 0; i < usedBufferSize; i++) {
if (buffer[i] == string[foundCharacters])
foundCharacters++;
else
foundCharacters = 0;
if (foundCharacters == string.size()) {
results.emplace_back(offset + i - foundCharacters + 1, offset + i + 1);
foundCharacters = 0;
}
}
}
return results;
}
static std::vector<std::pair<u64, u64>> findHex(prv::Provider* &provider, std::string string) {
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) {
size_t usedBufferSize = std::min(u64(buffer.size()), dataSize - offset);
2020-11-15 23:04:46 +01:00
provider->read(offset, buffer.data(), usedBufferSize);
for (u64 i = 0; i < usedBufferSize; i++) {
if (buffer[i] == hex[foundCharacters])
foundCharacters++;
else
foundCharacters = 0;
if (foundCharacters == hex.size()) {
results.emplace_back(offset + i - foundCharacters + 1, offset + i + 1);
foundCharacters = 0;
}
}
}
return results;
}
void ViewHexEditor::drawSearchPopup() {
2020-11-15 23:04:46 +01:00
static auto InputCallback = [](ImGuiInputTextCallbackData* data) -> int {
auto _this = static_cast<ViewHexEditor*>(data->UserData);
auto provider = SharedData::currentProvider;
*_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
2020-11-15 23:04:46 +01:00
if (_this->m_lastSearchBuffer->size() > 0)
_this->m_memoryEditor.GotoAddrAndHighlight((*_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) {
auto provider = SharedData::currentProvider;
*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
2020-11-15 23:04:46 +01:00
if (this->m_lastSearchBuffer->size() > 0)
this->m_memoryEditor.GotoAddrAndHighlight((*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
static auto FindNext = [this]() {
if (this->m_lastSearchBuffer->size() > 0) {
++this->m_lastSearchIndex %= this->m_lastSearchBuffer->size();
this->m_memoryEditor.GotoAddrAndHighlight((*this->m_lastSearchBuffer)[this->m_lastSearchIndex].first,
(*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]() {
if (this->m_lastSearchBuffer->size() > 0) {
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();
this->m_memoryEditor.GotoAddrAndHighlight((*this->m_lastSearchBuffer)[this->m_lastSearchIndex].first,
(*this->m_lastSearchBuffer)[this->m_lastSearchIndex].second);
}
};
if (ImGui::BeginPopupContextVoid("Search")) {
2020-11-15 23:04:46 +01:00
ImGui::TextUnformatted("Search");
if (ImGui::BeginTabBar("searchTabs")) {
char *currBuffer;
if (ImGui::BeginTabItem("String")) {
this->m_searchFunction = findString;
this->m_lastSearchBuffer = &this->m_lastStringSearch;
currBuffer = this->m_searchStringBuffer;
ImGui::InputText("##nolabel", currBuffer, 0xFFFF, ImGuiInputTextFlags_CallbackCompletion,
InputCallback, this);
ImGui::EndTabItem();
2020-11-11 14:42:01 +01:00
}
2020-11-15 23:04:46 +01:00
if (ImGui::BeginTabItem("Hex")) {
this->m_searchFunction = findHex;
this->m_lastSearchBuffer = &this->m_lastHexSearch;
currBuffer = this->m_searchHexBuffer;
ImGui::InputText("##nolabel", currBuffer, 0xFFFF,
ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CallbackCompletion,
InputCallback, this);
ImGui::EndTabItem();
}
2020-11-11 14:42:01 +01:00
2020-11-15 23:04:46 +01:00
if (ImGui::Button("Find"))
Find(currBuffer);
2020-11-11 14:42:01 +01:00
2020-11-15 23:04:46 +01:00
if (this->m_lastSearchBuffer->size() > 0) {
if ((ImGui::Button("Find Next")))
FindNext();
2020-11-11 14:42:01 +01:00
2020-11-15 23:04:46 +01:00
ImGui::SameLine();
2020-11-11 14:42:01 +01:00
2020-11-15 23:04:46 +01:00
if ((ImGui::Button("Find Prev")))
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
}
2020-11-15 23:04:46 +01:00
2020-11-11 14:42:01 +01:00
ImGui::EndPopup();
}
2020-11-10 21:31:04 +01:00
}
void ViewHexEditor::drawGotoPopup() {
auto provider = SharedData::currentProvider;
if (ImGui::BeginPopup("Goto")) {
ImGui::TextUnformatted("Goto");
if (ImGui::BeginTabBar("gotoTabs")) {
s64 newOffset = 0;
if (ImGui::BeginTabItem("Begin")) {
ImGui::InputScalar("##nolabel", ImGuiDataType_U64, &this->m_gotoAddress, nullptr, nullptr, "%llx", ImGuiInputTextFlags_CharsHexadecimal);
2020-11-10 21:31:04 +01:00
if (this->m_gotoAddress >= provider->getActualSize())
this->m_gotoAddress = provider->getActualSize() - 1;
2020-11-10 21:31:04 +01:00
newOffset = this->m_gotoAddress;
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("Current")) {
ImGui::InputScalar("##nolabel", ImGuiDataType_S64, &this->m_gotoAddress, nullptr, nullptr, "%llx", ImGuiInputTextFlags_CharsHexadecimal);
if (this->m_memoryEditor.DataPreviewAddr == -1 || this->m_memoryEditor.DataPreviewAddrEnd == -1) {
this->m_memoryEditor.DataPreviewAddr = 0;
this->m_memoryEditor.DataPreviewAddrEnd = 0;
}
s64 currHighlightStart = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
newOffset = this->m_gotoAddress + currHighlightStart;
if (newOffset >= provider->getActualSize()) {
newOffset = provider->getActualSize() - 1;
this->m_gotoAddress = (provider->getActualSize() - 1) - currHighlightStart;
} else if (newOffset < 0) {
newOffset = 0;
this->m_gotoAddress = -currHighlightStart;
}
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("End")) {
ImGui::InputScalar("##nolabel", ImGuiDataType_U64, &this->m_gotoAddress, nullptr, nullptr, "%llx", ImGuiInputTextFlags_CharsHexadecimal);
if (this->m_gotoAddress >= provider->getActualSize())
this->m_gotoAddress = provider->getActualSize() - 1;
newOffset = (provider->getActualSize() - 1) - this->m_gotoAddress;
ImGui::EndTabItem();
}
if (ImGui::Button("Goto")) {
provider->setCurrentPage(std::floor(newOffset / double(prv::Provider::PageSize)));
this->m_memoryEditor.GotoAddr = newOffset;
this->m_memoryEditor.DataPreviewAddr = newOffset;
this->m_memoryEditor.DataPreviewAddrEnd = newOffset;
}
ImGui::EndTabBar();
2020-11-10 21:31:04 +01:00
}
ImGui::EndPopup();
2020-11-11 14:42:01 +01:00
}
}
void ViewHexEditor::drawEditPopup() {
if (ImGui::BeginMenu("Copy as...", this->m_memoryEditor.DataPreviewAddr != -1 && this->m_memoryEditor.DataPreviewAddrEnd != -1)) {
if (ImGui::MenuItem("Bytes", "CTRL + ALT + C"))
this->copyBytes();
if (ImGui::MenuItem("Hex String", "CTRL + SHIFT + C"))
this->copyString();
ImGui::Separator();
if (ImGui::MenuItem("C Array"))
this->copyLanguageArray(Language::C);
if (ImGui::MenuItem("C++ Array"))
this->copyLanguageArray(Language::Cpp);
if (ImGui::MenuItem("C# Array"))
this->copyLanguageArray(Language::CSharp);
if (ImGui::MenuItem("Rust Array"))
this->copyLanguageArray(Language::Rust);
if (ImGui::MenuItem("Python Array"))
this->copyLanguageArray(Language::Python);
if (ImGui::MenuItem("Java Array"))
this->copyLanguageArray(Language::Java);
if (ImGui::MenuItem("JavaScript Array"))
this->copyLanguageArray(Language::JavaScript);
ImGui::Separator();
if (ImGui::MenuItem("Editor View"))
this->copyHexView();
if (ImGui::MenuItem("HTML"))
this->copyHexViewHTML();
ImGui::EndMenu();
}
if (ImGui::MenuItem("Create bookmark", nullptr, false, this->m_memoryEditor.DataPreviewAddr != -1 && this->m_memoryEditor.DataPreviewAddrEnd != -1)) {
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-20 20:16:24 +01:00
ImHexApi::Bookmarks::add(start, end - start + 1, { }, { });
}
auto provider = SharedData::currentProvider;
if (ImGui::MenuItem("Set base address", nullptr, false, provider != nullptr && provider->isReadable())) {
2021-01-20 20:16:24 +01:00
std::memset(this->m_baseAddressBuffer, 0x00, sizeof(this->m_baseAddressBuffer));
View::doLater([]{ ImGui::OpenPopup("Set base address"); });
}
}
2020-11-10 21:31:04 +01:00
}