1
0
mirror of synced 2024-11-28 01:20:51 +01:00

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:
WerWolv 2022-05-27 20:42:07 +02:00 committed by GitHub
parent c0ceaa4195
commit b751f98e91
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
48 changed files with 3403 additions and 2732 deletions

3
.idea/vcs.xml generated
View File

@ -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" />

View File

@ -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

@ -1 +1 @@
Subproject commit 0ad67f199db0ca65c9b25935553409480d1cdfd8
Subproject commit 99f3be2cc26632fcfb68f53d2fcd3baf0b8c6387

View File

@ -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;
}
};
}

View File

@ -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)...));
}
}
};
}

View File

@ -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> &);
}

View File

@ -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 &region, color_t color, const std::string &tooltip = "");
void removeHighlight(u32 id);
u32 addBackgroundHighlight(const Region &region, color_t color);
void removeBackgroundHighlight(u32 id);
u32 addHighlightingProvider(const impl::HighlightingFunction &function);
void removeHighlightingProvider(u32 id);
u32 addForegroundHighlight(const Region &region, 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 &region);
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);

View File

@ -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);

View 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;
};
}

View File

@ -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();
}

View File

@ -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;
}
}
}

View File

@ -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 &region, color_t color, const std::string &tooltip) {
auto &highlights = impl::getHighlights();
static u64 id = 0;
u32 addBackgroundHighlight(const Region &region, 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 &region) {
selectedRegion = region;
u32 addForegroundHighlight(const Region &region, 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 &region) {
@ -210,7 +297,7 @@ namespace hex {
}
static float s_globalScale;
static float s_globalScale = 1.0;
void setGlobalScale(float scale) {
s_globalScale = scale;
}

View File

@ -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);

View File

@ -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;
}
}
}

View File

@ -54,6 +54,8 @@ namespace hex {
std::vector<int> m_pressedKeys;
std::fs::path m_imguiSettingsPath;
bool m_mouseButtonDown = false;
};
}

View File

@ -180,7 +180,7 @@ namespace hex::init {
meanScale /= 2;
#endif
if (meanScale <= 0) {
if (meanScale <= 0.0) {
meanScale = 1.0;
}

View File

@ -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());

View File

@ -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));
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;

View File

@ -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

View File

@ -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 &region) { 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;
};
}

View File

@ -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();

View File

@ -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;

View File

@ -11,6 +11,35 @@
namespace hex {
template<typename T>
class MathEvaluator {
public:
MathEvaluator() = default;
std::optional<T> evaluate(const std::string &input);
void registerStandardVariables();
void registerStandardFunctions();
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, 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:
void setError(const std::string &error) {
this->m_lastError = error;
}
private:
enum class TokenType
{
Number,
@ -59,35 +88,31 @@ namespace hex {
TokenType type;
union {
long double number;
T number;
Operator op;
BracketType bracketType;
};
std::string name;
std::vector<long double> arguments;
std::vector<T> arguments;
};
class MathEvaluator {
public:
MathEvaluator() = default;
std::optional<long double> 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);
std::unordered_map<std::string, long double> &getVariables() { return this->m_variables; }
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::queue<Token> parseInput(std::string input);
std::optional<long double> evaluate(std::queue<Token> postfixTokens);
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, long double> m_variables;
std::unordered_map<std::string, std::function<std::optional<long double>(std::vector<long double>)>> m_functions;
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>;
}

View File

@ -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) { }
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("???");
});

View File

@ -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 = 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; };
},

View 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");
}
}

View 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>();
});
}
}

View File

@ -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()) {
@ -29,6 +278,10 @@ namespace hex::plugin::builtin {
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) {

View File

@ -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;
}
}
return false;
ImGui::EndCombo();
}
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");

View File

@ -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();

View File

@ -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();
});
}
}

View File

@ -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();
}

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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()) {

View File

@ -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();

View File

@ -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();

View File

@ -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();
}
});

View File

@ -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" },
});
}

View File

@ -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" },
});
}

View File

@ -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" },
});
}

View File

@ -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" },
});
}

View File

@ -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" },
});
}

View File

@ -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:
if constexpr (std::floating_point<T>)
result = std::fmod(leftOperand, rightOperand);
else
result = leftOperand % rightOperand;
break;
case Operator::Exponentiation:
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,25 +415,32 @@ 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() {
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(
@ -393,5 +465,9 @@ namespace hex {
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>;
}

View File

@ -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);

View File

@ -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();
}