ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512)
* ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
This commit is contained in:
parent
c0ceaa4195
commit
b751f98e91
@ -2,9 +2,6 @@
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/imhex_patterns-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/imhex_patterns-src/yara/official_rules" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/imhex_patterns-src/yara/official_rules/utils/yara-forensics" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/capstone" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/curl" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/fmt" vcs="Git" />
|
||||
|
805
lib/external/imgui/include/imgui_memory_editor.h
vendored
805
lib/external/imgui/include/imgui_memory_editor.h
vendored
@ -1,805 +0,0 @@
|
||||
// Mini memory editor for Dear ImGui (to embed in your game/tools)
|
||||
// Get latest version at http://www.github.com/ocornut/imgui_club
|
||||
//
|
||||
// Right-click anywhere to access the Options menu!
|
||||
// You can adjust the keyboard repeat delay/rate in ImGuiIO.
|
||||
// The code assume a mono-space font for simplicity!
|
||||
// If you don't use the default font, use ImGui::PushFont()/PopFont() to switch to a mono-space font before caling this.
|
||||
//
|
||||
// Usage:
|
||||
// // Create a window and draw memory editor inside it:
|
||||
// static MemoryEditor mem_edit_1;
|
||||
// static char data[0x10000];
|
||||
// size_t data_size = 0x10000;
|
||||
// mem_edit_1.DrawWindow("Memory Editor", data, data_size);
|
||||
//
|
||||
// Usage:
|
||||
// // If you already have a window, use DrawContents() instead:
|
||||
// static MemoryEditor mem_edit_2;
|
||||
// ImGui::Begin("MyWindow")
|
||||
// mem_edit_2.DrawContents(this, sizeof(*this), (size_t)this);
|
||||
// ImGui::End();
|
||||
//
|
||||
// Changelog:
|
||||
// - v0.10: initial version
|
||||
// - v0.23 (2017/08/17): added to github. fixed right-arrow triggering a byte write.
|
||||
// - v0.24 (2018/06/02): changed DragInt("Rows" to use a %d data format (which is desirable since imgui 1.61).
|
||||
// - v0.25 (2018/07/11): fixed wording: all occurrences of "Rows" renamed to "Columns".
|
||||
// - v0.26 (2018/08/02): fixed clicking on hex region
|
||||
// - v0.30 (2018/08/02): added data preview for common data types
|
||||
// - v0.31 (2018/10/10): added OptUpperCaseHex option to select lower/upper casing display [@samhocevar]
|
||||
// - v0.32 (2018/10/10): changed signatures to use void* instead of unsigned char*
|
||||
// - v0.33 (2018/10/10): added OptShowOptions option to hide all the interactive option setting.
|
||||
// - v0.34 (2019/05/07): binary preview now applies endianness setting [@nicolasnoble]
|
||||
// - v0.35 (2020/01/29): using ImGuiDataType available since Dear ImGui 1.69.
|
||||
// - v0.36 (2020/05/05): minor tweaks, minor refactor.
|
||||
// - v0.40 (2020/10/04): fix misuse of ImGuiListClipper API, broke with Dear ImGui 1.79. made cursor position appears on left-side of edit box. option popup appears on mouse release. fix MSVC warnings where _CRT_SECURE_NO_WARNINGS wasn't working in recent versions.
|
||||
// - v0.41 (2020/10/05): fix when using with keyboard/gamepad navigation enabled.
|
||||
// - v0.42 (2020/10/14): fix for . character in ASCII view always being greyed out.
|
||||
//
|
||||
// Todo/Bugs:
|
||||
// - This is generally old code, it should work but please don't use this as reference!
|
||||
// - Arrows are being sent to the InputText() about to disappear which for LeftArrow makes the text cursor appear at position 1 for one frame.
|
||||
// - Using InputText() is awkward and maybe overkill here, consider implementing something custom.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h> // sprintf, scanf
|
||||
#include <stdint.h> // uint8_t, etc.
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _PRISizeT "I"
|
||||
#define ImSnprintf _snprintf
|
||||
#else
|
||||
#define _PRISizeT "z"
|
||||
#define ImSnprintf snprintf
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4996) // warning C4996: 'sprintf': This function or variable may be unsafe.
|
||||
#endif
|
||||
|
||||
ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b);
|
||||
|
||||
struct MemoryEditor
|
||||
{
|
||||
enum DataFormat
|
||||
{
|
||||
DataFormat_Bin = 0,
|
||||
DataFormat_Dec = 1,
|
||||
DataFormat_Hex = 2,
|
||||
DataFormat_COUNT
|
||||
};
|
||||
|
||||
struct DecodeData {
|
||||
std::string data;
|
||||
size_t advance;
|
||||
ImColor color;
|
||||
};
|
||||
|
||||
// Settings
|
||||
bool ReadOnly; // = false // disable any editing.
|
||||
int Cols; // = 16 // number of columns to display.
|
||||
bool OptShowOptions; // = true // display options button/context menu. when disabled, options will be locked unless you provide your own UI for them.
|
||||
bool OptShowHexII; // = false // display values in HexII representation instead of regular hexadecimal: hide null/zero bytes, ascii values as ".X".
|
||||
bool OptShowAscii; // = true // display ASCII representation on the right side.
|
||||
bool OptShowAdvancedDecoding; // = true // display advanced decoding data on the right side.
|
||||
bool OptGreyOutZeroes; // = true // display null/zero bytes using the TextDisabled color.
|
||||
bool OptUpperCaseHex; // = true // display hexadecimal values as "FF" instead of "ff".
|
||||
bool OptShowExtraInfo; // = true // display extra information about size of data and current selection
|
||||
int OptMidColsCount; // = 8 // set to 0 to disable extra spacing between every mid-cols.
|
||||
int OptAddrDigitsCount; // = 0 // number of addr digits to display (default calculated based on maximum displayed addr).
|
||||
ImU32 HighlightColor; // // background color of highlighted bytes.
|
||||
ImU8 (*ReadFn)(const ImU8* data, size_t off); // = 0 // optional handler to read bytes.
|
||||
void (*WriteFn)(ImU8* data, size_t off, ImU8 d); // = 0 // optional handler to write bytes.
|
||||
bool (*HighlightFn)(const ImU8* data, size_t off, bool next);//= 0 // optional handler to return Highlight property (to support non-contiguous highlighting).
|
||||
void (*HoverFn)(const ImU8 *data, size_t off);
|
||||
DecodeData (*DecodeFn)(const ImU8 *data, size_t off);
|
||||
|
||||
// [Internal State]
|
||||
bool ContentsWidthChanged;
|
||||
size_t DataPreviewAddr;
|
||||
size_t DataPreviewAddrOld;
|
||||
size_t DataPreviewAddrEnd;
|
||||
size_t DataPreviewAddrEndOld;
|
||||
size_t DataEditingAddr;
|
||||
bool DataEditingTakeFocus;
|
||||
char DataInputBuf[32];
|
||||
char AddrInputBuf[32];
|
||||
size_t GotoAddr;
|
||||
size_t HighlightMin, HighlightMax;
|
||||
int PreviewEndianess;
|
||||
ImGuiDataType PreviewDataType;
|
||||
|
||||
MemoryEditor()
|
||||
{
|
||||
// Settings
|
||||
ReadOnly = false;
|
||||
Cols = 16;
|
||||
OptShowOptions = true;
|
||||
OptShowHexII = false;
|
||||
OptShowAscii = true;
|
||||
OptShowAdvancedDecoding = true;
|
||||
OptGreyOutZeroes = true;
|
||||
OptUpperCaseHex = true;
|
||||
OptMidColsCount = 8;
|
||||
OptAddrDigitsCount = 0;
|
||||
HighlightColor = IM_COL32(255, 255, 255, 50);
|
||||
ReadFn = NULL;
|
||||
WriteFn = NULL;
|
||||
HighlightFn = NULL;
|
||||
HoverFn = NULL;
|
||||
DecodeFn = NULL;
|
||||
|
||||
// State/Internals
|
||||
ContentsWidthChanged = false;
|
||||
DataPreviewAddr = DataEditingAddr = DataPreviewAddrEnd = (size_t)-1;
|
||||
DataPreviewAddrOld = DataPreviewAddrEndOld = (size_t)-1;
|
||||
DataEditingTakeFocus = false;
|
||||
memset(DataInputBuf, 0, sizeof(DataInputBuf));
|
||||
memset(AddrInputBuf, 0, sizeof(AddrInputBuf));
|
||||
GotoAddr = (size_t)-1;
|
||||
HighlightMin = HighlightMax = (size_t)-1;
|
||||
PreviewEndianess = 0;
|
||||
PreviewDataType = ImGuiDataType_S32;
|
||||
}
|
||||
|
||||
void GotoAddrAndHighlight(size_t addr_min, size_t addr_max)
|
||||
{
|
||||
GotoAddr = addr_min;
|
||||
HighlightMin = addr_min;
|
||||
HighlightMax = addr_max;
|
||||
}
|
||||
|
||||
void GotoAddrAndSelect(size_t addr_min, size_t addr_max)
|
||||
{
|
||||
GotoAddr = addr_min;
|
||||
DataPreviewAddr = addr_min;
|
||||
DataPreviewAddrEnd = addr_max;
|
||||
DataPreviewAddrOld = addr_min;
|
||||
DataPreviewAddrEndOld = addr_max;
|
||||
}
|
||||
|
||||
struct Sizes
|
||||
{
|
||||
int AddrDigitsCount;
|
||||
float LineHeight;
|
||||
float GlyphWidth;
|
||||
float HexCellWidth;
|
||||
float SpacingBetweenMidCols;
|
||||
float PosHexStart;
|
||||
float PosHexEnd;
|
||||
float PosAsciiStart;
|
||||
float PosAsciiEnd;
|
||||
float PosDecodingStart;
|
||||
float PosDecodingEnd;
|
||||
float WindowWidth;
|
||||
|
||||
Sizes() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
void CalcSizes(Sizes& s, size_t mem_size, size_t base_display_addr)
|
||||
{
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
s.AddrDigitsCount = OptAddrDigitsCount;
|
||||
if (s.AddrDigitsCount == 0)
|
||||
for (size_t n = base_display_addr + mem_size - 1; n > 0; n >>= 4)
|
||||
s.AddrDigitsCount++;
|
||||
s.LineHeight = ImGui::GetTextLineHeight();
|
||||
s.GlyphWidth = ImGui::CalcTextSize("F").x + 1; // We assume the font is mono-space
|
||||
s.HexCellWidth = (float)(int)(s.GlyphWidth * 2.5f); // "FF " we include trailing space in the width to easily catch clicks everywhere
|
||||
s.SpacingBetweenMidCols = (float)(int)(s.HexCellWidth * 0.25f); // Every OptMidColsCount columns we add a bit of extra spacing
|
||||
s.PosHexStart = (s.AddrDigitsCount + 2) * s.GlyphWidth;
|
||||
s.PosHexEnd = s.PosHexStart + (s.HexCellWidth * Cols);
|
||||
s.PosAsciiStart = s.PosAsciiEnd = s.PosHexEnd;
|
||||
|
||||
if (OptShowAscii && OptShowAdvancedDecoding) {
|
||||
s.PosAsciiStart = s.PosHexEnd + s.GlyphWidth * 1;
|
||||
if (OptMidColsCount > 0)
|
||||
s.PosAsciiStart += (float)((Cols + OptMidColsCount - 1) / OptMidColsCount) * s.SpacingBetweenMidCols;
|
||||
s.PosAsciiEnd = s.PosAsciiStart + Cols * s.GlyphWidth;
|
||||
|
||||
s.PosDecodingStart = s.PosAsciiEnd + s.GlyphWidth * 1;
|
||||
if (OptMidColsCount > 0)
|
||||
s.PosDecodingStart += (float)((Cols + OptMidColsCount - 1) / OptMidColsCount) * s.SpacingBetweenMidCols;
|
||||
s.PosDecodingEnd = s.PosDecodingStart + Cols * s.GlyphWidth;
|
||||
} else if (OptShowAscii) {
|
||||
s.PosAsciiStart = s.PosHexEnd + s.GlyphWidth * 1;
|
||||
if (OptMidColsCount > 0)
|
||||
s.PosAsciiStart += (float)((Cols + OptMidColsCount - 1) / OptMidColsCount) * s.SpacingBetweenMidCols;
|
||||
s.PosAsciiEnd = s.PosAsciiStart + Cols * s.GlyphWidth;
|
||||
} else if (OptShowAdvancedDecoding) {
|
||||
s.PosDecodingStart = s.PosHexEnd + s.GlyphWidth * 1;
|
||||
if (OptMidColsCount > 0)
|
||||
s.PosDecodingStart += (float)((Cols + OptMidColsCount - 1) / OptMidColsCount) * s.SpacingBetweenMidCols;
|
||||
s.PosDecodingEnd = s.PosDecodingStart + Cols * s.GlyphWidth;
|
||||
}
|
||||
s.WindowWidth = s.PosAsciiEnd + style.ScrollbarSize + style.WindowPadding.x * 2 + s.GlyphWidth;
|
||||
}
|
||||
|
||||
// Standalone Memory Editor window
|
||||
void DrawWindow(const char* title, bool *p_open, void* mem_data, size_t mem_size, size_t base_display_addr = 0x0000)
|
||||
{
|
||||
Sizes s;
|
||||
CalcSizes(s, mem_size, base_display_addr);
|
||||
|
||||
if (ImGui::Begin(title, p_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoNavInputs))
|
||||
{
|
||||
if (DataPreviewAddr != DataPreviewAddrOld || DataPreviewAddrEnd != DataPreviewAddrEndOld) {
|
||||
hex::Region selectionRegion = { std::min(DataPreviewAddr, DataPreviewAddrEnd) + base_display_addr, (std::max(DataPreviewAddr, DataPreviewAddrEnd) - std::min(DataPreviewAddr, DataPreviewAddrEnd)) + 1 };
|
||||
hex::EventManager::post<hex::EventRegionSelected>(selectionRegion);
|
||||
}
|
||||
|
||||
DataPreviewAddrOld = DataPreviewAddr;
|
||||
DataPreviewAddrEndOld = DataPreviewAddrEnd;
|
||||
|
||||
if (mem_size > 0)
|
||||
DrawContents(mem_data, mem_size, base_display_addr);
|
||||
|
||||
if (ContentsWidthChanged)
|
||||
{
|
||||
CalcSizes(s, mem_size, base_display_addr);
|
||||
ImGui::SetWindowSize(ImVec2(s.WindowWidth, ImGui::GetWindowSize().y));
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
}
|
||||
|
||||
// Memory Editor contents only
|
||||
void DrawContents(void* mem_data_void, size_t mem_size, size_t base_display_addr = 0x0000)
|
||||
{
|
||||
if (Cols < 1)
|
||||
Cols = 1;
|
||||
|
||||
ImU8* mem_data = (ImU8*)mem_data_void;
|
||||
Sizes s;
|
||||
CalcSizes(s, mem_size, base_display_addr);
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
|
||||
// We begin into our scrolling region with the 'ImGuiWindowFlags_NoMove' in order to prevent click from moving the window.
|
||||
// This is used as a facility since our main click detection code doesn't assign an ActiveId so the click would normally be caught as a window-move.
|
||||
const float height_separator = style.ItemSpacing.y;
|
||||
float footer_height = 0;
|
||||
if (OptShowOptions)
|
||||
footer_height += height_separator + ImGui::GetFrameHeightWithSpacing() * 2;
|
||||
|
||||
ImGui::BeginChild("offset", ImVec2(0, s.LineHeight), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav);
|
||||
ImGui::Text("%*c ", s.AddrDigitsCount, ' ');
|
||||
for (int i = 0; i < Cols; i++) {
|
||||
float byte_pos_x = s.PosHexStart + s.HexCellWidth * i;
|
||||
if (OptMidColsCount > 0)
|
||||
byte_pos_x += (float)(i / OptMidColsCount) * s.SpacingBetweenMidCols;
|
||||
ImGui::SameLine(byte_pos_x);
|
||||
ImGui::TextFormatted("{:02X}", i + (base_display_addr % Cols));
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::BeginChild("##scrolling", ImVec2(0, -footer_height), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
|
||||
|
||||
|
||||
|
||||
// We are not really using the clipper API correctly here, because we rely on visible_start_addr/visible_end_addr for our scrolling function.
|
||||
ImGuiListClipper clipper;
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
const int line_total_count = (int)((mem_size + Cols - 1) / Cols);
|
||||
clipper.Begin(line_total_count, s.LineHeight);
|
||||
const size_t visible_start_addr = clipper.DisplayStart * Cols;
|
||||
const size_t visible_end_addr = clipper.DisplayEnd * Cols;
|
||||
const size_t visible_count = visible_end_addr - visible_start_addr;
|
||||
|
||||
bool data_next = false;
|
||||
|
||||
if (DataEditingAddr >= mem_size)
|
||||
DataEditingAddr = (size_t)-1;
|
||||
if (DataPreviewAddr >= mem_size)
|
||||
DataPreviewAddr = (size_t)-1;
|
||||
if (DataPreviewAddrEnd >= mem_size)
|
||||
DataPreviewAddrEnd = (size_t)-1;
|
||||
|
||||
size_t data_editing_addr_backup = DataEditingAddr;
|
||||
size_t data_preview_addr_backup = DataPreviewAddr;
|
||||
size_t data_editing_addr_next = (size_t)-1;
|
||||
size_t data_preview_addr_next = (size_t)-1;
|
||||
|
||||
if (ImGui::IsWindowFocused()) {
|
||||
// Move cursor but only apply on next frame so scrolling with be synchronized (because currently we can't change the scrolling while the window is being rendered)
|
||||
if (DataEditingAddr != (size_t)-1) {
|
||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)) && DataEditingAddr >= (size_t)Cols) { data_editing_addr_next = DataEditingAddr - Cols; DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)) && DataEditingAddr < mem_size - Cols) { data_editing_addr_next = DataEditingAddr + Cols; DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)) && DataEditingAddr > 0) { data_editing_addr_next = DataEditingAddr - 1; DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)) && DataEditingAddr < mem_size - 1) { data_editing_addr_next = DataEditingAddr + 1; DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageUp)) && DataEditingAddr > 0) { data_editing_addr_next = std::max<i64>(0, DataEditingAddr - visible_count); DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageDown)) && DataEditingAddr < mem_size - 1) { data_editing_addr_next = std::min<i64>(mem_size - 1, DataEditingAddr + visible_count); DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)) && DataEditingAddr > 0) { data_editing_addr_next = 0; DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)) && DataEditingAddr < mem_size - 1) { data_editing_addr_next = mem_size - 1; DataEditingTakeFocus = true; }
|
||||
} else if (DataPreviewAddr != (size_t)-1) {
|
||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)) && DataPreviewAddr >= (size_t)Cols) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr - Cols; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)) && DataPreviewAddr < mem_size - Cols) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr + Cols; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)) && DataPreviewAddr > 0) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr - 1; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)) && DataPreviewAddr < mem_size - 1) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr + 1; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageUp)) && DataPreviewAddr > 0) { DataPreviewAddr = data_preview_addr_next = std::max<i64>(0, DataPreviewAddr - visible_count); if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageDown)) && DataPreviewAddr < mem_size - 1) { DataPreviewAddr = data_preview_addr_next = std::min<i64>(mem_size - 1, DataPreviewAddr + visible_count); if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)) && DataPreviewAddr > 0) { DataPreviewAddr = data_preview_addr_next = 0; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)) && DataPreviewAddr < mem_size - 1) { DataPreviewAddr = data_preview_addr_next = mem_size - 1; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
}
|
||||
} else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape))) {
|
||||
DataPreviewAddr = DataPreviewAddrOld = DataPreviewAddrEnd = DataPreviewAddrEndOld = data_preview_addr_next = (size_t)-1;
|
||||
HighlightMin = HighlightMax = (size_t)-1;
|
||||
|
||||
hex::EventManager::post<hex::EventRegionSelected>(hex::Region{ (size_t)-1, 0 });
|
||||
}
|
||||
|
||||
if (data_preview_addr_next != (size_t)-1 && (data_preview_addr_next / Cols) != (data_preview_addr_backup / Cols))
|
||||
{
|
||||
// Track cursor movements
|
||||
const int scroll_offset = ((int)(data_preview_addr_next / Cols) - (int)(data_preview_addr_backup / Cols));
|
||||
const bool scroll_desired = (scroll_offset < 0 && data_preview_addr_next < visible_start_addr + Cols * 2) || (scroll_offset > 0 && data_preview_addr_next > visible_end_addr - Cols * 2);
|
||||
if (scroll_desired)
|
||||
ImGui::SetScrollY(ImGui::GetScrollY() + scroll_offset * s.LineHeight);
|
||||
}
|
||||
if (data_editing_addr_next != (size_t)-1 && (data_editing_addr_next / Cols) != (data_editing_addr_backup / Cols))
|
||||
{
|
||||
// Track cursor movements
|
||||
const int scroll_offset = ((int)(data_editing_addr_next / Cols) - (int)(data_editing_addr_backup / Cols));
|
||||
const bool scroll_desired = (scroll_offset < 0 && data_editing_addr_next < visible_start_addr + Cols * 2) || (scroll_offset > 0 && data_editing_addr_next > visible_end_addr - Cols * 2);
|
||||
if (scroll_desired)
|
||||
ImGui::SetScrollY(ImGui::GetScrollY() + scroll_offset * s.LineHeight);
|
||||
}
|
||||
|
||||
// Draw vertical separator
|
||||
ImVec2 window_pos = ImGui::GetWindowPos();
|
||||
float scrollX = ImGui::GetScrollX();
|
||||
|
||||
if (OptShowAscii)
|
||||
draw_list->AddLine(ImVec2(window_pos.x + s.PosAsciiStart - s.GlyphWidth - scrollX, window_pos.y), ImVec2(window_pos.x + s.PosAsciiStart - s.GlyphWidth - scrollX, window_pos.y + 9999), ImGui::GetColorU32(ImGuiCol_Border));
|
||||
if (OptShowAdvancedDecoding)
|
||||
draw_list->AddLine(ImVec2(window_pos.x + s.PosDecodingStart - s.GlyphWidth - scrollX, window_pos.y), ImVec2(window_pos.x + s.PosDecodingStart - s.GlyphWidth - scrollX, window_pos.y + 9999), ImGui::GetColorU32(ImGuiCol_Border));
|
||||
|
||||
const ImU32 color_text = ImGui::GetColorU32(ImGuiCol_Text);
|
||||
const ImU32 color_disabled = OptGreyOutZeroes ? ImGui::GetColorU32(ImGuiCol_TextDisabled) : color_text;
|
||||
|
||||
const char* format_address = OptUpperCaseHex ? "%0*" _PRISizeT "X: " : "%0*" _PRISizeT "x: ";
|
||||
const char* format_data = OptUpperCaseHex ? "%0*" _PRISizeT "X" : "%0*" _PRISizeT "x";
|
||||
const char* format_byte = OptUpperCaseHex ? "%02X" : "%02x";
|
||||
const char* format_byte_space = OptUpperCaseHex ? "%02X " : "%02x ";
|
||||
|
||||
bool tooltipShown = false;
|
||||
while (clipper.Step())
|
||||
{
|
||||
for (int line_i = clipper.DisplayStart; line_i < clipper.DisplayEnd; line_i++) // display only visible lines
|
||||
{
|
||||
size_t addr = (size_t)(line_i * Cols);
|
||||
ImGui::Text(format_address, s.AddrDigitsCount, base_display_addr + addr);
|
||||
|
||||
// Draw Hexadecimal
|
||||
for (int n = 0; n < Cols && addr < mem_size; n++, addr++)
|
||||
{
|
||||
float byte_pos_x = s.PosHexStart + s.HexCellWidth * n;
|
||||
if (OptMidColsCount > 0)
|
||||
byte_pos_x += (float)(n / OptMidColsCount) * s.SpacingBetweenMidCols;
|
||||
ImGui::SameLine(byte_pos_x);
|
||||
|
||||
// Draw highlight
|
||||
bool is_highlight_from_user_range = (addr >= HighlightMin && addr < HighlightMax);
|
||||
bool is_highlight_from_user_func = (HighlightFn && HighlightFn(mem_data, addr, false));
|
||||
bool is_highlight_from_preview = (addr >= DataPreviewAddr && addr <= DataPreviewAddrEnd) || (addr >= DataPreviewAddrEnd && addr <= DataPreviewAddr);
|
||||
if (is_highlight_from_user_range || is_highlight_from_user_func || is_highlight_from_preview)
|
||||
{
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos() - ImVec2(ImGui::GetStyle().CellPadding.x / 2, 0);
|
||||
float highlight_width = s.GlyphWidth * 2 + ImGui::GetStyle().CellPadding.x / 2;
|
||||
bool is_next_byte_highlighted = (addr + 1 < mem_size) &&
|
||||
((HighlightMax != (size_t)-1 && addr + 1 < HighlightMax) ||
|
||||
(HighlightFn && HighlightFn(mem_data, addr + 1, true)) ||
|
||||
((addr + 1) >= DataPreviewAddr && (addr + 1) <= DataPreviewAddrEnd) || ((addr + 1) >= DataPreviewAddrEnd && (addr + 1) <= DataPreviewAddr));
|
||||
if (is_next_byte_highlighted)
|
||||
{
|
||||
highlight_width = s.HexCellWidth;
|
||||
if (OptMidColsCount > 0 && n > 0 && (n + 1) < Cols && ((n + 1) % OptMidColsCount) == 0)
|
||||
highlight_width += s.SpacingBetweenMidCols;
|
||||
}
|
||||
|
||||
ImU32 color = HighlightColor;
|
||||
if ((is_highlight_from_user_range + is_highlight_from_user_func + is_highlight_from_preview) > 1)
|
||||
color = (ImAlphaBlendColors(HighlightColor, 0x60C08080) & 0x00FFFFFF) | 0x90000000;
|
||||
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + highlight_width, pos.y + s.LineHeight), color);
|
||||
|
||||
if (is_highlight_from_preview) {
|
||||
size_t min = std::min(DataPreviewAddr, DataPreviewAddrEnd);
|
||||
size_t max = std::max(DataPreviewAddr, DataPreviewAddrEnd);
|
||||
|
||||
// Draw vertical line at the left of first byte and the start of the line
|
||||
if (n == 0 || addr == min)
|
||||
draw_list->AddLine(pos, pos + ImVec2(0, s.LineHeight), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
|
||||
|
||||
// Draw vertical line at the right of the last byte and the end of the line
|
||||
if (n == Cols - 1 || addr == max) {
|
||||
draw_list->AddRectFilled(pos + ImVec2(highlight_width, 0), pos + ImVec2(highlight_width + 1, s.LineHeight), color);
|
||||
draw_list->AddLine(pos + ImVec2(highlight_width + 1, -1), pos + ImVec2(highlight_width + 1, s.LineHeight), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
|
||||
}
|
||||
|
||||
// Draw horizontal line at the top of the bytes
|
||||
if ((addr - Cols) < min)
|
||||
draw_list->AddLine(pos, pos + ImVec2(highlight_width + 1, 0), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
|
||||
|
||||
// Draw horizontal line at the bottom of the bytes
|
||||
if ((addr + Cols) == (max + 1) && OptMidColsCount > 0 && n > 0 && (n + 1) < Cols && ((n + 1) % OptMidColsCount) == 1)
|
||||
draw_list->AddLine(pos + ImVec2(-s.SpacingBetweenMidCols, s.LineHeight), pos + ImVec2(highlight_width + 1, s.LineHeight), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
|
||||
else if ((addr + Cols) > max)
|
||||
draw_list->AddLine(pos + ImVec2(0, s.LineHeight), pos + ImVec2(highlight_width + 1, s.LineHeight), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
if (DataEditingAddr == addr)
|
||||
{
|
||||
// Display text input on current byte
|
||||
bool data_write = false;
|
||||
ImGui::PushID((void*)addr);
|
||||
if (DataEditingTakeFocus)
|
||||
{
|
||||
ImGui::SetKeyboardFocusHere();
|
||||
ImGui::CaptureKeyboardFromApp(true);
|
||||
sprintf(AddrInputBuf, format_data, s.AddrDigitsCount, base_display_addr + addr);
|
||||
sprintf(DataInputBuf, format_byte, ReadFn ? ReadFn(mem_data, addr) : mem_data[addr]);
|
||||
}
|
||||
ImGui::PushItemWidth(s.GlyphWidth * 2);
|
||||
struct UserData
|
||||
{
|
||||
// FIXME: We should have a way to retrieve the text edit cursor position more easily in the API, this is rather tedious. This is such a ugly mess we may be better off not using InputText() at all here.
|
||||
static int Callback(ImGuiInputTextCallbackData* data)
|
||||
{
|
||||
UserData* user_data = (UserData*)data->UserData;
|
||||
if (!data->HasSelection())
|
||||
user_data->CursorPos = data->CursorPos;
|
||||
if (data->SelectionStart == 0 && data->SelectionEnd == data->BufTextLen)
|
||||
{
|
||||
// When not editing a byte, always rewrite its content (this is a bit tricky, since InputText technically "owns" the master copy of the buffer we edit it in there)
|
||||
data->DeleteChars(0, data->BufTextLen);
|
||||
data->InsertChars(0, user_data->CurrentBufOverwrite);
|
||||
data->SelectionStart = 0;
|
||||
data->SelectionEnd = 2;
|
||||
data->CursorPos = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
char CurrentBufOverwrite[3]; // Input
|
||||
int CursorPos; // Output
|
||||
};
|
||||
UserData user_data;
|
||||
user_data.CursorPos = -1;
|
||||
sprintf(user_data.CurrentBufOverwrite, format_byte, ReadFn ? ReadFn(mem_data, addr) : mem_data[addr]);
|
||||
ImGuiInputTextFlags flags = ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoHorizontalScroll | ImGuiInputTextFlags_AlwaysInsertMode | ImGuiInputTextFlags_CallbackAlways;
|
||||
if (ImGui::InputText("##data", DataInputBuf, 32, flags, UserData::Callback, &user_data))
|
||||
data_write = data_next = true;
|
||||
else if (!DataEditingTakeFocus && !ImGui::IsItemActive())
|
||||
DataEditingAddr = data_editing_addr_next = (size_t)-1;
|
||||
DataEditingTakeFocus = false;
|
||||
ImGui::PopItemWidth();
|
||||
if (user_data.CursorPos >= 2)
|
||||
data_write = data_next = true;
|
||||
if (data_editing_addr_next != (size_t)-1)
|
||||
data_write = data_next = false;
|
||||
unsigned int data_input_value = 0;
|
||||
if (data_write && sscanf(DataInputBuf, "%X", &data_input_value) == 1)
|
||||
{
|
||||
if (WriteFn)
|
||||
WriteFn(mem_data, addr, (ImU8)data_input_value);
|
||||
else
|
||||
mem_data[addr] = (ImU8)data_input_value;
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
else
|
||||
{
|
||||
// NB: The trailing space is not visible but ensure there's no gap that the mouse cannot click on.
|
||||
ImU8 b = ReadFn ? ReadFn(mem_data, addr) : mem_data[addr];
|
||||
|
||||
if (OptShowHexII)
|
||||
{
|
||||
if ((b >= 32 && b < 128))
|
||||
ImGui::Text(".%c ", b);
|
||||
else if (b == 0xFF && OptGreyOutZeroes)
|
||||
ImGui::TextDisabled("## ");
|
||||
else if (b == 0x00)
|
||||
ImGui::Text(" ");
|
||||
else
|
||||
ImGui::Text(format_byte_space, b);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (b == 0 && OptGreyOutZeroes)
|
||||
ImGui::TextDisabled("00 ");
|
||||
else
|
||||
ImGui::Text(format_byte_space, b);
|
||||
}
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0) && !ImGui::GetIO().KeyShift)
|
||||
{
|
||||
if (!ReadOnly && ImGui::IsMouseDoubleClicked(0)) {
|
||||
DataEditingTakeFocus = true;
|
||||
data_editing_addr_next = addr;
|
||||
}
|
||||
|
||||
DataPreviewAddr = addr;
|
||||
DataPreviewAddrEnd = addr;
|
||||
}
|
||||
if (ImGui::IsItemHovered() && ((ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyShift) || ImGui::IsMouseDragging(0))) {
|
||||
DataPreviewAddrEnd = addr;
|
||||
}
|
||||
if (ImGui::IsItemHovered() && !tooltipShown) {
|
||||
if (HoverFn) {
|
||||
HoverFn(mem_data, addr);
|
||||
tooltipShown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (OptShowAscii)
|
||||
{
|
||||
// Draw ASCII values
|
||||
ImGui::SameLine(s.PosAsciiStart);
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
addr = line_i * Cols;
|
||||
|
||||
ImGui::PushID(-1);
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(s.GlyphWidth, s.LineHeight));
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
for (int n = 0; n < Cols && addr < mem_size; n++, addr++)
|
||||
{
|
||||
if (addr == DataEditingAddr)
|
||||
{
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_FrameBg));
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_TextSelectedBg));
|
||||
}
|
||||
unsigned char c = ReadFn ? ReadFn(mem_data, addr) : mem_data[addr];
|
||||
char display_c = (c < 32 || c >= 128) ? '.' : c;
|
||||
draw_list->AddText(pos, (display_c == c) ? color_text : color_disabled, &display_c, &display_c + 1);
|
||||
|
||||
// Draw highlight
|
||||
bool is_highlight_from_user_range = (addr >= HighlightMin && addr < HighlightMax);
|
||||
bool is_highlight_from_user_func = (HighlightFn && HighlightFn(mem_data, addr, false));
|
||||
bool is_highlight_from_preview = (addr >= DataPreviewAddr && addr <= DataPreviewAddrEnd) || (addr >= DataPreviewAddrEnd && addr <= DataPreviewAddr);
|
||||
if (is_highlight_from_user_range || is_highlight_from_user_func || is_highlight_from_preview)
|
||||
{
|
||||
ImU32 color = HighlightColor;
|
||||
if ((is_highlight_from_user_range + is_highlight_from_user_func + is_highlight_from_preview) > 1)
|
||||
color = (ImAlphaBlendColors(HighlightColor, 0x60C08080) & 0x00FFFFFF) | 0x90000000;
|
||||
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), color);
|
||||
}
|
||||
|
||||
|
||||
ImGui::PushID(line_i * Cols + n);
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(s.GlyphWidth, s.LineHeight));
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0) && !ImGui::GetIO().KeyShift)
|
||||
{
|
||||
if (!ReadOnly && ImGui::IsMouseDoubleClicked(0)) {
|
||||
DataEditingTakeFocus = true;
|
||||
data_editing_addr_next = addr;
|
||||
}
|
||||
|
||||
DataPreviewAddr = addr;
|
||||
DataPreviewAddrEnd = addr;
|
||||
|
||||
}
|
||||
if (ImGui::IsItemHovered() && ((ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyShift) || ImGui::IsMouseDragging(0))) {
|
||||
DataPreviewAddrEnd = addr;
|
||||
}
|
||||
|
||||
pos.x += s.GlyphWidth;
|
||||
}
|
||||
|
||||
ImGui::PushID(-1);
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(s.GlyphWidth, s.LineHeight));
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
if (OptShowAdvancedDecoding && DecodeFn) {
|
||||
// Draw decoded bytes
|
||||
ImGui::SameLine(s.PosDecodingStart);
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
addr = line_i * Cols;
|
||||
|
||||
ImGui::PushID(-1);
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(s.GlyphWidth, s.LineHeight));
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
for (int n = 0; n < Cols && addr < mem_size;)
|
||||
{
|
||||
auto decodedData = DecodeFn(mem_data, addr);
|
||||
|
||||
auto displayData = decodedData.data;
|
||||
auto glyphWidth = ImGui::CalcTextSize(displayData.c_str()).x + 1;
|
||||
|
||||
if (addr == DataEditingAddr)
|
||||
{
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + glyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_FrameBg));
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + glyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_TextSelectedBg));
|
||||
}
|
||||
|
||||
draw_list->AddText(pos, decodedData.color, displayData.c_str(), displayData.c_str() + displayData.length());
|
||||
|
||||
// Draw highlight
|
||||
bool is_highlight_from_user_range = (addr >= HighlightMin && addr < HighlightMax);
|
||||
bool is_highlight_from_user_func = (HighlightFn && HighlightFn(mem_data, addr, false));
|
||||
bool is_highlight_from_preview = (addr >= DataPreviewAddr && addr <= DataPreviewAddrEnd) || (addr >= DataPreviewAddrEnd && addr <= DataPreviewAddr);
|
||||
if (is_highlight_from_user_range || is_highlight_from_user_func || is_highlight_from_preview)
|
||||
{
|
||||
ImU32 color = HighlightColor;
|
||||
if ((is_highlight_from_user_range + is_highlight_from_user_func + is_highlight_from_preview) > 1)
|
||||
color = (ImAlphaBlendColors(HighlightColor, 0x60C08080) & 0x00FFFFFF) | 0x90000000;
|
||||
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + glyphWidth, pos.y + s.LineHeight), color);
|
||||
}
|
||||
|
||||
|
||||
ImGui::PushID(line_i * Cols + n);
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(glyphWidth, s.LineHeight));
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0) && !ImGui::GetIO().KeyShift)
|
||||
{
|
||||
if (!ReadOnly && ImGui::IsMouseDoubleClicked(0)) {
|
||||
DataEditingTakeFocus = true;
|
||||
data_editing_addr_next = addr;
|
||||
}
|
||||
|
||||
DataPreviewAddr = addr;
|
||||
DataPreviewAddrEnd = addr;
|
||||
|
||||
}
|
||||
if (ImGui::IsItemHovered() && ((ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyShift) || ImGui::IsMouseDragging(0))) {
|
||||
DataPreviewAddrEnd = addr;
|
||||
}
|
||||
|
||||
pos.x += glyphWidth;
|
||||
|
||||
if (addr <= 1) {
|
||||
n++;
|
||||
addr++;
|
||||
} else {
|
||||
n += decodedData.advance;
|
||||
addr += decodedData.advance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::EndChild();
|
||||
|
||||
if (data_next && DataEditingAddr < mem_size)
|
||||
{
|
||||
DataEditingAddr = DataPreviewAddr = DataPreviewAddrEnd = DataEditingAddr + 1;
|
||||
DataEditingTakeFocus = true;
|
||||
}
|
||||
else if (data_editing_addr_next != (size_t)-1)
|
||||
{
|
||||
DataEditingAddr = DataPreviewAddr = DataPreviewAddrEnd = data_editing_addr_next;
|
||||
}
|
||||
|
||||
if (OptShowOptions)
|
||||
{
|
||||
ImGui::Separator();
|
||||
DrawOptionsLine(s, mem_data, mem_size, base_display_addr);
|
||||
}
|
||||
|
||||
// Notify the main window of our ideal child content size (FIXME: we are missing an API to get the contents size from the child)
|
||||
ImGui::SetCursorPosX(s.WindowWidth);
|
||||
}
|
||||
|
||||
void DrawOptionsLine(const Sizes& s, void* mem_data, size_t mem_size, size_t base_display_addr)
|
||||
{
|
||||
IM_UNUSED(mem_data);
|
||||
const char* format_range = OptUpperCaseHex ? "Range 0x%0*" _PRISizeT "X..0x%0*" _PRISizeT "X" : "Range 0x%0*" _PRISizeT "x..0x%0*" _PRISizeT "x";
|
||||
const char* format_selection = OptUpperCaseHex ? "Selection 0x%0*" _PRISizeT "X..0x%0*" _PRISizeT "X (%ld [0x%lX] %s)" : "Range 0x%0*" _PRISizeT "x..0x%0*" _PRISizeT "x (%ld [0x%lX] %s)";
|
||||
|
||||
if (this->OptShowExtraInfo) {
|
||||
ImGui::Text(format_range, s.AddrDigitsCount, base_display_addr, s.AddrDigitsCount, base_display_addr + mem_size - 1);
|
||||
if (DataPreviewAddr != (size_t)-1 && DataPreviewAddrEnd != (size_t)-1) {
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
|
||||
auto selectionStart = std::min(DataPreviewAddr, DataPreviewAddrEnd);
|
||||
auto selectionEnd = std::max(DataPreviewAddr, DataPreviewAddrEnd);
|
||||
|
||||
size_t regionSize = (selectionEnd - selectionStart) + 1;
|
||||
ImGui::Text(format_selection, s.AddrDigitsCount, base_display_addr + selectionStart, s.AddrDigitsCount, base_display_addr + selectionEnd, regionSize, regionSize, regionSize == 1 ? "byte" : "bytes");
|
||||
}
|
||||
}
|
||||
|
||||
if (GotoAddr != (size_t)-1)
|
||||
{
|
||||
if (GotoAddr < mem_size)
|
||||
{
|
||||
ImGui::BeginChild("##scrolling");
|
||||
ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + (GotoAddr / Cols) * ImGui::GetTextLineHeight());
|
||||
ImGui::EndChild();
|
||||
}
|
||||
GotoAddr = (size_t)-1;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsBigEndian()
|
||||
{
|
||||
uint16_t x = 1;
|
||||
char c[2];
|
||||
memcpy(c, &x, 2);
|
||||
return c[0] != 0;
|
||||
}
|
||||
|
||||
static void* EndianessCopyBigEndian(void* _dst, void* _src, size_t s, int is_little_endian)
|
||||
{
|
||||
if (is_little_endian)
|
||||
{
|
||||
uint8_t* dst = (uint8_t*)_dst;
|
||||
uint8_t* src = (uint8_t*)_src + s - 1;
|
||||
for (int i = 0, n = (int)s; i < n; ++i)
|
||||
memcpy(dst++, src--, 1);
|
||||
return _dst;
|
||||
}
|
||||
else
|
||||
{
|
||||
return memcpy(_dst, _src, s);
|
||||
}
|
||||
}
|
||||
|
||||
static void* EndianessCopyLittleEndian(void* _dst, void* _src, size_t s, int is_little_endian)
|
||||
{
|
||||
if (is_little_endian)
|
||||
{
|
||||
return memcpy(_dst, _src, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t* dst = (uint8_t*)_dst;
|
||||
uint8_t* src = (uint8_t*)_src + s - 1;
|
||||
for (int i = 0, n = (int)s; i < n; ++i)
|
||||
memcpy(dst++, src--, 1);
|
||||
return _dst;
|
||||
}
|
||||
}
|
||||
|
||||
void* EndianessCopy(void* dst, void* src, size_t size) const
|
||||
{
|
||||
static void* (*fp)(void*, void*, size_t, int) = NULL;
|
||||
if (fp == NULL)
|
||||
fp = IsBigEndian() ? EndianessCopyBigEndian : EndianessCopyLittleEndian;
|
||||
return fp(dst, src, size, PreviewEndianess);
|
||||
}
|
||||
};
|
||||
|
||||
#undef _PRISizeT
|
||||
#undef ImSnprintf
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
@ -1 +1 @@
|
||||
Subproject commit 0ad67f199db0ca65c9b25935553409480d1cdfd8
|
||||
Subproject commit 99f3be2cc26632fcfb68f53d2fcd3baf0b8c6387
|
@ -27,6 +27,22 @@ namespace hex {
|
||||
struct Region {
|
||||
u64 address;
|
||||
size_t size;
|
||||
|
||||
[[nodiscard]] constexpr bool isWithin(const Region &other) const {
|
||||
return (this->address >= other.address) && ((this->address + this->size) <= (other.address + other.size));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool overlaps(const Region &other) const {
|
||||
return ((this->address + this->size) >= other.address) && (this->address < (other.address + other.size));
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u64 getStartAddress() const {
|
||||
return this->address;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u64 getEndAddress() const {
|
||||
return this->address + this->size - 1;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -10,12 +10,16 @@
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
|
||||
using ImGuiDataType = int;
|
||||
using ImGuiInputTextFlags = int;
|
||||
|
||||
namespace pl {
|
||||
class Evaluator;
|
||||
}
|
||||
@ -378,6 +382,45 @@ namespace hex {
|
||||
std::vector<impl::Entry> &getEntries();
|
||||
|
||||
}
|
||||
|
||||
namespace HexEditor {
|
||||
|
||||
class DataVisualizer {
|
||||
public:
|
||||
DataVisualizer(u16 bytesPerCell, u16 maxCharsPerCell)
|
||||
: m_bytesPerCell(bytesPerCell), m_maxCharsPerCell(maxCharsPerCell) {}
|
||||
|
||||
virtual ~DataVisualizer() = default;
|
||||
|
||||
virtual void draw(u64 address, const u8 *data, size_t size, bool upperCase) = 0;
|
||||
virtual bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) = 0;
|
||||
|
||||
[[nodiscard]] u16 getBytesPerCell() const { return this->m_bytesPerCell; }
|
||||
[[nodiscard]] u16 getMaxCharsPerCell() const { return this->m_maxCharsPerCell; }
|
||||
|
||||
protected:
|
||||
const static int TextInputFlags;
|
||||
|
||||
bool drawDefaultEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const;
|
||||
private:
|
||||
u16 m_bytesPerCell;
|
||||
u16 m_maxCharsPerCell;
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
|
||||
void addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer);
|
||||
|
||||
std::map<std::string, DataVisualizer*> &getVisualizers();
|
||||
|
||||
}
|
||||
|
||||
template<hex::derived_from<DataVisualizer> T, typename... Args>
|
||||
void addDataVisualizer(const std::string &unlocalizedName, Args &&...args) {
|
||||
return impl::addDataVisualizer(unlocalizedName, new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -129,6 +129,6 @@ namespace hex {
|
||||
EVENT_DEF(RequestOpenPopup, std::string);
|
||||
EVENT_DEF(RequestCreateProvider, std::string, hex::prv::Provider **);
|
||||
|
||||
EVENT_DEF(QuerySelection, Region &);
|
||||
EVENT_DEF(QuerySelection, std::optional<Region> &);
|
||||
|
||||
}
|
@ -6,6 +6,8 @@
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
#include <map>
|
||||
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/api/task.hpp>
|
||||
@ -31,37 +33,69 @@ namespace hex {
|
||||
|
||||
namespace HexEditor {
|
||||
|
||||
using TooltipFunction = std::function<void(u64, const u8*, size_t)>;
|
||||
|
||||
class Highlighting {
|
||||
public:
|
||||
Highlighting() = default;
|
||||
Highlighting(Region region, color_t color, std::string tooltip = "");
|
||||
Highlighting(Region region, color_t color);
|
||||
|
||||
[[nodiscard]] const Region &getRegion() const { return this->m_region; }
|
||||
[[nodiscard]] const color_t &getColor() const { return this->m_color; }
|
||||
[[nodiscard]] const std::string &getTooltip() const { return this->m_tooltip; }
|
||||
|
||||
private:
|
||||
Region m_region = {};
|
||||
color_t m_color = 0x00;
|
||||
std::string m_tooltip;
|
||||
};
|
||||
|
||||
class Tooltip {
|
||||
public:
|
||||
Tooltip() = default;
|
||||
Tooltip(Region region, std::string value, color_t color);
|
||||
|
||||
[[nodiscard]] const Region &getRegion() const { return this->m_region; }
|
||||
[[nodiscard]] const color_t &getColor() const { return this->m_color; }
|
||||
[[nodiscard]] const std::string &getValue() const { return this->m_value; }
|
||||
|
||||
private:
|
||||
Region m_region = {};
|
||||
std::string m_value;
|
||||
color_t m_color = 0x00;
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
|
||||
using HighlightingFunction = std::function<std::optional<Highlighting>(u64)>;
|
||||
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t)>;
|
||||
|
||||
std::map<u32, Highlighting> &getHighlights();
|
||||
std::map<u32, HighlightingFunction> &getHighlightingFunctions();
|
||||
std::map<u32, Highlighting> &getBackgroundHighlights();
|
||||
std::map<u32, HighlightingFunction> &getBackgroundHighlightingFunctions();
|
||||
std::map<u32, Highlighting> &getForegroundHighlights();
|
||||
std::map<u32, HighlightingFunction> &getForegroundHighlightingFunctions();
|
||||
std::map<u32, Tooltip> &getTooltips();
|
||||
std::map<u32, TooltipFunction> &getTooltipFunctions();
|
||||
|
||||
}
|
||||
|
||||
u32 addHighlight(const Region ®ion, color_t color, const std::string &tooltip = "");
|
||||
void removeHighlight(u32 id);
|
||||
u32 addBackgroundHighlight(const Region ®ion, color_t color);
|
||||
void removeBackgroundHighlight(u32 id);
|
||||
|
||||
u32 addHighlightingProvider(const impl::HighlightingFunction &function);
|
||||
void removeHighlightingProvider(u32 id);
|
||||
u32 addForegroundHighlight(const Region ®ion, color_t color);
|
||||
void removeForegroundHighlight(u32 id);
|
||||
|
||||
Region getSelection();
|
||||
u32 addTooltip(Region region, std::string value, color_t color);
|
||||
void removeTooltip(u32 id);
|
||||
|
||||
u32 addTooltipProvider(TooltipFunction function);
|
||||
void removeTooltipProvider(u32 id);
|
||||
|
||||
u32 addBackgroundHighlightingProvider(const impl::HighlightingFunction &function);
|
||||
void removeBackgroundHighlightingProvider(u32 id);
|
||||
|
||||
u32 addForegroundHighlightingProvider(const impl::HighlightingFunction &function);
|
||||
void removeForegroundHighlightingProvider(u32 id);
|
||||
|
||||
bool isSelectionValid();
|
||||
std::optional<Region> getSelection();
|
||||
void setSelection(const Region ®ion);
|
||||
void setSelection(u64 address, size_t size);
|
||||
|
||||
@ -76,8 +110,6 @@ namespace hex {
|
||||
std::string comment;
|
||||
u32 color;
|
||||
bool locked;
|
||||
|
||||
u32 highlightId;
|
||||
};
|
||||
|
||||
void add(u64 address, size_t size, const std::string &name, const std::string &comment, color_t color = 0x00000000);
|
||||
|
@ -188,6 +188,24 @@ namespace hex {
|
||||
return T(1) << bit_width(T(x - 1));
|
||||
}
|
||||
|
||||
template<hex::integral T, hex::integral U>
|
||||
auto powi(T base, U exp) {
|
||||
using ResultType = decltype(T{} * U{});
|
||||
|
||||
if (exp < 0)
|
||||
return ResultType(0);
|
||||
|
||||
ResultType result = 1;
|
||||
|
||||
while (exp != 0) {
|
||||
if ((exp & 0b1) == 0b1)
|
||||
result *= base;
|
||||
exp >>= 1;
|
||||
base *= base;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
void moveToVector(std::vector<T> &buffer, T &&first, Args &&...rest) {
|
||||
buffer.push_back(std::move(first));
|
||||
@ -287,6 +305,13 @@ namespace hex {
|
||||
return *value;
|
||||
}
|
||||
|
||||
template<hex::integral T>
|
||||
T alignTo(T value, T alignment) {
|
||||
T remainder = value % alignment;
|
||||
|
||||
return remainder != 0 ? value + (alignment - remainder) : value;
|
||||
}
|
||||
|
||||
bool isProcessElevated();
|
||||
|
||||
std::optional<std::string> getEnvironmentVariable(const std::string &env);
|
||||
|
223
lib/libimhex/include/hex/providers/buffered_reader.hpp
Normal file
223
lib/libimhex/include/hex/providers/buffered_reader.hpp
Normal file
@ -0,0 +1,223 @@
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
class BufferedReader {
|
||||
public:
|
||||
explicit BufferedReader(Provider *provider, size_t bufferSize = 0xFF'FFFF) : m_provider(provider), m_maxBufferSize(bufferSize), m_buffer(bufferSize) { }
|
||||
|
||||
void seek(u64 address) {
|
||||
this->m_baseAddress = address;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<u8> read(u64 address, size_t size) {
|
||||
if (size > this->m_buffer.size()) {
|
||||
std::vector<u8> result;
|
||||
result.resize(size);
|
||||
|
||||
this->m_provider->read(address, result.data(), result.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
this->updateBuffer(address, size);
|
||||
|
||||
auto result = &this->m_buffer[address - this->m_baseAddress];
|
||||
|
||||
return { result, result + std::min(size, this->m_buffer.size()) };
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<u8> readReverse(u64 address, size_t size) {
|
||||
if (size > this->m_buffer.size()) {
|
||||
std::vector<u8> result;
|
||||
result.resize(size);
|
||||
|
||||
this->m_provider->read(address, result.data(), result.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
this->updateBuffer(address - std::min<u64>(address, this->m_buffer.size()), size);
|
||||
|
||||
auto result = &this->m_buffer[address - this->m_baseAddress];
|
||||
|
||||
return { result, result + std::min(size, this->m_buffer.size()) };
|
||||
}
|
||||
|
||||
class Iterator {
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = u8;
|
||||
using pointer = const value_type*;
|
||||
using reference = const value_type&;
|
||||
|
||||
Iterator(BufferedReader *reader, u64 address) : m_reader(reader), m_address(address) {}
|
||||
|
||||
Iterator& operator++() {
|
||||
this->m_address++;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++(int) {
|
||||
auto copy = *this;
|
||||
this->m_address++;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
Iterator& operator+=(i64 offset) {
|
||||
this->m_address += offset;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator& operator-=(i64 offset) {
|
||||
this->m_address -= offset;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
value_type operator*() const {
|
||||
return (*this)[0];
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 getAddress() const {
|
||||
return this->m_address;
|
||||
}
|
||||
|
||||
difference_type operator-(const Iterator &other) const {
|
||||
return this->m_address - other.m_address;
|
||||
}
|
||||
|
||||
Iterator operator+(i64 offset) const {
|
||||
return { this->m_reader, this->m_address + offset };
|
||||
}
|
||||
|
||||
value_type operator[](i64 offset) const {
|
||||
auto result = this->m_reader->read(this->m_address + offset, 1);
|
||||
if (result.empty())
|
||||
return 0x00;
|
||||
|
||||
return result[0];
|
||||
}
|
||||
|
||||
friend bool operator== (const Iterator& left, const Iterator& right) { return left.m_address == right.m_address; };
|
||||
friend bool operator!= (const Iterator& left, const Iterator& right) { return left.m_address != right.m_address; };
|
||||
private:
|
||||
BufferedReader *m_reader;
|
||||
u64 m_address;
|
||||
};
|
||||
|
||||
class ReverseIterator {
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = u8;
|
||||
using pointer = const value_type*;
|
||||
using reference = const value_type&;
|
||||
|
||||
ReverseIterator(BufferedReader *reader, u64 address) : m_reader(reader), m_address(address) {}
|
||||
|
||||
ReverseIterator& operator++() {
|
||||
this->m_address--;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReverseIterator operator++(int) {
|
||||
auto copy = *this;
|
||||
this->m_address--;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
ReverseIterator& operator+=(i64 offset) {
|
||||
this->m_address -= offset;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReverseIterator& operator-=(i64 offset) {
|
||||
this->m_address += offset;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
value_type operator*() const {
|
||||
return (*this)[0];
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 getAddress() const {
|
||||
return this->m_address;
|
||||
}
|
||||
|
||||
difference_type operator-(const ReverseIterator &other) const {
|
||||
return other.m_address - this->m_address;
|
||||
}
|
||||
|
||||
ReverseIterator operator+(i64 offset) const {
|
||||
return { this->m_reader, this->m_address - offset };
|
||||
}
|
||||
|
||||
value_type operator[](i64 offset) const {
|
||||
auto result = this->m_reader->readReverse(this->m_address + offset, 1);
|
||||
if (result.empty())
|
||||
return 0x00;
|
||||
|
||||
return result[0];
|
||||
}
|
||||
|
||||
friend bool operator== (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address == right.m_address; };
|
||||
friend bool operator!= (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address != right.m_address; };
|
||||
|
||||
private:
|
||||
BufferedReader *m_reader;
|
||||
u64 m_address;
|
||||
};
|
||||
|
||||
Iterator begin() {
|
||||
return { this, this->m_baseAddress };
|
||||
}
|
||||
|
||||
Iterator end() {
|
||||
return { this, this->m_baseAddress + this->m_provider->getActualSize() };
|
||||
}
|
||||
|
||||
ReverseIterator rbegin() {
|
||||
return { this, this->m_baseAddress };
|
||||
}
|
||||
|
||||
ReverseIterator rend() {
|
||||
return { this, std::numeric_limits<u64>::max() };
|
||||
}
|
||||
|
||||
private:
|
||||
void updateBuffer(u64 address, size_t size) {
|
||||
if (!this->m_bufferValid || address < this->m_baseAddress || address + size > (this->m_baseAddress + this->m_buffer.size())) {
|
||||
const auto remainingBytes = this->m_provider->getActualSize() - address;
|
||||
if (remainingBytes < this->m_maxBufferSize)
|
||||
this->m_buffer.resize(remainingBytes);
|
||||
|
||||
this->m_provider->read(address, this->m_buffer.data(), this->m_buffer.size());
|
||||
this->m_baseAddress = address;
|
||||
this->m_bufferValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Provider *m_provider;
|
||||
|
||||
size_t m_maxBufferSize;
|
||||
bool m_bufferValid = false;
|
||||
u64 m_baseAddress = 0x00;
|
||||
std::vector<u8> m_buffer;
|
||||
};
|
||||
|
||||
}
|
@ -63,7 +63,6 @@ namespace ImGui {
|
||||
|
||||
void UnderlinedText(const char *label, ImColor color = ImGui::GetStyleColorVec4(ImGuiCol_Text), const ImVec2 &size_arg = ImVec2(0, 0));
|
||||
|
||||
void Disabled(const std::function<void()> &widgets, bool disabled);
|
||||
void TextSpinner(const char *label);
|
||||
|
||||
void Header(const char *label, bool firstEntry = false);
|
||||
@ -131,4 +130,8 @@ namespace ImGui {
|
||||
|
||||
bool InputText(const char* label, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputTextMultiline(const char* label, std::string &buffer, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
|
||||
bool InputScalarCallback(const char* label, ImGuiDataType data_type, void* p_data, const char* format, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data);
|
||||
|
||||
void HideTooltip();
|
||||
}
|
@ -536,4 +536,50 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
namespace ContentRegistry::HexEditor {
|
||||
|
||||
const int DataVisualizer::TextInputFlags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_NoHorizontalScroll | ImGuiInputTextFlags_EnterReturnsTrue;
|
||||
|
||||
bool DataVisualizer::drawDefaultEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const {
|
||||
struct UserData {
|
||||
u8 *data;
|
||||
i32 maxChars;
|
||||
|
||||
bool editingDone;
|
||||
};
|
||||
|
||||
UserData userData = {
|
||||
.data = data,
|
||||
.maxChars = this->getMaxCharsPerCell(),
|
||||
|
||||
.editingDone = false
|
||||
};
|
||||
|
||||
ImGui::PushID(reinterpret_cast<void*>(address));
|
||||
ImGui::InputScalarCallback("##editing_input", dataType, data, format, flags | TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int {
|
||||
auto &userData = *reinterpret_cast<UserData*>(data->UserData);
|
||||
|
||||
if (data->BufTextLen >= userData.maxChars)
|
||||
userData.editingDone = true;
|
||||
|
||||
return 0;
|
||||
}, &userData);
|
||||
ImGui::PopID();
|
||||
|
||||
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Enter);
|
||||
}
|
||||
|
||||
void impl::addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer) {
|
||||
getVisualizers().insert({ unlocalizedName, visualizer });
|
||||
|
||||
}
|
||||
|
||||
std::map<std::string, DataVisualizer*> &impl::getVisualizers() {
|
||||
static std::map<std::string, DataVisualizer*> visualizers;
|
||||
|
||||
return visualizers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -29,32 +29,55 @@ namespace hex {
|
||||
|
||||
namespace ImHexApi::HexEditor {
|
||||
|
||||
Highlighting::Highlighting(Region region, color_t color, std::string tooltip)
|
||||
: m_region(region), m_color(color), m_tooltip(std::move(tooltip)) {
|
||||
Highlighting::Highlighting(Region region, color_t color)
|
||||
: m_region(region), m_color(color) {
|
||||
}
|
||||
|
||||
Tooltip::Tooltip(Region region, std::string value, color_t color) : m_region(region), m_value(std::move(value)), m_color(color) {
|
||||
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
|
||||
static std::map<u32, Highlighting> s_highlights;
|
||||
std::map<u32, Highlighting> &getHighlights() {
|
||||
return s_highlights;
|
||||
static std::map<u32, Highlighting> s_backgroundHighlights;
|
||||
std::map<u32, Highlighting> &getBackgroundHighlights() {
|
||||
return s_backgroundHighlights;
|
||||
}
|
||||
|
||||
static std::map<u32, HighlightingFunction> s_highlightingFunctions;
|
||||
std::map<u32, HighlightingFunction> &getHighlightingFunctions() {
|
||||
return s_highlightingFunctions;
|
||||
static std::map<u32, HighlightingFunction> s_backgroundHighlightingFunctions;
|
||||
std::map<u32, HighlightingFunction> &getBackgroundHighlightingFunctions() {
|
||||
return s_backgroundHighlightingFunctions;
|
||||
}
|
||||
|
||||
static std::map<u32, Highlighting> s_foregroundHighlights;
|
||||
std::map<u32, Highlighting> &getForegroundHighlights() {
|
||||
return s_foregroundHighlights;
|
||||
}
|
||||
|
||||
static std::map<u32, HighlightingFunction> s_foregroundHighlightingFunctions;
|
||||
std::map<u32, HighlightingFunction> &getForegroundHighlightingFunctions() {
|
||||
return s_foregroundHighlightingFunctions;
|
||||
}
|
||||
|
||||
static std::map<u32, Tooltip> s_tooltips;
|
||||
std::map<u32, Tooltip> &getTooltips() {
|
||||
return s_tooltips;
|
||||
}
|
||||
|
||||
static std::map<u32, TooltipFunction> s_tooltipFunctions;
|
||||
std::map<u32, TooltipFunction> &getTooltipFunctions() {
|
||||
return s_tooltipFunctions;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
u32 addHighlight(const Region ®ion, color_t color, const std::string &tooltip) {
|
||||
auto &highlights = impl::getHighlights();
|
||||
static u64 id = 0;
|
||||
u32 addBackgroundHighlight(const Region ®ion, color_t color) {
|
||||
static u32 id = 0;
|
||||
|
||||
id++;
|
||||
|
||||
highlights.insert({
|
||||
id, Highlighting {region, color, tooltip}
|
||||
impl::getBackgroundHighlights().insert({
|
||||
id, Highlighting {region, color}
|
||||
});
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
@ -62,37 +85,101 @@ namespace hex {
|
||||
return id;
|
||||
}
|
||||
|
||||
void removeHighlight(u32 id) {
|
||||
impl::getHighlights().erase(id);
|
||||
void removeBackgroundHighlight(u32 id) {
|
||||
impl::getBackgroundHighlights().erase(id);
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
}
|
||||
|
||||
u32 addHighlightingProvider(const impl::HighlightingFunction &function) {
|
||||
auto &highlightFuncs = impl::getHighlightingFunctions();
|
||||
u32 addBackgroundHighlightingProvider(const impl::HighlightingFunction &function) {
|
||||
static u32 id = 0;
|
||||
|
||||
auto id = highlightFuncs.size();
|
||||
id++;
|
||||
|
||||
highlightFuncs.insert({ id, function });
|
||||
impl::getBackgroundHighlightingFunctions().insert({ id, function });
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void removeHighlightingProvider(u32 id) {
|
||||
impl::getHighlightingFunctions().erase(id);
|
||||
void removeBackgroundHighlightingProvider(u32 id) {
|
||||
impl::getBackgroundHighlightingFunctions().erase(id);
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
}
|
||||
|
||||
Region getSelection() {
|
||||
static Region selectedRegion;
|
||||
EventManager::subscribe<EventRegionSelected>([](const Region ®ion) {
|
||||
selectedRegion = region;
|
||||
u32 addForegroundHighlight(const Region ®ion, color_t color) {
|
||||
static u32 id = 0;
|
||||
|
||||
id++;
|
||||
|
||||
impl::getForegroundHighlights().insert({
|
||||
id, Highlighting {region, color}
|
||||
});
|
||||
|
||||
return selectedRegion;
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void removeForegroundHighlight(u32 id) {
|
||||
impl::getForegroundHighlights().erase(id);
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
}
|
||||
|
||||
u32 addForegroundHighlightingProvider(const impl::HighlightingFunction &function) {
|
||||
static u32 id = 0;
|
||||
|
||||
id++;
|
||||
|
||||
impl::getForegroundHighlightingFunctions().insert({ id, function });
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void removeForegroundHighlightingProvider(u32 id) {
|
||||
impl::getForegroundHighlightingFunctions().erase(id);
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
}
|
||||
|
||||
static u32 tooltipId = 0;
|
||||
u32 addTooltip(Region region, std::string value, color_t color) {
|
||||
tooltipId++;
|
||||
impl::getTooltips().insert({ tooltipId, { region, std::move(value), color } });
|
||||
|
||||
return tooltipId;
|
||||
}
|
||||
|
||||
void removeTooltip(u32 id) {
|
||||
impl::getTooltips().erase(id);
|
||||
}
|
||||
|
||||
static u32 tooltipFunctionId;
|
||||
u32 addTooltipProvider(TooltipFunction function) {
|
||||
tooltipFunctionId++;
|
||||
impl::getTooltipFunctions().insert({ tooltipFunctionId, std::move(function) });
|
||||
|
||||
return tooltipFunctionId;
|
||||
}
|
||||
|
||||
void removeTooltipProvider(u32 id) {
|
||||
impl::getTooltipFunctions().erase(id);
|
||||
}
|
||||
|
||||
bool isSelectionValid() {
|
||||
return getSelection().has_value();
|
||||
}
|
||||
|
||||
std::optional<Region> getSelection() {
|
||||
std::optional<Region> selection;
|
||||
EventManager::post<QuerySelection>(selection);
|
||||
|
||||
return selection;
|
||||
}
|
||||
|
||||
void setSelection(const Region ®ion) {
|
||||
@ -210,7 +297,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
|
||||
static float s_globalScale;
|
||||
static float s_globalScale = 1.0;
|
||||
void setGlobalScale(float scale) {
|
||||
s_globalScale = scale;
|
||||
}
|
||||
|
@ -40,9 +40,7 @@ namespace hex {
|
||||
|
||||
if (delimiterPos == std::string::npos)
|
||||
continue;
|
||||
if (delimiterPos >= from.length())
|
||||
continue;
|
||||
if (delimiterPos >= to.length())
|
||||
if (delimiterPos >= line.length())
|
||||
continue;
|
||||
|
||||
from = line.substr(0, delimiterPos);
|
||||
|
@ -191,16 +191,6 @@ namespace ImGui {
|
||||
PopStyleColor();
|
||||
}
|
||||
|
||||
void Disabled(const std::function<void()> &widgets, bool disabled) {
|
||||
if (disabled) {
|
||||
BeginDisabled();
|
||||
widgets();
|
||||
EndDisabled();
|
||||
} else {
|
||||
widgets();
|
||||
}
|
||||
}
|
||||
|
||||
void TextSpinner(const char *label) {
|
||||
ImGui::Text("[%c] %s", "|/-\\"[ImU32(ImGui::GetTime() * 20) % 4], label);
|
||||
}
|
||||
@ -563,4 +553,41 @@ namespace ImGui {
|
||||
return ImGui::InputTextMultiline(label, buffer.data(), buffer.size() + 1, size, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
|
||||
}
|
||||
|
||||
bool InputScalarCallback(const char* label, ImGuiDataType data_type, void* p_data, const char* format, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) {
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
ImGuiContext& g = *GImGui;
|
||||
|
||||
if (format == NULL)
|
||||
format = DataTypeGetInfo(data_type)->PrintFmt;
|
||||
|
||||
char buf[64];
|
||||
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format);
|
||||
|
||||
bool value_changed = false;
|
||||
if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0)
|
||||
flags |= ImGuiInputTextFlags_CharsDecimal;
|
||||
flags |= ImGuiInputTextFlags_AutoSelectAll;
|
||||
flags |= ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselves by comparing the actual data rather than the string.
|
||||
|
||||
if (InputText(label, buf, IM_ARRAYSIZE(buf), flags, callback, user_data))
|
||||
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format);
|
||||
|
||||
if (value_changed)
|
||||
MarkItemEdited(g.LastItemData.ID);
|
||||
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
void HideTooltip() {
|
||||
char window_name[16];
|
||||
ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", GImGui->TooltipOverrideCount);
|
||||
if (ImGuiWindow* window = FindWindowByName(window_name); window != nullptr) {
|
||||
if (window->Active)
|
||||
window->Hidden = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -54,6 +54,8 @@ namespace hex {
|
||||
std::vector<int> m_pressedKeys;
|
||||
|
||||
std::fs::path m_imguiSettingsPath;
|
||||
|
||||
bool m_mouseButtonDown = false;
|
||||
};
|
||||
|
||||
}
|
@ -180,7 +180,7 @@ namespace hex::init {
|
||||
meanScale /= 2;
|
||||
#endif
|
||||
|
||||
if (meanScale <= 0) {
|
||||
if (meanScale <= 0.0) {
|
||||
meanScale = 1.0;
|
||||
}
|
||||
|
||||
|
@ -172,8 +172,11 @@ namespace hex::init {
|
||||
bool deleteSharedData() {
|
||||
ImHexApi::System::getInitArguments().clear();
|
||||
ImHexApi::Tasks::getDeferredCalls().clear();
|
||||
ImHexApi::HexEditor::impl::getHighlights().clear();
|
||||
ImHexApi::HexEditor::impl::getHighlightingFunctions().clear();
|
||||
ImHexApi::HexEditor::impl::getBackgroundHighlights().clear();
|
||||
ImHexApi::HexEditor::impl::getForegroundHighlights().clear();
|
||||
ImHexApi::HexEditor::impl::getBackgroundHighlightingFunctions().clear();
|
||||
ImHexApi::HexEditor::impl::getForegroundHighlightingFunctions().clear();
|
||||
ImHexApi::HexEditor::impl::getTooltips().clear();
|
||||
|
||||
while (ImHexApi::Provider::isValid())
|
||||
ImHexApi::Provider::remove(ImHexApi::Provider::get());
|
||||
|
@ -177,9 +177,10 @@ namespace hex {
|
||||
glfwWaitEvents();
|
||||
|
||||
} else {
|
||||
double timeout = (1.0 / 5.0) - (glfwGetTime() - this->m_lastFrameTime);
|
||||
timeout = timeout > 0 ? timeout : 0;
|
||||
glfwWaitEventsTimeout(ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) || Task::getRunningTaskCount() > 0 ? 0 : timeout);
|
||||
const bool frameRateThrottled = !(ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) || Task::getRunningTaskCount() > 0 || this->m_mouseButtonDown);
|
||||
const double timeout = std::max(0.0, (1.0 / 5.0) - (glfwGetTime() - this->m_lastFrameTime));
|
||||
|
||||
glfwWaitEventsTimeout(frameRateThrottled ? timeout : 0);
|
||||
}
|
||||
|
||||
|
||||
@ -568,23 +569,32 @@ namespace hex {
|
||||
win->frameEnd();
|
||||
});
|
||||
|
||||
glfwSetMouseButtonCallback(this->m_window, [](GLFWwindow *window, int button, int action, int mods) {
|
||||
hex::unused(button, mods);
|
||||
|
||||
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
|
||||
|
||||
if (action == GLFW_PRESS)
|
||||
win->m_mouseButtonDown = true;
|
||||
else if (action == GLFW_RELEASE)
|
||||
win->m_mouseButtonDown = false;
|
||||
});
|
||||
|
||||
glfwSetKeyCallback(this->m_window, [](GLFWwindow *window, int key, int scancode, int action, int mods) {
|
||||
auto keyName = glfwGetKeyName(key, scancode);
|
||||
if (keyName != nullptr)
|
||||
key = std::toupper(keyName[0]);
|
||||
|
||||
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
|
||||
auto &io = ImGui::GetIO();
|
||||
|
||||
if (action == GLFW_PRESS) {
|
||||
auto &io = ImGui::GetIO();
|
||||
|
||||
if (action == GLFW_PRESS || action == GLFW_REPEAT) {
|
||||
win->m_pressedKeys.push_back(key);
|
||||
io.KeysDown[key] = true;
|
||||
io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
|
||||
io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
|
||||
io.KeyAlt = (mods & GLFW_MOD_ALT) != 0;
|
||||
} else if (action == GLFW_RELEASE) {
|
||||
auto &io = ImGui::GetIO();
|
||||
io.KeysDown[key] = false;
|
||||
io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
|
||||
io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
|
||||
|
@ -20,6 +20,8 @@ add_library(${PROJECT_NAME} SHARED
|
||||
source/content/layouts.cpp
|
||||
source/content/main_menu_items.cpp
|
||||
source/content/welcome_screen.cpp
|
||||
source/content/data_visualizers.cpp
|
||||
source/content/events.cpp
|
||||
|
||||
source/content/providers/file_provider.cpp
|
||||
source/content/providers/gdb_provider.cpp
|
||||
|
@ -1,96 +1,131 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/helpers/encoding_file.hpp>
|
||||
|
||||
#include <imgui_memory_editor.h>
|
||||
|
||||
#include <list>
|
||||
#include <tuple>
|
||||
#include <random>
|
||||
#include <vector>
|
||||
|
||||
namespace hex::prv {
|
||||
class Provider;
|
||||
}
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
using SearchFunction = std::vector<std::pair<u64, u64>> (*)(prv::Provider *&provider, std::string string);
|
||||
|
||||
struct HighlightBlock {
|
||||
struct Highlight {
|
||||
color_t color;
|
||||
std::vector<std::string> tooltips;
|
||||
};
|
||||
|
||||
constexpr static size_t Size = 0x2000;
|
||||
|
||||
u64 base = 0x00;
|
||||
std::array<Highlight, Size> highlight;
|
||||
};
|
||||
|
||||
class ViewHexEditor : public View {
|
||||
public:
|
||||
ViewHexEditor();
|
||||
~ViewHexEditor() override;
|
||||
|
||||
void drawContent() override;
|
||||
void drawAlwaysVisible() override;
|
||||
|
||||
private:
|
||||
MemoryEditor m_memoryEditor;
|
||||
|
||||
std::vector<char> m_searchStringBuffer;
|
||||
std::vector<char> m_searchHexBuffer;
|
||||
SearchFunction m_searchFunction = nullptr;
|
||||
std::vector<std::pair<u64, u64>> *m_lastSearchBuffer = nullptr;
|
||||
bool m_searchRequested = false;
|
||||
|
||||
i64 m_lastSearchIndex = 0;
|
||||
std::vector<std::pair<u64, u64>> m_lastStringSearch;
|
||||
std::vector<std::pair<u64, u64>> m_lastHexSearch;
|
||||
|
||||
std::string m_gotoAddressInput;
|
||||
bool m_gotoRequested = false;
|
||||
bool m_evaluateGoto = false;
|
||||
|
||||
u64 m_baseAddress = 0;
|
||||
u64 m_resizeSize = 0;
|
||||
|
||||
std::vector<u8> m_dataToSave;
|
||||
std::set<pl::Pattern *> m_highlightedPatterns;
|
||||
|
||||
std::string m_loaderScriptScriptPath;
|
||||
std::string m_loaderScriptFilePath;
|
||||
|
||||
hex::EncodingFile m_currEncodingFile;
|
||||
u8 m_highlightAlpha = 0x80;
|
||||
|
||||
std::list<HighlightBlock> m_highlights;
|
||||
|
||||
bool m_processingImportExport = false;
|
||||
bool m_advancedDecodingEnabled = false;
|
||||
|
||||
void drawSearchPopup();
|
||||
void drawSearchInput(std::vector<char> *currBuffer, ImGuiInputTextFlags flags);
|
||||
void performSearch(const char *buffer);
|
||||
void performSearchNext();
|
||||
void performSearchPrevious();
|
||||
static int inputCallback(ImGuiInputTextCallbackData *data);
|
||||
|
||||
void drawGotoPopup();
|
||||
void drawEditPopup();
|
||||
constexpr static auto InvalidSelection = std::numeric_limits<u64>::max();
|
||||
|
||||
void openFile(const std::fs::path &path);
|
||||
|
||||
void copyBytes() const;
|
||||
void pasteBytes() const;
|
||||
void copyString() const;
|
||||
|
||||
void registerEvents();
|
||||
void registerShortcuts();
|
||||
void registerEvents();
|
||||
void registerMenuItems();
|
||||
|
||||
void drawCell(u64 address, u8 *data, size_t size, bool hovered);
|
||||
void drawPopup();
|
||||
void drawSelectionFrame(u32 x, u32 y, u64 byteAddress, u16 bytesPerCell, const ImVec2 &cellPos, const ImVec2 &cellSize);
|
||||
|
||||
public:
|
||||
void setSelection(const Region ®ion) { this->setSelection(region.getStartAddress(), region.getEndAddress()); }
|
||||
void setSelection(i128 start, i128 end) {
|
||||
if (!ImHexApi::Provider::isValid()) return;
|
||||
|
||||
const size_t maxAddress = ImHexApi::Provider::get()->getActualSize() - 1;
|
||||
|
||||
this->m_selectionChanged = this->m_selectionStart != start || this->m_selectionEnd != end;
|
||||
|
||||
this->m_selectionStart = std::clamp<decltype(start)>(start, 0, maxAddress);
|
||||
this->m_selectionEnd = std::clamp<decltype(end)>(end, 0, maxAddress);
|
||||
|
||||
if (this->m_selectionChanged) {
|
||||
EventManager::post<EventRegionSelected>(this->getSelection());
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] Region getSelection() const {
|
||||
const auto start = std::min(this->m_selectionStart, this->m_selectionEnd);
|
||||
const auto end = std::max(this->m_selectionStart, this->m_selectionEnd);
|
||||
const size_t size = end - start + 1;
|
||||
|
||||
return { start, size };
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isSelectionValid() const {
|
||||
return this->m_selectionStart != InvalidSelection && this->m_selectionEnd != InvalidSelection;
|
||||
}
|
||||
|
||||
void jumpToSelection() {
|
||||
this->m_shouldJumpToSelection = true;
|
||||
}
|
||||
|
||||
void scrollToSelection() {
|
||||
this->m_shouldScrollToSelection = true;
|
||||
}
|
||||
|
||||
public:
|
||||
class Popup {
|
||||
public:
|
||||
virtual ~Popup() = default;
|
||||
virtual void draw(ViewHexEditor *editor) = 0;
|
||||
};
|
||||
|
||||
[[nodiscard]] bool isAnyPopupOpen() const {
|
||||
return this->m_currPopup != nullptr;
|
||||
}
|
||||
|
||||
template<std::derived_from<Popup> T>
|
||||
[[nodiscard]] bool isPopupOpen() const {
|
||||
return dynamic_cast<T*>(this->m_currPopup.get()) != nullptr;
|
||||
}
|
||||
|
||||
template<std::derived_from<Popup> T, typename ... Args>
|
||||
void openPopup(Args && ...args) {
|
||||
this->m_currPopup = std::make_unique<T>(std::forward<Args>(args)...);
|
||||
this->m_shouldOpenPopup = true;
|
||||
}
|
||||
|
||||
void closePopup() {
|
||||
this->m_currPopup.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
void drawEditor(const ImVec2 &size);
|
||||
void drawFooter(const ImVec2 &size);
|
||||
|
||||
void handleSelection(u64 address, u32 bytesPerCell, const u8 *data, bool cellHovered);
|
||||
|
||||
private:
|
||||
u16 m_bytesPerRow = 16;
|
||||
|
||||
ContentRegistry::HexEditor::DataVisualizer *m_currDataVisualizer;
|
||||
|
||||
bool m_shouldJumpToSelection = false;
|
||||
bool m_shouldScrollToSelection = false;
|
||||
|
||||
bool m_selectionChanged = false;
|
||||
u64 m_selectionStart = InvalidSelection;
|
||||
u64 m_selectionEnd = InvalidSelection;
|
||||
|
||||
u16 m_visibleRowCount = 0;
|
||||
|
||||
std::optional<u64> m_editingAddress;
|
||||
bool m_shouldModifyValue = false;
|
||||
bool m_enteredEditingMode = false;
|
||||
std::vector<u8> m_editingBytes;
|
||||
|
||||
color_t m_selectionColor = 0x00;
|
||||
bool m_upperCaseHex = true;
|
||||
bool m_grayOutZero = true;
|
||||
bool m_showAscii = true;
|
||||
|
||||
bool m_shouldOpenPopup = false;
|
||||
std::unique_ptr<Popup> m_currPopup;
|
||||
|
||||
std::optional<EncodingFile> m_currCustomEncoding;
|
||||
};
|
||||
|
||||
}
|
@ -12,6 +12,8 @@
|
||||
|
||||
#include <TextEditor.h>
|
||||
|
||||
namespace pl { class Pattern; }
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
class ViewPatternEditor : public View {
|
||||
@ -91,6 +93,8 @@ namespace hex::plugin::builtin {
|
||||
void drawEnvVars(ImVec2 size);
|
||||
void drawVariableSettings(ImVec2 size);
|
||||
|
||||
void drawPatternTooltip(pl::Pattern *pattern);
|
||||
|
||||
void loadPatternFile(const std::fs::path &path);
|
||||
void clearPatterns();
|
||||
|
||||
|
@ -21,7 +21,9 @@ namespace hex::plugin::builtin {
|
||||
u64 address;
|
||||
size_t size;
|
||||
bool wholeDataMatch;
|
||||
|
||||
u32 highlightId;
|
||||
u32 tooltipId;
|
||||
};
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> m_rules;
|
||||
|
@ -11,83 +11,108 @@
|
||||
|
||||
namespace hex {
|
||||
|
||||
enum class TokenType
|
||||
{
|
||||
Number,
|
||||
Variable,
|
||||
Function,
|
||||
Operator,
|
||||
Bracket
|
||||
};
|
||||
|
||||
enum class Operator : u16
|
||||
{
|
||||
Invalid = 0x000,
|
||||
Assign = 0x010,
|
||||
Or = 0x020,
|
||||
Xor = 0x030,
|
||||
And = 0x040,
|
||||
BitwiseOr = 0x050,
|
||||
BitwiseXor = 0x060,
|
||||
BitwiseAnd = 0x070,
|
||||
Equals = 0x080,
|
||||
NotEquals = 0x081,
|
||||
GreaterThan = 0x090,
|
||||
LessThan = 0x091,
|
||||
GreaterThanOrEquals = 0x092,
|
||||
LessThanOrEquals = 0x093,
|
||||
ShiftLeft = 0x0A0,
|
||||
ShiftRight = 0x0A1,
|
||||
Addition = 0x0B0,
|
||||
Subtraction = 0x0B1,
|
||||
Multiplication = 0x0C0,
|
||||
Division = 0x0C1,
|
||||
Modulus = 0x0C2,
|
||||
Exponentiation = 0x1D0,
|
||||
Combine = 0x0E0,
|
||||
BitwiseNot = 0x0F0,
|
||||
Not = 0x0F1
|
||||
};
|
||||
|
||||
enum class BracketType : std::uint8_t
|
||||
{
|
||||
Left,
|
||||
Right
|
||||
};
|
||||
|
||||
struct Token {
|
||||
TokenType type;
|
||||
|
||||
union {
|
||||
long double number;
|
||||
Operator op;
|
||||
BracketType bracketType;
|
||||
};
|
||||
|
||||
std::string name;
|
||||
std::vector<long double> arguments;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class MathEvaluator {
|
||||
public:
|
||||
MathEvaluator() = default;
|
||||
|
||||
std::optional<long double> evaluate(const std::string &input);
|
||||
std::optional<T> evaluate(const std::string &input);
|
||||
|
||||
void registerStandardVariables();
|
||||
void registerStandardFunctions();
|
||||
|
||||
void setVariable(const std::string &name, long double value);
|
||||
void setFunction(const std::string &name, const std::function<std::optional<long double>(std::vector<long double>)> &function, size_t minNumArgs, size_t maxNumArgs);
|
||||
void setVariable(const std::string &name, T value);
|
||||
void setFunction(const std::string &name, const std::function<std::optional<T>(std::vector<T>)> &function, size_t minNumArgs, size_t maxNumArgs);
|
||||
|
||||
std::unordered_map<std::string, long double> &getVariables() { return this->m_variables; }
|
||||
std::unordered_map<std::string, T> &getVariables() { return this->m_variables; }
|
||||
|
||||
[[nodiscard]] bool hasError() const {
|
||||
return this->m_lastError.has_value();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<std::string> getLastError() const {
|
||||
return this->m_lastError;
|
||||
}
|
||||
|
||||
private:
|
||||
std::queue<Token> parseInput(std::string input);
|
||||
std::optional<long double> evaluate(std::queue<Token> postfixTokens);
|
||||
void setError(const std::string &error) {
|
||||
this->m_lastError = error;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, long double> m_variables;
|
||||
std::unordered_map<std::string, std::function<std::optional<long double>(std::vector<long double>)>> m_functions;
|
||||
private:
|
||||
enum class TokenType
|
||||
{
|
||||
Number,
|
||||
Variable,
|
||||
Function,
|
||||
Operator,
|
||||
Bracket
|
||||
};
|
||||
|
||||
enum class Operator : u16
|
||||
{
|
||||
Invalid = 0x000,
|
||||
Assign = 0x010,
|
||||
Or = 0x020,
|
||||
Xor = 0x030,
|
||||
And = 0x040,
|
||||
BitwiseOr = 0x050,
|
||||
BitwiseXor = 0x060,
|
||||
BitwiseAnd = 0x070,
|
||||
Equals = 0x080,
|
||||
NotEquals = 0x081,
|
||||
GreaterThan = 0x090,
|
||||
LessThan = 0x091,
|
||||
GreaterThanOrEquals = 0x092,
|
||||
LessThanOrEquals = 0x093,
|
||||
ShiftLeft = 0x0A0,
|
||||
ShiftRight = 0x0A1,
|
||||
Addition = 0x0B0,
|
||||
Subtraction = 0x0B1,
|
||||
Multiplication = 0x0C0,
|
||||
Division = 0x0C1,
|
||||
Modulus = 0x0C2,
|
||||
Exponentiation = 0x1D0,
|
||||
Combine = 0x0E0,
|
||||
BitwiseNot = 0x0F0,
|
||||
Not = 0x0F1
|
||||
};
|
||||
|
||||
enum class BracketType : std::uint8_t
|
||||
{
|
||||
Left,
|
||||
Right
|
||||
};
|
||||
|
||||
struct Token {
|
||||
TokenType type;
|
||||
|
||||
union {
|
||||
T number;
|
||||
Operator op;
|
||||
BracketType bracketType;
|
||||
};
|
||||
|
||||
std::string name;
|
||||
std::vector<T> arguments;
|
||||
};
|
||||
|
||||
static i16 comparePrecedence(const Operator &a, const Operator &b);
|
||||
static bool isLeftAssociative(const Operator op);
|
||||
static std::pair<Operator, size_t> toOperator(const std::string &input);
|
||||
|
||||
private:
|
||||
std::optional<std::queue<Token>> parseInput(std::string input);
|
||||
std::optional<std::queue<Token>> toPostfix(std::queue<Token> inputQueue);
|
||||
std::optional<T> evaluate(std::queue<Token> postfixTokens);
|
||||
|
||||
std::unordered_map<std::string, T> m_variables;
|
||||
std::unordered_map<std::string, std::function<std::optional<T>(std::vector<T>)>> m_functions;
|
||||
|
||||
std::optional<std::string> m_lastError;
|
||||
};
|
||||
|
||||
extern template class MathEvaluator<long double>;
|
||||
extern template class MathEvaluator<i128>;
|
||||
|
||||
}
|
@ -16,19 +16,17 @@ namespace hex::plugin::builtin {
|
||||
"#",
|
||||
"hex.builtin.command.calc.desc",
|
||||
[](auto input) {
|
||||
hex::MathEvaluator evaluator;
|
||||
hex::MathEvaluator<long double> evaluator;
|
||||
evaluator.registerStandardVariables();
|
||||
evaluator.registerStandardFunctions();
|
||||
|
||||
std::optional<long double> result;
|
||||
|
||||
try {
|
||||
result = evaluator.evaluate(input);
|
||||
} catch (std::exception &e) { }
|
||||
|
||||
|
||||
result = evaluator.evaluate(input);
|
||||
if (result.has_value())
|
||||
return hex::format("#{0} = {1}", input.data(), result.value());
|
||||
else if (evaluator.hasError())
|
||||
return hex::format("Error: {}", *evaluator.getLastError());
|
||||
else
|
||||
return std::string("???");
|
||||
});
|
||||
|
@ -323,19 +323,25 @@ namespace hex::plugin::builtin {
|
||||
[](auto buffer, auto endian, auto style) {
|
||||
hex::unused(endian, style);
|
||||
|
||||
Region currSelection = { 0, 0 };
|
||||
EventManager::post<QuerySelection>(currSelection);
|
||||
auto currSelection = ImHexApi::HexEditor::getSelection();
|
||||
|
||||
constexpr static auto MaxStringLength = 32;
|
||||
|
||||
std::vector<u8> stringBuffer(std::min<size_t>(MaxStringLength, currSelection.size), 0x00);
|
||||
ImHexApi::Provider::get()->read(currSelection.address, stringBuffer.data(), stringBuffer.size());
|
||||
std::string value, copyValue;
|
||||
|
||||
auto value = hex::encodeByteString(stringBuffer);
|
||||
auto copyValue = hex::encodeByteString(buffer);
|
||||
if (currSelection.has_value()) {
|
||||
std::vector<u8> stringBuffer(std::min<size_t>(MaxStringLength, currSelection->size), 0x00);
|
||||
ImHexApi::Provider::get()->read(currSelection->address, stringBuffer.data(), stringBuffer.size());
|
||||
|
||||
if (currSelection.size > MaxStringLength)
|
||||
value += "...";
|
||||
value = hex::encodeByteString(stringBuffer);
|
||||
copyValue = hex::encodeByteString(buffer);
|
||||
|
||||
if (currSelection->size > MaxStringLength)
|
||||
value += "...";
|
||||
} else {
|
||||
value = "";
|
||||
copyValue = "";
|
||||
}
|
||||
|
||||
return [value, copyValue] { ImGui::TextFormatted("\"{0}\"", value.c_str()); return copyValue; };
|
||||
},
|
||||
|
272
plugins/builtin/source/content/data_visualizers.cpp
Normal file
272
plugins/builtin/source/content/data_visualizers.cpp
Normal file
@ -0,0 +1,272 @@
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
template<typename T>
|
||||
constexpr ImGuiDataType getImGuiDataType() {
|
||||
if constexpr (std::same_as<T, u8>) return ImGuiDataType_U8;
|
||||
else if constexpr (std::same_as<T, u16>) return ImGuiDataType_U16;
|
||||
else if constexpr (std::same_as<T, u32>) return ImGuiDataType_U32;
|
||||
else if constexpr (std::same_as<T, u64>) return ImGuiDataType_U64;
|
||||
else if constexpr (std::same_as<T, i8>) return ImGuiDataType_S8;
|
||||
else if constexpr (std::same_as<T, i16>) return ImGuiDataType_S16;
|
||||
else if constexpr (std::same_as<T, i32>) return ImGuiDataType_S32;
|
||||
else if constexpr (std::same_as<T, i64>) return ImGuiDataType_S64;
|
||||
else if constexpr (std::same_as<T, float>) return ImGuiDataType_Float;
|
||||
else if constexpr (std::same_as<T, double>) return ImGuiDataType_Double;
|
||||
else static_assert(hex::always_false<T>::value, "Invalid data type!");
|
||||
}
|
||||
|
||||
template<hex::integral T>
|
||||
class DataVisualizerHexadecimal : public hex::ContentRegistry::HexEditor::DataVisualizer {
|
||||
public:
|
||||
DataVisualizerHexadecimal() : DataVisualizer(ByteCount, CharCount) { }
|
||||
|
||||
void draw(u64 address, const u8 *data, size_t size, bool upperCase) override {
|
||||
hex::unused(address);
|
||||
|
||||
if (size == ByteCount)
|
||||
ImGui::Text(getFormatString(upperCase), *reinterpret_cast<const T*>(data));
|
||||
else
|
||||
ImGui::TextFormatted("{: {}s}", CharCount);
|
||||
}
|
||||
|
||||
bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) override {
|
||||
hex::unused(address, startedEditing);
|
||||
|
||||
if (size == ByteCount) {
|
||||
return drawDefaultEditingTextBox(address, getFormatString(upperCase), getImGuiDataType<T>(), data, ImGuiInputTextFlags_CharsHexadecimal);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr static inline auto ByteCount = sizeof(T);
|
||||
constexpr static inline auto CharCount = ByteCount * 2;
|
||||
|
||||
const static inline auto FormattingUpperCase = hex::format("%0{}X", CharCount);
|
||||
const static inline auto FormattingLowerCase = hex::format("%0{}x", CharCount);
|
||||
|
||||
const char *getFormatString(bool upperCase) {
|
||||
if (upperCase)
|
||||
return FormattingUpperCase.c_str();
|
||||
else
|
||||
return FormattingLowerCase.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class DataVisualizerHexii : public hex::ContentRegistry::HexEditor::DataVisualizer {
|
||||
public:
|
||||
DataVisualizerHexii() : DataVisualizer(ByteCount, CharCount) { }
|
||||
|
||||
void draw(u64 address, const u8 *data, size_t size, bool upperCase) override {
|
||||
hex::unused(address);
|
||||
|
||||
if (size == ByteCount) {
|
||||
const u8 c = data[0];
|
||||
switch (c) {
|
||||
case 0x00:
|
||||
ImGui::Text(" ");
|
||||
break;
|
||||
case 0xFF:
|
||||
ImGui::TextDisabled("##");
|
||||
break;
|
||||
case ' ' ... '~':
|
||||
ImGui::Text(".%c", c);
|
||||
break;
|
||||
default:
|
||||
ImGui::Text(getFormatString(upperCase), c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
ImGui::TextFormatted("{: {}s}", CharCount);
|
||||
}
|
||||
|
||||
bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) override {
|
||||
hex::unused(address, startedEditing);
|
||||
|
||||
if (size == ByteCount) {
|
||||
return drawDefaultEditingTextBox(address, getFormatString(upperCase), getImGuiDataType<u8>(), data, ImGuiInputTextFlags_CharsHexadecimal);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr static inline auto ByteCount = 1;
|
||||
constexpr static inline auto CharCount = ByteCount * 2;
|
||||
|
||||
const static inline auto FormattingUpperCase = hex::format("%0{}X", CharCount);
|
||||
const static inline auto FormattingLowerCase = hex::format("%0{}x", CharCount);
|
||||
|
||||
const char *getFormatString(bool upperCase) {
|
||||
if (upperCase)
|
||||
return FormattingUpperCase.c_str();
|
||||
else
|
||||
return FormattingLowerCase.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
template<hex::integral T>
|
||||
class DataVisualizerDecimal : public hex::ContentRegistry::HexEditor::DataVisualizer {
|
||||
public:
|
||||
DataVisualizerDecimal() : DataVisualizer(ByteCount, CharCount) { }
|
||||
|
||||
void draw(u64 address, const u8 *data, size_t size, bool upperCase) override {
|
||||
hex::unused(address, upperCase);
|
||||
|
||||
if (size == ByteCount) {
|
||||
if (hex::is_signed<T>::value)
|
||||
ImGui::Text(getFormatString(), static_cast<i64>(*reinterpret_cast<const T*>(data)));
|
||||
else
|
||||
ImGui::Text(getFormatString(), static_cast<u64>(*reinterpret_cast<const T*>(data)));
|
||||
}
|
||||
else
|
||||
ImGui::TextFormatted("{: {}s}", CharCount);
|
||||
}
|
||||
|
||||
bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) override {
|
||||
hex::unused(address, upperCase, startedEditing);
|
||||
|
||||
if (size == ByteCount) {
|
||||
return ImGui::InputScalar(
|
||||
"##hex_input",
|
||||
getImGuiDataType<T>(),
|
||||
data,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
DataVisualizer::TextInputFlags);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr static inline auto ByteCount = sizeof(T);
|
||||
constexpr static inline auto CharCount = std::numeric_limits<T>::digits10 + 2;
|
||||
|
||||
const static inline auto FormatString = hex::format("%{}{}", CharCount, hex::is_signed<T>::value ? "lld" : "llu");
|
||||
|
||||
const char *getFormatString() {
|
||||
return FormatString.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
template<hex::floating_point T>
|
||||
class DataVisualizerFloatingPoint : public hex::ContentRegistry::HexEditor::DataVisualizer {
|
||||
public:
|
||||
DataVisualizerFloatingPoint() : DataVisualizer(ByteCount, CharCount) { }
|
||||
|
||||
void draw(u64 address, const u8 *data, size_t size, bool upperCase) override {
|
||||
hex::unused(address);
|
||||
|
||||
if (size == ByteCount)
|
||||
ImGui::Text(getFormatString(upperCase), *reinterpret_cast<const T*>(data));
|
||||
else
|
||||
ImGui::TextFormatted("{: {}s}", CharCount);
|
||||
}
|
||||
|
||||
bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) override {
|
||||
hex::unused(address, upperCase, startedEditing);
|
||||
|
||||
if (size == ByteCount) {
|
||||
return ImGui::InputScalar(
|
||||
"##hex_input",
|
||||
getImGuiDataType<T>(),
|
||||
data,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
DataVisualizer::TextInputFlags | ImGuiInputTextFlags_CharsScientific);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr static inline auto ByteCount = sizeof(T);
|
||||
constexpr static inline auto CharCount = 14;
|
||||
|
||||
const static inline auto FormatStringUpperCase = hex::format("%{}E", CharCount);
|
||||
const static inline auto FormatStringLowerCase = hex::format("%{}e", CharCount);
|
||||
|
||||
const char *getFormatString(bool upperCase) {
|
||||
if (upperCase)
|
||||
return FormatStringUpperCase.c_str();
|
||||
else
|
||||
return FormatStringLowerCase.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class DataVisualizerRGBA8 : public hex::ContentRegistry::HexEditor::DataVisualizer {
|
||||
public:
|
||||
DataVisualizerRGBA8() : DataVisualizer(4, 2) { }
|
||||
|
||||
void draw(u64 address, const u8 *data, size_t size, bool upperCase) override {
|
||||
hex::unused(address, upperCase);
|
||||
|
||||
if (size == 4)
|
||||
ImGui::ColorButton("##color", ImColor(data[0], data[1], data[2], data[3]), ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoDragDrop, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
|
||||
else
|
||||
ImGui::ColorButton("##color", ImColor(0, 0, 0, 0xFF), ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoDragDrop, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
|
||||
}
|
||||
|
||||
bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) override {
|
||||
hex::unused(address, data, size, upperCase);
|
||||
|
||||
if (startedEditing) {
|
||||
this->m_currColor = { float(data[0]) / 0xFF, float(data[1]) / 0xFF, float(data[2]) / 0xFF, float(data[3]) / 0xFF };
|
||||
ImGui::OpenPopup("##color_popup");
|
||||
}
|
||||
|
||||
ImGui::ColorButton("##color", ImColor(this->m_currColor[0], this->m_currColor[1], this->m_currColor[2], this->m_currColor[3]), ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoDragDrop, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
|
||||
|
||||
if (ImGui::BeginPopup("##color_popup")) {
|
||||
if (ImGui::ColorPicker4("##picker", this->m_currColor.data(), ImGuiColorEditFlags_AlphaBar)) {
|
||||
for (u8 i = 0; i < 4; i++)
|
||||
data[i] = this->m_currColor[i] * 0xFF;
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
std::array<float, 4> m_currColor;
|
||||
|
||||
};
|
||||
|
||||
void registerDataVisualizers() {
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerHexadecimal<u8>>("hex.builtin.visualizer.hexadecimal.8bit");
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerHexadecimal<u16>>("hex.builtin.visualizer.hexadecimal.16bit");
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerHexadecimal<u32>>("hex.builtin.visualizer.hexadecimal.32bit");
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerHexadecimal<u64>>("hex.builtin.visualizer.hexadecimal.64bit");
|
||||
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<u8>>("hex.builtin.visualizer.decimal.unsigned.8bit");
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<u16>>("hex.builtin.visualizer.decimal.unsigned.16bit");
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<u32>>("hex.builtin.visualizer.decimal.unsigned.32bit");
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<u64>>("hex.builtin.visualizer.decimal.unsigned.64bit");
|
||||
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<i8>>("hex.builtin.visualizer.decimal.signed.8bit");
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<i16>>("hex.builtin.visualizer.decimal.signed.16bit");
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<i32>>("hex.builtin.visualizer.decimal.signed.32bit");
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<i64>>("hex.builtin.visualizer.decimal.signed.64bit");
|
||||
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerFloatingPoint<float>>("hex.builtin.visualizer.floating_point.32bit");
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerFloatingPoint<double>>("hex.builtin.visualizer.floating_point.64bit");
|
||||
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerRGBA8>("hex.builtin.visualizer.rgba8");
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerHexii>("hex.builtin.visualizer.hexii");
|
||||
}
|
||||
|
||||
}
|
91
plugins/builtin/source/content/events.cpp
Normal file
91
plugins/builtin/source/content/events.cpp
Normal file
@ -0,0 +1,91 @@
|
||||
#include <hex/api/event.hpp>
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/helpers/project_file_handler.hpp>
|
||||
#include <hex/api/localization.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "content/providers/file_provider.hpp"
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
static void openFile(const std::fs::path &path) {
|
||||
hex::prv::Provider *provider = nullptr;
|
||||
EventManager::post<RequestCreateProvider>("hex.builtin.provider.file", &provider);
|
||||
|
||||
if (auto fileProvider = dynamic_cast<prv::FileProvider *>(provider)) {
|
||||
fileProvider->setPath(path);
|
||||
if (!fileProvider->open()) {
|
||||
View::showErrorPopup("hex.builtin.popup.error.open"_lang);
|
||||
ImHexApi::Provider::remove(provider);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!provider->isWritable()) {
|
||||
View::showErrorPopup("hex.builtin.popup.error.read_only"_lang);
|
||||
}
|
||||
|
||||
if (!provider->isAvailable()) {
|
||||
View::showErrorPopup("hex.builtin.popup.error.open"_lang);
|
||||
ImHexApi::Provider::remove(provider);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ProjectFile::setFilePath(path);
|
||||
|
||||
EventManager::post<EventFileLoaded>(path);
|
||||
EventManager::post<EventDataChanged>();
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
}
|
||||
|
||||
void registerEventHandlers() {
|
||||
EventManager::subscribe<EventProjectFileLoad>([]() {
|
||||
EventManager::post<RequestOpenFile>(ProjectFile::getFilePath());
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventWindowClosing>([](GLFWwindow *window) {
|
||||
if (ProjectFile::hasUnsavedChanges()) {
|
||||
glfwSetWindowShouldClose(window, GLFW_FALSE);
|
||||
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.popup.exit_application.title"_lang); });
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<RequestOpenFile>(openFile);
|
||||
|
||||
EventManager::subscribe<RequestOpenWindow>([](const std::string &name) {
|
||||
if (name == "Create File") {
|
||||
fs::openFileBrowser(fs::DialogMode::Save, {}, [](const auto &path) {
|
||||
fs::File file(path, fs::File::Mode::Create);
|
||||
|
||||
if (!file.isValid()) {
|
||||
View::showErrorPopup("hex.builtin.popup.error.create"_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
file.setSize(1);
|
||||
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
});
|
||||
} else if (name == "Open File") {
|
||||
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
});
|
||||
} else if (name == "Open Project") {
|
||||
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} },
|
||||
[](const auto &path) {
|
||||
ProjectFile::load(path);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderChanged>([](auto, auto) {
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -4,18 +4,267 @@
|
||||
#include <implot.h>
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/helpers/project_file_handler.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/crypto.hpp>
|
||||
|
||||
#include <thread>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
static bool g_demoWindowOpen = false;
|
||||
|
||||
void registerMainMenuEntries() {
|
||||
|
||||
static void createFileMenu() {
|
||||
ContentRegistry::Interface::registerMainMenuItem("hex.builtin.menu.file", 1000);
|
||||
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1050, [&] {
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.open_file"_lang, "CTRL + O")) {
|
||||
|
||||
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
});
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("hex.builtin.menu.file.open_other"_lang)) {
|
||||
|
||||
for (const auto &unlocalizedProviderName : ContentRegistry::Provider::getEntries()) {
|
||||
if (ImGui::MenuItem(LangEntry(unlocalizedProviderName))) {
|
||||
EventManager::post<RequestCreateProvider>(unlocalizedProviderName, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
});
|
||||
|
||||
/* File open, quit imhex */
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1150, [&] {
|
||||
bool providerValid = ImHexApi::Provider::isValid();
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.close"_lang, "", false, providerValid)) {
|
||||
EventManager::post<EventFileUnloaded>();
|
||||
ImHexApi::Provider::remove(ImHexApi::Provider::get());
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.quit"_lang, "", false)) {
|
||||
ImHexApi::Common::closeImHex();
|
||||
}
|
||||
});
|
||||
|
||||
/* Project open / save */
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1250, [&] {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
bool providerValid = ImHexApi::Provider::isValid();
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.open_project"_lang, "")) {
|
||||
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"}
|
||||
},
|
||||
[](const auto &path) {
|
||||
ProjectFile::load(path);
|
||||
});
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.save_project"_lang, "", false, providerValid && provider->isWritable())) {
|
||||
if (ProjectFile::getProjectFilePath() == "") {
|
||||
fs::openFileBrowser(fs::DialogMode::Save, { {"Project File", "hexproj"}
|
||||
},
|
||||
[](std::fs::path path) {
|
||||
if (path.extension() != ".hexproj") {
|
||||
path.replace_extension(".hexproj");
|
||||
}
|
||||
|
||||
ProjectFile::store(path);
|
||||
});
|
||||
} else
|
||||
ProjectFile::store();
|
||||
}
|
||||
});
|
||||
|
||||
/* Import / Export */
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1300, [&] {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
bool providerValid = ImHexApi::Provider::isValid();
|
||||
|
||||
/* Import */
|
||||
if (ImGui::BeginMenu("hex.builtin.menu.file.import"_lang)) {
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.import.base64"_lang)) {
|
||||
|
||||
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
|
||||
fs::File inputFile(path, fs::File::Mode::Read);
|
||||
if (!inputFile.isValid()) {
|
||||
View::showErrorPopup("hex.builtin.menu.file.import.base64.popup.open_error"_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
auto base64 = inputFile.readBytes();
|
||||
|
||||
if (!base64.empty()) {
|
||||
auto data = crypt::decode64(base64);
|
||||
|
||||
if (data.empty())
|
||||
View::showErrorPopup("hex.builtin.menu.file.import.base64.popup.import_error"_lang);
|
||||
else {
|
||||
fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const std::fs::path &path) {
|
||||
fs::File outputFile(path, fs::File::Mode::Create);
|
||||
|
||||
if (!outputFile.isValid())
|
||||
View::showErrorPopup("hex.builtin.menu.file.import.base64.popup.import_error"_lang);
|
||||
|
||||
outputFile.write(data);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
View::showErrorPopup("hex.builtin.popup.file_open_error"_lang);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.import.ips"_lang, nullptr, false)) {
|
||||
|
||||
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
|
||||
std::thread([path] {
|
||||
auto task = ImHexApi::Tasks::createTask("hex.common.processing", 0);
|
||||
|
||||
auto patchData = fs::File(path, fs::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();
|
||||
}).detach();
|
||||
});
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.import.ips32"_lang, nullptr, false)) {
|
||||
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
|
||||
std::thread([path] {
|
||||
auto task = ImHexApi::Tasks::createTask("hex.common.processing", 0);
|
||||
|
||||
auto patchData = fs::File(path, fs::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();
|
||||
}).detach();
|
||||
});
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
|
||||
/* Export */
|
||||
if (ImGui::BeginMenu("hex.builtin.menu.file.export"_lang, providerValid && provider->isWritable())) {
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.export.ips"_lang, nullptr, false)) {
|
||||
Patches patches = provider->getPatches();
|
||||
if (!patches.contains(0x00454F45) && patches.contains(0x00454F46)) {
|
||||
u8 value = 0;
|
||||
provider->read(0x00454F45, &value, sizeof(u8));
|
||||
patches[0x00454F45] = value;
|
||||
}
|
||||
|
||||
std::thread([patches] {
|
||||
auto task = ImHexApi::Tasks::createTask("hex.common.processing", 0);
|
||||
|
||||
auto data = generateIPSPatch(patches);
|
||||
|
||||
ImHexApi::Tasks::doLater([data] {
|
||||
fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const auto &path) {
|
||||
auto file = fs::File(path, fs::File::Mode::Create);
|
||||
if (!file.isValid()) {
|
||||
View::showErrorPopup("hex.builtin.menu.file.export.base64.popup.export_error"_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
file.write(data);
|
||||
});
|
||||
});
|
||||
}).detach();
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.export.ips32"_lang, nullptr, false)) {
|
||||
Patches patches = provider->getPatches();
|
||||
if (!patches.contains(0x00454F45) && patches.contains(0x45454F46)) {
|
||||
u8 value = 0;
|
||||
provider->read(0x45454F45, &value, sizeof(u8));
|
||||
patches[0x45454F45] = value;
|
||||
}
|
||||
|
||||
std::thread([patches] {
|
||||
auto task = ImHexApi::Tasks::createTask("hex.common.processing", 0);
|
||||
|
||||
auto data = generateIPS32Patch(patches);
|
||||
|
||||
ImHexApi::Tasks::doLater([data] {
|
||||
fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const auto &path) {
|
||||
auto file = fs::File(path, fs::File::Mode::Create);
|
||||
if (!file.isValid()) {
|
||||
View::showErrorPopup("hex.builtin.menu.file.export.popup.create"_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
file.write(data);
|
||||
});
|
||||
});
|
||||
}).detach();
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void createEditMenu() {
|
||||
ContentRegistry::Interface::registerMainMenuItem("hex.builtin.menu.edit", 2000);
|
||||
|
||||
/* Provider Undo / Redo */
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.edit", 1000, [&] {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
bool providerValid = ImHexApi::Provider::isValid();
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.edit.undo"_lang, "CTRL + Z", false, providerValid && provider->canUndo()))
|
||||
provider->undo();
|
||||
if (ImGui::MenuItem("hex.builtin.menu.edit.redo"_lang, "CTRL + Y", false, providerValid && provider->canRedo()))
|
||||
provider->redo();
|
||||
});
|
||||
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.edit", 1050, [&] {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
bool providerValid = ImHexApi::Provider::isValid();
|
||||
auto selection = ImHexApi::HexEditor::getSelection();
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.edit.bookmark"_lang, nullptr, false, selection.has_value() && providerValid)) {
|
||||
auto base = provider->getBaseAddress();
|
||||
|
||||
ImHexApi::Bookmarks::add(base + selection->getStartAddress(), selection->getEndAddress(), {}, {});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
static void createViewMenu() {
|
||||
ContentRegistry::Interface::registerMainMenuItem("hex.builtin.menu.view", 3000);
|
||||
ContentRegistry::Interface::registerMainMenuItem("hex.builtin.menu.layout", 4000);
|
||||
ContentRegistry::Interface::registerMainMenuItem("hex.builtin.menu.help", 5000);
|
||||
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.view", 1000, [] {
|
||||
for (auto &[name, view] : ContentRegistry::Views::getEntries()) {
|
||||
@ -24,11 +273,15 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
});
|
||||
|
||||
#if defined(DEBUG)
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.view", 2000, [] {
|
||||
ImGui::MenuItem("hex.builtin.menu.view.demo"_lang, "", &g_demoWindowOpen);
|
||||
});
|
||||
#endif
|
||||
#if defined(DEBUG)
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.view", 2000, [] {
|
||||
ImGui::MenuItem("hex.builtin.menu.view.demo"_lang, "", &g_demoWindowOpen);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
static void createLayoutMenu() {
|
||||
ContentRegistry::Interface::registerMainMenuItem("hex.builtin.menu.layout", 4000);
|
||||
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.layout", 1000, [] {
|
||||
for (auto &[layoutName, func] : ContentRegistry::Interface::getLayouts()) {
|
||||
@ -46,7 +299,20 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static void createHelpMenu() {
|
||||
ContentRegistry::Interface::registerMainMenuItem("hex.builtin.menu.help", 5000);
|
||||
|
||||
}
|
||||
|
||||
|
||||
void registerMainMenuEntries() {
|
||||
createFileMenu();
|
||||
createEditMenu();
|
||||
createViewMenu();
|
||||
createLayoutMenu();
|
||||
createHelpMenu();
|
||||
|
||||
(void)EventManager::subscribe<EventFrameEnd>([] {
|
||||
if (g_demoWindowOpen) {
|
||||
|
@ -148,18 +148,32 @@ namespace hex::plugin::builtin {
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.highlight_alpha", 0x80, [](auto name, nlohmann::json &setting) {
|
||||
static int alpha = static_cast<int>(setting);
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.highlight_color", 0x60C08080, [](auto name, nlohmann::json &setting) {
|
||||
static auto color = static_cast<color_t>(setting);
|
||||
|
||||
std::array<float, 4> colorArray = {
|
||||
((color >> 0) & 0x000000FF) / float(0xFF),
|
||||
((color >> 8) & 0x000000FF) / float(0xFF),
|
||||
((color >> 16) & 0x000000FF) / float(0xFF),
|
||||
((color >> 24) & 0x000000FF) / float(0xFF)
|
||||
};
|
||||
|
||||
if (ImGui::ColorEdit4(name.data(), colorArray.data(), ImGuiColorEditFlags_AlphaBar | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoDragDrop | ImGuiColorEditFlags_NoInputs)) {
|
||||
color =
|
||||
(color_t(colorArray[0] * 0xFF) << 0) |
|
||||
(color_t(colorArray[1] * 0xFF) << 8) |
|
||||
(color_t(colorArray[2] * 0xFF) << 16) |
|
||||
(color_t(colorArray[3] * 0xFF) << 24);
|
||||
|
||||
setting = color;
|
||||
|
||||
if (ImGui::SliderInt(name.data(), &alpha, 0x00, 0xFF)) {
|
||||
setting = alpha;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.column_count", 16, [](auto name, nlohmann::json &setting) {
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.bytes_per_row", 16, [](auto name, nlohmann::json &setting) {
|
||||
static int columns = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::SliderInt(name.data(), &columns, 1, 32)) {
|
||||
@ -170,17 +184,6 @@ namespace hex::plugin::builtin {
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.hexii", 0, [](auto name, nlohmann::json &setting) {
|
||||
static bool hexii = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &hexii)) {
|
||||
setting = static_cast<int>(hexii);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.ascii", 1, [](auto name, nlohmann::json &setting) {
|
||||
static bool ascii = static_cast<int>(setting);
|
||||
|
||||
@ -225,18 +228,30 @@ namespace hex::plugin::builtin {
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.extra_info", 1, [](auto name, nlohmann::json &setting) {
|
||||
static bool extraInfos = static_cast<int>(setting);
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.visualizer", "hex.builtin.visualizer.hexadecimal.8bit", [](auto name, nlohmann::json &setting) {
|
||||
auto &visualizers = ContentRegistry::HexEditor::impl::getVisualizers();
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &extraInfos)) {
|
||||
setting = static_cast<int>(extraInfos);
|
||||
return true;
|
||||
auto selectedVisualizer = setting;
|
||||
|
||||
bool result = false;
|
||||
if (ImGui::BeginCombo(name.data(), LangEntry(selectedVisualizer))) {
|
||||
|
||||
for (const auto &[unlocalizedName, visualizer] : visualizers) {
|
||||
if (ImGui::Selectable(LangEntry(unlocalizedName))) {
|
||||
setting = unlocalizedName;
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
return false;
|
||||
return result;
|
||||
});
|
||||
|
||||
|
||||
/* Fonts */
|
||||
|
||||
static std::string fontPath;
|
||||
ContentRegistry::Settings::add(
|
||||
"hex.builtin.setting.font", "hex.builtin.setting.font.font_path", "", [](auto name, nlohmann::json &setting) {
|
||||
@ -282,6 +297,8 @@ namespace hex::plugin::builtin {
|
||||
true);
|
||||
|
||||
|
||||
/* Folders */
|
||||
|
||||
static const std::string dirsSetting { "hex.builtin.setting.folders" };
|
||||
|
||||
ContentRegistry::Settings::addCategoryDescription(dirsSetting, "hex.builtin.setting.folders.description");
|
||||
|
@ -134,8 +134,8 @@ namespace hex::plugin::builtin {
|
||||
static std::string mathInput;
|
||||
bool evaluate = false;
|
||||
|
||||
static MathEvaluator mathEvaluator = [&] {
|
||||
MathEvaluator evaluator;
|
||||
static MathEvaluator<long double> mathEvaluator = [&] {
|
||||
MathEvaluator<long double> evaluator;
|
||||
|
||||
evaluator.registerStandardVariables();
|
||||
evaluator.registerStandardFunctions();
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/api/localization.hpp>
|
||||
@ -15,6 +16,28 @@
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
static void drawGlobalPopups() {
|
||||
|
||||
// "Are you sure you want to exit?" Popup
|
||||
if (ImGui::BeginPopupModal("hex.builtin.popup.exit_application.title"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::NewLine();
|
||||
ImGui::TextUnformatted("hex.builtin.popup.exit_application.desc"_lang);
|
||||
ImGui::NewLine();
|
||||
|
||||
View::confirmButtons(
|
||||
"hex.builtin.common.yes"_lang, "hex.builtin.common.no"_lang, [] { ImHexApi::Common::closeImHex(true); }, [] { ImGui::CloseCurrentPopup(); });
|
||||
|
||||
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape)))
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
|
||||
void addGlobalUIItems() {
|
||||
EventManager::subscribe<EventFrameEnd>(drawGlobalPopups);
|
||||
}
|
||||
|
||||
void addFooterItems() {
|
||||
|
||||
if (hex::isProcessElevated()) {
|
||||
@ -68,19 +91,20 @@ namespace hex::plugin::builtin {
|
||||
bool providerValid = provider != nullptr;
|
||||
|
||||
// Undo
|
||||
ImGui::Disabled([&provider] {
|
||||
ImGui::BeginDisabled(!providerValid || !provider->canUndo());
|
||||
{
|
||||
if (ImGui::ToolBarButton(ICON_VS_DISCARD, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
|
||||
provider->undo();
|
||||
},
|
||||
!providerValid || !provider->canUndo());
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
// Redo
|
||||
ImGui::Disabled([&provider] {
|
||||
ImGui::BeginDisabled(!providerValid || !provider->canRedo());
|
||||
{
|
||||
if (ImGui::ToolBarButton(ICON_VS_REDO, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
|
||||
provider->redo();
|
||||
},
|
||||
!providerValid || !provider->canRedo());
|
||||
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
|
||||
@ -96,42 +120,45 @@ namespace hex::plugin::builtin {
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
|
||||
// Save file
|
||||
ImGui::Disabled([&provider] {
|
||||
ImGui::BeginDisabled(!providerValid || !provider->isWritable() || !provider->isSavable());
|
||||
{
|
||||
if (ImGui::ToolBarButton(ICON_VS_SAVE, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
|
||||
provider->save();
|
||||
},
|
||||
!providerValid || !provider->isWritable() || !provider->isSavable());
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
// Save file as
|
||||
ImGui::Disabled([&provider] {
|
||||
ImGui::BeginDisabled(!providerValid || !provider->isSavable());
|
||||
{
|
||||
if (ImGui::ToolBarButton(ICON_VS_SAVE_AS, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue)))
|
||||
fs::openFileBrowser(fs::DialogMode::Save, {}, [&provider](auto path) {
|
||||
provider->saveAs(path);
|
||||
});
|
||||
},
|
||||
!providerValid || !provider->isSavable());
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
|
||||
|
||||
// Create bookmark
|
||||
ImGui::Disabled([] {
|
||||
ImGui::BeginDisabled(!providerValid || !provider->isReadable() || !ImHexApi::HexEditor::isSelectionValid());
|
||||
{
|
||||
if (ImGui::ToolBarButton(ICON_VS_BOOKMARK, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen))) {
|
||||
Region region = { };
|
||||
EventManager::post<QuerySelection>(region);
|
||||
auto region = ImHexApi::HexEditor::getSelection();
|
||||
|
||||
ImHexApi::Bookmarks::add(region.address, region.size, {}, {});
|
||||
if (region.has_value())
|
||||
ImHexApi::Bookmarks::add(region->address, region->size, {}, {});
|
||||
}
|
||||
},
|
||||
!providerValid || !provider->isReadable() || ImHexApi::HexEditor::getSelection().size == 0);
|
||||
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
ImGui::Spacing();
|
||||
|
||||
// Provider switcher
|
||||
ImGui::Disabled([] {
|
||||
ImGui::BeginDisabled(!providerValid);
|
||||
{
|
||||
auto &providers = ImHexApi::Provider::getProviders();
|
||||
|
||||
std::string preview;
|
||||
@ -149,9 +176,10 @@ namespace hex::plugin::builtin {
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
},
|
||||
!providerValid);
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -23,9 +23,8 @@ namespace hex::plugin::builtin {
|
||||
name,
|
||||
std::move(comment),
|
||||
color,
|
||||
false,
|
||||
|
||||
ImHexApi::HexEditor::addHighlight(region, color, name) });
|
||||
false
|
||||
});
|
||||
|
||||
ProjectFile::markDirty();
|
||||
});
|
||||
@ -41,6 +40,75 @@ namespace hex::plugin::builtin {
|
||||
EventManager::subscribe<EventFileUnloaded>(this, [this] {
|
||||
this->m_bookmarks.clear();
|
||||
});
|
||||
|
||||
|
||||
ImHexApi::HexEditor::addBackgroundHighlightingProvider([this](u64 address, const u8* data, size_t size) -> std::optional<color_t> {
|
||||
hex::unused(data);
|
||||
|
||||
for (const auto &bookmark : this->m_bookmarks) {
|
||||
if (Region { address, size }.isWithin(bookmark.region))
|
||||
return bookmark.color;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) {
|
||||
hex::unused(data);
|
||||
for (const auto &bookmark : this->m_bookmarks) {
|
||||
if (!Region { address, size }.isWithin(bookmark.region))
|
||||
continue;
|
||||
|
||||
ImGui::BeginTooltip();
|
||||
|
||||
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::PushID(&bookmark);
|
||||
{
|
||||
ImGui::ColorButton("##color", ImColor(bookmark.color));
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::TextUnformatted(bookmark.name.c_str());
|
||||
|
||||
if (ImGui::GetIO().KeyShift) {
|
||||
ImGui::Indent();
|
||||
if (ImGui::BeginTable("##extra_info", 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoHostExtendX | ImGuiTableFlags_NoClip)) {
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("Region: ");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("[ 0x{:08X} - 0x{:08X} ]", bookmark.region.getStartAddress(), bookmark.region.getEndAddress());
|
||||
|
||||
if (!bookmark.comment.empty() && bookmark.comment[0] != '\x00') {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("Comment: ");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormattedWrapped("\"{}\"", bookmark.comment);
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::Unindent();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_TableRowBg, bookmark.color);
|
||||
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, bookmark.color);
|
||||
ImGui::EndTable();
|
||||
ImGui::PopStyleColor(2);
|
||||
}
|
||||
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ViewBookmarks::~ViewBookmarks() {
|
||||
@ -63,7 +131,7 @@ namespace hex::plugin::builtin {
|
||||
u32 id = 1;
|
||||
auto bookmarkToRemove = this->m_bookmarks.end();
|
||||
for (auto iter = this->m_bookmarks.begin(); iter != this->m_bookmarks.end(); iter++) {
|
||||
auto &[region, name, comment, color, locked, highlight] = *iter;
|
||||
auto &[region, name, comment, color, locked] = *iter;
|
||||
|
||||
auto headerColor = ImColor(color);
|
||||
auto hoverColor = ImColor(color);
|
||||
@ -169,7 +237,6 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
if (bookmarkToRemove != this->m_bookmarks.end()) {
|
||||
ImHexApi::HexEditor::removeHighlight(bookmarkToRemove->highlightId);
|
||||
this->m_bookmarks.erase(bookmarkToRemove);
|
||||
ProjectFile::markDirty();
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
EventManager::subscribe<EventSettingsChanged>(this, [this] {
|
||||
{
|
||||
auto columnCount = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.column_count");
|
||||
auto columnCount = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.bytes_per_row");
|
||||
|
||||
if (columnCount.is_number())
|
||||
this->m_columnCount = static_cast<int>(columnCount);
|
||||
|
@ -322,11 +322,12 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::Disabled([this] {
|
||||
ImGui::BeginDisabled(this->m_disassembling);
|
||||
{
|
||||
if (ImGui::Button("hex.builtin.view.disassembler.disassemble"_lang))
|
||||
this->disassemble();
|
||||
},
|
||||
this->m_disassembling);
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
if (this->m_disassembling) {
|
||||
ImGui::SameLine();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -135,11 +135,12 @@ namespace hex::plugin::builtin {
|
||||
ImGui::TextUnformatted("hex.builtin.view.information.control"_lang);
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Disabled([this] {
|
||||
ImGui::BeginDisabled(this->m_analyzing);
|
||||
{
|
||||
if (ImGui::Button("hex.builtin.view.information.analyze"_lang))
|
||||
this->analyze();
|
||||
},
|
||||
this->m_analyzing);
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
if (this->m_analyzing) {
|
||||
ImGui::TextSpinner("hex.builtin.view.information.analyzing"_lang);
|
||||
|
@ -231,17 +231,44 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
|
||||
ImHexApi::HexEditor::addHighlightingProvider([](u64 address) -> std::optional<ImHexApi::HexEditor::Highlighting> {
|
||||
ImHexApi::HexEditor::addBackgroundHighlightingProvider([](u64 address, const u8 *data, size_t size) -> std::optional<color_t> {
|
||||
hex::unused(data, size);
|
||||
|
||||
const auto &patterns = ImHexApi::Provider::get()->getPatternLanguageRuntime().getPatterns();
|
||||
for (const auto &pattern : patterns) {
|
||||
auto child = pattern->getPattern(address);
|
||||
if (child != nullptr) {
|
||||
return ImHexApi::HexEditor::Highlighting(Region { address, 1 }, child->getColor(), child->getDisplayName());
|
||||
return child->getColor();
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) {
|
||||
hex::unused(data, size);
|
||||
|
||||
auto &patterns = ImHexApi::Provider::get()->getPatternLanguageRuntime().getPatterns();
|
||||
for (auto &pattern : patterns) {
|
||||
auto child = pattern->getPattern(address);
|
||||
if (child != nullptr) {
|
||||
ImGui::BeginTooltip();
|
||||
|
||||
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
this->drawPatternTooltip(child);
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_TableRowBg, pattern->getColor());
|
||||
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, pattern->getColor());
|
||||
ImGui::EndTable();
|
||||
ImGui::PopStyleColor(2);
|
||||
}
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ViewPatternEditor::~ViewPatternEditor() {
|
||||
@ -608,6 +635,68 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
|
||||
void ViewPatternEditor::drawPatternTooltip(pl::Pattern *pattern) {
|
||||
ImGui::PushID(pattern);
|
||||
{
|
||||
ImGui::ColorButton(pattern->getVariableName().c_str(), ImColor(pattern->getColor()));
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{}", pattern->getFormattedName());
|
||||
ImGui::SameLine(0, 5);
|
||||
ImGui::TextFormatted("{}", pattern->getDisplayName());
|
||||
ImGui::SameLine();
|
||||
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
|
||||
ImGui::SameLine();
|
||||
ImGui::TextFormatted("{}", pattern->getFormattedValue());
|
||||
|
||||
if (ImGui::GetIO().KeyShift) {
|
||||
ImGui::Indent();
|
||||
if (ImGui::BeginTable("##extra_info", 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("Type: ");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", pattern->getTypeName());
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("Address: ");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{:08X}", pattern->getOffset());
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("Size: ");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{} {}", pattern->getSize(), pattern->getSize() > 1 ? "Bytes" : "Byte");
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("Endian: ");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", pattern->getEndian() == std::endian::little ? "Little" : "Big");
|
||||
|
||||
if (auto comment = pattern->getComment(); comment.has_value()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("Comment: ");
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextWrapped("\"%s\"", pattern->getComment()->c_str());
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
ImGui::Unindent();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
|
||||
void ViewPatternEditor::loadPatternFile(const std::fs::path &path) {
|
||||
fs::File file(path, fs::File::Mode::Read);
|
||||
if (file.isValid()) {
|
||||
|
@ -105,7 +105,8 @@ namespace hex::plugin::builtin {
|
||||
|
||||
if (ImGui::Begin(View::toWindowName("hex.builtin.view.strings.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
|
||||
if (ImHexApi::Provider::isValid() && provider->isReadable()) {
|
||||
ImGui::Disabled([this] {
|
||||
ImGui::BeginDisabled(this->m_searching);
|
||||
{
|
||||
if (ImGui::InputInt("hex.builtin.view.strings.min_length"_lang, &this->m_minimumLength, 1, 0))
|
||||
this->m_foundStrings.clear();
|
||||
|
||||
@ -158,8 +159,8 @@ namespace hex::plugin::builtin {
|
||||
|
||||
if (ImGui::Button("hex.builtin.view.strings.extract"_lang))
|
||||
this->searchStrings();
|
||||
},
|
||||
this->m_searching);
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
if (this->m_searching) {
|
||||
ImGui::SameLine();
|
||||
|
@ -44,7 +44,8 @@ namespace hex::plugin::builtin {
|
||||
|
||||
if (ImGui::Button("hex.builtin.view.yara.reload"_lang)) this->reloadRules();
|
||||
} else {
|
||||
ImGui::Disabled([this] {
|
||||
ImGui::BeginDisabled(this->m_matching);
|
||||
{
|
||||
if (ImGui::BeginCombo("hex.builtin.view.yara.header.rules"_lang, this->m_rules[this->m_selectedRule].first.c_str())) {
|
||||
for (u32 i = 0; i < this->m_rules.size(); i++) {
|
||||
const bool selected = (this->m_selectedRule == i);
|
||||
@ -59,8 +60,8 @@ namespace hex::plugin::builtin {
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("hex.builtin.view.yara.reload"_lang)) this->reloadRules();
|
||||
if (ImGui::Button("hex.builtin.view.yara.match"_lang)) this->applyRules();
|
||||
},
|
||||
this->m_matching);
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
if (this->m_matching) {
|
||||
ImGui::SameLine();
|
||||
@ -91,7 +92,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
while (clipper.Step()) {
|
||||
for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) {
|
||||
auto &[identifier, variableName, address, size, wholeDataMatch, highlightId] = this->m_matches[i];
|
||||
auto &[identifier, variableName, address, size, wholeDataMatch, highlightId, tooltipId] = this->m_matches[i];
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::PushID(i);
|
||||
@ -142,8 +143,10 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
void ViewYara::clearResult() {
|
||||
for (const auto &match : this->m_matches)
|
||||
ImHexApi::HexEditor::removeHighlight(match.highlightId);
|
||||
for (const auto &match : this->m_matches) {
|
||||
ImHexApi::HexEditor::removeBackgroundHighlight(match.highlightId);
|
||||
ImHexApi::HexEditor::removeTooltip(match.tooltipId);
|
||||
}
|
||||
|
||||
this->m_matches.clear();
|
||||
this->m_consoleMessages.clear();
|
||||
@ -310,11 +313,11 @@ namespace hex::plugin::builtin {
|
||||
if (rule->strings != nullptr) {
|
||||
yr_rule_strings_foreach(rule, string) {
|
||||
yr_string_matches_foreach(context, string, match) {
|
||||
results.newMatches.push_back({ rule->identifier, string->identifier, u64(match->offset), size_t(match->match_length), false, 0 });
|
||||
results.newMatches.push_back({ rule->identifier, string->identifier, u64(match->offset), size_t(match->match_length), false, 0, 0 });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
results.newMatches.push_back({ rule->identifier, "", 0, 0, true, 0 });
|
||||
results.newMatches.push_back({ rule->identifier, "", 0, 0, true, 0, 0 });
|
||||
}
|
||||
}
|
||||
break;
|
||||
@ -337,8 +340,10 @@ namespace hex::plugin::builtin {
|
||||
this->m_matches = resultContext.newMatches;
|
||||
this->m_consoleMessages = resultContext.consoleMessages;
|
||||
|
||||
constexpr static color_t YaraColor = 0x70B4771F;
|
||||
for (auto &match : this->m_matches) {
|
||||
match.highlightId = ImHexApi::HexEditor::addHighlight({ match.address, match.size }, 0x70B4771F, hex::format("{0} [{1}]", match.identifier, match.variable));
|
||||
match.highlightId = ImHexApi::HexEditor::addBackgroundHighlight({ match.address, match.size }, YaraColor);
|
||||
match.tooltipId = ImHexApi::HexEditor::addTooltip({ match. address, match.size }, hex::format("{0} [{1}]", match.identifier, match.variable), YaraColor);
|
||||
}
|
||||
});
|
||||
}).detach();
|
||||
|
@ -417,15 +417,8 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
});
|
||||
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1050, [&] {
|
||||
if (ImGui::MenuItem("hex.builtin.view.hex_editor.menu.file.open_file"_lang, "CTRL + O")) {
|
||||
|
||||
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
});
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("hex.builtin.view.hex_editor.menu.file.open_recent"_lang, !s_recentFilePaths.empty())) {
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1075, [&] {
|
||||
if (ImGui::BeginMenu("hex.builtin.menu.file.open_recent"_lang, !s_recentFilePaths.empty())) {
|
||||
// Copy to avoid changing list while iteration
|
||||
std::list<std::fs::path> recentFilePaths = s_recentFilePaths;
|
||||
for (auto &path : recentFilePaths) {
|
||||
@ -436,7 +429,7 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
if (ImGui::MenuItem("hex.builtin.view.hex_editor.menu.file.clear_recent"_lang)) {
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.clear_recent"_lang)) {
|
||||
s_recentFilePaths.clear();
|
||||
ContentRegistry::Settings::write(
|
||||
"hex.builtin.setting.imhex",
|
||||
@ -446,17 +439,6 @@ namespace hex::plugin::builtin {
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("hex.builtin.view.hex_editor.menu.file.open_other"_lang)) {
|
||||
|
||||
for (const auto &unlocalizedProviderName : ContentRegistry::Provider::getEntries()) {
|
||||
if (ImGui::MenuItem(LangEntry(unlocalizedProviderName))) {
|
||||
EventManager::post<RequestCreateProvider>(unlocalizedProviderName, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
@ -80,12 +80,40 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.common.open", "Öffnen" },
|
||||
{ "hex.builtin.common.browse", "Druchsuchen..." },
|
||||
{ "hex.builtin.common.choose_file", "Datei auswählen" },
|
||||
{ "hex.builtin.common.processing", "Verarbeiten" },
|
||||
|
||||
{ "hex.builtin.message.file_handler_failed", "Datei konnte nicht mit registriertem Dateihandler geöffnet werden." },
|
||||
|
||||
{ "hex.builtin.popup.exit_application.title", "Applikation verlassen?" },
|
||||
{ "hex.builtin.popup.exit_application.desc", "Es wurden ungespeicherte Änderungen an diesem Projekt vorgenommen\nBist du sicher, dass du ImHex schliessen willst?" },
|
||||
{ "hex.builtin.popup.error.read_only", "Schreibzugriff konnte nicht erlangt werden. Datei wurde im Lesemodus geöffnet." },
|
||||
{ "hex.builtin.popup.error.open", "Öffnen der Datei fehlgeschlagen!" },
|
||||
{ "hex.builtin.popup.error.create", "Erstellen der neuen Datei fehlgeschlagen!" },
|
||||
|
||||
{ "hex.builtin.menu.file", "Datei" },
|
||||
{ "hex.builtin.file.open_file", "Datei öffnen..." },
|
||||
{ "hex.builtin.file.open_recent", "Kürzlich geöffnete Dateien" },
|
||||
{ "hex.builtin.file.clear_recent", "Löschen" },
|
||||
{ "hex.builtin.file.open_other", "Provider öffnen..." },
|
||||
{ "hex.builtin.file.close", "Schliessen" },
|
||||
{ "hex.builtin.file.quit", "ImHex Beenden" },
|
||||
{ "hex.builtin.file.open_project", "Projekt öffnen..." },
|
||||
{ "hex.builtin.file.save_project", "Projekt speichern..." },
|
||||
{ "hex.builtin.menu.file.import", "Importieren..." },
|
||||
{ "hex.builtin.menu.file.import.base64", "Base64 Datei" },
|
||||
{ "hex.builtin.menu.file.import.base64.popup.import_error", "Datei ist nicht in einem korrekten Base64 Format!" },
|
||||
{ "hex.builtin.menu.file.import.base64.popup.open_error", "Öffnen der Datei fehlgeschlagen!" },
|
||||
{ "hex.builtin.menu.file.import.ips", "IPS Patch" },
|
||||
{ "hex.builtin.menu.file.import.ips32", "IPS32 Patch" },
|
||||
{ "hex.builtin.menu.file.export", "Exportieren..." },
|
||||
{ "hex.builtin.menu.file.export.title", "Datei exportieren" },
|
||||
{ "hex.builtin.menu.file.export.ips", "IPS Patch" },
|
||||
{ "hex.builtin.menu.file.export.ips32", "IPS32 Patch" },
|
||||
{ "hex.builtin.menu.file.export.base64.popup.export_error", "File is not in a valid Base64 format!" },
|
||||
|
||||
{ "hex.builtin.menu.edit", "Bearbeiten" },
|
||||
{ "hex.builtin.menu.edit.undo", "Rückgängig" },
|
||||
{ "hex.builtin.menu.edit.redo", "Wiederholen" },
|
||||
{ "hex.builtin.menu.edit.bookmark", "Lesezeichen erstellen" },
|
||||
|
||||
{ "hex.builtin.menu.view", "Ansicht" },
|
||||
{ "hex.builtin.menu.layout", "Layout" },
|
||||
{ "hex.builtin.menu.view.fps", "FPS anzeigen" },
|
||||
@ -207,48 +235,14 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.view.help.calc_cheat_sheet", "Rechner Cheat Sheet" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.name", "Hex editor" },
|
||||
{ "hex.builtin.view.hex_editor.create_file", "Neu" },
|
||||
{ "hex.builtin.view.hex_editor.open_file", "Öffnen" },
|
||||
{ "hex.builtin.view.hex_editor.open_project", "Projekt öffnen" },
|
||||
{ "hex.builtin.view.hex_editor.save_project", "Projekt speichern" },
|
||||
{ "hex.builtin.view.hex_editor.save_data", "Daten speichern" },
|
||||
{ "hex.builtin.view.hex_editor.open_base64", "Base64 Datei öffnen" },
|
||||
{ "hex.builtin.view.hex_editor.load_enconding_file", "Custom encoding Datei laden" },
|
||||
{ "hex.builtin.view.hex_editor.page", "Seite {0} / {1}" },
|
||||
{ "hex.builtin.view.hex_editor.save_as", "Speichern unter" },
|
||||
{ "hex.builtin.view.hex_editor.exit_application.title", "Applikation verlassen?" },
|
||||
{ "hex.builtin.view.hex_editor.exit_application.desc", "Es wurden ungespeicherte Änderungen an diesem Projekt vorgenommen\nBist du sicher, dass du ImHex schliessen willst?" },
|
||||
{ "hex.builtin.view.hex_editor.script.title", "Datei mit Loader Skript laden" },
|
||||
{ "hex.builtin.view.hex_editor.script.desc", "Lade eine Datei mit Hilfe eines Python Skriptes" },
|
||||
{ "hex.builtin.view.hex_editor.script.script", "Skript" },
|
||||
{ "hex.builtin.view.hex_editor.script.script.title", "Loader Script: Skript öffnen" },
|
||||
{ "hex.builtin.view.hex_editor.script.file", "Datei" },
|
||||
{ "hex.builtin.view.hex_editor.script.file.title", "Loader Script: Datei öffnen" },
|
||||
{ "hex.builtin.view.hex_editor.processing", "Importieren / Exportieren" },
|
||||
{ "hex.builtin.view.hex_editor.page", "Seite" },
|
||||
{ "hex.builtin.view.hex_editor.selection", "Auswahl" },
|
||||
{ "hex.builtin.view.hex_editor.selection.none", "Keine" },
|
||||
{ "hex.builtin.view.hex_editor.region", "Region" },
|
||||
{ "hex.builtin.view.hex_editor.data_size", "Datengrösse" },
|
||||
{ "hex.builtin.view.hex_editor.no_bytes", "Keine bytes verfügbar" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_file", "Datei öffnen..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_recent", "Kürzlich geöffnete Dateien" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.clear_recent", "Löschen" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_other", "Provider öffnen..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save", "Speichern" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save_as", "Speichern unter..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.close", "Schliessen" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.quit", "ImHex Beenden" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_project", "Projekt öffnen..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save_project", "Projekt speichern..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.load_encoding_file", "Custom encoding laden..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import", "Importieren..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.base64", "Base64 Datei" },
|
||||
{ "hex.builtin.view.hex_editor.base64.import_error", "Datei ist nicht in einem korrekten Base64 Format!" },
|
||||
{ "hex.builtin.view.hex_editor.file_open_error", "Öffnen der Datei fehlgeschlagen!" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.ips", "IPS Patch" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.ips32", "IPS32 Patch" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.script", "Datei mit Loader Script" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export", "Exportieren..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.title", "Datei exportieren" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.ips", "IPS Patch" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.ips32", "IPS32 Patch" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.search", "Suchen" },
|
||||
{ "hex.builtin.view.hex_editor.search.string", "String" },
|
||||
{ "hex.builtin.view.hex_editor.search.hex", "Hex" },
|
||||
@ -260,11 +254,8 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.current", "Momentan" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.begin", "Beginn" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.end", "Ende" },
|
||||
{ "hex.builtin.view.hex_editor.error.read_only", "Schreibzugriff konnte nicht erlangt werden. Datei wurde im Lesemodus geöffnet." },
|
||||
{ "hex.builtin.view.hex_editor.error.open", "Öffnen der Datei fehlgeschlagen!" },
|
||||
{ "hex.builtin.view.hex_editor.error.create", "Erstellen der neuen Datei fehlgeschlagen!" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.undo", "Rückgängig" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.redo", "Wiederholen" },
|
||||
{ "hex.builtin.view.hex_editor.file.save", "Speichern" },
|
||||
{ "hex.builtin.view.hex_editor.file.save_as", "Speichern unter..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.copy", "Kopieren" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.copy_as", "Kopieren als..." },
|
||||
{ "hex.builtin.view.hex_editor.copy.hex", "String" },
|
||||
@ -279,7 +270,6 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.view.hex_editor.copy.html", "HTML" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.paste", "Einfügen" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.select_all", "Alles auswählen" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.bookmark", "Lesezeichen erstellen" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.set_base", "Basisadresse setzen" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.resize", "Grösse ändern..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.insert", "Einsetzen..." },
|
||||
@ -666,22 +656,21 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.setting.interface.scaling.x1_5", "x1.5" },
|
||||
{ "hex.builtin.setting.interface.scaling.x2_0", "x2.0" },
|
||||
{ "hex.builtin.setting.interface.language", "Sprache" },
|
||||
//{ "hex.builtin.setting.interface.wiki_explain_language", "Wikipedia Language" },
|
||||
{ "hex.builtin.setting.interface.wiki_explain_language", "Wikipedia Sprache" },
|
||||
{ "hex.builtin.setting.interface.fps", "FPS Limite" },
|
||||
{ "hex.builtin.setting.interface.fps.unlocked", "Unbegrenzt" },
|
||||
{ "hex.builtin.setting.interface.highlight_alpha", "Markierungssichtbarkeit" },
|
||||
{ "hex.builtin.setting.hex_editor", "Hex Editor" },
|
||||
{ "hex.builtin.setting.hex_editor.column_count", "Anzahl Byte Spalten" },
|
||||
{ "hex.builtin.setting.hex_editor.hexii", "HexII anstatt Bytes anzeigen" },
|
||||
{ "hex.builtin.setting.hex_editor.highlight_color", "Auswahlfarbe" },
|
||||
{ "hex.builtin.setting.hex_editor.bytes_per_row", "Bytes pro Zeile" },
|
||||
{ "hex.builtin.setting.hex_editor.ascii", "ASCII Spalte anzeigen" },
|
||||
{ "hex.builtin.setting.hex_editor.advanced_decoding", "Erweiterte Dekodierungsspalte anzeigen" },
|
||||
{ "hex.builtin.setting.hex_editor.grey_zeros", "Nullen ausgrauen" },
|
||||
{ "hex.builtin.setting.hex_editor.uppercase_hex", "Hex Zeichen als Grossbuchstaben" },
|
||||
{ "hex.builtin.setting.hex_editor.extra_info", "Extra informationen anzeigen" },
|
||||
{ "hex.builtin.setting.hex_editor.visualizer", "Data visualizer" },
|
||||
{ "hex.builtin.setting.folders", "Ordner" },
|
||||
{ "hex.builtin.setting.folders.description", "Gib zusätzliche Orderpfade an in welchen Pattern, Scripts, Yara Rules und anderes gesucht wird" },
|
||||
// { "hex.builtin.setting.folders.add_folder", "Add new folder" },
|
||||
// { "hex.builtin.setting.folders.remove_folder", "Remove currently selected folder from list" },
|
||||
{ "hex.builtin.setting.folders.add_folder", "Neuer Ordner hinzufügen" },
|
||||
{ "hex.builtin.setting.folders.remove_folder", "Ausgewählter Ordner von Liste entfernen" },
|
||||
{ "hex.builtin.setting.font", "Schriftart" },
|
||||
{ "hex.builtin.setting.font.font_path", "Eigene Schriftart" },
|
||||
{ "hex.builtin.setting.font.font_size", "Schriftgrösse" },
|
||||
@ -704,7 +693,24 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.provider.disk.sector_size", "Sektorgrösse" },
|
||||
{ "hex.builtin.provider.disk.reload", "Neu laden" },
|
||||
|
||||
{ "hex.builtin.layouts.default", "Standard" }
|
||||
{ "hex.builtin.layouts.default", "Standard" },
|
||||
|
||||
{ "hex.builtin.visualizer.hexadecimal.8bit", "Hexadezimal (8 bits)" },
|
||||
{ "hex.builtin.visualizer.hexadecimal.16bit", "Hexadezimal (16 bits)" },
|
||||
{ "hex.builtin.visualizer.hexadecimal.32bit", "Hexadezimal (32 bits)" },
|
||||
{ "hex.builtin.visualizer.hexadecimal.64bit", "Hexadezimal (64 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.signed.8bit", "Dezimal Signed (8 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.signed.16bit", "Dezimal Signed (16 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.signed.32bit", "Dezimal Signed (32 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.signed.64bit", "Dezimal Signed (64 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.unsigned.8bit", "Dezimal Unsigned (8 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.unsigned.16bit", "Dezimal Unsigned (16 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.unsigned.32bit", "Dezimal Unsigned (32 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.unsigned.64bit", "Dezimal Unsigned (64 bits)" },
|
||||
{ "hex.builtin.visualizer.floating_point.32bit", "Floating Point (32 bits)" },
|
||||
{ "hex.builtin.visualizer.floating_point.64bit", "Floating Point (64 bits)" },
|
||||
{ "hex.builtin.visualizer.hexii", "HexII" },
|
||||
{ "hex.builtin.visualizer.rgba8", "RGBA8 Farbe" },
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -81,11 +81,41 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.common.open", "Open" },
|
||||
{ "hex.builtin.common.browse", "Browse..." },
|
||||
{ "hex.builtin.common.choose_file", "Choose file" },
|
||||
{ "hex.common.processing", "Processing" },
|
||||
|
||||
{ "hex.builtin.message.file_handler_failed", "Failed to open file with registered file handler." },
|
||||
{ "hex.builtin.popup.exit_application.title", "Exit Application?" },
|
||||
{ "hex.builtin.popup.exit_application.desc", "You have unsaved changes made to your Project.\nAre you sure you want to exit?" },
|
||||
{ "hex.builtin.popup.error.read_only", "Couldn't get write access. File opened in read-only mode." },
|
||||
{ "hex.builtin.popup.error.open", "Failed to open file!" },
|
||||
{ "hex.builtin.popup.error.create", "Failed to create new file!" },
|
||||
|
||||
{ "hex.builtin.menu.file", "File" },
|
||||
{ "hex.builtin.menu.file.open_file", "Open File..." },
|
||||
{ "hex.builtin.menu.file.open_recent", "Open Recent" },
|
||||
{ "hex.builtin.menu.file.clear_recent", "Clear" },
|
||||
{ "hex.builtin.menu.file.open_other", "Open Other..." },
|
||||
{ "hex.builtin.menu.file.close", "Close" },
|
||||
{ "hex.builtin.menu.file.quit", "Quit ImHex" },
|
||||
{ "hex.builtin.menu.file.open_project", "Open Project..." },
|
||||
{ "hex.builtin.menu.file.save_project", "Save Project..." },
|
||||
{ "hex.builtin.menu.file.import", "Import..." },
|
||||
{ "hex.builtin.menu.file.import.base64", "Base64 File" },
|
||||
{ "hex.builtin.menu.file.import.base64.popup.import_error", "File is not in a valid Base64 format!" },
|
||||
{ "hex.builtin.menu.file.import.base64.popup.open_error", "Failed to open file!" },
|
||||
{ "hex.builtin.menu.file.import.ips", "IPS Patch" },
|
||||
{ "hex.builtin.menu.file.import.ips32", "IPS32 Patch" },
|
||||
{ "hex.builtin.menu.file.export", "Export..." },
|
||||
{ "hex.builtin.menu.file.export.title", "Export File" },
|
||||
{ "hex.builtin.menu.file.export.ips", "IPS Patch" },
|
||||
{ "hex.builtin.menu.file.export.ips32", "IPS32 Patch" },
|
||||
{ "hex.builtin.menu.file.export.base64.popup.export_error", "File is not in a valid Base64 format!" },
|
||||
{ "hex.builtin.menu.file.export.popup.create", "Cannot export data. Failed to create file!" },
|
||||
|
||||
{ "hex.builtin.menu.edit", "Edit" },
|
||||
{ "hex.builtin.menu.edit.undo", "Undo" },
|
||||
{ "hex.builtin.menu.edit.redo", "Redo" },
|
||||
{ "hex.builtin.menu.edit.bookmark", "Create bookmark" },
|
||||
|
||||
{ "hex.builtin.menu.view", "View" },
|
||||
{ "hex.builtin.menu.layout", "Layout" },
|
||||
{ "hex.builtin.menu.view.fps", "Display FPS" },
|
||||
@ -211,64 +241,25 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.view.help.calc_cheat_sheet", "Calculator Cheat Sheet" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.name", "Hex editor" },
|
||||
{ "hex.builtin.view.hex_editor.create_file", "New" },
|
||||
{ "hex.builtin.view.hex_editor.open_file", "Open" },
|
||||
{ "hex.builtin.view.hex_editor.open_project", "Open Project" },
|
||||
{ "hex.builtin.view.hex_editor.save_project", "Save Project" },
|
||||
{ "hex.builtin.view.hex_editor.save_data", "Save Data" },
|
||||
{ "hex.builtin.view.hex_editor.open_base64", "Open Base64 File" },
|
||||
{ "hex.builtin.view.hex_editor.load_enconding_file", "Load custom encoding File" },
|
||||
{ "hex.builtin.view.hex_editor.page", "Page {0} / {1}" },
|
||||
{ "hex.builtin.view.hex_editor.save_as", "Save As" },
|
||||
{ "hex.builtin.view.hex_editor.exit_application.title", "Exit Application?" },
|
||||
{ "hex.builtin.view.hex_editor.exit_application.desc", "You have unsaved changes made to your Project.\nAre you sure you want to exit?" },
|
||||
{ "hex.builtin.view.hex_editor.script.title", "Load File with Loader Script" },
|
||||
{ "hex.builtin.view.hex_editor.script.desc", "Load a file using a Python loader script." },
|
||||
{ "hex.builtin.view.hex_editor.script.script", "Script" },
|
||||
{ "hex.builtin.view.hex_editor.script.script.title", "Loader Script: Open Script" },
|
||||
{ "hex.builtin.view.hex_editor.script.file", "File" },
|
||||
{ "hex.builtin.view.hex_editor.script.file.title", "Loader Script: Open File" },
|
||||
{ "hex.builtin.view.hex_editor.processing", "Importing / Exporting" },
|
||||
{ "hex.builtin.view.hex_editor.page", "Page" },
|
||||
{ "hex.builtin.view.hex_editor.selection", "Selection" },
|
||||
{ "hex.builtin.view.hex_editor.selection.none", "None" },
|
||||
{ "hex.builtin.view.hex_editor.region", "Region" },
|
||||
{ "hex.builtin.view.hex_editor.data_size", "Data Size" },
|
||||
{ "hex.builtin.view.hex_editor.no_bytes", "No bytes available" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_file", "Open File..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_recent", "Open Recent" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.clear_recent", "Clear" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_other", "Open Other..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save", "Save" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save_as", "Save As..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.close", "Close" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.quit", "Quit ImHex" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_project", "Open Project..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save_project", "Save Project..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.load_encoding_file", "Load custom encoding..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import", "Import..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.base64", "Base64 File" },
|
||||
{ "hex.builtin.view.hex_editor.base64.import_error", "File is not in a valid Base64 format!" },
|
||||
{ "hex.builtin.view.hex_editor.file_open_error", "Failed to open file!" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.ips", "IPS Patch" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.ips32", "IPS32 Patch" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.script", "File with Loader Script" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export", "Export..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.title", "Export File" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.ips", "IPS Patch" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.ips32", "IPS32 Patch" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.search", "Search" },
|
||||
{ "hex.builtin.view.hex_editor.search.string", "String" },
|
||||
{ "hex.builtin.view.hex_editor.search.hex", "Hex" },
|
||||
{ "hex.builtin.view.hex_editor.search.find", "Find" },
|
||||
{ "hex.builtin.view.hex_editor.search.find_next", "Find next" },
|
||||
{ "hex.builtin.view.hex_editor.search.find_prev", "Find previous" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.goto", "Goto" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.absolute", "Absolute" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.current", "Current" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.relative", "Relative" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.begin", "Begin" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.end", "End" },
|
||||
{ "hex.builtin.view.hex_editor.error.read_only", "Couldn't get write access. File opened in read-only mode." },
|
||||
{ "hex.builtin.view.hex_editor.error.open", "Failed to open file!" },
|
||||
{ "hex.builtin.view.hex_editor.error.create", "Failed to create new file!" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.undo", "Undo" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.redo", "Redo" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save", "Save" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save_as", "Save As..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.copy", "Copy" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.copy_as", "Copy as..." },
|
||||
{ "hex.builtin.view.hex_editor.copy.hex", "String" },
|
||||
@ -283,7 +274,6 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.view.hex_editor.copy.html", "HTML" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.paste", "Paste" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.select_all", "Select all" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.bookmark", "Create bookmark" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.set_base", "Set base address" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.resize", "Resize..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.insert", "Insert..." },
|
||||
@ -673,15 +663,14 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.setting.interface.wiki_explain_language", "Wikipedia Language" },
|
||||
{ "hex.builtin.setting.interface.fps", "FPS Limit" },
|
||||
{ "hex.builtin.setting.interface.fps.unlocked", "Unlocked" },
|
||||
{ "hex.builtin.setting.interface.highlight_alpha", "Highlighting opacity" },
|
||||
{ "hex.builtin.setting.hex_editor", "Hex Editor" },
|
||||
{ "hex.builtin.setting.hex_editor.column_count", "Byte column count" },
|
||||
{ "hex.builtin.setting.hex_editor.hexii", "Display HexII instead of Bytes" },
|
||||
{ "hex.builtin.setting.hex_editor.highlight_color", "Selection highlight color" },
|
||||
{ "hex.builtin.setting.hex_editor.bytes_per_row", "Bytes per row" },
|
||||
{ "hex.builtin.setting.hex_editor.ascii", "Display ASCII column" },
|
||||
{ "hex.builtin.setting.hex_editor.advanced_decoding", "Display advanced decoding column" },
|
||||
{ "hex.builtin.setting.hex_editor.grey_zeros", "Grey out zeros" },
|
||||
{ "hex.builtin.setting.hex_editor.uppercase_hex", "Upper case Hex characters" },
|
||||
{ "hex.builtin.setting.hex_editor.extra_info", "Display extra information" },
|
||||
{ "hex.builtin.setting.hex_editor.visualizer", "Data visualizer" },
|
||||
{ "hex.builtin.setting.folders", "Folders" },
|
||||
{ "hex.builtin.setting.folders.description", "Specify additional search paths for patterns, scripts, Yara rules and more" },
|
||||
{ "hex.builtin.setting.folders.add_folder", "Add new folder" },
|
||||
@ -708,7 +697,24 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.provider.disk.sector_size", "Sector Size" },
|
||||
{ "hex.builtin.provider.disk.reload", "Reload" },
|
||||
|
||||
{ "hex.builtin.layouts.default", "Default" }
|
||||
{ "hex.builtin.layouts.default", "Default" },
|
||||
|
||||
{ "hex.builtin.visualizer.hexadecimal.8bit", "Hexadecimal (8 bits)" },
|
||||
{ "hex.builtin.visualizer.hexadecimal.16bit", "Hexadecimal (16 bits)" },
|
||||
{ "hex.builtin.visualizer.hexadecimal.32bit", "Hexadecimal (32 bits)" },
|
||||
{ "hex.builtin.visualizer.hexadecimal.64bit", "Hexadecimal (64 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.signed.8bit", "Decimal Signed (8 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.signed.16bit", "Decimal Signed (16 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.signed.32bit", "Decimal Signed (32 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.signed.64bit", "Decimal Signed (64 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.unsigned.8bit", "Decimal Unsigned (8 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.unsigned.16bit", "Decimal Unsigned (16 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.unsigned.32bit", "Decimal Unsigned (32 bits)" },
|
||||
{ "hex.builtin.visualizer.decimal.unsigned.64bit", "Decimal Unsigned (64 bits)" },
|
||||
{ "hex.builtin.visualizer.floating_point.32bit", "Floating Point (32 bits)" },
|
||||
{ "hex.builtin.visualizer.floating_point.64bit", "Floating Point (64 bits)" },
|
||||
{ "hex.builtin.visualizer.hexii", "HexII" },
|
||||
{ "hex.builtin.visualizer.rgba8", "RGBA8 Color" },
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -80,11 +80,42 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.common.open", "Apri" },
|
||||
{ "hex.builtin.common.browse", "Esplora..." },
|
||||
{ "hex.builtin.common.choose_file", "Scegli file" },
|
||||
//{ "hex.common.processing", "Processing" },
|
||||
|
||||
{ "hex.builtin.message.file_handler_failed", "Impossibile aprire il file con il gestore di file registrato." },
|
||||
{ "hex.builtin.popup.exit_application.title", "Uscire dall'applicazione?" },
|
||||
{ "hex.builtin.popup.exit_application.desc", "Hai delle modifiche non salvate nel tuo progetto.\nSei sicuro di voler uscire?" },
|
||||
{ "hex.builtin.popup.error.read_only", "Impossibile scrivere sul File. File aperto solo in modalità lettura" },
|
||||
{ "hex.builtin.popup.error.open", "Impossibile aprire il File!" },
|
||||
{ "hex.builtin.popup.error.create", "Impossibile creare il nuovo File!" },
|
||||
|
||||
{ "hex.builtin.menu.file", "File" },
|
||||
{ "hex.builtin.menu.file.open_file", "Apri File..." },
|
||||
{ "hex.builtin.menu.file.open_recent", "File recenti" },
|
||||
{ "hex.builtin.menu.file.clear_recent", "Pulisci" },
|
||||
{ "hex.builtin.menu.file.open_other", "Apri altro..." },
|
||||
{ "hex.builtin.menu.file.close", "Chiudi" },
|
||||
{ "hex.builtin.menu.file.quit", "Uscita ImHex" },
|
||||
{ "hex.builtin.menu.file.open_project", "Apri un Progetto..." },
|
||||
{ "hex.builtin.menu.file.save_project", "Salva Progetto..." },
|
||||
{ "hex.builtin.menu.file.import", "Importa..." },
|
||||
{ "hex.builtin.menu.file.import.base64", "Base64 File" },
|
||||
//{ "hex.builtin.menu.file.import.base64.popup.import_error", "File is not in a valid Base64 format!" },
|
||||
//{ "hex.builtin.menu.file.import.base64.popup.open_error", "Failed to open file!" },
|
||||
{ "hex.builtin.file_open_error", "Impossibile aprire il File!" },
|
||||
{ "hex.builtin.menu.file.import.ips", "IPS Patch" },
|
||||
{ "hex.builtin.menu.file.import.ips32", "IPS32 Patch" },
|
||||
{ "hex.builtin.menu.file.export", "Esporta..." },
|
||||
{ "hex.builtin.menu.file.export.title", "Esporta File" },
|
||||
{ "hex.builtin.menu.file.export.ips", "IPS Patch" },
|
||||
{ "hex.builtin.menu.file.export.ips32", "IPS32 Patch" },
|
||||
//{ "hex.builtin.menu.file.export.base64.popup.export_error", "File is not in a valid Base64 format!" },
|
||||
//{ "hex.builtin.menu.file.export.popup.create", "Cannot export data. Failed to create file!" },
|
||||
|
||||
{ "hex.builtin.menu.edit", "Modifica" },
|
||||
{ "hex.builtin.menu.edit.undo", "Annulla" },
|
||||
{ "hex.builtin.menu.edit.redo", "Ripeti" },
|
||||
{ "hex.builtin.menu.edit.bookmark", "Crea segnalibro" },
|
||||
|
||||
{ "hex.builtin.menu.view", "Vista" },
|
||||
{ "hex.builtin.menu.layout", "Layout" },
|
||||
{ "hex.builtin.menu.view.fps", "Mostra FPS" },
|
||||
@ -206,48 +237,15 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.view.help.calc_cheat_sheet", "Calcolatrice Cheat Sheet" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.name", "Hex editor" },
|
||||
{ "hex.builtin.view.hex_editor.create_file", "Nuovo" },
|
||||
{ "hex.builtin.view.hex_editor.open_file", "Apri" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_recent", "File recenti" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.clear_recent", "Pulisci" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_other", "Apri altro..." },
|
||||
{ "hex.builtin.view.hex_editor.open_project", "Apri i Progetti" },
|
||||
{ "hex.builtin.view.hex_editor.save_project", "Salva i Progetti" },
|
||||
{ "hex.builtin.view.hex_editor.save_data", "Salva i Dati" },
|
||||
{ "hex.builtin.view.hex_editor.open_base64", "Apri Base64 File" },
|
||||
{ "hex.builtin.view.hex_editor.load_enconding_file", "Carica un File di codfica personalizzato" },
|
||||
{ "hex.builtin.view.hex_editor.page", "Pagina {0} / {1}" },
|
||||
{ "hex.builtin.view.hex_editor.save_as", "Salva come" },
|
||||
{ "hex.builtin.view.hex_editor.exit_application.title", "Uscire dall'applicazione?" },
|
||||
{ "hex.builtin.view.hex_editor.exit_application.desc", "Hai delle modifiche non salvate nel tuo progetto.\nSei sicuro di voler uscire?" },
|
||||
{ "hex.builtin.view.hex_editor.script.title", "Carica un File tramite il Caricatore di Script" },
|
||||
{ "hex.builtin.view.hex_editor.script.desc", "Carica un file tramite il Caricatore di Script di Python." },
|
||||
{ "hex.builtin.view.hex_editor.script.script", "Script" },
|
||||
{ "hex.builtin.view.hex_editor.script.script.title", "Caricatore Script: Apri Script" },
|
||||
{ "hex.builtin.view.hex_editor.script.file", "File" },
|
||||
{ "hex.builtin.view.hex_editor.script.file.title", "Caricatore Script: Apri File" },
|
||||
{ "hex.builtin.view.hex_editor.processing", "Importa / Esporta" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_file", "Apri File..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save", "Salva" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save_as", "Salva come..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.close", "Chiudi" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.quit", "Uscita ImHex" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_project", "Apri un Progetto..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save_project", "Salva Progetto..." },
|
||||
//{ "hex.builtin.view.hex_editor.page", "Page" },
|
||||
//{ "hex.builtin.view.hex_editor.selection", "Selection" },
|
||||
//{ "hex.builtin.view.hex_editor.selection.none", "None" },
|
||||
//{ "hex.builtin.view.hex_editor.region", "Region" },
|
||||
//{ "hex.builtin.view.hex_editor.data_size", "Data Size" },
|
||||
//{ "hex.builtin.view.hex_editor.no_bytes", "No bytes available" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.menu.file.load_encoding_file", "Carica una codifica personalizzata..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import", "Importa..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.base64", "Base64 File" },
|
||||
{ "hex.builtin.view.hex_editor.base64.import_error", "Il file non è in un formato bas64 corretto!" },
|
||||
{ "hex.builtin.view.hex_editor.file_open_error", "Impossibile aprire il File!" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.ips", "IPS Patch" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.ips32", "IPS32 Patch" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.script", "File con il Caricatore di Script" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export", "Esporta..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.title", "Esporta File" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.ips", "IPS Patch" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.ips32", "IPS32 Patch" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.search", "Cerca" },
|
||||
{ "hex.builtin.view.hex_editor.search.string", "Stringa" },
|
||||
{ "hex.builtin.view.hex_editor.search.hex", "Hex" },
|
||||
@ -256,14 +254,11 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.view.hex_editor.search.find_prev", "Cerca il precedente" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.goto", "Vai a" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.absolute", "Assoluto" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.current", "Corrente" },
|
||||
//{ "hex.builtin.view.hex_editor.goto.offset.current", "Relative" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.begin", "Inizo" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.end", "Fine" },
|
||||
{ "hex.builtin.view.hex_editor.error.read_only", "Impossibile scrivere sul File. File aperto solo in modalità lettura" },
|
||||
{ "hex.builtin.view.hex_editor.error.open", "Impossibile aprire il File!" },
|
||||
{ "hex.builtin.view.hex_editor.error.create", "Impossibile creare il nuovo File!" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.undo", "Annulla" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.redo", "Ripeti" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save", "Salva" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save_as", "Salva come..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.copy", "Copia" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.copy_as", "Copia come..." },
|
||||
{ "hex.builtin.view.hex_editor.copy.hex", "Stringa" },
|
||||
@ -278,7 +273,6 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.view.hex_editor.copy.html", "HTML" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.paste", "Incolla" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.select_all", "Seleziona tutti" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.bookmark", "Crea segnalibro" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.set_base", "Imposta indirizzo di base" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.resize", "Ridimensiona..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.insert", "Inserisci..." },
|
||||
@ -671,15 +665,14 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.setting.interface.scaling.x2_0", "x2.0" },
|
||||
{ "hex.builtin.setting.interface.fps", "Limite FPS" },
|
||||
{ "hex.builtin.setting.interface.fps.unlocked", "Unblocca" },
|
||||
{ "hex.builtin.setting.interface.highlight_alpha", "Evidenziazione dell'opacità" },
|
||||
{ "hex.builtin.setting.hex_editor", "Hex Editor" },
|
||||
{ "hex.builtin.setting.hex_editor.column_count", "Conteggio della colonna dei byte" },
|
||||
{ "hex.builtin.setting.hex_editor.hexii", "Mostra HexII invece dei byte" },
|
||||
//{ "hex.builtin.setting.hex_editor.highlight_color", "Selection highlight color" },
|
||||
//{ "hex.builtin.setting.hex_editor.bytes_per_row", "Bytes per row" },
|
||||
{ "hex.builtin.setting.hex_editor.ascii", "Mostra la colonna ASCII" },
|
||||
{ "hex.builtin.setting.hex_editor.advanced_decoding", "Mostra la colonna di decodifica avanzata" },
|
||||
{ "hex.builtin.setting.hex_editor.grey_zeros", "Taglia fuori gli zeri" },
|
||||
{ "hex.builtin.setting.hex_editor.uppercase_hex", "Caratteri esadecimali maiuscoli" },
|
||||
{ "hex.builtin.setting.hex_editor.extra_info", "Mostra informazioni extra" },
|
||||
//{ "hex.builtin.setting.hex_editor.visualizer", "Data visualizer" },
|
||||
//{ "hex.builtin.setting.folders", "Folders" },
|
||||
//{ "hex.builtin.setting.folders.description", "Specify additional search paths for patterns, scripts, rules and more" },
|
||||
// { "hex.builtin.setting.folders.add_folder", "Add new folder" },
|
||||
@ -706,7 +699,24 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.provider.disk.sector_size", "Dimensione settore" },
|
||||
{ "hex.builtin.provider.disk.reload", "Ricarica" },
|
||||
|
||||
{ "hex.builtin.layouts.default", "Default" }
|
||||
{ "hex.builtin.layouts.default", "Default" },
|
||||
|
||||
//{ "hex.builtin.visualizer.hexadecimal.8bit", "Hexadecimal (8 bits)" },
|
||||
//{ "hex.builtin.visualizer.hexadecimal.16bit", "Hexadecimal (16 bits)" },
|
||||
//{ "hex.builtin.visualizer.hexadecimal.32bit", "Hexadecimal (32 bits)" },
|
||||
//{ "hex.builtin.visualizer.hexadecimal.64bit", "Hexadecimal (64 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.signed.8bit", "Decimal Signed (8 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.signed.16bit", "Decimal Signed (16 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.signed.32bit", "Decimal Signed (32 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.signed.64bit", "Decimal Signed (64 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.unsigned.8bit", "Decimal Unsigned (8 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.unsigned.16bit", "Decimal Unsigned (16 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.unsigned.32bit", "Decimal Unsigned (32 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.unsigned.64bit", "Decimal Unsigned (64 bits)" },
|
||||
//{ "hex.builtin.visualizer.floating_point.32bit", "Floating Point (32 bits)" },
|
||||
//{ "hex.builtin.visualizer.floating_point.64bit", "Floating Point (64 bits)" },
|
||||
//{ "hex.builtin.visualizer.hexii", "HexII" },
|
||||
//{ "hex.builtin.visualizer.rgba8", "RGBA8 Color" },
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -80,11 +80,42 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.common.open", "開く" },
|
||||
{ "hex.builtin.common.browse", "ファイルを参照..." },
|
||||
{ "hex.builtin.common.choose_file", "ファイルを選択" },
|
||||
// { "hex.common.processing", "Processing" },
|
||||
|
||||
{ "hex.builtin.message.file_handler_failed", "登録されたファイルハンドラでファイルを開くのに失敗しました。" },
|
||||
{ "hex.builtin.popup.exit_application.title", "アプリケーションを終了しますか?" },
|
||||
{ "hex.builtin.popup.exit_application.desc", "プロジェクトに保存されていない変更があります。\n終了してもよろしいですか?" },
|
||||
{ "hex.builtin.popup.error.read_only", "書き込み権限を取得できませんでした。ファイルが読み取り専用で開かれました。" },
|
||||
{ "hex.builtin.popup.error.open", "ファイルを開けませんでした!" },
|
||||
{ "hex.builtin.popup.error.create", "新しいファイルを作成できませんでした!" },
|
||||
|
||||
{ "hex.builtin.menu.file", "ファイル" },
|
||||
{ "hex.builtin.menu.file.open_file", "ファイルを開く..." },
|
||||
{ "hex.builtin.menu.file.open_recent", "最近使用したファイルを開く" },
|
||||
{ "hex.builtin.menu.file.clear_recent", "消去" },
|
||||
{ "hex.builtin.menu.file.open_other", "その他の開くオプション..." },
|
||||
{ "hex.builtin.menu.file.close", "ファイルを閉じる" },
|
||||
{ "hex.builtin.menu.file.quit", "ImHexを終了" },
|
||||
{ "hex.builtin.menu.file.open_project", "プロジェクトを開く..." },
|
||||
{ "hex.builtin.menu.file.save_project", "プロジェクトを保存..." },
|
||||
{ "hex.builtin.menu.file.load_encoding_file", "カスタムエンコードを読み込み..." },
|
||||
{ "hex.builtin.menu.file.import", "インポート..." },
|
||||
{ "hex.builtin.menu.file.import.base64", "Base64ファイル" },
|
||||
{ "hex.builtin.menu.file.import.base64.popup.import_error", "ファイルが有効なBase64形式ではありません!" },
|
||||
{ "hex.builtin.menu.file.import.base64.popup.open_error", "ファイルを開けませんでした!" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.ips", "IPSパッチ" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.ips32", "IPS32パッチ" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export", "エクスポート..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.title", "ファイルをエクスポート" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.ips", "IPSパッチ" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.ips32", "IPS32パッチ" },
|
||||
{ "hex.builtin.menu.file.import.base64.popup.export_error", "ファイルが有効なBase64形式ではありません!" },
|
||||
//{ "hex.builtin.menu.file.export.popup.create", "Cannot export data. Failed to create file!" },
|
||||
|
||||
{ "hex.builtin.menu.edit", "編集" },
|
||||
{ "hex.builtin.menu.edit.undo", "もとに戻す" },
|
||||
{ "hex.builtin.menu.edit.redo", "やり直す" },
|
||||
{ "hex.builtin.menu.edit.bookmark", "ブックマークを作成" },
|
||||
|
||||
{ "hex.builtin.menu.view", "表示" },
|
||||
{ "hex.builtin.menu.layout", "レイアウト" },
|
||||
{ "hex.builtin.menu.view.fps", "FPSを表示" },
|
||||
@ -210,48 +241,13 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.view.help.calc_cheat_sheet", "計算機チートシート" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.name", "Hexエディタ" },
|
||||
{ "hex.builtin.view.hex_editor.create_file", "新規" },
|
||||
{ "hex.builtin.view.hex_editor.open_file", "開く" },
|
||||
{ "hex.builtin.view.hex_editor.open_project", "プロジェクトを開く" },
|
||||
{ "hex.builtin.view.hex_editor.save_project", "プロジェクトを保存" },
|
||||
{ "hex.builtin.view.hex_editor.save_data", "データを保存" },
|
||||
{ "hex.builtin.view.hex_editor.open_base64", "Base64ファイルを開く" },
|
||||
{ "hex.builtin.view.hex_editor.load_enconding_file", "カスタムエンコードファイルの読み込み" }, //?
|
||||
{ "hex.builtin.view.hex_editor.page", "ページ {0} / {1}" },
|
||||
{ "hex.builtin.view.hex_editor.save_as", "名前をつけて保存" },
|
||||
{ "hex.builtin.view.hex_editor.exit_application.title", "アプリケーションを終了しますか?" },
|
||||
{ "hex.builtin.view.hex_editor.exit_application.desc", "プロジェクトに保存されていない変更があります。\n終了してもよろしいですか?" },
|
||||
{ "hex.builtin.view.hex_editor.script.title", "ローダースクリプトでファイルを読み込む" },
|
||||
{ "hex.builtin.view.hex_editor.script.desc", "Pythonのローダースクリプトを使用してファイルを読み込みます。" },
|
||||
{ "hex.builtin.view.hex_editor.script.script", "スクリプト" },
|
||||
{ "hex.builtin.view.hex_editor.script.script.title", "ローダースクリプト: スクリプトを開く" },
|
||||
{ "hex.builtin.view.hex_editor.script.file", "ファイル" },
|
||||
{ "hex.builtin.view.hex_editor.script.file.title", "ローダースクリプト: ファイルを開く" },
|
||||
{ "hex.builtin.view.hex_editor.processing", "インポート / エクスポート" },
|
||||
//{ "hex.builtin.view.hex_editor.page", "Page" },
|
||||
//{ "hex.builtin.view.hex_editor.selection", "Selection" },
|
||||
//{ "hex.builtin.view.hex_editor.selection.none", "None" },
|
||||
//{ "hex.builtin.view.hex_editor.region", "Region" },
|
||||
//{ "hex.builtin.view.hex_editor.data_size", "Data Size" },
|
||||
//{ "hex.builtin.view.hex_editor.no_bytes", "No bytes available" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_file", "ファイルを開く..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_recent", "最近使用したファイルを開く" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.clear_recent", "消去" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_other", "その他の開くオプション..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save", "保存" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save_as", "名前をつけて保存..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.close", "ファイルを閉じる" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.quit", "ImHexを終了" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_project", "プロジェクトを開く..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save_project", "プロジェクトを保存..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.load_encoding_file", "カスタムエンコードを読み込み..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import", "インポート..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.base64", "Base64ファイル" },
|
||||
{ "hex.builtin.view.hex_editor.base64.import_error", "ファイルが有効なBase64形式ではありません!" },
|
||||
{ "hex.builtin.view.hex_editor.file_open_error", "ファイルを開けませんでした!" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.ips", "IPSパッチ" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.ips32", "IPS32パッチ" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.script", "ローダースクリプト付きのファイル" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export", "エクスポート..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.title", "ファイルをエクスポート" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.ips", "IPSパッチ" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.ips32", "IPS32パッチ" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.search", "検索" },
|
||||
{ "hex.builtin.view.hex_editor.search.string", "文字列" },
|
||||
{ "hex.builtin.view.hex_editor.search.hex", "16進" },
|
||||
@ -260,14 +256,11 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.view.hex_editor.search.find_prev", "前を検索" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.goto", "移動" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.absolute", "絶対値" }, //?
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.current", "現在" }, //?
|
||||
//{ "hex.builtin.view.hex_editor.goto.offset.relative", "Relative" }, //?
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.begin", "開始" }, //?
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.end", "終了" }, //?
|
||||
{ "hex.builtin.view.hex_editor.error.read_only", "書き込み権限を取得できませんでした。ファイルが読み取り専用で開かれました。" },
|
||||
{ "hex.builtin.view.hex_editor.error.open", "ファイルを開けませんでした!" },
|
||||
{ "hex.builtin.view.hex_editor.error.create", "新しいファイルを作成できませんでした!" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.undo", "もとに戻す" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.redo", "やり直す" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save", "保存" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save_as", "名前をつけて保存..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.copy", "コピー" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.copy_as", "〜としてコピー..." },
|
||||
{ "hex.builtin.view.hex_editor.copy.hex", "文字列" },
|
||||
@ -671,15 +664,15 @@ namespace hex::plugin::builtin {
|
||||
//{ "hex.builtin.setting.interface.wiki_explain_language", "Wikipedia Language" },
|
||||
{ "hex.builtin.setting.interface.fps", "FPS制限" },
|
||||
{ "hex.builtin.setting.interface.fps.unlocked", "無制限" },
|
||||
{ "hex.builtin.setting.interface.highlight_alpha", "ハイライトの不透明度" },
|
||||
{ "hex.builtin.setting.hex_editor", "Hexエディタ" },
|
||||
{ "hex.builtin.setting.hex_editor.column_count", "バイトのカラム数" },
|
||||
{ "hex.builtin.setting.hex_editor.hexii", "Bytesの代わりにHexIIを表示する" },
|
||||
//{ "hex.builtin.setting.hex_editor.highlight_color", "Selection highlight color" },
|
||||
//{ "hex.builtin.setting.hex_editor.bytes_per_row", "Bytes per row" },
|
||||
{ "hex.builtin.setting.hex_editor.ascii", "ASCIIカラムを表示" },
|
||||
{ "hex.builtin.setting.hex_editor.advanced_decoding", "高度なデコードカラムを表示" },
|
||||
{ "hex.builtin.setting.hex_editor.grey_zeros", "ゼロをグレーアウト" },
|
||||
{ "hex.builtin.setting.hex_editor.uppercase_hex", "16進数を大文字表記" },
|
||||
{ "hex.builtin.setting.hex_editor.extra_info", "追加情報を表示" },
|
||||
//{ "hex.builtin.setting.hex_editor.visualizer", "Data visualizer" },
|
||||
|
||||
//{ "hex.builtin.setting.folders", "Folders" },
|
||||
//{ "hex.builtin.setting.folders.description", "Specify additional search paths for patterns, scripts, rules and more" },
|
||||
// { "hex.builtin.setting.folders.add_folder", "Add new folder" },
|
||||
@ -706,7 +699,24 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.provider.disk.sector_size", "セクタサイズ" },
|
||||
{ "hex.builtin.provider.disk.reload", "リロード" },
|
||||
|
||||
{ "hex.builtin.layouts.default", "標準" }
|
||||
{ "hex.builtin.layouts.default", "標準" },
|
||||
|
||||
//{ "hex.builtin.visualizer.hexadecimal.8bit", "Hexadecimal (8 bits)" },
|
||||
//{ "hex.builtin.visualizer.hexadecimal.16bit", "Hexadecimal (16 bits)" },
|
||||
//{ "hex.builtin.visualizer.hexadecimal.32bit", "Hexadecimal (32 bits)" },
|
||||
//{ "hex.builtin.visualizer.hexadecimal.64bit", "Hexadecimal (64 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.signed.8bit", "Decimal Signed (8 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.signed.16bit", "Decimal Signed (16 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.signed.32bit", "Decimal Signed (32 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.signed.64bit", "Decimal Signed (64 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.unsigned.8bit", "Decimal Unsigned (8 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.unsigned.16bit", "Decimal Unsigned (16 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.unsigned.32bit", "Decimal Unsigned (32 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.unsigned.64bit", "Decimal Unsigned (64 bits)" },
|
||||
//{ "hex.builtin.visualizer.floating_point.32bit", "Floating Point (32 bits)" },
|
||||
//{ "hex.builtin.visualizer.floating_point.64bit", "Floating Point (64 bits)" },
|
||||
//{ "hex.builtin.visualizer.hexii", "HexII" },
|
||||
//{ "hex.builtin.visualizer.rgba8", "RGBA8 Color" },
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -80,11 +80,41 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.common.open", "打开" },
|
||||
{ "hex.builtin.common.browse", "浏览..." },
|
||||
{ "hex.builtin.common.choose_file", "选择文件" },
|
||||
//{ "hex.common.processing", "Processing" },
|
||||
|
||||
{ "hex.builtin.message.file_handler_failed", "通过注册的文件处理器打开文件失败。" },
|
||||
{ "hex.builtin.popup.exit_application.title", "退出?" },
|
||||
{ "hex.builtin.popup.exit_application.desc", "工程还有为保存的更改。\n确定要退出吗?" },
|
||||
{ "hex.builtin.popup.error.read_only", "无法获得写权限,文件以只读方式打开。" },
|
||||
{ "hex.builtin.popup.error.open", "打开文件失败!" },
|
||||
{ "hex.builtin.popup.error.create", "创建新文件失败!" },
|
||||
|
||||
{ "hex.builtin.menu.file", "文件" },
|
||||
{ "hex.builtin.menu.file.open_file", "打开文件..." },
|
||||
{ "hex.builtin.menu.file.open_recent", "打开最近" },
|
||||
{ "hex.builtin.menu.file.clear_recent", "清除" },
|
||||
{ "hex.builtin.menu.file.open_other", "打开其他..." },
|
||||
{ "hex.builtin.menu.file.close", "关闭" },
|
||||
{ "hex.builtin.menu.file.quit", "退出ImHex" },
|
||||
{ "hex.builtin.menu.file.open_project", "打开项目..." },
|
||||
{ "hex.builtin.menu.file.save_project", "保存项目..." },
|
||||
{ "hex.builtin.menu.file.import", "导入..." },
|
||||
{ "hex.builtin.menu.file.import.base64", "Base64文件" },
|
||||
{ "hex.builtin.menu.file.import.base64.popup.import_error", "文件不是有效的Base64格式!" },
|
||||
{ "hex.builtin.menu.file.import.base64.popup.open_error", "打开文件失败!" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.ips", "IPS补丁" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.ips32", "IPS32补丁" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export", "导出..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.title", "导出文件" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.ips", "IPS补丁" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.ips32", "IPS32补丁" },
|
||||
//{ "hex.builtin.menu.file.export.base64.popup.export_error", "File is not in a valid Base64 format!" },
|
||||
//{ "hex.builtin.menu.file.export.popup.create", "Cannot export data. Failed to create file!" },
|
||||
|
||||
{ "hex.builtin.menu.edit", "编辑" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.undo", "撤销" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.redo", "重做" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.bookmark", "添加书签" },
|
||||
|
||||
{ "hex.builtin.menu.view", "视图" },
|
||||
{ "hex.builtin.menu.layout", "布局" },
|
||||
{ "hex.builtin.menu.view.fps", "显示FPS" },
|
||||
@ -206,48 +236,14 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.view.help.calc_cheat_sheet", "计算器帮助" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.name", "Hex编辑器" },
|
||||
{ "hex.builtin.view.hex_editor.create_file", "新建" },
|
||||
{ "hex.builtin.view.hex_editor.open_file", "打开" },
|
||||
{ "hex.builtin.view.hex_editor.open_project", "打开项目" },
|
||||
{ "hex.builtin.view.hex_editor.save_project", "保存项目" },
|
||||
{ "hex.builtin.view.hex_editor.save_data", "保存数据" },
|
||||
{ "hex.builtin.view.hex_editor.open_base64", "打开Base64文件" },
|
||||
{ "hex.builtin.view.hex_editor.load_enconding_file", "加载自定义编码定义文件" },
|
||||
{ "hex.builtin.view.hex_editor.page", "页 {0} / {1}" },
|
||||
{ "hex.builtin.view.hex_editor.save_as", "另存为" },
|
||||
{ "hex.builtin.view.hex_editor.exit_application.title", "退出?" },
|
||||
{ "hex.builtin.view.hex_editor.exit_application.desc", "工程还有为保存的更改。\n确定要退出吗?" },
|
||||
{ "hex.builtin.view.hex_editor.script.title", "通过加载器脚本加载文件" },
|
||||
{ "hex.builtin.view.hex_editor.script.desc", "通过Python加载器脚本加载文件。" },
|
||||
{ "hex.builtin.view.hex_editor.script.script", "脚本" },
|
||||
{ "hex.builtin.view.hex_editor.script.script.title", "加载器脚本:打开脚本" },
|
||||
{ "hex.builtin.view.hex_editor.script.file", "文件" },
|
||||
{ "hex.builtin.view.hex_editor.script.file.title", "加载器脚本:打开文件" },
|
||||
{ "hex.builtin.view.hex_editor.processing", "导入 / 导出" },
|
||||
//{ "hex.builtin.view.hex_editor.page", "Page" },
|
||||
//{ "hex.builtin.view.hex_editor.selection", "Selection" },
|
||||
//{ "hex.builtin.view.hex_editor.selection.none", "None" },
|
||||
//{ "hex.builtin.view.hex_editor.region", "Region" },
|
||||
//{ "hex.builtin.view.hex_editor.data_size", "Data Size" },
|
||||
//{ "hex.builtin.view.hex_editor.no_bytes", "No bytes available" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_file", "打开文件..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_recent", "打开最近" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.clear_recent", "清除" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_other", "打开其他..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save", "保存" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save_as", "另存为..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.close", "关闭" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.quit", "退出ImHex" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.open_project", "打开项目..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save_project", "保存项目..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.load_encoding_file", "加载自定义编码..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import", "导入..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.base64", "Base64文件" },
|
||||
{ "hex.builtin.view.hex_editor.base64.import_error", "文件不是有效的Base64格式!" },
|
||||
{ "hex.builtin.view.hex_editor.file_open_error", "打开文件失败!" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.ips", "IPS补丁" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.ips32", "IPS32补丁" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.import.script", "带有加载器脚本的文件" },
|
||||
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export", "导出..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.title", "导出文件" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.ips", "IPS补丁" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.export.ips32", "IPS32补丁" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.search", "搜索" },
|
||||
{ "hex.builtin.view.hex_editor.search.string", "字符串" },
|
||||
{ "hex.builtin.view.hex_editor.search.hex", "Hex" },
|
||||
@ -256,14 +252,11 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.view.hex_editor.search.find_prev", "查找上一个" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.goto", "转到" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.absolute", "绝对" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.current", "当前" },
|
||||
//{ "hex.builtin.view.hex_editor.goto.offset.relative", "Relative" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.begin", "起始" },
|
||||
{ "hex.builtin.view.hex_editor.goto.offset.end", "末尾" },
|
||||
{ "hex.builtin.view.hex_editor.error.read_only", "无法获得写权限,文件以只读方式打开。" },
|
||||
{ "hex.builtin.view.hex_editor.error.open", "打开文件失败!" },
|
||||
{ "hex.builtin.view.hex_editor.error.create", "创建新文件失败!" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.undo", "撤销" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.redo", "重做" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save", "保存" },
|
||||
{ "hex.builtin.view.hex_editor.menu.file.save_as", "另存为..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.copy", "复制" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.copy_as", "复制为..." },
|
||||
{ "hex.builtin.view.hex_editor.copy.hex", "字符串" },
|
||||
@ -278,7 +271,6 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.view.hex_editor.copy.html", "HTML" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.paste", "粘贴" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.select_all", "全选" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.bookmark", "添加书签" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.set_base", "设置基地址" },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.resize", "修改大小..." },
|
||||
{ "hex.builtin.view.hex_editor.menu.edit.insert", "插入..." },
|
||||
@ -665,16 +657,14 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.setting.interface.wiki_explain_language", "维基百科语种" },
|
||||
{ "hex.builtin.setting.interface.fps", "FPS限制" },
|
||||
{ "hex.builtin.setting.interface.fps.unlocked", "无限制" },
|
||||
{ "hex.builtin.setting.interface.highlight_alpha", "高亮不透明度" },
|
||||
{ "hex.builtin.setting.hex_editor", "Hex编辑器" },
|
||||
{ "hex.builtin.setting.hex_editor.column_count", "字节列数" },
|
||||
{ "hex.builtin.setting.hex_editor.hexii", "显示HexII替代字节" },
|
||||
//{ "hex.builtin.setting.hex_editor.highlight_color", "Selection highlight color" },
|
||||
//{ "hex.builtin.setting.hex_editor.bytes_per_row", "Bytes per row" },
|
||||
{ "hex.builtin.setting.hex_editor.ascii", "显示ASCII栏" },
|
||||
{ "hex.builtin.setting.hex_editor.advanced_decoding", "显示高级解码栏" },
|
||||
{ "hex.builtin.setting.hex_editor.grey_zeros", "显示零字节为灰色" },
|
||||
{ "hex.builtin.setting.hex_editor.uppercase_hex", "大写Hex字符" },
|
||||
{ "hex.builtin.setting.hex_editor.extra_info", "显示额外信息" },
|
||||
|
||||
//{ "hex.builtin.setting.hex_editor.visualizer", "Data visualizer" },
|
||||
{ "hex.builtin.setting.folders", "扩展搜索路径" },
|
||||
{ "hex.builtin.setting.folders.description", "为模式、脚本和规则等指定额外的搜索路径" },
|
||||
{ "hex.builtin.setting.folders.add_folder", "添加新的目录" },
|
||||
@ -701,7 +691,24 @@ namespace hex::plugin::builtin {
|
||||
{ "hex.builtin.provider.disk.sector_size", "扇区大小" },
|
||||
{ "hex.builtin.provider.disk.reload", "刷新" },
|
||||
|
||||
{ "hex.builtin.layouts.default", "默认" }
|
||||
{ "hex.builtin.layouts.default", "默认" },
|
||||
|
||||
//{ "hex.builtin.visualizer.hexadecimal.8bit", "Hexadecimal (8 bits)" },
|
||||
//{ "hex.builtin.visualizer.hexadecimal.16bit", "Hexadecimal (16 bits)" },
|
||||
//{ "hex.builtin.visualizer.hexadecimal.32bit", "Hexadecimal (32 bits)" },
|
||||
//{ "hex.builtin.visualizer.hexadecimal.64bit", "Hexadecimal (64 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.signed.8bit", "Decimal Signed (8 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.signed.16bit", "Decimal Signed (16 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.signed.32bit", "Decimal Signed (32 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.signed.64bit", "Decimal Signed (64 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.unsigned.8bit", "Decimal Unsigned (8 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.unsigned.16bit", "Decimal Unsigned (16 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.unsigned.32bit", "Decimal Unsigned (32 bits)" },
|
||||
//{ "hex.builtin.visualizer.decimal.unsigned.64bit", "Decimal Unsigned (64 bits)" },
|
||||
//{ "hex.builtin.visualizer.floating_point.32bit", "Floating Point (32 bits)" },
|
||||
//{ "hex.builtin.visualizer.floating_point.64bit", "Floating Point (64 bits)" },
|
||||
//{ "hex.builtin.visualizer.hexii", "HexII" },
|
||||
//{ "hex.builtin.visualizer.rgba8", "RGBA8 Color" },
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,8 @@
|
||||
#include "math_evaluator.hpp"
|
||||
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#include <stack>
|
||||
@ -10,15 +13,18 @@
|
||||
|
||||
namespace hex {
|
||||
|
||||
i16 comparePrecedence(const Operator &a, const Operator &b) {
|
||||
template<typename T>
|
||||
i16 MathEvaluator<T>::comparePrecedence(const Operator &a, const Operator &b) {
|
||||
return static_cast<i16>((static_cast<i8>(a) & 0x0F0) - (static_cast<i8>(b) & 0x0F0));
|
||||
}
|
||||
|
||||
bool isLeftAssociative(const Operator op) {
|
||||
template<typename T>
|
||||
bool MathEvaluator<T>::isLeftAssociative(const Operator op) {
|
||||
return (static_cast<u32>(op) & 0xF00) == 0;
|
||||
}
|
||||
|
||||
std::pair<Operator, size_t> toOperator(const std::string &input) {
|
||||
template<typename T>
|
||||
std::pair<typename MathEvaluator<T>::Operator, size_t> MathEvaluator<T>::toOperator(const std::string &input) {
|
||||
if (input.starts_with("##")) return { Operator::Combine, 2 };
|
||||
if (input.starts_with("==")) return { Operator::Equals, 2 };
|
||||
if (input.starts_with("!=")) return { Operator::NotEquals, 2 };
|
||||
@ -47,7 +53,8 @@ namespace hex {
|
||||
return { Operator::Invalid, 0 };
|
||||
}
|
||||
|
||||
static std::queue<Token> toPostfix(std::queue<Token> inputQueue) {
|
||||
template<typename T>
|
||||
std::optional<std::queue<typename MathEvaluator<T>::Token>> MathEvaluator<T>::toPostfix(std::queue<Token> inputQueue) {
|
||||
std::queue<Token> outputQueue;
|
||||
std::stack<Token> operatorStack;
|
||||
|
||||
@ -67,12 +74,16 @@ namespace hex {
|
||||
if (currToken.bracketType == BracketType::Left)
|
||||
operatorStack.push(currToken);
|
||||
else {
|
||||
if (operatorStack.empty())
|
||||
throw std::invalid_argument("Mismatching parenthesis!");
|
||||
if (operatorStack.empty()) {
|
||||
this->setError("Mismatching parenthesis!");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
while (operatorStack.top().type != TokenType::Bracket || (operatorStack.top().type == TokenType::Bracket && operatorStack.top().bracketType != BracketType::Left)) {
|
||||
if (operatorStack.empty())
|
||||
throw std::invalid_argument("Mismatching parenthesis!");
|
||||
if (operatorStack.empty()) {
|
||||
this->setError("Mismatching parenthesis!");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
outputQueue.push(operatorStack.top());
|
||||
operatorStack.pop();
|
||||
@ -86,8 +97,10 @@ namespace hex {
|
||||
while (!operatorStack.empty()) {
|
||||
auto top = operatorStack.top();
|
||||
|
||||
if (top.type == TokenType::Bracket)
|
||||
throw std::invalid_argument("Mismatching parenthesis!");
|
||||
if (top.type == TokenType::Bracket) {
|
||||
this->setError("Mismatching parenthesis!");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
outputQueue.push(top);
|
||||
operatorStack.pop();
|
||||
@ -96,13 +109,23 @@ namespace hex {
|
||||
return outputQueue;
|
||||
}
|
||||
|
||||
std::queue<Token> MathEvaluator::parseInput(std::string input) {
|
||||
template<typename T>
|
||||
std::optional<std::queue<typename MathEvaluator<T>::Token>> MathEvaluator<T>::parseInput(std::string input) {
|
||||
std::queue<Token> inputQueue;
|
||||
|
||||
char *prevPos = input.data();
|
||||
for (char *pos = prevPos; *pos != 0x00;) {
|
||||
if (std::isdigit(*pos) || *pos == '.') {
|
||||
auto number = std::strtold(pos, &pos);
|
||||
auto number = [&] {
|
||||
if constexpr (hex::floating_point<T>)
|
||||
return std::strtold(pos, &pos);
|
||||
else if constexpr (hex::signed_integral<T>)
|
||||
return std::strtoll(pos, &pos, 10);
|
||||
else if constexpr (hex::unsigned_integral<T>)
|
||||
return std::strtoull(pos, &pos, 10);
|
||||
else
|
||||
static_assert(hex::always_false<T>::value, "Can't parse literal of this type");
|
||||
}();
|
||||
|
||||
if (*pos == 'x') {
|
||||
pos--;
|
||||
@ -159,17 +182,26 @@ namespace hex {
|
||||
pos++;
|
||||
|
||||
for (const auto &expression : expressions) {
|
||||
if (expression.empty() && expressions.size() > 1)
|
||||
throw std::invalid_argument("Invalid function call syntax!");
|
||||
if (expression.empty() && expressions.size() > 1) {
|
||||
this->setError("Invalid function call syntax!");
|
||||
return std::nullopt;
|
||||
}
|
||||
else if (expression.empty())
|
||||
break;
|
||||
|
||||
auto newInputQueue = parseInput(expression);
|
||||
auto postfixTokens = toPostfix(newInputQueue);
|
||||
auto result = evaluate(postfixTokens);
|
||||
if (!newInputQueue.has_value())
|
||||
return std::nullopt;
|
||||
|
||||
if (!result.has_value())
|
||||
throw std::invalid_argument("Invalid argument for function!");
|
||||
auto postfixTokens = toPostfix(*newInputQueue);
|
||||
if (!postfixTokens.has_value())
|
||||
return std::nullopt;
|
||||
|
||||
auto result = evaluate(*postfixTokens);
|
||||
if (!result.has_value()) {
|
||||
this->setError("Invalid argument for function!");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
token.arguments.push_back(result.value());
|
||||
}
|
||||
@ -184,8 +216,10 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
if (prevPos == pos)
|
||||
throw std::invalid_argument("Invalid syntax!");
|
||||
if (prevPos == pos) {
|
||||
this->setError("Invalid syntax!");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
prevPos = pos;
|
||||
}
|
||||
@ -193,8 +227,9 @@ namespace hex {
|
||||
return inputQueue;
|
||||
}
|
||||
|
||||
std::optional<long double> MathEvaluator::evaluate(std::queue<Token> postfixTokens) {
|
||||
std::stack<long double> evaluationStack;
|
||||
template<typename T>
|
||||
std::optional<T> MathEvaluator<T>::evaluate(std::queue<Token> postfixTokens) {
|
||||
std::stack<T> evaluationStack;
|
||||
|
||||
while (!postfixTokens.empty()) {
|
||||
auto front = postfixTokens.front();
|
||||
@ -203,13 +238,16 @@ namespace hex {
|
||||
if (front.type == TokenType::Number)
|
||||
evaluationStack.push(front.number);
|
||||
else if (front.type == TokenType::Operator) {
|
||||
long double rightOperand, leftOperand;
|
||||
T rightOperand, leftOperand;
|
||||
if (evaluationStack.size() < 2) {
|
||||
if ((front.op == Operator::Addition || front.op == Operator::Subtraction || front.op == Operator::Not || front.op == Operator::BitwiseNot) && evaluationStack.size() == 1) {
|
||||
rightOperand = evaluationStack.top();
|
||||
evaluationStack.pop();
|
||||
leftOperand = 0;
|
||||
} else throw std::invalid_argument("Not enough operands for operator!");
|
||||
} else {
|
||||
this->setError("Not enough operands for operator!");
|
||||
return std::nullopt;
|
||||
}
|
||||
} else {
|
||||
rightOperand = evaluationStack.top();
|
||||
evaluationStack.pop();
|
||||
@ -217,11 +255,17 @@ namespace hex {
|
||||
evaluationStack.pop();
|
||||
}
|
||||
|
||||
long double result = std::numeric_limits<long double>::quiet_NaN();
|
||||
T result = [] {
|
||||
if constexpr (std::numeric_limits<T>::has_quiet_NaN)
|
||||
return std::numeric_limits<T>::quiet_NaN();
|
||||
else
|
||||
return 0;
|
||||
}();
|
||||
switch (front.op) {
|
||||
default:
|
||||
case Operator::Invalid:
|
||||
throw std::invalid_argument("Invalid operator!");
|
||||
this->setError("Invalid operator!");
|
||||
return std::nullopt;
|
||||
case Operator::And:
|
||||
result = static_cast<i64>(leftOperand) && static_cast<i64>(rightOperand);
|
||||
break;
|
||||
@ -283,10 +327,16 @@ namespace hex {
|
||||
result = leftOperand / rightOperand;
|
||||
break;
|
||||
case Operator::Modulus:
|
||||
result = std::fmod(leftOperand, rightOperand);
|
||||
if constexpr (std::floating_point<T>)
|
||||
result = std::fmod(leftOperand, rightOperand);
|
||||
else
|
||||
result = leftOperand % rightOperand;
|
||||
break;
|
||||
case Operator::Exponentiation:
|
||||
result = std::pow(leftOperand, rightOperand);
|
||||
if constexpr (std::floating_point<T>)
|
||||
result = std::pow(leftOperand, rightOperand);
|
||||
else
|
||||
result = hex::powi(leftOperand, rightOperand);
|
||||
break;
|
||||
case Operator::Combine:
|
||||
result = (static_cast<u64>(leftOperand) << (64 - __builtin_clzll(static_cast<u64>(rightOperand)))) | static_cast<u64>(rightOperand);
|
||||
@ -297,51 +347,66 @@ namespace hex {
|
||||
} else if (front.type == TokenType::Variable) {
|
||||
if (this->m_variables.contains(front.name))
|
||||
evaluationStack.push(this->m_variables.at(front.name));
|
||||
else
|
||||
throw std::invalid_argument("Unknown variable!");
|
||||
else {
|
||||
this->setError("Unknown variable!");
|
||||
return std::nullopt;
|
||||
}
|
||||
} else if (front.type == TokenType::Function) {
|
||||
if (!this->m_functions[front.name])
|
||||
throw std::invalid_argument("Unknown function called!");
|
||||
if (!this->m_functions[front.name]) {
|
||||
this->setError("Unknown function called!");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto result = this->m_functions[front.name](front.arguments);
|
||||
|
||||
if (result.has_value())
|
||||
evaluationStack.push(result.value());
|
||||
} else
|
||||
throw std::invalid_argument("Parenthesis in postfix expression!");
|
||||
} else {
|
||||
this->setError("Parenthesis in postfix expression!");
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
if (evaluationStack.empty())
|
||||
if (evaluationStack.empty()) {
|
||||
return std::nullopt;
|
||||
else if (evaluationStack.size() > 1)
|
||||
throw std::invalid_argument("Undigested input left!");
|
||||
else
|
||||
}
|
||||
else if (evaluationStack.size() > 1) {
|
||||
this->setError("Undigested input left!");
|
||||
return std::nullopt;
|
||||
}
|
||||
else {
|
||||
return evaluationStack.top();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::optional<long double> MathEvaluator::evaluate(const std::string &input) {
|
||||
template<typename T>
|
||||
std::optional<T> MathEvaluator<T>::evaluate(const std::string &input) {
|
||||
auto inputQueue = parseInput(input);
|
||||
if (!inputQueue.has_value())
|
||||
return std::nullopt;
|
||||
|
||||
std::string resultVariable = "ans";
|
||||
|
||||
{
|
||||
std::queue<Token> queueCopy = inputQueue;
|
||||
auto queueCopy = *inputQueue;
|
||||
if (queueCopy.front().type == TokenType::Variable) {
|
||||
resultVariable = queueCopy.front().name;
|
||||
queueCopy.pop();
|
||||
if (queueCopy.front().type != TokenType::Operator || queueCopy.front().op != Operator::Assign)
|
||||
resultVariable = "ans";
|
||||
else {
|
||||
inputQueue.pop();
|
||||
inputQueue.pop();
|
||||
inputQueue->pop();
|
||||
inputQueue->pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto postfixTokens = toPostfix(inputQueue);
|
||||
auto postfixTokens = toPostfix(*inputQueue);
|
||||
if (!postfixTokens.has_value())
|
||||
return std::nullopt;
|
||||
|
||||
auto result = evaluate(postfixTokens);
|
||||
auto result = evaluate(*postfixTokens);
|
||||
|
||||
if (result.has_value()) {
|
||||
this->setVariable(resultVariable, result.value());
|
||||
@ -350,48 +415,59 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
void MathEvaluator::setVariable(const std::string &name, long double value) {
|
||||
template<typename T>
|
||||
void MathEvaluator<T>::setVariable(const std::string &name, T value) {
|
||||
this->m_variables[name] = value;
|
||||
}
|
||||
|
||||
void MathEvaluator::setFunction(const std::string &name, const std::function<std::optional<long double>(std::vector<long double>)> &function, size_t minNumArgs, size_t maxNumArgs) {
|
||||
this->m_functions[name] = [minNumArgs, maxNumArgs, function](auto args) {
|
||||
if (args.size() < minNumArgs || args.size() > maxNumArgs)
|
||||
throw std::invalid_argument("Invalid number of function arguments!");
|
||||
template<typename T>
|
||||
void MathEvaluator<T>::setFunction(const std::string &name, const std::function<std::optional<T>(std::vector<T>)> &function, size_t minNumArgs, size_t maxNumArgs) {
|
||||
this->m_functions[name] = [this, minNumArgs, maxNumArgs, function](auto args) -> std::optional<T> {
|
||||
if (args.size() < minNumArgs || args.size() > maxNumArgs) {
|
||||
this->setError("Invalid number of function arguments!");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
return function(args);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void MathEvaluator::registerStandardVariables() {
|
||||
template<typename T>
|
||||
void MathEvaluator<T>::registerStandardVariables() {
|
||||
this->setVariable("ans", 0);
|
||||
}
|
||||
|
||||
void MathEvaluator::registerStandardFunctions() {
|
||||
this->setFunction(
|
||||
"sin", [](auto args) { return std::sin(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"cos", [](auto args) { return std::cos(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"tan", [](auto args) { return std::tan(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"sqrt", [](auto args) { return std::sqrt(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"ceil", [](auto args) { return std::ceil(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"floor", [](auto args) { return std::floor(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"sign", [](auto args) { return (args[0] > 0) ? 1 : (args[0] == 0) ? 0
|
||||
: -1; }, 1, 1);
|
||||
this->setFunction(
|
||||
"abs", [](auto args) { return std::abs(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"ln", [](auto args) { return std::log(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"lb", [](auto args) { return std::log2(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"log", [](auto args) { return args.size() == 1 ? std::log10(args[0]) : std::log(args[1]) / std::log(args[0]); }, 1, 2);
|
||||
template<typename T>
|
||||
void MathEvaluator<T>::registerStandardFunctions() {
|
||||
if constexpr (hex::floating_point<T>) {
|
||||
this->setFunction(
|
||||
"sin", [](auto args) { return std::sin(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"cos", [](auto args) { return std::cos(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"tan", [](auto args) { return std::tan(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"sqrt", [](auto args) { return std::sqrt(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"ceil", [](auto args) { return std::ceil(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"floor", [](auto args) { return std::floor(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"sign", [](auto args) { return (args[0] > 0) ? 1 : (args[0] == 0) ? 0
|
||||
: -1; }, 1, 1);
|
||||
this->setFunction(
|
||||
"abs", [](auto args) { return std::abs(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"ln", [](auto args) { return std::log(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"lb", [](auto args) { return std::log2(args[0]); }, 1, 1);
|
||||
this->setFunction(
|
||||
"log", [](auto args) { return args.size() == 1 ? std::log10(args[0]) : std::log(args[1]) / std::log(args[0]); }, 1, 2);
|
||||
}
|
||||
}
|
||||
|
||||
template class MathEvaluator<long double>;
|
||||
template class MathEvaluator<i128>;
|
||||
|
||||
}
|
||||
|
@ -65,13 +65,10 @@ namespace hex {
|
||||
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "bits");
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
u64 extractedValue = pattern.getValue();
|
||||
ImGui::TextFormatted("{}", pattern.formatDisplayValue(hex::format("{0} (0x{1:X})", extractedValue, extractedValue), &pattern));
|
||||
ImGui::TextFormatted("{}", pattern.getFormattedValue());
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::PatternBitfield& pattern) {
|
||||
std::vector<u8> value = pattern.getValue();
|
||||
|
||||
bool open = true;
|
||||
if (!pattern.isInlined()) {
|
||||
ImGui::TableNextRow();
|
||||
@ -85,12 +82,7 @@ namespace hex {
|
||||
drawSizeColumn(pattern);
|
||||
drawTypenameColumn(pattern, "bitfield");
|
||||
|
||||
std::string valueString = "{ ";
|
||||
for (auto i : value)
|
||||
valueString += hex::format("{0:02X} ", i);
|
||||
valueString += "}";
|
||||
|
||||
ImGui::TextFormatted("{}", pattern.formatDisplayValue(valueString, &pattern));
|
||||
ImGui::TextFormatted("{}", pattern.getFormattedValue());
|
||||
} else {
|
||||
ImGui::SameLine();
|
||||
ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf);
|
||||
@ -106,50 +98,14 @@ namespace hex {
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::PatternBoolean& pattern) {
|
||||
u8 boolean = pattern.getValue();
|
||||
|
||||
if (boolean == 0)
|
||||
this->createDefaultEntry(pattern, "false", false);
|
||||
else if (boolean == 1)
|
||||
this->createDefaultEntry(pattern, "true", true);
|
||||
else
|
||||
this->createDefaultEntry(pattern, "true*", true);
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), static_cast<bool>(pattern.getValue()));
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::PatternCharacter& pattern) {
|
||||
char character = pattern.getValue();
|
||||
this->createDefaultEntry(pattern, hex::format("'{0}'", character), character);
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), pattern.getValue());
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::PatternEnum& pattern) {
|
||||
u64 value = pattern.getValue();
|
||||
|
||||
std::string valueString = pattern.getTypeName() + "::";
|
||||
|
||||
bool foundValue = false;
|
||||
for (auto &[entryValueLiteral, entryName] : pattern.getEnumValues()) {
|
||||
auto visitor = overloaded {
|
||||
[&, name = entryName](auto &entryValue) {
|
||||
if (static_cast<decltype(entryValue)>(value) == entryValue) {
|
||||
valueString += name;
|
||||
foundValue = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
[](const std::string &) { return false; },
|
||||
[](pl::Pattern *) { return false; },
|
||||
};
|
||||
|
||||
bool matches = std::visit(visitor, entryValueLiteral);
|
||||
if (matches)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!foundValue)
|
||||
valueString += "???";
|
||||
|
||||
ImGui::TableNextRow();
|
||||
createLeafNode(pattern);
|
||||
drawCommentTooltip(pattern);
|
||||
@ -161,20 +117,14 @@ namespace hex {
|
||||
drawOffsetColumn(pattern);
|
||||
drawSizeColumn(pattern);
|
||||
drawTypenameColumn(pattern, "enum");
|
||||
ImGui::TextFormatted("{}", pattern.formatDisplayValue(hex::format("{} (0x{:0{}X})", valueString.c_str(), value, pattern.getSize() * 2), &pattern));
|
||||
ImGui::TextFormatted("{}", pattern.getFormattedValue());
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::PatternFloat& pattern) {
|
||||
if (pattern.getSize() == 4) {
|
||||
float f32 = static_cast<float>(pattern.getValue());
|
||||
u32 integerResult = 0;
|
||||
std::memcpy(&integerResult, &f32, sizeof(float));
|
||||
this->createDefaultEntry(pattern, hex::format("{:e} (0x{:0{}X})", f32, integerResult, pattern.getSize() * 2), f32);
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), static_cast<float>(pattern.getValue()));
|
||||
} else if (pattern.getSize() == 8) {
|
||||
double f64 = pattern.getValue();
|
||||
u64 integerResult = 0;
|
||||
std::memcpy(&integerResult, &f64, sizeof(double));
|
||||
this->createDefaultEntry(pattern, hex::format("{:e} (0x{:0{}X})", f64, integerResult, pattern.getSize() * 2), f64);
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), static_cast<double>(pattern.getValue()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -184,8 +134,6 @@ namespace hex {
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::PatternPointer& pattern) {
|
||||
u64 data = pattern.getValue();
|
||||
|
||||
bool open = true;
|
||||
|
||||
if (!pattern.isInlined()) {
|
||||
@ -201,7 +149,7 @@ namespace hex {
|
||||
drawSizeColumn(pattern);
|
||||
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{}", pattern.getFormattedName());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", pattern.formatDisplayValue(hex::format("*(0x{0:X})", data), u128(data)));
|
||||
ImGui::TextFormatted("{}", pattern.getFormattedValue());
|
||||
} else {
|
||||
ImGui::SameLine();
|
||||
ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf);
|
||||
@ -215,18 +163,11 @@ namespace hex {
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::PatternSigned& pattern) {
|
||||
i128 data = pattern.getValue();
|
||||
this->createDefaultEntry(pattern, hex::format("{:d} (0x{:0{}X})", data, data, 1 * 2), data);
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), pattern.getValue());
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::PatternString& pattern) {
|
||||
auto size = std::min<size_t>(pattern.getSize(), 0x7F);
|
||||
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
std::string displayString = pattern.getValue(size);
|
||||
this->createDefaultEntry(pattern, hex::format("\"{0}\" {1}", displayString, size > pattern.getSize() ? "(truncated)" : ""), displayString);
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), pattern.getValue());
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::PatternStruct& pattern) {
|
||||
@ -243,7 +184,7 @@ namespace hex {
|
||||
drawOffsetColumn(pattern);
|
||||
drawSizeColumn(pattern);
|
||||
drawTypenameColumn(pattern, "struct");
|
||||
ImGui::TextFormatted("{}", pattern.formatDisplayValue("{ ... }", &pattern));
|
||||
ImGui::TextFormatted("{}", pattern.getFormattedValue());
|
||||
} else {
|
||||
ImGui::SameLine();
|
||||
ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf);
|
||||
@ -272,7 +213,7 @@ namespace hex {
|
||||
drawOffsetColumn(pattern);
|
||||
drawSizeColumn(pattern);
|
||||
drawTypenameColumn(pattern, "union");
|
||||
ImGui::TextFormatted("{}", pattern.formatDisplayValue("{ ... }", &pattern));
|
||||
ImGui::TextFormatted("{}", pattern.getFormattedValue());
|
||||
} else {
|
||||
ImGui::SameLine();
|
||||
ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf);
|
||||
@ -288,26 +229,17 @@ namespace hex {
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::PatternUnsigned& pattern) {
|
||||
u128 data = pattern.getValue();
|
||||
this->createDefaultEntry(pattern, hex::format("{:d} (0x{:0{}X})", data, data, pattern.getSize() * 2), data);
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), pattern.getValue());
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::PatternWideCharacter& pattern) {
|
||||
char16_t character = pattern.getValue();
|
||||
u128 literal = character;
|
||||
auto str = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.to_bytes(character);
|
||||
this->createDefaultEntry(pattern, hex::format("'{0}'", str), literal);
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), u128(pattern.getValue()));
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::PatternWideString& pattern) {
|
||||
auto size = std::min<size_t>(pattern.getSize(), 0x100);
|
||||
std::string utf8String = pattern.getValue();
|
||||
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
std::string utf8String = pattern.getValue(size);
|
||||
|
||||
this->createDefaultEntry(pattern, hex::format("\"{0}\" {1}", utf8String, size > pattern.getSize() ? "(truncated)" : ""), utf8String);
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), utf8String);
|
||||
}
|
||||
|
||||
void PatternDrawer::createDefaultEntry(const pl::Pattern &pattern, const std::string &value, pl::Token::Literal &&literal) const {
|
||||
@ -323,7 +255,7 @@ namespace hex {
|
||||
drawColorColumn(pattern);
|
||||
drawOffsetColumn(pattern);
|
||||
drawSizeColumn(pattern);
|
||||
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{}", pattern.getTypeName().empty() ? pattern.getFormattedName() : pattern.getTypeName());
|
||||
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{}", pattern.getFormattedName().empty() ? pattern.getTypeName() : pattern.getFormattedName());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", pattern.formatDisplayValue(value, literal));
|
||||
}
|
||||
@ -380,7 +312,7 @@ namespace hex {
|
||||
ImGui::TextUnformatted("]");
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", pattern.formatDisplayValue("{ ... }", &pattern));
|
||||
ImGui::TextFormatted("{}", pattern.getFormattedValue());
|
||||
} else {
|
||||
ImGui::SameLine();
|
||||
ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf);
|
||||
|
@ -2,7 +2,8 @@
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
void registerViews();
|
||||
void registerEventHandlers();
|
||||
void registerDataVisualizers();
|
||||
void registerDataInspectorEntries();
|
||||
void registerToolEntries();
|
||||
void registerPatternLanguageFunctions();
|
||||
@ -15,9 +16,11 @@ namespace hex::plugin::builtin {
|
||||
void registerLayouts();
|
||||
void registerMainMenuEntries();
|
||||
void createWelcomeScreen();
|
||||
void registerViews();
|
||||
|
||||
void addFooterItems();
|
||||
void addToolbarItems();
|
||||
void addGlobalUIItems();
|
||||
|
||||
void registerLanguageEnUS();
|
||||
void registerLanguageDeDE();
|
||||
@ -37,7 +40,8 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
||||
registerLanguageJaJP();
|
||||
registerLanguageZhCN();
|
||||
|
||||
registerViews();
|
||||
registerEventHandlers();
|
||||
registerDataVisualizers();
|
||||
registerDataInspectorEntries();
|
||||
registerToolEntries();
|
||||
registerPatternLanguageFunctions();
|
||||
@ -48,9 +52,12 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
|
||||
registerProviders();
|
||||
registerDataFormatters();
|
||||
createWelcomeScreen();
|
||||
registerViews();
|
||||
|
||||
addFooterItems();
|
||||
addToolbarItems();
|
||||
addGlobalUIItems();
|
||||
|
||||
registerLayouts();
|
||||
registerMainMenuEntries();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user