Compare commits

..

2 Commits

Author SHA1 Message Date
WerWolv
92b5fd84c2 impr: Simplify tracy integration 2024-06-01 23:57:34 +02:00
WerWolv
3e0bb6d8be feat: Added initial support for tracing function calls and printing exception stack traces 2024-06-01 16:36:36 +02:00
479 changed files with 9870 additions and 78283 deletions

View File

@@ -8,7 +8,7 @@ on:
jobs: jobs:
codeql: codeql:
name: 🐛 CodeQL name: 🐛 CodeQL
runs-on: ubuntu-24.04 runs-on: ubuntu-22.04
permissions: permissions:
actions: read actions: read
contents: read contents: read
@@ -49,7 +49,7 @@ jobs:
set -x set -x
mkdir -p build mkdir -p build
cd build cd build
CC=gcc-14 CXX=g++-14 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 \
@@ -57,9 +57,8 @@ jobs:
-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 \ -DIMHEX_PATTERNS_PULL_MASTER=ON \
-G Ninja \
.. ..
ninja install make -j 4 install
- name: 🗯️ Perform CodeQL Analysis - name: 🗯️ Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2 uses: github/codeql-action/analyze@v2

View File

@@ -64,7 +64,7 @@ jobs:
cd build cd build
cmake -G "Ninja" \ cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \ -DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DIMHEX_GENERATE_PACKAGE=ON \ -DIMHEX_GENERATE_PACKAGE=ON \
-DIMHEX_USE_DEFAULT_BUILD_SETTINGS=ON \ -DIMHEX_USE_DEFAULT_BUILD_SETTINGS=ON \
@@ -82,7 +82,7 @@ jobs:
cd build cd build
ninja install ninja install
cpack cpack
mv ImHex-*.msi ../imhex-${{ env.IMHEX_VERSION }}-Windows-x86_64.msi mv ImHex-*.msi ../imhex-${{env.IMHEX_VERSION}}-Windows-x86_64.msi
echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE
@@ -107,7 +107,7 @@ jobs:
run: | run: |
set -x set -x
echo "NoGPU version Powered by Mesa 3D : https://fdossena.com/?p=mesa%2Findex.frag" > build/install/MESA.md echo "NoGPU version Powered by Mesa 3D : https://fdossena.com/?p=mesa%2Findex.frag" > build/install/MESA.md
curl https://downloads.fdossena.com/geth.php?r=mesa64-latest -L -o mesa.7z curl https://werwolv.net/downloads/mesa/MesaForWindows-x64-latest.7z -L -o mesa.7z
7z e mesa.7z 7z e mesa.7z
mv opengl32.dll build/install mv opengl32.dll build/install
@@ -119,62 +119,9 @@ jobs:
path: | path: |
build/install/* build/install/*
win-plugin-template-test:
runs-on: windows-2022
name: 🧪 Plugin Template Test
defaults:
run:
shell: msys2 {0}
needs: win
env:
IMHEX_SDK_PATH: "${{ github.workspace }}/out/sdk"
steps:
- name: 🧰 Checkout ImHex
uses: actions/checkout@v4
with:
path: imhex
- name: 🟦 Install msys2
uses: msys2/setup-msys2@v2
with:
msystem: mingw64
- name: ⬇️ Install dependencies
run: |
set -x
imhex/dist/get_deps_msys2.sh
- name: 🧰 Checkout ImHex-Plugin-Template
uses: actions/checkout@v4
with:
repository: WerWolv/ImHex-Plugin-Template
submodules: recursive
path: template
- name: ⬇️ Download artifact
uses: actions/download-artifact@v4
with:
name: Windows Portable x86_64
path: out
- name: 🛠️ Build
run: |
set -x
cd template
mkdir -p build
cd build
cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
-DIMHEX_USE_DEFAULT_BUILD_SETTINGS=ON \
-DUSE_SYSTEM_CAPSTONE=ON \
..
ninja
# MacOS build # MacOS build
macos: macos:
runs-on: macos-13 runs-on: macos-12
strategy: strategy:
fail-fast: false fail-fast: false
@@ -185,7 +132,7 @@ jobs:
- suffix: "" - suffix: ""
custom_glfw: false custom_glfw: false
name: 🍎 macOS 13${{ matrix.suffix }} name: 🍎 macOS 12.0${{matrix.suffix}}
steps: steps:
- name: 🧰 Checkout - name: 🧰 Checkout
@@ -206,15 +153,15 @@ jobs:
- name: ⬇️ Install dependencies - name: ⬇️ Install dependencies
run: | run: |
brew reinstall python --quiet || true set -x
brew link --overwrite --quiet python || true brew reinstall python || brew link --overwrite python
brew bundle --no-lock --quiet --file dist/Brewfile || true brew bundle --no-lock --file dist/Brewfile
rm -rf /usr/local/Cellar/capstone rm -rf /usr/local/Cellar/capstone
- name: ⬇️ Install classic glfw - name: ⬇️ Install classic glfw
if: ${{! matrix.custom_glfw }} if: ${{! matrix.custom_glfw}}
run: | run: |
brew install --quiet glfw || true brew install glfw
- name: ⬇️ Install .NET - name: ⬇️ Install .NET
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
@@ -222,7 +169,7 @@ jobs:
dotnet-version: '8.0.100' dotnet-version: '8.0.100'
- name: 🧰 Checkout glfw - name: 🧰 Checkout glfw
if: ${{ matrix.custom_glfw }} if: ${{matrix.custom_glfw}}
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
repository: glfw/glfw repository: glfw/glfw
@@ -230,7 +177,7 @@ jobs:
# GLFW custom build (to allow software rendering) # GLFW custom build (to allow software rendering)
- name: ⬇️ Patch and install custom glfw - name: ⬇️ Patch and install custom glfw
if: ${{ matrix.custom_glfw }} if: ${{matrix.custom_glfw}}
run: | run: |
set -x set -x
cd glfw cd glfw
@@ -240,7 +187,7 @@ jobs:
cd build cd build
cmake -G "Ninja" \ cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
-DBUILD_SHARED_LIBS=ON \ -DBUILD_SHARED_LIBS=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
@@ -255,15 +202,14 @@ jobs:
set -x set -x
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 \ OBJC=$(brew --prefix llvm)/bin/clang \
OBJCXX=$(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" \
cmake -G "Ninja" \ cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
-DIMHEX_GENERATE_PACKAGE=ON \ -DIMHEX_GENERATE_PACKAGE=ON \
-DIMHEX_SYSTEM_LIBRARY_PATH="$(brew --prefix llvm)/lib;$(brew --prefix llvm)/lib/unwind;$(brew --prefix llvm)/lib/c++;$(brew --prefix)/lib" \
-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_OBJC_COMPILER_LAUNCHER=ccache \
@@ -291,12 +237,6 @@ jobs:
cd build/install cd build/install
chmod -R 755 ImHex.app/ chmod -R 755 ImHex.app/
- name: 🔫 Kill XProtect
run: |
# See https://github.com/actions/runner-images/issues/7522
echo Killing XProtect...; sudo pkill -9 XProtect >/dev/null || true;
echo Waiting for XProtect process...; while pgrep XProtect; do sleep 3; done;
- name: 📦 Create DMG - name: 📦 Create DMG
run: | run: |
set -x set -x
@@ -305,24 +245,18 @@ jobs:
cd bundle cd bundle
ln -s /Applications Applications ln -s /Applications Applications
cd .. cd ..
for i in $(seq 1 10); do hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}-x86_64.dmg
if hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{ env.IMHEX_VERSION }}-macOS${{ matrix.suffix }}-x86_64.dmg; then
echo "Created dmg after ${i} attempts"
break
fi
sleep 10
done
- name: ⬆️ Upload DMG - name: ⬆️ Upload DMG
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
if-no-files-found: error if-no-files-found: error
name: macOS DMG${{ matrix.suffix }} x86_64 name: macOS DMG${{matrix.suffix}} x86_64
path: ./*.dmg path: ./*.dmg
macos-arm64-build: macos-arm64-build:
runs-on: ubuntu-24.04 runs-on: ubuntu-22.04
name: 🍎 macOS 13 arm64 name: 🍎 macOS 12.1 arm64
outputs: outputs:
IMHEX_VERSION: ${{ steps.build.outputs.IMHEX_VERSION }} IMHEX_VERSION: ${{ steps.build.outputs.IMHEX_VERSION }}
steps: steps:
@@ -365,8 +299,8 @@ jobs:
gh actions-cache delete "build-macos-arm64-cache" --confirm || true gh actions-cache delete "build-macos-arm64-cache" --confirm || true
macos-arm64-package: macos-arm64-package:
runs-on: macos-13 runs-on: macos-12
name: 🍎 macOS 13 arm64 Packaging name: 🍎 macOS 12.1 arm64 Packaging
needs: macos-arm64-build needs: macos-arm64-build
env: env:
IMHEX_VERSION: ${{ needs.macos-arm64-build.outputs.IMHEX_VERSION }} IMHEX_VERSION: ${{ needs.macos-arm64-build.outputs.IMHEX_VERSION }}
@@ -396,12 +330,6 @@ jobs:
cd out cd out
chmod -R 755 ImHex.app/ chmod -R 755 ImHex.app/
- name: 🔫 Kill XProtect
run: |
# See https://github.com/actions/runner-images/issues/7522
echo Killing XProtect...; sudo pkill -9 XProtect >/dev/null || true;
echo Waiting for XProtect process...; while pgrep XProtect; do sleep 3; done;
- name: 📦 Create DMG - name: 📦 Create DMG
run: | run: |
set -x set -x
@@ -410,13 +338,7 @@ jobs:
cd bundle cd bundle
ln -s /Applications Applications ln -s /Applications Applications
cd .. cd ..
for i in $(seq 1 10); do hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{env.IMHEX_VERSION}}-macOS-arm64.dmg
if hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{ env.IMHEX_VERSION }}-macOS-arm64.dmg; then
echo "Created dmg after ${i} attempts"
break
fi
sleep 10
done
- name: ⬆️ Upload DMG - name: ⬆️ Upload DMG
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@@ -431,11 +353,11 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
- release_num: "24.04" - release_num: 22.04
- release_num: "24.10" - release_num: 23.04
name: 🐧 Ubuntu ${{ matrix.release_num }} name: 🐧 Ubuntu ${{ matrix.release_num }}
runs-on: ubuntu-24.04 runs-on: ubuntu-latest
container: container:
image: "ubuntu:${{ matrix.release_num }}" image: "ubuntu:${{ matrix.release_num }}"
@@ -453,8 +375,8 @@ jobs:
- name: 📜 Setup ccache - name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1 uses: hendrikmuhs/ccache-action@v1
with: with:
key: Ubuntu-${{ matrix.release_num }}-ccache-${{ github.run_id }} key: Ubuntu-${{matrix.release_num}}-ccache-${{ github.run_id }}
restore-keys: Ubuntu-${{ matrix.release_num }}-ccache restore-keys: Ubuntu-${{matrix.release_num}}-ccache
max-size: 1G max-size: 1G
- name: ⬇️ Install dependencies - name: ⬇️ Install dependencies
@@ -462,6 +384,11 @@ jobs:
apt update apt update
bash dist/get_deps_debian.sh bash dist/get_deps_debian.sh
apt install software-properties-common -y
add-apt-repository ppa:ubuntu-toolchain-r/test -y
apt update
apt install -y gcc-13 g++-13
- name: ⬇️ Install .NET - name: ⬇️ Install .NET
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v4
with: with:
@@ -475,8 +402,8 @@ jobs:
git config --global --add safe.directory '*' git config --global --add safe.directory '*'
mkdir -p build mkdir -p build
cd build cd build
CC=gcc-14 CXX=g++-14 cmake -G "Ninja" \ CC=gcc-13 CXX=g++-13 cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ -DCMAKE_BUILD_TYPE=${{env.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 \
@@ -499,7 +426,7 @@ jobs:
run: | run: |
cp -r build/DEBIAN build/DebDir cp -r build/DEBIAN build/DebDir
dpkg-deb -Zgzip --build build/DebDir dpkg-deb -Zgzip --build build/DebDir
mv build/DebDir.deb imhex-${{ env.IMHEX_VERSION }}-Ubuntu-${{ matrix.release_num }}-x86_64.deb mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-${{ matrix.release_num }}-x86_64.deb
- name: ⬆️ Upload DEB - name: ⬆️ Upload DEB
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@@ -510,7 +437,7 @@ jobs:
# AppImage build # AppImage build
appimage: appimage:
runs-on: ubuntu-24.04 runs-on: ubuntu-22.04
name: ⬇️ AppImage name: ⬇️ AppImage
steps: steps:
- name: 🧰 Checkout - name: 🧰 Checkout
@@ -554,7 +481,7 @@ jobs:
# ArchLinux build # ArchLinux build
archlinux-build: archlinux-build:
name: 🐧 ArchLinux name: 🐧 ArchLinux
runs-on: ubuntu-24.04 runs-on: ubuntu-latest
container: container:
image: archlinux:base-devel image: archlinux:base-devel
@@ -596,7 +523,7 @@ jobs:
mkdir -p build mkdir -p build
cd build cd build
CC=gcc CXX=g++ cmake -G "Ninja" \ CC=gcc CXX=g++ cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ -DCMAKE_BUILD_TYPE=${{env.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 \
@@ -621,7 +548,7 @@ jobs:
- name: ✒️ Prepare PKGBUILD - name: ✒️ Prepare PKGBUILD
run: | run: |
cp dist/Arch/PKGBUILD build cp dist/Arch/PKGBUILD build
sed -i 's/%version%/${{ env.IMHEX_VERSION }}/g' build/PKGBUILD 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 # makepkg doesn't want to run as root, so I had to chmod 777 all over
- name: 📦 Package ArchLinux .pkg.tar.zst - name: 📦 Package ArchLinux .pkg.tar.zst
@@ -631,16 +558,16 @@ jobs:
# the name is a small trick to make makepkg recognize it as the source # 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 # else, it would try to download the file from the release
tar -cvf imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst -C installDir . tar -cvf imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst -C installDir .
chmod -R 777 . chmod -R 777 .
sudo -u nobody makepkg sudo -u nobody makepkg
# Replace the old file # Replace the old file
rm imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst rm imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
rm *imhex-bin-debug* # rm debug package which is created for some reason rm *imhex-bin-debug* # rm debug package which is created for some reason
mv *.pkg.tar.zst imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst mv *.pkg.tar.zst imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
- name: ⬆️ Upload imhex-archlinux.pkg.tar.zst - name: ⬆️ Upload imhex-archlinux.pkg.tar.zst
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@@ -648,7 +575,7 @@ jobs:
if-no-files-found: error if-no-files-found: error
name: ArchLinux .pkg.tar.zst x86_64 name: ArchLinux .pkg.tar.zst x86_64
path: | path: |
build/imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst build/imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
# RPM distro builds # RPM distro builds
rpm-build: rpm-build:
@@ -661,41 +588,28 @@ jobs:
release_num: rawhide release_num: rawhide
mock_config: fedora-rawhide mock_config: fedora-rawhide
- name: Fedora - name: Fedora
mock_release: f41 mock_release: f39
release_num: 41 release_num: 39
mock_config: fedora-41 mock_config: fedora-39
- name: Fedora - name: Fedora
mock_release: f40 mock_release: f38
release_num: 40 release_num: 38
mock_config: fedora-40 mock_config: fedora-38
- name: RHEL-AlmaLinux - name: RHEL-AlmaLinux
mock_release: epel9 mock_release: epel9
release_num: 9 release_num: 9
mock_config: "alma+epel-9" mock_config: "alma+epel-9"
name: 🐧 ${{ matrix.name }} ${{ matrix.release_num }} name: 🐧 ${{ matrix.name }} ${{ matrix.release_num }}
runs-on: ubuntu-24.04 runs-on: ubuntu-latest
container: container:
image: "almalinux:9" image: "fedora:latest"
options: --privileged --pid=host --security-opt apparmor=unconfined options: --privileged
steps: steps:
# This, together with the `--pid=host --security-opt apparmor=unconfined` docker options is required to allow - name: ⬇️ Install git-core
# fedpkg to work inside a Docker container running on Ubuntu again. run: dnf install --disablerepo="*" --enablerepo="fedora" git-core -y
# GitHub seems to have enabled AppArmor on their Ubuntu CI runners which limits Docker in ways that cause
# programs inside it to fail.
# Without this, fedpkg will throw the unhelpful error message 'Insufficient Rights'
# This step uses nsenter to execute commands on the host that disable AppArmor entirely.
- name: 🛡️ Disable AppArmor on Host
run: |
nsenter -t 1 -m -u -n -i sudo systemctl disable --now apparmor.service
nsenter -t 1 -m -u -n -i sudo aa-teardown || true
nsenter -t 1 -m -u -n -i sudo sysctl --write kernel.apparmor_restrict_unprivileged_unconfined=0
nsenter -t 1 -m -u -n -i sudo sysctl --write kernel.apparmor_restrict_unprivileged_userns=0
- name: ⬇️ Install git-core and EPEL repo
run: dnf install git-core epel-release -y
- name: 🧰 Checkout - name: 🧰 Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -714,8 +628,8 @@ jobs:
- name: ⬇️ Update all packages and install dependencies - name: ⬇️ Update all packages and install dependencies
run: | run: |
set -x set -x
dnf upgrade -y dnf upgrade --disablerepo="*" --enablerepo="fedora,updates" -y
dnf install -y \ dnf install --disablerepo="*" --enablerepo="fedora,updates" -y \
fedpkg \ fedpkg \
ccache ccache
@@ -741,16 +655,16 @@ jobs:
- name: ✒️ Modify spec file - name: ✒️ Modify spec file
run: | run: |
sed -i \ sed -i \
-e 's/Version: VERSION$/Version: ${{ env.IMHEX_VERSION }}/g' \ -e 's/Version: VERSION$/Version: ${{env.IMHEX_VERSION}}/g' \
-e 's/IMHEX_OFFLINE_BUILD=ON/IMHEX_OFFLINE_BUILD=OFF/g' \ -e 's/IMHEX_OFFLINE_BUILD=ON/IMHEX_OFFLINE_BUILD=OFF/g' \
-e '/IMHEX_OFFLINE_BUILD=OFF/a -D IMHEX_PATTERNS_PULL_MASTER=ON \\' \ -e '/IMHEX_OFFLINE_BUILD=OFF/a -D IMHEX_PATTERNS_PULL_MASTER=ON \\' \
-e '/BuildRequires: cmake/a BuildRequires: git-core' \ -e '/BuildRequires: cmake/a BuildRequires: git-core' \
-e '/%files/a %{_datadir}/%{name}/' \ -e '/%files/a %{_datadir}/%{name}/' \
$GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec
- name: 📜 Fix ccache on EL9 - name: 📜 Fix ccache on EL9
if: matrix.mock_release == 'epel9' if: matrix.mock_release == 'epel9'
run: sed -i '/\. \/opt\/rh\/gcc-toolset-14\/enable/a PATH=/usr/lib64/ccache:$PATH' $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec run: sed -i '/\. \/opt\/rh\/gcc-toolset-12\/enable/a PATH=/usr/lib64/ccache:$PATH' $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec
- name: 🟩 Copy spec file to build root - name: 🟩 Copy spec file to build root
run: mv $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec $GITHUB_WORKSPACE/imhex.spec run: mv $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec $GITHUB_WORKSPACE/imhex.spec
@@ -772,8 +686,8 @@ jobs:
- name: 🟩 Move and rename finished RPM - name: 🟩 Move and rename finished RPM
run: | run: |
mv $GITHUB_WORKSPACE/results_imhex/${{ env.IMHEX_VERSION }}/*/imhex-${{ env.IMHEX_VERSION }}-0.*.x86_64.rpm \ mv $GITHUB_WORKSPACE/results_imhex/${{env.IMHEX_VERSION}}/*/imhex-${{env.IMHEX_VERSION}}-0.*.x86_64.rpm \
$GITHUB_WORKSPACE/imhex-${{ env.IMHEX_VERSION }}-${{ matrix.name }}-${{ matrix.release_num }}-x86_64.rpm $GITHUB_WORKSPACE/imhex-${{env.IMHEX_VERSION}}-${{matrix.name}}-${{matrix.release_num}}-x86_64.rpm
- name: ⬆️ Upload RPM - name: ⬆️ Upload RPM
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@@ -781,4 +695,4 @@ jobs:
if-no-files-found: error if-no-files-found: error
name: ${{ matrix.name }} ${{ matrix.release_num }} RPM x86_64 name: ${{ matrix.name }} ${{ matrix.release_num }} RPM x86_64
path: | path: |
imhex-${{ env.IMHEX_VERSION }}-${{ matrix.name }}-${{ matrix.release_num }}-x86_64.rpm imhex-${{env.IMHEX_VERSION}}-${{matrix.name}}-${{matrix.release_num}}-x86_64.rpm

View File

@@ -20,7 +20,7 @@ permissions:
jobs: jobs:
build: build:
runs-on: ubuntu-24.04 runs-on: ubuntu-22.04
name: 🌍 WebAssembly name: 🌍 WebAssembly
steps: steps:
- name: 🧰 Checkout - name: 🧰 Checkout
@@ -49,7 +49,7 @@ jobs:
chmod -c -R +rX "out/" chmod -c -R +rX "out/"
- name: ⬆️ Upload artifacts - name: ⬆️ Upload artifacts
uses: actions/upload-pages-artifact@v3 uses: actions/upload-pages-artifact@v2
with: with:
path: out/ path: out/
@@ -59,8 +59,9 @@ jobs:
env: env:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
run: | run: |
gh extension install actions/gh-actions-cache || true gh extension install actions/gh-actions-cache
gh actions-cache delete "build-web-cache" --confirm || true gh actions-cache delete "build-web-cache" --confirm
deploy: deploy:
environment: environment:
@@ -68,7 +69,7 @@ jobs:
url: ${{ steps.deployment.outputs.page_url }} url: ${{ steps.deployment.outputs.page_url }}
name: 📃 Deploy to GitHub Pages name: 📃 Deploy to GitHub Pages
runs-on: ubuntu-24.04 runs-on: ubuntu-latest
if: ${{ github.ref == 'refs/heads/master' && github.event.repository.fork == false }} if: ${{ github.ref == 'refs/heads/master' && github.event.repository.fork == false }}
needs: build needs: build
@@ -76,4 +77,4 @@ jobs:
steps: steps:
- name: 🌍 Deploy - name: 🌍 Deploy
id: deployment id: deployment
uses: actions/deploy-pages@v4 uses: actions/deploy-pages@v2

View File

@@ -10,7 +10,7 @@ on:
jobs: jobs:
release-update-repos: release-update-repos:
runs-on: ubuntu-24.04 runs-on: ubuntu-latest
name: Release Update Repos name: Release Update Repos
steps: steps:
@@ -90,7 +90,7 @@ jobs:
run: tar --exclude-vcs -czvf Full.Sources.tar.gz ImHex run: tar --exclude-vcs -czvf Full.Sources.tar.gz ImHex
- name: ⬇️ Download artifacts from latest workflow - name: ⬇️ Download artifacts from latest workflow
uses: dawidd6/action-download-artifact@v6 uses: dawidd6/action-download-artifact@v3
with: with:
github_token: ${{secrets.GITHUB_TOKEN}} github_token: ${{secrets.GITHUB_TOKEN}}
workflow: build.yml workflow: build.yml
@@ -147,7 +147,7 @@ jobs:
commit_email: itrooz@protonmail.com commit_email: itrooz@protonmail.com
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }} ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
commit_message: Bump to version ${{ env.IMHEX_VERSION }} commit_message: Bump to version ${{ env.IMHEX_VERSION }}
ssh_keyscan_types: rsa,ecdsa,ed25519 ssh_keyscan_types: rsa,dsa,ecdsa,ed25519
release-update-winget: release-update-winget:
name: Release update winget package name: Release update winget package

View File

@@ -1,30 +0,0 @@
name: Close inactive issues
on:
schedule:
- cron: "30 1 * * 0"
workflow_dispatch:
jobs:
close-issues:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v5
with:
operations-per-run: '200'
ascending: true
days-before-issue-stale: 334
days-before-issue-close: 30
stale-issue-label: "stale"
stale-issue-message: |
This issue is marked stale as it has been open for 11 months without activity.
Please try the latest ImHex version. (Avaiable here: https://imhex.download/ for release and https://imhex.download/#nightly for development version)
If the issue persists on the latest version, please make a comment on this issue again
Without response, this issue will be closed in one month.
close-issue-message: ""
days-before-pr-stale: -1
days-before-pr-close: -1
repo-token: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -15,7 +15,7 @@ on:
jobs: jobs:
tests: tests:
name: 🧪 Unit Tests name: 🧪 Unit Tests
runs-on: ubuntu-24.04 runs-on: ubuntu-22.04
permissions: permissions:
actions: read actions: read
contents: read contents: read
@@ -38,25 +38,23 @@ jobs:
run: | run: |
sudo apt update sudo apt update
sudo bash dist/get_deps_debian.sh sudo bash dist/get_deps_debian.sh
sudo apt install gcovr -y
- name: 🛠️ Build - name: 🛠️ Build
run: | run: |
set -x set -x
mkdir -p build mkdir -p build
cd build cd build
CC=gcc-14 CXX=g++-14 cmake \ CC=gcc-12 CXX=g++-12 cmake \
-DCMAKE_BUILD_TYPE=Debug \ -DCMAKE_BUILD_TYPE=Debug \
-DIMHEX_ENABLE_UNIT_TESTS=ON \ -DIMHEX_ENABLE_UNIT_TESTS=ON \
-DIMHEX_ENABLE_PLUGIN_TESTS=ON \
-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 -fsanitize=address,leak,undefined -fno-sanitize-recover=all --coverage" \ -DCMAKE_C_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all --coverage" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all --coverage" \ -DCMAKE_CXX_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all --coverage" \
-DIMHEX_OFFLINE_BUILD=ON \ -DIMHEX_OFFLINE_BUILD=ON \
-G Ninja \
.. ..
ninja unit_tests make -j4 unit_tests
ninja imhex_all
- name: 🧪 Perform plcli Integration Tests - name: 🧪 Perform plcli Integration Tests
run: | run: |
@@ -69,24 +67,16 @@ jobs:
ctest --output-on-failure ctest --output-on-failure
# Generate report from all gcov .gcda files # Generate report from all gcov .gcda files
#- name: 🧪 Generate coverage report - name: 🧪 Generate coverage report
# run: | run: |
# sudo apt install python3-pip python3-venv gcovr --gcov-executable /usr/bin/gcov-12 -r . build --xml coverage_report.xml --verbose
# python3 -m venv venv
# . venv/bin/activate - name: Upload coverage reports to Codecov
# pip3 install gcovr uses: codecov/codecov-action@v4
# cd build with:
# gcovr --gcov-executable /usr/bin/gcov-14 --exclude '.*/yara_rules/' --exclude '.*/third_party/' --exclude '.*/external/' --root .. --xml coverage_report.xml --verbose --gcov-ignore-errors all fail_ci_if_error: true
# token: ${{ secrets.CODECOV_TOKEN }}
#- name: Upload coverage reports to Codecov file: coverage_report.xml
# env:
# CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
# if: ${{ env.CODECOV_TOKEN }}
# uses: codecov/codecov-action@v4
# with:
# fail_ci_if_error: true
# token: ${{ secrets.CODECOV_TOKEN }}
# file: build/coverage_report.xml
langs: langs:
name: 🧪 Langs name: 🧪 Langs

1
.gitignore vendored
View File

@@ -6,7 +6,6 @@ cmake-build-*/
build*/ build*/
local/ local/
venv/ venv/
.cache/
*.mgc *.mgc
*.kdev4 *.kdev4

2
.gitmodules vendored
View File

@@ -28,7 +28,7 @@
ignore = dirty ignore = dirty
[submodule "lib/third_party/lunasvg"] [submodule "lib/third_party/lunasvg"]
path = lib/third_party/lunasvg path = lib/third_party/lunasvg
url = https://github.com/WerWolv/lunasvg url = https://github.com/sammycage/lunasvg
ignore = dirty ignore = dirty
[submodule "lib/external/libromfs"] [submodule "lib/external/libromfs"]

View File

@@ -21,7 +21,7 @@ option(IMHEX_REPLACE_DWARF_WITH_PDB "Remove DWARF information from binaries
option(IMHEX_ENABLE_STD_ASSERTS "Enable debug asserts in the C++ std library. (Breaks Plugin ABI!)" OFF) option(IMHEX_ENABLE_STD_ASSERTS "Enable debug asserts in the C++ std library. (Breaks Plugin ABI!)" OFF)
option(IMHEX_ENABLE_UNIT_TESTS "Enable building unit tests" OFF) option(IMHEX_ENABLE_UNIT_TESTS "Enable building unit tests" OFF)
option(IMHEX_ENABLE_PRECOMPILED_HEADERS "Enable precompiled headers" OFF) option(IMHEX_ENABLE_PRECOMPILED_HEADERS "Enable precompiled headers" OFF)
option(IMHEX_COMPRESS_DEBUG_INFO "Compress debug information" ON ) option(IMHEX_COMPRESS_DEBUG_INFO "Compress debug information" ON )
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")
@@ -32,17 +32,16 @@ include("${IMHEX_BASE_FOLDER}/cmake/ide_helpers.cmake")
# Basic compiler and cmake configurations # Basic compiler and cmake configurations
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON) set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake") include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
# Setup project # Setup project
loadVersion(IMHEX_VERSION IMHEX_VERSION_PLAIN) loadVersion(IMHEX_VERSION)
setVariableInParent(IMHEX_VERSION ${IMHEX_VERSION}) setVariableInParent(IMHEX_VERSION ${IMHEX_VERSION})
configureCMake() configureCMake()
project(imhex project(imhex
LANGUAGES C CXX LANGUAGES C CXX
VERSION ${IMHEX_VERSION_PLAIN} VERSION ${IMHEX_VERSION}
DESCRIPTION "The ImHex Hex Editor" DESCRIPTION "The ImHex Hex Editor"
HOMEPAGE_URL "https://imhex.werwolv.net" HOMEPAGE_URL "https://imhex.werwolv.net"
) )
@@ -70,14 +69,12 @@ addBundledLibraries()
add_subdirectory(lib/libimhex) add_subdirectory(lib/libimhex)
add_subdirectory(main) add_subdirectory(main)
addPluginDirectories() addPluginDirectories()
add_subdirectory(lib/trace)
# Add unit tests # Add unit tests
if (IMHEX_ENABLE_UNIT_TESTS) if (IMHEX_ENABLE_UNIT_TESTS)
if (NOT TARGET unit_tests) enable_testing()
enable_testing() add_subdirectory(tests EXCLUDE_FROM_ALL)
add_custom_target(unit_tests)
add_subdirectory(tests EXCLUDE_FROM_ALL)
endif ()
endif () endif ()
# Configure more resources that will be added to the install package # Configure more resources that will be added to the install package
@@ -87,5 +84,5 @@ generateSDKDirectory()
# Handle package generation # Handle package generation
createPackage() createPackage()
# Accommodate IDEs with FOLDER support # Accomodate IDEs with FOLDER support
tweakTargetsForIDESupport() tweakTargetsForIDESupport()

View File

@@ -1,16 +1,13 @@
<a href="https://imhex.werwolv.net"> <a href="https://imhex.werwolv.net">
<h1 align="center"> <h1 align="center">
<picture> <picture>
<img height="300px" style="margin: 0; padding: 0" src="./resources/dist/common/logo/ImHexLogoSVGBG.svg"> <img height="300px" src="./resources/dist/common/logo/ImHexLogoSVGBG.svg">
</picture> </picture>
</h1> </h1>
</a> </a>
<p align="center"> <p align="center">A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</p>
A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.
<br>
<a href="https://itinerarium.github.io/phoneme-synthesis/?w=/'ˈɪmhɛks/"><strong>/ˈɪmhɛks/</strong></a>
</p>
<p align="center"> <p align="center">
<a title="'Build' workflow Status" href="https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild"><img alt="'Build' workflow Status" src="https://img.shields.io/github/actions/workflow/status/WerWolv/ImHex/build.yml?longCache=true&style=for-the-badge&label=Build&logoColor=fff&logo=GitHub%20Actions&branch=master"></a> <a title="'Build' workflow Status" href="https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild"><img alt="'Build' workflow Status" src="https://img.shields.io/github/actions/workflow/status/WerWolv/ImHex/build.yml?longCache=true&style=for-the-badge&label=Build&logoColor=fff&logo=GitHub%20Actions&branch=master"></a>
<a title="Discord Server" href="https://discord.gg/X63jZ36xBY"><img alt="Discord Server" src="https://img.shields.io/discord/789833418631675954?label=Discord&logo=Discord&logoColor=fff&style=for-the-badge"></a> <a title="Discord Server" href="https://discord.gg/X63jZ36xBY"><img alt="Discord Server" src="https://img.shields.io/discord/789833418631675954?label=Discord&logo=Discord&logoColor=fff&style=for-the-badge"></a>
@@ -314,26 +311,22 @@ To use ImHex, the following minimal system requirements need to be met.
> ImHex requires a GPU with OpenGL 3.0 support in general. > ImHex requires a GPU with OpenGL 3.0 support in general.
> There are releases available (with the `-NoGPU` suffix) that are software rendered and don't require a GPU, however these can be a lot slower than the GPU accelerated versions. > There are releases available (with the `-NoGPU` suffix) that are software rendered and don't require a GPU, however these can be a lot slower than the GPU accelerated versions.
> >
> If possible at all, make ImHex use the dedicated GPU on your system instead of the integrated one. > If possible at all, make ImHex use the dedicated GPU on your system instead of the integrated one (especially Intel HD GPUs are known to cause issues).
> ImHex will usually run fine with integrated GPUs as well but certain Intel HD GPU drivers on Windows are known to cause graphical artifacts.
- **OS**: - **OS**:
- **Windows**: Windows 7 or higher (Windows 10/11 recommended) - **Windows**: Windows 7 or higher (Windows 10/11 recommended)
- **macOS**: macOS 13 (Ventura) or higher, - **macOS**: macOS 11 (Big Sur) or higher,
- Lower versions should still work too, but you'll need to compile ImHex yourself. The release binaries will NOT work.
- The macOS build is not signed and will require you to manually allow them in the Security & Privacy settings.
- **Linux**: "Modern" Linux. The following distributions have official releases available. Other distros are supported through the AppImage and Flatpak releases. - **Linux**: "Modern" Linux. The following distributions have official releases available. Other distros are supported through the AppImage and Flatpak releases.
- Ubuntu and Debian - Ubuntu 22.04/23.04
- Fedora - Fedora 36/37
- RHEL/AlmaLinux - RHEL/AlmaLinux 9
- Arch Linux - Arch Linux
- Basically any other distro will work as well when compiling ImHex from sources.
- **CPU**: x86_64 (64 Bit) - **CPU**: x86_64 (64 Bit)
- **GPU**: OpenGL 3.0 or higher - **GPU**: OpenGL 3.0 or higher
- Integrated Intel HD iGPUs are supported, however certain drivers are known to cause various graphical artifacts, especially on Windows. Use at your own risk. - Intel HD drivers are really buggy and often cause graphic artifacts
- In case you don't have a GPU available, there are software rendered releases available for Windows and macOS - In case you don't have a GPU available, there are software rendered releases available for Windows and macOS
- **RAM**: 256MB, more may be required for more complicated analysis - **RAM**: 256MB, more may be required for more complicated analysis
- **Storage**: 150MB - **Storage**: 100MB
## Installing ## Installing

View File

@@ -1 +1 @@
1.36.2 1.33.0

View File

@@ -59,7 +59,6 @@ macro(detectOS)
set(CMAKE_INSTALL_LIBDIR ".") set(CMAKE_INSTALL_LIBDIR ".")
set(PLUGINS_INSTALL_LOCATION "plugins") set(PLUGINS_INSTALL_LOCATION "plugins")
add_compile_definitions(WIN32_LEAN_AND_MEAN) add_compile_definitions(WIN32_LEAN_AND_MEAN)
add_compile_definitions(UNICODE)
elseif (APPLE) elseif (APPLE)
add_compile_definitions(OS_MACOS) add_compile_definitions(OS_MACOS)
set(CMAKE_INSTALL_BINDIR ".") set(CMAKE_INSTALL_BINDIR ".")
@@ -225,7 +224,6 @@ macro(createPackage)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_INSTALL_PREFIX}/share/licenses/imhex) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_INSTALL_PREFIX}/share/licenses/imhex)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dist/imhex.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dist/imhex.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dist/imhex.mime.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/mime/packages RENAME imhex.xml)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/icon.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.png) install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/icon.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.png)
downloadImHexPatternsFiles("./share/imhex") downloadImHexPatternsFiles("./share/imhex")
@@ -240,7 +238,6 @@ macro(createPackage)
if (APPLE) if (APPLE)
if (IMHEX_GENERATE_PACKAGE) if (IMHEX_GENERATE_PACKAGE)
set(EXTRA_BUNDLE_LIBRARY_PATHS ${EXTRA_BUNDLE_LIBRARY_PATHS} "${IMHEX_SYSTEM_LIBRARY_PATH}")
include(PostprocessBundle) include(PostprocessBundle)
set_target_properties(libimhex PROPERTIES SOVERSION ${IMHEX_VERSION}) set_target_properties(libimhex PROPERTIES SOVERSION ${IMHEX_VERSION})
@@ -271,7 +268,7 @@ macro(createPackage)
find_program(CODESIGN_PATH codesign) find_program(CODESIGN_PATH codesign)
if (CODESIGN_PATH) if (CODESIGN_PATH)
install(CODE "message(STATUS \"Signing bundle '${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}'...\")") install(CODE "message(STATUS \"Signing bundle '${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}'...\")")
install(CODE "execute_process(COMMAND ${CODESIGN_PATH} --force --deep --entitlements ${CMAKE_SOURCE_DIR}/resources/macos/Entitlements.plist --sign - ${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME} COMMAND_ERROR_IS_FATAL ANY)") install(CODE "execute_process(COMMAND ${CODESIGN_PATH} --force --deep --sign - ${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME} COMMAND_ERROR_IS_FATAL ANY)")
endif() endif()
endif() endif()
@@ -309,6 +306,9 @@ endfunction()
macro(configureCMake) macro(configureCMake)
message(STATUS "Configuring ImHex v${IMHEX_VERSION}") message(STATUS "Configuring ImHex v${IMHEX_VERSION}")
# Enable C and C++ languages
enable_language(C CXX)
set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE BOOL "Enable position independent code for all targets" FORCE) set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE BOOL "Enable position independent code for all targets" FORCE)
# Configure use of recommended build tools # Configure use of recommended build tools
@@ -382,9 +382,6 @@ macro(configureCMake)
endmacro() endmacro()
function(configureProject) function(configureProject)
# Enable C and C++ languages
enable_language(C CXX)
if (XCODE) if (XCODE)
# Support Xcode's multi configuration paradigm by placing built artifacts into separate directories # Support Xcode's multi configuration paradigm by placing built artifacts into separate directories
set(IMHEX_MAIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Configs/$<CONFIG>" PARENT_SCOPE) set(IMHEX_MAIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/Configs/$<CONFIG>" PARENT_SCOPE)
@@ -400,14 +397,12 @@ macro(setDefaultBuiltTypeIfUnset)
endif() endif()
endmacro() endmacro()
function(loadVersion version plain_version) function(loadVersion version)
set(VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/VERSION") set(VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${VERSION_FILE}) set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${VERSION_FILE})
file(READ "${VERSION_FILE}" read_version) file(READ "${VERSION_FILE}" read_version)
string(STRIP ${read_version} read_version) string(STRIP ${read_version} read_version)
string(REPLACE ".WIP" "" read_version_plain ${read_version})
set(${version} ${read_version} PARENT_SCOPE) set(${version} ${read_version} PARENT_SCOPE)
set(${plain_version} ${read_version_plain} PARENT_SCOPE)
endfunction() endfunction()
function(detectBadClone) function(detectBadClone)
@@ -548,10 +543,8 @@ macro(setupDebugCompressionFlag)
if (NOT DEBUG_COMPRESSION_FLAG) # Cache variable if (NOT DEBUG_COMPRESSION_FLAG) # Cache variable
if (ZSTD_AVAILABLE_COMPILER AND ZSTD_AVAILABLE_LINKER) if (ZSTD_AVAILABLE_COMPILER AND ZSTD_AVAILABLE_LINKER)
message("Using Zstd compression for debug info because both compiler and linker support it")
set(DEBUG_COMPRESSION_FLAG "-gz=zstd" CACHE STRING "Cache to use for debug info compression") set(DEBUG_COMPRESSION_FLAG "-gz=zstd" CACHE STRING "Cache to use for debug info compression")
elseif (COMPRESS_AVAILABLE_COMPILER AND COMPRESS_AVAILABLE_LINKER) elseif (COMPRESS_AVAILABLE_COMPILER AND COMPRESS_AVAILABLE_LINKER)
message("Using default compression for debug info because both compiler and linker support it")
set(DEBUG_COMPRESSION_FLAG "-gz" CACHE STRING "Cache to use for debug info compression") set(DEBUG_COMPRESSION_FLAG "-gz" CACHE STRING "Cache to use for debug info compression")
endif() endif()
endif() endif()
@@ -575,7 +568,7 @@ macro(setupCompilerFlags target)
set(IMHEX_CXX_FLAGS "-fexceptions -frtti") set(IMHEX_CXX_FLAGS "-fexceptions -frtti")
# Disable some warnings # Disable some warnings
set(IMHEX_C_CXX_FLAGS "-Wno-array-bounds -Wno-deprecated-declarations -Wno-unknown-pragmas") set(IMHEX_C_CXX_FLAGS "-Wno-unknown-warning-option -Wno-array-bounds -Wno-deprecated-declarations -Wno-unknown-pragmas")
endif() endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
@@ -584,13 +577,6 @@ macro(setupCompilerFlags target)
endif () endif ()
endif() endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND APPLE)
execute_process(COMMAND brew --prefix llvm OUTPUT_VARIABLE LLVM_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${LLVM_PREFIX}/lib/c++")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${LLVM_PREFIX}/lib/c++")
set(IMHEX_C_CXX_FLAGS "-Wno-unknown-warning-option")
endif()
# Disable some warnings for gcc # Disable some warnings for gcc
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") if(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(IMHEX_C_CXX_FLAGS "${IMHEX_C_CXX_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow -Wno-dangling-reference") set(IMHEX_C_CXX_FLAGS "${IMHEX_C_CXX_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow -Wno-dangling-reference")
@@ -710,14 +696,6 @@ macro(addBundledLibraries)
set(JTHREAD_LIBRARIES jthread) set(JTHREAD_LIBRARIES jthread)
endif() endif()
if (USE_SYSTEM_BOOST)
find_package(Boost REQUIRED)
set(BOOST_LIBRARIES Boost::regex)
else()
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/boost ${CMAKE_CURRENT_BINARY_DIR}/boost EXCLUDE_FROM_ALL)
set(BOOST_LIBRARIES boost::regex)
endif()
set(LIBPL_BUILD_CLI_AS_EXECUTABLE OFF CACHE BOOL "" FORCE) set(LIBPL_BUILD_CLI_AS_EXECUTABLE OFF CACHE BOOL "" FORCE)
set(LIBPL_ENABLE_PRECOMPILED_HEADERS ${IMHEX_ENABLE_PRECOMPILED_HEADERS} CACHE BOOL "" FORCE) set(LIBPL_ENABLE_PRECOMPILED_HEADERS ${IMHEX_ENABLE_PRECOMPILED_HEADERS} CACHE BOOL "" FORCE)
@@ -752,30 +730,6 @@ macro(addBundledLibraries)
find_package(mbedTLS 3.4.0 REQUIRED) find_package(mbedTLS 3.4.0 REQUIRED)
find_package(Magic 5.39 REQUIRED) find_package(Magic 5.39 REQUIRED)
if (NOT IMHEX_DISABLE_STACKTRACE)
if (WIN32)
message(STATUS "StackWalk enabled!")
set(LIBBACKTRACE_LIBRARIES DbgHelp.lib)
else ()
find_package(Backtrace)
if (${Backtrace_FOUND})
message(STATUS "Backtrace enabled! Header: ${Backtrace_HEADER}")
if (Backtrace_HEADER STREQUAL "backtrace.h")
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
add_compile_definitions(BACKTRACE_HEADER=<${Backtrace_HEADER}>)
add_compile_definitions(HEX_HAS_BACKTRACE)
elseif (Backtrace_HEADER STREQUAL "execinfo.h")
set(LIBBACKTRACE_LIBRARIES ${Backtrace_LIBRARY})
set(LIBBACKTRACE_INCLUDE_DIRS ${Backtrace_INCLUDE_DIR})
add_compile_definitions(BACKTRACE_HEADER=<${Backtrace_HEADER}>)
add_compile_definitions(HEX_HAS_EXECINFO)
endif()
endif()
endif()
endif()
endmacro() endmacro()
function(enableUnityBuild TARGET) function(enableUnityBuild TARGET)
@@ -857,9 +811,6 @@ function(generateSDKDirectory)
if (NOT USE_SYSTEM_NLOHMANN_JSON) if (NOT USE_SYSTEM_NLOHMANN_JSON)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/nlohmann_json DESTINATION "${SDK_PATH}/lib/third_party") install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/nlohmann_json DESTINATION "${SDK_PATH}/lib/third_party")
endif() endif()
if (NOT USE_SYSTEM_BOOST)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/boost DESTINATION "${SDK_PATH}/lib/third_party")
endif()
install(DIRECTORY ${CMAKE_SOURCE_DIR}/cmake/modules DESTINATION "${SDK_PATH}/cmake") install(DIRECTORY ${CMAKE_SOURCE_DIR}/cmake/modules DESTINATION "${SDK_PATH}/cmake")
install(FILES ${CMAKE_SOURCE_DIR}/cmake/build_helpers.cmake DESTINATION "${SDK_PATH}/cmake") install(FILES ${CMAKE_SOURCE_DIR}/cmake/build_helpers.cmake DESTINATION "${SDK_PATH}/cmake")

View File

@@ -89,5 +89,4 @@ if (CoreClrEmbed_INCLUDE_DIR AND CoreClrEmbed_LIBRARY)
set(CoreClrEmbed_LIBRARIES "${CoreClrEmbed_LIBRARY}" CACHE STRING "CoreClrEmbed libraries" FORCE) set(CoreClrEmbed_LIBRARIES "${CoreClrEmbed_LIBRARY}" CACHE STRING "CoreClrEmbed libraries" FORCE)
set(CoreClrEmbed_SHARED_LIBRARIES "${CoreClrEmbed_SHARED_LIBRARY}" CACHE STRING "CoreClrEmbed shared libraries" FORCE) set(CoreClrEmbed_SHARED_LIBRARIES "${CoreClrEmbed_SHARED_LIBRARY}" CACHE STRING "CoreClrEmbed shared libraries" FORCE)
set(CoreClrEmbed_INCLUDE_DIRS "${CoreClrEmbed_INCLUDE_DIR}" CACHE STRING "CoreClrEmbed include directories" FORCE) set(CoreClrEmbed_INCLUDE_DIRS "${CoreClrEmbed_INCLUDE_DIR}" CACHE STRING "CoreClrEmbed include directories" FORCE)
set(CoreClrEmbed_VERSION "${CORECLR_RUNTIME_VERSION_FULL}" CACHE STRING "CoreClrEmbed version" FORCE)
endif() endif()

View File

@@ -1,60 +0,0 @@
find_path(LZ4_INCLUDE_DIR
NAMES lz4.h
HINTS "${LZ4_INCLUDEDIR}" "${LZ4_HINTS}/include"
PATHS
/usr/local/include
/usr/include
)
find_library(LZ4_LIBRARY
NAMES lz4 liblz4
HINTS "${LZ4_LIBDIR}" "${LZ4_HINTS}/lib"
PATHS
/usr/local/lib
/usr/lib
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args( LZ4 DEFAULT_MSG LZ4_LIBRARY LZ4_INCLUDE_DIR )
if( LZ4_FOUND )
include( CheckIncludeFile )
include( CMakePushCheckState )
set( LZ4_INCLUDE_DIRS ${LZ4_INCLUDE_DIR} )
set( LZ4_LIBRARIES ${LZ4_LIBRARY} )
cmake_push_check_state()
set( CMAKE_REQUIRED_INCLUDES ${LZ4_INCLUDE_DIRS} )
check_include_file( lz4frame.h HAVE_LZ4FRAME_H )
cmake_pop_check_state()
if (WIN32)
set ( LZ4_DLL_DIR "${LZ4_HINTS}/bin"
CACHE PATH "Path to LZ4 DLL"
)
file( GLOB _lz4_dll RELATIVE "${LZ4_DLL_DIR}"
"${LZ4_DLL_DIR}/lz4*.dll"
)
set ( LZ4_DLL ${_lz4_dll}
# We're storing filenames only. Should we use STRING instead?
CACHE FILEPATH "LZ4 DLL file name"
)
file( GLOB _lz4_pdb RELATIVE "${LZ4_DLL_DIR}"
"${LZ4_DLL_DIR}/lz4*.pdb"
)
set ( LZ4_PDB ${_lz4_pdb}
CACHE FILEPATH "LZ4 PDB file name"
)
mark_as_advanced( LZ4_DLL_DIR LZ4_DLL LZ4_PDB )
endif()
else()
set( LZ4_INCLUDE_DIRS )
set( LZ4_LIBRARIES )
endif()
mark_as_advanced( LZ4_LIBRARIES LZ4_INCLUDE_DIRS )
add_library( LZ4::lz4 INTERFACE IMPORTED )
set_property( TARGET LZ4::lz4 PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${LZ4_INCLUDE_DIRS} )
set_property( TARGET LZ4::lz4 PROPERTY INTERFACE_LINK_LIBRARIES ${LZ4_LIBRARIES} )

View File

@@ -39,7 +39,3 @@ if (ZSTD_FOUND)
endif() endif()
mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY) mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)
add_library(ZSTD::zstd INTERFACE IMPORTED)
set_property(TARGET ZSTD::zstd PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${ZSTD_INCLUDE_DIR})
set_property(TARGET ZSTD::zstd PROPERTY INTERFACE_LINK_LIBRARIES ${ZSTD_LIBRARY})

View File

@@ -55,9 +55,9 @@ IF(MBEDTLS_FOUND)
MESSAGE(STATUS " Crypto: ${MBEDCRYPTO_LIBRARY}") MESSAGE(STATUS " Crypto: ${MBEDCRYPTO_LIBRARY}")
ENDIF(NOT MBEDTLS_FIND_QUIETLY) ENDIF(NOT MBEDTLS_FIND_QUIETLY)
ELSE(MBEDTLS_FOUND) ELSE(MBEDTLS_FOUND)
IF(mbedTLS_FIND_REQUIRED) IF(MBEDTLS_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find mbedTLS") MESSAGE(FATAL_ERROR "Could not find mbedTLS")
ENDIF(mbedTLS_FIND_REQUIRED) ENDIF(MBEDTLS_FIND_REQUIRED)
ENDIF(MBEDTLS_FOUND) ENDIF(MBEDTLS_FOUND)
MARK_AS_ADVANCED( MARK_AS_ADVANCED(

View File

@@ -37,7 +37,7 @@ macro(add_imhex_plugin)
# Add include directories and link libraries # Add include directories and link libraries
target_include_directories(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_INCLUDES}) target_include_directories(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_INCLUDES})
target_link_libraries(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_LIBRARIES}) target_link_libraries(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_LIBRARIES})
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE libimhex ${FMT_LIBRARIES} imgui_all_includes libwolv) target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE libimhex ${FMT_LIBRARIES} imgui_all_includes libwolv tracing)
addIncludesFromLibrary(${IMHEX_PLUGIN_NAME} libpl) addIncludesFromLibrary(${IMHEX_PLUGIN_NAME} libpl)
addIncludesFromLibrary(${IMHEX_PLUGIN_NAME} libpl-gen) addIncludesFromLibrary(${IMHEX_PLUGIN_NAME} libpl-gen)
@@ -72,23 +72,10 @@ macro(add_imhex_plugin)
add_subdirectory(${IMHEX_BASE_FOLDER}/lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs) add_subdirectory(${IMHEX_BASE_FOLDER}/lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE ${LIBROMFS_LIBRARY}) target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE ${LIBROMFS_LIBRARY})
set(FEATURE_DEFINE_CONTENT) foreach(feature ${IMHEX_PLUGIN_FEATURES})
string(TOUPPER ${feature} feature)
if (IMHEX_PLUGIN_FEATURES) add_definitions(-DIMHEX_PLUGIN_${IMHEX_PLUGIN_NAME}_FEATURE_${feature}=0)
list(LENGTH IMHEX_PLUGIN_FEATURES IMHEX_FEATURE_COUNT) endforeach()
math(EXPR IMHEX_FEATURE_COUNT "${IMHEX_FEATURE_COUNT} - 1" OUTPUT_FORMAT DECIMAL)
foreach(index RANGE 0 ${IMHEX_FEATURE_COUNT} 2)
list(SUBLIST IMHEX_PLUGIN_FEATURES ${index} 2 IMHEX_PLUGIN_FEATURE)
list(GET IMHEX_PLUGIN_FEATURE 0 feature_define)
list(GET IMHEX_PLUGIN_FEATURE 1 feature_description)
string(TOUPPER ${feature_define} feature_define)
add_definitions(-DIMHEX_PLUGIN_${IMHEX_PLUGIN_NAME}_FEATURE_${feature_define}=0)
set(FEATURE_DEFINE_CONTENT "${FEATURE_DEFINE_CONTENT}{ \"${feature_description}\", IMHEX_FEATURE_ENABLED(${feature_define}) },")
endforeach()
endif()
target_compile_options(${IMHEX_PLUGIN_NAME} PRIVATE -DIMHEX_PLUGIN_FEATURES_CONTENT=${FEATURE_DEFINE_CONTENT})
# Add the new plugin to the main dependency list so it gets built by default # Add the new plugin to the main dependency list so it gets built by default
if (TARGET imhex_all) if (TARGET imhex_all)
@@ -101,28 +88,12 @@ macro(add_imhex_plugin)
# Fix rpath # Fix rpath
if (APPLE) if (APPLE)
set_target_properties( set_target_properties(${IMHEX_PLUGIN_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks;@executable_path/plugins")
${IMHEX_PLUGIN_NAME}
PROPERTIES
INSTALL_RPATH "@executable_path/../Frameworks;@executable_path/plugins"
)
elseif (UNIX) elseif (UNIX)
set(PLUGIN_RPATH "") set_target_properties(${IMHEX_PLUGIN_NAME} PROPERTIES INSTALL_RPATH_USE_ORIGIN ON INSTALL_RPATH "$ORIGIN/")
list(APPEND PLUGIN_RPATH "$ORIGIN")
if (IMHEX_PLUGIN_ADD_INSTALL_PREFIX_TO_RPATH)
list(APPEND PLUGIN_RPATH "${CMAKE_INSTALL_PREFIX}/lib")
endif()
set_target_properties(
${IMHEX_PLUGIN_NAME}
PROPERTIES
INSTALL_RPATH_USE_ORIGIN ON
INSTALL_RPATH "${PLUGIN_RPATH}"
)
endif() endif()
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt AND IMHEX_ENABLE_UNIT_TESTS AND IMHEX_ENABLE_PLUGIN_TESTS) if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/tests/CMakeLists.txt AND IMHEX_ENABLE_UNIT_TESTS)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tests) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/tests)
target_link_libraries(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_NAME}_tests) target_link_libraries(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_NAME}_tests)
target_compile_definitions(${IMHEX_PLUGIN_NAME}_tests PRIVATE IMHEX_PROJECT_NAME="${IMHEX_PLUGIN_NAME}-tests") target_compile_definitions(${IMHEX_PLUGIN_NAME}_tests PRIVATE IMHEX_PROJECT_NAME="${IMHEX_PLUGIN_NAME}-tests")
@@ -130,10 +101,6 @@ macro(add_imhex_plugin)
endmacro() endmacro()
macro(add_romfs_resource input output) macro(add_romfs_resource input output)
if (NOT EXISTS ${input})
message(WARNING "Resource file ${input} does not exist")
endif()
configure_file(${input} ${CMAKE_CURRENT_BINARY_DIR}/romfs/${output} COPYONLY) configure_file(${input} ${CMAKE_CURRENT_BINARY_DIR}/romfs/${output} COPYONLY)
list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/romfs) list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/romfs)

View File

@@ -29,10 +29,6 @@ add_subdirectory_if_exists(lib/third_party/nlohmann_json)
set(NLOHMANN_JSON_LIBRARIES nlohmann_json PARENT_SCOPE) set(NLOHMANN_JSON_LIBRARIES nlohmann_json PARENT_SCOPE)
set(NLOHMANN_JSON_LIBRARIES nlohmann_json) set(NLOHMANN_JSON_LIBRARIES nlohmann_json)
add_subdirectory_if_exists(lib/third_party/boost)
set(BOOST_LIBRARIES boost::regex PARENT_SCOPE)
set(BOOST_LIBRARIES boost::regex)
add_subdirectory(lib/external/libwolv EXCLUDE_FROM_ALL) add_subdirectory(lib/external/libwolv EXCLUDE_FROM_ALL)
set(LIBPL_ENABLE_CLI OFF CACHE BOOL "" FORCE) set(LIBPL_ENABLE_CLI OFF CACHE BOOL "" FORCE)
@@ -48,7 +44,7 @@ add_subdirectory(lib/libimhex)
if (WIN32) if (WIN32)
set_target_properties(libimhex PROPERTIES set_target_properties(libimhex PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../libimhex.dll" IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../libimhex.dll"
IMPORTED_IMPLIB "${CMAKE_CURRENT_SOURCE_DIR}/lib/liblibimhex.dll.a" IMPORTED_IMPLIB "${CMAKE_CURRENT_SOURCE_DIR}/lib/libimhex.dll.a"
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/lib/libimhex/include") INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/lib/libimhex/include")
elseif (APPLE) elseif (APPLE)
file(GLOB LIBIMHEX_DYLIB "${CMAKE_CURRENT_SOURCE_DIR}/../../Frameworks/libimhex.*.dylib") file(GLOB LIBIMHEX_DYLIB "${CMAKE_CURRENT_SOURCE_DIR}/../../Frameworks/libimhex.*.dylib")

View File

@@ -14,23 +14,22 @@ AppDir:
- amd64 - amd64
allow_unauthenticated: true allow_unauthenticated: true
sources: sources:
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular main restricted - sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy main restricted
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-updates main restricted - sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates main restricted
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular universe - sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy universe
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-updates universe - sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates universe
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular multiverse - sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy multiverse
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-updates multiverse - sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates multiverse
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-backports main restricted - sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-backports main restricted
universe multiverse universe multiverse
- sourceline: deb http://security.ubuntu.com/ubuntu oracular-security main restricted - sourceline: deb http://security.ubuntu.com/ubuntu jammy-security main restricted
- sourceline: deb http://security.ubuntu.com/ubuntu oracular-security universe - sourceline: deb http://security.ubuntu.com/ubuntu jammy-security universe
- sourceline: deb http://security.ubuntu.com/ubuntu oracular-security multiverse - sourceline: deb http://security.ubuntu.com/ubuntu jammy-security multiverse
include: include:
- librsvg2-common - librsvg2-common
- libbz2-1.0:amd64 - libbz2-1.0:amd64
- libcap2:amd64 - libcap2:amd64
- libdbus-1-3:amd64 - libdbus-1-3:amd64
- libfontconfig1:amd64
- libgpg-error0:amd64 - libgpg-error0:amd64
- liblzma5:amd64 - liblzma5:amd64
- libnss-mdns:amd64 - libnss-mdns:amd64

View File

@@ -13,7 +13,6 @@ RUN pacman -S --needed --noconfirm \
glfw-x11 \ glfw-x11 \
file \ file \
mbedtls \ mbedtls \
fontconfig \
freetype2 \ freetype2 \
curl \ curl \
dbus \ dbus \

4
dist/Arch/PKGBUILD vendored
View File

@@ -8,7 +8,7 @@ pkgdesc="A Hex Editor for Reverse Engineers, Programmers and people who value th
arch=("x86_64") arch=("x86_64")
url="https://github.com/WerWolv/ImHex" url="https://github.com/WerWolv/ImHex"
license=('GPL2') license=('GPL2')
depends=(glfw mbedtls fontconfig freetype2 libglvnd dbus gtk3 curl fmt yara nlohmann-json zlib bzip2 xz zstd) depends=(glfw mbedtls freetype2 libglvnd dbus gtk3 curl fmt yara nlohmann-json zlib bzip2 xz zstd)
makedepends=(git) makedepends=(git)
provides=(imhex) provides=(imhex)
conflicts=(imhex) conflicts=(imhex)
@@ -26,5 +26,5 @@ package() {
install -d "$pkgdir/usr/share/imhex" install -d "$pkgdir/usr/share/imhex"
cp -r "$srcdir/usr/share/imhex/"{constants,encodings,includes,magic,patterns} "$pkgdir/usr/share/imhex" cp -r "$srcdir/usr/share/imhex/"{constants,encodings,includes,magic,patterns} "$pkgdir/usr/share/imhex"
cp -r "$srcdir/usr/share/"{applications,licenses,pixmaps,mime} "$pkgdir/usr/share" cp -r "$srcdir/usr/share/"{applications,licenses,pixmaps} "$pkgdir/usr/share"
} }

1
dist/Brewfile vendored
View File

@@ -6,6 +6,7 @@ brew "freetype2"
brew "libmagic" brew "libmagic"
brew "pkg-config" brew "pkg-config"
brew "curl" brew "curl"
brew "gcc@12"
brew "llvm" brew "llvm"
brew "glfw" brew "glfw"
brew "ninja" brew "ninja"

View File

@@ -4,7 +4,7 @@ Section: editors
Priority: optional Priority: optional
Architecture: amd64 Architecture: amd64
License: GNU GPL-2 License: GNU GPL-2
Depends: libfontconfig1, libglfw3 | libglfw3-wayland, libmagic1, libmbedtls14, libfreetype6, libopengl0, libdbus-1-3, xdg-desktop-portal Depends: libglfw3 | libglfw3-wayland, libmagic1, libmbedtls14, 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

View File

@@ -20,14 +20,13 @@ DEPEND=""
RDEPEND="${DEPEND} RDEPEND="${DEPEND}
media-libs/glfw media-libs/glfw
sys-apps/file sys-apps/file
net-libs/mbedtls dev-libs/mbedtls
dev-cpp/nlohmann_json dev-cpp/nlohmann_json
sys-apps/dbus dbus
sys-apps/xdg-desktop-portal xdg-desktop-portal
sys-libs/zlib sys-libs/zlib
app-arch/bzip2 app-arch/bzip2
app-arch/lzma app-arch/lzma
app-arch/zstd app-arch/zstd
app-arch/lz4
" "
BDEPEND="${DEPEND}" BDEPEND="${DEPEND}"

View File

@@ -1,4 +1,4 @@
FROM ubuntu:24.10 as build FROM ubuntu:22.04 as build
# Used to invalidate layer cache but not mount cache # Used to invalidate layer cache but not mount cache
# See https://github.com/moby/moby/issues/41715#issuecomment-733976493 # See https://github.com/moby/moby/issues/41715#issuecomment-733976493
@@ -14,13 +14,24 @@ apt update
# general deps # general deps
apt install -y ccache git wget apt install -y ccache git wget
# appimage tools deps # appimage tools deps
apt install -y python3-pip python3-venv python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fuse ninja-build apt install -y python3-pip python3-setuptools desktop-file-utils libgdk-pixbuf2.0-dev fuse ninja-build
apt install -y squashfs-tools zsync apt install -y squashfs-tools zsync
# imhex deps # imhex deps
/tmp/get_deps_debian.sh /tmp/get_deps_debian.sh
EOF EOF
RUN --mount=type=cache,target=/cache <<EOF
# Download appimage-builder
set -xe
mkdir -p /cache/bin
wget -nc https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /cache/bin/appimagetool || true
chmod +x /cache/bin/appimagetool
pip3 install git+https://github.com/AppImageCrafters/appimage-builder@f38699e
EOF
ENV PATH="/cache/bin/:${PATH}" ENV PATH="/cache/bin/:${PATH}"
# Copy Imhex source # Copy Imhex source
@@ -36,7 +47,7 @@ RUN <<EOF
# Prepare ImHex build # Prepare ImHex build
set -xe set -xe
CC=gcc-14 CXX=g++-14 cmake -G "Ninja" \ CC=gcc-12 CXX=g++-12 cmake -G "Ninja" \
-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 \
@@ -60,18 +71,9 @@ ccache -s
EOF EOF
RUN <<EOF RUN <<EOF
# Download appimage-builder # Package ImHex as AppImage
set -xe set -xe
mkdir -p /cache/bin
wget -nc https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O /cache/bin/appimagetool || true
chmod +x /cache/bin/appimagetool
python3 -m venv venv
. venv/bin/activate
pip3 install git+https://github.com/AppImageCrafters/appimage-builder@f38699e
# Package ImHex as AppImage
export VERSION=$(cat /imhex/VERSION) export VERSION=$(cat /imhex/VERSION)
appimage-builder --recipe /imhex/dist/AppImageBuilder.yml appimage-builder --recipe /imhex/dist/AppImageBuilder.yml
EOF EOF

View File

@@ -1,48 +0,0 @@
import subprocess
import sys
def get_commits(branch: str, start_tag: str, end_tag: str) -> list[str]:
try:
commits_raw = subprocess.check_output([ "git", "--no-pager", "log", branch, "--no-color", "--pretty=oneline", "--abbrev-commit", f"{start_tag}..{end_tag}"], stderr=subprocess.DEVNULL).decode("UTF-8").split("\n")
except:
return []
commits = []
for line in commits_raw:
commits.append(line[9:])
return commits
def main(args: list) -> int:
if len(args) != 2:
print(f"Usage: {args[0]} prev_minor")
return 1
last_minor_version = f"v1.{args[1]}"
master_commits = get_commits("master", f"{last_minor_version}.0", "master")
for i in range(1, 100):
branch_commits = get_commits(f"releases/{last_minor_version}.X", f"{last_minor_version}.0", f"{last_minor_version}.{i}")
if len(branch_commits) == 0:
break
master_commits = [commit for commit in master_commits if commit not in branch_commits]
sorted_commits = {}
for commit in master_commits:
category, commit_name = commit.split(":", 1)
if category not in sorted_commits:
sorted_commits[category] = []
sorted_commits[category].append(commit_name)
for category in sorted_commits:
print(f"## {category}\n")
for commit in sorted_commits[category]:
print(f"- {commit}")
print(f"\n")
if __name__ == "__main__":
exit(main(sys.argv))

View File

@@ -5,7 +5,6 @@ pacman -S $@ --needed \
gcc \ gcc \
lld \ lld \
glfw \ glfw \
fontconfig \
file \ file \
mbedtls \ mbedtls \
freetype2 \ freetype2 \
@@ -19,5 +18,4 @@ pacman -S $@ --needed \
zlib \ zlib \
bzip2 \ bzip2 \
xz \ xz \
zstd \ zstd
lz4

View File

@@ -8,8 +8,8 @@ fi
apt install -y \ apt install -y \
build-essential \ build-essential \
gcc-14 \ gcc-12 \
g++-14 \ g++-12 \
lld \ lld \
${PKGCONF:-} \ ${PKGCONF:-} \
cmake \ cmake \
@@ -18,7 +18,6 @@ apt install -y \
libglm-dev \ libglm-dev \
libmagic-dev \ libmagic-dev \
libmbedtls-dev \ libmbedtls-dev \
libfontconfig-dev \
libfreetype-dev \ libfreetype-dev \
libdbus-1-dev \ libdbus-1-dev \
libcurl4-gnutls-dev \ libcurl4-gnutls-dev \
@@ -27,5 +26,4 @@ apt install -y \
zlib1g-dev \ zlib1g-dev \
libbz2-dev \ libbz2-dev \
liblzma-dev \ liblzma-dev \
libzstd-dev \ libzstd-dev
liblz4-dev

View File

@@ -4,7 +4,6 @@ dnf install -y \
cmake \ cmake \
dbus-devel \ dbus-devel \
file-devel \ file-devel \
fontconfig-devel \
freetype-devel \ freetype-devel \
libcurl-devel \ libcurl-devel \
gcc-c++ \ gcc-c++ \
@@ -17,5 +16,4 @@ dnf install -y \
libzstd-devel \ libzstd-devel \
zlib-devel \ zlib-devel \
bzip2-devel \ bzip2-devel \
xz-devel \ xz-devel
lz4-devel

View File

@@ -17,5 +17,4 @@ pacboy -S --needed --noconfirm \
zlib:p \ zlib:p \
bzip2:p \ bzip2:p \
xz:p \ xz:p \
zstd:p \ zstd:p
lz4:p

View File

@@ -3,9 +3,8 @@
zypper install \ zypper install \
cmake \ cmake \
ninja \ ninja \
gcc14 \ gcc12 \
gcc14-c++ \ gcc12-c++ \
fontconfig-devel \
freetype2-devel \ freetype2-devel \
libcurl-devel \ libcurl-devel \
dbus-1-devel \ dbus-1-devel \
@@ -17,5 +16,4 @@ zypper install \
libzstd-devel \ libzstd-devel \
zlib-devel \ zlib-devel \
bzip3-devel \ bzip3-devel \
xz-devel \ xz-devel
lz4-dev

2
dist/imhex.desktop vendored
View File

@@ -8,5 +8,3 @@ Type=Application
StartupNotify=true StartupNotify=true
Categories=Development;IDE; Categories=Development;IDE;
StartupWMClass=imhex StartupWMClass=imhex
Keywords=static-analysis;reverse-engineering;disassembler;disassembly;hacking;forensics;hex-editor;cybersecurity;security;binary-analysis;
MimeType=application/vnd.imhex.proj;

8
dist/imhex.mime.xml vendored
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="application/vnd.imhex.proj">
<comment>ImHex Project</comment>
<glob pattern="*.hexproj"/>
</mime-type>
</mime-info>

16
dist/langtool.py vendored
View File

@@ -129,19 +129,16 @@ def main():
key in lang_data["translations"] key in lang_data["translations"]
and lang_data["translations"][key] != INVALID_TRANSLATION and lang_data["translations"][key] != INVALID_TRANSLATION
) )
if ( if not has_translation and not (
has_translation (command == "retranslate" or command == "untranslate")
and not ( and re.compile(args.keys).fullmatch(key)
(command == "retranslate" or command == "untranslate")
and re.compile(args.keys).fullmatch(key)
)
and not command == "fmtzh"
): ):
continue continue
if command == "check": if command == "check":
print( print(
f"Error: Translation {lang_data['code']} is missing translation for key '{key}'" f"Error: Translation {lang_data['code']} is missing translation for key '{key}'"
) )
exit(2)
elif ( elif (
command == "translate" command == "translate"
or command == "retranslate" or command == "retranslate"
@@ -151,10 +148,7 @@ def main():
continue continue
reference_tranlsation = ( reference_tranlsation = (
" '%s'" % reference_lang_data["translations"][key] " '%s'" % reference_lang_data["translations"][key]
if ( if reference_lang_data
reference_lang_data
and key in reference_lang_data["translations"]
)
else "" else ""
) )
print( print(

View File

@@ -1,7 +1,7 @@
# This base image is also known as "crosscompile". See arm64.crosscompile.Dockerfile # This base image is also known as "crosscompile". See arm64.crosscompile.Dockerfile
FROM ghcr.io/itrooz/macos-crosscompile:clang17-nosdk as build FROM ghcr.io/itrooz/macos-crosscompile:clang17-nosdk as build
ENV MACOSX_DEPLOYMENT_TARGET 13.0 ENV MACOSX_DEPLOYMENT_TARGET 12.1
# -- DOWNLOADING STUFF # -- DOWNLOADING STUFF
@@ -118,7 +118,7 @@ if [ "$CUSTOM_GLFW" ]; then
cd /mnt/glfw cd /mnt/glfw
mkdir build mkdir build
cd build cd build
CC=o64-clang CXX=o64-clang++ cmake -G "Ninja" \ CC=o64-gcc CXX=o64-g++ cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \ -DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DBUILD_SHARED_LIBS=ON \ -DBUILD_SHARED_LIBS=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \
@@ -126,7 +126,7 @@ if [ "$CUSTOM_GLFW" ]; then
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \ -DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_INSTALL_PREFIX=/vcpkg/installed/arm-osx-mytriplet \ -DCMAKE_INSTALL_PREFIX=/vcpkg/installed/arm-osx-mytriplet \
-DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0 \ -DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=12.1 \
.. ..
ninja -j $JOBS install ninja -j $JOBS install
@@ -148,7 +148,7 @@ RUN --mount=type=cache,target=/cache --mount=type=cache,target=/mnt/ImHex/build/
`# ccache flags` \ `# ccache flags` \
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_OBJC_COMPILER_LAUNCHER=ccache -DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_OBJC_COMPILER_LAUNCHER=ccache -DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
`# MacOS cross-compiling flags` \ `# MacOS cross-compiling flags` \
-DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0 \ -DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=12.1 \
`# Override compilers for code generators` \ `# Override compilers for code generators` \
-DNATIVE_CMAKE_C_COMPILER=/usr/bin/clang -DNATIVE_CMAKE_CXX_COMPILER=/usr/bin/clang++ \ -DNATIVE_CMAKE_C_COMPILER=/usr/bin/clang -DNATIVE_CMAKE_CXX_COMPILER=/usr/bin/clang++ \
`# Normal ImHex flags` \ `# Normal ImHex flags` \

View File

@@ -68,6 +68,19 @@ RUN --mount=type=cache,target=/cache <<EOF
ccache -s ccache -s
EOF EOF
# Not needed, because we don't use gcc for cross-compiling anymore
# ## Install dependencies for gcc-13
# RUN apt install -y gcc g++ zlib1g-dev libmpc-dev libmpfr-dev libgmp-dev
# ## Build cross-compiler gcc-13
# RUN --mount=type=cache,target=/cache <<EOF
# set -xe
# ccache -zs
# cd /osxcross
# UNATTENDED=1 CC=/usr/lib/ccache/gcc CXX=/usr/lib/ccache/g++ GCC_VERSION=13.2.0 ./build_gcc.sh
# ccache -s
# EOF
ARG DELETE_SDK=1 ARG DELETE_SDK=1
RUN <<EOF RUN <<EOF

17
dist/rpm/imhex.spec vendored
View File

@@ -1,5 +1,3 @@
%define source_date_epoch_from_changelog 0
Name: imhex Name: imhex
Version: VERSION Version: VERSION
Release: 0%{?dist} Release: 0%{?dist}
@@ -16,7 +14,6 @@ BuildRequires: cmake
BuildRequires: desktop-file-utils BuildRequires: desktop-file-utils
BuildRequires: dbus-devel BuildRequires: dbus-devel
BuildRequires: file-devel BuildRequires: file-devel
BuildRequires: fontconfig-devel
BuildRequires: freetype-devel BuildRequires: freetype-devel
BuildRequires: fmt-devel BuildRequires: fmt-devel
BuildRequires: gcc-c++ BuildRequires: gcc-c++
@@ -35,7 +32,7 @@ BuildRequires: zlib-devel
BuildRequires: bzip2-devel BuildRequires: bzip2-devel
BuildRequires: xz-devel BuildRequires: xz-devel
%if 0%{?rhel} %if 0%{?rhel}
BuildRequires: gcc-toolset-14 BuildRequires: gcc-toolset-12
%endif %endif
Provides: bundled(gnulib) Provides: bundled(gnulib)
@@ -71,9 +68,9 @@ rm -rf lib/third_party/{fmt,nlohmann_json,yara}
%build %build
%if 0%{?rhel} %if 0%{?rhel}
. /opt/rh/gcc-toolset-14/enable . /opt/rh/gcc-toolset-12/enable
%set_build_flags %set_build_flags
CXXFLAGS+=" -std=gnu++23" CXXFLAGS+=" -std=gnu++2b"
%endif %endif
%cmake \ %cmake \
-D CMAKE_BUILD_TYPE=Release \ -D CMAKE_BUILD_TYPE=Release \
@@ -94,9 +91,9 @@ CXXFLAGS+=" -std=gnu++23"
%check %check
%if 0%{?rhel} %if 0%{?rhel}
. /opt/rh/gcc-toolset-14/enable . /opt/rh/gcc-toolset-12/enable
%set_build_flags %set_build_flags
CXXFLAGS+=" -std=gnu++23" CXXFLAGS+=" -std=gnu++2b"
%endif %endif
@@ -125,7 +122,9 @@ cp -a lib/third_party/xdgpp/LICENSE %{buildroot
%{_bindir}/imhex-updater %{_bindir}/imhex-updater
%{_datadir}/pixmaps/%{name}.png %{_datadir}/pixmaps/%{name}.png
%{_datadir}/applications/%{name}.desktop %{_datadir}/applications/%{name}.desktop
%{_datadir}/mime/packages/%{name}.xml
%{_libdir}/libimhex.so* %{_libdir}/libimhex.so*
%{_libdir}/%{name}/ %{_libdir}/%{name}/
%{_metainfodir}/net.werwolv.%{name}.metainfo.xml %{_metainfodir}/net.werwolv.%{name}.metainfo.xml
%changelog

5
dist/web/Dockerfile vendored
View File

@@ -5,7 +5,7 @@ FROM emscripten/emsdk:3.1.51 as build
ARG UNIQUEKEY 1 ARG UNIQUEKEY 1
RUN apt update RUN apt update
RUN apt install -y git ccache autoconf automake libtool cmake pkg-config ninja-build RUN apt install -y git ccache autoconf automake libtool cmake pkg-config
RUN <<EOF RUN <<EOF
# Install vcpkg # Install vcpkg
@@ -56,7 +56,6 @@ set -xe
ccache -zs ccache -zs
cmake /imhex \ cmake /imhex \
-G "Ninja" \
-DIMHEX_OFFLINE_BUILD=ON \ -DIMHEX_OFFLINE_BUILD=ON \
-DIMHEX_STATIC_LINK_PLUGINS=ON \ -DIMHEX_STATIC_LINK_PLUGINS=ON \
-DIMHEX_EXCLUDE_PLUGINS="script_loader" \ -DIMHEX_EXCLUDE_PLUGINS="script_loader" \
@@ -69,7 +68,7 @@ cmake /imhex
-DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake \ -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake \
-DCMAKE_BUILD_TYPE=Release -DCMAKE_BUILD_TYPE=Release
ninja -j $JOBS make -j $JOBS
cp /imhex/dist/web/source/* /build cp /imhex/dist/web/source/* /build
ccache -s ccache -s

View File

@@ -62,7 +62,7 @@
</head> </head>
<body> <body>
<div id="loading" class="centered"> <div id="loading" class="centered">
<img src="https://raw.githubusercontent.com/WerWolv/ImHex/master/plugins/builtin/romfs/assets/dark/banner.svg" id="logo" alt="ImHex Logo"> <img src="https://raw.githubusercontent.com/WerWolv/ImHex/master/plugins/builtin/romfs/assets/dark/banner.png" id="logo" alt="ImHex Logo">
<h1>A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</h1> <h1>A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</h1>
<h2>Available both natively and on the web</h2> <h2>Available both natively and on the web</h2>
<h5>ImHex runs directly in your web browser with the help of Emscripten and WebAssembly.</h5> <h5>ImHex runs directly in your web browser with the help of Emscripten and WebAssembly.</h5>

View File

@@ -137,7 +137,7 @@ a:hover {
:root { :root {
--progress: 0%; --progress: 25%;
} }
.progress-bar-container { .progress-bar-container {
@@ -175,14 +175,3 @@ a:hover {
width: var(--progress); width: var(--progress);
background-color: #3864cb; background-color: #3864cb;
} }
#logo {
height: 25%;
margin-top: 50px;
}
.canvas-fixed {
position: absolute;
top: 0;
left: 0;
}

View File

@@ -100,77 +100,7 @@ var notWorkingTimer = setTimeout(() => {
var Module = { var Module = {
preRun: [], preRun: [],
postRun: function() { postRun: [],
// Patch the emscripten GLFW module to send mouse and touch events in the right order
// For ImGui interactions to correctly work with touch input, MousePos events need
// to be processed first and then MouseButton events in the next frame. By default,
// GLFW does the exact opposite, which causes buttons to require two taps to register
// and windows get "stuck" to the cursor when dragged or resized
GLFW.onMousemove = event => {
if (event.type === "touchmove") {
event.preventDefault();
let primaryChanged = false;
for (let i of event.changedTouches) {
if (GLFW.primaryTouchId === i.identifier) {
Browser.setMouseCoords(i.pageX, i.pageY);
primaryChanged = true;
break;
}
}
if (!primaryChanged) {
return;
}
} else {
Browser.calculateMouseEvent(event);
}
};
GLFW.onMouseButtonChanged = (event, status) => {
if (!GLFW.active) return;
if (event.target != Module["canvas"]) return;
const isTouchType = event.type === "touchstart" || event.type === "touchend" || event.type === "touchcancel";
let eventButton = 0;
if (isTouchType) {
event.preventDefault();
let primaryChanged = false;
if (GLFW.primaryTouchId === null && event.type === "touchstart" && event.targetTouches.length > 0) {
const chosenTouch = event.targetTouches[0];
GLFW.primaryTouchId = chosenTouch.identifier;
Browser.setMouseCoords(chosenTouch.pageX, chosenTouch.pageY);
primaryChanged = true;
} else if (event.type === "touchend" || event.type === "touchcancel") {
for (let i of event.changedTouches) {
if (GLFW.primaryTouchId === i.identifier) {
GLFW.primaryTouchId = null;
primaryChanged = true;
break;
}
}
}
if (!primaryChanged) {
return;
}
} else {
Browser.calculateMouseEvent(event);
eventButton = GLFW.DOMToGLFWMouseButton(event);
}
if (status == 1) {
GLFW.active.buttons |= (1 << eventButton);
try {
event.target.setCapture();
} catch (e) {}
} else {
GLFW.active.buttons &= ~(1 << eventButton);
}
if (GLFW.active.cursorPosFunc) {
getWasmTableEntry(GLFW.active.cursorPosFunc)(GLFW.active.id, Browser.mouseX, Browser.mouseY);
}
if (GLFW.active.mouseButtonFunc) {
getWasmTableEntry(GLFW.active.mouseButtonFunc)(GLFW.active.id, eventButton, status, GLFW.getModBits(GLFW.active));
}
};
},
onRuntimeInitialized: function() { onRuntimeInitialized: function() {
// Triggered when the wasm module is loaded and ready to use. // Triggered when the wasm module is loaded and ready to use.
document.getElementById("loading").style.display = "none" document.getElementById("loading").style.display = "none"
@@ -181,55 +111,13 @@ var Module = {
print: (function() { })(), print: (function() { })(),
printErr: function(text) { }, printErr: function(text) { },
canvas: (function() { canvas: (function() {
const canvas = document.getElementById('canvas'); let canvas = document.getElementById('canvas');
canvas.addEventListener("webglcontextlost", function(e) { // As a default initial behavior, pop up an alert when webgl context is lost. To make your
alert('WebGL context lost, please reload the page'); // application robust, you may want to override this behavior before shipping!
e.preventDefault(); // See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
}, false); canvas.addEventListener("webglcontextlost", function(e) { alert('WebGL context lost. You will need to reload the page.'); e.preventDefault(); }, false);
// Turn long touches into right-clicks return canvas;
let timer = null;
canvas.addEventListener('touchstart', event => {
timer = setTimeout(() => {
let eventArgs = {
bubbles: true,
cancelable: true,
view: window,
screenX: event.touches[0].screenX,
screenY: event.touches[0].screenY,
clientX: event.touches[0].clientX,
clientY: event.touches[0].clientY,
button: 2,
buttons: 2,
relatedTarget: event.target,
region: event.region
}
canvas.dispatchEvent(new MouseEvent('mousedown', eventArgs));
canvas.dispatchEvent(new MouseEvent('mouseup', eventArgs));
}, 400);
});
canvas.addEventListener('touchend', event => {
if (timer) {
clearTimeout(timer);
timer = null;
}
});
if (typeof WebGL2RenderingContext !== 'undefined') {
let gl = canvas.getContext('webgl2', { stencil: true });
if (!gl) {
console.error('WebGL 2 not available, falling back to WebGL');
gl = canvas.getContext('webgl', { stencil: true });
}
if (!gl) {
alert('WebGL not available with stencil buffer');
}
return canvas;
} else {
alert('WebGL 2 not supported by this browser');
}
})(), })(),
setStatus: function(text) { }, setStatus: function(text) { },
totalDependencies: 0, totalDependencies: 0,
@@ -256,16 +144,14 @@ if (urlParams.has("lang")) {
window.addEventListener('resize', js_resizeCanvas, false); window.addEventListener('resize', js_resizeCanvas, false);
function js_resizeCanvas() { function js_resizeCanvas() {
let canvas = document.getElementById('canvas'); let canvas = document.getElementById('canvas');
canvas.top = document.documentElement.clientTop;
canvas.left = document.documentElement.clientLeft;
canvas.width = Math.min(document.documentElement.clientWidth, window.innerWidth || 0); canvas.width = Math.min(document.documentElement.clientWidth, window.innerWidth || 0);
canvas.height = Math.min(document.documentElement.clientHeight, window.innerHeight || 0); canvas.height = Math.min(document.documentElement.clientHeight, window.innerHeight || 0);
}
// Prevent some default browser shortcuts from preventing ImHex ones to work canvas.classList.add("canvas_full_screen")
document.addEventListener('keydown', e => {
if (e.ctrlKey) { if (GLFW.active && GLFW.active.windowPosFunc) {
if (e.which == 83) e.preventDefault(); getWasmTableEntry(GLFW.active.windowPosFunc)(GLFW.active.id, GLFW.active.x, GLFW.active.y);
} }
})
GLFW.onWindowSizeChanged();
}

View File

@@ -36,9 +36,6 @@ set(LIBIMHEX_SOURCES
source/helpers/logger.cpp source/helpers/logger.cpp
source/helpers/tar.cpp source/helpers/tar.cpp
source/helpers/debugging.cpp source/helpers/debugging.cpp
source/helpers/default_paths.cpp
source/helpers/imgui_hooks.cpp
source/helpers/semantic_version.cpp
source/test/tests.cpp source/test/tests.cpp
@@ -126,7 +123,7 @@ target_link_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${MBEDTLS_LIBRARY_DIR}
if (NOT EMSCRIPTEN) if (NOT EMSCRIPTEN)
# curl is only used in non-emscripten builds # curl is only used in non-emscripten builds
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} CURL::libcurl) target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${CURL_LIBRARIES})
endif() endif()
@@ -145,7 +142,7 @@ if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD)
precompileHeaders(libimhex "${CMAKE_CURRENT_SOURCE_DIR}/include") precompileHeaders(libimhex "${CMAKE_CURRENT_SOURCE_DIR}/include")
endif() endif()
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${NLOHMANN_JSON_LIBRARIES} imgui_all_includes ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${LUNASVG_LIBRARIES} ${BOOST_LIBRARIES}) target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${NLOHMANN_JSON_LIBRARIES} imgui_all_includes ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${LUNASVG_LIBRARIES} tracing)
set_property(TARGET libimhex PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE) set_property(TARGET libimhex PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE)

View File

@@ -1,3 +1,4 @@
#pragma once #pragma once
#include <hex/helpers/types.hpp> #include <hex/helpers/types.hpp>
#include <hex/helpers/intrinsics.hpp>

View File

@@ -295,7 +295,6 @@ namespace hex {
}; };
class AchievementManager { class AchievementManager {
static bool s_initialized;
public: public:
AchievementManager() = delete; AchievementManager() = delete;

View File

@@ -2,10 +2,10 @@
#include <hex.hpp> #include <hex.hpp>
#include <hex/api/localization_manager.hpp> #include <hex/api/localization_manager.hpp>
#include <hex/api/shortcut_manager.hpp>
#include <hex/helpers/concepts.hpp> #include <hex/helpers/concepts.hpp>
#include <functional> #include <functional>
#include <map>
#include <mutex> #include <mutex>
#include <span> #include <span>
#include <string> #include <string>
@@ -24,6 +24,7 @@ enum ImGuiCustomCol : int;
namespace hex { namespace hex {
class View; class View;
class Shortcut;
class Task; class Task;
namespace dp { namespace dp {
@@ -380,7 +381,7 @@ namespace hex {
}; };
using DisplayCallback = std::function<std::string(std::string)>; using DisplayCallback = std::function<std::string(std::string)>;
using ExecuteCallback = std::function<std::optional<std::string>(std::string)>; using ExecuteCallback = std::function<void(std::string)>;
using QueryCallback = std::function<std::vector<QueryResult>(std::string)>; using QueryCallback = std::function<std::vector<QueryResult>(std::string)>;
struct Entry { struct Entry {
@@ -416,7 +417,7 @@ namespace hex {
const std::string &command, const std::string &command,
const UnlocalizedString &unlocalizedDescription, const UnlocalizedString &unlocalizedDescription,
const impl::DisplayCallback &displayCallback, const impl::DisplayCallback &displayCallback,
const impl::ExecuteCallback &executeCallback = [](auto) { return std::nullopt; }); const impl::ExecuteCallback &executeCallback = [](auto) {});
/** /**
* @brief Adds a new command handler to the command palette * @brief Adds a new command handler to the command palette
@@ -437,7 +438,7 @@ namespace hex {
namespace impl { namespace impl {
using VisualizerFunctionCallback = std::function<void(pl::ptrn::Pattern&, bool, std::span<const pl::core::Token::Literal>)>; using VisualizerFunctionCallback = std::function<void(pl::ptrn::Pattern&, pl::ptrn::IIterable&, bool, std::span<const pl::core::Token::Literal>)>;
struct FunctionDefinition { struct FunctionDefinition {
pl::api::Namespace ns; pl::api::Namespace ns;
@@ -449,14 +450,6 @@ namespace hex {
bool dangerous; bool dangerous;
}; };
struct TypeDefinition {
pl::api::Namespace ns;
std::string name;
pl::api::FunctionParameterCount parameterCount;
pl::api::TypeCallback callback;
};
struct Visualizer { struct Visualizer {
pl::api::FunctionParameterCount parameterCount; pl::api::FunctionParameterCount parameterCount;
VisualizerFunctionCallback callback; VisualizerFunctionCallback callback;
@@ -466,7 +459,6 @@ namespace hex {
const std::map<std::string, Visualizer>& getInlineVisualizers(); const std::map<std::string, Visualizer>& getInlineVisualizers();
const std::map<std::string, pl::api::PragmaHandler>& getPragmas(); const std::map<std::string, pl::api::PragmaHandler>& getPragmas();
const std::vector<FunctionDefinition>& getFunctions(); const std::vector<FunctionDefinition>& getFunctions();
const std::vector<TypeDefinition>& getTypes();
} }
@@ -525,20 +517,6 @@ namespace hex {
const pl::api::FunctionCallback &func const pl::api::FunctionCallback &func
); );
/**
* @brief Adds a new type to the pattern language
* @param ns The namespace of the type
* @param name The name of the type
* @param parameterCount The amount of non-type template parameters the type takes
* @param func The type callback
*/
void addType(
const pl::api::Namespace &ns,
const std::string &name,
pl::api::FunctionParameterCount parameterCount,
const pl::api::TypeCallback &func
);
/** /**
* @brief Adds a new visualizer to the pattern language * @brief Adds a new visualizer to the pattern language
* @note Visualizers are extensions to the [[hex::visualize]] attribute, used to visualize data * @note Visualizers are extensions to the [[hex::visualize]] attribute, used to visualize data
@@ -770,7 +748,7 @@ namespace hex {
struct MenuItem { struct MenuItem {
std::vector<UnlocalizedString> unlocalizedNames; std::vector<UnlocalizedString> unlocalizedNames;
Icon icon; Icon icon;
Shortcut shortcut; std::unique_ptr<Shortcut> shortcut;
View *view; View *view;
MenuCallback callback; MenuCallback callback;
EnabledCallback enabledCallback; EnabledCallback enabledCallback;
@@ -796,7 +774,6 @@ namespace hex {
const std::multimap<u32, MainMenuItem>& getMainMenuItems(); const std::multimap<u32, MainMenuItem>& getMainMenuItems();
const std::multimap<u32, MenuItem>& getMenuItems(); const std::multimap<u32, MenuItem>& getMenuItems();
const std::vector<MenuItem*>& getToolbarMenuItems();
std::multimap<u32, MenuItem>& getMenuItemsMutable(); std::multimap<u32, MenuItem>& getMenuItemsMutable();
const std::vector<DrawCallback>& getWelcomeScreenEntries(); const std::vector<DrawCallback>& getWelcomeScreenEntries();
@@ -939,11 +916,6 @@ namespace hex {
*/ */
void addMenuItemToToolbar(const UnlocalizedString &unlocalizedName, ImGuiCustomCol color); void addMenuItemToToolbar(const UnlocalizedString &unlocalizedName, ImGuiCustomCol color);
/**
* @brief Reconstructs the toolbar items list after they have been modified
*/
void updateToolbarItems();
/** /**
* @brief Adds a new sidebar item * @brief Adds a new sidebar item
* @param icon The icon to use for the item * @param icon The icon to use for the item
@@ -1009,34 +981,12 @@ namespace hex {
namespace impl { namespace impl {
using Callback = std::function<std::string(prv::Provider *provider, u64 address, size_t size)>; using Callback = std::function<std::string(prv::Provider *provider, u64 address, size_t size)>;
struct ExportMenuEntry { struct Entry {
UnlocalizedString unlocalizedName; UnlocalizedString unlocalizedName;
Callback callback; Callback callback;
}; };
struct FindOccurrence { const std::vector<Entry>& getEntries();
Region region;
enum class DecodeType { ASCII, Binary, UTF16, Unsigned, Signed, Float, Double } decodeType;
std::endian endian = std::endian::native;
bool selected;
};
using FindExporterCallback = std::function<std::vector<u8>(const std::vector<FindOccurrence>&, std::function<std::string(FindOccurrence)>)>;
struct FindExporterEntry {
UnlocalizedString unlocalizedName;
std::string fileExtension;
FindExporterCallback callback;
};
/**
* @brief Retrieves a list of all registered data formatters used by the 'File -> Export' menu
*/
const std::vector<ExportMenuEntry>& getExportMenuEntries();
/**
* @brief Retrieves a list of all registered data formatters used in the Results section of the 'Find' view
*/
const std::vector<FindExporterEntry>& getFindExporterEntries();
} }
@@ -1046,14 +996,7 @@ namespace hex {
* @param unlocalizedName The unlocalized name of the formatter * @param unlocalizedName The unlocalized name of the formatter
* @param callback The function to call to format the data * @param callback The function to call to format the data
*/ */
void addExportMenuEntry(const UnlocalizedString &unlocalizedName, const impl::Callback &callback); void add(const UnlocalizedString &unlocalizedName, const impl::Callback &callback);
/**
* @brief Adds a new data exporter for Find results
* @param unlocalizedName The unlocalized name of the formatter
* @param callback The function to call to format the data
*/
void addFindExportFormatter(const UnlocalizedString &unlocalizedName, const std::string fileExtension, const impl::FindExporterCallback &callback);
} }
@@ -1114,7 +1057,7 @@ namespace hex {
}; };
struct MiniMapVisualizer { struct MiniMapVisualizer {
using Callback = std::function<void(u64, std::span<const u8>, std::vector<ImColor>&)>; using Callback = std::function<ImColor(const std::vector<u8>&)>;
UnlocalizedString unlocalizedName; UnlocalizedString unlocalizedName;
Callback callback; Callback callback;
@@ -1295,7 +1238,7 @@ namespace hex {
void stopServices(); void stopServices();
} }
void registerService(const UnlocalizedString &unlocalizedString, const impl::Callback &callback); void registerService(const UnlocalizedString &unlocalizedName, const impl::Callback &callback);
} }
/* Network Communication Interface Registry. Allows adding new communication interface endpoints */ /* Network Communication Interface Registry. Allows adding new communication interface endpoints */

View File

@@ -11,22 +11,21 @@
#include <hex/api/imhex_api.hpp> #include <hex/api/imhex_api.hpp>
#include <hex/helpers/logger.hpp> #include <hex/helpers/logger.hpp>
#include <hex/helpers/patches.hpp>
#include <wolv/types/type_name.hpp> #include <wolv/types/type_name.hpp>
#define EVENT_DEF_IMPL(event_name, event_name_string, should_log, ...) \ #define EVENT_DEF_IMPL(event_name, event_name_string, should_log, ...) \
struct event_name final : public hex::impl::Event<__VA_ARGS__> { \ struct event_name final : public hex::impl::Event<__VA_ARGS__> { \
constexpr static auto Id = [] { return hex::impl::EventId(event_name_string); }(); \ constexpr static auto Id = [] { return hex::impl::EventId(event_name_string); }(); \
constexpr static auto ShouldLog = (should_log); \ constexpr static auto ShouldLog = (should_log); \
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \ explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
\ \
static EventManager::EventList::iterator subscribe(Event::Callback function) { return EventManager::subscribe<event_name>(std::move(function)); } \ static EventManager::EventList::iterator subscribe(Event::Callback function) { return EventManager::subscribe<event_name>(function); } \
static void subscribe(void *token, Event::Callback function) { EventManager::subscribe<event_name>(token, std::move(function)); } \ static void subscribe(void *token, Event::Callback function) { EventManager::subscribe<event_name>(token, function); } \
static void unsubscribe(const EventManager::EventList::iterator &token) noexcept { EventManager::unsubscribe(token); } \ static void unsubscribe(const EventManager::EventList::iterator &token) noexcept { EventManager::unsubscribe(token); } \
static void unsubscribe(void *token) noexcept { EventManager::unsubscribe<event_name>(token); } \ static void unsubscribe(void *token) noexcept { EventManager::unsubscribe<event_name>(token); } \
static void post(auto &&...args) { EventManager::post<event_name>(std::forward<decltype(args)>(args)...); } \ static void post(auto &&...args) { EventManager::post<event_name>(std::forward<decltype(args)>(args)...); } \
} };
#define EVENT_DEF(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, true, __VA_ARGS__) #define EVENT_DEF(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, true, __VA_ARGS__)
#define EVENT_DEF_NO_LOG(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, false, __VA_ARGS__) #define EVENT_DEF_NO_LOG(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, false, __VA_ARGS__)
@@ -59,10 +58,6 @@ namespace hex {
return m_hash == other.m_hash; return m_hash == other.m_hash;
} }
constexpr auto operator<=>(const EventId &other) const {
return m_hash <=> other.m_hash;
}
private: private:
u32 m_hash; u32 m_hash;
}; };
@@ -78,12 +73,11 @@ namespace hex {
explicit Event(Callback func) noexcept : m_func(std::move(func)) { } explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
template<typename E> void operator()(std::string_view eventName, Params... params) const {
void call(Params... params) const {
try { try {
m_func(params...); m_func(params...);
} catch (const std::exception &e) { } catch (const std::exception &e) {
log::error("An exception occurred while handling event {}: {}", wolv::type::getTypeName<E>(), e.what()); log::error("An exception occurred while handling event {}: {}", eventName, e.what());
throw; throw;
} }
} }
@@ -104,7 +98,7 @@ namespace hex {
*/ */
class EventManager { class EventManager {
public: public:
using EventList = std::multimap<impl::EventId, std::unique_ptr<impl::EventBase>>; using EventList = std::list<std::pair<impl::EventId, std::unique_ptr<impl::EventBase>>>;
/** /**
* @brief Subscribes to an event * @brief Subscribes to an event
@@ -117,7 +111,7 @@ namespace hex {
std::scoped_lock lock(getEventMutex()); std::scoped_lock lock(getEventMutex());
auto &events = getEvents(); auto &events = getEvents();
return events.insert({ E::Id, std::make_unique<E>(function) }); return events.insert(events.end(), std::make_pair(E::Id, std::make_unique<E>(function)));
} }
/** /**
@@ -130,9 +124,15 @@ namespace hex {
static void subscribe(void *token, typename E::Callback function) { static void subscribe(void *token, typename E::Callback function) {
std::scoped_lock lock(getEventMutex()); std::scoped_lock lock(getEventMutex());
if (isAlreadyRegistered(token, E::Id)) { if (getTokenStore().contains(token)) {
log::fatal("The token '{}' has already registered the same event ('{}')", token, wolv::type::getTypeName<E>()); auto&& [begin, end] = getTokenStore().equal_range(token);
return; const auto eventRegistered = std::any_of(begin, end, [&](auto &item) {
return item.second->first == E::Id;
});
if (eventRegistered) {
log::fatal("The token '{}' has already registered the same event ('{}')", token, wolv::type::getTypeName<E>());
return;
}
} }
getTokenStore().insert({ token, subscribe<E>(function) }); getTokenStore().insert({ token, subscribe<E>(function) });
@@ -157,7 +157,16 @@ namespace hex {
static void unsubscribe(void *token) noexcept { static void unsubscribe(void *token) noexcept {
std::scoped_lock lock(getEventMutex()); std::scoped_lock lock(getEventMutex());
unsubscribe(token, E::Id); auto &tokenStore = getTokenStore();
auto iter = std::find_if(tokenStore.begin(), tokenStore.end(), [&](auto &item) {
return item.first == token && item.second->first == E::Id;
});
if (iter != tokenStore.end()) {
getEvents().remove(*iter->second);
tokenStore.erase(iter);
}
} }
/** /**
@@ -169,14 +178,14 @@ namespace hex {
static void post(auto && ...args) { static void post(auto && ...args) {
std::scoped_lock lock(getEventMutex()); std::scoped_lock lock(getEventMutex());
auto [begin, end] = getEvents().equal_range(E::Id); for (const auto &[id, event] : getEvents()) {
for (auto it = begin; it != end; ++it) { if (id == E::Id) {
const auto &[id, event] = *it; (*static_cast<E *const>(event.get()))(wolv::type::getTypeName<E>(), std::forward<decltype(args)>(args)...);
(*static_cast<E *const>(event.get())).template call<E>(std::forward<decltype(args)>(args)...); }
} }
#if defined (DEBUG) #if defined (DEBUG)
if constexpr (E::ShouldLog) if (E::ShouldLog)
log::debug("Event posted: '{}'", wolv::type::getTypeName<E>()); log::debug("Event posted: '{}'", wolv::type::getTypeName<E>());
#endif #endif
} }
@@ -195,9 +204,6 @@ namespace hex {
static std::multimap<void *, EventList::iterator>& getTokenStore(); static std::multimap<void *, EventList::iterator>& getTokenStore();
static EventList& getEvents(); static EventList& getEvents();
static std::recursive_mutex& getEventMutex(); static std::recursive_mutex& getEventMutex();
static bool isAlreadyRegistered(void *token, impl::EventId id);
static void unsubscribe(void *token, impl::EventId id);
}; };
/* Default Events */ /* Default Events */
@@ -215,9 +221,7 @@ namespace hex {
EVENT_DEF(EventAbnormalTermination, int); EVENT_DEF(EventAbnormalTermination, int);
EVENT_DEF(EventThemeChanged); EVENT_DEF(EventThemeChanged);
EVENT_DEF(EventOSThemeChanged); EVENT_DEF(EventOSThemeChanged);
EVENT_DEF(EventDPIChanged, float, float);
EVENT_DEF(EventWindowFocused, bool); EVENT_DEF(EventWindowFocused, bool);
EVENT_DEF(EventImHexUpdated, SemanticVersion, SemanticVersion);
/** /**
* @brief Called when the provider is created. * @brief Called when the provider is created.
@@ -243,12 +247,7 @@ namespace hex {
EVENT_DEF(EventWindowInitialized); EVENT_DEF(EventWindowInitialized);
EVENT_DEF(EventWindowDeinitializing, GLFWwindow *); EVENT_DEF(EventWindowDeinitializing, GLFWwindow *);
EVENT_DEF(EventBookmarkCreated, ImHexApi::Bookmarks::Entry&); EVENT_DEF(EventBookmarkCreated, ImHexApi::Bookmarks::Entry&);
EVENT_DEF(EventPatchCreated, u64, u8, u8);
/**
* @brief Called upon creation of an IPS patch.
* As for now, the event only serves a purpose for the achievement unlock.
*/
EVENT_DEF(EventPatchCreated, const u8*, u64, const PatchKind);
EVENT_DEF(EventPatternEvaluating); EVENT_DEF(EventPatternEvaluating);
EVENT_DEF(EventPatternExecuted, const std::string&); EVENT_DEF(EventPatternExecuted, const std::string&);
EVENT_DEF(EventPatternEditorChanged, const std::string&); EVENT_DEF(EventPatternEditorChanged, const std::string&);
@@ -266,7 +265,6 @@ namespace hex {
EVENT_DEF(EventProviderDataModified, prv::Provider *, u64, u64, const u8*); EVENT_DEF(EventProviderDataModified, prv::Provider *, u64, u64, const u8*);
EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64); EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64);
EVENT_DEF(EventProviderDataRemoved, prv::Provider *, u64, u64); EVENT_DEF(EventProviderDataRemoved, prv::Provider *, u64, u64);
EVENT_DEF(EventProviderDirtied, prv::Provider *);
/** /**
* @brief Called when a project has been loaded * @brief Called when a project has been loaded
@@ -276,7 +274,6 @@ namespace hex {
EVENT_DEF_NO_LOG(EventFrameBegin); EVENT_DEF_NO_LOG(EventFrameBegin);
EVENT_DEF_NO_LOG(EventFrameEnd); EVENT_DEF_NO_LOG(EventFrameEnd);
EVENT_DEF_NO_LOG(EventSetTaskBarIconState, u32, u32, u32); EVENT_DEF_NO_LOG(EventSetTaskBarIconState, u32, u32, u32);
EVENT_DEF_NO_LOG(EventImGuiElementRendered, ImGuiID, const std::array<float, 4>&);
EVENT_DEF(RequestAddInitTask, std::string, bool, std::function<bool()>); EVENT_DEF(RequestAddInitTask, std::string, bool, std::function<bool()>);
EVENT_DEF(RequestAddExitTask, std::string, std::function<bool()>); EVENT_DEF(RequestAddExitTask, std::string, std::function<bool()>);

View File

@@ -2,7 +2,6 @@
#include <hex.hpp> #include <hex.hpp>
#include <hex/api/localization_manager.hpp> #include <hex/api/localization_manager.hpp>
#include <hex/helpers/semantic_version.hpp>
#include <functional> #include <functional>
#include <optional> #include <optional>
@@ -76,7 +75,7 @@ namespace hex {
namespace impl { namespace impl {
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t, bool)>; using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t, bool)>;
using HoveringFunction = std::function<std::set<Region>(const prv::Provider *, u64, size_t)>; using HoveringFunction = std::function<bool(const prv::Provider *, u64, const u8*, size_t)>;
const std::map<u32, Highlighting>& getBackgroundHighlights(); const std::map<u32, Highlighting>& getBackgroundHighlights();
const std::map<u32, HighlightingFunction>& getBackgroundHighlightingFunctions(); const std::map<u32, HighlightingFunction>& getBackgroundHighlightingFunctions();
@@ -294,7 +293,7 @@ namespace hex {
namespace impl { namespace impl {
void resetClosingProvider(); void resetClosingProvider();
std::set<prv::Provider*> getClosingProviders(); const std::set<prv::Provider*>& getClosingProviders();
} }
@@ -435,7 +434,6 @@ namespace hex {
void setInitialWindowProperties(InitialWindowProperties properties); void setInitialWindowProperties(InitialWindowProperties properties);
void setGPUVendor(const std::string &vendor); void setGPUVendor(const std::string &vendor);
void setGLRenderer(const std::string &renderer);
void addInitArgument(const std::string &key, const std::string &value = { }); void addInitArgument(const std::string &key, const std::string &value = { });
@@ -575,12 +573,6 @@ namespace hex {
*/ */
const std::string& getGPUVendor(); const std::string& getGPUVendor();
/**
* @brief Gets the current GPU vendor
* @return The current GPU vendor
*/
const std::string& getGLRenderer();
/** /**
* @brief Checks if ImHex is running in portable mode * @brief Checks if ImHex is running in portable mode
* @return Whether ImHex is running in portable mode * @return Whether ImHex is running in portable mode
@@ -605,21 +597,11 @@ namespace hex {
*/ */
std::string getArchitecture(); std::string getArchitecture();
struct LinuxDistro {
std::string name;
std::string version;
};
/**
* @brief Gets information related to the Linux distribution, if running on Linux
*/
std::optional<LinuxDistro> getLinuxDistro();
/** /**
* @brief Gets the current ImHex version * @brief Gets the current ImHex version
* @return ImHex version * @return ImHex version
*/ */
SemanticVersion getImHexVersion(); std::string getImHexVersion(bool withBuildType = true);
/** /**
* @brief Gets the current git commit hash * @brief Gets the current git commit hash
@@ -640,12 +622,6 @@ namespace hex {
*/ */
bool isDebugBuild(); bool isDebugBuild();
/**
* @brief Checks if this version of ImHex is a nightly build
* @return True if this version is a nightly, false if it's a release
*/
bool isNightlyBuild();
enum class UpdateType { enum class UpdateType {
Stable, Stable,
Nightly Nightly
@@ -696,13 +672,6 @@ namespace hex {
*/ */
void* getLibImHexModuleHandle(); void* getLibImHexModuleHandle();
/**
* Adds a new migration routine that will be executed when upgrading from a lower version than specified in migrationVersion
* @param migrationVersion Upgrade point version
* @param function Function to run
*/
void addMigrationRoutine(SemanticVersion migrationVersion, std::function<void()> function);
} }
/** /**

View File

@@ -1,14 +1,11 @@
#pragma once #pragma once
#include <hex.hpp>
#include <map> #include <map>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <vector> #include <vector>
#include <fmt/core.h> #include <fmt/format.h>
#include <wolv/types/static_string.hpp>
namespace hex { namespace hex {
@@ -25,10 +22,8 @@ namespace hex {
}; };
namespace impl { namespace impl {
void setFallbackLanguage(const std::string &language); void setFallbackLanguage(const std::string &language);
void resetLanguageStrings(); void resetLanguageStrings();
} }
void loadLanguage(const std::string &language); void loadLanguage(const std::string &language);
@@ -37,18 +32,14 @@ namespace hex {
[[nodiscard]] const std::map<std::string, std::string> &getSupportedLanguages(); [[nodiscard]] const std::map<std::string, std::string> &getSupportedLanguages();
[[nodiscard]] const std::string &getFallbackLanguage(); [[nodiscard]] const std::string &getFallbackLanguage();
[[nodiscard]] const std::string &getSelectedLanguage(); [[nodiscard]] const std::string &getSelectedLanguage();
} }
struct UnlocalizedString; struct UnlocalizedString;
class LangConst;
class Lang { class Lang {
public: public:
explicit Lang(const char *unlocalizedString); explicit Lang(const char *unlocalizedString);
explicit Lang(const std::string &unlocalizedString); explicit Lang(const std::string &unlocalizedString);
explicit(false) Lang(const LangConst &localizedString);
explicit Lang(const UnlocalizedString &unlocalizedString); explicit Lang(const UnlocalizedString &unlocalizedString);
explicit Lang(std::string_view unlocalizedString); explicit Lang(std::string_view unlocalizedString);
@@ -56,54 +47,30 @@ namespace hex {
[[nodiscard]] operator std::string_view() const; [[nodiscard]] operator std::string_view() const;
[[nodiscard]] operator const char *() const; [[nodiscard]] operator const char *() const;
const char* get() const; [[nodiscard]] const std::string &get() const;
private: private:
std::size_t m_entryHash;
std::string m_unlocalizedString; std::string m_unlocalizedString;
}; };
class LangConst { [[nodiscard]] std::string operator+(const std::string &&left, const Lang &&right);
public: [[nodiscard]] std::string operator+(const Lang &&left, const std::string &&right);
[[nodiscard]] operator std::string() const; [[nodiscard]] std::string operator+(const std::string_view &&left, const Lang &&right);
[[nodiscard]] operator std::string_view() const; [[nodiscard]] std::string operator+(const Lang &&left, const std::string_view &&right);
[[nodiscard]] operator const char *() const; [[nodiscard]] std::string operator+(const char *left, const Lang &&right);
[[nodiscard]] std::string operator+(const Lang &&left, const char *right);
[[nodiscard]] std::string operator+(const Lang &&left, const Lang &&right);
const char* get() const; [[nodiscard]] inline Lang operator""_lang(const char *string, size_t) {
return Lang(string);
}
constexpr static size_t hash(std::string_view string) {
constexpr u64 p = 131;
constexpr u64 m = std::numeric_limits<std::uint32_t>::max() - 4;
u64 total = 0;
u64 currentMultiplier = 1;
for (char c : string) {
total = (total + currentMultiplier * c) % m;
currentMultiplier = (currentMultiplier * p) % m;
}
return total;
}
private:
constexpr explicit LangConst(std::size_t hash, const char *unlocalizedString) : m_entryHash(hash), m_unlocalizedString(unlocalizedString) {}
template<wolv::type::StaticString>
friend consteval LangConst operator""_lang();
friend class Lang;
private:
std::size_t m_entryHash;
const char *m_unlocalizedString = nullptr;
};
struct UnlocalizedString { struct UnlocalizedString {
public: public:
UnlocalizedString() = default; UnlocalizedString() = default;
UnlocalizedString(auto && arg) : m_unlocalizedString(std::forward<decltype(arg)>(arg)) {
template<typename T> static_assert(!std::same_as<std::remove_cvref_t<decltype(arg)>, Lang>, "Expected a unlocalized name, got a localized one!");
UnlocalizedString(T &&arg) : m_unlocalizedString(std::forward<T>(arg)) {
static_assert(!std::same_as<std::remove_cvref_t<T>, Lang>, "Expected a unlocalized name, got a localized one!");
} }
[[nodiscard]] operator std::string() const { [[nodiscard]] operator std::string() const {
@@ -135,17 +102,12 @@ namespace hex {
std::string m_unlocalizedString; std::string m_unlocalizedString;
}; };
template<wolv::type::StaticString String>
[[nodiscard]] consteval LangConst operator""_lang() {
return LangConst(LangConst::hash(String.value.data()), String.value.data());
}
// {fmt} formatter for hex::Lang and hex::LangConst
inline auto format_as(const hex::Lang &entry) {
return entry.get();
}
inline auto format_as(const hex::LangConst &entry) {
return entry.get();
}
} }
template<>
struct fmt::formatter<hex::Lang> : fmt::formatter<std::string_view> {
template<typename FormatContext>
auto format(const hex::Lang &entry, FormatContext &ctx) {
return fmt::formatter<std::string_view>::format(entry.get(), ctx);
}
};

View File

@@ -17,7 +17,7 @@ namespace hex {
class View; class View;
enum class Keys : u32 { enum class Keys {
Space = GLFW_KEY_SPACE, Space = GLFW_KEY_SPACE,
Apostrophe = GLFW_KEY_APOSTROPHE, Apostrophe = GLFW_KEY_APOSTROPHE,
Comma = GLFW_KEY_COMMA, Comma = GLFW_KEY_COMMA,
@@ -138,7 +138,6 @@ namespace hex {
constexpr Key() = default; constexpr Key() = default;
constexpr Key(Keys key) : m_key(static_cast<u32>(key)) { } constexpr Key(Keys key) : m_key(static_cast<u32>(key)) { }
bool operator==(const Key &) const = default;
auto operator<=>(const Key &) const = default; auto operator<=>(const Key &) const = default;
[[nodiscard]] constexpr u32 getKeyCode() const { return m_key; } [[nodiscard]] constexpr u32 getKeyCode() const { return m_key; }
@@ -153,31 +152,224 @@ namespace hex {
constexpr static auto SUPER = Key(static_cast<Keys>(0x0800'0000)); constexpr static auto SUPER = Key(static_cast<Keys>(0x0800'0000));
constexpr static auto CurrentView = Key(static_cast<Keys>(0x1000'0000)); constexpr static auto CurrentView = Key(static_cast<Keys>(0x1000'0000));
constexpr static auto AllowWhileTyping = Key(static_cast<Keys>(0x2000'0000)); constexpr static auto AllowWhileTyping = Key(static_cast<Keys>(0x2000'0000));
constexpr static auto CTRLCMD = Key(static_cast<Keys>(0x4000'0000));
#if defined (OS_MACOS)
constexpr static auto CTRLCMD = SUPER;
#else
constexpr static auto CTRLCMD = CTRL;
#endif
class Shortcut { class Shortcut {
public: public:
Shortcut() = default; Shortcut() = default;
Shortcut(Keys key); Shortcut(Keys key) : m_keys({ key }) { }
explicit Shortcut(std::set<Key> keys); explicit Shortcut(std::set<Key> keys) : m_keys(std::move(keys)) { }
Shortcut(const Shortcut &other) = default; Shortcut(const Shortcut &other) = default;
Shortcut(Shortcut &&) noexcept = default; Shortcut(Shortcut &&) noexcept = default;
constexpr static auto None = Keys(0);
Shortcut& operator=(const Shortcut &other) = default; Shortcut& operator=(const Shortcut &other) = default;
Shortcut& operator=(Shortcut &&) noexcept = default; Shortcut& operator=(Shortcut &&) noexcept = default;
Shortcut operator+(const Key &other) const; constexpr static inline auto None = Keys(0);
Shortcut &operator+=(const Key &other);
bool operator<(const Shortcut &other) const;
bool operator==(const Shortcut &other) const;
bool isLocal() const; Shortcut operator+(const Key &other) const {
std::string toString() const; Shortcut result = *this;
const std::set<Key>& getKeys() const; result.m_keys.insert(other);
bool has(Key key) const;
bool matches(const Shortcut &other) const; return result;
}
Shortcut &operator+=(const Key &other) {
m_keys.insert(other);
return *this;
}
bool operator<(const Shortcut &other) const {
return m_keys < other.m_keys;
}
bool operator==(const Shortcut &other) const {
auto thisKeys = m_keys;
auto otherKeys = other.m_keys;
thisKeys.erase(CurrentView);
thisKeys.erase(AllowWhileTyping);
otherKeys.erase(CurrentView);
otherKeys.erase(AllowWhileTyping);
return thisKeys == otherKeys;
}
bool isLocal() const {
return m_keys.contains(CurrentView);
}
std::string toString() const {
std::string result;
#if defined(OS_MACOS)
constexpr static auto CTRL_NAME = "CTRL";
constexpr static auto ALT_NAME = "OPT";
constexpr static auto SHIFT_NAME = "SHIFT";
constexpr static auto SUPER_NAME = "CMD";
#else
constexpr static auto CTRL_NAME = "CTRL";
constexpr static auto ALT_NAME = "ALT";
constexpr static auto SHIFT_NAME = "SHIFT";
constexpr static auto SUPER_NAME = "SUPER";
#endif
constexpr static auto Concatination = " + ";
auto keys = m_keys;
if (keys.erase(CTRL) > 0) {
result += CTRL_NAME;
result += Concatination;
}
if (keys.erase(ALT) > 0) {
result += ALT_NAME;
result += Concatination;
}
if (keys.erase(SHIFT) > 0) {
result += SHIFT_NAME;
result += Concatination;
}
if (keys.erase(SUPER) > 0) {
result += SUPER_NAME;
result += Concatination;
}
keys.erase(CurrentView);
for (const auto &key : keys) {
switch (Keys(key.getKeyCode())) {
case Keys::Space: result += "SPACE"; break;
case Keys::Apostrophe: result += "'"; break;
case Keys::Comma: result += ","; break;
case Keys::Minus: result += "-"; break;
case Keys::Period: result += "."; break;
case Keys::Slash: result += "/"; break;
case Keys::Num0: result += "0"; break;
case Keys::Num1: result += "1"; break;
case Keys::Num2: result += "2"; break;
case Keys::Num3: result += "3"; break;
case Keys::Num4: result += "4"; break;
case Keys::Num5: result += "5"; break;
case Keys::Num6: result += "6"; break;
case Keys::Num7: result += "7"; break;
case Keys::Num8: result += "8"; break;
case Keys::Num9: result += "9"; break;
case Keys::Semicolon: result += ";"; break;
case Keys::Equals: result += "="; break;
case Keys::A: result += "A"; break;
case Keys::B: result += "B"; break;
case Keys::C: result += "C"; break;
case Keys::D: result += "D"; break;
case Keys::E: result += "E"; break;
case Keys::F: result += "F"; break;
case Keys::G: result += "G"; break;
case Keys::H: result += "H"; break;
case Keys::I: result += "I"; break;
case Keys::J: result += "J"; break;
case Keys::K: result += "K"; break;
case Keys::L: result += "L"; break;
case Keys::M: result += "M"; break;
case Keys::N: result += "N"; break;
case Keys::O: result += "O"; break;
case Keys::P: result += "P"; break;
case Keys::Q: result += "Q"; break;
case Keys::R: result += "R"; break;
case Keys::S: result += "S"; break;
case Keys::T: result += "T"; break;
case Keys::U: result += "U"; break;
case Keys::V: result += "V"; break;
case Keys::W: result += "W"; break;
case Keys::X: result += "X"; break;
case Keys::Y: result += "Y"; break;
case Keys::Z: result += "Z"; break;
case Keys::LeftBracket: result += "["; break;
case Keys::Backslash: result += "\\"; break;
case Keys::RightBracket: result += "]"; break;
case Keys::GraveAccent: result += "`"; break;
case Keys::World1: result += "WORLD1"; break;
case Keys::World2: result += "WORLD2"; break;
case Keys::Escape: result += "ESC"; break;
case Keys::Enter: result += "ENTER"; break;
case Keys::Tab: result += "TAB"; break;
case Keys::Backspace: result += "BACKSPACE"; break;
case Keys::Insert: result += "INSERT"; break;
case Keys::Delete: result += "DELETE"; break;
case Keys::Right: result += "RIGHT"; break;
case Keys::Left: result += "LEFT"; break;
case Keys::Down: result += "DOWN"; break;
case Keys::Up: result += "UP"; break;
case Keys::PageUp: result += "PAGEUP"; break;
case Keys::PageDown: result += "PAGEDOWN"; break;
case Keys::Home: result += "HOME"; break;
case Keys::End: result += "END"; break;
case Keys::CapsLock: result += "CAPSLOCK"; break;
case Keys::ScrollLock: result += "SCROLLLOCK"; break;
case Keys::NumLock: result += "NUMLOCK"; break;
case Keys::PrintScreen: result += "PRINTSCREEN"; break;
case Keys::Pause: result += "PAUSE"; break;
case Keys::F1: result += "F1"; break;
case Keys::F2: result += "F2"; break;
case Keys::F3: result += "F3"; break;
case Keys::F4: result += "F4"; break;
case Keys::F5: result += "F5"; break;
case Keys::F6: result += "F6"; break;
case Keys::F7: result += "F7"; break;
case Keys::F8: result += "F8"; break;
case Keys::F9: result += "F9"; break;
case Keys::F10: result += "F10"; break;
case Keys::F11: result += "F11"; break;
case Keys::F12: result += "F12"; break;
case Keys::F13: result += "F13"; break;
case Keys::F14: result += "F14"; break;
case Keys::F15: result += "F15"; break;
case Keys::F16: result += "F16"; break;
case Keys::F17: result += "F17"; break;
case Keys::F18: result += "F18"; break;
case Keys::F19: result += "F19"; break;
case Keys::F20: result += "F20"; break;
case Keys::F21: result += "F21"; break;
case Keys::F22: result += "F22"; break;
case Keys::F23: result += "F23"; break;
case Keys::F24: result += "F24"; break;
case Keys::F25: result += "F25"; break;
case Keys::KeyPad0: result += "KP0"; break;
case Keys::KeyPad1: result += "KP1"; break;
case Keys::KeyPad2: result += "KP2"; break;
case Keys::KeyPad3: result += "KP3"; break;
case Keys::KeyPad4: result += "KP4"; break;
case Keys::KeyPad5: result += "KP5"; break;
case Keys::KeyPad6: result += "KP6"; break;
case Keys::KeyPad7: result += "KP7"; break;
case Keys::KeyPad8: result += "KP8"; break;
case Keys::KeyPad9: result += "KP9"; break;
case Keys::KeyPadDecimal: result += "KPDECIMAL"; break;
case Keys::KeyPadDivide: result += "KPDIVIDE"; break;
case Keys::KeyPadMultiply: result += "KPMULTIPLY"; break;
case Keys::KeyPadSubtract: result += "KPSUBTRACT"; break;
case Keys::KeyPadAdd: result += "KPADD"; break;
case Keys::KeyPadEnter: result += "KPENTER"; break;
case Keys::KeyPadEqual: result += "KPEQUAL"; break;
case Keys::Menu: result += "MENU"; break;
default:
continue;
}
result += " + ";
}
if (result.ends_with(" + "))
result = result.substr(0, result.size() - 3);
return result;
}
const std::set<Key>& getKeys() const { return m_keys; }
private: private:
friend Shortcut operator+(const Key &lhs, const Key &rhs); friend Shortcut operator+(const Key &lhs, const Key &rhs);
@@ -185,7 +377,12 @@ namespace hex {
std::set<Key> m_keys; std::set<Key> m_keys;
}; };
Shortcut operator+(const Key &lhs, const Key &rhs); inline Shortcut operator+(const Key &lhs, const Key &rhs) {
Shortcut result;
result.m_keys = { lhs, rhs };
return result;
}
/** /**
* @brief The ShortcutManager handles global and view-specific shortcuts. * @brief The ShortcutManager handles global and view-specific shortcuts.
@@ -196,7 +393,7 @@ namespace hex {
using Callback = std::function<void()>; using Callback = std::function<void()>;
struct ShortcutEntry { struct ShortcutEntry {
Shortcut shortcut; Shortcut shortcut;
std::vector<UnlocalizedString> unlocalizedName; UnlocalizedString unlocalizedName;
Callback callback; Callback callback;
}; };
@@ -206,7 +403,6 @@ namespace hex {
* @param unlocalizedName The unlocalized name of the shortcut * @param unlocalizedName The unlocalized name of the shortcut
* @param callback The callback to call when the shortcut is triggered. * @param callback The callback to call when the shortcut is triggered.
*/ */
static void addGlobalShortcut(const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const Callback &callback);
static void addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback); static void addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback);
/** /**
@@ -216,7 +412,6 @@ namespace hex {
* @param unlocalizedName The unlocalized name of the shortcut * @param unlocalizedName The unlocalized name of the shortcut
* @param callback The callback to call when the shortcut is triggered. * @param callback The callback to call when the shortcut is triggered.
*/ */
static void addShortcut(View *view, const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const Callback &callback);
static void addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback); static void addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback);
@@ -250,14 +445,12 @@ namespace hex {
static void resumeShortcuts(); static void resumeShortcuts();
static void pauseShortcuts(); static void pauseShortcuts();
static void enableMacOSMode();
[[nodiscard]] static std::optional<Shortcut> getPreviousShortcut(); [[nodiscard]] static std::optional<Shortcut> getPreviousShortcut();
[[nodiscard]] static std::vector<ShortcutEntry> getGlobalShortcuts(); [[nodiscard]] static std::vector<ShortcutEntry> getGlobalShortcuts();
[[nodiscard]] static std::vector<ShortcutEntry> getViewShortcuts(const View *view); [[nodiscard]] static std::vector<ShortcutEntry> getViewShortcuts(const View *view);
[[nodiscard]] static bool updateShortcut(const Shortcut &oldShortcut, Shortcut newShortcut, View *view = nullptr); [[nodiscard]] static bool updateShortcut(const Shortcut &oldShortcut, const Shortcut &newShortcut, View *view = nullptr);
}; };
} }

View File

@@ -22,7 +22,7 @@ namespace hex {
class Task { class Task {
public: public:
Task() = default; Task() = default;
Task(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function); Task(UnlocalizedString unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function);
Task(const Task&) = delete; Task(const Task&) = delete;
Task(Task &&other) noexcept; Task(Task &&other) noexcept;
@@ -130,37 +130,20 @@ namespace hex {
/** /**
* @brief Creates a new asynchronous task that gets displayed in the Task Manager in the footer * @brief Creates a new asynchronous task that gets displayed in the Task Manager in the footer
* @param unlocalizedName Name of the task * @param name Name of the task
* @param maxValue Maximum value of the task * @param maxValue Maximum value of the task
* @param function Function to be executed * @param function Function to be executed
* @return A TaskHolder holding a weak reference to the task * @return A TaskHolder holding a weak reference to the task
*/ */
static TaskHolder createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void(Task &)> function); static TaskHolder createTask(std::string name, u64 maxValue, std::function<void(Task &)> function);
/**
* @brief Creates a new asynchronous task that gets displayed in the Task Manager in the footer
* @param unlocalizedName Name of the task
* @param maxValue Maximum value of the task
* @param function Function to be executed
* @return A TaskHolder holding a weak reference to the task
*/
static TaskHolder createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void()> function);
/** /**
* @brief Creates a new asynchronous task that does not get displayed in the Task Manager * @brief Creates a new asynchronous task that does not get displayed in the Task Manager
* @param unlocalizedName Name of the task * @param name Name of the task
* @param function Function to be executed * @param function Function to be executed
* @return A TaskHolder holding a weak reference to the task * @return A TaskHolder holding a weak reference to the task
*/ */
static TaskHolder createBackgroundTask(const UnlocalizedString &unlocalizedName, std::function<void(Task &)> function); static TaskHolder createBackgroundTask(std::string name, std::function<void(Task &)> function);
/**
* @brief Creates a new asynchronous task that does not get displayed in the Task Manager
* @param unlocalizedName Name of the task
* @param function Function to be executed
* @return A TaskHolder holding a weak reference to the task
*/
static TaskHolder createBackgroundTask(const UnlocalizedString &unlocalizedName, std::function<void()> function);
/** /**
* @brief Creates a new synchronous task that will execute the given function at the start of the next frame * @brief Creates a new synchronous task that will execute the given function at the start of the next frame
@@ -207,7 +190,7 @@ namespace hex {
static void runDeferredCalls(); static void runDeferredCalls();
private: private:
static TaskHolder createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function); static TaskHolder createTask(std::string name, u64 maxValue, bool background, std::function<void(Task &)> function);
}; };
} }

View File

@@ -56,7 +56,6 @@ namespace hex {
*/ */
static void addStyleHandler(const std::string &name, const StyleMap &styleMap); static void addStyleHandler(const std::string &name, const StyleMap &styleMap);
static void reapplyCurrentTheme();
static std::vector<std::string> getThemeNames(); static std::vector<std::string> getThemeNames();
static const std::string &getImageTheme(); static const std::string &getImageTheme();

View File

@@ -119,8 +119,6 @@ namespace hex {
decltype(m_steps)::iterator m_currentStep, m_latestStep; decltype(m_steps)::iterator m_currentStep, m_latestStep;
}; };
static void init();
/** /**
* @brief Gets a list of all tutorials * @brief Gets a list of all tutorials
* @return List of all tutorials * @return List of all tutorials
@@ -147,10 +145,6 @@ namespace hex {
*/ */
static void startTutorial(const UnlocalizedString &unlocalizedName); static void startTutorial(const UnlocalizedString &unlocalizedName);
static void startHelpHover();
static void addInteractiveHelpText(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, UnlocalizedString unlocalizedString);
static void addInteractiveHelpLink(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, std::string link);
/** /**
* @brief Draws the tutorial * @brief Draws the tutorial

View File

@@ -3,6 +3,7 @@
#include <hex.hpp> #include <hex.hpp>
#include <hex/api/localization_manager.hpp> #include <hex/api/localization_manager.hpp>
#include <hex/helpers/intrinsics.hpp>
#include <hex/data_processor/attribute.hpp> #include <hex/data_processor/attribute.hpp>
#include <set> #include <set>
@@ -11,7 +12,6 @@
#include <nlohmann/json_fwd.hpp> #include <nlohmann/json_fwd.hpp>
#include <imgui.h> #include <imgui.h>
#include <hex/providers/provider_data.hpp>
namespace hex::prv { namespace hex::prv {
class Provider; class Provider;
@@ -42,12 +42,11 @@ namespace hex::dp {
m_overlay = overlay; m_overlay = overlay;
} }
void draw(); virtual void drawNode() { }
virtual void process() = 0; virtual void process() = 0;
virtual void reset() { }
virtual void store(nlohmann::json &j) const { std::ignore = j; } virtual void store(nlohmann::json &j) const { hex::unused(j); }
virtual void load(const nlohmann::json &j) { std::ignore = j; } virtual void load(const nlohmann::json &j) { hex::unused(j); }
struct NodeError { struct NodeError {
Node *node; Node *node;
@@ -81,11 +80,6 @@ namespace hex::dp {
void setIntegerOnOutput(u32 index, i128 integer); void setIntegerOnOutput(u32 index, i128 integer);
void setFloatOnOutput(u32 index, double floatingPoint); void setFloatOnOutput(u32 index, double floatingPoint);
static void interrupt();
protected:
virtual void drawNode() { }
private: private:
int m_id; int m_id;
UnlocalizedString m_unlocalizedTitle, m_unlocalizedName; UnlocalizedString m_unlocalizedTitle, m_unlocalizedName;
@@ -96,16 +90,45 @@ namespace hex::dp {
static int s_idCounter; static int s_idCounter;
Attribute& getAttribute(u32 index); Attribute& getAttribute(u32 index) {
Attribute *getConnectedInputAttribute(u32 index); if (index >= this->getAttributes().size())
void markInputProcessed(u32 index); throw std::runtime_error("Attribute index out of bounds!");
void unmarkInputProcessed(u32 index);
return this->getAttributes()[index];
}
Attribute *getConnectedInputAttribute(u32 index) {
const auto &connectedAttribute = this->getAttribute(index).getConnectedAttributes();
if (connectedAttribute.empty())
return nullptr;
return connectedAttribute.begin()->second;
}
void markInputProcessed(u32 index) {
const auto &[iter, inserted] = m_processedInputs.insert(index);
if (!inserted)
throwNodeError("Recursion detected!");
}
void unmarkInputProcessed(u32 index) {
m_processedInputs.erase(index);
}
protected: protected:
[[noreturn]] void throwNodeError(const std::string &message); [[noreturn]] void throwNodeError(const std::string &message) {
throw NodeError { this, message };
}
void setOverlayData(u64 address, const std::vector<u8> &data); void setOverlayData(u64 address, const std::vector<u8> &data);
void setAttributes(std::vector<Attribute> attributes);
void setAttributes(std::vector<Attribute> attributes) {
m_attributes = std::move(attributes);
for (auto &attr : m_attributes)
attr.setParentNode(this);
}
}; };
} }

View File

@@ -2,15 +2,10 @@
#include <hex.hpp> #include <hex.hpp>
#include <wolv/utils/expected.hpp>
#include <array> #include <array>
#include <string> #include <string>
#include <vector> #include <vector>
#define CRYPTO_ERROR_INVALID_KEY_LENGTH (-1)
#define CRYPTO_ERROR_INVALID_MODE (-2)
namespace hex::prv { namespace hex::prv {
class Provider; class Provider;
} }
@@ -65,5 +60,5 @@ namespace hex::crypt {
Key256Bits = 2 Key256Bits = 2
}; };
wolv::util::Expected<std::vector<u8>, int> aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input); std::vector<u8> aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input);
} }

View File

@@ -1,111 +0,0 @@
#pragma once
#include <hex/helpers/fs.hpp>
#include <vector>
namespace hex::paths {
namespace impl {
class DefaultPath {
protected:
constexpr DefaultPath() = default;
virtual ~DefaultPath() = default;
public:
DefaultPath(const DefaultPath&) = delete;
DefaultPath(DefaultPath&&) = delete;
DefaultPath& operator=(const DefaultPath&) = delete;
DefaultPath& operator=(DefaultPath&&) = delete;
virtual std::vector<std::fs::path> all() const = 0;
virtual std::vector<std::fs::path> read() const;
virtual std::vector<std::fs::path> write() const;
};
class ConfigPath : public DefaultPath {
public:
explicit ConfigPath(std::fs::path postfix) : m_postfix(std::move(postfix)) {}
std::vector<std::fs::path> all() const override;
private:
std::fs::path m_postfix;
};
class DataPath : public DefaultPath {
public:
explicit DataPath(std::fs::path postfix) : m_postfix(std::move(postfix)) {}
std::vector<std::fs::path> all() const override;
std::vector<std::fs::path> write() const override;
private:
std::fs::path m_postfix;
};
class PluginPath : public DefaultPath {
public:
explicit PluginPath(std::fs::path postfix) : m_postfix(std::move(postfix)) {}
std::vector<std::fs::path> all() const override;
private:
std::fs::path m_postfix;
};
}
std::vector<std::fs::path> getDataPaths(bool includeSystemFolders);
std::vector<std::fs::path> getConfigPaths(bool includeSystemFolders);
const static inline impl::ConfigPath Config("config");
const static inline impl::ConfigPath Recent("recent");
const static inline impl::PluginPath Libraries("lib");
const static inline impl::PluginPath Plugins("plugins");
const static inline impl::DataPath Patterns("patterns");
const static inline impl::DataPath PatternsInclude("includes");
const static inline impl::DataPath Magic("magic");
const static inline impl::DataPath Yara("yara");
const static inline impl::DataPath YaraAdvancedAnalysis("yara/advanced_analysis");
const static inline impl::DataPath Backups("backups");
const static inline impl::DataPath Resources("resources");
const static inline impl::DataPath Constants("constants");
const static inline impl::DataPath Encodings("encodings");
const static inline impl::DataPath Logs("logs");
const static inline impl::DataPath Scripts("scripts");
const static inline impl::DataPath Inspectors("scripts/inspectors");
const static inline impl::DataPath Themes("themes");
const static inline impl::DataPath Nodes("scripts/nodes");
const static inline impl::DataPath Layouts("layouts");
const static inline impl::DataPath Workspaces("workspaces");
constexpr static inline std::array<const impl::DefaultPath*, 20> All = {
&Config,
&Recent,
&Libraries,
&Plugins,
&Patterns,
&PatternsInclude,
&Magic,
&Yara,
&YaraAdvancedAnalysis,
&Backups,
&Resources,
&Constants,
&Encodings,
&Logs,
&Scripts,
&Inspectors,
&Themes,
&Nodes,
&Layouts,
&Workspaces,
};
}

View File

@@ -1,8 +1,7 @@
#pragma once #pragma once
#include <string_view> #include <string_view>
#include <fmt/core.h> #include <fmt/format.h>
#include <fmt/ranges.h>
namespace hex { namespace hex {

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#include <hex.hpp>
#include <string> #include <string>
#include <vector> #include <vector>
#include <filesystem> #include <filesystem>
@@ -29,7 +31,36 @@ namespace hex::fs {
void openFolderExternal(const std::fs::path &dirPath); void openFolderExternal(const std::fs::path &dirPath);
void openFolderWithSelectionExternal(const std::fs::path &selectedFilePath); void openFolderWithSelectionExternal(const std::fs::path &selectedFilePath);
enum class ImHexPath : u32 {
Patterns = 0,
PatternsInclude,
Magic,
Plugins,
Yara,
YaraAdvancedAnalysis,
Config,
Backups,
Resources,
Constants,
Encodings,
Logs,
Recent,
Scripts,
Inspectors,
Themes,
Libraries,
Nodes,
Layouts,
Workspaces,
END
};
bool isPathWritable(const std::fs::path &path); bool isPathWritable(const std::fs::path &path);
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting = false);
// Temporarily expose these for the migration function
std::vector<std::fs::path> getDataPaths();
std::vector<std::fs::path> appendPath(std::vector<std::fs::path> paths, const std::fs::path &folder);
} }

View File

@@ -25,16 +25,13 @@
template<typename T> template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(const std::fs::path &path, const std::string &mimeName) { std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(const std::fs::path &path, const std::string &mimeName) {
std::ignore = path; hex::unused(path, mimeName);
std::ignore = mimeName;
throw std::logic_error("Not implemented"); throw std::logic_error("Not implemented");
} }
template<typename T> template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(std::vector<u8> data, const std::string &mimeName, const std::fs::path &fileName) { std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(std::vector<u8> data, const std::string &mimeName, const std::fs::path &fileName) {
std::ignore = data; hex::unused(data, mimeName, fileName);
std::ignore = mimeName;
std::ignore = fileName;
throw std::logic_error("Not implemented"); throw std::logic_error("Not implemented");
} }

View File

@@ -0,0 +1,9 @@
#pragma once
namespace hex {
void unused(auto && ... x) {
((void)x, ...);
}
}

View File

@@ -21,11 +21,6 @@ namespace hex {
MissingEOF MissingEOF
}; };
enum class PatchKind {
IPS,
IPS32
};
class Patches { class Patches {
public: public:
Patches() = default; Patches() = default;

View File

@@ -1,36 +0,0 @@
#pragma once
#include <hex.hpp>
#include <compare>
#include <string>
#include <vector>
namespace hex {
class SemanticVersion {
public:
SemanticVersion() = default;
SemanticVersion(std::string version);
SemanticVersion(std::string_view version);
SemanticVersion(const char *version);
std::strong_ordering operator<=>(const SemanticVersion &) const;
bool operator==(const SemanticVersion &other) const;
u32 major() const;
u32 minor() const;
u32 patch() const;
bool nightly() const;
const std::string& buildType() const;
bool isValid() const;
std::string get(bool withBuildType = true) const;
private:
std::vector<std::string> m_parts;
std::string m_buildType;
};
}

View File

@@ -29,7 +29,7 @@ namespace hex {
void close(); void close();
/** /**
* @brief get the error string explaining the error that occurred when opening the file. * @brief get the error string explaining the error that occured when opening the file.
* This error is a combination of the tar error and the native file open error * This error is a combination of the tar error and the native file open error
*/ */
std::string getOpenErrorString() const; std::string getOpenErrorString() const;

View File

@@ -4,7 +4,6 @@
#include <cstdint> #include <cstdint>
#include <concepts> #include <concepts>
#include <type_traits>
using u8 = std::uint8_t; using u8 = std::uint8_t;
using u16 = std::uint16_t; using u16 = std::uint16_t;
@@ -62,10 +61,6 @@ namespace hex {
constexpr static Region Invalid() { constexpr static Region Invalid() {
return { 0, 0 }; return { 0, 0 };
} }
constexpr bool operator<(const Region &other) const {
return this->address < other.address;
}
}; };

View File

@@ -34,29 +34,6 @@ namespace hex {
class Provider; class Provider;
} }
template<typename T>
[[nodiscard]] std::vector<std::vector<T>> sampleChannels(const std::vector<T> &data, size_t count, size_t channels) {
if (channels == 0) return {};
size_t signalLength = std::max(1.0, double(data.size()) / channels);
size_t stride = std::max(1.0, double(signalLength) / count);
std::vector<std::vector<T>> result;
result.resize(channels);
for (size_t i = 0; i < channels; i++) {
result[i].reserve(count);
}
result.reserve(count);
for (size_t i = 0; i < data.size(); i += stride) {
for (size_t j = 0; j < channels; j++) {
result[j].push_back(data[i + j]);
}
}
return result;
}
template<typename T> template<typename T>
[[nodiscard]] std::vector<T> sampleData(const std::vector<T> &data, size_t count) { [[nodiscard]] std::vector<T> sampleData(const std::vector<T> &data, size_t count) {
size_t stride = std::max(1.0, double(data.size()) / count); size_t stride = std::max(1.0, double(data.size()) / count);
@@ -285,13 +262,13 @@ namespace hex {
[[nodiscard]] float float16ToFloat32(u16 float16); [[nodiscard]] float float16ToFloat32(u16 float16);
[[nodiscard]] inline bool equalsIgnoreCase(std::string_view left, std::string_view right) { [[nodiscard]] inline bool equalsIgnoreCase(const std::string &left, const std::string &right) {
return std::equal(left.begin(), left.end(), right.begin(), right.end(), [](char a, char b) { return std::equal(left.begin(), left.end(), right.begin(), right.end(), [](char a, char b) {
return tolower(a) == tolower(b); return tolower(a) == tolower(b);
}); });
} }
[[nodiscard]] inline bool containsIgnoreCase(std::string_view a, std::string_view b) { [[nodiscard]] inline bool containsIgnoreCase(const std::string &a, const std::string &b) {
auto iter = std::search(a.begin(), a.end(), b.begin(), b.end(), [](char ch1, char ch2) { auto iter = std::search(a.begin(), a.end(), b.begin(), b.end(), [](char ch1, char ch2) {
return std::toupper(ch1) == std::toupper(ch2); return std::toupper(ch1) == std::toupper(ch2);
}); });
@@ -321,7 +298,31 @@ namespace hex {
[[nodiscard]] std::optional<std::string> getEnvironmentVariable(const std::string &env); [[nodiscard]] std::optional<std::string> getEnvironmentVariable(const std::string &env);
[[nodiscard]] std::string limitStringLength(const std::string &string, size_t maxLength); [[nodiscard]] inline std::string limitStringLength(const std::string &string, size_t maxLength) {
// If the string is shorter than the max length, return it as is
if (string.size() < maxLength)
return string;
// If the string is longer than the max length, find the last space before the max length
auto it = string.begin() + maxLength;
while (it != string.begin() && !std::isspace(*it)) --it;
// If there's no space before the max length, just cut the string
if (it == string.begin()) {
it = string.begin() + maxLength;
// Try to find a UTF-8 character boundary
while (it != string.begin() && (*it & 0x80) != 0x00) --it;
++it;
}
// If we still didn't find a valid boundary, just return the string as is
if (it == string.begin())
return string;
// Append
return std::string(string.begin(), it) + "";
}
[[nodiscard]] std::optional<std::fs::path> getInitialFilePath(); [[nodiscard]] std::optional<std::fs::path> getInitialFilePath();

View File

@@ -18,7 +18,6 @@
void macosHandleTitlebarDoubleClickGesture(GLFWwindow *window); void macosHandleTitlebarDoubleClickGesture(GLFWwindow *window);
bool macosIsWindowBeingResizedByUser(GLFWwindow *window); bool macosIsWindowBeingResizedByUser(GLFWwindow *window);
void macosMarkContentEdited(GLFWwindow *window, bool edited = true);
} }
#endif #endif

View File

@@ -37,40 +37,21 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
return nullptr; return nullptr;
} }
[[maybe_unused]] static auto& getFeaturesImpl() {
static std::vector<hex::Feature> features;
return features;
}
#if defined (IMHEX_STATIC_LINK_PLUGINS) #if defined (IMHEX_STATIC_LINK_PLUGINS)
#define IMHEX_PLUGIN_VISIBILITY_PREFIX static #define IMHEX_PLUGIN_VISIBILITY_PREFIX static
#else #else
#define IMHEX_PLUGIN_VISIBILITY_PREFIX extern "C" [[gnu::visibility("default")]] #define IMHEX_PLUGIN_VISIBILITY_PREFIX extern "C" [[gnu::visibility("default")]]
#endif #endif
#define IMHEX_FEATURE_ENABLED(feature) WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(IMHEX_PLUGIN_, IMHEX_PLUGIN_NAME), _FEATURE_), feature)
#define IMHEX_DEFINE_PLUGIN_FEATURES() IMHEX_DEFINE_PLUGIN_FEATURES_IMPL()
#define IMHEX_DEFINE_PLUGIN_FEATURES_IMPL() \
template<> \
struct PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation> { \
static void* getFeatures(); \
}; \
void* PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures() { \
return &getFeaturesImpl(); \
} \
static auto initFeatures = [] { getFeaturesImpl() = std::vector<hex::Feature>({ IMHEX_PLUGIN_FEATURES_CONTENT }); return 0; }()
#define IMHEX_PLUGIN_FEATURES ::getFeaturesImpl()
/** /**
* This macro is used to define all the required entry points for a plugin. * This macro is used to define all the required entry points for a plugin.
* Name, Author and Description will be displayed in the plugin list on the Welcome screen. * Name, Author and Description will be displayed in the in the plugin list on the Welcome screen.
*/ */
#define IMHEX_PLUGIN_SETUP(name, author, description) IMHEX_PLUGIN_SETUP_IMPL(name, author, description) #define IMHEX_PLUGIN_SETUP(name, author, description) IMHEX_PLUGIN_SETUP_IMPL(name, author, description)
#define IMHEX_LIBRARY_SETUP(name) IMHEX_LIBRARY_SETUP_IMPL(name) #define IMHEX_LIBRARY_SETUP(name) IMHEX_LIBRARY_SETUP_IMPL(name)
#define IMHEX_LIBRARY_SETUP_IMPL(name) \ #define IMHEX_LIBRARY_SETUP_IMPL(name) \
namespace { static struct EXIT_HANDLER { ~EXIT_HANDLER() { hex::log::info("Unloaded library '{}'", name); } } HANDLER; } \ namespace { static struct EXIT_HANDLER { ~EXIT_HANDLER() { hex::log::debug("Unloaded library '{}'", name); } } HANDLER; } \
IMHEX_PLUGIN_VISIBILITY_PREFIX void WOLV_TOKEN_CONCAT(initializeLibrary_, IMHEX_PLUGIN_NAME)(); \ IMHEX_PLUGIN_VISIBILITY_PREFIX void WOLV_TOKEN_CONCAT(initializeLibrary_, IMHEX_PLUGIN_NAME)(); \
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *WOLV_TOKEN_CONCAT(getLibraryName_, IMHEX_PLUGIN_NAME)() { return name; } \ IMHEX_PLUGIN_VISIBILITY_PREFIX const char *WOLV_TOKEN_CONCAT(getLibraryName_, IMHEX_PLUGIN_NAME)() { return name; } \
IMHEX_PLUGIN_VISIBILITY_PREFIX void WOLV_TOKEN_CONCAT(setImGuiContext_, IMHEX_PLUGIN_NAME)(ImGuiContext *ctx) { \ IMHEX_PLUGIN_VISIBILITY_PREFIX void WOLV_TOKEN_CONCAT(setImGuiContext_, IMHEX_PLUGIN_NAME)(ImGuiContext *ctx) { \
@@ -104,7 +85,6 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
ImGui::SetCurrentContext(ctx); \ ImGui::SetCurrentContext(ctx); \
GImGui = ctx; \ GImGui = ctx; \
} \ } \
IMHEX_DEFINE_PLUGIN_FEATURES(); \
IMHEX_PLUGIN_VISIBILITY_PREFIX void* getFeatures() { \ IMHEX_PLUGIN_VISIBILITY_PREFIX void* getFeatures() { \
return PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures(); \ return PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures(); \
} \ } \
@@ -149,3 +129,18 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
return &g_subCommands; \ return &g_subCommands; \
} \ } \
std::vector<hex::SubCommand> g_subCommands std::vector<hex::SubCommand> g_subCommands
#define IMHEX_FEATURE_ENABLED(feature) WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(IMHEX_PLUGIN_, IMHEX_PLUGIN_NAME), _FEATURE_), feature)
#define IMHEX_DEFINE_PLUGIN_FEATURES() IMHEX_DEFINE_PLUGIN_FEATURES_IMPL()
#define IMHEX_DEFINE_PLUGIN_FEATURES_IMPL() \
extern std::vector<hex::Feature> g_features; \
template<> \
struct PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation> { \
static void* getFeatures(); \
}; \
void* PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures() { \
return &g_features; \
} \
std::vector<hex::Feature> g_features
#define IMHEX_PLUGIN_FEATURES g_features

View File

@@ -165,7 +165,7 @@ namespace hex::prv {
void insert(u64 offset, u64 size); void insert(u64 offset, u64 size);
void remove(u64 offset, u64 size); void remove(u64 offset, u64 size);
virtual void resizeRaw(u64 newSize) { std::ignore = newSize; } virtual void resizeRaw(u64 newSize) { hex::unused(newSize); }
virtual void insertRaw(u64 offset, u64 size); virtual void insertRaw(u64 offset, u64 size);
virtual void removeRaw(u64 offset, u64 size); virtual void removeRaw(u64 offset, u64 size);

View File

@@ -97,30 +97,32 @@ namespace ImGuiExt {
Texture& operator=(Texture&& other) noexcept; Texture& operator=(Texture&& other) noexcept;
[[nodiscard]] constexpr bool isValid() const noexcept { [[nodiscard]] constexpr bool isValid() const noexcept {
return m_textureId != 0; return m_textureId != nullptr;
} }
[[nodiscard]] operator ImTextureID() const noexcept { [[nodiscard]] operator ImTextureID() const noexcept {
return m_textureId; return m_textureId;
} }
[[nodiscard]] ImVec2 getSize() const noexcept { [[nodiscard]] operator intptr_t() const noexcept {
return reinterpret_cast<intptr_t>(m_textureId);
}
[[nodiscard]] auto getSize() const noexcept {
return ImVec2(m_width, m_height); return ImVec2(m_width, m_height);
} }
[[nodiscard]] constexpr float getAspectRatio() const noexcept { [[nodiscard]] constexpr auto getAspectRatio() const noexcept {
if (m_height == 0) return 1.0F; if (m_height == 0) return 1.0F;
return float(m_width) / float(m_height); return float(m_width) / float(m_height);
} }
private: private:
ImTextureID m_textureId = 0; ImTextureID m_textureId = nullptr;
int m_width = 0, m_height = 0; int m_width = 0, m_height = 0;
}; };
float GetTextWrapPos();
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data); int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data);
bool IconHyperlink(const char *icon, const char *label, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0); bool IconHyperlink(const char *icon, const char *label, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
@@ -133,8 +135,6 @@ namespace ImGuiExt {
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 UnderwavedText(const char *label, ImColor textColor = ImGui::GetStyleColorVec4(ImGuiCol_Text), ImColor lineColor = ImGui::GetStyleColorVec4(ImGuiCol_Text), const ImVec2 &size_arg = ImVec2(0, 0));
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);
@@ -186,12 +186,7 @@ namespace ImGuiExt {
void SmallProgressBar(float fraction, float yOffset = 0.0F); void SmallProgressBar(float fraction, float yOffset = 0.0F);
inline void TextFormatted(std::string_view fmt, auto &&...args) { inline void TextFormatted(std::string_view fmt, auto &&...args) {
if constexpr (sizeof...(args) == 0) { ImGui::TextUnformatted(hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
ImGui::TextUnformatted(fmt.data(), fmt.data() + fmt.size());
} else {
const auto string = hex::format(fmt, std::forward<decltype(args)>(args)...);
ImGui::TextUnformatted(string.c_str(), string.c_str() + string.size());
}
} }
inline void TextFormattedSelectable(std::string_view fmt, auto &&...args) { inline void TextFormattedSelectable(std::string_view fmt, auto &&...args) {
@@ -213,24 +208,15 @@ namespace ImGuiExt {
} }
inline void TextFormattedColored(ImColor color, std::string_view fmt, auto &&...args) { inline void TextFormattedColored(ImColor color, std::string_view fmt, auto &&...args) {
ImGui::PushStyleColor(ImGuiCol_Text, color.Value); ImGui::TextColored(color, "%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
ImGuiExt::TextFormatted(fmt, std::forward<decltype(args)>(args)...);
ImGui::PopStyleColor();
} }
inline void TextFormattedDisabled(std::string_view fmt, auto &&...args) { inline void TextFormattedDisabled(std::string_view fmt, auto &&...args) {
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]); ImGui::TextDisabled("%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
ImGuiExt::TextFormatted(fmt, std::forward<decltype(args)>(args)...);
ImGui::PopStyleColor();
} }
inline void TextFormattedWrapped(std::string_view fmt, auto &&...args) { inline void TextFormattedWrapped(std::string_view fmt, auto &&...args) {
const bool need_backup = ImGuiExt::GetTextWrapPos() < 0.0F; // Keep existing wrap position if one is already set ImGui::TextWrapped("%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
if (need_backup)
ImGui::PushTextWrapPos(0.0F);
ImGuiExt::TextFormatted(fmt, std::forward<decltype(args)>(args)...);
if (need_backup)
ImGui::PopTextWrapPos();
} }
inline void TextFormattedWrappedSelectable(std::string_view fmt, auto &&...args) { inline void TextFormattedWrappedSelectable(std::string_view fmt, auto &&...args) {
@@ -282,7 +268,6 @@ namespace ImGuiExt {
} }
bool InputTextIcon(const char* label, const char *icon, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None); bool InputTextIcon(const char* label, const char *icon, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
bool InputTextIconHint(const char* label, const char *icon, 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); bool InputScalarCallback(const char* label, ImGuiDataType data_type, void* p_data, const char* format, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data);
@@ -296,12 +281,12 @@ namespace ImGuiExt {
bool DimmedIconToggle(const char *icon, bool *v); bool DimmedIconToggle(const char *icon, bool *v);
bool DimmedIconToggle(const char *iconOn, const char *iconOff, bool *v); bool DimmedIconToggle(const char *iconOn, const char *iconOff, bool *v);
void TextOverlay(const char *text, ImVec2 pos, float maxWidth = -1); void TextOverlay(const char *text, ImVec2 pos);
bool BeginBox(); bool BeginBox();
void EndBox(); void EndBox();
bool BeginSubWindow(const char *label, bool *collapsed = nullptr, ImVec2 size = ImVec2(0, 0), ImGuiChildFlags flags = ImGuiChildFlags_None); void BeginSubWindow(const char *label, ImVec2 size = ImVec2(0, 0), ImGuiChildFlags flags = ImGuiChildFlags_None);
void EndSubWindow(); void EndSubWindow();
void ConfirmButtons(const char *textLeft, const char *textRight, const auto &leftButtonCallback, const auto &rightButtonCallback) { void ConfirmButtons(const char *textLeft, const char *textRight, const auto &leftButtonCallback, const auto &rightButtonCallback) {

View File

@@ -158,7 +158,6 @@ namespace hex {
explicit Floating(UnlocalizedString unlocalizedName) : Window(std::move(unlocalizedName), "") {} explicit Floating(UnlocalizedString unlocalizedName) : Window(std::move(unlocalizedName), "") {}
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const override { return ImGuiWindowFlags_NoDocking; } [[nodiscard]] ImGuiWindowFlags getWindowFlags() const override { return ImGuiWindowFlags_NoDocking; }
[[nodiscard]] bool shouldStoreWindowState() const override { return false; }
}; };
/** /**

View File

@@ -2,14 +2,9 @@
#include <hex/api/event_manager.hpp> #include <hex/api/event_manager.hpp>
#include <hex/helpers/auto_reset.hpp> #include <hex/helpers/auto_reset.hpp>
#include <hex/helpers/default_paths.hpp>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#if defined(OS_WEB)
#include <emscripten.h>
#endif
namespace hex { namespace hex {
static AutoReset<std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>>> s_achievements; static AutoReset<std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>>> s_achievements;
@@ -200,12 +195,9 @@ namespace hex {
constexpr static auto AchievementsFile = "achievements.json"; constexpr static auto AchievementsFile = "achievements.json";
bool AchievementManager::s_initialized = false;
void AchievementManager::loadProgress() { void AchievementManager::loadProgress() {
if (s_initialized) for (const auto &directory : fs::getDefaultPaths(fs::ImHexPath::Config)) {
return;
for (const auto &directory : paths::Config.read()) {
auto path = directory / AchievementsFile; auto path = directory / AchievementsFile;
if (!wolv::io::fs::exists(path)) { if (!wolv::io::fs::exists(path)) {
@@ -219,16 +211,7 @@ namespace hex {
} }
try { try {
#if defined(OS_WEB) auto json = nlohmann::json::parse(file.readString());
auto data = (char *) MAIN_THREAD_EM_ASM_INT({
let data = localStorage.getItem("achievements");
return data ? stringToNewUTF8(data) : null;
});
#else
auto data = file.readString();
#endif
auto json = nlohmann::json::parse(data);
for (const auto &[categoryName, achievements] : getAchievements()) { for (const auto &[categoryName, achievements] : getAchievements()) {
for (const auto &[achievementName, achievement] : achievements) { for (const auto &[achievementName, achievement] : achievements) {
@@ -243,8 +226,6 @@ namespace hex {
} }
} }
} }
s_initialized = true;
} catch (const std::exception &e) { } catch (const std::exception &e) {
log::error("Failed to load achievements: {}", e.what()); log::error("Failed to load achievements: {}", e.what());
} }
@@ -253,8 +234,6 @@ namespace hex {
} }
void AchievementManager::storeProgress() { void AchievementManager::storeProgress() {
if (!s_initialized)
loadProgress();
nlohmann::json json; nlohmann::json json;
for (const auto &[categoryName, achievements] : getAchievements()) { for (const auto &[categoryName, achievements] : getAchievements()) {
json[categoryName] = nlohmann::json::object(); json[categoryName] = nlohmann::json::object();
@@ -267,23 +246,16 @@ namespace hex {
if (json.empty()) if (json.empty())
return; return;
#if defined(OS_WEB) for (const auto &directory : fs::getDefaultPaths(fs::ImHexPath::Config)) {
auto data = json.dump(); auto path = directory / AchievementsFile;
MAIN_THREAD_EM_ASM({
localStorage.setItem("achievements", UTF8ToString($0));
}, data.c_str());
#else
for (const auto &directory : paths::Config.write()) {
auto path = directory / AchievementsFile;
wolv::io::File file(path, wolv::io::File::Mode::Create); wolv::io::File file(path, wolv::io::File::Mode::Create);
if (!file.isValid()) if (!file.isValid())
continue; continue;
file.writeString(json.dump(4)); file.writeString(json.dump(4));
break; break;
} }
#endif
} }
} }

View File

@@ -4,7 +4,6 @@
#include <hex/helpers/fs.hpp> #include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp> #include <hex/helpers/logger.hpp>
#include <hex/helpers/auto_reset.hpp> #include <hex/helpers/auto_reset.hpp>
#include <hex/helpers/default_paths.hpp>
#include <hex/ui/view.hpp> #include <hex/ui/view.hpp>
#include <hex/data_processor/node.hpp> #include <hex/data_processor/node.hpp>
@@ -102,7 +101,7 @@ namespace hex {
void load() { void load() {
bool loaded = false; bool loaded = false;
for (const auto &dir : paths::Config.read()) { for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Read); wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Read);
if (file.isValid()) { if (file.isValid()) {
@@ -143,7 +142,7 @@ namespace hex {
if (result.empty()) { if (result.empty()) {
return; return;
} }
for (const auto &dir : paths::Config.write()) { for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Create); wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Create);
if (file.isValid()) { if (file.isValid()) {
@@ -154,7 +153,7 @@ namespace hex {
} }
void clear() { void clear() {
for (const auto &dir : paths::Config.write()) { for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
wolv::io::fs::remove(dir / SettingsFile); wolv::io::fs::remove(dir / SettingsFile);
} }
} }
@@ -191,17 +190,6 @@ namespace hex {
const auto entry = insertOrGetEntry(subCategory->entries, unlocalizedName); const auto entry = insertOrGetEntry(subCategory->entries, unlocalizedName);
entry->widget = std::move(widget); entry->widget = std::move(widget);
if (entry->widget != nullptr) {
onChange(unlocalizedCategory, unlocalizedName, [widget = entry->widget.get(), unlocalizedCategory, unlocalizedName](const SettingsValue &) {
try {
auto defaultValue = widget->store();
widget->load(ContentRegistry::Settings::impl::getSetting(unlocalizedCategory, unlocalizedName, defaultValue));
widget->onChanged();
} catch (const std::exception &e) {
log::error("Failed to load setting [{} / {}]: {}", unlocalizedCategory.get(), unlocalizedName.get(), e.what());
}
});
}
return entry->widget.get(); return entry->widget.get();
} }
@@ -563,11 +551,6 @@ namespace hex {
return *s_functions; return *s_functions;
} }
static AutoReset<std::vector<TypeDefinition>> s_types;
const std::vector<TypeDefinition>& getTypes() {
return *s_types;
}
} }
static std::string getFunctionName(const pl::api::Namespace &ns, const std::string &name) { static std::string getFunctionName(const pl::api::Namespace &ns, const std::string &name) {
@@ -612,7 +595,7 @@ namespace hex {
); );
} }
runtime.setIncludePaths(paths::PatternsInclude.read() | paths::Patterns.read()); runtime.setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude) | fs::getDefaultPaths(fs::ImHexPath::Patterns));
for (const auto &[ns, name, paramCount, callback, dangerous] : impl::getFunctions()) { for (const auto &[ns, name, paramCount, callback, dangerous] : impl::getFunctions()) {
if (dangerous) if (dangerous)
@@ -621,16 +604,12 @@ namespace hex {
runtime.addFunction(ns, name, paramCount, callback); runtime.addFunction(ns, name, paramCount, callback);
} }
for (const auto &[ns, name, paramCount, callback] : impl::getTypes()) {
runtime.addType(ns, name, paramCount, callback);
}
for (const auto &[name, callback] : impl::getPragmas()) { for (const auto &[name, callback] : impl::getPragmas()) {
runtime.addPragma(name, callback); runtime.addPragma(name, callback);
} }
runtime.addDefine("__IMHEX__"); runtime.addDefine("__IMHEX__");
runtime.addDefine("__IMHEX_VERSION__", ImHexApi::System::getImHexVersion().get()); runtime.addDefine("__IMHEX_VERSION__", ImHexApi::System::getImHexVersion());
} }
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) { void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
@@ -659,15 +638,6 @@ namespace hex {
}); });
} }
void addType(const pl::api::Namespace &ns, const std::string &name, pl::api::FunctionParameterCount parameterCount, const pl::api::TypeCallback &func) {
log::debug("Registered new pattern language type: {}", getFunctionName(ns, name));
impl::s_types->push_back({
ns, name,
parameterCount, func
});
}
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, pl::api::FunctionParameterCount parameterCount) { void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, pl::api::FunctionParameterCount parameterCount) {
log::debug("Registered new pattern visualizer function: {}", name); log::debug("Registered new pattern visualizer function: {}", name);
@@ -850,12 +820,6 @@ namespace hex {
return *s_menuItems; return *s_menuItems;
} }
static AutoReset<std::vector<MenuItem*>> s_toolbarMenuItems;
const std::vector<MenuItem*>& getToolbarMenuItems() {
return s_toolbarMenuItems;
}
std::multimap<u32, MenuItem>& getMenuItemsMutable() { std::multimap<u32, MenuItem>& getMenuItemsMutable() {
return *s_menuItems; return *s_menuItems;
} }
@@ -913,21 +877,14 @@ namespace hex {
coloredIcon.color = ImGuiCustomCol_ToolbarGray; coloredIcon.color = ImGuiCustomCol_ToolbarGray;
impl::s_menuItems->insert({ impl::s_menuItems->insert({
priority, impl::MenuItem { unlocalizedMainMenuNames, coloredIcon, shortcut, view, function, enabledCallback, selectedCallback, -1 } priority, impl::MenuItem { unlocalizedMainMenuNames, coloredIcon, std::make_unique<Shortcut>(shortcut), view, function, enabledCallback, selectedCallback, -1 }
}); });
if (shortcut != Shortcut::None) { if (shortcut != Shortcut::None) {
auto callbackIfEnabled = [enabledCallback, function]{ if (enabledCallback()) { function(); } };
const auto unlocalizedShortcutName =
unlocalizedMainMenuNames.size() == 1 ?
std::vector { unlocalizedMainMenuNames.back() } :
std::vector(unlocalizedMainMenuNames.begin() + 1, unlocalizedMainMenuNames.end());
if (shortcut.isLocal() && view != nullptr) if (shortcut.isLocal() && view != nullptr)
ShortcutManager::addShortcut(view, shortcut, unlocalizedShortcutName, callbackIfEnabled); ShortcutManager::addShortcut(view, shortcut, unlocalizedMainMenuNames.back(), function);
else else
ShortcutManager::addGlobalShortcut(shortcut, unlocalizedShortcutName, callbackIfEnabled); ShortcutManager::addGlobalShortcut(shortcut, unlocalizedMainMenuNames.back(), function);
} }
} }
@@ -940,14 +897,14 @@ namespace hex {
unlocalizedMainMenuNames.emplace_back(impl::SubMenuValue); unlocalizedMainMenuNames.emplace_back(impl::SubMenuValue);
impl::s_menuItems->insert({ impl::s_menuItems->insert({
priority, impl::MenuItem { unlocalizedMainMenuNames, icon, Shortcut::None, nullptr, function, enabledCallback, []{ return false; }, -1 } priority, impl::MenuItem { unlocalizedMainMenuNames, icon, std::make_unique<Shortcut>(), nullptr, function, enabledCallback, []{ return false; }, -1 }
}); });
} }
void addMenuItemSeparator(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority) { void addMenuItemSeparator(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority) {
unlocalizedMainMenuNames.emplace_back(impl::SeparatorValue); unlocalizedMainMenuNames.emplace_back(impl::SeparatorValue);
impl::s_menuItems->insert({ impl::s_menuItems->insert({
priority, impl::MenuItem { unlocalizedMainMenuNames, "", Shortcut::None, nullptr, []{}, []{ return true; }, []{ return false; }, -1 } priority, impl::MenuItem { unlocalizedMainMenuNames, "", std::make_unique<Shortcut>(), nullptr, []{}, []{ return true; }, []{ return false; }, -1 }
}); });
} }
@@ -972,35 +929,11 @@ namespace hex {
if (menuItem.unlocalizedNames.back() == unlocalizedName) { if (menuItem.unlocalizedNames.back() == unlocalizedName) {
menuItem.toolbarIndex = maxIndex + 1; menuItem.toolbarIndex = maxIndex + 1;
menuItem.icon.color = color; menuItem.icon.color = color;
updateToolbarItems();
break; break;
} }
} }
} }
struct MenuItemSorter {
bool operator()(const auto *a, const auto *b) const {
return a->toolbarIndex < b->toolbarIndex;
}
};
void updateToolbarItems() {
std::set<ContentRegistry::Interface::impl::MenuItem*, MenuItemSorter> menuItems;
for (auto &[priority, menuItem] : impl::getMenuItemsMutable()) {
if (menuItem.toolbarIndex != -1) {
menuItems.insert(&menuItem);
}
}
impl::s_toolbarMenuItems->clear();
for (auto menuItem : menuItems) {
impl::s_toolbarMenuItems->push_back(menuItem);
}
}
void addSidebarItem(const std::string &icon, const impl::DrawCallback &function, const impl::EnabledCallback &enabledCallback) { void addSidebarItem(const std::string &icon, const impl::DrawCallback &function, const impl::EnabledCallback &enabledCallback) {
impl::s_sidebarItems->push_back({ icon, function, enabledCallback }); impl::s_sidebarItems->push_back({ icon, function, enabledCallback });
@@ -1049,28 +982,17 @@ namespace hex {
namespace impl { namespace impl {
static AutoReset<std::vector<ExportMenuEntry>> s_exportMenuEntries; static AutoReset<std::vector<Entry>> s_entries;
const std::vector<ExportMenuEntry>& getExportMenuEntries() { const std::vector<Entry>& getEntries() {
return *s_exportMenuEntries; return *s_entries;
}
static AutoReset<std::vector<FindExporterEntry>> s_findExportEntries;
const std::vector<FindExporterEntry>& getFindExporterEntries() {
return *s_findExportEntries;
} }
} }
void addExportMenuEntry(const UnlocalizedString &unlocalizedName, const impl::Callback &callback) { void add(const UnlocalizedString &unlocalizedName, const impl::Callback &callback) {
log::debug("Registered new data formatter: {}", unlocalizedName.get()); log::debug("Registered new data formatter: {}", unlocalizedName.get());
impl::s_exportMenuEntries->push_back({ unlocalizedName, callback }); impl::s_entries->push_back({ unlocalizedName, callback });
}
void addFindExportFormatter(const UnlocalizedString &unlocalizedName, const std::string fileExtension, const impl::FindExporterCallback &callback) {
log::debug("Registered new export formatter: {}", unlocalizedName.get());
impl::s_findExportEntries->push_back({ unlocalizedName, fileExtension, callback });
} }
} }
@@ -1235,7 +1157,7 @@ namespace hex {
class Service { class Service {
public: public:
Service(const UnlocalizedString &unlocalizedName, std::jthread thread) : m_unlocalizedName(std::move(unlocalizedName)), m_thread(std::move(thread)) { } Service(std::string name, std::jthread thread) : m_name(std::move(name)), m_thread(std::move(thread)) { }
Service(const Service&) = delete; Service(const Service&) = delete;
Service(Service &&) = default; Service(Service &&) = default;
~Service() { ~Service() {
@@ -1247,8 +1169,8 @@ namespace hex {
Service& operator=(const Service&) = delete; Service& operator=(const Service&) = delete;
Service& operator=(Service &&) = default; Service& operator=(Service &&) = default;
[[nodiscard]] const UnlocalizedString& getUnlocalizedName() const { [[nodiscard]] const std::string& getName() const {
return m_unlocalizedName; return m_name;
} }
[[nodiscard]] const std::jthread& getThread() const { [[nodiscard]] const std::jthread& getThread() const {
@@ -1256,7 +1178,7 @@ namespace hex {
} }
private: private:
UnlocalizedString m_unlocalizedName; std::string m_name;
std::jthread m_thread; std::jthread m_thread;
}; };

View File

@@ -21,30 +21,4 @@ namespace hex {
} }
bool EventManager::isAlreadyRegistered(void *token, impl::EventId id) {
if (getTokenStore().contains(token)) {
auto&& [begin, end] = getTokenStore().equal_range(token);
return std::any_of(begin, end, [&](auto &item) {
return item.second->first == id;
});
}
return false;
}
void EventManager::unsubscribe(void *token, impl::EventId id) {
auto &tokenStore = getTokenStore();
auto iter = std::find_if(tokenStore.begin(), tokenStore.end(), [&](auto &item) {
return item.first == token && item.second->first == id;
});
if (iter != tokenStore.end()) {
getEvents().erase(iter->second);
tokenStore.erase(iter);
}
}
} }

View File

@@ -15,7 +15,6 @@
#include <imgui.h> #include <imgui.h>
#include <imgui_internal.h> #include <imgui_internal.h>
#include <set> #include <set>
#include <algorithm>
#include <GLFW/glfw3.h> #include <GLFW/glfw3.h>
#if defined(OS_WINDOWS) #if defined(OS_WINDOWS)
@@ -184,24 +183,24 @@ namespace hex {
impl::s_hoveringFunctions->erase(id); impl::s_hoveringFunctions->erase(id);
} }
static u32 s_tooltipId = 0; static u32 tooltipId = 0;
u32 addTooltip(Region region, std::string value, color_t color) { u32 addTooltip(Region region, std::string value, color_t color) {
s_tooltipId++; tooltipId++;
impl::s_tooltips->insert({ s_tooltipId, { region, std::move(value), color } }); impl::s_tooltips->insert({ tooltipId, { region, std::move(value), color } });
return s_tooltipId; return tooltipId;
} }
void removeTooltip(u32 id) { void removeTooltip(u32 id) {
impl::s_tooltips->erase(id); impl::s_tooltips->erase(id);
} }
static u32 s_tooltipFunctionId; static u32 tooltipFunctionId;
u32 addTooltipProvider(TooltipFunction function) { u32 addTooltipProvider(TooltipFunction function) {
s_tooltipFunctionId++; tooltipFunctionId++;
impl::s_tooltipFunctions->insert({ s_tooltipFunctionId, std::move(function) }); impl::s_tooltipFunctions->insert({ tooltipFunctionId, std::move(function) });
return s_tooltipFunctionId; return tooltipFunctionId;
} }
void removeTooltipProvider(u32 id) { void removeTooltipProvider(u32 id) {
@@ -268,7 +267,6 @@ namespace hex {
static i64 s_currentProvider = -1; static i64 s_currentProvider = -1;
static AutoReset<std::vector<std::unique_ptr<prv::Provider>>> s_providers; static AutoReset<std::vector<std::unique_ptr<prv::Provider>>> s_providers;
static AutoReset<std::map<prv::Provider*, std::unique_ptr<prv::Provider>>> s_providersToRemove;
namespace impl { namespace impl {
@@ -277,7 +275,7 @@ namespace hex {
s_closingProviders.clear(); s_closingProviders.clear();
} }
std::set<prv::Provider*> getClosingProviders() { const std::set<prv::Provider*>& getClosingProviders() {
return s_closingProviders; return s_closingProviders;
} }
@@ -337,11 +335,7 @@ namespace hex {
} }
void markDirty() { void markDirty() {
const auto provider = get(); get()->markDirty();
if (!provider->isDirty()) {
provider->markDirty();
EventProviderDirtied::post(provider);
}
} }
void resetDirty() { void resetDirty() {
@@ -429,38 +423,20 @@ namespace hex {
} }
} }
static std::mutex eraseMutex; provider->close();
EventProviderClosed::post(provider);
// Move provider over to a list of providers to delete
eraseMutex.lock();
auto providerToRemove = it->get();
(*s_providersToRemove)[providerToRemove] = std::move(*it);
eraseMutex.unlock();
// Remove left over references from the main provider list
s_providers->erase(it);
impl::s_closingProviders.erase(provider);
if (s_currentProvider >= i64(s_providers->size()) && !s_providers->empty())
setCurrentProvider(s_providers->size() - 1);
if (s_providers->empty())
EventProviderChanged::post(provider, nullptr);
EventProviderClosed::post(it->get());
RequestUpdateWindowTitle::post(); RequestUpdateWindowTitle::post();
// Do the destruction of the provider in the background once all tasks have finished TaskManager::runWhenTasksFinished([it, provider] {
TaskManager::runWhenTasksFinished([providerToRemove] { EventProviderDeleted::post(provider);
EventProviderDeleted::post(providerToRemove); impl::s_closingProviders.erase(provider);
TaskManager::createBackgroundTask("Closing Provider", [providerToRemove](Task &) {
eraseMutex.lock();
auto provider = std::move((*s_providersToRemove)[providerToRemove]);
s_providersToRemove->erase(providerToRemove);
eraseMutex.unlock();
provider->close(); s_providers->erase(it);
}); if (s_currentProvider >= i64(s_providers->size()))
setCurrentProvider(0);
if (s_providers->empty())
EventProviderChanged::post(provider, nullptr);
}); });
} }
@@ -536,11 +512,6 @@ namespace hex {
s_gpuVendor = vendor; s_gpuVendor = vendor;
} }
static AutoReset<std::string> s_glRenderer;
void setGLRenderer(const std::string &renderer) {
s_glRenderer = renderer;
}
static AutoReset<std::map<std::string, std::string>> s_initArguments; static AutoReset<std::map<std::string, std::string>> s_initArguments;
void addInitArgument(const std::string &key, const std::string &value) { void addInitArgument(const std::string &key, const std::string &value) {
static std::mutex initArgumentsMutex; static std::mutex initArgumentsMutex;
@@ -642,15 +613,7 @@ namespace hex {
} }
void* getLibImHexModuleHandle() { void* getLibImHexModuleHandle() {
return hex::getContainingModule(reinterpret_cast<void*>(&getLibImHexModuleHandle)); return hex::getContainingModule((void*)&getLibImHexModuleHandle);
}
void addMigrationRoutine(SemanticVersion migrationVersion, std::function<void()> function) {
EventImHexUpdated::subscribe([migrationVersion, function](const SemanticVersion &oldVersion, const SemanticVersion &newVersion) {
if (oldVersion < migrationVersion && newVersion >= migrationVersion) {
function();
}
});
} }
@@ -693,10 +656,6 @@ namespace hex {
return impl::s_gpuVendor; return impl::s_gpuVendor;
} }
const std::string &getGLRenderer() {
return impl::s_glRenderer;
}
bool isPortableVersion() { bool isPortableVersion() {
static std::optional<bool> portable; static std::optional<bool> portable;
if (portable.has_value()) if (portable.has_value())
@@ -783,30 +742,16 @@ namespace hex {
#endif #endif
} }
std::optional<LinuxDistro> getLinuxDistro() { std::string getImHexVersion(bool withBuildType) {
wolv::io::File file("/etc/os-release", wolv::io::File::Mode::Read);
std::string name;
std::string version;
auto fileContent = file.readString();
for (const auto &line : wolv::util::splitString(fileContent, "\n")) {
if (line.find("PRETTY_NAME=") != std::string::npos) {
name = line.substr(line.find("=") + 1);
std::erase(name, '\"');
} else if (line.find("VERSION_ID=") != std::string::npos) {
version = line.substr(line.find("=") + 1);
std::erase(version, '\"');
}
}
return { { name, version } };
}
SemanticVersion getImHexVersion() {
#if defined IMHEX_VERSION #if defined IMHEX_VERSION
return SemanticVersion(IMHEX_VERSION); if (withBuildType) {
return IMHEX_VERSION;
} else {
auto version = std::string(IMHEX_VERSION);
return version.substr(0, version.find('-'));
}
#else #else
return {}; return "Unknown";
#endif #endif
} }
@@ -818,7 +763,7 @@ namespace hex {
return std::string(GIT_COMMIT_HASH_LONG).substr(0, 7); return std::string(GIT_COMMIT_HASH_LONG).substr(0, 7);
} }
#else #else
std::ignore = longHash; hex::unused(longHash);
return "Unknown"; return "Unknown";
#endif #endif
} }
@@ -839,10 +784,6 @@ namespace hex {
#endif #endif
} }
bool isNightlyBuild() {
return getImHexVersion().nightly();
}
bool updateImHex(UpdateType updateType) { bool updateImHex(UpdateType updateType) {
// Get the path of the updater executable // Get the path of the updater executable
std::fs::path executablePath; std::fs::path executablePath;
@@ -869,7 +810,7 @@ namespace hex {
EventImHexClosing::subscribe([executablePath, updateTypeString] { EventImHexClosing::subscribe([executablePath, updateTypeString] {
hex::executeCommand( hex::executeCommand(
hex::format("\"{}\" \"{}\"", hex::format("{} {}",
wolv::util::toUTF8String(executablePath), wolv::util::toUTF8String(executablePath),
updateTypeString updateTypeString
) )
@@ -948,9 +889,9 @@ namespace hex {
s_fontSize = size; s_fontSize = size;
} }
static AutoReset<ImFontAtlas*> s_fontAtlas; static AutoReset<std::shared_ptr<ImFontAtlas>> s_fontAtlas;
void setFontAtlas(ImFontAtlas* fontAtlas) { void setFontAtlas(ImFontAtlas* fontAtlas) {
s_fontAtlas = fontAtlas; s_fontAtlas = std::unique_ptr<ImFontAtlas, void(*)(ImFontAtlas*)>(fontAtlas, IM_DELETE);
} }
static ImFont *s_boldFont = nullptr; static ImFont *s_boldFont = nullptr;
@@ -1033,7 +974,7 @@ namespace hex {
} }
ImFontAtlas* getFontAtlas() { ImFontAtlas* getFontAtlas() {
return impl::s_fontAtlas; return impl::s_fontAtlas->get();
} }
ImFont* Bold() { ImFont* Bold() {

View File

@@ -1,15 +1,13 @@
#include <hex/api/layout_manager.hpp> #include <hex/api/layout_manager.hpp>
#include <hex/api/content_registry.hpp>
#include <hex/ui/view.hpp>
#include <hex/helpers/fs.hpp> #include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp> #include <hex/helpers/logger.hpp>
#include <hex/helpers/auto_reset.hpp> #include <hex/helpers/auto_reset.hpp>
#include <hex/helpers/default_paths.hpp>
#include <wolv/utils/string.hpp> #include <wolv/utils/string.hpp>
#include <imgui.h> #include <imgui.h>
#include <hex/api/content_registry.hpp>
#include <hex/ui/view.hpp>
namespace hex { namespace hex {
@@ -42,7 +40,10 @@ namespace hex {
fileName += ".hexlyt"; fileName += ".hexlyt";
std::fs::path layoutPath; std::fs::path layoutPath;
for (const auto &path : paths::Layouts.write()) { for (const auto &path : hex::fs::getDefaultPaths(fs::ImHexPath::Layouts)) {
if (!hex::fs::isPathWritable(layoutPath))
continue;
layoutPath = path / fileName; layoutPath = path / fileName;
} }
@@ -108,7 +109,7 @@ namespace hex {
void LayoutManager::reload() { void LayoutManager::reload() {
s_layouts->clear(); s_layouts->clear();
for (const auto &directory : paths::Layouts.read()) { for (const auto &directory : hex::fs::getDefaultPaths(fs::ImHexPath::Layouts)) {
for (const auto &entry : std::fs::directory_iterator(directory)) { for (const auto &entry : std::fs::directory_iterator(directory)) {
const auto &path = entry.path(); const auto &path = entry.path();

View File

@@ -10,7 +10,7 @@ namespace hex {
AutoReset<std::string> s_fallbackLanguage; AutoReset<std::string> s_fallbackLanguage;
AutoReset<std::string> s_selectedLanguage; AutoReset<std::string> s_selectedLanguage;
AutoReset<std::map<size_t, std::string>> s_currStrings; AutoReset<std::map<std::string, std::string>> s_currStrings;
} }
@@ -41,21 +41,6 @@ namespace hex {
return m_entries; return m_entries;
} }
static void loadLanguageDefinitions(const std::vector<LanguageDefinition> &definitions) {
for (const auto &definition : definitions) {
const auto &entries = definition.getEntries();
if (entries.empty())
continue;
for (const auto &[key, value] : entries) {
if (value.empty())
continue;
s_currStrings->emplace(LangConst::hash(key), value);
}
}
}
void loadLanguage(const std::string &language) { void loadLanguage(const std::string &language) {
auto &definitions = ContentRegistry::Language::impl::getLanguageDefinitions(); auto &definitions = ContentRegistry::Language::impl::getLanguageDefinitions();
@@ -64,10 +49,14 @@ namespace hex {
s_currStrings->clear(); s_currStrings->clear();
loadLanguageDefinitions(definitions.at(language)); for (const auto &definition : definitions.at(language))
s_currStrings->insert(definition.getEntries().begin(), definition.getEntries().end());
const auto& fallbackLanguage = getFallbackLanguage(); const auto& fallbackLanguage = getFallbackLanguage();
loadLanguageDefinitions(definitions.at(fallbackLanguage)); if (language != fallbackLanguage && definitions.contains(fallbackLanguage)) {
for (const auto &definition : definitions.at(fallbackLanguage))
s_currStrings->insert(definition.getEntries().begin(), definition.getEntries().end());
}
s_selectedLanguage = language; s_selectedLanguage = language;
} }
@@ -109,11 +98,11 @@ namespace hex {
} }
Lang::Lang(const char *unlocalizedString) : m_entryHash(LangConst::hash(unlocalizedString)), m_unlocalizedString(unlocalizedString) { } Lang::Lang(const char *unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
Lang::Lang(const std::string &unlocalizedString) : m_entryHash(LangConst::hash(unlocalizedString)), m_unlocalizedString(unlocalizedString) { } Lang::Lang(const std::string &unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
Lang::Lang(const LangConst &localizedString) : m_entryHash(localizedString.m_entryHash), m_unlocalizedString(localizedString.m_unlocalizedString) { } Lang::Lang(const UnlocalizedString &unlocalizedString) : m_unlocalizedString(unlocalizedString.get()) { }
Lang::Lang(const UnlocalizedString &unlocalizedString) : m_entryHash(LangConst::hash(unlocalizedString.get())), m_unlocalizedString(unlocalizedString.get()) { } Lang::Lang(std::string_view unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
Lang::Lang(std::string_view unlocalizedString) : m_entryHash(LangConst::hash(unlocalizedString)), m_unlocalizedString(unlocalizedString) { }
Lang::operator std::string() const { Lang::operator std::string() const {
return get(); return get();
@@ -124,41 +113,43 @@ namespace hex {
} }
Lang::operator const char *() const { Lang::operator const char *() const {
return get(); return get().c_str();
} }
const char *Lang::get() const { std::string operator+(const std::string &&left, const Lang &&right) {
const auto &lang = *LocalizationManager::s_currStrings; return left + static_cast<std::string>(right);
const auto it = lang.find(m_entryHash);
if (it == lang.end()) {
return m_unlocalizedString.c_str();
} else {
return it->second.c_str();
}
} }
LangConst::operator std::string() const { std::string operator+(const Lang &&left, const std::string &&right) {
return get(); return static_cast<std::string>(left) + right;
} }
LangConst::operator std::string_view() const { std::string operator+(const Lang &&left, const Lang &&right) {
return get(); return static_cast<std::string>(left) + static_cast<std::string>(right);
} }
LangConst::operator const char *() const { std::string operator+(const std::string_view &&left, const Lang &&right) {
return get(); return std::string(left) + static_cast<std::string>(right);
} }
const char *LangConst::get() const { std::string operator+(const Lang &&left, const std::string_view &&right) {
const auto &lang = *LocalizationManager::s_currStrings; return static_cast<std::string>(left) + std::string(right);
}
const auto it = lang.find(m_entryHash); std::string operator+(const char *left, const Lang &&right) {
if (it == lang.end()) { return left + static_cast<std::string>(right);
}
std::string operator+(const Lang &&left, const char *right) {
return static_cast<std::string>(left) + right;
}
const std::string &Lang::get() const {
auto &lang = LocalizationManager::s_currStrings;
if (lang->contains(m_unlocalizedString))
return lang->at(m_unlocalizedString);
else
return m_unlocalizedString; return m_unlocalizedString;
} else {
return it->second.c_str();
}
} }
} }

View File

@@ -5,7 +5,6 @@
#include <hex/helpers/fmt.hpp> #include <hex/helpers/fmt.hpp>
#include <hex/helpers/auto_reset.hpp> #include <hex/helpers/auto_reset.hpp>
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
#include <hex/helpers/default_paths.hpp>
#include <wolv/utils/string.hpp> #include <wolv/utils/string.hpp>
@@ -112,6 +111,10 @@ namespace hex {
} }
Plugin::~Plugin() { Plugin::~Plugin() {
if (isLoaded()) {
log::info("Trying to unload plugin '{}'", getPluginName());
}
unloadLibrary(m_handle, m_path); unloadLibrary(m_handle, m_path);
} }
@@ -129,7 +132,7 @@ namespace hex {
const auto requestedVersion = getCompatibleVersion(); const auto requestedVersion = getCompatibleVersion();
const auto imhexVersion = ImHexApi::System::getImHexVersion().get(); const auto imhexVersion = ImHexApi::System::getImHexVersion();
if (!imhexVersion.starts_with(requestedVersion)) { if (!imhexVersion.starts_with(requestedVersion)) {
if (requestedVersion.empty()) { if (requestedVersion.empty()) {
log::warn("Plugin '{}' did not specify a compatible version, assuming it is compatible with the current version of ImHex.", wolv::util::toUTF8String(m_path.filename())); log::warn("Plugin '{}' did not specify a compatible version, assuming it is compatible with the current version of ImHex.", wolv::util::toUTF8String(m_path.filename()));
@@ -303,7 +306,7 @@ namespace hex {
bool PluginManager::loadLibraries() { bool PluginManager::loadLibraries() {
bool success = true; bool success = true;
for (const auto &loadPath : paths::Libraries.read()) for (const auto &loadPath : fs::getDefaultPaths(fs::ImHexPath::Libraries))
success = PluginManager::loadLibraries(loadPath) && success; success = PluginManager::loadLibraries(loadPath) && success;
return success; return success;
@@ -331,7 +334,7 @@ namespace hex {
void PluginManager::initializeNewPlugins() { void PluginManager::initializeNewPlugins() {
for (const auto &plugin : getPlugins()) { for (const auto &plugin : getPlugins()) {
if (!plugin.isLoaded()) if (!plugin.isLoaded())
std::ignore = plugin.initializePlugin(); hex::unused(plugin.initializePlugin());
} }
} }

View File

@@ -12,265 +12,31 @@ namespace hex {
AutoReset<std::map<Shortcut, ShortcutManager::ShortcutEntry>> s_globalShortcuts; AutoReset<std::map<Shortcut, ShortcutManager::ShortcutEntry>> s_globalShortcuts;
std::atomic<bool> s_paused; std::atomic<bool> s_paused;
std::optional<Shortcut> s_prevShortcut; std::optional<Shortcut> s_prevShortcut;
bool s_macOSMode = false;
} }
Shortcut operator+(const Key &lhs, const Key &rhs) {
Shortcut result;
result.m_keys = { lhs, rhs };
return result;
}
Shortcut::Shortcut(Keys key) : m_keys({ key }) {
}
Shortcut::Shortcut(std::set<Key> keys) : m_keys(std::move(keys)) {
}
Shortcut Shortcut::operator+(const Key &other) const {
Shortcut result = *this;
result.m_keys.insert(other);
return result;
}
Shortcut& Shortcut::operator+=(const Key &other) {
m_keys.insert(other);
return *this;
}
bool Shortcut::operator<(const Shortcut &other) const {
return m_keys < other.m_keys;
}
bool Shortcut::operator==(const Shortcut &other) const {
return m_keys == other.m_keys;
}
bool Shortcut::isLocal() const {
return m_keys.contains(CurrentView);
}
const std::set<Key>& Shortcut::getKeys() const {
return m_keys;
}
bool Shortcut::has(Key key) const {
return m_keys.contains(key);
}
bool Shortcut::matches(const Shortcut& other) const {
auto left = this->m_keys;
auto right = other.m_keys;
left.erase(CurrentView);
left.erase(AllowWhileTyping);
right.erase(CurrentView);
right.erase(AllowWhileTyping);
return left == right;
}
std::string Shortcut::toString() const {
std::string result;
const auto CTRL_NAME = s_macOSMode ? "" : "CTRL";
const auto ALT_NAME = s_macOSMode ? "" : "ALT";
const auto SHIFT_NAME = s_macOSMode ? "" : "SHIFT";
const auto SUPER_NAME = s_macOSMode ? "" : "SUPER";
const auto Concatination = s_macOSMode ? " " : " + ";
auto keys = m_keys;
if (keys.erase(CTRL) > 0 || (!s_macOSMode && keys.erase(CTRLCMD) > 0)) {
result += CTRL_NAME;
result += Concatination;
}
if (keys.erase(ALT) > 0) {
result += ALT_NAME;
result += Concatination;
}
if (keys.erase(SHIFT) > 0) {
result += SHIFT_NAME;
result += Concatination;
}
if (keys.erase(SUPER) > 0 || (s_macOSMode && keys.erase(CTRLCMD) > 0)) {
result += SUPER_NAME;
result += Concatination;
}
keys.erase(CurrentView);
for (const auto &key : keys) {
switch (Keys(key.getKeyCode())) {
case Keys::Space: result += ""; break;
case Keys::Apostrophe: result += "'"; break;
case Keys::Comma: result += ","; break;
case Keys::Minus: result += "-"; break;
case Keys::Period: result += "."; break;
case Keys::Slash: result += "/"; break;
case Keys::Num0: result += "0"; break;
case Keys::Num1: result += "1"; break;
case Keys::Num2: result += "2"; break;
case Keys::Num3: result += "3"; break;
case Keys::Num4: result += "4"; break;
case Keys::Num5: result += "5"; break;
case Keys::Num6: result += "6"; break;
case Keys::Num7: result += "7"; break;
case Keys::Num8: result += "8"; break;
case Keys::Num9: result += "9"; break;
case Keys::Semicolon: result += ";"; break;
case Keys::Equals: result += "="; break;
case Keys::A: result += "A"; break;
case Keys::B: result += "B"; break;
case Keys::C: result += "C"; break;
case Keys::D: result += "D"; break;
case Keys::E: result += "E"; break;
case Keys::F: result += "F"; break;
case Keys::G: result += "G"; break;
case Keys::H: result += "H"; break;
case Keys::I: result += "I"; break;
case Keys::J: result += "J"; break;
case Keys::K: result += "K"; break;
case Keys::L: result += "L"; break;
case Keys::M: result += "M"; break;
case Keys::N: result += "N"; break;
case Keys::O: result += "O"; break;
case Keys::P: result += "P"; break;
case Keys::Q: result += "Q"; break;
case Keys::R: result += "R"; break;
case Keys::S: result += "S"; break;
case Keys::T: result += "T"; break;
case Keys::U: result += "U"; break;
case Keys::V: result += "V"; break;
case Keys::W: result += "W"; break;
case Keys::X: result += "X"; break;
case Keys::Y: result += "Y"; break;
case Keys::Z: result += "Z"; break;
case Keys::LeftBracket: result += "["; break;
case Keys::Backslash: result += "\\"; break;
case Keys::RightBracket: result += "]"; break;
case Keys::GraveAccent: result += "`"; break;
case Keys::World1: result += "WORLD1"; break;
case Keys::World2: result += "WORLD2"; break;
case Keys::Escape: result += "ESC"; break;
case Keys::Enter: result += ""; break;
case Keys::Tab: result += ""; break;
case Keys::Backspace: result += ""; break;
case Keys::Insert: result += "INSERT"; break;
case Keys::Delete: result += "DELETE"; break;
case Keys::Right: result += "RIGHT"; break;
case Keys::Left: result += "LEFT"; break;
case Keys::Down: result += "DOWN"; break;
case Keys::Up: result += "UP"; break;
case Keys::PageUp: result += "PAGEUP"; break;
case Keys::PageDown: result += "PAGEDOWN"; break;
case Keys::Home: result += "HOME"; break;
case Keys::End: result += "END"; break;
case Keys::CapsLock: result += ""; break;
case Keys::ScrollLock: result += "SCROLLLOCK"; break;
case Keys::NumLock: result += "NUMLOCK"; break;
case Keys::PrintScreen: result += "PRINTSCREEN"; break;
case Keys::Pause: result += "PAUSE"; break;
case Keys::F1: result += "F1"; break;
case Keys::F2: result += "F2"; break;
case Keys::F3: result += "F3"; break;
case Keys::F4: result += "F4"; break;
case Keys::F5: result += "F5"; break;
case Keys::F6: result += "F6"; break;
case Keys::F7: result += "F7"; break;
case Keys::F8: result += "F8"; break;
case Keys::F9: result += "F9"; break;
case Keys::F10: result += "F10"; break;
case Keys::F11: result += "F11"; break;
case Keys::F12: result += "F12"; break;
case Keys::F13: result += "F13"; break;
case Keys::F14: result += "F14"; break;
case Keys::F15: result += "F15"; break;
case Keys::F16: result += "F16"; break;
case Keys::F17: result += "F17"; break;
case Keys::F18: result += "F18"; break;
case Keys::F19: result += "F19"; break;
case Keys::F20: result += "F20"; break;
case Keys::F21: result += "F21"; break;
case Keys::F22: result += "F22"; break;
case Keys::F23: result += "F23"; break;
case Keys::F24: result += "F24"; break;
case Keys::F25: result += "F25"; break;
case Keys::KeyPad0: result += "KP0"; break;
case Keys::KeyPad1: result += "KP1"; break;
case Keys::KeyPad2: result += "KP2"; break;
case Keys::KeyPad3: result += "KP3"; break;
case Keys::KeyPad4: result += "KP4"; break;
case Keys::KeyPad5: result += "KP5"; break;
case Keys::KeyPad6: result += "KP6"; break;
case Keys::KeyPad7: result += "KP7"; break;
case Keys::KeyPad8: result += "KP8"; break;
case Keys::KeyPad9: result += "KP9"; break;
case Keys::KeyPadDecimal: result += "KPDECIMAL"; break;
case Keys::KeyPadDivide: result += "KPDIVIDE"; break;
case Keys::KeyPadMultiply: result += "KPMULTIPLY"; break;
case Keys::KeyPadSubtract: result += "KPSUBTRACT"; break;
case Keys::KeyPadAdd: result += "KPADD"; break;
case Keys::KeyPadEnter: result += "KPENTER"; break;
case Keys::KeyPadEqual: result += "KPEQUAL"; break;
case Keys::Menu: result += "MENU"; break;
default:
continue;
}
result += Concatination;
}
if (result.ends_with(Concatination))
result = result.substr(0, result.size() - strlen(Concatination));
return result;
}
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const std::function<void()> &callback) {
log::debug("Adding global shortcut {} for {}", shortcut.toString(), unlocalizedName.back().get());
auto [it, inserted] = s_globalShortcuts->insert({ shortcut, { shortcut, unlocalizedName, callback } });
if (!inserted) log::error("Failed to add shortcut!");
}
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback) { void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback) {
log::debug("Adding global shortcut {} for {}", shortcut.toString(), unlocalizedName.get()); s_globalShortcuts->insert({ shortcut, { shortcut, unlocalizedName, callback } });
auto [it, inserted] = s_globalShortcuts->insert({ shortcut, { shortcut, { unlocalizedName }, callback } });
if (!inserted) log::error("Failed to add shortcut!");
}
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const std::function<void()> &callback) {
log::debug("Adding shortcut {} for {}", shortcut.toString(), unlocalizedName.back().get());
auto [it, inserted] = view->m_shortcuts.insert({ shortcut + CurrentView, { shortcut, unlocalizedName, callback } });
if (!inserted) log::error("Failed to add shortcut!");
} }
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback) { void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback) {
log::debug("Adding shortcut {} for {}", shortcut.toString(), unlocalizedName.get()); view->m_shortcuts.insert({ shortcut + CurrentView, { shortcut, unlocalizedName, callback } });
auto [it, inserted] = view->m_shortcuts.insert({ shortcut + CurrentView, { shortcut, { unlocalizedName }, callback } });
if (!inserted) log::error("Failed to add shortcut!");
} }
static Shortcut getShortcut(bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode) { static Shortcut getShortcut(bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode) {
Shortcut pressedShortcut; Shortcut pressedShortcut;
if (ctrl) if (ctrl)
pressedShortcut += s_macOSMode ? CTRL : CTRLCMD; pressedShortcut += CTRL;
if (alt) if (alt)
pressedShortcut += ALT; pressedShortcut += ALT;
if (shift) if (shift)
pressedShortcut += SHIFT; pressedShortcut += SHIFT;
if (super) if (super)
pressedShortcut += s_macOSMode ? CTRLCMD : SUPER; pressedShortcut += SUPER;
if (focused) if (focused)
pressedShortcut += CurrentView; pressedShortcut += CurrentView;
if (ImGui::GetIO().WantTextInput)
pressedShortcut += AllowWhileTyping;
pressedShortcut += static_cast<Keys>(keyCode); pressedShortcut += static_cast<Keys>(keyCode);
@@ -283,9 +49,11 @@ namespace hex {
if (ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId)) if (ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId))
return; return;
if (auto it = shortcuts.find(shortcut); it != shortcuts.end()) { if (shortcuts.contains(shortcut + AllowWhileTyping)) {
const auto &[foundShortcut, entry] = *it; shortcuts.at(shortcut + AllowWhileTyping).callback();
entry.callback(); } else if (shortcuts.contains(shortcut)) {
if (!ImGui::GetIO().WantTextInput)
shortcuts.at(shortcut).callback();
} }
} }
@@ -354,13 +122,10 @@ namespace hex {
return true; return true;
} }
bool ShortcutManager::updateShortcut(const Shortcut &oldShortcut, Shortcut newShortcut, View *view) { bool ShortcutManager::updateShortcut(const Shortcut &oldShortcut, const Shortcut &newShortcut, View *view) {
if (oldShortcut.matches(newShortcut)) if (oldShortcut == newShortcut)
return true; return true;
if (oldShortcut.has(AllowWhileTyping))
newShortcut += AllowWhileTyping;
bool result; bool result;
if (view != nullptr) { if (view != nullptr) {
result = updateShortcutImpl(oldShortcut + CurrentView, newShortcut + CurrentView , view->m_shortcuts); result = updateShortcutImpl(oldShortcut + CurrentView, newShortcut + CurrentView , view->m_shortcuts);
@@ -369,9 +134,9 @@ namespace hex {
} }
if (result) { if (result) {
for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItemsMutable()) { for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) {
if (menuItem.view == view && menuItem.shortcut == oldShortcut) { if (menuItem.view == view && *menuItem.shortcut == oldShortcut) {
menuItem.shortcut = newShortcut; *menuItem.shortcut = newShortcut;
break; break;
} }
} }
@@ -380,9 +145,4 @@ namespace hex {
return result; return result;
} }
void ShortcutManager::enableMacOSMode() {
s_macOSMode = true;
}
} }

View File

@@ -63,7 +63,7 @@ namespace hex {
} }
Task::Task(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function) Task::Task(UnlocalizedString unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function)
: m_unlocalizedName(std::move(unlocalizedName)), m_maxValue(maxValue), m_function(std::move(function)), m_background(background) { } : m_unlocalizedName(std::move(unlocalizedName)), m_maxValue(maxValue), m_function(std::move(function)), m_background(background) { }
Task::Task(hex::Task &&other) noexcept { Task::Task(hex::Task &&other) noexcept {
@@ -327,11 +327,11 @@ namespace hex {
s_tasksFinishedCallbacks.clear(); s_tasksFinishedCallbacks.clear();
} }
TaskHolder TaskManager::createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, std::function<void(Task&)> function) { TaskHolder TaskManager::createTask(std::string name, u64 maxValue, bool background, std::function<void(Task&)> function) {
std::scoped_lock lock(s_queueMutex); std::scoped_lock lock(s_queueMutex);
// Construct new task // Construct new task
auto task = std::make_shared<Task>(std::move(unlocalizedName), maxValue, background, std::move(function)); auto task = std::make_shared<Task>(std::move(name), maxValue, background, std::move(function));
s_tasks.emplace_back(task); s_tasks.emplace_back(task);
@@ -344,32 +344,14 @@ namespace hex {
} }
TaskHolder TaskManager::createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void(Task &)> function) { TaskHolder TaskManager::createTask(std::string name, u64 maxValue, std::function<void(Task &)> function) {
log::debug("Creating task {}", unlocalizedName.get()); log::debug("Creating task {}", name);
return createTask(std::move(unlocalizedName), maxValue, false, std::move(function)); return createTask(std::move(name), maxValue, false, std::move(function));
} }
TaskHolder TaskManager::createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void()> function) { TaskHolder TaskManager::createBackgroundTask(std::string name, std::function<void(Task &)> function) {
log::debug("Creating task {}", unlocalizedName.get()); log::debug("Creating background task {}", name);
return createTask(std::move(unlocalizedName), maxValue, false, return createTask(std::move(name), 0, true, std::move(function));
[function = std::move(function)](Task&) {
function();
}
);
}
TaskHolder TaskManager::createBackgroundTask(const UnlocalizedString &unlocalizedName, std::function<void(Task &)> function) {
log::debug("Creating background task {}", unlocalizedName.get());
return createTask(std::move(unlocalizedName), 0, true, std::move(function));
}
TaskHolder TaskManager::createBackgroundTask(const UnlocalizedString &unlocalizedName, std::function<void()> function) {
log::debug("Creating background task {}", unlocalizedName.get());
return createTask(std::move(unlocalizedName), 0, true,
[function = std::move(function)](Task&) {
function();
}
);
} }
void TaskManager::collectGarbage() { void TaskManager::collectGarbage() {
@@ -461,7 +443,7 @@ namespace hex {
static auto setThreadDescription = reinterpret_cast<SetThreadDescriptionFunc>( static auto setThreadDescription = reinterpret_cast<SetThreadDescriptionFunc>(
reinterpret_cast<uintptr_t>( reinterpret_cast<uintptr_t>(
::GetProcAddress( ::GetProcAddress(
::GetModuleHandleW(L"Kernel32.dll"), ::GetModuleHandle("Kernel32.dll"),
"SetThreadDescription" "SetThreadDescription"
) )
) )
@@ -490,7 +472,7 @@ namespace hex {
#elif defined(OS_LINUX) #elif defined(OS_LINUX)
pthread_setname_np(pthread_self(), name.c_str()); pthread_setname_np(pthread_self(), name.c_str());
#elif defined(OS_WEB) #elif defined(OS_WEB)
std::ignore = name; hex::unused(name);
#elif defined(OS_MACOS) #elif defined(OS_MACOS)
pthread_setname_np(name.c_str()); pthread_setname_np(name.c_str());
#endif #endif

View File

@@ -21,11 +21,6 @@ namespace hex {
} }
void ThemeManager::reapplyCurrentTheme() {
ThemeManager::changeTheme(s_currTheme);
}
void ThemeManager::addThemeHandler(const std::string &name, const ColorMap &colorMap, const std::function<ImColor(u32)> &getFunction, const std::function<void(u32, ImColor)> &setFunction) { void ThemeManager::addThemeHandler(const std::string &name, const ColorMap &colorMap, const std::function<ImColor(u32)> &getFunction, const std::function<void(u32, ImColor)> &setFunction) {
std::unique_lock lock(s_themeMutex); std::unique_lock lock(s_themeMutex);

View File

@@ -21,11 +21,6 @@ namespace hex {
AutoReset<std::map<ImGuiID, std::string>> s_highlights; AutoReset<std::map<ImGuiID, std::string>> s_highlights;
AutoReset<std::vector<std::pair<ImRect, std::string>>> s_highlightDisplays; AutoReset<std::vector<std::pair<ImRect, std::string>>> s_highlightDisplays;
AutoReset<std::map<ImGuiID, std::function<void()>>> s_interactiveHelpItems;
ImRect s_hoveredRect;
ImGuiID s_hoveredId;
bool s_helpHoverActive = false;
class IDStack { class IDStack {
public: public:
@@ -33,13 +28,6 @@ namespace hex {
idStack.push_back(0); idStack.push_back(0);
} }
void add(const char *string) {
const ImGuiID seed = idStack.back();
const ImGuiID id = ImHashStr(string, 0, seed);
idStack.push_back(id);
}
void add(const std::string &string) { void add(const std::string &string) {
const ImGuiID seed = idStack.back(); const ImGuiID seed = idStack.back();
const ImGuiID id = ImHashStr(string.c_str(), string.length(), seed); const ImGuiID id = ImHashStr(string.c_str(), string.length(), seed);
@@ -68,46 +56,8 @@ namespace hex {
ImVector<ImGuiID> idStack; ImVector<ImGuiID> idStack;
}; };
ImGuiID calculateId(const auto &ids) {
IDStack idStack;
for (const auto &id : ids) {
std::visit(wolv::util::overloaded {
[&idStack](const Lang &id) {
idStack.add(id.get());
},
[&idStack](const auto &id) {
idStack.add(id);
}
}, id);
}
return idStack.get();
}
} }
void TutorialManager::init() {
EventImGuiElementRendered::subscribe([](ImGuiID id, const std::array<float, 4> bb){
const auto boundingBox = ImRect(bb[0], bb[1], bb[2], bb[3]);
const auto element = hex::s_highlights->find(id);
if (element != hex::s_highlights->end()) {
hex::s_highlightDisplays->emplace_back(boundingBox, element->second);
const auto window = ImGui::GetCurrentWindow();
if (window != nullptr && window->DockNode != nullptr && window->DockNode->TabBar != nullptr)
window->DockNode->TabBar->NextSelectedTabId = window->TabId;
}
if (id != 0 && boundingBox.Contains(ImGui::GetMousePos())) {
if ((s_hoveredRect.GetArea() == 0 || boundingBox.GetArea() < s_hoveredRect.GetArea()) && s_interactiveHelpItems->contains(id)) {
s_hoveredRect = boundingBox;
s_hoveredId = id;
}
}
});
}
const std::map<std::string, TutorialManager::Tutorial>& TutorialManager::getTutorials() { const std::map<std::string, TutorialManager::Tutorial>& TutorialManager::getTutorials() {
return s_tutorials; return s_tutorials;
@@ -122,28 +72,6 @@ namespace hex {
return s_tutorials->try_emplace(unlocalizedName, Tutorial(unlocalizedName, unlocalizedDescription)).first->second; return s_tutorials->try_emplace(unlocalizedName, Tutorial(unlocalizedName, unlocalizedDescription)).first->second;
} }
void TutorialManager::startHelpHover() {
TaskManager::doLater([]{
s_helpHoverActive = true;
});
}
void TutorialManager::addInteractiveHelpText(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, UnlocalizedString text) {
auto id = calculateId(ids);
s_interactiveHelpItems->emplace(id, [text = std::move(text)]{
log::info("{}", Lang(text).get());
});
}
void TutorialManager::addInteractiveHelpLink(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, std::string link) {
auto id = calculateId(ids);
s_interactiveHelpItems->emplace(id, [link = std::move(link)]{
hex::openWebpage(link);
});
}
void TutorialManager::startTutorial(const UnlocalizedString &unlocalizedName) { void TutorialManager::startTutorial(const UnlocalizedString &unlocalizedName) {
s_currentTutorial = s_tutorials->find(unlocalizedName); s_currentTutorial = s_tutorials->find(unlocalizedName);
if (s_currentTutorial == s_tutorials->end()) if (s_currentTutorial == s_tutorials->end())
@@ -153,30 +81,6 @@ namespace hex {
} }
void TutorialManager::drawHighlights() { void TutorialManager::drawHighlights() {
if (s_helpHoverActive) {
const auto &drawList = ImGui::GetForegroundDrawList();
drawList->AddText(ImGui::GetMousePos() + scaled({ 10, -5, }), ImGui::GetColorU32(ImGuiCol_Text), "?");
const bool mouseClicked = ImGui::IsMouseClicked(ImGuiMouseButton_Left);
if (s_hoveredId != 0) {
drawList->AddRectFilled(s_hoveredRect.Min, s_hoveredRect.Max, 0x30FFFFFF);
if (mouseClicked) {
auto it = s_interactiveHelpItems->find(s_hoveredId);
if (it != s_interactiveHelpItems->end()) {
it->second();
}
}
s_hoveredId = 0;
s_hoveredRect = {};
}
if (mouseClicked || ImGui::IsKeyPressed(ImGuiKey_Escape)) {
s_helpHoverActive = false;
}
}
for (const auto &[rect, unlocalizedText] : *s_highlightDisplays) { for (const auto &[rect, unlocalizedText] : *s_highlightDisplays) {
const auto drawList = ImGui::GetForegroundDrawList(); const auto drawList = ImGui::GetForegroundDrawList();
@@ -337,13 +241,39 @@ namespace hex {
m_onAppear(); m_onAppear();
for (const auto &[text, ids] : m_highlights) { for (const auto &[text, ids] : m_highlights) {
s_highlights->emplace(calculateId(ids), text); IDStack idStack;
for (const auto &id : ids) {
std::visit(wolv::util::overloaded {
[&idStack](const Lang &id) {
idStack.add(id.get());
},
[&idStack](const auto &id) {
idStack.add(id);
}
}, id);
}
s_highlights->emplace(idStack.get(), text);
} }
} }
void TutorialManager::Tutorial::Step::removeHighlights() const { void TutorialManager::Tutorial::Step::removeHighlights() const {
for (const auto &[text, ids] : m_highlights) { for (const auto &[text, ids] : m_highlights) {
s_highlights->erase(calculateId(ids)); IDStack idStack;
for (const auto &id : ids) {
std::visit(wolv::util::overloaded {
[&idStack](const Lang &id) {
idStack.add(id.get());
},
[&idStack](const auto &id) {
idStack.add(id);
}
}, id);
}
s_highlights->erase(idStack.get());
} }
} }
@@ -439,3 +369,14 @@ namespace hex {
} }
} }
void ImGuiTestEngineHook_ItemAdd(ImGuiContext*, ImGuiID id, const ImRect& bb, const ImGuiLastItemData*) {
const auto element = hex::s_highlights->find(id);
if (element != hex::s_highlights->end()) {
hex::s_highlightDisplays->emplace_back(bb, element->second);
}
}
void ImGuiTestEngineHook_ItemInfo(ImGuiContext*, ImGuiID, const char*, ImGuiItemStatusFlags) {}
void ImGuiTestEngineHook_Log(ImGuiContext*, const char*, ...) {}
const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext*, ImGuiID) { return nullptr; }

View File

@@ -3,7 +3,6 @@
#include <hex/helpers/logger.hpp> #include <hex/helpers/logger.hpp>
#include <hex/helpers/auto_reset.hpp> #include <hex/helpers/auto_reset.hpp>
#include <hex/helpers/default_paths.hpp>
#include <wolv/io/file.hpp> #include <wolv/io/file.hpp>
@@ -26,7 +25,7 @@ namespace hex {
.builtin = false .builtin = false
}).first; }).first;
for (const auto &workspaceFolder : paths::Workspaces.write()) { for (const auto &workspaceFolder : fs::getDefaultPaths(fs::ImHexPath::Workspaces)) {
const auto workspacePath = workspaceFolder / (name + ".hexws"); const auto workspacePath = workspaceFolder / (name + ".hexws");
if (exportToFile(workspacePath)) { if (exportToFile(workspacePath)) {
s_currentWorkspace->second.path = workspacePath; s_currentWorkspace->second.path = workspacePath;
@@ -158,7 +157,7 @@ namespace hex {
void WorkspaceManager::reload() { void WorkspaceManager::reload() {
WorkspaceManager::reset(); WorkspaceManager::reset();
for (const auto &defaultPath : paths::Workspaces.read()) { for (const auto &defaultPath : fs::getDefaultPaths(fs::ImHexPath::Workspaces)) {
for (const auto &entry : std::fs::directory_iterator(defaultPath)) { for (const auto &entry : std::fs::directory_iterator(defaultPath)) {
if (!entry.is_regular_file()) { if (!entry.is_regular_file()) {
continue; continue;

View File

@@ -8,18 +8,12 @@
namespace hex::dp { namespace hex::dp {
int Node::s_idCounter = 1; int Node::s_idCounter = 1;
static std::atomic_bool s_interrupted;
Node::Node(UnlocalizedString unlocalizedTitle, std::vector<Attribute> attributes) : m_id(s_idCounter++), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_attributes(std::move(attributes)) { Node::Node(UnlocalizedString unlocalizedTitle, std::vector<Attribute> attributes) : m_id(s_idCounter++), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_attributes(std::move(attributes)) {
for (auto &attr : m_attributes) for (auto &attr : m_attributes)
attr.setParentNode(this); attr.setParentNode(this);
} }
void Node::draw() {
this->drawNode();
}
const std::vector<u8>& Node::getBufferOnInput(u32 index) { const std::vector<u8>& Node::getBufferOnInput(u32 index) {
auto attribute = this->getConnectedInputAttribute(index); auto attribute = this->getConnectedInputAttribute(index);
@@ -35,6 +29,9 @@ namespace hex::dp {
auto &outputData = attribute->getOutputData(); auto &outputData = attribute->getOutputData();
if (outputData.empty())
throwNodeError("No data available at connected attribute");
return outputData; return outputData;
} }
@@ -151,56 +148,9 @@ namespace hex::dp {
m_overlay->getData() = data; m_overlay->getData() = data;
} }
[[noreturn]] void Node::throwNodeError(const std::string &message) {
throw NodeError { this, message };
}
void Node::setAttributes(std::vector<Attribute> attributes) {
m_attributes = std::move(attributes);
for (auto &attr : m_attributes)
attr.setParentNode(this);
}
void Node::setIdCounter(int id) { void Node::setIdCounter(int id) {
if (id > s_idCounter) if (id > s_idCounter)
s_idCounter = id; s_idCounter = id;
} }
Attribute& Node::getAttribute(u32 index) {
if (index >= this->getAttributes().size())
throw std::runtime_error("Attribute index out of bounds!");
return this->getAttributes()[index];
}
Attribute *Node::getConnectedInputAttribute(u32 index) {
const auto &connectedAttribute = this->getAttribute(index).getConnectedAttributes();
if (connectedAttribute.empty())
return nullptr;
return connectedAttribute.begin()->second;
}
void Node::markInputProcessed(u32 index) {
const auto &[iter, inserted] = m_processedInputs.insert(index);
if (!inserted)
throwNodeError("Recursion detected!");
if (s_interrupted) {
s_interrupted = false;
throwNodeError("Execution interrupted!");
}
}
void Node::unmarkInputProcessed(u32 index) {
m_processedInputs.erase(index);
}
void Node::interrupt() {
s_interrupted = true;
}
} }

View File

@@ -1,10 +1,8 @@
#include <algorithm>
#include <hex/helpers/crypto.hpp> #include <hex/helpers/crypto.hpp>
#include <hex/providers/provider.hpp> #include <hex/providers/provider.hpp>
#include <wolv/utils/guards.hpp> #include <wolv/utils/guards.hpp>
#include <wolv/utils/expected.hpp>
#include <mbedtls/version.h> #include <mbedtls/version.h>
#include <mbedtls/base64.h> #include <mbedtls/base64.h>
@@ -498,8 +496,8 @@ namespace hex::crypt {
return encodeLeb128<i128>(value); return encodeLeb128<i128>(value);
} }
static wolv::util::Expected<std::vector<u8>, int> aes(mbedtls_cipher_type_t type, mbedtls_operation_t operation, const std::vector<u8> &key, static std::vector<u8> aes(mbedtls_cipher_type_t type, mbedtls_operation_t operation, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input) {
std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::span<const u8> &input) { std::vector<u8> output;
if (input.empty()) if (input.empty())
return {}; return {};
@@ -509,65 +507,38 @@ namespace hex::crypt {
mbedtls_cipher_context_t ctx; mbedtls_cipher_context_t ctx;
auto cipherInfo = mbedtls_cipher_info_from_type(type); auto cipherInfo = mbedtls_cipher_info_from_type(type);
if (cipherInfo == nullptr)
return {};
int setupResult = mbedtls_cipher_setup(&ctx, cipherInfo); mbedtls_cipher_setup(&ctx, cipherInfo);
if (setupResult != 0) mbedtls_cipher_setkey(&ctx, key.data(), key.size() * 8, operation);
return wolv::util::Unexpected(setupResult);
int setKeyResult = mbedtls_cipher_setkey(&ctx, key.data(), key.size() * 8, operation);
if (setKeyResult != 0)
return wolv::util::Unexpected(setKeyResult);
std::array<u8, 16> nonceCounter = { 0 }; std::array<u8, 16> nonceCounter = { 0 };
std::copy(nonce.begin(), nonce.end(), nonceCounter.begin());
auto mode = mbedtls_cipher_get_cipher_mode(&ctx); std::copy(iv.begin(), iv.end(), nonceCounter.begin() + 8);
// if we are in ECB mode, we don't need to set the nonce
if (mode != MBEDTLS_MODE_ECB) {
std::ranges::copy(nonce, nonceCounter.begin());
std::ranges::copy(iv, nonceCounter.begin() + 8);
}
size_t outputSize = input.size() + mbedtls_cipher_get_block_size(&ctx); size_t outputSize = input.size() + mbedtls_cipher_get_block_size(&ctx);
std::vector<u8> output(outputSize, 0x00); output.resize(outputSize, 0x00);
mbedtls_cipher_crypt(&ctx, nonceCounter.data(), nonceCounter.size(), input.data(), input.size(), output.data(), &outputSize);
int cryptResult = 0;
if (mode == MBEDTLS_MODE_ECB) {
cryptResult = mbedtls_cipher_crypt(&ctx, nullptr, 0, input.data(), input.size(), output.data(), &outputSize);
} else {
cryptResult = mbedtls_cipher_crypt(&ctx, nonceCounter.data(), nonceCounter.size(), input.data(), input.size(), output.data(), &outputSize);
}
// free regardless of the result
mbedtls_cipher_free(&ctx); mbedtls_cipher_free(&ctx);
if (cryptResult != 0) {
return wolv::util::Unexpected(cryptResult);
}
output.resize(input.size()); output.resize(input.size());
return output; return output;
} }
wolv::util::Expected<std::vector<u8>, int> aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input) { std::vector<u8> aesDecrypt(AESMode mode, KeyLength keyLength, const std::vector<u8> &key, std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::vector<u8> &input) {
switch (keyLength) { switch (keyLength) {
case KeyLength::Key128Bits: case KeyLength::Key128Bits:
if (key.size() != 128 / 8) if (key.size() != 128 / 8) return {};
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
break; break;
case KeyLength::Key192Bits: case KeyLength::Key192Bits:
if (key.size() != 192 / 8) if (key.size() != 192 / 8) return {};
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
break; break;
case KeyLength::Key256Bits: case KeyLength::Key256Bits:
if (key.size() != 256 / 8) if (key.size() != 256 / 8) return {};
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
break; break;
default: default:
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH); return {};
} }
mbedtls_cipher_type_t type; mbedtls_cipher_type_t type;
@@ -597,7 +568,7 @@ namespace hex::crypt {
type = MBEDTLS_CIPHER_AES_128_XTS; type = MBEDTLS_CIPHER_AES_128_XTS;
break; break;
default: default:
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_MODE); return {};
} }
type = mbedtls_cipher_type_t(type + u8(keyLength)); type = mbedtls_cipher_type_t(type + u8(keyLength));

View File

@@ -1,153 +0,0 @@
#include <hex/helpers/default_paths.hpp>
#include <hex/api/imhex_api.hpp>
#include <hex/api/project_file_manager.hpp>
#if defined(OS_WINDOWS)
#include <windows.h>
#include <shlobj.h>
#elif defined(OS_LINUX) || defined(OS_WEB)
#include <xdg.hpp>
# endif
namespace hex::paths {
std::vector<std::fs::path> getDataPaths(bool includeSystemFolders) {
std::vector<std::fs::path> paths;
#if defined(OS_WINDOWS)
// In the portable Windows version, we just use the executable directory
// Prevent the use of the AppData folder here
if (!ImHexApi::System::isPortableVersion()) {
PWSTR wAppDataPath = nullptr;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &wAppDataPath))) {
paths.emplace_back(wAppDataPath);
CoTaskMemFree(wAppDataPath);
}
}
#elif defined(OS_MACOS)
paths.push_back(wolv::io::fs::getApplicationSupportDirectoryPath() / "imhex");
#elif defined(OS_LINUX) || defined(OS_WEB)
paths.push_back(xdg::DataHomeDir());
auto dataDirs = xdg::DataDirs();
std::copy(dataDirs.begin(), dataDirs.end(), std::back_inserter(paths));
#endif
#if defined(OS_MACOS)
if (includeSystemFolders) {
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value()) {
paths.push_back(*executablePath);
}
}
#else
for (auto &path : paths)
path = path / "imhex";
if (ImHexApi::System::isPortableVersion() || includeSystemFolders) {
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value())
paths.push_back(executablePath->parent_path());
}
#endif
// Add additional data directories to the path
auto additionalDirs = ImHexApi::System::getAdditionalFolderPaths();
std::ranges::copy(additionalDirs, std::back_inserter(paths));
// Add the project file directory to the path, if one is loaded
if (ProjectFile::hasPath()) {
paths.push_back(ProjectFile::getPath().parent_path());
}
return paths;
}
std::vector<std::fs::path> getConfigPaths(bool includeSystemFolders) {
#if defined(OS_WINDOWS)
return getDataPaths(includeSystemFolders);
#elif defined(OS_MACOS)
return getDataPaths(includeSystemFolders);
#elif defined(OS_LINUX) || defined(OS_WEB)
std::ignore = includeSystemFolders;
return {xdg::ConfigHomeDir() / "imhex"};
#endif
}
static std::vector<std::fs::path> appendPath(std::vector<std::fs::path> paths, std::fs::path folder) {
folder.make_preferred();
for (auto &path : paths)
path = path / folder;
return paths;
}
static std::vector<std::fs::path> getPluginPaths() {
std::vector<std::fs::path> paths = getDataPaths(true);
// Add the system plugin directory to the path if one was provided at compile time
#if defined(OS_LINUX) && defined(SYSTEM_PLUGINS_LOCATION)
paths.push_back(SYSTEM_PLUGINS_LOCATION);
#endif
return paths;
}
namespace impl {
std::vector<std::fs::path> DefaultPath::read() const {
auto result = this->all();
std::erase_if(result, [](const auto &entryPath) {
return !wolv::io::fs::isDirectory(entryPath);
});
return result;
}
std::vector<std::fs::path> DefaultPath::write() const {
auto result = this->read();
std::erase_if(result, [](const auto &entryPath) {
return !hex::fs::isPathWritable(entryPath);
});
return result;
}
std::vector<std::fs::path> ConfigPath::all() const {
return appendPath(getConfigPaths(false), m_postfix);
}
std::vector<std::fs::path> DataPath::all() const {
return appendPath(getDataPaths(true), m_postfix);
}
std::vector<std::fs::path> DataPath::write() const {
auto result = appendPath(getDataPaths(false), m_postfix);
std::erase_if(result, [](const auto &entryPath) {
return !hex::fs::isPathWritable(entryPath);
});
return result;
}
std::vector<std::fs::path> PluginPath::all() const {
return appendPath(getPluginPaths(), m_postfix);
}
}
}

View File

@@ -23,7 +23,6 @@
#if defined(OS_WEB) #if defined(OS_WEB)
#include <emscripten.h> #include <emscripten.h>
#else #else
#include <GLFW/glfw3.h>
#include <nfd.hpp> #include <nfd.hpp>
#endif #endif
@@ -33,9 +32,6 @@
#include <wolv/io/fs.hpp> #include <wolv/io/fs.hpp>
#include <wolv/utils/string.hpp> #include <wolv/utils/string.hpp>
#include <fmt/format.h>
#include <fmt/xchar.h>
namespace hex::fs { namespace hex::fs {
static AutoReset<std::function<void(const std::string&)>> s_fileBrowserErrorCallback; static AutoReset<std::function<void(const std::string&)>> s_fileBrowserErrorCallback;
@@ -51,11 +47,13 @@ namespace hex::fs {
} }
#if defined(OS_WINDOWS) #if defined(OS_WINDOWS)
std::ignore = ShellExecuteW(nullptr, L"open", filePath.c_str(), nullptr, nullptr, SW_SHOWNORMAL); hex::unused(
#elif defined(OS_MACOS) ShellExecute(nullptr, "open", wolv::util::toUTF8String(filePath).c_str(), nullptr, nullptr, SW_SHOWNORMAL)
std::ignore = system(
hex::format("open {}", wolv::util::toUTF8String(filePath)).c_str()
); );
#elif defined(OS_MACOS)
hex::unused(system(
hex::format("open {}", wolv::util::toUTF8String(filePath)).c_str()
));
#elif defined(OS_LINUX) #elif defined(OS_LINUX)
executeCmd({"xdg-open", wolv::util::toUTF8String(filePath)}); executeCmd({"xdg-open", wolv::util::toUTF8String(filePath)});
#endif #endif
@@ -68,12 +66,13 @@ namespace hex::fs {
} }
#if defined(OS_WINDOWS) #if defined(OS_WINDOWS)
auto args = fmt::format(L"\"{}\"", dirPath.c_str()); hex::unused(system(
ShellExecuteW(nullptr, L"open", L"explorer.exe", args.c_str(), nullptr, SW_SHOWNORMAL); hex::format("explorer.exe {}", wolv::util::toUTF8String(dirPath)).c_str()
));
#elif defined(OS_MACOS) #elif defined(OS_MACOS)
std::ignore = system( hex::unused(system(
hex::format("open {}", wolv::util::toUTF8String(dirPath)).c_str() hex::format("open {}", wolv::util::toUTF8String(dirPath)).c_str()
); ));
#elif defined(OS_LINUX) #elif defined(OS_LINUX)
executeCmd({"xdg-open", wolv::util::toUTF8String(dirPath)}); executeCmd({"xdg-open", wolv::util::toUTF8String(dirPath)});
#endif #endif
@@ -86,15 +85,16 @@ namespace hex::fs {
} }
#if defined(OS_WINDOWS) #if defined(OS_WINDOWS)
auto args = fmt::format(L"/select,\"{}\"", selectedFilePath.c_str()); hex::unused(system(
ShellExecuteW(nullptr, L"open", L"explorer.exe", args.c_str(), nullptr, SW_SHOWNORMAL); hex::format(R"(explorer.exe /select,"{}")", wolv::util::toUTF8String(selectedFilePath)).c_str()
));
#elif defined(OS_MACOS) #elif defined(OS_MACOS)
std::ignore = system( hex::unused(system(
hex::format( hex::format(
R"(osascript -e 'tell application "Finder" to reveal POSIX file "{}"')", R"(osascript -e 'tell application "Finder" to reveal POSIX file "{}"')",
wolv::util::toUTF8String(selectedFilePath) wolv::util::toUTF8String(selectedFilePath)
).c_str() ).c_str()
); ));
system(R"(osascript -e 'tell application "Finder" to activate')"); system(R"(osascript -e 'tell application "Finder" to activate')");
#elif defined(OS_LINUX) #elif defined(OS_LINUX)
// Fallback to only opening the folder for now // Fallback to only opening the folder for now
@@ -123,13 +123,7 @@ namespace hex::fs {
// Call callback that will write the file // Call callback that will write the file
Module._fileBrowserCallback(stringToNewUTF8("/savedFiles/" + filename)); Module._fileBrowserCallback(stringToNewUTF8("/savedFiles/" + filename));
let data; let data = FS.readFile("/savedFiles/" + filename);
try {
data = FS.readFile("/savedFiles/" + filename);
} catch (e) {
console.log(e);
return;
}
const reader = Object.assign(new FileReader(), { const reader = Object.assign(new FileReader(), {
onload: () => { onload: () => {
@@ -197,7 +191,6 @@ namespace hex::fs {
else if (!validExtensions.empty()) else if (!validExtensions.empty())
path = "file." + validExtensions[0].spec; path = "file." + validExtensions[0].spec;
std::fs::create_directory("/savedFiles");
callJs_saveFile(path.filename().string().c_str()); callJs_saveFile(path.filename().string().c_str());
break; break;
} }
@@ -293,6 +286,170 @@ namespace hex::fs {
#endif #endif
std::vector<std::fs::path> getDataPaths() {
std::vector<std::fs::path> paths;
#if defined(OS_WINDOWS)
// In the portable Windows version, we just use the executable directory
// Prevent the use of the AppData folder here
if (!ImHexApi::System::isPortableVersion()) {
PWSTR wAppDataPath = nullptr;
if (SUCCEEDED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE, nullptr, &wAppDataPath))) {
paths.emplace_back(wAppDataPath);
CoTaskMemFree(wAppDataPath);
}
}
#elif defined(OS_MACOS)
paths.push_back(wolv::io::fs::getApplicationSupportDirectoryPath());
#elif defined(OS_LINUX) || defined(OS_WEB)
paths.push_back(xdg::DataHomeDir());
auto dataDirs = xdg::DataDirs();
std::copy(dataDirs.begin(), dataDirs.end(), std::back_inserter(paths));
#endif
#if defined(OS_MACOS)
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value())
paths.push_back(*executablePath);
#else
for (auto &path : paths)
path = path / "imhex";
if (auto executablePath = wolv::io::fs::getExecutablePath(); executablePath.has_value())
paths.push_back(executablePath->parent_path());
#endif
// Add additional data directories to the path
auto additionalDirs = ImHexApi::System::getAdditionalFolderPaths();
std::ranges::copy(additionalDirs, std::back_inserter(paths));
// Add the project file directory to the path, if one is loaded
if (ProjectFile::hasPath()) {
paths.push_back(ProjectFile::getPath().parent_path());
}
return paths;
}
static std::vector<std::fs::path> getConfigPaths() {
#if defined(OS_WINDOWS)
return getDataPaths();
#elif defined(OS_MACOS)
return getDataPaths();
#elif defined(OS_LINUX) || defined(OS_WEB)
return {xdg::ConfigHomeDir() / "imhex"};
#endif
}
std::vector<std::fs::path> appendPath(std::vector<std::fs::path> paths, const std::fs::path &folder) {
for (auto &path : paths)
path = path / folder;
return paths;
}
std::vector<std::fs::path> getPluginPaths() {
std::vector<std::fs::path> paths = getDataPaths();
// Add the system plugin directory to the path if one was provided at compile time
#if defined(OS_LINUX) && defined(SYSTEM_PLUGINS_LOCATION)
paths.push_back(SYSTEM_PLUGINS_LOCATION);
#endif
return paths;
}
std::vector<std::fs::path> getDefaultPaths(ImHexPath path, bool listNonExisting) {
std::vector<std::fs::path> result;
// Return the correct path based on the ImHexPath enum
switch (path) {
case ImHexPath::END:
return { };
case ImHexPath::Constants:
result = appendPath(getDataPaths(), "constants");
break;
case ImHexPath::Config:
result = appendPath(getConfigPaths(), "config");
break;
case ImHexPath::Backups:
result = appendPath(getDataPaths(), "backups");
break;
case ImHexPath::Encodings:
result = appendPath(getDataPaths(), "encodings");
break;
case ImHexPath::Logs:
result = appendPath(getDataPaths(), "logs");
break;
case ImHexPath::Plugins:
result = appendPath(getPluginPaths(), "plugins");
break;
case ImHexPath::Libraries:
result = appendPath(getPluginPaths(), "lib");
break;
case ImHexPath::Resources:
result = appendPath(getDataPaths(), "resources");
break;
case ImHexPath::Magic:
result = appendPath(getDataPaths(), "magic");
break;
case ImHexPath::Patterns:
result = appendPath(getDataPaths(), "patterns");
break;
case ImHexPath::PatternsInclude:
result = appendPath(getDataPaths(), "includes");
break;
case ImHexPath::Yara:
result = appendPath(getDataPaths(), "yara");
break;
case ImHexPath::YaraAdvancedAnalysis:
result = appendPath(getDefaultPaths(ImHexPath::Yara), "advanced_analysis");
break;
case ImHexPath::Recent:
result = appendPath(getConfigPaths(), "recent");
break;
case ImHexPath::Scripts:
result = appendPath(getDataPaths(), "scripts");
break;
case ImHexPath::Inspectors:
result = appendPath(getDefaultPaths(ImHexPath::Scripts), "inspectors");
break;
case ImHexPath::Nodes:
result = appendPath(getDefaultPaths(ImHexPath::Scripts), "nodes");
break;
case ImHexPath::Themes:
result = appendPath(getDataPaths(), "themes");
break;
case ImHexPath::Layouts:
result = appendPath(getDataPaths(), "layouts");
break;
case ImHexPath::Workspaces:
result = appendPath(getDataPaths(), "workspaces");
break;
}
// Remove all paths that don't exist if requested
if (!listNonExisting) {
std::erase_if(result, [](const auto &entryPath) {
return !wolv::io::fs::isDirectory(entryPath);
});
}
return result;
}
bool isPathWritable(const std::fs::path &path) { bool isPathWritable(const std::fs::path &path) {
constexpr static auto TestFileName = "__imhex__tmp__"; constexpr static auto TestFileName = "__imhex__tmp__";

View File

@@ -41,21 +41,17 @@ namespace hex {
} }
void HttpRequest::setProxyUrl(std::string proxy) { void HttpRequest::setProxyUrl(std::string proxy) {
std::ignore = proxy; hex::unused(proxy);
} }
void HttpRequest::setProxyState(bool state) { void HttpRequest::setProxyState(bool state) {
std::ignore = state; hex::unused(state);
} }
void HttpRequest::checkProxyErrors() { } void HttpRequest::checkProxyErrors() { }
int HttpRequest::progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow) { int HttpRequest::progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow) {
std::ignore = contents; hex::unused(contents, dlTotal, dlNow, ulTotal, ulNow);
std::ignore = dlTotal;
std::ignore = dlNow;
std::ignore = ulTotal;
std::ignore = ulNow;
return -1; return -1;
} }
} }

View File

@@ -1,15 +0,0 @@
#include <hex/api/event_manager.hpp>
#include <imgui.h>
#include <imgui_internal.h>
#include <array>
void ImGuiTestEngineHook_ItemAdd(ImGuiContext*, ImGuiID id, const ImRect& bb, const ImGuiLastItemData*) {
std::array<float, 4> boundingBox = { bb.Min.x, bb.Min.y, bb.Max.x, bb.Max.y };
hex::EventImGuiElementRendered::post(id, boundingBox);
}
void ImGuiTestEngineHook_ItemInfo(ImGuiContext*, ImGuiID, const char*, ImGuiItemStatusFlags) {}
void ImGuiTestEngineHook_Log(ImGuiContext*, const char*, ...) {}
const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext*, ImGuiID) { return nullptr; }

View File

@@ -2,10 +2,8 @@
#include <hex/api/task_manager.hpp> #include <hex/api/task_manager.hpp>
#include <hex/api/event_manager.hpp> #include <hex/api/event_manager.hpp>
#include <hex/helpers/fs.hpp> #include <hex/helpers/fs.hpp>
#include <hex/helpers/fmt.hpp> #include <hex/helpers/fmt.hpp>
#include <hex/helpers/default_paths.hpp>
#include <wolv/io/file.hpp> #include <wolv/io/file.hpp>
@@ -82,7 +80,7 @@ namespace hex::log {
void redirectToFile() { void redirectToFile() {
if (s_loggerFile.isValid()) return; if (s_loggerFile.isValid()) return;
for (const auto &path : paths::Logs.all()) { for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Logs, true)) {
wolv::io::fs::createDirectories(path); wolv::io::fs::createDirectories(path);
s_loggerFile = wolv::io::File(path / hex::format("{0:%Y%m%d_%H%M%S}.log", fmt::localtime(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()))), wolv::io::File::Mode::Create); s_loggerFile = wolv::io::File(path / hex::format("{0:%Y%m%d_%H%M%S}.log", fmt::localtime(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()))), wolv::io::File::Mode::Create);
s_loggerFile.disableBuffering(); s_loggerFile.disableBuffering();
@@ -144,12 +142,14 @@ namespace hex::log {
fmt::print(dest, "{0}", std::string(projectNameLength > MaxTagLength ? 0 : MaxTagLength - projectNameLength, ' ')); fmt::print(dest, "{0}", std::string(projectNameLength > MaxTagLength ? 0 : MaxTagLength - projectNameLength, ' '));
} }
void assertionHandler(const char* exprString, const char* file, int line) { void assertionHandler(bool expr, const char* exprString, const char* file, int line) {
log::error("Assertion failed: {} at {}:{}", exprString, file, line); if (!expr) {
log::error("Assertion failed: {} at {}:{}", exprString, file, line);
#if defined (DEBUG) #if defined (DEBUG)
std::abort(); std::abort();
#endif #endif
}
} }
namespace color { namespace color {

View File

@@ -3,7 +3,6 @@
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
#include <hex/helpers/fs.hpp> #include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp> #include <hex/helpers/logger.hpp>
#include <hex/helpers/default_paths.hpp>
#include <wolv/utils/guards.hpp> #include <wolv/utils/guards.hpp>
#include <wolv/utils/string.hpp> #include <wolv/utils/string.hpp>
@@ -30,7 +29,7 @@ namespace hex::magic {
std::string magicFiles; std::string magicFiles;
std::error_code error; std::error_code error;
for (const auto &dir : paths::Magic.read()) { 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)) {
auto path = std::fs::absolute(entry.path()); auto path = std::fs::absolute(entry.path());
@@ -65,12 +64,12 @@ namespace hex::magic {
if (magicFiles->empty()) if (magicFiles->empty())
return true; return true;
std::array<char, 1024> cwd = { }; std::array<char, 1024> cwd = { 0x00 };
if (getcwd(cwd.data(), cwd.size()) == nullptr) if (getcwd(cwd.data(), cwd.size()) == nullptr)
return false; return false;
std::optional<std::fs::path> magicFolder; std::optional<std::fs::path> magicFolder;
for (const auto &dir : paths::Magic.write()) { for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
if (std::fs::exists(dir) && fs::isPathWritable(dir)) { if (std::fs::exists(dir) && fs::isPathWritable(dir)) {
magicFolder = dir; magicFolder = dir;
break; break;

View File

@@ -28,9 +28,7 @@ namespace hex {
void close() override { } void close() override { }
void readRaw(u64 offset, void *buffer, size_t size) override { void readRaw(u64 offset, void *buffer, size_t size) override {
std::ignore = offset; hex::unused(offset, buffer, size);
std::ignore = buffer;
std::ignore = size;
} }
void writeRaw(u64 offset, const void *buffer, size_t size) override { void writeRaw(u64 offset, const void *buffer, size_t size) override {
@@ -46,7 +44,7 @@ namespace hex {
} }
void resizeRaw(u64 newSize) override { void resizeRaw(u64 newSize) override {
std::ignore = newSize; hex::unused(newSize);
} }
void insertRaw(u64 offset, u64 size) override { void insertRaw(u64 offset, u64 size) override {

View File

@@ -1,118 +0,0 @@
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/semantic_version.hpp>
#include <wolv/utils/string.hpp>
namespace hex {
SemanticVersion::SemanticVersion(const char *version) : SemanticVersion(std::string(version)) {
}
SemanticVersion::SemanticVersion(std::string_view version) : SemanticVersion(std::string(version.begin(), version.end())) {
}
SemanticVersion::SemanticVersion(std::string version) {
if (version.empty())
return;
if (version.starts_with("v"))
version = version.substr(1);
m_parts = wolv::util::splitString(version, ".");
if (m_parts.size() != 3 && m_parts.size() != 4) {
m_parts.clear();
return;
}
if (m_parts.back().contains("-")) {
auto buildTypeParts = wolv::util::splitString(m_parts.back(), "-");
if (buildTypeParts.size() != 2) {
m_parts.clear();
return;
}
m_parts.back() = buildTypeParts[0];
m_buildType = buildTypeParts[1];
}
}
u32 SemanticVersion::major() const {
if (!isValid()) return 0;
try {
return std::stoul(m_parts[0]);
} catch (...) {
return 0;
}
}
u32 SemanticVersion::minor() const {
if (!isValid()) return 0;
try {
return std::stoul(m_parts[1]);
} catch (...) {
return 0;
}
}
u32 SemanticVersion::patch() const {
if (!isValid()) return 0;
try {
return std::stoul(m_parts[2]);
} catch (...) {
return 0;
}
}
bool SemanticVersion::nightly() const {
if (!isValid()) return false;
return m_parts.size() == 4 && m_parts[3] == "WIP";
}
const std::string& SemanticVersion::buildType() const {
return m_buildType;
}
bool SemanticVersion::isValid() const {
return !m_parts.empty();
}
bool SemanticVersion::operator==(const SemanticVersion& other) const {
return this->m_parts == other.m_parts;
}
std::strong_ordering SemanticVersion::operator<=>(const SemanticVersion &other) const {
if (*this == other)
return std::strong_ordering::equivalent;
if (this->major() > other.major())
return std::strong_ordering::greater;
if (this->minor() > other.minor())
return std::strong_ordering::greater;
if (this->patch() > other.patch())
return std::strong_ordering::greater;
if (!this->nightly() && other.nightly())
return std::strong_ordering::greater;
return std::strong_ordering::less;
}
std::string SemanticVersion::get(bool withBuildType) const {
if (!isValid()) return "";
auto result = wolv::util::combineStrings(m_parts, ".");
if (withBuildType && !m_buildType.empty())
result += hex::format("-{}", m_buildType);
return result;
}
}

View File

@@ -336,13 +336,13 @@ namespace hex {
void startProgram(const std::string &command) { void startProgram(const std::string &command) {
#if defined(OS_WINDOWS) #if defined(OS_WINDOWS)
std::ignore = system(hex::format("start {0}", command).c_str()); hex::unused(system(hex::format("start {0}", command).c_str()));
#elif defined(OS_MACOS) #elif defined(OS_MACOS)
std::ignore = system(hex::format("open {0}", command).c_str()); hex::unused(system(hex::format("open {0}", command).c_str()));
#elif defined(OS_LINUX) #elif defined(OS_LINUX)
executeCmd({"xdg-open", command}); executeCmd({"xdg-open", command});
#elif defined(OS_WEB) #elif defined(OS_WEB)
std::ignore = command; hex::unused(command);
#endif #endif
} }
@@ -355,7 +355,7 @@ namespace hex {
url = "https://" + url; url = "https://" + url;
#if defined(OS_WINDOWS) #if defined(OS_WINDOWS)
ShellExecuteA(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)
openWebpageMacos(url.c_str()); openWebpageMacos(url.c_str());
#elif defined(OS_LINUX) #elif defined(OS_LINUX)
@@ -679,44 +679,6 @@ namespace hex {
return value; return value;
} }
[[nodiscard]] std::string limitStringLength(const std::string &string, size_t maxLength) {
// If the string is shorter than the max length, return it as is
if (string.size() < maxLength)
return string;
// If the string is longer than the max length, find the last space before the max length
auto it = string.begin() + maxLength;
while (it != string.begin() && !std::isspace(*it)) --it;
// If there's no space before the max length, just cut the string
if (it == string.begin()) {
it = string.begin() + maxLength / 2;
// Try to find a UTF-8 character boundary
while (it != string.begin() && (*it & 0xC0) == 0x80) --it;
}
// If we still didn't find a valid boundary, just return the string as is
if (it == string.begin())
return string;
auto result = std::string(string.begin(), it) + "";
// If the string is longer than the max length, find the last space before the max length
it = string.end() - 1 - maxLength / 2;
while (it != string.end() && !std::isspace(*it)) ++it;
// If there's no space before the max length, just cut the string
if (it == string.end()) {
it = string.end() - 1 - maxLength / 2;
// Try to find a UTF-8 character boundary
while (it != string.end() && (*it & 0xC0) == 0x80) ++it;
}
return result + std::string(it, string.end());
}
static std::optional<std::fs::path> s_fileToOpen; static std::optional<std::fs::path> s_fileToOpen;
extern "C" void openFile(const char *path) { extern "C" void openFile(const char *path) {
log::info("Opening file: {0}", path); log::info("Opening file: {0}", path);
@@ -839,7 +801,7 @@ namespace hex {
return dlopen(info.dli_fname, RTLD_LAZY); return dlopen(info.dli_fname, RTLD_LAZY);
#else #else
std::ignore = symbol; hex::unused(symbol);
return nullptr; return nullptr;
#endif #endif
} }

View File

@@ -118,12 +118,6 @@
return cocoaWindow.inLiveResize; return cocoaWindow.inLiveResize;
} }
void macosMarkContentEdited(GLFWwindow *window, bool edited) {
NSWindow* cocoaWindow = glfwGetCocoaWindow(window);
[cocoaWindow setDocumentEdited:edited];
}
@interface HexDocument : NSDocument @interface HexDocument : NSDocument
@end @end

View File

@@ -104,8 +104,7 @@ namespace hex::prv {
void Provider::insertRaw(u64 offset, u64 size) { void Provider::insertRaw(u64 offset, u64 size) {
auto oldSize = this->getActualSize(); auto oldSize = this->getActualSize();
auto newSize = oldSize + size; this->resizeRaw(oldSize + size);
this->resizeRaw(newSize);
std::vector<u8> buffer(0x1000); std::vector<u8> buffer(0x1000);
const std::vector<u8> zeroBuffer(0x1000); const std::vector<u8> zeroBuffer(0x1000);
@@ -117,7 +116,7 @@ namespace hex::prv {
position -= readSize; position -= readSize;
this->readRaw(position, buffer.data(), readSize); this->readRaw(position, buffer.data(), readSize);
this->writeRaw(position, zeroBuffer.data(), newSize - oldSize); this->writeRaw(position, zeroBuffer.data(), readSize);
this->writeRaw(position + size, buffer.data(), readSize); this->writeRaw(position + size, buffer.data(), readSize);
} }
} }

View File

@@ -20,7 +20,6 @@ namespace hex::subcommands {
} }
} }
} }
return std::nullopt; return std::nullopt;
} }
@@ -28,8 +27,7 @@ namespace hex::subcommands {
// If no arguments, do not even try to process arguments // If no arguments, do not even try to process arguments
// (important because this function will exit ImHex if an instance is already opened, // (important because this function will exit ImHex if an instance is already opened,
// and we don't want that if no arguments were provided) // and we don't want that if no arguments were provided)
if (args.empty()) if (args.empty()) return;
return;
std::vector<std::pair<SubCommand, std::vector<std::string>>> subCommands; std::vector<std::pair<SubCommand, std::vector<std::string>>> subCommands;
@@ -78,18 +76,18 @@ namespace hex::subcommands {
} }
// Save last command to run // Save last command to run
if (currentSubCommand.has_value()) { if (currentSubCommand) {
subCommands.emplace_back(*currentSubCommand, currentSubCommandArgs); subCommands.emplace_back(*currentSubCommand, currentSubCommandArgs);
} }
// Run the subcommands // Run the subcommands
for (auto &[subcommand, args] : subCommands) { for (auto& subCommandPair : subCommands) {
subcommand.callback(args); subCommandPair.first.callback(subCommandPair.second);
} }
// Exit the process if it's not the main instance (the commands have been forwarded to another instance) // Exit the process if its not the main instance (the commands have been forwarded to another instance)
if (!ImHexApi::System::isMainInstance()) { if (!ImHexApi::System::isMainInstance()) {
std::exit(0); exit(0);
} }
} }
@@ -97,14 +95,11 @@ namespace hex::subcommands {
log::debug("Forwarding subcommand {} (maybe to us)", cmdName); log::debug("Forwarding subcommand {} (maybe to us)", cmdName);
std::vector<u8> data; std::vector<u8> data;
if (!args.empty()) { for (const auto &arg: args) {
for (const auto &arg: args) { data.insert(data.end(), arg.begin(), arg.end());
data.insert(data.end(), arg.begin(), arg.end()); data.push_back('\0');
data.push_back('\0');
}
data.pop_back();
} }
data.erase(data.end()-1);
SendMessageToMainInstance::post(hex::format("command/{}", cmdName), data); SendMessageToMainInstance::post(hex::format("command/{}", cmdName), data);
} }

View File

@@ -165,7 +165,7 @@ namespace ImGuiExt {
STBI_FREE(imageData); STBI_FREE(imageData);
result.m_textureId = texture; result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
return result; return result;
} }
@@ -189,14 +189,14 @@ namespace ImGuiExt {
STBI_FREE(imageData); STBI_FREE(imageData);
result.m_textureId = texture; result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
return result; return result;
} }
Texture Texture::fromGLTexture(unsigned int glTexture, int width, int height) { Texture Texture::fromGLTexture(unsigned int glTexture, int width, int height) {
Texture texture; Texture texture;
texture.m_textureId = glTexture; texture.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(glTexture));
texture.m_width = width; texture.m_width = width;
texture.m_height = height; texture.m_height = height;
@@ -216,7 +216,7 @@ namespace ImGuiExt {
Texture result; Texture result;
result.m_width = width; result.m_width = width;
result.m_height = height; result.m_height = height;
result.m_textureId = texture; result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
return result; return result;
} }
@@ -230,7 +230,7 @@ namespace ImGuiExt {
Texture result; Texture result;
result.m_width = bitmap.width(); result.m_width = bitmap.width();
result.m_height = bitmap.height(); result.m_height = bitmap.height();
result.m_textureId = texture; result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
return result; return result;
} }
@@ -249,46 +249,42 @@ namespace ImGuiExt {
Texture result; Texture result;
result.m_width = bitmap.width(); result.m_width = bitmap.width();
result.m_height = bitmap.height(); result.m_height = bitmap.height();
result.m_textureId = texture; result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
return result; return result;
} }
Texture::Texture(Texture&& other) noexcept { Texture::Texture(Texture&& other) noexcept {
if (m_textureId != 0) if (m_textureId != nullptr)
glDeleteTextures(1, reinterpret_cast<GLuint*>(&m_textureId)); glDeleteTextures(1, reinterpret_cast<GLuint*>(&m_textureId));
m_textureId = other.m_textureId; m_textureId = other.m_textureId;
m_width = other.m_width; m_width = other.m_width;
m_height = other.m_height; m_height = other.m_height;
other.m_textureId = 0; other.m_textureId = nullptr;
} }
Texture& Texture::operator=(Texture&& other) noexcept { Texture& Texture::operator=(Texture&& other) noexcept {
if (m_textureId != 0) if (m_textureId != nullptr)
glDeleteTextures(1, reinterpret_cast<GLuint*>(&m_textureId)); glDeleteTextures(1, reinterpret_cast<GLuint*>(&m_textureId));
m_textureId = other.m_textureId; m_textureId = other.m_textureId;
m_width = other.m_width; m_width = other.m_width;
m_height = other.m_height; m_height = other.m_height;
other.m_textureId = 0; other.m_textureId = nullptr;
return *this; return *this;
} }
Texture::~Texture() { Texture::~Texture() {
if (m_textureId == 0) if (m_textureId == nullptr)
return; return;
glDeleteTextures(1, reinterpret_cast<GLuint*>(&m_textureId)); glDeleteTextures(1, reinterpret_cast<GLuint*>(&m_textureId));
} }
float GetTextWrapPos() {
return GImGui->CurrentWindow->DC.TextWrapPos;
}
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data) { int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data) {
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);
@@ -317,6 +313,8 @@ namespace ImGuiExt {
if (!ItemAdd(bb, id)) if (!ItemAdd(bb, id))
return false; return false;
if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat)
flags |= ImGuiButtonFlags_Repeat;
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
@@ -348,6 +346,8 @@ namespace ImGuiExt {
const ImRect bb(pos, pos + size); const ImRect bb(pos, pos + size);
ItemAdd(bb, id); ItemAdd(bb, id);
if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat)
flags |= ImGuiButtonFlags_Repeat;
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
@@ -383,6 +383,8 @@ namespace ImGuiExt {
if (!ItemAdd(bb, id)) if (!ItemAdd(bb, id))
return false; return false;
if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat)
flags |= ImGuiButtonFlags_Repeat;
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
@@ -419,6 +421,8 @@ namespace ImGuiExt {
if (!ItemAdd(bb, id)) if (!ItemAdd(bb, id))
return false; return false;
if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat)
flags |= ImGuiButtonFlags_Repeat;
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
@@ -428,7 +432,7 @@ namespace ImGuiExt {
// Render // Render
const ImU32 col = GetCustomColorU32((held && hovered) ? ImGuiCustomCol_DescButtonActive : hovered ? ImGuiCustomCol_DescButtonHovered const ImU32 col = GetCustomColorU32((held && hovered) ? ImGuiCustomCol_DescButtonActive : hovered ? ImGuiCustomCol_DescButtonHovered
: ImGuiCustomCol_DescButton); : ImGuiCustomCol_DescButton);
RenderNavCursor(bb, id); RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_ButtonActive)); PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_ButtonActive));
RenderTextClipped(bb.Min + style.FramePadding * 2, bb.Max - style.FramePadding, label, nullptr, nullptr); RenderTextClipped(bb.Min + style.FramePadding * 2, bb.Max - style.FramePadding, label, nullptr, nullptr);
@@ -470,6 +474,8 @@ namespace ImGuiExt {
if (!ItemAdd(bb, id)) if (!ItemAdd(bb, id))
return false; return false;
if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat)
flags |= ImGuiButtonFlags_Repeat;
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags); bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
@@ -479,7 +485,7 @@ namespace ImGuiExt {
// Render // Render
const ImU32 col = GetCustomColorU32((held && hovered) ? ImGuiCustomCol_DescButtonActive : hovered ? ImGuiCustomCol_DescButtonHovered const ImU32 col = GetCustomColorU32((held && hovered) ? ImGuiCustomCol_DescButtonActive : hovered ? ImGuiCustomCol_DescButtonHovered
: ImGuiCustomCol_DescButton); : ImGuiCustomCol_DescButton);
RenderNavCursor(bb, id); RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding); RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_ButtonActive)); PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_ButtonActive));
RenderTextClipped(bb.Min + style.FramePadding * 2, bb.Max - style.FramePadding, label, nullptr, nullptr); RenderTextClipped(bb.Min + style.FramePadding * 2, bb.Max - style.FramePadding, label, nullptr, nullptr);
@@ -508,17 +514,15 @@ namespace ImGuiExt {
PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0)); PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0)); PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0));
PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0)); PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0));
PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0)); PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, GetStyle().FramePadding.y));
PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0F); PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0F);
PushStyleColor(ImGuiCol_Text, iconColor); PushStyleColor(ImGuiCol_Text, iconColor);
ImGui::PushID(text);
Button(icon); Button(icon);
ImGui::PopID();
PopStyleColor(); PopStyleColor();
if (IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) { if (IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
SetNextWindowSizeConstraints(ImVec2(GetTextLineHeight() * 25, 0), ImVec2(GetTextLineHeight() * 35, FLT_MAX)); SetNextWindowSizeConstraints(ImVec2(GetTextLineHeight() * 25, 0), ImVec2(GetTextLineHeight() * 25, FLT_MAX));
BeginTooltip(); BeginTooltip();
TextFormattedWrapped("{}", text); TextFormattedWrapped("{}", text);
EndTooltip(); EndTooltip();
@@ -542,34 +546,6 @@ namespace ImGuiExt {
PopStyleColor(); PopStyleColor();
} }
void UnderwavedText(const char *label, ImColor textColor, ImColor lineColor, const ImVec2 &size_arg) {
ImGuiWindow *window = GetCurrentWindow();
std::string labelStr(label);
for (char letter : labelStr) {
std::string letterStr(1, letter);
const ImVec2 label_size = CalcTextSize(letterStr.c_str(), nullptr, true);
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
ImVec2 pos = window->DC.CursorPos;
float lineWidth = size.x / 3.0f;
float halfLineW = lineWidth / 2.0f;
float lineY = pos.y + size.y;
ImVec2 initial = ImVec2(pos.x, lineY);
ImVec2 pos1 = ImVec2(pos.x + lineWidth, lineY - 2.0f);
ImVec2 pos2 = ImVec2(pos.x + lineWidth + halfLineW, lineY);
ImVec2 pos3 = ImVec2(pos.x + lineWidth * 2 + halfLineW, lineY - 2.0f);
ImVec2 pos4 = ImVec2(pos.x + lineWidth * 3, lineY - 1.0f);
PushStyleColor(ImGuiCol_Text, ImU32(textColor));
TextEx(letterStr.c_str(), nullptr, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
GetWindowDrawList()->AddLine(initial, pos1, ImU32(lineColor),0.4f);
GetWindowDrawList()->AddLine(pos1, pos2, ImU32(lineColor),0.3f);
GetWindowDrawList()->AddLine(pos2, pos3, ImU32(lineColor),0.4f);
GetWindowDrawList()->AddLine(pos3, pos4, ImU32(lineColor),0.3f);
PopStyleColor();
window->DC.CursorPos = ImVec2(pos.x + size.x, pos.y);
}
}
void TextSpinner(const char *label) { void TextSpinner(const char *label) {
Text("[%c] %s", "|/-\\"[ImU32(GetTime() * 20) % 4], label); Text("[%c] %s", "|/-\\"[ImU32(GetTime() * 20) % 4], label);
} }
@@ -595,27 +571,15 @@ namespace ImGuiExt {
ImGuiID hoveredID = GetHoveredID(); ImGuiID hoveredID = GetHoveredID();
bool result = false; bool result = false;
if (IsItemHovered(ImGuiHoveredFlags_DelayNormal) && (currTime - lastMoveTime) >= 0.5 && hoveredID == lastHoveredID) { if (IsItemHovered() && (currTime - lastMoveTime) >= 0.5 && hoveredID == lastHoveredID) {
if (!std::string_view(text).empty()) { if (!std::string_view(text).empty()) {
const auto textWidth = CalcTextSize(text).x; const auto width = 300 * hex::ImHexApi::System::getGlobalScale();
ImGui::SetNextWindowSizeConstraints(ImVec2(width, 0), ImVec2(width, FLT_MAX));
const auto maxWidth = 300 * hex::ImHexApi::System::getGlobalScale();
const bool wrapping = textWidth > maxWidth;
if (wrapping)
ImGui::SetNextWindowSizeConstraints(ImVec2(maxWidth, 0), ImVec2(maxWidth, FLT_MAX));
else
ImGui::SetNextWindowSize(ImVec2(textWidth + GetStyle().WindowPadding.x * 2, 0));
if (BeginTooltip()) { if (BeginTooltip()) {
if (isSeparator) if (isSeparator)
SeparatorText(text); SeparatorText(text);
else { else
if (wrapping) TextFormattedWrapped("{}", text);
TextFormattedWrapped("{}", text);
else
TextFormatted("{}", text);
}
EndTooltip(); EndTooltip();
} }
@@ -762,7 +726,7 @@ namespace ImGuiExt {
// Render // Render
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered
: ImGuiCol_Button); : ImGuiCol_Button);
RenderNavCursor(bb, id); RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding); RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, nullptr, &label_size, style.ButtonTextAlign, &bb); RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, nullptr, &label_size, style.ButtonTextAlign, &bb);
@@ -788,9 +752,7 @@ namespace ImGuiExt {
ImVec2 pos = window->DC.CursorPos; ImVec2 pos = window->DC.CursorPos;
ImVec2 size = CalcItemSize(ImVec2(1, 1) * GetCurrentWindow()->MenuBarHeight, label_size.x + style.FramePadding.x * 2.0F, label_size.y + style.FramePadding.y * 2.0F); ImVec2 size = CalcItemSize(ImVec2(1, 1) * GetCurrentWindow()->MenuBarHeight(), label_size.x + style.FramePadding.x * 2.0F, label_size.y + style.FramePadding.y * 2.0F);
ImVec2 padding = (size - label_size) / 2;
const ImRect bb(pos, pos + size); const ImRect bb(pos, pos + size);
ItemSize(size, style.FramePadding.y); ItemSize(size, style.FramePadding.y);
@@ -805,9 +767,9 @@ namespace ImGuiExt {
// Render // Render
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered
: ImGuiCol_MenuBarBg); : ImGuiCol_MenuBarBg);
RenderNavCursor(bb, id); RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding); RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
RenderTextClipped(bb.Min + padding, bb.Max - padding, symbol, nullptr, &size, style.ButtonTextAlign, &bb); RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
PopStyleColor(); PopStyleColor();
@@ -848,7 +810,7 @@ namespace ImGuiExt {
// Render // Render
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered
: ImGuiCol_Button); : ImGuiCol_Button);
RenderNavCursor(bb, id); RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding); RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1.3, 1), bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb); RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1.3, 1), bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
@@ -877,7 +839,7 @@ namespace ImGuiExt {
char buf[64]; char buf[64];
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), type, value, format); DataTypeFormatString(buf, IM_ARRAYSIZE(buf), type, value, format);
RenderNavCursor(frame_bb, id); RenderNavHighlight(frame_bb, id);
RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
PushStyleVar(ImGuiStyleVar_Alpha, 0.6F); PushStyleVar(ImGuiStyleVar_Alpha, 0.6F);
@@ -901,7 +863,7 @@ namespace ImGuiExt {
} }
bool InputHexadecimal(const char *label, u32 *value, ImGuiInputTextFlags flags) { bool InputHexadecimal(const char *label, u32 *value, ImGuiInputTextFlags flags) {
return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U32, "%X", flags | ImGuiInputTextFlags_CharsHexadecimal); return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U32, "%lX", flags | ImGuiInputTextFlags_CharsHexadecimal);
} }
bool InputHexadecimal(const char *label, u64 *value, ImGuiInputTextFlags flags) { bool InputHexadecimal(const char *label, u64 *value, ImGuiInputTextFlags flags) {
@@ -971,14 +933,11 @@ namespace ImGuiExt {
} }
bool InputTextIcon(const char *label, const char *icon, std::string &buffer, ImGuiInputTextFlags flags) { bool InputTextIcon(const char *label, const char *icon, std::string &buffer, ImGuiInputTextFlags flags) {
return InputTextIconHint(label, icon, nullptr, buffer, flags);
}
bool InputTextIconHint(const char* label, const char *icon, const char *hint, std::string &buffer, ImGuiInputTextFlags flags) {
auto window = GetCurrentWindow(); auto window = GetCurrentWindow();
const ImGuiID id = window->GetID(label); const ImGuiID id = window->GetID(label);
const ImGuiStyle &style = GImGui->Style; const ImGuiStyle &style = GImGui->Style;
const ImVec2 label_size = CalcTextSize(label, nullptr, true); const ImVec2 label_size = CalcTextSize(label, nullptr, true);
const ImVec2 icon_frame_size = CalcTextSize(icon) + style.FramePadding * 2.0F; const ImVec2 icon_frame_size = CalcTextSize(icon) + style.FramePadding * 2.0F;
const ImVec2 frame_size = CalcItemSize(ImVec2(0, 0), icon_frame_size.x, label_size.y + style.FramePadding.y * 2.0F); const ImVec2 frame_size = CalcItemSize(ImVec2(0, 0), icon_frame_size.x, label_size.y + style.FramePadding.y * 2.0F);
@@ -986,14 +945,12 @@ namespace ImGuiExt {
SetCursorPosX(GetCursorPosX() + frame_size.x); SetCursorPosX(GetCursorPosX() + frame_size.x);
float width_adjustment = window->DC.ItemWidth < 0 ? 0 : icon_frame_size.x; bool value_changed = InputTextEx(label, nullptr, buffer.data(), buffer.size() + 1, ImVec2(CalcItemWidth() - icon_frame_size.x, label_size.y + style.FramePadding.y * 2.0F), ImGuiInputTextFlags_CallbackResize | flags, UpdateStringSizeCallback, &buffer);
bool value_changed = InputTextEx(label, hint, buffer.data(), buffer.size() + 1, ImVec2(CalcItemWidth() - width_adjustment, label_size.y + style.FramePadding.y * 2.0F), ImGuiInputTextFlags_CallbackResize | flags, UpdateStringSizeCallback, &buffer);
if (value_changed) if (value_changed)
MarkItemEdited(GImGui->LastItemData.ID); MarkItemEdited(GImGui->LastItemData.ID);
RenderNavCursor(frame_bb, id); RenderNavHighlight(frame_bb, id);
RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding); RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
RenderFrame(frame_bb.Min, frame_bb.Min + icon_frame_size, GetColorU32(ImGuiCol_TableBorderStrong), true, style.FrameRounding); RenderFrame(frame_bb.Min, frame_bb.Min + icon_frame_size, GetColorU32(ImGuiCol_TableBorderStrong), true, style.FrameRounding);
@@ -1019,6 +976,7 @@ namespace ImGuiExt {
if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0) if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0)
flags |= ImGuiInputTextFlags_CharsDecimal; flags |= ImGuiInputTextFlags_CharsDecimal;
flags |= ImGuiInputTextFlags_AutoSelectAll; flags |= ImGuiInputTextFlags_AutoSelectAll;
flags |= ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselves by comparing the actual data rather than the string.
if (ImGui::InputText(label, buf, IM_ARRAYSIZE(buf), flags, callback, user_data)) if (ImGui::InputText(label, buf, IM_ARRAYSIZE(buf), flags, callback, user_data))
value_changed = DataTypeApplyFromText(buf, data_type, p_data, format); value_changed = DataTypeApplyFromText(buf, data_type, p_data, format);
@@ -1068,7 +1026,7 @@ namespace ImGuiExt {
} }
const ImRect check_bb(pos, pos + size); const ImRect check_bb(pos, pos + size);
RenderNavCursor(total_bb, id); RenderNavHighlight(total_bb, id);
RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); 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"); RenderText(check_bb.Min + style.FramePadding, *v ? "1" : "0");
@@ -1171,19 +1129,17 @@ namespace ImGuiExt {
return toggled; return toggled;
} }
void TextOverlay(const char *text, ImVec2 pos, float maxWidth) { void TextOverlay(const char *text, ImVec2 pos) {
const auto textSize = CalcTextSize(text, nullptr, false, maxWidth); const auto textSize = CalcTextSize(text);
const auto textPos = pos - textSize / 2; const auto textPos = pos - textSize / 2;
const auto margin = GetStyle().FramePadding * 2; const auto margin = GetStyle().FramePadding * 2;
const auto textRect = ImRect(textPos - margin, textPos + textSize + margin); const auto textRect = ImRect(textPos - margin, textPos + textSize + margin);
auto drawList = GetWindowDrawList(); auto drawList = GetForegroundDrawList();
drawList->AddDrawCmd();
drawList->AddRectFilled(textRect.Min, textRect.Max, GetColorU32(ImGuiCol_WindowBg) | 0xFF000000); drawList->AddRectFilled(textRect.Min, textRect.Max, GetColorU32(ImGuiCol_WindowBg) | 0xFF000000);
drawList->AddRect(textRect.Min, textRect.Max, GetColorU32(ImGuiCol_Border)); drawList->AddRect(textRect.Min, textRect.Max, GetColorU32(ImGuiCol_Border));
drawList->AddDrawCmd(); drawList->AddText(textPos, GetColorU32(ImGuiCol_Text), text);
drawList->AddText(nullptr, 0.0F, textPos, GetColorU32(ImGuiCol_Text), text, nullptr, maxWidth);
} }
bool BeginBox() { bool BeginBox() {
@@ -1200,37 +1156,17 @@ namespace ImGuiExt {
PopStyleVar(); PopStyleVar();
} }
bool BeginSubWindow(const char *label, bool *collapsed, ImVec2 size, ImGuiChildFlags flags) { void BeginSubWindow(const char *label, ImVec2 size, ImGuiChildFlags flags) {
const bool hasMenuBar = !std::string_view(label).empty(); const bool hasMenuBar = !std::string_view(label).empty();
bool result = false;
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0F); ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0F);
if (ImGui::BeginChild(hex::format("{}##SubWindow", label).c_str(), size, ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY | flags, hasMenuBar ? ImGuiWindowFlags_MenuBar : ImGuiWindowFlags_None)) { if (ImGui::BeginChild(hex::format("{}##SubWindow", label).c_str(), size, ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY | flags, hasMenuBar ? ImGuiWindowFlags_MenuBar : ImGuiWindowFlags_None)) {
result = true;
if (hasMenuBar && ImGui::BeginMenuBar()) { if (hasMenuBar && ImGui::BeginMenuBar()) {
if (collapsed == nullptr) ImGui::TextUnformatted(label);
ImGui::TextUnformatted(label);
else {
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, ImGui::GetStyle().FramePadding.y));
ImGui::PushStyleColor(ImGuiCol_Button, 0x00);
if (ImGui::Button(label))
*collapsed = !*collapsed;
ImGui::PopStyleColor();
ImGui::PopStyleVar();
}
ImGui::EndMenuBar(); ImGui::EndMenuBar();
} }
if (collapsed != nullptr && *collapsed) {
ImGui::SetCursorPosY(ImGui::GetCursorPosY() - (ImGui::GetStyle().FramePadding.y * 2));
ImGuiExt::TextFormattedDisabled("...");
result = false;
}
} }
ImGui::PopStyleVar(); ImGui::PopStyleVar();
return result;
} }
void EndSubWindow() { void EndSubWindow() {

View File

@@ -71,7 +71,7 @@ namespace hex {
} }
std::string View::toWindowName(const UnlocalizedString &unlocalizedName) { std::string View::toWindowName(const UnlocalizedString &unlocalizedName) {
return fmt::format("{}###{}", Lang(unlocalizedName), unlocalizedName.get()); return Lang(unlocalizedName) + "###" + unlocalizedName.get();
} }
} }

View File

@@ -1,3 +0,0 @@
project(boost)
add_subdirectory(regex)

Some files were not shown because too many files have changed in this diff Show More