Compare commits

...

81 Commits

Author SHA1 Message Date
WerWolv
9d556ecc0f build: Bumped version to 1.17.0 2022-04-18 01:53:01 +02:00
WerWolv
ea2c2df614 sys: Updated pattern language library 2022-04-18 01:22:06 +02:00
Lukas Cone
202a02af10 fix: Crash on linux when opened file gets modified (#487) 2022-04-17 23:07:14 +02:00
WerWolv
6ee71e3a9e sys: Fixed log spam when displaying the custom paths settings tab 2022-04-17 23:05:03 +02:00
WerWolv
1e7ed14810 tests: Removed pattern language tests as they are now done in their own repo 2022-04-17 18:11:39 +02:00
WerWolv
17383083fb patterns: Use standalone pattern language library instead of built-in one 2022-04-17 16:57:30 +02:00
WerWolv
f5fe49923b fix: Let's not cause UB on every event call... 2022-04-15 19:02:36 +02:00
WerWolv
457d338a97 ui: Include null byte in InputText fields 2022-04-14 15:29:54 +02:00
Polshakov Dmitry
4928c044af patterns: Move pattern drawer into builtin plugin (#482)
Co-authored-by: Dmitry Polshakov <dmitry.polshakov@dsr-corporation.com>
2022-04-08 16:08:02 +02:00
WerWolv
299c69686e git: Move pattern repo link further up to make it easier to find 2022-04-08 14:26:56 +02:00
WerWolv
b7132af214 patterns: Added missing override 2022-04-07 18:19:19 +02:00
WerWolv
74a5c974e6 patterns: Fixed comments behind pre-processor defines 2022-04-07 13:15:07 +02:00
WerWolv
942a4e9616 patterns: Fixed selection of static array entries 2022-04-07 12:59:23 +02:00
WerWolv
76f732dc53 patterns: Fixed various render issues 2022-04-07 12:47:45 +02:00
WerWolv
0462cc3d0c sys: Enable -Wall, -Wextra, -Werror and fix all warnings on all Platforms (#483)
* sys: Make ImHex compile with -Wall -Wextra -Werror

* sys: Fixed various build errors on Linux

* sys: Explicitly ignore return value of `system` function

* sys: More fixes for the warnings GitHub Actions enables somehow

* sys: More fixes

* sys: Remove -Werror again to see all GitHub Actions warnings

* sys: Hopefully fixed all remaining warnings

* sys: Added back -Werror

* git: Change windows icon in GitHub Actions
2022-03-27 00:01:28 +01:00
WerWolv
965207d688 ui: Replace data inspector endian and format radio boxes with sliders 2022-03-26 17:44:01 +01:00
WerWolv
0f0a836fa0 ui: Enable undo and redo menu items only if that action is available 2022-03-26 17:21:51 +01:00
WerWolv
29fb1de882 ui/ux: Make information view plots not capture scroll, removed plot background 2022-03-26 17:19:08 +01:00
WerWolv
a807dc81a0 ui: Fixed displaying of file stat times in information view 2022-03-26 17:18:40 +01:00
WerWolv
a4d3173da9 ux: Moved bookmark remove button from body to header 2022-03-26 16:55:48 +01:00
WerWolv
4b6a76bf02 fix: Bookmarks not always creating new highlights correctly 2022-03-26 16:54:15 +01:00
WerWolv
35a520f132 ux: Disable various menu items when no provider is active 2022-03-26 16:42:11 +01:00
WerWolv
1c53d2c123 ux: Automatically remove recently opened file entries if the file doesn't exist anymore 2022-03-26 16:34:29 +01:00
WerWolv
591d98b55b sys: Improved string search filtering 2022-03-25 21:08:38 +01:00
WerWolv
f39ec58435 ui: Use pretty hexadecimal input fields in more places 2022-03-25 21:07:41 +01:00
WerWolv
e72a30ca59 patterns: Make default parameters work properly with parameter packs 2022-03-25 09:53:58 +01:00
WerWolv
368c943040 patterns: Added default parameters 2022-03-24 20:31:45 +01:00
WerWolv
a16e387dff patterns: Fixed copying of type decl nodes 2022-03-24 18:00:00 +01:00
WerWolv
95cf828975 patterns: Prevent usage of incomplete types 2022-03-24 17:00:10 +01:00
WerWolv
c09d85f46d patterns: Allow forward declaring of types 2022-03-24 16:57:12 +01:00
WerWolv
c2803fe1e2 sys: Fixed build errors and warnings on Unix 2022-03-22 09:34:26 +01:00
WerWolv
98dfc2e286 sys: Replace __builtin_unreachable() with hex::unreachable() 2022-03-22 09:08:34 +01:00
WerWolv
ea848dbfc0 ux: Added support for mathematical expressions in goto fields 2022-03-22 09:06:02 +01:00
WerWolv
f7cfee55d5 ui: Enable multi viewports on Linux again if you're not on Wayland 2022-03-22 08:20:14 +01:00
WerWolv
26a7b3325d patterns: Unified displaying and stringifying string patterns 2022-03-22 08:19:46 +01:00
WerWolv
47fd5bdc00 patterns: Fixed pointer type displaying causing crashes
Fixes #480
2022-03-22 08:19:14 +01:00
Polshakov Dmitry
5dfa9cf501 patterns: Move logic to draw patterns into separate class (#472)
* refactor(patterns): add visitor interface

* refactor(patterns): add public accessors

* refactor(patterns): add method to get pattern value

* refactor(pattern): make some methods public

* refactor(pattern): extract code to draw GUI

* refactor(patterns): remove GUI related code from patterns

* refactor: move common GUI function from pattern to pattern_drawer

* refactor(pattern_drawer): extract common code into methods

* refactor: rename ImGuiDrawer -> PatternDrawer

* refactor(patternr): move displayEnd into PatternDrawer

* refactor: use ArrayPattern concept to restrict argument type

Co-authored-by: Dmitry Polshakov <dmitry.polshakov@dsr-corporation.com>
2022-03-21 13:52:07 +01:00
WerWolv
854c99bafa build: Replace manual AppImage bundling with appimage-builder script (#477)
* build: Tried to streamline and fix AppImage building

* build: Tried fixing build

* build: Added back version key

* build: Fixed AppImage name

* build: Fixed python bundling, fixed ELF uploading

* build: Don't upload a bunch of AppImage garbage files in the portable ELF version

* build: Fixed another wrong library path

* build: Removed old manual AppImage building scripts
2022-03-20 23:43:55 +01:00
Polshakov Dmitry
937ccbc5bd patterns: Restore data offset for local variables / added array, nested structs and functions tests (#475)
* fix(eval): restore data offset for local variables

* test(pattern_lang): add tests for arrays, nested structs and functions

Co-authored-by: Dmitry Polshakov <dmitry.polshakov@dsr-corporation.com>
2022-03-20 21:42:21 +01:00
WerWolv
bc7c494316 patterns: Fixed highlighting of static array entries 2022-03-19 00:47:36 +01:00
WerWolv
17a2be41da patterns: Fixed crash when applying certain attributes to types 2022-03-19 00:24:41 +01:00
Lukas Cone
ab5966fa9d ui: fixed theme not changing on startup (#474) 2022-03-18 17:01:39 +01:00
WerWolv
89fe063b02 patterns: Fixed struct members that overlap with [[no_unique_address]] members not being highlighted 2022-03-17 23:32:22 +01:00
WerWolv
7061a1ebfa patterns: Allow bitfield fields to be selected 2022-03-17 23:31:36 +01:00
WerWolv
ec9a947259 patterns: Fixed highlight colors of arrays not matching color shown in pattern data view 2022-03-17 23:31:16 +01:00
WerWolv
11441d632b patterns: Fixed indentation of inlined variables 2022-03-17 23:30:38 +01:00
WerWolv
a17b647e79 patterns: Fixed static arrays showing same value for all entries 2022-03-17 23:29:52 +01:00
WerWolv
2d87d29fa0 patterns: Fixed recursive types 2022-03-17 00:10:16 +01:00
WerWolv
844845223f fix: Saving interface.ini file failing if imhex is installed in a non-writable location
Fixes #473
2022-03-16 13:23:36 +01:00
WerWolv
f2159e26d2 build: Updated libromfs 2022-03-16 00:15:06 +01:00
Polshakov Dmitry
d677762dff perf(pattern): save display value in cache (#466)
Co-authored-by: Dmitry Polshakov <dmitry.polshakov@dsr-corporation.com>
2022-03-16 00:01:01 +01:00
WerWolv
3801e0d60b build: Remove yara's cuckoo module again since we don't have jansson available 2022-03-15 23:54:55 +01:00
WerWolv
f6a498854c ui: Added console to yara view, add support for yara's new console module 2022-03-15 23:48:49 +01:00
WerWolv
29ded2483c sys: Make sure deferred call adding is thread safe 2022-03-15 23:46:02 +01:00
WerWolv
050e17298a build: Updated various dependencies 2022-03-15 23:45:33 +01:00
WerWolv
af882b172e sys: Cache provider validity when drawing toolbar items
Possibly addresses issue mentioned in #465
2022-03-13 17:46:59 +01:00
WerWolv
caad8c25ad sys: Prevent splash screen from creating a imgui.ini save file
Fixes #467
2022-03-13 17:36:50 +01:00
WerWolv
74ef9ece30 ui: Properly clear highlighting cache when switching provider
Fixes #471
2022-03-13 17:33:27 +01:00
WerWolv
97bfb4004b fix: Crash when custom font file can't be found
Fixes #468
2022-03-13 17:11:02 +01:00
Lukas Cone
3da1b3f05d ui/patterns: Added settings tooltips, fixed pattern crash (#464)
* fix: pattern segfault typo

* ui: added few tooltips into settings

Co-authored-by: WerWolv <werwolv98@gmail.com>
2022-03-05 23:32:30 +01:00
xtexChooser
f21b22ae15 feat(i18n): update Chinese(Simplified) translations (#463)
* feat(i18n): update Chinese(Simplified) translations

* fix(i18n): fix typo

* feat(i18n): update translations
2022-03-05 23:30:21 +01:00
WerWolv
327e904dbc sys: Fixed many clang tidy warnings and typos 2022-03-04 20:52:39 +01:00
WerWolv
57c449936f sys: Improved math evaluator 2022-03-04 19:20:21 +01:00
WerWolv
efe6137067 ui: Improved look of the about page 2022-03-04 19:06:29 +01:00
WerWolv
96e9400761 sys: Fixed unit test building 2022-03-04 14:34:37 +01:00
WerWolv
6a517feda3 sys: More Linux and macOS build fixes 2022-03-04 14:00:02 +01:00
WerWolv
3b7a928313 sys: Fixed missing includes on Unix 2022-03-04 11:44:11 +01:00
WerWolv
2739320f10 sys: Refactor of filesystem functions. Fixed crashes where fs errors weren't caught correctly
Addresses the crash mentioned in #462
2022-03-04 11:36:37 +01:00
WerWolv
7866e3fc2a build: Bumped version to 1.16.2 2022-03-03 14:32:30 +01:00
WerWolv
2abf89cd16 tests: Fixed build 2022-03-03 13:35:12 +01:00
WerWolv
8b2dcf976f patterns: Fixed auto parameter crash 2022-03-03 13:34:05 +01:00
WerWolv
559b86efe1 patterns: Display actual type name of types declared with using 2022-03-03 13:33:45 +01:00
WerWolv
949a26ca0e patterns: Fixed memory leak when using format attribute 2022-03-03 12:11:47 +01:00
WerWolv
2880ca00da patterns: Fixed crash when using attributes 2022-03-03 11:19:46 +01:00
WerWolv
39da62532b fix: Trailing zero at end of string input buffers 2022-03-03 09:27:27 +01:00
WerWolv
483ba95d80 fix: Some text boxes not being writable 2022-03-03 09:24:09 +01:00
WerWolv
2300b0c692 fix: Searching not working at all 2022-03-03 09:06:10 +01:00
WerWolv
cc59b36c54 patterns: Properly reset back current control flow type in arrays
Fixes issue mentioned in #460
2022-03-01 20:57:21 +01:00
WerWolv
61d9918dae patterns: Evaluate return value before setting control flow type
Fixes another issue mentioned in #460
2022-03-01 20:37:27 +01:00
WerWolv
2c361f9b0a build: Don't bundle yara rules anymore because Microsoft Defender is a little cry baby 2022-03-01 20:27:19 +01:00
WerWolv
775b3e8c52 patterns: Fixed crash when using control flow statements without value
Fixes #460
2022-03-01 20:17:03 +01:00
231 changed files with 2670 additions and 10645 deletions

View File

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

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

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

View File

@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.16)
# Updating the version here will update it throughout ImHex as well
set(IMHEX_VERSION "1.16.1")
set(IMHEX_VERSION "1.17.0")
project(imhex VERSION ${IMHEX_VERSION})
set(CMAKE_CXX_STANDARD 20)

View File

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

View File

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

View File

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

View File

@@ -1,6 +0,0 @@
[Desktop Entry]
Name=ImHex
Exec=imhex
Icon=imhex
Type=Application
Categories=Utility;

View File

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

View File

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

View File

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,7 +11,7 @@ struct ImGuiWindow;
namespace hex {
struct View;
class View;
enum class Keys
{

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

View File

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

View File

@@ -0,0 +1,13 @@
#pragma once
namespace hex {
[[noreturn]] inline void unreachable() {
__builtin_unreachable();
}
inline void unused(auto && ... x) {
((void)x, ...);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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