mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-31 05:15:55 -05:00
Compare commits
98 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
066161f397 | ||
|
|
d3e3de3fa2 | ||
|
|
194bc3e5be | ||
|
|
a9e3db0464 | ||
|
|
334ba3ede2 | ||
|
|
7978964995 | ||
|
|
d5ca4c4f28 | ||
|
|
08c2e1cd4e | ||
|
|
2f6e91cd9e | ||
|
|
888976873a | ||
|
|
5db608c3fc | ||
|
|
e46807c600 | ||
|
|
7799bbb57a | ||
|
|
7da8a5b1d8 | ||
|
|
ae9f4fa876 | ||
|
|
e3dd5900e2 | ||
|
|
aab865fe25 | ||
|
|
62656f4c51 | ||
|
|
b323d711cf | ||
|
|
9b4cf917d9 | ||
|
|
ba97573f93 | ||
|
|
9dc62e1469 | ||
|
|
55c0cb66e3 | ||
|
|
a8526585cb | ||
|
|
3850349eae | ||
|
|
f5bd0b7971 | ||
|
|
42d9753bdb | ||
|
|
17d5a5309a | ||
|
|
71be77c54b | ||
|
|
93c1fbd65e | ||
|
|
c8114347dc | ||
|
|
3c2c2b003f | ||
|
|
2edd6cd6c4 | ||
|
|
6713f65040 | ||
|
|
82ee4ad4ca | ||
|
|
d9134f7fe1 | ||
|
|
ee26839292 | ||
|
|
cd33376c07 | ||
|
|
e57481b87c | ||
|
|
5601aab043 | ||
|
|
1b7a1852bc | ||
|
|
509795e6c1 | ||
|
|
755642862f | ||
|
|
d1c05174b6 | ||
|
|
85b8698e35 | ||
|
|
471ba80b4d | ||
|
|
9dd555f111 | ||
|
|
7df1ff07a7 | ||
|
|
15a60930d2 | ||
|
|
eb779c5986 | ||
|
|
c051f5d3e7 | ||
|
|
ed9e463550 | ||
|
|
a7ebf1f60e | ||
|
|
6ab0ec547c | ||
|
|
26a0352851 | ||
|
|
8631cb0c2a | ||
|
|
a302448b76 | ||
|
|
fef072f721 | ||
|
|
46f196cb3f | ||
|
|
c5cd6422c6 | ||
|
|
5edc0b876c | ||
|
|
131699d309 | ||
|
|
59c01feaea | ||
|
|
772b50fdfb | ||
|
|
bf493c5763 | ||
|
|
e1f410ceff | ||
|
|
d3fb00d441 | ||
|
|
222e9f6645 | ||
|
|
22a904baf4 | ||
|
|
01670e5e85 | ||
|
|
7fbb540674 | ||
|
|
bed5361879 | ||
|
|
82cc528c49 | ||
|
|
1df64031c8 | ||
|
|
ea2d181741 | ||
|
|
3cd177bff2 | ||
|
|
132fc181cd | ||
|
|
987840e480 | ||
|
|
86096708da | ||
|
|
635f0606e0 | ||
|
|
3d15a108af | ||
|
|
254b204d6c | ||
|
|
ac645c63d3 | ||
|
|
0b9f1cc3b9 | ||
|
|
b96fee95f3 | ||
|
|
8cb7fb71d1 | ||
|
|
aac6385dc6 | ||
|
|
f7ee165f43 | ||
|
|
7132b75ffb | ||
|
|
bdd4854b0d | ||
|
|
8396e40fa0 | ||
|
|
71b06f4b20 | ||
|
|
a5274daeaa | ||
|
|
36f51c427b | ||
|
|
b3d102419b | ||
|
|
5c304c002b | ||
|
|
f96e529230 | ||
|
|
717f78ce7f |
62
.github/workflows/analysis.yml
vendored
Normal file
62
.github/workflows/analysis.yml
vendored
Normal 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
|
||||
87
.github/workflows/build.yml
vendored
87
.github/workflows/build.yml
vendored
@@ -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
|
||||
|
||||
71
.github/workflows/codeql-analysis.yml
vendored
71
.github/workflows/codeql-analysis.yml
vendored
@@ -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
|
||||
@@ -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()
|
||||
|
||||
@@ -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
1
dist/Brewfile
vendored
@@ -3,6 +3,7 @@ brew "mbedtls"
|
||||
brew "capstone"
|
||||
brew "nlohmann-json"
|
||||
brew "cmake"
|
||||
brew "ccache"
|
||||
brew "python3"
|
||||
brew "freetype2"
|
||||
brew "libmagic"
|
||||
|
||||
3
dist/get_deps_debian.sh
vendored
3
dist/get_deps_debian.sh
vendored
@@ -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 \
|
||||
|
||||
1
dist/get_deps_msys2.sh
vendored
1
dist/get_deps_msys2.sh
vendored
@@ -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 \
|
||||
|
||||
@@ -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];
|
||||
|
||||
50
external/ImGui/include/imgui_memory_editor.h
vendored
50
external/ImGui/include/imgui_memory_editor.h
vendored
@@ -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)
|
||||
|
||||
@@ -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
10
external/microtar/CMakeLists.txt
vendored
Normal 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
19
external/microtar/LICENSE
vendored
Normal 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
99
external/microtar/README.md
vendored
Normal 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
93
external/microtar/include/microtar.h
vendored
Normal 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
376
external/microtar/source/microtar.c
vendored
Normal 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);
|
||||
}
|
||||
4
external/yara/CMakeLists.txt
vendored
4
external/yara/CMakeLists.txt
vendored
@@ -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}
|
||||
)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
34
include/views/view_diff.hpp
Normal file
34
include/views/view_diff.hpp
Normal 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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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
|
||||
@@ -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 #
|
||||
|
||||
@@ -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 = ' ';
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 ¶m = 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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, ®exPattern);
|
||||
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, ®exInput);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@@ -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", "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", "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" },
|
||||
|
||||
@@ -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", "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", "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" },
|
||||
|
||||
@@ -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" },
|
||||
|
||||
668
plugins/builtin/source/lang/zh_CN.cpp
Normal file
668
plugins/builtin/source/lang/zh_CN.cpp
Normal 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", "最后更改时间" },
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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&);
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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]));
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 + "::";
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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 #
|
||||
|
||||
@@ -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([] {
|
||||
@@ -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" },
|
||||
|
||||
31
plugins/windows/source/lang/zh_CN.cpp
Normal file
31
plugins/windows/source/lang/zh_CN.cpp
Normal 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" }
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -165,7 +165,7 @@ namespace hex {
|
||||
|
||||
code += "};\n";
|
||||
|
||||
EventManager::post<RequestAppendPatternLanguageCode>(code);
|
||||
EventManager::post<RequestSetPatternLanguageCode>(code);
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
@@ -85,6 +85,8 @@ namespace hex {
|
||||
ProjectFile::s_hasUnsavedChanged = false;
|
||||
ProjectFile::s_currProjectFilePath = filePath;
|
||||
|
||||
EventManager::post<EventProjectFileLoad>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 },
|
||||
};
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
234
source/views/view_diff.cpp
Normal 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() {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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 ®ion) {
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user