mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-28 15:57:03 -05:00
Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9d556ecc0f | ||
|
|
ea2c2df614 | ||
|
|
202a02af10 | ||
|
|
6ee71e3a9e | ||
|
|
1e7ed14810 | ||
|
|
17383083fb | ||
|
|
f5fe49923b | ||
|
|
457d338a97 | ||
|
|
4928c044af | ||
|
|
299c69686e | ||
|
|
b7132af214 | ||
|
|
74a5c974e6 | ||
|
|
942a4e9616 | ||
|
|
76f732dc53 | ||
|
|
0462cc3d0c | ||
|
|
965207d688 | ||
|
|
0f0a836fa0 | ||
|
|
29fb1de882 | ||
|
|
a807dc81a0 | ||
|
|
a4d3173da9 | ||
|
|
4b6a76bf02 | ||
|
|
35a520f132 | ||
|
|
1c53d2c123 | ||
|
|
591d98b55b | ||
|
|
f39ec58435 | ||
|
|
e72a30ca59 | ||
|
|
368c943040 | ||
|
|
a16e387dff | ||
|
|
95cf828975 | ||
|
|
c09d85f46d | ||
|
|
c2803fe1e2 | ||
|
|
98dfc2e286 | ||
|
|
ea848dbfc0 | ||
|
|
f7cfee55d5 | ||
|
|
26a7b3325d | ||
|
|
47fd5bdc00 | ||
|
|
5dfa9cf501 | ||
|
|
854c99bafa | ||
|
|
937ccbc5bd | ||
|
|
bc7c494316 | ||
|
|
17a2be41da | ||
|
|
ab5966fa9d | ||
|
|
89fe063b02 | ||
|
|
7061a1ebfa | ||
|
|
ec9a947259 | ||
|
|
11441d632b | ||
|
|
a17b647e79 | ||
|
|
2d87d29fa0 | ||
|
|
844845223f | ||
|
|
f2159e26d2 | ||
|
|
d677762dff | ||
|
|
3801e0d60b | ||
|
|
f6a498854c | ||
|
|
29ded2483c | ||
|
|
050e17298a | ||
|
|
af882b172e | ||
|
|
caad8c25ad | ||
|
|
74ef9ece30 | ||
|
|
97bfb4004b | ||
|
|
3da1b3f05d | ||
|
|
f21b22ae15 | ||
|
|
327e904dbc | ||
|
|
57c449936f | ||
|
|
efe6137067 | ||
|
|
96e9400761 | ||
|
|
6a517feda3 | ||
|
|
3b7a928313 | ||
|
|
2739320f10 | ||
|
|
7866e3fc2a | ||
|
|
2abf89cd16 | ||
|
|
8b2dcf976f | ||
|
|
559b86efe1 | ||
|
|
949a26ca0e | ||
|
|
2880ca00da | ||
|
|
39da62532b | ||
|
|
483ba95d80 | ||
|
|
2300b0c692 | ||
|
|
cc59b36c54 | ||
|
|
61d9918dae | ||
|
|
2c361f9b0a | ||
|
|
775b3e8c52 |
55
.github/workflows/build.yml
vendored
55
.github/workflows/build.yml
vendored
@@ -12,7 +12,7 @@ jobs:
|
||||
# Windows build
|
||||
win:
|
||||
runs-on: windows-2022
|
||||
name: 🟦 Windows MINGW64
|
||||
name: 🪟 Windows MINGW64
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
@@ -180,6 +180,11 @@ jobs:
|
||||
|
||||
sudo apt update
|
||||
sudo bash dist/get_deps_debian.sh
|
||||
|
||||
sudo apt install -y python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace fuse
|
||||
sudo wget https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /usr/local/bin/appimagetool
|
||||
sudo chmod +x /usr/local/bin/appimagetool
|
||||
sudo pip3 install appimage-builder
|
||||
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
|
||||
sh rustup-init.sh -y --default-toolchain none
|
||||
@@ -192,16 +197,16 @@ jobs:
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-10 CXX=g++-10 cmake \
|
||||
CC=gcc-11 CXX=g++-11 cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install/usr" \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DRUST_PATH="$HOME/.cargo/bin/" \
|
||||
..
|
||||
make -j 4 install
|
||||
make -j 4 install DESTDIR=AppDir
|
||||
|
||||
#- name: 📦 Bundle Flatpak
|
||||
# run: |
|
||||
@@ -212,33 +217,35 @@ jobs:
|
||||
# flatpak-builder --jobs=4 --repo=imhex _flatpak dist/net.werwolv.ImHex.yaml --ccache --keep-build-dirs
|
||||
# flatpak build-bundle imhex imhex.flatpak net.werwolv.ImHex stable
|
||||
|
||||
- name: 📦 Bundle DEB
|
||||
run: |
|
||||
cp -r build/DEBIAN build/install
|
||||
dpkg-deb --build build/install
|
||||
mv build/install.deb imhex.deb
|
||||
rm -rf build/install/DEBIAN
|
||||
|
||||
- name: 📦 Bundle AppImage
|
||||
run: |
|
||||
dist/AppImage/package.sh build
|
||||
mv build/ImHex-x86_64.AppImage imhex.AppImage
|
||||
|
||||
- name: ⬆️ Upload ELF
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Linux ELF
|
||||
path: |
|
||||
build/install/*
|
||||
build/AppDir/*
|
||||
|
||||
- name: ⬆️ Upload Flatpak
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Linux Flatpak
|
||||
path: |
|
||||
imhex.flatpak
|
||||
- name: 📦 Bundle DEB
|
||||
run: |
|
||||
cp -r build/DEBIAN build/AppDir
|
||||
dpkg-deb --build build/AppDir
|
||||
mv build/AppDir.deb imhex.deb
|
||||
rm -rf build/AppDir/DEBIAN
|
||||
|
||||
- name: ⬆️ Upload .deb
|
||||
- name: 📦 Bundle AppImage
|
||||
run: |
|
||||
cd build
|
||||
appimage-builder --recipe ../dist/AppImageBuilder.yml
|
||||
mv ImHex-AppImage-x86_64.AppImage ../imhex.AppImage
|
||||
cd ..
|
||||
|
||||
#- name: ⬆️ Upload Flatpak
|
||||
# uses: actions/upload-artifact@v2
|
||||
# with:
|
||||
# name: Linux Flatpak
|
||||
# path: |
|
||||
# imhex.flatpak
|
||||
|
||||
- name: ⬆️ Upload DEB
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Linux DEB
|
||||
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -26,3 +26,6 @@
|
||||
path = lib/external/libromfs
|
||||
url = https://github.com/WerWolv/libromfs
|
||||
ignore = dirty
|
||||
[submodule "lib/external/pattern_language"]
|
||||
path = lib/external/pattern_language
|
||||
url = https://github.com/WerWolv/PatternLanguage
|
||||
|
||||
5
.idea/vcs.xml
generated
5
.idea/vcs.xml
generated
@@ -2,11 +2,16 @@
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/imhex_patterns-src" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/imhex_patterns-src/yara/official_rules" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/imhex_patterns-src/yara/official_rules/utils/yara-forensics" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/capstone" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/curl" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/fmt" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/libromfs" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/nativefiledialog" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language/external/fmt" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/xdgpp" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/yara/yara" vcs="Git" />
|
||||
</component>
|
||||
|
||||
@@ -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.16.1")
|
||||
set(IMHEX_VERSION "1.17.0")
|
||||
project(imhex VERSION ${IMHEX_VERSION})
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
|
||||
17
README.md
17
README.md
@@ -33,7 +33,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
- Hex string
|
||||
- C, C++, C#, Rust, Python, Java & JavaScript array
|
||||
- ASCII-Art hex view
|
||||
- HTML self contained div
|
||||
- HTML self-contained div
|
||||
- String and hex search
|
||||
- Colorful highlighting
|
||||
- Goto from start, end and current cursor position
|
||||
@@ -84,7 +84,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
- Built-in Content Store
|
||||
- Download all files found in the database directly from within ImHex
|
||||
- Yara Rules support
|
||||
- Quickly scan a file for vulnearabilities with official yara rules
|
||||
- Quickly scan a file for vulnerabilities with official yara rules
|
||||
- Helpful tools
|
||||
- Itanium and MSVC demangler
|
||||
- ASCII table
|
||||
@@ -98,7 +98,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
- File utilities
|
||||
- File splitter
|
||||
- File combiner
|
||||
- File shredderer
|
||||
- File shredder
|
||||
- Built-in cheat sheet for pattern language and Math evaluator
|
||||
- Doesn't burn out your retinas when used in late-night sessions
|
||||
|
||||
@@ -106,15 +106,16 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
|
||||
The custom C-like Pattern Language developed and used by ImHex is easy to read, understand and learn. A guide with all features of the language can be found [on the docs page](http://imhex.werwolv.net/docs).
|
||||
|
||||
## Database
|
||||
|
||||
For format patterns, includable libraries magic and constant files, check out the [ImHex-Patterns](https://github.com/WerWolv/ImHex-Patterns) repository. Feel free to PR your own files there as well!
|
||||
|
||||
## Plugin development
|
||||
|
||||
To develop plugins for ImHex, use one of the following two templates projects to get startet. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
|
||||
To develop plugins for ImHex, use one of the following two templates projects to get started. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
|
||||
- [C++ Plugin Template](https://github.com/WerWolv/ImHex-Cpp-Plugin-Template)
|
||||
- [Rust Plugin Template](https://github.com/WerWolv/ImHex-Rust-Plugin-Template)
|
||||
|
||||
## Additional Files
|
||||
|
||||
For format patterns, includable libraries and magic files, check out the [ImHex-Patterns](https://github.com/WerWolv/ImHex-Patterns) repository. Feel free to PR your own files there as well!
|
||||
|
||||
## Nightly builds
|
||||
|
||||
@@ -230,7 +231,7 @@ with the environment variables `XDG_CONFIG_HOME`, `XDG_CONFIG_DIRS`,
|
||||
- [Mary](https://github.com/Thog) for her immense help porting ImHex to MacOS and help during development
|
||||
- [Roblabla](https://github.com/Roblabla) for adding MSI Installer support to ImHex
|
||||
- [jam1garner](https://github.com/jam1garner) and [raytwo](https://github.com/raytwo) for their help with adding Rust support to plugins
|
||||
- All other people that have been reporting issues on Discord or GitHub that I had great conversations with :)
|
||||
- Everybody else who has reported issues on Discord or GitHub that I had great conversations with :)
|
||||
|
||||
### Libraries
|
||||
|
||||
|
||||
@@ -292,7 +292,7 @@ function(downloadImHexPatternsFiles)
|
||||
|
||||
FetchContent_Populate(imhex_patterns)
|
||||
|
||||
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns yara magic)
|
||||
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic)
|
||||
foreach (FOLDER ${PATTERNS_FOLDERS_TO_INSTALL})
|
||||
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION "./")
|
||||
endforeach()
|
||||
|
||||
40
dist/AppImage/Dockerfile
vendored
40
dist/AppImage/Dockerfile
vendored
@@ -1,40 +0,0 @@
|
||||
FROM debian:bullseye-slim
|
||||
LABEL maintainer Example <example@example.com>
|
||||
|
||||
ARG TAG=master
|
||||
ARG REPO=https://github.com/WerWolv/ImHex.git
|
||||
|
||||
USER root
|
||||
|
||||
# Bring packages up to date
|
||||
RUN apt-get update \
|
||||
&& apt-get upgrade -y \
|
||||
&& apt-get autoremove -y \
|
||||
&& apt-get install -y \
|
||||
git \
|
||||
cmake \
|
||||
curl \
|
||||
squashfs-tools
|
||||
|
||||
# Fetch source and dependencies
|
||||
RUN mkdir -p /source \
|
||||
&& cd /source \
|
||||
&& git clone $REPO \
|
||||
&& cd ImHex \
|
||||
&& git checkout $TAG \
|
||||
&& git submodule update --init --recursive \
|
||||
&& cd /source/ImHex/dist \
|
||||
&& ./get_deps_debian.sh
|
||||
|
||||
ARG CXX=g++-10
|
||||
|
||||
# Build ImHex
|
||||
RUN mkdir -p /source/ImHex/build \
|
||||
&& cd /source/ImHex/build \
|
||||
&& cmake --install-prefix /usr -DCMAKE_BUILD_TYPE=Release .. \
|
||||
&& make -j
|
||||
|
||||
# Prepare for AppImage
|
||||
RUN cd /source/ImHex/dist/AppImage \
|
||||
&& ./package.sh /source/ImHex/build \
|
||||
&& mv /source/ImHex/build/ImHex-x86_64.AppImage /
|
||||
6
dist/AppImage/ImHex.desktop
vendored
6
dist/AppImage/ImHex.desktop
vendored
@@ -1,6 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Name=ImHex
|
||||
Exec=imhex
|
||||
Icon=imhex
|
||||
Type=Application
|
||||
Categories=Utility;
|
||||
22
dist/AppImage/README.md
vendored
22
dist/AppImage/README.md
vendored
@@ -1,22 +0,0 @@
|
||||
# Building an AppImage
|
||||
There are two ways of building an AppImage for ImHex, using the provided
|
||||
tools here.
|
||||
|
||||
If you want to create an AppImage and do not have a build to work from
|
||||
already, you can use docker to build ImHex and package an AppImage.
|
||||
|
||||
Alternatively you can create an AppImage using an existing build.
|
||||
|
||||
## Using docker
|
||||
First run `build.sh` to create a docker image. Then run `extract.sh` to get the
|
||||
AppImage out. This needs to be in two steps, as a docker build cannot copy
|
||||
files out. Nor can docker build use volume mounts.
|
||||
|
||||
The environment variable TAG can be set to build for a specific git tag.
|
||||
Without the master branch is build.
|
||||
|
||||
## Using an existing build
|
||||
Run `package.sh` with the build dir as an argument. E.g.:
|
||||
```
|
||||
./package.sh ../../build
|
||||
```
|
||||
16
dist/AppImage/build.sh
vendored
16
dist/AppImage/build.sh
vendored
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set the TAG environment variable to build a specific tag
|
||||
# Set the REPO environment variable to point at a different git repository
|
||||
|
||||
# Make sure we're in the same directory as this script
|
||||
pushd $(dirname "$(realpath "$0")")
|
||||
|
||||
BUILDARG=""
|
||||
SUFFIX=""
|
||||
[ -n "${TAG}" ] && BUILDARG="${BUILDARG} --build-arg=TAG=${TAG}" && SUFFIX=":${TAG}"
|
||||
[ -n "${REPO}" ] && BUILDARG="${BUILDARG} --build-arg=REPO=${REPO}"
|
||||
|
||||
docker build ${BUILDARG} -t imhex-appimage-build${SUFFIX} .
|
||||
|
||||
popd
|
||||
26
dist/AppImage/extract.sh
vendored
26
dist/AppImage/extract.sh
vendored
@@ -1,26 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set the TAG environment variable to move to a versioned name while extracting
|
||||
|
||||
# Make sure we're in the same directory as this script
|
||||
pushd $(dirname "$(realpath "$0")")
|
||||
|
||||
SUFFIX=""
|
||||
[ -n "$TAG" ] && SUFFIX=":$TAG"
|
||||
|
||||
# Remove old containers
|
||||
docker rm imhex 2>&1 > /dev/null
|
||||
|
||||
docker run -d --name imhex imhex-appimage-build${SUFFIX} sleep 30 &
|
||||
sleep 15
|
||||
docker cp imhex:/ImHex-x86_64.AppImage .
|
||||
|
||||
# Move to tagged name if $TAG set
|
||||
if [ -n "$TAG" ]; then
|
||||
mv ImHex-x86_64.AppImage ImHex-${TAG}-x86_64.AppImage
|
||||
echo -e "\nThe created AppImage can be found here:\n $(pwd)/ImHex-${TAG}-x86_64.AppImage\n\n"
|
||||
else
|
||||
echo -e "\nThe created AppImage can be found here:\n $(pwd)/ImHex-x86_64.AppImage\n\n"
|
||||
fi
|
||||
|
||||
popd
|
||||
BIN
dist/AppImage/imhex.png
vendored
BIN
dist/AppImage/imhex.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 3.3 KiB |
58
dist/AppImage/package.sh
vendored
58
dist/AppImage/package.sh
vendored
@@ -1,58 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e # Exit on error
|
||||
set -o pipefail # Bash specific
|
||||
|
||||
usage() {
|
||||
echo "Tool to package an ImHex build into an AppImage"
|
||||
echo
|
||||
echo "Usage:"
|
||||
echo "$0 <build dir>"
|
||||
echo
|
||||
exit
|
||||
}
|
||||
|
||||
MYDIR=$(dirname "$(realpath "$0")")
|
||||
|
||||
# Check is a build dir has been specified and it's a dir
|
||||
[ -z "$1" ] && usage
|
||||
[ -d "$1" ] || usage
|
||||
|
||||
set -u # Throw errors when unset variables are used
|
||||
|
||||
BUILDDIR=$1
|
||||
APPDIR=${BUILDDIR}/ImHex.AppDir
|
||||
APPIMAGE=${BUILDDIR}/ImHex-x86_64.AppImage
|
||||
|
||||
# Prepare for AppImage
|
||||
## Fetch the needed AppImage binaries
|
||||
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/AppRun-x86_64 -o ${MYDIR}/AppRun-x86_64
|
||||
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/runtime-x86_64 -o ${MYDIR}/runtime-x86_64
|
||||
|
||||
## Setup directory structure
|
||||
mkdir -p ${BUILDDIR}/ImHex.AppDir/usr/{bin,lib} ${BUILDDIR}/ImHex.AppDir/usr/share/imhex/plugins
|
||||
|
||||
## Add ImHex files to structure
|
||||
cp ${BUILDDIR}/imhex ${APPDIR}/usr/bin
|
||||
cp ${BUILDDIR}/plugins/builtin/builtin.hexplug ${APPDIR}/usr/share/imhex/plugins
|
||||
cp ${MYDIR}/{AppRun-x86_64,ImHex.desktop,imhex.png} ${APPDIR}/
|
||||
mv ${BUILDDIR}/ImHex.AppDir/AppRun-x86_64 ${APPDIR}/AppRun
|
||||
chmod a+x ${BUILDDIR}/ImHex.AppDir/AppRun
|
||||
|
||||
## Add all dependencies
|
||||
ldd ${BUILDDIR}/imhex | awk '/ => /{print $3}' | awk '!/(libc|libstdc++|libc++|libdl|libpthread|libselinux|ld-linux|libgdk)/' | xargs -I '{}' cp '{}' ${APPDIR}/usr/lib
|
||||
ldd ${BUILDDIR}/plugins/builtin/builtin.hexplug | awk '/ => /{print $3}' | awk '!/(libc|libstdc++|libc++|libdl|libpthread|libselinux|ld-linux|libgdk)/' | xargs -I '{}' cp '{}' ${APPDIR}/usr/lib
|
||||
ldd ${BUILDDIR}/lib/libimhex/libimhex.so | awk '/ => /{print $3}' | awk '!/(libc|libstdc++|libc++|libdl|libpthread|libselinux|ld-linux|libgdk)/' | xargs -I '{}' cp '{}' ${APPDIR}/usr/lib
|
||||
|
||||
# Package it up as described here:
|
||||
# https://github.com/AppImage/AppImageKit#appimagetool-usage
|
||||
# under 'If you want to generate an AppImage manually'
|
||||
# This builds a v2 AppImage according to
|
||||
# https://github.com/AppImage/AppImageSpec/blob/master/draft.md#type-2-image-format
|
||||
mksquashfs ${APPDIR} ${BUILDDIR}/ImHex.squashfs -root-owned -noappend
|
||||
cat ${MYDIR}/runtime-x86_64 > ${APPIMAGE}
|
||||
cat ${BUILDDIR}/ImHex.squashfs >> ${APPIMAGE}
|
||||
chmod a+x ${APPIMAGE}
|
||||
|
||||
if [ ! -f /.dockerenv ]; then
|
||||
echo -e "\nThe created AppImage can be found here:\n ${APPIMAGE}\n\n"
|
||||
fi
|
||||
143
dist/AppImageBuilder.yml
vendored
Normal file
143
dist/AppImageBuilder.yml
vendored
Normal file
@@ -0,0 +1,143 @@
|
||||
# appimage-builder recipe see https://appimage-builder.readthedocs.io for details
|
||||
version: 1
|
||||
script:
|
||||
- rm -rf AppDir | true
|
||||
- CC=gcc-11 CXX=g++11 cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
||||
- make -j3 install DESTDIR=AppDir
|
||||
- mv AppDir/usr/share/imhex/plugins AppDir/usr/bin/plugins
|
||||
- mv AppDir/usr/constants AppDir/usr/bin/constants
|
||||
- mv AppDir/usr/encodings AppDir/usr/bin/encodings
|
||||
- mv AppDir/usr/includes AppDir/usr/bin/includes
|
||||
- mv AppDir/usr/magic AppDir/usr/bin/magic
|
||||
- mv AppDir/usr/patterns AppDir/usr/bin/patterns
|
||||
- mkdir -p AppDir/usr/share/icons/hicolor/512x512
|
||||
- cp AppDir/usr/share/pixmaps/imhex.png AppDir/usr/share/icons/hicolor/512x512/imhex.png
|
||||
|
||||
|
||||
AppDir:
|
||||
path: ./AppDir
|
||||
app_info:
|
||||
id: imhex
|
||||
name: ImHex
|
||||
icon: imhex
|
||||
version: AppImage
|
||||
exec: usr/bin/imhex
|
||||
exec_args: $@
|
||||
apt:
|
||||
arch:
|
||||
- amd64
|
||||
allow_unauthenticated: true
|
||||
sources:
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish main restricted
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish-updates main restricted
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish universe
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish-updates universe
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish multiverse
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish-updates multiverse
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish-backports main restricted
|
||||
universe multiverse
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu impish-security main restricted
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu impish-security universe
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu impish-security multiverse
|
||||
include:
|
||||
- libbz2-1.0:amd64
|
||||
- libcap2:amd64
|
||||
- libdbus-1-3:amd64
|
||||
- libgpg-error0:amd64
|
||||
- liblzma5:amd64
|
||||
- libnss-mdns:amd64
|
||||
- libpcre3:amd64
|
||||
- libselinux1:amd64
|
||||
- libtinfo6:amd64
|
||||
- yaru-theme-icon
|
||||
files:
|
||||
include:
|
||||
- /lib/x86_64-linux-gnu/libGLX.so.0
|
||||
- /lib/x86_64-linux-gnu/libGLdispatch.so.0
|
||||
- /lib/x86_64-linux-gnu/libLLVM-12.so.1
|
||||
- /lib/x86_64-linux-gnu/libOpenGL.so.0
|
||||
- /lib/x86_64-linux-gnu/libX11.so.6
|
||||
- /lib/x86_64-linux-gnu/libXau.so.6
|
||||
- /lib/x86_64-linux-gnu/libXcomposite.so.1
|
||||
- /lib/x86_64-linux-gnu/libXcursor.so.1
|
||||
- /lib/x86_64-linux-gnu/libXdamage.so.1
|
||||
- /lib/x86_64-linux-gnu/libXdmcp.so.6
|
||||
- /lib/x86_64-linux-gnu/libXext.so.6
|
||||
- /lib/x86_64-linux-gnu/libXfixes.so.3
|
||||
- /lib/x86_64-linux-gnu/libXi.so.6
|
||||
- /lib/x86_64-linux-gnu/libXinerama.so.1
|
||||
- /lib/x86_64-linux-gnu/libXrandr.so.2
|
||||
- /lib/x86_64-linux-gnu/libXrender.so.1
|
||||
- /lib/x86_64-linux-gnu/libXxf86vm.so.1
|
||||
- /lib/x86_64-linux-gnu/libatk-1.0.so.0
|
||||
- /lib/x86_64-linux-gnu/libatk-bridge-2.0.so.0
|
||||
- /lib/x86_64-linux-gnu/libatspi.so.0
|
||||
- /lib/x86_64-linux-gnu/libblkid.so.1
|
||||
- /lib/x86_64-linux-gnu/libbrotlicommon.so.1
|
||||
- /lib/x86_64-linux-gnu/libbrotlidec.so.1
|
||||
- /lib/x86_64-linux-gnu/libbsd.so.0
|
||||
- /lib/x86_64-linux-gnu/libcairo-gobject.so.2
|
||||
- /lib/x86_64-linux-gnu/libcairo.so.2
|
||||
- /lib/x86_64-linux-gnu/libdatrie.so.1
|
||||
- /lib/x86_64-linux-gnu/libedit.so.2
|
||||
- /lib/x86_64-linux-gnu/libelf.so.1
|
||||
- /lib/x86_64-linux-gnu/libepoxy.so.0
|
||||
- /lib/x86_64-linux-gnu/libffi.so.7
|
||||
- /lib/x86_64-linux-gnu/libfontconfig.so.1
|
||||
- /lib/x86_64-linux-gnu/libfreetype.so.6
|
||||
- /lib/x86_64-linux-gnu/libfribidi.so.0
|
||||
- /lib/x86_64-linux-gnu/libgcrypt.so.20
|
||||
- /lib/x86_64-linux-gnu/libgdk-3.so.0
|
||||
- /lib/x86_64-linux-gnu/libgdk_pixbuf-2.0.so.0
|
||||
- /lib/x86_64-linux-gnu/libgio-2.0.so.0
|
||||
- /lib/x86_64-linux-gnu/libglapi.so.0
|
||||
- /lib/x86_64-linux-gnu/libglfw.so.3
|
||||
- /lib/x86_64-linux-gnu/libglib-2.0.so.0
|
||||
- /lib/x86_64-linux-gnu/libgmodule-2.0.so.0
|
||||
- /lib/x86_64-linux-gnu/libgobject-2.0.so.0
|
||||
- /lib/x86_64-linux-gnu/libgraphite2.so.3
|
||||
- /lib/x86_64-linux-gnu/libgtk-3.so.0
|
||||
- /lib/x86_64-linux-gnu/libharfbuzz.so.0
|
||||
- /lib/x86_64-linux-gnu/libicudata.so.67
|
||||
- /lib/x86_64-linux-gnu/libicuuc.so.67
|
||||
- /lib/x86_64-linux-gnu/libjpeg.so.8
|
||||
- /lib/x86_64-linux-gnu/liblz4.so.1
|
||||
- /lib/x86_64-linux-gnu/libmagic.so.1
|
||||
- /lib/x86_64-linux-gnu/libmbedcrypto.so.3
|
||||
- /lib/x86_64-linux-gnu/libmbedtls.so.12
|
||||
- /lib/x86_64-linux-gnu/libmbedx509.so.0
|
||||
- /lib/x86_64-linux-gnu/libmd.so.0
|
||||
- /lib/x86_64-linux-gnu/libmount.so.1
|
||||
- /lib/x86_64-linux-gnu/libpango-1.0.so.0
|
||||
- /lib/x86_64-linux-gnu/libpangocairo-1.0.so.0
|
||||
- /lib/x86_64-linux-gnu/libpangoft2-1.0.so.0
|
||||
- /lib/x86_64-linux-gnu/libpcre2-8.so.0
|
||||
- /lib/x86_64-linux-gnu/libpixman-1.so.0
|
||||
- /lib/x86_64-linux-gnu/libpng16.so.16
|
||||
- /lib/x86_64-linux-gnu/libpython3.8.so.1.0
|
||||
- /lib/x86_64-linux-gnu/libsensors.so.5
|
||||
- /lib/x86_64-linux-gnu/libstdc++.so.6
|
||||
- /lib/x86_64-linux-gnu/libsystemd.so.0
|
||||
- /lib/x86_64-linux-gnu/libthai.so.0
|
||||
- /lib/x86_64-linux-gnu/libuuid.so.1
|
||||
- /lib/x86_64-linux-gnu/libvulkan.so.1
|
||||
- /lib/x86_64-linux-gnu/libwayland-client.so.0
|
||||
- /lib/x86_64-linux-gnu/libwayland-cursor.so.0
|
||||
- /lib/x86_64-linux-gnu/libwayland-egl.so.1
|
||||
- /lib/x86_64-linux-gnu/libxcb-dri2.so.0
|
||||
- /lib/x86_64-linux-gnu/libxcb-dri3.so.0
|
||||
- /lib/x86_64-linux-gnu/libxcb-present.so.0
|
||||
- /lib/x86_64-linux-gnu/libxcb-sync.so.1
|
||||
- /lib/x86_64-linux-gnu/libxkbcommon.so.0
|
||||
- /lib/x86_64-linux-gnu/libxml2.so.2
|
||||
- /lib/x86_64-linux-gnu/libxshmfence.so.1
|
||||
- /lib/x86_64-linux-gnu/libzstd.so.1
|
||||
exclude:
|
||||
- usr/share/man
|
||||
- usr/share/doc/*/README.*
|
||||
- usr/share/doc/*/changelog.*
|
||||
- usr/share/doc/*/NEWS.*
|
||||
- usr/share/doc/*/TODO.*
|
||||
AppImage:
|
||||
arch: x86_64
|
||||
update-information: guess
|
||||
6
dist/get_deps_debian.sh
vendored
6
dist/get_deps_debian.sh
vendored
@@ -12,8 +12,8 @@ fi
|
||||
|
||||
apt install -y \
|
||||
build-essential \
|
||||
gcc-10 \
|
||||
g++-10 \
|
||||
gcc-11 \
|
||||
g++-11 \
|
||||
lld \
|
||||
${PKGCONF:-} \
|
||||
cmake \
|
||||
@@ -28,4 +28,4 @@ apt install -y \
|
||||
libgtk-3-dev \
|
||||
|
||||
echo "Please consider this before running cmake (useful on e.g. Ubuntu 20.04):"
|
||||
echo "export CXX=g++-10"
|
||||
echo "export CXX=g++-11"
|
||||
|
||||
2
dist/imhex.desktop
vendored
2
dist/imhex.desktop
vendored
@@ -3,7 +3,7 @@ Name=ImHex
|
||||
Comment=ImHex Hex Editor
|
||||
GenericName=Hex Editor
|
||||
Exec=/usr/bin/imhex %U
|
||||
Icon=/usr/share/pixmaps/imhex.png
|
||||
Icon=imhex
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
Categories=GNOME;GTK;Development;
|
||||
|
||||
2
lib/external/capstone
vendored
2
lib/external/capstone
vendored
Submodule lib/external/capstone updated: c7c665f8f3...d5141c0478
2
lib/external/curl
vendored
2
lib/external/curl
vendored
Submodule lib/external/curl updated: 801bd5138c...64db5c575d
2
lib/external/fmt
vendored
2
lib/external/fmt
vendored
Submodule lib/external/fmt updated: d141cdbeb0...bc654faf82
@@ -50,6 +50,7 @@
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -278,7 +279,7 @@ struct MemoryEditor
|
||||
if (OptMidColsCount > 0)
|
||||
byte_pos_x += (float)(i / OptMidColsCount) * s.SpacingBetweenMidCols;
|
||||
ImGui::SameLine(byte_pos_x);
|
||||
ImGui::Text("%02llX", i + (base_display_addr % Cols));
|
||||
ImGui::TextFormatted("{:02X}", i + (base_display_addr % Cols));
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
@@ -324,7 +325,7 @@ struct MemoryEditor
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageDown)) && DataEditingAddr < mem_size - 1) { data_editing_addr_next = std::min<i64>(mem_size - 1, DataEditingAddr + visible_count); DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)) && DataEditingAddr > 0) { data_editing_addr_next = 0; DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)) && DataEditingAddr < mem_size - 1) { data_editing_addr_next = mem_size - 1; DataEditingTakeFocus = true; }
|
||||
} else if (DataPreviewAddr != -1) {
|
||||
} else if (DataPreviewAddr != (size_t)-1) {
|
||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)) && DataPreviewAddr >= (size_t)Cols) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr - Cols; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)) && DataPreviewAddr < mem_size - Cols) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr + Cols; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)) && DataPreviewAddr > 0) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr - 1; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
@@ -717,7 +718,6 @@ struct MemoryEditor
|
||||
void DrawOptionsLine(const Sizes& s, void* mem_data, size_t mem_size, size_t base_display_addr)
|
||||
{
|
||||
IM_UNUSED(mem_data);
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
const char* format_range = OptUpperCaseHex ? "Range 0x%0*" _PRISizeT "X..0x%0*" _PRISizeT "X" : "Range 0x%0*" _PRISizeT "x..0x%0*" _PRISizeT "x";
|
||||
const char* format_selection = OptUpperCaseHex ? "Selection 0x%0*" _PRISizeT "X..0x%0*" _PRISizeT "X (%ld [0x%lX] %s)" : "Range 0x%0*" _PRISizeT "x..0x%0*" _PRISizeT "x (%ld [0x%lX] %s)";
|
||||
|
||||
|
||||
2
lib/external/libromfs
vendored
2
lib/external/libromfs
vendored
Submodule lib/external/libromfs updated: 0842d22deb...f14e88a727
2
lib/external/nativefiledialog
vendored
2
lib/external/nativefiledialog
vendored
Submodule lib/external/nativefiledialog updated: 322d1bc2a9...28ade5a5cc
1
lib/external/pattern_language
vendored
Submodule
1
lib/external/pattern_language
vendored
Submodule
Submodule lib/external/pattern_language added at f276631e73
20
lib/external/yara/CMakeLists.txt
vendored
20
lib/external/yara/CMakeLists.txt
vendored
@@ -81,17 +81,19 @@ set(LIBYARA_SOURCE
|
||||
)
|
||||
|
||||
set(LIBYARA_MODULES
|
||||
${LIBYARA_SOURCE_PATH}/modules/tests/tests.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/pe/pe.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/pe/pe_utils.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/elf/elf.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/math/math.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/time/time.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/macho/macho.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/hash/hash.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/console/console.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/dex/dex.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/dotnet/dotnet.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/magic/magic.c)
|
||||
${LIBYARA_SOURCE_PATH}/modules/elf/elf.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/hash/hash.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/macho/macho.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/magic/magic.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/math/math.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/pe/pe.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/pe/pe_utils.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/tests/tests.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/time/time.c
|
||||
)
|
||||
|
||||
# Add mbedtls crypto wrappers
|
||||
add_compile_definitions("HAVE_MBEDTLS")
|
||||
|
||||
2
lib/external/yara/yara
vendored
2
lib/external/yara/yara
vendored
Submodule lib/external/yara/yara updated: 8206dc6f72...136794355c
@@ -71,15 +71,16 @@ if (NOT USE_SYSTEM_CAPSTONE)
|
||||
set(CAPSTONE_BUILD_SHARED OFF CACHE BOOL "Disable shared library building")
|
||||
set(CAPSTONE_BUILD_TESTS OFF CACHE BOOL "Disable tests")
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/capstone ${CMAKE_CURRENT_BINARY_DIR}/external/capstone EXCLUDE_FROM_ALL)
|
||||
set_target_properties(capstone-static PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(CAPSTONE_LIBRARIES "capstone-static")
|
||||
set_target_properties(capstone PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(CAPSTONE_LIBRARIES "capstone")
|
||||
set(CAPSTONE_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/../external/capstone/include)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_search_module(CAPSTONE 4.0.2 REQUIRED capstone)
|
||||
endif()
|
||||
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/pattern_language ${CMAKE_CURRENT_BINARY_DIR}/external/pattern_language EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libpl PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
find_package(mbedTLS 2.26.0 REQUIRED)
|
||||
configurePython()
|
||||
@@ -113,7 +114,7 @@ set(LIBIMHEX_SOURCES
|
||||
source/data_processor/node.cpp
|
||||
|
||||
source/helpers/utils.cpp
|
||||
source/helpers/paths.cpp
|
||||
source/helpers/fs.cpp
|
||||
source/helpers/magic.cpp
|
||||
source/helpers/crypto.cpp
|
||||
source/helpers/net.cpp
|
||||
@@ -125,14 +126,6 @@ set(LIBIMHEX_SOURCES
|
||||
source/helpers/loader_script_handler.cpp
|
||||
source/helpers/logger.cpp
|
||||
|
||||
source/pattern_language/pattern_language.cpp
|
||||
source/pattern_language/preprocessor.cpp
|
||||
source/pattern_language/lexer.cpp
|
||||
source/pattern_language/parser.cpp
|
||||
source/pattern_language/validator.cpp
|
||||
source/pattern_language/evaluator.cpp
|
||||
source/pattern_language/log_console.cpp
|
||||
|
||||
source/providers/provider.cpp
|
||||
|
||||
source/ui/imgui_imhex_extensions.cpp
|
||||
@@ -149,13 +142,14 @@ if (APPLE)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/paths_mac.mm)
|
||||
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/fs_macos.mm)
|
||||
endif ()
|
||||
|
||||
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||
|
||||
add_library(libimhex SHARED ${LIBIMHEX_SOURCES})
|
||||
set_target_properties(libimhex PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
target_compile_options(libimhex PRIVATE -Wall -Wextra -Werror)
|
||||
|
||||
target_include_directories(libimhex PUBLIC include ${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})
|
||||
@@ -165,4 +159,4 @@ if (APPLE)
|
||||
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
|
||||
endif ()
|
||||
|
||||
target_link_libraries(libimhex PUBLIC dl imgui nfd magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs)
|
||||
target_link_libraries(libimhex PUBLIC dl imgui nfd magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs libpl)
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
#include <hex/helpers/intrinsics.hpp>
|
||||
|
||||
constexpr static const auto ImHexApiURL = "https://api.werwolv.net/imhex";
|
||||
constexpr static const auto GitHubApiURL = "https://api.github.com/repos/WerWolv/ImHex";
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <hex/pattern_language/token.hpp>
|
||||
#include <pl/pattern_language.hpp>
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
|
||||
@@ -16,13 +16,15 @@
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
|
||||
namespace pl {
|
||||
class Evaluator;
|
||||
}
|
||||
|
||||
namespace hex {
|
||||
|
||||
class View;
|
||||
class LanguageDefinition;
|
||||
namespace pl {
|
||||
class Evaluator;
|
||||
}
|
||||
|
||||
namespace dp {
|
||||
class Node;
|
||||
}
|
||||
@@ -117,37 +119,28 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
struct ColorPalette {
|
||||
struct FunctionDefinition {
|
||||
pl::api::Namespace ns;
|
||||
std::string name;
|
||||
std::vector<u32> colors;
|
||||
|
||||
pl::api::FunctionParameterCount parameterCount;
|
||||
pl::api::FunctionCallback callback;
|
||||
|
||||
bool dangerous;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
constexpr static u32 UnlimitedParameters = 0xFFFF'FFFF;
|
||||
constexpr static u32 MoreParametersThan = 0x8000'0000;
|
||||
constexpr static u32 LessParametersThan = 0x4000'0000;
|
||||
constexpr static u32 ExactlyOrMoreParametersThan = 0x2000'0000;
|
||||
constexpr static u32 NoParameters = 0x0000'0000;
|
||||
std::unique_ptr<pl::PatternLanguage> createDefaultRuntime(prv::Provider *provider);
|
||||
|
||||
using Namespace = std::vector<std::string>;
|
||||
using Callback = std::function<std::optional<hex::pl::Token::Literal>(hex::pl::Evaluator *, const std::vector<hex::pl::Token::Literal> &)>;
|
||||
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler);
|
||||
|
||||
struct Function {
|
||||
u32 parameterCount;
|
||||
Callback func;
|
||||
bool dangerous;
|
||||
};
|
||||
void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func);
|
||||
void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func);
|
||||
|
||||
void addFunction(const Namespace &ns, const std::string &name, u32 parameterCount, const Callback &func);
|
||||
void addDangerousFunction(const Namespace &ns, const std::string &name, u32 parameterCount, const Callback &func);
|
||||
std::map<std::string, ContentRegistry::PatternLanguage::Function> &getFunctions();
|
||||
std::map<std::string, pl::api::PragmaHandler> &getPragmas();
|
||||
std::vector<impl::FunctionDefinition> &getFunctions();
|
||||
|
||||
std::vector<impl::ColorPalette> &getPalettes();
|
||||
void addColorPalette(const std::string &unlocalizedName, const std::vector<u32> &colors);
|
||||
void setSelectedPalette(u32 index);
|
||||
u32 getNextColor();
|
||||
void resetPalette();
|
||||
}
|
||||
|
||||
/* View Registry. Allows adding of new windows */
|
||||
@@ -372,7 +365,7 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
using Callback = std::function<bool(fs::path)>;
|
||||
using Callback = std::function<bool(std::fs::path)>;
|
||||
struct Entry {
|
||||
std::vector<std::string> extensions;
|
||||
Callback callback;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <functional>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#define EVENT_DEF(event_name, ...) \
|
||||
struct event_name final : public hex::Event<__VA_ARGS__> { \
|
||||
@@ -16,7 +16,11 @@
|
||||
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
|
||||
}
|
||||
|
||||
class GLFWwindow;
|
||||
struct GLFWwindow;
|
||||
|
||||
namespace pl {
|
||||
class Pattern;
|
||||
}
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -87,7 +91,7 @@ namespace hex {
|
||||
static void post(auto &&...args) noexcept {
|
||||
for (const auto &[id, event] : s_events) {
|
||||
if (id == E::id)
|
||||
(*reinterpret_cast<E *>(event))(std::forward<decltype(args)>(args)...);
|
||||
(*static_cast<E *const>(event))(std::forward<decltype(args)>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,12 +100,8 @@ namespace hex {
|
||||
static EventList s_events;
|
||||
};
|
||||
|
||||
namespace pl {
|
||||
class Pattern;
|
||||
}
|
||||
|
||||
/* Default Events */
|
||||
EVENT_DEF(EventFileLoaded, fs::path);
|
||||
EVENT_DEF(EventFileLoaded, std::fs::path);
|
||||
EVENT_DEF(EventFileUnloaded);
|
||||
EVENT_DEF(EventDataChanged);
|
||||
EVENT_DEF(EventHighlightingChanged);
|
||||
@@ -124,7 +124,7 @@ namespace hex {
|
||||
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
|
||||
EVENT_DEF(RequestChangeWindowTitle, std::string);
|
||||
EVENT_DEF(RequestCloseImHex, bool);
|
||||
EVENT_DEF(RequestOpenFile, fs::path);
|
||||
EVENT_DEF(RequestOpenFile, std::fs::path);
|
||||
EVENT_DEF(RequestChangeTheme, u32);
|
||||
EVENT_DEF(RequestOpenPopup, std::string);
|
||||
EVENT_DEF(RequestCreateProvider, std::string, hex::prv::Provider **);
|
||||
|
||||
@@ -11,7 +11,7 @@ struct ImGuiWindow;
|
||||
|
||||
namespace hex {
|
||||
|
||||
struct View;
|
||||
class View;
|
||||
|
||||
enum class Keys
|
||||
{
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace hex {
|
||||
public:
|
||||
LanguageDefinition(std::initializer_list<std::pair<std::string, std::string>> entries);
|
||||
|
||||
const std::map<std::string, std::string> &getEntries() const;
|
||||
[[nodiscard]] const std::map<std::string, std::string> &getEntries() const;
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> m_entries;
|
||||
@@ -20,7 +20,7 @@ namespace hex {
|
||||
class LangEntry {
|
||||
public:
|
||||
explicit LangEntry(const char *unlocalizedString);
|
||||
explicit LangEntry(const std::string &unlocalizedString);
|
||||
explicit LangEntry(std::string unlocalizedString);
|
||||
explicit LangEntry(std::string_view unlocalizedString);
|
||||
|
||||
operator std::string() const;
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace hex {
|
||||
|
||||
class Plugin {
|
||||
public:
|
||||
explicit Plugin(const fs::path &path);
|
||||
explicit Plugin(const std::fs::path &path);
|
||||
Plugin(const Plugin &) = delete;
|
||||
Plugin(Plugin &&other) noexcept;
|
||||
~Plugin();
|
||||
@@ -26,7 +26,7 @@ namespace hex {
|
||||
void setImGuiContext(ImGuiContext *ctx) const;
|
||||
[[nodiscard]] bool isBuiltinPlugin() const;
|
||||
|
||||
[[nodiscard]] const fs::path &getPath() const;
|
||||
[[nodiscard]] const std::fs::path &getPath() const;
|
||||
|
||||
[[nodiscard]] bool isLoaded() const;
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace hex {
|
||||
using IsBuiltinPluginFunc = bool (*)();
|
||||
|
||||
void *m_handle = nullptr;
|
||||
fs::path m_path;
|
||||
std::fs::path m_path;
|
||||
|
||||
mutable bool m_initialized = false;
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace hex {
|
||||
public:
|
||||
PluginManager() = delete;
|
||||
|
||||
static bool load(const fs::path &pluginFolder);
|
||||
static bool load(const std::fs::path &pluginFolder);
|
||||
static void unload();
|
||||
static void reload();
|
||||
|
||||
@@ -74,7 +74,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
private:
|
||||
static fs::path s_pluginFolder;
|
||||
static std::fs::path s_pluginFolder;
|
||||
static std::vector<Plugin> s_plugins;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <hex/helpers/intrinsics.hpp>
|
||||
#include <hex/data_processor/attribute.hpp>
|
||||
|
||||
#include <set>
|
||||
@@ -38,8 +39,8 @@ namespace hex::dp {
|
||||
virtual void drawNode() { }
|
||||
virtual void process() = 0;
|
||||
|
||||
virtual void store(nlohmann::json &j) { }
|
||||
virtual void load(nlohmann::json &j) { }
|
||||
virtual void store(nlohmann::json &j) { hex::unused(j); }
|
||||
virtual void load(nlohmann::json &j) { hex::unused(j); }
|
||||
|
||||
using NodeError = std::pair<Node *, std::string>;
|
||||
|
||||
@@ -90,11 +91,11 @@ namespace hex::dp {
|
||||
}
|
||||
|
||||
std::vector<u8> getBufferOnInput(u32 index);
|
||||
u64 getIntegerOnInput(u32 index);
|
||||
i64 getIntegerOnInput(u32 index);
|
||||
float getFloatOnInput(u32 index);
|
||||
|
||||
void setBufferOnOutput(u32 index, std::vector<u8> data);
|
||||
void setIntegerOnOutput(u32 index, u64 integer);
|
||||
void setBufferOnOutput(u32 index, const std::vector<u8> &data);
|
||||
void setIntegerOnOutput(u32 index, i64 integer);
|
||||
void setFloatOnOutput(u32 index, float floatingPoint);
|
||||
|
||||
void setOverlayData(u64 address, const std::vector<u8> &data);
|
||||
|
||||
@@ -31,12 +31,12 @@ namespace hex {
|
||||
|
||||
class Disassembler {
|
||||
public:
|
||||
static constexpr cs_arch toCapstoneArchictecture(Architecture architecture) {
|
||||
static constexpr cs_arch toCapstoneArchitecture(Architecture architecture) {
|
||||
return static_cast<cs_arch>(architecture);
|
||||
}
|
||||
|
||||
static inline bool isSupported(Architecture architecture) {
|
||||
return cs_support(toCapstoneArchictecture(architecture));
|
||||
return cs_support(toCapstoneArchitecture(architecture));
|
||||
}
|
||||
|
||||
constexpr static const char *const ArchitectureNames[] = { "ARM32", "ARM64", "MIPS", "x86", "PowerPC", "Sparc", "SystemZ", "XCore", "68K", "TMS320C64x", "680X", "Ethereum", "MOS65XX", "WebAssembly", "Berkeley Packet Filter", "RISC-V" };
|
||||
|
||||
@@ -6,18 +6,19 @@
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class EncodingFile {
|
||||
public:
|
||||
enum class Type {
|
||||
enum class Type
|
||||
{
|
||||
Thingy
|
||||
};
|
||||
|
||||
EncodingFile() = default;
|
||||
EncodingFile(Type type, const fs::path &path);
|
||||
EncodingFile(Type type, const std::fs::path &path);
|
||||
|
||||
[[nodiscard]] std::pair<std::string_view, size_t> getEncodingFor(const std::vector<u8> &buffer) const;
|
||||
[[nodiscard]] size_t getLongestSequence() const { return this->m_longestSequence; }
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#if defined(OS_MACOS)
|
||||
#define off64_t off_t
|
||||
@@ -16,7 +16,7 @@
|
||||
#define ftruncate64 ftruncate
|
||||
#endif
|
||||
|
||||
namespace hex {
|
||||
namespace hex::fs {
|
||||
|
||||
class File {
|
||||
public:
|
||||
@@ -27,7 +27,7 @@ namespace hex {
|
||||
Create
|
||||
};
|
||||
|
||||
explicit File(const fs::path &path, Mode mode) noexcept;
|
||||
explicit File(const std::fs::path &path, Mode mode) noexcept;
|
||||
File() noexcept;
|
||||
File(const File &) = delete;
|
||||
File(File &&other) noexcept;
|
||||
@@ -38,7 +38,7 @@ namespace hex {
|
||||
|
||||
|
||||
[[nodiscard]] bool isValid() const {
|
||||
return this->m_file != nullptr && fs::exists(this->m_path) && !fs::is_directory(this->m_path);
|
||||
return this->m_file != nullptr && fs::exists(this->m_path) && !fs::isDirectory(this->m_path);
|
||||
}
|
||||
|
||||
void seek(u64 offset);
|
||||
@@ -59,13 +59,13 @@ namespace hex {
|
||||
bool remove();
|
||||
|
||||
auto getHandle() { return this->m_file; }
|
||||
const fs::path &getPath() { return this->m_path; }
|
||||
const std::fs::path &getPath() { return this->m_path; }
|
||||
|
||||
void disableBuffering();
|
||||
|
||||
private:
|
||||
FILE *m_file;
|
||||
fs::path m_path;
|
||||
std::fs::path m_path;
|
||||
};
|
||||
|
||||
}
|
||||
92
lib/libimhex/include/hex/helpers/fs.hpp
Normal file
92
lib/libimhex/include/hex/helpers/fs.hpp
Normal file
@@ -0,0 +1,92 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
#include <functional>
|
||||
|
||||
#include <nfd.hpp>
|
||||
|
||||
namespace std::fs {
|
||||
using namespace std::filesystem;
|
||||
}
|
||||
|
||||
namespace hex::fs {
|
||||
|
||||
[[maybe_unused]]
|
||||
static inline bool exists(const std::fs::path &path) {
|
||||
std::error_code error;
|
||||
return std::filesystem::exists(path, error) && !error;
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
static inline bool createDirectories(const std::fs::path &path) {
|
||||
std::error_code error;
|
||||
return std::filesystem::create_directories(path, error) && !error;
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
static inline bool isRegularFile(const std::fs::path &path) {
|
||||
std::error_code error;
|
||||
return std::filesystem::is_regular_file(path, error) && !error;
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
static inline bool copyFile(const std::fs::path &from, const std::fs::path &to, std::fs::copy_options = std::fs::copy_options::none) {
|
||||
std::error_code error;
|
||||
return std::filesystem::copy_file(from, to, error) && !error;
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
static inline bool isDirectory(const std::fs::path &path) {
|
||||
std::error_code error;
|
||||
return std::filesystem::is_directory(path, error) && !error;
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
static inline bool remove(const std::fs::path &path) {
|
||||
std::error_code error;
|
||||
return std::filesystem::remove(path, error) && !error;
|
||||
}
|
||||
|
||||
[[maybe_unused]]
|
||||
static inline uintmax_t getFileSize(const std::fs::path &path) {
|
||||
std::error_code error;
|
||||
auto size = std::filesystem::file_size(path, error);
|
||||
|
||||
if (error) return 0;
|
||||
else return size;
|
||||
}
|
||||
|
||||
bool isPathWritable(const std::fs::path &path);
|
||||
|
||||
enum class DialogMode
|
||||
{
|
||||
Open,
|
||||
Save,
|
||||
Folder
|
||||
};
|
||||
|
||||
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath = {});
|
||||
|
||||
enum class ImHexPath
|
||||
{
|
||||
Patterns,
|
||||
PatternsInclude,
|
||||
Magic,
|
||||
Python,
|
||||
Plugins,
|
||||
Yara,
|
||||
Config,
|
||||
Resources,
|
||||
Constants,
|
||||
Encodings,
|
||||
Logs
|
||||
};
|
||||
|
||||
std::optional<std::fs::path> getExecutablePath();
|
||||
|
||||
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting = false);
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(OS_MACOS)
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
namespace hex {
|
||||
std::string getMacExecutableDirectoryPath();
|
||||
13
lib/libimhex/include/hex/helpers/intrinsics.hpp
Normal file
13
lib/libimhex/include/hex/helpers/intrinsics.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace hex {
|
||||
|
||||
[[noreturn]] inline void unreachable() {
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
inline void unused(auto && ... x) {
|
||||
((void)x, ...);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
struct _object;
|
||||
typedef struct _object PyObject;
|
||||
@@ -18,13 +18,13 @@ namespace hex {
|
||||
public:
|
||||
LoaderScript() = delete;
|
||||
|
||||
static bool processFile(const fs::path &scriptPath);
|
||||
static bool processFile(const std::fs::path &scriptPath);
|
||||
|
||||
static void setFilePath(const fs::path &filePath) { LoaderScript::s_filePath = filePath; }
|
||||
static void setFilePath(const std::fs::path &filePath) { LoaderScript::s_filePath = filePath; }
|
||||
static void setDataProvider(prv::Provider *provider) { LoaderScript::s_dataProvider = provider; }
|
||||
|
||||
private:
|
||||
static inline fs::path s_filePath;
|
||||
static inline std::fs::path s_filePath;
|
||||
static inline prv::Provider *s_dataProvider;
|
||||
|
||||
static PyObject *Py_getFilePath(PyObject *self, PyObject *args);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <fmt/core.h>
|
||||
@@ -13,7 +15,7 @@ namespace hex::log {
|
||||
|
||||
namespace {
|
||||
|
||||
void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level) {
|
||||
[[maybe_unused]] void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level) {
|
||||
const auto now = fmt::localtime(std::chrono::system_clock::now());
|
||||
|
||||
fmt::print(dest, "[{0:%H:%M:%S}] ", now);
|
||||
@@ -27,7 +29,7 @@ namespace hex::log {
|
||||
}
|
||||
|
||||
template<typename... T>
|
||||
void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) {
|
||||
[[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) {
|
||||
auto dest = getDestination();
|
||||
|
||||
printPrefix(dest, ts, level);
|
||||
@@ -37,28 +39,30 @@ namespace hex::log {
|
||||
|
||||
}
|
||||
|
||||
void debug(const std::string &fmt, auto &&...args) {
|
||||
[[maybe_unused]] void debug(const std::string &fmt, auto &&...args) {
|
||||
#if defined(DEBUG)
|
||||
log::print(fg(fmt::color::green_yellow) | fmt::emphasis::bold, "[DEBUG]", fmt, args...);
|
||||
hex::log::print(fg(fmt::color::green_yellow) | fmt::emphasis::bold, "[DEBUG]", fmt, args...);
|
||||
#else
|
||||
hex::unused(fmt, args...);
|
||||
#endif
|
||||
}
|
||||
|
||||
void info(const std::string &fmt, auto &&...args) {
|
||||
log::print(fg(fmt::color::cadet_blue) | fmt::emphasis::bold, "[INFO] ", fmt, args...);
|
||||
[[maybe_unused]] void info(const std::string &fmt, auto &&...args) {
|
||||
hex::log::print(fg(fmt::color::cadet_blue) | fmt::emphasis::bold, "[INFO] ", fmt, args...);
|
||||
}
|
||||
|
||||
void warn(const std::string &fmt, auto &&...args) {
|
||||
log::print(fg(fmt::color::orange) | fmt::emphasis::bold, "[WARN] ", fmt, args...);
|
||||
[[maybe_unused]] void warn(const std::string &fmt, auto &&...args) {
|
||||
hex::log::print(fg(fmt::color::orange) | fmt::emphasis::bold, "[WARN] ", fmt, args...);
|
||||
}
|
||||
|
||||
void error(const std::string &fmt, auto &&...args) {
|
||||
log::print(fg(fmt::color::red) | fmt::emphasis::bold, "[ERROR]", fmt, args...);
|
||||
[[maybe_unused]] void error(const std::string &fmt, auto &&...args) {
|
||||
hex::log::print(fg(fmt::color::red) | fmt::emphasis::bold, "[ERROR]", fmt, args...);
|
||||
}
|
||||
|
||||
void fatal(const std::string &fmt, auto &&...args) {
|
||||
log::print(fg(fmt::color::purple) | fmt::emphasis::bold, "[FATAL]", fmt, args...);
|
||||
[[maybe_unused]] void fatal(const std::string &fmt, auto &&...args) {
|
||||
hex::log::print(fg(fmt::color::purple) | fmt::emphasis::bold, "[FATAL]", fmt, args...);
|
||||
}
|
||||
|
||||
void redirectToFile();
|
||||
[[maybe_unused]] void redirectToFile();
|
||||
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <curl/system.h>
|
||||
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
using CURL = void;
|
||||
struct curl_slist;
|
||||
@@ -40,8 +40,8 @@ namespace hex {
|
||||
std::future<Response<std::string>> getString(const std::string &url, u32 timeout = DefaultTimeout);
|
||||
std::future<Response<nlohmann::json>> getJson(const std::string &url, u32 timeout = DefaultTimeout);
|
||||
|
||||
std::future<Response<std::string>> uploadFile(const std::string &url, const fs::path &filePath, u32 timeout = DefaultTimeout);
|
||||
std::future<Response<void>> downloadFile(const std::string &url, const fs::path &filePath, u32 timeout = DefaultTimeout);
|
||||
std::future<Response<std::string>> uploadFile(const std::string &url, const std::fs::path &filePath, u32 timeout = DefaultTimeout);
|
||||
std::future<Response<void>> downloadFile(const std::string &url, const std::fs::path &filePath, u32 timeout = DefaultTimeout);
|
||||
|
||||
[[nodiscard]] std::string encode(const std::string &input);
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
enum class ImHexPath {
|
||||
Patterns,
|
||||
PatternsInclude,
|
||||
Magic,
|
||||
Python,
|
||||
Plugins,
|
||||
Yara,
|
||||
Config,
|
||||
Resources,
|
||||
Constants,
|
||||
Encodings,
|
||||
Logs
|
||||
};
|
||||
|
||||
std::string getExecutablePath();
|
||||
|
||||
std::vector<fs::path> getPath(ImHexPath path, bool listNonExisting = false);
|
||||
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace hex {
|
||||
public:
|
||||
ProjectFile() = delete;
|
||||
|
||||
static bool load(const fs::path &filePath);
|
||||
static bool store(fs::path filePath = {});
|
||||
static bool load(const std::fs::path &filePath);
|
||||
static bool store(std::fs::path filePath = {});
|
||||
|
||||
[[nodiscard]] static bool hasUnsavedChanges() {
|
||||
return ProjectFile::s_hasUnsavedChanged;
|
||||
@@ -29,10 +29,10 @@ namespace hex {
|
||||
ProjectFile::s_hasUnsavedChanged = true;
|
||||
|
||||
if (setWindowTitle)
|
||||
EventManager::post<RequestChangeWindowTitle>(fs::path(getFilePath()).filename().string());
|
||||
EventManager::post<RequestChangeWindowTitle>(std::fs::path(getFilePath()).filename().string());
|
||||
}
|
||||
|
||||
[[nodiscard]] static const fs::path &getProjectFilePath() {
|
||||
[[nodiscard]] static const std::fs::path &getProjectFilePath() {
|
||||
return ProjectFile::s_currProjectFilePath;
|
||||
}
|
||||
|
||||
@@ -41,11 +41,11 @@ namespace hex {
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] static const fs::path &getFilePath() {
|
||||
[[nodiscard]] static const std::fs::path &getFilePath() {
|
||||
return ProjectFile::s_filePath;
|
||||
}
|
||||
|
||||
static void setFilePath(const fs::path &filePath) {
|
||||
static void setFilePath(const std::fs::path &filePath) {
|
||||
ProjectFile::s_filePath = filePath;
|
||||
|
||||
EventManager::post<RequestChangeWindowTitle>(filePath.filename().string());
|
||||
@@ -92,10 +92,10 @@ namespace hex {
|
||||
}
|
||||
|
||||
private:
|
||||
static fs::path s_currProjectFilePath;
|
||||
static std::fs::path s_currProjectFilePath;
|
||||
static bool s_hasUnsavedChanged;
|
||||
|
||||
static fs::path s_filePath;
|
||||
static std::fs::path s_filePath;
|
||||
static std::string s_pattern;
|
||||
static Patches s_patches;
|
||||
static std::list<ImHexApi::Bookmarks::Entry> s_bookmarks;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace hex {
|
||||
public:
|
||||
Socket() = default;
|
||||
Socket(const Socket &) = delete;
|
||||
Socket(Socket &&other);
|
||||
Socket(Socket &&other) noexcept;
|
||||
|
||||
Socket(const std::string &address, u16 port);
|
||||
~Socket();
|
||||
@@ -36,8 +36,8 @@ namespace hex {
|
||||
|
||||
[[nodiscard]] bool isConnected() const;
|
||||
|
||||
std::string readString(size_t size = 0x1000) const;
|
||||
std::vector<u8> readBytes(size_t size = 0x1000) const;
|
||||
[[nodiscard]] std::string readString(size_t size = 0x1000) const;
|
||||
[[nodiscard]] std::vector<u8> readBytes(size_t size = 0x1000) const;
|
||||
|
||||
void writeString(const std::string &string) const;
|
||||
void writeBytes(const std::vector<u8> &bytes) const;
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/intrinsics.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <bit>
|
||||
@@ -18,8 +19,6 @@
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include <nfd.hpp>
|
||||
|
||||
#define TOKEN_CONCAT_IMPL(x, y) x##y
|
||||
#define TOKEN_CONCAT(x, y) TOKEN_CONCAT_IMPL(x, y)
|
||||
#define ANONYMOUS_VARIABLE(prefix) TOKEN_CONCAT(prefix, __COUNTER__)
|
||||
@@ -44,8 +43,6 @@ namespace hex {
|
||||
std::string encodeByteString(const std::vector<u8> &bytes);
|
||||
std::vector<u8> decodeByteString(const std::string &string);
|
||||
|
||||
bool isPathWritable(fs::path path);
|
||||
|
||||
[[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const hex::unsigned_integral auto &value) {
|
||||
if (from < to) std::swap(from, to);
|
||||
|
||||
@@ -58,9 +55,6 @@ namespace hex {
|
||||
[[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++;
|
||||
@@ -132,7 +126,7 @@ namespace hex {
|
||||
swapped = (u128(__builtin_bswap64(unswapped & 0xFFFF'FFFF'FFFF'FFFF)) << 64) | __builtin_bswap64(u128(unswapped) >> 64);
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
hex::unreachable();
|
||||
}
|
||||
|
||||
T result;
|
||||
@@ -172,7 +166,7 @@ namespace hex {
|
||||
swapped = (u128(__builtin_bswap64(unswapped & 0xFFFF'FFFF'FFFF'FFFF)) << 64) | __builtin_bswap64(u128(unswapped) >> 64);
|
||||
break;
|
||||
default:
|
||||
__builtin_unreachable();
|
||||
hex::unreachable();
|
||||
}
|
||||
|
||||
T result = 0;
|
||||
@@ -268,15 +262,6 @@ namespace hex {
|
||||
trimRight(s);
|
||||
}
|
||||
|
||||
enum class DialogMode
|
||||
{
|
||||
Open,
|
||||
Save,
|
||||
Folder
|
||||
};
|
||||
|
||||
bool openFileBrowser(const std::string &title, DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(fs::path)> &callback, const std::string &defaultPath = {});
|
||||
|
||||
float float16ToFloat32(u16 float16);
|
||||
|
||||
inline bool equalsIgnoreCase(const std::string &left, const std::string &right) {
|
||||
@@ -304,10 +289,12 @@ namespace hex {
|
||||
|
||||
bool isProcessElevated();
|
||||
|
||||
std::optional<std::string> getEnvironmentVariable(const std::string &env);
|
||||
|
||||
namespace scope_guard {
|
||||
|
||||
#define SCOPE_GUARD ::hex::scope_guard::ScopeGuardOnExit() + [&]()
|
||||
#define ON_SCOPE_EXIT auto ANONYMOUS_VARIABLE(SCOPE_EXIT_) = SCOPE_GUARD
|
||||
#define ON_SCOPE_EXIT [[maybe_unused]] auto ANONYMOUS_VARIABLE(SCOPE_EXIT_) = SCOPE_GUARD
|
||||
|
||||
template<class F>
|
||||
class ScopeGuard {
|
||||
@@ -316,7 +303,7 @@ namespace hex {
|
||||
bool m_active;
|
||||
|
||||
public:
|
||||
constexpr ScopeGuard(F func) : m_func(std::move(func)), m_active(true) { }
|
||||
explicit constexpr ScopeGuard(F func) : m_func(std::move(func)), m_active(true) { }
|
||||
~ScopeGuard() {
|
||||
if (this->m_active) { this->m_func(); }
|
||||
}
|
||||
@@ -342,12 +329,12 @@ namespace hex {
|
||||
|
||||
namespace first_time_exec {
|
||||
|
||||
#define FIRST_TIME static auto ANONYMOUS_VARIABLE(FIRST_TIME_) = ::hex::first_time_exec::FirstTimeExecutor() + [&]()
|
||||
#define FIRST_TIME [[maybe_unused]] static auto ANONYMOUS_VARIABLE(FIRST_TIME_) = ::hex::first_time_exec::FirstTimeExecutor() + [&]()
|
||||
|
||||
template<class F>
|
||||
class FirstTimeExecute {
|
||||
public:
|
||||
constexpr FirstTimeExecute(F func) { func(); }
|
||||
explicit constexpr FirstTimeExecute(F func) { func(); }
|
||||
|
||||
FirstTimeExecute &operator=(FirstTimeExecute &&) = delete;
|
||||
};
|
||||
@@ -365,14 +352,14 @@ namespace hex {
|
||||
|
||||
namespace final_cleanup {
|
||||
|
||||
#define FINAL_CLEANUP static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]()
|
||||
#define FINAL_CLEANUP [[maybe_unused]] static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]()
|
||||
|
||||
template<class F>
|
||||
class FinalCleanupExecute {
|
||||
F m_func;
|
||||
|
||||
public:
|
||||
constexpr FinalCleanupExecute(F func) : m_func(func) { }
|
||||
explicit constexpr FinalCleanupExecute(F func) : m_func(func) { }
|
||||
constexpr ~FinalCleanupExecute() { this->m_func(); }
|
||||
|
||||
FinalCleanupExecute &operator=(FinalCleanupExecute &&) = delete;
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/token.hpp>
|
||||
#include <hex/pattern_language/evaluator.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class Pattern;
|
||||
class Evaluator;
|
||||
|
||||
class ASTNode : public Cloneable<ASTNode> {
|
||||
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 std::unique_ptr<ASTNode> evaluate(Evaluator *evaluator) const { return this->clone(); }
|
||||
|
||||
[[nodiscard]] virtual std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const { return {}; }
|
||||
|
||||
using FunctionResult = std::optional<Token::Literal>;
|
||||
virtual FunctionResult execute(Evaluator *evaluator) const { LogConsole::abortEvaluation("cannot execute non-function statement", this); }
|
||||
|
||||
private:
|
||||
u32 m_lineNumber = 1;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,309 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_attribute.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_literal.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_builtin_type.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_while_statement.hpp>
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_padding.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_character.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_wide_character.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_string.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_wide_string.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_array_dynamic.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_array_static.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeArrayVariableDecl : public ASTNode,
|
||||
public Attributable {
|
||||
public:
|
||||
ASTNodeArrayVariableDecl(std::string name, std::unique_ptr<ASTNode> &&type, std::unique_ptr<ASTNode> &&size, std::unique_ptr<ASTNode> &&placementOffset = {})
|
||||
: ASTNode(), m_name(std::move(name)), m_type(std::move(type)), m_size(std::move(size)), m_placementOffset(std::move(placementOffset)) { }
|
||||
|
||||
ASTNodeArrayVariableDecl(const ASTNodeArrayVariableDecl &other) : ASTNode(other), Attributable(other) {
|
||||
this->m_name = other.m_name;
|
||||
this->m_type = other.m_type->clone();
|
||||
if (other.m_size != nullptr)
|
||||
this->m_size = other.m_size->clone();
|
||||
else
|
||||
this->m_size = nullptr;
|
||||
|
||||
if (other.m_placementOffset != nullptr)
|
||||
this->m_placementOffset = other.m_placementOffset->clone();
|
||||
else
|
||||
this->m_placementOffset = nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeArrayVariableDecl(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
auto startOffset = evaluator->dataOffset();
|
||||
|
||||
if (this->m_placementOffset != nullptr) {
|
||||
auto evaluatedPlacement = this->m_placementOffset->evaluate(evaluator);
|
||||
auto offset = dynamic_cast<ASTNodeLiteral *>(evaluatedPlacement.get());
|
||||
|
||||
evaluator->dataOffset() = std::visit(overloaded {
|
||||
[this](const std::string &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a string", this); },
|
||||
[this](const std::shared_ptr<Pattern> &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a custom type", this); },
|
||||
[](auto &&offset) -> u64 { return offset; } },
|
||||
offset->getValue());
|
||||
}
|
||||
|
||||
auto type = this->m_type->evaluate(evaluator);
|
||||
|
||||
std::unique_ptr<Pattern> pattern;
|
||||
if (dynamic_cast<ASTNodeBuiltinType *>(type.get()))
|
||||
pattern = createStaticArray(evaluator);
|
||||
else if (auto attributable = dynamic_cast<Attributable *>(type.get())) {
|
||||
bool isStaticType = attributable->hasAttribute("static", false);
|
||||
|
||||
if (isStaticType)
|
||||
pattern = createStaticArray(evaluator);
|
||||
else
|
||||
pattern = createDynamicArray(evaluator);
|
||||
} else {
|
||||
LogConsole::abortEvaluation("invalid type used in array", this);
|
||||
}
|
||||
|
||||
applyVariableAttributes(evaluator, this, pattern.get());
|
||||
|
||||
if (this->m_placementOffset != nullptr && !evaluator->isGlobalScope()) {
|
||||
evaluator->dataOffset() = startOffset;
|
||||
}
|
||||
|
||||
return hex::moveToVector(std::move(pattern));
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::unique_ptr<ASTNode> m_type;
|
||||
std::unique_ptr<ASTNode> m_size;
|
||||
std::unique_ptr<ASTNode> m_placementOffset;
|
||||
|
||||
std::unique_ptr<Pattern> createStaticArray(Evaluator *evaluator) const {
|
||||
u64 startOffset = evaluator->dataOffset();
|
||||
|
||||
auto templatePatterns = this->m_type->createPatterns(evaluator);
|
||||
auto &templatePattern = templatePatterns.front();
|
||||
|
||||
evaluator->dataOffset() = startOffset;
|
||||
|
||||
i128 entryCount = 0;
|
||||
|
||||
if (this->m_size != nullptr) {
|
||||
auto sizeNode = this->m_size->evaluate(evaluator);
|
||||
|
||||
if (auto literal = dynamic_cast<ASTNodeLiteral *>(sizeNode.get())) {
|
||||
entryCount = std::visit(overloaded {
|
||||
[this](const std::string &) -> i128 { LogConsole::abortEvaluation("cannot use string to index array", this); },
|
||||
[this](const std::shared_ptr<Pattern> &) -> i128 { LogConsole::abortEvaluation("cannot use custom type to index array", this); },
|
||||
[](auto &&size) -> i128 { return size; } },
|
||||
literal->getValue());
|
||||
} else if (auto whileStatement = dynamic_cast<ASTNodeWhileStatement *>(sizeNode.get())) {
|
||||
while (whileStatement->evaluateCondition(evaluator)) {
|
||||
entryCount++;
|
||||
evaluator->dataOffset() += templatePattern->getSize();
|
||||
evaluator->handleAbort();
|
||||
}
|
||||
}
|
||||
|
||||
if (entryCount < 0)
|
||||
LogConsole::abortEvaluation("array cannot have a negative size", this);
|
||||
} else {
|
||||
std::vector<u8> buffer(templatePattern->getSize());
|
||||
while (true) {
|
||||
if (evaluator->dataOffset() > evaluator->getProvider()->getActualSize() - buffer.size())
|
||||
LogConsole::abortEvaluation("reached end of file before finding end of unsized array", this);
|
||||
|
||||
evaluator->getProvider()->read(evaluator->dataOffset(), buffer.data(), buffer.size());
|
||||
evaluator->dataOffset() += buffer.size();
|
||||
|
||||
entryCount++;
|
||||
|
||||
bool reachedEnd = true;
|
||||
for (u8 &byte : buffer) {
|
||||
if (byte != 0x00) {
|
||||
reachedEnd = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (reachedEnd) break;
|
||||
evaluator->handleAbort();
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<Pattern> outputPattern;
|
||||
if (dynamic_cast<PatternPadding *>(templatePattern.get())) {
|
||||
outputPattern = std::unique_ptr<Pattern>(new PatternPadding(evaluator, startOffset, 0));
|
||||
} else if (dynamic_cast<PatternCharacter *>(templatePattern.get())) {
|
||||
outputPattern = std::unique_ptr<Pattern>(new PatternString(evaluator, startOffset, 0));
|
||||
} else if (dynamic_cast<PatternWideCharacter *>(templatePattern.get())) {
|
||||
outputPattern = std::unique_ptr<Pattern>(new PatternWideString(evaluator, startOffset, 0));
|
||||
} else {
|
||||
auto arrayPattern = std::make_unique<PatternArrayStatic>(evaluator, startOffset, 0);
|
||||
arrayPattern->setEntries(templatePattern->clone(), entryCount);
|
||||
outputPattern = std::move(arrayPattern);
|
||||
}
|
||||
|
||||
outputPattern->setVariableName(this->m_name);
|
||||
outputPattern->setEndian(templatePattern->getEndian());
|
||||
outputPattern->setTypeName(templatePattern->getTypeName());
|
||||
outputPattern->setSize(templatePattern->getSize() * entryCount);
|
||||
|
||||
evaluator->dataOffset() = startOffset + outputPattern->getSize();
|
||||
|
||||
return outputPattern;
|
||||
}
|
||||
|
||||
std::unique_ptr<Pattern> createDynamicArray(Evaluator *evaluator) const {
|
||||
auto arrayPattern = std::make_unique<PatternArrayDynamic>(evaluator, evaluator->dataOffset(), 0);
|
||||
arrayPattern->setVariableName(this->m_name);
|
||||
|
||||
std::vector<std::shared_ptr<Pattern>> entries;
|
||||
|
||||
size_t size = 0;
|
||||
u64 entryIndex = 0;
|
||||
|
||||
auto addEntries = [&](std::vector<std::unique_ptr<Pattern>> &&patterns) {
|
||||
for (auto &pattern : patterns) {
|
||||
pattern->setVariableName(hex::format("[{}]", entryIndex));
|
||||
pattern->setEndian(arrayPattern->getEndian());
|
||||
|
||||
size += pattern->getSize();
|
||||
entryIndex++;
|
||||
|
||||
entries.push_back(std::move(pattern));
|
||||
|
||||
evaluator->handleAbort();
|
||||
}
|
||||
};
|
||||
|
||||
auto discardEntries = [&](u32 count) {
|
||||
for (u32 i = 0; i < count; i++) {
|
||||
entries.pop_back();
|
||||
entryIndex--;
|
||||
}
|
||||
};
|
||||
|
||||
if (this->m_size != nullptr) {
|
||||
auto sizeNode = this->m_size->evaluate(evaluator);
|
||||
|
||||
if (auto literal = dynamic_cast<ASTNodeLiteral *>(sizeNode.get())) {
|
||||
auto entryCount = std::visit(overloaded {
|
||||
[this](const std::string &) -> u128 { LogConsole::abortEvaluation("cannot use string to index array", this); },
|
||||
[this](const std::shared_ptr<Pattern> &) -> u128 { LogConsole::abortEvaluation("cannot use custom type to index array", this); },
|
||||
[](auto &&size) -> u128 { return size; } },
|
||||
literal->getValue());
|
||||
|
||||
auto limit = evaluator->getArrayLimit();
|
||||
if (entryCount > limit)
|
||||
LogConsole::abortEvaluation(hex::format("array grew past set limit of {}", limit), this);
|
||||
|
||||
for (u64 i = 0; i < entryCount; i++) {
|
||||
evaluator->setCurrentControlFlowStatement(ControlFlowStatement::None);
|
||||
|
||||
auto patterns = this->m_type->createPatterns(evaluator);
|
||||
size_t patternCount = patterns.size();
|
||||
|
||||
if (!patterns.empty())
|
||||
addEntries(std::move(patterns));
|
||||
|
||||
auto ctrlFlow = evaluator->getCurrentControlFlowStatement();
|
||||
if (ctrlFlow == ControlFlowStatement::Break)
|
||||
break;
|
||||
else if (ctrlFlow == ControlFlowStatement::Continue) {
|
||||
|
||||
discardEntries(patternCount);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
} else if (auto whileStatement = dynamic_cast<ASTNodeWhileStatement *>(sizeNode.get())) {
|
||||
while (whileStatement->evaluateCondition(evaluator)) {
|
||||
auto limit = evaluator->getArrayLimit();
|
||||
if (entryIndex > limit)
|
||||
LogConsole::abortEvaluation(hex::format("array grew past set limit of {}", limit), this);
|
||||
|
||||
evaluator->setCurrentControlFlowStatement(ControlFlowStatement::None);
|
||||
|
||||
auto patterns = this->m_type->createPatterns(evaluator);
|
||||
size_t patternCount = patterns.size();
|
||||
|
||||
if (!patterns.empty())
|
||||
addEntries(std::move(patterns));
|
||||
|
||||
auto ctrlFlow = evaluator->getCurrentControlFlowStatement();
|
||||
if (ctrlFlow == ControlFlowStatement::Break)
|
||||
break;
|
||||
else if (ctrlFlow == ControlFlowStatement::Continue) {
|
||||
discardEntries(patternCount);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while (true) {
|
||||
bool reachedEnd = true;
|
||||
auto limit = evaluator->getArrayLimit();
|
||||
if (entryIndex > limit)
|
||||
LogConsole::abortEvaluation(hex::format("array grew past set limit of {}", limit), this);
|
||||
|
||||
evaluator->setCurrentControlFlowStatement(ControlFlowStatement::None);
|
||||
|
||||
auto patterns = this->m_type->createPatterns(evaluator);
|
||||
|
||||
for (auto &pattern : patterns) {
|
||||
std::vector<u8> buffer(pattern->getSize());
|
||||
|
||||
if (evaluator->dataOffset() > evaluator->getProvider()->getActualSize() - buffer.size()) {
|
||||
LogConsole::abortEvaluation("reached end of file before finding end of unsized array", this);
|
||||
}
|
||||
|
||||
const auto patternSize = pattern->getSize();
|
||||
addEntries(hex::moveToVector(std::move(pattern)));
|
||||
|
||||
auto ctrlFlow = evaluator->getCurrentControlFlowStatement();
|
||||
if (ctrlFlow == ControlFlowStatement::None)
|
||||
break;
|
||||
|
||||
evaluator->getProvider()->read(evaluator->dataOffset() - patternSize, buffer.data(), buffer.size());
|
||||
reachedEnd = true;
|
||||
for (u8 &byte : buffer) {
|
||||
if (byte != 0x00) {
|
||||
reachedEnd = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (reachedEnd) break;
|
||||
}
|
||||
|
||||
auto ctrlFlow = evaluator->getCurrentControlFlowStatement();
|
||||
if (ctrlFlow == ControlFlowStatement::Break)
|
||||
break;
|
||||
else if (ctrlFlow == ControlFlowStatement::Continue) {
|
||||
discardEntries(1);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (reachedEnd) break;
|
||||
}
|
||||
}
|
||||
|
||||
arrayPattern->setEntries(std::move(entries));
|
||||
|
||||
if (auto &arrayEntries = arrayPattern->getEntries(); !entries.empty())
|
||||
arrayPattern->setTypeName(arrayEntries.front()->getTypeName());
|
||||
|
||||
arrayPattern->setSize(size);
|
||||
|
||||
return std::move(arrayPattern);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_literal.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeAssignment : public ASTNode {
|
||||
public:
|
||||
ASTNodeAssignment(std::string lvalueName, std::unique_ptr<ASTNode> &&rvalue) : m_lvalueName(std::move(lvalueName)), m_rvalue(std::move(rvalue)) {
|
||||
}
|
||||
|
||||
ASTNodeAssignment(const ASTNodeAssignment &other) : ASTNode(other) {
|
||||
this->m_lvalueName = other.m_lvalueName;
|
||||
this->m_rvalue = other.m_rvalue->clone();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeAssignment(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string &getLValueName() const {
|
||||
return this->m_lvalueName;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::unique_ptr<ASTNode> &getRValue() const {
|
||||
return this->m_rvalue;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
this->execute(evaluator);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
FunctionResult execute(Evaluator *evaluator) const override {
|
||||
const auto node = this->getRValue()->evaluate(evaluator);
|
||||
const auto literal = dynamic_cast<ASTNodeLiteral *>(node.get());
|
||||
|
||||
if (this->getLValueName() == "$")
|
||||
evaluator->dataOffset() = Token::literalToUnsigned(literal->getValue());
|
||||
else
|
||||
evaluator->setVariable(this->getLValueName(), literal->getValue());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_lvalueName;
|
||||
std::unique_ptr<ASTNode> m_rvalue;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,216 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_pointer.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_array_dynamic.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeAttribute : public ASTNode {
|
||||
public:
|
||||
explicit ASTNodeAttribute(std::string attribute, std::optional<std::string> value = std::nullopt)
|
||||
: ASTNode(), m_attribute(std::move(attribute)), m_value(std::move(value)) { }
|
||||
|
||||
~ASTNodeAttribute() override = default;
|
||||
|
||||
ASTNodeAttribute(const ASTNodeAttribute &other) : ASTNode(other) {
|
||||
this->m_attribute = other.m_attribute;
|
||||
this->m_value = other.m_value;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeAttribute(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string &getAttribute() const {
|
||||
return this->m_attribute;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::optional<std::string> &getValue() const {
|
||||
return this->m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_attribute;
|
||||
std::optional<std::string> m_value;
|
||||
};
|
||||
|
||||
|
||||
class Attributable {
|
||||
protected:
|
||||
Attributable() = default;
|
||||
|
||||
Attributable(const Attributable &other) {
|
||||
for (auto &attribute : other.m_attributes) {
|
||||
auto copy = attribute->clone();
|
||||
if (auto node = dynamic_cast<ASTNodeAttribute *>(copy.get()))
|
||||
this->m_attributes.push_back(std::unique_ptr<ASTNodeAttribute>(node));
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void addAttribute(std::unique_ptr<ASTNodeAttribute> &&attribute) {
|
||||
this->m_attributes.push_back(std::move(attribute));
|
||||
}
|
||||
|
||||
[[nodiscard]] const auto &getAttributes() const {
|
||||
return this->m_attributes;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool hasAttribute(const std::string &key, bool needsParameter) const {
|
||||
return std::any_of(this->m_attributes.begin(), this->m_attributes.end(), [&](const std::unique_ptr<ASTNodeAttribute> &attribute) {
|
||||
if (attribute->getAttribute() == key) {
|
||||
if (needsParameter && !attribute->getValue().has_value())
|
||||
LogConsole::abortEvaluation(hex::format("attribute '{}' expected a parameter"), attribute);
|
||||
else if (!needsParameter && attribute->getValue().has_value())
|
||||
LogConsole::abortEvaluation(hex::format("attribute '{}' did not expect a parameter "), attribute);
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<std::string> getAttributeValue(const std::string &key) const {
|
||||
auto attribute = std::find_if(this->m_attributes.begin(), this->m_attributes.end(), [&](const std::unique_ptr<ASTNodeAttribute> &attribute) {
|
||||
return attribute->getAttribute() == key;
|
||||
});
|
||||
|
||||
if (attribute != this->m_attributes.end())
|
||||
return (*attribute)->getValue();
|
||||
else
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<ASTNodeAttribute>> m_attributes;
|
||||
};
|
||||
|
||||
|
||||
inline void applyTypeAttributes(Evaluator *evaluator, const ASTNode *node, Pattern *pattern) {
|
||||
auto attributable = dynamic_cast<const Attributable *>(node);
|
||||
if (attributable == nullptr)
|
||||
LogConsole::abortEvaluation("attribute cannot be applied here", node);
|
||||
|
||||
if (attributable->hasAttribute("inline", false)) {
|
||||
auto inlinable = dynamic_cast<Inlinable *>(pattern);
|
||||
|
||||
if (inlinable == nullptr)
|
||||
LogConsole::abortEvaluation("inline attribute can only be applied to nested types", node);
|
||||
else
|
||||
inlinable->setInlined(true);
|
||||
}
|
||||
|
||||
if (auto value = attributable->getAttributeValue("format"); value) {
|
||||
auto functions = evaluator->getCustomFunctions();
|
||||
if (!functions.contains(*value))
|
||||
LogConsole::abortEvaluation(hex::format("cannot find formatter function '{}'", *value), node);
|
||||
|
||||
const auto &function = functions[*value];
|
||||
if (function.parameterCount != 1)
|
||||
LogConsole::abortEvaluation("formatter function needs exactly one parameter", node);
|
||||
|
||||
pattern->setFormatterFunction(function);
|
||||
}
|
||||
|
||||
if (auto value = attributable->getAttributeValue("format_entries"); value) {
|
||||
auto functions = evaluator->getCustomFunctions();
|
||||
if (!functions.contains(*value))
|
||||
LogConsole::abortEvaluation(hex::format("cannot find formatter function '{}'", *value), node);
|
||||
|
||||
const auto &function = functions[*value];
|
||||
if (function.parameterCount != 1)
|
||||
LogConsole::abortEvaluation("formatter function needs exactly one parameter", node);
|
||||
|
||||
auto array = dynamic_cast<PatternArrayDynamic *>(pattern);
|
||||
if (array == nullptr)
|
||||
LogConsole::abortEvaluation("inline_array attribute can only be applied to array types", node);
|
||||
|
||||
for (const auto &entry : array->getEntries()) {
|
||||
entry->setFormatterFunction(function);
|
||||
}
|
||||
}
|
||||
|
||||
if (auto value = attributable->getAttributeValue("transform"); value) {
|
||||
auto functions = evaluator->getCustomFunctions();
|
||||
if (!functions.contains(*value))
|
||||
LogConsole::abortEvaluation(hex::format("cannot find transform function '{}'", *value), node);
|
||||
|
||||
const auto &function = functions[*value];
|
||||
if (function.parameterCount != 1)
|
||||
LogConsole::abortEvaluation("transform function needs exactly one parameter", node);
|
||||
|
||||
pattern->setTransformFunction(function);
|
||||
}
|
||||
|
||||
if (auto value = attributable->getAttributeValue("pointer_base"); value) {
|
||||
auto functions = evaluator->getCustomFunctions();
|
||||
if (!functions.contains(*value))
|
||||
LogConsole::abortEvaluation(hex::format("cannot find pointer base function '{}'", *value), node);
|
||||
|
||||
const auto &function = functions[*value];
|
||||
if (function.parameterCount != 1)
|
||||
LogConsole::abortEvaluation("pointer base function needs exactly one parameter", node);
|
||||
|
||||
if (auto pointerPattern = dynamic_cast<PatternPointer *>(pattern)) {
|
||||
u128 pointerValue = pointerPattern->getPointedAtAddress();
|
||||
|
||||
auto result = function.func(evaluator, { pointerValue });
|
||||
|
||||
if (!result.has_value())
|
||||
LogConsole::abortEvaluation("pointer base function did not return a value", node);
|
||||
|
||||
pointerPattern->setPointedAtAddress(Token::literalToUnsigned(result.value()) + pointerValue);
|
||||
} else {
|
||||
LogConsole::abortEvaluation("pointer_base attribute may only be applied to a pointer");
|
||||
}
|
||||
}
|
||||
|
||||
if (attributable->hasAttribute("hidden", false)) {
|
||||
pattern->setHidden(true);
|
||||
}
|
||||
|
||||
if (!pattern->hasOverriddenColor()) {
|
||||
if (auto colorValue = attributable->getAttributeValue("color"); colorValue) {
|
||||
u32 color = strtoul(colorValue->c_str(), nullptr, 16);
|
||||
pattern->setColor(hex::changeEndianess(color, std::endian::big) >> 8);
|
||||
} else if (auto singleColor = attributable->hasAttribute("single_color", false); singleColor) {
|
||||
pattern->setColor(ContentRegistry::PatternLanguage::getNextColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline void applyVariableAttributes(Evaluator *evaluator, const ASTNode *node, Pattern *pattern) {
|
||||
auto attributable = dynamic_cast<const Attributable *>(node);
|
||||
if (attributable == nullptr)
|
||||
LogConsole::abortEvaluation("attribute cannot be applied here", node);
|
||||
|
||||
auto endOffset = evaluator->dataOffset();
|
||||
evaluator->dataOffset() = pattern->getOffset();
|
||||
ON_SCOPE_EXIT { evaluator->dataOffset() = endOffset; };
|
||||
|
||||
applyTypeAttributes(evaluator, node, pattern);
|
||||
|
||||
if (auto colorValue = attributable->getAttributeValue("color"); colorValue) {
|
||||
u32 color = strtoul(colorValue->c_str(), nullptr, 16);
|
||||
pattern->setColor(hex::changeEndianess(color, std::endian::big) >> 8);
|
||||
} else if (auto singleColor = attributable->hasAttribute("single_color", false); singleColor) {
|
||||
pattern->setColor(ContentRegistry::PatternLanguage::getNextColor());
|
||||
}
|
||||
|
||||
if (auto value = attributable->getAttributeValue("name"); value) {
|
||||
pattern->setDisplayName(*value);
|
||||
}
|
||||
|
||||
if (auto value = attributable->getAttributeValue("comment"); value) {
|
||||
pattern->setComment(*value);
|
||||
}
|
||||
|
||||
if (attributable->hasAttribute("no_unique_address", false)) {
|
||||
endOffset -= pattern->getSize();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,85 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_attribute.hpp>
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_bitfield.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeBitfield : public ASTNode,
|
||||
public Attributable {
|
||||
public:
|
||||
ASTNodeBitfield() : ASTNode() { }
|
||||
|
||||
ASTNodeBitfield(const ASTNodeBitfield &other) : ASTNode(other), Attributable(other) {
|
||||
for (const auto &[name, entry] : other.getEntries())
|
||||
this->m_entries.emplace_back(name, entry->clone());
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeBitfield(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::pair<std::string, std::unique_ptr<ASTNode>>> &getEntries() const { return this->m_entries; }
|
||||
void addEntry(const std::string &name, std::unique_ptr<ASTNode> &&size) { this->m_entries.emplace_back(name, std::move(size)); }
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
auto pattern = std::make_unique<PatternBitfield>(evaluator, evaluator->dataOffset(), 0);
|
||||
|
||||
size_t bitOffset = 0;
|
||||
std::vector<std::shared_ptr<Pattern>> fields;
|
||||
|
||||
BitfieldOrder order = evaluator->getBitfieldOrder();
|
||||
if (this->hasAttribute("left_to_right", false))
|
||||
order = BitfieldOrder::LeftToRight;
|
||||
else if (this->hasAttribute("right_to_left", false))
|
||||
order = BitfieldOrder::RightToLeft;
|
||||
|
||||
std::vector<std::pair<std::string, ASTNode *>> entries;
|
||||
for (const auto &[name, entry] : this->m_entries)
|
||||
entries.push_back({ name, entry.get() });
|
||||
|
||||
if (order == BitfieldOrder::LeftToRight)
|
||||
std::reverse(entries.begin(), entries.end());
|
||||
|
||||
evaluator->pushScope(pattern.get(), fields);
|
||||
ON_SCOPE_EXIT {
|
||||
evaluator->popScope();
|
||||
};
|
||||
|
||||
for (auto &[name, bitSizeNode] : entries) {
|
||||
auto literal = bitSizeNode->evaluate(evaluator);
|
||||
|
||||
u8 bitSize = std::visit(overloaded {
|
||||
[this](const std::string &) -> u8 { LogConsole::abortEvaluation("bitfield field size cannot be a string", this); },
|
||||
[this](const std::shared_ptr<Pattern> &) -> u8 { LogConsole::abortEvaluation("bitfield field size cannot be a custom type", this); },
|
||||
[](auto &&offset) -> u8 { return static_cast<u8>(offset); } },
|
||||
dynamic_cast<ASTNodeLiteral *>(literal.get())->getValue());
|
||||
|
||||
// If a field is named padding, it was created through a padding expression and only advances the bit position
|
||||
if (name != "padding") {
|
||||
auto field = std::make_unique<PatternBitfieldField>(evaluator, evaluator->dataOffset(), bitOffset, bitSize, pattern.get());
|
||||
field->setVariableName(name);
|
||||
|
||||
fields.push_back(std::move(field));
|
||||
}
|
||||
|
||||
bitOffset += bitSize;
|
||||
}
|
||||
|
||||
pattern->setSize((bitOffset + 7) / 8);
|
||||
pattern->setFields(std::move(fields));
|
||||
|
||||
evaluator->dataOffset() += pattern->getSize();
|
||||
|
||||
applyTypeAttributes(evaluator, this, pattern.get());
|
||||
|
||||
return hex::moveToVector<std::unique_ptr<Pattern>>(std::move(pattern));
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::pair<std::string, std::unique_ptr<ASTNode>>> m_entries;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_padding.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_unsigned.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_signed.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_float.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_boolean.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_character.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_wide_character.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_string.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeBuiltinType : public ASTNode {
|
||||
public:
|
||||
constexpr explicit ASTNodeBuiltinType(Token::ValueType type)
|
||||
: ASTNode(), m_type(type) { }
|
||||
|
||||
[[nodiscard]] constexpr const auto &getType() const { return this->m_type; }
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeBuiltinType(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
auto offset = evaluator->dataOffset();
|
||||
auto size = Token::getTypeSize(this->m_type);
|
||||
|
||||
evaluator->dataOffset() += size;
|
||||
|
||||
std::unique_ptr<Pattern> pattern;
|
||||
if (Token::isUnsigned(this->m_type))
|
||||
pattern = std::unique_ptr<Pattern>(new PatternUnsigned(evaluator, offset, size));
|
||||
else if (Token::isSigned(this->m_type))
|
||||
pattern = std::unique_ptr<Pattern>(new PatternSigned(evaluator, offset, size));
|
||||
else if (Token::isFloatingPoint(this->m_type))
|
||||
pattern = std::unique_ptr<Pattern>(new PatternFloat(evaluator, offset, size));
|
||||
else if (this->m_type == Token::ValueType::Boolean)
|
||||
pattern = std::unique_ptr<Pattern>(new PatternBoolean(evaluator, offset));
|
||||
else if (this->m_type == Token::ValueType::Character)
|
||||
pattern = std::unique_ptr<Pattern>(new PatternCharacter(evaluator, offset));
|
||||
else if (this->m_type == Token::ValueType::Character16)
|
||||
pattern = std::unique_ptr<Pattern>(new PatternWideCharacter(evaluator, offset));
|
||||
else if (this->m_type == Token::ValueType::Padding)
|
||||
pattern = std::unique_ptr<Pattern>(new PatternPadding(evaluator, offset, 1));
|
||||
else if (this->m_type == Token::ValueType::String)
|
||||
pattern = std::unique_ptr<Pattern>(new PatternString(evaluator, offset, 1));
|
||||
else if (this->m_type == Token::ValueType::Auto)
|
||||
return {};
|
||||
else
|
||||
LogConsole::abortEvaluation("invalid built-in type", this);
|
||||
|
||||
pattern->setTypeName(Token::getTypeName(this->m_type));
|
||||
|
||||
return hex::moveToVector(std::move(pattern));
|
||||
}
|
||||
|
||||
private:
|
||||
const Token::ValueType m_type;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeCast : public ASTNode {
|
||||
public:
|
||||
ASTNodeCast(std::unique_ptr<ASTNode> &&value, std::unique_ptr<ASTNode> &&type) : m_value(std::move(value)), m_type(std::move(type)) { }
|
||||
|
||||
ASTNodeCast(const ASTNodeCast &other) : ASTNode(other) {
|
||||
this->m_value = other.m_value->clone();
|
||||
this->m_type = other.m_type->clone();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeCast(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> evaluate(Evaluator *evaluator) const override {
|
||||
auto evaluatedValue = this->m_value->evaluate(evaluator);
|
||||
auto evaluatedType = this->m_type->evaluate(evaluator);
|
||||
|
||||
auto literal = dynamic_cast<ASTNodeLiteral *>(evaluatedValue.get());
|
||||
auto type = dynamic_cast<ASTNodeBuiltinType *>(evaluatedType.get())->getType();
|
||||
|
||||
auto startOffset = evaluator->dataOffset();
|
||||
|
||||
auto typePatterns = this->m_type->createPatterns(evaluator);
|
||||
auto &typePattern = typePatterns.front();
|
||||
|
||||
return std::unique_ptr<ASTNode>(std::visit(overloaded {
|
||||
[&, this](const std::shared_ptr<Pattern> &value) -> ASTNode * { LogConsole::abortEvaluation(hex::format("cannot cast custom type '{}' to '{}'", value->getTypeName(), Token::getTypeName(type)), this); },
|
||||
[&, this](const std::string &) -> ASTNode * { LogConsole::abortEvaluation(hex::format("cannot cast string to '{}'", Token::getTypeName(type)), this); },
|
||||
[&, this](auto &&value) -> ASTNode * {
|
||||
auto endianAdjustedValue = hex::changeEndianess(value, typePattern->getSize(), typePattern->getEndian());
|
||||
switch (type) {
|
||||
case Token::ValueType::Unsigned8Bit:
|
||||
return new ASTNodeLiteral(u128(u8(endianAdjustedValue)));
|
||||
case Token::ValueType::Unsigned16Bit:
|
||||
return new ASTNodeLiteral(u128(u16(endianAdjustedValue)));
|
||||
case Token::ValueType::Unsigned32Bit:
|
||||
return new ASTNodeLiteral(u128(u32(endianAdjustedValue)));
|
||||
case Token::ValueType::Unsigned64Bit:
|
||||
return new ASTNodeLiteral(u128(u64(endianAdjustedValue)));
|
||||
case Token::ValueType::Unsigned128Bit:
|
||||
return new ASTNodeLiteral(u128(endianAdjustedValue));
|
||||
case Token::ValueType::Signed8Bit:
|
||||
return new ASTNodeLiteral(i128(i8(endianAdjustedValue)));
|
||||
case Token::ValueType::Signed16Bit:
|
||||
return new ASTNodeLiteral(i128(i16(endianAdjustedValue)));
|
||||
case Token::ValueType::Signed32Bit:
|
||||
return new ASTNodeLiteral(i128(i32(endianAdjustedValue)));
|
||||
case Token::ValueType::Signed64Bit:
|
||||
return new ASTNodeLiteral(i128(i64(endianAdjustedValue)));
|
||||
case Token::ValueType::Signed128Bit:
|
||||
return new ASTNodeLiteral(i128(endianAdjustedValue));
|
||||
case Token::ValueType::Float:
|
||||
return new ASTNodeLiteral(double(float(endianAdjustedValue)));
|
||||
case Token::ValueType::Double:
|
||||
return new ASTNodeLiteral(double(endianAdjustedValue));
|
||||
case Token::ValueType::Character:
|
||||
return new ASTNodeLiteral(char(endianAdjustedValue));
|
||||
case Token::ValueType::Character16:
|
||||
return new ASTNodeLiteral(u128(char16_t(endianAdjustedValue)));
|
||||
case Token::ValueType::Boolean:
|
||||
return new ASTNodeLiteral(bool(endianAdjustedValue));
|
||||
case Token::ValueType::String:
|
||||
{
|
||||
std::string string(sizeof(value), '\x00');
|
||||
std::memcpy(string.data(), &value, string.size());
|
||||
hex::trim(string);
|
||||
|
||||
if (typePattern->getEndian() != std::endian::native)
|
||||
std::reverse(string.begin(), string.end());
|
||||
|
||||
return new ASTNodeLiteral(string);
|
||||
}
|
||||
default:
|
||||
LogConsole::abortEvaluation(hex::format("cannot cast value to '{}'", Token::getTypeName(type)), this);
|
||||
}
|
||||
},
|
||||
},
|
||||
literal->getValue()));
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<ASTNode> m_value;
|
||||
std::unique_ptr<ASTNode> m_type;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeCompoundStatement : public ASTNode {
|
||||
public:
|
||||
explicit ASTNodeCompoundStatement(std::vector<std::unique_ptr<ASTNode>> &&statements, bool newScope = false) : m_statements(std::move(statements)), m_newScope(newScope) {
|
||||
}
|
||||
|
||||
ASTNodeCompoundStatement(const ASTNodeCompoundStatement &other) : ASTNode(other) {
|
||||
for (const auto &statement : other.m_statements) {
|
||||
this->m_statements.push_back(statement->clone());
|
||||
}
|
||||
|
||||
this->m_newScope = other.m_newScope;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeCompoundStatement(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> evaluate(Evaluator *evaluator) const override {
|
||||
std::unique_ptr<ASTNode> result = nullptr;
|
||||
|
||||
for (const auto &statement : this->m_statements) {
|
||||
result = statement->evaluate(evaluator);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
std::vector<std::unique_ptr<Pattern>> result;
|
||||
|
||||
for (const auto &statement : this->m_statements) {
|
||||
auto patterns = statement->createPatterns(evaluator);
|
||||
std::move(patterns.begin(), patterns.end(), std::back_inserter(result));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
FunctionResult execute(Evaluator *evaluator) const override {
|
||||
FunctionResult result;
|
||||
|
||||
auto variables = *evaluator->getScope(0).scope;
|
||||
u32 startVariableCount = variables.size();
|
||||
|
||||
if (this->m_newScope) {
|
||||
evaluator->pushScope(nullptr, variables);
|
||||
}
|
||||
|
||||
for (const auto &statement : this->m_statements) {
|
||||
result = statement->execute(evaluator);
|
||||
if (evaluator->getCurrentControlFlowStatement() != ControlFlowStatement::None)
|
||||
return result;
|
||||
}
|
||||
|
||||
if (this->m_newScope) {
|
||||
i64 stackSize = evaluator->getStack().size();
|
||||
for (u32 i = startVariableCount; i < variables.size(); i++) {
|
||||
stackSize--;
|
||||
}
|
||||
if (stackSize < 0) LogConsole::abortEvaluation("stack pointer underflow!", this);
|
||||
evaluator->getStack().resize(stackSize);
|
||||
|
||||
evaluator->popScope();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public:
|
||||
std::vector<std::unique_ptr<ASTNode>> m_statements;
|
||||
bool m_newScope = false;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,92 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeConditionalStatement : public ASTNode {
|
||||
public:
|
||||
explicit ASTNodeConditionalStatement(std::unique_ptr<ASTNode> condition, std::vector<std::unique_ptr<ASTNode>> &&trueBody, std::vector<std::unique_ptr<ASTNode>> &&falseBody)
|
||||
: ASTNode(), m_condition(std::move(condition)), m_trueBody(std::move(trueBody)), m_falseBody(std::move(falseBody)) { }
|
||||
|
||||
|
||||
ASTNodeConditionalStatement(const ASTNodeConditionalStatement &other) : ASTNode(other) {
|
||||
this->m_condition = other.m_condition->clone();
|
||||
|
||||
for (auto &statement : other.m_trueBody)
|
||||
this->m_trueBody.push_back(statement->clone());
|
||||
for (auto &statement : other.m_falseBody)
|
||||
this->m_falseBody.push_back(statement->clone());
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeConditionalStatement(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
auto &scope = *evaluator->getScope(0).scope;
|
||||
auto &body = evaluateCondition(evaluator) ? this->m_trueBody : this->m_falseBody;
|
||||
|
||||
for (auto &node : body) {
|
||||
auto newPatterns = node->createPatterns(evaluator);
|
||||
for (auto &pattern : newPatterns) {
|
||||
scope.push_back(std::move(pattern));
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::unique_ptr<ASTNode> &getCondition() {
|
||||
return this->m_condition;
|
||||
}
|
||||
|
||||
FunctionResult execute(Evaluator *evaluator) const override {
|
||||
auto &body = evaluateCondition(evaluator) ? this->m_trueBody : this->m_falseBody;
|
||||
|
||||
auto variables = *evaluator->getScope(0).scope;
|
||||
auto parameterPack = evaluator->getScope(0).parameterPack;
|
||||
|
||||
u32 startVariableCount = variables.size();
|
||||
ON_SCOPE_EXIT {
|
||||
i64 stackSize = evaluator->getStack().size();
|
||||
for (u32 i = startVariableCount; i < variables.size(); i++) {
|
||||
stackSize--;
|
||||
}
|
||||
if (stackSize < 0) LogConsole::abortEvaluation("stack pointer underflow!", this);
|
||||
evaluator->getStack().resize(stackSize);
|
||||
};
|
||||
|
||||
evaluator->pushScope(nullptr, variables);
|
||||
evaluator->getScope(0).parameterPack = parameterPack;
|
||||
ON_SCOPE_EXIT {
|
||||
evaluator->popScope();
|
||||
};
|
||||
|
||||
for (auto &statement : body) {
|
||||
auto result = statement->execute(evaluator);
|
||||
if (auto ctrlStatement = evaluator->getCurrentControlFlowStatement(); ctrlStatement != ControlFlowStatement::None) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] bool evaluateCondition(Evaluator *evaluator) const {
|
||||
const auto node = this->m_condition->evaluate(evaluator);
|
||||
const auto literal = dynamic_cast<ASTNodeLiteral *>(node.get());
|
||||
|
||||
return std::visit(overloaded {
|
||||
[](const std::string &value) -> bool { return !value.empty(); },
|
||||
[this](Pattern *const &) -> bool { LogConsole::abortEvaluation("cannot cast custom type to bool", this); },
|
||||
[](auto &&value) -> bool { return value != 0; } },
|
||||
literal->getValue());
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> m_condition;
|
||||
std::vector<std::unique_ptr<ASTNode>> m_trueBody, m_falseBody;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeControlFlowStatement : public ASTNode {
|
||||
public:
|
||||
explicit ASTNodeControlFlowStatement(ControlFlowStatement type, std::unique_ptr<ASTNode> &&rvalue) : m_type(type), m_rvalue(std::move(rvalue)) {
|
||||
}
|
||||
|
||||
ASTNodeControlFlowStatement(const ASTNodeControlFlowStatement &other) : ASTNode(other) {
|
||||
this->m_type = other.m_type;
|
||||
|
||||
if (other.m_rvalue != nullptr)
|
||||
this->m_rvalue = other.m_rvalue->clone();
|
||||
else
|
||||
this->m_rvalue = nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeControlFlowStatement(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::unique_ptr<ASTNode> &getReturnValue() const {
|
||||
return this->m_rvalue;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
|
||||
this->execute(evaluator);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
FunctionResult execute(Evaluator *evaluator) const override {
|
||||
auto returnValue = this->m_rvalue->evaluate(evaluator);
|
||||
|
||||
auto literal = dynamic_cast<ASTNodeLiteral *>(returnValue.get());
|
||||
|
||||
evaluator->setCurrentControlFlowStatement(this->m_type);
|
||||
|
||||
if (literal == nullptr)
|
||||
return std::nullopt;
|
||||
else
|
||||
return literal->getValue();
|
||||
}
|
||||
|
||||
private:
|
||||
ControlFlowStatement m_type;
|
||||
std::unique_ptr<ASTNode> m_rvalue;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_attribute.hpp>
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_enum.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeEnum : public ASTNode,
|
||||
public Attributable {
|
||||
public:
|
||||
explicit ASTNodeEnum(std::unique_ptr<ASTNode> &&underlyingType) : ASTNode(), m_underlyingType(std::move(underlyingType)) { }
|
||||
|
||||
ASTNodeEnum(const ASTNodeEnum &other) : ASTNode(other), Attributable(other) {
|
||||
for (const auto &[name, entry] : other.getEntries())
|
||||
this->m_entries.emplace(name, entry->clone());
|
||||
this->m_underlyingType = other.m_underlyingType->clone();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeEnum(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
auto pattern = std::make_unique<PatternEnum>(evaluator, evaluator->dataOffset(), 0);
|
||||
|
||||
std::vector<std::pair<Token::Literal, std::string>> enumEntries;
|
||||
for (const auto &[name, value] : this->m_entries) {
|
||||
const auto node = value->evaluate(evaluator);
|
||||
auto literal = dynamic_cast<ASTNodeLiteral *>(node.get());
|
||||
|
||||
enumEntries.emplace_back(literal->getValue(), name);
|
||||
}
|
||||
|
||||
pattern->setEnumValues(enumEntries);
|
||||
|
||||
const auto nodes = this->m_underlyingType->createPatterns(evaluator);
|
||||
auto &underlying = nodes.front();
|
||||
|
||||
pattern->setSize(underlying->getSize());
|
||||
pattern->setEndian(underlying->getEndian());
|
||||
|
||||
applyTypeAttributes(evaluator, this, pattern.get());
|
||||
|
||||
return hex::moveToVector<std::unique_ptr<Pattern>>(std::move(pattern));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::map<std::string, std::unique_ptr<ASTNode>> &getEntries() const { return this->m_entries; }
|
||||
void addEntry(const std::string &name, std::unique_ptr<ASTNode> &&expression) { this->m_entries.insert({ name, std::move(expression) }); }
|
||||
|
||||
[[nodiscard]] const std::unique_ptr<ASTNode> &getUnderlyingType() { return this->m_underlyingType; }
|
||||
|
||||
private:
|
||||
std::map<std::string, std::unique_ptr<ASTNode>> m_entries;
|
||||
std::unique_ptr<ASTNode> m_underlyingType;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,129 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_parameter_pack.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_mathematical_expression.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_literal.hpp>
|
||||
|
||||
#include <thread>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeFunctionCall : public ASTNode {
|
||||
public:
|
||||
explicit ASTNodeFunctionCall(std::string functionName, std::vector<std::unique_ptr<ASTNode>> &¶ms)
|
||||
: ASTNode(), m_functionName(std::move(functionName)), m_params(std::move(params)) { }
|
||||
|
||||
ASTNodeFunctionCall(const ASTNodeFunctionCall &other) : ASTNode(other) {
|
||||
this->m_functionName = other.m_functionName;
|
||||
|
||||
for (auto ¶m : other.m_params)
|
||||
this->m_params.push_back(param->clone());
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeFunctionCall(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string &getFunctionName() {
|
||||
return this->m_functionName;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<ASTNode>> &getParams() const {
|
||||
return this->m_params;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
|
||||
this->execute(evaluator);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> evaluate(Evaluator *evaluator) const override {
|
||||
auto startOffset = evaluator->dataOffset();
|
||||
ON_SCOPE_EXIT { evaluator->dataOffset() = startOffset; };
|
||||
|
||||
std::vector<Token::Literal> evaluatedParams;
|
||||
for (auto ¶m : this->m_params) {
|
||||
const auto expression = param->evaluate(evaluator)->evaluate(evaluator);
|
||||
|
||||
if (auto literal = dynamic_cast<ASTNodeLiteral *>(expression.get())) {
|
||||
evaluatedParams.push_back(literal->getValue());
|
||||
} else if (auto parameterPack = dynamic_cast<ASTNodeParameterPack *>(expression.get())) {
|
||||
for (auto &value : parameterPack->getValues()) {
|
||||
evaluatedParams.push_back(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto &customFunctions = evaluator->getCustomFunctions();
|
||||
auto functions = ContentRegistry::PatternLanguage::getFunctions();
|
||||
|
||||
for (auto &func : customFunctions)
|
||||
functions.insert(func);
|
||||
|
||||
if (!functions.contains(this->m_functionName)) {
|
||||
if (this->m_functionName.starts_with("std::")) {
|
||||
evaluator->getConsole().log(LogConsole::Level::Warning, "This function might be part of the standard library.\nYou can install the standard library though\nthe Content Store found under Help -> Content Store and then\ninclude the correct file.");
|
||||
}
|
||||
|
||||
LogConsole::abortEvaluation(hex::format("call to unknown function '{}'", this->m_functionName), this);
|
||||
}
|
||||
|
||||
auto function = functions[this->m_functionName];
|
||||
if (function.parameterCount == ContentRegistry::PatternLanguage::UnlimitedParameters) {
|
||||
; // Don't check parameter count
|
||||
} else if (function.parameterCount & ContentRegistry::PatternLanguage::LessParametersThan) {
|
||||
if (evaluatedParams.size() >= (function.parameterCount & ~ContentRegistry::PatternLanguage::LessParametersThan))
|
||||
LogConsole::abortEvaluation(hex::format("too many parameters for function '{0}'. Expected less than {1}", this->m_functionName, function.parameterCount & ~ContentRegistry::PatternLanguage::LessParametersThan), this);
|
||||
} else if (function.parameterCount & ContentRegistry::PatternLanguage::MoreParametersThan) {
|
||||
if (evaluatedParams.size() <= (function.parameterCount & ~ContentRegistry::PatternLanguage::MoreParametersThan))
|
||||
LogConsole::abortEvaluation(hex::format("too few parameters for function '{0}'. Expected more than {1}", this->m_functionName, function.parameterCount & ~ContentRegistry::PatternLanguage::MoreParametersThan), this);
|
||||
} else if (function.parameterCount & ContentRegistry::PatternLanguage::ExactlyOrMoreParametersThan) {
|
||||
if (evaluatedParams.size() < (function.parameterCount & ~ContentRegistry::PatternLanguage::ExactlyOrMoreParametersThan))
|
||||
LogConsole::abortEvaluation(hex::format("too few parameters for function '{0}'. Expected more than {1}", this->m_functionName, (function.parameterCount - 1) & ~ContentRegistry::PatternLanguage::ExactlyOrMoreParametersThan), this);
|
||||
} else if (function.parameterCount != evaluatedParams.size()) {
|
||||
LogConsole::abortEvaluation(hex::format("invalid number of parameters for function '{0}'. Expected {1}", this->m_functionName, function.parameterCount), this);
|
||||
}
|
||||
|
||||
try {
|
||||
if (function.dangerous && evaluator->getDangerousFunctionPermission() != DangerousFunctionPermission::Allow) {
|
||||
evaluator->dangerousFunctionCalled();
|
||||
|
||||
while (evaluator->getDangerousFunctionPermission() == DangerousFunctionPermission::Ask) {
|
||||
using namespace std::literals::chrono_literals;
|
||||
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
|
||||
if (evaluator->getDangerousFunctionPermission() == DangerousFunctionPermission::Deny) {
|
||||
LogConsole::abortEvaluation(hex::format("calling of dangerous function '{}' is not allowed", this->m_functionName), this);
|
||||
}
|
||||
}
|
||||
|
||||
auto result = function.func(evaluator, evaluatedParams);
|
||||
|
||||
if (result.has_value())
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeLiteral(std::move(result.value())));
|
||||
else
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeMathematicalExpression(nullptr, nullptr, Token::Operator::Plus));
|
||||
} catch (std::string &error) {
|
||||
LogConsole::abortEvaluation(error, this);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
FunctionResult execute(Evaluator *evaluator) const override {
|
||||
(void)this->evaluate(evaluator);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_functionName;
|
||||
std::vector<std::unique_ptr<ASTNode>> m_params;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeFunctionDefinition : public ASTNode {
|
||||
public:
|
||||
ASTNodeFunctionDefinition(std::string name, std::vector<std::pair<std::string, std::unique_ptr<ASTNode>>> &¶ms, std::vector<std::unique_ptr<ASTNode>> &&body, std::optional<std::string> parameterPack)
|
||||
: m_name(std::move(name)), m_params(std::move(params)), m_body(std::move(body)), m_parameterPack(std::move(parameterPack)) {
|
||||
}
|
||||
|
||||
ASTNodeFunctionDefinition(const ASTNodeFunctionDefinition &other) : ASTNode(other) {
|
||||
this->m_name = other.m_name;
|
||||
|
||||
for (const auto &[name, type] : other.m_params) {
|
||||
this->m_params.emplace_back(name, type->clone());
|
||||
}
|
||||
|
||||
for (auto &statement : other.m_body) {
|
||||
this->m_body.push_back(statement->clone());
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeFunctionDefinition(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string &getName() const {
|
||||
return this->m_name;
|
||||
}
|
||||
|
||||
[[nodiscard]] const auto &getParams() const {
|
||||
return this->m_params;
|
||||
}
|
||||
|
||||
[[nodiscard]] const auto &getBody() const {
|
||||
return this->m_body;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> evaluate(Evaluator *evaluator) const override {
|
||||
|
||||
size_t paramCount = this->m_params.size();
|
||||
|
||||
if (this->m_parameterPack.has_value())
|
||||
paramCount |= ContentRegistry::PatternLanguage::ExactlyOrMoreParametersThan;
|
||||
|
||||
evaluator->addCustomFunction(this->m_name, paramCount, [this](Evaluator *ctx, const std::vector<Token::Literal> ¶ms) -> std::optional<Token::Literal> {
|
||||
std::vector<std::shared_ptr<Pattern>> variables;
|
||||
|
||||
auto startOffset = ctx->dataOffset();
|
||||
ctx->pushScope(nullptr, variables);
|
||||
ON_SCOPE_EXIT {
|
||||
ctx->popScope();
|
||||
ctx->dataOffset() = startOffset;
|
||||
};
|
||||
|
||||
if (this->m_parameterPack.has_value()) {
|
||||
std::vector<Token::Literal> parameterPackContent;
|
||||
for (u32 paramIndex = this->m_params.size(); paramIndex < params.size(); paramIndex++)
|
||||
parameterPackContent.push_back(params[paramIndex]);
|
||||
|
||||
ctx->createParameterPack(this->m_parameterPack.value(), parameterPackContent);
|
||||
}
|
||||
|
||||
for (u32 paramIndex = 0; paramIndex < this->m_params.size(); paramIndex++) {
|
||||
const auto &[name, type] = this->m_params[paramIndex];
|
||||
|
||||
ctx->createVariable(name, type.get(), params[paramIndex]);
|
||||
ctx->setVariable(name, params[paramIndex]);
|
||||
}
|
||||
|
||||
for (auto &statement : this->m_body) {
|
||||
auto result = statement->execute(ctx);
|
||||
|
||||
if (ctx->getCurrentControlFlowStatement() != ControlFlowStatement::None) {
|
||||
switch (ctx->getCurrentControlFlowStatement()) {
|
||||
case ControlFlowStatement::Break:
|
||||
LogConsole::abortEvaluation("break statement not within a loop", statement);
|
||||
case ControlFlowStatement::Continue:
|
||||
LogConsole::abortEvaluation("continue statement not within a loop", statement);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ctx->setCurrentControlFlowStatement(ControlFlowStatement::None);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::vector<std::pair<std::string, std::unique_ptr<ASTNode>>> m_params;
|
||||
std::vector<std::unique_ptr<ASTNode>> m_body;
|
||||
std::optional<std::string> m_parameterPack;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeLiteral : public ASTNode {
|
||||
public:
|
||||
explicit ASTNodeLiteral(Token::Literal literal) : ASTNode(), m_literal(std::move(literal)) { }
|
||||
|
||||
ASTNodeLiteral(const ASTNodeLiteral &) = default;
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeLiteral(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] const auto &getValue() const {
|
||||
return this->m_literal;
|
||||
}
|
||||
|
||||
private:
|
||||
Token::Literal m_literal;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,208 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
#define FLOAT_BIT_OPERATION(name) \
|
||||
auto name(hex::floating_point auto left, auto right) const { \
|
||||
LogConsole::abortEvaluation("invalid floating point operation", this); \
|
||||
return 0; \
|
||||
} \
|
||||
auto name(auto left, hex::floating_point auto right) const { \
|
||||
LogConsole::abortEvaluation("invalid floating point operation", this); \
|
||||
return 0; \
|
||||
} \
|
||||
auto name(hex::floating_point auto left, hex::floating_point auto right) const { \
|
||||
LogConsole::abortEvaluation("invalid floating point operation", this); \
|
||||
return 0; \
|
||||
} \
|
||||
auto name(hex::integral auto left, hex::integral auto right) const
|
||||
|
||||
class ASTNodeMathematicalExpression : public ASTNode {
|
||||
|
||||
FLOAT_BIT_OPERATION(shiftLeft) {
|
||||
return left << right;
|
||||
}
|
||||
|
||||
FLOAT_BIT_OPERATION(shiftRight) {
|
||||
return left >> right;
|
||||
}
|
||||
|
||||
FLOAT_BIT_OPERATION(bitAnd) {
|
||||
return left & right;
|
||||
}
|
||||
|
||||
FLOAT_BIT_OPERATION(bitOr) {
|
||||
return left | right;
|
||||
}
|
||||
|
||||
FLOAT_BIT_OPERATION(bitXor) {
|
||||
return left ^ right;
|
||||
}
|
||||
|
||||
FLOAT_BIT_OPERATION(bitNot) {
|
||||
return ~right;
|
||||
}
|
||||
|
||||
FLOAT_BIT_OPERATION(modulus) {
|
||||
return left % right;
|
||||
}
|
||||
|
||||
#undef FLOAT_BIT_OPERATION
|
||||
public:
|
||||
ASTNodeMathematicalExpression(std::unique_ptr<ASTNode> &&left, std::unique_ptr<ASTNode> &&right, Token::Operator op)
|
||||
: ASTNode(), m_left(std::move(left)), m_right(std::move(right)), m_operator(op) { }
|
||||
|
||||
ASTNodeMathematicalExpression(const ASTNodeMathematicalExpression &other) : ASTNode(other) {
|
||||
this->m_operator = other.m_operator;
|
||||
this->m_left = other.m_left->clone();
|
||||
this->m_right = other.m_right->clone();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeMathematicalExpression(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> evaluate(Evaluator *evaluator) const override {
|
||||
if (this->getLeftOperand() == nullptr || this->getRightOperand() == nullptr)
|
||||
LogConsole::abortEvaluation("attempted to use void expression in mathematical expression", this);
|
||||
|
||||
auto leftValue = this->getLeftOperand()->evaluate(evaluator);
|
||||
auto rightValue = this->getRightOperand()->evaluate(evaluator);
|
||||
|
||||
auto *left = dynamic_cast<ASTNodeLiteral *>(leftValue.get());
|
||||
auto *right = dynamic_cast<ASTNodeLiteral *>(rightValue.get());
|
||||
|
||||
return std::unique_ptr<ASTNode>(std::visit(overloaded {
|
||||
// TODO: :notlikethis:
|
||||
[this](u128 left, const std::shared_ptr<Pattern> &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](i128 left, const std::shared_ptr<Pattern> &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](double left, const std::shared_ptr<Pattern> &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](char left, const std::shared_ptr<Pattern> &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](bool left, const std::shared_ptr<Pattern> &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](const std::string &left, const std::shared_ptr<Pattern> &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](const std::shared_ptr<Pattern> &left, u128 right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](const std::shared_ptr<Pattern> &left, i128 right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](const std::shared_ptr<Pattern> &left, double right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](const std::shared_ptr<Pattern> &left, char right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](const std::shared_ptr<Pattern> &left, bool right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](const std::shared_ptr<Pattern> &left, const std::string &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](const std::shared_ptr<Pattern> &left, const std::shared_ptr<Pattern> &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
|
||||
[this](auto &&left, const std::string &right) -> ASTNode * { LogConsole::abortEvaluation("invalid operand used in mathematical expression", this); },
|
||||
[this](const std::string &left, auto &&right) -> ASTNode * {
|
||||
switch (this->getOperator()) {
|
||||
case Token::Operator::Star:
|
||||
{
|
||||
std::string result;
|
||||
for (auto i = 0; i < right; i++)
|
||||
result += left;
|
||||
return new ASTNodeLiteral(result);
|
||||
}
|
||||
default:
|
||||
LogConsole::abortEvaluation("invalid operand used in mathematical expression", this);
|
||||
}
|
||||
},
|
||||
[this](const std::string &left, const std::string &right) -> ASTNode * {
|
||||
switch (this->getOperator()) {
|
||||
case Token::Operator::Plus:
|
||||
return new ASTNodeLiteral(left + right);
|
||||
case Token::Operator::BoolEquals:
|
||||
return new ASTNodeLiteral(left == right);
|
||||
case Token::Operator::BoolNotEquals:
|
||||
return new ASTNodeLiteral(left != right);
|
||||
case Token::Operator::BoolGreaterThan:
|
||||
return new ASTNodeLiteral(left > right);
|
||||
case Token::Operator::BoolLessThan:
|
||||
return new ASTNodeLiteral(left < right);
|
||||
case Token::Operator::BoolGreaterThanOrEquals:
|
||||
return new ASTNodeLiteral(left >= right);
|
||||
case Token::Operator::BoolLessThanOrEquals:
|
||||
return new ASTNodeLiteral(left <= right);
|
||||
default:
|
||||
LogConsole::abortEvaluation("invalid operand used in mathematical expression", this);
|
||||
}
|
||||
},
|
||||
[this](const std::string &left, char right) -> ASTNode * {
|
||||
switch (this->getOperator()) {
|
||||
case Token::Operator::Plus:
|
||||
return new ASTNodeLiteral(left + right);
|
||||
default:
|
||||
LogConsole::abortEvaluation("invalid operand used in mathematical expression", this);
|
||||
}
|
||||
},
|
||||
[this](char left, const std::string &right) -> ASTNode * {
|
||||
switch (this->getOperator()) {
|
||||
case Token::Operator::Plus:
|
||||
return new ASTNodeLiteral(left + right);
|
||||
default:
|
||||
LogConsole::abortEvaluation("invalid operand used in mathematical expression", this);
|
||||
}
|
||||
},
|
||||
[this](auto &&left, auto &&right) -> ASTNode * {
|
||||
switch (this->getOperator()) {
|
||||
case Token::Operator::Plus:
|
||||
return new ASTNodeLiteral(left + right);
|
||||
case Token::Operator::Minus:
|
||||
return new ASTNodeLiteral(left - right);
|
||||
case Token::Operator::Star:
|
||||
return new ASTNodeLiteral(left * right);
|
||||
case Token::Operator::Slash:
|
||||
if (right == 0) LogConsole::abortEvaluation("division by zero!", this);
|
||||
return new ASTNodeLiteral(left / right);
|
||||
case Token::Operator::Percent:
|
||||
if (right == 0) LogConsole::abortEvaluation("division by zero!", this);
|
||||
return new ASTNodeLiteral(modulus(left, right));
|
||||
case Token::Operator::ShiftLeft:
|
||||
return new ASTNodeLiteral(shiftLeft(left, right));
|
||||
case Token::Operator::ShiftRight:
|
||||
return new ASTNodeLiteral(shiftRight(left, right));
|
||||
case Token::Operator::BitAnd:
|
||||
return new ASTNodeLiteral(bitAnd(left, right));
|
||||
case Token::Operator::BitXor:
|
||||
return new ASTNodeLiteral(bitXor(left, right));
|
||||
case Token::Operator::BitOr:
|
||||
return new ASTNodeLiteral(bitOr(left, right));
|
||||
case Token::Operator::BitNot:
|
||||
return new ASTNodeLiteral(bitNot(left, right));
|
||||
case Token::Operator::BoolEquals:
|
||||
return new ASTNodeLiteral(bool(left == right));
|
||||
case Token::Operator::BoolNotEquals:
|
||||
return new ASTNodeLiteral(bool(left != right));
|
||||
case Token::Operator::BoolGreaterThan:
|
||||
return new ASTNodeLiteral(bool(left > right));
|
||||
case Token::Operator::BoolLessThan:
|
||||
return new ASTNodeLiteral(bool(left < right));
|
||||
case Token::Operator::BoolGreaterThanOrEquals:
|
||||
return new ASTNodeLiteral(bool(left >= right));
|
||||
case Token::Operator::BoolLessThanOrEquals:
|
||||
return new ASTNodeLiteral(bool(left <= right));
|
||||
case Token::Operator::BoolAnd:
|
||||
return new ASTNodeLiteral(bool(left && right));
|
||||
case Token::Operator::BoolXor:
|
||||
return new ASTNodeLiteral(bool(left && !right || !left && right));
|
||||
case Token::Operator::BoolOr:
|
||||
return new ASTNodeLiteral(bool(left || right));
|
||||
case Token::Operator::BoolNot:
|
||||
return new ASTNodeLiteral(bool(!right));
|
||||
default:
|
||||
LogConsole::abortEvaluation("invalid operand used in mathematical expression", this);
|
||||
}
|
||||
} },
|
||||
left->getValue(),
|
||||
right->getValue()));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::unique_ptr<ASTNode> &getLeftOperand() const { return this->m_left; }
|
||||
[[nodiscard]] const std::unique_ptr<ASTNode> &getRightOperand() const { return this->m_right; }
|
||||
[[nodiscard]] Token::Operator getOperator() const { return this->m_operator; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<ASTNode> m_left, m_right;
|
||||
Token::Operator m_operator;
|
||||
};
|
||||
|
||||
#undef FLOAT_BIT_OPERATION
|
||||
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node_variable_decl.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeMultiVariableDecl : public ASTNode {
|
||||
public:
|
||||
explicit ASTNodeMultiVariableDecl(std::vector<std::unique_ptr<ASTNode>> &&variables) : m_variables(std::move(variables)) { }
|
||||
|
||||
ASTNodeMultiVariableDecl(const ASTNodeMultiVariableDecl &other) : ASTNode(other) {
|
||||
for (auto &variable : other.m_variables)
|
||||
this->m_variables.push_back(variable->clone());
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeMultiVariableDecl(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<ASTNode>> &getVariables() {
|
||||
return this->m_variables;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
std::vector<std::unique_ptr<Pattern>> patterns;
|
||||
|
||||
for (auto &node : this->m_variables) {
|
||||
auto newPatterns = node->createPatterns(evaluator);
|
||||
std::move(newPatterns.begin(), newPatterns.end(), std::back_inserter(patterns));
|
||||
}
|
||||
|
||||
return patterns;
|
||||
}
|
||||
|
||||
FunctionResult execute(Evaluator *evaluator) const override {
|
||||
for (auto &variable : this->m_variables) {
|
||||
auto variableDecl = dynamic_cast<ASTNodeVariableDecl *>(variable.get());
|
||||
auto variableType = variableDecl->getType()->evaluate(evaluator);
|
||||
|
||||
evaluator->createVariable(variableDecl->getName(), variableType.get());
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<ASTNode>> m_variables;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeParameterPack : public ASTNode {
|
||||
public:
|
||||
explicit ASTNodeParameterPack(std::vector<Token::Literal> &&values) : m_values(std::move(values)) { }
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeParameterPack(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<Token::Literal> &getValues() const {
|
||||
return this->m_values;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<Token::Literal> m_values;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_attribute.hpp>
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_pointer.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodePointerVariableDecl : public ASTNode,
|
||||
public Attributable {
|
||||
public:
|
||||
ASTNodePointerVariableDecl(std::string name, std::shared_ptr<ASTNode> &&type, std::shared_ptr<ASTNode> &&sizeType, std::unique_ptr<ASTNode> &&placementOffset = nullptr)
|
||||
: ASTNode(), m_name(std::move(name)), m_type(std::move(type)), m_sizeType(std::move(sizeType)), m_placementOffset(std::move(placementOffset)) { }
|
||||
|
||||
ASTNodePointerVariableDecl(const ASTNodePointerVariableDecl &other) : ASTNode(other), Attributable(other) {
|
||||
this->m_name = other.m_name;
|
||||
this->m_type = other.m_type->clone();
|
||||
this->m_sizeType = other.m_sizeType->clone();
|
||||
|
||||
if (other.m_placementOffset != nullptr)
|
||||
this->m_placementOffset = other.m_placementOffset->clone();
|
||||
else
|
||||
this->m_placementOffset = nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodePointerVariableDecl(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string &getName() const { return this->m_name; }
|
||||
[[nodiscard]] constexpr const std::shared_ptr<ASTNode> &getType() const { return this->m_type; }
|
||||
[[nodiscard]] constexpr const std::shared_ptr<ASTNode> &getSizeType() const { return this->m_sizeType; }
|
||||
[[nodiscard]] constexpr const std::unique_ptr<ASTNode> &getPlacementOffset() const { return this->m_placementOffset; }
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
auto startOffset = evaluator->dataOffset();
|
||||
|
||||
if (this->m_placementOffset != nullptr) {
|
||||
const auto node = this->m_placementOffset->evaluate(evaluator);
|
||||
const auto offset = dynamic_cast<ASTNodeLiteral *>(node.get());
|
||||
|
||||
evaluator->dataOffset() = std::visit(overloaded {
|
||||
[this](const std::string &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a string", this); },
|
||||
[this](const std::shared_ptr<Pattern> &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a custom type", this); },
|
||||
[](auto &&offset) -> u64 { return u64(offset); } },
|
||||
offset->getValue());
|
||||
}
|
||||
|
||||
auto pointerStartOffset = evaluator->dataOffset();
|
||||
|
||||
const auto sizePatterns = this->m_sizeType->createPatterns(evaluator);
|
||||
const auto &sizePattern = sizePatterns.front();
|
||||
|
||||
auto pattern = std::make_unique<PatternPointer>(evaluator, pointerStartOffset, sizePattern->getSize());
|
||||
pattern->setVariableName(this->m_name);
|
||||
|
||||
auto pointerEndOffset = evaluator->dataOffset();
|
||||
|
||||
{
|
||||
u128 pointerAddress = 0;
|
||||
evaluator->getProvider()->read(pattern->getOffset(), &pointerAddress, pattern->getSize());
|
||||
pointerAddress = hex::changeEndianess(pointerAddress, sizePattern->getSize(), sizePattern->getEndian());
|
||||
|
||||
evaluator->dataOffset() = pointerStartOffset;
|
||||
|
||||
pattern->setPointedAtAddress(pointerAddress);
|
||||
applyVariableAttributes(evaluator, this, pattern.get());
|
||||
|
||||
evaluator->dataOffset() = pattern->getPointedAtAddress();
|
||||
|
||||
auto pointedAtPatterns = this->m_type->createPatterns(evaluator);
|
||||
auto &pointedAtPattern = pointedAtPatterns.front();
|
||||
|
||||
pattern->setPointedAtPattern(std::move(pointedAtPattern));
|
||||
pattern->setEndian(sizePattern->getEndian());
|
||||
}
|
||||
|
||||
if (this->m_placementOffset != nullptr && !evaluator->isGlobalScope()) {
|
||||
evaluator->dataOffset() = startOffset;
|
||||
} else {
|
||||
evaluator->dataOffset() = pointerEndOffset;
|
||||
}
|
||||
|
||||
return hex::moveToVector<std::unique_ptr<Pattern>>(std::move(pattern));
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::shared_ptr<ASTNode> m_type;
|
||||
std::shared_ptr<ASTNode> m_sizeType;
|
||||
std::unique_ptr<ASTNode> m_placementOffset;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,293 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_literal.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_parameter_pack.hpp>
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_pointer.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_unsigned.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_signed.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_float.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_boolean.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_character.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_string.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_array_dynamic.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_array_static.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_struct.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_union.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_enum.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern_bitfield.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeRValue : public ASTNode {
|
||||
public:
|
||||
using PathSegment = std::variant<std::string, std::unique_ptr<ASTNode>>;
|
||||
using Path = std::vector<PathSegment>;
|
||||
|
||||
explicit ASTNodeRValue(Path &&path) : ASTNode(), m_path(std::move(path)) { }
|
||||
|
||||
ASTNodeRValue(const ASTNodeRValue &other) : ASTNode(other) {
|
||||
for (auto &part : other.m_path) {
|
||||
if (auto stringPart = std::get_if<std::string>(&part); stringPart != nullptr)
|
||||
this->m_path.push_back(*stringPart);
|
||||
else if (auto nodePart = std::get_if<std::unique_ptr<ASTNode>>(&part); nodePart != nullptr)
|
||||
this->m_path.push_back((*nodePart)->clone());
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeRValue(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] const Path &getPath() const {
|
||||
return this->m_path;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> evaluate(Evaluator *evaluator) const override {
|
||||
if (this->getPath().size() == 1) {
|
||||
if (auto name = std::get_if<std::string>(&this->getPath().front()); name != nullptr) {
|
||||
if (*name == "$") return std::unique_ptr<ASTNode>(new ASTNodeLiteral(u128(evaluator->dataOffset())));
|
||||
|
||||
auto parameterPack = evaluator->getScope(0).parameterPack;
|
||||
if (parameterPack && *name == parameterPack->name)
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeParameterPack(std::move(parameterPack->values)));
|
||||
}
|
||||
}
|
||||
|
||||
auto patterns = this->createPatterns(evaluator);
|
||||
auto &pattern = patterns.front();
|
||||
|
||||
Token::Literal literal;
|
||||
if (dynamic_cast<PatternUnsigned *>(pattern.get()) || dynamic_cast<PatternEnum *>(pattern.get())) {
|
||||
u128 value = 0;
|
||||
readVariable(evaluator, value, pattern.get());
|
||||
literal = value;
|
||||
} else if (dynamic_cast<PatternSigned *>(pattern.get())) {
|
||||
i128 value = 0;
|
||||
readVariable(evaluator, value, pattern.get());
|
||||
value = hex::signExtend(pattern->getSize() * 8, value);
|
||||
literal = value;
|
||||
} else if (dynamic_cast<PatternFloat *>(pattern.get())) {
|
||||
if (pattern->getSize() == sizeof(u16)) {
|
||||
u16 value = 0;
|
||||
readVariable(evaluator, value, pattern.get());
|
||||
literal = double(float16ToFloat32(value));
|
||||
} else if (pattern->getSize() == sizeof(float)) {
|
||||
float value = 0;
|
||||
readVariable(evaluator, value, pattern.get());
|
||||
literal = double(value);
|
||||
} else if (pattern->getSize() == sizeof(double)) {
|
||||
double value = 0;
|
||||
readVariable(evaluator, value, pattern.get());
|
||||
literal = value;
|
||||
} else LogConsole::abortEvaluation("invalid floating point type access", this);
|
||||
} else if (dynamic_cast<PatternCharacter *>(pattern.get())) {
|
||||
char value = 0;
|
||||
readVariable(evaluator, value, pattern.get());
|
||||
literal = value;
|
||||
} else if (dynamic_cast<PatternBoolean *>(pattern.get())) {
|
||||
bool value = false;
|
||||
readVariable(evaluator, value, pattern.get());
|
||||
literal = value;
|
||||
} else if (dynamic_cast<PatternString *>(pattern.get())) {
|
||||
std::string value;
|
||||
|
||||
if (pattern->isLocal()) {
|
||||
auto &variableValue = evaluator->getStack()[pattern->getOffset()];
|
||||
|
||||
std::visit(overloaded {
|
||||
[&](char assignmentValue) { if (assignmentValue != 0x00) value = std::string({ assignmentValue }); },
|
||||
[&](std::string &assignmentValue) { value = assignmentValue; },
|
||||
[&, this](Pattern *const &assignmentValue) {
|
||||
if (!dynamic_cast<PatternString *>(assignmentValue) && !dynamic_cast<PatternCharacter *>(assignmentValue))
|
||||
LogConsole::abortEvaluation(hex::format("cannot assign '{}' to string", pattern->getTypeName()), this);
|
||||
|
||||
readVariable(evaluator, value, assignmentValue);
|
||||
},
|
||||
[&, this](auto &&assignmentValue) { LogConsole::abortEvaluation(hex::format("cannot assign '{}' to string", pattern->getTypeName()), this); } },
|
||||
variableValue);
|
||||
} else {
|
||||
value.resize(pattern->getSize());
|
||||
evaluator->getProvider()->read(pattern->getOffset(), value.data(), value.size());
|
||||
value.erase(std::find(value.begin(), value.end(), '\0'), value.end());
|
||||
}
|
||||
|
||||
literal = value;
|
||||
} else if (auto bitfieldFieldPattern = dynamic_cast<PatternBitfieldField *>(pattern.get())) {
|
||||
u64 value = 0;
|
||||
readVariable(evaluator, value, pattern.get());
|
||||
literal = u128(hex::extract(bitfieldFieldPattern->getBitOffset() + (bitfieldFieldPattern->getBitSize() - 1), bitfieldFieldPattern->getBitOffset(), value));
|
||||
} else {
|
||||
literal = pattern->clone();
|
||||
}
|
||||
|
||||
if (auto transformFunc = pattern->getTransformFunction(); transformFunc.has_value()) {
|
||||
auto result = transformFunc->func(evaluator, { std::move(literal) });
|
||||
|
||||
if (!result.has_value())
|
||||
LogConsole::abortEvaluation("transform function did not return a value", this);
|
||||
literal = std::move(result.value());
|
||||
}
|
||||
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeLiteral(std::move(literal)));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
std::vector<std::shared_ptr<Pattern>> searchScope;
|
||||
std::unique_ptr<Pattern> currPattern;
|
||||
i32 scopeIndex = 0;
|
||||
|
||||
|
||||
if (!evaluator->isGlobalScope()) {
|
||||
auto globalScope = evaluator->getGlobalScope().scope;
|
||||
std::copy(globalScope->begin(), globalScope->end(), std::back_inserter(searchScope));
|
||||
}
|
||||
|
||||
{
|
||||
auto currScope = evaluator->getScope(scopeIndex).scope;
|
||||
std::copy(currScope->begin(), currScope->end(), std::back_inserter(searchScope));
|
||||
}
|
||||
|
||||
for (const auto &part : this->getPath()) {
|
||||
|
||||
if (part.index() == 0) {
|
||||
// Variable access
|
||||
auto name = std::get<std::string>(part);
|
||||
|
||||
if (name == "parent") {
|
||||
scopeIndex--;
|
||||
|
||||
if (-scopeIndex >= evaluator->getScopeCount())
|
||||
LogConsole::abortEvaluation("cannot access parent of global scope", this);
|
||||
|
||||
searchScope = *evaluator->getScope(scopeIndex).scope;
|
||||
auto currParent = evaluator->getScope(scopeIndex).parent;
|
||||
|
||||
if (currParent == nullptr) {
|
||||
currPattern = nullptr;
|
||||
} else {
|
||||
currPattern = currParent->clone();
|
||||
}
|
||||
|
||||
continue;
|
||||
} else if (name == "this") {
|
||||
searchScope = *evaluator->getScope(scopeIndex).scope;
|
||||
|
||||
auto currParent = evaluator->getScope(0).parent;
|
||||
|
||||
if (currParent == nullptr)
|
||||
LogConsole::abortEvaluation("invalid use of 'this' outside of struct-like type", this);
|
||||
|
||||
currPattern = currParent->clone();
|
||||
continue;
|
||||
} else {
|
||||
bool found = false;
|
||||
for (auto iter = searchScope.crbegin(); iter != searchScope.crend(); ++iter) {
|
||||
if ((*iter)->getVariableName() == name) {
|
||||
currPattern = (*iter)->clone();
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (name == "$")
|
||||
LogConsole::abortEvaluation("invalid use of placeholder operator in rvalue");
|
||||
|
||||
if (!found) {
|
||||
LogConsole::abortEvaluation(hex::format("no variable named '{}' found", name), this);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Array indexing
|
||||
auto node = std::get<std::unique_ptr<ASTNode>>(part)->evaluate(evaluator);
|
||||
auto index = dynamic_cast<ASTNodeLiteral *>(node.get());
|
||||
|
||||
std::visit(overloaded {
|
||||
[this](const std::string &) { LogConsole::abortEvaluation("cannot use string to index array", this); },
|
||||
[this](const std::shared_ptr<Pattern> &) { LogConsole::abortEvaluation("cannot use custom type to index array", this); },
|
||||
[&, this](auto &&index) {
|
||||
if (auto dynamicArrayPattern = dynamic_cast<PatternArrayDynamic *>(currPattern.get())) {
|
||||
if (index >= searchScope.size() || index < 0)
|
||||
LogConsole::abortEvaluation("array index out of bounds", this);
|
||||
|
||||
currPattern = searchScope[index]->clone();
|
||||
} else if (auto staticArrayPattern = dynamic_cast<PatternArrayStatic *>(currPattern.get())) {
|
||||
if (index >= staticArrayPattern->getEntryCount() || index < 0)
|
||||
LogConsole::abortEvaluation("array index out of bounds", this);
|
||||
|
||||
auto newPattern = searchScope.front()->clone();
|
||||
newPattern->setOffset(staticArrayPattern->getOffset() + index * staticArrayPattern->getTemplate()->getSize());
|
||||
currPattern = std::move(newPattern);
|
||||
}
|
||||
} },
|
||||
index->getValue());
|
||||
}
|
||||
|
||||
if (currPattern == nullptr)
|
||||
break;
|
||||
|
||||
if (auto pointerPattern = dynamic_cast<PatternPointer *>(currPattern.get())) {
|
||||
currPattern = pointerPattern->getPointedAtPattern()->clone();
|
||||
}
|
||||
|
||||
std::shared_ptr<Pattern> indexPattern;
|
||||
if (currPattern->isLocal()) {
|
||||
auto stackLiteral = evaluator->getStack()[currPattern->getOffset()];
|
||||
if (auto stackPattern = std::get_if<std::shared_ptr<Pattern>>(&stackLiteral); stackPattern != nullptr)
|
||||
indexPattern = *stackPattern;
|
||||
else
|
||||
return hex::moveToVector<std::unique_ptr<Pattern>>(std::move(currPattern));
|
||||
} else
|
||||
indexPattern = currPattern->clone();
|
||||
|
||||
if (auto structPattern = dynamic_cast<PatternStruct *>(indexPattern.get()))
|
||||
searchScope = structPattern->getMembers();
|
||||
else if (auto unionPattern = dynamic_cast<PatternUnion *>(indexPattern.get()))
|
||||
searchScope = unionPattern->getMembers();
|
||||
else if (auto bitfieldPattern = dynamic_cast<PatternBitfield *>(indexPattern.get()))
|
||||
searchScope = bitfieldPattern->getFields();
|
||||
else if (auto dynamicArrayPattern = dynamic_cast<PatternArrayDynamic *>(indexPattern.get()))
|
||||
searchScope = dynamicArrayPattern->getEntries();
|
||||
else if (auto staticArrayPattern = dynamic_cast<PatternArrayStatic *>(indexPattern.get()))
|
||||
searchScope = { staticArrayPattern->getTemplate() };
|
||||
}
|
||||
|
||||
if (currPattern == nullptr)
|
||||
LogConsole::abortEvaluation("cannot reference global scope", this);
|
||||
|
||||
return hex::moveToVector<std::unique_ptr<Pattern>>(std::move(currPattern));
|
||||
}
|
||||
|
||||
private:
|
||||
Path m_path;
|
||||
|
||||
void readVariable(Evaluator *evaluator, auto &value, Pattern *variablePattern) const {
|
||||
constexpr bool isString = std::same_as<std::remove_cvref_t<decltype(value)>, std::string>;
|
||||
|
||||
if (variablePattern->isLocal()) {
|
||||
auto &literal = evaluator->getStack()[variablePattern->getOffset()];
|
||||
|
||||
std::visit(overloaded {
|
||||
[&](std::string &assignmentValue) {
|
||||
if constexpr (isString) value = assignmentValue;
|
||||
},
|
||||
[&](std::shared_ptr<Pattern> &assignmentValue) { readVariable(evaluator, value, assignmentValue.get()); },
|
||||
[&](auto &&assignmentValue) { value = assignmentValue; } },
|
||||
literal);
|
||||
} else {
|
||||
if constexpr (isString) {
|
||||
value.resize(variablePattern->getSize());
|
||||
evaluator->getProvider()->read(variablePattern->getOffset(), value.data(), value.size());
|
||||
value.erase(std::find(value.begin(), value.end(), '\0'), value.end());
|
||||
} else {
|
||||
evaluator->getProvider()->read(variablePattern->getOffset(), &value, variablePattern->getSize());
|
||||
}
|
||||
}
|
||||
|
||||
if constexpr (!isString)
|
||||
value = hex::changeEndianess(value, variablePattern->getSize(), variablePattern->getEndian());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeScopeResolution : public ASTNode {
|
||||
public:
|
||||
explicit ASTNodeScopeResolution(std::unique_ptr<ASTNode> &&type, std::string name) : ASTNode(), m_type(std::move(type)), m_name(std::move(name)) { }
|
||||
|
||||
ASTNodeScopeResolution(const ASTNodeScopeResolution &other) : ASTNode(other) {
|
||||
this->m_type = other.m_type->clone();
|
||||
this->m_name = other.m_name;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeScopeResolution(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> evaluate(Evaluator *evaluator) const override {
|
||||
auto type = this->m_type->evaluate(evaluator);
|
||||
|
||||
if (auto enumType = dynamic_cast<ASTNodeEnum *>(type.get())) {
|
||||
for (auto &[name, value] : enumType->getEntries()) {
|
||||
if (name == this->m_name)
|
||||
return value->evaluate(evaluator);
|
||||
}
|
||||
} else {
|
||||
LogConsole::abortEvaluation("invalid scope resolution. Cannot access this type");
|
||||
}
|
||||
|
||||
LogConsole::abortEvaluation(hex::format("could not find constant '{}'", this->m_name), this);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<ASTNode> m_type;
|
||||
std::string m_name;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_attribute.hpp>
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_struct.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeStruct : public ASTNode,
|
||||
public Attributable {
|
||||
public:
|
||||
ASTNodeStruct() : ASTNode() { }
|
||||
|
||||
ASTNodeStruct(const ASTNodeStruct &other) : ASTNode(other), Attributable(other) {
|
||||
for (const auto &otherMember : other.getMembers())
|
||||
this->m_members.push_back(otherMember->clone());
|
||||
for (const auto &otherInheritance : other.getInheritance())
|
||||
this->m_inheritance.push_back(otherInheritance->clone());
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeStruct(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
auto pattern = std::make_unique<PatternStruct>(evaluator, evaluator->dataOffset(), 0);
|
||||
|
||||
u64 startOffset = evaluator->dataOffset();
|
||||
std::vector<std::shared_ptr<Pattern>> memberPatterns;
|
||||
|
||||
evaluator->pushScope(pattern.get(), memberPatterns);
|
||||
ON_SCOPE_EXIT {
|
||||
evaluator->popScope();
|
||||
};
|
||||
|
||||
for (auto &inheritance : this->m_inheritance) {
|
||||
auto inheritancePatterns = inheritance->createPatterns(evaluator);
|
||||
auto &inheritancePattern = inheritancePatterns.front();
|
||||
|
||||
if (auto structPattern = dynamic_cast<PatternStruct *>(inheritancePattern.get())) {
|
||||
for (auto &member : structPattern->getMembers()) {
|
||||
memberPatterns.push_back(member->clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &member : this->m_members) {
|
||||
for (auto &memberPattern : member->createPatterns(evaluator)) {
|
||||
memberPatterns.push_back(std::move(memberPattern));
|
||||
}
|
||||
}
|
||||
|
||||
pattern->setMembers(std::move(memberPatterns));
|
||||
pattern->setSize(evaluator->dataOffset() - startOffset);
|
||||
|
||||
applyTypeAttributes(evaluator, this, pattern.get());
|
||||
|
||||
return hex::moveToVector<std::unique_ptr<Pattern>>(std::move(pattern));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<ASTNode>> &getMembers() const { return this->m_members; }
|
||||
void addMember(std::shared_ptr<ASTNode> &&node) { this->m_members.push_back(std::move(node)); }
|
||||
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<ASTNode>> &getInheritance() const { return this->m_inheritance; }
|
||||
void addInheritance(std::shared_ptr<ASTNode> &&node) { this->m_inheritance.push_back(std::move(node)); }
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<ASTNode>> m_members;
|
||||
std::vector<std::shared_ptr<ASTNode>> m_inheritance;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeTernaryExpression : public ASTNode {
|
||||
public:
|
||||
ASTNodeTernaryExpression(std::unique_ptr<ASTNode> &&first, std::unique_ptr<ASTNode> &&second, std::unique_ptr<ASTNode> &&third, Token::Operator op)
|
||||
: ASTNode(), m_first(std::move(first)), m_second(std::move(second)), m_third(std::move(third)), m_operator(op) { }
|
||||
|
||||
ASTNodeTernaryExpression(const ASTNodeTernaryExpression &other) : ASTNode(other) {
|
||||
this->m_operator = other.m_operator;
|
||||
this->m_first = other.m_first->clone();
|
||||
this->m_second = other.m_second->clone();
|
||||
this->m_third = other.m_third->clone();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeTernaryExpression(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> evaluate(Evaluator *evaluator) const override {
|
||||
if (this->getFirstOperand() == nullptr || this->getSecondOperand() == nullptr || this->getThirdOperand() == nullptr)
|
||||
LogConsole::abortEvaluation("attempted to use void expression in mathematical expression", this);
|
||||
|
||||
auto firstNode = this->getFirstOperand()->evaluate(evaluator);
|
||||
auto secondNode = this->getSecondOperand()->evaluate(evaluator);
|
||||
auto thirdNode = this->getThirdOperand()->evaluate(evaluator);
|
||||
|
||||
auto *first = dynamic_cast<ASTNodeLiteral *>(firstNode.get());
|
||||
auto *second = dynamic_cast<ASTNodeLiteral *>(secondNode.get());
|
||||
auto *third = dynamic_cast<ASTNodeLiteral *>(thirdNode.get());
|
||||
|
||||
auto condition = std::visit(overloaded {
|
||||
[](const std::string &value) -> bool { return !value.empty(); },
|
||||
[this](const std::shared_ptr<Pattern> &) -> bool { LogConsole::abortEvaluation("cannot cast custom type to bool", this); },
|
||||
[](auto &&value) -> bool { return bool(value); } },
|
||||
first->getValue());
|
||||
|
||||
return std::visit(overloaded {
|
||||
[condition]<typename T>(const T &second, const T &third) -> std::unique_ptr<ASTNode> { return std::unique_ptr<ASTNode>(new ASTNodeLiteral(condition ? second : third)); },
|
||||
[this](auto &&second, auto &&third) -> std::unique_ptr<ASTNode> { LogConsole::abortEvaluation("operands to ternary expression have different types", this); } },
|
||||
second->getValue(),
|
||||
third->getValue());
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::unique_ptr<ASTNode> &getFirstOperand() const { return this->m_first; }
|
||||
[[nodiscard]] const std::unique_ptr<ASTNode> &getSecondOperand() const { return this->m_second; }
|
||||
[[nodiscard]] const std::unique_ptr<ASTNode> &getThirdOperand() const { return this->m_third; }
|
||||
[[nodiscard]] Token::Operator getOperator() const { return this->m_operator; }
|
||||
|
||||
private:
|
||||
std::unique_ptr<ASTNode> m_first, m_second, m_third;
|
||||
Token::Operator m_operator;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_attribute.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeTypeDecl : public ASTNode,
|
||||
public Attributable {
|
||||
public:
|
||||
ASTNodeTypeDecl(std::string name, std::shared_ptr<ASTNode> &&type, std::optional<std::endian> endian = std::nullopt)
|
||||
: ASTNode(), m_name(std::move(name)), m_type(std::move(type)), m_endian(endian) { }
|
||||
|
||||
ASTNodeTypeDecl(const ASTNodeTypeDecl &other) : ASTNode(other), Attributable(other) {
|
||||
this->m_name = other.m_name;
|
||||
this->m_type = other.m_type->clone();
|
||||
this->m_endian = other.m_endian;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeTypeDecl(*this));
|
||||
}
|
||||
|
||||
void setName(const std::string &name) { this->m_name = name; }
|
||||
[[nodiscard]] const std::string &getName() const { return this->m_name; }
|
||||
[[nodiscard]] const std::shared_ptr<ASTNode> &getType() { return this->m_type; }
|
||||
[[nodiscard]] std::optional<std::endian> getEndian() const { return this->m_endian; }
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> evaluate(Evaluator *evaluator) const override {
|
||||
auto type = this->m_type->evaluate(evaluator);
|
||||
|
||||
if (auto attributable = dynamic_cast<Attributable *>(type.get())) {
|
||||
for (auto &attribute : this->getAttributes()) {
|
||||
if (auto node = dynamic_cast<ASTNodeAttribute *>(attribute.get()))
|
||||
attributable->addAttribute(std::unique_ptr<ASTNodeAttribute>(node));
|
||||
}
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
auto patterns = this->m_type->createPatterns(evaluator);
|
||||
|
||||
for (auto &pattern : patterns) {
|
||||
if (pattern == nullptr)
|
||||
continue;
|
||||
|
||||
if (!this->m_name.empty())
|
||||
pattern->setTypeName(this->m_name);
|
||||
|
||||
if (this->m_endian.has_value())
|
||||
pattern->setEndian(this->m_endian.value());
|
||||
|
||||
applyTypeAttributes(evaluator, this, pattern.get());
|
||||
}
|
||||
|
||||
return patterns;
|
||||
}
|
||||
|
||||
void addAttribute(std::unique_ptr<ASTNodeAttribute> &&attribute) override {
|
||||
if (auto attributable = dynamic_cast<Attributable *>(this->m_type.get()); attributable != nullptr) {
|
||||
attributable->addAttribute(std::unique_ptr<ASTNodeAttribute>(static_cast<ASTNodeAttribute *>(attribute->clone().release())));
|
||||
}
|
||||
|
||||
Attributable::addAttribute(std::move(attribute));
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::shared_ptr<ASTNode> m_type;
|
||||
std::optional<std::endian> m_endian;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeTypeOperator : public ASTNode {
|
||||
public:
|
||||
ASTNodeTypeOperator(Token::Operator op, std::unique_ptr<ASTNode> &&expression) : m_op(op), m_expression(std::move(expression)) {
|
||||
}
|
||||
|
||||
ASTNodeTypeOperator(const ASTNodeTypeOperator &other) : ASTNode(other) {
|
||||
this->m_op = other.m_op;
|
||||
this->m_expression = other.m_expression->clone();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeTypeOperator(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] Token::Operator getOperator() const {
|
||||
return this->m_op;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::unique_ptr<ASTNode> &getExpression() const {
|
||||
return this->m_expression;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> evaluate(Evaluator *evaluator) const override {
|
||||
auto patterns = this->m_expression->createPatterns(evaluator);
|
||||
auto &pattern = patterns.front();
|
||||
|
||||
switch (this->getOperator()) {
|
||||
case Token::Operator::AddressOf:
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeLiteral(u128(pattern->getOffset())));
|
||||
case Token::Operator::SizeOf:
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeLiteral(u128(pattern->getSize())));
|
||||
default:
|
||||
LogConsole::abortEvaluation("invalid type operator", this);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
Token::Operator m_op;
|
||||
std::unique_ptr<ASTNode> m_expression;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_attribute.hpp>
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern_union.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeUnion : public ASTNode,
|
||||
public Attributable {
|
||||
public:
|
||||
ASTNodeUnion() : ASTNode() { }
|
||||
|
||||
ASTNodeUnion(const ASTNodeUnion &other) : ASTNode(other), Attributable(other) {
|
||||
for (const auto &otherMember : other.getMembers())
|
||||
this->m_members.push_back(otherMember->clone());
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeUnion(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
auto pattern = std::make_unique<PatternUnion>(evaluator, evaluator->dataOffset(), 0);
|
||||
|
||||
size_t size = 0;
|
||||
std::vector<std::shared_ptr<Pattern>> memberPatterns;
|
||||
u64 startOffset = evaluator->dataOffset();
|
||||
|
||||
evaluator->pushScope(pattern.get(), memberPatterns);
|
||||
ON_SCOPE_EXIT {
|
||||
evaluator->popScope();
|
||||
};
|
||||
|
||||
for (auto &member : this->m_members) {
|
||||
for (auto &memberPattern : member->createPatterns(evaluator)) {
|
||||
memberPattern->setOffset(startOffset);
|
||||
size = std::max(memberPattern->getSize(), size);
|
||||
|
||||
memberPatterns.push_back(std::move(memberPattern));
|
||||
}
|
||||
}
|
||||
|
||||
evaluator->dataOffset() = startOffset + size;
|
||||
pattern->setMembers(std::move(memberPatterns));
|
||||
pattern->setSize(size);
|
||||
|
||||
applyTypeAttributes(evaluator, this, pattern.get());
|
||||
|
||||
return hex::moveToVector<std::unique_ptr<Pattern>>(std::move(pattern));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<ASTNode>> &getMembers() const { return this->m_members; }
|
||||
void addMember(std::shared_ptr<ASTNode> &&node) { this->m_members.push_back(std::move(node)); }
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<ASTNode>> m_members;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_attribute.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_literal.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeVariableDecl : public ASTNode,
|
||||
public Attributable {
|
||||
public:
|
||||
ASTNodeVariableDecl(std::string name, std::unique_ptr<ASTNode> &&type, std::unique_ptr<ASTNode> &&placementOffset = nullptr, bool inVariable = false, bool outVariable = false)
|
||||
: ASTNode(), m_name(std::move(name)), m_type(std::move(type)), m_placementOffset(std::move(placementOffset)), m_inVariable(inVariable), m_outVariable(outVariable) { }
|
||||
|
||||
ASTNodeVariableDecl(const ASTNodeVariableDecl &other) : ASTNode(other), Attributable(other) {
|
||||
this->m_name = other.m_name;
|
||||
this->m_type = other.m_type->clone();
|
||||
|
||||
if (other.m_placementOffset != nullptr)
|
||||
this->m_placementOffset = other.m_placementOffset->clone();
|
||||
else
|
||||
this->m_placementOffset = nullptr;
|
||||
|
||||
this->m_inVariable = other.m_inVariable;
|
||||
this->m_outVariable = other.m_outVariable;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeVariableDecl(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string &getName() const { return this->m_name; }
|
||||
[[nodiscard]] constexpr const std::unique_ptr<ASTNode> &getType() const { return this->m_type; }
|
||||
[[nodiscard]] constexpr const std::unique_ptr<ASTNode> &getPlacementOffset() const { return this->m_placementOffset; }
|
||||
|
||||
[[nodiscard]] constexpr bool isInVariable() const { return this->m_inVariable; }
|
||||
[[nodiscard]] constexpr bool isOutVariable() const { return this->m_outVariable; }
|
||||
|
||||
[[nodiscard]] std::vector<std::unique_ptr<Pattern>> createPatterns(Evaluator *evaluator) const override {
|
||||
u64 startOffset = evaluator->dataOffset();
|
||||
|
||||
if (this->m_placementOffset != nullptr) {
|
||||
const auto node = this->m_placementOffset->evaluate(evaluator);
|
||||
const auto offset = dynamic_cast<ASTNodeLiteral *>(node.get());
|
||||
|
||||
evaluator->dataOffset() = std::visit(overloaded {
|
||||
[this](const std::string &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a string", this); },
|
||||
[this](const std::shared_ptr<Pattern> &) -> u64 { LogConsole::abortEvaluation("placement offset cannot be a custom type", this); },
|
||||
[](auto &&offset) -> u64 { return offset; } },
|
||||
offset->getValue());
|
||||
}
|
||||
|
||||
auto patterns = this->m_type->createPatterns(evaluator);
|
||||
auto &pattern = patterns.front();
|
||||
pattern->setVariableName(this->m_name);
|
||||
|
||||
applyVariableAttributes(evaluator, this, pattern.get());
|
||||
|
||||
if (this->m_placementOffset != nullptr && !evaluator->isGlobalScope()) {
|
||||
evaluator->dataOffset() = startOffset;
|
||||
}
|
||||
|
||||
return hex::moveToVector<std::unique_ptr<Pattern>>(std::move(pattern));
|
||||
}
|
||||
|
||||
FunctionResult execute(Evaluator *evaluator) const override {
|
||||
evaluator->createVariable(this->getName(), this->getType().get());
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
std::unique_ptr<ASTNode> m_type;
|
||||
std::unique_ptr<ASTNode> m_placementOffset;
|
||||
|
||||
bool m_inVariable = false, m_outVariable = false;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNodeWhileStatement : public ASTNode {
|
||||
public:
|
||||
explicit ASTNodeWhileStatement(std::unique_ptr<ASTNode> &&condition, std::vector<std::unique_ptr<ASTNode>> &&body, std::unique_ptr<ASTNode> &&postExpression = nullptr)
|
||||
: ASTNode(), m_condition(std::move(condition)), m_body(std::move(body)), m_postExpression(std::move(postExpression)) { }
|
||||
|
||||
ASTNodeWhileStatement(const ASTNodeWhileStatement &other) : ASTNode(other) {
|
||||
this->m_condition = other.m_condition->clone();
|
||||
|
||||
for (auto &statement : other.m_body)
|
||||
this->m_body.push_back(statement->clone());
|
||||
|
||||
if (other.m_postExpression != nullptr)
|
||||
this->m_postExpression = other.m_postExpression->clone();
|
||||
else
|
||||
this->m_postExpression = nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<ASTNode> clone() const override {
|
||||
return std::unique_ptr<ASTNode>(new ASTNodeWhileStatement(*this));
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::unique_ptr<ASTNode> &getCondition() {
|
||||
return this->m_condition;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<std::unique_ptr<ASTNode>> &getBody() {
|
||||
return this->m_body;
|
||||
}
|
||||
|
||||
FunctionResult execute(Evaluator *evaluator) const override {
|
||||
|
||||
u64 loopIterations = 0;
|
||||
while (evaluateCondition(evaluator)) {
|
||||
evaluator->handleAbort();
|
||||
|
||||
auto variables = *evaluator->getScope(0).scope;
|
||||
auto parameterPack = evaluator->getScope(0).parameterPack;
|
||||
u32 startVariableCount = variables.size();
|
||||
ON_SCOPE_EXIT {
|
||||
ssize_t stackSize = evaluator->getStack().size();
|
||||
for (u32 i = startVariableCount; i < variables.size(); i++) {
|
||||
stackSize--;
|
||||
}
|
||||
if (stackSize < 0) LogConsole::abortEvaluation("stack pointer underflow!", this);
|
||||
evaluator->getStack().resize(stackSize);
|
||||
};
|
||||
|
||||
evaluator->pushScope(nullptr, variables);
|
||||
evaluator->getScope(0).parameterPack = parameterPack;
|
||||
ON_SCOPE_EXIT {
|
||||
evaluator->popScope();
|
||||
};
|
||||
|
||||
auto ctrlFlow = ControlFlowStatement::None;
|
||||
for (auto &statement : this->m_body) {
|
||||
auto result = statement->execute(evaluator);
|
||||
|
||||
ctrlFlow = evaluator->getCurrentControlFlowStatement();
|
||||
evaluator->setCurrentControlFlowStatement(ControlFlowStatement::None);
|
||||
if (ctrlFlow == ControlFlowStatement::Return)
|
||||
return result;
|
||||
else if (ctrlFlow != ControlFlowStatement::None)
|
||||
break;
|
||||
}
|
||||
|
||||
if (this->m_postExpression != nullptr)
|
||||
this->m_postExpression->execute(evaluator);
|
||||
|
||||
loopIterations++;
|
||||
if (loopIterations >= evaluator->getLoopLimit())
|
||||
LogConsole::abortEvaluation(hex::format("loop iterations exceeded limit of {}", evaluator->getLoopLimit()), this);
|
||||
|
||||
evaluator->handleAbort();
|
||||
|
||||
if (ctrlFlow == ControlFlowStatement::Break)
|
||||
break;
|
||||
else if (ctrlFlow == ControlFlowStatement::Continue)
|
||||
continue;
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool evaluateCondition(Evaluator *evaluator) const {
|
||||
const auto node = this->m_condition->evaluate(evaluator);
|
||||
const auto literal = dynamic_cast<ASTNodeLiteral *>(node.get());
|
||||
|
||||
return std::visit(overloaded {
|
||||
[](const std::string &value) -> bool { return !value.empty(); },
|
||||
[this](Pattern *const &) -> bool { LogConsole::abortEvaluation("cannot cast custom type to bool", this); },
|
||||
[](auto &&value) -> bool { return value != 0; } },
|
||||
literal->getValue());
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<ASTNode> m_condition;
|
||||
std::vector<std::unique_ptr<ASTNode>> m_body;
|
||||
std::unique_ptr<ASTNode> m_postExpression;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternLanguageError : public std::exception {
|
||||
public:
|
||||
PatternLanguageError(u32 lineNumber, std::string message) : m_lineNumber(lineNumber), m_message(std::move(message)) { }
|
||||
|
||||
[[nodiscard]] const char *what() const noexcept override {
|
||||
return this->m_message.c_str();
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 getLineNumber() const {
|
||||
return this->m_lineNumber;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_lineNumber;
|
||||
std::string m_message;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,292 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <bit>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/pattern_language/log_console.hpp>
|
||||
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
|
||||
namespace hex::prv {
|
||||
class Provider;
|
||||
}
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
enum class DangerousFunctionPermission
|
||||
{
|
||||
Ask,
|
||||
Deny,
|
||||
Allow
|
||||
};
|
||||
|
||||
enum class ControlFlowStatement
|
||||
{
|
||||
None,
|
||||
Continue,
|
||||
Break,
|
||||
Return
|
||||
};
|
||||
|
||||
enum class BitfieldOrder
|
||||
{
|
||||
RightToLeft,
|
||||
LeftToRight
|
||||
};
|
||||
|
||||
class Pattern;
|
||||
class PatternCreationLimiter;
|
||||
class ASTNode;
|
||||
|
||||
class Evaluator {
|
||||
public:
|
||||
Evaluator() = default;
|
||||
|
||||
std::optional<std::vector<std::shared_ptr<Pattern>>> evaluate(const std::vector<std::shared_ptr<ASTNode>> &ast);
|
||||
|
||||
[[nodiscard]] LogConsole &getConsole() {
|
||||
return this->m_console;
|
||||
}
|
||||
|
||||
struct ParameterPack {
|
||||
std::string name;
|
||||
std::vector<Token::Literal> values;
|
||||
};
|
||||
|
||||
struct Scope {
|
||||
Pattern *parent;
|
||||
std::vector<std::shared_ptr<Pattern>> *scope;
|
||||
std::optional<ParameterPack> parameterPack;
|
||||
};
|
||||
void pushScope(Pattern *parent, std::vector<std::shared_ptr<Pattern>> &scope) {
|
||||
if (this->m_scopes.size() > this->getEvaluationDepth())
|
||||
LogConsole::abortEvaluation(hex::format("evaluation depth exceeded set limit of {}", this->getEvaluationDepth()));
|
||||
|
||||
this->handleAbort();
|
||||
|
||||
this->m_scopes.push_back({ parent, &scope });
|
||||
}
|
||||
|
||||
void popScope() {
|
||||
this->m_scopes.pop_back();
|
||||
}
|
||||
|
||||
Scope &getScope(i32 index) {
|
||||
return this->m_scopes[this->m_scopes.size() - 1 + index];
|
||||
}
|
||||
|
||||
const Scope &getScope(i32 index) const {
|
||||
return this->m_scopes[this->m_scopes.size() - 1 + index];
|
||||
}
|
||||
|
||||
Scope &getGlobalScope() {
|
||||
return this->m_scopes.front();
|
||||
}
|
||||
|
||||
const Scope &getGlobalScope() const {
|
||||
return this->m_scopes.front();
|
||||
}
|
||||
|
||||
size_t getScopeCount() {
|
||||
return this->m_scopes.size();
|
||||
}
|
||||
|
||||
bool isGlobalScope() {
|
||||
return this->m_scopes.size() == 1;
|
||||
}
|
||||
|
||||
void setProvider(prv::Provider *provider) {
|
||||
this->m_provider = provider;
|
||||
}
|
||||
|
||||
void setInVariables(const std::map<std::string, Token::Literal> &inVariables) {
|
||||
this->m_inVariables = inVariables;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::map<std::string, Token::Literal> getOutVariables() const {
|
||||
std::map<std::string, Token::Literal> result;
|
||||
|
||||
for (const auto &[name, offset] : this->m_outVariables) {
|
||||
result.insert({ name, this->getStack()[offset] });
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
[[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(u64 evalDepth) {
|
||||
this->m_evalDepth = evalDepth;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 getEvaluationDepth() const {
|
||||
return this->m_evalDepth;
|
||||
}
|
||||
|
||||
void setArrayLimit(u64 arrayLimit) {
|
||||
this->m_arrayLimit = arrayLimit;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 getArrayLimit() const {
|
||||
return this->m_arrayLimit;
|
||||
}
|
||||
|
||||
void setPatternLimit(u64 limit) {
|
||||
this->m_patternLimit = limit;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 getPatternLimit() {
|
||||
return this->m_patternLimit;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 getPatternCount() {
|
||||
return this->m_currPatternCount;
|
||||
}
|
||||
|
||||
void setLoopLimit(u64 limit) {
|
||||
this->m_loopLimit = limit;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 getLoopLimit() {
|
||||
return this->m_loopLimit;
|
||||
}
|
||||
|
||||
void setBitfieldOrder(BitfieldOrder order) {
|
||||
this->m_bitfieldOrder = order;
|
||||
}
|
||||
|
||||
[[nodiscard]] BitfieldOrder getBitfieldOrder() {
|
||||
return this->m_bitfieldOrder;
|
||||
}
|
||||
|
||||
u64 &dataOffset() { return this->m_currOffset; }
|
||||
|
||||
bool addCustomFunction(const std::string &name, u32 numParams, const ContentRegistry::PatternLanguage::Callback &function) {
|
||||
const auto [iter, inserted] = this->m_customFunctions.insert({
|
||||
name, {numParams, function}
|
||||
});
|
||||
|
||||
return inserted;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::map<std::string, ContentRegistry::PatternLanguage::Function> &getCustomFunctions() const {
|
||||
return this->m_customFunctions;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<Token::Literal> &getStack() {
|
||||
return this->m_stack;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::vector<Token::Literal> &getStack() const {
|
||||
return this->m_stack;
|
||||
}
|
||||
|
||||
void createParameterPack(const std::string &name, const std::vector<Token::Literal> &values);
|
||||
void createVariable(const std::string &name, ASTNode *type, const std::optional<Token::Literal> &value = std::nullopt, bool outVariable = false);
|
||||
void setVariable(const std::string &name, const Token::Literal &value);
|
||||
|
||||
void abort() {
|
||||
this->m_aborted = true;
|
||||
}
|
||||
|
||||
void handleAbort() {
|
||||
if (this->m_aborted)
|
||||
LogConsole::abortEvaluation("evaluation aborted by user");
|
||||
}
|
||||
|
||||
[[nodiscard]] std::optional<Token::Literal> getEnvVariable(const std::string &name) const {
|
||||
if (this->m_envVariables.contains(name)) {
|
||||
auto value = this->m_envVariables.at(name);
|
||||
return this->m_envVariables.at(name);
|
||||
} else
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
void setEnvVariable(const std::string &name, const Token::Literal &value) {
|
||||
this->m_envVariables[name] = value;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool hasDangerousFunctionBeenCalled() const {
|
||||
return this->m_dangerousFunctionCalled;
|
||||
}
|
||||
|
||||
void dangerousFunctionCalled() {
|
||||
this->m_dangerousFunctionCalled = true;
|
||||
}
|
||||
|
||||
void allowDangerousFunctions(bool allow) {
|
||||
this->m_allowDangerousFunctions = allow ? DangerousFunctionPermission::Allow : DangerousFunctionPermission::Deny;
|
||||
this->m_dangerousFunctionCalled = false;
|
||||
}
|
||||
|
||||
[[nodiscard]] DangerousFunctionPermission getDangerousFunctionPermission() const {
|
||||
return this->m_allowDangerousFunctions;
|
||||
}
|
||||
|
||||
void setCurrentControlFlowStatement(ControlFlowStatement statement) {
|
||||
this->m_currControlFlowStatement = statement;
|
||||
}
|
||||
|
||||
[[nodiscard]] ControlFlowStatement getCurrentControlFlowStatement() const {
|
||||
return this->m_currControlFlowStatement;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::optional<Token::Literal> &getMainResult() {
|
||||
return this->m_mainResult;
|
||||
}
|
||||
|
||||
private:
|
||||
void patternCreated();
|
||||
void patternDestroyed();
|
||||
|
||||
private:
|
||||
u64 m_currOffset;
|
||||
prv::Provider *m_provider = nullptr;
|
||||
LogConsole m_console;
|
||||
|
||||
std::endian m_defaultEndian = std::endian::native;
|
||||
u64 m_evalDepth;
|
||||
u64 m_arrayLimit;
|
||||
u64 m_patternLimit;
|
||||
u64 m_loopLimit;
|
||||
|
||||
u64 m_currPatternCount;
|
||||
|
||||
std::atomic<bool> m_aborted;
|
||||
|
||||
std::vector<Scope> m_scopes;
|
||||
std::map<std::string, ContentRegistry::PatternLanguage::Function> m_customFunctions;
|
||||
std::vector<std::unique_ptr<ASTNode>> m_customFunctionDefinitions;
|
||||
std::vector<Token::Literal> m_stack;
|
||||
|
||||
std::optional<Token::Literal> m_mainResult;
|
||||
|
||||
std::map<std::string, Token::Literal> m_envVariables;
|
||||
std::map<std::string, Token::Literal> m_inVariables;
|
||||
std::map<std::string, size_t> m_outVariables;
|
||||
|
||||
std::atomic<bool> m_dangerousFunctionCalled = false;
|
||||
std::atomic<DangerousFunctionPermission> m_allowDangerousFunctions = DangerousFunctionPermission::Ask;
|
||||
ControlFlowStatement m_currControlFlowStatement;
|
||||
BitfieldOrder m_bitfieldOrder = BitfieldOrder::RightToLeft;
|
||||
|
||||
friend class PatternCreationLimiter;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <hex/pattern_language/token.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class Lexer {
|
||||
public:
|
||||
Lexer() = default;
|
||||
|
||||
std::optional<std::vector<Token>> lex(const std::string &code);
|
||||
const std::optional<PatternLanguageError> &getError() { return this->m_error; }
|
||||
|
||||
private:
|
||||
std::optional<PatternLanguageError> m_error;
|
||||
|
||||
[[noreturn]] static void throwLexerError(const std::string &error, u32 lineNumber) {
|
||||
throw PatternLanguageError(lineNumber, "Lexer: " + error);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
|
||||
#include <hex/pattern_language/error.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNode;
|
||||
|
||||
class LogConsole {
|
||||
public:
|
||||
enum Level
|
||||
{
|
||||
Debug,
|
||||
Info,
|
||||
Warning,
|
||||
Error
|
||||
};
|
||||
|
||||
[[nodiscard]] const auto &getLog() const { return this->m_consoleLog; }
|
||||
|
||||
void log(Level level, const std::string &message) {
|
||||
this->m_consoleLog.emplace_back(level, message);
|
||||
}
|
||||
|
||||
[[noreturn]] static void abortEvaluation(const std::string &message) {
|
||||
abortEvaluation(message, nullptr);
|
||||
}
|
||||
|
||||
template<typename T = ASTNode>
|
||||
[[noreturn]] static void abortEvaluation(const std::string &message, const std::unique_ptr<T> &node) {
|
||||
abortEvaluation(message, node.get());
|
||||
}
|
||||
|
||||
[[noreturn]] static void abortEvaluation(const std::string &message, const ASTNode *node);
|
||||
|
||||
void clear() {
|
||||
this->m_consoleLog.clear();
|
||||
this->m_lastHardError.reset();
|
||||
}
|
||||
|
||||
void setHardError(const PatternLanguageError &error) { this->m_lastHardError = error; }
|
||||
|
||||
[[nodiscard]] const std::optional<PatternLanguageError> &getLastHardError() { return this->m_lastHardError; };
|
||||
|
||||
private:
|
||||
std::vector<std::pair<Level, std::string>> m_consoleLog;
|
||||
std::optional<PatternLanguageError> m_lastHardError;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,291 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <hex/pattern_language/error.hpp>
|
||||
#include <hex/pattern_language/token.hpp>
|
||||
|
||||
#include <hex/pattern_language/ast/ast_node.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_rvalue.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_attribute.hpp>
|
||||
#include <hex/pattern_language/ast/ast_node_type_decl.hpp>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class Parser {
|
||||
public:
|
||||
using TokenIter = std::vector<Token>::const_iterator;
|
||||
|
||||
Parser() = default;
|
||||
~Parser() = default;
|
||||
|
||||
std::optional<std::vector<std::shared_ptr<ASTNode>>> parse(const std::vector<Token> &tokens);
|
||||
const std::optional<PatternLanguageError> &getError() { return this->m_error; }
|
||||
|
||||
private:
|
||||
std::optional<PatternLanguageError> m_error;
|
||||
TokenIter m_curr;
|
||||
TokenIter m_originalPosition, m_partOriginalPosition;
|
||||
|
||||
std::unordered_map<std::string, std::shared_ptr<ASTNode>> m_types;
|
||||
std::vector<TokenIter> m_matchedOptionals;
|
||||
std::vector<std::vector<std::string>> m_currNamespace;
|
||||
|
||||
u32 getLineNumber(i32 index) const {
|
||||
return this->m_curr[index].lineNumber;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::unique_ptr<T> create(T *node) {
|
||||
node->setLineNumber(this->getLineNumber(-1));
|
||||
return std::unique_ptr<T>(node);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
const T &getValue(i32 index) const {
|
||||
auto value = std::get_if<T>(&this->m_curr[index].value);
|
||||
|
||||
if (value == nullptr)
|
||||
throwParserError("failed to decode token. Invalid type.", getLineNumber(index));
|
||||
|
||||
return *value;
|
||||
}
|
||||
|
||||
Token::Type getType(i32 index) const {
|
||||
return this->m_curr[index].type;
|
||||
}
|
||||
|
||||
std::string getNamespacePrefixedName(const std::string &name) {
|
||||
std::string result;
|
||||
for (const auto &part : this->m_currNamespace.back()) {
|
||||
result += part + "::";
|
||||
}
|
||||
|
||||
result += name;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<ASTNode> parseFunctionCall();
|
||||
std::unique_ptr<ASTNode> parseStringLiteral();
|
||||
std::string parseNamespaceResolution();
|
||||
std::unique_ptr<ASTNode> parseScopeResolution();
|
||||
std::unique_ptr<ASTNode> parseRValue();
|
||||
std::unique_ptr<ASTNode> parseRValue(ASTNodeRValue::Path &path);
|
||||
std::unique_ptr<ASTNode> parseFactor();
|
||||
std::unique_ptr<ASTNode> parseCastExpression();
|
||||
std::unique_ptr<ASTNode> parseUnaryExpression();
|
||||
std::unique_ptr<ASTNode> parseMultiplicativeExpression();
|
||||
std::unique_ptr<ASTNode> parseAdditiveExpression();
|
||||
std::unique_ptr<ASTNode> parseShiftExpression();
|
||||
std::unique_ptr<ASTNode> parseBinaryAndExpression();
|
||||
std::unique_ptr<ASTNode> parseBinaryXorExpression();
|
||||
std::unique_ptr<ASTNode> parseBinaryOrExpression();
|
||||
std::unique_ptr<ASTNode> parseBooleanAnd();
|
||||
std::unique_ptr<ASTNode> parseBooleanXor();
|
||||
std::unique_ptr<ASTNode> parseBooleanOr();
|
||||
std::unique_ptr<ASTNode> parseRelationExpression();
|
||||
std::unique_ptr<ASTNode> parseEqualityExpression();
|
||||
std::unique_ptr<ASTNode> parseTernaryConditional();
|
||||
std::unique_ptr<ASTNode> parseMathematicalExpression();
|
||||
|
||||
std::unique_ptr<ASTNode> parseFunctionDefinition();
|
||||
std::unique_ptr<ASTNode> parseFunctionVariableDecl();
|
||||
std::unique_ptr<ASTNode> parseFunctionStatement();
|
||||
std::unique_ptr<ASTNode> parseFunctionVariableAssignment(const std::string &lvalue);
|
||||
std::unique_ptr<ASTNode> parseFunctionVariableCompoundAssignment(const std::string &lvalue);
|
||||
std::unique_ptr<ASTNode> parseFunctionControlFlowStatement();
|
||||
std::vector<std::unique_ptr<ASTNode>> parseStatementBody();
|
||||
std::unique_ptr<ASTNode> parseFunctionConditional();
|
||||
std::unique_ptr<ASTNode> parseFunctionWhileLoop();
|
||||
std::unique_ptr<ASTNode> parseFunctionForLoop();
|
||||
|
||||
void parseAttribute(Attributable *currNode);
|
||||
std::unique_ptr<ASTNode> parseConditional();
|
||||
std::unique_ptr<ASTNode> parseWhileStatement();
|
||||
std::unique_ptr<ASTNodeTypeDecl> parseType(bool allowFunctionTypes = false);
|
||||
std::shared_ptr<ASTNodeTypeDecl> parseUsingDeclaration();
|
||||
std::unique_ptr<ASTNode> parsePadding();
|
||||
std::unique_ptr<ASTNode> parseMemberVariable(std::unique_ptr<ASTNodeTypeDecl> &&type);
|
||||
std::unique_ptr<ASTNode> parseMemberArrayVariable(std::unique_ptr<ASTNodeTypeDecl> &&type);
|
||||
std::unique_ptr<ASTNode> parseMemberPointerVariable(std::unique_ptr<ASTNodeTypeDecl> &&type);
|
||||
std::unique_ptr<ASTNode> parseMember();
|
||||
std::shared_ptr<ASTNodeTypeDecl> parseStruct();
|
||||
std::shared_ptr<ASTNodeTypeDecl> parseUnion();
|
||||
std::shared_ptr<ASTNodeTypeDecl> parseEnum();
|
||||
std::shared_ptr<ASTNodeTypeDecl> parseBitfield();
|
||||
std::unique_ptr<ASTNode> parseVariablePlacement(std::unique_ptr<ASTNodeTypeDecl> &&type);
|
||||
std::unique_ptr<ASTNode> parseArrayVariablePlacement(std::unique_ptr<ASTNodeTypeDecl> &&type);
|
||||
std::unique_ptr<ASTNode> parsePointerVariablePlacement(std::unique_ptr<ASTNodeTypeDecl> &&type);
|
||||
std::unique_ptr<ASTNode> parsePlacement();
|
||||
std::vector<std::shared_ptr<ASTNode>> parseNamespace();
|
||||
std::vector<std::shared_ptr<ASTNode>> parseStatements();
|
||||
|
||||
std::shared_ptr<ASTNodeTypeDecl> addType(const std::string &name, std::unique_ptr<ASTNode> &&node, std::optional<std::endian> endian = std::nullopt);
|
||||
|
||||
std::vector<std::shared_ptr<ASTNode>> parseTillToken(Token::Type endTokenType, const auto value) {
|
||||
std::vector<std::shared_ptr<ASTNode>> program;
|
||||
|
||||
while (this->m_curr->type != endTokenType || (*this->m_curr) != value) {
|
||||
for (auto &statement : parseStatements())
|
||||
program.push_back(std::move(statement));
|
||||
}
|
||||
|
||||
this->m_curr++;
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
[[noreturn]] void throwParserError(const std::string &error, i32 token = -1) const {
|
||||
throw PatternLanguageError(this->m_curr[token].lineNumber, "Parser: " + error);
|
||||
}
|
||||
|
||||
/* Token consuming */
|
||||
|
||||
enum class Setting
|
||||
{
|
||||
};
|
||||
constexpr static auto Normal = static_cast<Setting>(0);
|
||||
constexpr static auto Not = static_cast<Setting>(1);
|
||||
|
||||
bool begin() {
|
||||
this->m_originalPosition = this->m_curr;
|
||||
this->m_matchedOptionals.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool partBegin() {
|
||||
this->m_partOriginalPosition = this->m_curr;
|
||||
this->m_matchedOptionals.clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
this->m_curr = this->m_originalPosition;
|
||||
}
|
||||
|
||||
void partReset() {
|
||||
this->m_curr = this->m_partOriginalPosition;
|
||||
}
|
||||
|
||||
bool resetIfFailed(bool value) {
|
||||
if (!value) reset();
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
template<Setting S = Normal>
|
||||
bool sequenceImpl() {
|
||||
if constexpr (S == Normal)
|
||||
return true;
|
||||
else if constexpr (S == Not)
|
||||
return false;
|
||||
else
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
template<Setting S = Normal>
|
||||
bool sequenceImpl(Token::Type type, auto value, auto... args) {
|
||||
if constexpr (S == Normal) {
|
||||
if (!peek(type, value)) {
|
||||
partReset();
|
||||
return false;
|
||||
}
|
||||
|
||||
this->m_curr++;
|
||||
|
||||
if (!sequenceImpl<Normal>(args...)) {
|
||||
partReset();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
} else if constexpr (S == Not) {
|
||||
if (!peek(type, value))
|
||||
return true;
|
||||
|
||||
this->m_curr++;
|
||||
|
||||
if (!sequenceImpl<Normal>(args...))
|
||||
return true;
|
||||
|
||||
partReset();
|
||||
return false;
|
||||
} else
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
template<Setting S = Normal>
|
||||
bool sequence(Token::Type type, auto value, auto... args) {
|
||||
return partBegin() && sequenceImpl<S>(type, value, args...);
|
||||
}
|
||||
|
||||
template<Setting S = Normal>
|
||||
bool oneOfImpl() {
|
||||
if constexpr (S == Normal)
|
||||
return false;
|
||||
else if constexpr (S == Not)
|
||||
return true;
|
||||
else
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
template<Setting S = Normal>
|
||||
bool oneOfImpl(Token::Type type, auto value, auto... args) {
|
||||
if constexpr (S == Normal)
|
||||
return sequenceImpl<Normal>(type, value) || oneOfImpl(args...);
|
||||
else if constexpr (S == Not)
|
||||
return sequenceImpl<Not>(type, value) && oneOfImpl(args...);
|
||||
else
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
template<Setting S = Normal>
|
||||
bool oneOf(Token::Type type, auto value, auto... args) {
|
||||
return partBegin() && oneOfImpl<S>(type, value, args...);
|
||||
}
|
||||
|
||||
bool variantImpl(Token::Type type1, auto value1, Token::Type type2, auto value2) {
|
||||
if (!peek(type1, value1)) {
|
||||
if (!peek(type2, value2)) {
|
||||
partReset();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
this->m_curr++;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool variant(Token::Type type1, auto value1, Token::Type type2, auto value2) {
|
||||
return partBegin() && variantImpl(type1, value1, type2, value2);
|
||||
}
|
||||
|
||||
bool optionalImpl(Token::Type type, auto value) {
|
||||
if (peek(type, value)) {
|
||||
this->m_matchedOptionals.push_back(this->m_curr);
|
||||
this->m_curr++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool optional(Token::Type type, auto value) {
|
||||
return partBegin() && optionalImpl(type, value);
|
||||
}
|
||||
|
||||
bool peek(Token::Type type, auto value, i32 index = 0) {
|
||||
return this->m_curr[index].type == type && this->m_curr[index] == value;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <bit>
|
||||
#include <map>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/pattern_language/log_console.hpp>
|
||||
#include <hex/pattern_language/token.hpp>
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::prv {
|
||||
class Provider;
|
||||
}
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class Preprocessor;
|
||||
class Lexer;
|
||||
class Parser;
|
||||
class Validator;
|
||||
class Evaluator;
|
||||
class Pattern;
|
||||
|
||||
class ASTNode;
|
||||
|
||||
class PatternLanguage {
|
||||
public:
|
||||
PatternLanguage();
|
||||
~PatternLanguage();
|
||||
|
||||
[[nodiscard]] std::optional<std::vector<std::shared_ptr<ASTNode>>> parseString(const std::string &code);
|
||||
[[nodiscard]] bool executeString(prv::Provider *provider, const std::string &string, const std::map<std::string, Token::Literal> &envVars = {}, const std::map<std::string, Token::Literal> &inVariables = {}, bool checkResult = true);
|
||||
[[nodiscard]] bool executeFile(prv::Provider *provider, const fs::path &path, const std::map<std::string, Token::Literal> &envVars = {}, const std::map<std::string, Token::Literal> &inVariables = {});
|
||||
[[nodiscard]] std::pair<bool, std::optional<Token::Literal>> executeFunction(prv::Provider *provider, const std::string &code);
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<ASTNode>> &getCurrentAST() const;
|
||||
|
||||
void abort();
|
||||
|
||||
[[nodiscard]] const std::vector<std::pair<LogConsole::Level, std::string>> &getConsoleLog();
|
||||
[[nodiscard]] const std::optional<PatternLanguageError> &getError();
|
||||
[[nodiscard]] std::map<std::string, Token::Literal> getOutVariables() const;
|
||||
|
||||
[[nodiscard]] u32 getCreatedPatternCount();
|
||||
[[nodiscard]] u32 getMaximumPatternCount();
|
||||
|
||||
[[nodiscard]] bool hasDangerousFunctionBeenCalled() const;
|
||||
void allowDangerousFunctions(bool allow);
|
||||
|
||||
[[nodiscard]] const std::vector<std::shared_ptr<Pattern>> &getPatterns() {
|
||||
const static std::vector<std::shared_ptr<Pattern>> empty;
|
||||
|
||||
if (isRunning()) return empty;
|
||||
else return this->m_patterns;
|
||||
}
|
||||
|
||||
void reset();
|
||||
[[nodiscard]] bool isRunning() const { return this->m_running; }
|
||||
|
||||
private:
|
||||
Preprocessor *m_preprocessor;
|
||||
Lexer *m_lexer;
|
||||
Parser *m_parser;
|
||||
Validator *m_validator;
|
||||
Evaluator *m_evaluator;
|
||||
|
||||
std::vector<std::shared_ptr<ASTNode>> m_currAST;
|
||||
|
||||
std::optional<PatternLanguageError> m_currError;
|
||||
|
||||
std::vector<std::shared_ptr<Pattern>> m_patterns;
|
||||
|
||||
bool m_running = false;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,293 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
#include <hex/pattern_language/evaluator.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
using namespace ::std::literals::string_literals;
|
||||
|
||||
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 PatternCreationLimiter {
|
||||
public:
|
||||
explicit PatternCreationLimiter(Evaluator *evaluator) : m_evaluator(evaluator) {
|
||||
if (getEvaluator() == nullptr) return;
|
||||
|
||||
getEvaluator()->patternCreated();
|
||||
}
|
||||
|
||||
PatternCreationLimiter(const PatternCreationLimiter &other) : PatternCreationLimiter(other.m_evaluator) { }
|
||||
|
||||
virtual ~PatternCreationLimiter() {
|
||||
if (getEvaluator() == nullptr) return;
|
||||
|
||||
getEvaluator()->patternDestroyed();
|
||||
}
|
||||
|
||||
[[nodiscard]] Evaluator *getEvaluator() const {
|
||||
return this->m_evaluator;
|
||||
}
|
||||
|
||||
private:
|
||||
Evaluator *m_evaluator = nullptr;
|
||||
};
|
||||
|
||||
class Pattern : public PatternCreationLimiter,
|
||||
public Cloneable<Pattern> {
|
||||
public:
|
||||
Pattern(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0)
|
||||
: PatternCreationLimiter(evaluator), m_offset(offset), m_size(size), m_color(color) {
|
||||
|
||||
if (color != 0)
|
||||
return;
|
||||
|
||||
this->m_color = ContentRegistry::PatternLanguage::getNextColor();
|
||||
this->m_manualColor = false;
|
||||
}
|
||||
|
||||
Pattern(const Pattern &other) = default;
|
||||
|
||||
~Pattern() override = default;
|
||||
|
||||
[[nodiscard]] u64 getOffset() const { return this->m_offset; }
|
||||
virtual void setOffset(u64 offset) { this->m_offset = offset; }
|
||||
|
||||
[[nodiscard]] size_t getSize() const { return this->m_size; }
|
||||
void setSize(size_t size) { this->m_size = size; }
|
||||
|
||||
[[nodiscard]] const std::string &getVariableName() const { return this->m_variableName; }
|
||||
void setVariableName(std::string name) { this->m_variableName = std::move(name); }
|
||||
|
||||
[[nodiscard]] const std::optional<std::string> &getComment() const { return this->m_comment; }
|
||||
void setComment(std::string comment) { this->m_comment = std::move(comment); }
|
||||
|
||||
[[nodiscard]] const std::string &getTypeName() const { return this->m_typeName; }
|
||||
void setTypeName(std::string name) { this->m_typeName = std::move(name); }
|
||||
|
||||
[[nodiscard]] u32 getColor() const { return this->m_color; }
|
||||
virtual void setColor(u32 color) {
|
||||
this->m_color = color;
|
||||
this->m_manualColor = true;
|
||||
}
|
||||
[[nodiscard]] bool hasOverriddenColor() const { return this->m_manualColor; }
|
||||
|
||||
[[nodiscard]] std::endian getEndian() const {
|
||||
if (this->getEvaluator() == nullptr) return std::endian::native;
|
||||
else return this->m_endian.value_or(this->getEvaluator()->getDefaultEndian());
|
||||
}
|
||||
virtual void setEndian(std::endian endian) { this->m_endian = endian; }
|
||||
[[nodiscard]] bool hasOverriddenEndian() const { return this->m_endian.has_value(); }
|
||||
|
||||
[[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]] const auto &getTransformFunction() const { return this->m_transformFunction; }
|
||||
void setTransformFunction(const ContentRegistry::PatternLanguage::Function &function) { this->m_transformFunction = function; }
|
||||
[[nodiscard]] const auto &getFormatterFunction() const { return this->m_formatterFunction; }
|
||||
void setFormatterFunction(const ContentRegistry::PatternLanguage::Function &function) { this->m_formatterFunction = function; }
|
||||
|
||||
virtual void createEntry(prv::Provider *&provider) = 0;
|
||||
[[nodiscard]] virtual std::string getFormattedName() const = 0;
|
||||
|
||||
[[nodiscard]] virtual const Pattern *getPattern(u64 offset) const {
|
||||
if (offset >= this->getOffset() && offset < (this->getOffset() + this->getSize()) && !this->isHidden())
|
||||
return this;
|
||||
else
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
virtual void getHighlightedAddresses(std::map<u64, u32> &highlight) const {
|
||||
if (this->isHidden()) return;
|
||||
|
||||
for (u64 i = 0; i < this->getSize(); i++)
|
||||
highlight.insert({ this->getOffset() + i, this->getColor() });
|
||||
|
||||
this->getEvaluator()->handleAbort();
|
||||
}
|
||||
|
||||
virtual void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) { }
|
||||
|
||||
[[nodiscard]] virtual std::string toString(prv::Provider *provider) const {
|
||||
return hex::format("{} {} @ 0x{:X}", this->getTypeName(), this->getVariableName(), this->getOffset());
|
||||
}
|
||||
|
||||
static bool sortPatternTable(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider, pl::Pattern *left, pl::Pattern *right) {
|
||||
if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("name")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getDisplayName() > right->getDisplayName();
|
||||
else
|
||||
return left->getDisplayName() < right->getDisplayName();
|
||||
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("offset")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getOffset() > right->getOffset();
|
||||
else
|
||||
return left->getOffset() < right->getOffset();
|
||||
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("size")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getSize() > right->getSize();
|
||||
else
|
||||
return left->getSize() < right->getSize();
|
||||
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("value")) {
|
||||
size_t biggerSize = std::max(left->getSize(), right->getSize());
|
||||
std::vector<u8> leftBuffer(biggerSize, 0x00), rightBuffer(biggerSize, 0x00);
|
||||
|
||||
provider->read(left->getOffset(), leftBuffer.data(), left->getSize());
|
||||
provider->read(right->getOffset(), rightBuffer.data(), right->getSize());
|
||||
|
||||
if (left->m_endian != std::endian::native)
|
||||
std::reverse(leftBuffer.begin(), leftBuffer.end());
|
||||
if (right->m_endian != std::endian::native)
|
||||
std::reverse(rightBuffer.begin(), rightBuffer.end());
|
||||
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return leftBuffer > rightBuffer;
|
||||
else
|
||||
return leftBuffer < rightBuffer;
|
||||
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("type")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getTypeName() > right->getTypeName();
|
||||
else
|
||||
return left->getTypeName() < right->getTypeName();
|
||||
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("color")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getColor() > right->getColor();
|
||||
else
|
||||
return left->getColor() < right->getColor();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void draw(prv::Provider *provider) {
|
||||
if (isHidden()) return;
|
||||
|
||||
this->createEntry(provider);
|
||||
}
|
||||
|
||||
void setHidden(bool hidden) {
|
||||
this->m_hidden = hidden;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isHidden() const {
|
||||
return this->m_hidden;
|
||||
}
|
||||
|
||||
void setLocal(bool local) {
|
||||
this->m_local = local;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isLocal() const {
|
||||
return this->m_local;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual bool operator!=(const Pattern &other) const final { return !operator==(other); }
|
||||
[[nodiscard]] virtual bool operator==(const Pattern &other) const = 0;
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] bool areCommonPropertiesEqual(const Pattern &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_endian.has_value() && other.m_endian == std::endian::native) || (!other.m_endian.has_value() && this->m_endian == std::endian::native)) &&
|
||||
this->m_variableName == other.m_variableName &&
|
||||
this->m_typeName == other.m_typeName &&
|
||||
this->m_comment == other.m_comment &&
|
||||
this->m_local == other.m_local;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string formatDisplayValue(const std::string &value, const Token::Literal &literal) const {
|
||||
if (!this->m_formatterFunction.has_value())
|
||||
return value;
|
||||
else {
|
||||
try {
|
||||
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)
|
||||
return *displayValue;
|
||||
else
|
||||
return "???";
|
||||
} else {
|
||||
return "???";
|
||||
}
|
||||
} catch (PatternLanguageError &error) {
|
||||
return "Error: "s + error.what();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void createDefaultEntry(const std::string &value, const Token::Literal &literal) const {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::PushID(this->getOffset());
|
||||
ImGui::PushID(this->getVariableName().c_str());
|
||||
if (ImGui::Selectable("##PatternLine", false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
||||
ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize());
|
||||
}
|
||||
ImGui::PopID();
|
||||
ImGui::PopID();
|
||||
|
||||
this->drawCommentTooltip();
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted(this->getDisplayName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:04X}", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{}", this->getFormattedName());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", formatDisplayValue(value, literal));
|
||||
}
|
||||
|
||||
void drawCommentTooltip() const {
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && this->getComment().has_value()) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted(this->getComment()->c_str());
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
std::optional<std::endian> m_endian;
|
||||
bool m_hidden = false;
|
||||
|
||||
private:
|
||||
u64 m_offset = 0x00;
|
||||
size_t m_size = 0x00;
|
||||
|
||||
u32 m_color = 0x00;
|
||||
std::optional<std::string> m_displayName;
|
||||
std::string m_variableName;
|
||||
std::optional<std::string> m_comment;
|
||||
std::string m_typeName;
|
||||
|
||||
std::optional<ContentRegistry::PatternLanguage::Function> m_formatterFunction;
|
||||
std::optional<ContentRegistry::PatternLanguage::Function> m_transformFunction;
|
||||
|
||||
bool m_local = false;
|
||||
bool m_manualColor = false;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternArrayDynamic : public Pattern,
|
||||
public Inlinable {
|
||||
public:
|
||||
PatternArrayDynamic(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0)
|
||||
: Pattern(evaluator, offset, size, color) {
|
||||
}
|
||||
|
||||
PatternArrayDynamic(const PatternArrayDynamic &other) : Pattern(other) {
|
||||
std::vector<std::shared_ptr<Pattern>> entries;
|
||||
for (const auto &entry : other.m_entries)
|
||||
entries.push_back(entry->clone());
|
||||
|
||||
this->setEntries(std::move(entries));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternArrayDynamic(*this));
|
||||
}
|
||||
|
||||
void setColor(u32 color) override {
|
||||
Pattern::setColor(color);
|
||||
for (auto &entry : this->m_entries)
|
||||
entry->setColor(color);
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
if (this->m_entries.empty())
|
||||
return;
|
||||
|
||||
bool open = true;
|
||||
if (!this->isInlined()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(this))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
||||
ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize());
|
||||
}
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:04X}", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{0}", this->m_entries[0]->getTypeName());
|
||||
ImGui::SameLine(0, 0);
|
||||
|
||||
ImGui::TextUnformatted("[");
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextFormattedColored(ImColor(0xFF00FF00), "{0}", this->m_entries.size());
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextUnformatted("]");
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", this->formatDisplayValue("{ ... }", this->clone()));
|
||||
}
|
||||
|
||||
if (open) {
|
||||
for (u64 i = 0; i < this->m_entries.size(); i++) {
|
||||
this->m_entries[i]->draw(provider);
|
||||
|
||||
if (i >= (this->m_displayEnd - 1)) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::Selectable("... (Double-click to see more items)", false, ImGuiSelectableFlags_SpanAllColumns);
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
|
||||
this->m_displayEnd += 50;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->isInlined())
|
||||
ImGui::TreePop();
|
||||
} else {
|
||||
this->m_displayEnd = 50;
|
||||
}
|
||||
}
|
||||
|
||||
void getHighlightedAddresses(std::map<u64, u32> &highlight) const override {
|
||||
for (auto &entry : this->m_entries) {
|
||||
entry->getHighlightedAddresses(highlight);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
return this->m_entries[0]->getTypeName() + "[" + std::to_string(this->m_entries.size()) + "]";
|
||||
}
|
||||
|
||||
void setOffset(u64 offset) override {
|
||||
for (auto &entry : this->m_entries)
|
||||
entry->setOffset(entry->getOffset() - this->getOffset() + offset);
|
||||
|
||||
Pattern::setOffset(offset);
|
||||
}
|
||||
|
||||
[[nodiscard]] const auto &getEntries() {
|
||||
return this->m_entries;
|
||||
}
|
||||
|
||||
void setEntries(std::vector<std::shared_ptr<Pattern>> &&entries) {
|
||||
this->m_entries = std::move(entries);
|
||||
|
||||
if (this->hasOverriddenColor()) {
|
||||
for (auto &entry : this->m_entries) {
|
||||
entry->setColor(this->getColor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override {
|
||||
if (!areCommonPropertiesEqual<decltype(*this)>(other))
|
||||
return false;
|
||||
|
||||
auto &otherArray = *static_cast<const PatternArrayDynamic *>(&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;
|
||||
}
|
||||
|
||||
[[nodiscard]] const Pattern *getPattern(u64 offset) const override {
|
||||
if (this->isHidden()) return nullptr;
|
||||
|
||||
for (auto &pattern : this->m_entries) {
|
||||
auto result = pattern->getPattern(offset);
|
||||
if (result != nullptr)
|
||||
return result;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void setEndian(std::endian endian) override {
|
||||
for (auto &entry : this->m_entries) {
|
||||
entry->setEndian(endian);
|
||||
}
|
||||
|
||||
Pattern::setEndian(endian);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<Pattern>> m_entries;
|
||||
u64 m_displayEnd = 50;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternArrayStatic : public Pattern,
|
||||
public Inlinable {
|
||||
public:
|
||||
PatternArrayStatic(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0)
|
||||
: Pattern(evaluator, offset, size, color) {
|
||||
}
|
||||
|
||||
PatternArrayStatic(const PatternArrayStatic &other) : Pattern(other) {
|
||||
this->setEntries(other.getTemplate()->clone(), other.getEntryCount());
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternArrayStatic(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
if (this->getEntryCount() == 0)
|
||||
return;
|
||||
|
||||
bool open = true;
|
||||
|
||||
if (!this->isInlined()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(this))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
||||
ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize());
|
||||
}
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:04X}", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{0}", this->m_template->getTypeName().c_str());
|
||||
ImGui::SameLine(0, 0);
|
||||
|
||||
ImGui::TextUnformatted("[");
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextFormattedColored(ImColor(0xFF00FF00), "{0}", this->m_entryCount);
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextUnformatted("]");
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", this->formatDisplayValue("{ ... }", this->clone()));
|
||||
}
|
||||
|
||||
if (open) {
|
||||
auto entry = this->m_template->clone();
|
||||
for (u64 index = 0; index < this->m_entryCount; index++) {
|
||||
entry->setVariableName(hex::format("[{0}]", index));
|
||||
entry->setOffset(this->getOffset() + index * this->m_template->getSize());
|
||||
entry->draw(provider);
|
||||
|
||||
if (index >= (this->m_displayEnd - 1)) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::Selectable("... (Double-click to see more items)", false, ImGuiSelectableFlags_SpanAllColumns);
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
|
||||
this->m_displayEnd += 50;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!this->isInlined())
|
||||
ImGui::TreePop();
|
||||
} else {
|
||||
this->m_displayEnd = 50;
|
||||
}
|
||||
}
|
||||
|
||||
void getHighlightedAddresses(std::map<u64, u32> &highlight) const override {
|
||||
auto entry = this->m_template->clone();
|
||||
|
||||
for (u64 address = this->getOffset(); address < this->getOffset() + this->getSize(); address += entry->getSize()) {
|
||||
entry->setOffset(address);
|
||||
entry->getHighlightedAddresses(highlight);
|
||||
}
|
||||
}
|
||||
|
||||
void setOffset(u64 offset) override {
|
||||
this->m_template->setOffset(this->m_template->getOffset() - this->getOffset() + offset);
|
||||
|
||||
Pattern::setOffset(offset);
|
||||
}
|
||||
|
||||
void setColor(u32 color) override {
|
||||
Pattern::setColor(color);
|
||||
this->m_template->setColor(color);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
return this->m_template->getTypeName() + "[" + std::to_string(this->m_entryCount) + "]";
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::shared_ptr<Pattern> &getTemplate() const {
|
||||
return this->m_template;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t getEntryCount() const {
|
||||
return this->m_entryCount;
|
||||
}
|
||||
|
||||
void setEntryCount(size_t count) {
|
||||
this->m_entryCount = count;
|
||||
}
|
||||
|
||||
void setEntries(std::unique_ptr<Pattern> &&templatePattern, size_t count) {
|
||||
this->m_template = std::move(templatePattern);
|
||||
this->m_highlightTemplate = this->m_template->clone();
|
||||
this->m_entryCount = count;
|
||||
|
||||
if (this->hasOverriddenColor())
|
||||
this->setColor(this->m_template->getColor());
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override {
|
||||
if (!areCommonPropertiesEqual<decltype(*this)>(other))
|
||||
return false;
|
||||
|
||||
auto &otherArray = *static_cast<const PatternArrayStatic *>(&other);
|
||||
return *this->m_template == *otherArray.m_template && this->m_entryCount == otherArray.m_entryCount;
|
||||
}
|
||||
|
||||
[[nodiscard]] const Pattern *getPattern(u64 offset) const override {
|
||||
if (this->isHidden()) return nullptr;
|
||||
|
||||
this->m_highlightTemplate->setColor(this->getColor());
|
||||
this->m_highlightTemplate->setVariableName(this->getVariableName());
|
||||
this->m_highlightTemplate->setDisplayName(this->getDisplayName());
|
||||
|
||||
if (offset >= this->getOffset() && offset < (this->getOffset() + this->getSize())) {
|
||||
this->m_highlightTemplate->setOffset((offset / this->m_highlightTemplate->getSize()) * this->m_highlightTemplate->getSize());
|
||||
return this->m_highlightTemplate->getPattern(offset);
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void setEndian(std::endian endian) override {
|
||||
this->m_template->setEndian(endian);
|
||||
|
||||
Pattern::setEndian(endian);
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<Pattern> m_template = nullptr;
|
||||
mutable std::unique_ptr<Pattern> m_highlightTemplate = nullptr;
|
||||
size_t m_entryCount = 0;
|
||||
u64 m_displayEnd = 50;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternBitfieldField : public Pattern {
|
||||
public:
|
||||
PatternBitfieldField(Evaluator *evaluator, u64 offset, u8 bitOffset, u8 bitSize, Pattern *bitField, u32 color = 0)
|
||||
: Pattern(evaluator, offset, 0, color), m_bitOffset(bitOffset), m_bitSize(bitSize), m_bitField(bitField) {
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternBitfieldField(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
std::vector<u8> value(this->m_bitField->getSize(), 0);
|
||||
provider->read(this->m_bitField->getOffset(), &value[0], value.size());
|
||||
|
||||
if (this->m_bitField->getEndian() != std::endian::native)
|
||||
std::reverse(value.begin(), value.end());
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(this->getDisplayName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
|
||||
ImGui::TableNextColumn();
|
||||
if (this->m_bitSize == 1)
|
||||
ImGui::TextFormatted("0x{0:08X} bit {1}", this->getOffset() + this->m_bitOffset / 8, (this->m_bitOffset + (this->m_bitSize - 1)) % 8);
|
||||
else
|
||||
ImGui::TextFormatted("0x{0:08X} bits {1} - {2}", 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::TextFormatted("{0} bit", this->m_bitSize);
|
||||
else
|
||||
ImGui::TextFormatted("{0} bits", this->m_bitSize);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "bits");
|
||||
ImGui::TableNextColumn();
|
||||
{
|
||||
u8 numBytes = (this->m_bitSize / 8) + 1;
|
||||
|
||||
u64 extractedValue = hex::extract(this->m_bitOffset + (this->m_bitSize - 1), this->m_bitOffset, value);
|
||||
ImGui::TextFormatted("{}", this->formatDisplayValue(hex::format("{0} (0x{1:X})", extractedValue, extractedValue), this->clone()));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
return "bits";
|
||||
}
|
||||
|
||||
[[nodiscard]] u8 getBitOffset() const {
|
||||
return this->m_bitOffset;
|
||||
}
|
||||
|
||||
[[nodiscard]] u8 getBitSize() const {
|
||||
return this->m_bitSize;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override {
|
||||
if (!areCommonPropertiesEqual<decltype(*this)>(other))
|
||||
return false;
|
||||
|
||||
auto &otherBitfieldField = *static_cast<const PatternBitfieldField *>(&other);
|
||||
return this->m_bitOffset == otherBitfieldField.m_bitOffset && this->m_bitSize == otherBitfieldField.m_bitSize;
|
||||
}
|
||||
|
||||
private:
|
||||
u8 m_bitOffset, m_bitSize;
|
||||
Pattern *m_bitField;
|
||||
};
|
||||
|
||||
class PatternBitfield : public Pattern,
|
||||
public Inlinable {
|
||||
public:
|
||||
PatternBitfield(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0)
|
||||
: Pattern(evaluator, offset, size, color) {
|
||||
}
|
||||
|
||||
PatternBitfield(const PatternBitfield &other) : Pattern(other) {
|
||||
for (auto &field : other.m_fields)
|
||||
this->m_fields.push_back(field->clone());
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternBitfield(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
std::vector<u8> value(this->getSize(), 0);
|
||||
provider->read(this->getOffset(), &value[0], value.size());
|
||||
|
||||
if (this->m_endian == std::endian::little)
|
||||
std::reverse(value.begin(), value.end());
|
||||
|
||||
bool open = true;
|
||||
if (!this->isInlined()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(this))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
||||
ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize());
|
||||
}
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:04X}", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormattedColored(ImColor(0xFFD69C56), "bitfield");
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted(Pattern::getTypeName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
std::string valueString = "{ ";
|
||||
for (auto i : value)
|
||||
valueString += hex::format("{0:02X} ", i);
|
||||
valueString += "}";
|
||||
|
||||
ImGui::TextFormatted("{}", this->formatDisplayValue(valueString, this->clone()));
|
||||
}
|
||||
|
||||
if (open) {
|
||||
|
||||
for (auto &field : this->m_fields)
|
||||
field->draw(provider);
|
||||
|
||||
if (!this->isInlined())
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
void setOffset(u64 offset) override {
|
||||
for (auto &field : this->m_fields)
|
||||
field->setOffset(field->getOffset() - this->getOffset() + offset);
|
||||
|
||||
Pattern::setOffset(offset);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
return "bitfield " + Pattern::getTypeName();
|
||||
}
|
||||
|
||||
[[nodiscard]] const auto &getFields() const {
|
||||
return this->m_fields;
|
||||
}
|
||||
|
||||
void setFields(std::vector<std::shared_ptr<Pattern>> &&fields) {
|
||||
this->m_fields = std::move(fields);
|
||||
|
||||
for (auto &field : this->m_fields) {
|
||||
field->setSize(this->getSize());
|
||||
field->setColor(this->getColor());
|
||||
}
|
||||
}
|
||||
|
||||
void setColor(u32 color) override {
|
||||
Pattern::setColor(color);
|
||||
for (auto &field : this->m_fields)
|
||||
field->setColor(color);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override {
|
||||
if (!areCommonPropertiesEqual<decltype(*this)>(other))
|
||||
return false;
|
||||
|
||||
auto &otherBitfield = *static_cast<const PatternBitfield *>(&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:
|
||||
std::vector<std::shared_ptr<Pattern>> m_fields;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternBoolean : public Pattern {
|
||||
public:
|
||||
explicit PatternBoolean(Evaluator *evaluator, u64 offset, u32 color = 0)
|
||||
: Pattern(evaluator, offset, 1, color) { }
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternBoolean(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
u8 boolean;
|
||||
provider->read(this->getOffset(), &boolean, 1);
|
||||
|
||||
if (boolean == 0)
|
||||
this->createDefaultEntry("false", false);
|
||||
else if (boolean == 1)
|
||||
this->createDefaultEntry("true", true);
|
||||
else
|
||||
this->createDefaultEntry("true*", true);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
return "bool";
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternCharacter : public Pattern {
|
||||
public:
|
||||
explicit PatternCharacter(Evaluator *evaluator, u64 offset, u32 color = 0)
|
||||
: Pattern(evaluator, offset, 1, color) { }
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternCharacter(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
char character;
|
||||
provider->read(this->getOffset(), &character, 1);
|
||||
|
||||
this->createDefaultEntry(hex::format("'{0}'", character), character);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
return "char";
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternEnum : public Pattern {
|
||||
public:
|
||||
PatternEnum(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0)
|
||||
: Pattern(evaluator, offset, size, color) {
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternEnum(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
u64 value = 0;
|
||||
provider->read(this->getOffset(), &value, this->getSize());
|
||||
value = hex::changeEndianess(value, this->getSize(), this->getEndian());
|
||||
|
||||
std::string valueString = Pattern::getTypeName() + "::";
|
||||
|
||||
bool foundValue = false;
|
||||
for (auto &[entryValueLiteral, entryName] : this->m_enumValues) {
|
||||
bool matches = std::visit(overloaded {
|
||||
[&, name = entryName](auto &&entryValue) {
|
||||
if (value == entryValue) {
|
||||
valueString += name;
|
||||
foundValue = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
[](std::string &) { return false; },
|
||||
[](std::shared_ptr<Pattern> &) { return false; } },
|
||||
entryValueLiteral);
|
||||
if (matches)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!foundValue)
|
||||
valueString += "???";
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_AllowItemOverlap);
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(this))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns)) {
|
||||
ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize());
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted(this->getDisplayName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:04X}", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormattedColored(ImColor(0xFFD69C56), "enum");
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted(Pattern::getTypeName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", this->formatDisplayValue(hex::format("{} (0x{:0{}X})", valueString.c_str(), value, this->getSize() * 2), this->clone()));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
return "enum " + Pattern::getTypeName();
|
||||
}
|
||||
|
||||
[[nodiscard]] const auto &getEnumValues() const {
|
||||
return this->m_enumValues;
|
||||
}
|
||||
|
||||
void setEnumValues(const std::vector<std::pair<Token::Literal, std::string>> &enumValues) {
|
||||
this->m_enumValues = enumValues;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override {
|
||||
if (!areCommonPropertiesEqual<decltype(*this)>(other))
|
||||
return false;
|
||||
|
||||
auto &otherEnum = *static_cast<const PatternEnum *>(&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::Literal, std::string>> m_enumValues;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternFloat : public Pattern {
|
||||
public:
|
||||
PatternFloat(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0)
|
||||
: Pattern(evaluator, offset, size, color) { }
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternFloat(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
if (this->getSize() == 4) {
|
||||
u32 data = 0;
|
||||
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), *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), *reinterpret_cast<double *>(&data));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
switch (this->getSize()) {
|
||||
case 4:
|
||||
return "float";
|
||||
case 8:
|
||||
return "double";
|
||||
default:
|
||||
return "Floating point data";
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternPadding : public Pattern {
|
||||
public:
|
||||
PatternPadding(Evaluator *evaluator, u64 offset, size_t size) : Pattern(evaluator, offset, size, 0xFF000000) { }
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternPadding(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
return "";
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternPointer : public Pattern,
|
||||
public Inlinable {
|
||||
public:
|
||||
PatternPointer(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0)
|
||||
: Pattern(evaluator, offset, size, color), m_pointedAt(nullptr) {
|
||||
}
|
||||
|
||||
PatternPointer(const PatternPointer &other) : Pattern(other) {
|
||||
this->m_pointedAt = other.m_pointedAt->clone();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternPointer(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
u64 data = 0;
|
||||
provider->read(this->getOffset(), &data, this->getSize());
|
||||
data = hex::changeEndianess(data, this->getSize(), this->getEndian());
|
||||
|
||||
bool open = true;
|
||||
|
||||
if (!this->isInlined()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(this))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
||||
ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize());
|
||||
}
|
||||
this->drawCommentTooltip();
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::ColorButton("color", ImColor(this->getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), this->getOffset() + this->getSize() - 1);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:04X}", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{}", this->getFormattedName());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", formatDisplayValue(hex::format("*(0x{0:X})", data), u128(data)));
|
||||
}
|
||||
|
||||
if (open) {
|
||||
this->m_pointedAt->createEntry(provider);
|
||||
|
||||
if (!this->isInlined())
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
void getHighlightedAddresses(std::map<u64, u32> &highlight) const override {
|
||||
Pattern::getHighlightedAddresses(highlight);
|
||||
this->m_pointedAt->getHighlightedAddresses(highlight);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
std::string result = this->m_pointedAt->getFormattedName() + "* : ";
|
||||
switch (this->getSize()) {
|
||||
case 1:
|
||||
result += "u8";
|
||||
break;
|
||||
case 2:
|
||||
result += "u16";
|
||||
break;
|
||||
case 4:
|
||||
result += "u32";
|
||||
break;
|
||||
case 8:
|
||||
result += "u64";
|
||||
break;
|
||||
case 16:
|
||||
result += "u128";
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void setPointedAtPattern(std::unique_ptr<Pattern> &&pattern) {
|
||||
this->m_pointedAt = std::move(pattern);
|
||||
this->m_pointedAt->setVariableName(hex::format("*({})", this->getVariableName()));
|
||||
this->m_pointedAt->setOffset(this->m_pointedAtAddress);
|
||||
}
|
||||
|
||||
void setPointedAtAddress(u64 address) {
|
||||
this->m_pointedAtAddress = address;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 getPointedAtAddress() const {
|
||||
return this->m_pointedAtAddress;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::unique_ptr<Pattern> &getPointedAtPattern() {
|
||||
return this->m_pointedAt;
|
||||
}
|
||||
|
||||
void setColor(u32 color) override {
|
||||
Pattern::setColor(color);
|
||||
this->m_pointedAt->setColor(color);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override {
|
||||
return areCommonPropertiesEqual<decltype(*this)>(other) &&
|
||||
*static_cast<const PatternPointer *>(&other)->m_pointedAt == *this->m_pointedAt;
|
||||
}
|
||||
|
||||
void rebase(u64 base) {
|
||||
if (this->m_pointedAt != nullptr) {
|
||||
this->m_pointedAtAddress = (this->m_pointedAt->getOffset() - this->m_pointerBase) + base;
|
||||
this->m_pointedAt->setOffset(this->m_pointedAtAddress);
|
||||
}
|
||||
|
||||
this->m_pointerBase = base;
|
||||
}
|
||||
|
||||
[[nodiscard]] const Pattern *getPattern(u64 offset) const override {
|
||||
if (offset >= this->getOffset() && offset < (this->getOffset() + this->getSize()) && !this->isHidden())
|
||||
return this;
|
||||
else
|
||||
return this->m_pointedAt->getPattern(offset);
|
||||
}
|
||||
|
||||
void setEndian(std::endian endian) override {
|
||||
this->m_pointedAt->setEndian(endian);
|
||||
|
||||
Pattern::setEndian(endian);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<Pattern> m_pointedAt;
|
||||
u64 m_pointedAtAddress = 0;
|
||||
|
||||
u64 m_pointerBase = 0;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternSigned : public Pattern {
|
||||
public:
|
||||
PatternSigned(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0)
|
||||
: Pattern(evaluator, offset, size, color) { }
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternSigned(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
i128 data = 0;
|
||||
provider->read(this->getOffset(), &data, this->getSize());
|
||||
data = hex::changeEndianess(data, this->getSize(), this->getEndian());
|
||||
|
||||
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 {
|
||||
switch (this->getSize()) {
|
||||
case 1:
|
||||
return "s8";
|
||||
case 2:
|
||||
return "s16";
|
||||
case 4:
|
||||
return "s32";
|
||||
case 8:
|
||||
return "s64";
|
||||
case 16:
|
||||
return "s128";
|
||||
default:
|
||||
return "Signed data";
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternString : public Pattern {
|
||||
public:
|
||||
PatternString(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0)
|
||||
: Pattern(evaluator, offset, size, color) { }
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternString(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
auto size = std::min<size_t>(this->getSize(), 0x7F);
|
||||
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
std::vector<u8> buffer(size, 0x00);
|
||||
provider->read(this->getOffset(), buffer.data(), size);
|
||||
|
||||
auto displayString = hex::encodeByteString(buffer);
|
||||
this->createDefaultEntry(hex::format("\"{0}\" {1}", displayString, size > this->getSize() ? "(truncated)" : ""), displayString);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
return "String";
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string toString(prv::Provider *provider) const override {
|
||||
std::string buffer(this->getSize(), 0x00);
|
||||
provider->read(this->getOffset(), buffer.data(), buffer.size());
|
||||
|
||||
std::erase_if(buffer, [](auto c) {
|
||||
return c == 0x00;
|
||||
});
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,156 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternStruct : public Pattern,
|
||||
public Inlinable {
|
||||
public:
|
||||
PatternStruct(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0)
|
||||
: Pattern(evaluator, offset, size, color) {
|
||||
}
|
||||
|
||||
PatternStruct(const PatternStruct &other) : Pattern(other) {
|
||||
for (const auto &member : other.m_members) {
|
||||
auto copy = member->clone();
|
||||
|
||||
this->m_sortedMembers.push_back(copy.get());
|
||||
this->m_members.push_back(std::move(copy));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternStruct(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
bool open = true;
|
||||
|
||||
if (!this->isInlined()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(this))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
||||
ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize());
|
||||
}
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), this->getOffset() + this->getSize() - (this->getSize() == 0 ? 0 : 1));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:04X}", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormattedColored(ImColor(0xFFD69C56), "struct");
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted(this->getTypeName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", this->formatDisplayValue("{ ... }", this->clone()));
|
||||
}
|
||||
|
||||
if (open) {
|
||||
for (auto &member : this->m_sortedMembers)
|
||||
member->draw(provider);
|
||||
|
||||
if (!this->isInlined())
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
void getHighlightedAddresses(std::map<u64, u32> &highlight) const override {
|
||||
for (auto &member : this->m_members) {
|
||||
member->getHighlightedAddresses(highlight);
|
||||
}
|
||||
}
|
||||
|
||||
void setOffset(u64 offset) override {
|
||||
for (auto &member : this->m_members)
|
||||
member->setOffset(member->getOffset() - this->getOffset() + offset);
|
||||
|
||||
Pattern::setOffset(offset);
|
||||
}
|
||||
|
||||
void setColor(u32 color) override {
|
||||
Pattern::setColor(color);
|
||||
for (auto &member : this->m_members) {
|
||||
if (!member->hasOverriddenColor())
|
||||
member->setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) override {
|
||||
this->m_sortedMembers.clear();
|
||||
for (auto &member : this->m_members)
|
||||
this->m_sortedMembers.push_back(member.get());
|
||||
|
||||
std::sort(this->m_sortedMembers.begin(), this->m_sortedMembers.end(), [&sortSpecs, &provider](Pattern *left, Pattern *right) {
|
||||
return Pattern::sortPatternTable(sortSpecs, provider, left, right);
|
||||
});
|
||||
|
||||
for (auto &member : this->m_members)
|
||||
member->sort(sortSpecs, provider);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
return "struct " + Pattern::getTypeName();
|
||||
}
|
||||
|
||||
[[nodiscard]] const auto &getMembers() const {
|
||||
return this->m_members;
|
||||
}
|
||||
|
||||
void setMembers(std::vector<std::shared_ptr<Pattern>> &&members) {
|
||||
this->m_members.clear();
|
||||
|
||||
for (auto &member : members) {
|
||||
if (member == nullptr) continue;
|
||||
|
||||
this->m_sortedMembers.push_back(member.get());
|
||||
this->m_members.push_back(std::move(member));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override {
|
||||
if (!areCommonPropertiesEqual<decltype(*this)>(other))
|
||||
return false;
|
||||
|
||||
auto &otherStruct = *static_cast<const PatternStruct *>(&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;
|
||||
}
|
||||
|
||||
[[nodiscard]] const Pattern *getPattern(u64 offset) const override {
|
||||
if (this->isHidden()) return nullptr;
|
||||
|
||||
auto iter = std::find_if(this->m_members.begin(), this->m_members.end(), [offset](const std::shared_ptr<Pattern> &pattern) {
|
||||
return offset >= pattern->getOffset() && offset < (pattern->getOffset() + pattern->getSize());
|
||||
});
|
||||
|
||||
if (iter == this->m_members.end())
|
||||
return nullptr;
|
||||
else
|
||||
return (*iter)->getPattern(offset);
|
||||
}
|
||||
|
||||
void setEndian(std::endian endian) override {
|
||||
for (auto &member : this->m_members) {
|
||||
if (!member->hasOverriddenEndian())
|
||||
member->setEndian(endian);
|
||||
}
|
||||
|
||||
Pattern::setEndian(endian);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<Pattern>> m_members;
|
||||
std::vector<Pattern *> m_sortedMembers;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternUnion : public Pattern,
|
||||
public Inlinable {
|
||||
public:
|
||||
PatternUnion(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0)
|
||||
: Pattern(evaluator, offset, size, color) {
|
||||
}
|
||||
|
||||
PatternUnion(const PatternUnion &other) : Pattern(other) {
|
||||
for (const auto &member : other.m_members) {
|
||||
auto copy = member->clone();
|
||||
|
||||
this->m_sortedMembers.push_back(copy.get());
|
||||
this->m_members.push_back(std::move(copy));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternUnion(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
bool open = true;
|
||||
|
||||
if (!this->isInlined()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
open = ImGui::TreeNodeEx(this->getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
ImGui::TableNextColumn();
|
||||
if (ImGui::Selectable(("##PatternLine"s + std::to_string(u64(this))).c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
||||
ImHexApi::HexEditor::setSelection(this->getOffset(), this->getSize());
|
||||
}
|
||||
this->drawCommentTooltip();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", this->getOffset(), std::max(this->getOffset() + this->getSize() - (this->getSize() == 0 ? 0 : 1), u64(0)));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:04X}", this->getSize());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormattedColored(ImColor(0xFFD69C56), "union");
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted(Pattern::getTypeName().c_str());
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", this->formatDisplayValue("{ ... }", this->clone()));
|
||||
}
|
||||
|
||||
if (open) {
|
||||
for (auto &member : this->m_sortedMembers)
|
||||
member->draw(provider);
|
||||
|
||||
if (!this->isInlined())
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
void getHighlightedAddresses(std::map<u64, u32> &highlight) const override {
|
||||
for (auto &member : this->m_members) {
|
||||
member->getHighlightedAddresses(highlight);
|
||||
}
|
||||
}
|
||||
|
||||
void setOffset(u64 offset) override {
|
||||
for (auto &member : this->m_members)
|
||||
member->setOffset(member->getOffset() - this->getOffset() + offset);
|
||||
|
||||
Pattern::setOffset(offset);
|
||||
}
|
||||
|
||||
void setColor(u32 color) override {
|
||||
Pattern::setColor(color);
|
||||
for (auto &member : this->m_members) {
|
||||
if (!member->hasOverriddenColor())
|
||||
member->setColor(color);
|
||||
}
|
||||
}
|
||||
|
||||
void sort(ImGuiTableSortSpecs *sortSpecs, prv::Provider *provider) override {
|
||||
this->m_sortedMembers.clear();
|
||||
for (auto &member : this->m_members)
|
||||
this->m_sortedMembers.push_back(member.get());
|
||||
|
||||
std::sort(this->m_sortedMembers.begin(), this->m_sortedMembers.end(), [&sortSpecs, &provider](Pattern *left, Pattern *right) {
|
||||
return Pattern::sortPatternTable(sortSpecs, provider, left, right);
|
||||
});
|
||||
|
||||
for (auto &member : this->m_members)
|
||||
member->sort(sortSpecs, provider);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
return "union " + Pattern::getTypeName();
|
||||
;
|
||||
}
|
||||
|
||||
[[nodiscard]] const auto &getMembers() const {
|
||||
return this->m_members;
|
||||
}
|
||||
|
||||
void setMembers(std::vector<std::shared_ptr<Pattern>> &&members) {
|
||||
this->m_members.clear();
|
||||
for (auto &member : members) {
|
||||
if (member == nullptr) continue;
|
||||
|
||||
this->m_sortedMembers.push_back(member.get());
|
||||
this->m_members.push_back(std::move(member));
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override {
|
||||
if (!areCommonPropertiesEqual<decltype(*this)>(other))
|
||||
return false;
|
||||
|
||||
auto &otherUnion = *static_cast<const PatternUnion *>(&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;
|
||||
}
|
||||
|
||||
[[nodiscard]] const Pattern *getPattern(u64 offset) const override {
|
||||
if (this->isHidden()) return nullptr;
|
||||
|
||||
auto largestMember = std::find_if(this->m_members.begin(), this->m_members.end(), [this](const std::shared_ptr<Pattern> &pattern) {
|
||||
return pattern->getSize() == this->getSize();
|
||||
});
|
||||
|
||||
if (largestMember == this->m_members.end())
|
||||
return nullptr;
|
||||
else
|
||||
return (*largestMember)->getPattern(offset);
|
||||
;
|
||||
}
|
||||
|
||||
void setEndian(std::endian endian) override {
|
||||
for (auto &member : this->m_members) {
|
||||
if (!member->hasOverriddenEndian())
|
||||
member->setEndian(endian);
|
||||
}
|
||||
|
||||
Pattern::setEndian(endian);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<std::shared_ptr<Pattern>> m_members;
|
||||
std::vector<Pattern *> m_sortedMembers;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternUnsigned : public Pattern {
|
||||
public:
|
||||
PatternUnsigned(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0)
|
||||
: Pattern(evaluator, offset, size, color) { }
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternUnsigned(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
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), data);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
switch (this->getSize()) {
|
||||
case 1:
|
||||
return "u8";
|
||||
case 2:
|
||||
return "u16";
|
||||
case 4:
|
||||
return "u32";
|
||||
case 8:
|
||||
return "u64";
|
||||
case 16:
|
||||
return "u128";
|
||||
default:
|
||||
return "Unsigned data";
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
#include <codecvt>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternWideCharacter : public Pattern {
|
||||
public:
|
||||
explicit PatternWideCharacter(Evaluator *evaluator, u64 offset, u32 color = 0)
|
||||
: Pattern(evaluator, offset, 2, color) { }
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternWideCharacter(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
char16_t character;
|
||||
provider->read(this->getOffset(), &character, 2);
|
||||
character = hex::changeEndianess(character, this->getEndian());
|
||||
|
||||
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]] std::string toString(prv::Provider *provider) const override {
|
||||
char16_t character;
|
||||
provider->read(this->getOffset(), &character, 2);
|
||||
character = hex::changeEndianess(character, this->getEndian());
|
||||
|
||||
return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.to_bytes(character);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/pattern_language/patterns/pattern.hpp>
|
||||
|
||||
#include <codecvt>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternWideString : public Pattern {
|
||||
public:
|
||||
PatternWideString(Evaluator *evaluator, u64 offset, size_t size, u32 color = 0)
|
||||
: Pattern(evaluator, offset, size, color) { }
|
||||
|
||||
[[nodiscard]] std::unique_ptr<Pattern> clone() const override {
|
||||
return std::unique_ptr<Pattern>(new PatternWideString(*this));
|
||||
}
|
||||
|
||||
void createEntry(prv::Provider *&provider) override {
|
||||
auto size = std::min<size_t>(this->getSize(), 0x100);
|
||||
|
||||
if (size == 0)
|
||||
return;
|
||||
|
||||
std::u16string buffer(this->getSize() / sizeof(char16_t), 0x00);
|
||||
provider->read(this->getOffset(), buffer.data(), size);
|
||||
|
||||
for (auto &c : buffer)
|
||||
c = hex::changeEndianess(c, 2, this->getEndian());
|
||||
|
||||
buffer.erase(std::remove_if(buffer.begin(), buffer.end(), [](auto c) {
|
||||
return c == 0x00;
|
||||
}),
|
||||
buffer.end());
|
||||
|
||||
auto utf8String = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.to_bytes(buffer);
|
||||
|
||||
this->createDefaultEntry(hex::format("\"{0}\" {1}", utf8String, size > this->getSize() ? "(truncated)" : ""), utf8String);
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getFormattedName() const override {
|
||||
return "String16";
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string toString(prv::Provider *provider) const override {
|
||||
std::u16string buffer(this->getSize() / sizeof(char16_t), 0x00);
|
||||
provider->read(this->getOffset(), buffer.data(), this->getSize());
|
||||
|
||||
for (auto &c : buffer)
|
||||
c = hex::changeEndianess(c, 2, this->getEndian());
|
||||
|
||||
std::erase_if(buffer, [](auto c) {
|
||||
return c == 0x00;
|
||||
});
|
||||
|
||||
return std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> {}.to_bytes(buffer);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool operator==(const Pattern &other) const override { return areCommonPropertiesEqual<decltype(*this)>(other); }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include <hex/helpers/paths.hpp>
|
||||
|
||||
#include <hex/pattern_language/error.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class Preprocessor {
|
||||
public:
|
||||
Preprocessor() = default;
|
||||
|
||||
std::optional<std::string> preprocess(const std::string &code, bool initialRun = true);
|
||||
|
||||
void addPragmaHandler(const std::string &pragmaType, const std::function<bool(const std::string &)> &function);
|
||||
void removePragmaHandler(const std::string &pragmaType);
|
||||
void addDefaultPragmaHandlers();
|
||||
|
||||
const std::optional<PatternLanguageError> &getError() { return this->m_error; }
|
||||
|
||||
bool shouldOnlyIncludeOnce() {
|
||||
return this->m_onlyIncludeOnce;
|
||||
}
|
||||
|
||||
private:
|
||||
[[noreturn]] static void throwPreprocessorError(const std::string &error, u32 lineNumber) {
|
||||
throw PatternLanguageError(lineNumber, "Preprocessor: " + error);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::function<bool(std::string)>> m_pragmaHandlers;
|
||||
|
||||
std::set<std::tuple<std::string, std::string, u32>> m_defines;
|
||||
std::set<std::tuple<std::string, std::string, u32>> m_pragmas;
|
||||
|
||||
std::set<fs::path> m_onceIncludedFiles;
|
||||
|
||||
std::optional<PatternLanguageError> m_error;
|
||||
|
||||
bool m_onlyIncludeOnce = false;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,364 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <variant>
|
||||
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/pattern_language/log_console.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNode;
|
||||
class Pattern;
|
||||
|
||||
class Token {
|
||||
public:
|
||||
enum class Type : u64
|
||||
{
|
||||
Keyword,
|
||||
ValueType,
|
||||
Operator,
|
||||
Integer,
|
||||
String,
|
||||
Identifier,
|
||||
Separator
|
||||
};
|
||||
|
||||
enum class Keyword
|
||||
{
|
||||
Struct,
|
||||
Union,
|
||||
Using,
|
||||
Enum,
|
||||
Bitfield,
|
||||
LittleEndian,
|
||||
BigEndian,
|
||||
If,
|
||||
Else,
|
||||
Parent,
|
||||
This,
|
||||
While,
|
||||
For,
|
||||
Function,
|
||||
Return,
|
||||
Namespace,
|
||||
In,
|
||||
Out,
|
||||
Break,
|
||||
Continue
|
||||
};
|
||||
|
||||
enum class Operator
|
||||
{
|
||||
AtDeclaration,
|
||||
Assignment,
|
||||
Inherit,
|
||||
Plus,
|
||||
Minus,
|
||||
Star,
|
||||
Slash,
|
||||
Percent,
|
||||
ShiftLeft,
|
||||
ShiftRight,
|
||||
BitOr,
|
||||
BitAnd,
|
||||
BitXor,
|
||||
BitNot,
|
||||
BoolEquals,
|
||||
BoolNotEquals,
|
||||
BoolGreaterThan,
|
||||
BoolLessThan,
|
||||
BoolGreaterThanOrEquals,
|
||||
BoolLessThanOrEquals,
|
||||
BoolAnd,
|
||||
BoolOr,
|
||||
BoolXor,
|
||||
BoolNot,
|
||||
TernaryConditional,
|
||||
Dollar,
|
||||
AddressOf,
|
||||
SizeOf,
|
||||
ScopeResolution
|
||||
};
|
||||
|
||||
enum class ValueType
|
||||
{
|
||||
Unsigned8Bit = 0x10,
|
||||
Signed8Bit = 0x11,
|
||||
Unsigned16Bit = 0x20,
|
||||
Signed16Bit = 0x21,
|
||||
Unsigned32Bit = 0x40,
|
||||
Signed32Bit = 0x41,
|
||||
Unsigned64Bit = 0x80,
|
||||
Signed64Bit = 0x81,
|
||||
Unsigned128Bit = 0x100,
|
||||
Signed128Bit = 0x101,
|
||||
Character = 0x13,
|
||||
Character16 = 0x23,
|
||||
Boolean = 0x14,
|
||||
Float = 0x42,
|
||||
Double = 0x82,
|
||||
String = 0x15,
|
||||
Auto = 0x16,
|
||||
CustomType = 0x00,
|
||||
Padding = 0x1F,
|
||||
|
||||
Unsigned = 0xFF00,
|
||||
Signed = 0xFF01,
|
||||
FloatingPoint = 0xFF02,
|
||||
Integer = 0xFF03,
|
||||
Any = 0xFFFF
|
||||
};
|
||||
|
||||
enum class Separator
|
||||
{
|
||||
RoundBracketOpen,
|
||||
RoundBracketClose,
|
||||
CurlyBracketOpen,
|
||||
CurlyBracketClose,
|
||||
SquareBracketOpen,
|
||||
SquareBracketClose,
|
||||
Comma,
|
||||
Dot,
|
||||
EndOfExpression,
|
||||
EndOfProgram
|
||||
};
|
||||
|
||||
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, i128, double, std::string, std::shared_ptr<Pattern>>;
|
||||
using ValueTypes = std::variant<Keyword, Identifier, Operator, Literal, ValueType, Separator>;
|
||||
|
||||
Token(Type type, auto value, u32 lineNumber) : type(type), value(value), lineNumber(lineNumber) {
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr static inline bool isUnsigned(const ValueType type) {
|
||||
return (static_cast<u32>(type) & 0x0F) == 0x00;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr static inline bool isSigned(const ValueType type) {
|
||||
return (static_cast<u32>(type) & 0x0F) == 0x01;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr static inline bool isFloatingPoint(const ValueType type) {
|
||||
return (static_cast<u32>(type) & 0x0F) == 0x02;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr static inline u32 getTypeSize(const ValueType type) {
|
||||
return static_cast<u32>(type) >> 4;
|
||||
}
|
||||
|
||||
static u128 literalToUnsigned(const pl::Token::Literal &literal) {
|
||||
return std::visit(overloaded {
|
||||
[](const std::string &) -> u128 { LogConsole::abortEvaluation("expected integral type, got string"); },
|
||||
[](const std::shared_ptr<Pattern> &) -> u128 { LogConsole::abortEvaluation("expected integral type, got custom type"); },
|
||||
[](auto &&result) -> u128 { return result; } },
|
||||
literal);
|
||||
}
|
||||
|
||||
static i128 literalToSigned(const pl::Token::Literal &literal) {
|
||||
return std::visit(overloaded {
|
||||
[](const std::string &) -> i128 { LogConsole::abortEvaluation("expected integral type, got string"); },
|
||||
[](const std::shared_ptr<Pattern> &) -> i128 { LogConsole::abortEvaluation("expected integral type, got custom type"); },
|
||||
[](auto &&result) -> i128 { return result; } },
|
||||
literal);
|
||||
}
|
||||
|
||||
static double literalToFloatingPoint(const pl::Token::Literal &literal) {
|
||||
return std::visit(overloaded {
|
||||
[](const std::string &) -> double { LogConsole::abortEvaluation("expected integral type, got string"); },
|
||||
[](const std::shared_ptr<Pattern> &) -> double { LogConsole::abortEvaluation("expected integral type, got custom type"); },
|
||||
[](auto &&result) -> double { return result; } },
|
||||
literal);
|
||||
}
|
||||
|
||||
static bool literalToBoolean(const pl::Token::Literal &literal) {
|
||||
return std::visit(overloaded {
|
||||
[](const std::string &) -> bool { LogConsole::abortEvaluation("expected integral type, got string"); },
|
||||
[](const std::unique_ptr<Pattern> &) -> bool { LogConsole::abortEvaluation("expected integral type, got custom type"); },
|
||||
[](auto &&result) -> bool { return result != 0; } },
|
||||
literal);
|
||||
}
|
||||
|
||||
static std::string literalToString(const pl::Token::Literal &literal, bool cast) {
|
||||
if (!cast && std::get_if<std::string>(&literal) == nullptr)
|
||||
LogConsole::abortEvaluation("expected string type, got integral");
|
||||
|
||||
return std::visit(overloaded {
|
||||
[](std::string result) -> std::string { return result; },
|
||||
[](u128 result) -> std::string { return hex::to_string(result); },
|
||||
[](i128 result) -> std::string { return hex::to_string(result); },
|
||||
[](bool result) -> std::string { return result ? "true" : "false"; },
|
||||
[](char result) -> std::string { return { 1, result }; },
|
||||
[](const std::shared_ptr<Pattern> &) -> std::string { LogConsole::abortEvaluation("expected integral type, got custom type"); },
|
||||
[](auto &&result) -> std::string { return std::to_string(result); } },
|
||||
literal);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr static auto getTypeName(const pl::Token::ValueType type) {
|
||||
switch (type) {
|
||||
case ValueType::Signed8Bit:
|
||||
return "s8";
|
||||
case ValueType::Signed16Bit:
|
||||
return "s16";
|
||||
case ValueType::Signed32Bit:
|
||||
return "s32";
|
||||
case ValueType::Signed64Bit:
|
||||
return "s64";
|
||||
case ValueType::Signed128Bit:
|
||||
return "s128";
|
||||
case ValueType::Unsigned8Bit:
|
||||
return "u8";
|
||||
case ValueType::Unsigned16Bit:
|
||||
return "u16";
|
||||
case ValueType::Unsigned32Bit:
|
||||
return "u32";
|
||||
case ValueType::Unsigned64Bit:
|
||||
return "u64";
|
||||
case ValueType::Unsigned128Bit:
|
||||
return "u128";
|
||||
case ValueType::Float:
|
||||
return "float";
|
||||
case ValueType::Double:
|
||||
return "double";
|
||||
case ValueType::Character:
|
||||
return "char";
|
||||
case ValueType::Character16:
|
||||
return "char16";
|
||||
case ValueType::Padding:
|
||||
return "padding";
|
||||
case ValueType::String:
|
||||
return "str";
|
||||
default:
|
||||
return "< ??? >";
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const ValueTypes &other) const {
|
||||
if (this->type == Type::Integer || this->type == Type::Identifier || this->type == Type::String)
|
||||
return true;
|
||||
else if (this->type == Type::ValueType) {
|
||||
auto otherValueType = std::get_if<ValueType>(&other);
|
||||
auto valueType = std::get_if<ValueType>(&this->value);
|
||||
|
||||
if (otherValueType == nullptr) return false;
|
||||
if (valueType == nullptr) return false;
|
||||
|
||||
if (*otherValueType == *valueType)
|
||||
return true;
|
||||
else if (*otherValueType == ValueType::Any)
|
||||
return *valueType != ValueType::CustomType && *valueType != ValueType::Padding;
|
||||
else if (*otherValueType == ValueType::Unsigned)
|
||||
return isUnsigned(*valueType);
|
||||
else if (*otherValueType == ValueType::Signed)
|
||||
return isSigned(*valueType);
|
||||
else if (*otherValueType == ValueType::FloatingPoint)
|
||||
return isFloatingPoint(*valueType);
|
||||
else if (*otherValueType == ValueType::Integer)
|
||||
return isUnsigned(*valueType) || isSigned(*valueType);
|
||||
} else
|
||||
return other == this->value;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator!=(const ValueTypes &other) const {
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
Type type;
|
||||
ValueTypes value;
|
||||
u32 lineNumber;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#define COMPONENT(type, value) hex::pl::Token::Type::type, hex::pl::Token::type::value
|
||||
|
||||
#define KEYWORD_STRUCT COMPONENT(Keyword, Struct)
|
||||
#define KEYWORD_UNION COMPONENT(Keyword, Union)
|
||||
#define KEYWORD_USING COMPONENT(Keyword, Using)
|
||||
#define KEYWORD_ENUM COMPONENT(Keyword, Enum)
|
||||
#define KEYWORD_BITFIELD COMPONENT(Keyword, Bitfield)
|
||||
#define KEYWORD_LE COMPONENT(Keyword, LittleEndian)
|
||||
#define KEYWORD_BE COMPONENT(Keyword, BigEndian)
|
||||
#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_FOR COMPONENT(Keyword, For)
|
||||
#define KEYWORD_FUNCTION COMPONENT(Keyword, Function)
|
||||
#define KEYWORD_RETURN COMPONENT(Keyword, Return)
|
||||
#define KEYWORD_NAMESPACE COMPONENT(Keyword, Namespace)
|
||||
#define KEYWORD_IN COMPONENT(Keyword, In)
|
||||
#define KEYWORD_OUT COMPONENT(Keyword, Out)
|
||||
#define KEYWORD_BREAK COMPONENT(Keyword, Break)
|
||||
#define KEYWORD_CONTINUE COMPONENT(Keyword, Continue)
|
||||
|
||||
#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, hex::pl::Token::Literal("")
|
||||
|
||||
#define OPERATOR_ANY COMPONENT(Operator, Any)
|
||||
#define OPERATOR_AT COMPONENT(Operator, AtDeclaration)
|
||||
#define OPERATOR_ASSIGNMENT COMPONENT(Operator, Assignment)
|
||||
#define OPERATOR_INHERIT COMPONENT(Operator, Inherit)
|
||||
#define OPERATOR_PLUS COMPONENT(Operator, Plus)
|
||||
#define OPERATOR_MINUS COMPONENT(Operator, Minus)
|
||||
#define OPERATOR_STAR COMPONENT(Operator, Star)
|
||||
#define OPERATOR_SLASH COMPONENT(Operator, Slash)
|
||||
#define OPERATOR_PERCENT COMPONENT(Operator, Percent)
|
||||
#define OPERATOR_SHIFTLEFT COMPONENT(Operator, ShiftLeft)
|
||||
#define OPERATOR_SHIFTRIGHT COMPONENT(Operator, ShiftRight)
|
||||
#define OPERATOR_BITOR COMPONENT(Operator, BitOr)
|
||||
#define OPERATOR_BITAND COMPONENT(Operator, BitAnd)
|
||||
#define OPERATOR_BITXOR COMPONENT(Operator, BitXor)
|
||||
#define OPERATOR_BITNOT COMPONENT(Operator, BitNot)
|
||||
#define OPERATOR_BOOLEQUALS COMPONENT(Operator, BoolEquals)
|
||||
#define OPERATOR_BOOLNOTEQUALS COMPONENT(Operator, BoolNotEquals)
|
||||
#define OPERATOR_BOOLGREATERTHAN COMPONENT(Operator, BoolGreaterThan)
|
||||
#define OPERATOR_BOOLLESSTHAN COMPONENT(Operator, BoolLessThan)
|
||||
#define OPERATOR_BOOLGREATERTHANOREQUALS COMPONENT(Operator, BoolGreaterThanOrEquals)
|
||||
#define OPERATOR_BOOLLESSTHANOREQUALS COMPONENT(Operator, BoolLessThanOrEquals)
|
||||
#define OPERATOR_BOOLAND COMPONENT(Operator, BoolAnd)
|
||||
#define OPERATOR_BOOLOR COMPONENT(Operator, BoolOr)
|
||||
#define OPERATOR_BOOLXOR COMPONENT(Operator, BoolXor)
|
||||
#define OPERATOR_BOOLNOT COMPONENT(Operator, BoolNot)
|
||||
#define OPERATOR_TERNARYCONDITIONAL COMPONENT(Operator, TernaryConditional)
|
||||
#define OPERATOR_DOLLAR COMPONENT(Operator, Dollar)
|
||||
#define OPERATOR_ADDRESSOF COMPONENT(Operator, AddressOf)
|
||||
#define OPERATOR_SIZEOF COMPONENT(Operator, SizeOf)
|
||||
#define OPERATOR_SCOPERESOLUTION COMPONENT(Operator, ScopeResolution)
|
||||
|
||||
#define VALUETYPE_CUSTOMTYPE COMPONENT(ValueType, CustomType)
|
||||
#define VALUETYPE_PADDING COMPONENT(ValueType, Padding)
|
||||
#define VALUETYPE_UNSIGNED COMPONENT(ValueType, Unsigned)
|
||||
#define VALUETYPE_SIGNED COMPONENT(ValueType, Signed)
|
||||
#define VALUETYPE_FLOATINGPOINT COMPONENT(ValueType, FloatingPoint)
|
||||
#define VALUETYPE_AUTO COMPONENT(ValueType, Auto)
|
||||
#define VALUETYPE_ANY COMPONENT(ValueType, Any)
|
||||
|
||||
#define SEPARATOR_ROUNDBRACKETOPEN COMPONENT(Separator, RoundBracketOpen)
|
||||
#define SEPARATOR_ROUNDBRACKETCLOSE COMPONENT(Separator, RoundBracketClose)
|
||||
#define SEPARATOR_CURLYBRACKETOPEN COMPONENT(Separator, CurlyBracketOpen)
|
||||
#define SEPARATOR_CURLYBRACKETCLOSE COMPONENT(Separator, CurlyBracketClose)
|
||||
#define SEPARATOR_SQUAREBRACKETOPEN COMPONENT(Separator, SquareBracketOpen)
|
||||
#define SEPARATOR_SQUAREBRACKETCLOSE COMPONENT(Separator, SquareBracketClose)
|
||||
#define SEPARATOR_COMMA COMPONENT(Separator, Comma)
|
||||
#define SEPARATOR_DOT COMPONENT(Separator, Dot)
|
||||
#define SEPARATOR_ENDOFEXPRESSION COMPONENT(Separator, EndOfExpression)
|
||||
#define SEPARATOR_ENDOFPROGRAM COMPONENT(Separator, EndOfProgram)
|
||||
@@ -1,32 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/pattern_language/error.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class ASTNode;
|
||||
|
||||
class Validator {
|
||||
public:
|
||||
Validator() = default;
|
||||
|
||||
bool validate(const std::vector<std::shared_ptr<ASTNode>> &ast);
|
||||
|
||||
const std::optional<PatternLanguageError> &getError() { return this->m_error; }
|
||||
|
||||
private:
|
||||
std::optional<PatternLanguageError> m_error;
|
||||
|
||||
[[noreturn]] static void throwValidatorError(const std::string &error, u32 lineNumber) {
|
||||
throw PatternLanguageError(lineNumber, "Validator: " + error);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -8,7 +8,7 @@ namespace hex::prv {
|
||||
|
||||
class Overlay {
|
||||
public:
|
||||
Overlay() { }
|
||||
Overlay() = default;
|
||||
|
||||
void setAddress(u64 address) { this->m_address = address; }
|
||||
[[nodiscard]] u64 getAddress() const { return this->m_address; }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user