mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-04-02 05:27:41 -05:00
Compare commits
180 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
54b31b8a55 | ||
|
|
93aa1247df | ||
|
|
fb4c21b97a | ||
|
|
d356993e33 | ||
|
|
cf017540e2 | ||
|
|
c776bb6c03 | ||
|
|
e7399d223d | ||
|
|
8aff20b374 | ||
|
|
3b8b95a22f | ||
|
|
2cb65aac72 | ||
|
|
0c8deecfc5 | ||
|
|
74f17fd638 | ||
|
|
f3f13ae4d3 | ||
|
|
daffa4e555 | ||
|
|
c618eec843 | ||
|
|
71a7ae70d0 | ||
|
|
c1a2697e42 | ||
|
|
d4dd57c7c8 | ||
|
|
9e3c6898ad | ||
|
|
b6d7fd6984 | ||
|
|
d8eb027c94 | ||
|
|
80d47b658e | ||
|
|
51f2b24daa | ||
|
|
fe86f69da3 | ||
|
|
2fb51d1a56 | ||
|
|
ca3b5b72ca | ||
|
|
3db8e2aec2 | ||
|
|
499b68b7ad | ||
|
|
2e3bb8e555 | ||
|
|
0c9eab70d5 | ||
|
|
0d3eaa5d86 | ||
|
|
c20634e093 | ||
|
|
5ee3b550bc | ||
|
|
831dac9b47 | ||
|
|
626c34dce8 | ||
|
|
ed67c20cba | ||
|
|
35c209c791 | ||
|
|
315109aa1f | ||
|
|
a57fa34f82 | ||
|
|
d1a2f7d6ed | ||
|
|
8382f68601 | ||
|
|
3aa1dd1e06 | ||
|
|
0571fe383c | ||
|
|
461c5eac3e | ||
|
|
e34f94bb79 | ||
|
|
071bae345e | ||
|
|
9f4625aa00 | ||
|
|
9837473810 | ||
|
|
9d3759c6cd | ||
|
|
6aa55eb056 | ||
|
|
c8b7f350ad | ||
|
|
b6b5045340 | ||
|
|
ab4f17a6f4 | ||
|
|
541f1d5550 | ||
|
|
12942a4e71 | ||
|
|
1a378381bd | ||
|
|
1354c913a4 | ||
|
|
c752fba1c4 | ||
|
|
d40a445f33 | ||
|
|
e0cae1dacb | ||
|
|
31a746f3fc | ||
|
|
b401059678 | ||
|
|
a30f49c75e | ||
|
|
e981fa53f3 | ||
|
|
4cd390ab02 | ||
|
|
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 |
28
.github/workflows/analysis.yml
vendored
28
.github/workflows/analysis.yml
vendored
@@ -3,11 +3,12 @@ name: "CodeQL"
|
|||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * *'
|
- cron: '0 0 * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
codeql:
|
codeql:
|
||||||
name: 🐛 CodeQL
|
name: 🐛 CodeQL
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
permissions:
|
permissions:
|
||||||
actions: read
|
actions: read
|
||||||
contents: read
|
contents: read
|
||||||
@@ -15,23 +16,29 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 🧰 Checkout
|
- name: 🧰 Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: ✋ Initialize CodeQL
|
- name: ✋ Initialize CodeQL
|
||||||
uses: github/codeql-action/init@v1
|
uses: github/codeql-action/init@v2
|
||||||
with:
|
with:
|
||||||
languages: 'cpp'
|
languages: 'cpp'
|
||||||
|
|
||||||
- name: 📜 Restore cache
|
- name: 📜 Restore ccache
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
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') }}
|
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
|
||||||
|
|
||||||
- name: ⬇️ Install dependencies
|
- name: ⬇️ Install dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -42,15 +49,16 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
CC=gcc-10 CXX=g++-10 cmake \
|
CC=gcc-12 CXX=g++-12 cmake \
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||||
|
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||||
..
|
..
|
||||||
make -j 4 install
|
make -j 4 install
|
||||||
|
|
||||||
- name: 🗯️ Perform CodeQL Analysis
|
- name: 🗯️ Perform CodeQL Analysis
|
||||||
uses: github/codeql-action/analyze@v1
|
uses: github/codeql-action/analyze@v2
|
||||||
253
.github/workflows/build.yml
vendored
253
.github/workflows/build.yml
vendored
@@ -2,7 +2,9 @@ name: Build
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
|
branches: ["*"]
|
||||||
pull_request:
|
pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
env:
|
env:
|
||||||
BUILD_TYPE: Release
|
BUILD_TYPE: Release
|
||||||
@@ -22,11 +24,33 @@ jobs:
|
|||||||
CCACHE_COMPRESS: "true"
|
CCACHE_COMPRESS: "true"
|
||||||
steps:
|
steps:
|
||||||
- name: 🧰 Checkout
|
- name: 🧰 Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
|
||||||
submodules: recursive
|
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
|
- name: 🟦 Install msys2
|
||||||
uses: msys2/setup-msys2@v2
|
uses: msys2/setup-msys2@v2
|
||||||
with:
|
with:
|
||||||
@@ -52,21 +76,6 @@ jobs:
|
|||||||
$USERPROFILE/.cargo/bin/rustup.exe target add x86_64-pc-windows-gnu
|
$USERPROFILE/.cargo/bin/rustup.exe target add x86_64-pc-windows-gnu
|
||||||
$USERPROFILE/.cargo/bin/rustup.exe default nightly
|
$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
|
- name: 🛠️ Build
|
||||||
run: |
|
run: |
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
@@ -84,20 +93,23 @@ jobs:
|
|||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||||
-DCMAKE_CXX_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/" \
|
-DRUST_PATH="$USERPROFILE/.cargo/bin/" \
|
||||||
|
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||||
..
|
..
|
||||||
mingw32-make -j4 install
|
mingw32-make -j4 install
|
||||||
cpack
|
cpack
|
||||||
|
|
||||||
- name: ⬆️ Upload Portable ZIP
|
- name: ⬆️ Upload Portable ZIP
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: Windows Portable ZIP
|
name: Windows Portable
|
||||||
path: |
|
path: |
|
||||||
build/install/*
|
build/install/*
|
||||||
|
|
||||||
- name: ⬆️ Upload Windows Installer
|
- name: ⬆️ Upload Windows Installer
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: Windows Installer
|
name: Windows Installer
|
||||||
path: |
|
path: |
|
||||||
@@ -105,71 +117,89 @@ jobs:
|
|||||||
|
|
||||||
# MacOS build
|
# MacOS build
|
||||||
macos:
|
macos:
|
||||||
runs-on: macos-11.0
|
runs-on: macos-11
|
||||||
name: 🍎 macOS 11.0
|
name: 🍎 macOS 11.0
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: 🧰 Checkout
|
- name: 🧰 Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
|
||||||
submodules: recursive
|
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
|
- name: ⬇️ Install dependencies
|
||||||
run: |
|
run: |
|
||||||
brew bundle --no-lock --file dist/Brewfile
|
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
|
- name: 🛠️ Build
|
||||||
run: |
|
run: |
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
CC=$(brew --prefix llvm)/bin/clang \
|
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
|
||||||
CXX=$(brew --prefix llvm)/bin/clang++ \
|
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" \
|
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
|
||||||
MACOSX_DEPLOYMENT_TARGET="10.15" \
|
MACOSX_DEPLOYMENT_TARGET="10.15" \
|
||||||
cmake \
|
cmake \
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DCREATE_BUNDLE=ON \
|
-DCREATE_BUNDLE=ON \
|
||||||
-DCREATE_PACKAGE=ON \
|
-DCREATE_PACKAGE=ON \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||||
|
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||||
..
|
..
|
||||||
make -j4 package
|
make -j4 package
|
||||||
|
|
||||||
- name: ⬆️ Upload DMG
|
- name: ⬆️ Upload DMG
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: macOS DMG
|
name: macOS DMG
|
||||||
path: build/*.dmg
|
path: build/*.dmg
|
||||||
|
|
||||||
# Linux build
|
# Linux build
|
||||||
linux:
|
linux:
|
||||||
runs-on: ubuntu-20.04
|
runs-on: ubuntu-22.04
|
||||||
name: 🐧 Ubuntu 20.04
|
name: 🐧 Ubuntu 22.04
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: 🧰 Checkout
|
- name: 🧰 Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: 📜 Restore cache
|
- name: 📜 Restore cache
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
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
|
.flatpak-builder
|
||||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.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
|
- name: ⬇️ Install dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -184,7 +214,7 @@ jobs:
|
|||||||
sudo apt install -y python3-pip python3-setuptools patchelf desktop-file-utils libgdk-pixbuf2.0-dev fakeroot strace fuse
|
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 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 chmod +x /usr/local/bin/appimagetool
|
||||||
sudo pip3 install appimage-builder
|
sudo pip3 install appimage-builder==1.0.0
|
||||||
|
|
||||||
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
|
||||||
sh rustup-init.sh -y --default-toolchain none
|
sh rustup-init.sh -y --default-toolchain none
|
||||||
@@ -197,17 +227,24 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
CC=gcc-11 CXX=g++-11 cmake \
|
CC=gcc-12 CXX=g++-12 cmake \
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||||
-DCMAKE_CXX_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/" \
|
-DRUST_PATH="$HOME/.cargo/bin/" \
|
||||||
|
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||||
..
|
..
|
||||||
make -j 4 install DESTDIR=AppDir
|
make -j 4 install DESTDIR=AppDir
|
||||||
|
|
||||||
|
- name: 📜 Set version variable
|
||||||
|
run: |
|
||||||
|
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||||
|
|
||||||
#- name: 📦 Bundle Flatpak
|
#- name: 📦 Bundle Flatpak
|
||||||
# run: |
|
# run: |
|
||||||
# sudo apt install flatpak flatpak-builder
|
# sudo apt install flatpak flatpak-builder
|
||||||
@@ -217,45 +254,125 @@ jobs:
|
|||||||
# flatpak-builder --jobs=4 --repo=imhex _flatpak dist/net.werwolv.ImHex.yaml --ccache --keep-build-dirs
|
# flatpak-builder --jobs=4 --repo=imhex _flatpak dist/net.werwolv.ImHex.yaml --ccache --keep-build-dirs
|
||||||
# flatpak build-bundle imhex imhex.flatpak net.werwolv.ImHex stable
|
# flatpak build-bundle imhex imhex.flatpak net.werwolv.ImHex stable
|
||||||
|
|
||||||
- name: ⬆️ Upload ELF
|
|
||||||
uses: actions/upload-artifact@v2
|
|
||||||
with:
|
|
||||||
name: Linux ELF
|
|
||||||
path: |
|
|
||||||
build/AppDir/*
|
|
||||||
|
|
||||||
- name: 📦 Bundle DEB
|
- name: 📦 Bundle DEB
|
||||||
run: |
|
run: |
|
||||||
cp -r build/DEBIAN build/AppDir
|
cp -r build/DEBIAN build/AppDir
|
||||||
dpkg-deb --build build/AppDir
|
dpkg-deb --build build/AppDir
|
||||||
mv build/AppDir.deb imhex.deb
|
mv build/AppDir.deb imhex-${{env.IMHEX_VERSION}}.deb
|
||||||
rm -rf build/AppDir/DEBIAN
|
rm -rf build/AppDir/DEBIAN
|
||||||
|
|
||||||
- name: 📦 Bundle AppImage
|
- name: 📦 Bundle AppImage
|
||||||
run: |
|
run: |
|
||||||
cd build
|
cd build
|
||||||
appimage-builder --recipe ../dist/AppImageBuilder.yml
|
appimage-builder --recipe ../dist/AppImageBuilder.yml
|
||||||
mv ImHex-AppImage-x86_64.AppImage ../imhex.AppImage
|
mv ImHex-AppImage-x86_64.AppImage ../imhex-${{env.IMHEX_VERSION}}.AppImage
|
||||||
cd ..
|
cd ..
|
||||||
|
|
||||||
#- name: ⬆️ Upload Flatpak
|
#- name: ⬆️ Upload Flatpak
|
||||||
# uses: actions/upload-artifact@v2
|
# uses: actions/upload-artifact@v3
|
||||||
# with:
|
# with:
|
||||||
# name: Linux Flatpak
|
# name: Linux Flatpak
|
||||||
# path: |
|
# path: |
|
||||||
# imhex.flatpak
|
# imhex.flatpak
|
||||||
|
|
||||||
- name: ⬆️ Upload DEB
|
- name: ⬆️ Upload DEB
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: Linux DEB
|
name: Linux DEB (Ubuntu 22.04)
|
||||||
path: |
|
path: '*.deb'
|
||||||
imhex.deb
|
|
||||||
|
|
||||||
- name: ⬆️ Upload AppImage
|
- name: ⬆️ Upload AppImage
|
||||||
uses: actions/upload-artifact@v2
|
uses: actions/upload-artifact@v3
|
||||||
with:
|
with:
|
||||||
name: Linux AppImage
|
name: Linux AppImage
|
||||||
path: |
|
path: '*.AppImage'
|
||||||
imhex.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/" \
|
||||||
|
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||||
|
..
|
||||||
|
make -j 4 install DESTDIR=installDir
|
||||||
|
|
||||||
|
- name: 📜 Set version variable
|
||||||
|
run: |
|
||||||
|
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: ✒️ Prepare PKGBUILD
|
||||||
|
run: |
|
||||||
|
cp dist/Arch/PKGBUILD build
|
||||||
|
sed -i 's/%version%/${{env.IMHEX_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.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst -C installDir .
|
||||||
|
|
||||||
|
chmod -R 777 .
|
||||||
|
|
||||||
|
sudo -u nobody makepkg
|
||||||
|
|
||||||
|
# Remplace the old file
|
||||||
|
rm imhex-${{env.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst
|
||||||
|
mv *.pkg.tar.zst imhex-${{env.IMHEX_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.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst
|
||||||
|
|
||||||
|
|||||||
112
.github/workflows/release.yml
vendored
Normal file
112
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
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 "IMHEX_VERSION=$project_version" >> $GITHUB_ENV
|
||||||
|
|
||||||
|
- name: 🗜️ Create tarball from sources with dependencies
|
||||||
|
run: tar --exclude-vcs -czvf 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.IMHEX_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.IMHEX_VERSION}}-ArchLinux.pkg.tar.zst | cut -d ' ' -f 1`
|
||||||
|
|
||||||
|
sed -i 's/%version%/${{env.IMHEX_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:
|
||||||
|
AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||||
|
if: "${{ env.AUR_SSH_PRIVATE_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.IMHEX_VERSION}}
|
||||||
|
ssh_keyscan_types: rsa,dsa,ecdsa,ed25519
|
||||||
|
|
||||||
|
- name: 🎫 Create PatternLanguage release
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
env:
|
||||||
|
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||||
|
with:
|
||||||
|
tag: ImHex-v${{env.IMHEX_VERSION}}
|
||||||
|
repo: PatternLanguage
|
||||||
|
token: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
|
||||||
|
- name: 🎫 Create ImHex-Patterns release
|
||||||
|
uses: ncipollo/release-action@v1
|
||||||
|
env:
|
||||||
|
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||||
|
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||||
|
with:
|
||||||
|
tag: ImHex-v${{env.IMHEX_VERSION}}
|
||||||
|
repo: ImHex-Patterns
|
||||||
|
token: ${{ secrets.RELEASE_TOKEN }}
|
||||||
25
.github/workflows/tests.yml
vendored
25
.github/workflows/tests.yml
vendored
@@ -5,11 +5,12 @@ on:
|
|||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
pull_request:
|
pull_request:
|
||||||
branches: [ master ]
|
branches: [ master ]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
tests:
|
tests:
|
||||||
name: 🧪 Unit Tests
|
name: 🧪 Unit Tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-22.04
|
||||||
permissions:
|
permissions:
|
||||||
actions: read
|
actions: read
|
||||||
contents: read
|
contents: read
|
||||||
@@ -17,18 +18,25 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: 🧰 Checkout
|
- name: 🧰 Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
|
|
||||||
- name: 📜 Restore cache
|
- name: 📜 Restore ccache
|
||||||
uses: actions/cache@v2
|
uses: actions/cache@v3
|
||||||
with:
|
with:
|
||||||
path: |
|
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') }}
|
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
|
||||||
|
|
||||||
- name: ⬇️ Install dependencies
|
- name: ⬇️ Install dependencies
|
||||||
run: |
|
run: |
|
||||||
@@ -39,13 +47,14 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
mkdir -p build
|
mkdir -p build
|
||||||
cd build
|
cd build
|
||||||
CC=gcc-10 CXX=g++-10 cmake \
|
CC=gcc-12 CXX=g++-12 cmake \
|
||||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||||
|
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||||
..
|
..
|
||||||
make -j4 unit_tests install
|
make -j4 unit_tests install
|
||||||
|
|
||||||
|
|||||||
3
.idea/vcs.xml
generated
3
.idea/vcs.xml
generated
@@ -2,9 +2,6 @@
|
|||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="VcsDirectoryMappings">
|
<component name="VcsDirectoryMappings">
|
||||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/imhex_patterns-src" vcs="Git" />
|
|
||||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/imhex_patterns-src/yara/official_rules" vcs="Git" />
|
|
||||||
<mapping directory="$PROJECT_DIR$/cmake-build-debug/_deps/imhex_patterns-src/yara/official_rules/utils/yara-forensics" vcs="Git" />
|
|
||||||
<mapping directory="$PROJECT_DIR$/lib/external/capstone" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$/lib/external/capstone" vcs="Git" />
|
||||||
<mapping directory="$PROJECT_DIR$/lib/external/curl" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$/lib/external/curl" vcs="Git" />
|
||||||
<mapping directory="$PROJECT_DIR$/lib/external/fmt" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$/lib/external/fmt" vcs="Git" />
|
||||||
|
|||||||
@@ -1,14 +1,18 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
# Updating the version here will update it throughout ImHex as well
|
# Updating the version here will update it throughout ImHex as well
|
||||||
set(IMHEX_VERSION "1.17.0")
|
file(READ "VERSION" IMHEX_VERSION)
|
||||||
project(imhex VERSION ${IMHEX_VERSION})
|
project(imhex VERSION ${IMHEX_VERSION})
|
||||||
|
message("Project version ${IMHEX_VERSION}")
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(IMHEX_BASE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
|
set(IMHEX_BASE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
|
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
|
||||||
include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
|
include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
|
||||||
|
|
||||||
|
option(IMHEX_OFFLINE_BUILD "Enable offline build" OFF)
|
||||||
|
option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of the ImHex-Patterns repo" OFF)
|
||||||
|
|
||||||
# Make sure project is configured correctly
|
# Make sure project is configured correctly
|
||||||
setDefaultBuiltTypeIfUnset()
|
setDefaultBuiltTypeIfUnset()
|
||||||
detectBadClone()
|
detectBadClone()
|
||||||
@@ -36,6 +40,3 @@ add_subdirectory(tests EXCLUDE_FROM_ALL)
|
|||||||
|
|
||||||
# Configure packaging
|
# Configure packaging
|
||||||
createPackage()
|
createPackage()
|
||||||
|
|
||||||
# Download and install all current files from the ImHex-Patterns repo
|
|
||||||
downloadImHexPatternsFiles()
|
|
||||||
96
README.md
96
README.md
@@ -122,108 +122,22 @@ To develop plugins for ImHex, use one of the following two templates projects to
|
|||||||
Nightlies are available via GitHub Actions [here](https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild).
|
Nightlies are available via GitHub Actions [here](https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild).
|
||||||
|
|
||||||
- Windows • __x86_64__
|
- Windows • __x86_64__
|
||||||
- [MSI](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Installer.zip)
|
- [Installer](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Installer.zip)
|
||||||
- [EXE](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Portable%20ZIP.zip)
|
- [Portable](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Portable%20ZIP.zip)
|
||||||
- MacOS • __x86_64__
|
- MacOS • __x86_64__
|
||||||
- [DMG](https://nightly.link/WerWolv/ImHex/workflows/build/master/macOS%20DMG.zip)
|
- [DMG](https://nightly.link/WerWolv/ImHex/workflows/build/master/macOS%20DMG.zip)
|
||||||
- Linux • __x86_64__
|
- 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)
|
- [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)
|
- [AppImage](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20AppImage.zip)
|
||||||
|
- [Arch Package](https://nightly.link/WerWolv/ImHex/workflows/build/master/ArchLinux%20.pkg.tar.zst.zip)
|
||||||
|
|
||||||
## Compiling
|
## 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.
|
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.
|
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
|
## Credits
|
||||||
|
|
||||||
### Contributors
|
### Contributors
|
||||||
@@ -231,6 +145,8 @@ 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
|
- [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
|
- [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
|
- [jam1garner](https://github.com/jam1garner) and [raytwo](https://github.com/raytwo) for their help with adding Rust support to plugins
|
||||||
|
- [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 :)
|
- Everybody else who has reported issues on Discord or GitHub that I had great conversations with :)
|
||||||
|
|
||||||
### Libraries
|
### Libraries
|
||||||
|
|||||||
@@ -70,19 +70,18 @@ macro(detectOS)
|
|||||||
set(CMAKE_INSTALL_BINDIR ".")
|
set(CMAKE_INSTALL_BINDIR ".")
|
||||||
set(CMAKE_INSTALL_LIBDIR ".")
|
set(CMAKE_INSTALL_LIBDIR ".")
|
||||||
set(PLUGINS_INSTALL_LOCATION "plugins")
|
set(PLUGINS_INSTALL_LOCATION "plugins")
|
||||||
set(MAGIC_INSTALL_LOCATION "magic")
|
|
||||||
elseif (APPLE)
|
elseif (APPLE)
|
||||||
add_compile_definitions(OS_MACOS)
|
add_compile_definitions(OS_MACOS)
|
||||||
set(CMAKE_INSTALL_BINDIR ".")
|
set(CMAKE_INSTALL_BINDIR ".")
|
||||||
set(CMAKE_INSTALL_LIBDIR ".")
|
set(CMAKE_INSTALL_LIBDIR ".")
|
||||||
set(PLUGINS_INSTALL_LOCATION "plugins")
|
set(PLUGINS_INSTALL_LOCATION "plugins")
|
||||||
set(MAGIC_INSTALL_LOCATION "magic")
|
enable_language(OBJC)
|
||||||
|
enable_language(OBJCXX)
|
||||||
elseif (UNIX AND NOT APPLE)
|
elseif (UNIX AND NOT APPLE)
|
||||||
add_compile_definitions(OS_LINUX)
|
add_compile_definitions(OS_LINUX)
|
||||||
set(CMAKE_INSTALL_BINDIR "bin")
|
set(CMAKE_INSTALL_BINDIR "bin")
|
||||||
set(CMAKE_INSTALL_LIBDIR "lib")
|
set(CMAKE_INSTALL_LIBDIR "lib")
|
||||||
set(PLUGINS_INSTALL_LOCATION "share/imhex/plugins")
|
set(PLUGINS_INSTALL_LOCATION "share/imhex/plugins")
|
||||||
set(MAGIC_INSTALL_LOCATION "share/imhex/magic")
|
|
||||||
else ()
|
else ()
|
||||||
message(FATAL_ERROR "Unknown / unsupported system!")
|
message(FATAL_ERROR "Unknown / unsupported system!")
|
||||||
endif()
|
endif()
|
||||||
@@ -133,14 +132,14 @@ macro(configurePackingResources)
|
|||||||
set(MACOSX_BUNDLE_INFO_STRING "WerWolv")
|
set(MACOSX_BUNDLE_INFO_STRING "WerWolv")
|
||||||
set(MACOSX_BUNDLE_BUNDLE_NAME "ImHex")
|
set(MACOSX_BUNDLE_BUNDLE_NAME "ImHex")
|
||||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
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_LONG_VERSION_STRING "${PROJECT_VERSION}-${GIT_COMMIT_HASH}")
|
||||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
|
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
|
||||||
set(MACOSX_BUNDLE_COPYRIGHT "Copyright © 2020 WerWolv and Thog. All rights reserved." )
|
set(MACOSX_BUNDLE_COPYRIGHT "Copyright © 2020 WerWolv and Thog. All rights reserved." )
|
||||||
if ("${CMAKE_GENERATOR}" STREQUAL "Xcode")
|
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 ()
|
else ()
|
||||||
set ( bundle_path "${CMAKE_BINARY_DIR}/imhex.app" )
|
set ( bundle_path "${CMAKE_BINARY_DIR}/ImHex.app" )
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
@@ -151,11 +150,11 @@ macro(createPackage)
|
|||||||
foreach (plugin IN LISTS PLUGINS)
|
foreach (plugin IN LISTS PLUGINS)
|
||||||
add_subdirectory("plugins/${plugin}")
|
add_subdirectory("plugins/${plugin}")
|
||||||
if (TARGET ${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)
|
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)
|
if (IS_RUST_PROJECT)
|
||||||
set_target_properties(${plugin} PROPERTIES CARGO_BUILD_TARGET_DIR ${CMAKE_BINARY_DIR}/plugins)
|
set_target_properties(${plugin} PROPERTIES CARGO_BUILD_TARGET_DIR ${CMAKE_BINARY_DIR}/plugins)
|
||||||
|
|
||||||
@@ -163,7 +162,6 @@ macro(createPackage)
|
|||||||
|
|
||||||
install(FILES "${PLUGIN_LOCATION}/../${plugin}.hexplug" DESTINATION "${PLUGINS_INSTALL_LOCATION}")
|
install(FILES "${PLUGIN_LOCATION}/../${plugin}.hexplug" DESTINATION "${PLUGINS_INSTALL_LOCATION}")
|
||||||
else ()
|
else ()
|
||||||
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
install(TARGETS ${plugin} RUNTIME DESTINATION ${PLUGINS_INSTALL_LOCATION})
|
install(TARGETS ${plugin} RUNTIME DESTINATION ${PLUGINS_INSTALL_LOCATION})
|
||||||
elseif (APPLE)
|
elseif (APPLE)
|
||||||
@@ -181,7 +179,6 @@ macro(createPackage)
|
|||||||
endif ()
|
endif ()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
|
||||||
set_target_properties(libimhex PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
set_target_properties(libimhex PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
@@ -218,10 +215,18 @@ macro(createPackage)
|
|||||||
)
|
)
|
||||||
endforeach()
|
endforeach()
|
||||||
]])
|
]])
|
||||||
|
|
||||||
|
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||||
|
downloadImHexPatternsFiles("./")
|
||||||
elseif(UNIX AND NOT APPLE)
|
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}/LICENSE DESTINATION ${CMAKE_INSTALL_PREFIX}/share/licenses/imhex)
|
||||||
install(FILES ${CMAKE_SOURCE_DIR}/dist/imhex.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
|
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 ${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()
|
endif()
|
||||||
|
|
||||||
if (CREATE_BUNDLE)
|
if (CREATE_BUNDLE)
|
||||||
@@ -234,20 +239,21 @@ macro(createPackage)
|
|||||||
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-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")
|
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(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
|
# Update library references to make the bundle portable
|
||||||
postprocess_bundle(imhex_all main)
|
postprocess_bundle(imhex_all main)
|
||||||
|
|
||||||
# Enforce DragNDrop packaging.
|
# Enforce DragNDrop packaging.
|
||||||
set(CPACK_GENERATOR "DragNDrop")
|
set(CPACK_GENERATOR "DragNDrop")
|
||||||
|
|
||||||
install(TARGETS main BUNDLE DESTINATION .)
|
|
||||||
else()
|
else()
|
||||||
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
if (CREATE_PACKAGE)
|
if (CREATE_PACKAGE)
|
||||||
include(apple)
|
include(apple)
|
||||||
include(CPack)
|
include(CPack)
|
||||||
@@ -283,18 +289,26 @@ macro(detectBadClone)
|
|||||||
endmacro()
|
endmacro()
|
||||||
|
|
||||||
|
|
||||||
function(downloadImHexPatternsFiles)
|
function(downloadImHexPatternsFiles dest)
|
||||||
FetchContent_Declare(
|
if (NOT IMHEX_OFFLINE_BUILD)
|
||||||
imhex_patterns
|
if (IMHEX_PATTERNS_PULL_MASTER)
|
||||||
GIT_REPOSITORY https://github.com/WerWolv/ImHex-Patterns.git
|
set(PATTERNS_BRANCH master)
|
||||||
GIT_TAG master
|
else ()
|
||||||
)
|
set(PATTERNS_BRANCH ImHex-v${IMHEX_VERSION})
|
||||||
|
endif ()
|
||||||
|
|
||||||
FetchContent_Populate(imhex_patterns)
|
FetchContent_Declare(
|
||||||
|
imhex_patterns
|
||||||
|
GIT_REPOSITORY https://github.com/WerWolv/ImHex-Patterns.git
|
||||||
|
GIT_TAG master
|
||||||
|
)
|
||||||
|
|
||||||
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic)
|
FetchContent_Populate(imhex_patterns)
|
||||||
foreach (FOLDER ${PATTERNS_FOLDERS_TO_INSTALL})
|
|
||||||
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION "./")
|
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic)
|
||||||
endforeach()
|
foreach (FOLDER ${PATTERNS_FOLDERS_TO_INSTALL})
|
||||||
|
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION ${dest})
|
||||||
|
endforeach ()
|
||||||
|
endif ()
|
||||||
|
|
||||||
endfunction()
|
endfunction()
|
||||||
66
dist/AppImageBuilder.yml
vendored
66
dist/AppImageBuilder.yml
vendored
@@ -1,21 +1,7 @@
|
|||||||
# appimage-builder recipe see https://appimage-builder.readthedocs.io for details
|
# appimage-builder recipe see https://appimage-builder.readthedocs.io for details
|
||||||
version: 1
|
version: 1
|
||||||
script:
|
|
||||||
- rm -rf AppDir | true
|
|
||||||
- CC=gcc-11 CXX=g++11 cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr
|
|
||||||
- make -j3 install DESTDIR=AppDir
|
|
||||||
- mv AppDir/usr/share/imhex/plugins AppDir/usr/bin/plugins
|
|
||||||
- mv AppDir/usr/constants AppDir/usr/bin/constants
|
|
||||||
- mv AppDir/usr/encodings AppDir/usr/bin/encodings
|
|
||||||
- mv AppDir/usr/includes AppDir/usr/bin/includes
|
|
||||||
- mv AppDir/usr/magic AppDir/usr/bin/magic
|
|
||||||
- mv AppDir/usr/patterns AppDir/usr/bin/patterns
|
|
||||||
- mkdir -p AppDir/usr/share/icons/hicolor/512x512
|
|
||||||
- cp AppDir/usr/share/pixmaps/imhex.png AppDir/usr/share/icons/hicolor/512x512/imhex.png
|
|
||||||
|
|
||||||
|
|
||||||
AppDir:
|
AppDir:
|
||||||
path: ./AppDir
|
path: .AppDir
|
||||||
app_info:
|
app_info:
|
||||||
id: imhex
|
id: imhex
|
||||||
name: ImHex
|
name: ImHex
|
||||||
@@ -28,18 +14,19 @@ AppDir:
|
|||||||
- amd64
|
- amd64
|
||||||
allow_unauthenticated: true
|
allow_unauthenticated: true
|
||||||
sources:
|
sources:
|
||||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish main restricted
|
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy main restricted
|
||||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish-updates main restricted
|
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates main restricted
|
||||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish universe
|
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy universe
|
||||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish-updates universe
|
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates universe
|
||||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish multiverse
|
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy multiverse
|
||||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish-updates multiverse
|
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates multiverse
|
||||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ impish-backports main restricted
|
- sourceline: deb http://.archive.ubuntu.com/ubuntu/ jammy-backports main restricted
|
||||||
universe multiverse
|
universe multiverse
|
||||||
- sourceline: deb http://security.ubuntu.com/ubuntu impish-security main restricted
|
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security main restricted
|
||||||
- sourceline: deb http://security.ubuntu.com/ubuntu impish-security universe
|
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security universe
|
||||||
- sourceline: deb http://security.ubuntu.com/ubuntu impish-security multiverse
|
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security multiverse
|
||||||
include:
|
include:
|
||||||
|
- librsvg2-common
|
||||||
- libbz2-1.0:amd64
|
- libbz2-1.0:amd64
|
||||||
- libcap2:amd64
|
- libcap2:amd64
|
||||||
- libdbus-1-3:amd64
|
- libdbus-1-3:amd64
|
||||||
@@ -49,12 +36,11 @@ AppDir:
|
|||||||
- libpcre3:amd64
|
- libpcre3:amd64
|
||||||
- libselinux1:amd64
|
- libselinux1:amd64
|
||||||
- libtinfo6:amd64
|
- libtinfo6:amd64
|
||||||
- yaru-theme-icon
|
|
||||||
files:
|
files:
|
||||||
include:
|
include:
|
||||||
- /lib/x86_64-linux-gnu/libGLX.so.0
|
- /lib/x86_64-linux-gnu/libGLX.so.0
|
||||||
- /lib/x86_64-linux-gnu/libGLdispatch.so.0
|
- /lib/x86_64-linux-gnu/libGLdispatch.so.0
|
||||||
- /lib/x86_64-linux-gnu/libLLVM-12.so.1
|
- /lib/x86_64-linux-gnu/libLLVM-13.so.1
|
||||||
- /lib/x86_64-linux-gnu/libOpenGL.so.0
|
- /lib/x86_64-linux-gnu/libOpenGL.so.0
|
||||||
- /lib/x86_64-linux-gnu/libX11.so.6
|
- /lib/x86_64-linux-gnu/libX11.so.6
|
||||||
- /lib/x86_64-linux-gnu/libXau.so.6
|
- /lib/x86_64-linux-gnu/libXau.so.6
|
||||||
@@ -82,7 +68,7 @@ AppDir:
|
|||||||
- /lib/x86_64-linux-gnu/libedit.so.2
|
- /lib/x86_64-linux-gnu/libedit.so.2
|
||||||
- /lib/x86_64-linux-gnu/libelf.so.1
|
- /lib/x86_64-linux-gnu/libelf.so.1
|
||||||
- /lib/x86_64-linux-gnu/libepoxy.so.0
|
- /lib/x86_64-linux-gnu/libepoxy.so.0
|
||||||
- /lib/x86_64-linux-gnu/libffi.so.7
|
- /lib/x86_64-linux-gnu/libffi.so.8
|
||||||
- /lib/x86_64-linux-gnu/libfontconfig.so.1
|
- /lib/x86_64-linux-gnu/libfontconfig.so.1
|
||||||
- /lib/x86_64-linux-gnu/libfreetype.so.6
|
- /lib/x86_64-linux-gnu/libfreetype.so.6
|
||||||
- /lib/x86_64-linux-gnu/libfribidi.so.0
|
- /lib/x86_64-linux-gnu/libfribidi.so.0
|
||||||
@@ -94,31 +80,41 @@ AppDir:
|
|||||||
- /lib/x86_64-linux-gnu/libglfw.so.3
|
- /lib/x86_64-linux-gnu/libglfw.so.3
|
||||||
- /lib/x86_64-linux-gnu/libglib-2.0.so.0
|
- /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/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/libgobject-2.0.so.0
|
||||||
- /lib/x86_64-linux-gnu/libgraphite2.so.3
|
- /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/libharfbuzz.so.0
|
||||||
- /lib/x86_64-linux-gnu/libicudata.so.67
|
- /lib/x86_64-linux-gnu/libhogweed.so.6
|
||||||
- /lib/x86_64-linux-gnu/libicuuc.so.67
|
- /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/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/liblz4.so.1
|
||||||
- /lib/x86_64-linux-gnu/libmagic.so.1
|
- /lib/x86_64-linux-gnu/libmagic.so.1
|
||||||
- /lib/x86_64-linux-gnu/libmbedcrypto.so.3
|
- /lib/x86_64-linux-gnu/libmbedcrypto.so.7
|
||||||
- /lib/x86_64-linux-gnu/libmbedtls.so.12
|
- /lib/x86_64-linux-gnu/libmbedtls.so.14
|
||||||
- /lib/x86_64-linux-gnu/libmbedx509.so.0
|
- /lib/x86_64-linux-gnu/libmbedx509.so.1
|
||||||
- /lib/x86_64-linux-gnu/libmd.so.0
|
- /lib/x86_64-linux-gnu/libmd.so.0
|
||||||
- /lib/x86_64-linux-gnu/libmount.so.1
|
- /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/libpango-1.0.so.0
|
||||||
- /lib/x86_64-linux-gnu/libpangocairo-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/libpangoft2-1.0.so.0
|
||||||
- /lib/x86_64-linux-gnu/libpcre2-8.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/libpixman-1.so.0
|
||||||
- /lib/x86_64-linux-gnu/libpng16.so.16
|
- /lib/x86_64-linux-gnu/libpng16.so.16
|
||||||
- /lib/x86_64-linux-gnu/libpython3.8.so.1.0
|
- /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/libsensors.so.5
|
||||||
- /lib/x86_64-linux-gnu/libstdc++.so.6
|
- /lib/x86_64-linux-gnu/libstdc++.so.6
|
||||||
- /lib/x86_64-linux-gnu/libsystemd.so.0
|
- /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/libthai.so.0
|
||||||
|
- /lib/x86_64-linux-gnu/libunistring.so.2
|
||||||
- /lib/x86_64-linux-gnu/libuuid.so.1
|
- /lib/x86_64-linux-gnu/libuuid.so.1
|
||||||
- /lib/x86_64-linux-gnu/libvulkan.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-client.so.0
|
||||||
|
|||||||
39
dist/Arch/PKGBUILD
vendored
Normal file
39
dist/Arch/PKGBUILD
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# 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 dbus xdg-desktop-portal)
|
||||||
|
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
|
||||||
|
cp -r $srcdir/usr/share/{applications,licenses} $pkgdir/usr/share
|
||||||
|
install -d $pkgdir/usr/share
|
||||||
|
}
|
||||||
4
dist/Brewfile
vendored
4
dist/Brewfile
vendored
@@ -7,6 +7,4 @@ brew "python3"
|
|||||||
brew "freetype2"
|
brew "freetype2"
|
||||||
brew "libmagic"
|
brew "libmagic"
|
||||||
brew "pkg-config"
|
brew "pkg-config"
|
||||||
|
brew "gcc@12"
|
||||||
# TODO: Remove this when XCode version of clang will support the same level as LLVM 10
|
|
||||||
brew "llvm"
|
|
||||||
|
|||||||
2
dist/DEBIAN/control.in
vendored
2
dist/DEBIAN/control.in
vendored
@@ -4,7 +4,7 @@ Section: editors
|
|||||||
Priority: optional
|
Priority: optional
|
||||||
Architecture: amd64
|
Architecture: amd64
|
||||||
License: GNU GPL-2
|
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, libdbus-1-3, xdg-desktop-portal
|
||||||
Maintainer: WerWolv <hey@werwolv.net>
|
Maintainer: WerWolv <hey@werwolv.net>
|
||||||
Description: ImHex Hex Editor
|
Description: ImHex Hex Editor
|
||||||
A Hex Editor for Reverse Engineers, Programmers and
|
A Hex Editor for Reverse Engineers, Programmers and
|
||||||
|
|||||||
11
dist/DEBIAN/imhex.desktop
vendored
11
dist/DEBIAN/imhex.desktop
vendored
@@ -1,11 +0,0 @@
|
|||||||
[Desktop Entry]
|
|
||||||
Name=ImHex
|
|
||||||
Comment=ImHex Hex Editor
|
|
||||||
GenericName=Hex Editor
|
|
||||||
Exec=/usr/bin/imhex %U
|
|
||||||
Icon=/usr/share/pixmaps/imhex.png
|
|
||||||
Type=Application
|
|
||||||
StartupNotify=true
|
|
||||||
Categories=GNOME;GTK;Development;
|
|
||||||
StartupWMClass=imhex
|
|
||||||
|
|
||||||
3
dist/Dockerfile
vendored
3
dist/Dockerfile
vendored
@@ -15,7 +15,8 @@ RUN pacman -S --needed --noconfirm \
|
|||||||
mbedtls \
|
mbedtls \
|
||||||
python3 \
|
python3 \
|
||||||
freetype2 \
|
freetype2 \
|
||||||
gtk3
|
dbus \
|
||||||
|
xdg-desktop-portal
|
||||||
|
|
||||||
# Clone ImHex
|
# Clone ImHex
|
||||||
RUN git clone https://github.com/WerWolv/ImHex --recurse-submodules /root/ImHex
|
RUN git clone https://github.com/WerWolv/ImHex --recurse-submodules /root/ImHex
|
||||||
|
|||||||
3
dist/ImHex-9999.ebuild
vendored
3
dist/ImHex-9999.ebuild
vendored
@@ -27,6 +27,7 @@ RDEPEND="${DEPEND}
|
|||||||
sys-apps/file
|
sys-apps/file
|
||||||
dev-libs/mbedtls
|
dev-libs/mbedtls
|
||||||
dev-cpp/nlohmann_json
|
dev-cpp/nlohmann_json
|
||||||
x11-libs/gtk+
|
dbus
|
||||||
|
xdg-desktop-portal
|
||||||
"
|
"
|
||||||
BDEPEND="${DEPEND}"
|
BDEPEND="${DEPEND}"
|
||||||
|
|||||||
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 msys2 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`
|
||||||
5
dist/get_deps_archlinux.sh
vendored
5
dist/get_deps_archlinux.sh
vendored
@@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env sh
|
#!/usr/bin/env sh
|
||||||
|
|
||||||
pacman -S --needed \
|
pacman -S $@ --needed \
|
||||||
cmake \
|
cmake \
|
||||||
gcc \
|
gcc \
|
||||||
lld \
|
lld \
|
||||||
@@ -9,4 +9,5 @@ pacman -S --needed \
|
|||||||
mbedtls \
|
mbedtls \
|
||||||
python3 \
|
python3 \
|
||||||
freetype2 \
|
freetype2 \
|
||||||
gtk3
|
dbus \
|
||||||
|
xdg-desktop-portal
|
||||||
|
|||||||
14
dist/get_deps_debian.sh
vendored
14
dist/get_deps_debian.sh
vendored
@@ -1,9 +1,5 @@
|
|||||||
#!/usr/bin/env sh
|
#!/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.
|
# Install pkgconf (adds minimum dependencies) only if the equivalent pkf-config is not already installed.
|
||||||
if ! which pkg-config
|
if ! which pkg-config
|
||||||
then
|
then
|
||||||
@@ -12,8 +8,8 @@ fi
|
|||||||
|
|
||||||
apt install -y \
|
apt install -y \
|
||||||
build-essential \
|
build-essential \
|
||||||
gcc-11 \
|
gcc-12 \
|
||||||
g++-11 \
|
g++-12 \
|
||||||
lld \
|
lld \
|
||||||
${PKGCONF:-} \
|
${PKGCONF:-} \
|
||||||
cmake \
|
cmake \
|
||||||
@@ -25,7 +21,5 @@ apt install -y \
|
|||||||
libmbedtls-dev \
|
libmbedtls-dev \
|
||||||
python3-dev \
|
python3-dev \
|
||||||
libfreetype-dev \
|
libfreetype-dev \
|
||||||
libgtk-3-dev \
|
libdbus-1-dev \
|
||||||
|
xdg-desktop-portal
|
||||||
echo "Please consider this before running cmake (useful on e.g. Ubuntu 20.04):"
|
|
||||||
echo "export CXX=g++-11"
|
|
||||||
|
|||||||
3
dist/get_deps_fedora.sh
vendored
3
dist/get_deps_fedora.sh
vendored
@@ -10,4 +10,5 @@ dnf install \
|
|||||||
mbedtls-devel \
|
mbedtls-devel \
|
||||||
python-devel \
|
python-devel \
|
||||||
freetype-devel \
|
freetype-devel \
|
||||||
gtk3-devel
|
dbus \
|
||||||
|
xdg-desktop-portal
|
||||||
|
|||||||
5
dist/imhex.desktop
vendored
5
dist/imhex.desktop
vendored
@@ -2,10 +2,9 @@
|
|||||||
Name=ImHex
|
Name=ImHex
|
||||||
Comment=ImHex Hex Editor
|
Comment=ImHex Hex Editor
|
||||||
GenericName=Hex Editor
|
GenericName=Hex Editor
|
||||||
Exec=/usr/bin/imhex %U
|
Exec=imhex %U
|
||||||
Icon=imhex
|
Icon=imhex
|
||||||
Type=Application
|
Type=Application
|
||||||
StartupNotify=true
|
StartupNotify=true
|
||||||
Categories=GNOME;GTK;Development;
|
Categories=Development;IDE;
|
||||||
StartupWMClass=imhex
|
StartupWMClass=imhex
|
||||||
|
|
||||||
|
|||||||
2
lib/external/curl
vendored
2
lib/external/curl
vendored
Submodule lib/external/curl updated: 64db5c575d...45ac4d0194
2
lib/external/fmt
vendored
2
lib/external/fmt
vendored
Submodule lib/external/fmt updated: bc654faf82...c4ee726532
8
lib/external/imgui/CMakeLists.txt
vendored
8
lib/external/imgui/CMakeLists.txt
vendored
@@ -32,14 +32,14 @@ add_library(imgui OBJECT
|
|||||||
source/implot_items.cpp
|
source/implot_items.cpp
|
||||||
source/implot_demo.cpp
|
source/implot_demo.cpp
|
||||||
|
|
||||||
fonts/fontawesome_font.c
|
source/fonts/fontawesome_font.c
|
||||||
fonts/codicons_font.c
|
source/fonts/codicons_font.c
|
||||||
fonts/unifont_font.c
|
source/fonts/unifont_font.c
|
||||||
)
|
)
|
||||||
|
|
||||||
add_compile_definitions(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
add_compile_definitions(IMGUI_IMPL_OPENGL_LOADER_GLAD)
|
||||||
|
|
||||||
target_include_directories(imgui PUBLIC include fonts ${CMAKE_CURRENT_SOURCE_DIR} ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS})
|
target_include_directories(imgui PUBLIC include ${FREETYPE_INCLUDE_DIRS} ${GLFW_INCLUDE_DIRS})
|
||||||
|
|
||||||
target_link_directories(imgui PUBLIC ${GLFW_LIBRARY_DIRS})
|
target_link_directories(imgui PUBLIC ${GLFW_LIBRARY_DIRS})
|
||||||
|
|
||||||
|
|||||||
805
lib/external/imgui/include/imgui_memory_editor.h
vendored
805
lib/external/imgui/include/imgui_memory_editor.h
vendored
@@ -1,805 +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 <hex/helpers/logger.hpp>
|
|
||||||
#include <hex/ui/imgui_imhex_extensions.h>
|
|
||||||
|
|
||||||
#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::TextFormatted("{:02X}", 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);
|
|
||||||
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 != (size_t)-1) {
|
|
||||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_UpArrow)) && DataPreviewAddr >= (size_t)Cols) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr - Cols; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
|
||||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_DownArrow)) && DataPreviewAddr < mem_size - Cols) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr + Cols; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
|
||||||
else if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_LeftArrow)) && DataPreviewAddr > 0) { DataPreviewAddr = data_preview_addr_next = DataPreviewAddr - 1; if (!ImGui::GetIO().KeyShift) DataPreviewAddrEnd = DataPreviewAddr; }
|
|
||||||
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;
|
|
||||||
while (clipper.Step())
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::PopStyleVar(2);
|
|
||||||
ImGui::EndChild();
|
|
||||||
|
|
||||||
if (data_next && DataEditingAddr < mem_size)
|
|
||||||
{
|
|
||||||
DataEditingAddr = DataPreviewAddr = DataPreviewAddrEnd = 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);
|
|
||||||
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::Text("Error at line %d:", errorIt->first);
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
ImGui::Separator();
|
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::Text("%s", errorIt->second.c_str());
|
||||||
ImGui::PopStyleColor();
|
ImGui::PopStyleColor();
|
||||||
ImGui::EndTooltip();
|
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.
|
// 2016-10-15: Misc: Added a void* user_data parameter to Clipboard function handlers.
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "imgui.h"
|
||||||
|
#include "imgui_internal.h"
|
||||||
#include "imgui_impl_glfw.h"
|
#include "imgui_impl_glfw.h"
|
||||||
|
|
||||||
// GLFW
|
// GLFW
|
||||||
@@ -136,6 +137,51 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
|||||||
glfwSetClipboardString((GLFWwindow*)user_data, 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)
|
void ImGui_ImplGlfw_MouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
|
||||||
{
|
{
|
||||||
ImGui_ImplGlfw_Data* bd = ImGui_ImplGlfw_GetBackendData();
|
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_Y] = GLFW_KEY_Y;
|
||||||
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
|
io.KeyMap[ImGuiKey_Z] = GLFW_KEY_Z;
|
||||||
|
|
||||||
io.SetClipboardTextFn = ImGui_ImplGlfw_SetClipboardText;
|
#if defined(OS_WINDOWS)
|
||||||
io.GetClipboardTextFn = ImGui_ImplGlfw_GetClipboardText;
|
io.SetClipboardTextFn = ImGui_ImplWin_SetClipboardText;
|
||||||
io.ClipboardUserData = bd->Window;
|
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
|
// Create mouse cursors
|
||||||
// (By design, on X11 cursors are user configurable and some cursors may be missing. When a cursor doesn't exist,
|
// (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: f14e88a727...58757f6cad
2
lib/external/nativefiledialog
vendored
2
lib/external/nativefiledialog
vendored
Submodule lib/external/nativefiledialog updated: 28ade5a5cc...3311592818
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
Submodule lib/external/pattern_language updated: f276631e73...1b0de5e85b
2
lib/external/yara/yara
vendored
2
lib/external/yara/yara
vendored
Submodule lib/external/yara/yara updated: 136794355c...d5a7565a8b
8
lib/libimhex-rs/Cargo.lock
generated
8
lib/libimhex-rs/Cargo.lock
generated
@@ -568,9 +568,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex"
|
name = "regex"
|
||||||
version = "1.5.4"
|
version = "1.5.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
|
checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
@@ -579,9 +579,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.6.25"
|
version = "0.6.26"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
|
checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "remove_dir_all"
|
name = "remove_dir_all"
|
||||||
|
|||||||
@@ -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)
|
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_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)
|
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)
|
set_target_properties(nfd PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
@@ -123,14 +124,14 @@ set(LIBIMHEX_SOURCES
|
|||||||
source/helpers/patches.cpp
|
source/helpers/patches.cpp
|
||||||
source/helpers/project_file_handler.cpp
|
source/helpers/project_file_handler.cpp
|
||||||
source/helpers/encoding_file.cpp
|
source/helpers/encoding_file.cpp
|
||||||
source/helpers/loader_script_handler.cpp
|
|
||||||
source/helpers/logger.cpp
|
source/helpers/logger.cpp
|
||||||
|
source/helpers/tar.cpp
|
||||||
|
|
||||||
source/providers/provider.cpp
|
source/providers/provider.cpp
|
||||||
|
|
||||||
source/ui/imgui_imhex_extensions.cpp
|
source/ui/imgui_imhex_extensions.cpp
|
||||||
source/ui/view.cpp
|
source/ui/view.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
if (APPLE)
|
if (APPLE)
|
||||||
set(OSX_11_0_SDK_PATH /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk)
|
set(OSX_11_0_SDK_PATH /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk)
|
||||||
@@ -142,7 +143,9 @@ if (APPLE)
|
|||||||
endif ()
|
endif ()
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/fs_macos.mm)
|
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES}
|
||||||
|
source/helpers/fs_macos.m
|
||||||
|
source/helpers/utils_macos.m)
|
||||||
endif ()
|
endif ()
|
||||||
|
|
||||||
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||||
|
|||||||
@@ -3,30 +3,8 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include <hex/helpers/types.hpp>
|
||||||
#include <hex/helpers/intrinsics.hpp>
|
#include <hex/helpers/intrinsics.hpp>
|
||||||
|
|
||||||
constexpr static const auto ImHexApiURL = "https://api.werwolv.net/imhex";
|
constexpr static const auto ImHexApiURL = "https://api.werwolv.net/imhex";
|
||||||
constexpr static const auto GitHubApiURL = "https://api.github.com/repos/WerWolv/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;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,12 +10,16 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <unordered_map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <nlohmann/json_fwd.hpp>
|
#include <nlohmann/json_fwd.hpp>
|
||||||
|
|
||||||
|
using ImGuiDataType = int;
|
||||||
|
using ImGuiInputTextFlags = int;
|
||||||
|
|
||||||
namespace pl {
|
namespace pl {
|
||||||
class Evaluator;
|
class Evaluator;
|
||||||
}
|
}
|
||||||
@@ -152,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) {
|
void add(Args &&...args) {
|
||||||
return impl::add(new T(std::forward<Args>(args)...));
|
return impl::add(new T(std::forward<Args>(args)...));
|
||||||
}
|
}
|
||||||
@@ -230,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) {
|
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, Args &&...args) {
|
||||||
add(impl::Entry { unlocalizedCategory.c_str(), unlocalizedName.c_str(), [=] {
|
add(impl::Entry { unlocalizedCategory.c_str(), unlocalizedName.c_str(), [=] {
|
||||||
auto node = new T(std::forward<Args>(args)...);
|
auto node = new T(std::forward<Args>(args)...);
|
||||||
@@ -322,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 add(const std::string &unlocalizedName, bool addToList = true) {
|
||||||
(void)EventManager::subscribe<RequestCreateProvider>([expectedName = unlocalizedName](const std::string &name, hex::prv::Provider **provider) {
|
(void)EventManager::subscribe<RequestCreateProvider>([expectedName = unlocalizedName](const std::string &name, hex::prv::Provider **provider) {
|
||||||
if (name != expectedName) return;
|
if (name != expectedName) return;
|
||||||
@@ -378,6 +382,113 @@ namespace hex {
|
|||||||
std::vector<impl::Entry> &getEntries();
|
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)...));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -129,6 +129,12 @@ namespace hex {
|
|||||||
EVENT_DEF(RequestOpenPopup, std::string);
|
EVENT_DEF(RequestOpenPopup, std::string);
|
||||||
EVENT_DEF(RequestCreateProvider, std::string, hex::prv::Provider **);
|
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> &);
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -6,10 +6,13 @@
|
|||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
#include <variant>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
#include <hex/helpers/concepts.hpp>
|
#include <hex/helpers/concepts.hpp>
|
||||||
#include <hex/api/task.hpp>
|
#include <hex/api/task.hpp>
|
||||||
#include <hex/api/keybinding.hpp>
|
#include <hex/api/keybinding.hpp>
|
||||||
|
#include <hex/helpers/fs.hpp>
|
||||||
|
|
||||||
using ImGuiID = unsigned int;
|
using ImGuiID = unsigned int;
|
||||||
struct ImVec2;
|
struct ImVec2;
|
||||||
@@ -31,37 +34,69 @@ namespace hex {
|
|||||||
|
|
||||||
namespace HexEditor {
|
namespace HexEditor {
|
||||||
|
|
||||||
|
using TooltipFunction = std::function<void(u64, const u8*, size_t)>;
|
||||||
|
|
||||||
class Highlighting {
|
class Highlighting {
|
||||||
public:
|
public:
|
||||||
Highlighting() = default;
|
Highlighting() = default;
|
||||||
Highlighting(Region region, color_t color, std::string tooltip = "");
|
Highlighting(Region region, color_t color);
|
||||||
|
|
||||||
[[nodiscard]] const Region &getRegion() const { return this->m_region; }
|
[[nodiscard]] const Region &getRegion() const { return this->m_region; }
|
||||||
[[nodiscard]] const color_t &getColor() const { return this->m_color; }
|
[[nodiscard]] const color_t &getColor() const { return this->m_color; }
|
||||||
[[nodiscard]] const std::string &getTooltip() const { return this->m_tooltip; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Region m_region = {};
|
Region m_region = {};
|
||||||
color_t m_color = 0x00;
|
color_t m_color = 0x00;
|
||||||
std::string m_tooltip;
|
};
|
||||||
|
|
||||||
|
class Tooltip {
|
||||||
|
public:
|
||||||
|
Tooltip() = default;
|
||||||
|
Tooltip(Region region, std::string value, 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 &getValue() const { return this->m_value; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
Region m_region = {};
|
||||||
|
std::string m_value;
|
||||||
|
color_t m_color = 0x00;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
using HighlightingFunction = std::function<std::optional<Highlighting>(u64)>;
|
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t)>;
|
||||||
|
|
||||||
std::map<u32, Highlighting> &getHighlights();
|
std::map<u32, Highlighting> &getBackgroundHighlights();
|
||||||
std::map<u32, HighlightingFunction> &getHighlightingFunctions();
|
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 addHighlight(const Region ®ion, color_t color, const std::string &tooltip = "");
|
u32 addBackgroundHighlight(const Region ®ion, color_t color);
|
||||||
void removeHighlight(u32 id);
|
void removeBackgroundHighlight(u32 id);
|
||||||
|
|
||||||
u32 addHighlightingProvider(const impl::HighlightingFunction &function);
|
u32 addForegroundHighlight(const Region ®ion, color_t color);
|
||||||
void removeHighlightingProvider(u32 id);
|
void removeForegroundHighlight(u32 id);
|
||||||
|
|
||||||
Region getSelection();
|
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(const Region ®ion);
|
||||||
void setSelection(u64 address, size_t size);
|
void setSelection(u64 address, size_t size);
|
||||||
|
|
||||||
@@ -76,8 +111,6 @@ namespace hex {
|
|||||||
std::string comment;
|
std::string comment;
|
||||||
u32 color;
|
u32 color;
|
||||||
bool locked;
|
bool locked;
|
||||||
|
|
||||||
u32 highlightId;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void add(u64 address, size_t size, 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);
|
||||||
@@ -95,7 +128,7 @@ namespace hex {
|
|||||||
|
|
||||||
void add(prv::Provider *provider);
|
void add(prv::Provider *provider);
|
||||||
|
|
||||||
template<hex::derived_from<prv::Provider> T>
|
template<std::derived_from<prv::Provider> T>
|
||||||
void add(auto &&...args) {
|
void add(auto &&...args) {
|
||||||
add(new T(std::forward<decltype(args)>(args)...));
|
add(new T(std::forward<decltype(args)>(args)...));
|
||||||
}
|
}
|
||||||
@@ -126,6 +159,11 @@ namespace hex {
|
|||||||
void setProgramArguments(int argc, char **argv, char **envp);
|
void setProgramArguments(int argc, char **argv, char **envp);
|
||||||
|
|
||||||
void setBorderlessWindowMode(bool enabled);
|
void setBorderlessWindowMode(bool enabled);
|
||||||
|
|
||||||
|
void setCustomFontPath(const std::fs::path &path);
|
||||||
|
void setFontSize(float size);
|
||||||
|
|
||||||
|
void setGPUVendor(const std::string &vendor);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ProgramArguments {
|
struct ProgramArguments {
|
||||||
@@ -134,6 +172,12 @@ namespace hex {
|
|||||||
char **envp;
|
char **envp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class Theme {
|
||||||
|
Dark = 1,
|
||||||
|
Light = 2,
|
||||||
|
Classic = 3
|
||||||
|
};
|
||||||
|
|
||||||
const ProgramArguments &getProgramArguments();
|
const ProgramArguments &getProgramArguments();
|
||||||
|
|
||||||
float getTargetFPS();
|
float getTargetFPS();
|
||||||
@@ -149,6 +193,19 @@ namespace hex {
|
|||||||
|
|
||||||
std::map<std::string, std::string> &getInitArguments();
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,12 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#if defined(OS_WINDOWS)
|
||||||
|
#include <windows.h>
|
||||||
|
#else
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
struct ImGuiContext;
|
struct ImGuiContext;
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
@@ -39,7 +45,11 @@ namespace hex {
|
|||||||
using SetImGuiContextFunc = void (*)(ImGuiContext *);
|
using SetImGuiContextFunc = void (*)(ImGuiContext *);
|
||||||
using IsBuiltinPluginFunc = bool (*)();
|
using IsBuiltinPluginFunc = bool (*)();
|
||||||
|
|
||||||
void *m_handle = nullptr;
|
#if defined(OS_WINDOWS)
|
||||||
|
HMODULE m_handle = nullptr;
|
||||||
|
#else
|
||||||
|
void *m_handle = nullptr;
|
||||||
|
#endif
|
||||||
std::fs::path m_path;
|
std::fs::path m_path;
|
||||||
|
|
||||||
mutable bool m_initialized = false;
|
mutable bool m_initialized = false;
|
||||||
|
|||||||
@@ -5,151 +5,7 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
namespace hex {
|
#include <concepts>
|
||||||
|
|
||||||
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;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
@@ -159,11 +15,6 @@ namespace hex {
|
|||||||
template<typename T, size_t Size>
|
template<typename T, size_t Size>
|
||||||
concept has_size = sizeof(T) == Size;
|
concept has_size = sizeof(T) == Size;
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
namespace hex {
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class Cloneable {
|
class Cloneable {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -2,11 +2,22 @@
|
|||||||
|
|
||||||
#include <hex.hpp>
|
#include <hex.hpp>
|
||||||
|
|
||||||
#include <map>
|
// 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
|
||||||
#include <string_view>
|
#pragma GCC diagnostic push
|
||||||
#include <vector>
|
|
||||||
|
#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/fs.hpp>
|
||||||
|
#include <hex/helpers/file.hpp>
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
@@ -26,11 +37,11 @@ namespace hex {
|
|||||||
[[nodiscard]] bool valid() const { return this->m_valid; }
|
[[nodiscard]] bool valid() const { return this->m_valid; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void parseThingyFile(std::ifstream &content);
|
void parseThingyFile(fs::File &file);
|
||||||
|
|
||||||
bool m_valid = false;
|
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;
|
size_t m_longestSequence = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -47,10 +47,12 @@ namespace hex::fs {
|
|||||||
size_t readBuffer(u8 *buffer, size_t size);
|
size_t readBuffer(u8 *buffer, size_t size);
|
||||||
std::vector<u8> readBytes(size_t numBytes = 0);
|
std::vector<u8> readBytes(size_t numBytes = 0);
|
||||||
std::string readString(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 u8 *buffer, size_t size);
|
||||||
void write(const std::vector<u8> &bytes);
|
void write(const std::vector<u8> &bytes);
|
||||||
void write(const std::string &string);
|
void write(const std::string &string);
|
||||||
|
void write(const std::u8string &string);
|
||||||
|
|
||||||
[[nodiscard]] size_t getSize() const;
|
[[nodiscard]] size_t getSize() const;
|
||||||
void setSize(u64 size);
|
void setSize(u64 size);
|
||||||
|
|||||||
@@ -50,6 +50,12 @@ namespace hex::fs {
|
|||||||
return std::filesystem::remove(path, error) && !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]]
|
[[maybe_unused]]
|
||||||
static inline uintmax_t getFileSize(const std::fs::path &path) {
|
static inline uintmax_t getFileSize(const std::fs::path &path) {
|
||||||
std::error_code error;
|
std::error_code error;
|
||||||
@@ -61,6 +67,8 @@ namespace hex::fs {
|
|||||||
|
|
||||||
bool isPathWritable(const std::fs::path &path);
|
bool isPathWritable(const std::fs::path &path);
|
||||||
|
|
||||||
|
std::fs::path toShortPath(const std::fs::path &path);
|
||||||
|
|
||||||
enum class DialogMode
|
enum class DialogMode
|
||||||
{
|
{
|
||||||
Open,
|
Open,
|
||||||
|
|||||||
@@ -1,10 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#if defined(OS_MACOS)
|
|
||||||
#include <hex/helpers/fs.hpp>
|
|
||||||
|
|
||||||
namespace hex {
|
|
||||||
std::string getMacExecutableDirectoryPath();
|
|
||||||
std::string getMacApplicationSupportDirectoryPath();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
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
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <string_view>
|
|
||||||
|
|
||||||
#include <hex/helpers/fs.hpp>
|
|
||||||
|
|
||||||
struct _object;
|
|
||||||
typedef struct _object PyObject;
|
|
||||||
|
|
||||||
namespace hex {
|
|
||||||
|
|
||||||
namespace prv {
|
|
||||||
class Provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
class LoaderScript {
|
|
||||||
public:
|
|
||||||
LoaderScript() = delete;
|
|
||||||
|
|
||||||
static bool processFile(const std::fs::path &scriptPath);
|
|
||||||
|
|
||||||
static void setFilePath(const std::fs::path &filePath) { LoaderScript::s_filePath = filePath; }
|
|
||||||
static void setDataProvider(prv::Provider *provider) { LoaderScript::s_dataProvider = provider; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
static inline std::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);
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -44,11 +44,14 @@ namespace hex {
|
|||||||
std::future<Response<void>> downloadFile(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);
|
[[nodiscard]] std::string encode(const std::string &input);
|
||||||
|
[[nodiscard]] std::string decode(const std::string &input);
|
||||||
|
|
||||||
[[nodiscard]] float getProgress() const { return this->m_progress; }
|
[[nodiscard]] float getProgress() const { return this->m_progress; }
|
||||||
|
|
||||||
void cancel() { this->m_shouldCancel = true; }
|
void cancel() { this->m_shouldCancel = true; }
|
||||||
|
|
||||||
|
static void setProxy(const std::string &url);
|
||||||
|
|
||||||
private:
|
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 = {});
|
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();
|
std::optional<i32> execute();
|
||||||
@@ -62,6 +65,8 @@ namespace hex {
|
|||||||
std::mutex m_transmissionActive;
|
std::mutex m_transmissionActive;
|
||||||
float m_progress = 0.0F;
|
float m_progress = 0.0F;
|
||||||
bool m_shouldCancel = false;
|
bool m_shouldCancel = false;
|
||||||
|
|
||||||
|
static std::string s_proxyUrl;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -43,7 +43,7 @@ namespace hex {
|
|||||||
std::string encodeByteString(const std::vector<u8> &bytes);
|
std::string encodeByteString(const std::vector<u8> &bytes);
|
||||||
std::vector<u8> decodeByteString(const std::string &string);
|
std::vector<u8> decodeByteString(const std::string &string);
|
||||||
|
|
||||||
[[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const hex::unsigned_integral auto &value) {
|
[[nodiscard]] constexpr inline u64 extract(u8 from, u8 to, const std::unsigned_integral auto &value) {
|
||||||
if (from < to) std::swap(from, to);
|
if (from < to) std::swap(from, to);
|
||||||
|
|
||||||
using ValueType = std::remove_cvref_t<decltype(value)>;
|
using ValueType = std::remove_cvref_t<decltype(value)>;
|
||||||
@@ -72,6 +72,18 @@ namespace hex {
|
|||||||
return (value ^ mask) - mask;
|
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>
|
template<class... Ts>
|
||||||
struct overloaded : Ts... { using Ts::operator()...; };
|
struct overloaded : Ts... { using Ts::operator()...; };
|
||||||
template<class... Ts>
|
template<class... Ts>
|
||||||
@@ -188,6 +200,24 @@ namespace hex {
|
|||||||
return T(1) << bit_width(T(x - 1));
|
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>
|
template<typename T, typename... Args>
|
||||||
void moveToVector(std::vector<T> &buffer, T &&first, Args &&...rest) {
|
void moveToVector(std::vector<T> &buffer, T &&first, Args &&...rest) {
|
||||||
buffer.push_back(std::move(first));
|
buffer.push_back(std::move(first));
|
||||||
@@ -234,7 +264,7 @@ namespace hex {
|
|||||||
return result;
|
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";
|
if (number == 0) return "0";
|
||||||
|
|
||||||
std::string result;
|
std::string result;
|
||||||
@@ -287,6 +317,13 @@ namespace hex {
|
|||||||
return *value;
|
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();
|
bool isProcessElevated();
|
||||||
|
|
||||||
std::optional<std::string> getEnvironmentVariable(const std::string &env);
|
std::optional<std::string> getEnvironmentVariable(const std::string &env);
|
||||||
|
|||||||
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
|
||||||
232
lib/libimhex/include/hex/providers/buffered_reader.hpp
Normal file
232
lib/libimhex/include/hex/providers/buffered_reader.hpp
Normal file
@@ -0,0 +1,232 @@
|
|||||||
|
#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; };
|
||||||
|
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; };
|
||||||
|
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; };
|
||||||
|
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; };
|
||||||
|
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 = 0x00;
|
||||||
|
};
|
||||||
|
|
||||||
|
Iterator begin() {
|
||||||
|
return { this, this->m_baseAddress };
|
||||||
|
}
|
||||||
|
|
||||||
|
Iterator end() {
|
||||||
|
return { this, 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;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -35,6 +35,7 @@ namespace hex::prv {
|
|||||||
|
|
||||||
virtual void resize(size_t newSize);
|
virtual void resize(size_t newSize);
|
||||||
virtual void insert(u64 offset, size_t size);
|
virtual void insert(u64 offset, size_t size);
|
||||||
|
virtual void remove(u64 offset, size_t size);
|
||||||
|
|
||||||
virtual void save();
|
virtual void save();
|
||||||
virtual void saveAs(const std::fs::path &path);
|
virtual void saveAs(const std::fs::path &path);
|
||||||
|
|||||||
@@ -63,7 +63,6 @@ namespace ImGui {
|
|||||||
|
|
||||||
void UnderlinedText(const char *label, ImColor color = ImGui::GetStyleColorVec4(ImGuiCol_Text), const ImVec2 &size_arg = ImVec2(0, 0));
|
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 TextSpinner(const char *label);
|
||||||
|
|
||||||
void Header(const char *label, bool firstEntry = false);
|
void Header(const char *label, bool firstEntry = false);
|
||||||
@@ -75,7 +74,8 @@ namespace ImGui {
|
|||||||
bool ToolBarButton(const char *symbol, ImVec4 color);
|
bool ToolBarButton(const char *symbol, ImVec4 color);
|
||||||
bool IconButton(const char *symbol, ImVec4 color, ImVec2 size_arg = ImVec2(0, 0));
|
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);
|
bool InputHexadecimal(const char* label, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||||
|
|
||||||
inline bool HasSecondPassed() {
|
inline bool HasSecondPassed() {
|
||||||
@@ -130,5 +130,13 @@ namespace ImGui {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool InputText(const char* label, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
bool InputText(const char* label, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||||
|
bool InputText(const char *label, std::u8string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||||
bool InputTextMultiline(const char* label, std::string &buffer, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
bool InputTextMultiline(const char* label, std::string &buffer, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||||
|
bool InputTextWithHint(const char *label, const char *hint, std::string &buffer, 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);
|
||||||
}
|
}
|
||||||
@@ -7,8 +7,8 @@
|
|||||||
#include <imgui_internal.h>
|
#include <imgui_internal.h>
|
||||||
#include <hex/ui/imgui_imhex_extensions.h>
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
|
|
||||||
#include <fontawesome_font.h>
|
#include <fonts/fontawesome_font.h>
|
||||||
#include <codicons_font.h>
|
#include <fonts/codicons_font.h>
|
||||||
|
|
||||||
#include <hex/api/imhex_api.hpp>
|
#include <hex/api/imhex_api.hpp>
|
||||||
#include <hex/api/event.hpp>
|
#include <hex/api/event.hpp>
|
||||||
@@ -34,11 +34,9 @@ namespace hex {
|
|||||||
[[nodiscard]] virtual bool isAvailable() const;
|
[[nodiscard]] virtual bool isAvailable() const;
|
||||||
[[nodiscard]] virtual bool shouldProcess() const { return this->isAvailable() && this->getWindowOpenState(); }
|
[[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 showMessagePopup(const std::string &message);
|
static void showFatalPopup(const std::string &message);
|
||||||
static void showErrorPopup(const std::string &errorMessage);
|
|
||||||
static void showFatalPopup(const std::string &errorMessage);
|
|
||||||
static void showYesNoQuestionPopup(const std::string &message, const std::function<void()> &yesCallback, const std::function<void()> &noCallback);
|
static void showYesNoQuestionPopup(const std::string &message, const std::function<void()> &yesCallback, const std::function<void()> &noCallback);
|
||||||
|
|
||||||
static void showFileChooserPopup(const std::vector<std::fs::path> &paths, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::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);
|
||||||
@@ -71,15 +69,6 @@ namespace hex {
|
|||||||
bool m_windowOpen = false;
|
bool m_windowOpen = false;
|
||||||
std::map<Shortcut, std::function<void()>> m_shortcuts;
|
std::map<Shortcut, std::function<void()>> m_shortcuts;
|
||||||
|
|
||||||
static std::string s_popupMessage;
|
|
||||||
|
|
||||||
static std::function<void()> s_yesCallback, s_noCallback;
|
|
||||||
|
|
||||||
static u32 s_selectableFileIndex;
|
|
||||||
static std::vector<std::fs::path> s_selectableFiles;
|
|
||||||
static std::function<void(std::fs::path)> s_selectableFileOpenCallback;
|
|
||||||
static std::vector<nfdfilteritem_t> s_selectableFilesValidExtensions;
|
|
||||||
|
|
||||||
static ImFontAtlas *s_fontAtlas;
|
static ImFontAtlas *s_fontAtlas;
|
||||||
static ImFontConfig s_fontConfig;
|
static ImFontConfig s_fontConfig;
|
||||||
|
|
||||||
|
|||||||
@@ -536,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,13 +1,16 @@
|
|||||||
#include <hex/api/imhex_api.hpp>
|
#include <hex/api/imhex_api.hpp>
|
||||||
|
#include <hex/api/content_registry.hpp>
|
||||||
|
|
||||||
#include <hex/api/event.hpp>
|
#include <hex/api/event.hpp>
|
||||||
#include <hex/providers/provider.hpp>
|
#include <hex/providers/provider.hpp>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
namespace ImHexApi::Common {
|
namespace ImHexApi::Common {
|
||||||
@@ -29,32 +32,55 @@ namespace hex {
|
|||||||
|
|
||||||
namespace ImHexApi::HexEditor {
|
namespace ImHexApi::HexEditor {
|
||||||
|
|
||||||
Highlighting::Highlighting(Region region, color_t color, std::string tooltip)
|
Highlighting::Highlighting(Region region, color_t color)
|
||||||
: m_region(region), m_color(color), m_tooltip(std::move(tooltip)) {
|
: m_region(region), m_color(color) {
|
||||||
|
}
|
||||||
|
|
||||||
|
Tooltip::Tooltip(Region region, std::string value, color_t color) : m_region(region), m_value(std::move(value)), m_color(color) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
|
|
||||||
static std::map<u32, Highlighting> s_highlights;
|
static std::map<u32, Highlighting> s_backgroundHighlights;
|
||||||
std::map<u32, Highlighting> &getHighlights() {
|
std::map<u32, Highlighting> &getBackgroundHighlights() {
|
||||||
return s_highlights;
|
return s_backgroundHighlights;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::map<u32, HighlightingFunction> s_highlightingFunctions;
|
static std::map<u32, HighlightingFunction> s_backgroundHighlightingFunctions;
|
||||||
std::map<u32, HighlightingFunction> &getHighlightingFunctions() {
|
std::map<u32, HighlightingFunction> &getBackgroundHighlightingFunctions() {
|
||||||
return s_highlightingFunctions;
|
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 addHighlight(const Region ®ion, color_t color, const std::string &tooltip) {
|
u32 addBackgroundHighlight(const Region ®ion, color_t color) {
|
||||||
auto &highlights = impl::getHighlights();
|
static u32 id = 0;
|
||||||
static u64 id = 0;
|
|
||||||
|
|
||||||
id++;
|
id++;
|
||||||
|
|
||||||
highlights.insert({
|
impl::getBackgroundHighlights().insert({
|
||||||
id, Highlighting {region, color, tooltip}
|
id, Highlighting {region, color}
|
||||||
});
|
});
|
||||||
|
|
||||||
EventManager::post<EventHighlightingChanged>();
|
EventManager::post<EventHighlightingChanged>();
|
||||||
@@ -62,37 +88,101 @@ namespace hex {
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeHighlight(u32 id) {
|
void removeBackgroundHighlight(u32 id) {
|
||||||
impl::getHighlights().erase(id);
|
impl::getBackgroundHighlights().erase(id);
|
||||||
|
|
||||||
EventManager::post<EventHighlightingChanged>();
|
EventManager::post<EventHighlightingChanged>();
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 addHighlightingProvider(const impl::HighlightingFunction &function) {
|
u32 addBackgroundHighlightingProvider(const impl::HighlightingFunction &function) {
|
||||||
auto &highlightFuncs = impl::getHighlightingFunctions();
|
static u32 id = 0;
|
||||||
|
|
||||||
auto id = highlightFuncs.size();
|
id++;
|
||||||
|
|
||||||
highlightFuncs.insert({ id, function });
|
impl::getBackgroundHighlightingFunctions().insert({ id, function });
|
||||||
|
|
||||||
EventManager::post<EventHighlightingChanged>();
|
EventManager::post<EventHighlightingChanged>();
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void removeHighlightingProvider(u32 id) {
|
void removeBackgroundHighlightingProvider(u32 id) {
|
||||||
impl::getHighlightingFunctions().erase(id);
|
impl::getBackgroundHighlightingFunctions().erase(id);
|
||||||
|
|
||||||
EventManager::post<EventHighlightingChanged>();
|
EventManager::post<EventHighlightingChanged>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Region getSelection() {
|
u32 addForegroundHighlight(const Region ®ion, color_t color) {
|
||||||
static Region selectedRegion;
|
static u32 id = 0;
|
||||||
EventManager::subscribe<EventRegionSelected>([](const Region ®ion) {
|
|
||||||
selectedRegion = region;
|
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) {
|
void setSelection(const Region ®ion) {
|
||||||
@@ -144,7 +234,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isValid() {
|
bool isValid() {
|
||||||
return !s_providers.empty();
|
return !s_providers.empty() && s_currentProvider < s_providers.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void add(prv::Provider *provider) {
|
void add(prv::Provider *provider) {
|
||||||
@@ -159,7 +249,7 @@ namespace hex {
|
|||||||
|
|
||||||
s_providers.erase(it);
|
s_providers.erase(it);
|
||||||
|
|
||||||
if (it - s_providers.begin() == s_currentProvider)
|
if (it - s_providers.begin() == s_currentProvider && !s_providers.empty())
|
||||||
setCurrentProvider(0);
|
setCurrentProvider(0);
|
||||||
|
|
||||||
delete provider;
|
delete provider;
|
||||||
@@ -210,7 +300,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static float s_globalScale;
|
static float s_globalScale = 1.0;
|
||||||
void setGlobalScale(float scale) {
|
void setGlobalScale(float scale) {
|
||||||
s_globalScale = scale;
|
s_globalScale = scale;
|
||||||
}
|
}
|
||||||
@@ -228,6 +318,21 @@ namespace hex {
|
|||||||
s_borderlessWindowMode = 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -273,6 +378,54 @@ namespace hex {
|
|||||||
|
|
||||||
return 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,19 +3,26 @@
|
|||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <dlfcn.h>
|
#include <system_error>
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
Plugin::Plugin(const std::fs::path &path) : m_path(path) {
|
Plugin::Plugin(const std::fs::path &path) : m_path(path) {
|
||||||
this->m_handle = dlopen(path.string().c_str(), RTLD_LAZY);
|
#if defined(OS_WINDOWS)
|
||||||
|
this->m_handle = LoadLibraryW(path.c_str());
|
||||||
|
|
||||||
if (this->m_handle == nullptr) {
|
if (this->m_handle == nullptr) {
|
||||||
log::error("dlopen failed: {}", dlerror());
|
log::error("LoadLibraryW failed: {}!", std::system_category().message(::GetLastError()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
this->m_handle = dlopen(path.string().c_str(), RTLD_LAZY);
|
||||||
|
|
||||||
auto pluginName = std::fs::path(path).stem().string();
|
if (this->m_handle == nullptr) {
|
||||||
|
log::error("dlopen failed: {}!", dlerror());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
this->m_initializePluginFunction = getPluginFunction<InitializePluginFunc>("initializePlugin");
|
this->m_initializePluginFunction = getPluginFunction<InitializePluginFunc>("initializePlugin");
|
||||||
this->m_getPluginNameFunction = getPluginFunction<GetPluginNameFunc>("getPluginName");
|
this->m_getPluginNameFunction = getPluginFunction<GetPluginNameFunc>("getPluginName");
|
||||||
@@ -49,8 +56,13 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Plugin::~Plugin() {
|
Plugin::~Plugin() {
|
||||||
if (this->m_handle != nullptr)
|
#if defined(OS_WINDOWS)
|
||||||
dlclose(this->m_handle);
|
if (this->m_handle != nullptr)
|
||||||
|
FreeLibrary(this->m_handle);
|
||||||
|
#else
|
||||||
|
if (this->m_handle != nullptr)
|
||||||
|
dlclose(this->m_handle);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Plugin::initializePlugin() const {
|
bool Plugin::initializePlugin() const {
|
||||||
@@ -120,7 +132,11 @@ namespace hex {
|
|||||||
|
|
||||||
|
|
||||||
void *Plugin::getPluginFunction(const std::string &symbol) {
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -135,7 +151,7 @@ namespace hex {
|
|||||||
|
|
||||||
for (auto &pluginPath : std::fs::directory_iterator(pluginFolder)) {
|
for (auto &pluginPath : std::fs::directory_iterator(pluginFolder)) {
|
||||||
if (pluginPath.is_regular_file() && pluginPath.path().extension() == ".hexplug")
|
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())
|
if (PluginManager::s_plugins.empty())
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <hex/providers/provider.hpp>
|
#include <hex/providers/provider.hpp>
|
||||||
#include <hex/helpers/utils.hpp>
|
#include <hex/helpers/utils.hpp>
|
||||||
|
#include <hex/helpers/concepts.hpp>
|
||||||
|
|
||||||
#include <mbedtls/version.h>
|
#include <mbedtls/version.h>
|
||||||
#include <mbedtls/base64.h>
|
#include <mbedtls/base64.h>
|
||||||
@@ -15,7 +16,6 @@
|
|||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <concepts>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|||||||
@@ -2,16 +2,13 @@
|
|||||||
|
|
||||||
#include <hex/helpers/utils.hpp>
|
#include <hex/helpers/utils.hpp>
|
||||||
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
EncodingFile::EncodingFile(Type type, const std::fs::path &path) {
|
EncodingFile::EncodingFile(Type type, const std::fs::path &path) {
|
||||||
std::ifstream encodingFile(path.c_str());
|
auto file = fs::File(path, fs::File::Mode::Read);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Type::Thingy:
|
case Type::Thingy:
|
||||||
parseThingyFile(encodingFile);
|
parseThingyFile(file);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
return;
|
return;
|
||||||
@@ -34,29 +31,30 @@ namespace hex {
|
|||||||
return { ".", 1 };
|
return { ".", 1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncodingFile::parseThingyFile(std::ifstream &content) {
|
void EncodingFile::parseThingyFile(fs::File &file) {
|
||||||
for (std::string line; std::getline(content, line);) {
|
for (const auto &line : splitString(file.readString(), "\n")) {
|
||||||
|
|
||||||
std::string from, to;
|
std::string from, to;
|
||||||
{
|
{
|
||||||
auto delimiterPos = line.find('=', 0);
|
auto delimiterPos = line.find('=');
|
||||||
|
|
||||||
if (delimiterPos == std::string::npos)
|
if (delimiterPos >= line.length())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
from = line.substr(0, delimiterPos);
|
from = line.substr(0, delimiterPos);
|
||||||
to = line.substr(delimiterPos + 1);
|
to = line.substr(delimiterPos + 1);
|
||||||
|
|
||||||
hex::trim(from);
|
|
||||||
hex::trim(to);
|
|
||||||
|
|
||||||
if (from.empty()) continue;
|
if (from.empty()) continue;
|
||||||
if (to.empty()) to = " ";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fromBytes = hex::parseByteString(from);
|
auto fromBytes = hex::parseByteString(from);
|
||||||
if (fromBytes.empty()) continue;
|
if (fromBytes.empty()) continue;
|
||||||
|
|
||||||
|
if (to.length() > 1)
|
||||||
|
hex::trim(to);
|
||||||
|
if (to.empty())
|
||||||
|
to = " ";
|
||||||
|
|
||||||
if (!this->m_mapping.contains(fromBytes.size()))
|
if (!this->m_mapping.contains(fromBytes.size()))
|
||||||
this->m_mapping.insert({ fromBytes.size(), {} });
|
this->m_mapping.insert({ fromBytes.size(), {} });
|
||||||
this->m_mapping[fromBytes.size()].insert({ fromBytes, to });
|
this->m_mapping[fromBytes.size()].insert({ fromBytes, to });
|
||||||
|
|||||||
@@ -1,16 +1,28 @@
|
|||||||
#include <hex/helpers/file.hpp>
|
#include <hex/helpers/file.hpp>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <cstring>
|
||||||
|
|
||||||
namespace hex::fs {
|
namespace hex::fs {
|
||||||
|
|
||||||
File::File(const std::fs::path &path, Mode mode) noexcept : m_path(path) {
|
File::File(const std::fs::path &path, Mode mode) noexcept : m_path(path) {
|
||||||
if (mode == File::Mode::Read)
|
#if defined(OS_WINDOWS)
|
||||||
this->m_file = fopen64(path.string().c_str(), "rb");
|
if (mode == File::Mode::Read)
|
||||||
else if (mode == File::Mode::Write)
|
this->m_file = _wfopen(path.c_str(), L"rb");
|
||||||
this->m_file = fopen64(path.string().c_str(), "r+b");
|
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))
|
if (mode == File::Mode::Create || (mode == File::Mode::Write && this->m_file == nullptr))
|
||||||
this->m_file = fopen64(path.string().c_str(), "w+b");
|
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 {
|
File::File() noexcept {
|
||||||
@@ -77,7 +89,22 @@ namespace hex::fs {
|
|||||||
if (bytes.empty())
|
if (bytes.empty())
|
||||||
return "";
|
return "";
|
||||||
|
|
||||||
return { reinterpret_cast<char *>(bytes.data()), bytes.size() };
|
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) {
|
void File::write(const u8 *buffer, size_t size) {
|
||||||
@@ -98,6 +125,12 @@ namespace hex::fs {
|
|||||||
std::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 {
|
size_t File::getSize() const {
|
||||||
if (!isValid()) return 0;
|
if (!isValid()) return 0;
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
#include <hex/helpers/fs.hpp>
|
#include <hex/helpers/fs.hpp>
|
||||||
|
|
||||||
#include <hex/api/content_registry.hpp>
|
#include <hex/api/content_registry.hpp>
|
||||||
#include <hex/helpers/fs_macos.h>
|
#include <hex/helpers/fs_macos.hpp>
|
||||||
#include <hex/helpers/file.hpp>
|
#include <hex/helpers/file.hpp>
|
||||||
#include <hex/helpers/intrinsics.hpp>
|
#include <hex/helpers/intrinsics.hpp>
|
||||||
|
#include <hex/helpers/net.hpp>
|
||||||
|
|
||||||
#include <xdg.hpp>
|
#include <xdg.hpp>
|
||||||
|
|
||||||
@@ -22,8 +23,8 @@ namespace hex::fs {
|
|||||||
|
|
||||||
std::optional<std::fs::path> getExecutablePath() {
|
std::optional<std::fs::path> getExecutablePath() {
|
||||||
#if defined(OS_WINDOWS)
|
#if defined(OS_WINDOWS)
|
||||||
std::string exePath(MAX_PATH, '\0');
|
std::wstring exePath(MAX_PATH, '\0');
|
||||||
if (GetModuleFileName(nullptr, exePath.data(), exePath.length()) == 0)
|
if (GetModuleFileNameW(nullptr, exePath.data(), exePath.length()) == 0)
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
||||||
return exePath;
|
return exePath;
|
||||||
@@ -34,7 +35,15 @@ namespace hex::fs {
|
|||||||
|
|
||||||
return exePath;
|
return exePath;
|
||||||
#elif defined(OS_MACOS)
|
#elif defined(OS_MACOS)
|
||||||
return getMacExecutableDirectoryPath();
|
std::string result;
|
||||||
|
|
||||||
|
{
|
||||||
|
auto string = getMacExecutableDirectoryPath();
|
||||||
|
result = string;
|
||||||
|
macFree(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
#else
|
#else
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
#endif
|
#endif
|
||||||
@@ -62,7 +71,7 @@ namespace hex::fs {
|
|||||||
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath) {
|
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath) {
|
||||||
NFD::Init();
|
NFD::Init();
|
||||||
|
|
||||||
nfdchar_t *outPath;
|
nfdchar_t *outPath = nullptr;
|
||||||
nfdresult_t result;
|
nfdresult_t result;
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case DialogMode::Open:
|
case DialogMode::Open:
|
||||||
@@ -78,8 +87,8 @@ namespace hex::fs {
|
|||||||
hex::unreachable();
|
hex::unreachable();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == NFD_OKAY) {
|
if (result == NFD_OKAY && outPath != nullptr) {
|
||||||
callback(reinterpret_cast<const char8_t *>(outPath));
|
callback(reinterpret_cast<char8_t*>(outPath));
|
||||||
NFD::FreePath(outPath);
|
NFD::FreePath(outPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,8 +101,7 @@ namespace hex::fs {
|
|||||||
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting) {
|
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting) {
|
||||||
std::vector<std::fs::path> result;
|
std::vector<std::fs::path> result;
|
||||||
const auto exePath = getExecutablePath();
|
const auto exePath = getExecutablePath();
|
||||||
const std::string settingName { "hex.builtin.setting.folders" };
|
auto userDirs = ImHexApi::System::getAdditionalFolderPaths();
|
||||||
auto userDirs = ContentRegistry::Settings::read(settingName, settingName, std::vector<std::string> {});
|
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
auto addUserDirs = [&userDirs](auto &paths) {
|
auto addUserDirs = [&userDirs](auto &paths) {
|
||||||
@@ -105,11 +113,11 @@ namespace hex::fs {
|
|||||||
#if defined(OS_WINDOWS)
|
#if defined(OS_WINDOWS)
|
||||||
std::fs::path appDataDir;
|
std::fs::path appDataDir;
|
||||||
{
|
{
|
||||||
LPWSTR wAppDataPath = nullptr;
|
PWSTR wAppDataPath = nullptr;
|
||||||
if (!SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &wAppDataPath)))
|
if (!SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &wAppDataPath)))
|
||||||
throw std::runtime_error("Failed to get APPDATA folder path");
|
throw std::runtime_error("Failed to get APPDATA folder path");
|
||||||
|
|
||||||
appDataDir = wAppDataPath;
|
appDataDir = std::wstring(wAppDataPath);
|
||||||
CoTaskMemFree(wAppDataPath);
|
CoTaskMemFree(wAppDataPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -122,60 +130,60 @@ namespace hex::fs {
|
|||||||
case ImHexPath::Patterns:
|
case ImHexPath::Patterns:
|
||||||
addUserDirs(paths);
|
addUserDirs(paths);
|
||||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||||
return (path / "patterns").string();
|
return path / "patterns";
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case ImHexPath::PatternsInclude:
|
case ImHexPath::PatternsInclude:
|
||||||
addUserDirs(paths);
|
addUserDirs(paths);
|
||||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||||
return (path / "includes").string();
|
return path / "includes";
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Magic:
|
case ImHexPath::Magic:
|
||||||
addUserDirs(paths);
|
addUserDirs(paths);
|
||||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||||
return (path / "magic").string();
|
return path / "magic";
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Python:
|
case ImHexPath::Python:
|
||||||
addUserDirs(paths);
|
addUserDirs(paths);
|
||||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||||
return (path / "python").string();
|
return path / "python";
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Plugins:
|
case ImHexPath::Plugins:
|
||||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||||
return (path / "plugins").string();
|
return path / "plugins";
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Yara:
|
case ImHexPath::Yara:
|
||||||
addUserDirs(paths);
|
addUserDirs(paths);
|
||||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||||
return (path / "yara").string();
|
return path / "yara";
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Config:
|
case ImHexPath::Config:
|
||||||
return { (appDataDir / "imhex" / "config").string() };
|
return { appDataDir / "imhex" / "config" };
|
||||||
case ImHexPath::Resources:
|
case ImHexPath::Resources:
|
||||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||||
return (path / "resources").string();
|
return path / "resources";
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Constants:
|
case ImHexPath::Constants:
|
||||||
addUserDirs(paths);
|
addUserDirs(paths);
|
||||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||||
return (path / "constants").string();
|
return path / "constants";
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Encodings:
|
case ImHexPath::Encodings:
|
||||||
addUserDirs(paths);
|
addUserDirs(paths);
|
||||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||||
return (path / "encodings").string();
|
return path / "encodings";
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Logs:
|
case ImHexPath::Logs:
|
||||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||||
return (path / "logs").string();
|
return path / "logs";
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@@ -183,48 +191,54 @@ namespace hex::fs {
|
|||||||
}
|
}
|
||||||
#elif defined(OS_MACOS)
|
#elif defined(OS_MACOS)
|
||||||
// Get path to special directories
|
// Get path to special directories
|
||||||
const std::fs::path applicationSupportDir(getMacApplicationSupportDirectoryPath());
|
std::string applicationSupportDir;
|
||||||
|
{
|
||||||
|
auto string = getMacApplicationSupportDirectoryPath();
|
||||||
|
applicationSupportDir = string;
|
||||||
|
macFree(string);
|
||||||
|
}
|
||||||
|
const std::fs::path applicationSupportDirPath(applicationSupportDir);
|
||||||
|
|
||||||
std::vector<std::fs::path> paths = { applicationSupportDir };
|
std::vector<std::fs::path> paths = { applicationSupportDirPath };
|
||||||
|
|
||||||
if (exePath)
|
if (exePath.has_value())
|
||||||
paths.push_back(exePath->parent_path());
|
paths.push_back(exePath.value());
|
||||||
|
|
||||||
switch (path) {
|
switch (path) {
|
||||||
case ImHexPath::Patterns:
|
case ImHexPath::Patterns:
|
||||||
result.push_back((applicationSupportDir / "patterns").string());
|
result.push_back(applicationSupportDirPath / "patterns");
|
||||||
break;
|
break;
|
||||||
case ImHexPath::PatternsInclude:
|
case ImHexPath::PatternsInclude:
|
||||||
result.push_back((applicationSupportDir / "includes").string());
|
result.push_back(applicationSupportDirPath / "includes");
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Magic:
|
case ImHexPath::Magic:
|
||||||
result.push_back((applicationSupportDir / "magic").string());
|
result.push_back(applicationSupportDirPath / "magic");
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Python:
|
case ImHexPath::Python:
|
||||||
result.push_back((applicationSupportDir / "python").string());
|
result.push_back(applicationSupportDirPath / "python");
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Plugins:
|
case ImHexPath::Plugins:
|
||||||
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
std::transform(paths.begin(), paths.end(), std::back_inserter(result), [](auto &path) {
|
||||||
return (path / "plugins").string();
|
return path / "plugins";
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Yara:
|
case ImHexPath::Yara:
|
||||||
result.push_back((applicationSupportDir / "yara").string());
|
result.push_back(applicationSupportDirPath / "yara");
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Config:
|
case ImHexPath::Config:
|
||||||
result.push_back((applicationSupportDir / "config").string());
|
result.push_back(applicationSupportDirPath / "config");
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Resources:
|
case ImHexPath::Resources:
|
||||||
result.push_back((applicationSupportDir / "resources").string());
|
result.push_back(applicationSupportDirPath / "resources");
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Constants:
|
case ImHexPath::Constants:
|
||||||
result.push_back((applicationSupportDir / "constants").string());
|
result.push_back(applicationSupportDirPath / "constants");
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Encodings:
|
case ImHexPath::Encodings:
|
||||||
result.push_back((applicationSupportDir / "encodings").string());
|
result.push_back(applicationSupportDirPath / "encodings");
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Logs:
|
case ImHexPath::Logs:
|
||||||
result.push_back((applicationSupportDir / "logs").string());
|
result.push_back(applicationSupportDirPath / "logs");
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
hex::unreachable();
|
hex::unreachable();
|
||||||
@@ -233,8 +247,8 @@ namespace hex::fs {
|
|||||||
std::vector<std::fs::path> configDirs = xdg::ConfigDirs();
|
std::vector<std::fs::path> configDirs = xdg::ConfigDirs();
|
||||||
std::vector<std::fs::path> dataDirs = xdg::DataDirs();
|
std::vector<std::fs::path> dataDirs = xdg::DataDirs();
|
||||||
|
|
||||||
configDirs.push_back(xdg::ConfigHomeDir());
|
configDirs.insert(configDirs.begin(), xdg::ConfigHomeDir());
|
||||||
dataDirs.push_back(xdg::DataHomeDir());
|
dataDirs.insert(dataDirs.begin(), xdg::DataHomeDir());
|
||||||
|
|
||||||
for (auto &dir : dataDirs)
|
for (auto &dir : dataDirs)
|
||||||
dir = dir / "imhex";
|
dir = dir / "imhex";
|
||||||
@@ -245,43 +259,43 @@ namespace hex::fs {
|
|||||||
switch (path) {
|
switch (path) {
|
||||||
case ImHexPath::Patterns:
|
case ImHexPath::Patterns:
|
||||||
addUserDirs(dataDirs);
|
addUserDirs(dataDirs);
|
||||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "patterns").string(); });
|
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "patterns"; });
|
||||||
break;
|
break;
|
||||||
case ImHexPath::PatternsInclude:
|
case ImHexPath::PatternsInclude:
|
||||||
addUserDirs(dataDirs);
|
addUserDirs(dataDirs);
|
||||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "includes").string(); });
|
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "includes"; });
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Magic:
|
case ImHexPath::Magic:
|
||||||
addUserDirs(dataDirs);
|
addUserDirs(dataDirs);
|
||||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "magic").string(); });
|
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "magic"; });
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Python:
|
case ImHexPath::Python:
|
||||||
addUserDirs(dataDirs);
|
addUserDirs(dataDirs);
|
||||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p).string(); });
|
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p; });
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Plugins:
|
case ImHexPath::Plugins:
|
||||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "plugins").string(); });
|
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "plugins"; });
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Yara:
|
case ImHexPath::Yara:
|
||||||
addUserDirs(dataDirs);
|
addUserDirs(dataDirs);
|
||||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "yara").string(); });
|
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "yara"; });
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Config:
|
case ImHexPath::Config:
|
||||||
std::transform(configDirs.begin(), configDirs.end(), std::back_inserter(result), [](auto p) { return (p / "imhex").string(); });
|
std::transform(configDirs.begin(), configDirs.end(), std::back_inserter(result), [](auto p) { return p / "imhex"; });
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Resources:
|
case ImHexPath::Resources:
|
||||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "resources").string(); });
|
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "resources"; });
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Constants:
|
case ImHexPath::Constants:
|
||||||
addUserDirs(dataDirs);
|
addUserDirs(dataDirs);
|
||||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "constants").string(); });
|
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "constants"; });
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Encodings:
|
case ImHexPath::Encodings:
|
||||||
addUserDirs(dataDirs);
|
addUserDirs(dataDirs);
|
||||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "encodings").string(); });
|
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "encodings"; });
|
||||||
break;
|
break;
|
||||||
case ImHexPath::Logs:
|
case ImHexPath::Logs:
|
||||||
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return (p / "logs").string(); });
|
std::transform(dataDirs.begin(), dataDirs.end(), std::back_inserter(result), [](auto p) { return p / "logs"; });
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
hex::unreachable();
|
hex::unreachable();
|
||||||
@@ -299,4 +313,20 @@ namespace hex::fs {
|
|||||||
return result;
|
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
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
#if defined(OS_MACOS)
|
|
||||||
#include <hex/helpers/fs_macos.h>
|
|
||||||
|
|
||||||
#include <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
namespace hex {
|
|
||||||
std::string getMacExecutableDirectoryPath() {
|
|
||||||
@autoreleasepool {
|
|
||||||
return {[[[[[NSBundle mainBundle] executableURL] URLByDeletingLastPathComponent] path] UTF8String]};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string getMacApplicationSupportDirectoryPath() {
|
|
||||||
@autoreleasepool {
|
|
||||||
NSError* error = nil;
|
|
||||||
NSURL* dirUrl = [[NSFileManager defaultManager] URLForDirectory:NSApplicationSupportDirectory
|
|
||||||
inDomain:NSUserDomainMask
|
|
||||||
appropriateForURL:nil
|
|
||||||
create:YES
|
|
||||||
error:&error];
|
|
||||||
|
|
||||||
if (error != nil) {
|
|
||||||
__builtin_unreachable();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {[[[dirUrl URLByAppendingPathComponent:(@"imhex")] path] UTF8String]};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
@@ -1,240 +0,0 @@
|
|||||||
#include <hex/helpers/loader_script_handler.hpp>
|
|
||||||
|
|
||||||
#include <hex/helpers/utils.hpp>
|
|
||||||
#include <hex/helpers/fs.hpp>
|
|
||||||
#include <hex/helpers/file.hpp>
|
|
||||||
#include <hex/ui/view.hpp>
|
|
||||||
#include <hex/providers/provider.hpp>
|
|
||||||
#include <hex/helpers/intrinsics.hpp>
|
|
||||||
|
|
||||||
#define PY_SSIZE_T_CLEAN
|
|
||||||
#include <Python.h>
|
|
||||||
#include <structmember.h>
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
using namespace std::literals::string_literals;
|
|
||||||
|
|
||||||
namespace hex {
|
|
||||||
|
|
||||||
PyObject *LoaderScript::Py_getFilePath(PyObject *self, PyObject *args) {
|
|
||||||
hex::unused(self, args);
|
|
||||||
|
|
||||||
return PyUnicode_FromString(LoaderScript::s_filePath.string().c_str());
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *LoaderScript::Py_addPatch(PyObject *self, PyObject *args) {
|
|
||||||
hex::unused(self);
|
|
||||||
|
|
||||||
u64 address;
|
|
||||||
u8 *patches;
|
|
||||||
Py_ssize_t count;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "K|y#", &address, &patches, &count)) {
|
|
||||||
PyErr_BadArgument();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (patches == nullptr || count == 0) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "Invalid patch provided");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (address >= LoaderScript::s_dataProvider->getActualSize()) {
|
|
||||||
PyErr_SetString(PyExc_IndexError, "address out of range");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
LoaderScript::s_dataProvider->write(address, patches, count);
|
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *LoaderScript::Py_addBookmark(PyObject *self, PyObject *args) {
|
|
||||||
hex::unused(self);
|
|
||||||
|
|
||||||
u64 address;
|
|
||||||
size_t size;
|
|
||||||
|
|
||||||
char *name = nullptr;
|
|
||||||
char *comment = nullptr;
|
|
||||||
|
|
||||||
if (!PyArg_ParseTuple(args, "K|n|s|s", &address, &size, &name, &comment)) {
|
|
||||||
PyErr_BadArgument();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name == nullptr || comment == nullptr) {
|
|
||||||
PyErr_SetString(PyExc_IndexError, "address out of range");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImHexApi::Bookmarks::add(address, size, name, comment);
|
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
static PyObject *createStructureType(const std::string &keyword, PyObject *args) {
|
|
||||||
auto type = PyTuple_GetItem(args, 0);
|
|
||||||
if (type == nullptr) {
|
|
||||||
PyErr_BadArgument();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto instance = PyObject_CallObject(type, nullptr);
|
|
||||||
if (instance == nullptr) {
|
|
||||||
PyErr_BadArgument();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ON_SCOPE_EXIT { Py_DECREF(instance); };
|
|
||||||
|
|
||||||
if (instance->ob_type->tp_base == nullptr || instance->ob_type->tp_base->tp_name != "ImHexType"s) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "class type must extend from ImHexType");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto dict = instance->ob_type->tp_dict;
|
|
||||||
if (dict == nullptr) {
|
|
||||||
PyErr_BadArgument();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto annotations = PyDict_GetItemString(dict, "__annotations__");
|
|
||||||
if (annotations == nullptr) {
|
|
||||||
PyErr_BadArgument();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto list = PyDict_Items(annotations);
|
|
||||||
if (list == nullptr) {
|
|
||||||
PyErr_BadArgument();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
ON_SCOPE_EXIT { Py_DECREF(list); };
|
|
||||||
|
|
||||||
std::string code = keyword + " " + instance->ob_type->tp_name + " {\n";
|
|
||||||
|
|
||||||
for (Py_ssize_t i = 0; i < PyList_Size(list); i++) {
|
|
||||||
auto item = PyList_GetItem(list, i);
|
|
||||||
|
|
||||||
auto memberName = PyUnicode_AsUTF8(PyTuple_GetItem(item, 0));
|
|
||||||
auto memberType = PyTuple_GetItem(item, 1);
|
|
||||||
if (memberType == nullptr) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "member needs to have a annotation extending from ImHexType");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Array already is an object
|
|
||||||
if (memberType->ob_type->tp_name == "array"s) {
|
|
||||||
|
|
||||||
auto arrayType = PyObject_GetAttrString(memberType, "array_type");
|
|
||||||
if (arrayType == nullptr) {
|
|
||||||
PyErr_BadArgument();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
code += " "s + arrayType->ob_type->tp_name + " " + memberName;
|
|
||||||
|
|
||||||
auto arraySize = PyObject_GetAttrString(memberType, "size");
|
|
||||||
if (arraySize == nullptr) {
|
|
||||||
PyErr_BadArgument();
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PyUnicode_Check(arraySize))
|
|
||||||
code += "["s + PyUnicode_AsUTF8(arraySize) + "];\n";
|
|
||||||
else if (PyLong_Check(arraySize))
|
|
||||||
code += "["s + std::to_string(PyLong_AsLong(arraySize)) + "];\n";
|
|
||||||
else {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "invalid array size type. Expected string or int");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} else {
|
|
||||||
auto memberTypeInstance = PyObject_CallObject(memberType, nullptr);
|
|
||||||
if (memberTypeInstance == nullptr || memberTypeInstance->ob_type->tp_base == nullptr || memberTypeInstance->ob_type->tp_base->tp_name != "ImHexType"s) {
|
|
||||||
PyErr_SetString(PyExc_TypeError, "member needs to have a annotation extending from ImHexType");
|
|
||||||
if (memberTypeInstance != nullptr)
|
|
||||||
Py_DECREF(memberTypeInstance);
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
code += " "s + memberTypeInstance->ob_type->tp_name + " "s + memberName + ";\n";
|
|
||||||
|
|
||||||
Py_DECREF(memberTypeInstance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
code += "};\n";
|
|
||||||
|
|
||||||
EventManager::post<RequestSetPatternLanguageCode>(code);
|
|
||||||
|
|
||||||
Py_RETURN_NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *LoaderScript::Py_addStruct(PyObject *self, PyObject *args) {
|
|
||||||
hex::unused(self);
|
|
||||||
|
|
||||||
return createStructureType("struct", args);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *LoaderScript::Py_addUnion(PyObject *self, PyObject *args) {
|
|
||||||
hex::unused(self);
|
|
||||||
|
|
||||||
return createStructureType("union", args);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool LoaderScript::processFile(const std::fs::path &scriptPath) {
|
|
||||||
Py_SetProgramName(Py_DecodeLocale("ImHex", nullptr));
|
|
||||||
|
|
||||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Python)) {
|
|
||||||
if (fs::exists(std::fs::path(dir / "lib" / "python" PYTHON_VERSION_MAJOR_MINOR))) {
|
|
||||||
Py_SetPythonHome(Py_DecodeLocale(dir.string().c_str(), nullptr));
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PyImport_AppendInittab("_imhex", []() -> PyObject * {
|
|
||||||
static PyMethodDef ImHexMethods[] = {
|
|
||||||
{"get_file_path", &LoaderScript::Py_getFilePath, METH_NOARGS, "Returns the path of the file being loaded."},
|
|
||||||
{ "patch", &LoaderScript::Py_addPatch, METH_VARARGS, "Patches a region of memory" },
|
|
||||||
{ "add_bookmark", &LoaderScript::Py_addBookmark, METH_VARARGS, "Adds a bookmark" },
|
|
||||||
{ "add_struct", &LoaderScript::Py_addStruct, METH_VARARGS, "Adds a struct" },
|
|
||||||
{ "add_union", &LoaderScript::Py_addUnion, METH_VARARGS, "Adds a union" },
|
|
||||||
{ nullptr, nullptr, 0, nullptr }
|
|
||||||
};
|
|
||||||
|
|
||||||
static PyModuleDef ImHexModule = {
|
|
||||||
PyModuleDef_HEAD_INIT, "imhex", nullptr, -1, ImHexMethods, nullptr, nullptr, nullptr, nullptr
|
|
||||||
};
|
|
||||||
|
|
||||||
auto module = PyModule_Create(&ImHexModule);
|
|
||||||
if (module == nullptr)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
return module;
|
|
||||||
});
|
|
||||||
|
|
||||||
Py_Initialize();
|
|
||||||
|
|
||||||
{
|
|
||||||
auto sysPath = PySys_GetObject("path");
|
|
||||||
auto path = PyUnicode_FromString("lib");
|
|
||||||
|
|
||||||
PyList_Insert(sysPath, 0, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
fs::File scriptFile(scriptPath, fs::File::Mode::Read);
|
|
||||||
PyRun_SimpleFile(scriptFile.getHandle(), scriptFile.getPath().string().c_str());
|
|
||||||
|
|
||||||
Py_Finalize();
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -26,8 +26,9 @@ namespace hex::magic {
|
|||||||
std::error_code error;
|
std::error_code error;
|
||||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
|
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
|
||||||
for (const auto &entry : std::fs::directory_iterator(dir, error)) {
|
for (const auto &entry : std::fs::directory_iterator(dir, error)) {
|
||||||
if (entry.is_regular_file() && ((sourceFiles && entry.path().extension().empty()) || (!sourceFiles && entry.path().extension() == ".mgc")))
|
if (entry.is_regular_file() && ((sourceFiles && entry.path().extension().empty()) || (!sourceFiles && entry.path().extension() == ".mgc"))) {
|
||||||
magicFiles += entry.path().string() + MAGIC_PATH_SEPARATOR;
|
magicFiles += fs::toShortPath(entry.path()).string() + MAGIC_PATH_SEPARATOR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,8 @@
|
|||||||
#include <hex/helpers/file.hpp>
|
#include <hex/helpers/file.hpp>
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
|
|
||||||
|
#include <hex/api/content_registry.hpp>
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
@@ -113,12 +115,14 @@ namespace hex {
|
|||||||
curl_easy_setopt(this->m_ctx, CURLOPT_SSLCERTTYPE, "PEM");
|
curl_easy_setopt(this->m_ctx, CURLOPT_SSLCERTTYPE, "PEM");
|
||||||
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_FUNCTION, sslCtxFunction);
|
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_FUNCTION, sslCtxFunction);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
curl_easy_setopt(this->m_ctx, CURLOPT_PROXY, Net::s_proxyUrl.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
std::optional<i32> Net::execute() {
|
std::optional<i32> Net::execute() {
|
||||||
CURLcode result = curl_easy_perform(this->m_ctx);
|
CURLcode result = curl_easy_perform(this->m_ctx);
|
||||||
if (result != CURLE_OK)
|
if (result != CURLE_OK)
|
||||||
log::error("Net request failed with error {0}: '{1}'", result, curl_easy_strerror(result));
|
log::error("Net request failed with error {0}: '{1}'", u32(result), curl_easy_strerror(result));
|
||||||
|
|
||||||
i32 responseCode = 0;
|
i32 responseCode = 0;
|
||||||
curl_easy_getinfo(this->m_ctx, CURLINFO_RESPONSE_CODE, &responseCode);
|
curl_easy_getinfo(this->m_ctx, CURLINFO_RESPONSE_CODE, &responseCode);
|
||||||
@@ -176,7 +180,7 @@ namespace hex {
|
|||||||
|
|
||||||
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
|
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
|
||||||
|
|
||||||
fs::File file(filePath.string(), fs::File::Mode::Read);
|
fs::File file(filePath, fs::File::Mode::Read);
|
||||||
if (!file.isValid())
|
if (!file.isValid())
|
||||||
return Response<std::string> { 400, {} };
|
return Response<std::string> { 400, {} };
|
||||||
|
|
||||||
@@ -214,7 +218,7 @@ namespace hex {
|
|||||||
|
|
||||||
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
|
ON_SCOPE_EXIT { this->m_transmissionActive.unlock(); };
|
||||||
|
|
||||||
fs::File file(filePath.string(), fs::File::Mode::Create);
|
fs::File file(filePath, fs::File::Mode::Create);
|
||||||
if (!file.isValid())
|
if (!file.isValid())
|
||||||
return Response<void> { 400 };
|
return Response<void> { 400 };
|
||||||
|
|
||||||
@@ -241,4 +245,23 @@ namespace hex {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string Net::decode(const std::string &input) {
|
||||||
|
auto unescapedString = curl_easy_unescape(this->m_ctx, input.c_str(), std::strlen(input.c_str()), nullptr);
|
||||||
|
|
||||||
|
if (unescapedString != nullptr) {
|
||||||
|
std::string output = unescapedString;
|
||||||
|
curl_free(unescapedString);
|
||||||
|
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Net::s_proxyUrl;
|
||||||
|
|
||||||
|
void Net::setProxy(const std::string &url) {
|
||||||
|
Net::s_proxyUrl = url;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -52,10 +52,10 @@ namespace hex {
|
|||||||
json projectFileData;
|
json projectFileData;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::ifstream projectFile(filePath.c_str());
|
std::ifstream projectFile(filePath);
|
||||||
projectFile >> projectFileData;
|
projectFile >> projectFileData;
|
||||||
|
|
||||||
ProjectFile::s_filePath = std::fs::path(projectFileData["filePath"].get<std::string>());
|
ProjectFile::s_filePath = std::fs::path(projectFileData["filePath"].get<std::u8string>());
|
||||||
ProjectFile::s_pattern = projectFileData["pattern"];
|
ProjectFile::s_pattern = projectFileData["pattern"];
|
||||||
ProjectFile::s_patches = projectFileData["patches"].get<Patches>();
|
ProjectFile::s_patches = projectFileData["patches"].get<Patches>();
|
||||||
ProjectFile::s_dataProcessorContent = projectFileData["dataProcessor"];
|
ProjectFile::s_dataProcessorContent = projectFileData["dataProcessor"];
|
||||||
@@ -89,7 +89,7 @@ namespace hex {
|
|||||||
filePath = ProjectFile::s_currProjectFilePath;
|
filePath = ProjectFile::s_currProjectFilePath;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
projectFileData["filePath"] = ProjectFile::s_filePath.string();
|
projectFileData["filePath"] = ProjectFile::s_filePath.u8string();
|
||||||
projectFileData["pattern"] = ProjectFile::s_pattern;
|
projectFileData["pattern"] = ProjectFile::s_pattern;
|
||||||
projectFileData["patches"] = ProjectFile::s_patches;
|
projectFileData["patches"] = ProjectFile::s_patches;
|
||||||
projectFileData["dataProcessor"] = ProjectFile::s_dataProcessorContent;
|
projectFileData["dataProcessor"] = ProjectFile::s_dataProcessorContent;
|
||||||
|
|||||||
99
lib/libimhex/source/helpers/tar.cpp
Normal file
99
lib/libimhex/source/helpers/tar.cpp
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
#include <hex/helpers/tar.hpp>
|
||||||
|
#include <hex/helpers/literals.hpp>
|
||||||
|
#include <hex/helpers/file.hpp>
|
||||||
|
|
||||||
|
namespace hex {
|
||||||
|
|
||||||
|
using namespace hex::literals;
|
||||||
|
|
||||||
|
Tar::Tar(const std::fs::path &path, Mode mode) {
|
||||||
|
if (mode == Tar::Mode::Read)
|
||||||
|
mtar_open(&this->m_ctx, path.string().c_str(), "r");
|
||||||
|
else if (mode == Tar::Mode::Write)
|
||||||
|
mtar_open(&this->m_ctx, path.string().c_str(), "a");
|
||||||
|
else if (mode == Tar::Mode::Create)
|
||||||
|
mtar_open(&this->m_ctx, path.string().c_str(), "w");
|
||||||
|
}
|
||||||
|
|
||||||
|
Tar::~Tar() {
|
||||||
|
mtar_finalize(&this->m_ctx);
|
||||||
|
mtar_close(&this->m_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::fs::path> Tar::listEntries() {
|
||||||
|
std::vector<std::fs::path> result;
|
||||||
|
|
||||||
|
const std::string PaxHeaderName = "@PaxHeader";
|
||||||
|
mtar_header_t header;
|
||||||
|
while (mtar_read_header(&this->m_ctx, &header) != MTAR_ENULLRECORD) {
|
||||||
|
if (header.name != PaxHeaderName) {
|
||||||
|
result.emplace_back(header.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
mtar_next(&this->m_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<u8> Tar::read(const std::fs::path &path) {
|
||||||
|
mtar_header_t header;
|
||||||
|
mtar_find(&this->m_ctx, path.string().c_str(), &header);
|
||||||
|
|
||||||
|
std::vector<u8> result(header.size, 0x00);
|
||||||
|
mtar_read_data(&this->m_ctx, result.data(), result.size());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tar::write(const std::fs::path &path, const std::vector<u8> &data) {
|
||||||
|
if (path.has_parent_path()) {
|
||||||
|
std::fs::path pathPart;
|
||||||
|
for (const auto &part : path.parent_path()) {
|
||||||
|
pathPart /= part;
|
||||||
|
mtar_write_dir_header(&this->m_ctx, pathPart.string().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mtar_write_file_header(&this->m_ctx, path.string().c_str(), data.size());
|
||||||
|
mtar_write_data(&this->m_ctx, data.data(), data.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void writeFile(mtar_t *ctx, mtar_header_t *header, const std::fs::path &path) {
|
||||||
|
constexpr static u64 BufferSize = 1_MiB;
|
||||||
|
|
||||||
|
fs::File outputFile(path, fs::File::Mode::Create);
|
||||||
|
|
||||||
|
std::vector<u8> buffer;
|
||||||
|
for (u64 offset = 0; offset < header->size; offset += BufferSize) {
|
||||||
|
buffer.resize(std::min<u64>(BufferSize, header->size - offset));
|
||||||
|
|
||||||
|
mtar_read_data(ctx, buffer.data(), buffer.size());
|
||||||
|
outputFile.write(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tar::extract(const std::fs::path &path, const std::fs::path &outputPath) {
|
||||||
|
mtar_header_t header;
|
||||||
|
mtar_find(&this->m_ctx, path.string().c_str(), &header);
|
||||||
|
|
||||||
|
writeFile(&this->m_ctx, &header, outputPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tar::extractAll(const std::fs::path &outputPath) {
|
||||||
|
mtar_header_t header;
|
||||||
|
while (mtar_read_header(&this->m_ctx, &header) != MTAR_ENULLRECORD) {
|
||||||
|
const auto filePath = std::fs::absolute(outputPath / std::fs::path(header.name));
|
||||||
|
|
||||||
|
if (filePath.filename() != "@PaxHeader") {
|
||||||
|
|
||||||
|
std::fs::create_directories(filePath.parent_path());
|
||||||
|
|
||||||
|
writeFile(&this->m_ctx, &header, filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
mtar_next(&this->m_ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -2,8 +2,6 @@
|
|||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <locale>
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
#include <hex/api/imhex_api.hpp>
|
#include <hex/api/imhex_api.hpp>
|
||||||
|
|
||||||
@@ -18,13 +16,10 @@
|
|||||||
#elif defined(OS_LINUX)
|
#elif defined(OS_LINUX)
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#elif defined(OS_MACOS)
|
#elif defined(OS_MACOS)
|
||||||
#include <CoreFoundation/CFBundle.h>
|
#include <hex/helpers/utils_macos.hpp>
|
||||||
#include <ApplicationServices/ApplicationServices.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <hex/helpers/logger.hpp>
|
|
||||||
#include <hex/helpers/file.hpp>
|
|
||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
long double operator""_scaled(long double value) {
|
long double operator""_scaled(long double value) {
|
||||||
@@ -83,29 +78,34 @@ namespace hex {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string result = hex::format("{0:.2f}", value);
|
std::string result;
|
||||||
|
|
||||||
|
if (unitIndex == 0)
|
||||||
|
result = hex::format("{0:}", value);
|
||||||
|
else
|
||||||
|
result = hex::format("{0:.2f}", value);
|
||||||
|
|
||||||
switch (unitIndex) {
|
switch (unitIndex) {
|
||||||
case 0:
|
case 0:
|
||||||
result += " Bytes";
|
result += ((value == 1) ? " Byte" : " Bytes");
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
result += " kB";
|
result += " kiB";
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
result += " MB";
|
result += " MiB";
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
result += " GB";
|
result += " GiB";
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
result += " TB";
|
result += " TiB";
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
result += " PB";
|
result += " PiB";
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
result += " EB";
|
result += " EiB";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
result = "A lot!";
|
result = "A lot!";
|
||||||
@@ -204,11 +204,15 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> splitString(const std::string &string, const std::string &delimiter) {
|
std::vector<std::string> splitString(const std::string &string, const std::string &delimiter) {
|
||||||
size_t start = 0, end;
|
size_t start = 0, end = 0;
|
||||||
std::string token;
|
std::string token;
|
||||||
std::vector<std::string> res;
|
std::vector<std::string> res;
|
||||||
|
|
||||||
while ((end = string.find(delimiter, start)) != std::string::npos) {
|
while ((end = string.find(delimiter, start)) != std::string::npos) {
|
||||||
|
size_t size = end - start;
|
||||||
|
if (start + size > string.length())
|
||||||
|
break;
|
||||||
|
|
||||||
token = string.substr(start, end - start);
|
token = string.substr(start, end - start);
|
||||||
start = end + delimiter.length();
|
start = end + delimiter.length();
|
||||||
res.push_back(token);
|
res.push_back(token);
|
||||||
@@ -248,13 +252,14 @@ namespace hex {
|
|||||||
|
|
||||||
void runCommand(const std::string &command) {
|
void runCommand(const std::string &command) {
|
||||||
|
|
||||||
#if defined(OS_WINDOWS)
|
#if defined(OS_WINDOWS)
|
||||||
auto result = system(hex::format("start {0}", command).c_str());
|
auto result = system(hex::format("start {0}", command).c_str());
|
||||||
#elif defined(OS_MACOS)
|
#elif defined(OS_MACOS)
|
||||||
auto result = system(hex::format("open {0}", command).c_str());
|
auto result = system(hex::format("open {0}", command).c_str());
|
||||||
#elif defined(OS_LINUX)
|
#elif defined(OS_LINUX)
|
||||||
auto result = system(hex::format("xdg-open {0}", command).c_str());
|
auto result = system(hex::format("xdg-open {0}", command).c_str());
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
hex::unused(result);
|
hex::unused(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -263,18 +268,16 @@ namespace hex {
|
|||||||
if (url.find("://") == std::string::npos)
|
if (url.find("://") == std::string::npos)
|
||||||
url = "https://" + url;
|
url = "https://" + url;
|
||||||
|
|
||||||
#if defined(OS_WINDOWS)
|
#if defined(OS_WINDOWS)
|
||||||
ShellExecute(nullptr, "open", url.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
ShellExecute(nullptr, "open", url.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
||||||
#elif defined(OS_MACOS)
|
#elif defined(OS_MACOS)
|
||||||
CFURLRef urlRef = CFURLCreateWithBytes(nullptr, reinterpret_cast<u8 *>(url.data()), url.length(), kCFStringEncodingASCII, nullptr);
|
openWebpageMacos(url.c_str());
|
||||||
LSOpenCFURLRef(urlRef, nullptr);
|
#elif defined(OS_LINUX)
|
||||||
CFRelease(urlRef);
|
auto result = system(hex::format("xdg-open {0}", url).c_str());
|
||||||
#elif defined(OS_LINUX)
|
hex::unused(result);
|
||||||
auto result = system(hex::format("xdg-open {0}", url).c_str());
|
#else
|
||||||
hex::unused(result);
|
#warning "Unknown OS, can't open webpages"
|
||||||
#else
|
#endif
|
||||||
#warning "Unknown OS, can't open webpages"
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string encodeByteString(const std::vector<u8> &bytes) {
|
std::string encodeByteString(const std::vector<u8> &bytes) {
|
||||||
|
|||||||
28
lib/libimhex/source/helpers/utils_macos.m
Normal file
28
lib/libimhex/source/helpers/utils_macos.m
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
#if defined(OS_MACOS)
|
||||||
|
|
||||||
|
#include <CoreFoundation/CFBundle.h>
|
||||||
|
#include <ApplicationServices/ApplicationServices.h>
|
||||||
|
#include <Foundation/NSUserDefaults.h>
|
||||||
|
#include <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void openWebpageMacos(const char *url) {
|
||||||
|
CFURLRef urlRef = CFURLCreateWithBytes(NULL, (uint8_t*)(url), strlen(url), kCFStringEncodingASCII, NULL);
|
||||||
|
LSOpenCFURLRef(urlRef, NULL);
|
||||||
|
CFRelease(urlRef);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool isMacosSystemDarkModeEnabled() {
|
||||||
|
NSString * appleInterfaceStyle = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
|
||||||
|
|
||||||
|
if (appleInterfaceStyle && [appleInterfaceStyle length] > 0) {
|
||||||
|
return [[appleInterfaceStyle lowercaseString] containsString:@"dark"];
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -2,25 +2,17 @@
|
|||||||
|
|
||||||
#include <hex.hpp>
|
#include <hex.hpp>
|
||||||
#include <hex/api/content_registry.hpp>
|
#include <hex/api/content_registry.hpp>
|
||||||
#include <hex/api/event.hpp>
|
|
||||||
#include <hex/ui/view.hpp>
|
|
||||||
|
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include <pl/pattern_language.hpp>
|
|
||||||
|
|
||||||
namespace hex::prv {
|
namespace hex::prv {
|
||||||
|
|
||||||
Provider::Provider() {
|
Provider::Provider() {
|
||||||
this->m_patches.emplace_back();
|
this->m_patches.emplace_back();
|
||||||
this->m_patternLanguageRuntime = ContentRegistry::PatternLanguage::createDefaultRuntime(this);
|
this->m_patternLanguageRuntime = ContentRegistry::PatternLanguage::createDefaultRuntime(this);
|
||||||
|
|
||||||
if (this->hasLoadInterface())
|
|
||||||
EventManager::post<RequestOpenPopup>(View::toWindowName("hex.builtin.view.provider_settings.load_popup"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Provider::~Provider() {
|
Provider::~Provider() {
|
||||||
@@ -63,6 +55,22 @@ namespace hex::prv {
|
|||||||
patches.insert({ address + size, value });
|
patches.insert({ address + size, value });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Provider::remove(u64 offset, size_t size) {
|
||||||
|
auto &patches = getPatches();
|
||||||
|
|
||||||
|
std::vector<std::pair<u64, u8>> patchesToMove;
|
||||||
|
|
||||||
|
for (auto &[address, value] : patches) {
|
||||||
|
if (address > offset)
|
||||||
|
patchesToMove.emplace_back(address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &[address, value] : patchesToMove)
|
||||||
|
patches.erase(address);
|
||||||
|
for (const auto &[address, value] : patchesToMove)
|
||||||
|
patches.insert({ address - size, value });
|
||||||
|
}
|
||||||
|
|
||||||
void Provider::applyOverlays(u64 offset, void *buffer, size_t size) {
|
void Provider::applyOverlays(u64 offset, void *buffer, size_t size) {
|
||||||
for (auto &overlay : this->m_overlays) {
|
for (auto &overlay : this->m_overlays) {
|
||||||
auto overlayOffset = overlay->getAddress();
|
auto overlayOffset = overlay->getAddress();
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace ImGui {
|
|||||||
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
|
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
|
||||||
auto &string = *static_cast<std::string *>(data->UserData);
|
auto &string = *static_cast<std::string *>(data->UserData);
|
||||||
|
|
||||||
string.resize(data->BufSize);
|
string.resize(data->BufTextLen);
|
||||||
data->Buf = string.data();
|
data->Buf = string.data();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -191,16 +191,6 @@ namespace ImGui {
|
|||||||
PopStyleColor();
|
PopStyleColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Disabled(const std::function<void()> &widgets, bool disabled) {
|
|
||||||
if (disabled) {
|
|
||||||
BeginDisabled();
|
|
||||||
widgets();
|
|
||||||
EndDisabled();
|
|
||||||
} else {
|
|
||||||
widgets();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextSpinner(const char *label) {
|
void TextSpinner(const char *label) {
|
||||||
ImGui::Text("[%c] %s", "|/-\\"[ImU32(ImGui::GetTime() * 20) % 4], label);
|
ImGui::Text("[%c] %s", "|/-\\"[ImU32(ImGui::GetTime() * 20) % 4], label);
|
||||||
}
|
}
|
||||||
@@ -344,8 +334,8 @@ namespace ImGui {
|
|||||||
glGenTextures(1, &texture);
|
glGenTextures(1, &texture);
|
||||||
glBindTexture(GL_TEXTURE_2D, texture);
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
|
||||||
#if defined(GL_UNPACK_ROW_LENGTH)
|
#if defined(GL_UNPACK_ROW_LENGTH)
|
||||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||||
@@ -497,7 +487,7 @@ namespace ImGui {
|
|||||||
return pressed;
|
return pressed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool InputIntegerPrefix(const char *label, const char *prefix, u64 *value, ImGuiInputTextFlags flags) {
|
bool InputIntegerPrefix(const char *label, const char *prefix, void *value, ImGuiDataType type, ImGuiInputTextFlags flags) {
|
||||||
auto window = ImGui::GetCurrentWindow();
|
auto window = ImGui::GetCurrentWindow();
|
||||||
const ImGuiID id = window->GetID(label);
|
const ImGuiID id = window->GetID(label);
|
||||||
const ImGuiStyle &style = GImGui->Style;
|
const ImGuiStyle &style = GImGui->Style;
|
||||||
@@ -510,7 +500,7 @@ namespace ImGui {
|
|||||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + frame_size.x);
|
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + frame_size.x);
|
||||||
|
|
||||||
char buf[64];
|
char buf[64];
|
||||||
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), ImGuiDataType_U64, value, "%llX");
|
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), type, value, "%llX");
|
||||||
|
|
||||||
bool value_changed = false;
|
bool value_changed = false;
|
||||||
if (InputTextEx(label, nullptr, buf, IM_ARRAYSIZE(buf), ImVec2(CalcItemWidth() - frame_size.x, label_size.y + style.FramePadding.y * 2.0f), flags))
|
if (InputTextEx(label, nullptr, buf, IM_ARRAYSIZE(buf), ImVec2(CalcItemWidth() - frame_size.x, label_size.y + style.FramePadding.y * 2.0f), flags))
|
||||||
@@ -529,8 +519,12 @@ namespace ImGui {
|
|||||||
return value_changed;
|
return value_changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InputHexadecimal(const char *label, u32 *value, ImGuiInputTextFlags flags) {
|
||||||
|
return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U32, flags | ImGuiInputTextFlags_CharsHexadecimal);
|
||||||
|
}
|
||||||
|
|
||||||
bool InputHexadecimal(const char *label, u64 *value, ImGuiInputTextFlags flags) {
|
bool InputHexadecimal(const char *label, u64 *value, ImGuiInputTextFlags flags) {
|
||||||
return InputIntegerPrefix(label, "0x", value, flags | ImGuiInputTextFlags_CharsHexadecimal);
|
return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U64, flags | ImGuiInputTextFlags_CharsHexadecimal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SmallProgressBar(float fraction, float yOffset) {
|
void SmallProgressBar(float fraction, float yOffset) {
|
||||||
@@ -559,8 +553,96 @@ namespace ImGui {
|
|||||||
return ImGui::InputText(label, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
|
return ImGui::InputText(label, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InputTextWithHint(const char *label, const char *hint, std::string &buffer, ImGuiInputTextFlags flags) {
|
||||||
|
return ImGui::InputTextWithHint(label, hint, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool InputText(const char *label, std::u8string &buffer, ImGuiInputTextFlags flags) {
|
||||||
|
return ImGui::InputText(label, reinterpret_cast<char *>(buffer.data()), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
|
||||||
|
}
|
||||||
|
|
||||||
bool InputTextMultiline(const char *label, std::string &buffer, const ImVec2 &size, ImGuiInputTextFlags flags) {
|
bool InputTextMultiline(const char *label, std::string &buffer, const ImVec2 &size, ImGuiInputTextFlags flags) {
|
||||||
return ImGui::InputTextMultiline(label, buffer.data(), buffer.size() + 1, size, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
|
return ImGui::InputTextMultiline(label, buffer.data(), buffer.size() + 1, size, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InputScalarCallback(const char* label, ImGuiDataType data_type, void* p_data, const char* format, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) {
|
||||||
|
ImGuiWindow* window = GetCurrentWindow();
|
||||||
|
if (window->SkipItems)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ImGuiContext& g = *GImGui;
|
||||||
|
|
||||||
|
if (format == NULL)
|
||||||
|
format = DataTypeGetInfo(data_type)->PrintFmt;
|
||||||
|
|
||||||
|
char buf[64];
|
||||||
|
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format);
|
||||||
|
|
||||||
|
bool value_changed = false;
|
||||||
|
if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0)
|
||||||
|
flags |= ImGuiInputTextFlags_CharsDecimal;
|
||||||
|
flags |= ImGuiInputTextFlags_AutoSelectAll;
|
||||||
|
flags |= ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselves by comparing the actual data rather than the string.
|
||||||
|
|
||||||
|
if (InputText(label, buf, IM_ARRAYSIZE(buf), flags, callback, user_data))
|
||||||
|
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, p_data, format);
|
||||||
|
|
||||||
|
if (value_changed)
|
||||||
|
MarkItemEdited(g.LastItemData.ID);
|
||||||
|
|
||||||
|
return value_changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
void HideTooltip() {
|
||||||
|
char window_name[16];
|
||||||
|
ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", GImGui->TooltipOverrideCount);
|
||||||
|
if (ImGuiWindow* window = FindWindowByName(window_name); window != nullptr) {
|
||||||
|
if (window->Active)
|
||||||
|
window->Hidden = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool BitCheckbox(const char* label, bool* v) {
|
||||||
|
ImGuiWindow* window = GetCurrentWindow();
|
||||||
|
if (window->SkipItems)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
ImGuiContext& g = *GImGui;
|
||||||
|
const ImGuiStyle& style = g.Style;
|
||||||
|
const ImGuiID id = window->GetID(label);
|
||||||
|
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||||
|
|
||||||
|
const ImVec2 size = ImVec2(CalcTextSize("0").x + style.FramePadding.x * 2, GetFrameHeight());
|
||||||
|
const ImVec2 pos = window->DC.CursorPos;
|
||||||
|
const ImRect total_bb(pos, pos + size);
|
||||||
|
ItemSize(total_bb, style.FramePadding.y);
|
||||||
|
if (!ItemAdd(total_bb, id))
|
||||||
|
{
|
||||||
|
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool hovered, held;
|
||||||
|
bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
|
||||||
|
if (pressed)
|
||||||
|
{
|
||||||
|
*v = !(*v);
|
||||||
|
MarkItemEdited(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImRect check_bb(pos, pos + size);
|
||||||
|
RenderNavHighlight(total_bb, id);
|
||||||
|
RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
|
||||||
|
|
||||||
|
RenderText(check_bb.Min + style.FramePadding, *v ? "1" : "0");
|
||||||
|
|
||||||
|
ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);
|
||||||
|
if (label_size.x > 0.0f)
|
||||||
|
RenderText(label_pos, label);
|
||||||
|
|
||||||
|
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
|
||||||
|
return pressed;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -8,15 +8,6 @@
|
|||||||
|
|
||||||
namespace hex {
|
namespace hex {
|
||||||
|
|
||||||
std::string View::s_popupMessage;
|
|
||||||
|
|
||||||
std::function<void()> View::s_yesCallback, View::s_noCallback;
|
|
||||||
|
|
||||||
u32 View::s_selectableFileIndex;
|
|
||||||
std::vector<std::fs::path> View::s_selectableFiles;
|
|
||||||
std::function<void(std::fs::path)> View::s_selectableFileOpenCallback;
|
|
||||||
std::vector<nfdfilteritem_t> View::s_selectableFilesValidExtensions;
|
|
||||||
|
|
||||||
ImFontAtlas *View::s_fontAtlas;
|
ImFontAtlas *View::s_fontAtlas;
|
||||||
ImFontConfig View::s_fontConfig;
|
ImFontConfig View::s_fontConfig;
|
||||||
|
|
||||||
@@ -26,123 +17,21 @@ namespace hex {
|
|||||||
return ImHexApi::Provider::isValid() && ImHexApi::Provider::get()->isAvailable();
|
return ImHexApi::Provider::isValid() && ImHexApi::Provider::get()->isAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
void View::drawCommonInterfaces() {
|
void View::showInfoPopup(const std::string &message) {
|
||||||
auto windowSize = ImHexApi::System::getMainWindowSize();
|
EventManager::post<RequestShowInfoPopup>(message);
|
||||||
|
|
||||||
ImGui::SetNextWindowSizeConstraints(scaled(ImVec2(400, 100)), scaled(ImVec2(600, 300)));
|
|
||||||
if (ImGui::BeginPopupModal("hex.builtin.common.info"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
|
||||||
ImGui::TextFormattedWrapped("{}", s_popupMessage.c_str());
|
|
||||||
ImGui::NewLine();
|
|
||||||
ImGui::Separator();
|
|
||||||
if (ImGui::Button("hex.builtin.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape))
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
|
|
||||||
ImGui::SetWindowPos((windowSize - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SetNextWindowSizeConstraints(scaled(ImVec2(400, 100)), scaled(ImVec2(600, 300)));
|
|
||||||
if (ImGui::BeginPopupModal("hex.builtin.common.error"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
|
||||||
ImGui::TextFormattedWrapped("{}", s_popupMessage.c_str());
|
|
||||||
ImGui::NewLine();
|
|
||||||
ImGui::Separator();
|
|
||||||
if (ImGui::Button("hex.builtin.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape))
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
|
|
||||||
ImGui::SetWindowPos((windowSize - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SetNextWindowSizeConstraints(scaled(ImVec2(400, 100)), scaled(ImVec2(600, 300)));
|
|
||||||
if (ImGui::BeginPopupModal("hex.builtin.common.fatal"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
|
||||||
ImGui::TextFormattedWrapped("{}", s_popupMessage.c_str());
|
|
||||||
ImGui::NewLine();
|
|
||||||
ImGui::Separator();
|
|
||||||
if (ImGui::Button("hex.builtin.common.okay"_lang) || ImGui::IsKeyDown(ImGuiKey_Escape)) {
|
|
||||||
ImHexApi::Common::closeImHex();
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SetWindowPos((windowSize - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SetNextWindowSizeConstraints(scaled(ImVec2(400, 100)), scaled(ImVec2(600, 300)));
|
|
||||||
if (ImGui::BeginPopupModal("hex.builtin.common.question"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
|
||||||
ImGui::TextFormattedWrapped("{}", s_popupMessage.c_str());
|
|
||||||
ImGui::NewLine();
|
|
||||||
ImGui::Separator();
|
|
||||||
|
|
||||||
View::confirmButtons(
|
|
||||||
"hex.builtin.common.yes"_lang, "hex.builtin.common.no"_lang, [] {
|
|
||||||
s_yesCallback();
|
|
||||||
ImGui::CloseCurrentPopup(); }, [] {
|
|
||||||
s_noCallback();
|
|
||||||
ImGui::CloseCurrentPopup(); });
|
|
||||||
|
|
||||||
ImGui::SetWindowPos((windowSize - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing);
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool opened = true;
|
|
||||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F));
|
|
||||||
if (ImGui::BeginPopupModal("hex.builtin.common.choose_file"_lang, &opened, ImGuiWindowFlags_AlwaysAutoResize)) {
|
|
||||||
|
|
||||||
if (ImGui::BeginListBox("##files", ImVec2(300_scaled, 0))) {
|
|
||||||
|
|
||||||
u32 index = 0;
|
|
||||||
for (auto &path : View::s_selectableFiles) {
|
|
||||||
if (ImGui::Selectable(path.filename().string().c_str(), index == View::s_selectableFileIndex))
|
|
||||||
View::s_selectableFileIndex = index;
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndListBox();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::Button("hex.builtin.common.open"_lang)) {
|
|
||||||
View::s_selectableFileOpenCallback(View::s_selectableFiles[View::s_selectableFileIndex]);
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::SameLine();
|
|
||||||
|
|
||||||
if (ImGui::Button("hex.builtin.common.browse"_lang)) {
|
|
||||||
fs::openFileBrowser(fs::DialogMode::Open, View::s_selectableFilesValidExtensions, [](const auto &path) {
|
|
||||||
View::s_selectableFileOpenCallback(path);
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void View::showMessagePopup(const std::string &message) {
|
void View::showErrorPopup(const std::string &message) {
|
||||||
s_popupMessage = message;
|
EventManager::post<RequestShowErrorPopup>(message);
|
||||||
|
|
||||||
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.info"_lang); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void View::showErrorPopup(const std::string &errorMessage) {
|
void View::showFatalPopup(const std::string &message) {
|
||||||
s_popupMessage = errorMessage;
|
EventManager::post<RequestShowFatalErrorPopup>(message);
|
||||||
|
|
||||||
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.error"_lang); });
|
|
||||||
}
|
|
||||||
|
|
||||||
void View::showFatalPopup(const std::string &errorMessage) {
|
|
||||||
s_popupMessage = errorMessage;
|
|
||||||
|
|
||||||
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.fatal"_lang); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void View::showYesNoQuestionPopup(const std::string &message, const std::function<void()> &yesCallback, const std::function<void()> &noCallback) {
|
void View::showYesNoQuestionPopup(const std::string &message, const std::function<void()> &yesCallback, const std::function<void()> &noCallback) {
|
||||||
s_popupMessage = message;
|
EventManager::post<RequestShowYesNoQuestionPopup>(message, yesCallback, noCallback);
|
||||||
|
|
||||||
s_yesCallback = yesCallback;
|
|
||||||
s_noCallback = noCallback;
|
|
||||||
|
|
||||||
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.question"_lang); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void View::showFileChooserPopup(const std::vector<std::fs::path> &paths, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback) {
|
void View::showFileChooserPopup(const std::vector<std::fs::path> &paths, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback) {
|
||||||
@@ -151,12 +40,7 @@ namespace hex {
|
|||||||
callback(path);
|
callback(path);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
View::s_selectableFileIndex = 0;
|
EventManager::post<RequestShowFileChooserPopup>(paths, validExtensions, callback);
|
||||||
View::s_selectableFiles = paths;
|
|
||||||
View::s_selectableFilesValidExtensions = validExtensions;
|
|
||||||
View::s_selectableFileOpenCallback = callback;
|
|
||||||
|
|
||||||
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.common.choose_file"_lang); });
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ set_target_properties(main PROPERTIES
|
|||||||
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
target_link_libraries(main PUBLIC libimhex wsock32 ws2_32 Dwmapi.lib)
|
target_link_libraries(main PUBLIC usp10 libimhex wsock32 ws2_32 Dwmapi.lib)
|
||||||
else ()
|
else ()
|
||||||
target_link_libraries(main PUBLIC libimhex pthread)
|
target_link_libraries(main PUBLIC libimhex pthread)
|
||||||
endif ()
|
endif ()
|
||||||
|
|||||||
@@ -23,8 +23,6 @@ namespace hex::init {
|
|||||||
this->m_tasks.emplace_back(taskName, task);
|
this->m_tasks.emplace_back(taskName, task);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const std::string &getGPUVendor() const { return this->m_gpuVendor; }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
GLFWwindow *m_window;
|
GLFWwindow *m_window;
|
||||||
std::mutex m_progressMutex;
|
std::mutex m_progressMutex;
|
||||||
|
|||||||
@@ -54,6 +54,8 @@ namespace hex {
|
|||||||
std::vector<int> m_pressedKeys;
|
std::vector<int> m_pressedKeys;
|
||||||
|
|
||||||
std::fs::path m_imguiSettingsPath;
|
std::fs::path m_imguiSettingsPath;
|
||||||
|
|
||||||
|
bool m_mouseButtonDown = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -13,7 +13,7 @@
|
|||||||
#include <hex/ui/imgui_imhex_extensions.h>
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
#include <imgui_impl_glfw.h>
|
#include <imgui_impl_glfw.h>
|
||||||
#include <imgui_impl_opengl3.h>
|
#include <imgui_impl_opengl3.h>
|
||||||
#include <fontawesome_font.h>
|
#include <fonts/fontawesome_font.h>
|
||||||
#include <GLFW/glfw3.h>
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
@@ -30,7 +30,7 @@ namespace hex::init {
|
|||||||
this->initGLFW();
|
this->initGLFW();
|
||||||
this->initImGui();
|
this->initImGui();
|
||||||
|
|
||||||
this->m_gpuVendor = reinterpret_cast<const char *>(glGetString(GL_VENDOR));
|
ImHexApi::System::impl::setGPUVendor(reinterpret_cast<const char *>(glGetString(GL_VENDOR)));
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowSplash::~WindowSplash() {
|
WindowSplash::~WindowSplash() {
|
||||||
@@ -173,18 +173,20 @@ namespace hex::init {
|
|||||||
|
|
||||||
auto meanScale = std::midpoint(xScale, yScale);
|
auto meanScale = std::midpoint(xScale, yScale);
|
||||||
|
|
||||||
// On Macs with a retina display (basically all modern ones we care about), the OS reports twice
|
// On Macs with a retina display (basically all modern ones we care about), the OS reports twice
|
||||||
// the actual monitor scale for some obscure reason. Get rid of this here so ImHex doesn't look
|
// the actual monitor scale for some obscure reason. Get rid of this here so ImHex doesn't look
|
||||||
// extremely huge with native scaling on macOS.
|
// extremely huge with native scaling on macOS.
|
||||||
#if defined(OS_MACOS)
|
#if defined(OS_MACOS)
|
||||||
meanScale /= 2;
|
meanScale /= 2;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (meanScale <= 0) {
|
if (meanScale <= 0.0) {
|
||||||
meanScale = 1.0;
|
meanScale = 1.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ImHexApi::System::impl::setGlobalScale(meanScale);
|
ImHexApi::System::impl::setGlobalScale(meanScale);
|
||||||
|
} else {
|
||||||
|
ImHexApi::System::impl::setGlobalScale(1.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
this->m_window = glfwCreateWindow(640_scaled, 400_scaled, "Starting ImHex...", nullptr, nullptr);
|
this->m_window = glfwCreateWindow(640_scaled, 400_scaled, "Starting ImHex...", nullptr, nullptr);
|
||||||
|
|||||||
@@ -9,9 +9,9 @@
|
|||||||
#include <hex/helpers/fs.hpp>
|
#include <hex/helpers/fs.hpp>
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
|
|
||||||
#include <fontawesome_font.h>
|
#include <fonts/fontawesome_font.h>
|
||||||
#include <codicons_font.h>
|
#include <fonts/codicons_font.h>
|
||||||
#include <unifont_font.h>
|
#include <fonts/unifont_font.h>
|
||||||
|
|
||||||
#include <hex/api/plugin_manager.hpp>
|
#include <hex/api/plugin_manager.hpp>
|
||||||
|
|
||||||
@@ -93,23 +93,6 @@ namespace hex::init {
|
|||||||
auto fonts = IM_NEW(ImFontAtlas)();
|
auto fonts = IM_NEW(ImFontAtlas)();
|
||||||
ImFontConfig cfg = {};
|
ImFontConfig cfg = {};
|
||||||
|
|
||||||
std::fs::path fontFile = ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_path", "");
|
|
||||||
if (!fs::exists(fontFile))
|
|
||||||
fontFile.clear();
|
|
||||||
|
|
||||||
// If no custom font has been specified, search for a file called "font.ttf" in one of the resource folders
|
|
||||||
if (fontFile.empty()) {
|
|
||||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Resources)) {
|
|
||||||
auto path = dir / "font.ttf";
|
|
||||||
if (fs::exists(path)) {
|
|
||||||
log::info("Loading custom front from {}", path.string());
|
|
||||||
|
|
||||||
fontFile = path;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ImVector<ImWchar> ranges;
|
ImVector<ImWchar> ranges;
|
||||||
{
|
{
|
||||||
ImFontGlyphRangesBuilder glyphRangesBuilder;
|
ImFontGlyphRangesBuilder glyphRangesBuilder;
|
||||||
@@ -135,7 +118,8 @@ namespace hex::init {
|
|||||||
0x0100, 0xFFF0, 0
|
0x0100, 0xFFF0, 0
|
||||||
};
|
};
|
||||||
|
|
||||||
float fontSize = 13.0F * ImHexApi::System::getGlobalScale();
|
auto fontFile = ImHexApi::System::getCustomFontPath();
|
||||||
|
float fontSize = ImHexApi::System::getFontSize();
|
||||||
if (fontFile.empty()) {
|
if (fontFile.empty()) {
|
||||||
// Load default font if no custom one has been specified
|
// Load default font if no custom one has been specified
|
||||||
|
|
||||||
@@ -147,8 +131,6 @@ namespace hex::init {
|
|||||||
} else {
|
} else {
|
||||||
// Load custom font
|
// Load custom font
|
||||||
|
|
||||||
fontSize = ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_size", 13) * ImHexApi::System::getGlobalScale();
|
|
||||||
|
|
||||||
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
|
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
|
||||||
cfg.SizePixels = fontSize;
|
cfg.SizePixels = fontSize;
|
||||||
|
|
||||||
@@ -170,24 +152,34 @@ namespace hex::init {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool deleteSharedData() {
|
bool deleteSharedData() {
|
||||||
ImHexApi::System::getInitArguments().clear();
|
|
||||||
ImHexApi::Tasks::getDeferredCalls().clear();
|
|
||||||
ImHexApi::HexEditor::impl::getHighlights().clear();
|
|
||||||
ImHexApi::HexEditor::impl::getHighlightingFunctions().clear();
|
|
||||||
|
|
||||||
while (ImHexApi::Provider::isValid())
|
while (ImHexApi::Provider::isValid())
|
||||||
ImHexApi::Provider::remove(ImHexApi::Provider::get());
|
ImHexApi::Provider::remove(ImHexApi::Provider::get());
|
||||||
ContentRegistry::Provider::getEntries().clear();
|
ContentRegistry::Provider::getEntries().clear();
|
||||||
|
|
||||||
|
ImHexApi::System::getInitArguments().clear();
|
||||||
|
ImHexApi::Tasks::getDeferredCalls().clear();
|
||||||
|
ImHexApi::HexEditor::impl::getBackgroundHighlights().clear();
|
||||||
|
ImHexApi::HexEditor::impl::getForegroundHighlights().clear();
|
||||||
|
ImHexApi::HexEditor::impl::getBackgroundHighlightingFunctions().clear();
|
||||||
|
ImHexApi::HexEditor::impl::getForegroundHighlightingFunctions().clear();
|
||||||
|
ImHexApi::HexEditor::impl::getTooltips().clear();
|
||||||
|
ImHexApi::HexEditor::impl::getTooltipFunctions().clear();
|
||||||
|
|
||||||
ContentRegistry::Settings::getEntries().clear();
|
ContentRegistry::Settings::getEntries().clear();
|
||||||
ContentRegistry::Settings::getSettingsData().clear();
|
ContentRegistry::Settings::getSettingsData().clear();
|
||||||
|
|
||||||
ContentRegistry::CommandPaletteCommands::getEntries().clear();
|
ContentRegistry::CommandPaletteCommands::getEntries().clear();
|
||||||
ContentRegistry::PatternLanguage::getFunctions().clear();
|
|
||||||
|
|
||||||
for (auto &[name, view] : ContentRegistry::Views::getEntries())
|
ContentRegistry::PatternLanguage::getFunctions().clear();
|
||||||
delete view;
|
ContentRegistry::PatternLanguage::getPragmas().clear();
|
||||||
ContentRegistry::Views::getEntries().clear();
|
|
||||||
|
{
|
||||||
|
auto &views = ContentRegistry::Views::getEntries();
|
||||||
|
for (auto &[name, view] : views)
|
||||||
|
delete view;
|
||||||
|
views.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ContentRegistry::Tools::getEntries().clear();
|
ContentRegistry::Tools::getEntries().clear();
|
||||||
ContentRegistry::DataInspector::getEntries().clear();
|
ContentRegistry::DataInspector::getEntries().clear();
|
||||||
@@ -214,6 +206,13 @@ namespace hex::init {
|
|||||||
ContentRegistry::DataFormatter::getEntries().clear();
|
ContentRegistry::DataFormatter::getEntries().clear();
|
||||||
ContentRegistry::FileHandler::getEntries().clear();
|
ContentRegistry::FileHandler::getEntries().clear();
|
||||||
|
|
||||||
|
{
|
||||||
|
auto &visualizers = ContentRegistry::HexEditor::impl::getVisualizers();
|
||||||
|
for (auto &[name, visualizer] : visualizers)
|
||||||
|
delete visualizer;
|
||||||
|
visualizers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -286,28 +285,6 @@ namespace hex::init {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
float interfaceScaling = 1.0F;
|
|
||||||
switch (ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.scaling", 0)) {
|
|
||||||
default:
|
|
||||||
case 0:
|
|
||||||
// Native scaling
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
interfaceScaling = 0.5F;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
interfaceScaling = 1.0F;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
interfaceScaling = 1.5F;
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
interfaceScaling = 2.0F;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImHexApi::System::impl::setGlobalScale(interfaceScaling);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,17 +25,6 @@ int main(int argc, char **argv, char **envp) {
|
|||||||
|
|
||||||
init::WindowSplash splashWindow;
|
init::WindowSplash splashWindow;
|
||||||
|
|
||||||
// Intel's OpenGL driver has weird bugs that cause the drawn window to be offset to the bottom right.
|
|
||||||
// This can be fixed by either using Mesa3D's OpenGL Software renderer or by simply disabling it.
|
|
||||||
// If you want to try if it works anyways on your GPU, set the hex.builtin.setting.interface.force_borderless_window_mode setting to 1
|
|
||||||
if (ImHexApi::System::isBorderlessWindowModeEnabled()) {
|
|
||||||
bool isIntelGPU = hex::containsIgnoreCase(splashWindow.getGPUVendor(), "Intel");
|
|
||||||
ImHexApi::System::impl::setBorderlessWindowMode(!isIntelGPU);
|
|
||||||
|
|
||||||
if (isIntelGPU)
|
|
||||||
log::warn("Intel GPU detected! Intel's OpenGL driver has bugs that can cause issues when using ImHex. If you experience any rendering bugs, please try the Mesa3D Software Renderer");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto &[name, task] : init::getInitTasks())
|
for (const auto &[name, task] : init::getInitTasks())
|
||||||
splashWindow.addStartupTask(name, task);
|
splashWindow.addStartupTask(name, task);
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#if defined(OS_LINUX)
|
#if defined(OS_LINUX)
|
||||||
|
|
||||||
|
#include <hex/api/imhex_api.hpp>
|
||||||
#include <hex/api/content_registry.hpp>
|
#include <hex/api/content_registry.hpp>
|
||||||
#include <hex/api/event.hpp>
|
#include <hex/api/event.hpp>
|
||||||
|
|
||||||
@@ -21,7 +22,7 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Window::setupNativeWindow() {
|
void Window::setupNativeWindow() {
|
||||||
bool themeFollowSystem = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color") == 0;
|
bool themeFollowSystem = ImHexApi::System::usesSystemThemeDetection();
|
||||||
EventManager::subscribe<EventOSThemeChanged>(this, [themeFollowSystem] {
|
EventManager::subscribe<EventOSThemeChanged>(this, [themeFollowSystem] {
|
||||||
if (!themeFollowSystem) return;
|
if (!themeFollowSystem) return;
|
||||||
|
|
||||||
@@ -38,7 +39,7 @@ namespace hex {
|
|||||||
auto exitCode = WEXITSTATUS(pclose(pipe));
|
auto exitCode = WEXITSTATUS(pclose(pipe));
|
||||||
if (exitCode != 0) return;
|
if (exitCode != 0) return;
|
||||||
|
|
||||||
EventManager::post<RequestChangeTheme>(hex::containsIgnoreCase(result, "dark") ? 1 : 2);
|
EventManager::post<RequestChangeTheme>(hex::containsIgnoreCase(result, "light") ? 2 : 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (themeFollowSystem)
|
if (themeFollowSystem)
|
||||||
|
|||||||
@@ -2,9 +2,11 @@
|
|||||||
|
|
||||||
#if defined(OS_MACOS)
|
#if defined(OS_MACOS)
|
||||||
|
|
||||||
|
#include <hex/api/imhex_api.hpp>
|
||||||
#include <hex/api/content_registry.hpp>
|
#include <hex/api/content_registry.hpp>
|
||||||
#include <hex/api/event.hpp>
|
#include <hex/api/event.hpp>
|
||||||
|
|
||||||
|
#include <hex/helpers/utils_macos.hpp>
|
||||||
#include <hex/helpers/logger.hpp>
|
#include <hex/helpers/logger.hpp>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
@@ -19,12 +21,14 @@ namespace hex {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Window::setupNativeWindow() {
|
void Window::setupNativeWindow() {
|
||||||
bool themeFollowSystem = ContentRegistry::Settings::getSetting("hex.builtin.setting.interface", "hex.builtin.setting.interface.color") == 0;
|
bool themeFollowSystem = ImHexApi::System::usesSystemThemeDetection();
|
||||||
EventManager::subscribe<EventOSThemeChanged>(this, [themeFollowSystem] {
|
EventManager::subscribe<EventOSThemeChanged>(this, [themeFollowSystem] {
|
||||||
if (!themeFollowSystem) return;
|
if (!themeFollowSystem) return;
|
||||||
|
|
||||||
// TODO: Implement this when MacOS build is working again
|
if (!isMacosSystemDarkModeEnabled())
|
||||||
EventManager::post<RequestChangeTheme>(1);
|
EventManager::post<RequestChangeTheme>(2);
|
||||||
|
else
|
||||||
|
EventManager::post<RequestChangeTheme>(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
if (themeFollowSystem)
|
if (themeFollowSystem)
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <imgui_internal.h>
|
#include <imgui_internal.h>
|
||||||
#include <codicons_font.h>
|
#include <fonts/codicons_font.h>
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
#include <imnodes.h>
|
#include <imnodes.h>
|
||||||
#include <imnodes_internal.h>
|
#include <imnodes_internal.h>
|
||||||
|
|
||||||
#include <codicons_font.h>
|
#include <fonts/codicons_font.h>
|
||||||
|
|
||||||
#include <hex/helpers/project_file_handler.hpp>
|
#include <hex/helpers/project_file_handler.hpp>
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ namespace hex {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||||
if (ProjectFile::store((std::fs::path(path) / CrashBackupFileName).string()))
|
if (ProjectFile::store(std::fs::path(path) / CrashBackupFileName))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -177,9 +177,10 @@ namespace hex {
|
|||||||
glfwWaitEvents();
|
glfwWaitEvents();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
double timeout = (1.0 / 5.0) - (glfwGetTime() - this->m_lastFrameTime);
|
const bool frameRateThrottled = !(ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) || Task::getRunningTaskCount() > 0 || this->m_mouseButtonDown);
|
||||||
timeout = timeout > 0 ? timeout : 0;
|
const double timeout = std::max(0.0, (1.0 / 5.0) - (glfwGetTime() - this->m_lastFrameTime));
|
||||||
glfwWaitEventsTimeout(ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) || Task::getRunningTaskCount() > 0 ? 0 : timeout);
|
|
||||||
|
glfwWaitEventsTimeout(frameRateThrottled ? timeout : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -197,7 +198,7 @@ namespace hex {
|
|||||||
|
|
||||||
ImGuiViewport *viewport = ImGui::GetMainViewport();
|
ImGuiViewport *viewport = ImGui::GetMainViewport();
|
||||||
ImGui::SetNextWindowPos(viewport->WorkPos);
|
ImGui::SetNextWindowPos(viewport->WorkPos);
|
||||||
ImGui::SetNextWindowSize(viewport->WorkSize);
|
ImGui::SetNextWindowSize(ImHexApi::System::getMainWindowSize() - ImVec2(0, ImGui::GetTextLineHeightWithSpacing()));
|
||||||
ImGui::SetNextWindowViewport(viewport->ID);
|
ImGui::SetNextWindowViewport(viewport->ID);
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||||
@@ -347,11 +348,12 @@ namespace hex {
|
|||||||
ImGui::TableHeadersRow();
|
ImGui::TableHeadersRow();
|
||||||
|
|
||||||
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Plugins, true)) {
|
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Plugins, true)) {
|
||||||
|
const auto filePath = path / "builtin.hexplug";
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::TextUnformatted(path.string().c_str());
|
ImGui::TextUnformatted(filePath.string().c_str());
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::TextUnformatted(fs::exists(path) ? ICON_VS_CHECK : ICON_VS_CLOSE);
|
ImGui::TextUnformatted(fs::exists(filePath) ? ICON_VS_CHECK : ICON_VS_CLOSE);
|
||||||
}
|
}
|
||||||
ImGui::EndTable();
|
ImGui::EndTable();
|
||||||
}
|
}
|
||||||
@@ -419,8 +421,6 @@ namespace hex {
|
|||||||
calls.clear();
|
calls.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
View::drawCommonInterfaces();
|
|
||||||
|
|
||||||
for (auto &[name, view] : ContentRegistry::Views::getEntries()) {
|
for (auto &[name, view] : ContentRegistry::Views::getEntries()) {
|
||||||
ImGui::GetCurrentContext()->NextWindowData.ClearFlags();
|
ImGui::GetCurrentContext()->NextWindowData.ClearFlags();
|
||||||
|
|
||||||
@@ -558,7 +558,8 @@ namespace hex {
|
|||||||
});
|
});
|
||||||
|
|
||||||
glfwSetWindowSizeCallback(this->m_window, [](GLFWwindow *window, int width, int height) {
|
glfwSetWindowSizeCallback(this->m_window, [](GLFWwindow *window, int width, int height) {
|
||||||
ImHexApi::System::impl::setMainWindowSize(width, height);
|
if (!glfwGetWindowAttrib(window, GLFW_ICONIFIED))
|
||||||
|
ImHexApi::System::impl::setMainWindowSize(width, height);
|
||||||
|
|
||||||
if (auto g = ImGui::GetCurrentContext(); g == nullptr || g->WithinFrameScope) return;
|
if (auto g = ImGui::GetCurrentContext(); g == nullptr || g->WithinFrameScope) return;
|
||||||
|
|
||||||
@@ -568,23 +569,32 @@ namespace hex {
|
|||||||
win->frameEnd();
|
win->frameEnd();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
glfwSetMouseButtonCallback(this->m_window, [](GLFWwindow *window, int button, int action, int mods) {
|
||||||
|
hex::unused(button, mods);
|
||||||
|
|
||||||
|
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
|
||||||
|
|
||||||
|
if (action == GLFW_PRESS)
|
||||||
|
win->m_mouseButtonDown = true;
|
||||||
|
else if (action == GLFW_RELEASE)
|
||||||
|
win->m_mouseButtonDown = false;
|
||||||
|
});
|
||||||
|
|
||||||
glfwSetKeyCallback(this->m_window, [](GLFWwindow *window, int key, int scancode, int action, int mods) {
|
glfwSetKeyCallback(this->m_window, [](GLFWwindow *window, int key, int scancode, int action, int mods) {
|
||||||
auto keyName = glfwGetKeyName(key, scancode);
|
auto keyName = glfwGetKeyName(key, scancode);
|
||||||
if (keyName != nullptr)
|
if (keyName != nullptr)
|
||||||
key = std::toupper(keyName[0]);
|
key = std::toupper(keyName[0]);
|
||||||
|
|
||||||
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
|
auto win = static_cast<Window *>(glfwGetWindowUserPointer(window));
|
||||||
|
auto &io = ImGui::GetIO();
|
||||||
|
|
||||||
if (action == GLFW_PRESS) {
|
if (action == GLFW_PRESS || action == GLFW_REPEAT) {
|
||||||
auto &io = ImGui::GetIO();
|
|
||||||
|
|
||||||
win->m_pressedKeys.push_back(key);
|
win->m_pressedKeys.push_back(key);
|
||||||
io.KeysDown[key] = true;
|
io.KeysDown[key] = true;
|
||||||
io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
|
io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
|
||||||
io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
|
io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
|
||||||
io.KeyAlt = (mods & GLFW_MOD_ALT) != 0;
|
io.KeyAlt = (mods & GLFW_MOD_ALT) != 0;
|
||||||
} else if (action == GLFW_RELEASE) {
|
} else if (action == GLFW_RELEASE) {
|
||||||
auto &io = ImGui::GetIO();
|
|
||||||
io.KeysDown[key] = false;
|
io.KeysDown[key] = false;
|
||||||
io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
|
io.KeyCtrl = (mods & GLFW_MOD_CONTROL) != 0;
|
||||||
io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
|
io.KeyShift = (mods & GLFW_MOD_SHIFT) != 0;
|
||||||
@@ -643,8 +653,9 @@ namespace hex {
|
|||||||
|
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_NavEnableKeyboard;
|
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable | ImGuiConfigFlags_NavEnableKeyboard;
|
||||||
|
|
||||||
{
|
if (glfwGetPrimaryMonitor() != nullptr) {
|
||||||
auto sessionType = hex::getEnvironmentVariable("XDG_SESSION_TYPE");
|
auto sessionType = hex::getEnvironmentVariable("XDG_SESSION_TYPE");
|
||||||
|
|
||||||
if (!sessionType || !hex::containsIgnoreCase(*sessionType, "wayland"))
|
if (!sessionType || !hex::containsIgnoreCase(*sessionType, "wayland"))
|
||||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,9 @@ add_library(${PROJECT_NAME} SHARED
|
|||||||
source/content/layouts.cpp
|
source/content/layouts.cpp
|
||||||
source/content/main_menu_items.cpp
|
source/content/main_menu_items.cpp
|
||||||
source/content/welcome_screen.cpp
|
source/content/welcome_screen.cpp
|
||||||
|
source/content/data_visualizers.cpp
|
||||||
|
source/content/events.cpp
|
||||||
|
source/content/hashes.cpp
|
||||||
|
|
||||||
source/content/providers/file_provider.cpp
|
source/content/providers/file_provider.cpp
|
||||||
source/content/providers/gdb_provider.cpp
|
source/content/providers/gdb_provider.cpp
|
||||||
@@ -55,6 +58,7 @@ add_library(${PROJECT_NAME} SHARED
|
|||||||
source/lang/it_IT.cpp
|
source/lang/it_IT.cpp
|
||||||
source/lang/zh_CN.cpp
|
source/lang/zh_CN.cpp
|
||||||
source/lang/ja_JP.cpp
|
source/lang/ja_JP.cpp
|
||||||
|
source/lang/pt_BR.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add additional include directories here #
|
# Add additional include directories here #
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ namespace hex::plugin::builtin::prv {
|
|||||||
|
|
||||||
void resize(size_t newSize) override;
|
void resize(size_t newSize) override;
|
||||||
void insert(u64 offset, size_t size) override;
|
void insert(u64 offset, size_t size) override;
|
||||||
|
void remove(u64 offset, size_t size) override;
|
||||||
|
|
||||||
void readRaw(u64 offset, void *buffer, size_t size) override;
|
void readRaw(u64 offset, void *buffer, size_t size) override;
|
||||||
void writeRaw(u64 offset, const void *buffer, size_t size) override;
|
void writeRaw(u64 offset, const void *buffer, size_t size) override;
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ namespace hex::plugin::builtin {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
std::list<ImHexApi::Bookmarks::Entry> m_bookmarks;
|
std::list<ImHexApi::Bookmarks::Entry> m_bookmarks;
|
||||||
|
std::string m_currFilter;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -29,6 +29,7 @@ namespace hex::plugin::builtin {
|
|||||||
|
|
||||||
std::endian m_endian = std::endian::native;
|
std::endian m_endian = std::endian::native;
|
||||||
ContentRegistry::DataInspector::NumberDisplayStyle m_numberDisplayStyle = ContentRegistry::DataInspector::NumberDisplayStyle::Decimal;
|
ContentRegistry::DataInspector::NumberDisplayStyle m_numberDisplayStyle = ContentRegistry::DataInspector::NumberDisplayStyle::Decimal;
|
||||||
|
bool m_invert = false;
|
||||||
|
|
||||||
u64 m_startAddress = 0;
|
u64 m_startAddress = 0;
|
||||||
size_t m_validBytes = 0;
|
size_t m_validBytes = 0;
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <hex/api/content_registry.hpp>
|
||||||
|
|
||||||
#include <hex/ui/view.hpp>
|
#include <hex/ui/view.hpp>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
@@ -16,35 +18,10 @@ namespace hex::plugin::builtin {
|
|||||||
void drawContent() override;
|
void drawContent() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum class HashFunctions
|
ContentRegistry::Hashes::Hash *m_selectedHash = nullptr;
|
||||||
{
|
std::string m_newHashName;
|
||||||
Crc8,
|
|
||||||
Crc16,
|
|
||||||
Crc32,
|
|
||||||
Md5,
|
|
||||||
Sha1,
|
|
||||||
Sha224,
|
|
||||||
Sha256,
|
|
||||||
Sha384,
|
|
||||||
Sha512
|
|
||||||
};
|
|
||||||
|
|
||||||
bool m_shouldInvalidate = true;
|
std::vector<ContentRegistry::Hashes::Hash::Function> m_hashFunctions;
|
||||||
int m_currHashFunction = 0;
|
|
||||||
u64 m_hashRegion[2] = { 0 };
|
|
||||||
bool m_shouldMatchSelection = false;
|
|
||||||
|
|
||||||
static constexpr std::array hashFunctionNames {
|
|
||||||
std::pair {HashFunctions::Crc8, "CRC8" },
|
|
||||||
std::pair { HashFunctions::Crc16, "CRC16" },
|
|
||||||
std::pair { HashFunctions::Crc32, "CRC32" },
|
|
||||||
std::pair { HashFunctions::Md5, "MD5" },
|
|
||||||
std::pair { HashFunctions::Sha1, "SHA-1" },
|
|
||||||
std::pair { HashFunctions::Sha224, "SHA-224"},
|
|
||||||
std::pair { HashFunctions::Sha256, "SHA-256"},
|
|
||||||
std::pair { HashFunctions::Sha384, "SHA-384"},
|
|
||||||
std::pair { HashFunctions::Sha512, "SHA-512"},
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,96 +1,146 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <hex/api/content_registry.hpp>
|
||||||
|
|
||||||
#include <hex/ui/view.hpp>
|
#include <hex/ui/view.hpp>
|
||||||
|
#include <hex/helpers/concepts.hpp>
|
||||||
#include <hex/helpers/encoding_file.hpp>
|
#include <hex/helpers/encoding_file.hpp>
|
||||||
|
|
||||||
#include <imgui_memory_editor.h>
|
#include <algorithm>
|
||||||
|
#include <limits>
|
||||||
#include <list>
|
|
||||||
#include <tuple>
|
|
||||||
#include <random>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace hex::prv {
|
|
||||||
class Provider;
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace hex::plugin::builtin {
|
namespace hex::plugin::builtin {
|
||||||
|
|
||||||
using SearchFunction = std::vector<std::pair<u64, u64>> (*)(prv::Provider *&provider, std::string string);
|
|
||||||
|
|
||||||
struct HighlightBlock {
|
|
||||||
struct Highlight {
|
|
||||||
color_t color;
|
|
||||||
std::vector<std::string> tooltips;
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr static size_t Size = 0x2000;
|
|
||||||
|
|
||||||
u64 base = 0x00;
|
|
||||||
std::array<Highlight, Size> highlight;
|
|
||||||
};
|
|
||||||
|
|
||||||
class ViewHexEditor : public View {
|
class ViewHexEditor : public View {
|
||||||
public:
|
public:
|
||||||
ViewHexEditor();
|
ViewHexEditor();
|
||||||
~ViewHexEditor() override;
|
|
||||||
|
|
||||||
void drawContent() override;
|
void drawContent() override;
|
||||||
void drawAlwaysVisible() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MemoryEditor m_memoryEditor;
|
constexpr static auto InvalidSelection = std::numeric_limits<u64>::max();
|
||||||
|
|
||||||
std::vector<char> m_searchStringBuffer;
|
|
||||||
std::vector<char> m_searchHexBuffer;
|
|
||||||
SearchFunction m_searchFunction = nullptr;
|
|
||||||
std::vector<std::pair<u64, u64>> *m_lastSearchBuffer = nullptr;
|
|
||||||
bool m_searchRequested = false;
|
|
||||||
|
|
||||||
i64 m_lastSearchIndex = 0;
|
|
||||||
std::vector<std::pair<u64, u64>> m_lastStringSearch;
|
|
||||||
std::vector<std::pair<u64, u64>> m_lastHexSearch;
|
|
||||||
|
|
||||||
std::string m_gotoAddressInput;
|
|
||||||
bool m_gotoRequested = false;
|
|
||||||
bool m_evaluateGoto = false;
|
|
||||||
|
|
||||||
u64 m_baseAddress = 0;
|
|
||||||
u64 m_resizeSize = 0;
|
|
||||||
|
|
||||||
std::vector<u8> m_dataToSave;
|
|
||||||
std::set<pl::Pattern *> m_highlightedPatterns;
|
|
||||||
|
|
||||||
std::string m_loaderScriptScriptPath;
|
|
||||||
std::string m_loaderScriptFilePath;
|
|
||||||
|
|
||||||
hex::EncodingFile m_currEncodingFile;
|
|
||||||
u8 m_highlightAlpha = 0x80;
|
|
||||||
|
|
||||||
std::list<HighlightBlock> m_highlights;
|
|
||||||
|
|
||||||
bool m_processingImportExport = false;
|
|
||||||
bool m_advancedDecodingEnabled = false;
|
|
||||||
|
|
||||||
void drawSearchPopup();
|
|
||||||
void drawSearchInput(std::vector<char> *currBuffer, ImGuiInputTextFlags flags);
|
|
||||||
void performSearch(const char *buffer);
|
|
||||||
void performSearchNext();
|
|
||||||
void performSearchPrevious();
|
|
||||||
static int inputCallback(ImGuiInputTextCallbackData *data);
|
|
||||||
|
|
||||||
void drawGotoPopup();
|
|
||||||
void drawEditPopup();
|
|
||||||
|
|
||||||
void openFile(const std::fs::path &path);
|
|
||||||
|
|
||||||
void copyBytes() const;
|
|
||||||
void pasteBytes() const;
|
|
||||||
void copyString() const;
|
|
||||||
|
|
||||||
void registerEvents();
|
|
||||||
void registerShortcuts();
|
void registerShortcuts();
|
||||||
|
void registerEvents();
|
||||||
void registerMenuItems();
|
void registerMenuItems();
|
||||||
|
|
||||||
|
void drawCell(u64 address, u8 *data, size_t size, bool hovered);
|
||||||
|
void drawPopup();
|
||||||
|
void drawSelectionFrame(u32 x, u32 y, u64 byteAddress, u16 bytesPerCell, const ImVec2 &cellPos, const ImVec2 &cellSize);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void setSelection(const Region ®ion) { this->setSelection(region.getStartAddress(), region.getEndAddress()); }
|
||||||
|
void setSelection(u128 start, u128 end) {
|
||||||
|
if (!ImHexApi::Provider::isValid())
|
||||||
|
return;
|
||||||
|
if (start == InvalidSelection && end == InvalidSelection)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (start == InvalidSelection)
|
||||||
|
start = end;
|
||||||
|
if (end == InvalidSelection)
|
||||||
|
end = start;
|
||||||
|
|
||||||
|
auto provider = ImHexApi::Provider::get();
|
||||||
|
|
||||||
|
const size_t maxAddress = provider->getActualSize() + provider->getBaseAddress() - 1;
|
||||||
|
|
||||||
|
this->m_selectionChanged = this->m_selectionStart != start || this->m_selectionEnd != end;
|
||||||
|
|
||||||
|
this->m_selectionStart = std::clamp<u128>(start, 0, maxAddress);
|
||||||
|
this->m_selectionEnd = std::clamp<u128>(end, 0, maxAddress);
|
||||||
|
|
||||||
|
if (this->m_selectionChanged) {
|
||||||
|
EventManager::post<EventRegionSelected>(this->getSelection());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] Region getSelection() const {
|
||||||
|
const auto start = std::min(this->m_selectionStart, this->m_selectionEnd);
|
||||||
|
const auto end = std::max(this->m_selectionStart, this->m_selectionEnd);
|
||||||
|
const size_t size = end - start + 1;
|
||||||
|
|
||||||
|
return { start, size };
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool isSelectionValid() const {
|
||||||
|
return this->m_selectionStart != InvalidSelection && this->m_selectionEnd != InvalidSelection;
|
||||||
|
}
|
||||||
|
|
||||||
|
void jumpToSelection() {
|
||||||
|
this->m_shouldJumpToSelection = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scrollToSelection() {
|
||||||
|
this->m_shouldScrollToSelection = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void jumpIfOffScreen() {
|
||||||
|
this->m_shouldJumpWhenOffScreen = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
class Popup {
|
||||||
|
public:
|
||||||
|
virtual ~Popup() = default;
|
||||||
|
virtual void draw(ViewHexEditor *editor) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
[[nodiscard]] bool isAnyPopupOpen() const {
|
||||||
|
return this->m_currPopup != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::derived_from<Popup> T>
|
||||||
|
[[nodiscard]] bool isPopupOpen() const {
|
||||||
|
return dynamic_cast<T*>(this->m_currPopup.get()) != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<std::derived_from<Popup> T, typename ... Args>
|
||||||
|
void openPopup(Args && ...args) {
|
||||||
|
this->m_currPopup = std::make_unique<T>(std::forward<Args>(args)...);
|
||||||
|
this->m_shouldOpenPopup = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void closePopup() {
|
||||||
|
this->m_currPopup.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void drawEditor(const ImVec2 &size);
|
||||||
|
void drawFooter(const ImVec2 &size);
|
||||||
|
|
||||||
|
void handleSelection(u64 address, u32 bytesPerCell, const u8 *data, bool cellHovered);
|
||||||
|
|
||||||
|
private:
|
||||||
|
u16 m_bytesPerRow = 16;
|
||||||
|
|
||||||
|
ContentRegistry::HexEditor::DataVisualizer *m_currDataVisualizer;
|
||||||
|
|
||||||
|
bool m_shouldJumpToSelection = false;
|
||||||
|
bool m_shouldScrollToSelection = false;
|
||||||
|
bool m_shouldJumpWhenOffScreen = false;
|
||||||
|
|
||||||
|
bool m_selectionChanged = false;
|
||||||
|
u64 m_selectionStart = InvalidSelection;
|
||||||
|
u64 m_selectionEnd = InvalidSelection;
|
||||||
|
|
||||||
|
u16 m_visibleRowCount = 0;
|
||||||
|
|
||||||
|
std::optional<u64> m_editingAddress;
|
||||||
|
bool m_shouldModifyValue = false;
|
||||||
|
bool m_enteredEditingMode = false;
|
||||||
|
bool m_shouldUpdateEditingValue = false;
|
||||||
|
std::vector<u8> m_editingBytes;
|
||||||
|
|
||||||
|
color_t m_selectionColor = 0x00;
|
||||||
|
bool m_upperCaseHex = true;
|
||||||
|
bool m_grayOutZero = true;
|
||||||
|
bool m_showAscii = true;
|
||||||
|
|
||||||
|
bool m_shouldOpenPopup = false;
|
||||||
|
std::unique_ptr<Popup> m_currPopup;
|
||||||
|
|
||||||
|
std::optional<EncodingFile> m_currCustomEncoding;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -21,7 +21,7 @@ namespace hex::plugin::builtin {
|
|||||||
void drawContent() override;
|
void drawContent() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<prv::Provider *, std::vector<std::shared_ptr<pl::Pattern>>> m_sortedPatterns;
|
std::map<prv::Provider *, std::vector<pl::Pattern*>> m_sortedPatterns;
|
||||||
hex::PatternDrawer m_patternDrawer;
|
hex::PatternDrawer m_patternDrawer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
|
|
||||||
#include <TextEditor.h>
|
#include <TextEditor.h>
|
||||||
|
|
||||||
|
namespace pl { class Pattern; }
|
||||||
|
|
||||||
namespace hex::plugin::builtin {
|
namespace hex::plugin::builtin {
|
||||||
|
|
||||||
class ViewPatternEditor : public View {
|
class ViewPatternEditor : public View {
|
||||||
@@ -23,7 +25,7 @@ namespace hex::plugin::builtin {
|
|||||||
void drawContent() override;
|
void drawContent() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
pl::PatternLanguage *m_parserRuntime;
|
std::unique_ptr<pl::PatternLanguage> m_parserRuntime;
|
||||||
|
|
||||||
std::vector<std::fs::path> m_possiblePatternFiles;
|
std::vector<std::fs::path> m_possiblePatternFiles;
|
||||||
u32 m_selectedPatternFile = 0;
|
u32 m_selectedPatternFile = 0;
|
||||||
@@ -54,7 +56,6 @@ namespace hex::plugin::builtin {
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::map<std::string, PatternVariable> m_patternVariables;
|
std::map<std::string, PatternVariable> m_patternVariables;
|
||||||
std::vector<std::string> m_patternTypes;
|
|
||||||
|
|
||||||
enum class EnvVarType
|
enum class EnvVarType
|
||||||
{
|
{
|
||||||
@@ -91,6 +92,8 @@ namespace hex::plugin::builtin {
|
|||||||
void drawEnvVars(ImVec2 size);
|
void drawEnvVars(ImVec2 size);
|
||||||
void drawVariableSettings(ImVec2 size);
|
void drawVariableSettings(ImVec2 size);
|
||||||
|
|
||||||
|
void drawPatternTooltip(pl::Pattern *pattern);
|
||||||
|
|
||||||
void loadPatternFile(const std::fs::path &path);
|
void loadPatternFile(const std::fs::path &path);
|
||||||
void clearPatterns();
|
void clearPatterns();
|
||||||
|
|
||||||
|
|||||||
@@ -21,10 +21,12 @@ namespace hex::plugin::builtin {
|
|||||||
u64 address;
|
u64 address;
|
||||||
size_t size;
|
size_t size;
|
||||||
bool wholeDataMatch;
|
bool wholeDataMatch;
|
||||||
|
|
||||||
u32 highlightId;
|
u32 highlightId;
|
||||||
|
u32 tooltipId;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::vector<std::pair<std::string, std::string>> m_rules;
|
std::vector<std::pair<std::fs::path, std::fs::path>> m_rules;
|
||||||
std::vector<YaraMatch> m_matches;
|
std::vector<YaraMatch> m_matches;
|
||||||
u32 m_selectedRule = 0;
|
u32 m_selectedRule = 0;
|
||||||
bool m_matching = false;
|
bool m_matching = false;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user