Compare commits

..

98 Commits

Author SHA1 Message Date
WerWolv
066161f397 build: Bump version to 1.10.1 2021-09-30 12:52:12 +02:00
WerWolv
d3e3de3fa2 ux: Improved dropped file loading; Added magic db loading 2021-09-30 12:29:03 +02:00
WerWolv
194bc3e5be settings: Add option for auto-loading patterns 2021-09-30 12:00:11 +02:00
WerWolv
a9e3db0464 patterns: Fixed inlined variable drawing 2021-09-29 20:51:57 +02:00
WerWolv
334ba3ede2 hex-editor: Fixed open file shortcut, improved find/goto popup position 2021-09-28 12:34:55 +02:00
WerWolv
7978964995 ui: Centered "No bookmarks" text 2021-09-27 23:19:41 +02:00
WerWolv
d5ca4c4f28 patterns: Fixed pointer name displaying 2021-09-27 20:16:23 +02:00
WerWolv
08c2e1cd4e patterns: Added [[transform]] and [[pointer_base]] attributes 2021-09-27 18:32:48 +02:00
WerWolv
2f6e91cd9e fix: Open Popup crash 2021-09-27 15:04:30 +02:00
WerWolv
888976873a patterns: Added [[inline]] attribute 2021-09-27 13:31:10 +02:00
WerWolv
5db608c3fc ui: Fixed automatic pattern loading, added better pattern browse popup 2021-09-26 21:18:25 +02:00
WerWolv
e46807c600 ux: Open dropped pattern files in pattern editor 2021-09-26 21:17:46 +02:00
WerWolv
7799bbb57a ui: Improved borderless window resizing and moving 2021-09-26 21:16:49 +02:00
WerWolv
7da8a5b1d8 patterns: Unified expression body parsing 2021-09-26 18:27:18 +02:00
WerWolv
ae9f4fa876 patterns: Increased highlighting performance 2021-09-26 02:23:27 +02:00
WerWolv
e3dd5900e2 patterns: Added parse_int and parse_float functions 2021-09-26 02:23:10 +02:00
WerWolv
aab865fe25 patterns: Fix member access inside if body 2021-09-26 02:22:50 +02:00
WerWolv
62656f4c51 tests: Added pointer test 2021-09-25 23:31:37 +02:00
WerWolv
b323d711cf patterns: Respect endianess when accessing rvalues 2021-09-25 22:46:16 +02:00
WerWolv
9b4cf917d9 patterns: Fixed recursive types 2021-09-25 22:03:55 +02:00
WerWolv
ba97573f93 patterns: Fixed pointers not working correctly 2021-09-25 18:45:23 +02:00
WerWolv
9dc62e1469 patterns: Added std::http::get 2021-09-25 16:24:08 +02:00
WerWolv
55c0cb66e3 patterns: Ignore comments inside strings 2021-09-25 16:23:51 +02:00
WerWolv
a8526585cb patterns: Fixed string access 2021-09-25 14:52:34 +02:00
WerWolv
3850349eae patterns: Fixed enum entry scope resolution 2021-09-25 14:52:17 +02:00
WerWolv
f5bd0b7971 patterns: Moved std::str to std::string 2021-09-25 00:04:54 +02:00
WerWolv
42d9753bdb patterns: Fixed std::str::substr 2021-09-25 00:04:40 +02:00
WerWolv
17d5a5309a patterns: Fixed setting variables in functions 2021-09-25 00:03:32 +02:00
WerWolv
71be77c54b patterns: Fix boolean operations and cast syntax 2021-09-24 12:15:50 +02:00
WerWolv
93c1fbd65e patterns: Fixed function parameters being set in the wrong order 2021-09-24 11:34:06 +02:00
WerWolv
c8114347dc patterns: Fixed project only being marked dirty when evaluating 2021-09-24 01:55:30 +02:00
WerWolv
3c2c2b003f patterns: Fixed unary expressions in parenthesis 2021-09-24 01:55:00 +02:00
WerWolv
2edd6cd6c4 patterns: Added inheritance for structs 2021-09-24 00:47:34 +02:00
WerWolv
6713f65040 patterns: Added auto type 2021-09-23 23:43:16 +02:00
WerWolv
82ee4ad4ca yara: Fixed major memory leak and added include support 2021-09-23 22:57:19 +02:00
WerWolv
d9134f7fe1 store: Added support for downloading tar'd folders 2021-09-23 22:56:49 +02:00
KokaKiwi
ee26839292 build: Fix system libraries usage (#308)
Signed-off-by: KokaKiwi <kokakiwi+git@kokakiwi.net>
2021-09-23 22:01:38 +02:00
WerWolv
cd33376c07 ui: Added custom font size setting 2021-09-22 23:42:52 +02:00
WerWolv
e57481b87c tools: Added file shredder, splitter and combiner 2021-09-22 17:56:06 +02:00
WerWolv
5601aab043 fix: Close file option crashing 2021-09-22 12:58:49 +02:00
WerWolv
1b7a1852bc fix: Update prompt displaying even on current version 2021-09-22 12:57:40 +02:00
WerWolv
509795e6c1 build: Bump version to 1.10.0 2021-09-22 02:33:08 +02:00
WerWolv
755642862f patterns: Added recursion and array size limit pragma 2021-09-22 00:45:04 +02:00
WerWolv
d1c05174b6 patterns: Allow casting integers to str 2021-09-21 23:45:45 +02:00
WerWolv
85b8698e35 patterns: Add std::mem::read_string 2021-09-21 23:29:30 +02:00
WerWolv
471ba80b4d ux: Properly evaluate pattern changes when already evaluating 2021-09-21 23:17:50 +02:00
WerWolv
9dd555f111 build: Added minimum library versions to cmake 2021-09-21 22:21:43 +02:00
WerWolv
7df1ff07a7 lang: Added diffing view localization 2021-09-21 22:06:30 +02:00
DrivebyCoding
15a60930d2 build: Fix typo in Debian/Ubuntu dependencies script (#232)
The "!" parameter to if needs to be free-standing. As is the script always outputs this on Ubuntu 20.04:

./get_deps_debian.sh: 8: !which: not found
2021-09-21 21:33:34 +02:00
xtex
eb779c5986 i18n: more zh_CN, fix: crashes when connecting with no COM port, feat: remove View suffix for view menu (#305)
* fix: crashes when connecting with no COM port

* feat: remove `View` suffix for view menu

* i18n: add more to Chinese(Simplified)

* Revert "Merge branch 'master' of github.com:xtexChooser/ImHex"

This reverts commit 8afcfe8f9d, reversing
changes made to 7651ad6661.
2021-09-21 21:30:52 +02:00
WerWolv
c051f5d3e7 patterns: Rewrite evaluation engine (#306)
* patterns: Rewrite most of the evaluator to mainly use polymorphism instead of just RTTI

* patterns: Fixed a couple of AST memory leaks

* patterns: Parse string operations correctly

* patterns: Various fixes and cleanup

* patterns: Implement primitive function definitions

Function parameters now need to provide their type in the definition

* patterns: Added function variable definition and assignment

* patterns: Added remaining function statements

* patterns: Added unsized and while-sized arrays

* patterns: Added multi variable declarations to functions

* patterns: Added std::format built-in function

* patterns: Allow passing custom types to functions

* patterns: Added attributes and new "format" attribute

* patterns: Use libfmt for std::print instead of custom version

* patterns: Remove unnecessary string compare function

* pattern: Fix preprocessor directives

* patterns: Fix unit tests

* patterns: Added cast expression

* patterns: Handle endianess in function parameters

* patterns: Added casting to different endian

* patterns: Added 'str' type for functions
2021-09-21 21:29:18 +02:00
WerWolv
ed9e463550 ui: Added diff view 2021-09-21 19:54:13 +02:00
WerWolv
a7ebf1f60e build: Adjust old file name in cmake 2021-09-21 03:20:17 +02:00
WerWolv
6ab0ec547c ui: Make footer items jump around less 2021-09-21 03:10:09 +02:00
WerWolv
26a0352851 tests: Fixed unit test compiling 2021-09-21 02:48:41 +02:00
WerWolv
8631cb0c2a sys: Allow multiple files to be loaded simultaneously 2021-09-21 02:29:54 +02:00
WerWolv
a302448b76 tools: Fixed regex replacer 2021-09-20 23:50:37 +02:00
WerWolv
fef072f721 ui: Moved hex editor settings to settings menu 2021-09-20 23:40:36 +02:00
WerWolv
46f196cb3f sys: Added debug function to crash ImHex 2021-09-20 20:48:08 +02:00
WerWolv
c5cd6422c6 fix: Settings menu closing when changing language 2021-09-20 20:42:30 +02:00
xtex
5edc0b876c i18n: Chinese(Simplified) (#303)
* feat(i18n): add Chinese(Simplified) translations

* feat: keep console window on Windows for debug builds

* feat(18n)

* feat(i18n): improve Chinese translation

* fix: unify the line terminators

* feat(build): formatting

* fix: exclude from SysWow64 for 64bits windows

* Revert "fix: exclude from SysWow64 for 64bits windows"

This reverts commit a6d66a4a56.

* Revert "feat: keep console window on Windows for debug builds"

This reverts commit 9fd4699c9f.
2021-09-20 18:41:22 +02:00
WerWolv
131699d309 ui: Fixed language list crashing 2021-09-20 12:44:12 +02:00
WerWolv
59c01feaea github: Use ccache for CI runners 2021-09-19 21:49:09 +02:00
WerWolv
772b50fdfb fix: Missing include on Linux 2021-09-16 22:34:48 +02:00
WerWolv
bf493c5763 ui: Add follow system theme option 2021-09-16 22:23:51 +02:00
Russ
e1f410ceff warnings: fix format-security warnings (#299) 2021-09-15 10:02:16 +02:00
WerWolv
d3fb00d441 sys: Allow resources to be placed in appdata on windows 2021-09-13 23:55:50 +02:00
WerWolv
222e9f6645 fix: File -> Resize crashing 2021-09-13 17:26:30 +02:00
WerWolv
22a904baf4 tests: Added RValue, Namespaces and extra semicolon test 2021-09-13 10:49:24 +02:00
WerWolv
01670e5e85 patterns: Ignore superfluous semicolons 2021-09-13 10:48:45 +02:00
WerWolv
7fbb540674 tests: Added operator test 2021-09-12 21:54:18 +02:00
WerWolv
bed5361879 tests: Added bitfield test 2021-09-12 20:29:05 +02:00
WerWolv
82cc528c49 api: Fix loading of string array settings (Recent files) 2021-09-12 20:29:05 +02:00
WerWolv
1df64031c8 patterns: Fix bitfield member access 2021-09-12 20:29:05 +02:00
WerWolv
ea2d181741 utils: Fix file wrapper 2021-09-12 20:29:05 +02:00
WerWolv
3cd177bff2 build: Fix build error when python is installed in Program Files 2021-09-12 14:33:08 +02:00
WerWolv
132fc181cd patterns: Fix bitfields with unaligned sizes
Correction for #292
2021-09-12 14:28:13 +02:00
WerWolv
987840e480 sys: Fixed settings not initializing correctly 2021-09-12 13:59:23 +02:00
WerWolv
86096708da patterns: Fixed bitfields not respecting endian setting
Various other improvements. Fixes #292
2021-09-12 13:08:52 +02:00
WerWolv
635f0606e0 patterns: Fixed enums not counting properly 2021-09-11 23:14:22 +02:00
WerWolv
3d15a108af tests: Added more tests 2021-09-11 23:13:49 +02:00
WerWolv
254b204d6c github: Don't use build matrix for analysis 2021-09-11 19:37:20 +02:00
WerWolv
ac645c63d3 github: Just run ctest manually. Added some emojis 2021-09-11 18:58:53 +02:00
WerWolv
0b9f1cc3b9 github: Run unit tests 2021-09-11 18:15:27 +02:00
WerWolv
b96fee95f3 github: Missed one 2021-09-11 18:11:59 +02:00
WerWolv
8cb7fb71d1 github: Don't look for magic dbs anymore in CI 2021-09-11 18:11:17 +02:00
WerWolv
aac6385dc6 build: Fixed unit tests on linux. Fuck cmake... 2021-09-11 18:09:15 +02:00
WerWolv
f7ee165f43 build: Removed magic database files from main repo
They can still be found in the ImHex-Patterns repo
2021-09-11 18:08:55 +02:00
WerWolv
7132b75ffb build: Don't copy crypto header but just overwrite includes 2021-09-11 15:10:35 +02:00
WerWolv
bdd4854b0d build: Try fixing file copying on runner 2021-09-11 14:58:49 +02:00
WerWolv
8396e40fa0 tests: Added initial test structure 2021-09-11 14:41:18 +02:00
WerWolv
71b06f4b20 build: Only copy yara crypto wrapper if it changed 2021-09-11 14:40:53 +02:00
WerWolv
a5274daeaa patterns: Fixed padding not padding 2021-09-10 22:12:37 +02:00
WerWolv
36f51c427b ui: Added "Quit ImHex" option to File menu 2021-09-10 21:48:51 +02:00
WerWolv
b3d102419b sys: Fixed opening custom protocols in the web browser 2021-09-10 21:42:35 +02:00
WerWolv
5c304c002b fix: Constants store page not getting cleared on reload
Fixes #290
2021-09-10 21:16:08 +02:00
WerWolv
f96e529230 patterns: Fixed parent keyword 2021-09-10 21:00:18 +02:00
WerWolv
717f78ce7f patterns: Fix negative array sizes causing crashes 2021-09-10 17:33:02 +02:00
121 changed files with 6910 additions and 2752 deletions

62
.github/workflows/analysis.yml vendored Normal file
View File

@@ -0,0 +1,62 @@
name: "CodeQL and Unit Tests"
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
schedule:
- cron: '21 0 * * 2'
jobs:
analyze:
name: 🐛 Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
steps:
- name: 🧰 Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
submodules: recursive
- name: ✋ Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: 'cpp'
- name: 📜 Restore cache
uses: actions/cache@v2
with:
path: |
~/.ccache
.flatpak-builder
key: ${{ runner.os }}-build
- name: ⬇️ Install dependencies
run: |
sudo apt update
sudo bash dist/get_deps_debian.sh
- name: 🛠️ Build
run: |
mkdir build
cd build
CC=gcc-10 CXX=g++-10 cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-D CMAKE_C_COMPILER_LAUNCHER=ccache -D CMAKE_CXX_COMPILER_LAUNCHER=ccache \
..
make -j 4 install
- name: 🧪 Perform Unit Tests
run: |
cd build
ctest
- name: 🗯️ Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@@ -19,43 +19,49 @@ jobs:
with:
fetch-depth: 0
submodules: recursive
- name: 📜 Restore cache
uses: actions/cache@v2
with:
path: |
~/.ccache
.flatpak-builder
key: ${{ runner.os }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-build-
- name: ⬇️ Install dependencies
run: |
sudo apt update
sudo bash dist/get_deps_debian.sh
- name: Build
- name: 🛠️ Build
run: |
# Get path to magic db
MAGICDB_PATH=$(file --version | grep -oP "(?<=magic file from ).+")
mkdir build
mkdir -p build
cd build
CC=gcc-10 CXX=g++-10 cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DEXTRA_MAGICDBS="$MAGICDB_PATH" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
..
make -j 4 install
- name: Bundle Flatpak
- name: 📦 Bundle Flatpak
run: |
sudo apt install flatpak flatpak-builder
flatpak --user remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
flatpak --user install -y flathub org.freedesktop.Platform//20.08
flatpak --user install -y flathub org.freedesktop.Sdk//20.08
flatpak-builder --repo=imhex _flatpak dist/net.werwolv.ImHex.yaml
flatpak-builder --repo=imhex _flatpak dist/net.werwolv.ImHex.yaml --ccache --keep-build-dirs
flatpak build-bundle imhex imhex.flatpak net.werwolv.ImHex stable
- name: 📦 Upload ELF
- name: ⬆️ Upload ELF
uses: actions/upload-artifact@v2
with:
name: Linux ELF
path: |
build/install/*
- name: 📦 Upload Flatpak
- name: ⬆️ Upload Flatpak
uses: actions/upload-artifact@v2
with:
name: Linux Flatpak
@@ -68,51 +74,65 @@ jobs:
defaults:
run:
shell: msys2 {0}
env:
CCACHE_DIR: "${{ github.workspace }}/.ccache"
CCACHE_MAXSIZE: "1000M"
CCACHE_COMPRESS: "true"
steps:
- name: 🧰 Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
submodules: recursive
- name: 🟦 Install msys2
uses: msys2/setup-msys2@v2
- name: ⬇️ Install dependencies
run: |
bash dist/get_deps_msys2.sh
bash dist/get_deps_msys2.sh
- name: ✋ Build
- name: 📜 Prepare Cache
id: prep-ccache
shell: bash
run: |
mkdir build
mkdir -p "${CCACHE_DIR}"
echo "::set-output name=dir::$CCACHE_DIR"
- name: 📜 Restore Cache
uses: actions/cache@v1
id: cache-ccache
with:
path: ${{ steps.prep-ccache.outputs.dir }}
key: ${{ runner.os }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-build-
- name: 🛠️ Build
run: |
mkdir -p build
cd build
# Get path to mingw python library
PYTHON_LIB_NAME=$(pkg-config --libs-only-l python3 | sed 's/^-l//' | sed 's/ //')
PYTHON_LIB_PATH=$(cygpath -m $(which lib${PYTHON_LIB_NAME}.dll))
# Get path to magic db
MAGICDB_PATH=$(cygpath -m $(file --version | grep -oP "(?<=magic file from ).+"))
echo Python_LIBRARY: $PYTHON_LIB_PATH
echo MagicDB Path: $MAGICDB_PATH
cmake -G "MinGW Makefiles" \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DCREATE_PACKAGE=ON \
-DPython_LIBRARY="$PYTHON_LIB_PATH" \
-DEXTRA_MAGICDBS="$MAGICDB_PATH" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
..
mingw32-make -j4
mingw32-make install
mingw32-make -j4 install
cpack
- name: 📦 Upload Portable ZIP
- name: ⬆️ Upload Portable ZIP
uses: actions/upload-artifact@v2
with:
name: Windows Portable ZIP
path: |
build/install/*
- name: 📦 Upload Windows Installer
- name: ⬆️ Upload Windows Installer
uses: actions/upload-artifact@v2
with:
name: Windows Installer
@@ -135,9 +155,17 @@ jobs:
run: |
brew bundle --no-lock --file dist/Brewfile
- name: ✋ Build
- name: 📜 Restore cache
uses: actions/cache@v2
with:
path: |
~/.ccache
key: ${{ runner.os }}-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-build-
- name: 🛠️ Build
run: |
mkdir build
mkdir -p build
cd build
CC=$(brew --prefix llvm)/bin/clang \
CXX=$(brew --prefix llvm)/bin/clang++ \
@@ -147,10 +175,11 @@ jobs:
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCREATE_BUNDLE=ON \
-DCREATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
..
make -j 4 package
make -j4 package
- name: 📦 Upload DMG
- name: ⬆️ Upload DMG
uses: actions/upload-artifact@v2
with:
name: macOS DMG

View File

@@ -1,71 +0,0 @@
# For most projects, this workflow file will not need changing; you simply need
# to commit it to your repository.
#
# You may wish to alter this file to override the set of languages analyzed,
# or to provide custom queries or build logic.
#
# ******** NOTE ********
# We have attempted to detect the languages in your repository. Please check
# the `language` matrix defined below to confirm you have the correct set of
# supported CodeQL languages.
#
name: "CodeQL"
on:
push:
branches: [ master ]
pull_request:
# The branches below must be a subset of the branches above
branches: [ master ]
schedule:
- cron: '21 0 * * 2'
jobs:
analyze:
name: Analyze
runs-on: ubuntu-latest
permissions:
actions: read
contents: read
security-events: write
strategy:
fail-fast: false
matrix:
language: [ 'cpp' ]
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
fetch-depth: 0
submodules: recursive
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
languages: ${{ matrix.language }}
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
# Prefix the list here with "+" to use these queries and those in the config file.
# queries: ./path/to/local/query, your-org/your-repo/queries@main
- name: Install dependencies
run: |
sudo apt update
sudo bash dist/get_deps_debian.sh
- name: Build
run: |
# Get path to magic db
MAGICDB_PATH=$(file --version | grep -oP "(?<=magic file from ).+")
mkdir build
cd build
CC=gcc-10 CXX=g++-10 cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DEXTRA_MAGICDBS="$MAGICDB_PATH" \
..
make -j 4 install
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.16)
# Updating the version here will update it throughout ImHex as well
set(IMHEX_VERSION "1.9.0")
set(IMHEX_VERSION "1.10.1")
project(imhex VERSION ${IMHEX_VERSION})
set(CMAKE_CXX_STANDARD 20)
@@ -17,39 +17,19 @@ set(PLUGINS
# example
)
# List extra magic databases to compile here
set(MAGICDBS
magic_dbs/nintendo_magic
)
findLibraries()
detectOS()
detectArch()
if (NOT USE_SYSTEM_LLVM)
add_subdirectory(external/llvm)
else()
find_package(LLVM REQUIRED Demangle)
endif()
if (NOT USE_SYSTEM_YARA)
add_subdirectory(external/yara)
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(YARA REQUIRED IMPORTED_TARGET yara)
endif()
# Add bundled dependencies
add_subdirectory(plugins/libimhex)
# Add include directories
include_directories(include ${MBEDTLS_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${Python_INCLUDE_DIRS})
if (USE_SYSTEM_LLVM)
include_directories(include ${LLVM_INCLUDE_DIRS})
endif()
if (USE_SYSTEM_YARA)
include_directories(include ${YARA_INCLUDE_DIRS})
endif()
include_directories(include)
enable_testing()
add_subdirectory(tests)
addVersionDefines()
configurePackageCreation()
@@ -91,17 +71,17 @@ add_executable(imhex ${application_type}
source/views/view_yara.cpp
source/views/view_constants.cpp
source/views/view_store.cpp
source/views/view_diff.cpp
${imhex_icon}
)
set_target_properties(imhex PROPERTIES CXX_VISIBILITY_PRESET hidden)
target_link_directories(imhex PRIVATE ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS})
if (WIN32)
target_link_libraries(imhex ${CMAKE_DL_LIBS} capstone LLVMDemangle libimhex ${Python_LIBRARIES} wsock32 ws2_32 libyara Dwmapi.lib dl)
target_link_libraries(imhex dl libimhex wsock32 ws2_32 Dwmapi.lib)
else ()
target_link_libraries(imhex ${CMAKE_DL_LIBS} capstone LLVMDemangle libimhex ${Python_LIBRARIES} dl pthread libyara)
target_link_libraries(imhex dl libimhex pthread)
endif ()
createPackage()

View File

@@ -37,9 +37,9 @@ macro(findLibraries)
# Find packages
find_package(PkgConfig REQUIRED)
find_package(mbedTLS REQUIRED)
find_package(mbedTLS 2.26.0 REQUIRED)
pkg_search_module(CAPSTONE REQUIRED capstone)
pkg_search_module(CAPSTONE 4.0.2 REQUIRED capstone)
find_package(OpenGL REQUIRED)
@@ -60,9 +60,9 @@ macro(findLibraries)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_C_FLAGS} -DPYTHON_VERSION_MAJOR_MINOR=\"\\\"${PYTHON_VERSION_MAJOR_MINOR}\"\\\"")
pkg_search_module(MAGIC libmagic)
pkg_search_module(MAGIC libmagic>=5.39)
if(NOT MAGIC_FOUND)
find_library(MAGIC magic REQUIRED)
find_library(MAGIC 5.39 magic REQUIRED)
else()
set(MAGIC_INCLUDE_DIRS ${MAGIC_INCLUDEDIR})
endif()
@@ -176,7 +176,7 @@ macro(createPackage)
# Grab all dynamically linked dependencies.
INSTALL(CODE "set(CMAKE_INSTALL_BINDIR \"${CMAKE_INSTALL_BINDIR}\")")
INSTALL(CODE "get_filename_component(PY_PARENT ${Python_LIBRARIES} DIRECTORY)")
INSTALL(CODE "get_filename_component(PY_PARENT \"${Python_LIBRARIES}\" DIRECTORY)")
INSTALL(CODE "LIST(APPEND DEP_FOLDERS \${PY_PARENT})")
install(CODE [[
file(GET_RUNTIME_DEPENDENCIES
@@ -203,37 +203,9 @@ macro(createPackage)
FILES "${_file}"
)
endforeach()
]])
]])
endif()
if (UNIX AND NOT APPLE)
string(REPLACE ":" ";" EXTRA_MAGICDBS "${EXTRA_MAGICDBS}")
endif ()
if (NOT EXTRA_MAGICDBS STREQUAL "")
list(GET EXTRA_MAGICDBS -1 EXTRA_MAGICDBS)
if (NOT EXTRA_MAGICDBS STREQUAL "NOTFOUND")
if (EXTRA_MAGICDBS MATCHES ".*\\.mgc")
install(FILES "${EXTRA_MAGICDBS}" DESTINATION ${MAGIC_INSTALL_LOCATION})
else ()
install(FILES "${EXTRA_MAGICDBS}.mgc" DESTINATION ${MAGIC_INSTALL_LOCATION})
endif ()
endif ()
endif ()
# Compile the imhex-specific magicdb
add_custom_target(magic_dbs ALL
SOURCES ${MAGICDBS}
)
add_custom_command(TARGET magic_dbs
COMMAND file -C -m ${CMAKE_SOURCE_DIR}/magic_dbs
)
# Install the magicdb files.
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/magic_dbs.mgc DESTINATION ${MAGIC_INSTALL_LOCATION} RENAME imhex.mgc)
if (CREATE_BUNDLE)
include(PostprocessBundle)

1
dist/Brewfile vendored
View File

@@ -3,6 +3,7 @@ brew "mbedtls"
brew "capstone"
brew "nlohmann-json"
brew "cmake"
brew "ccache"
brew "python3"
brew "freetype2"
brew "libmagic"

View File

@@ -5,7 +5,7 @@ echo "As of 2020-12, Debian stable does not include g++-10, needs debian testing
# Tested on 2020-12-09 with Docker image bitnami/minideb:unstable
# Install pkgconf (adds minimum dependencies) only if the equivalent pkf-config is not already installed.
if !which pkg-config
if ! which pkg-config
then
PKGCONF="pkgconf"
fi
@@ -17,6 +17,7 @@ apt install -y \
${PKGCONF:-} \
cmake \
make \
ccache \
libglfw3-dev \
libglm-dev \
libmagic-dev \

View File

@@ -4,6 +4,7 @@ pacman -S --needed --noconfirm \
mingw-w64-x86_64-gcc \
mingw-w64-x86_64-cmake \
mingw-w64-x86_64-make \
mingw-w64-x86_64-ccache \
mingw-w64-x86_64-capstone \
mingw-w64-x86_64-glfw \
mingw-w64-x86_64-file \

View File

@@ -71,6 +71,7 @@ namespace ImGui {
Texture LoadImageFromMemory(ImU8 *buffer, int size);
void UnloadImage(Texture &texture);
void OpenPopupInWindow(const char *window_name, const char *popup_name);
struct ImHexCustomData {
ImVec4 Colors[ImGuiCustomCol_COUNT];

View File

@@ -92,6 +92,7 @@ struct MemoryEditor
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.
@@ -311,9 +312,8 @@ struct MemoryEditor
size_t data_preview_addr_next = (size_t)-1;
if (ImGui::IsWindowFocused()) {
if (DataEditingAddr != (size_t)-1)
{
// 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)
// 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; }
@@ -323,7 +323,6 @@ struct MemoryEditor
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 != -1) {
// 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 (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; }
@@ -333,6 +332,11 @@ struct MemoryEditor
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 = data_preview_addr_next = DataPreviewAddrEnd = (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))
@@ -688,35 +692,19 @@ struct MemoryEditor
const char* format_range = OptUpperCaseHex ? "Range %0*" _PRISizeT "X..%0*" _PRISizeT "X" : "Range %0*" _PRISizeT "x..%0*" _PRISizeT "x";
const char* format_selection = OptUpperCaseHex ? "Selection %0*" _PRISizeT "X..%0*" _PRISizeT "X (%ld %s)" : "Range %0*" _PRISizeT "x..%0*" _PRISizeT "x (%ld %s)";
// Options menu
if (ImGui::Button("Options"))
ImGui::OpenPopup("options");
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();
if (ImGui::BeginPopup("options")) {
ImGui::PushItemWidth(ImGui::CalcTextSize("00 cols").x * 1.1f);
if (ImGui::DragInt("##cols", &Cols, 0.2f, 4, 32, "%d cols")) { ContentsWidthChanged = true; if (Cols < 1) Cols = 1; }
ImGui::PopItemWidth();
ImGui::Checkbox("Show HexII", &OptShowHexII);
if (ImGui::Checkbox("Show Ascii", &OptShowAscii)) { ContentsWidthChanged = true; }
if (ImGui::Checkbox("Show Advanced Decoding", &OptShowAdvancedDecoding)) { ContentsWidthChanged = true; }
ImGui::Checkbox("Grey out zeroes", &OptGreyOutZeroes);
ImGui::Checkbox("Uppercase Hex", &OptUpperCaseHex);
auto selectionStart = std::min(DataPreviewAddr, DataPreviewAddrEnd);
auto selectionEnd = std::max(DataPreviewAddr, DataPreviewAddrEnd);
ImGui::EndPopup();
}
ImGui::SameLine();
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 == 1 ? "byte" : "bytes");
size_t regionSize = (selectionEnd - selectionStart) + 1;
ImGui::Text(format_selection, s.AddrDigitsCount, base_display_addr + selectionStart, s.AddrDigitsCount, base_display_addr + selectionEnd, regionSize, regionSize == 1 ? "byte" : "bytes");
}
}
if (GotoAddr != (size_t)-1)

View File

@@ -357,6 +357,13 @@ namespace ImGui {
texture = { nullptr, 0, 0 };
}
void OpenPopupInWindow(const char *window_name, const char *popup_name) {
if (ImGui::Begin(window_name)) {
ImGui::OpenPopup(popup_name);
}
ImGui::End();
}
bool TitleBarButton(const char* label, ImVec2 size_arg) {
ImGuiWindow* window = GetCurrentWindow();

10
external/microtar/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 3.16)
project(microtar)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fPIC")
add_library(microtar STATIC
source/microtar.c
)
target_include_directories(microtar PUBLIC include)

19
external/microtar/LICENSE vendored Normal file
View File

@@ -0,0 +1,19 @@
Copyright (c) 2017 rxi
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

99
external/microtar/README.md vendored Normal file
View File

@@ -0,0 +1,99 @@
# microtar
A lightweight tar library written in ANSI C
## Basic Usage
The library consists of `microtar.c` and `microtar.h`. These two files can be
dropped into an existing project and compiled along with it.
#### Reading
```c
mtar_t tar;
mtar_header_t h;
char *p;
/* Open archive for reading */
mtar_open(&tar, "test.tar", "r");
/* Print all file names and sizes */
while ( (mtar_read_header(&tar, &h)) != MTAR_ENULLRECORD ) {
printf("%s (%d bytes)\n", h.name, h.size);
mtar_next(&tar);
}
/* Load and print contents of file "test.txt" */
mtar_find(&tar, "test.txt", &h);
p = calloc(1, h.size + 1);
mtar_read_data(&tar, p, h.size);
printf("%s", p);
free(p);
/* Close archive */
mtar_close(&tar);
```
#### Writing
```c
mtar_t tar;
const char *str1 = "Hello world";
const char *str2 = "Goodbye world";
/* Open archive for writing */
mtar_open(&tar, "test.tar", "w");
/* Write strings to files `test1.txt` and `test2.txt` */
mtar_write_file_header(&tar, "test1.txt", strlen(str1));
mtar_write_data(&tar, str1, strlen(str1));
mtar_write_file_header(&tar, "test2.txt", strlen(str2));
mtar_write_data(&tar, str2, strlen(str2));
/* Finalize -- this needs to be the last thing done before closing */
mtar_finalize(&tar);
/* Close archive */
mtar_close(&tar);
```
## Error handling
All functions which return an `int` will return `MTAR_ESUCCESS` if the operation
is successful. If an error occurs an error value less-than-zero will be
returned; this value can be passed to the function `mtar_strerror()` to get its
corresponding error string.
## Wrapping a stream
If you want to read or write from something other than a file, the `mtar_t`
struct can be manually initialized with your own callback functions and a
`stream` pointer.
All callback functions are passed a pointer to the `mtar_t` struct as their
first argument. They should return `MTAR_ESUCCESS` if the operation succeeds
without an error, or an integer below zero if an error occurs.
After the `stream` field has been set, all required callbacks have been set and
all unused fields have been zeroset the `mtar_t` struct can be safely used with
the microtar functions. `mtar_open` *should not* be called if the `mtar_t`
struct was initialized manually.
#### Reading
The following callbacks should be set for reading an archive from a stream:
Name | Arguments | Description
--------|------------------------------------------|---------------------------
`read` | `mtar_t *tar, void *data, unsigned size` | Read data from the stream
`seek` | `mtar_t *tar, unsigned pos` | Set the position indicator
`close` | `mtar_t *tar` | Close the stream
#### Writing
The following callbacks should be set for writing an archive to a stream:
Name | Arguments | Description
--------|------------------------------------------------|---------------------
`write` | `mtar_t *tar, const void *data, unsigned size` | Write data to the stream
## License
This library is free software; you can redistribute it and/or modify it under
the terms of the MIT license. See [LICENSE](LICENSE) for details.

93
external/microtar/include/microtar.h vendored Normal file
View File

@@ -0,0 +1,93 @@
/**
* Copyright (c) 2017 rxi
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the MIT license. See `microtar.c` for details.
*/
#ifndef MICROTAR_H
#define MICROTAR_H
#include <stdio.h>
#include <stdlib.h>
#if defined(__cplusplus)
extern "C" {
#endif
#define MTAR_VERSION "0.1.0"
enum {
MTAR_ESUCCESS = 0,
MTAR_EFAILURE = -1,
MTAR_EOPENFAIL = -2,
MTAR_EREADFAIL = -3,
MTAR_EWRITEFAIL = -4,
MTAR_ESEEKFAIL = -5,
MTAR_EBADCHKSUM = -6,
MTAR_ENULLRECORD = -7,
MTAR_ENOTFOUND = -8
};
enum {
MTAR_TREG = '0',
MTAR_TLNK = '1',
MTAR_TSYM = '2',
MTAR_TCHR = '3',
MTAR_TBLK = '4',
MTAR_TDIR = '5',
MTAR_TFIFO = '6'
};
typedef struct {
unsigned mode;
unsigned owner;
unsigned size;
unsigned mtime;
unsigned type;
char name[100];
char linkname[100];
} mtar_header_t;
typedef struct mtar_t mtar_t;
struct mtar_t {
int (*read)(mtar_t *tar, void *data, unsigned size);
int (*write)(mtar_t *tar, const void *data, unsigned size);
int (*seek)(mtar_t *tar, unsigned pos);
int (*close)(mtar_t *tar);
void *stream;
unsigned pos;
unsigned remaining_data;
unsigned last_header;
};
const char *mtar_strerror(int err);
int mtar_open(mtar_t *tar, const char *filename, const char *mode);
int mtar_close(mtar_t *tar);
int mtar_seek(mtar_t *tar, unsigned pos);
int mtar_rewind(mtar_t *tar);
int mtar_next(mtar_t *tar);
int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h);
int mtar_read_header(mtar_t *tar, mtar_header_t *h);
int mtar_read_data(mtar_t *tar, void *ptr, unsigned size);
int mtar_write_header(mtar_t *tar, const mtar_header_t *h);
int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size);
int mtar_write_dir_header(mtar_t *tar, const char *name);
int mtar_write_data(mtar_t *tar, const void *data, unsigned size);
int mtar_finalize(mtar_t *tar);
#if defined(__cplusplus)
}
#endif
#endif

376
external/microtar/source/microtar.c vendored Normal file
View File

@@ -0,0 +1,376 @@
/*
* Copyright (c) 2017 rxi
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <microtar.h>
typedef struct {
char name[100];
char mode[8];
char owner[8];
char group[8];
char size[12];
char mtime[12];
char checksum[8];
char type;
char linkname[100];
char _padding[255];
} mtar_raw_header_t;
static unsigned round_up(unsigned n, unsigned incr) {
return n + (incr - n % incr) % incr;
}
static unsigned checksum(const mtar_raw_header_t* rh) {
unsigned i;
unsigned char *p = (unsigned char*) rh;
unsigned res = 256;
for (i = 0; i < offsetof(mtar_raw_header_t, checksum); i++) {
res += p[i];
}
for (i = offsetof(mtar_raw_header_t, type); i < sizeof(*rh); i++) {
res += p[i];
}
return res;
}
static int tread(mtar_t *tar, void *data, unsigned size) {
int err = tar->read(tar, data, size);
tar->pos += size;
return err;
}
static int twrite(mtar_t *tar, const void *data, unsigned size) {
int err = tar->write(tar, data, size);
tar->pos += size;
return err;
}
static int write_null_bytes(mtar_t *tar, int n) {
int i, err;
char nul = '\0';
for (i = 0; i < n; i++) {
err = twrite(tar, &nul, 1);
if (err) {
return err;
}
}
return MTAR_ESUCCESS;
}
static int raw_to_header(mtar_header_t *h, const mtar_raw_header_t *rh) {
unsigned chksum1, chksum2;
/* If the checksum starts with a null byte we assume the record is NULL */
if (*rh->checksum == '\0') {
return MTAR_ENULLRECORD;
}
/* Build and compare checksum */
chksum1 = checksum(rh);
sscanf(rh->checksum, "%o", &chksum2);
if (chksum1 != chksum2) {
return MTAR_EBADCHKSUM;
}
/* Load raw header into header */
sscanf(rh->mode, "%o", &h->mode);
sscanf(rh->owner, "%o", &h->owner);
sscanf(rh->size, "%o", &h->size);
sscanf(rh->mtime, "%o", &h->mtime);
h->type = rh->type;
strcpy(h->name, rh->name);
strcpy(h->linkname, rh->linkname);
return MTAR_ESUCCESS;
}
static int header_to_raw(mtar_raw_header_t *rh, const mtar_header_t *h) {
unsigned chksum;
/* Load header into raw header */
memset(rh, 0, sizeof(*rh));
sprintf(rh->mode, "%o", h->mode);
sprintf(rh->owner, "%o", h->owner);
sprintf(rh->size, "%o", h->size);
sprintf(rh->mtime, "%o", h->mtime);
rh->type = h->type ? h->type : MTAR_TREG;
strcpy(rh->name, h->name);
strcpy(rh->linkname, h->linkname);
/* Calculate and write checksum */
chksum = checksum(rh);
sprintf(rh->checksum, "%06o", chksum);
rh->checksum[7] = ' ';
return MTAR_ESUCCESS;
}
const char* mtar_strerror(int err) {
switch (err) {
case MTAR_ESUCCESS : return "success";
case MTAR_EFAILURE : return "failure";
case MTAR_EOPENFAIL : return "could not open";
case MTAR_EREADFAIL : return "could not read";
case MTAR_EWRITEFAIL : return "could not write";
case MTAR_ESEEKFAIL : return "could not seek";
case MTAR_EBADCHKSUM : return "bad checksum";
case MTAR_ENULLRECORD : return "null record";
case MTAR_ENOTFOUND : return "file not found";
}
return "unknown error";
}
static int file_write(mtar_t *tar, const void *data, unsigned size) {
unsigned res = fwrite(data, 1, size, tar->stream);
return (res == size) ? MTAR_ESUCCESS : MTAR_EWRITEFAIL;
}
static int file_read(mtar_t *tar, void *data, unsigned size) {
unsigned res = fread(data, 1, size, tar->stream);
return (res == size) ? MTAR_ESUCCESS : MTAR_EREADFAIL;
}
static int file_seek(mtar_t *tar, unsigned offset) {
int res = fseek(tar->stream, offset, SEEK_SET);
return (res == 0) ? MTAR_ESUCCESS : MTAR_ESEEKFAIL;
}
static int file_close(mtar_t *tar) {
fclose(tar->stream);
return MTAR_ESUCCESS;
}
int mtar_open(mtar_t *tar, const char *filename, const char *mode) {
int err;
mtar_header_t h;
/* Init tar struct and functions */
memset(tar, 0, sizeof(*tar));
tar->write = file_write;
tar->read = file_read;
tar->seek = file_seek;
tar->close = file_close;
/* Assure mode is always binary */
if ( strchr(mode, 'r') ) mode = "rb";
if ( strchr(mode, 'w') ) mode = "wb";
if ( strchr(mode, 'a') ) mode = "ab";
/* Open file */
tar->stream = fopen(filename, mode);
if (!tar->stream) {
return MTAR_EOPENFAIL;
}
/* Read first header to check it is valid if mode is `r` */
if (*mode == 'r') {
err = mtar_read_header(tar, &h);
if (err != MTAR_ESUCCESS) {
mtar_close(tar);
return err;
}
}
/* Return ok */
return MTAR_ESUCCESS;
}
int mtar_close(mtar_t *tar) {
return tar->close(tar);
}
int mtar_seek(mtar_t *tar, unsigned pos) {
int err = tar->seek(tar, pos);
tar->pos = pos;
return err;
}
int mtar_rewind(mtar_t *tar) {
tar->remaining_data = 0;
tar->last_header = 0;
return mtar_seek(tar, 0);
}
int mtar_next(mtar_t *tar) {
int err, n;
mtar_header_t h;
/* Load header */
err = mtar_read_header(tar, &h);
if (err) {
return err;
}
/* Seek to next record */
n = round_up(h.size, 512) + sizeof(mtar_raw_header_t);
return mtar_seek(tar, tar->pos + n);
}
int mtar_find(mtar_t *tar, const char *name, mtar_header_t *h) {
int err;
mtar_header_t header;
/* Start at beginning */
err = mtar_rewind(tar);
if (err) {
return err;
}
/* Iterate all files until we hit an error or find the file */
while ( (err = mtar_read_header(tar, &header)) == MTAR_ESUCCESS ) {
if ( !strcmp(header.name, name) ) {
if (h) {
*h = header;
}
return MTAR_ESUCCESS;
}
mtar_next(tar);
}
/* Return error */
if (err == MTAR_ENULLRECORD) {
err = MTAR_ENOTFOUND;
}
return err;
}
int mtar_read_header(mtar_t *tar, mtar_header_t *h) {
int err;
mtar_raw_header_t rh;
/* Save header position */
tar->last_header = tar->pos;
/* Read raw header */
err = tread(tar, &rh, sizeof(rh));
if (err) {
return err;
}
/* Seek back to start of header */
err = mtar_seek(tar, tar->last_header);
if (err) {
return err;
}
/* Load raw header into header struct and return */
return raw_to_header(h, &rh);
}
int mtar_read_data(mtar_t *tar, void *ptr, unsigned size) {
int err;
/* If we have no remaining data then this is the first read, we get the size,
* set the remaining data and seek to the beginning of the data */
if (tar->remaining_data == 0) {
mtar_header_t h;
/* Read header */
err = mtar_read_header(tar, &h);
if (err) {
return err;
}
/* Seek past header and init remaining data */
err = mtar_seek(tar, tar->pos + sizeof(mtar_raw_header_t));
if (err) {
return err;
}
tar->remaining_data = h.size;
}
/* Read data */
err = tread(tar, ptr, size);
if (err) {
return err;
}
tar->remaining_data -= size;
/* If there is no remaining data we've finished reading and seek back to the
* header */
if (tar->remaining_data == 0) {
return mtar_seek(tar, tar->last_header);
}
return MTAR_ESUCCESS;
}
int mtar_write_header(mtar_t *tar, const mtar_header_t *h) {
mtar_raw_header_t rh;
/* Build raw header and write */
header_to_raw(&rh, h);
tar->remaining_data = h->size;
return twrite(tar, &rh, sizeof(rh));
}
int mtar_write_file_header(mtar_t *tar, const char *name, unsigned size) {
mtar_header_t h;
/* Build header */
memset(&h, 0, sizeof(h));
strcpy(h.name, name);
h.size = size;
h.type = MTAR_TREG;
h.mode = 0664;
/* Write header */
return mtar_write_header(tar, &h);
}
int mtar_write_dir_header(mtar_t *tar, const char *name) {
mtar_header_t h;
/* Build header */
memset(&h, 0, sizeof(h));
strcpy(h.name, name);
h.type = MTAR_TDIR;
h.mode = 0775;
/* Write header */
return mtar_write_header(tar, &h);
}
int mtar_write_data(mtar_t *tar, const void *data, unsigned size) {
int err;
/* Write data */
err = twrite(tar, data, size);
if (err) {
return err;
}
tar->remaining_data -= size;
/* Write padding if we've written all the data for this file */
if (tar->remaining_data == 0) {
return write_null_bytes(tar, round_up(tar->pos, 512) - tar->pos);
}
return MTAR_ESUCCESS;
}
int mtar_finalize(mtar_t *tar) {
/* Write two NULL records */
return write_null_bytes(tar, sizeof(mtar_raw_header_t) * 2);
}

View File

@@ -94,8 +94,6 @@ set(LIBYARA_MODULES
${LIBYARA_SOURCE_PATH}/modules/magic/magic.c)
# Add mbedtls crypto wrappers
file(READ crypto_mbedtls.h MBEDTLS_CRYPTO_H)
file(WRITE ${LIBYARA_SOURCE_PATH}/crypto.h "${MBEDTLS_CRYPTO_H}")
add_compile_definitions("HAVE_MBEDTLS")
add_compile_definitions("USE_NO_PROC")
@@ -112,7 +110,7 @@ add_library(libyara STATIC ${LIBYARA_SOURCE} ${LIBYARA_INCLUDES} ${LIBYARA_MODUL
target_include_directories(
libyara
PUBLIC $<BUILD_INTERFACE:${LIBYARA_SOURCE_PATH}/include> $<INSTALL_INTERFACE:include>
PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/yara> $<BUILD_INTERFACE:${LIBYARA_SOURCE_PATH}/include> $<INSTALL_INTERFACE:include>
PRIVATE ${LIBYARA_SOURCE_PATH} ${MBEDTLS_INCLUDE_DIR}
)

View File

@@ -21,11 +21,11 @@ namespace hex::prv {
explicit FileProvider(std::string path);
~FileProvider() override;
bool isAvailable() override;
bool isReadable() override;
bool isWritable() override;
bool isResizable() override;
bool isSavable() override;
bool isAvailable() const override;
bool isReadable() const override;
bool isWritable() const override;
bool isResizable() const override;
bool isSavable() const override;
void read(u64 offset, void *buffer, size_t size, bool overlays) override;
void write(u64 offset, const void *buffer, size_t size) override;
@@ -33,12 +33,13 @@ namespace hex::prv {
void readRaw(u64 offset, void *buffer, size_t size) override;
void writeRaw(u64 offset, const void *buffer, size_t size) override;
size_t getActualSize() override;
size_t getActualSize() const override;
void save() override;
void saveAs(const std::string &path) override;
std::vector<std::pair<std::string, std::string>> getDataInformation() override;
[[nodiscard]] std::string getName() const override;
[[nodiscard]] std::vector<std::pair<std::string, std::string>> getDataInformation() const override;
private:
#if defined(OS_WINDOWS)

View File

@@ -0,0 +1,34 @@
#pragma once
#include <hex.hpp>
#include <imgui.h>
#include <hex/views/view.hpp>
#include <array>
#include <string>
#include <vector>
namespace hex {
namespace prv { class Provider; }
class ViewDiff : public View {
public:
ViewDiff();
~ViewDiff() override;
void drawContent() override;
void drawMenu() override;
private:
void drawDiffLine(const std::array<int, 2> &providerIds, u64 row) const;
int m_providerA = -1, m_providerB = -1;
bool m_greyedOutZeros = true;
bool m_upperCaseHex = true;
int m_columnCount = 16;
};
}

View File

@@ -1,9 +1,8 @@
#pragma once
#include <hex/views/view.hpp>
#include <hex/pattern_language/evaluator.hpp>
#include <hex/pattern_language/pattern_language.hpp>
#include <hex/pattern_language/log_console.hpp>
#include <hex/providers/provider.hpp>
#include <cstring>
@@ -27,10 +26,13 @@ namespace hex {
private:
pl::PatternLanguage *m_patternLanguageRuntime;
std::vector<std::string> m_possiblePatternFiles;
int m_selectedPatternFile = 0;
std::vector<std::filesystem::path> m_possiblePatternFiles;
u32 m_selectedPatternFile = 0;
bool m_runAutomatically = false;
bool m_evaluatorRunning = false;
bool m_hasUnevaluatedChanges = false;
bool m_acceptPatternWindowOpen = false;
TextEditor m_textEditor;
std::vector<std::pair<pl::LogConsole::Level, std::string>> m_console;

View File

@@ -9,6 +9,7 @@
#include <array>
#include <future>
#include <string>
#include <filesystem>
namespace hex {
@@ -19,6 +20,8 @@ namespace hex {
std::string link;
std::string hash;
bool isFolder;
bool downloading;
bool installed;
bool hasUpdate;
@@ -39,8 +42,9 @@ namespace hex {
Net m_net;
std::future<Response<std::string>> m_apiRequest;
std::future<Response<void>> m_download;
std::filesystem::path m_downloadPath;
std::vector<StoreEntry> m_patterns, m_includes, m_magics, m_constants;
std::vector<StoreEntry> m_patterns, m_includes, m_magics, m_constants, m_yara;
void drawStore();

View File

@@ -23,7 +23,7 @@ namespace hex {
bool wholeDataMatch;
};
std::vector<std::string> m_rules;
std::vector<std::pair<std::string, std::string>> m_rules;
std::vector<YaraMatch> m_matches;
u32 m_selectedRule = 0;
bool m_matching = false;

View File

@@ -3,6 +3,7 @@
#include <filesystem>
#include <memory>
#include <string>
#include <list>
#include <vector>
#include <hex/views/view.hpp>
@@ -64,6 +65,8 @@ namespace hex {
ImGui::Texture m_logoTexture;
std::filesystem::path m_safetyBackupPath;
std::list<std::string> m_popupsToOpen;
};
}

View File

@@ -1,18 +0,0 @@
# A libmagic database containing definitions for files used by Nintendo consoles
# Nintendo Switch NRO file
0x10 string NRO0 Nintendo Switch NRO file
>0x08 string HOMEBREW (Homebrew)
>0x18 long x (Size %d)
# Nintendo Switch NSO file
0x00 string NSO0 Nintendo Switch NSO file
>0x04 long x Version %d
>0x0C long x Flags %08x
# Nintendo Switch NCA file
0x200 string NCA Nintendo Switch NCA file
>0x203 byte x Version %c
>0x204 byte 0 System NCA
>0x204 byte 1 Gamecard NCA
>0x210 quad x ProgramId %016llx

View File

@@ -19,6 +19,7 @@ add_library(${PROJECT_NAME} SHARED
source/lang/en_US.cpp
source/lang/de_DE.cpp
source/lang/it_IT.cpp
source/lang/zh_CN.cpp
)
# Add additional include directories here #

View File

@@ -131,19 +131,19 @@ namespace hex::plugin::builtin {
return [value] { ImGui::TextUnformatted(value.c_str()); return value; };
});
ContentRegistry::DataInspector::add("hex.builtin.inspector.string", 0, [](auto buffer, auto endian, auto style) {
ContentRegistry::DataInspector::add("hex.builtin.inspector.string", 1, [](auto buffer, auto endian, auto style) {
Region currSelection = { 0 };
EventManager::post<QuerySelection>(currSelection);
constexpr static auto MaxStringLength = 32;
std::string stringBuffer(std::min<ssize_t>(MaxStringLength, currSelection.size), 0x00);
SharedData::currentProvider->read(currSelection.address, stringBuffer.data(), stringBuffer.size());
ImHexApi::Provider::get()->read(currSelection.address, stringBuffer.data(), stringBuffer.size());
if (currSelection.size > MaxStringLength)
stringBuffer += "...";
for (auto &c : stringBuffer)
if (c < 0x20 || c == '\n' || c == '\r')
if (c < 0x20)
c = ' ';

View File

@@ -380,7 +380,7 @@ namespace hex::plugin::builtin {
std::vector<u8> data;
data.resize(size);
SharedData::currentProvider->readRaw(address, data.data(), size);
ImHexApi::Provider::get()->readRaw(address, data.data(), size);
this->setBufferOnOutput(2, data);
}
@@ -407,7 +407,7 @@ namespace hex::plugin::builtin {
}) { }
void process() override {
auto size = SharedData::currentProvider->getActualSize();
auto size = ImHexApi::Provider::get()->getActualSize();
this->setIntegerOnOutput(0, size);
}

View File

@@ -2,17 +2,44 @@
#include <hex/helpers/shared_data.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/net.hpp>
#include <hex/pattern_language/ast_node.hpp>
#include <hex/pattern_language/token.hpp>
#include <hex/pattern_language/log_console.hpp>
#include <hex/pattern_language/evaluator.hpp>
#include <hex/pattern_language/pattern_data.hpp>
#include <vector>
#include <fmt/args.h>
namespace hex::plugin::builtin {
#define LITERAL_COMPARE(literal, cond) std::visit([&](auto &&literal) { return (cond) != 0; }, literal)
#define AS_TYPE(type, value) ctx.template asType<type>(value)
std::string format(pl::Evaluator *, auto params) {
auto format = pl::Token::literalToString(params[0], true);
std::string message;
fmt::dynamic_format_arg_store<fmt::format_context> formatArgs;
for (u32 i = 1; i < params.size(); i++) {
auto &param = params[i];
std::visit(overloaded {
[&](pl::PatternData* value) {
formatArgs.push_back(hex::format("{} {} @ 0x{:X}", value->getTypeName(), value->getVariableName(), value->getOffset()));
},
[&](auto &&value) {
formatArgs.push_back(value);
}
}, param);
}
try {
return fmt::vformat(format, formatArgs);
} catch (fmt::format_error &error) {
hex::pl::LogConsole::abortEvaluation(hex::format("format error: {}", error.what()));
}
}
void registerPatternLanguageFunctions() {
using namespace hex::pl;
@@ -21,55 +48,37 @@ namespace hex::plugin::builtin {
{
/* assert(condition, message) */
ContentRegistry::PatternLanguageFunctions::add(nsStd, "assert", 2, [](auto &ctx, auto params) {
auto condition = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue();
auto message = AS_TYPE(ASTNodeStringLiteral, params[1])->getString();
ContentRegistry::PatternLanguageFunctions::add(nsStd, "assert", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto condition = Token::literalToBoolean(params[0]);
auto message = std::get<std::string>(params[1]);
if (LITERAL_COMPARE(condition, condition == 0))
ctx.getConsole().abortEvaluation(hex::format("assertion failed \"{0}\"", message.data()));
if (!condition)
LogConsole::abortEvaluation(hex::format("assertion failed \"{0}\"", message));
return nullptr;
return std::nullopt;
});
/* assert_warn(condition, message) */
ContentRegistry::PatternLanguageFunctions::add(nsStd, "assert_warn", 2, [](auto ctx, auto params) {
auto condition = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue();
auto message = AS_TYPE(ASTNodeStringLiteral, params[1])->getString();
ContentRegistry::PatternLanguageFunctions::add(nsStd, "assert_warn", 2, [](auto *ctx, auto params) -> std::optional<Token::Literal> {
auto condition = Token::literalToBoolean(params[0]);
auto message = std::get<std::string>(params[1]);
if (LITERAL_COMPARE(condition, condition == 0))
ctx.getConsole().log(LogConsole::Level::Warning, hex::format("assertion failed \"{0}\"", message));
if (!condition)
ctx->getConsole().log(LogConsole::Level::Warning, hex::format("assertion failed \"{0}\"", message));
return nullptr;
return std::nullopt;
});
/* print(values...) */
ContentRegistry::PatternLanguageFunctions::add(nsStd, "print", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 0, [](auto &ctx, auto params) {
std::string message;
for (auto& param : params) {
if (auto integerLiteral = dynamic_cast<ASTNodeIntegerLiteral*>(param); integerLiteral != nullptr) {
std::visit([&](auto &&value) {
using Type = std::remove_cvref_t<decltype(value)>;
if constexpr (std::is_same_v<Type, char>)
message += (char)value;
else if constexpr (std::is_same_v<Type, bool>)
message += value == 0 ? "false" : "true";
else if constexpr (std::is_unsigned_v<Type>)
message += std::to_string(static_cast<u64>(value));
else if constexpr (std::is_signed_v<Type>)
message += std::to_string(static_cast<s64>(value));
else if constexpr (std::is_floating_point_v<Type>)
message += std::to_string(value);
else
message += "< Custom Type >";
}, integerLiteral->getValue());
}
else if (auto stringLiteral = dynamic_cast<ASTNodeStringLiteral*>(param); stringLiteral != nullptr)
message += stringLiteral->getString();
}
/* print(format, args...) */
ContentRegistry::PatternLanguageFunctions::add(nsStd, "print", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 0, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
ctx->getConsole().log(LogConsole::Level::Info, format(ctx, params));
ctx.getConsole().log(LogConsole::Level::Info, message);
return std::nullopt;
});
return nullptr;
/* format(format, args...) */
ContentRegistry::PatternLanguageFunctions::add(nsStd, "format", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 0, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return format(ctx, params);
});
}
@@ -78,141 +87,159 @@ namespace hex::plugin::builtin {
{
/* align_to(alignment, value) */
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "align_to", 2, [](auto &ctx, auto params) -> ASTNode* {
auto alignment = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue();
auto value = AS_TYPE(ASTNodeIntegerLiteral, params[1])->getValue();
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "align_to", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto alignment = Token::literalToUnsigned(params[0]);
auto value = Token::literalToUnsigned(params[1]);
auto result = std::visit([](auto &&alignment, auto &&value) {
u64 remainder = u64(value) % u64(alignment);
return remainder != 0 ? u64(value) + (u64(alignment) - remainder) : u64(value);
}, alignment, value);
u128 remainder = value % alignment;
return new ASTNodeIntegerLiteral(u64(result));
return remainder != 0 ? value + (alignment - remainder) : value;
});
/* base_address() */
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "base_address", ContentRegistry::PatternLanguageFunctions::NoParameters, [](auto &ctx, auto params) -> ASTNode* {
return new ASTNodeIntegerLiteral(u64(SharedData::currentProvider->getBaseAddress()));
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "base_address", ContentRegistry::PatternLanguageFunctions::NoParameters, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return u128(ctx->getProvider()->getBaseAddress());
});
/* size() */
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "size", ContentRegistry::PatternLanguageFunctions::NoParameters, [](auto &ctx, auto params) -> ASTNode* {
return new ASTNodeIntegerLiteral(u64(SharedData::currentProvider->getActualSize()));
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "size", ContentRegistry::PatternLanguageFunctions::NoParameters, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
return u128(ctx->getProvider()->getActualSize());
});
/* find_sequence(occurrence_index, bytes...) */
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "find_sequence", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 1, [](auto &ctx, auto params) {
auto& occurrenceIndex = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue();
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "find_sequence", ContentRegistry::PatternLanguageFunctions::MoreParametersThan | 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto occurrenceIndex = Token::literalToUnsigned(params[0]);
std::vector<u8> sequence;
for (u32 i = 1; i < params.size(); i++) {
sequence.push_back(std::visit([&](auto &&value) -> u8 {
if (value <= 0xFF)
return value;
else
ctx.getConsole().abortEvaluation("sequence bytes need to fit into 1 byte");
}, AS_TYPE(ASTNodeIntegerLiteral, params[i])->getValue()));
auto byte = Token::literalToUnsigned(params[i]);
if (byte > 0xFF)
LogConsole::abortEvaluation(hex::format("byte #{} value out of range: {} > 0xFF", i, u64(byte)));
sequence.push_back(u8(byte & 0xFF));
}
std::vector<u8> bytes(sequence.size(), 0x00);
u32 occurrences = 0;
for (u64 offset = 0; offset < SharedData::currentProvider->getSize() - sequence.size(); offset++) {
SharedData::currentProvider->read(offset, bytes.data(), bytes.size());
for (u64 offset = 0; offset < ctx->getProvider()->getSize() - sequence.size(); offset++) {
ctx->getProvider()->read(offset, bytes.data(), bytes.size());
if (bytes == sequence) {
if (LITERAL_COMPARE(occurrenceIndex, occurrences < occurrenceIndex)) {
if (occurrences < occurrenceIndex) {
occurrences++;
continue;
}
return new ASTNodeIntegerLiteral(offset);
return u128(offset);
}
}
ctx.getConsole().abortEvaluation("failed to find sequence");
LogConsole::abortEvaluation("failed to find sequence");
});
/* read_unsigned(address, size) */
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "read_unsigned", 2, [](auto &ctx, auto params) {
auto address = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue();
auto size = AS_TYPE(ASTNodeIntegerLiteral, params[1])->getValue();
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "read_unsigned", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto address = Token::literalToUnsigned(params[0]);
auto size = Token::literalToUnsigned(params[1]);
if (LITERAL_COMPARE(address, address >= SharedData::currentProvider->getActualSize()))
ctx.getConsole().abortEvaluation("address out of range");
if (size > 16)
LogConsole::abortEvaluation("read size out of range");
return std::visit([&](auto &&address, auto &&size) {
if (size <= 0 || size > 16)
ctx.getConsole().abortEvaluation("invalid read size");
u128 result = 0;
ctx->getProvider()->read(address, &result, size);
u8 value[(u8)size];
SharedData::currentProvider->read(address, value, size);
switch ((u8)size) {
case 1: return new ASTNodeIntegerLiteral(*reinterpret_cast<u8*>(value));
case 2: return new ASTNodeIntegerLiteral(*reinterpret_cast<u16*>(value));
case 4: return new ASTNodeIntegerLiteral(*reinterpret_cast<u32*>(value));
case 8: return new ASTNodeIntegerLiteral(*reinterpret_cast<u64*>(value));
case 16: return new ASTNodeIntegerLiteral(*reinterpret_cast<u128*>(value));
default: ctx.getConsole().abortEvaluation("invalid read size");
}
}, address, size);
return result;
});
/* read_signed(address, size) */
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "read_signed", 2, [](auto &ctx, auto params) {
auto address = AS_TYPE(ASTNodeIntegerLiteral, params[0])->getValue();
auto size = AS_TYPE(ASTNodeIntegerLiteral, params[1])->getValue();
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "read_signed", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto address = Token::literalToUnsigned(params[0]);
auto size = Token::literalToUnsigned(params[1]);
if (LITERAL_COMPARE(address, address >= SharedData::currentProvider->getActualSize()))
ctx.getConsole().abortEvaluation("address out of range");
if (size > 16)
LogConsole::abortEvaluation("read size out of range");
return std::visit([&](auto &&address, auto &&size) {
if (size <= 0 || size > 16)
ctx.getConsole().abortEvaluation("invalid read size");
s128 value;
ctx->getProvider()->read(address, &value, size);
return hex::signExtend(size * 8, value);
});
u8 value[(u8)size];
SharedData::currentProvider->read(address, value, size);
/* read_string(address, size) */
ContentRegistry::PatternLanguageFunctions::add(nsStdMem, "read_string", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto address = Token::literalToUnsigned(params[0]);
auto size = Token::literalToUnsigned(params[1]);
switch ((u8)size) {
case 1: return new ASTNodeIntegerLiteral(*reinterpret_cast<s8*>(value));
case 2: return new ASTNodeIntegerLiteral(*reinterpret_cast<s16*>(value));
case 4: return new ASTNodeIntegerLiteral(*reinterpret_cast<s32*>(value));
case 8: return new ASTNodeIntegerLiteral(*reinterpret_cast<s64*>(value));
case 16: return new ASTNodeIntegerLiteral(*reinterpret_cast<s128*>(value));
default: ctx.getConsole().abortEvaluation("invalid read size");
}
}, address, size);
std::string result(size, '\x00');
ctx->getProvider()->read(address, result.data(), size);
return result;
});
}
ContentRegistry::PatternLanguageFunctions::Namespace nsStdStr = { "std", "str" };
ContentRegistry::PatternLanguageFunctions::Namespace nsStdString = { "std", "string" };
{
/* length(string) */
ContentRegistry::PatternLanguageFunctions::add(nsStdStr, "length", 1, [](auto &ctx, auto params) {
auto string = AS_TYPE(ASTNodeStringLiteral, params[1])->getString();
ContentRegistry::PatternLanguageFunctions::add(nsStdString, "length", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto string = Token::literalToString(params[0], false);
return new ASTNodeIntegerLiteral(u32(string.length()));
return u128(string.length());
});
/* at(string, index) */
ContentRegistry::PatternLanguageFunctions::add(nsStdStr, "at", 2, [](auto &ctx, auto params) {
auto string = AS_TYPE(ASTNodeStringLiteral, params[0])->getString();
auto index = AS_TYPE(ASTNodeIntegerLiteral, params[1])->getValue();
ContentRegistry::PatternLanguageFunctions::add(nsStdString, "at", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto string = Token::literalToString(params[0], false);
auto index = Token::literalToSigned(params[1]);
if (LITERAL_COMPARE(index, index >= string.length() || index < 0))
ctx.getConsole().abortEvaluation("character index out of bounds");
if (std::abs(index) >= string.length())
LogConsole::abortEvaluation("character index out of range");
return std::visit([&](auto &&value) { return new ASTNodeIntegerLiteral(char(string[u32(value)])); }, index);
if (index >= 0)
return char(string[index]);
else
return char(string[string.length() - -index]);
});
/* compare(left, right) */
ContentRegistry::PatternLanguageFunctions::add(nsStdStr, "compare", 2, [](auto &ctx, auto params) {
auto left = AS_TYPE(ASTNodeStringLiteral, params[0])->getString();
auto right = AS_TYPE(ASTNodeStringLiteral, params[1])->getString();
/* substr(string, pos, count) */
ContentRegistry::PatternLanguageFunctions::add(nsStdString, "substr", 3, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto string = Token::literalToString(params[0], false);
auto pos = Token::literalToUnsigned(params[1]);
auto size = Token::literalToUnsigned(params[2]);
return new ASTNodeIntegerLiteral(bool(left == right));
if (pos > string.length())
LogConsole::abortEvaluation("character index out of range");
return string.substr(pos, size);
});
/* parse_int(string, base) */
ContentRegistry::PatternLanguageFunctions::add(nsStdString, "parse_int", 2, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto string = Token::literalToString(params[0], false);
auto base = Token::literalToUnsigned(params[1]);
return s128(std::strtoll(string.c_str(), nullptr, base));
});
/* parse_float(string) */
ContentRegistry::PatternLanguageFunctions::add(nsStdString, "parse_float", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
auto string = Token::literalToString(params[0], false);
return double(std::strtod(string.c_str(), nullptr));
});
}
ContentRegistry::PatternLanguageFunctions::Namespace nsStdHttp = { "std", "http" };
{
/* get(url) */
ContentRegistry::PatternLanguageFunctions::add(nsStdHttp, "get", 1, [](Evaluator *ctx, auto params) -> std::optional<Token::Literal> {
const auto url = Token::literalToString(params[0], false);
hex::Net net;
return net.getString(url).get().body;
});
}
}
}
}

View File

@@ -15,7 +15,18 @@ namespace hex::plugin::builtin {
/* General */
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.show_tips", 1, [](auto name, nlohmann::json &setting) {
static bool enabled = setting.is_number() ? static_cast<int>(setting) : 1;
static bool enabled = static_cast<int>(setting);
if (ImGui::Checkbox(name.data(), &enabled)) {
setting = static_cast<int>(enabled);
return true;
}
return false;
});
ContentRegistry::Settings::add("hex.builtin.setting.general", "hex.builtin.setting.general.auto_load_patterns", 1, [](auto name, nlohmann::json &setting) {
static bool enabled = static_cast<int>(setting);
if (ImGui::Checkbox(name.data(), &enabled)) {
setting = static_cast<int>(enabled);
@@ -28,9 +39,10 @@ namespace hex::plugin::builtin {
/* Interface */
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.color", 0, [](auto name, nlohmann::json &setting) {
static int selection = setting.is_number() ? static_cast<int>(setting) : 0;
static int selection = static_cast<int>(setting);
const char* themes[] = {
"hex.builtin.setting.interface.color.system"_lang,
"hex.builtin.setting.interface.color.dark"_lang,
"hex.builtin.setting.interface.color.light"_lang,
"hex.builtin.setting.interface.color.classic"_lang
@@ -45,7 +57,7 @@ namespace hex::plugin::builtin {
});
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.scaling", 0, [](auto name, nlohmann::json &setting) {
static int selection = setting.is_number() ? static_cast<int>(setting) : 0;
static int selection = static_cast<int>(setting);
const char* scaling[] = {
"hex.builtin.setting.interface.scaling.native"_lang,
@@ -82,6 +94,8 @@ namespace hex::plugin::builtin {
static auto languageNames = [&]() {
std::vector<const char*> result;
result.reserve(languages.size());
for (auto &[languageCode, languageName] : languages)
result.push_back(languageName.c_str());
@@ -107,7 +121,7 @@ namespace hex::plugin::builtin {
});
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.fps", 60, [](auto name, nlohmann::json &setting) {
static int fps = setting.is_number() ? static_cast<int>(setting) : 60;
static int fps = static_cast<int>(setting);
if (ImGui::SliderInt(name.data(), &fps, 15, 60)) {
setting = fps;
@@ -118,7 +132,7 @@ namespace hex::plugin::builtin {
});
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.highlight_alpha", 0x80, [](auto name, nlohmann::json &setting) {
static int alpha = setting.is_number() ? static_cast<int>(setting) : 0x80;
static int alpha = static_cast<int>(setting);
if (ImGui::SliderInt(name.data(), &alpha, 0x00, 0xFF)) {
setting = alpha;
@@ -128,6 +142,83 @@ namespace hex::plugin::builtin {
return false;
});
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.column_count", 16, [](auto name, nlohmann::json &setting) {
static int columns = static_cast<int>(setting);
if (ImGui::SliderInt(name.data(), &columns, 1, 32)) {
setting = columns;
return true;
}
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);
if (ImGui::Checkbox(name.data(), &ascii)) {
setting = static_cast<int>(ascii);
return true;
}
return false;
});
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.advanced_decoding", 0, [](auto name, nlohmann::json &setting) {
static bool advancedDecoding = static_cast<int>(setting);
if (ImGui::Checkbox(name.data(), &advancedDecoding)) {
setting = static_cast<int>(advancedDecoding);
return true;
}
return false;
});
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.grey_zeros", 1, [](auto name, nlohmann::json &setting) {
static bool greyZeros = static_cast<int>(setting);
if (ImGui::Checkbox(name.data(), &greyZeros)) {
setting = static_cast<int>(greyZeros);
return true;
}
return false;
});
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.uppercase_hex", 1, [](auto name, nlohmann::json &setting) {
static bool upperCaseHex = static_cast<int>(setting);
if (ImGui::Checkbox(name.data(), &upperCaseHex)) {
setting = static_cast<int>(upperCaseHex);
return true;
}
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);
if (ImGui::Checkbox(name.data(), &extraInfos)) {
setting = static_cast<int>(extraInfos);
return true;
}
return false;
});
}
}

View File

@@ -1,12 +1,17 @@
#include <hex/api/content_registry.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/helpers/net.hpp>
#include <hex/helpers/shared_data.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/literals.hpp>
#include <regex>
#include <algorithm>
#include <chrono>
#include <random>
#include <regex>
#include <llvm/Demangle/Demangle.h>
#include "math_evaluator.hpp"
@@ -23,6 +28,7 @@ namespace hex::plugin::builtin {
using namespace std::literals::string_literals;
using namespace std::literals::chrono_literals;
using namespace hex::literals;
int updateStringSizeCallback(ImGuiInputTextCallbackData *data) {
auto &mathInput = *static_cast<std::string*>(data->UserData);
@@ -97,24 +103,22 @@ namespace hex::plugin::builtin {
}
void drawRegexReplacer() {
static std::vector<char> regexInput(0xF'FFFF, 0x00);;
static std::vector<char> regexPattern(0xF'FFFF, 0x00);;
static std::vector<char> replacePattern(0xF'FFFF, 0x00);;
static std::string regexOutput(0xF'FFFF, 0x00);;
static auto regexInput = []{ std::string s; s.reserve(0xFFF); return s; }();
static auto regexPattern = []{ std::string s; s.reserve(0xFFF); return s; }();
static auto replacePattern = []{ std::string s; s.reserve(0xFFF); return s; }();
static auto regexOutput = []{ std::string s; s.reserve(0xFFF); return s; }();
bool shouldInvalidate;
bool changed1 = ImGui::InputText("hex.builtin.tools.regex_replacer.pattern"_lang, regexPattern.data(), regexPattern.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &regexPattern);
bool changed2 = ImGui::InputText("hex.builtin.tools.regex_replacer.replace"_lang, replacePattern.data(), replacePattern.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &replacePattern);
bool changed3 = ImGui::InputTextMultiline("hex.builtin.tools.regex_replacer.input"_lang, regexInput.data(), regexInput.capacity(), ImVec2(0, 0), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &regexInput);
shouldInvalidate = ImGui::InputText("hex.builtin.tools.regex_replacer.pattern"_lang, regexPattern.data(), regexPattern.size());
shouldInvalidate = ImGui::InputText("hex.builtin.tools.regex_replacer.replace"_lang, replacePattern.data(), replacePattern.size()) || shouldInvalidate;
shouldInvalidate = ImGui::InputTextMultiline("hex.builtin.tools.regex_replacer.input"_lang, regexInput.data(), regexInput.size()) || shouldInvalidate;
if (shouldInvalidate) {
if (changed1 || changed2 || changed3) {
try {
regexOutput = std::regex_replace(regexInput.data(), std::regex(regexPattern.data()), replacePattern.data());
} catch (std::regex_error&) {}
}
ImGui::InputTextMultiline("hex.builtin.tools.regex_replacer.input"_lang, regexOutput.data(), regexOutput.size(), ImVec2(0, 0), ImGuiInputTextFlags_ReadOnly);
ImGui::InputTextMultiline("hex.builtin.tools.regex_replacer.output"_lang, regexOutput.data(), regexOutput.size(), ImVec2(0, 0), ImGuiInputTextFlags_ReadOnly);
ImGui::NewLine();
}
@@ -158,8 +162,8 @@ namespace hex::plugin::builtin {
evaluator.setFunction("read", [](auto args) -> std::optional<long double> {
u8 value = 0;
auto provider = SharedData::currentProvider;
if (provider == nullptr || !provider->isReadable() || args[0] >= provider->getActualSize())
auto provider = ImHexApi::Provider::get();
if (!ImHexApi::Provider::isValid() || !provider->isReadable() || args[0] >= provider->getActualSize())
return { };
provider->read(args[0], &value, sizeof(u8));
@@ -168,8 +172,8 @@ namespace hex::plugin::builtin {
}, 1, 1);
evaluator.setFunction("write", [](auto args) -> std::optional<long double> {
auto provider = SharedData::currentProvider;
if (provider == nullptr || !provider->isWritable() || args[0] >= provider->getActualSize())
auto provider = ImHexApi::Provider::get();
if (!ImHexApi::Provider::isValid() || !provider->isWritable() || args[0] >= provider->getActualSize())
return { };
if (args[1] > 0xFF)
@@ -667,6 +671,371 @@ namespace hex::plugin::builtin {
}
}
void drawFileToolShredder() {
static bool shredding = false;
static auto selectedFile = []{ std::string s; s.reserve(0x1000); return s; }();
static bool fastMode = false;
ImGui::TextUnformatted("hex.builtin.tools.file_tools.shredder.warning"_lang);
ImGui::NewLine();
if (ImGui::BeginChild("settings", { 0, ImGui::GetTextLineHeightWithSpacing() * 4 }, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
ImGui::BeginDisabled(shredding);
{
ImGui::TextUnformatted("hex.builtin.tools.file_tools.shredder.input"_lang);
ImGui::SameLine();
ImGui::InputText("##path", selectedFile.data(), selectedFile.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &selectedFile);
ImGui::SameLine();
if (ImGui::Button("...")) {
hex::openFileBrowser("hex.builtin.tools.file_tools.shredder.picker"_lang, DialogMode::Open, {}, [](const std::string &path) {
selectedFile = path;
});
}
ImGui::Checkbox("hex.builtin.tools.file_tools.shredder.fast"_lang, &fastMode);
}
ImGui::EndDisabled();
}
ImGui::EndChild();
if (shredding)
ImGui::TextSpinner("hex.builtin.tools.file_tools.shredder.shredding"_lang);
else {
ImGui::BeginDisabled(selectedFile.empty());
{
if (ImGui::Button("hex.builtin.tools.file_tools.shredder.shred"_lang)) {
shredding = true;
std::thread([]{
ON_SCOPE_EXIT { shredding = false; selectedFile.clear(); };
File file(selectedFile, File::Mode::Write);
if (!file.isValid()) {
View::showErrorPopup("hex.builtin.tools.file_tools.shredder.error.open"_lang);
return;
}
std::vector<std::array<u8, 3>> overwritePattern;
if (fastMode) {
/* Should be sufficient for modern disks */
overwritePattern.push_back({ 0x00, 0x00, 0x00 });
overwritePattern.push_back({ 0xFF, 0xFF, 0xFF });
}
else {
/* Gutmann's method. Secure for magnetic storage */
std::random_device rd;
std::uniform_int_distribution<u8> dist(0x00, 0xFF);
/* Fill fixed patterns */
overwritePattern = {
{}, {}, {}, {},
{ 0x55, 0x55, 0x55 }, { 0xAA, 0xAA, 0xAA }, { 0x92, 0x49, 0x24 }, { 0x49, 0x24, 0x92 },
{ 0x24, 0x92, 0x49 }, { 0x00, 0x00, 0x00 }, { 0x11, 0x11, 0x11 }, { 0x22, 0x22, 0x22 },
{ 0x33, 0x33, 0x44 }, { 0x55, 0x55, 0x55 }, { 0x66, 0x66, 0x66 }, { 0x77, 0x77, 0x77 },
{ 0x88, 0x88, 0x88 }, { 0x99, 0x99, 0x99 }, { 0xAA, 0xAA, 0xAA }, { 0xBB, 0xBB, 0xBB },
{ 0xCC, 0xCC, 0xCC }, { 0xDD, 0xDD, 0xDD }, { 0xEE, 0xEE, 0xEE }, { 0xFF, 0xFF, 0xFF },
{ 0x92, 0x49, 0x24 }, { 0x49, 0x24, 0x92 }, { 0x24, 0x92, 0x49 }, { 0x6D, 0xB6, 0xDB },
{ 0xB6, 0xDB, 0x6D }, { 0xBD, 0x6D, 0xB6 },
{}, {}, {}, {}
};
/* Fill random patterns */
for (u8 i = 0; i < 4; i++)
overwritePattern[i] = { dist(rd), dist(rd), dist(rd) };
for (u8 i = 0; i < 4; i++)
overwritePattern[overwritePattern.size() - 1 - i] = { dist(rd), dist(rd), dist(rd) };
}
size_t fileSize = file.getSize();
for (const auto &pattern : overwritePattern) {
for (u64 offset = 0; offset < fileSize; offset += 3) {
file.write(pattern.data(), std::min(pattern.size(), fileSize - offset));
}
file.flush();
}
file.remove();
View::showMessagePopup("hex.builtin.tools.file_tools.shredder.success"_lang);
}).detach();
}
}
ImGui::EndDisabled();
}
}
void drawFileToolSplitter() {
std::array sizeText = {
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy"_lang,
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy"_lang,
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.zip100"_lang,
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.zip200"_lang,
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.cdrom650"_lang,
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.cdrom700"_lang,
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.fat32"_lang,
(const char*)"hex.builtin.tools.file_tools.splitter.sizes.custom"_lang
};
std::array<u64, sizeText.size()> sizes = {
1200_KiB,
1400_KiB,
100_MiB,
200_MiB,
650_MiB,
700_MiB,
4_GiB,
1
};
static bool splitting = false;
static auto selectedFile = []{ std::string s; s.reserve(0x1000); return s; }();
static auto baseOutputPath = []{ std::string s; s.reserve(0x1000); return s; }();
static u64 splitSize = sizes[0];
static int selectedItem = 0;
if (ImGui::BeginChild("split_settings", { 0, ImGui::GetTextLineHeightWithSpacing() * 7 }, true, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
ImGui::BeginDisabled(splitting);
{
ImGui::TextUnformatted("hex.builtin.tools.file_tools.splitter.input"_lang);
ImGui::SameLine();
ImGui::InputText("##path", selectedFile.data(), selectedFile.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &selectedFile);
ImGui::SameLine();
if (ImGui::Button("...##input")) {
hex::openFileBrowser("hex.builtin.tools.file_tools.splitter.picker.input"_lang, DialogMode::Open, {}, [](const std::string &path) {
selectedFile = path;
});
}
ImGui::TextUnformatted("hex.builtin.tools.file_tools.splitter.output"_lang);
ImGui::SameLine();
ImGui::InputText("##base_path", baseOutputPath.data(), baseOutputPath.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &baseOutputPath);
ImGui::SameLine();
if (ImGui::Button("...##output")) {
hex::openFileBrowser("hex.builtin.tools.file_tools.splitter.picker.output"_lang, DialogMode::Save, {}, [](const std::string &path) {
baseOutputPath = path;
});
}
ImGui::Separator();
if (ImGui::Combo("###part_size", &selectedItem, sizeText.data(), sizeText.size())) {
splitSize = sizes[selectedItem];
}
}
ImGui::EndDisabled();
ImGui::BeginDisabled(splitting || selectedItem != sizes.size() - 1);
{
ImGui::InputScalar("###custom_size", ImGuiDataType_U64, &splitSize);
ImGui::SameLine();
ImGui::TextUnformatted("Bytes");
}
ImGui::EndDisabled();
}
ImGui::EndChild();
ImGui::BeginDisabled(selectedFile.empty() || baseOutputPath.empty() || splitSize == 0);
{
if (splitting)
ImGui::TextSpinner("hex.builtin.tools.file_tools.splitter.splitting"_lang);
else {
if (ImGui::Button("hex.builtin.tools.file_tools.splitter.split"_lang)) {
splitting = true;
std::thread([]{
ON_SCOPE_EXIT { splitting = false; selectedFile.clear(); baseOutputPath.clear(); };
File file(selectedFile, File::Mode::Read);
if (!file.isValid()) {
View::showErrorPopup("hex.builtin.tools.file_tools.splitter.error.open"_lang);
return;
}
if (file.getSize() < splitSize) {
View::showErrorPopup("hex.builtin.tools.file_tools.splitter.error.size"_lang);
return;
}
u32 index = 1;
for (u64 offset = 0; offset < file.getSize(); offset += splitSize) {
File partFile(baseOutputPath + hex::format(".{:05}", index), File::Mode::Create);
if (!partFile.isValid()) {
View::showErrorPopup(hex::format("hex.builtin.tools.file_tools.splitter.error.create"_lang, index));
return;
}
constexpr auto BufferSize = 0xFF'FFFF;
for (u64 partOffset = 0; partOffset < splitSize; partOffset += BufferSize) {
partFile.write(file.readBytes(std::min<u64>(BufferSize, splitSize - partOffset)));
partFile.flush();
}
index++;
}
View::showMessagePopup("hex.builtin.tools.file_tools.splitter.success"_lang);
}).detach();
}
}
}
ImGui::EndDisabled();
}
void drawFileToolCombiner() {
static bool combining = false;
static std::vector<std::string> files;
static auto outputPath = []{ std::string s; s.reserve(0x1000); return s; }();
static s32 selectedIndex;
if (ImGui::BeginTable("files_table", 2, ImGuiTableFlags_SizingStretchProp)) {
ImGui::TableSetupColumn("file list", ImGuiTableColumnFlags_NoHeaderLabel, 10);
ImGui::TableSetupColumn("buttons", ImGuiTableColumnFlags_NoHeaderLabel, 1);
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (ImGui::BeginListBox("##files", { -FLT_MIN, 10 * ImGui::GetTextLineHeightWithSpacing() })) {
s32 index = 0;
for (auto &file : files) {
if (ImGui::Selectable(std::filesystem::path(file).filename().string().c_str(), index == selectedIndex))
selectedIndex = index;
index++;
}
ImGui::EndListBox();
}
ImGui::TableNextColumn();
ImGui::BeginDisabled(selectedIndex <= 0) ;
{
if (ImGui::ArrowButton("move_up", ImGuiDir_Up)) {
std::iter_swap(files.begin() + selectedIndex, files.begin() + selectedIndex - 1);
selectedIndex--;
}
}
ImGui::EndDisabled();
ImGui::BeginDisabled(files.empty() || selectedIndex >= files.size() - 1) ;
{
if (ImGui::ArrowButton("move_down", ImGuiDir_Down)) {
std::iter_swap(files.begin() + selectedIndex, files.begin() + selectedIndex + 1);
selectedIndex++;
}
}
ImGui::EndDisabled();
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::BeginDisabled(combining);
{
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.add"_lang)) {
hex::openFileBrowser("hex.builtin.tools.file_tools.combiner.add.picker"_lang, DialogMode::Open, {}, [](const std::string &path) {
files.push_back(path);
});
}
ImGui::SameLine();
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.delete"_lang)) {
files.erase(files.begin() + selectedIndex);
selectedIndex--;
}
ImGui::SameLine();
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.clear"_lang)) {
files.clear();
}
}
ImGui::EndDisabled();
ImGui::EndTable();
}
ImGui::BeginDisabled(combining);
{
ImGui::TextUnformatted("hex.builtin.tools.file_tools.combiner.output"_lang);
ImGui::SameLine();
ImGui::InputText("##output_path", outputPath.data(), outputPath.capacity(), ImGuiInputTextFlags_CallbackEdit, updateStringSizeCallback, &outputPath);
ImGui::SameLine();
if (ImGui::Button("...")) {
hex::openFileBrowser("hex.builtin.tools.file_tools.combiner.output.picker"_lang, DialogMode::Save, {}, [](const std::string &path) {
outputPath = path;
});
}
}
ImGui::EndDisabled();
ImGui::BeginDisabled(files.empty() || outputPath.empty());
{
if (combining)
ImGui::TextSpinner("hex.builtin.tools.file_tools.combiner.combining"_lang);
else {
if (ImGui::Button("hex.builtin.tools.file_tools.combiner.combine"_lang)) {
combining = true;
std::thread([]{
ON_SCOPE_EXIT { combining = false; };
File output(outputPath, File::Mode::Create);
if (!output.isValid()) {
View::showErrorPopup("hex.builtin.tools.file_tools.combiner.error.open_output"_lang);
return;
}
for (const auto &file : files) {
File input(file, File::Mode::Read);
if (!input.isValid()) {
View::showErrorPopup(hex::format("hex.builtin.tools.file_tools.combiner.open_input"_lang, std::filesystem::path(file).filename().string()));
return;
}
constexpr auto BufferSize = 0xFF'FFFF;
auto inputSize = input.getSize();
for (u64 inputOffset = 0; inputOffset < inputSize; inputOffset += BufferSize) {
output.write(input.readBytes(std::min<u64>(BufferSize, inputSize - inputOffset)));
output.flush();
}
}
files.clear();
selectedIndex = 0;
outputPath.clear();
View::showMessagePopup("hex.builtin.tools.file_tools.combiner.success"_lang);
}).detach();
}
}
}
ImGui::EndDisabled();
}
void drawFileTools() {
if (ImGui::BeginTabBar("file_tools_tabs")) {
if (ImGui::BeginTabItem("hex.builtin.tools.file_tools.shredder"_lang)) {
drawFileToolShredder();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("hex.builtin.tools.file_tools.splitter"_lang)) {
drawFileToolSplitter();
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("hex.builtin.tools.file_tools.combiner"_lang)) {
drawFileToolCombiner();
ImGui::EndTabItem();
}
ImGui::EndTabBar();
}
}
void registerToolEntries() {
ContentRegistry::Tools::add("hex.builtin.tools.demangler", drawDemangler);
ContentRegistry::Tools::add("hex.builtin.tools.ascii_table", drawASCIITable);
@@ -677,6 +1046,7 @@ namespace hex::plugin::builtin {
ContentRegistry::Tools::add("hex.builtin.tools.permissions", drawPermissionsCalculator);
ContentRegistry::Tools::add("hex.builtin.tools.file_uploader", drawFileUploader);
ContentRegistry::Tools::add("hex.builtin.tools.wiki_explain", drawWikiExplainer);
ContentRegistry::Tools::add("hex.builtin.tools.file_tools", drawFileTools);
}
}

View File

@@ -19,7 +19,7 @@ namespace hex::plugin::builtin {
framerate = 1.0F / ImGui::GetIO().DeltaTime;
}
ImGui::TextUnformatted(hex::format("FPS {0:.2f}", framerate).c_str());
ImGui::TextUnformatted(hex::format("FPS {0:2}.{1:02}", u32(framerate), u32(framerate * 100) % 100).c_str());
});
}
@@ -28,19 +28,19 @@ namespace hex::plugin::builtin {
ContentRegistry::Interface::addToolbarItem([] {
const static auto buttonSize = ImVec2(ImGui::GetCurrentWindow()->MenuBarHeight(), ImGui::GetCurrentWindow()->MenuBarHeight());
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
// Undo
ImGui::Disabled([&provider] {
if (ImGui::ToolBarButton(ICON_VS_DISCARD, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue), buttonSize))
provider->undo();
}, provider == nullptr || !provider->canUndo());
}, !ImHexApi::Provider::isValid() || !provider->canUndo());
// Redo
ImGui::Disabled([&provider] {
if (ImGui::ToolBarButton(ICON_VS_REDO, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue), buttonSize))
provider->redo();
}, provider == nullptr || !provider->canRedo());
}, !ImHexApi::Provider::isValid() || !provider->canRedo());
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
@@ -60,7 +60,7 @@ namespace hex::plugin::builtin {
ImGui::Disabled([&provider] {
if (ImGui::ToolBarButton(ICON_VS_SAVE, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarBlue), buttonSize))
provider->save();
}, provider == nullptr || !provider->isWritable() || !provider->isSavable());
}, !ImHexApi::Provider::isValid() || !provider->isWritable() || !provider->isSavable());
// Save file as
ImGui::Disabled([&provider] {
@@ -68,7 +68,7 @@ namespace hex::plugin::builtin {
hex::openFileBrowser("hex.view.hexeditor.save_as"_lang, DialogMode::Save, { }, [&provider](auto path) {
provider->saveAs(path);
});
}, provider == nullptr || !provider->isSavable());
}, !ImHexApi::Provider::isValid() || !provider->isSavable());
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
@@ -82,8 +82,33 @@ namespace hex::plugin::builtin {
ImHexApi::Bookmarks::add(region.address, region.size, { }, { });
}
}, provider == nullptr || !provider->isReadable());
}, !ImHexApi::Provider::isValid() || !provider->isReadable());
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::Spacing();
// Provider switcher
ImGui::Disabled([] {
auto &providers = ImHexApi::Provider::getProviders();
std::string preview;
if (ImHexApi::Provider::isValid())
preview = providers[SharedData::currentProvider]->getName();
ImGui::SetNextItemWidth(200 * SharedData::globalScale);
if (ImGui::BeginCombo("", preview.c_str())) {
for (int i = 0; i < providers.size(); i++) {
if (ImGui::Selectable(providers[i]->getName().c_str())) {
SharedData::currentProvider = i;
}
}
ImGui::EndCombo();
}
}, !ImHexApi::Provider::isValid());
});
}

View File

@@ -63,6 +63,7 @@ namespace hex::plugin::builtin {
{ "hex.common.decimal", "Dezimal" },
{ "hex.common.hexadecimal", "Hexadezimal" },
{ "hex.common.octal", "Oktal" },
{ "hex.common.info", "Information" },
{ "hex.common.error", "Fehler" },
{ "hex.common.fatal", "Fataler Fehler" },
{ "hex.common.address", "Adresse" },
@@ -79,10 +80,15 @@ namespace hex::plugin::builtin {
{ "hex.common.dont_show_again", "Nicht mehr anzeigen" },
{ "hex.common.link", "Link" },
{ "hex.common.file", "Datei" },
{ "hex.common.open", "Öffnen" },
{ "hex.common.browse", "Druchsuchen..." },
{ "hex.message.yara_rule_added", "Yara Regel hinzugefügt!" },
{ "hex.message.magic_db_added", "Magic Datenbank hinzugefügt!" },
{ "hex.view.bookmarks.name", "Lesezeichen" },
{ "hex.view.bookmarks.default_title", "Lesezeichen [0x{0:X} - 0x{1:X}]" },
{ "hex.view.bookmarks.no_bookmarks", "Noch kein Lesezeichen erstellt. Füge eines hinzu mit Bearbeiten -> Lesezeichen hinzufügen" },
{ "hex.view.bookmarks.no_bookmarks", "Noch kein Lesezeichen erstellt. Füge eines hinzu mit Bearbeiten -> Lesezeichen erstellen" },
{ "hex.view.bookmarks.title.info", "Informationen" },
{ "hex.view.bookmarks.address", "0x{0:X} : 0x{1:X} ({2} bytes)" },
{ "hex.view.bookmarks.button.jump", "Springen" },
@@ -96,6 +102,7 @@ namespace hex::plugin::builtin {
{ "hex.view.data_inspector.name", "Dateninspektor" },
{ "hex.view.data_inspector.table.name", "Name" },
{ "hex.view.data_inspector.table.value", "Wert" },
{ "hex.view.data_inspector.no_data", "Keine bytes angewählt"},
{ "hex.view.data_processor.name", "Datenprozessor" },
{ "hex.view.data_processor.menu.remove_selection", "Auswahl entfernen" },
@@ -178,6 +185,7 @@ namespace hex::plugin::builtin {
{ "hex.view.hexeditor.menu.file.save", "Speichern" },
{ "hex.view.hexeditor.menu.file.save_as", "Speichern unter..." },
{ "hex.view.hexeditor.menu.file.close", "Schliessen" },
{ "hex.view.hexeditor.menu.file.quit", "ImHex Beenden" },
{ "hex.view.hexeditor.menu.file.open_project", "Projekt öffnen..." },
{ "hex.view.hexeditor.menu.file.save_project", "Projekt speichern..." },
{ "hex.view.hexeditor.menu.file.load_encoding_file", "Custom encoding laden..." },
@@ -314,7 +322,9 @@ namespace hex::plugin::builtin {
{ "hex.view.store.tab.libraries", "Libraries" },
{ "hex.view.store.tab.magics", "Magic Files" },
{ "hex.view.store.tab.constants", "Konstanten" },
{ "hex.view.store.tab.yara", "Yara Rules" },
{ "hex.view.store.loading", "Store inhalt wird geladen..." },
{ "hex.view.diff.name", "Diffing" },
/* Builtin plugin features */
@@ -575,13 +585,56 @@ namespace hex::plugin::builtin {
{ "hex.builtin.tools.wiki_explain.search", "Suchen" },
{ "hex.builtin.tools.wiki_explain.results", "Resultate" },
{ "hex.builtin.tools.wiki_explain.invalid_response", "Ungültige Antwort von Wikipedia!" },
{ "hex.builtin.tools.file_tools", "File Tools" },
{ "hex.builtin.tools.file_tools.shredder", "Schredder" },
{ "hex.builtin.tools.file_tools.shredder.warning", "Dieses Tool zerstört eine Datei UNWIEDERRUFLICH. Mit Vorsicht verwenden" },
{ "hex.builtin.tools.file_tools.shredder.input", "Datei zum schreddern" },
{ "hex.builtin.tools.file_tools.shredder.picker", "Öffne Datei zum schreddern" },
{ "hex.builtin.tools.file_tools.shredder.fast", "Schneller Modus" },
{ "hex.builtin.tools.file_tools.shredder.shredding", "Schreddert..." },
{ "hex.builtin.tools.file_tools.shredder.shred", "Schreddern" },
{ "hex.builtin.tools.file_tools.shredder.error.open", "Öffnen der ausgewählten Datei fehlgeschlagen" },
{ "hex.builtin.tools.file_tools.shredder.success", "Datei erfolgreich geschreddert!" },
{ "hex.builtin.tools.file_tools.splitter", "Splitter" },
{ "hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy", "\" Floppy disk (1200KiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy", "\" Floppy disk (1400KiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.zip100", "Zip 100 Disk (100MiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.zip200", "Zip 200 Disk (200MiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom650", "CD-ROM (650MiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom700", "CD-ROM (700MiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.fat32", "FAT32 (4GiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.custom", "Benutzerdefiniert" },
{ "hex.builtin.tools.file_tools.splitter.input", "Zu splittende Datei " },
{ "hex.builtin.tools.file_tools.splitter.picker.input", "Zu splittende Datei öffnen" },
{ "hex.builtin.tools.file_tools.splitter.output", "Ziel Pfad" },
{ "hex.builtin.tools.file_tools.splitter.picker.output", "Ziel Pfad setzen" },
{ "hex.builtin.tools.file_tools.splitter.splitting", "Splittet..." },
{ "hex.builtin.tools.file_tools.splitter.split", "Splitten" },
{ "hex.builtin.tools.file_tools.splitter.error.open", "Öffnen der ausgewählten Datei fehlgeschlagen" },
{ "hex.builtin.tools.file_tools.splitter.error.size", "Datei ist kleiner als Zielgrösse" },
{ "hex.builtin.tools.file_tools.splitter.error.create", "Erstellen der Teildatei {0} fehlgeschlagen" },
{ "hex.builtin.tools.file_tools.splitter.success", "Datei erfolgreich gesplittet!" },
{ "hex.builtin.tools.file_tools.combiner", "Kombinierer" },
{ "hex.builtin.tools.file_tools.combiner.add", "Hinzufügen..." },
{ "hex.builtin.tools.file_tools.combiner.add.picker", "Datei hinzufügen" },
{ "hex.builtin.tools.file_tools.combiner.delete", "Entfernen" },
{ "hex.builtin.tools.file_tools.combiner.clear", "Alle entfernen" },
{ "hex.builtin.tools.file_tools.combiner.output", "Zieldatei " },
{ "hex.builtin.tools.file_tools.combiner.output.picker", "Ziel Pfad setzen" },
{ "hex.builtin.tools.file_tools.combiner.combining", "Kombiniert..." },
{ "hex.builtin.tools.file_tools.combiner.combine", "Kombinieren" },
{ "hex.builtin.tools.file_tools.combiner.error.open_output", "Erstellen der Zieldatei fehlgeschlagen" },
{ "hex.builtin.tools.file_tools.combiner.open_input", "Öffnen der Inputdatei {0} fehlgeschlagen" },
{ "hex.builtin.tools.file_tools.combiner.success", "Dateien erfolgreich kombiniert!" },
{ "hex.builtin.setting.imhex", "ImHex" },
{ "hex.builtin.setting.imhex.recent_files", "Kürzlich geöffnete Dateien" },
{ "hex.builtin.setting.general", "Allgemein" },
{ "hex.builtin.setting.general.show_tips", "Tipps beim start anzeigen" },
{ "hex.builtin.setting.general.auto_load_patterns", "Unterstützte Pattern automatisch laden" },
{ "hex.builtin.setting.interface", "Aussehen" },
{ "hex.builtin.setting.interface.color", "Farbthema" },
{ "hex.builtin.setting.interface.color.system", "System" },
{ "hex.builtin.setting.interface.color.dark", "Dunkel" },
{ "hex.builtin.setting.interface.color.light", "Hell" },
{ "hex.builtin.setting.interface.color.classic", "Klassisch" },
@@ -594,6 +647,14 @@ namespace hex::plugin::builtin {
{ "hex.builtin.setting.interface.language", "Sprache" },
{ "hex.builtin.setting.interface.fps", "FPS Limite" },
{ "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.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.provider.file.path", "Dateipfad" },
{ "hex.builtin.provider.file.size", "Größe" },

View File

@@ -44,7 +44,7 @@ namespace hex::plugin::builtin {
{ "hex.welcome.learn.latest.desc", "Read ImHex's current changelog" },
{ "hex.welcome.learn.latest.link", "https://github.com/WerWolv/ImHex/releases/latest" },
{ "hex.welcome.learn.pattern.title", "Pattern Language Documentation" },
{ "hex.welcome.learn.pattern.desc", "Learn how to write ImHex pattern_language with our extensive documentation" },
{ "hex.welcome.learn.pattern.desc", "Learn how to write ImHex patterns with our extensive documentation" },
{ "hex.welcome.learn.pattern.link", "https://imhex.werwolv.net/docs/pattern_language/pattern_language.html" },
{ "hex.welcome.learn.plugins.title", "Plugins API" },
{ "hex.welcome.learn.plugins.desc", "Extend ImHex with additional features using plugins" },
@@ -63,6 +63,7 @@ namespace hex::plugin::builtin {
{ "hex.common.decimal", "Decimal" },
{ "hex.common.hexadecimal", "Hexadecimal" },
{ "hex.common.octal", "Octal" },
{ "hex.common.info", "Information" },
{ "hex.common.error", "Error" },
{ "hex.common.fatal", "Fatal Error" },
{ "hex.common.address", "Address" },
@@ -79,10 +80,15 @@ namespace hex::plugin::builtin {
{ "hex.common.dont_show_again", "Don't show again" },
{ "hex.common.link", "Link" },
{ "hex.common.file", "File" },
{ "hex.common.open", "Open" },
{ "hex.common.browse", "Browse..." },
{ "hex.message.yara_rule_added", "Yara rule added!" },
{ "hex.message.magic_db_added", "Magic database added!" },
{ "hex.view.bookmarks.name", "Bookmarks" },
{ "hex.view.bookmarks.default_title", "Bookmark [0x{0:X} - 0x{1:X}]" },
{ "hex.view.bookmarks.no_bookmarks", "No bookmarks created yet. Add one with Edit -> Add Bookmark" },
{ "hex.view.bookmarks.no_bookmarks", "No bookmarks created yet. Add one with Edit -> Create Bookmark" },
{ "hex.view.bookmarks.title.info", "Information" },
{ "hex.view.bookmarks.address", "0x{0:X} : 0x{1:X} ({2} bytes)" },
{ "hex.view.bookmarks.button.jump", "Jump to" },
@@ -96,6 +102,7 @@ namespace hex::plugin::builtin {
{ "hex.view.data_inspector.name", "Data Inspector" },
{ "hex.view.data_inspector.table.name", "Name" },
{ "hex.view.data_inspector.table.value", "Value" },
{ "hex.view.data_inspector.no_data", "No bytes selected"},
{ "hex.view.data_processor.name", "Data Processor" },
{ "hex.view.data_processor.menu.remove_selection", "Remove Selected" },
@@ -178,6 +185,7 @@ namespace hex::plugin::builtin {
{ "hex.view.hexeditor.menu.file.save", "Save" },
{ "hex.view.hexeditor.menu.file.save_as", "Save As..." },
{ "hex.view.hexeditor.menu.file.close", "Close" },
{ "hex.view.hexeditor.menu.file.quit", "Quit ImHex" },
{ "hex.view.hexeditor.menu.file.open_project", "Open Project..." },
{ "hex.view.hexeditor.menu.file.save_project", "Save Project..." },
{ "hex.view.hexeditor.menu.file.load_encoding_file", "Load custom encoding..." },
@@ -314,7 +322,9 @@ namespace hex::plugin::builtin {
{ "hex.view.store.tab.libraries", "Libraries" },
{ "hex.view.store.tab.magics", "Magic Files" },
{ "hex.view.store.tab.constants", "Constants" },
{ "hex.view.store.tab.yara", "Yara Rules" },
{ "hex.view.store.loading", "Loading store content..." },
{ "hex.view.diff.name", "Diffing" },
/* Builtin plugin features */
@@ -576,13 +586,56 @@ namespace hex::plugin::builtin {
{ "hex.builtin.tools.wiki_explain.search", "Search" },
{ "hex.builtin.tools.wiki_explain.results", "Results" },
{ "hex.builtin.tools.wiki_explain.invalid_response", "Invalid response from Wikipedia!" },
{ "hex.builtin.tools.file_tools", "File Tools" },
{ "hex.builtin.tools.file_tools.shredder", "Shredder" },
{ "hex.builtin.tools.file_tools.shredder.warning", "This tool IRRECOVERABLY destroys a file. Use with caution" },
{ "hex.builtin.tools.file_tools.shredder.input", "File to shred " },
{ "hex.builtin.tools.file_tools.shredder.picker", "Open File to Shred" },
{ "hex.builtin.tools.file_tools.shredder.fast", "Fast Mode" },
{ "hex.builtin.tools.file_tools.shredder.shredding", "Shredding..." },
{ "hex.builtin.tools.file_tools.shredder.shred", "Shred" },
{ "hex.builtin.tools.file_tools.shredder.error.open", "Failed to open selected file!" },
{ "hex.builtin.tools.file_tools.shredder.success", "Shredded successfully!" },
{ "hex.builtin.tools.file_tools.splitter", "Splitter" },
{ "hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy", "\" Floppy disk (1200KiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy", "\" Floppy disk (1400KiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.zip100", "Zip 100 Disk (100MiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.zip200", "Zip 200 Disk (200MiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom650", "CD-ROM (650MiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom700", "CD-ROM (700MiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.fat32", "FAT32 (4GiB)" },
{ "hex.builtin.tools.file_tools.splitter.sizes.custom", "Custom" },
{ "hex.builtin.tools.file_tools.splitter.input", "File to split " },
{ "hex.builtin.tools.file_tools.splitter.picker.input", "Open File to split" },
{ "hex.builtin.tools.file_tools.splitter.output", "Output path " },
{ "hex.builtin.tools.file_tools.splitter.picker.output", "Set base path" },
{ "hex.builtin.tools.file_tools.splitter.picker.splitting", "Splitting..." },
{ "hex.builtin.tools.file_tools.splitter.picker.split", "Split" },
{ "hex.builtin.tools.file_tools.splitter.picker.error.open", "Failed to open selected file!" },
{ "hex.builtin.tools.file_tools.splitter.picker.error.size", "File is smaller than part size" },
{ "hex.builtin.tools.file_tools.splitter.picker.error.create", "Failed to create part file {0}" },
{ "hex.builtin.tools.file_tools.splitter.picker.success", "File split successfully!" },
{ "hex.builtin.tools.file_tools.combiner", "Combiner" },
{ "hex.builtin.tools.file_tools.combiner.add", "Add..." },
{ "hex.builtin.tools.file_tools.combiner.add.picker", "Add file" },
{ "hex.builtin.tools.file_tools.combiner.delete", "Delete" },
{ "hex.builtin.tools.file_tools.combiner.clear", "Clear" },
{ "hex.builtin.tools.file_tools.combiner.output", "Output file " },
{ "hex.builtin.tools.file_tools.combiner.output.picker", "Set output base path" },
{ "hex.builtin.tools.file_tools.combiner.combining", "Combining..." },
{ "hex.builtin.tools.file_tools.combiner.combine", "Combine" },
{ "hex.builtin.tools.file_tools.combiner.error.open_output", "Failed to create output file" },
{ "hex.builtin.tools.file_tools.combiner.open_input", "Failed to open input file {0}" },
{ "hex.builtin.tools.file_tools.combiner.success", "Files combined successfully!" },
{ "hex.builtin.setting.imhex", "ImHex" },
{ "hex.builtin.setting.imhex.recent_files", "Recent Files" },
{ "hex.builtin.setting.general", "General" },
{ "hex.builtin.setting.general.show_tips", "Show tips on startup" },
{ "hex.builtin.setting.general.auto_load_patterns", "Auto-load supported pattern" },
{ "hex.builtin.setting.interface", "Interface" },
{ "hex.builtin.setting.interface.color", "Color theme" },
{ "hex.builtin.setting.interface.color.system", "System" },
{ "hex.builtin.setting.interface.color.dark", "Dark" },
{ "hex.builtin.setting.interface.color.light", "Light" },
{ "hex.builtin.setting.interface.color.classic", "Classic" },
@@ -595,6 +648,14 @@ namespace hex::plugin::builtin {
{ "hex.builtin.setting.interface.language", "Language" },
{ "hex.builtin.setting.interface.fps", "FPS Limit" },
{ "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.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.provider.file.path", "File path" },
{ "hex.builtin.provider.file.size", "Size" },

View File

@@ -62,6 +62,7 @@ namespace hex::plugin::builtin {
{ "hex.common.decimal", "Decimale" },
{ "hex.common.hexadecimal", "Esadecimale" },
{ "hex.common.octal", "Ottale" },
//{ "hex.common.info", "Information" },
{ "hex.common.error", "Errore" },
{ "hex.common.fatal", "Errore Fatale" },
{ "hex.common.address", "Indirizzo" },
@@ -78,10 +79,15 @@ namespace hex::plugin::builtin {
{ "hex.common.dont_show_again", "Non mostrare di nuovo" },
{ "hex.common.link", "Link" },
{ "hex.common.file", "File" },
//{ "hex.common.open", "Open" },
//{ "hex.common.browse", "Browse..." },
//{ "hex.message.yara_rule_added", "Yara rule added!" },
//{ "hex.message.magic_db_added", "Magic database added!" },
{ "hex.view.bookmarks.name", "Segnalibri" },
{ "hex.view.bookmarks.default_title", "Segnalibro [0x{0:X} - 0x{1:X}]" },
{ "hex.view.bookmarks.no_bookmarks", "Non è stato creato alcun segnalibro. Aggiungine uno andando su Modifica -> Aggiungi Segnalibro" },
{ "hex.view.bookmarks.no_bookmarks", "Non è stato creato alcun segnalibro. Aggiungine uno andando su Modifica -> Crea Segnalibro" },
{ "hex.view.bookmarks.title.info", "Informazioni" },
{ "hex.view.bookmarks.address", "0x{0:X} : 0x{1:X} ({2} bytes)" },
{ "hex.view.bookmarks.button.jump", "Vai a" },
@@ -95,6 +101,8 @@ namespace hex::plugin::builtin {
{ "hex.view.data_inspector.name", "Ispezione Dati" },
{ "hex.view.data_inspector.table.name", "Nome" },
{ "hex.view.data_inspector.table.value", "Valore" },
//{ "hex.view.data_inspector.no_data", "No bytes selected"},
{ "hex.view.data_processor.name", "Processa Dati" },
{ "hex.view.data_processor.menu.remove_selection", "Rimuovi i selezionati" },
@@ -177,6 +185,7 @@ namespace hex::plugin::builtin {
{ "hex.view.hexeditor.menu.file.save", "Salva" },
{ "hex.view.hexeditor.menu.file.save_as", "Salva come..." },
{ "hex.view.hexeditor.menu.file.close", "Chiudi" },
{ "hex.view.hexeditor.menu.file.quit", "Uscita ImHex" },
{ "hex.view.hexeditor.menu.file.open_project", "Apri un Progetto..." },
{ "hex.view.hexeditor.menu.file.save_project", "Salva Progetto..." },
{ "hex.view.hexeditor.menu.file.load_encoding_file", "Carica una codifica personalizzata..." },
@@ -301,19 +310,20 @@ namespace hex::plugin::builtin {
{ "hex.view.constants.row.desc", "Descrizione" },
{ "hex.view.constants.row.value", "Valore" },
{ "hex.view.store.name", "Content Store" },
{ "hex.view.store.desc", "Scarica nuovi contenuti dal database online di ImHex" },
{ "hex.view.store.reload", "Ricarica" },
{ "hex.view.store.row.name", "Nome" },
{ "hex.view.store.row.description", "Descrizione" },
{ "hex.view.store.download", "Download" },
{ "hex.view.store.update", "Aggiorna" },
{ "hex.view.store.remove", "Rimuovi" },
{ "hex.view.store.tab.patterns", "Modelli" },
{ "hex.view.store.tab.libraries", "Librerie" },
{ "hex.view.store.tab.magics", "File Magici" },
{ "hex.view.store.tab.constants", "Costanti" },
{ "hex.view.store.loading", "Caricamento del content store..." },
{ "hex.view.store.desc", "Scarica nuovi contenuti dal database online di ImHex" },
{ "hex.view.store.reload", "Ricarica" },
{ "hex.view.store.row.name", "Nome" },
{ "hex.view.store.row.description", "Descrizione" },
{ "hex.view.store.download", "Download" },
{ "hex.view.store.update", "Aggiorna" },
{ "hex.view.store.remove", "Rimuovi" },
{ "hex.view.store.tab.patterns", "Modelli" },
{ "hex.view.store.tab.libraries", "Librerie" },
{ "hex.view.store.tab.magics", "File Magici" },
{ "hex.view.store.tab.constants", "Costanti" },
{ "hex.view.store.tab.yara", "Regole di Yara" },
{ "hex.view.store.loading", "Caricamento del content store..." },
//{ "hex.view.diff.name", "Diffing" },
/* Builtin plugin features */
@@ -574,13 +584,56 @@ namespace hex::plugin::builtin {
{ "hex.builtin.tools.wiki_explain.search", "Cerca" },
{ "hex.builtin.tools.wiki_explain.results", "Risultati" },
{ "hex.builtin.tools.wiki_explain.invalid_response", "Risposta non valida da Wikipedia!" },
//{ "hex.builtin.tools.file_tools", "File Tools" },
//{ "hex.builtin.tools.file_tools.shredder", "Shredder" },
//{ "hex.builtin.tools.file_tools.shredder.warning", "This tool IRRECOVERABLY destroys a file. Use with caution" },
//{ "hex.builtin.tools.file_tools.shredder.input", "File to shred " },
//{ "hex.builtin.tools.file_tools.shredder.picker", "Open File to Shred" },
//{ "hex.builtin.tools.file_tools.shredder.fast", "Fast Mode" },
//{ "hex.builtin.tools.file_tools.shredder.shredding", "Shredding..." },
//{ "hex.builtin.tools.file_tools.shredder.shred", "Shred" },
//{ "hex.builtin.tools.file_tools.shredder.error.open", "Failed to open selected file!" },
//{ "hex.builtin.tools.file_tools.shredder.success", "Shredded successfully!" },
//{ "hex.builtin.tools.file_tools.splitter", "Splitter" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy", "5¼\" Floppy disk (1200KiB)" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy", "3½\" Floppy disk (1400KiB)" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.zip100", "Zip 100 Disk (100MiB)" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.zip200", "Zip 200 Disk (200MiB)" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom650", "CD-ROM (650MiB)" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom700", "CD-ROM (700MiB)" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.fat32", "FAT32 (4GiB)" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.custom", "Custom" },
//{ "hex.builtin.tools.file_tools.splitter.input", "File to split " },
//{ "hex.builtin.tools.file_tools.splitter.picker.input", "Open File to split" },
//{ "hex.builtin.tools.file_tools.splitter.output", "Output path " },
//{ "hex.builtin.tools.file_tools.splitter.picker.output", "Set base path" },
//{ "hex.builtin.tools.file_tools.splitter.picker.splitting", "Splitting..." },
//{ "hex.builtin.tools.file_tools.splitter.picker.split", "Split" },
//{ "hex.builtin.tools.file_tools.splitter.picker.error.open", "Failed to open selected file!" },
//{ "hex.builtin.tools.file_tools.splitter.picker.error.size", "File is smaller than part size" },
//{ "hex.builtin.tools.file_tools.splitter.picker.error.create", "Failed to create part file {0}" },
//{ "hex.builtin.tools.file_tools.splitter.picker.success", "File split successfully!" },
//{ "hex.builtin.tools.file_tools.combiner", "Combiner" },
//{ "hex.builtin.tools.file_tools.combiner.add", "Add..." },
//{ "hex.builtin.tools.file_tools.combiner.add.picker", "Add file" },
//{ "hex.builtin.tools.file_tools.combiner.delete", "Delete" },
//{ "hex.builtin.tools.file_tools.combiner.clear", "Clear" },
//{ "hex.builtin.tools.file_tools.combiner.output", "Output file " },
//{ "hex.builtin.tools.file_tools.combiner.output.picker", "Set output base path" },
//{ "hex.builtin.tools.file_tools.combiner.combining", "Combining..." },
//{ "hex.builtin.tools.file_tools.combiner.combine", "Combine" },
//{ "hex.builtin.tools.file_tools.combiner.error.open_output", "Failed to create output file" },
//{ "hex.builtin.tools.file_tools.combiner.open_input", "Failed to open input file {0}" },
//{ "hex.builtin.tools.file_tools.combiner.success", "Files combined successfully!" },
{ "hex.builtin.setting.imhex", "ImHex" },
{ "hex.builtin.setting.imhex.recent_files", "File recenti" },
{ "hex.builtin.setting.general", "Generali" },
{ "hex.builtin.setting.general.show_tips", "Mostra consigli all'avvio" },
//{ "hex.builtin.setting.general.auto_load_patterns", "Auto-load supported pattern" },
{ "hex.builtin.setting.interface", "Interfaccia" },
{ "hex.builtin.setting.interface.color", "Colore del Tema" },
{ "hex.builtin.setting.interface.color.system", "Sistema" },
{ "hex.builtin.setting.interface.color.dark", "Scuro" },
{ "hex.builtin.setting.interface.color.light", "Chiaro" },
{ "hex.builtin.setting.interface.color.classic", "Classico" },
@@ -591,8 +644,16 @@ namespace hex::plugin::builtin {
{ "hex.builtin.setting.interface.scaling.x1_0", "x1.0" },
{ "hex.builtin.setting.interface.scaling.x1_5", "x1.5" },
{ "hex.builtin.setting.interface.scaling.x2_0", "x2.0" },
{ "hex.builtin.setting.interface.fps", "Limite FPS" },
{ "hex.builtin.setting.interface.highlight_alpha", "Evidenziazione dell'opacità" },
{ "hex.builtin.setting.interface.fps", "Limite FPS" },
{ "hex.builtin.setting.interface.highlight_alpha", "Evidenziazione dell'opacità" },
//{ "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.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.provider.file.path", "Percorso del File" },
{ "hex.builtin.provider.file.size", "Dimensione" },

View File

@@ -0,0 +1,668 @@
#include <hex/api/content_registry.hpp>
#include <hex/helpers/lang.hpp>
namespace hex::plugin::builtin {
void registerLanguageZhCN() {
ContentRegistry::Language::registerLanguage("Chinese (Simplified)", "zh-CN");
ContentRegistry::Language::addLocalizations("zh-CN", {
/* ImHex default functionality */
{ "hex.menu.file", "文件" },
{ "hex.menu.edit", "编辑" },
{ "hex.menu.view", "视图" },
{ "hex.menu.view.fps", "显示FPS" },
{ "hex.menu.view.demo", "显示ImGui演示" },
{ "hex.menu.help", "帮助" },
{ "hex.menu.feedback", "反馈" },
{ "hex.menu.debug_build", "调试构建"},
{ "hex.welcome.header.main", "欢迎来到ImHex" },
{ "hex.welcome.header.start", "开始" },
{ "hex.welcome.start.create_file", "创建新文件" },
{ "hex.welcome.start.open_file", "打开文件" },
{ "hex.welcome.start.open_project", "打开工程" },
{ "hex.welcome.start.recent", "最近文件" },
{ "hex.welcome.header.help", "帮助" },
{ "hex.welcome.help.repo", "GitHub仓库" },
{ "hex.welcome.help.repo.link", "https://github.com/WerWolv/ImHex" },
{ "hex.welcome.help.gethelp", "获得帮助" },
{ "hex.welcome.help.gethelp.link", "https://github.com/WerWolv/ImHex/discussions/categories/get-help" },
{ "hex.welcome.header.plugins", "已加载插件" },
{ "hex.welcome.plugins.plugin", "插件" },
{ "hex.welcome.plugins.author", "作者" },
{ "hex.welcome.plugins.desc", "描述" },
{ "hex.welcome.header.customize", "自定义" },
{ "hex.welcome.customize.settings.title", "设置" },
{ "hex.welcome.customize.settings.desc", "更改ImHex的设置" },
{ "hex.welcome.header.update", "更新" },
{ "hex.welcome.update.title", "新的更新可用!" },
{ "hex.welcome.update.desc", "ImHex {0} 已发布!在这里下载。" },
{ "hex.welcome.update.link", "https://github.com/WerWolv/ImHex/releases/latest" },
{ "hex.welcome.header.learn", "学习" },
{ "hex.welcome.learn.latest.title", "最新版本" },
{ "hex.welcome.learn.latest.desc", "阅读ImHex最新版本的更改日志" },
{ "hex.welcome.learn.latest.link", "https://github.com/WerWolv/ImHex/releases/latest" },
{ "hex.welcome.learn.pattern.title", "模式文档" },
{ "hex.welcome.learn.pattern.desc", "如何基于我们完善的文档编写ImHex模式" },
{ "hex.welcome.learn.pattern.link", "https://imhex.werwolv.net/docs/pattern_language/pattern_language.html" },
{ "hex.welcome.learn.plugins.title", "插件API" },
{ "hex.welcome.learn.plugins.desc", "通过插件扩展ImHex获得更多功能" },
{ "hex.welcome.learn.plugins.link", "https://github.com/WerWolv/ImHex/wiki/Plugins-Development-Guide" },
{ "hex.welcome.header.various", "杂项" },
{ "hex.welcome.tip_of_the_day", "小提示" },
{ "hex.safety_backup.title", "恢复丢失数据" },
{ "hex.safety_backup.desc", "ImHex上次崩溃了\n你想恢复你之前的工作吗?"},
{ "hex.safety_backup.restore", "恢复" },
{ "hex.safety_backup.delete", "删除" },
{ "hex.common.little_endian", "小端序" },
{ "hex.common.big_endian", "大端序" },
{ "hex.common.decimal", "十进制" },
{ "hex.common.hexadecimal", "十六进制" },
{ "hex.common.octal", "八进制" },
//{ "hex.common.info", "Information" },
{ "hex.common.error", "错误" },
{ "hex.common.fatal", "致命错误" },
{ "hex.common.address", "地址" },
{ "hex.common.size", "大小" },
{ "hex.common.region", "区域" },
{ "hex.common.match_selection", "匹配选择" },
{ "hex.common.yes", "" },
{ "hex.common.no", "" },
{ "hex.common.okay", "好的" },
{ "hex.common.load", "加载" },
{ "hex.common.cancel", "取消" },
{ "hex.common.set", "设置" },
{ "hex.common.close", "关闭文件" },
{ "hex.common.dont_show_again", "不要再次显示" },
{ "hex.common.link", "链接" },
{ "hex.common.file", "文件" },
//{ "hex.common.open", "Open" },
//{ "hex.common.browse", "Browse..." },
//{ "hex.message.yara_rule_added", "Yara rule added!" },
//{ "hex.message.magic_db_added", "Magic database added!" },
{ "hex.view.bookmarks.name", "书签" },
{ "hex.view.bookmarks.default_title", "书签 [0x{0:X} - 0x{1:X}]" },
{ "hex.view.bookmarks.no_bookmarks", "空空如也。通过 编辑->添加书签" },
{ "hex.view.bookmarks.title.info", "信息" },
{ "hex.view.bookmarks.address", "0x{0:X} : 0x{1:X} ({2} 字节)" },
{ "hex.view.bookmarks.button.jump", "转到" },
{ "hex.view.bookmarks.button.remove", "移除" },
{ "hex.view.bookmarks.header.name", "名称" },
{ "hex.view.bookmarks.header.color", "颜色" },
{ "hex.view.bookmarks.header.comment", "注释" },
{ "hex.view.command_palette.name", "命令栏" },
{ "hex.view.data_inspector.name", "数据分析器" },
{ "hex.view.data_inspector.table.name", "名称" },
{ "hex.view.data_inspector.table.value", "" },
//{ "hex.view.data_inspector.no_data", "No bytes selected"},
{ "hex.view.data_processor.name", "数据处理器" },
{ "hex.view.data_processor.menu.remove_selection", "移除已选" },
{ "hex.view.data_processor.menu.remove_node", "移除节点" },
{ "hex.view.data_processor.menu.remove_link", "移除链接" },
{ "hex.view.disassembler.name", "反汇编" },
{ "hex.view.disassembler.position", "位置" },
{ "hex.view.disassembler.base", "基地址" },
{ "hex.view.disassembler.region", "代码范围" },
{ "hex.view.disassembler.settings.header", "设置" },
{ "hex.view.disassembler.arch", "架构" },
{ "hex.view.disassembler.arm.arm", "ARM" },
{ "hex.view.disassembler.arm.thumb", "Thumb" },
{ "hex.view.disassembler.arm.default", "默认" },
{ "hex.view.disassembler.arm.cortex_m", "Cortex-M" },
{ "hex.view.disassembler.arm.armv8", "ARMv8" },
{ "hex.view.disassembler.mips.mips32", "MIPS32" },
{ "hex.view.disassembler.mips.mips64", "MIPS64" },
{ "hex.view.disassembler.mips.mips32R6", "MIPS32R6" },
{ "hex.view.disassembler.mips.micro", "Micro MIPS" },
{ "hex.view.disassembler.x86.16bit", "16位" },
{ "hex.view.disassembler.x86.32bit", "32位" },
{ "hex.view.disassembler.x86.64bit", "64位" },
{ "hex.view.disassembler.ppc.32bit", "32位" },
{ "hex.view.disassembler.ppc.64bit", "64位" },
{ "hex.view.disassembler.sparc.v9", "Sparc V9" },
{ "hex.view.disassembler.disassemble", "反汇编" },
{ "hex.view.disassembler.disassembling", "反汇编中..." },
{ "hex.view.disassembler.disassembly.title", "反汇编" },
{ "hex.view.disassembler.disassembly.address", "地址" },
{ "hex.view.disassembler.disassembly.offset", "偏移" },
{ "hex.view.disassembler.disassembly.bytes", "字节" },
{ "hex.view.hashes.name", "哈希" },
{ "hex.view.hashes.settings", "设置" },
{ "hex.view.hashes.function", "哈希函数" },
{ "hex.view.hashes.iv", "初始值" },
{ "hex.view.hashes.poly", "多项式" },
{ "hex.view.hashes.result", "结果" },
{ "hex.view.help.name", "帮助" },
{ "hex.view.help.about.name", "关于" },
{ "hex.view.help.about.translator", "由xtexChooser翻译" },
{ "hex.view.help.about.source", "源代码位于GitHub:" },
{ "hex.view.help.about.donations", "赞助" },
{ "hex.view.help.about.thanks", "如果你喜欢我的工作,请赞助以帮助此项目继续前进。非常感谢 <3" },
{ "hex.view.help.about.libs", "使用的库" },
{ "hex.view.help.about.paths", "ImHex目录" },
{ "hex.view.help.documentation", "ImHex文档" },
{ "hex.view.help.pattern_cheat_sheet", "模式语言帮助"},
{ "hex.view.help.calc_cheat_sheet", "计算器帮助" },
{ "hex.view.hexeditor.name", "Hex编辑器" },
{ "hex.view.hexeditor.create_file", "新建" },
{ "hex.view.hexeditor.open_file", "打开" },
{ "hex.view.hexeditor.open_project", "打开项目" },
{ "hex.view.hexeditor.save_project", "保存项目" },
{ "hex.view.hexeditor.save_data", "保存数据" },
{ "hex.view.hexeditor.open_base64", "打开Base64文件" },
{ "hex.view.hexeditor.load_enconding_file", "加载自定义编码定义文件" },
{ "hex.view.hexeditor.page", "页 {0} / {1}" },
{ "hex.view.hexeditor.save_as", "另存为" },
{ "hex.view.hexeditor.exit_application.title", "退出?" },
{ "hex.view.hexeditor.exit_application.desc", "工程还有为保存的更改。\n确定要退出吗?" },
{ "hex.view.hexeditor.script.title", "通过加载器脚本加载文件" },
{ "hex.view.hexeditor.script.desc", "通过Python加载器脚本加载文件。" },
{ "hex.view.hexeditor.script.script", "脚本" },
{ "hex.view.hexeditor.script.script.title", "加载器脚本:打开脚本" },
{ "hex.view.hexeditor.script.file", "文件" },
{ "hex.view.hexeditor.script.file.title", "加载器脚本:打开文件" },
{ "hex.view.hexeditor.menu.file.open_file", "打开文件..." },
{ "hex.view.hexeditor.menu.file.open_recent", "打开最近"},
{ "hex.view.hexeditor.menu.file.save", "保存" },
{ "hex.view.hexeditor.menu.file.save_as", "另存为..." },
{ "hex.view.hexeditor.menu.file.close", "关闭" },
{ "hex.view.hexeditor.menu.file.quit", "退出ImHex" },
{ "hex.view.hexeditor.menu.file.open_project", "打开项目..." },
{ "hex.view.hexeditor.menu.file.save_project", "保存项目..." },
{ "hex.view.hexeditor.menu.file.load_encoding_file", "加载自定义编码..." },
{ "hex.view.hexeditor.menu.file.import", "导入..." },
{ "hex.view.hexeditor.menu.file.import.base64", "Base64文件" },
{ "hex.view.hexeditor.base64.import_error", "文件不是有效的Base64格式" },
{ "hex.view.hexeditor.file_open_error", "打开文件失败!" },
{ "hex.view.hexeditor.menu.file.import.ips", "IPS补丁" },
{ "hex.view.hexeditor.menu.file.import.ips32", "IPS32补丁" },
{ "hex.view.hexeditor.menu.file.import.script", "带有加载器脚本的文件" },
{ "hex.view.hexeditor.menu.file.export", "导出..." },
{ "hex.view.hexeditor.menu.file.export.title", "导出文件" },
{ "hex.view.hexeditor.menu.file.export.ips", "IPS补丁" },
{ "hex.view.hexeditor.menu.file.export.ips32", "IPS32补丁" },
{ "hex.view.hexeditor.menu.file.search", "搜索" },
{ "hex.view.hexeditor.search.string", "字符串" },
{ "hex.view.hexeditor.search.hex", "Hex" },
{ "hex.view.hexeditor.search.find", "查找" },
{ "hex.view.hexeditor.search.find_next", "查找下一个" },
{ "hex.view.hexeditor.search.find_prev", "查找上一个" },
{ "hex.view.hexeditor.menu.file.goto", "转到" },
{ "hex.view.hexeditor.goto.offset.absolute", "绝对" },
{ "hex.view.hexeditor.goto.offset.current", "当前" },
{ "hex.view.hexeditor.goto.offset.begin", "起始" },
{ "hex.view.hexeditor.goto.offset.end", "末尾" },
{ "hex.view.hexeditor.error.read_only", "无法获得写权限,文件以只读方式打开。" },
{ "hex.view.hexeditor.error.open", "打开文件失败!" },
{ "hex.view.hexeditor.error.create", "创建新文件失败!" },
{ "hex.view.hexeditor.menu.edit.undo", "撤销" },
{ "hex.view.hexeditor.menu.edit.redo", "重做" },
{ "hex.view.hexeditor.menu.edit.copy", "复制" },
{ "hex.view.hexeditor.menu.edit.copy_as", "复制为..." },
{ "hex.view.hexeditor.copy.hex", "字符串" },
{ "hex.view.hexeditor.copy.c", "C数组" },
{ "hex.view.hexeditor.copy.cpp", "C++数组" },
{ "hex.view.hexeditor.copy.csharp", "C#数组" },
{ "hex.view.hexeditor.copy.rust", "Rust数组" },
{ "hex.view.hexeditor.copy.python", "Python数组" },
{ "hex.view.hexeditor.copy.java", "Java数组" },
{ "hex.view.hexeditor.copy.js", "JavaScript数组" },
{ "hex.view.hexeditor.copy.ascii", "ASCII Art" },
{ "hex.view.hexeditor.copy.html", "HTML" },
{ "hex.view.hexeditor.menu.edit.paste", "粘贴" },
{ "hex.view.hexeditor.menu.edit.select_all", "全选" },
{ "hex.view.hexeditor.menu.edit.bookmark", "添加书签" },
{ "hex.view.hexeditor.menu.edit.set_base", "设置基地址" },
{ "hex.view.hexeditor.menu.edit.resize", "修改大小" },
{ "hex.view.information.name", "数据信息" },
{ "hex.view.information.control", "控制" },
{ "hex.view.information.analyze", "分析" },
{ "hex.view.information.analyzing", "分析中..." },
{ "hex.view.information.region", "已分析区域" },
{ "hex.view.information.magic", "魔术信息" },
{ "hex.view.information.description", "描述:" },
{ "hex.view.information.mime", "MIME类型:" },
{ "hex.view.information.info_analysis", "信息分析" },
{ "hex.view.information.distribution", "字节分布" },
{ "hex.view.information.entropy", "" },
{ "hex.view.information.block_size", "块大小" },
{ "hex.view.information.block_size.desc", "{0} 块 × {1} 字节" },
{ "hex.view.information.file_entropy", "文件熵" },
{ "hex.view.information.highest_entropy", "最高熵" },
{ "hex.view.information.encrypted", "此数据似乎经过了加密或压缩!" },
{ "hex.view.patches.name", "补丁" },
{ "hex.view.patches.offset", "偏移" },
{ "hex.view.patches.orig", "原始值" },
{ "hex.view.patches.patch", "修改值"},
{ "hex.view.patches.remove", "移除补丁" },
{ "hex.view.pattern.name", "模式编辑器" },
{ "hex.view.pattern.accept_pattern", "接受模式" },
{ "hex.view.pattern.accept_pattern.desc", "一个或多个模式与所找到的数据类型兼容" },
{ "hex.view.pattern.accept_pattern.pattern_language", "模式" },
{ "hex.view.pattern.accept_pattern.question", "是否应用找到的模式?" },
{ "hex.view.pattern.menu.file.load_pattern", "加载模式文件..." },
{ "hex.view.pattern.open_pattern", "打开模式" },
{ "hex.view.pattern.evaluating", "计算中..." },
{ "hex.view.pattern.auto", "自动计算" },
{ "hex.view.pattern_data.name", "模式数据" },
{ "hex.view.pattern_data.name", "名称" },
{ "hex.view.pattern_data.color", "颜色" },
{ "hex.view.pattern_data.offset", "偏移" },
{ "hex.view.pattern_data.size", "大小" },
{ "hex.view.pattern_data.type", "类型" },
{ "hex.view.pattern_data.value", "" },
{ "hex.view.settings.name", "设置" },
{ "hex.view.strings.name", "字符串" },
{ "hex.view.strings.copy", "复制字符串" },
{ "hex.view.strings.demangle", "还原" },
{ "hex.view.strings.min_length", "最小长度" },
{ "hex.view.strings.filter", "过滤" },
{ "hex.view.strings.extract", "提取" },
{ "hex.view.strings.searching", "搜索中..." },
{ "hex.view.strings.offset", "偏移" },
{ "hex.view.strings.size", "大小" },
{ "hex.view.strings.string", "字符串" },
{ "hex.view.strings.demangle.title", "还原名" },
{ "hex.view.strings.demangle.copy", "复制" },
{ "hex.view.tools.name", "工具" },
{ "hex.view.yara.name", "Yara规则" },
{ "hex.view.yara.header.rules", "规则" },
{ "hex.view.yara.reload", "重新加载" },
{ "hex.view.yara.match", "匹配规则" },
{ "hex.view.yara.matching", "匹配中..." },
{ "hex.view.yara.error", "Yara编译器错误: " },
{ "hex.view.yara.header.matches", "匹配" },
{ "hex.view.yara.matches.identifier", "标识符" },
{ "hex.view.yara.whole_data", "全文件匹配!" },
{ "hex.view.yara.no_rules", "没有找到YARA规则。请将规则放到ImHex的'yara'目录下。" },
{ "hex.view.constants.name", "常量" },
{ "hex.view.constants.row.category", "分类" },
{ "hex.view.constants.row.name", "名称" },
{ "hex.view.constants.row.desc", "描述" },
{ "hex.view.constants.row.value", "" },
{ "hex.view.store.name", "内容仓库" },
{ "hex.view.store.desc", "从ImHex在线数据库下载新内容" },
{ "hex.view.store.reload", "刷新" },
{ "hex.view.store.row.name", "名称" },
{ "hex.view.store.row.description", "描述" },
{ "hex.view.store.download", "下载" },
{ "hex.view.store.update", "更新" },
{ "hex.view.store.remove", "移除" },
{ "hex.view.store.tab.patterns", "模式" },
{ "hex.view.store.tab.libraries", "" },
{ "hex.view.store.tab.magics", "魔术数据库" },
{ "hex.view.store.tab.constants", "常量" },
{ "hex.view.store.tab.yara", "Yara规则" },
{ "hex.view.store.loading", "正在加载仓库内容..." },
//{ "hex.view.diff.name", "Diffing" },
/* Builtin plugin features */
{ "hex.builtin.command.calc.desc", "计算器" },
{ "hex.builtin.command.cmd.desc", "指令" },
{ "hex.builtin.command.cmd.result", "运行指令 '{0}'" },
{ "hex.builtin.command.web.desc", "网站解析" },
{ "hex.builtin.command.web.result", "导航到 '{0}'" },
// Use half angle for inspector names because displayable space
{ "hex.builtin.inspector.binary", "二进制(8位)" },
{ "hex.builtin.inspector.u8", "uint8_t" },
{ "hex.builtin.inspector.s8", "int8_t" },
{ "hex.builtin.inspector.u16", "uint16_t" },
{ "hex.builtin.inspector.s16", "int16_t" },
{ "hex.builtin.inspector.u32", "uint32_t" },
{ "hex.builtin.inspector.s32", "int32_t" },
{ "hex.builtin.inspector.u64", "uint64_t" },
{ "hex.builtin.inspector.s64", "int64_t" },
{ "hex.builtin.inspector.float16", "半浮点(16位)" },
{ "hex.builtin.inspector.float", "float(32位单精度浮点)" },
{ "hex.builtin.inspector.double", "double(64位双精度浮点)" },
{ "hex.builtin.inspector.ascii", "ASCII字符" },
{ "hex.builtin.inspector.wide", "宽字符" },
{ "hex.builtin.inspector.utf8", "UTF-8代码点" },
{ "hex.builtin.inspector.string", "字符串" },
{ "hex.builtin.inspector.time32", "__time32_t" },
{ "hex.builtin.inspector.time64", "__time64_t" },
{ "hex.builtin.inspector.time", "time_t" },
{ "hex.builtin.inspector.guid", "GUID" },
{ "hex.builtin.inspector.rgba8", "RGBA8颜色" },
{ "hex.builtin.nodes.constants", "常量" },
{ "hex.builtin.nodes.constants.int", "整数" },
{ "hex.builtin.nodes.constants.int.header", "整数" },
{ "hex.builtin.nodes.constants.int.output", "" },
{ "hex.builtin.nodes.constants.float", "浮点数" },
{ "hex.builtin.nodes.constants.float.header", "浮点数" },
{ "hex.builtin.nodes.constants.float.output", "" },
{ "hex.builtin.nodes.constants.nullptr", "空指针" },
{ "hex.builtin.nodes.constants.nullptr.header", "空指针" },
{ "hex.builtin.nodes.constants.nullptr.output", "" },
{ "hex.builtin.nodes.constants.buffer", "缓冲区" },
{ "hex.builtin.nodes.constants.buffer.header", "缓冲区" },
{ "hex.builtin.nodes.constants.buffer.size", "大小" },
{ "hex.builtin.nodes.constants.buffer.output", "" },
{ "hex.builtin.nodes.constants.string", "字符串" },
{ "hex.builtin.nodes.constants.string.header", "字符串" },
{ "hex.builtin.nodes.constants.string.output", "" },
{ "hex.builtin.nodes.constants.rgba8", "RGBA8颜色" },
{ "hex.builtin.nodes.constants.rgba8.header", "RGBA8颜色" },
{ "hex.builtin.nodes.constants.rgba8.output.r", "" },
{ "hex.builtin.nodes.constants.rgba8.output.g", "绿" },
{ "hex.builtin.nodes.constants.rgba8.output.b", "" },
{ "hex.builtin.nodes.constants.rgba8.output.a", "透明" },
{ "hex.builtin.nodes.constants.comment", "注释" },
{ "hex.builtin.nodes.constants.comment.header", "注释" },
{ "hex.builtin.nodes.display", "显示" },
{ "hex.builtin.nodes.display.int", "整数" },
{ "hex.builtin.nodes.display.int.header", "整数显示" },
{ "hex.builtin.nodes.display.int.input", "" },
{ "hex.builtin.nodes.display.float", "浮点数" },
{ "hex.builtin.nodes.display.float.header", "浮点数显示" },
{ "hex.builtin.nodes.display.float.input", "" },
{ "hex.builtin.nodes.data_access", "数据访问" },
{ "hex.builtin.nodes.data_access.read", "读取" },
{ "hex.builtin.nodes.data_access.read.header", "读取" },
{ "hex.builtin.nodes.data_access.read.address", "地址" },
{ "hex.builtin.nodes.data_access.read.size", "大小" },
{ "hex.builtin.nodes.data_access.read.data", "数据" },
{ "hex.builtin.nodes.data_access.write", "写入" },
{ "hex.builtin.nodes.data_access.write.header", "写入" },
{ "hex.builtin.nodes.data_access.write.address", "地址" },
{ "hex.builtin.nodes.data_access.write.data", "数据" },
{ "hex.builtin.nodes.data_access.size", "数据大小"},
{ "hex.builtin.nodes.data_access.size.header", "数据大小"},
{ "hex.builtin.nodes.data_access.size.size", "大小"},
{ "hex.builtin.nodes.casting", "数据转换" },
{ "hex.builtin.nodes.casting.int_to_buffer", "整数到缓冲区" },
{ "hex.builtin.nodes.casting.int_to_buffer.header", "整数到缓冲区" },
{ "hex.builtin.nodes.casting.int_to_buffer.input", "输入" },
{ "hex.builtin.nodes.casting.int_to_buffer.output", "输出" },
{ "hex.builtin.nodes.casting.buffer_to_int", "缓冲区到整数" },
{ "hex.builtin.nodes.casting.buffer_to_int.header", "缓冲区到整数" },
{ "hex.builtin.nodes.casting.buffer_to_int.input", "输入" },
{ "hex.builtin.nodes.casting.buffer_to_int.output", "输出" },
{ "hex.builtin.nodes.arithmetic", "运算" },
{ "hex.builtin.nodes.arithmetic.add", "加法" },
{ "hex.builtin.nodes.arithmetic.add.header", "加法" },
{ "hex.builtin.nodes.arithmetic.add.input.a", "输入A" },
{ "hex.builtin.nodes.arithmetic.add.input.b", "输入B" },
{ "hex.builtin.nodes.arithmetic.add.output", "输出" },
{ "hex.builtin.nodes.arithmetic.sub", "减法" },
{ "hex.builtin.nodes.arithmetic.sub.header", "减法" },
{ "hex.builtin.nodes.arithmetic.sub.input.a", "输入A" },
{ "hex.builtin.nodes.arithmetic.sub.input.b", "输入B" },
{ "hex.builtin.nodes.arithmetic.sub.output", "输出" },
{ "hex.builtin.nodes.arithmetic.mul", "乘法" },
{ "hex.builtin.nodes.arithmetic.mul.header", "乘法" },
{ "hex.builtin.nodes.arithmetic.mul.input.a", "输入A" },
{ "hex.builtin.nodes.arithmetic.mul.input.b", "输入B" },
{ "hex.builtin.nodes.arithmetic.mul.output", "输出" },
{ "hex.builtin.nodes.arithmetic.div", "除法" },
{ "hex.builtin.nodes.arithmetic.div.header", "除法" },
{ "hex.builtin.nodes.arithmetic.div.input.a", "输入A" },
{ "hex.builtin.nodes.arithmetic.div.input.b", "输入B" },
{ "hex.builtin.nodes.arithmetic.div.output", "输出" },
{ "hex.builtin.nodes.arithmetic.mod", "模数" },
{ "hex.builtin.nodes.arithmetic.mod.header", "模数" },
{ "hex.builtin.nodes.arithmetic.mod.input.a", "输入A" },
{ "hex.builtin.nodes.arithmetic.mod.input.b", "输入B" },
{ "hex.builtin.nodes.arithmetic.mod.output", "输出" },
{ "hex.builtin.nodes.buffer", "缓冲区" },
{ "hex.builtin.nodes.buffer.combine", "组合" },
{ "hex.builtin.nodes.buffer.combine.header", "缓冲区组合" },
{ "hex.builtin.nodes.buffer.combine.input.a", "输入A" },
{ "hex.builtin.nodes.buffer.combine.input.b", "输入B" },
{ "hex.builtin.nodes.buffer.combine.output", "输出" },
{ "hex.builtin.nodes.buffer.slice", "切片" },
{ "hex.builtin.nodes.buffer.slice.header", "缓冲区切片" },
{ "hex.builtin.nodes.buffer.slice.input.buffer", "输入" },
{ "hex.builtin.nodes.buffer.slice.input.from", "" },
{ "hex.builtin.nodes.buffer.slice.input.to", "" },
{ "hex.builtin.nodes.buffer.slice.output", "输出" },
{ "hex.builtin.nodes.buffer.repeat", "重复" },
{ "hex.builtin.nodes.buffer.repeat.header", "缓冲区重复" },
{ "hex.builtin.nodes.buffer.repeat.input.buffer", "输入" },
{ "hex.builtin.nodes.buffer.repeat.input.count", "次数" },
{ "hex.builtin.nodes.buffer.repeat.output", "输出" },
{ "hex.builtin.nodes.control_flow", "控制流" },
{ "hex.builtin.nodes.control_flow.if", "如果" },
{ "hex.builtin.nodes.control_flow.if.header", "如果" },
{ "hex.builtin.nodes.control_flow.if.condition", "条件" },
{ "hex.builtin.nodes.control_flow.if.true", "True" },
{ "hex.builtin.nodes.control_flow.if.false", "False" },
{ "hex.builtin.nodes.control_flow.if.output", "输出" },
{ "hex.builtin.nodes.control_flow.equals", "等于" },
{ "hex.builtin.nodes.control_flow.equals.header", "等于" },
{ "hex.builtin.nodes.control_flow.equals.input.a", "输入A" },
{ "hex.builtin.nodes.control_flow.equals.input.b", "输入B" },
{ "hex.builtin.nodes.control_flow.equals.output", "输出" },
{ "hex.builtin.nodes.control_flow.not", "取反" },
{ "hex.builtin.nodes.control_flow.not.header", "取反" },
{ "hex.builtin.nodes.control_flow.not.input", "输入" },
{ "hex.builtin.nodes.control_flow.not.output", "输出" },
{ "hex.builtin.nodes.control_flow.gt", "大于" },
{ "hex.builtin.nodes.control_flow.gt.header", "大于" },
{ "hex.builtin.nodes.control_flow.gt.input.a", "输入A" },
{ "hex.builtin.nodes.control_flow.gt.input.b", "输入B" },
{ "hex.builtin.nodes.control_flow.gt.output", "输出" },
{ "hex.builtin.nodes.control_flow.lt", "小于" },
{ "hex.builtin.nodes.control_flow.lt.header", "小于" },
{ "hex.builtin.nodes.control_flow.lt.input.a", "输入A" },
{ "hex.builtin.nodes.control_flow.lt.input.b", "输入B" },
{ "hex.builtin.nodes.control_flow.lt.output", "输出" },
{ "hex.builtin.nodes.control_flow.and", "" },
{ "hex.builtin.nodes.control_flow.and.header", "逻辑与" },
{ "hex.builtin.nodes.control_flow.and.input.a", "输入A" },
{ "hex.builtin.nodes.control_flow.and.input.b", "输入B" },
{ "hex.builtin.nodes.control_flow.and.output", "输出" },
{ "hex.builtin.nodes.control_flow.or", "" },
{ "hex.builtin.nodes.control_flow.or.header", "逻辑或" },
{ "hex.builtin.nodes.control_flow.or.input.a", "输入A" },
{ "hex.builtin.nodes.control_flow.or.input.b", "输入B" },
{ "hex.builtin.nodes.control_flow.or.output", "输出" },
{ "hex.builtin.nodes.bitwise", "按位操作" },
{ "hex.builtin.nodes.bitwise.and", "" },
{ "hex.builtin.nodes.bitwise.and.header", "位与" },
{ "hex.builtin.nodes.bitwise.and.input.a", "输入A" },
{ "hex.builtin.nodes.bitwise.and.input.b", "输入B" },
{ "hex.builtin.nodes.bitwise.and.output", "输出" },
{ "hex.builtin.nodes.bitwise.or", "" },
{ "hex.builtin.nodes.bitwise.or.header", "位或" },
{ "hex.builtin.nodes.bitwise.or.input.a", "输入A" },
{ "hex.builtin.nodes.bitwise.or.input.b", "输入B" },
{ "hex.builtin.nodes.bitwise.or.output", "输出" },
{ "hex.builtin.nodes.bitwise.xor", "异或" },
{ "hex.builtin.nodes.bitwise.xor.header", "按位异或" },
{ "hex.builtin.nodes.bitwise.xor.input.a", "输入A" },
{ "hex.builtin.nodes.bitwise.xor.input.b", "输入B" },
{ "hex.builtin.nodes.bitwise.xor.output", "输出" },
{ "hex.builtin.nodes.bitwise.not", "取反" },
{ "hex.builtin.nodes.bitwise.not.header", "按位取反" },
{ "hex.builtin.nodes.bitwise.not.input", "输入" },
{ "hex.builtin.nodes.bitwise.not.output", "输出" },
{ "hex.builtin.nodes.decoding", "编码" },
{ "hex.builtin.nodes.decoding.base64", "Base64" },
{ "hex.builtin.nodes.decoding.base64.header", "Base64解码" },
{ "hex.builtin.nodes.decoding.base64.input", "输入" },
{ "hex.builtin.nodes.decoding.base64.output", "输出" },
{ "hex.builtin.nodes.decoding.hex", "十六进制" },
{ "hex.builtin.nodes.decoding.hex.header", "十六进制解码" },
{ "hex.builtin.nodes.decoding.hex.input", "输入" },
{ "hex.builtin.nodes.decoding.hex.output", "输出" },
{ "hex.builtin.nodes.crypto", "加密" },
{ "hex.builtin.nodes.crypto.aes", "AES解密" },
{ "hex.builtin.nodes.crypto.aes.header", "AES解密" },
{ "hex.builtin.nodes.crypto.aes.key", "密钥" },
{ "hex.builtin.nodes.crypto.aes.iv", "IV" },
{ "hex.builtin.nodes.crypto.aes.nonce", "Nonce" },
{ "hex.builtin.nodes.crypto.aes.input", "输入" },
{ "hex.builtin.nodes.crypto.aes.output", "输出" },
{ "hex.builtin.nodes.crypto.aes.mode", "模式" },
{ "hex.builtin.nodes.crypto.aes.key_length", "密钥长度" },
{ "hex.builtin.tools.demangler", "Itanium/MSVC名还原" },
{ "hex.builtin.tools.demangler.mangled", "修饰名" },
{ "hex.builtin.tools.demangler.demangled", "还原名" },
{ "hex.builtin.tools.ascii_table", "ASCII表" },
{ "hex.builtin.tools.ascii_table.octal", "显示八进制" },
{ "hex.builtin.tools.regex_replacer", "正则替换" },
{ "hex.builtin.tools.regex_replacer.pattern", "正则表达式" },
{ "hex.builtin.tools.regex_replacer.replace", "替换表达式" },
{ "hex.builtin.tools.regex_replacer.input", "输入" },
{ "hex.builtin.tools.regex_replacer.output", "输出" },
{ "hex.builtin.tools.color", "颜色选择器" },
{ "hex.builtin.tools.calc", "计算器" },
{ "hex.builtin.tools.input", "输入" },
{ "hex.builtin.tools.format.standard", "标准" },
{ "hex.builtin.tools.format.scientific", "科学" },
{ "hex.builtin.tools.format.engineering", "工程师" },
{ "hex.builtin.tools.format.programmer", "程序员" },
{ "hex.builtin.tools.error", "最后错误: '{0}'" },
{ "hex.builtin.tools.history", "历史" },
{ "hex.builtin.tools.name", "名称" },
{ "hex.builtin.tools.value", "" },
{ "hex.builtin.tools.base_converter", "基本进制转换" },
{ "hex.builtin.tools.base_converter.dec", "DEC" },
{ "hex.builtin.tools.base_converter.hex", "HEX" },
{ "hex.builtin.tools.base_converter.oct", "OCT" },
{ "hex.builtin.tools.base_converter.bin", "BIN" },
{ "hex.builtin.tools.permissions", "UNIX权限计算器" },
{ "hex.builtin.tools.permissions.perm_bits", "权限位" },
{ "hex.builtin.tools.permissions.absolute", "绝对符号" },
{ "hex.builtin.tools.permissions.setuid_error", "用户必须具有 setuid 位的执行权限才能应用!" },
{ "hex.builtin.tools.permissions.setgid_error", "组必须具有 setgid 位的执行权限才能应用!" },
{ "hex.builtin.tools.permissions.sticky_error", "必须有执行权限才能申请粘滞位!" },
{ "hex.builtin.tools.file_uploader", "文件上传" },
{ "hex.builtin.tools.file_uploader.control", "控制" },
{ "hex.builtin.tools.file_uploader.upload", "上传" },
{ "hex.builtin.tools.file_uploader.done", "完成!" },
{ "hex.builtin.tools.file_uploader.recent", "最近上传" },
{ "hex.builtin.tools.file_uploader.tooltip", "点击复制\n按住CTRL并点击以打开" },
{ "hex.builtin.tools.file_uploader.invalid_response", "接收到来自Anonfiles的无效响应" },
{ "hex.builtin.tools.file_uploader.error", "上传文件失败!\n\n错误代码:{0}" },
{ "hex.builtin.tools.wiki_explain", "维基百科术语定义" },
{ "hex.builtin.tools.wiki_explain.control", "控制" },
{ "hex.builtin.tools.wiki_explain.search", "搜索" },
{ "hex.builtin.tools.wiki_explain.results", "结果" },
{ "hex.builtin.tools.wiki_explain.invalid_response", "接收到来自Wikipedia的无效响应" },
//{ "hex.builtin.tools.file_tools", "File Tools" },
//{ "hex.builtin.tools.file_tools.shredder", "Shredder" },
//{ "hex.builtin.tools.file_tools.shredder.warning", "This tool IRRECOVERABLY destroys a file. Use with caution" },
//{ "hex.builtin.tools.file_tools.shredder.input", "File to shred " },
//{ "hex.builtin.tools.file_tools.shredder.picker", "Open File to Shred" },
//{ "hex.builtin.tools.file_tools.shredder.fast", "Fast Mode" },
//{ "hex.builtin.tools.file_tools.shredder.shredding", "Shredding..." },
//{ "hex.builtin.tools.file_tools.shredder.shred", "Shred" },
//{ "hex.builtin.tools.file_tools.shredder.error.open", "Failed to open selected file!" },
//{ "hex.builtin.tools.file_tools.shredder.success", "Shredded successfully!" },
//{ "hex.builtin.tools.file_tools.splitter", "Splitter" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.5_75_floppy", "5¼\" Floppy disk (1200KiB)" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.3_5_floppy", "3½\" Floppy disk (1400KiB)" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.zip100", "Zip 100 Disk (100MiB)" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.zip200", "Zip 200 Disk (200MiB)" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom650", "CD-ROM (650MiB)" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.cdrom700", "CD-ROM (700MiB)" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.fat32", "FAT32 (4GiB)" },
//{ "hex.builtin.tools.file_tools.splitter.sizes.custom", "Custom" },
//{ "hex.builtin.tools.file_tools.splitter.input", "File to split " },
//{ "hex.builtin.tools.file_tools.splitter.picker.input", "Open File to split" },
//{ "hex.builtin.tools.file_tools.splitter.output", "Output path " },
//{ "hex.builtin.tools.file_tools.splitter.picker.output", "Set base path" },
//{ "hex.builtin.tools.file_tools.splitter.picker.splitting", "Splitting..." },
//{ "hex.builtin.tools.file_tools.splitter.picker.split", "Split" },
//{ "hex.builtin.tools.file_tools.splitter.picker.error.open", "Failed to open selected file!" },
//{ "hex.builtin.tools.file_tools.splitter.picker.error.size", "File is smaller than part size" },
//{ "hex.builtin.tools.file_tools.splitter.picker.error.create", "Failed to create part file {0}" },
//{ "hex.builtin.tools.file_tools.splitter.picker.success", "File split successfully!" },
//{ "hex.builtin.tools.file_tools.combiner", "Combiner" },
//{ "hex.builtin.tools.file_tools.combiner.add", "Add..." },
//{ "hex.builtin.tools.file_tools.combiner.add.picker", "Add file" },
//{ "hex.builtin.tools.file_tools.combiner.delete", "Delete" },
//{ "hex.builtin.tools.file_tools.combiner.clear", "Clear" },
//{ "hex.builtin.tools.file_tools.combiner.output", "Output file " },
//{ "hex.builtin.tools.file_tools.combiner.output.picker", "Set output base path" },
//{ "hex.builtin.tools.file_tools.combiner.combining", "Combining..." },
//{ "hex.builtin.tools.file_tools.combiner.combine", "Combine" },
//{ "hex.builtin.tools.file_tools.combiner.error.open_output", "Failed to create output file" },
//{ "hex.builtin.tools.file_tools.combiner.open_input", "Failed to open input file {0}" },
//{ "hex.builtin.tools.file_tools.combiner.success", "Files combined successfully!" },
{ "hex.builtin.setting.imhex", "ImHex" },
{ "hex.builtin.setting.imhex.recent_files", "最近文件" },
{ "hex.builtin.setting.general", "通用" },
{ "hex.builtin.setting.general.show_tips", "在启动时显示每日提示" },
//{ "hex.builtin.setting.general.auto_load_patterns", "Auto-load supported pattern" },
{ "hex.builtin.setting.interface", "界面" },
{ "hex.builtin.setting.interface.color", "颜色主题" },
{ "hex.builtin.setting.interface.color.system", "跟随系统" },
{ "hex.builtin.setting.interface.color.dark", "" },
{ "hex.builtin.setting.interface.color.light", "" },
{ "hex.builtin.setting.interface.color.classic", "经典" },
{ "hex.builtin.setting.interface.scaling", "缩放" },
{ "hex.builtin.setting.interface.scaling.native", "本地默认" },
{ "hex.builtin.setting.interface.scaling.x0_5", "x0.5" },
{ "hex.builtin.setting.interface.scaling.x1_0", "x1.0" },
{ "hex.builtin.setting.interface.scaling.x1_5", "x1.5" },
{ "hex.builtin.setting.interface.scaling.x2_0", "x2.0" },
{ "hex.builtin.setting.interface.language", "语言" },
{ "hex.builtin.setting.interface.fps", "FPS限制" },
{ "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.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.provider.file.path", "路径" },
{ "hex.builtin.provider.file.size", "大小" },
{ "hex.builtin.provider.file.creation", "创建时间" },
{ "hex.builtin.provider.file.access", "最后访问时间" },
{ "hex.builtin.provider.file.modification", "最后更改时间" },
});
}
}

View File

@@ -15,6 +15,7 @@ namespace hex::plugin::builtin {
void registerLanguageEnUS();
void registerLanguageDeDE();
void registerLanguageItIT();
void registerLanguageZhCN();
}
@@ -35,6 +36,7 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") {
registerLanguageEnUS();
registerLanguageDeDE();
registerLanguageItIT();
registerLanguageZhCN();
}

View File

@@ -5,31 +5,51 @@ set(CMAKE_CXX_STANDARD 20)
set(BUILD_SHARED_LIBS OFF)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/ImGui ${CMAKE_CURRENT_BINARY_DIR}/external/ImGui)
if(NOT USE_SYSTEM_NLOHMANN_JSON)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/nlohmann_json ${CMAKE_CURRENT_BINARY_DIR}/external/nlohmann_json)
else()
find_package(nlohmann_json REQUIRED)
endif()
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/nativefiledialog ${CMAKE_CURRENT_BINARY_DIR}/external/nativefiledialog EXCLUDE_FROM_ALL)
if(NOT USE_SYSTEM_FMT)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/fmt ${CMAKE_CURRENT_BINARY_DIR}/external/fmt)
else()
find_package(fmt REQUIRED)
endif()
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/microtar ${CMAKE_CURRENT_BINARY_DIR}/external/microtar EXCLUDE_FROM_ALL)
set(XDGPP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../../external/xdgpp")
set(CMAKE_USE_MBEDTLS ON)
set(BUILD_CURL_EXE OFF)
set(FPHSA_NAME_MISMATCHED ON CACHE BOOL "")
if(NOT USE_SYSTEM_NLOHMANN_JSON)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/nlohmann_json ${CMAKE_CURRENT_BINARY_DIR}/external/nlohmann_json)
set(NLOHMANN_JSON_LIBRARIES nlohmann_json)
else()
find_package(nlohmann_json 3.10.2 REQUIRED)
set(NLOHMANN_JSON_LIBRARIES nlohmann_json::nlohmann_json)
endif()
if(NOT USE_SYSTEM_FMT)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/fmt ${CMAKE_CURRENT_BINARY_DIR}/external/fmt)
set(FMT_LIBRARIES fmt-header-only)
else()
find_package(fmt 8.0.0 REQUIRED)
set(FMT_LIBRARIES fmt::fmt)
endif()
if(NOT USE_SYSTEM_CURL)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/curl ${CMAKE_CURRENT_BINARY_DIR}/external/curl EXCLUDE_FROM_ALL)
set_target_properties(libcurl PROPERTIES POSITION_INDEPENDENT_CODE ON)
set(LIBCURL_LIBRARIES libcurl)
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl)
pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl>=7.78.0)
endif()
if (NOT USE_SYSTEM_LLVM)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/llvm ${CMAKE_CURRENT_BINARY_DIR}/external/llvm EXCLUDE_FROM_ALL)
else()
find_package(LLVM REQUIRED Demangle)
endif()
if (NOT USE_SYSTEM_YARA)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../external/yara ${CMAKE_CURRENT_BINARY_DIR}/external/yara EXCLUDE_FROM_ALL)
set(YARA_LIBRARIES libyara)
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(YARA REQUIRED IMPORTED_TARGET yara)
endif()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC")
@@ -78,38 +98,17 @@ if (APPLE)
endif ()
endif ()
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/paths_mac.mm include/hex/helpers/file.hpp)
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/paths_mac.mm)
endif ()
add_library(libimhex SHARED ${LIBIMHEX_SOURCES})
target_include_directories(libimhex PUBLIC include ${MBEDTLS_INCLUDE_DIR} ${XDGPP_INCLUDE_DIRS})
if (USE_SYSTEM_FMT)
target_include_directories(libimhex PUBLIC include ${FMT_INCLUDE_DIRS})
endif()
if (USE_SYSTEM_CURL)
target_include_directories(libimhex PUBLIC include ${CURL_INCLUDE_DIRS})
endif()
target_link_directories(libimhex PUBLIC ${MBEDTLS_LIBRARY_DIR})
target_include_directories(libimhex PUBLIC include ${MBEDTLS_INCLUDE_DIR} ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIRS} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${Python_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${YARA_INCLUDE_DIRS})
target_link_directories(libimhex PUBLIC ${MBEDTLS_LIBRARY_DIR} ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS})
if (APPLE)
find_library(FOUNDATION NAMES Foundation)
target_link_libraries(libimhex PUBLIC imgui nlohmann_json mbedcrypto ${FOUNDATION} nfd fmt-header-only libcurl magic)
else ()
target_link_libraries(libimhex PUBLIC imgui nlohmann_json mbedcrypto nfd magic)
if (NOT USE_SYSTEM_FMT)
target_link_libraries(libimhex PUBLIC fmt-header-only)
else()
target_link_libraries(libimhex PUBLIC fmt)
endif()
if (NOT USE_SYSTEM_CURL)
target_link_libraries(libimhex PUBLIC libcurl)
else()
target_link_libraries(libimhex PUBLIC curl)
endif()
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
endif ()
target_link_libraries(libimhex PUBLIC imgui nfd magic capstone LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES})

View File

@@ -2,6 +2,7 @@
#include <hex.hpp>
#include <hex/helpers/concepts.hpp>
#include <hex/pattern_language/token.hpp>
#include <functional>
#include <map>
@@ -15,7 +16,7 @@ namespace hex {
class View;
class LanguageDefinition;
namespace pl { class ASTNode; class Evaluator; }
namespace pl { class Evaluator; }
namespace dp { class Node; }
/*
@@ -90,7 +91,7 @@ namespace hex {
constexpr static u32 NoParameters = 0x0000'0000;
using Namespace = std::vector<std::string>;
using Callback = std::function<hex::pl::ASTNode*(hex::pl::Evaluator&, std::vector<hex::pl::ASTNode*>&)>;
using Callback = std::function<std::optional<hex::pl::Token::Literal>(hex::pl::Evaluator*, const std::vector<hex::pl::Token::Literal>&)>;
struct Function {
u32 parameterCount;

View File

@@ -106,14 +106,17 @@ namespace hex {
EVENT_DEF(EventProjectFileLoad);
EVENT_DEF(EventSettingsChanged);
EVENT_DEF(EventAbnormalTermination, int);
EVENT_DEF(EventOSThemeChanged);
EVENT_DEF(RequestOpenWindow, std::string);
EVENT_DEF(RequestSelectionChange, Region);
EVENT_DEF(RequestAddBookmark, ImHexApi::Bookmarks::Entry);
EVENT_DEF(RequestAppendPatternLanguageCode, std::string);
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
EVENT_DEF(RequestChangeWindowTitle, std::string);
EVENT_DEF(RequestCloseImHex, bool);
EVENT_DEF(RequestOpenFile, std::string);
EVENT_DEF(RequestChangeTheme, u32);
EVENT_DEF(RequestOpenPopup, std::string);
EVENT_DEF(QuerySelection, Region&);

View File

@@ -6,8 +6,12 @@
#include <vector>
#include <string>
#include <hex/helpers/concepts.hpp>
namespace hex {
namespace prv { class Provider; }
struct ImHexApi {
ImHexApi() = delete;
@@ -36,6 +40,24 @@ namespace hex {
static std::list<Entry>& getEntries();
};
struct Provider {
static prv::Provider* get();
static const std::vector<prv::Provider*>& getProviders();
static bool isValid();
template<hex::derived_from<prv::Provider> T>
static void add(auto&& ... args) {
add(new T(std::forward<decltype(args)>(args)...));
}
static void remove(prv::Provider *provider);
private:
static void add(prv::Provider *provider);
};
};
}

View File

@@ -24,25 +24,37 @@ namespace hex {
};
explicit File(const std::string &path, Mode mode);
File();
File(const File&) = delete;
File(File &&other) noexcept;
~File();
bool isValid() { return this->m_file != nullptr; }
[[nodiscard]] bool isValid() const { return this->m_file != nullptr; }
void seek(u64 offset);
void close();
size_t readBuffer(u8 *buffer, size_t size);
std::vector<u8> readBytes(size_t numBytes = 0);
std::string readString(size_t numBytes = 0);
void write(const u8 *buffer, size_t size);
void write(const std::vector<u8> &bytes);
void write(const std::string &string);
size_t getSize();
[[nodiscard]] size_t getSize() const;
void setSize(u64 size);
void flush();
void remove();
auto getHandle() { return this->m_file; }
const std::string& getPath() { return this->m_path; }
private:
FILE *m_file;
std::string m_path;
};
}

View File

@@ -8,12 +8,12 @@ namespace hex::literals {
return bytes;
}
constexpr static inline unsigned long long operator ""_kiB(unsigned long long kiB) noexcept {
constexpr static inline unsigned long long operator ""_KiB(unsigned long long kiB) noexcept {
return operator ""_Bytes(kiB * 1024);
}
constexpr static inline unsigned long long operator ""_MiB(unsigned long long MiB) noexcept {
return operator ""_kiB(MiB * 1024);
return operator ""_KiB(MiB * 1024);
}
constexpr static inline unsigned long long operator ""_GiB(unsigned long long GiB) noexcept {

View File

@@ -53,7 +53,10 @@ namespace hex {
public:
static std::vector<std::function<void()>> deferredCalls;
static prv::Provider *currentProvider;
static std::vector<prv::Provider*> providers;
static u32 currentProvider;
static std::map<std::string, std::vector<ContentRegistry::Settings::Entry>> settingsEntries;
static nlohmann::json settingsJson;
static std::vector<ContentRegistry::CommandPaletteCommands::Entry> commandPaletteCommands;
@@ -62,7 +65,7 @@ namespace hex {
static std::vector<ContentRegistry::Tools::Entry> toolsEntries;
static std::vector<ContentRegistry::DataInspector::Entry> dataInspectorEntries;
static u32 patternPaletteOffset;
static std::string errorPopupMessage;
static std::string popupMessage;
static std::list<ImHexApi::Bookmarks::Entry> bookmarkEntries;
static std::vector<pl::PatternData*> patternData;

View File

@@ -8,6 +8,7 @@
#include <cstring>
#include <cctype>
#include <functional>
#include <limits>
#include <memory>
#include <optional>
#include <string>
@@ -38,6 +39,29 @@ namespace hex {
return (value & mask) >> to;
}
[[nodiscard]] inline u64 extract(u32 from, u32 to, const std::vector<u8> &bytes) {
u8 index = 0;
while(from > 32 && to > 32) {
if (from - 8 < 0 || to - 8 < 0)
return 0;
from -= 8;
to -= 8;
index++;
}
u64 value = 0;
std::memcpy(&value, &bytes[index], std::min(sizeof(value), bytes.size() - index));
u64 mask = (std::numeric_limits<u64>::max() >> (64 - (from + 1)));
return (value & mask) >> to;
}
constexpr inline s128 signExtend(size_t numBits, s128 value) {
s128 mask = 1U << (numBits - 1);
return (value ^ mask) - mask;
}
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
@@ -134,13 +158,13 @@ namespace hex {
inline void trimLeft(std::string &s) {
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
return !std::isspace(ch) && ch >= 0x20;
}));
}
inline void trimRight(std::string &s) {
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
return !std::isspace(ch) && ch >= 0x20;
}).base(), s.end());
}
@@ -155,7 +179,7 @@ namespace hex {
Folder
};
void openFileBrowser(const std::string &title, DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::string)> &callback);
void openFileBrowser(const std::string &title, DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::string)> &callback, const std::string &defaultPath = {});
float float16ToFloat32(u16 float16);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,65 @@
#pragma once
#include <optional>
#include <vector>
#include <hex/pattern_language/token.hpp>
namespace hex::pl {
class ASTNode;
class ASTNodeAttribute;
class PatternData;
class Evaluator;
class Attributable {
protected:
Attributable() = default;
Attributable(const Attributable &) = default;
public:
void addAttribute(ASTNodeAttribute *attribute) {
this->m_attributes.push_back(attribute);
}
[[nodiscard]] const auto &getAttributes() const {
return this->m_attributes;
}
private:
std::vector<ASTNodeAttribute *> m_attributes;
};
class Clonable {
public:
[[nodiscard]]
virtual ASTNode* clone() const = 0;
};
class ASTNode : public Clonable {
public:
constexpr ASTNode() = default;
constexpr virtual ~ASTNode() = default;
constexpr ASTNode(const ASTNode &) = default;
[[nodiscard]] constexpr u32 getLineNumber() const { return this->m_lineNumber; }
[[maybe_unused]] constexpr void setLineNumber(u32 lineNumber) { this->m_lineNumber = lineNumber; }
[[nodiscard]] virtual ASTNode *evaluate(Evaluator *evaluator) const { return this->clone(); }
[[nodiscard]] virtual std::vector<PatternData *> createPatterns(Evaluator *evaluator) const { return {}; }
using FunctionResult = std::pair<bool, std::optional<Token::Literal>>;
virtual FunctionResult execute(Evaluator *evaluator) { throw std::pair<u32, std::string>(this->getLineNumber(), "cannot execute non-function statement"); }
private:
u32 m_lineNumber = 1;
};
}

View File

@@ -1,90 +1,127 @@
#pragma once
#include <hex.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/pattern_language/ast_node.hpp>
#include <hex/pattern_language/log_console.hpp>
#include <bit>
#include <string>
#include <map>
#include <optional>
#include <vector>
#include <hex/pattern_language/log_console.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/helpers/fmt.hpp>
namespace hex::prv { class Provider; }
namespace hex::pl {
class PatternData;
class ASTNode;
class Evaluator {
public:
Evaluator() = default;
std::optional<std::vector<PatternData*>> evaluate(const std::vector<ASTNode*>& ast);
std::optional<std::vector<PatternData*>> evaluate(const std::vector<ASTNode*> &ast);
LogConsole& getConsole() { return this->m_console; }
void setDefaultEndian(std::endian endian) { this->m_defaultDataEndian = endian; }
void setRecursionLimit(u32 limit) { this->m_recursionLimit = limit; }
void setProvider(prv::Provider *provider) { this->m_provider = provider; }
[[nodiscard]] std::endian getCurrentEndian() const { return this->m_endianStack.back(); }
PatternData* patternFromName(const ASTNodeRValue::Path &name);
template<typename T>
T* asType(ASTNode *param) {
if (auto evaluatedParam = dynamic_cast<T*>(param); evaluatedParam != nullptr)
return evaluatedParam;
else
this->getConsole().abortEvaluation("function got wrong type of parameter");
[[nodiscard]]
LogConsole& getConsole() {
return this->m_console;
}
struct Scope { PatternData *parent; std::vector<PatternData*>* scope; };
void pushScope(PatternData *parent, std::vector<PatternData*> &scope) {
if (this->m_scopes.size() > this->m_evalDepth)
LogConsole::abortEvaluation(hex::format("recursion limit of {} reached", this->m_evalDepth));
this->m_scopes.push_back({ parent, &scope });
}
void popScope() {
this->m_scopes.pop_back();
}
const Scope& getScope(s32 index) {
static Scope empty;
if (index > 0 || -index >= this->m_scopes.size()) return empty;
return this->m_scopes[this->m_scopes.size() - 1 + index];
}
const Scope& getGlobalScope() {
return this->m_scopes.front();
}
void setProvider(prv::Provider *provider) {
this->m_provider = provider;
}
[[nodiscard]]
prv::Provider *getProvider() const {
return this->m_provider;
}
void setDefaultEndian(std::endian endian) {
this->m_defaultEndian = endian;
}
[[nodiscard]]
std::endian getDefaultEndian() const {
return this->m_defaultEndian;
}
void setEvaluationDepth(u32 evalDepth) {
this->m_evalDepth = evalDepth;
}
[[nodiscard]]
u32 getEvaluationDepth() const {
return this->m_evalDepth;
}
void setArrayLimit(u32 arrayLimit) {
this->m_arrayLimit = arrayLimit;
}
[[nodiscard]]
u32 getArrayLimit() const {
return this->m_arrayLimit;
}
u64& dataOffset() { return this->m_currOffset; }
bool addCustomFunction(const std::string &name, u32 numParams, const ContentRegistry::PatternLanguageFunctions::Callback &function) {
const auto [iter, inserted] = this->m_customFunctions.insert({ name, { numParams, function } });
return inserted;
}
[[nodiscard]]
const std::map<std::string, ContentRegistry::PatternLanguageFunctions::Function>& getCustomFunctions() const {
return this->m_customFunctions;
}
[[nodiscard]]
std::vector<Token::Literal>& getStack() {
return this->m_stack;
}
void createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value = std::nullopt);
void setVariable(const std::string &name, const Token::Literal& value);
private:
std::map<std::string, ASTNode*> m_types;
prv::Provider* m_provider = nullptr;
std::endian m_defaultDataEndian = std::endian::native;
u64 m_currOffset = 0;
std::vector<std::endian> m_endianStack;
std::vector<PatternData*> m_globalMembers;
std::vector<std::vector<PatternData*>*> m_currMembers;
std::vector<std::vector<PatternData*>*> m_localVariables;
std::vector<PatternData*> m_currMemberScope;
std::vector<u8> m_localStack;
std::map<std::string, ContentRegistry::PatternLanguageFunctions::Function> m_definedFunctions;
u64 m_currOffset;
prv::Provider *m_provider = nullptr;
LogConsole m_console;
u32 m_recursionLimit;
u32 m_currRecursionDepth;
std::endian m_defaultEndian = std::endian::native;
u32 m_evalDepth;
u32 m_arrayLimit;
void createLocalVariable(const std::string &varName, PatternData *pattern);
void setLocalVariableValue(const std::string &varName, const void *value, size_t size);
ASTNodeIntegerLiteral* evaluateScopeResolution(ASTNodeScopeResolution *node);
ASTNodeIntegerLiteral* evaluateRValue(ASTNodeRValue *node);
ASTNode* evaluateFunctionCall(ASTNodeFunctionCall *node);
ASTNodeIntegerLiteral* evaluateTypeOperator(ASTNodeTypeOperator *typeOperatorNode);
ASTNodeIntegerLiteral* evaluateOperator(ASTNodeIntegerLiteral *left, ASTNodeIntegerLiteral *right, Token::Operator op);
ASTNodeIntegerLiteral* evaluateOperand(ASTNode *node);
ASTNodeIntegerLiteral* evaluateTernaryExpression(ASTNodeTernaryExpression *node);
ASTNodeIntegerLiteral* evaluateMathematicalExpression(ASTNodeNumericExpression *node);
void evaluateFunctionDefinition(ASTNodeFunctionDefinition *node);
std::optional<ASTNode*> evaluateFunctionBody(const std::vector<ASTNode*> &body);
PatternData* findPattern(std::vector<PatternData*> currMembers, const ASTNodeRValue::Path &path);
PatternData* evaluateAttributes(ASTNode *currNode, PatternData *currPattern);
PatternData* evaluateBuiltinType(ASTNodeBuiltinType *node);
void evaluateMember(ASTNode *node, std::vector<PatternData*> &currMembers, bool increaseOffset);
PatternData* evaluateStruct(ASTNodeStruct *node);
PatternData* evaluateUnion(ASTNodeUnion *node);
PatternData* evaluateEnum(ASTNodeEnum *node);
PatternData* evaluateBitfield(ASTNodeBitfield *node);
PatternData* evaluateType(ASTNodeTypeDecl *node);
PatternData* evaluateVariable(ASTNodeVariableDecl *node);
PatternData* evaluateArray(ASTNodeArrayVariableDecl *node);
PatternData* evaluateStaticArray(ASTNodeArrayVariableDecl *node);
PatternData* evaluateDynamicArray(ASTNodeArrayVariableDecl *node);
PatternData* evaluatePointer(ASTNodePointerVariableDecl *node);
std::vector<Scope> m_scopes;
std::map<std::string, ContentRegistry::PatternLanguageFunctions::Function> m_customFunctions;
std::vector<ASTNode*> m_customFunctionDefinitions;
std::vector<Token::Literal> m_stack;
};
}

View File

@@ -7,8 +7,12 @@
#include <utility>
#include <vector>
#include <hex/pattern_language/ast_node_base.hpp>
namespace hex::pl {
class ASTNode;
class LogConsole {
public:
enum Level {
@@ -18,9 +22,10 @@ namespace hex::pl {
Error
};
const auto& getLog() { return this->m_consoleLog; }
[[nodiscard]]
const auto& getLog() const { return this->m_consoleLog; }
using EvaluateError = std::string;
using EvaluateError = std::pair<u32, std::string>;
void log(Level level, const std::string &message) {
switch (level) {
@@ -32,16 +37,29 @@ namespace hex::pl {
}
}
[[noreturn]] void abortEvaluation(const std::string &message) {
throw EvaluateError(message);
[[noreturn]]
static void abortEvaluation(const std::string &message) {
throw EvaluateError(0, message);
}
[[noreturn]]
static void abortEvaluation(const std::string &message, const auto *node) {
throw EvaluateError(static_cast<const ASTNode*>(node)->getLineNumber(), message);
}
void clear() {
this->m_consoleLog.clear();
this->m_lastHardError = { };
}
void setHardError(const EvaluateError &error) { this->m_lastHardError = error; }
[[nodiscard]]
const LogConsole::EvaluateError& getLastHardError() { return this->m_lastHardError; };
private:
std::vector<std::pair<Level, std::string>> m_consoleLog;
EvaluateError m_lastHardError;
};
}

View File

@@ -37,6 +37,11 @@ namespace hex::pl {
return this->m_curr[index].lineNumber;
}
auto* create(auto *node) {
node->setLineNumber(this->getLineNumber(-1));
return node;
}
template<typename T>
const T& getValue(s32 index) const {
auto value = std::get_if<T>(&this->m_curr[index].value);
@@ -68,6 +73,7 @@ namespace hex::pl {
ASTNode* parseScopeResolution();
ASTNode* parseRValue(ASTNodeRValue::Path &path);
ASTNode* parseFactor();
ASTNode* parseCastExpression();
ASTNode* parseUnaryExpression();
ASTNode* parseMultiplicativeExpression();
ASTNode* parseAdditiveExpression();
@@ -83,17 +89,18 @@ namespace hex::pl {
ASTNode* parseTernaryConditional();
ASTNode* parseMathematicalExpression();
ASTNode* parseFunctionDefintion();
ASTNode* parseFunctionDefinition();
ASTNode* parseFunctionStatement();
ASTNode* parseFunctionVariableAssignment();
ASTNode* parseFunctionReturnStatement();
std::vector<ASTNode*> parseStatementBody();
ASTNode* parseFunctionConditional();
ASTNode* parseFunctionWhileLoop();
void parseAttribute(Attributable *currNode);
ASTNode* parseConditional();
ASTNode* parseWhileStatement();
ASTNodeTypeDecl* parseType();
ASTNodeTypeDecl* parseType(bool allowFunctionTypes = false);
ASTNode* parseUsingDeclaration();
ASTNode* parsePadding();
ASTNode* parseMemberVariable(ASTNodeTypeDecl *type);
@@ -111,6 +118,8 @@ namespace hex::pl {
std::vector<ASTNode*> parseNamespace();
std::vector<ASTNode*> parseStatements();
ASTNodeTypeDecl* addType(const std::string &name, ASTNode *node, std::optional<std::endian> endian = std::nullopt);
std::vector<ASTNode*> parseTillToken(Token::Type endTokenType, const auto value) {
std::vector<ASTNode*> program;
auto guard = SCOPE_GUARD {
@@ -238,12 +247,6 @@ namespace hex::pl {
return this->m_curr[index].type == type && this->m_curr[index] == value;
}
bool peekOptional(Token::Type type, auto value, u32 index = 0) {
if (index >= this->m_matchedOptionals.size())
return false;
return peek(type, value, std::distance(this->m_curr, this->m_matchedOptionals[index]));
}
};
}

View File

@@ -10,12 +10,14 @@
#include <hex/helpers/utils.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/concepts.hpp>
#include <hex/helpers/logger.hpp>
#include <cstring>
#include <codecvt>
#include <locale>
#include <random>
#include <string>
#include <type_traits>
namespace hex::pl {
@@ -41,6 +43,14 @@ namespace hex::pl {
}
class Inlinable {
public:
[[nodiscard]] bool isInlined() const { return this->m_inlined; }
void setInlined(bool inlined) { this->m_inlined = inlined; }
private:
bool m_inlined = false;
};
class PatternData {
public:
PatternData(u64 offset, size_t size, u32 color = 0)
@@ -86,6 +96,17 @@ namespace hex::pl {
[[nodiscard]] PatternData* getParent() const { return this->m_parent; }
void setParent(PatternData *parent) { this->m_parent = parent; }
[[nodiscard]] std::string getDisplayName() const { return this->m_displayName.value_or(this->m_variableName); }
void setDisplayName(const std::string &name) { this->m_displayName = name; }
[[nodiscard]] Evaluator* getEvaluator() const { return this->m_evaluator; }
void setEvaluator(Evaluator *evaluator) { this->m_evaluator = evaluator; }
[[nodiscard]] const auto& getTransformFunction() const { return this->m_transformFunction; }
void setTransformFunction(const ContentRegistry::PatternLanguageFunctions::Function &function) { this->m_transformFunction = function; }
[[nodiscard]] const auto& getFormatterFunction() const { return this->m_formatterFunction; }
void setFormatterFunction(const ContentRegistry::PatternLanguageFunctions::Function &function) { this->m_formatterFunction = function; }
virtual void createEntry(prv::Provider* &provider) = 0;
[[nodiscard]] virtual std::string getFormattedName() const = 0;
@@ -116,9 +137,9 @@ namespace hex::pl {
static bool sortPatternDataTable(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider, pl::PatternData* left, pl::PatternData* right) {
if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("name")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return left->getVariableName() > right->getVariableName();
return left->getDisplayName() > right->getDisplayName();
else
return left->getVariableName() < right->getVariableName();
return left->getDisplayName() < right->getDisplayName();
}
else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("offset")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
@@ -189,17 +210,34 @@ namespace hex::pl {
return this->m_local;
}
[[nodiscard]] virtual bool operator!=(const PatternData &other) const final { return !operator==(other); }
[[nodiscard]] virtual bool operator==(const PatternData &other) const = 0;
template<typename T>
[[nodiscard]] bool areCommonPropertiesEqual(const PatternData &other) const {
return
typeid(other) == typeid(std::remove_cvref_t<T>) &&
this->m_offset == other.m_offset &&
this->m_size == other.m_size &&
this->m_hidden == other.m_hidden &&
this->m_endian == other.m_endian &&
this->m_variableName == other.m_variableName &&
this->m_typeName == other.m_typeName &&
this->m_comment == other.m_comment &&
this->m_local == other.m_local;
}
protected:
void createDefaultEntry(const std::string &value) const {
void createDefaultEntry(const std::string &value, const Token::Literal &literal) const {
ImGui::TableNextRow();
ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
ImGui::TableNextColumn();
if (ImGui::Selectable(("##PatternDataLine"s + std::to_string(this->getOffset())).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
EventManager::post<RequestSelectionChange>(Region { this->getOffset(), this->getSize() });
}
this->drawCommentTooltip();
ImGui::SameLine();
ImGui::Text("%s", this->getVariableName().c_str());
ImGui::Text("%s", this->getDisplayName().c_str());
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
ImGui::TableNextColumn();
@@ -209,7 +247,19 @@ namespace hex::pl {
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->getFormattedName().c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", value.c_str());
if (!this->m_formatterFunction.has_value())
ImGui::Text("%s", value.c_str());
else {
auto result = this->m_formatterFunction->func(this->getEvaluator(), { literal });
if (result.has_value()) {
if (auto displayValue = std::get_if<std::string>(&result.value()); displayValue != nullptr)
ImGui::Text("%s", displayValue->c_str());
} else {
ImGui::Text("???");
}
}
}
void drawCommentTooltip() const {
@@ -230,10 +280,15 @@ namespace hex::pl {
size_t m_size;
u32 m_color;
std::optional<std::string> m_displayName;
std::string m_variableName;
std::optional<std::string> m_comment;
std::string m_typeName;
Evaluator *m_evaluator = nullptr;
std::optional<ContentRegistry::PatternLanguageFunctions::Function> m_formatterFunction;
std::optional<ContentRegistry::PatternLanguageFunctions::Function> m_transformFunction;
PatternData *m_parent;
bool m_local = false;
};
@@ -252,6 +307,8 @@ namespace hex::pl {
[[nodiscard]] std::string getFormattedName() const override {
return "";
}
[[nodiscard]] bool operator==(const PatternData &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
};
class PatternDataPointer : public PatternData {
@@ -279,7 +336,7 @@ namespace hex::pl {
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
bool open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
this->drawCommentTooltip();
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
@@ -334,15 +391,26 @@ namespace hex::pl {
void setPointedAtPattern(PatternData *pattern) {
this->m_pointedAt = pattern;
this->m_pointedAt->setVariableName("*" + this->getVariableName());
this->m_pointedAt->setVariableName(hex::format("*({})", this->getVariableName()));
}
[[nodiscard]] PatternData* getPointedAtPattern() {
return this->m_pointedAt;
}
[[nodiscard]] bool operator==(const PatternData &other) const override {
return areCommonPropertiesEqual<decltype(*this)>(other) &&
*static_cast<const PatternDataPointer*>(&other)->m_pointedAt == *this->m_pointedAt;
}
void rebase(u64 base) {
this->m_pointedAt->setOffset((this->m_pointedAt->getOffset() - this->m_pointerBase) + base);
this->m_pointerBase = base;
}
private:
PatternData *m_pointedAt;
u64 m_pointerBase = 0;
};
class PatternDataUnsigned : public PatternData {
@@ -355,11 +423,11 @@ namespace hex::pl {
}
void createEntry(prv::Provider* &provider) override {
u64 data = 0;
u128 data = 0;
provider->read(this->getOffset(), &data, this->getSize());
data = hex::changeEndianess(data, this->getSize(), this->getEndian());
this->createDefaultEntry(hex::format("{:d} (0x{:0{}X})", data, data, this->getSize() * 2));
this->createDefaultEntry(hex::format("{:d} (0x{:0{}X})", data, data, this->getSize() * 2), data);
}
[[nodiscard]] std::string getFormattedName() const override {
@@ -372,6 +440,8 @@ namespace hex::pl {
default: return "Unsigned data";
}
}
[[nodiscard]] bool operator==(const PatternData &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
};
class PatternDataSigned : public PatternData {
@@ -384,42 +454,12 @@ namespace hex::pl {
}
void createEntry(prv::Provider* &provider) override {
u128 data = 0;
s128 data = 0;
provider->read(this->getOffset(), &data, this->getSize());
data = hex::changeEndianess(data, this->getSize(), this->getEndian());
switch (this->getSize()) {
case 1: {
s8 signedData;
std::memcpy(&signedData, &data, 1);
this->createDefaultEntry(hex::format("{:d} (0x{:0{}X})", signedData, data, 1 * 2));
}
break;
case 2: {
s16 signedData;
std::memcpy(&signedData, &data, 2);
this->createDefaultEntry(hex::format("{:d} (0x{:0{}X})", signedData, data, 2 * 2));
}
break;
case 4: {
s32 signedData;
std::memcpy(&signedData, &data, 4);
this->createDefaultEntry(hex::format("{:d} (0x{:0{}X})", signedData, data, 4 * 2));
}
break;
case 8: {
s64 signedData;
std::memcpy(&signedData, &data, 8);
this->createDefaultEntry(hex::format("{:d} (0x{:0{}X})", signedData, data, 8 * 2));
}
break;
case 16: {
s128 signedData;
std::memcpy(&signedData, &data, 16);
this->createDefaultEntry(hex::format("{:d} (0x{:0{}X})", signedData, data, 16 * 2));
}
break;
}
data = hex::signExtend(this->getSize() * 8, data);
this->createDefaultEntry(hex::format("{:d} (0x{:0{}X})", data, data, 1 * 2), data);
}
[[nodiscard]] std::string getFormattedName() const override {
@@ -432,6 +472,8 @@ namespace hex::pl {
default: return "Signed data";
}
}
[[nodiscard]] bool operator==(const PatternData &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
};
class PatternDataFloat : public PatternData {
@@ -449,13 +491,13 @@ namespace hex::pl {
provider->read(this->getOffset(), &data, 4);
data = hex::changeEndianess(data, 4, this->getEndian());
this->createDefaultEntry(hex::format("{:e} (0x{:0{}X})", *reinterpret_cast<float*>(&data), data, this->getSize() * 2));
this->createDefaultEntry(hex::format("{:e} (0x{:0{}X})", *reinterpret_cast<float*>(&data), data, this->getSize() * 2), *reinterpret_cast<float*>(&data));
} else if (this->getSize() == 8) {
u64 data = 0;
provider->read(this->getOffset(), &data, 8);
data = hex::changeEndianess(data, 8, this->getEndian());
this->createDefaultEntry(hex::format("{:e} (0x{:0{}X})", *reinterpret_cast<double*>(&data), data, this->getSize() * 2));
this->createDefaultEntry(hex::format("{:e} (0x{:0{}X})", *reinterpret_cast<double*>(&data), data, this->getSize() * 2), *reinterpret_cast<double*>(&data));
}
}
@@ -466,6 +508,8 @@ namespace hex::pl {
default: return "Floating point data";
}
}
[[nodiscard]] bool operator==(const PatternData &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
};
class PatternDataBoolean : public PatternData {
@@ -482,16 +526,18 @@ namespace hex::pl {
provider->read(this->getOffset(), &boolean, 1);
if (boolean == 0)
this->createDefaultEntry("false");
this->createDefaultEntry("false", false);
else if (boolean == 1)
this->createDefaultEntry("true");
this->createDefaultEntry("true", true);
else
this->createDefaultEntry("true*");
this->createDefaultEntry("true*", true);
}
[[nodiscard]] std::string getFormattedName() const override {
return "bool";
}
[[nodiscard]] bool operator==(const PatternData &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
};
class PatternDataCharacter : public PatternData {
@@ -507,12 +553,14 @@ namespace hex::pl {
char character;
provider->read(this->getOffset(), &character, 1);
this->createDefaultEntry(hex::format("'{0}'", character));
this->createDefaultEntry(hex::format("'{0}'", character), character);
}
[[nodiscard]] std::string getFormattedName() const override {
return "char";
}
[[nodiscard]] bool operator==(const PatternData &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
};
class PatternDataCharacter16 : public PatternData {
@@ -529,12 +577,15 @@ namespace hex::pl {
provider->read(this->getOffset(), &character, 2);
character = hex::changeEndianess(character, this->getEndian());
this->createDefaultEntry(hex::format("'{0}'", std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(character)));
u128 literal = character;
this->createDefaultEntry(hex::format("'{0}'", std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(character)), literal);
}
[[nodiscard]] std::string getFormattedName() const override {
return "char16";
}
[[nodiscard]] bool operator==(const PatternData &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
};
class PatternDataString : public PatternData {
@@ -550,12 +601,14 @@ namespace hex::pl {
std::string buffer(this->getSize(), 0x00);
provider->read(this->getOffset(), buffer.data(), this->getSize());
this->createDefaultEntry(hex::format("\"{0}\"", makeDisplayable(buffer.data(), this->getSize()).c_str()));
this->createDefaultEntry(hex::format("\"{0}\"", makeDisplayable(buffer.data(), this->getSize()).c_str()), buffer);
}
[[nodiscard]] std::string getFormattedName() const override {
return "String";
}
[[nodiscard]] bool operator==(const PatternData &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
};
class PatternDataString16 : public PatternData {
@@ -576,15 +629,17 @@ namespace hex::pl {
auto utf8String = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>{}.to_bytes(buffer);
this->createDefaultEntry(hex::format("\"{0}\"", utf8String)) ;
this->createDefaultEntry(hex::format("\"{0}\"", utf8String), utf8String);
}
[[nodiscard]] std::string getFormattedName() const override {
return "String16";
}
[[nodiscard]] bool operator==(const PatternData &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
};
class PatternDataDynamicArray : public PatternData {
class PatternDataDynamicArray : public PatternData, public Inlinable {
public:
PatternDataDynamicArray(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) {
@@ -619,34 +674,38 @@ namespace hex::pl {
if (this->m_entries.empty())
return;
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
this->drawCommentTooltip();
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
ImGui::TableNextColumn();
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04llX", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->m_entries[0]->getTypeName().c_str());
ImGui::SameLine(0, 0);
bool open = true;
if (!this->isInlined()) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
this->drawCommentTooltip();
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
ImGui::TableNextColumn();
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04llX", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->m_entries[0]->getTypeName().c_str());
ImGui::SameLine(0, 0);
ImGui::TextUnformatted("[");
ImGui::SameLine(0, 0);
ImGui::TextColored(ImColor(0xFF00FF00), "%llu", this->m_entries.size());
ImGui::SameLine(0, 0);
ImGui::TextUnformatted("]");
ImGui::TextUnformatted("[");
ImGui::SameLine(0, 0);
ImGui::TextColored(ImColor(0xFF00FF00), "%llu", this->m_entries.size());
ImGui::SameLine(0, 0);
ImGui::TextUnformatted("]");
ImGui::TableNextColumn();
ImGui::Text("%s", "{ ... }");
ImGui::TableNextColumn();
ImGui::Text("%s", "{ ... }");
}
if (open) {
for (auto &member : this->m_entries)
member->draw(provider);
ImGui::TreePop();
if (!this->isInlined())
ImGui::TreePop();
}
}
@@ -692,11 +751,27 @@ namespace hex::pl {
}
}
[[nodiscard]] bool operator==(const PatternData &other) const override {
if (!areCommonPropertiesEqual<decltype(*this)>(other))
return false;
auto &otherArray = *static_cast<const PatternDataDynamicArray*>(&other);
if (this->m_entries.size() != otherArray.m_entries.size())
return false;
for (u64 i = 0; i < this->m_entries.size(); i++) {
if (*this->m_entries[i] != *otherArray.m_entries[i])
return false;
}
return true;
}
private:
std::vector<PatternData*> m_entries;
};
class PatternDataStaticArray : public PatternData {
class PatternDataStaticArray : public PatternData, public Inlinable {
public:
PatternDataStaticArray(u64 offset, size_t size, u32 color = 0)
: PatternData(offset, size, color) {
@@ -718,28 +793,32 @@ namespace hex::pl {
if (this->getEntryCount() == 0)
return;
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
this->drawCommentTooltip();
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
ImGui::TableNextColumn();
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04llX", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->m_template->getTypeName().c_str());
ImGui::SameLine(0, 0);
bool open = true;
ImGui::TextUnformatted("[");
ImGui::SameLine(0, 0);
ImGui::TextColored(ImColor(0xFF00FF00), "%llu", this->m_entryCount);
ImGui::SameLine(0, 0);
ImGui::TextUnformatted("]");
if (!this->isInlined()) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
this->drawCommentTooltip();
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
ImGui::TableNextColumn();
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04llX", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFF9BC64D), "%s", this->m_template->getTypeName().c_str());
ImGui::SameLine(0, 0);
ImGui::TableNextColumn();
ImGui::Text("%s", "{ ... }");
ImGui::TextUnformatted("[");
ImGui::SameLine(0, 0);
ImGui::TextColored(ImColor(0xFF00FF00), "%llu", this->m_entryCount);
ImGui::SameLine(0, 0);
ImGui::TextUnformatted("]");
ImGui::TableNextColumn();
ImGui::Text("%s", "{ ... }");
}
if (open) {
auto entry = this->m_template->clone();
@@ -750,22 +829,24 @@ namespace hex::pl {
}
delete entry;
ImGui::TreePop();
if (!this->isInlined())
ImGui::TreePop();
}
}
std::optional<u32> highlightBytes(size_t offset) override{
auto entry = this->m_template->clone();
ON_SCOPE_EXIT { delete entry; };
for (u64 address = this->getOffset(); address < this->getOffset() + this->getSize(); address += this->m_template->getSize()) {
entry->setOffset(address);
if (auto color = entry->highlightBytes(offset); color.has_value())
return color.value();
}
if (offset < this->getOffset() || offset >= this->getOffset() + this->getSize())
return { };
delete entry;
return { };
auto index = (offset - this->getOffset()) / this->m_template->getSize();
entry->setOffset(this->getOffset() + this->m_template->getSize() * index);
if (auto color = entry->highlightBytes(offset); color.has_value())
return color.value();
else
return { };
}
std::map<u64, u32> getHighlightedAddresses() override {
@@ -809,16 +890,25 @@ namespace hex::pl {
this->m_template = templ;
this->m_entryCount = count;
this->m_template->setColor(this->getColor());
this->setColor(this->m_template->getColor());
this->m_template->setEndian(templ->getEndian());
this->m_template->setParent(this);
}
[[nodiscard]] bool operator==(const PatternData &other) const override {
if (!areCommonPropertiesEqual<decltype(*this)>(other))
return false;
auto &otherArray = *static_cast<const PatternDataStaticArray*>(&other);
return *this->m_template == *otherArray.m_template && this->m_entryCount == otherArray.m_entryCount;
}
private:
PatternData *m_template;
size_t m_entryCount;
};
class PatternDataStruct : public PatternData {
class PatternDataStruct : public PatternData, public Inlinable {
public:
PatternDataStruct(u64 offset, size_t size, u32 color = 0) : PatternData(offset, size, color){
}
@@ -847,25 +937,30 @@ namespace hex::pl {
}
void createEntry(prv::Provider* &provider) override {
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
this->drawCommentTooltip();
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - (this->getSize() == 0 ? 0 : 1));
ImGui::TableNextColumn();
ImGui::Text("0x%04llX", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFFD69C56), "struct"); ImGui::SameLine(); ImGui::Text("%s", this->getTypeName().c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", "{ ... }");
bool open = true;
if (!this->isInlined()) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
this->drawCommentTooltip();
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - (this->getSize() == 0 ? 0 : 1));
ImGui::TableNextColumn();
ImGui::Text("0x%04llX", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFFD69C56), "struct"); ImGui::SameLine(); ImGui::Text("%s", this->getTypeName().c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", "{ ... }");
}
if (open) {
for (auto &member : this->m_sortedMembers)
member->draw(provider);
ImGui::TreePop();
if (!this->isInlined())
ImGui::TreePop();
}
}
@@ -927,12 +1022,28 @@ namespace hex::pl {
this->m_sortedMembers = this->m_members;
}
[[nodiscard]] bool operator==(const PatternData &other) const override {
if (!areCommonPropertiesEqual<decltype(*this)>(other))
return false;
auto &otherStruct = *static_cast<const PatternDataStruct*>(&other);
if (this->m_members.size() != otherStruct.m_members.size())
return false;
for (u64 i = 0; i < this->m_members.size(); i++) {
if (*this->m_members[i] != *otherStruct.m_members[i])
return false;
}
return true;
}
private:
std::vector<PatternData*> m_members;
std::vector<PatternData*> m_sortedMembers;
};
class PatternDataUnion : public PatternData {
class PatternDataUnion : public PatternData, public Inlinable {
public:
PatternDataUnion(u64 offset, size_t size, u32 color = 0) : PatternData(offset, size, color) {
@@ -962,25 +1073,30 @@ namespace hex::pl {
}
void createEntry(prv::Provider* &provider) override {
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
this->drawCommentTooltip();
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), std::max(this->getOffset() + this->getSize() - (this->getSize() == 0 ? 0 : 1), u64(0)));
ImGui::TableNextColumn();
ImGui::Text("0x%04llX", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFFD69C56), "union"); ImGui::SameLine(); ImGui::Text("%s", PatternData::getTypeName().c_str());
bool open = true;
ImGui::TableNextColumn();
ImGui::Text("%s", "{ ... }");
if (!this->isInlined()) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
this->drawCommentTooltip();
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), std::max(this->getOffset() + this->getSize() - (this->getSize() == 0 ? 0 : 1), u64(0)));
ImGui::TableNextColumn();
ImGui::Text("0x%04llX", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFFD69C56), "union"); ImGui::SameLine(); ImGui::Text("%s", PatternData::getTypeName().c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", "{ ... }");
}
if (open) {
for (auto &member : this->m_sortedMembers)
member->draw(provider);
if (!this->isInlined())
ImGui::TreePop();
}
@@ -1042,6 +1158,22 @@ namespace hex::pl {
this->m_sortedMembers = this->m_members;
}
[[nodiscard]] bool operator==(const PatternData &other) const override {
if (!areCommonPropertiesEqual<decltype(*this)>(other))
return false;
auto &otherUnion = *static_cast<const PatternDataUnion*>(&other);
if (this->m_members.size() != otherUnion.m_members.size())
return false;
for (u64 i = 0; i < this->m_members.size(); i++) {
if (*this->m_members[i] != *otherUnion.m_members[i])
return false;
}
return true;
}
private:
std::vector<PatternData*> m_members;
std::vector<PatternData*> m_sortedMembers;
@@ -1066,14 +1198,18 @@ namespace hex::pl {
bool foundValue = false;
for (auto &[entryValueLiteral, entryName] : this->m_enumValues) {
bool matches = std::visit([&, name = entryName](auto &&entryValue) {
if (value == entryValue) {
valueString += name;
foundValue = true;
return true;
}
bool matches = std::visit(overloaded {
[&, name = entryName](auto &&entryValue) {
if (value == entryValue) {
valueString += name;
foundValue = true;
return true;
}
return false;
return false;
},
[](std::string) { return false; },
[](PatternData*) { return false; }
}, entryValueLiteral);
if (matches)
break;
@@ -1083,14 +1219,14 @@ namespace hex::pl {
valueString += "???";
ImGui::TableNextRow();
ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
this->drawCommentTooltip();
ImGui::TableNextColumn();
if (ImGui::Selectable(("##PatternDataLine"s + std::to_string(this->getOffset())).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) {
EventManager::post<RequestSelectionChange>(Region { this->getOffset(), this->getSize() });
}
ImGui::SameLine();
ImGui::Text("%s", this->getVariableName().c_str());
ImGui::Text("%s", this->getDisplayName().c_str());
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
ImGui::TableNextColumn();
@@ -1111,12 +1247,28 @@ namespace hex::pl {
return this->m_enumValues;
}
void setEnumValues(const std::vector<std::pair<Token::IntegerLiteral, std::string>> &enumValues) {
void setEnumValues(const std::vector<std::pair<Token::Literal, std::string>> &enumValues) {
this->m_enumValues = enumValues;
}
[[nodiscard]] bool operator==(const PatternData &other) const override {
if (!areCommonPropertiesEqual<decltype(*this)>(other))
return false;
auto &otherEnum = *static_cast<const PatternDataEnum*>(&other);
if (this->m_enumValues.size() != otherEnum.m_enumValues.size())
return false;
for (u64 i = 0; i < this->m_enumValues.size(); i++) {
if (this->m_enumValues[i] != otherEnum.m_enumValues[i])
return false;
}
return true;
}
private:
std::vector<std::pair<Token::IntegerLiteral, std::string>> m_enumValues;
std::vector<std::pair<Token::Literal, std::string>> m_enumValues;
};
@@ -1132,20 +1284,22 @@ namespace hex::pl {
}
void createEntry(prv::Provider* &provider) override {
std::vector<u8> value(this->getSize(), 0);
provider->read(this->getOffset(), &value[0], value.size());
std::vector<u8> value(this->getParent()->getSize(), 0);
provider->read(this->getParent()->getOffset(), &value[0], value.size());
if (this->m_endian != std::endian::native)
if (this->getParent()->getEndian() == std::endian::little)
std::reverse(value.begin(), value.end());
ImGui::TableNextRow();
ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
ImGui::TableNextColumn();
ImGui::Text("%s", this->getVariableName().c_str());
ImGui::Text("%s", this->getDisplayName().c_str());
ImGui::TableNextColumn();
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
ImGui::TableNextColumn();
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset() + (this->m_bitOffset >> 3), this->getOffset() + ((this->m_bitOffset + this->m_bitSize) >> 3));
if (this->m_bitSize == 1)
ImGui::Text("0x%08llX bit %u", this->getOffset() + this->m_bitOffset / 8, (this->m_bitOffset + (this->m_bitSize - 1)) % 8);
else
ImGui::Text("0x%08llX bits %u - %u", this->getOffset() + this->m_bitOffset / 8, this->m_bitOffset % 8, this->m_bitOffset % 8 + (this->m_bitSize - 1) % 8);
ImGui::TableNextColumn();
if (this->m_bitSize == 1)
ImGui::Text("%u bit", this->m_bitSize);
@@ -1155,10 +1309,10 @@ namespace hex::pl {
ImGui::TextColored(ImColor(0xFF9BC64D), "bits");
ImGui::TableNextColumn();
{
u128 fieldValue = 0;
std::memcpy(&fieldValue, value.data() + (this->m_bitOffset / 8), (this->m_bitSize / 8) + 1);
u64 maskedValue = hex::extract((this->m_bitOffset + this->m_bitSize) - 1 - ((this->m_bitOffset / 8) * 8), this->m_bitOffset - ((this->m_bitOffset / 8) * 8), fieldValue);
ImGui::Text("%llu (0x%llX)", maskedValue, maskedValue);
u8 numBytes = (this->m_bitSize / 8) + 1;
u64 extractedValue = hex::extract(this->m_bitOffset + (this->m_bitSize - 1), this->m_bitOffset, value);
ImGui::Text("%llu (0x%llX)", extractedValue, extractedValue);
}
}
@@ -1175,16 +1329,29 @@ namespace hex::pl {
return this->m_bitSize;
}
[[nodiscard]] bool operator==(const PatternData &other) const override {
if (!areCommonPropertiesEqual<decltype(*this)>(other))
return false;
auto &otherBitfieldField = *static_cast<const PatternDataBitfieldField*>(&other);
return this->m_bitOffset == otherBitfieldField.m_bitOffset && this->m_bitSize == otherBitfieldField.m_bitSize;
}
private:
u8 m_bitOffset, m_bitSize;
};
class PatternDataBitfield : public PatternData {
class PatternDataBitfield : public PatternData, public Inlinable {
public:
PatternDataBitfield(u64 offset, size_t size, u32 color = 0) : PatternData(offset, size, color) {
}
PatternDataBitfield(const PatternDataBitfield &other) : PatternData(other) {
for (auto &field : other.m_fields)
this->m_fields.push_back(field->clone());
}
~PatternDataBitfield() override {
for (auto field : this->m_fields)
delete field;
@@ -1198,35 +1365,39 @@ namespace hex::pl {
std::vector<u8> value(this->getSize(), 0);
provider->read(this->getOffset(), &value[0], value.size());
if (this->m_endian != std::endian::native)
if (this->m_endian == std::endian::little)
std::reverse(value.begin(), value.end());
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool open = ImGui::TreeNodeEx(this->getVariableName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
this->drawCommentTooltip();
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04llX", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFFD69C56), "bitfield"); ImGui::SameLine(); ImGui::Text("%s", PatternData::getTypeName().c_str());
ImGui::TableNextColumn();
bool open = true;
if (!this->isInlined()) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
this->drawCommentTooltip();
ImGui::TableNextColumn();
ImGui::TableNextColumn();
ImGui::Text("0x%08llX : 0x%08llX", this->getOffset(), this->getOffset() + this->getSize() - 1);
ImGui::TableNextColumn();
ImGui::Text("0x%04llX", this->getSize());
ImGui::TableNextColumn();
ImGui::TextColored(ImColor(0xFFD69C56), "bitfield"); ImGui::SameLine(); ImGui::Text("%s", PatternData::getTypeName().c_str());
ImGui::TableNextColumn();
std::string valueString = "{ ";
for (auto i : value)
valueString += hex::format("{0:02X} ", i);
valueString += "}";
std::string valueString = "{ ";
for (auto i : value)
valueString += hex::format("{0:02X} ", i);
valueString += "}";
ImGui::TextUnformatted(valueString.c_str());
ImGui::TextUnformatted(valueString.c_str());
}
if (open) {
for (auto &field : this->m_fields)
field->draw(provider);
ImGui::TreePop();
if (!this->isInlined())
ImGui::TreePop();
}
}
@@ -1242,8 +1413,27 @@ namespace hex::pl {
void setFields(const std::vector<PatternData*> &fields) {
this->m_fields = fields;
for (auto &field : this->m_fields)
for (auto &field : this->m_fields) {
field->setSize(this->getSize());
field->setColor(this->getColor());
field->setParent(this);
}
}
[[nodiscard]] bool operator==(const PatternData &other) const override {
if (!areCommonPropertiesEqual<decltype(*this)>(other))
return false;
auto &otherBitfield = *static_cast<const PatternDataBitfield*>(&other);
if (this->m_fields.size() != otherBitfield.m_fields.size())
return false;
for (u64 i = 0; i < this->m_fields.size(); i++) {
if (*this->m_fields[i] != *otherBitfield.m_fields[i])
return false;
}
return true;
}
private:

View File

@@ -21,6 +21,8 @@ namespace hex::pl {
class Evaluator;
class PatternData;
class ASTNode;
class PatternLanguage {
public:
PatternLanguage();
@@ -39,9 +41,12 @@ namespace hex::pl {
Validator *m_validator;
Evaluator *m_evaluator;
std::vector<ASTNode*> m_currAST;
prv::Provider *m_provider = nullptr;
std::endian m_defaultEndian = std::endian::native;
u32 m_recursionLimit = 32;
u32 m_evalDepth;
u32 m_arrayLimit;
std::optional<std::pair<u32, std::string>> m_currError;
};

View File

@@ -6,8 +6,12 @@
#include <string>
#include <variant>
#include <hex/helpers/utils.hpp>
namespace hex::pl {
class PatternData;
class Token {
public:
enum class Type : u64 {
@@ -31,6 +35,7 @@ namespace hex::pl {
If,
Else,
Parent,
This,
While,
Function,
Return,
@@ -85,6 +90,8 @@ namespace hex::pl {
Boolean = 0x14,
Float = 0x42,
Double = 0x82,
String = 0x15,
Auto = 0x16,
CustomType = 0x00,
Padding = 0x1F,
@@ -108,8 +115,21 @@ namespace hex::pl {
EndOfProgram
};
using IntegerLiteral = std::variant<char, bool, u8, s8, u16, s16, u32, s32, u64, s64, u128, s128, float, double>;
using ValueTypes = std::variant<Keyword, std::string, Operator, IntegerLiteral, ValueType, Separator>;
struct Identifier {
explicit Identifier(std::string identifier) : m_identifier(std::move(identifier)) { }
[[nodiscard]]
const std::string &get() const { return this->m_identifier; }
auto operator<=>(const Identifier&) const = default;
bool operator==(const Identifier&) const = default;
private:
std::string m_identifier;
};
using Literal = std::variant<char, bool, u128, s128, double, std::string, PatternData*>;
using ValueTypes = std::variant<Keyword, Identifier, Operator, Literal, ValueType, Separator>;
Token(Type type, auto value, u32 lineNumber) : type(type), value(value), lineNumber(lineNumber) {
@@ -131,6 +151,58 @@ namespace hex::pl {
return static_cast<u32>(type) >> 4;
}
static u128 literalToUnsigned(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](std::string) -> u128 { throw std::string("expected integral type, got string"); },
[](PatternData*) -> u128 { throw std::string("expected integral type, got custom type"); },
[](auto &&value) -> u128 { return value; }
},
literal);
}
static s128 literalToSigned(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](std::string) -> s128 { throw std::string("expected integral type, got string"); },
[](PatternData*) -> s128 { throw std::string("expected integral type, got custom type"); },
[](auto &&value) -> s128 { return value; }
},
literal);
}
static double literalToFloatingPoint(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](std::string) -> double { throw std::string("expected integral type, got string"); },
[](PatternData*) -> double { throw std::string("expected integral type, got custom type"); },
[](auto &&value) -> double { return value; }
},
literal);
}
static bool literalToBoolean(const pl::Token::Literal &literal) {
return std::visit(overloaded {
[](std::string) -> bool { throw std::string("expected integral type, got string"); },
[](PatternData*) -> bool { throw std::string("expected integral type, got custom type"); },
[](auto &&value) -> bool { return value != 0; }
},
literal);
}
static std::string literalToString(const pl::Token::Literal &literal, bool cast) {
if (!cast && std::get_if<std::string>(&literal) == nullptr)
throw std::string("expected string type, got integral");
return std::visit(overloaded {
[](std::string value) -> std::string { return value; },
[](u128 value) -> std::string { return std::to_string(u64(value)); },
[](s128 value) -> std::string { return std::to_string(s64(value)); },
[](bool value) -> std::string { return value ? "true" : "false"; },
[](char value) -> std::string { return std::string() + value; },
[](PatternData*) -> std::string { throw std::string("expected integral type, got custom type"); },
[](auto &&value) -> std::string { return std::to_string(value); }
},
literal);
}
[[nodiscard]] constexpr static auto getTypeName(const pl::Token::ValueType type) {
switch (type) {
case ValueType::Signed8Bit: return "s8";
@@ -147,6 +219,7 @@ namespace hex::pl {
case ValueType::Double: return "double";
case ValueType::Character: return "char";
case ValueType::Character16: return "char16";
case ValueType::Padding: return "padding";
default: return "< ??? >";
}
}
@@ -204,14 +277,15 @@ namespace hex::pl {
#define KEYWORD_IF COMPONENT(Keyword, If)
#define KEYWORD_ELSE COMPONENT(Keyword, Else)
#define KEYWORD_PARENT COMPONENT(Keyword, Parent)
#define KEYWORD_THIS COMPONENT(Keyword, This)
#define KEYWORD_WHILE COMPONENT(Keyword, While)
#define KEYWORD_FUNCTION COMPONENT(Keyword, Function)
#define KEYWORD_RETURN COMPONENT(Keyword, Return)
#define KEYWORD_NAMESPACE COMPONENT(Keyword, Namespace)
#define INTEGER hex::pl::Token::Type::Integer, hex::pl::Token::IntegerLiteral(u64(0))
#define INTEGER hex::pl::Token::Type::Integer, hex::pl::Token::Literal(u128(0))
#define IDENTIFIER hex::pl::Token::Type::Identifier, ""
#define STRING hex::pl::Token::Type::String, ""
#define STRING hex::pl::Token::Type::String, hex::pl::Token::Literal("")
#define OPERATOR_AT COMPONENT(Operator, AtDeclaration)
#define OPERATOR_ASSIGNMENT COMPONENT(Operator, Assignment)

View File

@@ -19,11 +19,11 @@ namespace hex::prv {
Provider();
virtual ~Provider();
virtual bool isAvailable() = 0;
virtual bool isReadable() = 0;
virtual bool isWritable() = 0;
virtual bool isResizable() = 0;
virtual bool isSavable() = 0;
virtual bool isAvailable() const = 0;
virtual bool isReadable() const = 0;
virtual bool isWritable() const = 0;
virtual bool isResizable() const = 0;
virtual bool isSavable() const = 0;
virtual void read(u64 offset, void *buffer, size_t size, bool overlays = true);
virtual void readRelative(u64 offset, void *buffer, size_t size, bool overlays = true);
@@ -37,35 +37,37 @@ namespace hex::prv {
virtual void readRaw(u64 offset, void *buffer, size_t size) = 0;
virtual void writeRaw(u64 offset, const void *buffer, size_t size) = 0;
virtual size_t getActualSize() = 0;
virtual size_t getActualSize() const = 0;
void applyOverlays(u64 offset, void *buffer, size_t size);
std::map<u64, u8>& getPatches();
const std::map<u64, u8>& getPatches() const;
void applyPatches();
[[nodiscard]] Overlay* newOverlay();
void deleteOverlay(Overlay *overlay);
[[nodiscard]] const std::list<Overlay*>& getOverlays();
u32 getPageCount();
u32 getPageCount() const;
u32 getCurrentPage() const;
void setCurrentPage(u32 page);
virtual void setBaseAddress(u64 address);
virtual u64 getBaseAddress();
virtual size_t getSize();
virtual std::optional<u32> getPageOfAddress(u64 address);
virtual u64 getBaseAddress() const;
virtual size_t getSize() const;
virtual std::optional<u32> getPageOfAddress(u64 address) const;
virtual std::vector<std::pair<std::string, std::string>> getDataInformation() = 0;
[[nodiscard]] virtual std::string getName() const = 0;
[[nodiscard]] virtual std::vector<std::pair<std::string, std::string>> getDataInformation() const = 0;
void addPatch(u64 offset, const void *buffer, size_t size);
void undo();
void redo();
bool canUndo();
bool canRedo();
bool canUndo() const;
bool canRedo() const;
protected:
u32 m_currPage = 0;

View File

@@ -3,6 +3,8 @@
#include <hex.hpp>
#include <imgui.h>
#define IMGUI_DEFINE_MATH_OPERATORS
#include <imgui_internal.h>
#include <imgui_imhex_extensions.h>
#include <fontawesome_font.h>
@@ -40,6 +42,7 @@ namespace hex {
static void drawCommonInterfaces();
static void showMessagePopup(const std::string &message);
static void showErrorPopup(const std::string &errorMessage);
static void showFatalPopup(const std::string &errorMessage);
@@ -49,15 +52,13 @@ namespace hex {
bool& getWindowOpenState();
const std::string& getUnlocalizedName() const;
[[nodiscard]] const std::string& getUnlocalizedName() const;
protected:
void discardNavigationRequests();
void confirmButtons(const std::string &textLeft, const std::string &textRight, const std::function<void()> &leftButtonFn, const std::function<void()> &rightButtonFn);
static void confirmButtons(const std::string &textLeft, const std::string &textRight, const std::function<void()> &leftButtonFn, const std::function<void()> &rightButtonFn);
static void discardNavigationRequests();
static inline std::string toWindowName(const std::string &unlocalizedName) {
return LangEntry(unlocalizedName) + "##" + unlocalizedName;
return LangEntry(unlocalizedName) + "###" + unlocalizedName;
}
private:

View File

@@ -97,6 +97,9 @@ namespace hex {
if (!json[unlocalizedCategory].contains(unlocalizedName))
return defaultValue;
if (!json[unlocalizedCategory][unlocalizedName].is_number())
json[unlocalizedCategory][unlocalizedName] = defaultValue;
return json[unlocalizedCategory][unlocalizedName].get<s64>();
}
@@ -108,6 +111,9 @@ namespace hex {
if (!json[unlocalizedCategory].contains(unlocalizedName))
return defaultValue;
if (!json[unlocalizedCategory][unlocalizedName].is_string())
json[unlocalizedCategory][unlocalizedName] = defaultValue;
return json[unlocalizedCategory][unlocalizedName].get<std::string>();
}
@@ -119,6 +125,12 @@ namespace hex {
if (!json[unlocalizedCategory].contains(unlocalizedName))
return defaultValue;
if (!json[unlocalizedCategory][unlocalizedName].is_array())
json[unlocalizedCategory][unlocalizedName] = defaultValue;
if (!json[unlocalizedCategory][unlocalizedName].array().empty() && !json[unlocalizedCategory][unlocalizedName][0].is_string())
json[unlocalizedCategory][unlocalizedName] = defaultValue;
return json[unlocalizedCategory][unlocalizedName].get<std::vector<std::string>>();
}
@@ -155,7 +167,7 @@ namespace hex {
/* Pattern Language Functions */
void ContentRegistry::PatternLanguageFunctions::add(const Namespace &ns, const std::string &name, u32 parameterCount, const std::function<hex::pl::ASTNode*(hex::pl::Evaluator&, std::vector<hex::pl::ASTNode*>&)> &func) {
void ContentRegistry::PatternLanguageFunctions::add(const Namespace &ns, const std::string &name, u32 parameterCount, const ContentRegistry::PatternLanguageFunctions::Callback &func) {
std::string functionName;
for (auto &scope : ns)
functionName += scope + "::";

View File

@@ -43,4 +43,38 @@ namespace hex {
return SharedData::bookmarkEntries;
}
prv::Provider* ImHexApi::Provider::get() {
if (!ImHexApi::Provider::isValid())
return nullptr;
return SharedData::providers[SharedData::currentProvider];
}
const std::vector<prv::Provider*>& ImHexApi::Provider::getProviders() {
return SharedData::providers;
}
bool ImHexApi::Provider::isValid() {
return !SharedData::providers.empty();
}
void ImHexApi::Provider::add(prv::Provider *provider) {
SharedData::providers.push_back(provider);
SharedData::currentProvider = SharedData::providers.size() - 1;
}
void ImHexApi::Provider::remove(prv::Provider *provider) {
auto &providers = SharedData::providers;
auto it = std::find(providers.begin(), providers.end(), provider);
providers.erase(it);
if (it - providers.begin() == SharedData::currentProvider)
SharedData::currentProvider = 0;
delete provider;
}
}

View File

@@ -3,7 +3,7 @@
namespace hex {
File::File(const std::string &path, Mode mode) {
File::File(const std::string &path, Mode mode) : m_path(path) {
if (mode == File::Mode::Read)
this->m_file = fopen64(path.c_str(), "rb");
else if (mode == File::Mode::Write)
@@ -13,18 +13,41 @@ namespace hex {
this->m_file = fopen64(path.c_str(), "w+b");
}
File::File() {
this->m_file = nullptr;
}
File::File(File &&other) noexcept {
this->m_file = other.m_file;
other.m_file = nullptr;
}
File::~File() {
if (isValid())
fclose(this->m_file);
this->close();
}
void File::seek(u64 offset) {
fseeko64(this->m_file, offset, SEEK_SET);
}
void File::close() {
if (isValid()) {
fclose(this->m_file);
this->m_file = nullptr;
}
}
size_t File::readBuffer(u8 *buffer, size_t size) {
if (!isValid()) return 0;
return fread(buffer, size, 1, this->m_file);
}
std::vector<u8> File::readBytes(size_t numBytes) {
if (!isValid()) return { };
std::vector<u8> bytes(numBytes ?: getSize());
auto bytesRead = fread(bytes.data(), bytes.size(), 1, this->m_file);
auto bytesRead = fread(bytes.data(), 1, bytes.size(), this->m_file);
bytes.resize(bytesRead);
@@ -32,18 +55,32 @@ namespace hex {
}
std::string File::readString(size_t numBytes) {
if (!isValid()) return { };
return reinterpret_cast<char*>(readBytes(numBytes).data());
}
void File::write(const u8 *buffer, size_t size) {
if (!isValid()) return;
fwrite(buffer, size, 1, this->m_file);
}
void File::write(const std::vector<u8> &bytes) {
fwrite(bytes.data(), bytes.size(), 1, this->m_file);
if (!isValid()) return;
fwrite(bytes.data(), 1, bytes.size(), this->m_file);
}
void File::write(const std::string &string) {
if (!isValid()) return;
fwrite(string.data(), string.size(), 1, this->m_file);
}
size_t File::getSize() {
size_t File::getSize() const {
if (!isValid()) return 0;
auto startPos = ftello64(this->m_file);
fseeko64(this->m_file, 0, SEEK_END);
size_t size = ftello64(this->m_file);
@@ -53,7 +90,18 @@ namespace hex {
}
void File::setSize(u64 size) {
if (!isValid()) return;
ftruncate64(fileno(this->m_file), size);
}
void File::flush() {
fflush(this->m_file);
}
void File::remove() {
this->close();
std::remove(this->m_path.c_str());
}
}

View File

@@ -74,7 +74,7 @@ namespace hex::magic {
auto magicFiles = getMagicFiles();
if (magicFiles.has_value()) {
magic_t ctx = magic_open(MAGIC_MIME);
magic_t ctx = magic_open(MAGIC_MIME_TYPE);
ON_SCOPE_EXIT { magic_close(ctx); };
if (magic_load(ctx, magicFiles->c_str()) == 0)

View File

@@ -32,27 +32,56 @@ namespace hex {
CoTaskMemFree(wAppDataPath);
}
std::vector<std::filesystem::path> paths = { parentDir, appDataDir / "imhex" };
std::vector<std::string> results;
switch (path) {
case ImHexPath::Patterns:
return { (parentDir / "pattern_language").string() };
std::transform(paths.begin(), paths.end(), std::back_inserter(results), [](auto &path){
return (path / "patterns").string();
});
break;
case ImHexPath::PatternsInclude:
return { (parentDir / "includes").string() };
std::transform(paths.begin(), paths.end(), std::back_inserter(results), [](auto &path){
return (path / "includes").string();
});
break;
case ImHexPath::Magic:
return { (parentDir / "magic").string() };
std::transform(paths.begin(), paths.end(), std::back_inserter(results), [](auto &path){
return (path / "magic").string();
});
break;
case ImHexPath::Python:
return { parentDir.string() };
std::transform(paths.begin(), paths.end(), std::back_inserter(results), [](auto &path){
return (path / "python").string();
});
break;
case ImHexPath::Plugins:
return { (parentDir / "plugins").string() };
std::transform(paths.begin(), paths.end(), std::back_inserter(results), [](auto &path){
return (path / "plugins").string();
});
break;
case ImHexPath::Yara:
return { (parentDir / "yara").string() };
std::transform(paths.begin(), paths.end(), std::back_inserter(results), [](auto &path){
return (path / "yara").string();
});
break;
case ImHexPath::Config:
return { (appDataDir / "imhex" / "config").string() };
case ImHexPath::Resources:
return { (parentDir / "resources").string() };
std::transform(paths.begin(), paths.end(), std::back_inserter(results), [](auto &path){
return (path / "resources").string();
});
break;
case ImHexPath::Constants:
return { (parentDir / "constants").string() };
std::transform(paths.begin(), paths.end(), std::back_inserter(results), [](auto &path){
return (path / "constants").string();
});
break;
default: __builtin_unreachable();
}
return results;
#elif defined(OS_MACOS)
return { getPathForMac(path) };
#else

View File

@@ -5,7 +5,10 @@
namespace hex {
std::vector<std::function<void()>> SharedData::deferredCalls;
prv::Provider *SharedData::currentProvider;
std::vector<prv::Provider*> SharedData::providers;
u32 SharedData::currentProvider;
std::map<std::string, std::vector<ContentRegistry::Settings::Entry>> SharedData::settingsEntries;
nlohmann::json SharedData::settingsJson;
std::vector<ContentRegistry::CommandPaletteCommands::Entry> SharedData::commandPaletteCommands;
@@ -14,7 +17,7 @@ namespace hex {
std::vector<ContentRegistry::Tools::Entry> SharedData::toolsEntries;
std::vector<ContentRegistry::DataInspector::Entry> SharedData::dataInspectorEntries;
u32 SharedData::patternPaletteOffset;
std::string SharedData::errorPopupMessage;
std::string SharedData::popupMessage;
std::list<ImHexApi::Bookmarks::Entry> SharedData::bookmarkEntries;
std::vector<pl::PatternData*> SharedData::patternData;

View File

@@ -169,7 +169,7 @@ namespace hex {
void openWebpage(std::string url) {
if (!url.starts_with("http://") && !url.starts_with("https://"))
if (url.find("://") == std::string::npos)
url = "https://" + url;
#if defined(OS_WINDOWS)
@@ -184,20 +184,20 @@ namespace hex {
}
void openFileBrowser(const std::string &title, DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::string)> &callback) {
void openFileBrowser(const std::string &title, DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::string)> &callback, const std::string &defaultPath) {
NFD::Init();
nfdchar_t *outPath;
nfdresult_t result;
switch (mode) {
case DialogMode::Open:
result = NFD::OpenDialog(outPath, validExtensions.data(), validExtensions.size(), nullptr);
result = NFD::OpenDialog(outPath, validExtensions.data(), validExtensions.size(), defaultPath.c_str());
break;
case DialogMode::Save:
result = NFD::SaveDialog(outPath, validExtensions.data(), validExtensions.size(), nullptr);
result = NFD::SaveDialog(outPath, validExtensions.data(), validExtensions.size(), defaultPath.c_str());
break;
case DialogMode::Folder:
result = NFD::PickFolder(outPath, nullptr);
result = NFD::PickFolder(outPath, defaultPath.c_str());
break;
default: __builtin_unreachable();
}

File diff suppressed because it is too large Load Diff

View File

@@ -28,9 +28,9 @@ namespace hex::pl {
return string.find_first_not_of("0123456789ABCDEFabcdef.xUL");
}
std::optional<Token::IntegerLiteral> parseIntegerLiteral(const std::string &string) {
std::optional<Token::Literal> parseIntegerLiteral(const std::string &string) {
Token::ValueType type = Token::ValueType::Any;
Token::IntegerLiteral result;
Token::Literal result;
u8 base;
@@ -38,20 +38,8 @@ namespace hex::pl {
auto numberData = std::string_view(string).substr(0, endPos);
if (numberData.ends_with('U')) {
type = Token::ValueType::Unsigned32Bit;
numberData.remove_suffix(1);
} else if (numberData.ends_with("UL")) {
type = Token::ValueType::Unsigned64Bit;
numberData.remove_suffix(2);
} else if (numberData.ends_with("ULL")) {
type = Token::ValueType::Unsigned128Bit;
numberData.remove_suffix(3);
} else if (numberData.ends_with("L")) {
type = Token::ValueType::Signed64Bit;
numberData.remove_suffix(1);
} else if (numberData.ends_with("LL")) {
type = Token::ValueType::Signed128Bit;
numberData.remove_suffix(2);
} else if (!numberData.starts_with("0x") && !numberData.starts_with("0b")) {
if (numberData.ends_with('F')) {
type = Token::ValueType::Float;
@@ -98,7 +86,7 @@ namespace hex::pl {
} else return { };
if (type == Token::ValueType::Any)
type = Token::ValueType::Signed32Bit;
type = Token::ValueType::Signed128Bit;
if (numberData.length() == 0)
@@ -119,10 +107,6 @@ namespace hex::pl {
}
switch (type) {
case Token::ValueType::Unsigned32Bit: return { u32(integer) };
case Token::ValueType::Signed32Bit: return { s32(integer) };
case Token::ValueType::Unsigned64Bit: return { u64(integer) };
case Token::ValueType::Signed64Bit: return { s64(integer) };
case Token::ValueType::Unsigned128Bit: return { u128(integer) };
case Token::ValueType::Signed128Bit: return { s128(integer) };
default: return { };
@@ -379,7 +363,7 @@ namespace hex::pl {
auto [c, charSize] = character.value();
tokens.emplace_back(VALUE_TOKEN(Integer, c));
tokens.emplace_back(VALUE_TOKEN(Integer, Token::Literal(c)));
offset += charSize;
} else if (c == '\"') {
auto string = getStringLiteral(code.substr(offset));
@@ -389,9 +373,9 @@ namespace hex::pl {
auto [s, stringSize] = string.value();
tokens.emplace_back(VALUE_TOKEN(String, s));
tokens.emplace_back(VALUE_TOKEN(String, Token::Literal(s)));
offset += stringSize;
} else if (std::isalpha(c)) {
} else if (std::isalpha(c) || c == '_') {
std::string identifier = matchTillInvalid(&code[offset], [](char c) -> bool { return std::isalnum(c) || c == '_'; });
// Check for reserved keywords
@@ -415,11 +399,13 @@ namespace hex::pl {
else if (identifier == "else")
tokens.emplace_back(TOKEN(Keyword, Else));
else if (identifier == "false")
tokens.emplace_back(VALUE_TOKEN(Integer, bool(0)));
tokens.emplace_back(VALUE_TOKEN(Integer, Token::Literal(false)));
else if (identifier == "true")
tokens.emplace_back(VALUE_TOKEN(Integer, bool(1)));
tokens.emplace_back(VALUE_TOKEN(Integer, Token::Literal(true)));
else if (identifier == "parent")
tokens.emplace_back(TOKEN(Keyword, Parent));
else if (identifier == "this")
tokens.emplace_back(TOKEN(Keyword, This));
else if (identifier == "while")
tokens.emplace_back(TOKEN(Keyword, While));
else if (identifier == "fn")
@@ -460,13 +446,17 @@ namespace hex::pl {
tokens.emplace_back(TOKEN(ValueType, Character16));
else if (identifier == "bool")
tokens.emplace_back(TOKEN(ValueType, Boolean));
else if (identifier == "str")
tokens.emplace_back(TOKEN(ValueType, String));
else if (identifier == "padding")
tokens.emplace_back(TOKEN(ValueType, Padding));
else if (identifier == "auto")
tokens.emplace_back(TOKEN(ValueType, Auto));
// If it's not a keyword and a builtin type, it has to be an identifier
else
tokens.emplace_back(VALUE_TOKEN(Identifier, identifier));
tokens.emplace_back(VALUE_TOKEN(Identifier, Token::Identifier(identifier)));
offset += identifier.length();
} else if (std::isdigit(c)) {
@@ -476,7 +466,7 @@ namespace hex::pl {
throwLexerError("invalid integer literal", lineNumber);
tokens.emplace_back(VALUE_TOKEN(Integer, integer.value()));
tokens.emplace_back(VALUE_TOKEN(Integer, Token::Literal(integer.value())));
offset += getIntegerLiteralLength(&code[offset]);
} else
throwLexerError("unknown token", lineNumber);

View File

@@ -1,13 +1,9 @@
#include <hex/pattern_language/parser.hpp>
#include <hex/helpers/fmt.hpp>
#include <optional>
#define MATCHES(x) (begin() && x)
#define TO_NUMERIC_EXPRESSION(node) new ASTNodeNumericExpression((node), new ASTNodeIntegerLiteral(s32(0)), Token::Operator::Plus)
// Definition syntax:
// [A] : Either A or no token
// [A|B] : Either A, B or no token
@@ -33,10 +29,7 @@ namespace hex::pl {
};
while (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) {
if (MATCHES(sequence(STRING)))
params.push_back(parseStringLiteral());
else
params.push_back(parseMathematicalExpression());
params.push_back(parseMathematicalExpression());
if (MATCHES(sequence(SEPARATOR_COMMA, SEPARATOR_ROUNDBRACKETCLOSE)))
throwParseError("unexpected ',' at end of function parameter list", -1);
@@ -49,18 +42,18 @@ namespace hex::pl {
paramCleanup.release();
return new ASTNodeFunctionCall(functionName, params);
return create(new ASTNodeFunctionCall(functionName, params));
}
ASTNode* Parser::parseStringLiteral() {
return new ASTNodeStringLiteral(getValue<std::string>(-1));
return create(new ASTNodeLiteral(getValue<Token::Literal>(-1)));
}
std::string Parser::parseNamespaceResolution() {
std::string name;
while (true) {
name += getValue<std::string>(-1);
name += getValue<Token::Identifier>(-1).get();
if (MATCHES(sequence(OPERATOR_SCOPERESOLUTION, IDENTIFIER))) {
name += "::";
@@ -77,14 +70,17 @@ namespace hex::pl {
std::string typeName;
while (true) {
typeName += getValue<std::string>(-1);
typeName += getValue<Token::Identifier>(-1).get();
if (MATCHES(sequence(OPERATOR_SCOPERESOLUTION, IDENTIFIER))) {
if (peek(OPERATOR_SCOPERESOLUTION, 0) && peek(IDENTIFIER, 1)) {
typeName += "::";
continue;
} else {
return new ASTNodeScopeResolution({ typeName, getValue<std::string>(-1) });
if (!this->m_types.contains(typeName))
throwParseError(hex::format("cannot access scope of invalid type '{}'", typeName), -1);
return create(new ASTNodeScopeResolution(this->m_types[typeName]->clone(), getValue<Token::Identifier>(-1).get()));
}
}
else
@@ -97,9 +93,11 @@ namespace hex::pl {
// <Identifier[.]...>
ASTNode* Parser::parseRValue(ASTNodeRValue::Path &path) {
if (peek(IDENTIFIER, -1))
path.push_back(getValue<std::string>(-1));
path.push_back(getValue<Token::Identifier>(-1).get());
else if (peek(KEYWORD_PARENT, -1))
path.emplace_back("parent");
else if (peek(KEYWORD_THIS, -1))
path.emplace_back("this");
if (MATCHES(sequence(SEPARATOR_SQUAREBRACKETOPEN))) {
path.push_back(parseMathematicalExpression());
@@ -113,13 +111,15 @@ namespace hex::pl {
else
throwParseError("expected member name or 'parent' keyword", -1);
} else
return new ASTNodeRValue(path);
return create(new ASTNodeRValue(path));
}
// <Integer|((parseMathematicalExpression))>
ASTNode* Parser::parseFactor() {
if (MATCHES(sequence(INTEGER)))
return TO_NUMERIC_EXPRESSION(new ASTNodeIntegerLiteral(getValue<Token::IntegerLiteral>(-1)));
return new ASTNodeLiteral(getValue<Token::Literal>(-1));
else if (peek(OPERATOR_PLUS) || peek(OPERATOR_MINUS) || peek(OPERATOR_BITNOT) || peek(OPERATOR_BOOLNOT))
return this->parseMathematicalExpression();
else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETOPEN))) {
auto node = this->parseMathematicalExpression();
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) {
@@ -135,34 +135,51 @@ namespace hex::pl {
if (isFunction) {
return TO_NUMERIC_EXPRESSION(this->parseFunctionCall());
return this->parseFunctionCall();
} else if (peek(OPERATOR_SCOPERESOLUTION, 0)) {
return TO_NUMERIC_EXPRESSION(this->parseScopeResolution());
return this->parseScopeResolution();
} else {
ASTNodeRValue::Path path;
return TO_NUMERIC_EXPRESSION(this->parseRValue(path));
return this->parseRValue(path);
}
} else if (MATCHES(oneOf(KEYWORD_PARENT))) {
} else if (MATCHES(oneOf(KEYWORD_PARENT, KEYWORD_THIS))) {
ASTNodeRValue::Path path;
return TO_NUMERIC_EXPRESSION(this->parseRValue(path));
return this->parseRValue(path);
} else if (MATCHES(sequence(OPERATOR_DOLLAR))) {
return TO_NUMERIC_EXPRESSION(new ASTNodeRValue({ "$" }));
return new ASTNodeRValue({ "$" });
} else if (MATCHES(oneOf(OPERATOR_ADDRESSOF, OPERATOR_SIZEOF) && sequence(SEPARATOR_ROUNDBRACKETOPEN))) {
auto op = getValue<Token::Operator>(-2);
if (!MATCHES(oneOf(IDENTIFIER, KEYWORD_PARENT))) {
if (!MATCHES(oneOf(IDENTIFIER, KEYWORD_PARENT, KEYWORD_THIS))) {
throwParseError("expected rvalue identifier");
}
ASTNodeRValue::Path path;
auto node = new ASTNodeTypeOperator(op, this->parseRValue(path));
auto node = create(new ASTNodeTypeOperator(op, this->parseRValue(path)));
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) {
delete node;
throwParseError("expected closing parenthesis");
}
return TO_NUMERIC_EXPRESSION(node);
return node;
} else
throwParseError("expected integer or parenthesis");
throwParseError("expected value or parenthesis");
}
ASTNode* Parser::parseCastExpression() {
if (peek(KEYWORD_BE) || peek(KEYWORD_LE) || peek(VALUETYPE_ANY)) {
auto type = parseType(true);
auto builtinType = dynamic_cast<ASTNodeBuiltinType*>(type->getType());
if (builtinType == nullptr)
throwParseError("invalid type used for pointer size", -1);
if (!peek(SEPARATOR_ROUNDBRACKETOPEN))
throwParseError("expected '(' before cast expression", -1);
auto node = parseFactor();
return new ASTNodeCast(node, type);
} else return parseFactor();
}
// <+|-|!|~> (parseFactor)
@@ -170,10 +187,12 @@ namespace hex::pl {
if (MATCHES(oneOf(OPERATOR_PLUS, OPERATOR_MINUS, OPERATOR_BOOLNOT, OPERATOR_BITNOT))) {
auto op = getValue<Token::Operator>(-1);
return new ASTNodeNumericExpression(new ASTNodeIntegerLiteral(0), this->parseFactor(), op);
return create(new ASTNodeMathematicalExpression(new ASTNodeLiteral(0), this->parseCastExpression(), op));
} else if (MATCHES(sequence(STRING))) {
return this->parseStringLiteral();
}
return this->parseFactor();
return this->parseCastExpression();
}
// (parseUnaryExpression) <*|/|%> (parseUnaryExpression)
@@ -184,7 +203,7 @@ namespace hex::pl {
while (MATCHES(oneOf(OPERATOR_STAR, OPERATOR_SLASH, OPERATOR_PERCENT))) {
auto op = getValue<Token::Operator>(-1);
node = new ASTNodeNumericExpression(node, this->parseUnaryExpression(), op);
node = create(new ASTNodeMathematicalExpression(node, this->parseUnaryExpression(), op));
}
nodeCleanup.release();
@@ -200,7 +219,7 @@ namespace hex::pl {
while (MATCHES(variant(OPERATOR_PLUS, OPERATOR_MINUS))) {
auto op = getValue<Token::Operator>(-1);
node = new ASTNodeNumericExpression(node, this->parseMultiplicativeExpression(), op);
node = create(new ASTNodeMathematicalExpression(node, this->parseMultiplicativeExpression(), op));
}
nodeCleanup.release();
@@ -216,7 +235,7 @@ namespace hex::pl {
while (MATCHES(variant(OPERATOR_SHIFTLEFT, OPERATOR_SHIFTRIGHT))) {
auto op = getValue<Token::Operator>(-1);
node = new ASTNodeNumericExpression(node, this->parseAdditiveExpression(), op);
node = create(new ASTNodeMathematicalExpression(node, this->parseAdditiveExpression(), op));
}
nodeCleanup.release();
@@ -232,7 +251,7 @@ namespace hex::pl {
while (MATCHES(sequence(OPERATOR_BOOLGREATERTHAN) || sequence(OPERATOR_BOOLLESSTHAN) || sequence(OPERATOR_BOOLGREATERTHANOREQUALS) || sequence(OPERATOR_BOOLLESSTHANOREQUALS))) {
auto op = getValue<Token::Operator>(-1);
node = new ASTNodeNumericExpression(node, this->parseShiftExpression(), op);
node = create(new ASTNodeMathematicalExpression(node, this->parseShiftExpression(), op));
}
nodeCleanup.release();
@@ -248,7 +267,7 @@ namespace hex::pl {
while (MATCHES(sequence(OPERATOR_BOOLEQUALS) || sequence(OPERATOR_BOOLNOTEQUALS))) {
auto op = getValue<Token::Operator>(-1);
node = new ASTNodeNumericExpression(node, this->parseRelationExpression(), op);
node = create(new ASTNodeMathematicalExpression(node, this->parseRelationExpression(), op));
}
nodeCleanup.release();
@@ -263,7 +282,7 @@ namespace hex::pl {
auto nodeCleanup = SCOPE_GUARD { delete node; };
while (MATCHES(sequence(OPERATOR_BITAND))) {
node = new ASTNodeNumericExpression(node, this->parseEqualityExpression(), Token::Operator::BitAnd);
node = create(new ASTNodeMathematicalExpression(node, this->parseEqualityExpression(), Token::Operator::BitAnd));
}
nodeCleanup.release();
@@ -278,7 +297,7 @@ namespace hex::pl {
auto nodeCleanup = SCOPE_GUARD { delete node; };
while (MATCHES(sequence(OPERATOR_BITXOR))) {
node = new ASTNodeNumericExpression(node, this->parseBinaryAndExpression(), Token::Operator::BitXor);
node = create(new ASTNodeMathematicalExpression(node, this->parseBinaryAndExpression(), Token::Operator::BitXor));
}
nodeCleanup.release();
@@ -293,7 +312,7 @@ namespace hex::pl {
auto nodeCleanup = SCOPE_GUARD { delete node; };
while (MATCHES(sequence(OPERATOR_BITOR))) {
node = new ASTNodeNumericExpression(node, this->parseBinaryXorExpression(), Token::Operator::BitOr);
node = create(new ASTNodeMathematicalExpression(node, this->parseBinaryXorExpression(), Token::Operator::BitOr));
}
nodeCleanup.release();
@@ -308,7 +327,7 @@ namespace hex::pl {
auto nodeCleanup = SCOPE_GUARD { delete node; };
while (MATCHES(sequence(OPERATOR_BOOLAND))) {
node = new ASTNodeNumericExpression(node, this->parseBinaryOrExpression(), Token::Operator::BitOr);
node = create(new ASTNodeMathematicalExpression(node, this->parseBinaryOrExpression(), Token::Operator::BoolAnd));
}
nodeCleanup.release();
@@ -323,7 +342,7 @@ namespace hex::pl {
auto nodeCleanup = SCOPE_GUARD { delete node; };
while (MATCHES(sequence(OPERATOR_BOOLXOR))) {
node = new ASTNodeNumericExpression(node, this->parseBooleanAnd(), Token::Operator::BitOr);
node = create(new ASTNodeMathematicalExpression(node, this->parseBooleanAnd(), Token::Operator::BoolXor));
}
nodeCleanup.release();
@@ -338,7 +357,7 @@ namespace hex::pl {
auto nodeCleanup = SCOPE_GUARD { delete node; };
while (MATCHES(sequence(OPERATOR_BOOLOR))) {
node = new ASTNodeNumericExpression(node, this->parseBooleanXor(), Token::Operator::BitOr);
node = create(new ASTNodeMathematicalExpression(node, this->parseBooleanXor(), Token::Operator::BoolOr));
}
nodeCleanup.release();
@@ -359,7 +378,7 @@ namespace hex::pl {
throwParseError("expected ':' in ternary expression");
auto third = this->parseBooleanOr();
node = TO_NUMERIC_EXPRESSION(new ASTNodeTernaryExpression(node, second, third, Token::Operator::TernaryConditional));
node = create(new ASTNodeTernaryExpression(node, second, third, Token::Operator::TernaryConditional));
}
nodeCleanup.release();
@@ -381,14 +400,19 @@ namespace hex::pl {
if (!MATCHES(sequence(IDENTIFIER)))
throwParseError("expected attribute expression");
auto attribute = this->getValue<std::string>(-1);
auto attribute = getValue<Token::Identifier>(-1).get();
if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETOPEN, STRING, SEPARATOR_ROUNDBRACKETCLOSE))) {
auto value = this->getValue<std::string>(-2);
currNode->addAttribute(new ASTNodeAttribute(attribute, value));
auto value = getValue<Token::Literal>(-2);
auto string = std::get_if<std::string>(&value);
if (string == nullptr)
throwParseError("expected string attribute argument");
currNode->addAttribute(create(new ASTNodeAttribute(attribute, *string)));
}
else
currNode->addAttribute(new ASTNodeAttribute(attribute));
currNode->addAttribute(create(new ASTNodeAttribute(attribute)));
} while (MATCHES(sequence(SEPARATOR_COMMA)));
@@ -398,16 +422,24 @@ namespace hex::pl {
/* Functions */
ASTNode* Parser::parseFunctionDefintion() {
const auto &functionName = getValue<std::string>(-2);
std::vector<std::string> params;
ASTNode* Parser::parseFunctionDefinition() {
const auto &functionName = getValue<Token::Identifier>(-2).get();
std::vector<std::pair<std::string, ASTNode*>> params;
// Parse parameter list
bool hasParams = MATCHES(sequence(IDENTIFIER));
bool hasParams = !peek(SEPARATOR_ROUNDBRACKETCLOSE);
u32 unnamedParamCount = 0;
while (hasParams) {
params.push_back(getValue<std::string>(-1));
auto type = parseType(true);
if (!MATCHES(sequence(SEPARATOR_COMMA, IDENTIFIER))) {
if (MATCHES(sequence(IDENTIFIER)))
params.emplace_back(getValue<Token::Identifier>(-1).get(), type);
else {
params.emplace_back(std::to_string(unnamedParamCount), type);
unnamedParamCount++;
}
if (!MATCHES(sequence(SEPARATOR_COMMA))) {
if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE)))
break;
else
@@ -435,7 +467,7 @@ namespace hex::pl {
}
bodyCleanup.release();
return new ASTNodeFunctionDefinition(getNamespacePrefixedName(functionName), params, body);
return create(new ASTNodeFunctionDefinition(getNamespacePrefixedName(functionName), params, body));
}
ASTNode* Parser::parseFunctionStatement() {
@@ -480,22 +512,46 @@ namespace hex::pl {
throwParseError("missing ';' at end of expression", -1);
}
// Consume superfluous semicolons
while (needsSemicolon && MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)));
return statement;
}
ASTNode* Parser::parseFunctionVariableAssignment() {
const auto &lvalue = getValue<std::string>(-2);
const auto &lvalue = getValue<Token::Identifier>(-2).get();
auto rvalue = this->parseMathematicalExpression();
return new ASTNodeAssignment(lvalue, rvalue);
return create(new ASTNodeAssignment(lvalue, rvalue));
}
ASTNode* Parser::parseFunctionReturnStatement() {
if (peek(SEPARATOR_ENDOFEXPRESSION))
return new ASTNodeReturnStatement(nullptr);
return create(new ASTNodeReturnStatement(nullptr));
else
return new ASTNodeReturnStatement(this->parseMathematicalExpression());
return create(new ASTNodeReturnStatement(this->parseMathematicalExpression()));
}
std::vector<ASTNode*> Parser::parseStatementBody() {
std::vector<ASTNode*> body;
auto bodyCleanup = SCOPE_GUARD {
for (auto &node : body)
delete node;
};
if (MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN))) {
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
body.push_back(parseFunctionStatement());
}
} else {
body.push_back(parseFunctionStatement());
}
bodyCleanup.release();
return body;
}
ASTNode* Parser::parseFunctionConditional() {
@@ -510,26 +566,17 @@ namespace hex::pl {
delete statement;
};
if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE, SEPARATOR_CURLYBRACKETOPEN))) {
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
trueBody.push_back(parseFunctionStatement());
}
} else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) {
trueBody.push_back(parseFunctionStatement());
} else
throwParseError("expected body of conditional statement");
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE)))
throwParseError("expected closing ')' after statement head");
if (MATCHES(sequence(KEYWORD_ELSE, SEPARATOR_CURLYBRACKETOPEN))) {
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
falseBody.push_back(parseFunctionStatement());
}
} else if (MATCHES(sequence(KEYWORD_ELSE))) {
falseBody.push_back(parseFunctionStatement());
}
trueBody = parseStatementBody();
if (MATCHES(sequence(KEYWORD_ELSE)))
falseBody = parseStatementBody();
cleanup.release();
return new ASTNodeConditionalStatement(condition, trueBody, falseBody);
return create(new ASTNodeConditionalStatement(condition, trueBody, falseBody));
}
ASTNode* Parser::parseFunctionWhileLoop() {
@@ -542,18 +589,14 @@ namespace hex::pl {
delete statement;
};
if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE, SEPARATOR_CURLYBRACKETOPEN))) {
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
body.push_back(parseFunctionStatement());
}
} else if (MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE))) {
body.push_back(parseFunctionStatement());
} else
throwParseError("expected body of conditional statement");
if (!MATCHES(sequence(SEPARATOR_ROUNDBRACKETCLOSE)))
throwParseError("expected closing ')' after statement head");
body = parseStatementBody();
cleanup.release();
return new ASTNodeWhileStatement(condition, body);
return create(new ASTNodeWhileStatement(condition, body));
}
/* Control flow */
@@ -590,7 +633,7 @@ namespace hex::pl {
cleanup.release();
return new ASTNodeConditionalStatement(condition, trueBody, falseBody);
return create(new ASTNodeConditionalStatement(condition, trueBody, falseBody));
}
// while ((parseMathematicalExpression))
@@ -606,13 +649,13 @@ namespace hex::pl {
cleanup.release();
return new ASTNodeWhileStatement(condition, { });
return create(new ASTNodeWhileStatement(condition, { }));
}
/* Type declarations */
// [be|le] <Identifier|u8|u16|u32|u64|u128|s8|s16|s32|s64|s128|float|double>
ASTNodeTypeDecl* Parser::parseType() {
// [be|le] <Identifier|u8|u16|u32|u64|u128|s8|s16|s32|s64|s128|float|double|str>
ASTNodeTypeDecl* Parser::parseType(bool allowFunctionTypes) {
std::optional<std::endian> endian;
if (MATCHES(sequence(KEYWORD_LE)))
@@ -624,24 +667,32 @@ namespace hex::pl {
std::string typeName = parseNamespaceResolution();
if (this->m_types.contains(typeName))
return new ASTNodeTypeDecl({ }, this->m_types[typeName]->clone(), endian);
return create(new ASTNodeTypeDecl({ }, this->m_types[typeName]->clone(), endian));
else if (this->m_types.contains(getNamespacePrefixedName(typeName)))
return new ASTNodeTypeDecl({ }, this->m_types[getNamespacePrefixedName(typeName)]->clone(), endian);
return create(new ASTNodeTypeDecl({ }, this->m_types[getNamespacePrefixedName(typeName)]->clone(), endian));
else
throwParseError(hex::format("unknown type '{}'", typeName));
}
else if (MATCHES(sequence(VALUETYPE_ANY))) { // Builtin type
return new ASTNodeTypeDecl({ }, new ASTNodeBuiltinType(getValue<Token::ValueType>(-1)), endian);
auto type = getValue<Token::ValueType>(-1);
if (!allowFunctionTypes) {
if (type == Token::ValueType::String)
throwParseError("cannot use 'str' in this context. Use a character array instead");
else if (type == Token::ValueType::Auto)
throwParseError("cannot use 'auto' in this context");
}
return create(new ASTNodeTypeDecl({ }, new ASTNodeBuiltinType(type), endian));
} else throwParseError("failed to parse type. Expected identifier or builtin type");
}
// using Identifier = (parseType)
ASTNode* Parser::parseUsingDeclaration() {
auto name = getValue<std::string>(-2);
auto name = getValue<Token::Identifier>(-2).get();
auto *type = dynamic_cast<ASTNodeTypeDecl *>(parseType());
if (type == nullptr) throwParseError("invalid type used in variable declaration", -1);
return new ASTNodeTypeDecl(name, type, type->getEndian());
return addType(name, type, type->getEndian());
}
// padding[(parseMathematicalExpression)]
@@ -653,7 +704,7 @@ namespace hex::pl {
throwParseError("expected closing ']' at end of array declaration", -1);
}
return new ASTNodeArrayVariableDecl({ }, new ASTNodeTypeDecl({ }, new ASTNodeBuiltinType(Token::ValueType::Padding)), size);;
return create(new ASTNodeArrayVariableDecl({ }, new ASTNodeTypeDecl({ }, new ASTNodeBuiltinType(Token::ValueType::Padding)), size));
}
// (parseType) Identifier
@@ -664,19 +715,19 @@ namespace hex::pl {
auto variableCleanup = SCOPE_GUARD { for (auto var : variables) delete var; };
do {
variables.push_back(new ASTNodeVariableDecl(getValue<std::string>(-1), type->clone()));
variables.push_back(create(new ASTNodeVariableDecl(getValue<Token::Identifier>(-1).get(), type)));
} while (MATCHES(sequence(SEPARATOR_COMMA, IDENTIFIER)));
variableCleanup.release();
return new ASTNodeMultiVariableDecl(variables);
return create(new ASTNodeMultiVariableDecl(variables));
} else
return new ASTNodeVariableDecl(getValue<std::string>(-1), type->clone());
return create(new ASTNodeVariableDecl(getValue<Token::Identifier>(-1).get(), type));
}
// (parseType) Identifier[(parseMathematicalExpression)]
ASTNode* Parser::parseMemberArrayVariable(ASTNodeTypeDecl *type) {
auto name = getValue<std::string>(-2);
auto name = getValue<Token::Identifier>(-2).get();
ASTNode *size = nullptr;
auto sizeCleanup = SCOPE_GUARD { delete size; };
@@ -693,12 +744,12 @@ namespace hex::pl {
sizeCleanup.release();
return new ASTNodeArrayVariableDecl(name, type->clone(), size);
return create(new ASTNodeArrayVariableDecl(name, type, size));
}
// (parseType) *Identifier : (parseType)
ASTNode* Parser::parseMemberPointerVariable(ASTNodeTypeDecl *type) {
auto name = getValue<std::string>(-2);
auto name = getValue<Token::Identifier>(-2).get();
auto sizeType = parseType();
@@ -709,7 +760,7 @@ namespace hex::pl {
throwParseError("invalid type used for pointer size", -1);
}
return new ASTNodePointerVariableDecl(name, type->clone(), sizeType);
return create(new ASTNodePointerVariableDecl(name, type, sizeType));
}
// [(parsePadding)|(parseMemberVariable)|(parseMemberArrayVariable)|(parseMemberPointerVariable)]
@@ -721,7 +772,6 @@ namespace hex::pl {
// Some kind of variable definition
auto type = parseType();
ON_SCOPE_EXIT { delete type; };
if (MATCHES(sequence(IDENTIFIER, SEPARATOR_SQUAREBRACKETOPEN)) && sequence<Not>(SEPARATOR_SQUAREBRACKETOPEN))
member = parseMemberArrayVariable(type);
@@ -747,14 +797,37 @@ namespace hex::pl {
if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)))
throwParseError("missing ';' at end of expression", -1);
// Consume superfluous semicolons
while (MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)));
return member;
}
// struct Identifier { <(parseMember)...> }
ASTNode* Parser::parseStruct() {
const auto structNode = new ASTNodeStruct();
const auto &typeName = getValue<std::string>(-2);
auto structGuard = SCOPE_GUARD { delete structNode; };
const auto &typeName = getValue<Token::Identifier>(-1).get();
const auto structNode = create(new ASTNodeStruct());
const auto typeDecl = addType(typeName, structNode);
auto structGuard = SCOPE_GUARD { delete structNode; delete typeDecl; };
if (MATCHES(sequence(OPERATOR_INHERIT, IDENTIFIER))) {
// Inheritance
do {
auto inheritedTypeName = getValue<Token::Identifier>(-1).get();
if (!this->m_types.contains(inheritedTypeName))
throwParseError(hex::format("cannot inherit from unknown type '{}'", inheritedTypeName), -1);
structNode->addInheritance(this->m_types[inheritedTypeName]->clone());
} while (MATCHES(sequence(SEPARATOR_COMMA, IDENTIFIER)));
} else if (MATCHES(sequence(OPERATOR_INHERIT, VALUETYPE_ANY))) {
throwParseError("cannot inherit from builtin type");
}
if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN)))
throwParseError("expected '{' after struct definition", -1);
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
structNode->addMember(parseMember());
@@ -762,14 +835,16 @@ namespace hex::pl {
structGuard.release();
return new ASTNodeTypeDecl(typeName, structNode);
return typeDecl;
}
// union Identifier { <(parseMember)...> }
ASTNode* Parser::parseUnion() {
const auto unionNode = new ASTNodeUnion();
const auto &typeName = getValue<std::string>(-2);
auto unionGuard = SCOPE_GUARD { delete unionNode; };
const auto &typeName = getValue<Token::Identifier>(-2).get();
const auto unionNode = create(new ASTNodeUnion());
const auto typeDecl = addType(typeName, unionNode);
auto unionGuard = SCOPE_GUARD { delete unionNode; delete typeDecl; };
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
unionNode->addMember(parseMember());
@@ -777,18 +852,19 @@ namespace hex::pl {
unionGuard.release();
return new ASTNodeTypeDecl(typeName, unionNode);
return typeDecl;
}
// enum Identifier : (parseType) { <<Identifier|Identifier = (parseMathematicalExpression)[,]>...> }
ASTNode* Parser::parseEnum() {
auto typeName = getValue<std::string>(-2);
auto typeName = getValue<Token::Identifier>(-2).get();
auto underlyingType = parseType();
if (underlyingType->getEndian().has_value()) throwParseError("underlying type may not have an endian specification", -2);
const auto enumNode = new ASTNodeEnum(underlyingType);
auto enumGuard = SCOPE_GUARD { delete enumNode; };
const auto enumNode = create(new ASTNodeEnum(underlyingType));
const auto typeDecl = addType(typeName, enumNode);
auto enumGuard = SCOPE_GUARD { delete enumNode; delete typeDecl; };
if (!MATCHES(sequence(SEPARATOR_CURLYBRACKETOPEN)))
throwParseError("expected '{' after enum definition", -1);
@@ -796,7 +872,7 @@ namespace hex::pl {
ASTNode *lastEntry = nullptr;
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
if (MATCHES(sequence(IDENTIFIER, OPERATOR_ASSIGNMENT))) {
auto name = getValue<std::string>(-2);
auto name = getValue<Token::Identifier>(-2).get();
auto value = parseMathematicalExpression();
enumNode->addEntry(name, value);
@@ -804,11 +880,11 @@ namespace hex::pl {
}
else if (MATCHES(sequence(IDENTIFIER))) {
ASTNode *valueExpr;
auto name = getValue<std::string>(-1);
auto name = getValue<Token::Identifier>(-1).get();
if (enumNode->getEntries().empty())
valueExpr = lastEntry = TO_NUMERIC_EXPRESSION(new ASTNodeIntegerLiteral(u8(0)));
valueExpr = lastEntry = create(new ASTNodeLiteral(u128(0)));
else
valueExpr = new ASTNodeNumericExpression(lastEntry->clone(), new ASTNodeIntegerLiteral(s32(1)), Token::Operator::Plus);
valueExpr = lastEntry = create(new ASTNodeMathematicalExpression(lastEntry->clone(), new ASTNodeLiteral(u128(1)), Token::Operator::Plus));
enumNode->addEntry(name, valueExpr);
}
@@ -827,19 +903,21 @@ namespace hex::pl {
enumGuard.release();
return new ASTNodeTypeDecl(typeName, enumNode);
return typeDecl;
}
// bitfield Identifier { <Identifier : (parseMathematicalExpression)[;]...> }
ASTNode* Parser::parseBitfield() {
std::string typeName = getValue<std::string>(-2);
std::string typeName = getValue<Token::Identifier>(-2).get();
const auto bitfieldNode = new ASTNodeBitfield();
auto enumGuard = SCOPE_GUARD { delete bitfieldNode; };
const auto bitfieldNode = create(new ASTNodeBitfield());
const auto typeDecl = addType(typeName, bitfieldNode);
auto enumGuard = SCOPE_GUARD { delete bitfieldNode; delete typeDecl; };
while (!MATCHES(sequence(SEPARATOR_CURLYBRACKETCLOSE))) {
if (MATCHES(sequence(IDENTIFIER, OPERATOR_INHERIT))) {
auto name = getValue<std::string>(-2);
auto name = getValue<Token::Identifier>(-2).get();
bitfieldNode->addEntry(name, parseMathematicalExpression());
}
else if (MATCHES(sequence(SEPARATOR_ENDOFPROGRAM)))
@@ -847,31 +925,33 @@ namespace hex::pl {
else
throwParseError("invalid bitfield member", 0);
if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION))) {
if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)))
throwParseError("missing ';' at end of expression", -1);
}
// Consume superfluous semicolons
while (MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)));
}
enumGuard.release();
return new ASTNodeTypeDecl(typeName, bitfieldNode);
return typeDecl;
}
// (parseType) Identifier @ Integer
ASTNode* Parser::parseVariablePlacement(ASTNodeTypeDecl *type) {
auto name = getValue<std::string>(-1);
auto name = getValue<Token::Identifier>(-1).get();
if (!MATCHES(sequence(OPERATOR_AT)))
throwParseError("expected placement instruction", -1);
auto placementOffset = parseMathematicalExpression();
return new ASTNodeVariableDecl(name, type, placementOffset);
return create(new ASTNodeVariableDecl(name, type, placementOffset));
}
// (parseType) Identifier[[(parseMathematicalExpression)]] @ Integer
ASTNode* Parser::parseArrayVariablePlacement(ASTNodeTypeDecl *type) {
auto name = getValue<std::string>(-2);
auto name = getValue<Token::Identifier>(-2).get();
ASTNode *size = nullptr;
auto sizeCleanup = SCOPE_GUARD { delete size; };
@@ -893,12 +973,12 @@ namespace hex::pl {
sizeCleanup.release();
return new ASTNodeArrayVariableDecl(name, type, size, placementOffset);
return create(new ASTNodeArrayVariableDecl(name, type, size, placementOffset));
}
// (parseType) *Identifier : (parseType) @ Integer
ASTNode* Parser::parsePointerVariablePlacement(ASTNodeTypeDecl *type) {
auto name = getValue<std::string>(-2);
auto name = getValue<Token::Identifier>(-2).get();
auto sizeType = parseType();
auto sizeCleanup = SCOPE_GUARD { delete sizeType; };
@@ -917,7 +997,7 @@ namespace hex::pl {
sizeCleanup.release();
return new ASTNodePointerVariableDecl(name, type, sizeType, placementOffset);
return create(new ASTNodePointerVariableDecl(name, type, sizeType, placementOffset));
}
std::vector<ASTNode*> Parser::parseNamespace() {
@@ -929,7 +1009,7 @@ namespace hex::pl {
this->m_currNamespace.push_back(this->m_currNamespace.back());
while (true) {
this->m_currNamespace.back().push_back(getValue<std::string>(-1));
this->m_currNamespace.back().push_back(getValue<Token::Identifier>(-1).get());
if (MATCHES(sequence(OPERATOR_SCOPERESOLUTION, IDENTIFIER)))
continue;
@@ -986,7 +1066,7 @@ namespace hex::pl {
}
else if (peek(KEYWORD_BE) || peek(KEYWORD_LE) || peek(VALUETYPE_ANY))
statement = parsePlacement();
else if (MATCHES(sequence(KEYWORD_STRUCT, IDENTIFIER, SEPARATOR_CURLYBRACKETOPEN)))
else if (MATCHES(sequence(KEYWORD_STRUCT, IDENTIFIER)))
statement = parseStruct();
else if (MATCHES(sequence(KEYWORD_UNION, IDENTIFIER, SEPARATOR_CURLYBRACKETOPEN)))
statement = parseUnion();
@@ -995,7 +1075,7 @@ namespace hex::pl {
else if (MATCHES(sequence(KEYWORD_BITFIELD, IDENTIFIER, SEPARATOR_CURLYBRACKETOPEN)))
statement = parseBitfield();
else if (MATCHES(sequence(KEYWORD_FUNCTION, IDENTIFIER, SEPARATOR_ROUNDBRACKETOPEN)))
statement = parseFunctionDefintion();
statement = parseFunctionDefinition();
else if (MATCHES(sequence(KEYWORD_NAMESPACE)))
return parseNamespace();
else throwParseError("invalid sequence", 0);
@@ -1006,19 +1086,24 @@ namespace hex::pl {
if (!MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)))
throwParseError("missing ';' at end of expression", -1);
if (auto typeDecl = dynamic_cast<ASTNodeTypeDecl*>(statement); typeDecl != nullptr) {
auto typeName = getNamespacePrefixedName(typeDecl->getName().data());
if (this->m_types.contains(typeName))
throwParseError(hex::format("redefinition of type '{}'", typeName));
typeDecl->setName(typeName);
this->m_types.insert({ typeName, typeDecl });
}
// Consume superfluous semicolons
while (MATCHES(sequence(SEPARATOR_ENDOFEXPRESSION)));
return { statement };
}
ASTNodeTypeDecl* Parser::addType(const std::string &name, ASTNode *node, std::optional<std::endian> endian) {
auto typeName = getNamespacePrefixedName(name);
if (this->m_types.contains(typeName))
throwParseError(hex::format("redefinition of type '{}'", typeName));
auto typeDecl = create(new ASTNodeTypeDecl(typeName, node, endian));
this->m_types.insert({ typeName, typeDecl });
return typeDecl;
}
// <(parseNamespace)...> EndOfProgram
std::optional<std::vector<ASTNode*>> Parser::parse(const std::vector<Token> &tokens) {
this->m_curr = tokens.begin();

View File

@@ -2,6 +2,7 @@
#include <hex/helpers/file.hpp>
#include <hex/providers/provider.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/pattern_language/preprocessor.hpp>
#include <hex/pattern_language/lexer.hpp>
@@ -42,14 +43,24 @@ namespace hex::pl {
if (limit <= 0)
return false;
this->m_recursionLimit = limit;
this->m_evalDepth = limit;
return true;
});
this->m_preprocessor->addPragmaHandler("array_limit", [this](std::string value) {
auto limit = strtol(value.c_str(), nullptr, 0);
if (limit <= 0)
return false;
this->m_arrayLimit = limit;
return true;
});
this->m_preprocessor->addPragmaHandler("base_address", [](std::string value) {
auto baseAddress = strtoull(value.c_str(), nullptr, 0);
SharedData::currentProvider->setBaseAddress(baseAddress);
ImHexApi::Provider::get()->setBaseAddress(baseAddress);
return true;
});
@@ -61,7 +72,6 @@ namespace hex::pl {
delete this->m_lexer;
delete this->m_parser;
delete this->m_validator;
delete this->m_evaluator;
}
@@ -69,6 +79,12 @@ namespace hex::pl {
this->m_currError.reset();
this->m_evaluator->getConsole().clear();
this->m_evaluator->setProvider(provider);
this->m_evalDepth = 32;
this->m_arrayLimit = 0x1000;
for (auto &node : this->m_currAST)
delete node;
this->m_currAST.clear();
auto preprocessedCode = this->m_preprocessor->preprocess(string);
if (!preprocessedCode.has_value()) {
@@ -77,7 +93,8 @@ namespace hex::pl {
}
this->m_evaluator->setDefaultEndian(this->m_defaultEndian);
this->m_evaluator->setRecursionLimit(this->m_recursionLimit);
this->m_evaluator->setEvaluationDepth(this->m_evalDepth);
this->m_evaluator->setArrayLimit(this->m_arrayLimit);
auto tokens = this->m_lexer->lex(preprocessedCode.value());
if (!tokens.has_value()) {
@@ -91,22 +108,15 @@ namespace hex::pl {
return { };
}
ON_SCOPE_EXIT {
for(auto &node : ast.value())
delete node;
};
this->m_currAST = ast.value();
auto validatorResult = this->m_validator->validate(ast.value());
if (!validatorResult) {
this->m_currError = this->m_validator->getError();
auto patterns = this->m_evaluator->evaluate(ast.value());
if (!patterns.has_value()) {
this->m_currError = this->m_evaluator->getConsole().getLastHardError();
return { };
}
auto patternData = this->m_evaluator->evaluate(ast.value());
if (!patternData.has_value())
return { };
return patternData.value();
return patterns;
}
std::optional<std::vector<PatternData*>> PatternLanguage::executeFile(prv::Provider *provider, const std::string &path) {

View File

@@ -15,6 +15,7 @@ namespace hex::pl {
std::optional<std::string> Preprocessor::preprocess(const std::string& code, bool initialRun) {
u32 offset = 0;
u32 lineNumber = 1;
bool isInString = false;
if (initialRun) {
this->m_defines.clear();
@@ -25,8 +26,17 @@ namespace hex::pl {
output.reserve(code.length());
try {
bool startOfLine = true;
while (offset < code.length()) {
if (code[offset] == '#') {
if (offset > 0 && code[offset - 1] != '\\' && code[offset] == '\"')
isInString = !isInString;
else if (isInString) {
output += code[offset];
offset += 1;
continue;
}
if (code[offset] == '#' && startOfLine) {
offset += 1;
if (code.substr(offset, 7) == "include") {
@@ -164,8 +174,11 @@ namespace hex::pl {
throwPreprocessorError("unterminated comment", lineNumber - 1);
}
if (code[offset] == '\n')
if (code[offset] == '\n') {
lineNumber++;
startOfLine = true;
} else if (!std::isspace(code[offset]))
startOfLine = false;
output += code[offset];
offset += 1;

View File

@@ -57,6 +57,10 @@ namespace hex::prv {
return *(this->m_patches.end() - 1 - this->m_patchTreeOffset);
}
const std::map<u64, u8>& Provider::getPatches() const {
return *(this->m_patches.end() - 1 - this->m_patchTreeOffset);
}
void Provider::applyPatches() {
for (auto &[patchAddress, patch] : getPatches())
this->writeRaw(patchAddress, &patch, 1);
@@ -77,7 +81,7 @@ namespace hex::prv {
}
u32 Provider::getPageCount() {
u32 Provider::getPageCount() const {
return std::ceil(this->getActualSize() / double(PageSize));
}
@@ -95,15 +99,15 @@ namespace hex::prv {
this->m_baseAddress = address;
}
u64 Provider::getBaseAddress() {
u64 Provider::getBaseAddress() const {
return this->m_baseAddress + PageSize * this->m_currPage;
}
size_t Provider::getSize() {
size_t Provider::getSize() const {
return std::min(this->getActualSize() - PageSize * this->m_currPage, PageSize);
}
std::optional<u32> Provider::getPageOfAddress(u64 address) {
std::optional<u32> Provider::getPageOfAddress(u64 address) const {
u32 page = std::floor((address - this->getBaseAddress()) / double(PageSize));
if (page >= this->getPageCount())
@@ -134,11 +138,11 @@ namespace hex::prv {
this->m_patchTreeOffset--;
}
bool Provider::canUndo() {
bool Provider::canUndo() const {
return this->m_patchTreeOffset < this->m_patches.size() - 1;
}
bool Provider::canRedo() {
bool Provider::canRedo() const {
return this->m_patchTreeOffset > 0;
}

View File

@@ -16,7 +16,7 @@ namespace hex {
bool View::handleShortcut(bool keys[512], bool ctrl, bool shift, bool alt) { return false; }
bool View::isAvailable() {
return SharedData::currentProvider != nullptr && SharedData::currentProvider->isAvailable();
return ImHexApi::Provider::isValid() && ImHexApi::Provider::get()->isAvailable();
}
std::vector<std::function<void()>>& View::getDeferedCalls() {
@@ -24,8 +24,9 @@ namespace hex {
}
void View::drawCommonInterfaces() {
if (ImGui::BeginPopupModal("hex.common.error"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("%s", SharedData::errorPopupMessage.c_str());
ImGui::SetNextWindowSizeConstraints(ImVec2(400, 100) * SharedData::globalScale, ImVec2(600, 300) * SharedData::globalScale);
if (ImGui::BeginPopupModal("hex.common.info"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextWrapped("%s", SharedData::popupMessage.c_str());
ImGui::NewLine();
ImGui::Separator();
if (ImGui::Button("hex.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape))
@@ -34,8 +35,20 @@ namespace hex {
ImGui::EndPopup();
}
ImGui::SetNextWindowSizeConstraints(ImVec2(400, 100) * SharedData::globalScale, ImVec2(600, 300) * SharedData::globalScale);
if (ImGui::BeginPopupModal("hex.common.error"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextWrapped("%s", SharedData::popupMessage.c_str());
ImGui::NewLine();
ImGui::Separator();
if (ImGui::Button("hex.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
}
ImGui::SetNextWindowSizeConstraints(ImVec2(400, 100) * SharedData::globalScale, ImVec2(600, 300) * SharedData::globalScale);
if (ImGui::BeginPopupModal("hex.common.fatal"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::Text("%s", SharedData::errorPopupMessage.c_str());
ImGui::TextWrapped("%s", SharedData::popupMessage.c_str());
ImGui::NewLine();
ImGui::Separator();
if (ImGui::Button("hex.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape)) {
@@ -47,14 +60,20 @@ namespace hex {
}
}
void View::showMessagePopup(const std::string &message) {
SharedData::popupMessage = message;
View::doLater([] { ImGui::OpenPopup("hex.common.info"_lang); });
}
void View::showErrorPopup(const std::string &errorMessage) {
SharedData::errorPopupMessage = errorMessage;
SharedData::popupMessage = errorMessage;
View::doLater([] { ImGui::OpenPopup("hex.common.error"_lang); });
}
void View::showFatalPopup(const std::string &errorMessage) {
SharedData::errorPopupMessage = errorMessage;
SharedData::popupMessage = errorMessage;
View::doLater([] { ImGui::OpenPopup("hex.common.fatal"_lang); });
}
@@ -64,11 +83,11 @@ namespace hex {
}
ImVec2 View::getMinSize() {
return ImVec2(480, 720);
return ImVec2(480, 720) * SharedData::globalScale;
}
ImVec2 View::getMaxSize() {
return ImVec2(FLT_MAX, FLT_MAX);
return { FLT_MAX, FLT_MAX };
}

View File

@@ -11,8 +11,9 @@ if (WIN32)
source/views/view_tty_console.cpp
source/lang/en_US.cpp
source/lang/zh_CN.cpp
source/content/footer_items.cpp
source/content/ui_items.cpp
)
# Add additional include directories here #

View File

@@ -67,9 +67,11 @@ namespace hex::plugin::windows {
lastUserCPU = user;
lastSysCPU = sys;
}
cpuUsage *= 100;
}
ImGui::TextUnformatted(hex::format(ICON_FA_TACHOMETER_ALT " {0:.2f}%", cpuUsage * 100).c_str());
ImGui::TextUnformatted(hex::format(ICON_FA_TACHOMETER_ALT " {0:2}.{1:02}", u32(cpuUsage), u32(cpuUsage * 100) % 100).c_str());
});
ContentRegistry::Interface::addFooterItem([] {

View File

@@ -17,6 +17,7 @@ namespace hex::plugin::windows {
{ "hex.windows.view.tty_console.connect", "Connect" },
{ "hex.windows.view.tty_console.disconnect", "Disconnect" },
{ "hex.windows.view.tty_console.connect_error", "Failed to connect to COM Port!" },
{ "hex.windows.view.tty_console.no_available_port", "No valid COM port is selected or no COM port is available!" },
{ "hex.windows.view.tty_console.clear", "Clear" },
{ "hex.windows.view.tty_console.auto_scroll", "Auto scroll" },
{ "hex.windows.view.tty_console.console", "Console" },

View File

@@ -0,0 +1,31 @@
#include <hex/api/content_registry.hpp>
#include <hex/helpers/lang.hpp>
namespace hex::plugin::windows {
void registerLanguageZhCN() {
ContentRegistry::Language::addLocalizations("zh-CN", {
{ "hex.windows.view.tty_console.name", "TTY控制台" },
{ "hex.windows.view.tty_console.config", "配置"},
{ "hex.windows.view.tty_console.port", "端口" },
{ "hex.windows.view.tty_console.reload", "刷新" },
{ "hex.windows.view.tty_console.baud", "波特率" },
{ "hex.windows.view.tty_console.num_bits", "数据位" },
{ "hex.windows.view.tty_console.stop_bits", "终止位" },
{ "hex.windows.view.tty_console.parity_bits", "奇偶校验位" },
{ "hex.windows.view.tty_console.cts", "使用CTS流控制" },
{ "hex.windows.view.tty_console.connect", "连接" },
{ "hex.windows.view.tty_console.disconnect", "断开" },
{ "hex.windows.view.tty_console.connect_error", "无法连接到COM端口" },
{ "hex.windows.view.tty_console.no_available_port", "未选择有效的COM端口或无可用COM端口" },
{ "hex.windows.view.tty_console.clear", "清除" },
{ "hex.windows.view.tty_console.auto_scroll", "自动滚动" },
{ "hex.windows.view.tty_console.console", "控制台" },
{ "hex.windows.view.tty_console.send_etx", "发送ETX" },
{ "hex.windows.view.tty_console.send_eot", "发送EOT" },
{ "hex.windows.view.tty_console.send_sub", "发送SUB" }
});
}
}

View File

@@ -5,6 +5,7 @@
namespace hex::plugin::windows {
void registerLanguageEnUS();
void registerLanguageZhCN();
void addFooterItems();
}
@@ -16,6 +17,7 @@ IMHEX_PLUGIN_SETUP("Windows", "WerWolv", "Windows-only features") {
ContentRegistry::Views::add<ViewTTYConsole>();
registerLanguageEnUS();
registerLanguageZhCN();
addFooterItems();
}

View File

@@ -178,6 +178,10 @@ namespace hex::plugin::windows {
}
bool ViewTTYConsole::connect() {
if(this->m_comPorts.size() == 0 || this->m_selectedPort >= this->m_comPorts.size()) {
View::showErrorPopup("hex.windows.view.tty_console.no_available_port"_lang);
return true; // If false, connect_error error popup will override this error popup
}
this->m_portHandle = ::CreateFile(("\\\\.\\" + this->m_comPorts[this->m_selectedPort].first).c_str(),
GENERIC_READ | GENERIC_WRITE,
0,

View File

@@ -165,7 +165,7 @@ namespace hex {
code += "};\n";
EventManager::post<RequestAppendPatternLanguageCode>(code);
EventManager::post<RequestSetPatternLanguageCode>(code);
Py_RETURN_NONE;
}

View File

@@ -85,6 +85,8 @@ namespace hex {
ProjectFile::s_hasUnsavedChanged = false;
ProjectFile::s_currProjectFilePath = filePath;
EventManager::post<EventProjectFileLoad>();
return true;
}

View File

@@ -25,7 +25,7 @@ using namespace std::literals::chrono_literals;
namespace hex::init {
WindowSplash::WindowSplash(int &argc, char **&argv) {
WindowSplash::WindowSplash(int &argc, char **&argv) : m_window(nullptr) {
SharedData::mainArgc = argc;
SharedData::mainArgv = argv;
@@ -57,7 +57,7 @@ namespace hex::init {
{
std::lock_guard guard(this->m_progressMutex);
this->m_progress += 1.0F / m_tasks.size();
this->m_progress += 1.0F / this->m_tasks.size();
}
}
@@ -69,9 +69,7 @@ namespace hex::init {
}
bool WindowSplash::loop() {
ImGui::Texture splashTexture;
splashTexture = ImGui::LoadImageFromMemory(splash, splash_size);
ImGui::Texture splashTexture = ImGui::LoadImageFromMemory(splash, splash_size);
if (splashTexture == nullptr) {
log::fatal("Could not load splash screen image!");
@@ -168,10 +166,14 @@ namespace hex::init {
glfwWindowHint(GLFW_FLOATING, GLFW_TRUE);
if (GLFWmonitor *monitor = glfwGetPrimaryMonitor(); monitor != nullptr) {
float xscale, yscale;
glfwGetMonitorContentScale(monitor, &xscale, &yscale);
float xScale = 0, yScale = 0;
glfwGetMonitorContentScale(monitor, &xScale, &yScale);
SharedData::globalScale = SharedData::fontScale = std::midpoint(xscale, yscale);
SharedData::globalScale = SharedData::fontScale = std::midpoint(xScale, yScale);
if (SharedData::globalScale <= 0) {
SharedData::globalScale = 1.0;
}
}
this->m_window = glfwCreateWindow(640 * SharedData::globalScale, 400 * SharedData::globalScale, "ImHex", nullptr, nullptr);

View File

@@ -29,6 +29,7 @@
#include "views/view_yara.hpp"
#include "views/view_constants.hpp"
#include "views/view_store.hpp"
#include "views/view_diff.hpp"
#include "helpers/plugin_manager.hpp"
@@ -50,7 +51,8 @@ namespace hex::init {
if (!releases.body.contains("tag_name") || !releases.body["tag_name"].is_string())
return false;
auto currVersion = "v" + std::string(IMHEX_VERSION).substr(0, 5);
auto versionString = std::string(IMHEX_VERSION);
auto currVersion = "v" + versionString.substr(0, versionString.find_first_of('-'));
auto latestVersion = releases.body["tag_name"].get<std::string_view>();
if (latestVersion != currVersion)
@@ -111,9 +113,11 @@ namespace hex::init {
std::string fontFile;
for (const auto &dir : hex::getPath(ImHexPath::Resources)) {
fontFile = dir + "/font.ttf";
if (std::filesystem::exists(fontFile))
auto path = dir + "/font.ttf";
if (std::filesystem::exists(path)) {
fontFile = path;
break;
}
}
ImVector<ImWchar> ranges;
@@ -144,8 +148,10 @@ namespace hex::init {
0
};
if (!std::filesystem::exists(fontFile)) {
if (fontFile.empty()) {
// Load default font
fonts->Clear();
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
@@ -154,10 +160,12 @@ namespace hex::init {
} else {
// Load custom font
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
cfg.SizePixels = 13.0f * SharedData::fontScale;
auto fontSize = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.font_size", 14);
fonts->AddFontFromFileTTF(fontFile.c_str(), std::floor(14.0f * SharedData::fontScale), &cfg, ranges.Data); // Needs conversion to char for Windows
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
cfg.SizePixels = fontSize * SharedData::fontScale;
fonts->AddFontFromFileTTF(fontFile.c_str(), std::floor(fontSize * SharedData::fontScale), &cfg, ranges.Data); // Needs conversion to char for Windows
}
cfg.MergeMode = true;
@@ -191,6 +199,7 @@ namespace hex::init {
ContentRegistry::Views::add<ViewYara>();
ContentRegistry::Views::add<ViewConstants>();
ContentRegistry::Views::add<ViewStore>();
ContentRegistry::Views::add<ViewDiff>();
return true;
}
@@ -198,8 +207,8 @@ namespace hex::init {
bool deleteSharedData() {
SharedData::deferredCalls.clear();
delete SharedData::currentProvider;
SharedData::currentProvider = nullptr;
while (ImHexApi::Provider::isValid())
ImHexApi::Provider::remove(ImHexApi::Provider::get());
SharedData::settingsEntries.clear();
SharedData::settingsJson.clear();
@@ -304,8 +313,8 @@ namespace hex::init {
{ "Downloading information...", downloadInformation },
{ "Creating directories...", createDirectories },
{ "Loading default views...", loadDefaultViews },
{ "Loading plugins...", loadPlugins },
{ "Loading settings...", loadSettings },
{ "Loading plugins...", loadPlugins },
{ "Loading fonts...", loadFonts },
};
}

View File

@@ -18,7 +18,7 @@ namespace hex::prv {
}
bool FileProvider::isAvailable() {
bool FileProvider::isAvailable() const {
#if defined(OS_WINDOWS)
return this->m_file != nullptr && this->m_mapping != nullptr && this->m_mappedFile != nullptr;
#else
@@ -26,26 +26,26 @@ namespace hex::prv {
#endif
}
bool FileProvider::isReadable() {
bool FileProvider::isReadable() const {
return isAvailable() && this->m_readable;
}
bool FileProvider::isWritable() {
bool FileProvider::isWritable() const {
return isAvailable() && this->m_writable;
}
bool FileProvider::isResizable() {
bool FileProvider::isResizable() const {
return true;
}
bool FileProvider::isSavable() {
bool FileProvider::isSavable() const {
return !this->getPatches().empty();
}
void FileProvider::read(u64 offset, void *buffer, size_t size, bool overlays) {
if (((offset - this->getBaseAddress()) + size) > this->getSize() || buffer == nullptr || size == 0)
if ((offset - this->getBaseAddress()) > (this->getSize() - size) || buffer == nullptr || size == 0)
return;
std::memcpy(buffer, reinterpret_cast<u8*>(this->m_mappedFile) + PageSize * this->m_currPage + offset - this->getBaseAddress(), size);
@@ -94,7 +94,7 @@ namespace hex::prv {
std::vector<u8> buffer(std::min<size_t>(0xFF'FFFF, file.getSize()), 0x00);
size_t bufferSize = buffer.size();
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
for (u64 offset = 0; offset < provider->getActualSize(); offset += bufferSize) {
if (bufferSize > provider->getActualSize() - offset)
bufferSize = provider->getActualSize() - offset;
@@ -137,11 +137,15 @@ namespace hex::prv {
this->open();
}
size_t FileProvider::getActualSize() {
size_t FileProvider::getActualSize() const {
return this->m_fileSize;
}
std::vector<std::pair<std::string, std::string>> FileProvider::getDataInformation() {
std::string FileProvider::getName() const {
return std::filesystem::path(this->m_path).filename().string();
}
std::vector<std::pair<std::string, std::string>> FileProvider::getDataInformation() const {
std::vector<std::pair<std::string, std::string>> result;
result.emplace_back("hex.builtin.provider.file.path"_lang, this->m_path);

View File

@@ -52,9 +52,12 @@ namespace hex {
auto &bookmarks = ImHexApi::Bookmarks::getEntries();
if (bookmarks.empty()) {
ImGui::NewLine();
ImGui::Indent(30);
ImGui::TextWrapped("%s", static_cast<const char*>("hex.view.bookmarks.no_bookmarks"_lang));
std::string text = "hex.view.bookmarks.no_bookmarks"_lang;
auto textSize = ImGui::CalcTextSize(text.c_str());
auto availableSpace = ImGui::GetContentRegionAvail();
ImGui::SetCursorPos((availableSpace - textSize) / 2.0F);
ImGui::TextUnformatted(text.c_str());
}
u32 id = 1;
@@ -91,7 +94,7 @@ namespace hex {
{
std::array<u8, 0x10> bytes = { 0 };
size_t byteCount = std::min<size_t>(0x10 - offset, region.size);
SharedData::currentProvider->read(region.address, bytes.data() + offset, byteCount);
ImHexApi::Provider::get()->read(region.address, bytes.data() + offset, byteCount);
for (size_t byte = 0; byte < 0x10; byte++) {
if (byte < offset)
@@ -108,7 +111,7 @@ namespace hex {
std::array<u8, 0x10> bytes = { 0 };
for (u32 i = 0x10 - offset; i < region.size; i += 0x10) {
size_t byteCount = std::min<size_t>(region.size - i, 0x10);
SharedData::currentProvider->read(region.address + i, bytes.data(), byteCount);
ImHexApi::Provider::get()->read(region.address + i, bytes.data(), byteCount);
for (size_t byte = 0; byte < byteCount; byte++) {
ImGui::Text("%02X", bytes[byte]);

View File

@@ -12,21 +12,15 @@ namespace hex {
ViewDataInspector::ViewDataInspector() : View("hex.view.data_inspector.name") {
EventManager::subscribe<EventRegionSelected>(this, [this](Region region) {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
if (provider == nullptr) {
if (!ImHexApi::Provider::isValid() || region.address == (size_t)-1) {
this->m_validBytes = 0;
return;
} else {
this->m_validBytes = u64(provider->getSize() - region.address);
this->m_startAddress = region.address;
}
if (region.address == (size_t)-1) {
this->m_validBytes = 0;
return;
}
this->m_validBytes = u64(provider->getSize() - region.address);
this->m_startAddress = region.address;
this->m_shouldInvalidate = true;
});
}
@@ -40,7 +34,7 @@ namespace hex {
this->m_shouldInvalidate = false;
this->m_cachedData.clear();
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
for (auto &entry : ContentRegistry::DataInspector::getEntries()) {
if (this->m_validBytes < entry.requiredSize)
continue;
@@ -54,9 +48,9 @@ namespace hex {
if (ImGui::Begin(View::toWindowName("hex.view.data_inspector.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
if (provider != nullptr && provider->isReadable()) {
if (ImHexApi::Provider::isValid() && provider->isReadable() && this->m_validBytes > 0) {
if (ImGui::BeginTable("##datainspector", 2,
ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_RowBg,
ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * (this->m_cachedData.size() + 1)))) {
@@ -112,6 +106,13 @@ namespace hex {
this->m_numberDisplayStyle = NumberDisplayStyle::Octal;
this->m_shouldInvalidate = true;
}
} else {
std::string text = "hex.view.data_inspector.no_data"_lang;
auto textSize = ImGui::CalcTextSize(text.c_str());
auto availableSpace = ImGui::GetContentRegionAvail();
ImGui::SetCursorPos((availableSpace - textSize) / 2.0F);
ImGui::TextUnformatted(text.c_str());
}
}
ImGui::End();

View File

@@ -9,25 +9,21 @@
namespace hex {
ViewDataProcessor::ViewDataProcessor() : View("hex.view.data_processor.name") {
EventManager::subscribe<EventSettingsChanged>(this, [] {
auto theme = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color");
if (theme.is_number()) {
switch (static_cast<int>(theme)) {
default:
case 0: /* Dark theme */
ImNodes::StyleColorsDark();
break;
case 1: /* Light theme */
ImNodes::StyleColorsLight();
break;
case 2: /* Classic theme */
ImNodes::StyleColorsClassic();
break;
}
ImNodes::GetStyle().Flags = ImNodesStyleFlags_NodeOutline | ImNodesStyleFlags_GridLines;
EventManager::subscribe<RequestChangeTheme>(this, [](u32 theme) {
switch (theme) {
default:
case 1: /* Dark theme */
ImNodes::StyleColorsDark();
break;
case 2: /* Light theme */
ImNodes::StyleColorsLight();
break;
case 3: /* Classic theme */
ImNodes::StyleColorsClassic();
break;
}
ImNodes::GetStyle().Flags = ImNodesStyleFlags_NodeOutline | ImNodesStyleFlags_GridLines;
});
EventManager::subscribe<EventProjectFileStore>(this, [this] {
@@ -50,7 +46,7 @@ namespace hex {
for (auto &node : this->m_nodes)
delete node;
EventManager::unsubscribe<EventSettingsChanged>(this);
EventManager::unsubscribe<RequestChangeTheme>(this);
EventManager::unsubscribe<EventFileLoaded>(this);
EventManager::unsubscribe<EventProjectFileStore>(this);
EventManager::unsubscribe<EventProjectFileLoad>(this);
@@ -104,11 +100,11 @@ namespace hex {
void ViewDataProcessor::processNodes() {
if (this->m_dataOverlays.size() != this->m_endNodes.size()) {
for (auto overlay : this->m_dataOverlays)
SharedData::currentProvider->deleteOverlay(overlay);
ImHexApi::Provider::get()->deleteOverlay(overlay);
this->m_dataOverlays.clear();
for (u32 i = 0; i < this->m_endNodes.size(); i++)
this->m_dataOverlays.push_back(SharedData::currentProvider->newOverlay());
this->m_dataOverlays.push_back(ImHexApi::Provider::get()->newOverlay());
u32 overlayIndex = 0;
for (auto endNode : this->m_endNodes) {
@@ -132,7 +128,7 @@ namespace hex {
this->m_currNodeError = e;
for (auto overlay : this->m_dataOverlays)
SharedData::currentProvider->deleteOverlay(overlay);
ImHexApi::Provider::get()->deleteOverlay(overlay);
this->m_dataOverlays.clear();
} catch (std::runtime_error &e) {

234
source/views/view_diff.cpp Normal file
View File

@@ -0,0 +1,234 @@
#include "views/view_diff.hpp"
#include <hex/api/imhex_api.hpp>
#include <hex/providers/provider.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/api/content_registry.hpp>
#include <nlohmann/json.hpp>
namespace hex {
ViewDiff::ViewDiff() : View("hex.view.diff.name") {
EventManager::subscribe<EventSettingsChanged>(this, [this]{
{
auto columnCount = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.column_count");
this->m_columnCount = static_cast<int>(columnCount);
}
{
auto greyOutZeros = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.grey_zeros");
this->m_greyedOutZeros = static_cast<int>(greyOutZeros);
}
{
auto upperCaseHex = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.uppercase_hex");
this->m_upperCaseHex = static_cast<int>(upperCaseHex);
}
});
}
ViewDiff::~ViewDiff() {
EventManager::unsubscribe<EventSettingsChanged>(this);
}
static void drawProviderSelector(int &provider) {
auto &providers = ImHexApi::Provider::getProviders();
std::string preview;
if (ImHexApi::Provider::isValid() && provider >= 0)
preview = providers[provider]->getName();
ImGui::SetNextItemWidth(200 * SharedData::globalScale);
if (ImGui::BeginCombo("", preview.c_str())) {
for (int i = 0; i < providers.size(); i++) {
if (ImGui::Selectable(providers[i]->getName().c_str())) {
provider = i;
}
}
ImGui::EndCombo();
}
}
static u32 getDiffColor(u32 color) {
return (color & 0x00FFFFFF) | 0x40000000;
}
enum class DiffResult { Same, Changed, Added, Removed };
struct LineInfo {
std::vector<u8> bytes;
s64 validBytes = 0;
};
static DiffResult diffBytes(u8 index, const LineInfo &a, const LineInfo &b) {
/* Very simple binary diff. Only detects additions and changes */
if (a.validBytes > index) {
if (b.validBytes <= index)
return DiffResult::Added;
else if (a.bytes[index] != b.bytes[index])
return DiffResult::Changed;
}
return DiffResult::Same;
}
void ViewDiff::drawDiffLine(const std::array<int, 2> &providerIds, u64 row) const {
std::array<LineInfo, 2> lineInfo;
u8 addressDigitCount = 0;
for (u8 i = 0; i < 2; i++) {
int id = providerIds[i];
if (id < 0) continue;
auto &provider = ImHexApi::Provider::getProviders()[id];
// Read one line of each provider
lineInfo[i].bytes.resize(this->m_columnCount);
provider->read(row * this->m_columnCount, lineInfo[i].bytes.data(), lineInfo[i].bytes.size());
lineInfo[i].validBytes = std::min<s64>(this->m_columnCount, provider->getSize() - row * this->m_columnCount);
// Calculate address width
u8 addressDigits = 0;
for (size_t n = provider->getSize() - 1; n > 0; n >>= 4)
addressDigits++;
addressDigitCount = std::max(addressDigits, addressDigitCount);
}
ImDrawList* drawList = ImGui::GetWindowDrawList();
auto glyphWidth = ImGui::CalcTextSize("0").x + 1;
static auto highlightSize = ImGui::CalcTextSize("00");
auto startY = ImGui::GetCursorPosY();
ImGui::TextUnformatted(hex::format(this->m_upperCaseHex ? "{:0{}X}:" : "{:0{}x}:", row * this->m_columnCount, addressDigitCount).c_str());
ImGui::SetCursorPosY(startY);
ImGui::TableNextColumn();
const ImColor colorText = ImGui::GetColorU32(ImGuiCol_Text);
const ImColor colorDisabled = this->m_greyedOutZeros ? ImGui::GetColorU32(ImGuiCol_TextDisabled) : static_cast<u32>(colorText);
for (s8 curr = 0; curr < 2; curr++) {
auto other = !curr;
std::optional<ImVec2> lastHighlightEnd;
for (s64 col = 0; col < lineInfo[curr].validBytes; col++) {
auto pos = ImGui::GetCursorScreenPos();
// Diff bytes
std::optional<u32> highlightColor;
switch (diffBytes(col, lineInfo[curr], lineInfo[other])) {
default:
case DiffResult::Same:
/* No highlight */
break;
case DiffResult::Changed:
highlightColor = getDiffColor(ImGui::GetCustomColorU32(ImGuiCustomCol_ToolbarYellow));
break;
case DiffResult::Added:
highlightColor = getDiffColor(ImGui::GetCustomColorU32(ImGuiCustomCol_ToolbarGreen));
break;
case DiffResult::Removed:
highlightColor = getDiffColor(ImGui::GetCustomColorU32(ImGuiCustomCol_ToolbarRed));
break;
}
// Draw byte
u8 byte = lineInfo[curr].bytes[col];
ImGui::TextColored(byte == 0x00 ? colorDisabled : colorText, "%s", hex::format(this->m_upperCaseHex ? "{:02X}" : "{:02x}", byte).c_str());
ImGui::SetCursorPosY(startY);
// Draw highlighting
if (highlightColor.has_value()) {
drawList->AddRectFilled(lastHighlightEnd.value_or(pos), pos + highlightSize, highlightColor.value());
lastHighlightEnd = pos + ImVec2((glyphWidth - 1) * 2, 0);
} else {
lastHighlightEnd.reset();
}
ImGui::SameLine(0.0F, col % 8 == 7 ? glyphWidth * 2.5F : glyphWidth * 0.25F);
}
ImGui::TableNextColumn();
}
}
void ViewDiff::drawContent() {
if (ImGui::Begin(View::toWindowName("hex.view.diff.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
ImGui::SameLine();
ImGui::PushID(1);
drawProviderSelector(this->m_providerA);
ImGui::PopID();
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
ImGui::TextUnformatted("<=>");
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
ImGui::PushID(2);
drawProviderSelector(this->m_providerB);
ImGui::PopID();
ImGui::Separator();
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(20, 1));
if (ImGui::BeginTable("diff", 3, ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_SizingFixedFit)) {
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableNextColumn();
ImGui::TableNextColumn();
// Draw header line
{
auto glyphWidth = ImGui::CalcTextSize("0").x + 1;
for (u8 i = 0; i < 2; i++) {
for (u8 col = 0; col < this->m_columnCount; col++) {
ImGui::TextUnformatted(hex::format(this->m_upperCaseHex ? "{:02X}" : "{:02x}", col).c_str());
ImGui::SameLine(0.0F, col % 8 == 7 ? glyphWidth * 2.5F : glyphWidth * 0.25F);
}
ImGui::TableNextColumn();
}
}
if (this->m_providerA >= 0 && this->m_providerB >= 0) {
auto &providers = ImHexApi::Provider::getProviders();
ImGuiListClipper clipper;
clipper.Begin(std::max(providers[this->m_providerA]->getSize() / this->m_columnCount, providers[this->m_providerB]->getSize() / this->m_columnCount));
// Draw diff lines
while (clipper.Step()) {
for (u64 row = clipper.DisplayStart; row < clipper.DisplayEnd; row++) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
drawDiffLine({this->m_providerA, this->m_providerB}, row);
}
}
}
ImGui::EndTable();
}
ImGui::PopStyleVar();
}
ImGui::End();
}
void ViewDiff::drawMenu() {
}
}

View File

@@ -19,8 +19,12 @@ namespace hex {
EventManager::subscribe<EventRegionSelected>(this, [this](Region region) {
if (this->m_shouldMatchSelection) {
this->m_codeRegion[0] = region.address;
this->m_codeRegion[1] = region.address + region.size;
if (region.address == size_t(-1)) {
this->m_codeRegion[0] = this->m_codeRegion[1] = 0;
} else {
this->m_codeRegion[0] = region.address;
this->m_codeRegion[1] = region.address + region.size;
}
}
});
}
@@ -55,7 +59,7 @@ namespace hex {
cs_option(capstoneHandle, CS_OPT_SKIPDATA, CS_OPT_ON);
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
std::vector<u8> buffer(2048, 0x00);
for (u64 address = 0; address < (this->m_codeRegion[1] - this->m_codeRegion[0] + 1); address += 2048) {
size_t bufferSize = std::min(u64(2048), (this->m_codeRegion[1] - this->m_codeRegion[0] + 1) - address);
@@ -102,8 +106,8 @@ namespace hex {
if (ImGui::Begin(View::toWindowName("hex.view.disassembler.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
auto provider = SharedData::currentProvider;
if (provider != nullptr && provider->isReadable()) {
auto provider = ImHexApi::Provider::get();
if (ImHexApi::Provider::isValid() && provider->isReadable()) {
ImGui::TextUnformatted("hex.view.disassembler.position"_lang);
ImGui::Separator();

View File

@@ -15,8 +15,12 @@ namespace hex {
EventManager::subscribe<EventRegionSelected>(this, [this](Region region) {
if (this->m_shouldMatchSelection) {
this->m_hashRegion[0] = region.address;
this->m_hashRegion[1] = region.address + region.size;
if (region.address == size_t(-1)) {
this->m_hashRegion[0] = this->m_hashRegion[1] = 0;
} else {
this->m_hashRegion[0] = region.address;
this->m_hashRegion[1] = region.address + region.size;
}
this->m_shouldInvalidate = true;
}
});
@@ -39,8 +43,8 @@ namespace hex {
if (ImGui::BeginChild("##scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav)) {
auto provider = SharedData::currentProvider;
if (provider != nullptr && provider->isAvailable()) {
auto provider = ImHexApi::Provider::get();
if (ImHexApi::Provider::isValid() && provider->isAvailable()) {
ImGui::TextUnformatted("hex.common.region"_lang);
ImGui::Separator();

View File

@@ -17,7 +17,7 @@ namespace hex {
static void drawTitle(const std::string &title) {
ImGui::TextColored(ImVec4(0.6F, 0.6F, 1.0F, 1.0F), title.c_str());
ImGui::TextColored(ImVec4(0.6F, 0.6F, 1.0F, 1.0F), "%s", title.c_str());
}
static void drawBuiltinFunction(
@@ -27,9 +27,9 @@ namespace hex {
const std::string &description
) {
ImGui::Bullet();
ImGui::TextColored(ImVec4(0.3F, 0.7F, 0.2F, 1.0F), return_type.c_str());
ImGui::TextColored(ImVec4(0.3F, 0.7F, 0.2F, 1.0F), "%s", return_type.c_str());
ImGui::SameLine();
ImGui::TextColored(ImVec4(0.57F, 0.24F, 0.69F, 1.0F), name.c_str());
ImGui::TextColored(ImVec4(0.57F, 0.24F, 0.69F, 1.0F), "%s", name.c_str());
ImGui::SameLine();
ImGui::TextColored(ImVec4(0.71F, 0.19F, 0.31F, 1.0F), "(");
ImGui::SameLine();
@@ -77,7 +77,7 @@ namespace hex {
constexpr const char* Links[] = { "https://werwolv.net/donate", "https://www.patreon.com/werwolv", "https://github.com/sponsors/WerWolv" };
ImGui::TextWrapped("hex.view.help.about.thanks"_lang);
ImGui::TextWrapped("%s", static_cast<const char *>("hex.view.help.about.thanks"_lang));
ImGui::NewLine();

View File

@@ -35,7 +35,7 @@ namespace hex {
this->m_searchHexBuffer.resize(0xFFF, 0x00);
this->m_memoryEditor.ReadFn = [](const ImU8 *data, size_t off) -> ImU8 {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
if (!provider->isAvailable() || !provider->isReadable())
return 0x00;
@@ -46,7 +46,7 @@ namespace hex {
};
this->m_memoryEditor.WriteFn = [](ImU8 *data, size_t off, ImU8 d) -> void {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
if (!provider->isAvailable() || !provider->isWritable())
return;
@@ -60,7 +60,7 @@ namespace hex {
std::optional<u32> currColor, prevColor;
off += SharedData::currentProvider->getBaseAddress();
off += ImHexApi::Provider::get()->getBaseAddress();
u32 alpha = static_cast<u32>(_this->m_highlightAlpha) << 24;
@@ -96,7 +96,7 @@ namespace hex {
this->m_memoryEditor.HoverFn = [](const ImU8 *data, size_t off) {
bool tooltipShown = false;
off += SharedData::currentProvider->getBaseAddress();
off += ImHexApi::Provider::get()->getBaseAddress();
for (const auto &[region, name, comment, color, locked] : ImHexApi::Bookmarks::getEntries()) {
if (off >= region.address && off < (region.address + region.size)) {
@@ -120,7 +120,7 @@ namespace hex {
if (_this->m_currEncodingFile.getLongestSequence() == 0)
return { ".", 1, 0xFFFF8000 };
auto &provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
size_t size = std::min<size_t>(_this->m_currEncodingFile.getLongestSequence(), provider->getActualSize() - addr);
std::vector<u8> buffer(size);
@@ -144,7 +144,7 @@ namespace hex {
});
EventManager::subscribe<RequestSelectionChange>(this, [this](Region region) {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
auto page = provider->getPageOfAddress(region.address);
if (!page.has_value())
@@ -197,17 +197,59 @@ namespace hex {
} else if (name == "Open Project") {
hex::openFileBrowser("hex.view.hexeditor.open_project"_lang, DialogMode::Open, { { "Project File", "hexproj" } }, [this](auto path) {
ProjectFile::load(path);
EventManager::post<EventProjectFileLoad>();
this->getWindowOpenState() = true;
});
}
});
EventManager::subscribe<EventSettingsChanged>(this, [this] {
auto alpha = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.highlight_alpha");
{
auto alpha = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.highlight_alpha");
if (alpha.is_number())
this->m_highlightAlpha = alpha;
}
{
auto columnCount = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.column_count");
this->m_memoryEditor.Cols = static_cast<int>(columnCount);
}
{
auto hexii = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.hexii");
this->m_memoryEditor.OptShowHexII = static_cast<int>(hexii);
}
{
auto ascii = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.ascii");
this->m_memoryEditor.OptShowAscii = static_cast<int>(ascii);
}
{
auto advancedDecoding = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.advanced_decoding");
this->m_memoryEditor.OptShowAdvancedDecoding = static_cast<int>(advancedDecoding);
}
{
auto greyOutZeros = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.grey_zeros");
this->m_memoryEditor.OptGreyOutZeroes = static_cast<int>(greyOutZeros);
}
{
auto upperCaseHex = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.uppercase_hex");
this->m_memoryEditor.OptUpperCaseHex = static_cast<int>(upperCaseHex);
}
{
auto showExtraInfo = ContentRegistry::Settings::getSetting("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.extra_info");
this->m_memoryEditor.OptShowExtraInfo = static_cast<int>(showExtraInfo);
}
});
EventManager::subscribe<QuerySelection>(this, [this](auto &region) {
@@ -229,9 +271,9 @@ namespace hex {
}
void ViewHexEditor::drawContent() {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
size_t dataSize = (provider == nullptr || !provider->isReadable()) ? 0x00 : provider->getSize();
size_t dataSize = (!ImHexApi::Provider::isValid() || !provider->isReadable()) ? 0x00 : provider->getSize();
this->m_memoryEditor.DrawWindow(View::toWindowName("hex.view.hexeditor.name").c_str(), &this->getWindowOpenState(), this, dataSize, dataSize == 0 ? 0x00 : provider->getBaseAddress());
@@ -246,47 +288,46 @@ namespace hex {
ImGui::EndPopup();
}
ImGui::SameLine();
ImGui::Spacing();
ImGui::SameLine();
ImGui::TextUnformatted(hex::format("hex.view.hexeditor.page"_lang, provider->getCurrentPage() + 1, provider->getPageCount()).c_str());
ImGui::SameLine();
if (provider->getPageCount() > 1) {
ImGui::TextUnformatted(hex::format("hex.view.hexeditor.page"_lang, provider->getCurrentPage() + 1, provider->getPageCount()).c_str());
if (ImGui::ArrowButton("prevPage", ImGuiDir_Left)) {
provider->setCurrentPage(provider->getCurrentPage() - 1);
ImGui::SameLine();
EventManager::post<EventRegionSelected>(Region { std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd), 1 });
if (ImGui::ArrowButton("prevPage", ImGuiDir_Left)) {
provider->setCurrentPage(provider->getCurrentPage() - 1);
EventManager::post<EventRegionSelected>(Region { std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd), 1 });
}
ImGui::SameLine();
if (ImGui::ArrowButton("nextPage", ImGuiDir_Right)) {
provider->setCurrentPage(provider->getCurrentPage() + 1);
EventManager::post<EventRegionSelected>(Region { std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd), 1 });
}
}
ImGui::SameLine();
this->drawSearchPopup();
this->drawGotoPopup();
if (ImGui::ArrowButton("nextPage", ImGuiDir_Right)) {
provider->setCurrentPage(provider->getCurrentPage() + 1);
EventManager::post<EventRegionSelected>(Region { std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd), 1 });
}
}
ImGui::End();
this->drawSearchPopup();
this->drawGotoPopup();
}
}
static void save() {
auto provider = SharedData::currentProvider;
provider->save();
ImHexApi::Provider::get()->save();
}
static void saveAs() {
hex::openFileBrowser("hex.view.hexeditor.save_as"_lang, DialogMode::Save, { }, [](auto path) {
auto provider = SharedData::currentProvider;
provider->saveAs(path);
ImHexApi::Provider::get()->saveAs(path);
});
}
void ViewHexEditor::drawAlwaysVisible() {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
if (ImGui::BeginPopupModal("hex.view.hexeditor.exit_application.title"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::NewLine();
@@ -308,7 +349,7 @@ namespace hex {
if (ImGui::BeginPopupModal("hex.view.hexeditor.script.title"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::SetCursorPosX(10);
ImGui::TextWrapped("hex.view.hexeditor.script.desc"_lang);
ImGui::TextWrapped("%s", static_cast<const char *>("hex.view.hexeditor.script.desc"_lang));
ImGui::NewLine();
ImGui::InputText("##nolabel", this->m_loaderScriptScriptPath.data(), this->m_loaderScriptScriptPath.length(), ImGuiInputTextFlags_ReadOnly);
@@ -387,7 +428,8 @@ namespace hex {
}
void ViewHexEditor::drawMenu() {
auto &provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
bool providerValid = ImHexApi::Provider::isValid();
if (ImGui::BeginMenu("hex.menu.file"_lang)) {
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.open_file"_lang, "CTRL + O")) {
@@ -407,18 +449,22 @@ namespace hex {
ImGui::EndMenu();
}
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.save"_lang, "CTRL + S", false, provider != nullptr && provider->isWritable())) {
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.save"_lang, "CTRL + S", false, providerValid && provider->isWritable())) {
save();
}
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.save_as"_lang, "CTRL + SHIFT + S", false, provider != nullptr && provider->isWritable())) {
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.save_as"_lang, "CTRL + SHIFT + S", false, providerValid && provider->isWritable())) {
saveAs();
}
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.close"_lang, "", false, provider != nullptr && provider->isAvailable())) {
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.close"_lang, "", false, providerValid && provider->isAvailable())) {
EventManager::post<EventFileUnloaded>();
delete SharedData::currentProvider;
SharedData::currentProvider = nullptr;
ImHexApi::Provider::remove(ImHexApi::Provider::get());
providerValid = false;
}
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.quit"_lang, "", false)) {
ImHexApi::Common::closeImHex();
}
ImGui::Separator();
@@ -426,11 +472,10 @@ namespace hex {
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.open_project"_lang, "")) {
hex::openFileBrowser("hex.view.hexeditor.menu.file.open_project"_lang, DialogMode::Open, { { "Project File", "hexproj" } }, [this](auto path) {
ProjectFile::load(path);
EventManager::post<EventProjectFileLoad>();
});
}
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.save_project"_lang, "", false, provider != nullptr && provider->isWritable())) {
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.save_project"_lang, "", false, providerValid && provider->isWritable())) {
if (ProjectFile::getProjectFilePath() == "") {
hex::openFileBrowser("hex.view.hexeditor.save_project"_lang, DialogMode::Save, { { "Project File", "hexproj" } }, [](auto path) {
if (path.ends_with(".hexproj")) {
@@ -480,8 +525,9 @@ namespace hex {
auto patchData = File(path, File::Mode::Read).readBytes();
auto patch = hex::loadIPSPatch(patchData);
auto provider = ImHexApi::Provider::get();
for (auto &[address, value] : patch) {
SharedData::currentProvider->write(address, &value, 1);
provider->write(address, &value, 1);
}
this->getWindowOpenState() = true;
});
@@ -494,8 +540,9 @@ namespace hex {
auto patchData = File(path, File::Mode::Read).readBytes();
auto patch = hex::loadIPS32Patch(patchData);
auto provider = ImHexApi::Provider::get();
for (auto &[address, value] : patch) {
SharedData::currentProvider->write(address, &value, 1);
provider->write(address, &value, 1);
}
this->getWindowOpenState() = true;
});
@@ -510,7 +557,7 @@ namespace hex {
ImGui::EndMenu();
}
if (ImGui::BeginMenu("hex.view.hexeditor.menu.file.export"_lang, provider != nullptr && provider->isWritable())) {
if (ImGui::BeginMenu("hex.view.hexeditor.menu.file.export"_lang, providerValid && provider->isWritable())) {
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.export.ips"_lang)) {
Patches patches = provider->getPatches();
if (!patches.contains(0x00454F45) && patches.contains(0x00454F46)) {
@@ -547,12 +594,12 @@ namespace hex {
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.search"_lang, "CTRL + F")) {
this->getWindowOpenState() = true;
View::doLater([]{ ImGui::OpenPopup("hex.view.hexeditor.menu.file.search"_lang); });
ImGui::OpenPopupInWindow(View::toWindowName("hex.view.hexeditor.name").c_str(), "hex.view.hexeditor.menu.file.search"_lang);
}
if (ImGui::MenuItem("hex.view.hexeditor.menu.file.goto"_lang, "CTRL + G")) {
this->getWindowOpenState() = true;
View::doLater([]{ ImGui::OpenPopup("hex.view.hexeditor.menu.file.goto"_lang); });
ImGui::OpenPopupInWindow(View::toWindowName("hex.view.hexeditor.name").c_str(), "hex.view.hexeditor.menu.file.goto"_lang);
}
ImGui::EndMenu();
@@ -578,20 +625,22 @@ namespace hex {
if (ImGui::IsWindowFocused(ImGuiFocusedFlags_ChildWindows)) {
if (ctrl && keys['Z']) {
if (SharedData::currentProvider != nullptr)
SharedData::currentProvider->undo();
if (ImHexApi::Provider::isValid())
ImHexApi::Provider::get()->undo();
return true;
} else if (ctrl && keys['Y']) {
if (SharedData::currentProvider != nullptr)
SharedData::currentProvider->redo();
if (ImHexApi::Provider::isValid())
ImHexApi::Provider::get()->redo();
} else if (ctrl && keys['F']) {
View::doLater([]{ ImGui::OpenPopup("hex.view.hexeditor.menu.file.search"_lang); });
ImGui::OpenPopupInWindow(View::toWindowName("hex.view.hexeditor.name").c_str(), "hex.view.hexeditor.menu.file.search"_lang);
return true;
} else if (ctrl && keys['G']) {
View::doLater([]{ ImGui::OpenPopup("hex.view.hexeditor.menu.file.goto"_lang); });
ImGui::OpenPopupInWindow(View::toWindowName("hex.view.hexeditor.name").c_str(), "hex.view.hexeditor.menu.file.goto"_lang);
return true;
} else if (ctrl && keys['O']) {
View::doLater([]{ ImGui::OpenPopup("hex.view.hexeditor.open_file"_lang); });
hex::openFileBrowser("hex.view.hexeditor.open_file"_lang, DialogMode::Open, { }, [](auto path) {
EventManager::post<RequestOpenFile>(path);
});
return true;
} else if (ctrl && keys['C']) {
this->copyBytes();
@@ -603,7 +652,8 @@ namespace hex {
this->pasteBytes();
return true;
} else if (ctrl && keys['A']) {
EventManager::post<RequestSelectionChange>(Region { SharedData::currentProvider->getBaseAddress(), SharedData::currentProvider->getActualSize() });
auto provider = ImHexApi::Provider::get();
EventManager::post<RequestSelectionChange>(Region { provider->getBaseAddress(), provider->getActualSize() });
return true;
}
}
@@ -647,11 +697,9 @@ namespace hex {
}
void ViewHexEditor::openFile(const std::string &path) {
auto& provider = SharedData::currentProvider;
ImHexApi::Provider::add<prv::FileProvider>(path);
auto provider = ImHexApi::Provider::get();
delete provider;
provider = new prv::FileProvider(path);
if (!provider->isWritable()) {
this->m_memoryEditor.ReadOnly = true;
View::showErrorPopup("hex.view.hexeditor.error.read_only"_lang);
@@ -661,8 +709,7 @@ namespace hex {
if (!provider->isAvailable()) {
View::showErrorPopup("hex.view.hexeditor.error.open"_lang);
delete provider;
provider = nullptr;
ImHexApi::Provider::remove(provider);
return;
}
@@ -689,7 +736,7 @@ namespace hex {
}
void ViewHexEditor::copyBytes() const {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
size_t start = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
size_t end = std::max(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
@@ -708,7 +755,7 @@ namespace hex {
}
void ViewHexEditor::pasteBytes() const {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
size_t start = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
size_t end = std::max(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
@@ -750,7 +797,7 @@ namespace hex {
}
void ViewHexEditor::copyString() const {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
size_t start = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
size_t end = std::max(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
@@ -765,7 +812,7 @@ namespace hex {
}
void ViewHexEditor::copyLanguageArray(Language language) const {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
size_t start = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
size_t end = std::max(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
@@ -867,7 +914,7 @@ namespace hex {
}
void ViewHexEditor::copyHexView() const {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
size_t start = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
size_t end = std::max(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
@@ -914,7 +961,7 @@ namespace hex {
}
void ViewHexEditor::copyHexViewHTML() const {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
size_t start = std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
size_t end = std::max(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
@@ -996,7 +1043,7 @@ R"(
foundCharacters = 0;
if (foundCharacters == string.size()) {
results.emplace_back(offset + i - foundCharacters + 1, offset + i + 1);
results.emplace_back(offset + i - foundCharacters + 1, offset + i);
foundCharacters = 0;
}
}
@@ -1034,7 +1081,7 @@ R"(
foundCharacters = 0;
if (foundCharacters == hex.size()) {
results.emplace_back(offset + i - foundCharacters + 1, offset + i + 1);
results.emplace_back(offset + i - foundCharacters + 1, offset + i);
foundCharacters = 0;
}
}
@@ -1047,7 +1094,7 @@ R"(
void ViewHexEditor::drawSearchPopup() {
static auto InputCallback = [](ImGuiInputTextCallbackData* data) -> int {
auto _this = static_cast<ViewHexEditor*>(data->UserData);
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
*_this->m_lastSearchBuffer = _this->m_searchFunction(provider, data->Buf);
_this->m_lastSearchIndex = 0;
@@ -1059,7 +1106,7 @@ R"(
};
static auto Find = [this](char *buffer) {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
*this->m_lastSearchBuffer = this->m_searchFunction(provider, buffer);
this->m_lastSearchIndex = 0;
@@ -1090,8 +1137,9 @@ R"(
}
};
if (ImGui::BeginPopupContextVoid("hex.view.hexeditor.menu.file.search"_lang)) {
ImGui::TextUnformatted("hex.view.hexeditor.menu.file.search"_lang);
ImGui::SetNextWindowPos(ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMin() - ImGui::GetStyle().WindowPadding);
if (ImGui::BeginPopup("hex.view.hexeditor.menu.file.search"_lang)) {
if (ImGui::BeginTabBar("searchTabs")) {
std::vector<char> *currBuffer = nullptr;
if (ImGui::BeginTabItem("hex.view.hexeditor.search.string"_lang)) {
@@ -1133,18 +1181,17 @@ R"(
ImGui::EndTabBar();
}
ImGui::EndPopup();
}
}
void ViewHexEditor::drawGotoPopup() {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
auto baseAddress = provider->getBaseAddress();
auto dataSize = provider->getActualSize();
ImGui::SetNextWindowPos(ImGui::GetWindowPos() + ImGui::GetWindowContentRegionMin() - ImGui::GetStyle().WindowPadding);
if (ImGui::BeginPopup("hex.view.hexeditor.menu.file.goto"_lang)) {
ImGui::TextUnformatted("hex.view.hexeditor.menu.file.goto"_lang);
if (ImGui::BeginTabBar("gotoTabs")) {
u64 newOffset = 0;
if (ImGui::BeginTabItem("hex.view.hexeditor.goto.offset.absolute"_lang)) {
@@ -1205,10 +1252,12 @@ R"(
}
void ViewHexEditor::drawEditPopup() {
if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.undo"_lang, "CTRL + Z", false, SharedData::currentProvider != nullptr))
SharedData::currentProvider->undo();
if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.redo"_lang, "CTRL + Y", false, SharedData::currentProvider != nullptr))
SharedData::currentProvider->redo();
auto provider = ImHexApi::Provider::get();
bool providerValid = ImHexApi::Provider::isValid();
if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.undo"_lang, "CTRL + Z", false, providerValid))
provider->undo();
if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.redo"_lang, "CTRL + Y", false, providerValid))
provider->redo();
ImGui::Separator();
@@ -1251,13 +1300,13 @@ R"(
if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.paste"_lang, "CTRL + V", false, bytesSelected))
this->pasteBytes();
if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.select_all"_lang, "CTRL + A", false, SharedData::currentProvider != nullptr))
EventManager::post<RequestSelectionChange>(Region { SharedData::currentProvider->getBaseAddress(), SharedData::currentProvider->getActualSize() });
if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.select_all"_lang, "CTRL + A", false, providerValid))
EventManager::post<RequestSelectionChange>(Region { provider->getBaseAddress(), provider->getActualSize() });
ImGui::Separator();
if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.bookmark"_lang, nullptr, false, this->m_memoryEditor.DataPreviewAddr != -1 && this->m_memoryEditor.DataPreviewAddrEnd != -1)) {
auto base = SharedData::currentProvider->getBaseAddress();
auto base = ImHexApi::Provider::get()->getBaseAddress();
size_t start = base + std::min(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
size_t end = base + std::max(this->m_memoryEditor.DataPreviewAddr, this->m_memoryEditor.DataPreviewAddrEnd);
@@ -1265,15 +1314,14 @@ R"(
ImHexApi::Bookmarks::add(start, end - start + 1, { }, { });
}
auto provider = SharedData::currentProvider;
if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.set_base"_lang, nullptr, false, provider != nullptr && provider->isReadable())) {
if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.set_base"_lang, nullptr, false, providerValid && provider->isReadable())) {
std::memset(this->m_baseAddressBuffer, 0x00, sizeof(this->m_baseAddressBuffer));
View::doLater([]{ ImGui::OpenPopup("hex.view.hexeditor.menu.edit.set_base"_lang); });
}
if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.resize"_lang, nullptr, false, provider != nullptr && provider->isResizable())) {
View::doLater([this, &provider]{
this->m_resizeSize = provider->getActualSize();
if (ImGui::MenuItem("hex.view.hexeditor.menu.edit.resize"_lang, nullptr, false, providerValid && provider->isResizable())) {
View::doLater([this]{
this->m_resizeSize = ImHexApi::Provider::get()->getActualSize();
ImGui::OpenPopup("hex.view.hexeditor.menu.edit.resize"_lang);
});
}

View File

@@ -69,7 +69,7 @@ namespace hex {
this->m_analyzing = true;
std::thread([this]{
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
this->m_analyzedRegion = { provider->getBaseAddress(), provider->getBaseAddress() + provider->getSize() };
@@ -110,8 +110,8 @@ namespace hex {
if (ImGui::BeginChild("##scrolling", ImVec2(0, 0), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav)) {
auto provider = SharedData::currentProvider;
if (provider != nullptr && provider->isReadable()) {
auto provider = ImHexApi::Provider::get();
if (ImHexApi::Provider::isValid() && provider->isReadable()) {
ImGui::TextUnformatted("hex.view.information.control"_lang);
ImGui::Separator();
@@ -131,7 +131,7 @@ namespace hex {
ImGui::TextUnformatted("hex.view.information.region"_lang);
ImGui::Separator();
for (auto &[name, value] : (SharedData::currentProvider)->getDataInformation()) {
for (auto &[name, value] : provider->getDataInformation()) {
ImGui::LabelText(name.c_str(), "%s", value.c_str());
}

View File

@@ -12,14 +12,14 @@ namespace hex {
ViewPatches::ViewPatches() : View("hex.view.patches.name") {
EventManager::subscribe<EventProjectFileStore>(this, []{
auto provider = SharedData::currentProvider;
if (provider != nullptr)
auto provider = ImHexApi::Provider::get();
if (ImHexApi::Provider::isValid())
ProjectFile::setPatches(provider->getPatches());
});
EventManager::subscribe<EventProjectFileLoad>(this, []{
auto provider = SharedData::currentProvider;
if (provider != nullptr)
auto provider = ImHexApi::Provider::get();
if (ImHexApi::Provider::isValid())
provider->getPatches() = ProjectFile::getPatches();
});
}
@@ -31,9 +31,9 @@ namespace hex {
void ViewPatches::drawContent() {
if (ImGui::Begin(View::toWindowName("hex.view.patches.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
if (provider != nullptr && provider->isReadable()) {
if (ImHexApi::Provider::isValid() && provider->isReadable()) {
if (ImGui::BeginTable("##patchesTable", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable |
ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY)) {

View File

@@ -49,8 +49,8 @@ namespace hex {
void ViewPatternData::drawContent() {
if (ImGui::Begin(View::toWindowName("hex.view.pattern_data.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
auto provider = SharedData::currentProvider;
if (provider != nullptr && provider->isReadable()) {
auto provider = ImHexApi::Provider::get();
if (ImHexApi::Provider::isValid() && provider->isReadable()) {
if (beginPatternDataTable(provider, SharedData::patternData, this->m_sortedPatternData)) {
ImGui::TableHeadersRow();

View File

@@ -17,27 +17,28 @@
namespace hex {
using namespace hex::literals;
namespace fs = std::filesystem;
static const TextEditor::LanguageDefinition& PatternLanguage() {
static bool initialized = false;
static TextEditor::LanguageDefinition langDef;
if (!initialized) {
static const char* const keywords[] = {
"using", "struct", "union", "enum", "bitfield", "be", "le", "if", "else", "false", "true", "parent", "addressof", "sizeof", "$", "while", "fn", "return", "namespace"
"using", "struct", "union", "enum", "bitfield", "be", "le", "if", "else", "false", "true", "this", "parent", "addressof", "sizeof", "$", "while", "fn", "return", "namespace"
};
for (auto& k : keywords)
langDef.mKeywords.insert(k);
static std::pair<const char* const, size_t> builtInTypes[] = {
{ "u8", 1 }, { "u16", 2 }, { "u32", 4 }, { "u64", 8 }, { "u128", 16 },
{ "s8", 1 }, { "s16", 2 }, { "s32", 4 }, { "s64", 8 }, { "s128", 16 },
{ "float", 4 }, { "double", 8 }, { "char", 1 }, { "char16", 2 }, { "bool", 1 }, { "padding", 1 }
static const char* const builtInTypes[] = {
"u8", "u16", "u32", "u64", "u128",
"s8", "s16", "s32", "s64", "s128",
"float", "double", "char", "char16",
"bool", "padding", "str", "auto"
};
for (const auto &[name, size] : builtInTypes) {
for (const auto name : builtInTypes) {
TextEditor::Identifier id;
id.mDeclaration = std::to_string(size);
id.mDeclaration += size == 1 ? " byte" : " bytes";
id.mDeclaration = "Built-in type";
langDef.mIdentifiers.insert(std::make_pair(std::string(name), id));
}
@@ -96,22 +97,22 @@ namespace hex {
this->parsePattern(this->m_textEditor.GetText().data());
});
EventManager::subscribe<RequestAppendPatternLanguageCode>(this, [this](std::string code) {
this->m_textEditor.InsertText("\n");
EventManager::subscribe<RequestSetPatternLanguageCode>(this, [this](std::string code) {
this->m_textEditor.SelectAll();
this->m_textEditor.Delete();
this->m_textEditor.InsertText(code);
});
EventManager::subscribe<EventFileLoaded>(this, [this](const std::string &path) {
if (this->m_textEditor.GetText().find_first_not_of(" \f\n\r\t\v") != std::string::npos)
if (!ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.auto_load_patterns", 1))
return;
pl::Preprocessor preprocessor;
auto provider = SharedData::currentProvider;
if (provider == nullptr)
if (!ImHexApi::Provider::isValid())
return;
std::string mimeType = magic::getMIMEType(provider);
std::string mimeType = magic::getMIMEType(ImHexApi::Provider::get());
bool foundCorrectType = false;
preprocessor.addPragmaHandler("MIME", [&mimeType, &foundCorrectType](std::string value) {
@@ -128,6 +129,7 @@ namespace hex {
std::error_code errorCode;
for (const auto &dir : hex::getPath(ImHexPath::Patterns)) {
for (auto &entry : std::filesystem::directory_iterator(dir, errorCode)) {
foundCorrectType = false;
if (!entry.is_regular_file())
continue;
@@ -138,36 +140,33 @@ namespace hex {
preprocessor.preprocess(file.readString());
if (foundCorrectType)
this->m_possiblePatternFiles.push_back(entry.path().string());
this->m_possiblePatternFiles.push_back(entry.path());
}
}
if (!this->m_possiblePatternFiles.empty()) {
this->m_selectedPatternFile = 0;
View::doLater([] { ImGui::OpenPopup("hex.view.pattern.accept_pattern"_lang); });
EventManager::post<RequestOpenPopup>("hex.view.pattern.accept_pattern"_lang);
this->m_acceptPatternWindowOpen = true;
}
});
/* Settings */
{
EventManager::subscribe<EventSettingsChanged>(this, [this]() {
auto theme = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color");
if (theme.is_number()) {
switch (static_cast<int>(theme)) {
default:
case 0: /* Dark theme */
this->m_textEditor.SetPalette(TextEditor::GetDarkPalette());
break;
case 1: /* Light theme */
this->m_textEditor.SetPalette(TextEditor::GetLightPalette());
break;
case 2: /* Classic theme */
this->m_textEditor.SetPalette(TextEditor::GetRetroBluePalette());
break;
}
EventManager::subscribe<RequestChangeTheme>(this, [this](u32 theme) {
switch (theme) {
default:
case 1: /* Dark theme */
this->m_textEditor.SetPalette(TextEditor::GetDarkPalette());
break;
case 2: /* Light theme */
this->m_textEditor.SetPalette(TextEditor::GetLightPalette());
break;
case 3: /* Classic theme */
this->m_textEditor.SetPalette(TextEditor::GetRetroBluePalette());
break;
}
});
@@ -179,17 +178,27 @@ namespace hex {
EventManager::unsubscribe<EventProjectFileStore>(this);
EventManager::unsubscribe<EventProjectFileLoad>(this);
EventManager::unsubscribe<RequestAppendPatternLanguageCode>(this);
EventManager::unsubscribe<RequestSetPatternLanguageCode>(this);
EventManager::unsubscribe<EventFileLoaded>(this);
EventManager::unsubscribe<EventSettingsChanged>(this);
EventManager::unsubscribe<RequestChangeTheme>(this);
}
void ViewPatternEditor::drawMenu() {
if (ImGui::BeginMenu("hex.menu.file"_lang)) {
if (ImGui::MenuItem("hex.view.pattern.menu.file.load_pattern"_lang)) {
hex::openFileBrowser("hex.view.pattern.open_pattern"_lang, DialogMode::Open, { { "Pattern File", "hexpat" } }, [this](auto path) {
this->loadPatternFile(path);
});
this->m_selectedPatternFile = 0;
this->m_possiblePatternFiles.clear();
for (auto &imhexPath : hex::getPath(ImHexPath::Patterns)) {
for (auto &entry: fs::recursive_directory_iterator(imhexPath)) {
if (entry.is_regular_file() && entry.path().extension() == ".hexpat") {
this->m_possiblePatternFiles.push_back(entry.path());
}
}
}
View::doLater([]{ ImGui::OpenPopup("hex.view.pattern.menu.file.load_pattern"_lang); });
}
ImGui::EndMenu();
}
@@ -197,9 +206,9 @@ namespace hex {
void ViewPatternEditor::drawContent() {
if (ImGui::Begin(View::toWindowName("hex.view.pattern.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_None | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse)) {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
if (provider != nullptr && provider->isAvailable()) {
if (ImHexApi::Provider::isValid() && provider->isAvailable()) {
auto textEditorSize = ImGui::GetContentRegionAvail();
textEditorSize.y *= 4.0/5.0;
textEditorSize.y -= ImGui::GetTextLineHeightWithSpacing();
@@ -251,13 +260,21 @@ namespace hex {
if (this->m_evaluatorRunning)
ImGui::TextSpinner("hex.view.pattern.evaluating"_lang);
else
ImGui::Checkbox("hex.view.pattern.auto"_lang, &this->m_runAutomatically);
if (ImGui::Checkbox("hex.view.pattern.auto"_lang, &this->m_runAutomatically)) {
if (this->m_runAutomatically)
this->m_hasUnevaluatedChanges = true;
}
if (this->m_textEditor.IsTextChanged()) {
if (this->m_runAutomatically)
this->parsePattern(this->m_textEditor.GetText().data());
ProjectFile::markDirty();
if (this->m_runAutomatically)
this->m_hasUnevaluatedChanges = true;
}
if (this->m_hasUnevaluatedChanges && !this->m_evaluatorRunning) {
this->m_hasUnevaluatedChanges = false;
this->parsePattern(this->m_textEditor.GetText().data());
}
}
@@ -267,8 +284,8 @@ namespace hex {
}
void ViewPatternEditor::drawAlwaysVisible() {
if (ImGui::BeginPopupModal("hex.view.pattern.accept_pattern"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextWrapped("hex.view.pattern.accept_pattern.desc"_lang);
if (ImGui::BeginPopupModal("hex.view.pattern.accept_pattern"_lang, &this->m_acceptPatternWindowOpen, ImGuiWindowFlags_AlwaysAutoResize)) {
ImGui::TextWrapped("%s", static_cast<const char *>("hex.view.pattern.accept_pattern.desc"_lang));
std::vector<std::string> entries;
entries.resize(this->m_possiblePatternFiles.size());
@@ -277,19 +294,23 @@ namespace hex {
entries[i] = std::filesystem::path(this->m_possiblePatternFiles[i]).filename().string();
}
ImGui::ListBox("hex.view.pattern.accept_pattern.pattern_language"_lang, &this->m_selectedPatternFile, [](void *data, int id, const char** outText) -> bool {
auto &entries = *static_cast<std::vector<std::string>*>(data);
if (ImGui::BeginListBox("##patterns_accept", ImVec2(-FLT_MIN, 0))) {
*outText = entries[id].c_str();
u32 index = 0;
for (auto &path : this->m_possiblePatternFiles) {
if (ImGui::Selectable(path.filename().string().c_str(), index == this->m_selectedPatternFile))
this->m_selectedPatternFile = index;
index++;
}
return true;
}, &entries, entries.size(), 4);
ImGui::EndListBox();
}
ImGui::NewLine();
ImGui::Text("hex.view.pattern.accept_pattern.question"_lang);
ImGui::Text("%s", static_cast<const char *>("hex.view.pattern.accept_pattern.question"_lang));
confirmButtons("hex.common.yes"_lang, "hex.common.no"_lang, [this]{
this->loadPatternFile(this->m_possiblePatternFiles[this->m_selectedPatternFile]);
this->loadPatternFile(this->m_possiblePatternFiles[this->m_selectedPatternFile].string());
ImGui::CloseCurrentPopup();
}, []{
ImGui::CloseCurrentPopup();
@@ -300,6 +321,37 @@ namespace hex {
ImGui::EndPopup();
}
if (ImGui::BeginPopupModal("hex.view.pattern.menu.file.load_pattern"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
if (ImGui::BeginListBox("##patterns", ImVec2(-FLT_MIN, 0))) {
u32 index = 0;
for (auto &path : this->m_possiblePatternFiles) {
if (ImGui::Selectable(path.filename().string().c_str(), index == this->m_selectedPatternFile))
this->m_selectedPatternFile = index;
index++;
}
ImGui::EndListBox();
}
if (ImGui::Button("hex.common.open"_lang)) {
this->loadPatternFile(this->m_possiblePatternFiles[this->m_selectedPatternFile].string());
ImGui::CloseCurrentPopup();
}
ImGui::SameLine();
if (ImGui::Button("hex.common.browse"_lang)) {
hex::openFileBrowser("hex.view.pattern.open_pattern"_lang, DialogMode::Open, { { "Pattern File", "hexpat" } }, [this](auto path) {
this->loadPatternFile(path);
ImGui::CloseCurrentPopup();
});
}
ImGui::EndPopup();
}
}
@@ -338,13 +390,13 @@ namespace hex {
void ViewPatternEditor::parsePattern(char *buffer) {
this->m_evaluatorRunning = true;
this->clearPatternData();
this->m_textEditor.SetErrorMarkers({ });
this->m_console.clear();
this->clearPatternData();
EventManager::post<EventPatternChanged>();
std::thread([this, buffer = std::string(buffer)] {
auto result = this->m_patternLanguageRuntime->executeString(SharedData::currentProvider, buffer);
auto result = this->m_patternLanguageRuntime->executeString(ImHexApi::Provider::get(), buffer);
auto error = this->m_patternLanguageRuntime->getError();
if (error.has_value()) {
@@ -355,9 +407,9 @@ namespace hex {
if (result.has_value()) {
SharedData::patternData = std::move(result.value());
View::doLater([]{
//View::doLater([]{
EventManager::post<EventPatternChanged>();
});
//});
}
this->m_evaluatorRunning = false;

View File

@@ -24,14 +24,22 @@ namespace hex {
ImGui::SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, FLT_MAX));
if (ImGui::BeginPopupModal(View::toWindowName("hex.view.settings.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_AlwaysAutoResize)) {
for (auto &[category, entries] : ContentRegistry::Settings::getEntries()) {
ImGui::TextUnformatted(LangEntry(category));
ImGui::Separator();
for (auto &[name, callback] : entries) {
if (callback(LangEntry(name), ContentRegistry::Settings::getSettingsData()[category][name]))
EventManager::post<EventSettingsChanged>();
if (ImGui::BeginTabBar("settings")) {
for (auto &[category, entries] : ContentRegistry::Settings::getEntries()) {
if (ImGui::BeginTabItem(LangEntry(category))) {
ImGui::TextUnformatted(LangEntry(category));
ImGui::Separator();
for (auto &[name, callback] : entries) {
if (callback(LangEntry(name), ContentRegistry::Settings::getSettingsData()[category][name]))
EventManager::post<EventSettingsChanged>();
}
ImGui::EndTabItem();
}
}
ImGui::NewLine();
ImGui::EndTabBar();
}
ImGui::EndPopup();
} else

View File

@@ -13,6 +13,8 @@
#include <filesystem>
#include <functional>
#include <nlohmann/json.hpp>
#include <microtar.h>
#include <hex/helpers/file.hpp>
namespace hex {
@@ -34,7 +36,7 @@ namespace hex {
this->refresh();
}
auto drawTab = [this](auto title, ImHexPath pathType, auto &content, std::function<void()> downloadDoneCallback) {
auto drawTab = [this](auto title, ImHexPath pathType, auto &content, std::function<void(const StoreEntry&)> downloadDoneCallback) {
if (ImGui::BeginTabItem(title)) {
if (ImGui::BeginTable("##pattern_language", 3, ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_RowBg)) {
ImGui::TableSetupScrollFreeze(0, 1);
@@ -66,7 +68,34 @@ namespace hex {
if (response.code == 200) {
entry.installed = true;
entry.hasUpdate = false;
downloadDoneCallback();
if (entry.isFolder) {
mtar_t ctx;
mtar_open(&ctx, this->m_downloadPath.string().c_str(), "r");
mtar_header_t header;
auto extractBasePath = this->m_downloadPath.parent_path() / this->m_downloadPath.stem();
while (mtar_read_header(&ctx, &header) != MTAR_ENULLRECORD) {
auto filePath = extractBasePath / fs::path(header.name);
fs::create_directories(filePath.parent_path());
File outputFile(filePath.string(), File::Mode::Create);
std::vector<u8> buffer(0x10000);
for (u64 offset = 0; offset < header.size; offset += buffer.size()) {
auto readSize = std::min(buffer.size(), header.size - offset);
mtar_read_data(&ctx, buffer.data(), readSize);
buffer.resize(readSize);
outputFile.write(buffer);
}
mtar_next(&ctx);
}
mtar_finalize(&ctx);
mtar_close(&ctx);
}
downloadDoneCallback(entry);
} else
log::error("Download failed!");
@@ -103,12 +132,17 @@ namespace hex {
};
if (ImGui::BeginTabBar("storeTabs")) {
drawTab("hex.view.store.tab.patterns"_lang, ImHexPath::Patterns, this->m_patterns, []{});
drawTab("hex.view.store.tab.libraries"_lang, ImHexPath::PatternsInclude, this->m_includes, []{});
drawTab("hex.view.store.tab.magics"_lang, ImHexPath::Magic, this->m_magics, []{
auto extractTar = []{
};
drawTab("hex.view.store.tab.patterns"_lang, ImHexPath::Patterns, this->m_patterns, [](auto){});
drawTab("hex.view.store.tab.libraries"_lang, ImHexPath::PatternsInclude, this->m_includes, [](auto){});
drawTab("hex.view.store.tab.magics"_lang, ImHexPath::Magic, this->m_magics, [](auto){
magic::compile();
});
drawTab("hex.view.store.tab.constants"_lang, ImHexPath::Constants, this->m_constants, []{});
drawTab("hex.view.store.tab.constants"_lang, ImHexPath::Constants, this->m_constants, [](auto){});
drawTab("hex.view.store.tab.yara"_lang, ImHexPath::Yara, this->m_yara, [](auto){});
ImGui::EndTabBar();
}
@@ -118,6 +152,8 @@ namespace hex {
this->m_patterns.clear();
this->m_includes.clear();
this->m_magics.clear();
this->m_constants.clear();
this->m_yara.clear();
this->m_apiRequest = this->m_net.getString(ImHexApiURL + "/store"s);
}
@@ -134,10 +170,10 @@ namespace hex {
for (auto &entry : storeJson[name]) {
// Check if entry is valid
if (entry.contains("name") && entry.contains("desc") && entry.contains("file") && entry.contains("url") && entry.contains("hash")) {
if (entry.contains("name") && entry.contains("desc") && entry.contains("file") && entry.contains("url") && entry.contains("hash") && entry.contains("folder")) {
// Parse entry
StoreEntry storeEntry = { entry["name"], entry["desc"], entry["file"], entry["url"], entry["hash"], false, false, false };
StoreEntry storeEntry = { entry["name"], entry["desc"], entry["file"], entry["url"], entry["hash"], entry["folder"],false, false, false };
// Check if file is installed already or has an update available
for (const auto &folder : hex::getPath(pathType)) {
@@ -169,6 +205,7 @@ namespace hex {
parseStoreEntries(json, "includes", ImHexPath::PatternsInclude, this->m_includes);
parseStoreEntries(json, "magic", ImHexPath::Magic, this->m_magics);
parseStoreEntries(json, "constants", ImHexPath::Constants, this->m_constants);
parseStoreEntries(json, "yara", ImHexPath::Yara, this->m_yara);
}
this->m_apiRequest = { };
@@ -207,11 +244,13 @@ namespace hex {
void ViewStore::download(ImHexPath pathType, const std::string &fileName, const std::string &url, bool update) {
if (!update) {
this->m_download = this->m_net.downloadFile(url, hex::getPath(pathType).front() / fs::path(fileName));
this->m_downloadPath = hex::getPath(pathType).front() / fs::path(fileName);
this->m_download = this->m_net.downloadFile(url, this->m_downloadPath);
} else {
for (const auto &path : hex::getPath(pathType)) {
auto fullPath = path / fs::path(fileName);
if (fs::exists(fullPath)) {
this->m_downloadPath = fullPath;
this->m_download = this->m_net.downloadFile(url, fullPath);
}
}

View File

@@ -27,7 +27,7 @@ namespace hex {
std::string readString(const FoundString &foundString) {
std::string string(foundString.size + 1, '\0');
SharedData::currentProvider->read(foundString.offset, string.data(), foundString.size);
ImHexApi::Provider::get()->read(foundString.offset, string.data(), foundString.size);
return string;
}
@@ -57,7 +57,7 @@ namespace hex {
this->m_searching = true;
std::thread([this] {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
std::vector<u8> buffer(1024, 0x00);
u32 foundCharacters = 0;
@@ -91,10 +91,10 @@ namespace hex {
}
void ViewStrings::drawContent() {
auto provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
if (ImGui::Begin(View::toWindowName("hex.view.strings.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
if (provider != nullptr && provider->isReadable()) {
if (ImHexApi::Provider::isValid() && provider->isReadable()) {
ImGui::Disabled([this]{
if (ImGui::InputInt("hex.view.strings.min_length"_lang, &this->m_minimumLength, 1, 0))
this->m_foundStrings.clear();

View File

@@ -3,15 +3,19 @@
#include <hex/providers/provider.hpp>
#include <hex/helpers/utils.hpp>
#include <hex/helpers/file.hpp>
#include <hex/helpers/logger.hpp>
#include <yara.h>
#include <filesystem>
#include <thread>
#include <imgui_imhex_extensions.h>
#include <hex/helpers/paths.hpp>
namespace hex {
namespace fs = std::filesystem;
ViewYara::ViewYara() : View("hex.view.yara.name") {
yr_initialize();
@@ -39,10 +43,10 @@ namespace hex {
if (ImGui::Button("hex.view.yara.reload"_lang)) this->reloadRules();
} else {
ImGui::Disabled([this]{
if (ImGui::BeginCombo("hex.view.yara.header.rules"_lang, this->m_rules[this->m_selectedRule].c_str())) {
if (ImGui::BeginCombo("hex.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);
if (ImGui::Selectable(this->m_rules[i].c_str(), selected))
if (ImGui::Selectable(this->m_rules[i].first.c_str(), selected))
this->m_selectedRule = i;
if (selected)
@@ -119,12 +123,15 @@ namespace hex {
void ViewYara::reloadRules() {
this->m_rules.clear();
if (!std::filesystem::exists("./yara"))
return;
for (auto path : hex::getPath(ImHexPath::Yara)) {
if (!fs::exists(path))
continue;
for (const auto &entry : std::filesystem::directory_iterator("yara")) {
if (entry.is_regular_file())
this->m_rules.push_back(entry.path().string());
for (const auto &entry : fs::recursive_directory_iterator(path)) {
if (entry.is_regular_file() && entry.path().extension() == ".yar") {
this->m_rules.push_back({ fs::relative(entry.path(), fs::path(path)).string(), entry.path().string() });
}
}
}
}
@@ -137,21 +144,45 @@ namespace hex {
YR_COMPILER *compiler = nullptr;
yr_compiler_create(&compiler);
ON_SCOPE_EXIT {
yr_compiler_destroy(compiler);
this->m_matching = false;
};
File file(this->m_rules[this->m_selectedRule], File::Mode::Read);
yr_compiler_set_include_callback(
compiler,
[](const char *includeName, const char *callingRuleFileName, const char *callingRuleNamespace, void *userData) -> const char * {
auto currFilePath = static_cast<const char*>(userData);
File file((fs::path(currFilePath).parent_path() / includeName).string(), File::Mode::Read);
if (!file.isValid())
return nullptr;
auto size = file.getSize();
char *buffer = new char[size + 1];
file.readBuffer(reinterpret_cast<u8*>(buffer), size);
buffer[size] = 0x00;
return buffer;
},
[](const char *ptr, void *userData) {
delete[] ptr;
},
this->m_rules[this->m_selectedRule].second.data());
File file(this->m_rules[this->m_selectedRule].second, File::Mode::Read);
if (!file.isValid()) return;
if (yr_compiler_add_file(compiler, file.getHandle(), nullptr, nullptr) != 0) {
this->m_errorMessage.resize(0xFFFF);
yr_compiler_get_error_message(compiler, this->m_errorMessage.data(), this->m_errorMessage.size());
this->m_matching = false;
return;
}
YR_RULES *rules;
yr_compiler_get_rules(compiler, &rules);
auto &provider = SharedData::currentProvider;
ON_SCOPE_EXIT { yr_rules_destroy(rules); };
std::vector<YaraMatch> newMatches;
@@ -167,7 +198,7 @@ namespace hex {
context.currBlock.fetch_data = [](auto *block) -> const u8* {
auto &context = *static_cast<ScanContext*>(block->context);
auto &provider = SharedData::currentProvider;
auto provider = ImHexApi::Provider::get();
context.buffer.resize(std::min<u64>(0xF'FFFF, provider->getSize() - context.currBlock.base));
@@ -178,7 +209,7 @@ namespace hex {
return context.buffer.data();
};
iterator.file_size = [](auto *iterator) -> u64 {
return SharedData::currentProvider->getSize();
return ImHexApi::Provider::get()->getSize();
};
iterator.context = &context;
@@ -199,7 +230,7 @@ namespace hex {
iterator->last_error = ERROR_SUCCESS;
context.currBlock.base = address;
context.currBlock.size = std::min<u64>(0xF'FFFF, SharedData::currentProvider->getSize() - address);
context.currBlock.size = std::min<u64>(0xF'FFFF, ImHexApi::Provider::get()->getSize() - address);
context.currBlock.context = &context;
if (context.currBlock.size == 0) return nullptr;
@@ -232,10 +263,6 @@ namespace hex {
}, &newMatches, 0);
std::copy(newMatches.begin(), newMatches.end(), std::back_inserter(this->m_matches));
yr_compiler_destroy(compiler);
this->m_matching = false;
}).detach();
}

View File

@@ -2,6 +2,10 @@
#if defined(OS_LINUX)
#include <hex/helpers/utils.hpp>
#include <nlohmann/json.hpp>
#include <sys/wait.h>
namespace hex {
void Window::initNative() {
@@ -9,7 +13,28 @@
}
void Window::setupNativeWindow() {
bool themeFollowSystem = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color") == 0;
EventManager::subscribe<EventOSThemeChanged>(this, [themeFollowSystem]{
if (!themeFollowSystem) return;
std::array<char, 128> buffer = { 0 };
std::string result;
// TODO: In the future maybe support more DEs instead of just GNOME
FILE* pipe = popen("gsettings get org.gnome.desktop.interface gtk-theme 2>&1", "r");
if (pipe == nullptr) return;
while (fgets(buffer.data(), buffer.size(), pipe) != nullptr)
result += buffer.data();
auto exitCode = WEXITSTATUS(pclose(pipe));
if (exitCode != 0) return;
EventManager::post<RequestChangeTheme>(hex::containsIgnoreCase(result, "dark") ? 1 : 2);
});
if (themeFollowSystem)
EventManager::post<EventOSThemeChanged>();
}
void Window::updateNativeWindow() {

View File

@@ -2,6 +2,8 @@
#if defined(OS_MACOS)
#include <nlohmann/json.hpp>
namespace hex {
void Window::initNative() {
@@ -9,7 +11,16 @@
}
void Window::setupNativeWindow() {
bool themeFollowSystem = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color") == 0;
EventManager::subscribe<EventOSThemeChanged>(this, [themeFollowSystem]{
if (!themeFollowSystem) return;
// TODO: Implement this when MacOS build is working again
EventManager::post<RequestChangeTheme>(1);
});
if (themeFollowSystem)
EventManager::post<EventOSThemeChanged>();
}
void Window::updateNativeWindow() {

View File

@@ -4,11 +4,14 @@
#if defined(OS_WINDOWS)
#include <hex/helpers/utils.hpp>
#include <hex/helpers/logger.hpp>
#include <imgui.h>
#include <imgui_internal.h>
#include <codicons_font.h>
#include <nlohmann/json.hpp>
#include <GLFW/glfw3.h>
#define GLFW_EXPOSE_NATIVE_WIN32
#include <GLFW/glfw3native.h>
@@ -96,8 +99,8 @@
POINT cursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
const POINT border{
static_cast<LONG>((::GetSystemMetrics(SM_CXFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * SharedData::globalScale / 2.0F),
static_cast<LONG>((::GetSystemMetrics(SM_CYFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * SharedData::globalScale / 2.0F)
static_cast<LONG>((::GetSystemMetrics(SM_CXFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * SharedData::globalScale / 1.5F),
static_cast<LONG>((::GetSystemMetrics(SM_CYFRAME) + ::GetSystemMetrics(SM_CXPADDEDBORDER)) * SharedData::globalScale / 1.5F)
};
RECT window;
@@ -117,6 +120,9 @@
RegionTop * (cursor.y < (window.top + border.y)) |
RegionBottom * (cursor.y >= (window.bottom - border.y));
if (result != 0 && (ImGui::IsItemHovered() || ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId)))
break;
switch (result) {
case RegionLeft:
return HTLEFT;
@@ -136,10 +142,19 @@
return HTBOTTOMRIGHT;
case RegionClient:
default:
if ((cursor.y < (window.top + titleBarHeight * 2)) && !ImGui::IsAnyItemHovered())
if ((cursor.y < (window.top + titleBarHeight * 2)) && !(ImGui::IsAnyItemHovered() || ImGui::IsPopupOpen(nullptr, ImGuiPopupFlags_AnyPopupId)))
return HTCAPTION;
else break;
}
break;
}
case WM_SETTINGCHANGE:
{
if (LPCTSTR(lParam) == std::string_view("ImmersiveColorSet")) {
EventManager::post<EventOSThemeChanged>();
}
break;
}
default: break;
}
@@ -172,6 +187,25 @@
::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_ASYNCWINDOWPOS | SWP_NOSIZE | SWP_NOMOVE);
::SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_POPUP | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CAPTION | WS_SYSMENU);
bool themeFollowSystem = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color") == 0;
EventManager::subscribe<EventOSThemeChanged>(this, [themeFollowSystem]{
if (!themeFollowSystem) return;
HKEY hkey;
if (RegOpenKey(HKEY_CURRENT_USER, "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", &hkey) == ERROR_SUCCESS) {
DWORD value = 0;
DWORD size = sizeof(DWORD);
auto error = RegQueryValueEx(hkey, "AppsUseLightTheme", nullptr, nullptr, reinterpret_cast<LPBYTE>(&value), &size);
if (error == ERROR_SUCCESS) {
EventManager::post<RequestChangeTheme>(value == 0 ? 1 : 2);
}
}
});
if (themeFollowSystem)
EventManager::post<EventOSThemeChanged>();
}
void Window::updateNativeWindow() {
@@ -191,8 +225,15 @@
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - buttonSize.x * 6);
#if defined(DEBUG)
if (ImGui::TitleBarButton(ICON_VS_DEBUG, buttonSize))
hex::openWebpage("https://imhex.werwolv.net/debug");
if (ImGui::TitleBarButton(ICON_VS_DEBUG, buttonSize)) {
if (ImGui::GetIO().KeyCtrl && ImGui::GetIO().KeyShift) {
// Explicitly trigger a segfault by writing to an invalid memory location
// Used for debugging crashes
*reinterpret_cast<u8*>(0x10) = 0x10;
} else {
hex::openWebpage("https://imhex.werwolv.net/debug");
}
}
ImGui::InfoTooltip("hex.menu.debug_build"_lang);
#endif
if (ImGui::TitleBarButton(ICON_VS_SMILEY, buttonSize))

View File

@@ -6,6 +6,7 @@
#include <hex/helpers/utils.hpp>
#include <hex/helpers/paths.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/file.hpp>
#include <chrono>
#include <csignal>
@@ -65,8 +66,6 @@ namespace hex {
}
Window::Window() {
SharedData::currentProvider = nullptr;
{
for (const auto &[argument, value] : init::getInitArguments()) {
if (argument == "update-available") {
@@ -85,47 +84,12 @@ namespace hex {
this->initGLFW();
this->initImGui();
this->setupNativeWindow();
EventManager::subscribe<EventSettingsChanged>(this, [this]() {
{
auto theme = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color");
if (this->m_bannerTexture.valid())
ImGui::UnloadImage(this->m_bannerTexture);
if (theme.is_number()) {
switch (static_cast<int>(theme)) {
default:
case 0: /* Dark theme */
ImGui::StyleColorsDark();
ImGui::StyleCustomColorsDark();
ImPlot::StyleColorsDark();
this->m_bannerTexture = ImGui::LoadImageFromMemory(banner_dark, banner_dark_size);
break;
case 1: /* Light theme */
ImGui::StyleColorsLight();
ImGui::StyleCustomColorsLight();
ImPlot::StyleColorsLight();
this->m_bannerTexture = ImGui::LoadImageFromMemory(banner_light, banner_light_size);
break;
case 2: /* Classic theme */
ImGui::StyleColorsClassic();
ImGui::StyleCustomColorsClassic();
ImPlot::StyleColorsClassic();
this->m_bannerTexture = ImGui::LoadImageFromMemory(banner_dark, banner_dark_size);
break;
}
ImGui::GetStyle().Colors[ImGuiCol_DockingEmptyBg] = ImGui::GetStyle().Colors[ImGuiCol_WindowBg];
ImGui::GetStyle().Colors[ImGuiCol_TitleBg] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg];
ImGui::GetStyle().Colors[ImGuiCol_TitleBgActive] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg];
ImGui::GetStyle().Colors[ImGuiCol_TitleBgCollapsed] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg];
if (!this->m_bannerTexture.valid()) {
log::fatal("Failed to load banner texture!");
exit(EXIT_FAILURE);
}
}
EventManager::post<RequestChangeTheme>(theme.get<int>());
}
{
@@ -154,6 +118,43 @@ namespace hex {
}
});
EventManager::subscribe<RequestChangeTheme>(this, [this](u32 theme) {
if (this->m_bannerTexture.valid())
ImGui::UnloadImage(this->m_bannerTexture);
switch (theme) {
default:
case 1: /* Dark theme */
ImGui::StyleColorsDark();
ImGui::StyleCustomColorsDark();
ImPlot::StyleColorsDark();
this->m_bannerTexture = ImGui::LoadImageFromMemory(banner_dark, banner_dark_size);
break;
case 2: /* Light theme */
ImGui::StyleColorsLight();
ImGui::StyleCustomColorsLight();
ImPlot::StyleColorsLight();
this->m_bannerTexture = ImGui::LoadImageFromMemory(banner_light, banner_light_size);
break;
case 3: /* Classic theme */
ImGui::StyleColorsClassic();
ImGui::StyleCustomColorsClassic();
ImPlot::StyleColorsClassic();
this->m_bannerTexture = ImGui::LoadImageFromMemory(banner_dark, banner_dark_size);
break;
}
ImGui::GetStyle().Colors[ImGuiCol_DockingEmptyBg] = ImGui::GetStyle().Colors[ImGuiCol_WindowBg];
ImGui::GetStyle().Colors[ImGuiCol_TitleBg] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg];
ImGui::GetStyle().Colors[ImGuiCol_TitleBgActive] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg];
ImGui::GetStyle().Colors[ImGuiCol_TitleBgCollapsed] = ImGui::GetStyle().Colors[ImGuiCol_MenuBarBg];
if (!this->m_bannerTexture.valid()) {
log::fatal("Failed to load banner texture!");
std::abort();
}
});
EventManager::subscribe<EventFileLoaded>(this, [](const std::string &path){
SharedData::recentFilePaths.push_front(path);
@@ -198,7 +199,7 @@ namespace hex {
EventManager::subscribe<RequestChangeWindowTitle>(this, [this](std::string windowTitle) {
std::string title = "ImHex";
if (SharedData::currentProvider != nullptr) {
if (ImHexApi::Provider::isValid()) {
if (!windowTitle.empty())
title += " - " + windowTitle;
@@ -222,6 +223,10 @@ namespace hex {
}
});
EventManager::subscribe<RequestOpenPopup>(this, [this](auto name){
this->m_popupsToOpen.push_back(name);
});
for (const auto &path : hex::getPath(ImHexPath::Config)) {
if (auto filePath = std::filesystem::path(path) / CrashBackupFileName; std::filesystem::exists(filePath)) {
this->m_safetyBackupPath = filePath;
@@ -248,6 +253,7 @@ namespace hex {
this->m_logoTexture = ImGui::LoadImageFromMemory(imhex_logo, imhex_logo_size);
ContentRegistry::Settings::store();
EventManager::post<EventSettingsChanged>();
}
@@ -261,6 +267,8 @@ namespace hex {
EventManager::unsubscribe<RequestCloseImHex>(this);
EventManager::unsubscribe<RequestChangeWindowTitle>(this);
EventManager::unsubscribe<EventAbnormalTermination>(this);
EventManager::unsubscribe<RequestChangeTheme>(this);
EventManager::unsubscribe<RequestOpenPopup>(this);
ImGui::UnloadImage(this->m_bannerTexture);
ImGui::UnloadImage(this->m_logoTexture);
@@ -335,7 +343,7 @@ namespace hex {
if (ImGui::BeginMenu("hex.menu.view"_lang)) {
for (auto &view : ContentRegistry::Views::getEntries()) {
if (view->hasViewMenuItemEntry())
ImGui::MenuItem((LangEntry(view->getUnlocalizedName()) + " " + "hex.menu.view"_lang).c_str(), "", &view->getWindowOpenState());
ImGui::MenuItem(LangEntry(view->getUnlocalizedName()), "", &view->getWindowOpenState());
}
ImGui::EndMenu();
}
@@ -369,7 +377,7 @@ namespace hex {
ImGui::EndMenuBar();
}
if (SharedData::currentProvider == nullptr) {
if (!ImHexApi::Provider::isValid()) {
static char title[256];
ImFormatString(title, IM_ARRAYSIZE(title), "%s/DockSpace_%08X", ImGui::GetCurrentWindow()->Name, ImGui::GetID("MainDock"));
if (ImGui::Begin(title)) {
@@ -432,7 +440,6 @@ namespace hex {
ImGui::SetCursorPosX(width / 9);
if (ImGui::Button("hex.safety_backup.restore"_lang, ImVec2(width / 3, 0))) {
ProjectFile::load(this->m_safetyBackupPath.string());
EventManager::post<EventProjectFileLoad>();
ProjectFile::markDirty();
ProjectFile::clearProjectFilePath();
@@ -450,6 +457,15 @@ namespace hex {
ImGui::EndPopup();
}
this->m_popupsToOpen.remove_if([](const auto &name) {
if (ImGui::IsPopupOpen(name.c_str()))
return true;
else
ImGui::OpenPopup(name.c_str());
return false;
});
}
void Window::frame() {
@@ -690,8 +706,6 @@ namespace hex {
this->m_windowTitle = "ImHex";
this->m_window = glfwCreateWindow(1280 * SharedData::globalScale, 720 * SharedData::globalScale, this->m_windowTitle.c_str(), nullptr, nullptr);
this->setupNativeWindow();
glfwSetWindowUserPointer(this->m_window, this);
if (this->m_window == nullptr)
@@ -761,7 +775,36 @@ namespace hex {
if (count != 1)
return;
EventManager::post<RequestOpenFile>(paths[0]);
for (u32 i = 0; i < count; i++) {
auto path = std::filesystem::path(paths[i]);
if (path.extension() == ".hexpat" || path.extension() == ".pat") {
File file(path.string(), File::Mode::Read);
if (file.isValid())
EventManager::post<RequestSetPatternLanguageCode>(file.readString());
} else if (path.extension() == ".hexproj") {
ProjectFile::load(path.string());
} else if (path.extension() == ".yar") {
for (auto &destPath : hex::getPath(ImHexPath::Yara)) {
std::error_code error;
if (std::filesystem::copy_file(path, destPath / path.filename(), std::filesystem::copy_options::overwrite_existing, error)) {
View::showMessagePopup("hex.message.yara_rule_added"_lang);
break;
}
}
} else if (path.extension() == ".mgc") {
for (auto &destPath : hex::getPath(ImHexPath::Magic)) {
std::error_code error;
if (std::filesystem::copy_file(path, destPath / path.filename(), std::filesystem::copy_options::overwrite_existing, error)) {
View::showMessagePopup("hex.message.magic_db_added"_lang);
break;
}
}
} else {
EventManager::post<RequestOpenFile>(path.string());
}
}
});
glfwSetWindowCloseCallback(this->m_window, [](GLFWwindow *window) {

Some files were not shown because too many files have changed in this diff Show More