mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-28 07:47:03 -05:00
Compare commits
254 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
716d6ae850 | ||
|
|
ceb07b7425 | ||
|
|
4885175ac6 | ||
|
|
d0f1a40f16 | ||
|
|
fc20d751bb | ||
|
|
dfc22abf35 | ||
|
|
de269e7a48 | ||
|
|
0ed885fe0f | ||
|
|
f9fc7051fc | ||
|
|
ab1f4df9d9 | ||
|
|
710771b8b1 | ||
|
|
2d982e2088 | ||
|
|
ef5fbba56b | ||
|
|
eadcc6f38c | ||
|
|
3db50a690c | ||
|
|
96aa929c31 | ||
|
|
e07fc76abf | ||
|
|
f01e227c87 | ||
|
|
cd34d567a7 | ||
|
|
bb429aae62 | ||
|
|
19f99bab0c | ||
|
|
1f433fc36d | ||
|
|
034cc0cd2f | ||
|
|
3efdc02fed | ||
|
|
501d141e13 | ||
|
|
9c1006f3ae | ||
|
|
5b0813478e | ||
|
|
ac964dc5ec | ||
|
|
11c2f240a1 | ||
|
|
8db2bdb6a7 | ||
|
|
7242eb8f4c | ||
|
|
60c6abbfcc | ||
|
|
a4c432f435 | ||
|
|
d50be26771 | ||
|
|
673027c82d | ||
|
|
e02ccd9b9b | ||
|
|
956276d1ee | ||
|
|
a936cf1ce4 | ||
|
|
5800546369 | ||
|
|
01adc8a2cd | ||
|
|
b1b33b2ae4 | ||
|
|
6506291e4e | ||
|
|
3471b314dd | ||
|
|
546d0a4922 | ||
|
|
c6989c2ef7 | ||
|
|
a5aa002752 | ||
|
|
b89490bca3 | ||
|
|
e33726f526 | ||
|
|
c238767750 | ||
|
|
116aeede2d | ||
|
|
662d80abea | ||
|
|
f6ddb3c5e7 | ||
|
|
6490e565d3 | ||
|
|
6b7ade8d61 | ||
|
|
9b77d7b5e2 | ||
|
|
1785088456 | ||
|
|
4dcd26a21f | ||
|
|
12e99a9d4c | ||
|
|
5e67a1f27b | ||
|
|
2a76e45dc5 | ||
|
|
6266883e81 | ||
|
|
aed9d15625 | ||
|
|
5551e82fea | ||
|
|
653a688fe6 | ||
|
|
dfc1dc2529 | ||
|
|
1e511acf37 | ||
|
|
141ee62af9 | ||
|
|
a5d202ffc8 | ||
|
|
f243ac7464 | ||
|
|
91ac9ca120 | ||
|
|
a56ba50cf9 | ||
|
|
fdaad55cc6 | ||
|
|
9d19214be9 | ||
|
|
038a6b9757 | ||
|
|
bad109ef8d | ||
|
|
5623e1342b | ||
|
|
6bad50c78b | ||
|
|
6929ffb865 | ||
|
|
2d7fdc0896 | ||
|
|
d1d73bcff6 | ||
|
|
bf1441223c | ||
|
|
fadca9a34a | ||
|
|
2ef3a0c157 | ||
|
|
c96a0a7bda | ||
|
|
fe6be686b7 | ||
|
|
05862ae991 | ||
|
|
6a6b6b94cf | ||
|
|
4701b1b67c | ||
|
|
f1b2d5881e | ||
|
|
efed07ac8b | ||
|
|
e5ff987392 | ||
|
|
8a24517fb9 | ||
|
|
a4c8bcab18 | ||
|
|
4fd8ada4ff | ||
|
|
7bf94ffe42 | ||
|
|
088205385f | ||
|
|
39c743631b | ||
|
|
603a95debb | ||
|
|
28a8adb26d | ||
|
|
e2bfd26bb3 | ||
|
|
857aadfa61 | ||
|
|
b8bbbd5489 | ||
|
|
ffb9a8b7ed | ||
|
|
b751f98e91 | ||
|
|
c0ceaa4195 | ||
|
|
6121c35e02 | ||
|
|
c3ea0c74ee | ||
|
|
610f189839 | ||
|
|
5b74739c51 | ||
|
|
775e87ff1f | ||
|
|
c4b7d89713 | ||
|
|
5f17d7aa75 | ||
|
|
3595a94b67 | ||
|
|
435edad604 | ||
|
|
87e616ad23 | ||
|
|
9d556ecc0f | ||
|
|
ea2c2df614 | ||
|
|
202a02af10 | ||
|
|
6ee71e3a9e | ||
|
|
1e7ed14810 | ||
|
|
17383083fb | ||
|
|
f5fe49923b | ||
|
|
457d338a97 | ||
|
|
4928c044af | ||
|
|
299c69686e | ||
|
|
b7132af214 | ||
|
|
74a5c974e6 | ||
|
|
942a4e9616 | ||
|
|
76f732dc53 | ||
|
|
0462cc3d0c | ||
|
|
965207d688 | ||
|
|
0f0a836fa0 | ||
|
|
29fb1de882 | ||
|
|
a807dc81a0 | ||
|
|
a4d3173da9 | ||
|
|
4b6a76bf02 | ||
|
|
35a520f132 | ||
|
|
1c53d2c123 | ||
|
|
591d98b55b | ||
|
|
f39ec58435 | ||
|
|
e72a30ca59 | ||
|
|
368c943040 | ||
|
|
a16e387dff | ||
|
|
95cf828975 | ||
|
|
c09d85f46d | ||
|
|
c2803fe1e2 | ||
|
|
98dfc2e286 | ||
|
|
ea848dbfc0 | ||
|
|
f7cfee55d5 | ||
|
|
26a7b3325d | ||
|
|
47fd5bdc00 | ||
|
|
5dfa9cf501 | ||
|
|
854c99bafa | ||
|
|
937ccbc5bd | ||
|
|
bc7c494316 | ||
|
|
17a2be41da | ||
|
|
ab5966fa9d | ||
|
|
89fe063b02 | ||
|
|
7061a1ebfa | ||
|
|
ec9a947259 | ||
|
|
11441d632b | ||
|
|
a17b647e79 | ||
|
|
2d87d29fa0 | ||
|
|
844845223f | ||
|
|
f2159e26d2 | ||
|
|
d677762dff | ||
|
|
3801e0d60b | ||
|
|
f6a498854c | ||
|
|
29ded2483c | ||
|
|
050e17298a | ||
|
|
af882b172e | ||
|
|
caad8c25ad | ||
|
|
74ef9ece30 | ||
|
|
97bfb4004b | ||
|
|
3da1b3f05d | ||
|
|
f21b22ae15 | ||
|
|
327e904dbc | ||
|
|
57c449936f | ||
|
|
efe6137067 | ||
|
|
96e9400761 | ||
|
|
6a517feda3 | ||
|
|
3b7a928313 | ||
|
|
2739320f10 | ||
|
|
7866e3fc2a | ||
|
|
2abf89cd16 | ||
|
|
8b2dcf976f | ||
|
|
559b86efe1 | ||
|
|
949a26ca0e | ||
|
|
2880ca00da | ||
|
|
39da62532b | ||
|
|
483ba95d80 | ||
|
|
2300b0c692 | ||
|
|
cc59b36c54 | ||
|
|
61d9918dae | ||
|
|
2c361f9b0a | ||
|
|
775b3e8c52 | ||
|
|
2a989c6cc1 | ||
|
|
3d7adf6483 | ||
|
|
56079f70c7 | ||
|
|
6c9e969099 | ||
|
|
76f8e6d6ef | ||
|
|
174cf3ed95 | ||
|
|
540f468e8a | ||
|
|
6b2423cdce | ||
|
|
e4a3181e1d | ||
|
|
b57730c28b | ||
|
|
5a02c38fcd | ||
|
|
2847098020 | ||
|
|
0cc6d90e3d | ||
|
|
66d1b3fd2f | ||
|
|
b28eaf2dbf | ||
|
|
191a99f91b | ||
|
|
f3f1ac939a | ||
|
|
9737b9cd62 | ||
|
|
e3fbb490df | ||
|
|
73d74f6cde | ||
|
|
1487f760b0 | ||
|
|
bdb2ac3a0b | ||
|
|
75bd7805c9 | ||
|
|
ef8e9a83bb | ||
|
|
7d9c24ff51 | ||
|
|
a8e83154f0 | ||
|
|
27c2c4dc33 | ||
|
|
a9a538cec8 | ||
|
|
57e1f7ee10 | ||
|
|
754eb89f04 | ||
|
|
2e95184d30 | ||
|
|
9deab9c497 | ||
|
|
5ae6c8a627 | ||
|
|
05104aef6c | ||
|
|
08da408471 | ||
|
|
4a4d5ac694 | ||
|
|
3b4d6d465b | ||
|
|
26f998ecb6 | ||
|
|
60a717365c | ||
|
|
07ae00aa20 | ||
|
|
39cc845df3 | ||
|
|
6c8b75a05f | ||
|
|
4c8efed256 | ||
|
|
faaa90fa0d | ||
|
|
7e075e5ebb | ||
|
|
b9508d853e | ||
|
|
716d52f3e3 | ||
|
|
90753f4d42 | ||
|
|
7117592f38 | ||
|
|
b9030d7e47 | ||
|
|
b79cfa213d | ||
|
|
60af9970c1 | ||
|
|
33a1e7f055 | ||
|
|
f72e9700ab | ||
|
|
4357d68462 | ||
|
|
adfaa95149 | ||
|
|
d6b887b7db | ||
|
|
227040f82f |
29
.github/workflows/analysis.yml
vendored
29
.github/workflows/analysis.yml
vendored
@@ -3,11 +3,12 @@ name: "CodeQL"
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
codeql:
|
||||
name: 🐛 CodeQL
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
@@ -15,24 +16,30 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: ✋ Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v2
|
||||
with:
|
||||
languages: 'cpp'
|
||||
|
||||
- name: 📜 Restore cache
|
||||
uses: actions/cache@v2
|
||||
- name: 📜 Restore ccache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.ccache
|
||||
~/.cache/ccache
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
@@ -42,7 +49,7 @@ jobs:
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-10 CXX=g++-10 cmake \
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
@@ -53,4 +60,4 @@ jobs:
|
||||
make -j 4 install
|
||||
|
||||
- name: 🗯️ Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v2
|
||||
280
.github/workflows/build.yml
vendored
280
.github/workflows/build.yml
vendored
@@ -2,7 +2,9 @@ name: Build
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["*"]
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
env:
|
||||
BUILD_TYPE: Release
|
||||
@@ -12,7 +14,7 @@ jobs:
|
||||
# Windows build
|
||||
win:
|
||||
runs-on: windows-2022
|
||||
name: 🟦 Windows MINGW64
|
||||
name: 🪟 Windows MINGW64
|
||||
defaults:
|
||||
run:
|
||||
shell: msys2 {0}
|
||||
@@ -22,11 +24,33 @@ jobs:
|
||||
CCACHE_COMPRESS: "true"
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Prepare Cache
|
||||
id: prep-ccache
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p "${CCACHE_DIR}"
|
||||
echo "::set-output name=dir::$CCACHE_DIR"
|
||||
|
||||
- name: 📜 Restore ccache
|
||||
uses: actions/cache@v3
|
||||
id: cache-ccache
|
||||
with:
|
||||
path: |
|
||||
${{ steps.prep-ccache.outputs.dir }}
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: 🟦 Install msys2
|
||||
uses: msys2/setup-msys2@v2
|
||||
with:
|
||||
@@ -52,21 +76,6 @@ jobs:
|
||||
$USERPROFILE/.cargo/bin/rustup.exe target add x86_64-pc-windows-gnu
|
||||
$USERPROFILE/.cargo/bin/rustup.exe default nightly
|
||||
|
||||
- name: 📜 Prepare Cache
|
||||
id: prep-ccache
|
||||
shell: bash
|
||||
run: |
|
||||
mkdir -p "${CCACHE_DIR}"
|
||||
echo "::set-output name=dir::$CCACHE_DIR"
|
||||
|
||||
- name: 📜 Restore Cache
|
||||
uses: actions/cache@v1
|
||||
id: cache-ccache
|
||||
with:
|
||||
path: ${{ steps.prep-ccache.outputs.dir }}
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
mkdir -p build
|
||||
@@ -84,20 +93,22 @@ jobs:
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-DRUST_PATH="$USERPROFILE/.cargo/bin/" \
|
||||
..
|
||||
mingw32-make -j4 install
|
||||
cpack
|
||||
|
||||
- name: ⬆️ Upload Portable ZIP
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Portable ZIP
|
||||
name: Windows Portable
|
||||
path: |
|
||||
build/install/*
|
||||
|
||||
- name: ⬆️ Upload Windows Installer
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Installer
|
||||
path: |
|
||||
@@ -105,72 +116,89 @@ jobs:
|
||||
|
||||
# MacOS build
|
||||
macos:
|
||||
runs-on: macos-11.0
|
||||
runs-on: macos-11
|
||||
name: 🍎 macOS 11.0
|
||||
steps:
|
||||
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Restore ccache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/Library/Caches/ccache
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
|
||||
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
brew bundle --no-lock --file dist/Brewfile
|
||||
|
||||
- name: 📜 Restore cache
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
~/.ccache
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=$(brew --prefix llvm)/bin/clang \
|
||||
CXX=$(brew --prefix llvm)/bin/clang++ \
|
||||
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
|
||||
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
|
||||
OBJC=$(brew --prefix llvm)/bin/clang \
|
||||
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
|
||||
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
|
||||
MACOSX_DEPLOYMENT_TARGET="10.15" \
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCREATE_BUNDLE=ON \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
MACOSX_DEPLOYMENT_TARGET="10.15" \
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCREATE_BUNDLE=ON \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
..
|
||||
make -j4 package
|
||||
|
||||
- name: ⬆️ Upload DMG
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macOS DMG
|
||||
path: build/*.dmg
|
||||
|
||||
# Linux build
|
||||
linux:
|
||||
runs-on: ubuntu-20.04
|
||||
name: 🐧 Ubuntu 20.04
|
||||
runs-on: ubuntu-22.04
|
||||
name: 🐧 Ubuntu 22.04
|
||||
steps:
|
||||
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Restore cache
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.ccache
|
||||
~/.cache/ccache
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
|
||||
|
||||
- name: 📜 Restore other caches
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
.flatpak-builder
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo rm -rf /usr/share/dotnet
|
||||
@@ -180,6 +208,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==1.0.0
|
||||
|
||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
|
||||
sh rustup-init.sh -y --default-toolchain none
|
||||
@@ -192,16 +225,22 @@ jobs:
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-10 CXX=g++-10 cmake \
|
||||
CC=gcc-12 CXX=g++-12 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" \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-DRUST_PATH="$HOME/.cargo/bin/" \
|
||||
..
|
||||
make -j 4 install
|
||||
make -j 4 install DESTDIR=AppDir
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
echo "version=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
#- name: 📦 Bundle Flatpak
|
||||
# run: |
|
||||
@@ -214,41 +253,122 @@ jobs:
|
||||
|
||||
- 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
|
||||
cp -r build/DEBIAN build/AppDir
|
||||
dpkg-deb --build build/AppDir
|
||||
mv build/AppDir.deb imhex-${{env.version}}.deb
|
||||
rm -rf build/AppDir/DEBIAN
|
||||
|
||||
- name: 📦 Bundle AppImage
|
||||
run: |
|
||||
dist/AppImage/package.sh build
|
||||
mv build/ImHex-x86_64.AppImage imhex.AppImage
|
||||
cd build
|
||||
appimage-builder --recipe ../dist/AppImageBuilder.yml
|
||||
mv ImHex-AppImage-x86_64.AppImage ../imhex-${{env.version}}.AppImage
|
||||
cd ..
|
||||
|
||||
- name: ⬆️ Upload ELF
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Linux ELF
|
||||
path: |
|
||||
build/install/*
|
||||
#- name: ⬆️ Upload Flatpak
|
||||
# uses: actions/upload-artifact@v3
|
||||
# with:
|
||||
# name: Linux Flatpak
|
||||
# path: |
|
||||
# imhex.flatpak
|
||||
|
||||
- name: ⬆️ Upload Flatpak
|
||||
uses: actions/upload-artifact@v2
|
||||
- name: ⬆️ Upload DEB
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Linux Flatpak
|
||||
path: |
|
||||
imhex.flatpak
|
||||
|
||||
- name: ⬆️ Upload .deb
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: Linux DEB
|
||||
path: |
|
||||
imhex.deb
|
||||
name: Linux DEB (Ubuntu 22.04)
|
||||
path: '*.deb'
|
||||
|
||||
- name: ⬆️ Upload AppImage
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Linux AppImage
|
||||
path: |
|
||||
imhex.AppImage
|
||||
path: '*.AppImage'
|
||||
|
||||
archlinux-build:
|
||||
name: 🐧 ArchLinux
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container:
|
||||
image: archlinux:base-devel
|
||||
|
||||
steps:
|
||||
- name: ⬇️ Update all packages
|
||||
run: |
|
||||
pacman -Syyu --noconfirm
|
||||
|
||||
- name: ⬇️ Install setup dependencies
|
||||
run: |
|
||||
pacman -Syu git ccache --noconfirm
|
||||
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: ⬇️ Install ImHex dependencies
|
||||
run: |
|
||||
dist/get_deps_archlinux.sh --noconfirm
|
||||
|
||||
- name: 📜 Restore ccache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.cache/ccache
|
||||
key: archlinux-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: archlinux-${{ secrets.CACHE_VERSION }}-build
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: archlinux-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc CXX=g++ cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-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 DESTDIR=installDir
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
echo "version=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
- name: ✒️ Prepare PKGBUILD
|
||||
run: |
|
||||
cp dist/Arch/PKGBUILD build
|
||||
sed -i 's/%version%/${{env.version}}/g' build/PKGBUILD
|
||||
|
||||
# makepkg doesn't want to run as root, so I had to chmod 777 all over
|
||||
- name: 📦 Package ArchLinux .pkg.tar.zst
|
||||
run: |
|
||||
cd build
|
||||
|
||||
# the name is a small trick to make makepkg recognize it as the source
|
||||
# else, it would try to download the file from the release
|
||||
tar -cvf imhex-${{env.version}}-ArchLinux.pkg.tar.zst -C installDir .
|
||||
|
||||
chmod -R 777 .
|
||||
|
||||
sudo -u nobody makepkg
|
||||
|
||||
# Remplace the old file
|
||||
rm imhex-${{env.version}}-ArchLinux.pkg.tar.zst
|
||||
mv *.pkg.tar.zst imhex-${{env.version}}-ArchLinux.pkg.tar.zst
|
||||
|
||||
- name: ⬆️ Upload imhex-archlinux.pkg.tar.zst
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ArchLinux .pkg.tar.zst
|
||||
path: |
|
||||
build/imhex-${{env.version}}-ArchLinux.pkg.tar.zst
|
||||
|
||||
|
||||
92
.github/workflows/release.yml
vendored
Normal file
92
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,92 @@
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
name: Release
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
name: Release
|
||||
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: ImHex
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Verify version and set version variable
|
||||
run: |
|
||||
project_version=`cat ImHex/VERSION`
|
||||
tag_version="${{github.event.release.tag_name}}"
|
||||
tag_version="${tag_version:1}"
|
||||
if [ "$project_version" != "$tag_version" ]; then
|
||||
echo "::warning::$project_version and $tag_version are not the same ! Refusing to populate release"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "version=$project_version" >> $GITHUB_ENV
|
||||
|
||||
- name: 🗜️ Create tarball from sources with dependencies
|
||||
run: tar -cvf Full.Sources.tar.gz ImHex
|
||||
|
||||
- name: ⬇️ Download artifacts from latest workflow
|
||||
uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
workflow: build.yml
|
||||
branch: ${{ github.event.release.target_commitish }}
|
||||
workflow_conclusion: success
|
||||
skip_unpack: true
|
||||
|
||||
- name: 🗜️ Unzip files when needed
|
||||
run: |
|
||||
for zipfile in ./*.zip
|
||||
do
|
||||
if [ `zipinfo -1 "$zipfile" | wc -l` -eq 1 ];
|
||||
then
|
||||
echo "unzipping $zipfile"
|
||||
unzip "$zipfile"
|
||||
rm "$zipfile"
|
||||
else
|
||||
echo "keeping $zipfile zipped"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: 🟩 Rename Windows Portable Zip
|
||||
run: mv "Windows Portable.zip" imhex-${{env.version}}-Windows-Portable.zip
|
||||
|
||||
- name: ⬆️ Upload everything to release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
files: '*'
|
||||
|
||||
- name: ✒️ Prepare PKGBUILD
|
||||
run: |
|
||||
cp ImHex/dist/Arch/PKGBUILD .
|
||||
|
||||
hash=`md5sum imhex-${{env.version}}-ArchLinux.pkg.tar.zst | cut -d ' ' -f 1`
|
||||
|
||||
sed -i 's/%version%/${{env.version}}/g' PKGBUILD
|
||||
sed -i "s/(SKIP)/($hash)/g" PKGBUILD
|
||||
|
||||
- name: ⬆️ Publish AUR package
|
||||
|
||||
# I couldn't make the condition in the env directly for some reason
|
||||
env:
|
||||
MY_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||
if: "${{ env.MY_KEY != '' }}"
|
||||
|
||||
uses: KSXGitHub/github-actions-deploy-aur@v2
|
||||
with:
|
||||
pkgname: imhex-bin
|
||||
pkgbuild: ./PKGBUILD
|
||||
commit_username: iTrooz
|
||||
commit_email: itrooz@protonmail.com
|
||||
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||
commit_message: Bump to version ${{env.version}}
|
||||
ssh_keyscan_types: rsa,dsa,ecdsa,ed25519
|
||||
26
.github/workflows/tests.yml
vendored
26
.github/workflows/tests.yml
vendored
@@ -5,11 +5,12 @@ on:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
tests:
|
||||
name: 🧪 Unit Tests
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
@@ -17,19 +18,26 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Restore cache
|
||||
uses: actions/cache@v2
|
||||
- name: 📜 Restore ccache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.ccache
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
~/.cache/ccache
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
|
||||
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
@@ -39,7 +47,7 @@ jobs:
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-10 CXX=g++-10 cmake \
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -12,3 +12,5 @@ imgui.ini
|
||||
plugins/.rustc_info.json
|
||||
|
||||
**/target
|
||||
|
||||
plugins/example_rust/Cargo.lock
|
||||
|
||||
5
.gitmodules
vendored
5
.gitmodules
vendored
@@ -21,6 +21,11 @@
|
||||
[submodule "lib/external/capstone"]
|
||||
path = lib/external/capstone
|
||||
url = https://github.com/capstone-engine/capstone
|
||||
ignore = dirty
|
||||
[submodule "lib/external/libromfs"]
|
||||
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
|
||||
|
||||
2
.idea/vcs.xml
generated
2
.idea/vcs.xml
generated
@@ -7,6 +7,8 @@
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/fmt" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/libromfs" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/nativefiledialog" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language/external/fmt" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/xdgpp" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/yara/yara" vcs="Git" />
|
||||
</component>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
# Updating the version here will update it throughout ImHex as well
|
||||
set(IMHEX_VERSION "1.15.0")
|
||||
file(READ "VERSION" IMHEX_VERSION)
|
||||
project(imhex VERSION ${IMHEX_VERSION})
|
||||
message("Project version ${IMHEX_VERSION}")
|
||||
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(IMHEX_BASE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
@@ -28,9 +29,10 @@ configurePackingResources()
|
||||
# Add ImHex sources
|
||||
add_subdirectory(lib/libimhex)
|
||||
add_subdirectory(main)
|
||||
add_custom_target(imhex ALL DEPENDS main)
|
||||
add_custom_target(imhex_all ALL DEPENDS main)
|
||||
|
||||
# Add unit tests
|
||||
enable_testing()
|
||||
add_subdirectory(tests EXCLUDE_FROM_ALL)
|
||||
|
||||
# Configure packaging
|
||||
|
||||
108
README.md
108
README.md
@@ -33,7 +33,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
- Hex string
|
||||
- C, C++, C#, Rust, Python, Java & JavaScript array
|
||||
- ASCII-Art hex view
|
||||
- HTML self contained div
|
||||
- HTML self-contained div
|
||||
- String and hex search
|
||||
- Colorful highlighting
|
||||
- Goto from start, end and current cursor position
|
||||
@@ -84,7 +84,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
- Built-in Content Store
|
||||
- Download all files found in the database directly from within ImHex
|
||||
- Yara Rules support
|
||||
- Quickly scan a file for vulnearabilities with official yara rules
|
||||
- Quickly scan a file for vulnerabilities with official yara rules
|
||||
- Helpful tools
|
||||
- Itanium and MSVC demangler
|
||||
- ASCII table
|
||||
@@ -98,7 +98,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
- File utilities
|
||||
- File splitter
|
||||
- File combiner
|
||||
- File shredderer
|
||||
- File shredder
|
||||
- Built-in cheat sheet for pattern language and Math evaluator
|
||||
- Doesn't burn out your retinas when used in late-night sessions
|
||||
|
||||
@@ -106,15 +106,16 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
|
||||
The custom C-like Pattern Language developed and used by ImHex is easy to read, understand and learn. A guide with all features of the language can be found [on the docs page](http://imhex.werwolv.net/docs).
|
||||
|
||||
## Database
|
||||
|
||||
For format patterns, includable libraries magic and constant files, check out the [ImHex-Patterns](https://github.com/WerWolv/ImHex-Patterns) repository. Feel free to PR your own files there as well!
|
||||
|
||||
## Plugin development
|
||||
|
||||
To develop plugins for ImHex, use one of the following two templates projects to get startet. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
|
||||
To develop plugins for ImHex, use one of the following two templates projects to get started. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
|
||||
- [C++ Plugin Template](https://github.com/WerWolv/ImHex-Cpp-Plugin-Template)
|
||||
- [Rust Plugin Template](https://github.com/WerWolv/ImHex-Rust-Plugin-Template)
|
||||
|
||||
## Additional Files
|
||||
|
||||
For format patterns, includable libraries and magic files, check out the [ImHex-Patterns](https://github.com/WerWolv/ImHex-Patterns) repository. Feel free to PR your own files there as well!
|
||||
|
||||
## Nightly builds
|
||||
|
||||
@@ -126,103 +127,16 @@ Nightlies are available via GitHub Actions [here](https://github.com/WerWolv/ImH
|
||||
- MacOS • __x86_64__
|
||||
- [DMG](https://nightly.link/WerWolv/ImHex/workflows/build/master/macOS%20DMG.zip)
|
||||
- Linux • __x86_64__
|
||||
- [ELF](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20ELF.zip)
|
||||
- [DEB](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20DEB.zip)
|
||||
- [Flatpak](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20Flatpak.zip)
|
||||
- [AppImage](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20AppImage.zip)
|
||||
|
||||
## Compiling
|
||||
|
||||
You need a C++20 compatible compiler such as GCC 10.2.0 to compile ImHex.
|
||||
To compile ImHex, a C++20 compiler is required. Releases are all mainly built using GCC, however on macOS, clang is also required to compile some ObjC code.
|
||||
|
||||
Many dependencies are bundled into the repository using submodules so make sure to clone it using the `--recurse-submodules` option.
|
||||
All dependencies that aren't bundled, can be installed using the dependency installer scripts found in the `/dist` folder.
|
||||
|
||||
For working examples
|
||||
|
||||
### Windows
|
||||
|
||||
On Windows, ImHex is built through msys2 / mingw. To install all dependencies, open a mys2 window and run the PKGCONFIG script in the [dist/msys2](dist/msys2) folder.
|
||||
After all the dependencies are installed, run the following commands to build ImHex:
|
||||
|
||||
```sh
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
make -j
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
To create a standalone zipfile on Windows, get the Python standard library (e.g. from https://github.com/python/cpython/tree/master/Lib) and place the files and folders in `lib/python3.8` next to your built executable. Don't forget to also copy the `libpython3.8.dll` and `libwinpthread-1.dll` from your mingw setup next to the executable.
|
||||
|
||||
- Copy the files inside the `/resources/lib/python` folder into the `lib` folder next to your built executable.
|
||||
- Place your magic databases in the `magic` folder next to your built executable
|
||||
- Place your patterns in the `pattern` folder next to your built executable
|
||||
- Place your include pattern files in the `include` folder next to your built executable
|
||||
|
||||
### macOS
|
||||
|
||||
To build ImHex on macOS, run the following commands:
|
||||
|
||||
```sh
|
||||
brew bundle --no-lock --file dist/Brewfile
|
||||
mkdir build
|
||||
cd build
|
||||
CC=$(brew --prefix llvm)/bin/clang CXX=$(brew --prefix llvm)/bin/clang++ PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
make -j
|
||||
```
|
||||
|
||||
Install the ImHex executable as well as libimhex.dylib to wherever ImHex should be installed.
|
||||
|
||||
All other files belong in `~/Library/Application Support/imhex`:
|
||||
```
|
||||
Patterns: ~/Library/Application Support/imhex/patterns
|
||||
Pattern Includes: ~/Library/Application Support/imhex/includes
|
||||
Magic files: ~/Library/Application Support/imhex/magic
|
||||
Python: ~/Library/Application Support/imhex/lib/pythonX.X
|
||||
Plugins: ~/Library/Application Support/imhex/plugins
|
||||
Configuration: ~/Library/Application Support/imhex/config
|
||||
Resources: ~/Library/Application Support/imhex/resources
|
||||
```
|
||||
|
||||
If the build fails while trying to find the macOS libraries, make sure you have
|
||||
XCode installed with `xcode-select --install`. Homebrew will also help get the
|
||||
most recent SDK installed and configured with `brew doctor`.
|
||||
|
||||
### Linux
|
||||
|
||||
Dependency installation scripts are available for many common Linux distributions in the [/dist](dist) folder.
|
||||
After all the dependencies are installed, run the following commands to build ImHex:
|
||||
|
||||
```sh
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DCMAKE_BUILD_TYPE=Release ..
|
||||
make -j
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Put the ImHex executable into the `/usr/bin` folder.
|
||||
Put libimhex.so into the `/usr/lib` folder.
|
||||
Configuration files go to `/etc/xdg/imhex` or `~/.config/imhex`.
|
||||
All other files belong in `/usr/share/imhex` or `~/.local/share/imhex`:
|
||||
|
||||
```
|
||||
Patterns: /usr/share/imhex/patterns
|
||||
Pattern Includes: /usr/share/imhex/includes
|
||||
Magic files: /usr/share/imhex/magic
|
||||
Python: /usr/share/imhex/lib/pythonX.X
|
||||
Plugins: /usr/share/imhex/plugins
|
||||
Configuration: /etc/xdg/imhex/config
|
||||
Resources: /usr/share/imhex/resources
|
||||
```
|
||||
|
||||
All paths follow the XDG Base Directories standard, and can thus be modified
|
||||
with the environment variables `XDG_CONFIG_HOME`, `XDG_CONFIG_DIRS`,
|
||||
`XDG_DATA_HOME` and `XDG_DATA_DIRS`.
|
||||
|
||||
## Credits
|
||||
|
||||
### Contributors
|
||||
@@ -230,7 +144,9 @@ 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 :)
|
||||
- [Mailaender](https://github.com/Mailaender) for getting ImHex onto Flathub
|
||||
- [iTrooz](https://github.com/iTrooz) for many improvements related to release packaging and the GitHub Action runners.
|
||||
- Everybody else who has reported issues on Discord or GitHub that I had great conversations with :)
|
||||
|
||||
### Libraries
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
include(FetchContent)
|
||||
|
||||
macro(addVersionDefines)
|
||||
if (IS_DIRECTORY "${CMAKE_SOURCE_DIR}/.git")
|
||||
# Get the current working branch
|
||||
@@ -21,19 +23,18 @@ macro(addVersionDefines)
|
||||
|
||||
set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -DPROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} -DPROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR} -DPROJECT_VERSION_PATCH=${PROJECT_VERSION_PATCH} ")
|
||||
|
||||
add_compile_definitions(
|
||||
$<$<CONFIG:Release>:IMHEX_VERSION="${IMHEX_VERSION}">
|
||||
$<$<CONFIG:Debug>:IMHEX_VERSION="${IMHEX_VERSION}-Debug">
|
||||
$<$<CONFIG:RelWithDebInfo>:IMHEX_VERSION="${IMHEX_VERSION}-ReleaseWithDebugInfo">
|
||||
$<$<CONFIG:MinSizeRel>:IMHEX_VERSION="${IMHEX_VERSION}-ReleaseMinimumSize">
|
||||
)
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION})
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION}-Debug)
|
||||
add_compile_definitions(DEBUG)
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION}-RelWithDebInfo)
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION}-MinSizeRel)
|
||||
endif ()
|
||||
|
||||
add_compile_definitions(
|
||||
$<$<CONFIG:Release>:RELEASE>
|
||||
$<$<CONFIG:Debug>:DEBUG>
|
||||
$<$<CONFIG:RelWithDebInfo>:RELEASE>
|
||||
$<$<CONFIG:MinSizeRel>:RELEASE>
|
||||
)
|
||||
add_compile_definitions(IMHEX_VERSION="${IMHEX_VERSION_STRING}")
|
||||
|
||||
endmacro()
|
||||
|
||||
@@ -69,19 +70,18 @@ macro(detectOS)
|
||||
set(CMAKE_INSTALL_BINDIR ".")
|
||||
set(CMAKE_INSTALL_LIBDIR ".")
|
||||
set(PLUGINS_INSTALL_LOCATION "plugins")
|
||||
set(MAGIC_INSTALL_LOCATION "magic")
|
||||
elseif (APPLE)
|
||||
add_compile_definitions(OS_MACOS)
|
||||
set(CMAKE_INSTALL_BINDIR ".")
|
||||
set(CMAKE_INSTALL_LIBDIR ".")
|
||||
set(PLUGINS_INSTALL_LOCATION "plugins")
|
||||
set(MAGIC_INSTALL_LOCATION "magic")
|
||||
enable_language(OBJC)
|
||||
enable_language(OBJCXX)
|
||||
elseif (UNIX AND NOT APPLE)
|
||||
add_compile_definitions(OS_LINUX)
|
||||
set(CMAKE_INSTALL_BINDIR "bin")
|
||||
set(CMAKE_INSTALL_LIBDIR "lib")
|
||||
set(PLUGINS_INSTALL_LOCATION "share/imhex/plugins")
|
||||
set(MAGIC_INSTALL_LOCATION "share/imhex/magic")
|
||||
else ()
|
||||
message(FATAL_ERROR "Unknown / unsupported system!")
|
||||
endif()
|
||||
@@ -132,14 +132,14 @@ macro(configurePackingResources)
|
||||
set(MACOSX_BUNDLE_INFO_STRING "WerWolv")
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME "ImHex")
|
||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "WerWolv.ImHex")
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "net.WerWolv.ImHex")
|
||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}-${GIT_COMMIT_HASH}")
|
||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
|
||||
set(MACOSX_BUNDLE_COPYRIGHT "Copyright © 2020 WerWolv and Thog. All rights reserved." )
|
||||
if ("${CMAKE_GENERATOR}" STREQUAL "Xcode")
|
||||
set ( bundle_path "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/imhex.app" )
|
||||
set ( bundle_path "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/ImHex.app" )
|
||||
else ()
|
||||
set ( bundle_path "${CMAKE_BINARY_DIR}/imhex.app" )
|
||||
set ( bundle_path "${CMAKE_BINARY_DIR}/ImHex.app" )
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
@@ -150,11 +150,11 @@ macro(createPackage)
|
||||
foreach (plugin IN LISTS PLUGINS)
|
||||
add_subdirectory("plugins/${plugin}")
|
||||
if (TARGET ${plugin})
|
||||
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
set_target_properties(${plugin} PROPERTIES CARGO_BUILD_TARGET_DIR ${CMAKE_BINARY_DIR}/plugins)
|
||||
|
||||
get_target_property(IS_RUST_PROJECT ${plugin} RUST_PROJECT)
|
||||
|
||||
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
|
||||
if (IS_RUST_PROJECT)
|
||||
set_target_properties(${plugin} PROPERTIES CARGO_BUILD_TARGET_DIR ${CMAKE_BINARY_DIR}/plugins)
|
||||
|
||||
@@ -162,7 +162,6 @@ macro(createPackage)
|
||||
|
||||
install(FILES "${PLUGIN_LOCATION}/../${plugin}.hexplug" DESTINATION "${PLUGINS_INSTALL_LOCATION}")
|
||||
else ()
|
||||
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
if (WIN32)
|
||||
install(TARGETS ${plugin} RUNTIME DESTINATION ${PLUGINS_INSTALL_LOCATION})
|
||||
elseif (APPLE)
|
||||
@@ -176,11 +175,10 @@ macro(createPackage)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
add_dependencies(imhex ${plugin})
|
||||
add_dependencies(imhex_all ${plugin})
|
||||
endif ()
|
||||
endforeach()
|
||||
|
||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
set_target_properties(libimhex PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
|
||||
if (WIN32)
|
||||
@@ -217,36 +215,44 @@ macro(createPackage)
|
||||
)
|
||||
endforeach()
|
||||
]])
|
||||
|
||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
downloadImHexPatternsFiles("./")
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
configure_file(${CMAKE_SOURCE_DIR}/dist/DEBIAN/control.in ${CMAKE_BINARY_DIR}/DEBIAN/control)
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/dist/DEBIAN/control.in ${CMAKE_BINARY_DIR}/DEBIAN/control)
|
||||
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/dist/imhex.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/resources/icon.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.png)
|
||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
downloadImHexPatternsFiles("./share/imhex")
|
||||
endif()
|
||||
|
||||
|
||||
if (CREATE_BUNDLE)
|
||||
include(PostprocessBundle)
|
||||
|
||||
# Fix rpath
|
||||
add_custom_command(TARGET imhex POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $<TARGET_FILE:main>)
|
||||
add_custom_command(TARGET imhex_all POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $<TARGET_FILE:main>)
|
||||
|
||||
# FIXME: Remove this once we move/integrate the plugins directory.
|
||||
add_custom_target(build-time-make-plugins-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${bundle_path}/Contents/MacOS/plugins")
|
||||
add_custom_target(build-time-make-resources-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${bundle_path}/Contents/Resources")
|
||||
|
||||
downloadImHexPatternsFiles("${bundle_path}/Contents/MacOS")
|
||||
|
||||
install(FILES ${IMHEX_ICON} DESTINATION "${bundle_path}/Contents/Resources")
|
||||
install(TARGETS main BUNDLE DESTINATION ".")
|
||||
install(FILES $<TARGET_FILE:main> DESTINATION "${bundle_path}")
|
||||
|
||||
# Update library references to make the bundle portable
|
||||
postprocess_bundle(imhex main)
|
||||
postprocess_bundle(imhex_all main)
|
||||
|
||||
# Enforce DragNDrop packaging.
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
|
||||
install(TARGETS main BUNDLE DESTINATION .)
|
||||
else()
|
||||
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
|
||||
|
||||
if (CREATE_PACKAGE)
|
||||
include(apple)
|
||||
include(CPack)
|
||||
@@ -279,4 +285,21 @@ macro(detectBadClone)
|
||||
message(FATAL_ERROR "External dependency ${EXTERNAL_DIR} is empty!\nMake sure to correctly clone ImHex using the --recurse-submodules git option or initialize the submodules manually.")
|
||||
endif()
|
||||
endforeach ()
|
||||
endmacro()
|
||||
endmacro()
|
||||
|
||||
|
||||
function(downloadImHexPatternsFiles dest)
|
||||
FetchContent_Declare(
|
||||
imhex_patterns
|
||||
GIT_REPOSITORY https://github.com/WerWolv/ImHex-Patterns.git
|
||||
GIT_TAG master
|
||||
)
|
||||
|
||||
FetchContent_Populate(imhex_patterns)
|
||||
|
||||
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic)
|
||||
foreach (FOLDER ${PATTERNS_FOLDERS_TO_INSTALL})
|
||||
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION ${dest})
|
||||
endforeach()
|
||||
|
||||
endfunction()
|
||||
40
dist/AppImage/Dockerfile
vendored
40
dist/AppImage/Dockerfile
vendored
@@ -1,40 +0,0 @@
|
||||
FROM debian:bullseye-slim
|
||||
LABEL maintainer Example <example@example.com>
|
||||
|
||||
ARG TAG=master
|
||||
ARG REPO=https://github.com/WerWolv/ImHex.git
|
||||
|
||||
USER root
|
||||
|
||||
# Bring packages up to date
|
||||
RUN apt-get update \
|
||||
&& apt-get upgrade -y \
|
||||
&& apt-get autoremove -y \
|
||||
&& apt-get install -y \
|
||||
git \
|
||||
cmake \
|
||||
curl \
|
||||
squashfs-tools
|
||||
|
||||
# Fetch source and dependencies
|
||||
RUN mkdir -p /source \
|
||||
&& cd /source \
|
||||
&& git clone $REPO \
|
||||
&& cd ImHex \
|
||||
&& git checkout $TAG \
|
||||
&& git submodule update --init --recursive \
|
||||
&& cd /source/ImHex/dist \
|
||||
&& ./get_deps_debian.sh
|
||||
|
||||
ARG CXX=g++-10
|
||||
|
||||
# Build ImHex
|
||||
RUN mkdir -p /source/ImHex/build \
|
||||
&& cd /source/ImHex/build \
|
||||
&& cmake --install-prefix /usr -DCMAKE_BUILD_TYPE=Release .. \
|
||||
&& make -j
|
||||
|
||||
# Prepare for AppImage
|
||||
RUN cd /source/ImHex/dist/AppImage \
|
||||
&& ./package.sh /source/ImHex/build \
|
||||
&& mv /source/ImHex/build/ImHex-x86_64.AppImage /
|
||||
6
dist/AppImage/ImHex.desktop
vendored
6
dist/AppImage/ImHex.desktop
vendored
@@ -1,6 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Name=ImHex
|
||||
Exec=imhex
|
||||
Icon=imhex
|
||||
Type=Application
|
||||
Categories=Utility;
|
||||
22
dist/AppImage/README.md
vendored
22
dist/AppImage/README.md
vendored
@@ -1,22 +0,0 @@
|
||||
# Building an AppImage
|
||||
There are two ways of building an AppImage for ImHex, using the provided
|
||||
tools here.
|
||||
|
||||
If you want to create an AppImage and do not have a build to work from
|
||||
already, you can use docker to build ImHex and package an AppImage.
|
||||
|
||||
Alternatively you can create an AppImage using an existing build.
|
||||
|
||||
## Using docker
|
||||
First run `build.sh` to create a docker image. Then run `extract.sh` to get the
|
||||
AppImage out. This needs to be in two steps, as a docker build cannot copy
|
||||
files out. Nor can docker build use volume mounts.
|
||||
|
||||
The environment variable TAG can be set to build for a specific git tag.
|
||||
Without the master branch is build.
|
||||
|
||||
## Using an existing build
|
||||
Run `package.sh` with the build dir as an argument. E.g.:
|
||||
```
|
||||
./package.sh ../../build
|
||||
```
|
||||
16
dist/AppImage/build.sh
vendored
16
dist/AppImage/build.sh
vendored
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set the TAG environment variable to build a specific tag
|
||||
# Set the REPO environment variable to point at a different git repository
|
||||
|
||||
# Make sure we're in the same directory as this script
|
||||
pushd $(dirname "$(realpath "$0")")
|
||||
|
||||
BUILDARG=""
|
||||
SUFFIX=""
|
||||
[ -n "${TAG}" ] && BUILDARG="${BUILDARG} --build-arg=TAG=${TAG}" && SUFFIX=":${TAG}"
|
||||
[ -n "${REPO}" ] && BUILDARG="${BUILDARG} --build-arg=REPO=${REPO}"
|
||||
|
||||
docker build ${BUILDARG} -t imhex-appimage-build${SUFFIX} .
|
||||
|
||||
popd
|
||||
26
dist/AppImage/extract.sh
vendored
26
dist/AppImage/extract.sh
vendored
@@ -1,26 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Set the TAG environment variable to move to a versioned name while extracting
|
||||
|
||||
# Make sure we're in the same directory as this script
|
||||
pushd $(dirname "$(realpath "$0")")
|
||||
|
||||
SUFFIX=""
|
||||
[ -n "$TAG" ] && SUFFIX=":$TAG"
|
||||
|
||||
# Remove old containers
|
||||
docker rm imhex 2>&1 > /dev/null
|
||||
|
||||
docker run -d --name imhex imhex-appimage-build${SUFFIX} sleep 30 &
|
||||
sleep 15
|
||||
docker cp imhex:/ImHex-x86_64.AppImage .
|
||||
|
||||
# Move to tagged name if $TAG set
|
||||
if [ -n "$TAG" ]; then
|
||||
mv ImHex-x86_64.AppImage ImHex-${TAG}-x86_64.AppImage
|
||||
echo -e "\nThe created AppImage can be found here:\n $(pwd)/ImHex-${TAG}-x86_64.AppImage\n\n"
|
||||
else
|
||||
echo -e "\nThe created AppImage can be found here:\n $(pwd)/ImHex-x86_64.AppImage\n\n"
|
||||
fi
|
||||
|
||||
popd
|
||||
BIN
dist/AppImage/imhex.png
vendored
BIN
dist/AppImage/imhex.png
vendored
Binary file not shown.
|
Before Width: | Height: | Size: 3.3 KiB |
58
dist/AppImage/package.sh
vendored
58
dist/AppImage/package.sh
vendored
@@ -1,58 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e # Exit on error
|
||||
set -o pipefail # Bash specific
|
||||
|
||||
usage() {
|
||||
echo "Tool to package an ImHex build into an AppImage"
|
||||
echo
|
||||
echo "Usage:"
|
||||
echo "$0 <build dir>"
|
||||
echo
|
||||
exit
|
||||
}
|
||||
|
||||
MYDIR=$(dirname "$(realpath "$0")")
|
||||
|
||||
# Check is a build dir has been specified and it's a dir
|
||||
[ -z "$1" ] && usage
|
||||
[ -d "$1" ] || usage
|
||||
|
||||
set -u # Throw errors when unset variables are used
|
||||
|
||||
BUILDDIR=$1
|
||||
APPDIR=${BUILDDIR}/ImHex.AppDir
|
||||
APPIMAGE=${BUILDDIR}/ImHex-x86_64.AppImage
|
||||
|
||||
# Prepare for AppImage
|
||||
## Fetch the needed AppImage binaries
|
||||
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/AppRun-x86_64 -o ${MYDIR}/AppRun-x86_64
|
||||
curl -L https://github.com/AppImage/AppImageKit/releases/download/13/runtime-x86_64 -o ${MYDIR}/runtime-x86_64
|
||||
|
||||
## Setup directory structure
|
||||
mkdir -p ${BUILDDIR}/ImHex.AppDir/usr/{bin,lib} ${BUILDDIR}/ImHex.AppDir/usr/share/imhex/plugins
|
||||
|
||||
## Add ImHex files to structure
|
||||
cp ${BUILDDIR}/imhex ${APPDIR}/usr/bin
|
||||
cp ${BUILDDIR}/plugins/builtin/builtin.hexplug ${APPDIR}/usr/share/imhex/plugins
|
||||
cp ${MYDIR}/{AppRun-x86_64,ImHex.desktop,imhex.png} ${APPDIR}/
|
||||
mv ${BUILDDIR}/ImHex.AppDir/AppRun-x86_64 ${APPDIR}/AppRun
|
||||
chmod a+x ${BUILDDIR}/ImHex.AppDir/AppRun
|
||||
|
||||
## Add all dependencies
|
||||
ldd ${BUILDDIR}/imhex | awk '/ => /{print $3}' | awk '!/(libc|libstdc++|libc++|libdl|libpthread|libselinux|ld-linux|libgdk)/' | xargs -I '{}' cp '{}' ${APPDIR}/usr/lib
|
||||
ldd ${BUILDDIR}/plugins/builtin/builtin.hexplug | awk '/ => /{print $3}' | awk '!/(libc|libstdc++|libc++|libdl|libpthread|libselinux|ld-linux|libgdk)/' | xargs -I '{}' cp '{}' ${APPDIR}/usr/lib
|
||||
ldd ${BUILDDIR}/lib/libimhex/libimhex.so | awk '/ => /{print $3}' | awk '!/(libc|libstdc++|libc++|libdl|libpthread|libselinux|ld-linux|libgdk)/' | xargs -I '{}' cp '{}' ${APPDIR}/usr/lib
|
||||
|
||||
# Package it up as described here:
|
||||
# https://github.com/AppImage/AppImageKit#appimagetool-usage
|
||||
# under 'If you want to generate an AppImage manually'
|
||||
# This builds a v2 AppImage according to
|
||||
# https://github.com/AppImage/AppImageSpec/blob/master/draft.md#type-2-image-format
|
||||
mksquashfs ${APPDIR} ${BUILDDIR}/ImHex.squashfs -root-owned -noappend
|
||||
cat ${MYDIR}/runtime-x86_64 > ${APPIMAGE}
|
||||
cat ${BUILDDIR}/ImHex.squashfs >> ${APPIMAGE}
|
||||
chmod a+x ${APPIMAGE}
|
||||
|
||||
if [ ! -f /.dockerenv ]; then
|
||||
echo -e "\nThe created AppImage can be found here:\n ${APPIMAGE}\n\n"
|
||||
fi
|
||||
141
dist/AppImageBuilder.yml
vendored
Normal file
141
dist/AppImageBuilder.yml
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
# appimage-builder recipe see https://appimage-builder.readthedocs.io for details
|
||||
version: 1
|
||||
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/ jammy main restricted
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates main restricted
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy universe
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates universe
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy multiverse
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates multiverse
|
||||
- sourceline: deb http://.archive.ubuntu.com/ubuntu/ jammy-backports main restricted
|
||||
universe multiverse
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security main restricted
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security universe
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security multiverse
|
||||
include:
|
||||
- adwaita-icon-theme-full
|
||||
- librsvg2-common
|
||||
- libbz2-1.0:amd64
|
||||
- libcap2:amd64
|
||||
- libdbus-1-3:amd64
|
||||
- libgpg-error0:amd64
|
||||
- liblzma5:amd64
|
||||
- libnss-mdns:amd64
|
||||
- libpcre3:amd64
|
||||
- libselinux1:amd64
|
||||
- libtinfo6:amd64
|
||||
files:
|
||||
include:
|
||||
- /lib/x86_64-linux-gnu/libGLX.so.0
|
||||
- /lib/x86_64-linux-gnu/libGLdispatch.so.0
|
||||
- /lib/x86_64-linux-gnu/libLLVM-13.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.8
|
||||
- /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/libgmp.so.10
|
||||
- /lib/x86_64-linux-gnu/libgnutls.so.30
|
||||
- /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/libhogweed.so.6
|
||||
- /lib/x86_64-linux-gnu/libicudata.so.70
|
||||
- /lib/x86_64-linux-gnu/libicuuc.so.70
|
||||
- /lib/x86_64-linux-gnu/libidn2.so.0
|
||||
- /lib/x86_64-linux-gnu/libjpeg.so.8
|
||||
- /lib/x86_64-linux-gnu/liblber-2.5.so.0
|
||||
- /lib/x86_64-linux-gnu/libldap-2.5.so.0
|
||||
- /lib/x86_64-linux-gnu/liblz4.so.1
|
||||
- /lib/x86_64-linux-gnu/libmagic.so.1
|
||||
- /lib/x86_64-linux-gnu/libmbedcrypto.so.7
|
||||
- /lib/x86_64-linux-gnu/libmbedtls.so.14
|
||||
- /lib/x86_64-linux-gnu/libmbedx509.so.1
|
||||
- /lib/x86_64-linux-gnu/libmd.so.0
|
||||
- /lib/x86_64-linux-gnu/libmount.so.1
|
||||
- /lib/x86_64-linux-gnu/libnettle.so.8
|
||||
- /lib/x86_64-linux-gnu/libp11-kit.so.0
|
||||
- /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.10.so.1.0
|
||||
- /lib/x86_64-linux-gnu/libsasl2.so.2
|
||||
- /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/libtasn1.so.6
|
||||
- /lib/x86_64-linux-gnu/libthai.so.0
|
||||
- /lib/x86_64-linux-gnu/libunistring.so.2
|
||||
- /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
|
||||
38
dist/Arch/PKGBUILD
vendored
Normal file
38
dist/Arch/PKGBUILD
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# Maintainer: iTrooz_ <itrooz at protonmail dot com>
|
||||
pkgname=imhex-bin
|
||||
pkgver=%version%
|
||||
pkgrel=1
|
||||
pkgdesc="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM. "
|
||||
arch=("x86_64")
|
||||
url="https://github.com/WerWolv/ImHex"
|
||||
repo=$url
|
||||
license=('GPL 2.0')
|
||||
groups=()
|
||||
depends=(glfw mbedtls python freetype2 libglvnd gtk3)
|
||||
makedepends=(git)
|
||||
checkdepends=()
|
||||
optdepends=()
|
||||
provides=(imhex)
|
||||
conflicts=(imhex)
|
||||
replaces=()
|
||||
backup=()
|
||||
options=()
|
||||
source=($repo"/releases/download/v$pkgver/imhex-$pkgver-ArchLinux.pkg.tar.zst")
|
||||
noextract=()
|
||||
md5sums=(SKIP)
|
||||
validpgpkeys=()
|
||||
|
||||
package() {
|
||||
tar -xf imhex-$pkgver-ArchLinux.pkg.tar.zst
|
||||
|
||||
install -DT $srcdir/usr/bin/imhex $pkgdir/usr/bin/imhex
|
||||
install -DT $srcdir/usr/lib/libimhex.so $pkgdir/usr/lib/libimhex.so
|
||||
|
||||
for plugin in $srcdir/usr/share/imhex/plugins/*.hexplug;
|
||||
do
|
||||
install -DT $plugin $pkgdir/usr/share/imhex/plugins/`basename $plugin`
|
||||
done
|
||||
|
||||
cp -r $srcdir/usr/share/imhex/{constants,encodings,includes,magic,patterns} $pkgdir/usr/share/imhex
|
||||
install -d $pkgdir/usr/share/imhex
|
||||
}
|
||||
3
dist/Brewfile
vendored
3
dist/Brewfile
vendored
@@ -7,6 +7,5 @@ brew "python3"
|
||||
brew "freetype2"
|
||||
brew "libmagic"
|
||||
brew "pkg-config"
|
||||
|
||||
# TODO: Remove this when XCode version of clang will support the same level as LLVM 10
|
||||
brew "llvm"
|
||||
brew "gcc@12"
|
||||
|
||||
2
dist/DEBIAN/control.in
vendored
2
dist/DEBIAN/control.in
vendored
@@ -4,7 +4,7 @@ Section: editors
|
||||
Priority: optional
|
||||
Architecture: amd64
|
||||
License: GNU GPL-2
|
||||
Depends: libglfw3-dev, libmagic-dev, libmbedtls-dev, libcapstone-dev, python3-dev, libfreetype-dev, libgtk-3-dev, libldap2-dev
|
||||
Depends: libglfw3, libmagic1, libmbedtls14, libpython3.10, libfreetype6, libopengl0, libgtk-3-0
|
||||
Maintainer: WerWolv <hey@werwolv.net>
|
||||
Description: ImHex Hex Editor
|
||||
A Hex Editor for Reverse Engineers, Programmers and
|
||||
|
||||
41
dist/compiling/linux.md
vendored
Normal file
41
dist/compiling/linux.md
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
### Compiling ImHex on Linux
|
||||
|
||||
Dependency installation scripts are available for many common Linux distributions in the [/dist](dist) folder.
|
||||
After all the dependencies are installed, run the following commands to build ImHex:
|
||||
|
||||
```sh
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-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" \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-DRUST_PATH="$HOME/.cargo/bin/" \
|
||||
..
|
||||
make -j 4 install
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Put the ImHex executable into the `/usr/bin` folder.
|
||||
Put libimhex.so into the `/usr/lib` folder.
|
||||
Configuration files go to `/usr/etc/imhex` or `~/.config/imhex`.
|
||||
All other files belong in `/usr/share/imhex` or `~/.local/share/imhex`:
|
||||
|
||||
```
|
||||
Patterns: /usr/share/imhex/patterns
|
||||
Pattern Includes: /usr/share/imhex/includes
|
||||
Magic files: /usr/share/imhex/magic
|
||||
Python: /usr/share/imhex/lib/pythonX.X
|
||||
Plugins: /usr/share/imhex/plugins
|
||||
Configuration: /etc/xdg/imhex/config
|
||||
```
|
||||
|
||||
All paths follow the XDG Base Directories standard, and can thus be modified
|
||||
with the environment variables `XDG_CONFIG_HOME`, `XDG_CONFIG_DIRS`,
|
||||
`XDG_DATA_HOME` and `XDG_DATA_DIRS`.
|
||||
41
dist/compiling/macOS.md
vendored
Normal file
41
dist/compiling/macOS.md
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
### Compiling ImHex on macOS
|
||||
|
||||
To build ImHex on macOS, run the following commands:
|
||||
|
||||
```sh
|
||||
brew bundle --no-lock --file dist/Brewfile
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
|
||||
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
|
||||
OBJC=$(brew --prefix llvm)/bin/clang \
|
||||
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
|
||||
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
|
||||
MACOSX_DEPLOYMENT_TARGET="10.15" \
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCREATE_BUNDLE=ON \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
..
|
||||
make -j4 package
|
||||
```
|
||||
|
||||
Open the generated .dmg file and drag-n-drop the ImHex executable to the Applications folder
|
||||
|
||||
All other files belong in `~/Library/Application Support/imhex`:
|
||||
```
|
||||
Patterns: ~/Library/Application Support/imhex/patterns
|
||||
Pattern Includes: ~/Library/Application Support/imhex/includes
|
||||
Magic files: ~/Library/Application Support/imhex/magic
|
||||
Python: ~/Library/Application Support/imhex/lib/pythonX.X
|
||||
Plugins: ~/Library/Application Support/imhex/plugins
|
||||
Configuration: ~/Library/Application Support/imhex/config
|
||||
```
|
||||
|
||||
If the build fails while trying to find the macOS libraries, make sure you have
|
||||
XCode installed with `xcode-select --install`. Homebrew will also help get the
|
||||
most recent SDK installed and configured with `brew doctor`.
|
||||
23
dist/compiling/windows.md
vendored
Normal file
23
dist/compiling/windows.md
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
### Compiling ImHex on Windows
|
||||
|
||||
On Windows, ImHex is built through msys2 / mingw. To install all dependencies, open a mys2 window and run the PKGCONFIG script in the [dist/msys2](dist/msys2) folder.
|
||||
After all the dependencies are installed, run the following commands to build ImHex:
|
||||
|
||||
```sh
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "MinGW Makefiles" \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-DRUST_PATH="$USERPROFILE/.cargo/bin/" \
|
||||
..
|
||||
mingw32-make -j install
|
||||
```
|
||||
|
||||
ImHex will look for any extra resources either in various folders directly next to the executable or in `%localappdata%/imhex`
|
||||
2
dist/get_deps_archlinux.sh
vendored
2
dist/get_deps_archlinux.sh
vendored
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
pacman -S --needed \
|
||||
pacman -S $@ --needed \
|
||||
cmake \
|
||||
gcc \
|
||||
lld \
|
||||
|
||||
13
dist/get_deps_debian.sh
vendored
13
dist/get_deps_debian.sh
vendored
@@ -1,9 +1,5 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
echo "As of 2020-12, Debian stable does not include g++-10, needs debian testing or unstable."
|
||||
|
||||
# Tested on 2020-12-09 with Docker image bitnami/minideb:unstable
|
||||
|
||||
# Install pkgconf (adds minimum dependencies) only if the equivalent pkf-config is not already installed.
|
||||
if ! which pkg-config
|
||||
then
|
||||
@@ -12,8 +8,8 @@ fi
|
||||
|
||||
apt install -y \
|
||||
build-essential \
|
||||
gcc-10 \
|
||||
g++-10 \
|
||||
gcc-12 \
|
||||
g++-12 \
|
||||
lld \
|
||||
${PKGCONF:-} \
|
||||
cmake \
|
||||
@@ -25,7 +21,4 @@ apt install -y \
|
||||
libmbedtls-dev \
|
||||
python3-dev \
|
||||
libfreetype-dev \
|
||||
libgtk-3-dev \
|
||||
|
||||
echo "Please consider this before running cmake (useful on e.g. Ubuntu 20.04):"
|
||||
echo "export CXX=g++-10"
|
||||
libgtk-3-dev
|
||||
7
dist/imhex.desktop
vendored
7
dist/imhex.desktop
vendored
@@ -2,10 +2,9 @@
|
||||
Name=ImHex
|
||||
Comment=ImHex Hex Editor
|
||||
GenericName=Hex Editor
|
||||
Exec=/usr/bin/imhex %U
|
||||
Icon=/usr/share/pixmaps/imhex.png
|
||||
Exec=imhex %U
|
||||
Icon=imhex
|
||||
Type=Application
|
||||
StartupNotify=true
|
||||
Categories=GNOME;GTK;Development;
|
||||
Categories=Development;IDE;
|
||||
StartupWMClass=imhex
|
||||
|
||||
|
||||
2
lib/external/capstone
vendored
2
lib/external/capstone
vendored
Submodule lib/external/capstone updated: c7c665f8f3...d5141c0478
2
lib/external/curl
vendored
2
lib/external/curl
vendored
Submodule lib/external/curl updated: 801bd5138c...64db5c575d
2
lib/external/fmt
vendored
2
lib/external/fmt
vendored
Submodule lib/external/fmt updated: d141cdbeb0...bc654faf82
803
lib/external/imgui/include/imgui_memory_editor.h
vendored
803
lib/external/imgui/include/imgui_memory_editor.h
vendored
@@ -1,803 +0,0 @@
|
||||
// Mini memory editor for Dear ImGui (to embed in your game/tools)
|
||||
// Get latest version at http://www.github.com/ocornut/imgui_club
|
||||
//
|
||||
// Right-click anywhere to access the Options menu!
|
||||
// You can adjust the keyboard repeat delay/rate in ImGuiIO.
|
||||
// The code assume a mono-space font for simplicity!
|
||||
// If you don't use the default font, use ImGui::PushFont()/PopFont() to switch to a mono-space font before caling this.
|
||||
//
|
||||
// Usage:
|
||||
// // Create a window and draw memory editor inside it:
|
||||
// static MemoryEditor mem_edit_1;
|
||||
// static char data[0x10000];
|
||||
// size_t data_size = 0x10000;
|
||||
// mem_edit_1.DrawWindow("Memory Editor", data, data_size);
|
||||
//
|
||||
// Usage:
|
||||
// // If you already have a window, use DrawContents() instead:
|
||||
// static MemoryEditor mem_edit_2;
|
||||
// ImGui::Begin("MyWindow")
|
||||
// mem_edit_2.DrawContents(this, sizeof(*this), (size_t)this);
|
||||
// ImGui::End();
|
||||
//
|
||||
// Changelog:
|
||||
// - v0.10: initial version
|
||||
// - v0.23 (2017/08/17): added to github. fixed right-arrow triggering a byte write.
|
||||
// - v0.24 (2018/06/02): changed DragInt("Rows" to use a %d data format (which is desirable since imgui 1.61).
|
||||
// - v0.25 (2018/07/11): fixed wording: all occurrences of "Rows" renamed to "Columns".
|
||||
// - v0.26 (2018/08/02): fixed clicking on hex region
|
||||
// - v0.30 (2018/08/02): added data preview for common data types
|
||||
// - v0.31 (2018/10/10): added OptUpperCaseHex option to select lower/upper casing display [@samhocevar]
|
||||
// - v0.32 (2018/10/10): changed signatures to use void* instead of unsigned char*
|
||||
// - v0.33 (2018/10/10): added OptShowOptions option to hide all the interactive option setting.
|
||||
// - v0.34 (2019/05/07): binary preview now applies endianness setting [@nicolasnoble]
|
||||
// - v0.35 (2020/01/29): using ImGuiDataType available since Dear ImGui 1.69.
|
||||
// - v0.36 (2020/05/05): minor tweaks, minor refactor.
|
||||
// - v0.40 (2020/10/04): fix misuse of ImGuiListClipper API, broke with Dear ImGui 1.79. made cursor position appears on left-side of edit box. option popup appears on mouse release. fix MSVC warnings where _CRT_SECURE_NO_WARNINGS wasn't working in recent versions.
|
||||
// - v0.41 (2020/10/05): fix when using with keyboard/gamepad navigation enabled.
|
||||
// - v0.42 (2020/10/14): fix for . character in ASCII view always being greyed out.
|
||||
//
|
||||
// Todo/Bugs:
|
||||
// - This is generally old code, it should work but please don't use this as reference!
|
||||
// - Arrows are being sent to the InputText() about to disappear which for LeftArrow makes the text cursor appear at position 1 for one frame.
|
||||
// - Using InputText() is awkward and maybe overkill here, consider implementing something custom.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdio.h> // sprintf, scanf
|
||||
#include <stdint.h> // uint8_t, etc.
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define _PRISizeT "I"
|
||||
#define ImSnprintf _snprintf
|
||||
#else
|
||||
#define _PRISizeT "z"
|
||||
#define ImSnprintf snprintf
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (push)
|
||||
#pragma warning (disable: 4996) // warning C4996: 'sprintf': This function or variable may be unsafe.
|
||||
#endif
|
||||
|
||||
ImU32 ImAlphaBlendColors(ImU32 col_a, ImU32 col_b);
|
||||
|
||||
struct MemoryEditor
|
||||
{
|
||||
enum DataFormat
|
||||
{
|
||||
DataFormat_Bin = 0,
|
||||
DataFormat_Dec = 1,
|
||||
DataFormat_Hex = 2,
|
||||
DataFormat_COUNT
|
||||
};
|
||||
|
||||
struct DecodeData {
|
||||
std::string data;
|
||||
size_t advance;
|
||||
ImColor color;
|
||||
};
|
||||
|
||||
// Settings
|
||||
bool ReadOnly; // = false // disable any editing.
|
||||
int Cols; // = 16 // number of columns to display.
|
||||
bool OptShowOptions; // = true // display options button/context menu. when disabled, options will be locked unless you provide your own UI for them.
|
||||
bool OptShowHexII; // = false // display values in HexII representation instead of regular hexadecimal: hide null/zero bytes, ascii values as ".X".
|
||||
bool OptShowAscii; // = true // display ASCII representation on the right side.
|
||||
bool OptShowAdvancedDecoding; // = true // display advanced decoding data on the right side.
|
||||
bool OptGreyOutZeroes; // = true // display null/zero bytes using the TextDisabled color.
|
||||
bool OptUpperCaseHex; // = true // display hexadecimal values as "FF" instead of "ff".
|
||||
bool OptShowExtraInfo; // = true // display extra information about size of data and current selection
|
||||
int OptMidColsCount; // = 8 // set to 0 to disable extra spacing between every mid-cols.
|
||||
int OptAddrDigitsCount; // = 0 // number of addr digits to display (default calculated based on maximum displayed addr).
|
||||
ImU32 HighlightColor; // // background color of highlighted bytes.
|
||||
ImU8 (*ReadFn)(const ImU8* data, size_t off); // = 0 // optional handler to read bytes.
|
||||
void (*WriteFn)(ImU8* data, size_t off, ImU8 d); // = 0 // optional handler to write bytes.
|
||||
bool (*HighlightFn)(const ImU8* data, size_t off, bool next);//= 0 // optional handler to return Highlight property (to support non-contiguous highlighting).
|
||||
void (*HoverFn)(const ImU8 *data, size_t off);
|
||||
DecodeData (*DecodeFn)(const ImU8 *data, size_t off);
|
||||
|
||||
// [Internal State]
|
||||
bool ContentsWidthChanged;
|
||||
size_t DataPreviewAddr;
|
||||
size_t DataPreviewAddrOld;
|
||||
size_t DataPreviewAddrEnd;
|
||||
size_t DataPreviewAddrEndOld;
|
||||
size_t DataEditingAddr;
|
||||
bool DataEditingTakeFocus;
|
||||
char DataInputBuf[32];
|
||||
char AddrInputBuf[32];
|
||||
size_t GotoAddr;
|
||||
size_t HighlightMin, HighlightMax;
|
||||
int PreviewEndianess;
|
||||
ImGuiDataType PreviewDataType;
|
||||
|
||||
MemoryEditor()
|
||||
{
|
||||
// Settings
|
||||
ReadOnly = false;
|
||||
Cols = 16;
|
||||
OptShowOptions = true;
|
||||
OptShowHexII = false;
|
||||
OptShowAscii = true;
|
||||
OptShowAdvancedDecoding = true;
|
||||
OptGreyOutZeroes = true;
|
||||
OptUpperCaseHex = true;
|
||||
OptMidColsCount = 8;
|
||||
OptAddrDigitsCount = 0;
|
||||
HighlightColor = IM_COL32(255, 255, 255, 50);
|
||||
ReadFn = NULL;
|
||||
WriteFn = NULL;
|
||||
HighlightFn = NULL;
|
||||
HoverFn = NULL;
|
||||
DecodeFn = NULL;
|
||||
|
||||
// State/Internals
|
||||
ContentsWidthChanged = false;
|
||||
DataPreviewAddr = DataEditingAddr = DataPreviewAddrEnd = (size_t)-1;
|
||||
DataPreviewAddrOld = DataPreviewAddrEndOld = (size_t)-1;
|
||||
DataEditingTakeFocus = false;
|
||||
memset(DataInputBuf, 0, sizeof(DataInputBuf));
|
||||
memset(AddrInputBuf, 0, sizeof(AddrInputBuf));
|
||||
GotoAddr = (size_t)-1;
|
||||
HighlightMin = HighlightMax = (size_t)-1;
|
||||
PreviewEndianess = 0;
|
||||
PreviewDataType = ImGuiDataType_S32;
|
||||
}
|
||||
|
||||
void GotoAddrAndHighlight(size_t addr_min, size_t addr_max)
|
||||
{
|
||||
GotoAddr = addr_min;
|
||||
HighlightMin = addr_min;
|
||||
HighlightMax = addr_max;
|
||||
}
|
||||
|
||||
void GotoAddrAndSelect(size_t addr_min, size_t addr_max)
|
||||
{
|
||||
GotoAddr = addr_min;
|
||||
DataPreviewAddr = addr_min;
|
||||
DataPreviewAddrEnd = addr_max;
|
||||
DataPreviewAddrOld = addr_min;
|
||||
DataPreviewAddrEndOld = addr_max;
|
||||
}
|
||||
|
||||
struct Sizes
|
||||
{
|
||||
int AddrDigitsCount;
|
||||
float LineHeight;
|
||||
float GlyphWidth;
|
||||
float HexCellWidth;
|
||||
float SpacingBetweenMidCols;
|
||||
float PosHexStart;
|
||||
float PosHexEnd;
|
||||
float PosAsciiStart;
|
||||
float PosAsciiEnd;
|
||||
float PosDecodingStart;
|
||||
float PosDecodingEnd;
|
||||
float WindowWidth;
|
||||
|
||||
Sizes() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
void CalcSizes(Sizes& s, size_t mem_size, size_t base_display_addr)
|
||||
{
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
s.AddrDigitsCount = OptAddrDigitsCount;
|
||||
if (s.AddrDigitsCount == 0)
|
||||
for (size_t n = base_display_addr + mem_size - 1; n > 0; n >>= 4)
|
||||
s.AddrDigitsCount++;
|
||||
s.LineHeight = ImGui::GetTextLineHeight();
|
||||
s.GlyphWidth = ImGui::CalcTextSize("F").x + 1; // We assume the font is mono-space
|
||||
s.HexCellWidth = (float)(int)(s.GlyphWidth * 2.5f); // "FF " we include trailing space in the width to easily catch clicks everywhere
|
||||
s.SpacingBetweenMidCols = (float)(int)(s.HexCellWidth * 0.25f); // Every OptMidColsCount columns we add a bit of extra spacing
|
||||
s.PosHexStart = (s.AddrDigitsCount + 2) * s.GlyphWidth;
|
||||
s.PosHexEnd = s.PosHexStart + (s.HexCellWidth * Cols);
|
||||
s.PosAsciiStart = s.PosAsciiEnd = s.PosHexEnd;
|
||||
|
||||
if (OptShowAscii && OptShowAdvancedDecoding) {
|
||||
s.PosAsciiStart = s.PosHexEnd + s.GlyphWidth * 1;
|
||||
if (OptMidColsCount > 0)
|
||||
s.PosAsciiStart += (float)((Cols + OptMidColsCount - 1) / OptMidColsCount) * s.SpacingBetweenMidCols;
|
||||
s.PosAsciiEnd = s.PosAsciiStart + Cols * s.GlyphWidth;
|
||||
|
||||
s.PosDecodingStart = s.PosAsciiEnd + s.GlyphWidth * 1;
|
||||
if (OptMidColsCount > 0)
|
||||
s.PosDecodingStart += (float)((Cols + OptMidColsCount - 1) / OptMidColsCount) * s.SpacingBetweenMidCols;
|
||||
s.PosDecodingEnd = s.PosDecodingStart + Cols * s.GlyphWidth;
|
||||
} else if (OptShowAscii) {
|
||||
s.PosAsciiStart = s.PosHexEnd + s.GlyphWidth * 1;
|
||||
if (OptMidColsCount > 0)
|
||||
s.PosAsciiStart += (float)((Cols + OptMidColsCount - 1) / OptMidColsCount) * s.SpacingBetweenMidCols;
|
||||
s.PosAsciiEnd = s.PosAsciiStart + Cols * s.GlyphWidth;
|
||||
} else if (OptShowAdvancedDecoding) {
|
||||
s.PosDecodingStart = s.PosHexEnd + s.GlyphWidth * 1;
|
||||
if (OptMidColsCount > 0)
|
||||
s.PosDecodingStart += (float)((Cols + OptMidColsCount - 1) / OptMidColsCount) * s.SpacingBetweenMidCols;
|
||||
s.PosDecodingEnd = s.PosDecodingStart + Cols * s.GlyphWidth;
|
||||
}
|
||||
s.WindowWidth = s.PosAsciiEnd + style.ScrollbarSize + style.WindowPadding.x * 2 + s.GlyphWidth;
|
||||
}
|
||||
|
||||
// Standalone Memory Editor window
|
||||
void DrawWindow(const char* title, bool *p_open, void* mem_data, size_t mem_size, size_t base_display_addr = 0x0000)
|
||||
{
|
||||
Sizes s;
|
||||
CalcSizes(s, mem_size, base_display_addr);
|
||||
|
||||
if (ImGui::Begin(title, p_open, ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoNavInputs))
|
||||
{
|
||||
if (DataPreviewAddr != DataPreviewAddrOld || DataPreviewAddrEnd != DataPreviewAddrEndOld) {
|
||||
hex::Region selectionRegion = { std::min(DataPreviewAddr, DataPreviewAddrEnd) + base_display_addr, (std::max(DataPreviewAddr, DataPreviewAddrEnd) - std::min(DataPreviewAddr, DataPreviewAddrEnd)) + 1 };
|
||||
hex::EventManager::post<hex::EventRegionSelected>(selectionRegion);
|
||||
}
|
||||
|
||||
DataPreviewAddrOld = DataPreviewAddr;
|
||||
DataPreviewAddrEndOld = DataPreviewAddrEnd;
|
||||
|
||||
if (mem_size > 0)
|
||||
DrawContents(mem_data, mem_size, base_display_addr);
|
||||
|
||||
if (ContentsWidthChanged)
|
||||
{
|
||||
CalcSizes(s, mem_size, base_display_addr);
|
||||
ImGui::SetWindowSize(ImVec2(s.WindowWidth, ImGui::GetWindowSize().y));
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
|
||||
}
|
||||
|
||||
// Memory Editor contents only
|
||||
void DrawContents(void* mem_data_void, size_t mem_size, size_t base_display_addr = 0x0000)
|
||||
{
|
||||
if (Cols < 1)
|
||||
Cols = 1;
|
||||
|
||||
ImU8* mem_data = (ImU8*)mem_data_void;
|
||||
Sizes s;
|
||||
CalcSizes(s, mem_size, base_display_addr);
|
||||
ImGuiStyle& style = ImGui::GetStyle();
|
||||
|
||||
// We begin into our scrolling region with the 'ImGuiWindowFlags_NoMove' in order to prevent click from moving the window.
|
||||
// This is used as a facility since our main click detection code doesn't assign an ActiveId so the click would normally be caught as a window-move.
|
||||
const float height_separator = style.ItemSpacing.y;
|
||||
float footer_height = 0;
|
||||
if (OptShowOptions)
|
||||
footer_height += height_separator + ImGui::GetFrameHeightWithSpacing() * 2;
|
||||
|
||||
ImGui::BeginChild("offset", ImVec2(0, s.LineHeight), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav);
|
||||
ImGui::Text("%*c ", s.AddrDigitsCount, ' ');
|
||||
for (int i = 0; i < Cols; i++) {
|
||||
float byte_pos_x = s.PosHexStart + s.HexCellWidth * i;
|
||||
if (OptMidColsCount > 0)
|
||||
byte_pos_x += (float)(i / OptMidColsCount) * s.SpacingBetweenMidCols;
|
||||
ImGui::SameLine(byte_pos_x);
|
||||
ImGui::Text("%02llX", i + (base_display_addr % Cols));
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::BeginChild("##scrolling", ImVec2(0, -footer_height), false, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoNav);
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
|
||||
|
||||
|
||||
|
||||
// We are not really using the clipper API correctly here, because we rely on visible_start_addr/visible_end_addr for our scrolling function.
|
||||
ImGuiListClipper clipper;
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
const int line_total_count = (int)((mem_size + Cols - 1) / Cols);
|
||||
clipper.Begin(line_total_count, s.LineHeight);
|
||||
clipper.Step();
|
||||
const size_t visible_start_addr = clipper.DisplayStart * Cols;
|
||||
const size_t visible_end_addr = clipper.DisplayEnd * Cols;
|
||||
const size_t visible_count = visible_end_addr - visible_start_addr;
|
||||
|
||||
bool data_next = false;
|
||||
|
||||
if (DataEditingAddr >= mem_size)
|
||||
DataEditingAddr = (size_t)-1;
|
||||
if (DataPreviewAddr >= mem_size)
|
||||
DataPreviewAddr = (size_t)-1;
|
||||
if (DataPreviewAddrEnd >= mem_size)
|
||||
DataPreviewAddrEnd = (size_t)-1;
|
||||
|
||||
size_t data_editing_addr_backup = DataEditingAddr;
|
||||
size_t data_preview_addr_backup = DataPreviewAddr;
|
||||
size_t data_editing_addr_next = (size_t)-1;
|
||||
size_t data_preview_addr_next = (size_t)-1;
|
||||
|
||||
if (ImGui::IsWindowFocused()) {
|
||||
// Move cursor but only apply on next frame so scrolling with be synchronized (because currently we can't change the scrolling while the window is being rendered)
|
||||
if (DataEditingAddr != (size_t)-1) {
|
||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)) && DataEditingAddr >= (size_t)Cols) { data_editing_addr_next = DataEditingAddr - Cols; DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)) && DataEditingAddr < mem_size - Cols) { data_editing_addr_next = DataEditingAddr + Cols; DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)) && DataEditingAddr > 0) { data_editing_addr_next = DataEditingAddr - 1; DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)) && DataEditingAddr < mem_size - 1) { data_editing_addr_next = DataEditingAddr + 1; DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageUp)) && DataEditingAddr > 0) { data_editing_addr_next = std::max<i64>(0, DataEditingAddr - visible_count); DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageDown)) && DataEditingAddr < mem_size - 1) { data_editing_addr_next = std::min<i64>(mem_size - 1, DataEditingAddr + visible_count); DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)) && DataEditingAddr > 0) { data_editing_addr_next = 0; DataEditingTakeFocus = true; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)) && DataEditingAddr < mem_size - 1) { data_editing_addr_next = mem_size - 1; DataEditingTakeFocus = true; }
|
||||
} else if (DataPreviewAddr != -1) {
|
||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)) && DataPreviewAddr >= (size_t)Cols) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr - Cols; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)) && DataPreviewAddr < mem_size - Cols) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr + Cols; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)) && DataPreviewAddr > 0) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr - 1; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_RightArrow)) && DataPreviewAddr < mem_size - 1) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr + 1; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageUp)) && DataPreviewAddr > 0) { DataPreviewAddr = data_preview_addr_next = std::max<i64>(0, DataPreviewAddr - visible_count); if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_PageDown)) && DataPreviewAddr < mem_size - 1) { DataPreviewAddr = data_preview_addr_next = std::min<i64>(mem_size - 1, DataPreviewAddr + visible_count); if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Home)) && DataPreviewAddr > 0) { DataPreviewAddr = data_preview_addr_next = 0; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_End)) && DataPreviewAddr < mem_size - 1) { DataPreviewAddr = data_preview_addr_next = mem_size - 1; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
||||
}
|
||||
} else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape))) {
|
||||
DataPreviewAddr = DataPreviewAddrOld = DataPreviewAddrEnd = DataPreviewAddrEndOld = data_preview_addr_next = (size_t)-1;
|
||||
HighlightMin = HighlightMax = (size_t)-1;
|
||||
|
||||
hex::EventManager::post<hex::EventRegionSelected>(hex::Region{ (size_t)-1, 0 });
|
||||
}
|
||||
|
||||
if (data_preview_addr_next != (size_t)-1 && (data_preview_addr_next / Cols) != (data_preview_addr_backup / Cols))
|
||||
{
|
||||
// Track cursor movements
|
||||
const int scroll_offset = ((int)(data_preview_addr_next / Cols) - (int)(data_preview_addr_backup / Cols));
|
||||
const bool scroll_desired = (scroll_offset < 0 && data_preview_addr_next < visible_start_addr + Cols * 2) || (scroll_offset > 0 && data_preview_addr_next > visible_end_addr - Cols * 2);
|
||||
if (scroll_desired)
|
||||
ImGui::SetScrollY(ImGui::GetScrollY() + scroll_offset * s.LineHeight);
|
||||
}
|
||||
if (data_editing_addr_next != (size_t)-1 && (data_editing_addr_next / Cols) != (data_editing_addr_backup / Cols))
|
||||
{
|
||||
// Track cursor movements
|
||||
const int scroll_offset = ((int)(data_editing_addr_next / Cols) - (int)(data_editing_addr_backup / Cols));
|
||||
const bool scroll_desired = (scroll_offset < 0 && data_editing_addr_next < visible_start_addr + Cols * 2) || (scroll_offset > 0 && data_editing_addr_next > visible_end_addr - Cols * 2);
|
||||
if (scroll_desired)
|
||||
ImGui::SetScrollY(ImGui::GetScrollY() + scroll_offset * s.LineHeight);
|
||||
}
|
||||
|
||||
// Draw vertical separator
|
||||
ImVec2 window_pos = ImGui::GetWindowPos();
|
||||
float scrollX = ImGui::GetScrollX();
|
||||
|
||||
if (OptShowAscii)
|
||||
draw_list->AddLine(ImVec2(window_pos.x + s.PosAsciiStart - s.GlyphWidth - scrollX, window_pos.y), ImVec2(window_pos.x + s.PosAsciiStart - s.GlyphWidth - scrollX, window_pos.y + 9999), ImGui::GetColorU32(ImGuiCol_Border));
|
||||
if (OptShowAdvancedDecoding)
|
||||
draw_list->AddLine(ImVec2(window_pos.x + s.PosDecodingStart - s.GlyphWidth - scrollX, window_pos.y), ImVec2(window_pos.x + s.PosDecodingStart - s.GlyphWidth - scrollX, window_pos.y + 9999), ImGui::GetColorU32(ImGuiCol_Border));
|
||||
|
||||
const ImU32 color_text = ImGui::GetColorU32(ImGuiCol_Text);
|
||||
const ImU32 color_disabled = OptGreyOutZeroes ? ImGui::GetColorU32(ImGuiCol_TextDisabled) : color_text;
|
||||
|
||||
const char* format_address = OptUpperCaseHex ? "%0*" _PRISizeT "X: " : "%0*" _PRISizeT "x: ";
|
||||
const char* format_data = OptUpperCaseHex ? "%0*" _PRISizeT "X" : "%0*" _PRISizeT "x";
|
||||
const char* format_byte = OptUpperCaseHex ? "%02X" : "%02x";
|
||||
const char* format_byte_space = OptUpperCaseHex ? "%02X " : "%02x ";
|
||||
|
||||
bool tooltipShown = false;
|
||||
for (int line_i = clipper.DisplayStart; line_i < clipper.DisplayEnd; line_i++) // display only visible lines
|
||||
{
|
||||
size_t addr = (size_t)(line_i * Cols);
|
||||
ImGui::Text(format_address, s.AddrDigitsCount, base_display_addr + addr);
|
||||
|
||||
// Draw Hexadecimal
|
||||
for (int n = 0; n < Cols && addr < mem_size; n++, addr++)
|
||||
{
|
||||
float byte_pos_x = s.PosHexStart + s.HexCellWidth * n;
|
||||
if (OptMidColsCount > 0)
|
||||
byte_pos_x += (float)(n / OptMidColsCount) * s.SpacingBetweenMidCols;
|
||||
ImGui::SameLine(byte_pos_x);
|
||||
|
||||
// Draw highlight
|
||||
bool is_highlight_from_user_range = (addr >= HighlightMin && addr < HighlightMax);
|
||||
bool is_highlight_from_user_func = (HighlightFn && HighlightFn(mem_data, addr, false));
|
||||
bool is_highlight_from_preview = (addr >= DataPreviewAddr && addr <= DataPreviewAddrEnd) || (addr >= DataPreviewAddrEnd && addr <= DataPreviewAddr);
|
||||
if (is_highlight_from_user_range || is_highlight_from_user_func || is_highlight_from_preview)
|
||||
{
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos() - ImVec2(ImGui::GetStyle().CellPadding.x / 2, 0);
|
||||
float highlight_width = s.GlyphWidth * 2 + ImGui::GetStyle().CellPadding.x / 2;
|
||||
bool is_next_byte_highlighted = (addr + 1 < mem_size) &&
|
||||
((HighlightMax != (size_t)-1 && addr + 1 < HighlightMax) ||
|
||||
(HighlightFn && HighlightFn(mem_data, addr + 1, true)) ||
|
||||
((addr + 1) >= DataPreviewAddr && (addr + 1) <= DataPreviewAddrEnd) || ((addr + 1) >= DataPreviewAddrEnd && (addr + 1) <= DataPreviewAddr));
|
||||
if (is_next_byte_highlighted)
|
||||
{
|
||||
highlight_width = s.HexCellWidth;
|
||||
if (OptMidColsCount > 0 && n > 0 && (n + 1) < Cols && ((n + 1) % OptMidColsCount) == 0)
|
||||
highlight_width += s.SpacingBetweenMidCols;
|
||||
}
|
||||
|
||||
ImU32 color = HighlightColor;
|
||||
if ((is_highlight_from_user_range + is_highlight_from_user_func + is_highlight_from_preview) > 1)
|
||||
color = (ImAlphaBlendColors(HighlightColor, 0x60C08080) & 0x00FFFFFF) | 0x90000000;
|
||||
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + highlight_width, pos.y + s.LineHeight), color);
|
||||
|
||||
if (is_highlight_from_preview) {
|
||||
size_t min = std::min(DataPreviewAddr, DataPreviewAddrEnd);
|
||||
size_t max = std::max(DataPreviewAddr, DataPreviewAddrEnd);
|
||||
|
||||
// Draw vertical line at the left of first byte and the start of the line
|
||||
if (n == 0 || addr == min)
|
||||
draw_list->AddLine(pos, pos + ImVec2(0, s.LineHeight), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
|
||||
|
||||
// Draw vertical line at the right of the last byte and the end of the line
|
||||
if (n == Cols - 1 || addr == max) {
|
||||
draw_list->AddRectFilled(pos + ImVec2(highlight_width, 0), pos + ImVec2(highlight_width + 1, s.LineHeight), color);
|
||||
draw_list->AddLine(pos + ImVec2(highlight_width + 1, -1), pos + ImVec2(highlight_width + 1, s.LineHeight), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
|
||||
}
|
||||
|
||||
// Draw horizontal line at the top of the bytes
|
||||
if ((addr - Cols) < min)
|
||||
draw_list->AddLine(pos, pos + ImVec2(highlight_width + 1, 0), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
|
||||
|
||||
// Draw horizontal line at the bottom of the bytes
|
||||
if ((addr + Cols) == (max + 1) && OptMidColsCount > 0 && n > 0 && (n + 1) < Cols && ((n + 1) % OptMidColsCount) == 1)
|
||||
draw_list->AddLine(pos + ImVec2(-s.SpacingBetweenMidCols, s.LineHeight), pos + ImVec2(highlight_width + 1, s.LineHeight), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
|
||||
else if ((addr + Cols) > max)
|
||||
draw_list->AddLine(pos + ImVec2(0, s.LineHeight), pos + ImVec2(highlight_width + 1, s.LineHeight), ImColor(ImGui::GetStyleColorVec4(ImGuiCol_Text)), 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
if (DataEditingAddr == addr)
|
||||
{
|
||||
// Display text input on current byte
|
||||
bool data_write = false;
|
||||
ImGui::PushID((void*)addr);
|
||||
if (DataEditingTakeFocus)
|
||||
{
|
||||
ImGui::SetKeyboardFocusHere();
|
||||
ImGui::CaptureKeyboardFromApp(true);
|
||||
sprintf(AddrInputBuf, format_data, s.AddrDigitsCount, base_display_addr + addr);
|
||||
sprintf(DataInputBuf, format_byte, ReadFn ? ReadFn(mem_data, addr) : mem_data[addr]);
|
||||
}
|
||||
ImGui::PushItemWidth(s.GlyphWidth * 2);
|
||||
struct UserData
|
||||
{
|
||||
// FIXME: We should have a way to retrieve the text edit cursor position more easily in the API, this is rather tedious. This is such a ugly mess we may be better off not using InputText() at all here.
|
||||
static int Callback(ImGuiInputTextCallbackData* data)
|
||||
{
|
||||
UserData* user_data = (UserData*)data->UserData;
|
||||
if (!data->HasSelection())
|
||||
user_data->CursorPos = data->CursorPos;
|
||||
if (data->SelectionStart == 0 && data->SelectionEnd == data->BufTextLen)
|
||||
{
|
||||
// When not editing a byte, always rewrite its content (this is a bit tricky, since InputText technically "owns" the master copy of the buffer we edit it in there)
|
||||
data->DeleteChars(0, data->BufTextLen);
|
||||
data->InsertChars(0, user_data->CurrentBufOverwrite);
|
||||
data->SelectionStart = 0;
|
||||
data->SelectionEnd = 2;
|
||||
data->CursorPos = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
char CurrentBufOverwrite[3]; // Input
|
||||
int CursorPos; // Output
|
||||
};
|
||||
UserData user_data;
|
||||
user_data.CursorPos = -1;
|
||||
sprintf(user_data.CurrentBufOverwrite, format_byte, ReadFn ? ReadFn(mem_data, addr) : mem_data[addr]);
|
||||
ImGuiInputTextFlags flags = ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoHorizontalScroll | ImGuiInputTextFlags_AlwaysInsertMode | ImGuiInputTextFlags_CallbackAlways;
|
||||
if (ImGui::InputText("##data", DataInputBuf, 32, flags, UserData::Callback, &user_data))
|
||||
data_write = data_next = true;
|
||||
else if (!DataEditingTakeFocus && !ImGui::IsItemActive())
|
||||
DataEditingAddr = data_editing_addr_next = (size_t)-1;
|
||||
DataEditingTakeFocus = false;
|
||||
ImGui::PopItemWidth();
|
||||
if (user_data.CursorPos >= 2)
|
||||
data_write = data_next = true;
|
||||
if (data_editing_addr_next != (size_t)-1)
|
||||
data_write = data_next = false;
|
||||
unsigned int data_input_value = 0;
|
||||
if (data_write && sscanf(DataInputBuf, "%X", &data_input_value) == 1)
|
||||
{
|
||||
if (WriteFn)
|
||||
WriteFn(mem_data, addr, (ImU8)data_input_value);
|
||||
else
|
||||
mem_data[addr] = (ImU8)data_input_value;
|
||||
}
|
||||
ImGui::PopID();
|
||||
}
|
||||
else
|
||||
{
|
||||
// NB: The trailing space is not visible but ensure there's no gap that the mouse cannot click on.
|
||||
ImU8 b = ReadFn ? ReadFn(mem_data, addr) : mem_data[addr];
|
||||
|
||||
if (OptShowHexII)
|
||||
{
|
||||
if ((b >= 32 && b < 128))
|
||||
ImGui::Text(".%c ", b);
|
||||
else if (b == 0xFF && OptGreyOutZeroes)
|
||||
ImGui::TextDisabled("## ");
|
||||
else if (b == 0x00)
|
||||
ImGui::Text(" ");
|
||||
else
|
||||
ImGui::Text(format_byte_space, b);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (b == 0 && OptGreyOutZeroes)
|
||||
ImGui::TextDisabled("00 ");
|
||||
else
|
||||
ImGui::Text(format_byte_space, b);
|
||||
}
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0) && !ImGui::GetIO().KeyShift)
|
||||
{
|
||||
if (!ReadOnly && ImGui::IsMouseDoubleClicked(0)) {
|
||||
DataEditingTakeFocus = true;
|
||||
data_editing_addr_next = addr;
|
||||
}
|
||||
|
||||
DataPreviewAddr = addr;
|
||||
DataPreviewAddrEnd = addr;
|
||||
}
|
||||
if (ImGui::IsItemHovered() && ((ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyShift) || ImGui::IsMouseDragging(0))) {
|
||||
DataPreviewAddrEnd = addr;
|
||||
}
|
||||
if (ImGui::IsItemHovered() && !tooltipShown) {
|
||||
if (HoverFn) {
|
||||
HoverFn(mem_data, addr);
|
||||
tooltipShown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (OptShowAscii)
|
||||
{
|
||||
// Draw ASCII values
|
||||
ImGui::SameLine(s.PosAsciiStart);
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
addr = line_i * Cols;
|
||||
|
||||
ImGui::PushID(-1);
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(s.GlyphWidth, s.LineHeight));
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
for (int n = 0; n < Cols && addr < mem_size; n++, addr++)
|
||||
{
|
||||
if (addr == DataEditingAddr)
|
||||
{
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_FrameBg));
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_TextSelectedBg));
|
||||
}
|
||||
unsigned char c = ReadFn ? ReadFn(mem_data, addr) : mem_data[addr];
|
||||
char display_c = (c < 32 || c >= 128) ? '.' : c;
|
||||
draw_list->AddText(pos, (display_c == c) ? color_text : color_disabled, &display_c, &display_c + 1);
|
||||
|
||||
// Draw highlight
|
||||
bool is_highlight_from_user_range = (addr >= HighlightMin && addr < HighlightMax);
|
||||
bool is_highlight_from_user_func = (HighlightFn && HighlightFn(mem_data, addr, false));
|
||||
bool is_highlight_from_preview = (addr >= DataPreviewAddr && addr <= DataPreviewAddrEnd) || (addr >= DataPreviewAddrEnd && addr <= DataPreviewAddr);
|
||||
if (is_highlight_from_user_range || is_highlight_from_user_func || is_highlight_from_preview)
|
||||
{
|
||||
ImU32 color = HighlightColor;
|
||||
if ((is_highlight_from_user_range + is_highlight_from_user_func + is_highlight_from_preview) > 1)
|
||||
color = (ImAlphaBlendColors(HighlightColor, 0x60C08080) & 0x00FFFFFF) | 0x90000000;
|
||||
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + s.GlyphWidth, pos.y + s.LineHeight), color);
|
||||
}
|
||||
|
||||
|
||||
ImGui::PushID(line_i * Cols + n);
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(s.GlyphWidth, s.LineHeight));
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0) && !ImGui::GetIO().KeyShift)
|
||||
{
|
||||
if (!ReadOnly && ImGui::IsMouseDoubleClicked(0)) {
|
||||
DataEditingTakeFocus = true;
|
||||
data_editing_addr_next = addr;
|
||||
}
|
||||
|
||||
DataPreviewAddr = addr;
|
||||
DataPreviewAddrEnd = addr;
|
||||
|
||||
}
|
||||
if (ImGui::IsItemHovered() && ((ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyShift) || ImGui::IsMouseDragging(0))) {
|
||||
DataPreviewAddrEnd = addr;
|
||||
}
|
||||
|
||||
pos.x += s.GlyphWidth;
|
||||
}
|
||||
|
||||
ImGui::PushID(-1);
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(s.GlyphWidth, s.LineHeight));
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
if (OptShowAdvancedDecoding && DecodeFn) {
|
||||
// Draw decoded bytes
|
||||
ImGui::SameLine(s.PosDecodingStart);
|
||||
ImVec2 pos = ImGui::GetCursorScreenPos();
|
||||
addr = line_i * Cols;
|
||||
|
||||
ImGui::PushID(-1);
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(s.GlyphWidth, s.LineHeight));
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
for (int n = 0; n < Cols && addr < mem_size;)
|
||||
{
|
||||
auto decodedData = DecodeFn(mem_data, addr);
|
||||
|
||||
auto displayData = decodedData.data;
|
||||
auto glyphWidth = ImGui::CalcTextSize(displayData.c_str()).x + 1;
|
||||
|
||||
if (addr == DataEditingAddr)
|
||||
{
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + glyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_FrameBg));
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + glyphWidth, pos.y + s.LineHeight), ImGui::GetColorU32(ImGuiCol_TextSelectedBg));
|
||||
}
|
||||
|
||||
draw_list->AddText(pos, decodedData.color, displayData.c_str(), displayData.c_str() + displayData.length());
|
||||
|
||||
// Draw highlight
|
||||
bool is_highlight_from_user_range = (addr >= HighlightMin && addr < HighlightMax);
|
||||
bool is_highlight_from_user_func = (HighlightFn && HighlightFn(mem_data, addr, false));
|
||||
bool is_highlight_from_preview = (addr >= DataPreviewAddr && addr <= DataPreviewAddrEnd) || (addr >= DataPreviewAddrEnd && addr <= DataPreviewAddr);
|
||||
if (is_highlight_from_user_range || is_highlight_from_user_func || is_highlight_from_preview)
|
||||
{
|
||||
ImU32 color = HighlightColor;
|
||||
if ((is_highlight_from_user_range + is_highlight_from_user_func + is_highlight_from_preview) > 1)
|
||||
color = (ImAlphaBlendColors(HighlightColor, 0x60C08080) & 0x00FFFFFF) | 0x90000000;
|
||||
|
||||
draw_list->AddRectFilled(pos, ImVec2(pos.x + glyphWidth, pos.y + s.LineHeight), color);
|
||||
}
|
||||
|
||||
|
||||
ImGui::PushID(line_i * Cols + n);
|
||||
ImGui::SameLine();
|
||||
ImGui::Dummy(ImVec2(glyphWidth, s.LineHeight));
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(0) && !ImGui::GetIO().KeyShift)
|
||||
{
|
||||
if (!ReadOnly && ImGui::IsMouseDoubleClicked(0)) {
|
||||
DataEditingTakeFocus = true;
|
||||
data_editing_addr_next = addr;
|
||||
}
|
||||
|
||||
DataPreviewAddr = addr;
|
||||
DataPreviewAddrEnd = addr;
|
||||
|
||||
}
|
||||
if (ImGui::IsItemHovered() && ((ImGui::IsMouseClicked(0) && ImGui::GetIO().KeyShift) || ImGui::IsMouseDragging(0))) {
|
||||
DataPreviewAddrEnd = addr;
|
||||
}
|
||||
|
||||
pos.x += glyphWidth;
|
||||
|
||||
if (addr <= 1) {
|
||||
n++;
|
||||
addr++;
|
||||
} else {
|
||||
n += decodedData.advance;
|
||||
addr += decodedData.advance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
IM_ASSERT(clipper.Step() == false);
|
||||
clipper.End();
|
||||
ImGui::PopStyleVar(2);
|
||||
ImGui::EndChild();
|
||||
|
||||
if (data_next && DataEditingAddr < mem_size)
|
||||
{
|
||||
DataEditingAddr = DataPreviewAddr = DataEditingAddr + 1;
|
||||
DataEditingTakeFocus = true;
|
||||
}
|
||||
else if (data_editing_addr_next != (size_t)-1)
|
||||
{
|
||||
DataEditingAddr = DataPreviewAddr = DataPreviewAddrEnd = data_editing_addr_next;
|
||||
}
|
||||
|
||||
if (OptShowOptions)
|
||||
{
|
||||
ImGui::Separator();
|
||||
DrawOptionsLine(s, mem_data, mem_size, base_display_addr);
|
||||
}
|
||||
|
||||
// Notify the main window of our ideal child content size (FIXME: we are missing an API to get the contents size from the child)
|
||||
ImGui::SetCursorPosX(s.WindowWidth);
|
||||
}
|
||||
|
||||
void DrawOptionsLine(const Sizes& s, void* mem_data, size_t mem_size, size_t base_display_addr)
|
||||
{
|
||||
IM_UNUSED(mem_data);
|
||||
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)";
|
||||
|
||||
if (this->OptShowExtraInfo) {
|
||||
ImGui::Text(format_range, s.AddrDigitsCount, base_display_addr, s.AddrDigitsCount, base_display_addr + mem_size - 1);
|
||||
if (DataPreviewAddr != (size_t)-1 && DataPreviewAddrEnd != (size_t)-1) {
|
||||
ImGui::SameLine();
|
||||
ImGui::Spacing();
|
||||
ImGui::SameLine();
|
||||
|
||||
auto selectionStart = std::min(DataPreviewAddr, DataPreviewAddrEnd);
|
||||
auto selectionEnd = std::max(DataPreviewAddr, DataPreviewAddrEnd);
|
||||
|
||||
size_t regionSize = (selectionEnd - selectionStart) + 1;
|
||||
ImGui::Text(format_selection, s.AddrDigitsCount, base_display_addr + selectionStart, s.AddrDigitsCount, base_display_addr + selectionEnd, regionSize, regionSize, regionSize == 1 ? "byte" : "bytes");
|
||||
}
|
||||
}
|
||||
|
||||
if (GotoAddr != (size_t)-1)
|
||||
{
|
||||
if (GotoAddr < mem_size)
|
||||
{
|
||||
ImGui::BeginChild("##scrolling");
|
||||
ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + (GotoAddr / Cols) * ImGui::GetTextLineHeight());
|
||||
ImGui::EndChild();
|
||||
}
|
||||
GotoAddr = (size_t)-1;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsBigEndian()
|
||||
{
|
||||
uint16_t x = 1;
|
||||
char c[2];
|
||||
memcpy(c, &x, 2);
|
||||
return c[0] != 0;
|
||||
}
|
||||
|
||||
static void* EndianessCopyBigEndian(void* _dst, void* _src, size_t s, int is_little_endian)
|
||||
{
|
||||
if (is_little_endian)
|
||||
{
|
||||
uint8_t* dst = (uint8_t*)_dst;
|
||||
uint8_t* src = (uint8_t*)_src + s - 1;
|
||||
for (int i = 0, n = (int)s; i < n; ++i)
|
||||
memcpy(dst++, src--, 1);
|
||||
return _dst;
|
||||
}
|
||||
else
|
||||
{
|
||||
return memcpy(_dst, _src, s);
|
||||
}
|
||||
}
|
||||
|
||||
static void* EndianessCopyLittleEndian(void* _dst, void* _src, size_t s, int is_little_endian)
|
||||
{
|
||||
if (is_little_endian)
|
||||
{
|
||||
return memcpy(_dst, _src, s);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t* dst = (uint8_t*)_dst;
|
||||
uint8_t* src = (uint8_t*)_src + s - 1;
|
||||
for (int i = 0, n = (int)s; i < n; ++i)
|
||||
memcpy(dst++, src--, 1);
|
||||
return _dst;
|
||||
}
|
||||
}
|
||||
|
||||
void* EndianessCopy(void* dst, void* src, size_t size) const
|
||||
{
|
||||
static void* (*fp)(void*, void*, size_t, int) = NULL;
|
||||
if (fp == NULL)
|
||||
fp = IsBigEndian() ? EndianessCopyBigEndian : EndianessCopyLittleEndian;
|
||||
return fp(dst, src, size, PreviewEndianess);
|
||||
}
|
||||
};
|
||||
|
||||
#undef _PRISizeT
|
||||
#undef ImSnprintf
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning (pop)
|
||||
#endif
|
||||
2
lib/external/imgui/source/TextEditor.cpp
vendored
2
lib/external/imgui/source/TextEditor.cpp
vendored
@@ -821,7 +821,7 @@ void TextEditor::Render() {
|
||||
ImGui::Text("Error at line %d:", errorIt->first);
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::Separator();
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 0.2f, 1.0f));
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.5f, 0.5f, 0.2f, 1.0f));
|
||||
ImGui::Text("%s", errorIt->second.c_str());
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::EndTooltip();
|
||||
|
||||
58
lib/external/imgui/source/imgui_impl_glfw.cpp
vendored
58
lib/external/imgui/source/imgui_impl_glfw.cpp
vendored
@@ -47,6 +47,7 @@
|
||||
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
|
||||
|
||||
#include "imgui.h"
|
||||
#include "imgui_internal.h"
|
||||
#include "imgui_impl_glfw.h"
|
||||
|
||||
// GLFW
|
||||
@@ -136,6 +137,51 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||
glfwSetClipboardString((GLFWwindow*)user_data, text);
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
static const char* ImGui_ImplWin_GetClipboardText(void*)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.ClipboardHandlerData.clear();
|
||||
if (!::OpenClipboard(NULL))
|
||||
return NULL;
|
||||
HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);
|
||||
if (wbuf_handle == NULL)
|
||||
{
|
||||
::CloseClipboard();
|
||||
return NULL;
|
||||
}
|
||||
if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle))
|
||||
{
|
||||
int buf_len = ::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, NULL, 0, NULL, NULL);
|
||||
g.ClipboardHandlerData.resize(buf_len);
|
||||
::WideCharToMultiByte(CP_UTF8, 0, wbuf_global, -1, g.ClipboardHandlerData.Data, buf_len, NULL, NULL);
|
||||
}
|
||||
::GlobalUnlock(wbuf_handle);
|
||||
::CloseClipboard();
|
||||
return g.ClipboardHandlerData.Data;
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin_SetClipboardText(void*, const char* text)
|
||||
{
|
||||
if (!::OpenClipboard(NULL))
|
||||
return;
|
||||
const int wbuf_length = ::MultiByteToWideChar(CP_UTF8, 0, text, -1, NULL, 0);
|
||||
HGLOBAL wbuf_handle = ::GlobalAlloc(GMEM_MOVEABLE, (SIZE_T)wbuf_length * sizeof(WCHAR));
|
||||
if (wbuf_handle == NULL)
|
||||
{
|
||||
::CloseClipboard();
|
||||
return;
|
||||
}
|
||||
WCHAR* wbuf_global = (WCHAR*)::GlobalLock(wbuf_handle);
|
||||
::MultiByteToWideChar(CP_UTF8, 0, text, -1, wbuf_global, wbuf_length);
|
||||
::GlobalUnlock(wbuf_handle);
|
||||
::EmptyClipboard();
|
||||
if (::SetClipboardData(CF_UNICODETEXT, wbuf_handle) == NULL)
|
||||
::GlobalFree(wbuf_handle);
|
||||
::CloseClipboard();
|
||||
}
|
||||
#endif
|
||||
|
||||
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
|
||||
{
|
||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
||||
@@ -271,9 +317,15 @@ static bool ImGui_ImplGlfw_Init(GLFWwindow* window, bool install_callbacks, Glfw
|
||||
io.KeyMap[ImGuiKey_Y] = GLFW_KEY_Y;
|
||||
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
|
||||
|
||||
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
|
||||
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
|
||||
io.ClipboardUserData = bd->Window;
|
||||
#if defined(OS_WINDOWS)
|
||||
io.SetClipboardTextFn = ImGui_ImplWin_SetClipboardText;
|
||||
io.GetClipboardTextFn = ImGui_ImplWin_GetClipboardText;
|
||||
io.ClipboardUserData = bd->Window;
|
||||
#else
|
||||
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
|
||||
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
|
||||
io.ClipboardUserData = bd->Window;
|
||||
#endif
|
||||
|
||||
// Create mouse cursors
|
||||
// (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
|
||||
|
||||
2
lib/external/libromfs
vendored
2
lib/external/libromfs
vendored
Submodule lib/external/libromfs updated: 0842d22deb...12063078f0
2
lib/external/nativefiledialog
vendored
2
lib/external/nativefiledialog
vendored
Submodule lib/external/nativefiledialog updated: 322d1bc2a9...28ade5a5cc
1
lib/external/pattern_language
vendored
Submodule
1
lib/external/pattern_language
vendored
Submodule
Submodule lib/external/pattern_language added at 5ab770490e
20
lib/external/yara/CMakeLists.txt
vendored
20
lib/external/yara/CMakeLists.txt
vendored
@@ -81,17 +81,19 @@ set(LIBYARA_SOURCE
|
||||
)
|
||||
|
||||
set(LIBYARA_MODULES
|
||||
${LIBYARA_SOURCE_PATH}/modules/tests/tests.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/pe/pe.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/pe/pe_utils.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/elf/elf.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/math/math.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/time/time.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/macho/macho.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/hash/hash.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/console/console.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/dex/dex.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/dotnet/dotnet.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/magic/magic.c)
|
||||
${LIBYARA_SOURCE_PATH}/modules/elf/elf.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/hash/hash.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/macho/macho.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/magic/magic.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/math/math.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/pe/pe.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/pe/pe_utils.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/tests/tests.c
|
||||
${LIBYARA_SOURCE_PATH}/modules/time/time.c
|
||||
)
|
||||
|
||||
# Add mbedtls crypto wrappers
|
||||
add_compile_definitions("HAVE_MBEDTLS")
|
||||
|
||||
2
lib/external/yara/yara
vendored
2
lib/external/yara/yara
vendored
Submodule lib/external/yara/yara updated: 8206dc6f72...136794355c
558
lib/libimhex-rs/Cargo.lock
generated
558
lib/libimhex-rs/Cargo.lock
generated
@@ -2,6 +2,149 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ansi_term"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "aquamarine"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96e14cb2a51c8b45d26a4219981985c7350fc05eacb7b5b2939bceb2ffefdf3e"
|
||||
dependencies = [
|
||||
"itertools 0.9.0",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atty"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocxx"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "13e6384cb95b48be8c5b83764ef800858322436f57aa17974915d23dadb6a7d5"
|
||||
dependencies = [
|
||||
"aquamarine",
|
||||
"autocxx-engine",
|
||||
"autocxx-macro",
|
||||
"cxx",
|
||||
"moveit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocxx-bindgen"
|
||||
version = "0.59.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e603c1eb79e21068072ef990e5463f613e0cedddd6712ff11afeae2a90b2510"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cexpr",
|
||||
"clang-sys",
|
||||
"clap",
|
||||
"env_logger",
|
||||
"itertools 0.10.3",
|
||||
"lazy_static",
|
||||
"lazycell",
|
||||
"log",
|
||||
"peeking_take_while",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"regex",
|
||||
"rustc-hash",
|
||||
"shlex",
|
||||
"which",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocxx-build"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4a5f5b45a4fe71d3ac68d8b4fd11abe54c791046ec4def7effe27961269b6ab3"
|
||||
dependencies = [
|
||||
"autocxx-engine",
|
||||
"env_logger",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocxx-engine"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02323905bec49fde96ff028fcff1c478d0eba14fa34ea5eb5e4d17439748e42a"
|
||||
dependencies = [
|
||||
"aquamarine",
|
||||
"autocxx-bindgen",
|
||||
"autocxx-parser",
|
||||
"cc",
|
||||
"cxx",
|
||||
"cxx-gen",
|
||||
"indoc",
|
||||
"itertools 0.10.3",
|
||||
"log",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde_json",
|
||||
"strum_macros",
|
||||
"syn",
|
||||
"tempfile",
|
||||
"unzip-n",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocxx-macro"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8106ca477cbe6edf188311f2e05606b81bf463c41748ce7120c31d1b11875515"
|
||||
dependencies = [
|
||||
"autocxx-parser",
|
||||
"proc-macro-error",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "autocxx-parser"
|
||||
version = "0.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ad0ad08260adcecc119b08f460b0633b6e306ea2f6fda4f27e4dd28e20b9a2f4"
|
||||
dependencies = [
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.3.2"
|
||||
@@ -14,6 +157,15 @@ version = "1.0.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d26a6ce4b6a484fa3edb70f7efa6fc430fd2b87285fe8b84304fd0936faa0dc0"
|
||||
|
||||
[[package]]
|
||||
name = "cexpr"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
|
||||
dependencies = [
|
||||
"nom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
@@ -26,6 +178,32 @@ version = "1.0.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd650552110e39b7c5058986cf177decd3365841836578ac50a286094eac0be6"
|
||||
|
||||
[[package]]
|
||||
name = "clang-sys"
|
||||
version = "1.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4cc00842eed744b858222c4c9faf7243aafc6d33f92f96935263ef4d8a41ce21"
|
||||
dependencies = [
|
||||
"glob",
|
||||
"libc",
|
||||
"libloading",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "clap"
|
||||
version = "2.34.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"atty",
|
||||
"bitflags",
|
||||
"strsim",
|
||||
"textwrap",
|
||||
"unicode-width",
|
||||
"vec_map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
@@ -49,17 +227,14 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "1.0.55"
|
||||
name = "cxx-gen"
|
||||
version = "0.7.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83363b96cfd226eb820e37a21088c30c55e47f9fc8299c2d08a6090d50414ccc"
|
||||
checksum = "836e95ae34fc21fb39c206444879afda2c6e704424c9c621662764f1b459e83a"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
"lazy_static",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn",
|
||||
]
|
||||
|
||||
@@ -81,15 +256,63 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libimhex-rs"
|
||||
version = "0.1.0"
|
||||
name = "either"
|
||||
version = "1.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
"imgui",
|
||||
"macros",
|
||||
"atty",
|
||||
"humantime",
|
||||
"log",
|
||||
"regex",
|
||||
"termcolor",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
|
||||
dependencies = [
|
||||
"unicode-segmentation",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "humantime"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
|
||||
|
||||
[[package]]
|
||||
name = "imgui"
|
||||
version = "0.8.0"
|
||||
@@ -107,6 +330,23 @@ dependencies = [
|
||||
"chlorine",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "imhex-macros"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indoc"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7906a9fababaeacb774f72410e497a1d18de916322e33797bb2cd29baa23c9e"
|
||||
dependencies = [
|
||||
"unindent",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.11"
|
||||
@@ -116,18 +356,69 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
|
||||
dependencies = [
|
||||
"either",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "lazycell"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.103"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8f7255a17a627354f321ef0055d63b898c6fb27eff628af4d1b66b7331edf6"
|
||||
|
||||
[[package]]
|
||||
name = "libimhex-rs"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"autocxx",
|
||||
"autocxx-build",
|
||||
"cxx",
|
||||
"imgui",
|
||||
"imhex-macros",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "link-cplusplus"
|
||||
version = "1.0.5"
|
||||
@@ -147,13 +438,52 @@ dependencies = [
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "macros"
|
||||
version = "0.1.0"
|
||||
name = "log"
|
||||
version = "0.4.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"syn",
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
|
||||
|
||||
[[package]]
|
||||
name = "minimal-lexical"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||
|
||||
[[package]]
|
||||
name = "moveit"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bd833d6adefa6bcfc56948d061c1d697dfa3ab63711963c7ef4aa23eda945676"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"minimal-lexical",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.11.2"
|
||||
@@ -179,6 +509,36 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "peeking_take_while"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
|
||||
dependencies = [
|
||||
"proc-macro-error-attr",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro-error-attr"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.29"
|
||||
@@ -206,6 +566,50 @@ dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
|
||||
|
||||
[[package]]
|
||||
name = "rustversion"
|
||||
version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
@@ -213,10 +617,38 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "scratch"
|
||||
version = "1.0.0"
|
||||
name = "serde"
|
||||
version = "1.0.136"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e114536316b51a5aa7a0e59fc49661fd263c5507dd08bd28de052e57626ce69"
|
||||
checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.136"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3"
|
||||
|
||||
[[package]]
|
||||
name = "smallvec"
|
||||
@@ -224,6 +656,25 @@ version = "1.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309"
|
||||
|
||||
[[package]]
|
||||
name = "strsim"
|
||||
version = "0.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
|
||||
|
||||
[[package]]
|
||||
name = "strum_macros"
|
||||
version = "0.23.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5bb0dc7ee9c15cea6199cde9a127fa16a4c5819af85395457ad72d68edc85a38"
|
||||
dependencies = [
|
||||
"heck",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rustversion",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.77"
|
||||
@@ -235,6 +686,20 @@ dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.2"
|
||||
@@ -244,6 +709,21 @@ dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "textwrap"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
|
||||
dependencies = [
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.9"
|
||||
@@ -256,6 +736,46 @@ version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
|
||||
|
||||
[[package]]
|
||||
name = "unindent"
|
||||
version = "0.1.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "514672a55d7380da379785a4d70ca8386c8883ff7eaae877be4d2081cebe73d8"
|
||||
|
||||
[[package]]
|
||||
name = "unzip-n"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2e7e85a0596447f0f2ac090e16bc4c516c6fe91771fb0c0ccf7fa3dae896b9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "which"
|
||||
version = "4.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a5a7e487e921cf220206864a94a89b6c6905bfc19f1057fa26a4cb360e5c1d2"
|
||||
dependencies = [
|
||||
"either",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
|
||||
@@ -11,6 +11,8 @@ imhex-macros = { path = "proc_macros" }
|
||||
imgui = { path = "imgui-rs" }
|
||||
|
||||
cxx = "1.0.55"
|
||||
autocxx = "0.16"
|
||||
|
||||
[build-dependencies]
|
||||
cxx-build = "1.0.55"
|
||||
autocxx-build = "0.16"
|
||||
#cxx-build = "1.0.55"
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
fn main() {
|
||||
println!("cargo:rustc-link-lib=dylib=imhex");
|
||||
println!("cargo:rustc-link-search=all={}", env!("LIBIMHEX_OUTPUT_DIRECTORY"));
|
||||
println!(
|
||||
"cargo:rustc-link-search=all={}",
|
||||
env!("LIBIMHEX_OUTPUT_DIRECTORY")
|
||||
);
|
||||
|
||||
println!("cargo:rerun-if-changed=src/lib.rs");
|
||||
println!("cargo:rerun-if-changed=src/imhex_api.rs");
|
||||
|
||||
cxx_build::bridge("src/imhex_api.rs")
|
||||
let include = format!("-I{}/include", env!("LIBIMHEX_SOURCE_DIRECTORY"));
|
||||
|
||||
let path = std::path::PathBuf::from("src");
|
||||
let mut build = autocxx_build::Builder::new("src/lib.rs", &[&path])
|
||||
.extra_clang_args(&[&include, "-x", "c++", "-std=gnu++20"])
|
||||
.auto_allowlist(true)
|
||||
.expect_build();
|
||||
|
||||
build
|
||||
.include(format!("{}/include", env!("LIBIMHEX_SOURCE_DIRECTORY")))
|
||||
.flag_if_supported("-std=gnu++20")
|
||||
.flag_if_supported("-std=gnu++2a")
|
||||
.flag_if_supported("-fconcepts")
|
||||
.compiler(env!("CXX_COMPILER"))
|
||||
.compile("libimhex-bridge");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,17 +13,6 @@ impl Parse for AttrList {
|
||||
}
|
||||
}
|
||||
|
||||
fn symbol(name: &str) -> String {
|
||||
let pkg_name = std::env::var("CARGO_PKG_NAME").unwrap();
|
||||
format!(
|
||||
"_ZN3hex6plugin{}{}8internal{}{}Ev",
|
||||
pkg_name.len(),
|
||||
pkg_name,
|
||||
name.len(),
|
||||
name,
|
||||
)
|
||||
}
|
||||
|
||||
#[proc_macro_attribute]
|
||||
pub fn plugin_setup(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
let args = syn::parse_macro_input!(attr as AttrList)
|
||||
@@ -36,11 +25,14 @@ pub fn plugin_setup(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
|
||||
let function = syn::parse_macro_input!(item as syn::ItemFn);
|
||||
|
||||
let plugin_name_export = symbol("getPluginName");
|
||||
let plugin_author_export = symbol("getPluginAuthor");
|
||||
let plugin_desc_export = symbol("getPluginDescription");
|
||||
let plugin_init_export = symbol("initializePlugin");
|
||||
let plugin_set_imgui_ctxt_export = symbol("setImGuiContext");
|
||||
let plugin_name_export = "getPluginName";
|
||||
let plugin_author_export = "getPluginAuthor";
|
||||
let plugin_desc_export = "getPluginDescription";
|
||||
let plugin_version_export = "getCompatibleVersion";
|
||||
let plugin_init_export = "initializePlugin";
|
||||
let plugin_set_imgui_ctx_export = "setImGuiContext";
|
||||
|
||||
let imhex_version = std::env::var("IMHEX_VERSION").unwrap();
|
||||
|
||||
quote!(
|
||||
#[export_name = #plugin_name_export]
|
||||
@@ -58,11 +50,16 @@ pub fn plugin_setup(attr: TokenStream, item: TokenStream) -> TokenStream {
|
||||
concat!(#description, "\0").as_ptr()
|
||||
}
|
||||
|
||||
#[export_name = #plugin_set_imgui_ctxt_export]
|
||||
#[export_name = #plugin_set_imgui_ctx_export]
|
||||
pub unsafe extern "C" fn set_imgui_context(context: *mut ::hex::imgui::sys::ImGuiContext) {
|
||||
::hex::imgui::sys::igSetCurrentContext(context);
|
||||
}
|
||||
|
||||
#[export_name = #plugin_version_export]
|
||||
pub unsafe extern "C" fn plugin_version() -> *const u8 {
|
||||
concat!(#imhex_version, "\0").as_ptr()
|
||||
}
|
||||
|
||||
#[export_name = #plugin_init_export]
|
||||
pub extern "C" #function
|
||||
)
|
||||
|
||||
27
lib/libimhex-rs/src/bookmarks.rs
Normal file
27
lib/libimhex-rs/src/bookmarks.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
use autocxx::c_ulong;
|
||||
|
||||
use crate::Color;
|
||||
use std::ops::Range;
|
||||
|
||||
/// Add a bookmark to a region of the current imhex view with an optionally provided color
|
||||
///
|
||||
/// ```rust,ignore
|
||||
/// use hex::bookmarks;
|
||||
///
|
||||
/// bookmarks::add(0..0x10, "header", "this is the header of the file", None);
|
||||
///
|
||||
/// let red = Color::new(0xFF, 0, 0, 0xFF);
|
||||
/// bookmarks::add(0x10..0x30, "table", "this is the table of the file", red);
|
||||
/// ```
|
||||
pub fn add(region: Range<u64>, name: &str, comment: &str, color: impl Into<Option<Color>>) {
|
||||
cxx::let_cxx_string!(cpp_name = name);
|
||||
cxx::let_cxx_string!(cpp_comment = comment);
|
||||
|
||||
crate::ffi::hex::ImHexApi::Bookmarks::add(
|
||||
region.start,
|
||||
c_ulong::from(region.end.saturating_sub(region.start)),
|
||||
&cpp_name,
|
||||
&cpp_comment,
|
||||
color.into().unwrap_or(crate::Color::new(0, 0, 0, 0)).rgba(),
|
||||
);
|
||||
}
|
||||
11
lib/libimhex-rs/src/imhex.rs
Normal file
11
lib/libimhex-rs/src/imhex.rs
Normal file
@@ -0,0 +1,11 @@
|
||||
use crate::ffi::hex::ImHexApi::Common;
|
||||
|
||||
/// Close ImHex, optionally prompting the user if they'd like to quit
|
||||
pub fn close_imhex(without_question: bool) {
|
||||
Common::closeImHex(without_question)
|
||||
}
|
||||
|
||||
/// Close and reopen ImHex
|
||||
pub fn restart_imhex() {
|
||||
Common::restartImHex()
|
||||
}
|
||||
@@ -1,99 +1,17 @@
|
||||
pub mod ffi {
|
||||
|
||||
pub mod ImHexApi {
|
||||
|
||||
#[cxx::bridge]
|
||||
pub mod Common {
|
||||
|
||||
#[namespace = "hex::ImHexApi::Common"]
|
||||
extern "C++" {
|
||||
include!("hex/api/imhex_api.hpp");
|
||||
|
||||
pub unsafe fn closeImHex(no_questions: bool);
|
||||
pub unsafe fn restartImHex();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#[cxx::bridge]
|
||||
pub mod Bookmarks {
|
||||
|
||||
#[namespace = "hex::ImHexApi::Bookmarks"]
|
||||
extern "C++" {
|
||||
include!("hex/api/imhex_api.hpp");
|
||||
|
||||
pub unsafe fn add(addr : u64, size : usize, name : &CxxString, comment : &CxxString, color : u32);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Region {
|
||||
pub address : u64,
|
||||
pub size : usize
|
||||
}
|
||||
|
||||
/// A highlight color for use with the bookmarks API
|
||||
pub struct Color {
|
||||
pub a : u8,
|
||||
pub g : u8,
|
||||
pub b : u8,
|
||||
pub r : u8
|
||||
}
|
||||
|
||||
impl Region {
|
||||
|
||||
pub fn new(address : u64, size : usize) -> Self {
|
||||
Region { address, size }
|
||||
}
|
||||
|
||||
pub a: u8,
|
||||
pub g: u8,
|
||||
pub b: u8,
|
||||
pub r: u8,
|
||||
}
|
||||
|
||||
impl Color {
|
||||
|
||||
pub fn new(r : u8, g : u8, b : u8, a : u8) -> Self {
|
||||
pub const fn new(r: u8, g: u8, b: u8, a: u8) -> Self {
|
||||
Color { a, g, b, r }
|
||||
}
|
||||
|
||||
pub fn rgba(self) -> u32 {
|
||||
pub const fn rgba(self) -> u32 {
|
||||
(self.a as u32) << 24 | (self.b as u32) << 16 | (self.g as u32) << 8 | (self.r as u32) << 0
|
||||
}
|
||||
}
|
||||
|
||||
pub mod ImHexApi {
|
||||
|
||||
pub mod Common {
|
||||
|
||||
pub fn closeImHex() {
|
||||
|
||||
unsafe {
|
||||
crate::imhex_api::ffi::ImHexApi::Common::closeImHex(false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub fn restartImmHex() {
|
||||
|
||||
unsafe {
|
||||
crate::imhex_api::ffi::ImHexApi::Common::restartImHex();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
pub mod Bookmarks {
|
||||
|
||||
pub fn add(region : crate::Region, name : &str, comment : &str, color : Option<crate::Color>) {
|
||||
cxx::let_cxx_string!(cpp_name = name);
|
||||
cxx::let_cxx_string!(cpp_comment = comment);
|
||||
|
||||
unsafe {
|
||||
crate::imhex_api::ffi::ImHexApi::Bookmarks::add(region.address, region.size, &cpp_name, &cpp_comment, color.unwrap_or(crate::Color::new(0, 0, 0, 0)).rgba());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,9 +1,42 @@
|
||||
#![allow(non_snake_case)]
|
||||
use autocxx::prelude::*;
|
||||
|
||||
include_cpp! {
|
||||
#include "hex/api/imhex_api.hpp"
|
||||
|
||||
safety!(unsafe)
|
||||
|
||||
generate!("hex::ImHexApi::Common::closeImHex")
|
||||
generate!("hex::ImHexApi::Common::restartImHex")
|
||||
generate!("hex::ImHexApi::Bookmarks::add")
|
||||
}
|
||||
|
||||
//pub use crate::ffi::*;
|
||||
|
||||
/// API for working with imhex bookmarks/highlights
|
||||
pub mod bookmarks;
|
||||
|
||||
/// API for working with imhex itself
|
||||
pub mod imhex;
|
||||
|
||||
mod imhex_api;
|
||||
|
||||
pub use imhex_macros::plugin_setup;
|
||||
pub use imhex_api::ImHexApi;
|
||||
pub use imhex_api::Region;
|
||||
pub use imgui;
|
||||
|
||||
#[doc(inline)]
|
||||
pub use imhex_api::Color;
|
||||
pub use imgui;
|
||||
|
||||
/// A macro for declaring the init function for your plugin
|
||||
///
|
||||
/// ## Example
|
||||
///
|
||||
/// ```
|
||||
/// #[hex::plugin_setup(
|
||||
/// /* Display name*/ "Example Rust",
|
||||
/// /* Author */ "WerWolv",
|
||||
/// /* Description */ "Example Rust plugin used as template for plugin devs"
|
||||
/// )]
|
||||
/// fn init() {
|
||||
/// // plugin initialization logic here
|
||||
/// }
|
||||
/// ```
|
||||
pub use imhex_macros::plugin_setup;
|
||||
|
||||
@@ -10,6 +10,7 @@ set_target_properties(imgui PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/microtar ${CMAKE_CURRENT_BINARY_DIR}/external/microtar EXCLUDE_FROM_ALL)
|
||||
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(NFD_PORTAL ON CACHE BOOL "Use Portals for Linux file dialogs" FORCE)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/nativefiledialog ${CMAKE_CURRENT_BINARY_DIR}/external/nativefiledialog EXCLUDE_FROM_ALL)
|
||||
set_target_properties(nfd PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
@@ -71,15 +72,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 +115,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
|
||||
@@ -122,22 +124,14 @@ set(LIBIMHEX_SOURCES
|
||||
source/helpers/patches.cpp
|
||||
source/helpers/project_file_handler.cpp
|
||||
source/helpers/encoding_file.cpp
|
||||
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/helpers/tar.cpp
|
||||
|
||||
source/providers/provider.cpp
|
||||
|
||||
source/ui/imgui_imhex_extensions.cpp
|
||||
source/ui/view.cpp
|
||||
)
|
||||
)
|
||||
|
||||
if (APPLE)
|
||||
set(OSX_11_0_SDK_PATH /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk)
|
||||
@@ -149,13 +143,16 @@ if (APPLE)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/paths_mac.mm)
|
||||
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES}
|
||||
source/helpers/fs_macos.m
|
||||
source/helpers/utils_macos.m)
|
||||
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 +162,4 @@ if (APPLE)
|
||||
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
|
||||
endif ()
|
||||
|
||||
target_link_libraries(libimhex PUBLIC dl imgui nfd magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs)
|
||||
target_link_libraries(libimhex PUBLIC dl imgui nfd magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs libpl)
|
||||
|
||||
@@ -3,28 +3,8 @@
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
#include <hex/helpers/types.hpp>
|
||||
#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";
|
||||
|
||||
using u8 = std::uint8_t;
|
||||
using u16 = std::uint16_t;
|
||||
using u32 = std::uint32_t;
|
||||
using u64 = std::uint64_t;
|
||||
using u128 = __uint128_t;
|
||||
|
||||
using i8 = std::int8_t;
|
||||
using i16 = std::int16_t;
|
||||
using i32 = std::int32_t;
|
||||
using i64 = std::int64_t;
|
||||
using i128 = __int128_t;
|
||||
|
||||
using color_t = u32;
|
||||
|
||||
namespace hex {
|
||||
|
||||
struct Region {
|
||||
u64 address;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -2,27 +2,33 @@
|
||||
|
||||
#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>
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
|
||||
using ImGuiDataType = int;
|
||||
using ImGuiInputTextFlags = int;
|
||||
|
||||
namespace pl {
|
||||
class Evaluator;
|
||||
}
|
||||
|
||||
namespace hex {
|
||||
|
||||
class View;
|
||||
class LanguageDefinition;
|
||||
namespace pl {
|
||||
class Evaluator;
|
||||
}
|
||||
|
||||
namespace dp {
|
||||
class Node;
|
||||
}
|
||||
@@ -43,14 +49,31 @@ namespace hex {
|
||||
|
||||
struct Entry {
|
||||
std::string name;
|
||||
bool requiresRestart;
|
||||
Callback callback;
|
||||
};
|
||||
|
||||
struct Category {
|
||||
std::string name;
|
||||
size_t slot = 0;
|
||||
|
||||
bool operator<(const Category &other) const {
|
||||
return name < other.name;
|
||||
}
|
||||
|
||||
operator const std::string &() const {
|
||||
return name;
|
||||
}
|
||||
};
|
||||
|
||||
void load();
|
||||
void store();
|
||||
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback);
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback);
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback, bool requiresRestart = false);
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback, bool requiresRestart = false);
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const Callback &callback, bool requiresRestart = false);
|
||||
|
||||
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription);
|
||||
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value);
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &value);
|
||||
@@ -60,7 +83,8 @@ namespace hex {
|
||||
std::string read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue);
|
||||
std::vector<std::string> read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue = {});
|
||||
|
||||
std::map<std::string, std::vector<Entry>> &getEntries();
|
||||
std::map<Category, std::vector<Entry>> &getEntries();
|
||||
std::map<std::string, std::string> &getCategoryDescriptions();
|
||||
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName);
|
||||
nlohmann::json &getSettingsData();
|
||||
}
|
||||
@@ -68,7 +92,8 @@ namespace hex {
|
||||
/* Command Palette Command Registry. Allows adding of new commands to the command palette */
|
||||
namespace CommandPaletteCommands {
|
||||
|
||||
enum class Type : u32 {
|
||||
enum class Type : u32
|
||||
{
|
||||
SymbolCommand,
|
||||
KeywordCommand
|
||||
};
|
||||
@@ -98,37 +123,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 */
|
||||
@@ -140,7 +156,7 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
template<hex::derived_from<View> T, typename... Args>
|
||||
template<std::derived_from<View> T, typename... Args>
|
||||
void add(Args &&...args) {
|
||||
return impl::add(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
@@ -173,7 +189,8 @@ namespace hex {
|
||||
/* Data Inspector Registry. Allows adding of new types to the data inspector */
|
||||
namespace DataInspector {
|
||||
|
||||
enum class NumberDisplayStyle {
|
||||
enum class NumberDisplayStyle
|
||||
{
|
||||
Decimal,
|
||||
Hexadecimal,
|
||||
Octal
|
||||
@@ -182,17 +199,19 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
using DisplayFunction = std::function<std::string()>;
|
||||
using EditingFunction = std::function<std::vector<u8>(std::string, std::endian)>;
|
||||
using GeneratorFunction = std::function<DisplayFunction(const std::vector<u8> &, std::endian, NumberDisplayStyle)>;
|
||||
|
||||
struct Entry {
|
||||
std::string unlocalizedName;
|
||||
size_t requiredSize;
|
||||
impl::GeneratorFunction generatorFunction;
|
||||
std::optional<impl::EditingFunction> editingFunction;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction function);
|
||||
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
|
||||
|
||||
std::vector<impl::Entry> &getEntries();
|
||||
}
|
||||
@@ -215,7 +234,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
|
||||
template<hex::derived_from<dp::Node> T, typename... Args>
|
||||
template<std::derived_from<dp::Node> T, typename... Args>
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, Args &&...args) {
|
||||
add(impl::Entry { unlocalizedCategory.c_str(), unlocalizedName.c_str(), [=] {
|
||||
auto node = new T(std::forward<Args>(args)...);
|
||||
@@ -307,7 +326,7 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
template<hex::derived_from<hex::prv::Provider> T>
|
||||
template<std::derived_from<hex::prv::Provider> T>
|
||||
void add(const std::string &unlocalizedName, bool addToList = true) {
|
||||
(void)EventManager::subscribe<RequestCreateProvider>([expectedName = unlocalizedName](const std::string &name, hex::prv::Provider **provider) {
|
||||
if (name != expectedName) return;
|
||||
@@ -350,7 +369,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;
|
||||
@@ -363,6 +382,113 @@ namespace hex {
|
||||
std::vector<impl::Entry> &getEntries();
|
||||
|
||||
}
|
||||
|
||||
namespace HexEditor {
|
||||
|
||||
class DataVisualizer {
|
||||
public:
|
||||
DataVisualizer(u16 bytesPerCell, u16 maxCharsPerCell)
|
||||
: m_bytesPerCell(bytesPerCell), m_maxCharsPerCell(maxCharsPerCell) {}
|
||||
|
||||
virtual ~DataVisualizer() = default;
|
||||
|
||||
virtual void draw(u64 address, const u8 *data, size_t size, bool upperCase) = 0;
|
||||
virtual bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) = 0;
|
||||
|
||||
[[nodiscard]] u16 getBytesPerCell() const { return this->m_bytesPerCell; }
|
||||
[[nodiscard]] u16 getMaxCharsPerCell() const { return this->m_maxCharsPerCell; }
|
||||
|
||||
protected:
|
||||
const static int TextInputFlags;
|
||||
|
||||
bool drawDefaultEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const;
|
||||
private:
|
||||
u16 m_bytesPerCell;
|
||||
u16 m_maxCharsPerCell;
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
|
||||
void addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer);
|
||||
|
||||
std::map<std::string, DataVisualizer*> &getVisualizers();
|
||||
|
||||
}
|
||||
|
||||
template<std::derived_from<DataVisualizer> T, typename... Args>
|
||||
void addDataVisualizer(const std::string &unlocalizedName, Args &&...args) {
|
||||
return impl::addDataVisualizer(unlocalizedName, new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace Hashes {
|
||||
|
||||
class Hash {
|
||||
public:
|
||||
Hash(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
|
||||
|
||||
class Function {
|
||||
public:
|
||||
using Callback = std::function<std::vector<u8>(const Region&, prv::Provider *)>;
|
||||
|
||||
Function(const Hash *type, std::string name, Callback callback)
|
||||
: m_type(type), m_name(std::move(name)), m_callback(std::move(callback)) {
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] const Hash *getType() const { return this->m_type; }
|
||||
[[nodiscard]] const std::string &getName() const { return this->m_name; }
|
||||
|
||||
const std::vector<u8>& get(const Region& region, prv::Provider *provider) {
|
||||
if (this->m_cache.empty()) {
|
||||
this->m_cache = this->m_callback(region, provider);
|
||||
}
|
||||
|
||||
return this->m_cache;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
this->m_cache.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
const Hash *m_type;
|
||||
std::string m_name;
|
||||
Callback m_callback;
|
||||
|
||||
std::vector<u8> m_cache;
|
||||
};
|
||||
|
||||
virtual void draw() { }
|
||||
[[nodiscard]] virtual Function create(std::string name) = 0;
|
||||
|
||||
[[nodiscard]] const std::string &getUnlocalizedName() const {
|
||||
return this->m_unlocalizedName;
|
||||
}
|
||||
|
||||
protected:
|
||||
[[nodiscard]] Function create(const std::string &name, const Function::Callback &callback) const {
|
||||
return { this, name, callback };
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_unlocalizedName;
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
|
||||
std::vector<Hash*> &getHashes();
|
||||
|
||||
void add(Hash* hash);
|
||||
}
|
||||
|
||||
template<typename T, typename ... Args>
|
||||
void add(Args && ... args) {
|
||||
impl::add(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 PatternData;
|
||||
}
|
||||
|
||||
/* Default Events */
|
||||
EVENT_DEF(EventFileLoaded, fs::path);
|
||||
EVENT_DEF(EventFileLoaded, std::fs::path);
|
||||
EVENT_DEF(EventFileUnloaded);
|
||||
EVENT_DEF(EventDataChanged);
|
||||
EVENT_DEF(EventHighlightingChanged);
|
||||
@@ -116,6 +116,7 @@ namespace hex {
|
||||
EVENT_DEF(EventProviderChanged, prv::Provider *, prv::Provider *);
|
||||
EVENT_DEF(EventFrameBegin);
|
||||
EVENT_DEF(EventFrameEnd);
|
||||
EVENT_DEF(EventWindowInitialized);
|
||||
|
||||
EVENT_DEF(RequestOpenWindow, std::string);
|
||||
EVENT_DEF(RequestSelectionChange, Region);
|
||||
@@ -123,11 +124,17 @@ 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 **);
|
||||
|
||||
EVENT_DEF(QuerySelection, Region &);
|
||||
EVENT_DEF(RequestShowInfoPopup, std::string);
|
||||
EVENT_DEF(RequestShowErrorPopup, std::string);
|
||||
EVENT_DEF(RequestShowFatalErrorPopup, std::string);
|
||||
EVENT_DEF(RequestShowYesNoQuestionPopup, std::string, std::function<void()>, std::function<void()>);
|
||||
EVENT_DEF(RequestShowFileChooserPopup, std::vector<std::fs::path>, std::vector<nfdfilteritem_t>, std::function<void(std::fs::path)>);
|
||||
|
||||
EVENT_DEF(QuerySelection, std::optional<Region> &);
|
||||
|
||||
}
|
||||
@@ -3,14 +3,19 @@
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <variant>
|
||||
#include <map>
|
||||
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/api/task.hpp>
|
||||
#include <hex/api/keybinding.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
using ImGuiID = unsigned int;
|
||||
struct ImVec2;
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -29,26 +34,69 @@ namespace hex {
|
||||
|
||||
namespace HexEditor {
|
||||
|
||||
using TooltipFunction = std::function<void(u64, const u8*, size_t)>;
|
||||
|
||||
class Highlighting {
|
||||
public:
|
||||
Highlighting() = default;
|
||||
Highlighting(Region region, color_t color, const std::string &tooltip = "");
|
||||
Highlighting(Region region, color_t color);
|
||||
|
||||
[[nodiscard]] const Region &getRegion() const { return this->m_region; }
|
||||
[[nodiscard]] const color_t &getColor() const { return this->m_color; }
|
||||
[[nodiscard]] const std::string &getTooltip() const { return this->m_tooltip; }
|
||||
|
||||
private:
|
||||
Region m_region;
|
||||
color_t m_color;
|
||||
std::string m_tooltip;
|
||||
Region m_region = {};
|
||||
color_t m_color = 0x00;
|
||||
};
|
||||
|
||||
u32 addHighlight(const Region ®ion, color_t color, std::string tooltip = "");
|
||||
void removeHighlight(u32 id);
|
||||
std::map<u32, Highlighting> &getHighlights();
|
||||
class Tooltip {
|
||||
public:
|
||||
Tooltip() = default;
|
||||
Tooltip(Region region, std::string value, color_t color);
|
||||
|
||||
Region getSelection();
|
||||
[[nodiscard]] const Region &getRegion() const { return this->m_region; }
|
||||
[[nodiscard]] const color_t &getColor() const { return this->m_color; }
|
||||
[[nodiscard]] const std::string &getValue() const { return this->m_value; }
|
||||
|
||||
private:
|
||||
Region m_region = {};
|
||||
std::string m_value;
|
||||
color_t m_color = 0x00;
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
|
||||
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t)>;
|
||||
|
||||
std::map<u32, Highlighting> &getBackgroundHighlights();
|
||||
std::map<u32, HighlightingFunction> &getBackgroundHighlightingFunctions();
|
||||
std::map<u32, Highlighting> &getForegroundHighlights();
|
||||
std::map<u32, HighlightingFunction> &getForegroundHighlightingFunctions();
|
||||
std::map<u32, Tooltip> &getTooltips();
|
||||
std::map<u32, TooltipFunction> &getTooltipFunctions();
|
||||
|
||||
}
|
||||
|
||||
u32 addBackgroundHighlight(const Region ®ion, color_t color);
|
||||
void removeBackgroundHighlight(u32 id);
|
||||
|
||||
u32 addForegroundHighlight(const Region ®ion, color_t color);
|
||||
void removeForegroundHighlight(u32 id);
|
||||
|
||||
u32 addTooltip(Region region, std::string value, color_t color);
|
||||
void removeTooltip(u32 id);
|
||||
|
||||
u32 addTooltipProvider(TooltipFunction function);
|
||||
void removeTooltipProvider(u32 id);
|
||||
|
||||
u32 addBackgroundHighlightingProvider(const impl::HighlightingFunction &function);
|
||||
void removeBackgroundHighlightingProvider(u32 id);
|
||||
|
||||
u32 addForegroundHighlightingProvider(const impl::HighlightingFunction &function);
|
||||
void removeForegroundHighlightingProvider(u32 id);
|
||||
|
||||
bool isSelectionValid();
|
||||
std::optional<Region> getSelection();
|
||||
void setSelection(const Region ®ion);
|
||||
void setSelection(u64 address, size_t size);
|
||||
|
||||
@@ -63,11 +111,8 @@ namespace hex {
|
||||
std::string comment;
|
||||
u32 color;
|
||||
bool locked;
|
||||
|
||||
u32 highlightId;
|
||||
};
|
||||
|
||||
void add(Region region, const std::string &name, const std::string &comment, color_t color = 0x00000000);
|
||||
void add(u64 address, size_t size, const std::string &name, const std::string &comment, color_t color = 0x00000000);
|
||||
|
||||
}
|
||||
@@ -83,7 +128,7 @@ namespace hex {
|
||||
|
||||
void add(prv::Provider *provider);
|
||||
|
||||
template<hex::derived_from<prv::Provider> T>
|
||||
template<std::derived_from<prv::Provider> T>
|
||||
void add(auto &&...args) {
|
||||
add(new T(std::forward<decltype(args)>(args)...));
|
||||
}
|
||||
@@ -112,6 +157,13 @@ namespace hex {
|
||||
void setGlobalScale(float scale);
|
||||
|
||||
void setProgramArguments(int argc, char **argv, char **envp);
|
||||
|
||||
void setBorderlessWindowMode(bool enabled);
|
||||
|
||||
void setCustomFontPath(const std::fs::path &path);
|
||||
void setFontSize(float size);
|
||||
|
||||
void setGPUVendor(const std::string &vendor);
|
||||
}
|
||||
|
||||
struct ProgramArguments {
|
||||
@@ -120,6 +172,12 @@ namespace hex {
|
||||
char **envp;
|
||||
};
|
||||
|
||||
enum class Theme {
|
||||
Dark = 1,
|
||||
Light = 2,
|
||||
Classic = 3
|
||||
};
|
||||
|
||||
const ProgramArguments &getProgramArguments();
|
||||
|
||||
float getTargetFPS();
|
||||
@@ -131,8 +189,23 @@ namespace hex {
|
||||
ImVec2 getMainWindowSize();
|
||||
ImGuiID getMainDockSpaceId();
|
||||
|
||||
bool isBorderlessWindowModeEnabled();
|
||||
|
||||
std::map<std::string, std::string> &getInitArguments();
|
||||
|
||||
const std::fs::path &getCustomFontPath();
|
||||
float getFontSize();
|
||||
|
||||
void setTheme(Theme theme);
|
||||
Theme getTheme();
|
||||
|
||||
void enableSystemThemeDetection(bool enabled);
|
||||
bool usesSystemThemeDetection();
|
||||
|
||||
const std::vector<std::fs::path> &getAdditionalFolderPaths();
|
||||
void setAdditionalFolderPaths(const std::vector<std::fs::path> &paths);
|
||||
|
||||
const std::string &getGPUVendor();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,9 +11,10 @@ struct ImGuiWindow;
|
||||
|
||||
namespace hex {
|
||||
|
||||
struct View;
|
||||
class View;
|
||||
|
||||
enum class Keys {
|
||||
enum class Keys
|
||||
{
|
||||
Space = GLFW_KEY_SPACE,
|
||||
Apostrophe = GLFW_KEY_APOSTROPHE,
|
||||
Comma = GLFW_KEY_COMMA,
|
||||
@@ -141,6 +142,9 @@ namespace hex {
|
||||
|
||||
class Shortcut {
|
||||
public:
|
||||
Shortcut() = default;
|
||||
Shortcut(Keys key) : m_keys({ key }) { }
|
||||
|
||||
Shortcut operator+(const Key &other) const {
|
||||
Shortcut result = *this;
|
||||
result.m_keys.insert(other);
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace hex {
|
||||
public:
|
||||
LanguageDefinition(std::initializer_list<std::pair<std::string, std::string>> entries);
|
||||
|
||||
const std::map<std::string, std::string> &getEntries() const;
|
||||
[[nodiscard]] const std::map<std::string, std::string> &getEntries() const;
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> m_entries;
|
||||
@@ -20,7 +20,7 @@ namespace hex {
|
||||
class LangEntry {
|
||||
public:
|
||||
explicit LangEntry(const char *unlocalizedString);
|
||||
explicit LangEntry(const std::string &unlocalizedString);
|
||||
explicit LangEntry(std::string unlocalizedString);
|
||||
explicit LangEntry(std::string_view unlocalizedString);
|
||||
|
||||
operator std::string() const;
|
||||
|
||||
@@ -3,17 +3,23 @@
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
struct ImGuiContext;
|
||||
|
||||
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 +32,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;
|
||||
|
||||
@@ -39,8 +45,12 @@ namespace hex {
|
||||
using SetImGuiContextFunc = void (*)(ImGuiContext *);
|
||||
using IsBuiltinPluginFunc = bool (*)();
|
||||
|
||||
void *m_handle = nullptr;
|
||||
fs::path m_path;
|
||||
#if defined(OS_WINDOWS)
|
||||
HMODULE m_handle = nullptr;
|
||||
#else
|
||||
void *m_handle = nullptr;
|
||||
#endif
|
||||
std::fs::path m_path;
|
||||
|
||||
mutable bool m_initialized = false;
|
||||
|
||||
@@ -65,7 +75,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 +84,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
private:
|
||||
static fs::path s_pluginFolder;
|
||||
static std::fs::path s_pluginFolder;
|
||||
static std::vector<Plugin> s_plugins;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <hex/helpers/intrinsics.hpp>
|
||||
#include <hex/data_processor/attribute.hpp>
|
||||
|
||||
#include <set>
|
||||
@@ -38,8 +39,8 @@ namespace hex::dp {
|
||||
virtual void drawNode() { }
|
||||
virtual void process() = 0;
|
||||
|
||||
virtual void store(nlohmann::json &j) { }
|
||||
virtual void load(nlohmann::json &j) { }
|
||||
virtual void store(nlohmann::json &j) { hex::unused(j); }
|
||||
virtual void load(nlohmann::json &j) { hex::unused(j); }
|
||||
|
||||
using NodeError = std::pair<Node *, std::string>;
|
||||
|
||||
@@ -90,11 +91,11 @@ namespace hex::dp {
|
||||
}
|
||||
|
||||
std::vector<u8> getBufferOnInput(u32 index);
|
||||
u64 getIntegerOnInput(u32 index);
|
||||
i64 getIntegerOnInput(u32 index);
|
||||
float getFloatOnInput(u32 index);
|
||||
|
||||
void setBufferOnOutput(u32 index, std::vector<u8> data);
|
||||
void setIntegerOnOutput(u32 index, u64 integer);
|
||||
void setBufferOnOutput(u32 index, const std::vector<u8> &data);
|
||||
void setIntegerOnOutput(u32 index, i64 integer);
|
||||
void setFloatOnOutput(u32 index, float floatingPoint);
|
||||
|
||||
void setOverlayData(u64 address, const std::vector<u8> &data);
|
||||
|
||||
@@ -3,152 +3,9 @@
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <type_traits>
|
||||
#include <memory>
|
||||
|
||||
namespace hex {
|
||||
|
||||
template<typename>
|
||||
struct is_integral_helper : public std::false_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<u8> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<i8> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<u16> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<i16> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<u32> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<i32> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<u64> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<i64> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<u128> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<i128> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<bool> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<char> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<char8_t> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<char16_t> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<char32_t> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_integral_helper<wchar_t> : public std::true_type { };
|
||||
|
||||
template<typename T>
|
||||
struct is_integral : public is_integral_helper<std::remove_cvref_t<T>>::type { };
|
||||
|
||||
|
||||
template<typename>
|
||||
struct is_signed_helper : public std::false_type { };
|
||||
|
||||
template<>
|
||||
struct is_signed_helper<i8> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_signed_helper<i16> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_signed_helper<i32> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_signed_helper<i64> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_signed_helper<i128> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_signed_helper<char> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_signed_helper<float> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_signed_helper<double> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_signed_helper<long double> : public std::true_type { };
|
||||
|
||||
template<typename T>
|
||||
struct is_signed : public is_signed_helper<std::remove_cvref_t<T>>::type { };
|
||||
|
||||
|
||||
template<typename>
|
||||
struct is_floating_point_helper : public std::false_type { };
|
||||
|
||||
template<>
|
||||
struct is_floating_point_helper<float> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_floating_point_helper<double> : public std::true_type { };
|
||||
|
||||
template<>
|
||||
struct is_floating_point_helper<long double> : public std::true_type { };
|
||||
|
||||
template<typename T>
|
||||
struct is_floating_point : public is_floating_point_helper<std::remove_cvref_t<T>>::type { };
|
||||
|
||||
}
|
||||
|
||||
#if defined(_LIBCPP_VERSION) && _LIBCPP_VERSION <= 12000
|
||||
#if __has_include(<concepts>)
|
||||
// Make sure we break when derived_from is implemented in libc++. Then we can fix a compatibility version above
|
||||
#include <concepts>
|
||||
#endif
|
||||
// libcxx 12 still doesn't have many default concepts implemented, as a result we need to define it ourself using clang built-ins.
|
||||
// [concept.derived] (patch from https://reviews.llvm.org/D74292)
|
||||
namespace hex {
|
||||
template<class _Dp, class _Bp>
|
||||
concept derived_from =
|
||||
__is_base_of(_Bp, _Dp) && __is_convertible_to(const volatile _Dp *, const volatile _Bp *);
|
||||
}
|
||||
|
||||
#else
|
||||
// Assume supported
|
||||
#include <concepts>
|
||||
namespace hex {
|
||||
using std::derived_from;
|
||||
}
|
||||
#endif
|
||||
|
||||
// [concepts.arithmetic]
|
||||
namespace hex {
|
||||
|
||||
template<class T>
|
||||
concept integral = hex::is_integral<T>::value;
|
||||
|
||||
template<class T>
|
||||
concept signed_integral = integral<T> && hex::is_signed<T>::value;
|
||||
|
||||
template<class T>
|
||||
concept unsigned_integral = integral<T> && !signed_integral<T>;
|
||||
|
||||
template<class T>
|
||||
concept floating_point = std::is_floating_point<T>::value;
|
||||
|
||||
}
|
||||
#include <concepts>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -158,15 +15,10 @@ namespace hex {
|
||||
template<typename T, size_t Size>
|
||||
concept has_size = sizeof(T) == Size;
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace hex {
|
||||
|
||||
template<typename T>
|
||||
class Cloneable {
|
||||
public:
|
||||
[[nodiscard]] virtual T *clone() const = 0;
|
||||
[[nodiscard]] virtual std::unique_ptr<T> clone() const = 0;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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" };
|
||||
|
||||
@@ -2,22 +2,34 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
// TODO: Workaround for weird issue picked up by GCC 12.1.0 and later. This seems like a compiler bug mentioned in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=98465
|
||||
#pragma GCC diagnostic push
|
||||
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#if (__GNUC__ >= 12)
|
||||
#pragma GCC diagnostic ignored "-Wrestrict"
|
||||
#pragma GCC diagnostic ignored "-Wstringop-overread"
|
||||
#endif
|
||||
|
||||
#include <map>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/file.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; }
|
||||
@@ -25,12 +37,12 @@ namespace hex {
|
||||
[[nodiscard]] bool valid() const { return this->m_valid; }
|
||||
|
||||
private:
|
||||
void parseThingyFile(std::ifstream &content);
|
||||
void parseThingyFile(fs::File &file);
|
||||
|
||||
bool m_valid = false;
|
||||
|
||||
std::map<u32, std::map<std::vector<u8>, std::string>> m_mapping;
|
||||
std::map<size_t, std::map<std::vector<u8>, std::string>> m_mapping;
|
||||
size_t m_longestSequence = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,17 +16,18 @@
|
||||
#define ftruncate64 ftruncate
|
||||
#endif
|
||||
|
||||
namespace hex {
|
||||
namespace hex::fs {
|
||||
|
||||
class File {
|
||||
public:
|
||||
enum class Mode {
|
||||
enum class Mode
|
||||
{
|
||||
Read,
|
||||
Write,
|
||||
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;
|
||||
@@ -36,7 +37,9 @@ namespace hex {
|
||||
File &operator=(File &&other) noexcept;
|
||||
|
||||
|
||||
[[nodiscard]] bool isValid() const { return this->m_file != nullptr; }
|
||||
[[nodiscard]] bool isValid() const {
|
||||
return this->m_file != nullptr && fs::exists(this->m_path) && !fs::isDirectory(this->m_path);
|
||||
}
|
||||
|
||||
void seek(u64 offset);
|
||||
void close();
|
||||
@@ -44,23 +47,27 @@ namespace hex {
|
||||
size_t readBuffer(u8 *buffer, size_t size);
|
||||
std::vector<u8> readBytes(size_t numBytes = 0);
|
||||
std::string readString(size_t numBytes = 0);
|
||||
std::u8string readU8String(size_t numBytes = 0);
|
||||
|
||||
void write(const u8 *buffer, size_t size);
|
||||
void write(const std::vector<u8> &bytes);
|
||||
void write(const std::string &string);
|
||||
void write(const std::u8string &string);
|
||||
|
||||
[[nodiscard]] size_t getSize() const;
|
||||
void setSize(u64 size);
|
||||
|
||||
void flush();
|
||||
void remove();
|
||||
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;
|
||||
};
|
||||
|
||||
}
|
||||
100
lib/libimhex/include/hex/helpers/fs.hpp
Normal file
100
lib/libimhex/include/hex/helpers/fs.hpp
Normal file
@@ -0,0 +1,100 @@
|
||||
#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 bool removeAll(const std::fs::path &path) {
|
||||
std::error_code error;
|
||||
return std::filesystem::remove_all(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);
|
||||
|
||||
std::fs::path toShortPath(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);
|
||||
|
||||
}
|
||||
12
lib/libimhex/include/hex/helpers/fs_macos.hpp
Normal file
12
lib/libimhex/include/hex/helpers/fs_macos.hpp
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(OS_MACOS)
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
extern "C" char * getMacExecutableDirectoryPath();
|
||||
extern "C" char * getMacApplicationSupportDirectoryPath();
|
||||
|
||||
extern "C" void macFree(void *ptr);
|
||||
|
||||
#endif
|
||||
13
lib/libimhex/include/hex/helpers/intrinsics.hpp
Normal file
13
lib/libimhex/include/hex/helpers/intrinsics.hpp
Normal file
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace hex {
|
||||
|
||||
[[noreturn]] inline void unreachable() {
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
inline void unused(auto && ... x) {
|
||||
((void)x, ...);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <hex/helpers/paths.hpp>
|
||||
|
||||
struct _object;
|
||||
typedef struct _object PyObject;
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace prv {
|
||||
class Provider;
|
||||
}
|
||||
|
||||
class LoaderScript {
|
||||
public:
|
||||
LoaderScript() = delete;
|
||||
|
||||
static bool processFile(const fs::path &scriptPath);
|
||||
|
||||
static void setFilePath(const 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 prv::Provider *s_dataProvider;
|
||||
|
||||
static PyObject *Py_getFilePath(PyObject *self, PyObject *args);
|
||||
static PyObject *Py_addPatch(PyObject *self, PyObject *args);
|
||||
static PyObject *Py_addBookmark(PyObject *self, PyObject *args);
|
||||
|
||||
static PyObject *Py_addStruct(PyObject *self, PyObject *args);
|
||||
static PyObject *Py_addUnion(PyObject *self, PyObject *args);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
#include <fmt/core.h>
|
||||
@@ -13,44 +15,54 @@ namespace hex::log {
|
||||
|
||||
namespace {
|
||||
|
||||
void printPrefix(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("[{0:%H:%M:%S}] ", now);
|
||||
fmt::print(ts, "{0} ", level);
|
||||
fmt::print("[{0}] ", IMHEX_PROJECT_NAME);
|
||||
|
||||
fmt::print(dest, "[{0:%H:%M:%S}] ", now);
|
||||
|
||||
if (isRedirected())
|
||||
fmt::print(dest, "{0} ", level);
|
||||
else
|
||||
fmt::print(dest, ts, "{0} ", level);
|
||||
|
||||
fmt::print(dest, "[{0}] ", IMHEX_PROJECT_NAME);
|
||||
}
|
||||
|
||||
template<typename... T>
|
||||
void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) {
|
||||
printPrefix(ts, level);
|
||||
fmt::print(getDestination(), fmt::runtime(fmt), args...);
|
||||
fmt::print("\n");
|
||||
[[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);
|
||||
fmt::print(dest, fmt::runtime(fmt), args...);
|
||||
fmt::print(dest, "\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void debug(const std::string &fmt, auto &&...args) {
|
||||
[[maybe_unused]] void debug(const std::string &fmt, auto &&...args) {
|
||||
#if defined(DEBUG)
|
||||
log::print(fg(fmt::color::green_yellow) | fmt::emphasis::bold, "[DEBUG]", fmt, args...);
|
||||
hex::log::print(fg(fmt::color::green_yellow) | fmt::emphasis::bold, "[DEBUG]", fmt, args...);
|
||||
#else
|
||||
hex::unused(fmt, args...);
|
||||
#endif
|
||||
}
|
||||
|
||||
void info(const std::string &fmt, auto &&...args) {
|
||||
log::print(fg(fmt::color::cadet_blue) | fmt::emphasis::bold, "[INFO] ", fmt, args...);
|
||||
[[maybe_unused]] void info(const std::string &fmt, auto &&...args) {
|
||||
hex::log::print(fg(fmt::color::cadet_blue) | fmt::emphasis::bold, "[INFO] ", fmt, args...);
|
||||
}
|
||||
|
||||
void warn(const std::string &fmt, auto &&...args) {
|
||||
log::print(fg(fmt::color::orange) | fmt::emphasis::bold, "[WARN] ", fmt, args...);
|
||||
[[maybe_unused]] void warn(const std::string &fmt, auto &&...args) {
|
||||
hex::log::print(fg(fmt::color::orange) | fmt::emphasis::bold, "[WARN] ", fmt, args...);
|
||||
}
|
||||
|
||||
void error(const std::string &fmt, auto &&...args) {
|
||||
log::print(fg(fmt::color::red) | fmt::emphasis::bold, "[ERROR]", fmt, args...);
|
||||
[[maybe_unused]] void error(const std::string &fmt, auto &&...args) {
|
||||
hex::log::print(fg(fmt::color::red) | fmt::emphasis::bold, "[ERROR]", fmt, args...);
|
||||
}
|
||||
|
||||
void fatal(const std::string &fmt, auto &&...args) {
|
||||
log::print(fg(fmt::color::purple) | fmt::emphasis::bold, "[FATAL]", fmt, args...);
|
||||
[[maybe_unused]] void fatal(const std::string &fmt, auto &&...args) {
|
||||
hex::log::print(fg(fmt::color::purple) | fmt::emphasis::bold, "[FATAL]", fmt, args...);
|
||||
}
|
||||
|
||||
void redirectToFile();
|
||||
[[maybe_unused]] void redirectToFile();
|
||||
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <curl/system.h>
|
||||
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
using CURL = void;
|
||||
struct curl_slist;
|
||||
@@ -35,11 +35,13 @@ namespace hex {
|
||||
Net();
|
||||
~Net();
|
||||
|
||||
std::future<Response<std::string>> getString(const std::string &url, u32 timeout = 2000);
|
||||
std::future<Response<nlohmann::json>> getJson(const std::string &url, u32 timeout = 2000);
|
||||
static constexpr u32 DefaultTimeout = 2'000;
|
||||
|
||||
std::future<Response<std::string>> uploadFile(const std::string &url, const fs::path &filePath, u32 timeout = 2000);
|
||||
std::future<Response<void>> downloadFile(const std::string &url, const fs::path &filePath, u32 timeout = 2000);
|
||||
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 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);
|
||||
|
||||
@@ -47,6 +49,8 @@ namespace hex {
|
||||
|
||||
void cancel() { this->m_shouldCancel = true; }
|
||||
|
||||
static void setProxy(const std::string &url);
|
||||
|
||||
private:
|
||||
void setCommonSettings(std::string &response, const std::string &url, u32 timeout = 2000, const std::map<std::string, std::string> &extraHeaders = {}, const std::string &body = {});
|
||||
std::optional<i32> execute();
|
||||
@@ -60,6 +64,8 @@ namespace hex {
|
||||
std::mutex m_transmissionActive;
|
||||
float m_progress = 0.0F;
|
||||
bool m_shouldCancel = false;
|
||||
|
||||
static std::string s_proxyUrl;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(OS_MACOS)
|
||||
#include <hex/helpers/paths.hpp>
|
||||
|
||||
namespace hex {
|
||||
std::string getMacExecutableDirectoryPath();
|
||||
std::string getMacApplicationSupportDirectoryPath();
|
||||
}
|
||||
#endif
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -16,8 +16,8 @@ namespace hex {
|
||||
public:
|
||||
ProjectFile() = delete;
|
||||
|
||||
static bool load(const fs::path &filePath);
|
||||
static bool store(fs::path filePath = {});
|
||||
static bool load(const std::fs::path &filePath);
|
||||
static bool store(std::fs::path filePath = {});
|
||||
|
||||
[[nodiscard]] static bool hasUnsavedChanges() {
|
||||
return ProjectFile::s_hasUnsavedChanged;
|
||||
@@ -29,10 +29,10 @@ namespace hex {
|
||||
ProjectFile::s_hasUnsavedChanged = true;
|
||||
|
||||
if (setWindowTitle)
|
||||
EventManager::post<RequestChangeWindowTitle>(fs::path(getFilePath()).filename().string());
|
||||
EventManager::post<RequestChangeWindowTitle>(std::fs::path(getFilePath()).filename().string());
|
||||
}
|
||||
|
||||
[[nodiscard]] static const fs::path &getProjectFilePath() {
|
||||
[[nodiscard]] static const std::fs::path &getProjectFilePath() {
|
||||
return ProjectFile::s_currProjectFilePath;
|
||||
}
|
||||
|
||||
@@ -41,11 +41,11 @@ namespace hex {
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] static const fs::path &getFilePath() {
|
||||
[[nodiscard]] static const std::fs::path &getFilePath() {
|
||||
return ProjectFile::s_filePath;
|
||||
}
|
||||
|
||||
static void setFilePath(const fs::path &filePath) {
|
||||
static void setFilePath(const std::fs::path &filePath) {
|
||||
ProjectFile::s_filePath = filePath;
|
||||
|
||||
EventManager::post<RequestChangeWindowTitle>(filePath.filename().string());
|
||||
@@ -92,10 +92,10 @@ namespace hex {
|
||||
}
|
||||
|
||||
private:
|
||||
static fs::path s_currProjectFilePath;
|
||||
static std::fs::path s_currProjectFilePath;
|
||||
static bool s_hasUnsavedChanged;
|
||||
|
||||
static fs::path s_filePath;
|
||||
static std::fs::path s_filePath;
|
||||
static std::string s_pattern;
|
||||
static Patches s_patches;
|
||||
static std::list<ImHexApi::Bookmarks::Entry> s_bookmarks;
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace hex {
|
||||
public:
|
||||
Socket() = default;
|
||||
Socket(const Socket &) = delete;
|
||||
Socket(Socket &&other);
|
||||
Socket(Socket &&other) noexcept;
|
||||
|
||||
Socket(const std::string &address, u16 port);
|
||||
~Socket();
|
||||
@@ -36,8 +36,8 @@ namespace hex {
|
||||
|
||||
[[nodiscard]] bool isConnected() const;
|
||||
|
||||
std::string readString(size_t size = 0x1000) const;
|
||||
std::vector<u8> readBytes(size_t size = 0x1000) const;
|
||||
[[nodiscard]] std::string readString(size_t size = 0x1000) const;
|
||||
[[nodiscard]] std::vector<u8> readBytes(size_t size = 0x1000) const;
|
||||
|
||||
void writeString(const std::string &string) const;
|
||||
void writeBytes(const std::vector<u8> &bytes) const;
|
||||
|
||||
35
lib/libimhex/include/hex/helpers/tar.hpp
Normal file
35
lib/libimhex/include/hex/helpers/tar.hpp
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <microtar.h>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class Tar {
|
||||
public:
|
||||
enum class Mode {
|
||||
Read,
|
||||
Write,
|
||||
Create
|
||||
};
|
||||
|
||||
Tar() = default;
|
||||
Tar(const std::fs::path &path, Mode mode);
|
||||
~Tar();
|
||||
|
||||
std::vector<u8> read(const std::fs::path &path);
|
||||
void write(const std::fs::path &path, const std::vector<u8> &data);
|
||||
|
||||
std::vector<std::fs::path> listEntries();
|
||||
|
||||
void extract(const std::fs::path &path, const std::fs::path &outputPath);
|
||||
void extractAll(const std::fs::path &outputPath);
|
||||
|
||||
private:
|
||||
mtar_t m_ctx = { };
|
||||
};
|
||||
|
||||
}
|
||||
44
lib/libimhex/include/hex/helpers/types.hpp
Normal file
44
lib/libimhex/include/hex/helpers/types.hpp
Normal file
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
using u8 = std::uint8_t;
|
||||
using u16 = std::uint16_t;
|
||||
using u32 = std::uint32_t;
|
||||
using u64 = std::uint64_t;
|
||||
using u128 = __uint128_t;
|
||||
|
||||
using i8 = std::int8_t;
|
||||
using i16 = std::int16_t;
|
||||
using i32 = std::int32_t;
|
||||
using i64 = std::int64_t;
|
||||
using i128 = __int128_t;
|
||||
|
||||
using color_t = u32;
|
||||
|
||||
namespace hex {
|
||||
|
||||
struct Region {
|
||||
u64 address;
|
||||
size_t size;
|
||||
|
||||
[[nodiscard]] constexpr bool isWithin(const Region &other) const {
|
||||
return (this->getStartAddress() >= other.getStartAddress()) && (this->getEndAddress() <= other.getEndAddress());
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool overlaps(const Region &other) const {
|
||||
return (this->getEndAddress() >= other.getStartAddress()) && (this->getStartAddress() < other.getEndAddress());
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u64 getStartAddress() const {
|
||||
return this->address;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u64 getEndAddress() const {
|
||||
return this->address + this->size - 1;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr size_t getSize() const {
|
||||
return this->size;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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__)
|
||||
@@ -41,7 +40,10 @@ namespace hex {
|
||||
void runCommand(const std::string &command);
|
||||
void openWebpage(std::string url);
|
||||
|
||||
[[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const hex::unsigned_integral auto &value) {
|
||||
std::string encodeByteString(const std::vector<u8> &bytes);
|
||||
std::vector<u8> decodeByteString(const std::string &string);
|
||||
|
||||
[[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const std::unsigned_integral auto &value) {
|
||||
if (from < to) std::swap(from, to);
|
||||
|
||||
using ValueType = std::remove_cvref_t<decltype(value)>;
|
||||
@@ -53,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++;
|
||||
@@ -73,6 +72,18 @@ namespace hex {
|
||||
return (value ^ mask) - mask;
|
||||
}
|
||||
|
||||
template<std::integral T>
|
||||
constexpr inline T swapBitOrder(size_t numBits, T value) {
|
||||
T result = 0x00;
|
||||
|
||||
for (size_t bit = 0; bit < numBits; bit++) {
|
||||
result <<= 1;
|
||||
result |= (value & (1 << bit)) != 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<class... Ts>
|
||||
struct overloaded : Ts... { using Ts::operator()...; };
|
||||
template<class... Ts>
|
||||
@@ -127,7 +138,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;
|
||||
@@ -167,7 +178,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;
|
||||
@@ -189,6 +200,40 @@ namespace hex {
|
||||
return T(1) << bit_width(T(x - 1));
|
||||
}
|
||||
|
||||
template<std::integral T, std::integral U>
|
||||
auto powi(T base, U exp) {
|
||||
using ResultType = decltype(T{} * U{});
|
||||
|
||||
if (exp < 0)
|
||||
return ResultType(0);
|
||||
|
||||
ResultType result = 1;
|
||||
|
||||
while (exp != 0) {
|
||||
if ((exp & 0b1) == 0b1)
|
||||
result *= base;
|
||||
exp >>= 1;
|
||||
base *= base;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
void moveToVector(std::vector<T> &buffer, T &&first, Args &&...rest) {
|
||||
buffer.push_back(std::move(first));
|
||||
|
||||
if constexpr (sizeof...(rest) > 0)
|
||||
moveToVector(buffer, std::move(rest)...);
|
||||
}
|
||||
|
||||
template<typename T, typename... Args>
|
||||
std::vector<T> moveToVector(T &&first, Args &&...rest) {
|
||||
std::vector<T> result;
|
||||
moveToVector(result, T(std::move(first)), std::move(rest)...);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<std::string> splitString(const std::string &string, const std::string &delimiter);
|
||||
std::string combineStrings(const std::vector<std::string> &strings, const std::string &delimiter = "");
|
||||
|
||||
@@ -219,7 +264,7 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
inline std::string toBinaryString(hex::unsigned_integral auto number) {
|
||||
inline std::string toBinaryString(std::unsigned_integral auto number) {
|
||||
if (number == 0) return "0";
|
||||
|
||||
std::string result;
|
||||
@@ -247,14 +292,6 @@ namespace hex {
|
||||
trimRight(s);
|
||||
}
|
||||
|
||||
enum class DialogMode {
|
||||
Open,
|
||||
Save,
|
||||
Folder
|
||||
};
|
||||
|
||||
void 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) {
|
||||
@@ -280,12 +317,21 @@ namespace hex {
|
||||
return *value;
|
||||
}
|
||||
|
||||
template<std::integral T>
|
||||
T alignTo(T value, T alignment) {
|
||||
T remainder = value % alignment;
|
||||
|
||||
return remainder != 0 ? value + (alignment - remainder) : value;
|
||||
}
|
||||
|
||||
bool isProcessElevated();
|
||||
|
||||
std::optional<std::string> getEnvironmentVariable(const std::string &env);
|
||||
|
||||
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 {
|
||||
@@ -294,7 +340,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(); }
|
||||
}
|
||||
@@ -307,7 +353,9 @@ namespace hex {
|
||||
ScopeGuard &operator=(ScopeGuard &&) = delete;
|
||||
};
|
||||
|
||||
enum class ScopeGuardOnExit { };
|
||||
enum class ScopeGuardOnExit
|
||||
{
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
constexpr ScopeGuard<F> operator+(ScopeGuardOnExit, F &&f) {
|
||||
@@ -318,17 +366,19 @@ 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;
|
||||
};
|
||||
|
||||
enum class FirstTimeExecutor { };
|
||||
enum class FirstTimeExecutor
|
||||
{
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
constexpr FirstTimeExecute<F> operator+(FirstTimeExecutor, F &&f) {
|
||||
@@ -339,20 +389,22 @@ 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;
|
||||
};
|
||||
|
||||
enum class FinalCleanupExecutor { };
|
||||
enum class FinalCleanupExecutor
|
||||
{
|
||||
};
|
||||
|
||||
template<typename F>
|
||||
constexpr FinalCleanupExecute<F> operator+(FinalCleanupExecutor, F &&f) {
|
||||
|
||||
10
lib/libimhex/include/hex/helpers/utils_macos.hpp
Normal file
10
lib/libimhex/include/hex/helpers/utils_macos.hpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(OS_MACOS)
|
||||
|
||||
#include <string>
|
||||
|
||||
extern "C" void openWebpageMacos(const char *url);
|
||||
extern "C" bool isMacosSystemDarkModeEnabled();
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class PatternLanguageError : public std::exception {
|
||||
public:
|
||||
PatternLanguageError(u32 lineNumber, std::string message) : m_lineNumber(lineNumber), m_message(std::move(message)) { }
|
||||
|
||||
[[nodiscard]] const char *what() const noexcept override {
|
||||
return this->m_message.c_str();
|
||||
}
|
||||
|
||||
[[nodiscard]] u32 getLineNumber() const {
|
||||
return this->m_lineNumber;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_lineNumber;
|
||||
std::string m_message;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,276 +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
|
||||
};
|
||||
|
||||
class PatternData;
|
||||
class PatternCreationLimiter;
|
||||
class ASTNode;
|
||||
|
||||
class Evaluator {
|
||||
public:
|
||||
Evaluator() = default;
|
||||
|
||||
std::optional<std::vector<PatternData *>> evaluate(const std::vector<ASTNode *> &ast);
|
||||
|
||||
[[nodiscard]] LogConsole &getConsole() {
|
||||
return this->m_console;
|
||||
}
|
||||
|
||||
struct ParameterPack {
|
||||
std::string name;
|
||||
std::vector<Token::Literal> values;
|
||||
};
|
||||
|
||||
struct Scope {
|
||||
PatternData *parent;
|
||||
std::vector<PatternData *> *scope;
|
||||
std::optional<ParameterPack> parameterPack;
|
||||
};
|
||||
void pushScope(PatternData *parent, std::vector<PatternData *> &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;
|
||||
}
|
||||
|
||||
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))
|
||||
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]] 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<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;
|
||||
|
||||
friend class PatternCreationLimiter;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <hex/pattern_language/token.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class Lexer {
|
||||
public:
|
||||
Lexer() = default;
|
||||
|
||||
std::optional<std::vector<Token>> lex(const std::string &code);
|
||||
const std::optional<PatternLanguageError> &getError() { return this->m_error; }
|
||||
|
||||
private:
|
||||
std::optional<PatternLanguageError> m_error;
|
||||
|
||||
[[noreturn]] static void throwLexerError(const std::string &error, u32 lineNumber) {
|
||||
throw PatternLanguageError(lineNumber, "Lexer: " + error);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#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);
|
||||
|
||||
[[noreturn]] static void abortEvaluation(const std::string &message, const ASTNode *node = nullptr);
|
||||
|
||||
void clear();
|
||||
|
||||
void setHardError(const PatternLanguageError &error) { this->m_lastHardError = error; }
|
||||
|
||||
[[nodiscard]] const std::optional<PatternLanguageError> &getLastHardError() { return this->m_lastHardError; };
|
||||
|
||||
private:
|
||||
std::vector<std::pair<Level, std::string>> m_consoleLog;
|
||||
std::optional<PatternLanguageError> m_lastHardError;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,292 +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_node.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<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, 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;
|
||||
}
|
||||
|
||||
auto *create(auto *node) {
|
||||
node->setLineNumber(this->getLineNumber(-1));
|
||||
return 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;
|
||||
}
|
||||
|
||||
ASTNode *parseFunctionCall();
|
||||
ASTNode *parseStringLiteral();
|
||||
std::string parseNamespaceResolution();
|
||||
ASTNode *parseScopeResolution();
|
||||
ASTNode *parseRValue();
|
||||
ASTNode *parseRValue(ASTNodeRValue::Path &path);
|
||||
ASTNode *parseFactor();
|
||||
ASTNode *parseCastExpression();
|
||||
ASTNode *parseUnaryExpression();
|
||||
ASTNode *parseMultiplicativeExpression();
|
||||
ASTNode *parseAdditiveExpression();
|
||||
ASTNode *parseShiftExpression();
|
||||
ASTNode *parseBinaryAndExpression();
|
||||
ASTNode *parseBinaryXorExpression();
|
||||
ASTNode *parseBinaryOrExpression();
|
||||
ASTNode *parseBooleanAnd();
|
||||
ASTNode *parseBooleanXor();
|
||||
ASTNode *parseBooleanOr();
|
||||
ASTNode *parseRelationExpression();
|
||||
ASTNode *parseEqualityExpression();
|
||||
ASTNode *parseTernaryConditional();
|
||||
ASTNode *parseMathematicalExpression();
|
||||
|
||||
ASTNode *parseFunctionDefinition();
|
||||
ASTNode *parseFunctionVariableDecl();
|
||||
ASTNode *parseFunctionStatement();
|
||||
ASTNode *parseFunctionVariableAssignment(const std::string &lvalue);
|
||||
ASTNode *parseFunctionVariableCompoundAssignment(const std::string &lvalue);
|
||||
ASTNode *parseFunctionControlFlowStatement();
|
||||
std::vector<ASTNode *> parseStatementBody();
|
||||
ASTNode *parseFunctionConditional();
|
||||
ASTNode *parseFunctionWhileLoop();
|
||||
ASTNode *parseFunctionForLoop();
|
||||
|
||||
void parseAttribute(Attributable *currNode);
|
||||
ASTNode *parseConditional();
|
||||
ASTNode *parseWhileStatement();
|
||||
ASTNodeTypeDecl *parseType(bool allowFunctionTypes = false);
|
||||
ASTNode *parseUsingDeclaration();
|
||||
ASTNode *parsePadding();
|
||||
ASTNode *parseMemberVariable(ASTNodeTypeDecl *type);
|
||||
ASTNode *parseMemberArrayVariable(ASTNodeTypeDecl *type);
|
||||
ASTNode *parseMemberPointerVariable(ASTNodeTypeDecl *type);
|
||||
ASTNode *parseMember();
|
||||
ASTNode *parseStruct();
|
||||
ASTNode *parseUnion();
|
||||
ASTNode *parseEnum();
|
||||
ASTNode *parseBitfield();
|
||||
ASTNode *parseVariablePlacement(ASTNodeTypeDecl *type);
|
||||
ASTNode *parseArrayVariablePlacement(ASTNodeTypeDecl *type);
|
||||
ASTNode *parsePointerVariablePlacement(ASTNodeTypeDecl *type);
|
||||
ASTNode *parsePlacement();
|
||||
std::vector<ASTNode *> parseNamespace();
|
||||
std::vector<ASTNode *> parseStatements();
|
||||
|
||||
ASTNodeTypeDecl *addType(const std::string &name, ASTNode *node, std::optional<std::endian> endian = std::nullopt);
|
||||
|
||||
std::vector<ASTNode *> parseTillToken(Token::Type endTokenType, const auto value) {
|
||||
std::vector<ASTNode *> program;
|
||||
auto guard = SCOPE_GUARD {
|
||||
for (auto &node : program)
|
||||
delete node;
|
||||
};
|
||||
|
||||
while (this->m_curr->type != endTokenType || (*this->m_curr) != value) {
|
||||
for (auto statement : parseStatements())
|
||||
program.push_back(statement);
|
||||
}
|
||||
|
||||
this->m_curr++;
|
||||
|
||||
guard.release();
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,79 +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>
|
||||
|
||||
namespace hex::prv {
|
||||
class Provider;
|
||||
}
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class Preprocessor;
|
||||
class Lexer;
|
||||
class Parser;
|
||||
class Validator;
|
||||
class Evaluator;
|
||||
class PatternData;
|
||||
|
||||
class ASTNode;
|
||||
|
||||
class PatternLanguage {
|
||||
public:
|
||||
PatternLanguage();
|
||||
~PatternLanguage();
|
||||
|
||||
[[nodiscard]] std::optional<std::vector<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<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<PatternData *> &getPatterns() {
|
||||
const static std::vector<PatternData *> 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<ASTNode *> m_currAST;
|
||||
|
||||
std::optional<PatternLanguageError> m_currError;
|
||||
|
||||
std::vector<PatternData *> m_patterns;
|
||||
|
||||
bool m_running = false;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
#include <hex/helpers/paths.hpp>
|
||||
|
||||
#include <hex/pattern_language/error.hpp>
|
||||
|
||||
namespace hex::pl {
|
||||
|
||||
class Preprocessor {
|
||||
public:
|
||||
Preprocessor() = default;
|
||||
|
||||
std::optional<std::string> preprocess(const std::string &code, bool initialRun = true);
|
||||
|
||||
void addPragmaHandler(const std::string &pragmaType, const std::function<bool(const std::string &)> &function);
|
||||
void removePragmaHandler(const std::string &pragmaType);
|
||||
void addDefaultPragmaHandlers();
|
||||
|
||||
const std::optional<PatternLanguageError> &getError() { return this->m_error; }
|
||||
|
||||
bool shouldOnlyIncludeOnce() {
|
||||
return this->m_onlyIncludeOnce;
|
||||
}
|
||||
|
||||
private:
|
||||
[[noreturn]] static void throwPreprocessorError(const std::string &error, u32 lineNumber) {
|
||||
throw PatternLanguageError(lineNumber, "Preprocessor: " + error);
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, std::function<bool(std::string)>> m_pragmaHandlers;
|
||||
|
||||
std::set<std::tuple<std::string, std::string, u32>> m_defines;
|
||||
std::set<std::tuple<std::string, std::string, u32>> m_pragmas;
|
||||
|
||||
std::set<fs::path> m_onceIncludedFiles;
|
||||
|
||||
std::optional<PatternLanguageError> m_error;
|
||||
|
||||
bool m_onlyIncludeOnce = false;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,358 +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 PatternData;
|
||||
|
||||
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, PatternData *>;
|
||||
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"); },
|
||||
[](PatternData *) -> 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"); },
|
||||
[](PatternData *) -> 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"); },
|
||||
[](PatternData *) -> 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"); },
|
||||
[](PatternData *) -> 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 }; },
|
||||
[](PatternData *) -> std::string { LogConsole::abortEvaluation("expected integral type, got custom type"); },
|
||||
[](auto &&result) -> std::string { return std::to_string(result); } },
|
||||
literal);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr static auto getTypeName(const pl::Token::ValueType type) {
|
||||
switch (type) {
|
||||
case ValueType::Signed8Bit:
|
||||
return "s8";
|
||||
case ValueType::Signed16Bit:
|
||||
return "s16";
|
||||
case ValueType::Signed32Bit:
|
||||
return "s32";
|
||||
case ValueType::Signed64Bit:
|
||||
return "s64";
|
||||
case ValueType::Signed128Bit:
|
||||
return "s128";
|
||||
case ValueType::Unsigned8Bit:
|
||||
return "u8";
|
||||
case ValueType::Unsigned16Bit:
|
||||
return "u16";
|
||||
case ValueType::Unsigned32Bit:
|
||||
return "u32";
|
||||
case ValueType::Unsigned64Bit:
|
||||
return "u64";
|
||||
case ValueType::Unsigned128Bit:
|
||||
return "u128";
|
||||
case ValueType::Float:
|
||||
return "float";
|
||||
case ValueType::Double:
|
||||
return "double";
|
||||
case ValueType::Character:
|
||||
return "char";
|
||||
case ValueType::Character16:
|
||||
return "char16";
|
||||
case ValueType::Padding:
|
||||
return "padding";
|
||||
case ValueType::String:
|
||||
return "str";
|
||||
default:
|
||||
return "< ??? >";
|
||||
}
|
||||
}
|
||||
|
||||
bool operator==(const ValueTypes &other) const {
|
||||
if (this->type == Type::Integer || this->type == Type::Identifier || this->type == Type::String)
|
||||
return true;
|
||||
else if (this->type == Type::ValueType) {
|
||||
auto otherValueType = std::get_if<ValueType>(&other);
|
||||
auto valueType = std::get_if<ValueType>(&this->value);
|
||||
|
||||
if (otherValueType == nullptr) return false;
|
||||
if (valueType == nullptr) return false;
|
||||
|
||||
if (*otherValueType == *valueType)
|
||||
return true;
|
||||
else if (*otherValueType == ValueType::Any)
|
||||
return *valueType != ValueType::CustomType && *valueType != ValueType::Padding;
|
||||
else if (*otherValueType == ValueType::Unsigned)
|
||||
return isUnsigned(*valueType);
|
||||
else if (*otherValueType == ValueType::Signed)
|
||||
return isSigned(*valueType);
|
||||
else if (*otherValueType == ValueType::FloatingPoint)
|
||||
return isFloatingPoint(*valueType);
|
||||
else if (*otherValueType == ValueType::Integer)
|
||||
return isUnsigned(*valueType) || isSigned(*valueType);
|
||||
} else
|
||||
return other == this->value;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool operator!=(const ValueTypes &other) const {
|
||||
return !operator==(other);
|
||||
}
|
||||
|
||||
Type type;
|
||||
ValueTypes value;
|
||||
u32 lineNumber;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#define COMPONENT(type, value) hex::pl::Token::Type::type, hex::pl::Token::type::value
|
||||
|
||||
#define KEYWORD_STRUCT COMPONENT(Keyword, Struct)
|
||||
#define KEYWORD_UNION COMPONENT(Keyword, Union)
|
||||
#define KEYWORD_USING COMPONENT(Keyword, Using)
|
||||
#define KEYWORD_ENUM COMPONENT(Keyword, Enum)
|
||||
#define KEYWORD_BITFIELD COMPONENT(Keyword, Bitfield)
|
||||
#define KEYWORD_LE COMPONENT(Keyword, LittleEndian)
|
||||
#define KEYWORD_BE COMPONENT(Keyword, BigEndian)
|
||||
#define KEYWORD_IF COMPONENT(Keyword, If)
|
||||
#define KEYWORD_ELSE COMPONENT(Keyword, Else)
|
||||
#define KEYWORD_PARENT COMPONENT(Keyword, Parent)
|
||||
#define KEYWORD_THIS COMPONENT(Keyword, This)
|
||||
#define KEYWORD_WHILE COMPONENT(Keyword, While)
|
||||
#define KEYWORD_FOR COMPONENT(Keyword, For)
|
||||
#define KEYWORD_FUNCTION COMPONENT(Keyword, Function)
|
||||
#define KEYWORD_RETURN COMPONENT(Keyword, Return)
|
||||
#define KEYWORD_NAMESPACE COMPONENT(Keyword, Namespace)
|
||||
#define KEYWORD_IN COMPONENT(Keyword, In)
|
||||
#define KEYWORD_OUT COMPONENT(Keyword, Out)
|
||||
#define KEYWORD_BREAK COMPONENT(Keyword, Break)
|
||||
#define KEYWORD_CONTINUE COMPONENT(Keyword, Continue)
|
||||
|
||||
#define INTEGER hex::pl::Token::Type::Integer, hex::pl::Token::Literal(u128(0))
|
||||
#define IDENTIFIER hex::pl::Token::Type::Identifier, ""
|
||||
#define STRING hex::pl::Token::Type::String, hex::pl::Token::Literal("")
|
||||
|
||||
#define OPERATOR_ANY COMPONENT(Operator, Any)
|
||||
#define OPERATOR_AT COMPONENT(Operator, AtDeclaration)
|
||||
#define OPERATOR_ASSIGNMENT COMPONENT(Operator, Assignment)
|
||||
#define OPERATOR_INHERIT COMPONENT(Operator, Inherit)
|
||||
#define OPERATOR_PLUS COMPONENT(Operator, Plus)
|
||||
#define OPERATOR_MINUS COMPONENT(Operator, Minus)
|
||||
#define OPERATOR_STAR COMPONENT(Operator, Star)
|
||||
#define OPERATOR_SLASH COMPONENT(Operator, Slash)
|
||||
#define OPERATOR_PERCENT COMPONENT(Operator, Percent)
|
||||
#define OPERATOR_SHIFTLEFT COMPONENT(Operator, ShiftLeft)
|
||||
#define OPERATOR_SHIFTRIGHT COMPONENT(Operator, ShiftRight)
|
||||
#define OPERATOR_BITOR COMPONENT(Operator, BitOr)
|
||||
#define OPERATOR_BITAND COMPONENT(Operator, BitAnd)
|
||||
#define OPERATOR_BITXOR COMPONENT(Operator, BitXor)
|
||||
#define OPERATOR_BITNOT COMPONENT(Operator, BitNot)
|
||||
#define OPERATOR_BOOLEQUALS COMPONENT(Operator, BoolEquals)
|
||||
#define OPERATOR_BOOLNOTEQUALS COMPONENT(Operator, BoolNotEquals)
|
||||
#define OPERATOR_BOOLGREATERTHAN COMPONENT(Operator, BoolGreaterThan)
|
||||
#define OPERATOR_BOOLLESSTHAN COMPONENT(Operator, BoolLessThan)
|
||||
#define OPERATOR_BOOLGREATERTHANOREQUALS COMPONENT(Operator, BoolGreaterThanOrEquals)
|
||||
#define OPERATOR_BOOLLESSTHANOREQUALS COMPONENT(Operator, BoolLessThanOrEquals)
|
||||
#define OPERATOR_BOOLAND COMPONENT(Operator, BoolAnd)
|
||||
#define OPERATOR_BOOLOR COMPONENT(Operator, BoolOr)
|
||||
#define OPERATOR_BOOLXOR COMPONENT(Operator, BoolXor)
|
||||
#define OPERATOR_BOOLNOT COMPONENT(Operator, BoolNot)
|
||||
#define OPERATOR_TERNARYCONDITIONAL COMPONENT(Operator, TernaryConditional)
|
||||
#define OPERATOR_DOLLAR COMPONENT(Operator, Dollar)
|
||||
#define OPERATOR_ADDRESSOF COMPONENT(Operator, AddressOf)
|
||||
#define OPERATOR_SIZEOF COMPONENT(Operator, SizeOf)
|
||||
#define OPERATOR_SCOPERESOLUTION COMPONENT(Operator, ScopeResolution)
|
||||
|
||||
#define VALUETYPE_CUSTOMTYPE COMPONENT(ValueType, CustomType)
|
||||
#define VALUETYPE_PADDING COMPONENT(ValueType, Padding)
|
||||
#define VALUETYPE_UNSIGNED COMPONENT(ValueType, Unsigned)
|
||||
#define VALUETYPE_SIGNED COMPONENT(ValueType, Signed)
|
||||
#define VALUETYPE_FLOATINGPOINT COMPONENT(ValueType, FloatingPoint)
|
||||
#define VALUETYPE_AUTO COMPONENT(ValueType, Auto)
|
||||
#define VALUETYPE_ANY COMPONENT(ValueType, Any)
|
||||
|
||||
#define SEPARATOR_ROUNDBRACKETOPEN COMPONENT(Separator, RoundBracketOpen)
|
||||
#define SEPARATOR_ROUNDBRACKETCLOSE COMPONENT(Separator, RoundBracketClose)
|
||||
#define SEPARATOR_CURLYBRACKETOPEN COMPONENT(Separator, CurlyBracketOpen)
|
||||
#define SEPARATOR_CURLYBRACKETCLOSE COMPONENT(Separator, CurlyBracketClose)
|
||||
#define SEPARATOR_SQUAREBRACKETOPEN COMPONENT(Separator, SquareBracketOpen)
|
||||
#define SEPARATOR_SQUAREBRACKETCLOSE COMPONENT(Separator, SquareBracketClose)
|
||||
#define SEPARATOR_COMMA COMPONENT(Separator, Comma)
|
||||
#define SEPARATOR_DOT COMPONENT(Separator, Dot)
|
||||
#define SEPARATOR_ENDOFEXPRESSION COMPONENT(Separator, EndOfExpression)
|
||||
#define SEPARATOR_ENDOFPROGRAM COMPONENT(Separator, EndOfProgram)
|
||||
@@ -1,31 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#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<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);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
223
lib/libimhex/include/hex/providers/buffered_reader.hpp
Normal file
223
lib/libimhex/include/hex/providers/buffered_reader.hpp
Normal file
@@ -0,0 +1,223 @@
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
class BufferedReader {
|
||||
public:
|
||||
explicit BufferedReader(Provider *provider, size_t bufferSize = 0xFF'FFFF) : m_provider(provider), m_maxBufferSize(bufferSize), m_buffer(bufferSize) { }
|
||||
|
||||
void seek(u64 address) {
|
||||
this->m_baseAddress = address;
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<u8> read(u64 address, size_t size) {
|
||||
if (size > this->m_buffer.size()) {
|
||||
std::vector<u8> result;
|
||||
result.resize(size);
|
||||
|
||||
this->m_provider->read(address, result.data(), result.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
this->updateBuffer(address, size);
|
||||
|
||||
auto result = &this->m_buffer[address - this->m_baseAddress];
|
||||
|
||||
return { result, result + std::min(size, this->m_buffer.size()) };
|
||||
}
|
||||
|
||||
[[nodiscard]] std::vector<u8> readReverse(u64 address, size_t size) {
|
||||
if (size > this->m_buffer.size()) {
|
||||
std::vector<u8> result;
|
||||
result.resize(size);
|
||||
|
||||
this->m_provider->read(address, result.data(), result.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
this->updateBuffer(address - std::min<u64>(address, this->m_buffer.size()), size);
|
||||
|
||||
auto result = &this->m_buffer[address - this->m_baseAddress];
|
||||
|
||||
return { result, result + std::min(size, this->m_buffer.size()) };
|
||||
}
|
||||
|
||||
class Iterator {
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = u8;
|
||||
using pointer = const value_type*;
|
||||
using reference = const value_type&;
|
||||
|
||||
Iterator(BufferedReader *reader, u64 address) : m_reader(reader), m_address(address) {}
|
||||
|
||||
Iterator& operator++() {
|
||||
this->m_address++;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++(int) {
|
||||
auto copy = *this;
|
||||
this->m_address++;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
Iterator& operator+=(i64 offset) {
|
||||
this->m_address += offset;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator& operator-=(i64 offset) {
|
||||
this->m_address -= offset;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
value_type operator*() const {
|
||||
return (*this)[0];
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 getAddress() const {
|
||||
return this->m_address;
|
||||
}
|
||||
|
||||
difference_type operator-(const Iterator &other) const {
|
||||
return this->m_address - other.m_address;
|
||||
}
|
||||
|
||||
Iterator operator+(i64 offset) const {
|
||||
return { this->m_reader, this->m_address + offset };
|
||||
}
|
||||
|
||||
value_type operator[](i64 offset) const {
|
||||
auto result = this->m_reader->read(this->m_address + offset, 1);
|
||||
if (result.empty())
|
||||
return 0x00;
|
||||
|
||||
return result[0];
|
||||
}
|
||||
|
||||
friend bool operator== (const Iterator& left, const Iterator& right) { return left.m_address == right.m_address; };
|
||||
friend bool operator!= (const Iterator& left, const Iterator& right) { return left.m_address != right.m_address; };
|
||||
private:
|
||||
BufferedReader *m_reader;
|
||||
u64 m_address;
|
||||
};
|
||||
|
||||
class ReverseIterator {
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using value_type = u8;
|
||||
using pointer = const value_type*;
|
||||
using reference = const value_type&;
|
||||
|
||||
ReverseIterator(BufferedReader *reader, u64 address) : m_reader(reader), m_address(address) {}
|
||||
|
||||
ReverseIterator& operator++() {
|
||||
this->m_address--;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReverseIterator operator++(int) {
|
||||
auto copy = *this;
|
||||
this->m_address--;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
ReverseIterator& operator+=(i64 offset) {
|
||||
this->m_address -= offset;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReverseIterator& operator-=(i64 offset) {
|
||||
this->m_address += offset;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
value_type operator*() const {
|
||||
return (*this)[0];
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 getAddress() const {
|
||||
return this->m_address;
|
||||
}
|
||||
|
||||
difference_type operator-(const ReverseIterator &other) const {
|
||||
return other.m_address - this->m_address;
|
||||
}
|
||||
|
||||
ReverseIterator operator+(i64 offset) const {
|
||||
return { this->m_reader, this->m_address - offset };
|
||||
}
|
||||
|
||||
value_type operator[](i64 offset) const {
|
||||
auto result = this->m_reader->readReverse(this->m_address + offset, 1);
|
||||
if (result.empty())
|
||||
return 0x00;
|
||||
|
||||
return result[0];
|
||||
}
|
||||
|
||||
friend bool operator== (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address == right.m_address; };
|
||||
friend bool operator!= (const ReverseIterator& left, const ReverseIterator& right) { return left.m_address != right.m_address; };
|
||||
|
||||
private:
|
||||
BufferedReader *m_reader;
|
||||
u64 m_address;
|
||||
};
|
||||
|
||||
Iterator begin() {
|
||||
return { this, this->m_baseAddress };
|
||||
}
|
||||
|
||||
Iterator end() {
|
||||
return { this, this->m_baseAddress + this->m_provider->getActualSize() };
|
||||
}
|
||||
|
||||
ReverseIterator rbegin() {
|
||||
return { this, this->m_baseAddress };
|
||||
}
|
||||
|
||||
ReverseIterator rend() {
|
||||
return { this, std::numeric_limits<u64>::max() };
|
||||
}
|
||||
|
||||
private:
|
||||
void updateBuffer(u64 address, size_t size) {
|
||||
if (!this->m_bufferValid || address < this->m_baseAddress || address + size > (this->m_baseAddress + this->m_buffer.size())) {
|
||||
const auto remainingBytes = this->m_provider->getActualSize() - address;
|
||||
if (remainingBytes < this->m_maxBufferSize)
|
||||
this->m_buffer.resize(remainingBytes);
|
||||
|
||||
this->m_provider->read(address, this->m_buffer.data(), this->m_buffer.size());
|
||||
this->m_baseAddress = address;
|
||||
this->m_bufferValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Provider *m_provider;
|
||||
|
||||
size_t m_maxBufferSize;
|
||||
bool m_bufferValid = false;
|
||||
u64 m_baseAddress = 0x00;
|
||||
std::vector<u8> m_buffer;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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; }
|
||||
|
||||
@@ -9,7 +9,11 @@
|
||||
#include <vector>
|
||||
|
||||
#include <hex/providers/overlay.hpp>
|
||||
#include <hex/pattern_language/pattern_language.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
namespace pl {
|
||||
class PatternLanguage;
|
||||
}
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
@@ -31,9 +35,10 @@ namespace hex::prv {
|
||||
|
||||
virtual void resize(size_t newSize);
|
||||
virtual void insert(u64 offset, size_t size);
|
||||
virtual void remove(u64 offset, size_t size);
|
||||
|
||||
virtual void save();
|
||||
virtual void saveAs(const fs::path &path);
|
||||
virtual void saveAs(const std::fs::path &path);
|
||||
|
||||
virtual void readRaw(u64 offset, void *buffer, size_t size) = 0;
|
||||
virtual void writeRaw(u64 offset, const void *buffer, size_t size) = 0;
|
||||
@@ -79,7 +84,7 @@ namespace hex::prv {
|
||||
virtual void drawLoadInterface();
|
||||
virtual void drawInterface();
|
||||
|
||||
pl::PatternLanguage &getPatternLanguageRuntime() { return this->m_patternLanguageRuntime; }
|
||||
pl::PatternLanguage &getPatternLanguageRuntime() { return *this->m_patternLanguageRuntime; }
|
||||
std::string &getPatternLanguageSourceCode() { return this->m_patternLanguageSourceCode; }
|
||||
|
||||
protected:
|
||||
@@ -90,7 +95,7 @@ namespace hex::prv {
|
||||
std::list<std::map<u64, u8>> m_patches;
|
||||
std::list<Overlay *> m_overlays;
|
||||
|
||||
pl::PatternLanguage m_patternLanguageRuntime;
|
||||
std::unique_ptr<pl::PatternLanguage> m_patternLanguageRuntime;
|
||||
std::string m_patternLanguageSourceCode;
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#include <imgui.h>
|
||||
@@ -62,7 +63,6 @@ namespace ImGui {
|
||||
|
||||
void UnderlinedText(const char *label, ImColor color = ImGui::GetStyleColorVec4(ImGuiCol_Text), const ImVec2 &size_arg = ImVec2(0, 0));
|
||||
|
||||
void Disabled(const std::function<void()> &widgets, bool disabled);
|
||||
void TextSpinner(const char *label);
|
||||
|
||||
void Header(const char *label, bool firstEntry = false);
|
||||
@@ -74,7 +74,8 @@ namespace ImGui {
|
||||
bool ToolBarButton(const char *symbol, ImVec4 color);
|
||||
bool IconButton(const char *symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0));
|
||||
|
||||
bool InputIntegerPrefix(const char* label, const char *prefix, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputIntegerPrefix(const char* label, const char *prefix, void *value, ImGuiDataType type, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputHexadecimal(const char* label, u32 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputHexadecimal(const char* label, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
|
||||
inline bool HasSecondPassed() {
|
||||
@@ -117,7 +118,7 @@ namespace ImGui {
|
||||
}
|
||||
|
||||
void TextFormattedCentered(const std::string &fmt, auto &&...args) {
|
||||
auto text = hex::format(fmt);
|
||||
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
|
||||
auto availableSpace = ImGui::GetContentRegionAvail();
|
||||
auto textSize = ImGui::CalcTextSize(text.c_str(), nullptr, false, availableSpace.x * 0.75F);
|
||||
|
||||
@@ -127,4 +128,13 @@ namespace ImGui {
|
||||
ImGui::TextFormattedWrapped("{}", text);
|
||||
ImGui::PopTextWrapPos();
|
||||
}
|
||||
|
||||
bool InputText(const char* label, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputTextMultiline(const char* label, std::string &buffer, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
|
||||
bool InputScalarCallback(const char* label, ImGuiDataType data_type, void* p_data, const char* format, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data);
|
||||
|
||||
void HideTooltip();
|
||||
|
||||
bool BitCheckbox(const char* label, bool* v);
|
||||
}
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <hex/api/localization.hpp>
|
||||
|
||||
@@ -33,13 +34,12 @@ namespace hex {
|
||||
[[nodiscard]] virtual bool isAvailable() const;
|
||||
[[nodiscard]] virtual bool shouldProcess() const { return this->isAvailable() && this->getWindowOpenState(); }
|
||||
|
||||
static void drawCommonInterfaces();
|
||||
static void showInfoPopup(const std::string &message);
|
||||
static void showErrorPopup(const std::string &message);
|
||||
static void showFatalPopup(const std::string &message);
|
||||
static void showYesNoQuestionPopup(const std::string &message, const std::function<void()> &yesCallback, const std::function<void()> &noCallback);
|
||||
|
||||
static void showMessagePopup(const std::string &message);
|
||||
static void showErrorPopup(const std::string &errorMessage);
|
||||
static void showFatalPopup(const std::string &errorMessage);
|
||||
|
||||
static void showFileChooserPopup(const std::vector<fs::path> &paths, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(fs::path)> &callback);
|
||||
static void showFileChooserPopup(const std::vector<std::fs::path> &paths, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback);
|
||||
|
||||
[[nodiscard]] virtual bool hasViewMenuItemEntry() const;
|
||||
[[nodiscard]] virtual ImVec2 getMinSize() const;
|
||||
@@ -69,13 +69,6 @@ namespace hex {
|
||||
bool m_windowOpen = false;
|
||||
std::map<Shortcut, std::function<void()>> m_shortcuts;
|
||||
|
||||
static std::string s_popupMessage;
|
||||
|
||||
static u32 s_selectableFileIndex;
|
||||
static std::vector<fs::path> s_selectableFiles;
|
||||
static std::function<void(fs::path)> s_selectableFileOpenCallback;
|
||||
static std::vector<nfdfilteritem_t> s_selectableFilesValidExtensions;
|
||||
|
||||
static ImFontAtlas *s_fontAtlas;
|
||||
static ImFontConfig s_fontConfig;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <hex/helpers/paths.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
@@ -16,7 +16,7 @@ namespace hex {
|
||||
|
||||
void load() {
|
||||
bool loaded = false;
|
||||
for (const auto &dir : hex::getPath(ImHexPath::Config)) {
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
std::ifstream settingsFile(dir / "settings.json");
|
||||
|
||||
if (settingsFile.good()) {
|
||||
@@ -31,7 +31,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void store() {
|
||||
for (const auto &dir : hex::getPath(ImHexPath::Config)) {
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
std::ofstream settingsFile(dir / "settings.json", std::ios::trunc);
|
||||
|
||||
if (settingsFile.good()) {
|
||||
@@ -41,10 +41,23 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback) {
|
||||
static auto getCategoryEntry(const std::string &unlocalizedCategory) {
|
||||
auto &entries = getEntries();
|
||||
const size_t curSlot = entries.size();
|
||||
auto found = entries.find(Category { unlocalizedCategory });
|
||||
|
||||
if (found == entries.end()) {
|
||||
auto [iter, _] = entries.emplace(Category { unlocalizedCategory, curSlot }, std::vector<Entry> {});
|
||||
return iter;
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 defaultValue, const Callback &callback, bool requiresRestart) {
|
||||
log::info("Registered new integer setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
|
||||
|
||||
getEntries()[unlocalizedCategory.c_str()].emplace_back(Entry { unlocalizedName.c_str(), callback });
|
||||
getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback });
|
||||
|
||||
auto &json = getSettingsData();
|
||||
|
||||
@@ -54,10 +67,10 @@ namespace hex {
|
||||
json[unlocalizedCategory][unlocalizedName] = int(defaultValue);
|
||||
}
|
||||
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback) {
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::string &defaultValue, const Callback &callback, bool requiresRestart) {
|
||||
log::info("Registered new string setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
|
||||
|
||||
getEntries()[unlocalizedCategory].emplace_back(Entry { unlocalizedName, callback });
|
||||
getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback });
|
||||
|
||||
auto &json = getSettingsData();
|
||||
|
||||
@@ -67,6 +80,23 @@ namespace hex {
|
||||
json[unlocalizedCategory][unlocalizedName] = std::string(defaultValue);
|
||||
}
|
||||
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const std::vector<std::string> &defaultValue, const Callback &callback, bool requiresRestart) {
|
||||
log::info("Registered new string array setting: [{}]: {}", unlocalizedCategory, unlocalizedName);
|
||||
|
||||
getCategoryEntry(unlocalizedCategory)->second.emplace_back(Entry { unlocalizedName, requiresRestart, callback });
|
||||
|
||||
auto &json = getSettingsData();
|
||||
|
||||
if (!json.contains(unlocalizedCategory))
|
||||
json[unlocalizedCategory] = nlohmann::json::object();
|
||||
if (!json[unlocalizedCategory].contains(unlocalizedName) || !json[unlocalizedCategory][unlocalizedName].is_array())
|
||||
json[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
}
|
||||
|
||||
void addCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedCategoryDescription) {
|
||||
getCategoryDescriptions()[unlocalizedCategory] = unlocalizedCategoryDescription;
|
||||
}
|
||||
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, i64 value) {
|
||||
auto &json = getSettingsData();
|
||||
|
||||
@@ -141,12 +171,18 @@ namespace hex {
|
||||
}
|
||||
|
||||
|
||||
std::map<std::string, std::vector<Entry>> &getEntries() {
|
||||
static std::map<std::string, std::vector<Entry>> entries;
|
||||
std::map<Category, std::vector<Entry>> &getEntries() {
|
||||
static std::map<Category, std::vector<Entry>> entries;
|
||||
|
||||
return entries;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> &getCategoryDescriptions() {
|
||||
static std::map<std::string, std::string> descriptions;
|
||||
|
||||
return descriptions;
|
||||
}
|
||||
|
||||
nlohmann::json getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName) {
|
||||
auto &settings = getSettingsData();
|
||||
|
||||
@@ -184,7 +220,7 @@ namespace hex {
|
||||
|
||||
namespace ContentRegistry::PatternLanguage {
|
||||
|
||||
static std::string getFunctionName(const Namespace &ns, const std::string &name) {
|
||||
static std::string getFunctionName(const pl::api::Namespace &ns, const std::string &name) {
|
||||
std::string functionName;
|
||||
for (auto &scope : ns)
|
||||
functionName += scope + "::";
|
||||
@@ -194,63 +230,67 @@ namespace hex {
|
||||
return functionName;
|
||||
}
|
||||
|
||||
void addFunction(const Namespace &ns, const std::string &name, u32 parameterCount, const Callback &func) {
|
||||
std::unique_ptr<pl::PatternLanguage> createDefaultRuntime(prv::Provider *provider) {
|
||||
auto runtime = std::make_unique<pl::PatternLanguage>();
|
||||
|
||||
runtime->setDataSource([provider](u64 offset, u8 *buffer, size_t size) {
|
||||
provider->read(offset, buffer, size);
|
||||
}, 0, 0);
|
||||
|
||||
runtime->setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude));
|
||||
|
||||
for (const auto &func : getFunctions()) {
|
||||
if (func.dangerous)
|
||||
runtime->addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
else
|
||||
runtime->addFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
}
|
||||
|
||||
for (const auto &[name, callback] : getPragmas()) {
|
||||
runtime->addPragma(name, callback);
|
||||
}
|
||||
|
||||
return runtime;
|
||||
}
|
||||
|
||||
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
|
||||
log::info("Registered new pattern language pragma: {}", name);
|
||||
|
||||
getPragmas()[name] = handler;
|
||||
}
|
||||
|
||||
void addFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
|
||||
log::info("Registered new pattern language function: {}", getFunctionName(ns, name));
|
||||
|
||||
getFunctions()[getFunctionName(ns, name)] = Function { parameterCount, func, false };
|
||||
getFunctions().push_back({
|
||||
ns, name,
|
||||
parameterCount, func,
|
||||
false
|
||||
});
|
||||
}
|
||||
|
||||
void addDangerousFunction(const Namespace &ns, const std::string &name, u32 parameterCount, const Callback &func) {
|
||||
void addDangerousFunction(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::FunctionCallback &func) {
|
||||
log::info("Registered new dangerous pattern language function: {}", getFunctionName(ns, name));
|
||||
|
||||
getFunctions()[getFunctionName(ns, name)] = Function { parameterCount, func, true };
|
||||
getFunctions().push_back({
|
||||
ns, name,
|
||||
parameterCount, func,
|
||||
true
|
||||
});
|
||||
}
|
||||
|
||||
std::map<std::string, Function> &getFunctions() {
|
||||
static std::map<std::string, Function> functions;
|
||||
std::map<std::string, pl::api::PragmaHandler> &getPragmas() {
|
||||
static std::map<std::string, pl::api::PragmaHandler> pragmas;
|
||||
|
||||
return pragmas;
|
||||
}
|
||||
|
||||
std::vector<impl::FunctionDefinition> &getFunctions() {
|
||||
static std::vector<impl::FunctionDefinition> functions;
|
||||
|
||||
return functions;
|
||||
}
|
||||
|
||||
|
||||
static std::vector<impl::ColorPalette> s_colorPalettes;
|
||||
static u32 s_colorIndex;
|
||||
static u32 s_selectedColorPalette;
|
||||
|
||||
std::vector<impl::ColorPalette> &getPalettes() {
|
||||
return s_colorPalettes;
|
||||
}
|
||||
|
||||
void addColorPalette(const std::string &unlocalizedName, const std::vector<u32> &colors) {
|
||||
s_colorPalettes.push_back({ unlocalizedName,
|
||||
colors });
|
||||
}
|
||||
|
||||
void setSelectedPalette(u32 index) {
|
||||
if (index < s_colorPalettes.size())
|
||||
s_selectedColorPalette = index;
|
||||
|
||||
resetPalette();
|
||||
}
|
||||
|
||||
u32 getNextColor() {
|
||||
if (s_colorPalettes.empty())
|
||||
return 0x00;
|
||||
|
||||
auto &currColors = s_colorPalettes[s_selectedColorPalette].colors;
|
||||
|
||||
u32 color = currColors[s_colorIndex];
|
||||
|
||||
s_colorIndex++;
|
||||
s_colorIndex %= currColors.size();
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
void resetPalette() {
|
||||
s_colorIndex = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -297,10 +337,10 @@ namespace hex {
|
||||
|
||||
namespace ContentRegistry::DataInspector {
|
||||
|
||||
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction function) {
|
||||
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
|
||||
log::info("Registered new data inspector format: {}", unlocalizedName);
|
||||
|
||||
getEntries().push_back({ unlocalizedName, requiredSize, std::move(function) });
|
||||
getEntries().push_back({ unlocalizedName, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
|
||||
}
|
||||
|
||||
std::vector<impl::Entry> &getEntries() {
|
||||
@@ -314,7 +354,7 @@ namespace hex {
|
||||
namespace ContentRegistry::DataProcessorNode {
|
||||
|
||||
void impl::add(const impl::Entry &entry) {
|
||||
log::info("Registered new data processor node type: [{}]: ", entry.category, entry.name);
|
||||
log::info("Registered new data processor node type: [{}]: {}", entry.category, entry.name);
|
||||
|
||||
getEntries().push_back(entry);
|
||||
}
|
||||
@@ -496,4 +536,64 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
namespace ContentRegistry::HexEditor {
|
||||
|
||||
const int DataVisualizer::TextInputFlags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoHorizontalScroll;
|
||||
|
||||
bool DataVisualizer::drawDefaultEditingTextBox(u64 address, const char *format, ImGuiDataType dataType, u8 *data, ImGuiInputTextFlags flags) const {
|
||||
struct UserData {
|
||||
u8 *data;
|
||||
i32 maxChars;
|
||||
|
||||
bool editingDone;
|
||||
};
|
||||
|
||||
UserData userData = {
|
||||
.data = data,
|
||||
.maxChars = this->getMaxCharsPerCell(),
|
||||
|
||||
.editingDone = false
|
||||
};
|
||||
|
||||
ImGui::PushID(reinterpret_cast<void*>(address));
|
||||
ImGui::InputScalarCallback("##editing_input", dataType, data, format, flags | TextInputFlags | ImGuiInputTextFlags_CallbackEdit, [](ImGuiInputTextCallbackData *data) -> int {
|
||||
auto &userData = *reinterpret_cast<UserData*>(data->UserData);
|
||||
|
||||
if (data->BufTextLen >= userData.maxChars)
|
||||
userData.editingDone = true;
|
||||
|
||||
return 0;
|
||||
}, &userData);
|
||||
ImGui::PopID();
|
||||
|
||||
return userData.editingDone || ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Enter);
|
||||
}
|
||||
|
||||
void impl::addDataVisualizer(const std::string &unlocalizedName, DataVisualizer *visualizer) {
|
||||
getVisualizers().insert({ unlocalizedName, visualizer });
|
||||
|
||||
}
|
||||
|
||||
std::map<std::string, DataVisualizer*> &impl::getVisualizers() {
|
||||
static std::map<std::string, DataVisualizer*> visualizers;
|
||||
|
||||
return visualizers;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
namespace ContentRegistry::Hashes {
|
||||
|
||||
std::vector<Hash *> &impl::getHashes() {
|
||||
static std::vector<Hash *> hashes;
|
||||
|
||||
return hashes;
|
||||
}
|
||||
|
||||
void impl::add(Hash *hash) {
|
||||
getHashes().push_back(hash);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <hex/api/event.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <utility>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace ImHexApi::Common {
|
||||
@@ -26,17 +32,55 @@ namespace hex {
|
||||
|
||||
namespace ImHexApi::HexEditor {
|
||||
|
||||
static std::map<u32, ImHexApi::HexEditor::Highlighting> s_highlights;
|
||||
|
||||
Highlighting::Highlighting(Region region, color_t color, const std::string &tooltip)
|
||||
: m_region(region), m_color(color), m_tooltip(tooltip) {
|
||||
Highlighting::Highlighting(Region region, color_t color)
|
||||
: m_region(region), m_color(color) {
|
||||
}
|
||||
|
||||
u32 addHighlight(const Region ®ion, color_t color, std::string tooltip) {
|
||||
auto id = s_highlights.size();
|
||||
Tooltip::Tooltip(Region region, std::string value, color_t color) : m_region(region), m_value(std::move(value)), m_color(color) {
|
||||
|
||||
s_highlights.insert({
|
||||
id, Highlighting {region, color, tooltip}
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
|
||||
static std::map<u32, Highlighting> s_backgroundHighlights;
|
||||
std::map<u32, Highlighting> &getBackgroundHighlights() {
|
||||
return s_backgroundHighlights;
|
||||
}
|
||||
|
||||
static std::map<u32, HighlightingFunction> s_backgroundHighlightingFunctions;
|
||||
std::map<u32, HighlightingFunction> &getBackgroundHighlightingFunctions() {
|
||||
return s_backgroundHighlightingFunctions;
|
||||
}
|
||||
|
||||
static std::map<u32, Highlighting> s_foregroundHighlights;
|
||||
std::map<u32, Highlighting> &getForegroundHighlights() {
|
||||
return s_foregroundHighlights;
|
||||
}
|
||||
|
||||
static std::map<u32, HighlightingFunction> s_foregroundHighlightingFunctions;
|
||||
std::map<u32, HighlightingFunction> &getForegroundHighlightingFunctions() {
|
||||
return s_foregroundHighlightingFunctions;
|
||||
}
|
||||
|
||||
static std::map<u32, Tooltip> s_tooltips;
|
||||
std::map<u32, Tooltip> &getTooltips() {
|
||||
return s_tooltips;
|
||||
}
|
||||
|
||||
static std::map<u32, TooltipFunction> s_tooltipFunctions;
|
||||
std::map<u32, TooltipFunction> &getTooltipFunctions() {
|
||||
return s_tooltipFunctions;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
u32 addBackgroundHighlight(const Region ®ion, color_t color) {
|
||||
static u32 id = 0;
|
||||
|
||||
id++;
|
||||
|
||||
impl::getBackgroundHighlights().insert({
|
||||
id, Highlighting {region, color}
|
||||
});
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
@@ -44,23 +88,101 @@ namespace hex {
|
||||
return id;
|
||||
}
|
||||
|
||||
void removeHighlight(u32 id) {
|
||||
s_highlights.erase(id);
|
||||
void removeBackgroundHighlight(u32 id) {
|
||||
impl::getBackgroundHighlights().erase(id);
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
}
|
||||
|
||||
std::map<u32, Highlighting> &getHighlights() {
|
||||
return s_highlights;
|
||||
u32 addBackgroundHighlightingProvider(const impl::HighlightingFunction &function) {
|
||||
static u32 id = 0;
|
||||
|
||||
id++;
|
||||
|
||||
impl::getBackgroundHighlightingFunctions().insert({ id, function });
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
Region getSelection() {
|
||||
static Region selectedRegion;
|
||||
EventManager::subscribe<EventRegionSelected>([](const Region ®ion) {
|
||||
selectedRegion = region;
|
||||
void removeBackgroundHighlightingProvider(u32 id) {
|
||||
impl::getBackgroundHighlightingFunctions().erase(id);
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
}
|
||||
|
||||
u32 addForegroundHighlight(const Region ®ion, color_t color) {
|
||||
static u32 id = 0;
|
||||
|
||||
id++;
|
||||
|
||||
impl::getForegroundHighlights().insert({
|
||||
id, Highlighting {region, color}
|
||||
});
|
||||
|
||||
return selectedRegion;
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void removeForegroundHighlight(u32 id) {
|
||||
impl::getForegroundHighlights().erase(id);
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
}
|
||||
|
||||
u32 addForegroundHighlightingProvider(const impl::HighlightingFunction &function) {
|
||||
static u32 id = 0;
|
||||
|
||||
id++;
|
||||
|
||||
impl::getForegroundHighlightingFunctions().insert({ id, function });
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
void removeForegroundHighlightingProvider(u32 id) {
|
||||
impl::getForegroundHighlightingFunctions().erase(id);
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
}
|
||||
|
||||
static u32 tooltipId = 0;
|
||||
u32 addTooltip(Region region, std::string value, color_t color) {
|
||||
tooltipId++;
|
||||
impl::getTooltips().insert({ tooltipId, { region, std::move(value), color } });
|
||||
|
||||
return tooltipId;
|
||||
}
|
||||
|
||||
void removeTooltip(u32 id) {
|
||||
impl::getTooltips().erase(id);
|
||||
}
|
||||
|
||||
static u32 tooltipFunctionId;
|
||||
u32 addTooltipProvider(TooltipFunction function) {
|
||||
tooltipFunctionId++;
|
||||
impl::getTooltipFunctions().insert({ tooltipFunctionId, std::move(function) });
|
||||
|
||||
return tooltipFunctionId;
|
||||
}
|
||||
|
||||
void removeTooltipProvider(u32 id) {
|
||||
impl::getTooltipFunctions().erase(id);
|
||||
}
|
||||
|
||||
bool isSelectionValid() {
|
||||
return getSelection().has_value();
|
||||
}
|
||||
|
||||
std::optional<Region> getSelection() {
|
||||
std::optional<Region> selection;
|
||||
EventManager::post<QuerySelection>(selection);
|
||||
|
||||
return selection;
|
||||
}
|
||||
|
||||
void setSelection(const Region ®ion) {
|
||||
@@ -112,7 +234,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
bool isValid() {
|
||||
return !s_providers.empty();
|
||||
return !s_providers.empty() && s_currentProvider < s_providers.size();
|
||||
}
|
||||
|
||||
void add(prv::Provider *provider) {
|
||||
@@ -127,7 +249,7 @@ namespace hex {
|
||||
|
||||
s_providers.erase(it);
|
||||
|
||||
if (it - s_providers.begin() == s_currentProvider)
|
||||
if (it - s_providers.begin() == s_currentProvider && !s_providers.empty())
|
||||
setCurrentProvider(0);
|
||||
|
||||
delete provider;
|
||||
@@ -139,18 +261,20 @@ namespace hex {
|
||||
namespace ImHexApi::Tasks {
|
||||
|
||||
Task createTask(const std::string &unlocalizedName, u64 maxValue) {
|
||||
return Task(unlocalizedName, maxValue);
|
||||
return { unlocalizedName, maxValue };
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::function<void()>> s_deferredCalls;
|
||||
|
||||
void doLater(const std::function<void()> &function) {
|
||||
static std::mutex tasksMutex;
|
||||
std::scoped_lock lock(tasksMutex);
|
||||
|
||||
getDeferredCalls().push_back(function);
|
||||
}
|
||||
|
||||
std::vector<std::function<void()>> &getDeferredCalls() {
|
||||
return s_deferredCalls;
|
||||
static std::vector<std::function<void()>> deferredCalls;
|
||||
|
||||
return deferredCalls;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -176,7 +300,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
|
||||
static float s_globalScale;
|
||||
static float s_globalScale = 1.0;
|
||||
void setGlobalScale(float scale) {
|
||||
s_globalScale = scale;
|
||||
}
|
||||
@@ -189,6 +313,26 @@ namespace hex {
|
||||
s_programArguments.envp = envp;
|
||||
}
|
||||
|
||||
static bool s_borderlessWindowMode;
|
||||
void setBorderlessWindowMode(bool enabled) {
|
||||
s_borderlessWindowMode = enabled;
|
||||
}
|
||||
|
||||
static std::fs::path s_customFontPath;
|
||||
void setCustomFontPath(const std::fs::path &path) {
|
||||
s_customFontPath = path;
|
||||
}
|
||||
|
||||
static float s_fontSize;
|
||||
void setFontSize(float size) {
|
||||
s_fontSize = size;
|
||||
}
|
||||
|
||||
static std::string s_gpuVendor;
|
||||
void setGPUVendor(const std::string &vendor) {
|
||||
s_gpuVendor = vendor;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -225,11 +369,63 @@ namespace hex {
|
||||
return impl::s_mainDockSpaceId;
|
||||
}
|
||||
|
||||
bool isBorderlessWindowModeEnabled() {
|
||||
return impl::s_borderlessWindowMode;
|
||||
}
|
||||
|
||||
std::map<std::string, std::string> &getInitArguments() {
|
||||
static std::map<std::string, std::string> initArgs;
|
||||
|
||||
return initArgs;
|
||||
}
|
||||
|
||||
const std::fs::path &getCustomFontPath() {
|
||||
return impl::s_customFontPath;
|
||||
}
|
||||
|
||||
float getFontSize() {
|
||||
return impl::s_fontSize;
|
||||
}
|
||||
|
||||
|
||||
static Theme s_theme;
|
||||
static bool s_systemThemeDetection;
|
||||
|
||||
void setTheme(Theme theme) {
|
||||
s_theme = theme;
|
||||
|
||||
EventManager::post<EventSettingsChanged>();
|
||||
}
|
||||
|
||||
Theme getTheme() {
|
||||
return s_theme;
|
||||
}
|
||||
|
||||
|
||||
void enableSystemThemeDetection(bool enabled) {
|
||||
s_systemThemeDetection = enabled;
|
||||
|
||||
EventManager::post<EventSettingsChanged>();
|
||||
}
|
||||
|
||||
bool usesSystemThemeDetection() {
|
||||
return s_systemThemeDetection;
|
||||
}
|
||||
|
||||
|
||||
static std::vector<std::fs::path> s_additionalFolderPaths;
|
||||
const std::vector<std::fs::path> &getAdditionalFolderPaths() {
|
||||
return s_additionalFolderPaths;
|
||||
}
|
||||
|
||||
void setAdditionalFolderPaths(const std::vector<std::fs::path> &paths) {
|
||||
s_additionalFolderPaths = paths;
|
||||
}
|
||||
|
||||
|
||||
const std::string &getGPUVendor() {
|
||||
return impl::s_gpuVendor;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace hex {
|
||||
std::map<std::string, std::string> LangEntry::s_currStrings;
|
||||
|
||||
LanguageDefinition::LanguageDefinition(std::initializer_list<std::pair<std::string, std::string>> entries) {
|
||||
for (auto pair : entries)
|
||||
for (const auto &pair : entries)
|
||||
this->m_entries.insert(pair);
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
LangEntry::LangEntry(const char *unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
|
||||
LangEntry::LangEntry(const std::string &unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
|
||||
LangEntry::LangEntry(std::string unlocalizedString) : m_unlocalizedString(std::move(unlocalizedString)) { }
|
||||
LangEntry::LangEntry(std::string_view unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
|
||||
|
||||
LangEntry::operator std::string() const {
|
||||
|
||||
@@ -3,19 +3,28 @@
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <dlfcn.h>
|
||||
#include <system_error>
|
||||
|
||||
namespace hex {
|
||||
|
||||
Plugin::Plugin(const fs::path &path) : m_path(path) {
|
||||
this->m_handle = dlopen(path.string().c_str(), RTLD_LAZY);
|
||||
Plugin::Plugin(const std::fs::path &path) : m_path(path) {
|
||||
#if defined(OS_WINDOWS)
|
||||
this->m_handle = LoadLibraryW(path.c_str());
|
||||
|
||||
if (this->m_handle == nullptr) {
|
||||
log::error("dlopen failed: {}", dlerror());
|
||||
return;
|
||||
}
|
||||
if (this->m_handle == nullptr) {
|
||||
log::error("LoadLibraryW failed: {}!", std::system_category().message(::GetLastError()));
|
||||
return;
|
||||
}
|
||||
#else
|
||||
this->m_handle = dlopen(path.string().c_str(), RTLD_LAZY);
|
||||
|
||||
auto pluginName = fs::path(path).stem().string();
|
||||
if (this->m_handle == nullptr) {
|
||||
log::error("dlopen failed: {}!", dlerror());
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
auto pluginName = std::fs::path(path).stem().string();
|
||||
|
||||
this->m_initializePluginFunction = getPluginFunction<InitializePluginFunc>("initializePlugin");
|
||||
this->m_getPluginNameFunction = getPluginFunction<GetPluginNameFunc>("getPluginName");
|
||||
@@ -49,8 +58,13 @@ namespace hex {
|
||||
}
|
||||
|
||||
Plugin::~Plugin() {
|
||||
if (this->m_handle != nullptr)
|
||||
dlclose(this->m_handle);
|
||||
#if defined(OS_WINDOWS)
|
||||
if (this->m_handle != nullptr)
|
||||
FreeLibrary(this->m_handle);
|
||||
#else
|
||||
if (this->m_handle != nullptr)
|
||||
dlclose(this->m_handle);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Plugin::initializePlugin() const {
|
||||
@@ -110,7 +124,7 @@ namespace hex {
|
||||
return false;
|
||||
}
|
||||
|
||||
const fs::path &Plugin::getPath() const {
|
||||
const std::fs::path &Plugin::getPath() const {
|
||||
return this->m_path;
|
||||
}
|
||||
|
||||
@@ -120,22 +134,26 @@ namespace hex {
|
||||
|
||||
|
||||
void *Plugin::getPluginFunction(const std::string &symbol) {
|
||||
return dlsym(this->m_handle, symbol.c_str());
|
||||
#if defined(OS_WINDOWS)
|
||||
return reinterpret_cast<void *>(GetProcAddress(this->m_handle, symbol.c_str()));
|
||||
#else
|
||||
return dlsym(this->m_handle, symbol.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
fs::path PluginManager::s_pluginFolder;
|
||||
std::fs::path PluginManager::s_pluginFolder;
|
||||
std::vector<Plugin> PluginManager::s_plugins;
|
||||
|
||||
bool PluginManager::load(const fs::path &pluginFolder) {
|
||||
bool PluginManager::load(const std::fs::path &pluginFolder) {
|
||||
if (!fs::exists(pluginFolder))
|
||||
return false;
|
||||
|
||||
PluginManager::s_pluginFolder = pluginFolder;
|
||||
|
||||
for (auto &pluginPath : fs::directory_iterator(pluginFolder)) {
|
||||
for (auto &pluginPath : std::fs::directory_iterator(pluginFolder)) {
|
||||
if (pluginPath.is_regular_file() && pluginPath.path().extension() == ".hexplug")
|
||||
PluginManager::s_plugins.emplace_back(pluginPath.path().string());
|
||||
PluginManager::s_plugins.emplace_back(pluginPath.path());
|
||||
}
|
||||
|
||||
if (PluginManager::s_plugins.empty())
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace hex::dp {
|
||||
return outputData.value();
|
||||
}
|
||||
|
||||
u64 Node::getIntegerOnInput(u32 index) {
|
||||
i64 Node::getIntegerOnInput(u32 index) {
|
||||
auto attribute = this->getConnectedInputAttribute(index);
|
||||
|
||||
if (attribute == nullptr)
|
||||
@@ -54,7 +54,7 @@ namespace hex::dp {
|
||||
if (outputData->size() < sizeof(u64))
|
||||
throw std::runtime_error("Not enough data provided for integer");
|
||||
|
||||
return *reinterpret_cast<u64 *>(outputData->data());
|
||||
return *reinterpret_cast<i64 *>(outputData->data());
|
||||
}
|
||||
|
||||
float Node::getFloatOnInput(u32 index) {
|
||||
@@ -77,10 +77,12 @@ namespace hex::dp {
|
||||
if (outputData->size() < sizeof(float))
|
||||
throw std::runtime_error("Not enough data provided for float");
|
||||
|
||||
return *reinterpret_cast<float *>(outputData->data());
|
||||
float result = 0;
|
||||
std::memcpy(&result, outputData->data(), sizeof(float));
|
||||
return result;
|
||||
}
|
||||
|
||||
void Node::setBufferOnOutput(u32 index, std::vector<u8> data) {
|
||||
void Node::setBufferOnOutput(u32 index, const std::vector<u8> &data) {
|
||||
if (index >= this->getAttributes().size())
|
||||
throw std::runtime_error("Attribute index out of bounds!");
|
||||
|
||||
@@ -92,7 +94,7 @@ namespace hex::dp {
|
||||
attribute.getOutputData() = data;
|
||||
}
|
||||
|
||||
void Node::setIntegerOnOutput(u32 index, u64 integer) {
|
||||
void Node::setIntegerOnOutput(u32 index, i64 integer) {
|
||||
if (index >= this->getAttributes().size())
|
||||
throw std::runtime_error("Attribute index out of bounds!");
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
|
||||
#include <mbedtls/version.h>
|
||||
#include <mbedtls/base64.h>
|
||||
@@ -15,11 +16,11 @@
|
||||
|
||||
#include <array>
|
||||
#include <span>
|
||||
#include <concepts>
|
||||
#include <functional>
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <bit>
|
||||
|
||||
#if MBEDTLS_VERSION_MAJOR <= 2
|
||||
|
||||
@@ -82,91 +83,90 @@ namespace hex::crypt {
|
||||
}
|
||||
}
|
||||
|
||||
template<size_t NumBits> requires (std::has_single_bit(NumBits))
|
||||
class Crc {
|
||||
// use reflected algorithm, so we reflect only if refin / refout is FALSE
|
||||
// mask values, 0b1 << 64 is UB, so use 0b10 << 63
|
||||
|
||||
public:
|
||||
using calc_type = uint64_t;
|
||||
constexpr Crc(u64 polynomial, u64 init, u64 xorOut, bool reflectInput, bool reflectOutput)
|
||||
: m_value(0x00), m_init(init & ((0b10ull << (NumBits - 1)) - 1)), m_xorOut(xorOut & ((0b10ull << (NumBits - 1)) - 1)),
|
||||
m_reflectInput(reflectInput), m_reflectOutput(reflectOutput),
|
||||
m_table([polynomial]() {
|
||||
auto reflectedPoly = reflect(polynomial & ((0b10ull << (NumBits - 1)) - 1), NumBits);
|
||||
std::array<uint64_t, 256> table = { 0 };
|
||||
|
||||
Crc(int bits, calc_type polynomial, calc_type init, calc_type xorout, bool refin, bool refout) : m_bits(bits),
|
||||
m_init(init & ((0b10ull << (bits - 1)) - 1)),
|
||||
m_xorout(xorout & ((0b10ull << (bits - 1)) - 1)),
|
||||
m_refin(refin),
|
||||
m_refout(refout),
|
||||
table([polynomial, bits]() {
|
||||
auto reflectedpoly = reflect(polynomial & ((0b10ull << (bits - 1)) - 1), bits);
|
||||
std::array<uint64_t, 256> table = { 0 };
|
||||
for (uint32_t i = 0; i < 256; i++) {
|
||||
uint64_t c = i;
|
||||
for (std::size_t j = 0; j < 8; j++) {
|
||||
if (c & 0b1)
|
||||
c = reflectedPoly ^ (c >> 1);
|
||||
else
|
||||
c >>= 1;
|
||||
}
|
||||
table[i] = c;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < 256; i++) {
|
||||
uint64_t c = i;
|
||||
for (std::size_t j = 0; j < 8; j++) {
|
||||
if (c & 0b1)
|
||||
c = reflectedpoly ^ (c >> 1);
|
||||
else
|
||||
c >>= 1;
|
||||
}
|
||||
table[i] = c;
|
||||
}
|
||||
|
||||
return table;
|
||||
}()) {
|
||||
return table;
|
||||
}()) {
|
||||
reset();
|
||||
};
|
||||
|
||||
void reset() {
|
||||
c = reflect(m_init, m_bits);
|
||||
constexpr void reset() {
|
||||
this->m_value = reflect(m_init, NumBits);
|
||||
}
|
||||
|
||||
void processBytes(const unsigned char *data, std::size_t size) {
|
||||
constexpr void processBytes(const unsigned char *data, std::size_t size) {
|
||||
for (std::size_t i = 0; i < size; i++) {
|
||||
unsigned char d;
|
||||
if (m_refin)
|
||||
d = data[i];
|
||||
u8 byte;
|
||||
if (this->m_reflectInput)
|
||||
byte = data[i];
|
||||
else
|
||||
d = reflect(data[i]);
|
||||
byte = reflect(data[i]);
|
||||
|
||||
c = table[(c ^ d) & 0xFFL] ^ (c >> 8);
|
||||
this->m_value = this->m_table[(this->m_value ^ byte) & 0xFFL] ^ (this->m_value >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
calc_type checksum() const {
|
||||
if (m_refout)
|
||||
return c ^ m_xorout;
|
||||
[[nodiscard]]
|
||||
constexpr u64 checksum() const {
|
||||
if (this->m_reflectOutput)
|
||||
return this->m_value ^ m_xorOut;
|
||||
else
|
||||
return reflect(c, m_bits) ^ m_xorout;
|
||||
return reflect(this->m_value, NumBits) ^ m_xorOut;
|
||||
}
|
||||
|
||||
private:
|
||||
const int m_bits;
|
||||
const calc_type m_init;
|
||||
const calc_type m_xorout;
|
||||
const bool m_refin;
|
||||
const bool m_refout;
|
||||
const std::array<uint64_t, 256> table;
|
||||
u64 m_value;
|
||||
|
||||
calc_type c;
|
||||
u64 m_init;
|
||||
u64 m_xorOut;
|
||||
bool m_reflectInput;
|
||||
bool m_reflectOutput;
|
||||
|
||||
std::array<uint64_t, 256> m_table;
|
||||
};
|
||||
|
||||
template<int bits>
|
||||
template<size_t NumBits>
|
||||
auto calcCrc(prv::Provider *data, u64 offset, std::size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut) {
|
||||
Crc crc(bits, polynomial, init, xorout, reflectIn, reflectOut);
|
||||
using Crc = Crc<NumBits>;
|
||||
Crc crc(polynomial, init, xorout, reflectIn, reflectOut);
|
||||
|
||||
processDataByChunks(data, offset, size, std::bind(&Crc::processBytes, &crc, _1, _2));
|
||||
|
||||
return crc.checksum();
|
||||
}
|
||||
|
||||
u16 crc8(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut) {
|
||||
return calcCrc<8>(data, offset, size, polynomial, init, xorout, reflectIn, reflectOut);
|
||||
u16 crc8(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorOut, bool reflectIn, bool reflectOut) {
|
||||
return calcCrc<8>(data, offset, size, polynomial, init, xorOut, reflectIn, reflectOut);
|
||||
}
|
||||
|
||||
u16 crc16(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut) {
|
||||
return calcCrc<16>(data, offset, size, polynomial, init, xorout, reflectIn, reflectOut);
|
||||
u16 crc16(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorOut, bool reflectIn, bool reflectOut) {
|
||||
return calcCrc<16>(data, offset, size, polynomial, init, xorOut, reflectIn, reflectOut);
|
||||
}
|
||||
|
||||
u32 crc32(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorout, bool reflectIn, bool reflectOut) {
|
||||
return calcCrc<32>(data, offset, size, polynomial, init, xorout, reflectIn, reflectOut);
|
||||
u32 crc32(prv::Provider *&data, u64 offset, size_t size, u32 polynomial, u32 init, u32 xorOut, bool reflectIn, bool reflectOut) {
|
||||
return calcCrc<32>(data, offset, size, polynomial, init, xorOut, reflectIn, reflectOut);
|
||||
}
|
||||
|
||||
|
||||
@@ -414,7 +414,7 @@ namespace hex::crypt {
|
||||
|
||||
std::string output(input.size() * 2, '\0');
|
||||
|
||||
for (int i = 0; i < input.size(); i++) {
|
||||
for (size_t i = 0; i < input.size(); i++) {
|
||||
output[2 * i + 0] = "0123456789ABCDEF"[input[i] / 16];
|
||||
output[2 * i + 1] = "0123456789ABCDEF"[input[i] % 16];
|
||||
}
|
||||
@@ -427,13 +427,15 @@ namespace hex::crypt {
|
||||
|
||||
if (input.empty())
|
||||
return {};
|
||||
if (key.size() > 256)
|
||||
return {};
|
||||
|
||||
mbedtls_cipher_context_t ctx;
|
||||
auto cipherInfo = mbedtls_cipher_info_from_type(type);
|
||||
|
||||
|
||||
mbedtls_cipher_setup(&ctx, cipherInfo);
|
||||
mbedtls_cipher_setkey(&ctx, key.data(), key.size() * 8, operation);
|
||||
mbedtls_cipher_setkey(&ctx, key.data(), static_cast<int>(key.size() * 8), operation);
|
||||
|
||||
std::array<u8, 16> nonceCounter = { 0 };
|
||||
std::copy(nonce.begin(), nonce.end(), nonceCounter.begin());
|
||||
|
||||
@@ -2,16 +2,13 @@
|
||||
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace hex {
|
||||
|
||||
EncodingFile::EncodingFile(Type type, const fs::path &path) {
|
||||
std::ifstream encodingFile(path.c_str());
|
||||
|
||||
EncodingFile::EncodingFile(Type type, const std::fs::path &path) {
|
||||
auto file = fs::File(path, fs::File::Mode::Read);
|
||||
switch (type) {
|
||||
case Type::Thingy:
|
||||
parseThingyFile(encodingFile);
|
||||
parseThingyFile(file);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@@ -34,22 +31,21 @@ namespace hex {
|
||||
return { ".", 1 };
|
||||
}
|
||||
|
||||
void EncodingFile::parseThingyFile(std::ifstream &content) {
|
||||
for (std::string line; std::getline(content, line);) {
|
||||
void EncodingFile::parseThingyFile(fs::File &file) {
|
||||
for (const auto &line : splitString(file.readString(), "\n")) {
|
||||
|
||||
std::string from, to;
|
||||
{
|
||||
auto delimiterPos = line.find('=', 0);
|
||||
auto delimiterPos = line.find('=');
|
||||
|
||||
if (delimiterPos == std::string::npos)
|
||||
continue;
|
||||
if (delimiterPos >= line.length())
|
||||
continue;
|
||||
|
||||
from = line.substr(0, delimiterPos);
|
||||
to = line.substr(delimiterPos + 1);
|
||||
|
||||
hex::trim(from);
|
||||
hex::trim(to);
|
||||
|
||||
if (from.empty()) continue;
|
||||
if (to.empty()) to = " ";
|
||||
}
|
||||
|
||||
@@ -1,16 +1,28 @@
|
||||
#include <hex/helpers/file.hpp>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace hex {
|
||||
namespace hex::fs {
|
||||
|
||||
File::File(const fs::path &path, Mode mode) noexcept : m_path(path) {
|
||||
if (mode == File::Mode::Read)
|
||||
this->m_file = fopen64(path.string().c_str(), "rb");
|
||||
else if (mode == File::Mode::Write)
|
||||
this->m_file = fopen64(path.string().c_str(), "r+b");
|
||||
File::File(const std::fs::path &path, Mode mode) noexcept : m_path(path) {
|
||||
#if defined(OS_WINDOWS)
|
||||
if (mode == File::Mode::Read)
|
||||
this->m_file = _wfopen(path.c_str(), L"rb");
|
||||
else if (mode == File::Mode::Write)
|
||||
this->m_file = _wfopen(path.c_str(), L"r+b");
|
||||
|
||||
if (mode == File::Mode::Create || (mode == File::Mode::Write && this->m_file == nullptr))
|
||||
this->m_file = fopen64(path.string().c_str(), "w+b");
|
||||
if (mode == File::Mode::Create || (mode == File::Mode::Write && this->m_file == nullptr))
|
||||
this->m_file = _wfopen(path.c_str(), L"w+b");
|
||||
#else
|
||||
if (mode == File::Mode::Read)
|
||||
this->m_file = fopen64(path.string().c_str(), "rb");
|
||||
else if (mode == File::Mode::Write)
|
||||
this->m_file = fopen64(path.string().c_str(), "r+b");
|
||||
|
||||
if (mode == File::Mode::Create || (mode == File::Mode::Write && this->m_file == nullptr))
|
||||
this->m_file = fopen64(path.string().c_str(), "w+b");
|
||||
#endif
|
||||
}
|
||||
|
||||
File::File() noexcept {
|
||||
@@ -42,7 +54,7 @@ namespace hex {
|
||||
|
||||
void File::close() {
|
||||
if (isValid()) {
|
||||
fclose(this->m_file);
|
||||
std::fclose(this->m_file);
|
||||
this->m_file = nullptr;
|
||||
}
|
||||
}
|
||||
@@ -57,6 +69,8 @@ namespace hex {
|
||||
if (!isValid()) return {};
|
||||
|
||||
auto size = numBytes ?: getSize();
|
||||
if (size == 0) return {};
|
||||
|
||||
std::vector<u8> bytes(size);
|
||||
auto bytesRead = fread(bytes.data(), 1, bytes.size(), this->m_file);
|
||||
|
||||
@@ -72,25 +86,49 @@ namespace hex {
|
||||
|
||||
auto bytes = readBytes(numBytes);
|
||||
|
||||
return { reinterpret_cast<char *>(bytes.data()), bytes.size() };
|
||||
if (bytes.empty())
|
||||
return "";
|
||||
|
||||
auto cString = reinterpret_cast<const char *>(bytes.data());
|
||||
return { cString, std::min(bytes.size(), std::strlen(cString)) };
|
||||
}
|
||||
|
||||
std::u8string File::readU8String(size_t numBytes) {
|
||||
if (!isValid()) return {};
|
||||
|
||||
if (getSize() == 0) return {};
|
||||
|
||||
auto bytes = readBytes(numBytes);
|
||||
|
||||
if (bytes.empty())
|
||||
return u8"";
|
||||
|
||||
auto cString = reinterpret_cast<const char8_t *>(bytes.data());
|
||||
return { cString, std::min(bytes.size(), std::strlen(reinterpret_cast<const char*>(bytes.data()))) };
|
||||
}
|
||||
|
||||
void File::write(const u8 *buffer, size_t size) {
|
||||
if (!isValid()) return;
|
||||
|
||||
fwrite(buffer, size, 1, this->m_file);
|
||||
std::fwrite(buffer, size, 1, this->m_file);
|
||||
}
|
||||
|
||||
void File::write(const std::vector<u8> &bytes) {
|
||||
if (!isValid()) return;
|
||||
|
||||
fwrite(bytes.data(), 1, bytes.size(), this->m_file);
|
||||
std::fwrite(bytes.data(), 1, bytes.size(), this->m_file);
|
||||
}
|
||||
|
||||
void File::write(const std::string &string) {
|
||||
if (!isValid()) return;
|
||||
|
||||
fwrite(string.data(), string.size(), 1, this->m_file);
|
||||
std::fwrite(string.data(), string.size(), 1, this->m_file);
|
||||
}
|
||||
|
||||
void File::write(const std::u8string &string) {
|
||||
if (!isValid()) return;
|
||||
|
||||
std::fwrite(string.data(), string.size(), 1, this->m_file);
|
||||
}
|
||||
|
||||
size_t File::getSize() const {
|
||||
@@ -98,25 +136,35 @@ namespace hex {
|
||||
|
||||
auto startPos = ftello64(this->m_file);
|
||||
fseeko64(this->m_file, 0, SEEK_END);
|
||||
size_t size = ftello64(this->m_file);
|
||||
auto size = ftello64(this->m_file);
|
||||
fseeko64(this->m_file, startPos, SEEK_SET);
|
||||
|
||||
if (size < 0)
|
||||
return 0;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void File::setSize(u64 size) {
|
||||
if (!isValid()) return;
|
||||
|
||||
ftruncate64(fileno(this->m_file), size);
|
||||
auto result = ftruncate64(fileno(this->m_file), size);
|
||||
hex::unused(result);
|
||||
}
|
||||
|
||||
void File::flush() {
|
||||
fflush(this->m_file);
|
||||
std::fflush(this->m_file);
|
||||
}
|
||||
|
||||
void File::remove() {
|
||||
bool File::remove() {
|
||||
this->close();
|
||||
std::remove(this->m_path.string().c_str());
|
||||
return std::remove(this->m_path.string().c_str()) == 0;
|
||||
}
|
||||
|
||||
void File::disableBuffering() {
|
||||
if (!isValid()) return;
|
||||
|
||||
std::setvbuf(this->m_file, nullptr, _IONBF, 0);
|
||||
}
|
||||
|
||||
}
|
||||
331
lib/libimhex/source/helpers/fs.cpp
Normal file
331
lib/libimhex/source/helpers/fs.cpp
Normal file
@@ -0,0 +1,331 @@
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/helpers/fs_macos.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/intrinsics.hpp>
|
||||
|
||||
#include <xdg.hpp>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <shlobj.h>
|
||||
#elif defined(OS_LINUX)
|
||||
#include <xdg.hpp>
|
||||
#include <linux/limits.h>
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <filesystem>
|
||||
|
||||
namespace hex::fs {
|
||||
|
||||
std::optional<std::fs::path> getExecutablePath() {
|
||||
#if defined(OS_WINDOWS)
|
||||
std::wstring exePath(MAX_PATH, '\0');
|
||||
if (GetModuleFileNameW(nullptr, exePath.data(), exePath.length()) == 0)
|
||||
return std::nullopt;
|
||||
|
||||
return exePath;
|
||||
#elif defined(OS_LINUX)
|
||||
std::string exePath(PATH_MAX, '\0');
|
||||
if (readlink("/proc/self/exe", exePath.data(), PATH_MAX) < 0)
|
||||
return std::nullopt;
|
||||
|
||||
return exePath;
|
||||
#elif defined(OS_MACOS)
|
||||
std::string result;
|
||||
|
||||
{
|
||||
auto string = getMacExecutableDirectoryPath();
|
||||
result = string;
|
||||
macFree(string);
|
||||
}
|
||||
|
||||
return result;
|
||||
#else
|
||||
return std::nullopt;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool isPathWritable(const std::fs::path &path) {
|
||||
constexpr static auto TestFileName = "__imhex__tmp__";
|
||||
{
|
||||
File file(path / TestFileName, File::Mode::Read);
|
||||
if (file.isValid()) {
|
||||
if (!file.remove())
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
File file(path / TestFileName, File::Mode::Create);
|
||||
bool result = file.isValid();
|
||||
if (!file.remove())
|
||||
return false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath) {
|
||||
NFD::Init();
|
||||
|
||||
nfdchar_t *outPath;
|
||||
nfdresult_t result;
|
||||
switch (mode) {
|
||||
case DialogMode::Open:
|
||||
result = NFD::OpenDialog(outPath, validExtensions.data(), validExtensions.size(), defaultPath.c_str());
|
||||
break;
|
||||
case DialogMode::Save:
|
||||
result = NFD::SaveDialog(outPath, validExtensions.data(), validExtensions.size(), defaultPath.c_str());
|
||||
break;
|
||||
case DialogMode::Folder:
|
||||
result = NFD::PickFolder(outPath, defaultPath.c_str());
|
||||
break;
|
||||
default:
|
||||
hex::unreachable();
|
||||
}
|
||||
|
||||
if (result == NFD_OKAY) {
|
||||
callback(reinterpret_cast<const char8_t *>(outPath));
|
||||
NFD::FreePath(outPath);
|
||||
}
|
||||
|
||||
NFD::Quit();
|
||||
|
||||
return result == NFD_OKAY;
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting) {
|
||||
std::vector<std::fs::path> result;
|
||||
const auto exePath = getExecutablePath();
|
||||
auto userDirs = ImHexApi::System::getAdditionalFolderPaths();
|
||||
|
||||
[[maybe_unused]]
|
||||
auto addUserDirs = [&userDirs](auto &paths) {
|
||||
std::transform(userDirs.begin(), userDirs.end(), std::back_inserter(paths), [](auto &item) {
|
||||
return std::move(item);
|
||||
});
|
||||
};
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
std::fs::path appDataDir;
|
||||
{
|
||||
PWSTR wAppDataPath = nullptr;
|
||||
if (!SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &wAppDataPath)))
|
||||
throw std::runtime_error("Failed to get APPDATA folder path");
|
||||
|
||||
appDataDir = std::wstring(wAppDataPath);
|
||||
CoTaskMemFree(wAppDataPath);
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> paths = { appDataDir / "imhex" };
|
||||
|
||||
if (exePath)
|
||||
paths.push_back(exePath->parent_path());
|
||||
|
||||
switch (path) {
|
||||
case ImHexPath::Patterns:
|
||||
addUserDirs(paths);
|
||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||
return path / "patterns";
|
||||
});
|
||||
break;
|
||||
case ImHexPath::PatternsInclude:
|
||||
addUserDirs(paths);
|
||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||
return path / "includes";
|
||||
});
|
||||
break;
|
||||
case ImHexPath::Magic:
|
||||
addUserDirs(paths);
|
||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||
return path / "magic";
|
||||
});
|
||||
break;
|
||||
case ImHexPath::Python:
|
||||
addUserDirs(paths);
|
||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||
return path / "python";
|
||||
});
|
||||
break;
|
||||
case ImHexPath::Plugins:
|
||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||
return path / "plugins";
|
||||
});
|
||||
break;
|
||||
case ImHexPath::Yara:
|
||||
addUserDirs(paths);
|
||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||
return path / "yara";
|
||||
});
|
||||
break;
|
||||
case ImHexPath::Config:
|
||||
return { appDataDir / "imhex" / "config" };
|
||||
case ImHexPath::Resources:
|
||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||
return path / "resources";
|
||||
});
|
||||
break;
|
||||
case ImHexPath::Constants:
|
||||
addUserDirs(paths);
|
||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||
return path / "constants";
|
||||
});
|
||||
break;
|
||||
case ImHexPath::Encodings:
|
||||
addUserDirs(paths);
|
||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||
return path / "encodings";
|
||||
});
|
||||
break;
|
||||
case ImHexPath::Logs:
|
||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||
return path / "logs";
|
||||
});
|
||||
break;
|
||||
default:
|
||||
hex::unreachable();
|
||||
}
|
||||
#elif defined(OS_MACOS)
|
||||
// Get path to special directories
|
||||
std::string applicationSupportDir;
|
||||
{
|
||||
auto string = getMacApplicationSupportDirectoryPath();
|
||||
applicationSupportDir = string;
|
||||
macFree(string);
|
||||
}
|
||||
const std::fs::path applicationSupportDirPath(applicationSupportDir);
|
||||
|
||||
std::vector<std::fs::path> paths = { applicationSupportDirPath };
|
||||
|
||||
if (exePath.has_value())
|
||||
paths.push_back(exePath.value());
|
||||
|
||||
switch (path) {
|
||||
case ImHexPath::Patterns:
|
||||
result.push_back((applicationSupportDirPath / "patterns").string());
|
||||
break;
|
||||
case ImHexPath::PatternsInclude:
|
||||
result.push_back((applicationSupportDirPath / "includes").string());
|
||||
break;
|
||||
case ImHexPath::Magic:
|
||||
result.push_back((applicationSupportDirPath / "magic").string());
|
||||
break;
|
||||
case ImHexPath::Python:
|
||||
result.push_back((applicationSupportDirPath / "python").string());
|
||||
break;
|
||||
case ImHexPath::Plugins:
|
||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||
return (path / "plugins").string();
|
||||
});
|
||||
break;
|
||||
case ImHexPath::Yara:
|
||||
result.push_back((applicationSupportDirPath / "yara").string());
|
||||
break;
|
||||
case ImHexPath::Config:
|
||||
result.push_back((applicationSupportDirPath / "config").string());
|
||||
break;
|
||||
case ImHexPath::Resources:
|
||||
result.push_back((applicationSupportDirPath / "resources").string());
|
||||
break;
|
||||
case ImHexPath::Constants:
|
||||
result.push_back((applicationSupportDirPath / "constants").string());
|
||||
break;
|
||||
case ImHexPath::Encodings:
|
||||
result.push_back((applicationSupportDirPath / "encodings").string());
|
||||
break;
|
||||
case ImHexPath::Logs:
|
||||
result.push_back((applicationSupportDirPath / "logs").string());
|
||||
break;
|
||||
default:
|
||||
hex::unreachable();
|
||||
}
|
||||
#else
|
||||
std::vector<std::fs::path> configDirs = xdg::ConfigDirs();
|
||||
std::vector<std::fs::path> dataDirs = xdg::DataDirs();
|
||||
|
||||
configDirs.push_back(xdg::ConfigHomeDir());
|
||||
dataDirs.push_back(xdg::DataHomeDir());
|
||||
|
||||
for (auto &dir : dataDirs)
|
||||
dir = dir / "imhex";
|
||||
|
||||
if (exePath && !exePath->empty())
|
||||
dataDirs.push_back(exePath->parent_path());
|
||||
|
||||
switch (path) {
|
||||
case ImHexPath::Patterns:
|
||||
addUserDirs(dataDirs);
|
||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "patterns").string(); });
|
||||
break;
|
||||
case ImHexPath::PatternsInclude:
|
||||
addUserDirs(dataDirs);
|
||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "includes").string(); });
|
||||
break;
|
||||
case ImHexPath::Magic:
|
||||
addUserDirs(dataDirs);
|
||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "magic").string(); });
|
||||
break;
|
||||
case ImHexPath::Python:
|
||||
addUserDirs(dataDirs);
|
||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p).string(); });
|
||||
break;
|
||||
case ImHexPath::Plugins:
|
||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "plugins").string(); });
|
||||
break;
|
||||
case ImHexPath::Yara:
|
||||
addUserDirs(dataDirs);
|
||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "yara").string(); });
|
||||
break;
|
||||
case ImHexPath::Config:
|
||||
std::transform(configDirs.begin(), configDirs.end(), std::back_inserter(result), [](auto p) { return (p / "imhex").string(); });
|
||||
break;
|
||||
case ImHexPath::Resources:
|
||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "resources").string(); });
|
||||
break;
|
||||
case ImHexPath::Constants:
|
||||
addUserDirs(dataDirs);
|
||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "constants").string(); });
|
||||
break;
|
||||
case ImHexPath::Encodings:
|
||||
addUserDirs(dataDirs);
|
||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "encodings").string(); });
|
||||
break;
|
||||
case ImHexPath::Logs:
|
||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "logs").string(); });
|
||||
break;
|
||||
default:
|
||||
hex::unreachable();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
if (!listNonExisting) {
|
||||
result.erase(std::remove_if(result.begin(), result.end(), [](const auto &path) {
|
||||
return !fs::isDirectory(path);
|
||||
}),
|
||||
result.end());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::fs::path toShortPath(const std::fs::path &path) {
|
||||
#if defined(OS_WINDOWS)
|
||||
size_t size = GetShortPathNameW(path.c_str(), nullptr, 0) * sizeof(TCHAR);
|
||||
if (size == 0)
|
||||
return path;
|
||||
|
||||
std::wstring newPath(size, 0x00);
|
||||
GetShortPathNameW(path.c_str(), newPath.data(), newPath.size());
|
||||
|
||||
return newPath;
|
||||
#else
|
||||
return path;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
44
lib/libimhex/source/helpers/fs_macos.m
Normal file
44
lib/libimhex/source/helpers/fs_macos.m
Normal file
@@ -0,0 +1,44 @@
|
||||
#if defined(OS_MACOS)
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <Foundation/Foundation.h>
|
||||
|
||||
char* getMacExecutableDirectoryPath() {
|
||||
@autoreleasepool {
|
||||
const char *pathString = [[[[[NSBundle mainBundle] executableURL] URLByDeletingLastPathComponent] path] UTF8String];
|
||||
|
||||
char *result = malloc(strlen(pathString) + 1);
|
||||
strcpy(result, pathString);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
char* getMacApplicationSupportDirectoryPath() {
|
||||
@autoreleasepool {
|
||||
NSError* error = nil;
|
||||
NSURL* dirUrl = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory
|
||||
inDomain:NSUserDomainMask
|
||||
appropriateForURL:nil
|
||||
create:YES
|
||||
error:&error];
|
||||
|
||||
if (error != nil) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const char *pathString = [[[dirUrl URLByAppendingPathComponent:(@"imhex")] path] UTF8String];
|
||||
|
||||
char *result = malloc(strlen(pathString) + 1);
|
||||
strcpy(result, pathString);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
void macFree(void *ptr) {
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user