mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-28 07:47:03 -05:00
Compare commits
4 Commits
releases/v
...
python_scr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
16b91eb715 | ||
|
|
8b9d09aa97 | ||
|
|
ccb78246ab | ||
|
|
3144d79605 |
5
.github/codecov.yml
vendored
5
.github/codecov.yml
vendored
@@ -1,5 +0,0 @@
|
||||
comment: false
|
||||
ignore:
|
||||
- "lib/third_party" # Third party libraries should be ignored
|
||||
- "lib/external" # Our own libraries should be checked in their own repositories
|
||||
- "tests" # https://about.codecov.io/blog/should-i-include-test-files-in-code-coverage-calculations/
|
||||
7
.github/workflows/analysis.yml
vendored
7
.github/workflows/analysis.yml
vendored
@@ -8,7 +8,7 @@ on:
|
||||
jobs:
|
||||
codeql:
|
||||
name: 🐛 CodeQL
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
set -x
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-14 CXX=g++-14 cmake \
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
@@ -57,9 +57,8 @@ jobs:
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-G Ninja \
|
||||
..
|
||||
ninja install
|
||||
make -j 4 install
|
||||
|
||||
- name: 🗯️ Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
244
.github/workflows/build.yml
vendored
244
.github/workflows/build.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'releases/**'
|
||||
- 'tests/**'
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -64,7 +63,7 @@ jobs:
|
||||
cd build
|
||||
|
||||
cmake -G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DIMHEX_GENERATE_PACKAGE=ON \
|
||||
-DIMHEX_USE_DEFAULT_BUILD_SETTINGS=ON \
|
||||
@@ -76,13 +75,13 @@ jobs:
|
||||
-DIMHEX_REPLACE_DWARF_WITH_PDB=ON \
|
||||
-DDOTNET_EXECUTABLE="C:/Program Files/dotnet/dotnet.exe" \
|
||||
..
|
||||
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
cd build
|
||||
ninja install
|
||||
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
|
||||
|
||||
@@ -107,7 +106,7 @@ jobs:
|
||||
run: |
|
||||
set -x
|
||||
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
|
||||
mv opengl32.dll build/install
|
||||
|
||||
@@ -119,62 +118,9 @@ jobs:
|
||||
path: |
|
||||
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:
|
||||
runs-on: macos-13
|
||||
runs-on: macos-12
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -185,7 +131,7 @@ jobs:
|
||||
- suffix: ""
|
||||
custom_glfw: false
|
||||
|
||||
name: 🍎 macOS 13${{ matrix.suffix }}
|
||||
name: 🍎 macOS 12.0${{matrix.suffix}}
|
||||
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
@@ -206,15 +152,15 @@ jobs:
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
brew reinstall python --quiet || true
|
||||
brew link --overwrite --quiet python || true
|
||||
brew bundle --no-lock --quiet --file dist/Brewfile || true
|
||||
set -x
|
||||
brew reinstall python || brew link --overwrite python
|
||||
brew bundle --no-lock --file dist/Brewfile
|
||||
rm -rf /usr/local/Cellar/capstone
|
||||
|
||||
- name: ⬇️ Install classic glfw
|
||||
if: ${{! matrix.custom_glfw }}
|
||||
if: ${{! matrix.custom_glfw}}
|
||||
run: |
|
||||
brew install --quiet glfw || true
|
||||
brew install glfw
|
||||
|
||||
- name: ⬇️ Install .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
@@ -222,15 +168,15 @@ jobs:
|
||||
dotnet-version: '8.0.100'
|
||||
|
||||
- name: 🧰 Checkout glfw
|
||||
if: ${{ matrix.custom_glfw }}
|
||||
if: ${{matrix.custom_glfw}}
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: glfw/glfw
|
||||
path: glfw
|
||||
|
||||
|
||||
# GLFW custom build (to allow software rendering)
|
||||
- name: ⬇️ Patch and install custom glfw
|
||||
if: ${{ matrix.custom_glfw }}
|
||||
if: ${{matrix.custom_glfw}}
|
||||
run: |
|
||||
set -x
|
||||
cd glfw
|
||||
@@ -240,7 +186,7 @@ jobs:
|
||||
cd build
|
||||
|
||||
cmake -G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
|
||||
-DBUILD_SHARED_LIBS=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
@@ -255,15 +201,14 @@ jobs:
|
||||
set -x
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=$(brew --prefix llvm)/bin/clang \
|
||||
CXX=$(brew --prefix llvm)/bin/clang++ \
|
||||
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
|
||||
CXX=$(brew --prefix gcc@12)/bin/g++-12 \
|
||||
OBJC=$(brew --prefix llvm)/bin/clang \
|
||||
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
|
||||
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
|
||||
cmake -G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
|
||||
-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_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
@@ -273,7 +218,7 @@ jobs:
|
||||
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||
..
|
||||
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: cd build && ninja install
|
||||
|
||||
@@ -291,12 +236,6 @@ jobs:
|
||||
cd build/install
|
||||
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
|
||||
run: |
|
||||
set -x
|
||||
@@ -305,24 +244,18 @@ jobs:
|
||||
cd bundle
|
||||
ln -s /Applications Applications
|
||||
cd ..
|
||||
for i in $(seq 1 10); do
|
||||
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
|
||||
hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}-x86_64.dmg
|
||||
|
||||
- name: ⬆️ Upload DMG
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: macOS DMG${{ matrix.suffix }} x86_64
|
||||
name: macOS DMG${{matrix.suffix}} x86_64
|
||||
path: ./*.dmg
|
||||
|
||||
macos-arm64-build:
|
||||
runs-on: ubuntu-24.04
|
||||
name: 🍎 macOS 13 arm64
|
||||
runs-on: ubuntu-22.04
|
||||
name: 🍎 macOS 12.1 arm64
|
||||
outputs:
|
||||
IMHEX_VERSION: ${{ steps.build.outputs.IMHEX_VERSION }}
|
||||
steps:
|
||||
@@ -330,7 +263,7 @@ jobs:
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
- name: 📁 Restore docker /cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
@@ -365,8 +298,8 @@ jobs:
|
||||
gh actions-cache delete "build-macos-arm64-cache" --confirm || true
|
||||
|
||||
macos-arm64-package:
|
||||
runs-on: macos-13
|
||||
name: 🍎 macOS 13 arm64 Packaging
|
||||
runs-on: macos-12
|
||||
name: 🍎 macOS 12.1 arm64 Packaging
|
||||
needs: macos-arm64-build
|
||||
env:
|
||||
IMHEX_VERSION: ${{ needs.macos-arm64-build.outputs.IMHEX_VERSION }}
|
||||
@@ -396,12 +329,6 @@ jobs:
|
||||
cd out
|
||||
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
|
||||
run: |
|
||||
set -x
|
||||
@@ -410,13 +337,7 @@ jobs:
|
||||
cd bundle
|
||||
ln -s /Applications Applications
|
||||
cd ..
|
||||
for i in $(seq 1 10); do
|
||||
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
|
||||
hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{env.IMHEX_VERSION}}-macOS-arm64.dmg
|
||||
|
||||
- name: ⬆️ Upload DMG
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -424,18 +345,20 @@ jobs:
|
||||
if-no-files-found: error
|
||||
name: macOS DMG arm64
|
||||
path: ./*.dmg
|
||||
|
||||
|
||||
# Ubuntu build
|
||||
ubuntu:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- release_num: "24.04"
|
||||
- release_num: "24.10"
|
||||
- name: Ubuntu
|
||||
release_num: 22.04
|
||||
- name: Ubuntu
|
||||
release_num: 23.04
|
||||
|
||||
name: 🐧 Ubuntu ${{ matrix.release_num }}
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container:
|
||||
image: "ubuntu:${{ matrix.release_num }}"
|
||||
@@ -453,8 +376,8 @@ jobs:
|
||||
- name: 📜 Setup ccache
|
||||
uses: hendrikmuhs/ccache-action@v1
|
||||
with:
|
||||
key: Ubuntu-${{ matrix.release_num }}-ccache-${{ github.run_id }}
|
||||
restore-keys: Ubuntu-${{ matrix.release_num }}-ccache
|
||||
key: Ubuntu-${{matrix.release_num}}-ccache-${{ github.run_id }}
|
||||
restore-keys: Ubuntu-${{matrix.release_num}}-ccache
|
||||
max-size: 1G
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
@@ -475,8 +398,8 @@ jobs:
|
||||
git config --global --add safe.directory '*'
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-14 CXX=g++-14 cmake -G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
|
||||
CC=gcc-12 CXX=g++-12 cmake -G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
@@ -487,9 +410,9 @@ jobs:
|
||||
-DIMHEX_USE_GTK_FILE_PICKER=ON \
|
||||
-DDOTNET_EXECUTABLE="dotnet" \
|
||||
..
|
||||
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: cd build && DESTDIR=DebDir ninja install
|
||||
run: cd build && DESTDIR=DebDir ninja install
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
@@ -499,7 +422,7 @@ jobs:
|
||||
run: |
|
||||
cp -r build/DEBIAN 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
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -510,7 +433,7 @@ jobs:
|
||||
|
||||
# AppImage build
|
||||
appimage:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
name: ⬇️ AppImage
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
@@ -524,7 +447,7 @@ jobs:
|
||||
path: cache
|
||||
key: appimage-ccache-${{ github.run_id }}
|
||||
restore-keys: appimage-cache
|
||||
|
||||
|
||||
- name: 🐳 Inject /cache into docker
|
||||
uses: reproducible-containers/buildkit-cache-dance@v2
|
||||
with:
|
||||
@@ -554,7 +477,7 @@ jobs:
|
||||
# ArchLinux build
|
||||
archlinux-build:
|
||||
name: 🐧 ArchLinux
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container:
|
||||
image: archlinux:base-devel
|
||||
@@ -596,7 +519,7 @@ jobs:
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc CXX=g++ cmake -G "Ninja" \
|
||||
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
|
||||
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
@@ -610,9 +533,9 @@ jobs:
|
||||
-DIMHEX_ENABLE_LTO=ON \
|
||||
-DIMHEX_USE_GTK_FILE_PICKER=ON \
|
||||
..
|
||||
|
||||
|
||||
- name: 🛠️ Build
|
||||
run: cd build && DESTDIR=installDir ninja install
|
||||
run: cd build && DESTDIR=installDir ninja install
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
@@ -621,7 +544,7 @@ jobs:
|
||||
- name: ✒️ Prepare PKGBUILD
|
||||
run: |
|
||||
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
|
||||
- name: 📦 Package ArchLinux .pkg.tar.zst
|
||||
@@ -631,16 +554,16 @@ jobs:
|
||||
|
||||
# the name is a small trick to make makepkg recognize it as the source
|
||||
# else, it would try to download the file from the release
|
||||
tar -cvf imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst -C installDir .
|
||||
tar -cvf imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst -C installDir .
|
||||
|
||||
chmod -R 777 .
|
||||
|
||||
sudo -u nobody makepkg
|
||||
|
||||
# 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
|
||||
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
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -648,7 +571,7 @@ jobs:
|
||||
if-no-files-found: error
|
||||
name: ArchLinux .pkg.tar.zst x86_64
|
||||
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-build:
|
||||
@@ -661,41 +584,28 @@ jobs:
|
||||
release_num: rawhide
|
||||
mock_config: fedora-rawhide
|
||||
- name: Fedora
|
||||
mock_release: f41
|
||||
release_num: 41
|
||||
mock_config: fedora-41
|
||||
mock_release: f39
|
||||
release_num: 39
|
||||
mock_config: fedora-39
|
||||
- name: Fedora
|
||||
mock_release: f40
|
||||
release_num: 40
|
||||
mock_config: fedora-40
|
||||
mock_release: f38
|
||||
release_num: 38
|
||||
mock_config: fedora-38
|
||||
- name: RHEL-AlmaLinux
|
||||
mock_release: epel9
|
||||
release_num: 9
|
||||
mock_config: "alma+epel-9"
|
||||
|
||||
name: 🐧 ${{ matrix.name }} ${{ matrix.release_num }}
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
container:
|
||||
image: "almalinux:9"
|
||||
options: --privileged --pid=host --security-opt apparmor=unconfined
|
||||
image: "fedora:latest"
|
||||
options: --privileged
|
||||
|
||||
steps:
|
||||
# This, together with the `--pid=host --security-opt apparmor=unconfined` docker options is required to allow
|
||||
# fedpkg to work inside a Docker container running on Ubuntu again.
|
||||
# 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: ⬇️ Install git-core
|
||||
run: dnf install --disablerepo="*" --enablerepo="fedora" git-core -y
|
||||
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v4
|
||||
@@ -714,8 +624,8 @@ jobs:
|
||||
- name: ⬇️ Update all packages and install dependencies
|
||||
run: |
|
||||
set -x
|
||||
dnf upgrade -y
|
||||
dnf install -y \
|
||||
dnf upgrade --disablerepo="*" --enablerepo="fedora,updates" -y
|
||||
dnf install --disablerepo="*" --enablerepo="fedora,updates" -y \
|
||||
fedpkg \
|
||||
ccache
|
||||
|
||||
@@ -741,16 +651,16 @@ jobs:
|
||||
- name: ✒️ Modify spec file
|
||||
run: |
|
||||
sed -i \
|
||||
-e 's/Version: VERSION$/Version: ${{ env.IMHEX_VERSION }}/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 '/BuildRequires: cmake/a BuildRequires: git-core' \
|
||||
-e '/%files/a %{_datadir}/%{name}/' \
|
||||
-e 's/Version: VERSION$/Version: ${{env.IMHEX_VERSION}}/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 '/BuildRequires: cmake/a BuildRequires: git-core' \
|
||||
-e '/%files/a %{_datadir}/%{name}/' \
|
||||
$GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec
|
||||
|
||||
- name: 📜 Fix ccache on EL9
|
||||
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
|
||||
run: mv $GITHUB_WORKSPACE/ImHex/dist/rpm/imhex.spec $GITHUB_WORKSPACE/imhex.spec
|
||||
@@ -765,6 +675,14 @@ jobs:
|
||||
config_opts['plugin_conf']['ccache_opts']['dir'] = "$GITHUB_WORKSPACE/.ccache"
|
||||
EOT
|
||||
|
||||
- name: 📜 Setup Mock Cache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: /var/cache/mock
|
||||
key: ${{ matrix.mock_release }}-mock-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
${{ matrix.mock_release }}-mock
|
||||
|
||||
# Fedora cmake build (in imhex.spec)
|
||||
- name: 📦 Build RPM
|
||||
run: |
|
||||
@@ -772,8 +690,8 @@ jobs:
|
||||
|
||||
- name: 🟩 Move and rename finished RPM
|
||||
run: |
|
||||
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
|
||||
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
|
||||
|
||||
- name: ⬆️ Upload RPM
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -781,4 +699,4 @@ jobs:
|
||||
if-no-files-found: error
|
||||
name: ${{ matrix.name }} ${{ matrix.release_num }} RPM x86_64
|
||||
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
|
||||
|
||||
16
.github/workflows/build_web.yml
vendored
16
.github/workflows/build_web.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'releases/**'
|
||||
- 'tests/**'
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
@@ -20,7 +19,7 @@ permissions:
|
||||
jobs:
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
name: 🌍 WebAssembly
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
@@ -32,7 +31,7 @@ jobs:
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: cache
|
||||
key: web-cache-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
key: web-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: 🐳 Inject /cache into docker
|
||||
uses: reproducible-containers/buildkit-cache-dance@v2
|
||||
@@ -49,7 +48,7 @@ jobs:
|
||||
chmod -c -R +rX "out/"
|
||||
|
||||
- name: ⬆️ Upload artifacts
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
uses: actions/upload-pages-artifact@v2
|
||||
with:
|
||||
path: out/
|
||||
|
||||
@@ -59,8 +58,9 @@ jobs:
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh extension install actions/gh-actions-cache || true
|
||||
gh actions-cache delete "build-web-cache" --confirm || true
|
||||
gh extension install actions/gh-actions-cache
|
||||
gh actions-cache delete "build-web-cache" --confirm
|
||||
|
||||
|
||||
deploy:
|
||||
environment:
|
||||
@@ -68,7 +68,7 @@ jobs:
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
|
||||
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 }}
|
||||
needs: build
|
||||
@@ -76,4 +76,4 @@ jobs:
|
||||
steps:
|
||||
- name: 🌍 Deploy
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
uses: actions/deploy-pages@v2
|
||||
6
.github/workflows/release.yml
vendored
6
.github/workflows/release.yml
vendored
@@ -10,7 +10,7 @@ on:
|
||||
|
||||
jobs:
|
||||
release-update-repos:
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
name: Release Update Repos
|
||||
|
||||
steps:
|
||||
@@ -90,7 +90,7 @@ jobs:
|
||||
run: tar --exclude-vcs -czvf Full.Sources.tar.gz ImHex
|
||||
|
||||
- name: ⬇️ Download artifacts from latest workflow
|
||||
uses: dawidd6/action-download-artifact@v6
|
||||
uses: dawidd6/action-download-artifact@v3
|
||||
with:
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
workflow: build.yml
|
||||
@@ -147,7 +147,7 @@ jobs:
|
||||
commit_email: itrooz@protonmail.com
|
||||
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
|
||||
commit_message: Bump to version ${{ env.IMHEX_VERSION }}
|
||||
ssh_keyscan_types: rsa,ecdsa,ed25519
|
||||
ssh_keyscan_types: rsa,dsa,ecdsa,ed25519
|
||||
|
||||
release-update-winget:
|
||||
name: Release update winget package
|
||||
|
||||
30
.github/workflows/stale_issues.yml
vendored
30
.github/workflows/stale_issues.yml
vendored
@@ -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 }}
|
||||
57
.github/workflows/tests.yml
vendored
57
.github/workflows/tests.yml
vendored
@@ -5,7 +5,6 @@ on:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'releases/**'
|
||||
- 'tests/**'
|
||||
pull_request:
|
||||
branches:
|
||||
- 'master'
|
||||
@@ -15,7 +14,7 @@ on:
|
||||
jobs:
|
||||
tests:
|
||||
name: 🧪 Unit Tests
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-22.04
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
@@ -34,6 +33,14 @@ jobs:
|
||||
restore-keys: ${{ runner.os }}-tests-build
|
||||
max-size: 50M
|
||||
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-tests-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
sudo apt update
|
||||
@@ -44,50 +51,22 @@ jobs:
|
||||
set -x
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-14 CXX=g++-14 cmake \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DIMHEX_ENABLE_UNIT_TESTS=ON \
|
||||
-DIMHEX_ENABLE_PLUGIN_TESTS=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-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" \
|
||||
-DIMHEX_OFFLINE_BUILD=ON \
|
||||
-G Ninja \
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DIMHEX_ENABLE_UNIT_TESTS=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
|
||||
-DIMHEX_OFFLINE_BUILD=ON \
|
||||
..
|
||||
ninja unit_tests
|
||||
ninja imhex_all
|
||||
|
||||
- name: 🧪 Perform plcli Integration Tests
|
||||
run: |
|
||||
cd lib/external/pattern_language
|
||||
python tests/integration/integration.py ../../../build/imhex --pl
|
||||
make -j4 unit_tests
|
||||
|
||||
- name: 🧪 Perform Unit Tests
|
||||
run: |
|
||||
cd build
|
||||
ctest --output-on-failure
|
||||
|
||||
# Generate report from all gcov .gcda files
|
||||
#- name: 🧪 Generate coverage report
|
||||
# run: |
|
||||
# sudo apt install python3-pip python3-venv
|
||||
# python3 -m venv venv
|
||||
# . venv/bin/activate
|
||||
# pip3 install gcovr
|
||||
# cd build
|
||||
# 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
|
||||
#
|
||||
#- name: Upload coverage reports to Codecov
|
||||
# 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:
|
||||
name: 🧪 Langs
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -1,16 +1,13 @@
|
||||
.vscode/
|
||||
.idea/
|
||||
.kdev4/
|
||||
|
||||
cmake-build-*/
|
||||
build*/
|
||||
local/
|
||||
venv/
|
||||
.cache/
|
||||
|
||||
*.mgc
|
||||
*.kdev4
|
||||
imgui.ini
|
||||
.DS_Store
|
||||
CMakeUserPresets.json
|
||||
Brewfile.lock.json
|
||||
./CMakeUserPresets.json
|
||||
Brewfile.lock.json
|
||||
13
.gitmodules
vendored
13
.gitmodules
vendored
@@ -22,14 +22,6 @@
|
||||
path = lib/third_party/jthread/jthread
|
||||
url = https://github.com/josuttis/jthread
|
||||
ignore = dirty
|
||||
[submodule "lib/third_party/edlib"]
|
||||
path = lib/third_party/edlib
|
||||
url = https://github.com/Martinsos/edlib
|
||||
ignore = dirty
|
||||
[submodule "lib/third_party/lunasvg"]
|
||||
path = lib/third_party/lunasvg
|
||||
url = https://github.com/WerWolv/lunasvg
|
||||
ignore = dirty
|
||||
|
||||
[submodule "lib/external/libromfs"]
|
||||
path = lib/external/libromfs
|
||||
@@ -43,4 +35,7 @@
|
||||
|
||||
[submodule "lib/third_party/HashLibPlus"]
|
||||
path = lib/third_party/HashLibPlus
|
||||
url = https://github.com/WerWolv/HashLibPlus
|
||||
url = https://github.com/WerWolv/HashLibPlus
|
||||
[submodule "lib/third_party/edlib"]
|
||||
path = lib/third_party/edlib
|
||||
url = https://github.com/Martinsos/edlib
|
||||
|
||||
@@ -21,32 +21,24 @@ 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_UNIT_TESTS "Enable building unit tests" OFF)
|
||||
option(IMHEX_ENABLE_PRECOMPILED_HEADERS "Enable precompiled headers" OFF)
|
||||
option(IMHEX_COMPRESS_DEBUG_INFO "Compress debug information" ON )
|
||||
|
||||
set(IMHEX_BASE_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
|
||||
|
||||
# Optional IDE support
|
||||
include("${IMHEX_BASE_FOLDER}/cmake/ide_helpers.cmake")
|
||||
|
||||
# Basic compiler and cmake configurations
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
|
||||
set(IMHEX_BASE_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
|
||||
include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
|
||||
|
||||
# Setup project
|
||||
loadVersion(IMHEX_VERSION IMHEX_VERSION_PLAIN)
|
||||
loadVersion(IMHEX_VERSION)
|
||||
setVariableInParent(IMHEX_VERSION ${IMHEX_VERSION})
|
||||
|
||||
configureCMake()
|
||||
project(imhex
|
||||
LANGUAGES C CXX
|
||||
VERSION ${IMHEX_VERSION_PLAIN}
|
||||
VERSION ${IMHEX_VERSION}
|
||||
DESCRIPTION "The ImHex Hex Editor"
|
||||
HOMEPAGE_URL "https://imhex.werwolv.net"
|
||||
)
|
||||
configureProject()
|
||||
|
||||
# Add ImHex sources
|
||||
add_custom_target(imhex_all ALL)
|
||||
@@ -73,11 +65,8 @@ addPluginDirectories()
|
||||
|
||||
# Add unit tests
|
||||
if (IMHEX_ENABLE_UNIT_TESTS)
|
||||
if (NOT TARGET unit_tests)
|
||||
enable_testing()
|
||||
add_custom_target(unit_tests)
|
||||
add_subdirectory(tests EXCLUDE_FROM_ALL)
|
||||
endif ()
|
||||
enable_testing()
|
||||
add_subdirectory(tests EXCLUDE_FROM_ALL)
|
||||
endif ()
|
||||
|
||||
# Configure more resources that will be added to the install package
|
||||
@@ -86,6 +75,3 @@ generateSDKDirectory()
|
||||
|
||||
# Handle package generation
|
||||
createPackage()
|
||||
|
||||
# Accommodate IDEs with FOLDER support
|
||||
tweakTargetsForIDESupport()
|
||||
|
||||
@@ -28,23 +28,6 @@
|
||||
"displayName": "x86_64 Build",
|
||||
"description": "x86_64 build",
|
||||
"inherits": [ "base" ]
|
||||
},
|
||||
{
|
||||
"name": "xcode",
|
||||
"inherits": [ "base" ],
|
||||
|
||||
"displayName": "Xcode",
|
||||
"description": "Xcode with external compiler override",
|
||||
"generator": "Xcode",
|
||||
|
||||
"cacheVariables": {
|
||||
"CMAKE_C_COMPILER": "clang",
|
||||
|
||||
"CMAKE_CXX_COMPILER": "clang++",
|
||||
"CMAKE_CXX_FLAGS": "-fexperimental-library -Wno-shorten-64-to-32 -Wno-deprecated-declarations",
|
||||
|
||||
"IMHEX_IDE_HELPERS_OVERRIDE_XCODE_COMPILER": "ON"
|
||||
}
|
||||
}
|
||||
],
|
||||
"buildPresets": [
|
||||
|
||||
53
README.md
53
README.md
@@ -1,16 +1,14 @@
|
||||
<a href="https://imhex.werwolv.net">
|
||||
<h1 align="center">
|
||||
<picture>
|
||||
<img height="300px" style="margin: 0; padding: 0" src="./resources/dist/common/logo/ImHexLogoSVGBG.svg">
|
||||
<source media="(prefers-color-scheme: dark)" srcset="./resources/projects/logo_text_light.svg">
|
||||
<img height="100px" src="./resources/projects/logo_text_dark.svg">
|
||||
</picture>
|
||||
</h1>
|
||||
</a>
|
||||
|
||||
<p align="center">
|
||||
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">A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</p>
|
||||
|
||||
<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="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>
|
||||
@@ -111,7 +109,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
<details>
|
||||
<summary><strong>Data Inspector</strong></summary>
|
||||
|
||||
- Interpreting data as many different types with endianness, decimal, hexadecimal and octal support and bit inversion
|
||||
- Interpreting data as many different types with endianess, decimal, hexadecimal and octal support and bit inversion
|
||||
- Unsigned and signed integers (8, 16, 24, 32, 48, 64 bit)
|
||||
- Floats (16, 32, 64 bit)
|
||||
- Signed and Unsigned LEB128
|
||||
@@ -160,7 +158,7 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
- Numeric Value search
|
||||
- Search for signed/unsigned integers and floats
|
||||
- Search for ranges of values
|
||||
- Option to specify size and endianness
|
||||
- Option to specify size and endianess
|
||||
- Option to ignore unaligned values
|
||||
</details>
|
||||
<details>
|
||||
@@ -314,26 +312,22 @@ To use ImHex, the following minimal system requirements need to be met.
|
||||
> 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.
|
||||
>
|
||||
> If possible at all, make ImHex use the dedicated GPU on your system instead of the integrated one.
|
||||
> ImHex will usually run fine with integrated GPUs as well but certain Intel HD GPU drivers on Windows are known to cause graphical artifacts.
|
||||
> 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).
|
||||
|
||||
- **OS**:
|
||||
- **Windows**: Windows 7 or higher (Windows 10/11 recommended)
|
||||
- **macOS**: macOS 13 (Ventura) 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.
|
||||
- **macOS**: macOS 11 (Big Sur) or higher,
|
||||
- **Linux**: "Modern" Linux. The following distributions have official releases available. Other distros are supported through the AppImage and Flatpak releases.
|
||||
- Ubuntu and Debian
|
||||
- Fedora
|
||||
- RHEL/AlmaLinux
|
||||
- Ubuntu 22.04/23.04
|
||||
- Fedora 36/37
|
||||
- RHEL/AlmaLinux 9
|
||||
- Arch Linux
|
||||
- Basically any other distro will work as well when compiling ImHex from sources.
|
||||
- **CPU**: x86_64 (64 Bit)
|
||||
- **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
|
||||
- **RAM**: 256MB, more may be required for more complicated analysis
|
||||
- **Storage**: 150MB
|
||||
- **Storage**: 100MB
|
||||
|
||||
## Installing
|
||||
|
||||
@@ -364,29 +358,24 @@ To develop plugins for ImHex, use the following template project to get started.
|
||||
|
||||
### Contributors
|
||||
|
||||
- [iTrooz](https://github.com/iTrooz) for getting ImHex onto the Web as well as hundreds of contributions in every part of the project
|
||||
- [jumanji144](https://github.com/jumanji144) for huge contributions to the Pattern Language and ImHex's infrastructure
|
||||
- [Mary](https://github.com/marysaka) for her immense help porting ImHex to MacOS and help during development
|
||||
- [Roblabla](https://github.com/Roblabla) for adding MSI Installer support to ImHex
|
||||
- [jam1garner](https://github.com/jam1garner) and [raytwo](https://github.com/raytwo) for their help with adding Rust support to plugins
|
||||
- [Mailaender](https://github.com/Mailaender) for getting ImHex onto Flathub
|
||||
- [iTrooz](https://github.com/iTrooz) for many improvements and new features to Imhex
|
||||
- Everybody else who has reported issues on Discord or GitHub that I had great conversations with :)
|
||||
|
||||
### Dependencies
|
||||
|
||||
- Thanks a lot to ocornut for their amazing [Dear ImGui](https://github.com/ocornut/imgui) which is used for building the entire interface
|
||||
- Thanks to epezent for [ImPlot](https://github.com/epezent/implot) used to plot data in various places
|
||||
- Thanks to Nelarius for [ImNodes](https://github.com/Nelarius/imnodes) used as base for the data processor
|
||||
- Thanks to BalazsJako for [ImGuiColorTextEdit](https://github.com/BalazsJako/ImGuiColorTextEdit) used for the pattern language syntax highlighting
|
||||
- Thanks to nlohmann for their [json](https://github.com/nlohmann/json) library used for configuration files
|
||||
- Thanks to vitaut for their [libfmt](https://github.com/fmtlib/fmt) library which makes formatting and logging so much better
|
||||
- Thanks to btzy for [nativefiledialog-extended](https://github.com/btzy/nativefiledialog-extended) and their great support, used for handling file dialogs on all platforms
|
||||
- Thanks to danyspin97 for [xdgpp](https://sr.ht/~danyspin97/xdgpp) used to handle folder paths on Linux
|
||||
- Thanks to ocornut as well for their hex editor view used as base for this project.
|
||||
- Thanks to BalazsJako for their incredible [ImGuiColorTextEdit](https://github.com/BalazsJako/ImGuiColorTextEdit) used for the pattern language syntax highlighting
|
||||
- Thanks to nlohmann for their [json](https://github.com/nlohmann/json) library used for project files
|
||||
- Thanks to aquynh for [capstone](https://github.com/aquynh/capstone) which is the base of the disassembly window
|
||||
- Thanks to vitaut for their [libfmt](https://github.com/fmtlib/fmt) library which makes formatting and logging so much better
|
||||
- Thanks to rxi for [microtar](https://github.com/rxi/microtar) used for extracting downloaded store assets
|
||||
- Thanks to VirusTotal for [Yara](https://github.com/VirusTotal/yara) used by the Yara plugin
|
||||
- Thanks to Martinsos for [edlib](https://github.com/Martinsos/edlib) used for sequence searching in the diffing view
|
||||
- Thanks to ron4fun for [HashLibPlus](https://github.com/ron4fun/HashLibPlus) which implements every hashing algorithm under the sun
|
||||
- Thanks to mackron for [miniaudio](https://github.com/mackron/miniaudio) used to play audio files
|
||||
- Thanks to btzy for [nativefiledialog-extended](https://github.com/btzy/nativefiledialog-extended)
|
||||
- Thanks to danyspin97 for [xdgpp](https://sr.ht/~danyspin97/xdgpp)
|
||||
- Thanks to all other groups and organizations whose libraries are used in ImHex
|
||||
|
||||
### License
|
||||
|
||||
@@ -59,7 +59,6 @@ macro(detectOS)
|
||||
set(CMAKE_INSTALL_LIBDIR ".")
|
||||
set(PLUGINS_INSTALL_LOCATION "plugins")
|
||||
add_compile_definitions(WIN32_LEAN_AND_MEAN)
|
||||
add_compile_definitions(UNICODE)
|
||||
elseif (APPLE)
|
||||
add_compile_definitions(OS_MACOS)
|
||||
set(CMAKE_INSTALL_BINDIR ".")
|
||||
@@ -153,12 +152,14 @@ macro(addPluginDirectories)
|
||||
foreach (plugin IN LISTS PLUGINS)
|
||||
add_subdirectory("plugins/${plugin}")
|
||||
if (TARGET ${plugin})
|
||||
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${IMHEX_MAIN_OUTPUT_DIRECTORY}/plugins")
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${IMHEX_MAIN_OUTPUT_DIRECTORY}/plugins")
|
||||
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
|
||||
if (APPLE)
|
||||
if (IMHEX_GENERATE_PACKAGE)
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PLUGINS_INSTALL_LOCATION})
|
||||
else ()
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
endif ()
|
||||
else ()
|
||||
if (WIN32)
|
||||
@@ -225,7 +226,6 @@ macro(createPackage)
|
||||
|
||||
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.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)
|
||||
downloadImHexPatternsFiles("./share/imhex")
|
||||
|
||||
@@ -240,7 +240,6 @@ macro(createPackage)
|
||||
|
||||
if (APPLE)
|
||||
if (IMHEX_GENERATE_PACKAGE)
|
||||
set(EXTRA_BUNDLE_LIBRARY_PATHS ${EXTRA_BUNDLE_LIBRARY_PATHS} "${IMHEX_SYSTEM_LIBRARY_PATH}")
|
||||
include(PostprocessBundle)
|
||||
|
||||
set_target_properties(libimhex PROPERTIES SOVERSION ${IMHEX_VERSION})
|
||||
@@ -271,13 +270,11 @@ macro(createPackage)
|
||||
find_program(CODESIGN_PATH codesign)
|
||||
if (CODESIGN_PATH)
|
||||
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()
|
||||
|
||||
install(CODE [[ message(STATUS "MacOS Bundle finalized. DO NOT TOUCH IT ANYMORE! ANY MODIFICATIONS WILL BREAK IT FROM NOW ON!") ]])
|
||||
else()
|
||||
downloadImHexPatternsFiles("${IMHEX_MAIN_OUTPUT_DIRECTORY}")
|
||||
endif()
|
||||
else()
|
||||
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
@@ -309,6 +306,9 @@ endfunction()
|
||||
macro(configureCMake)
|
||||
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)
|
||||
|
||||
# Configure use of recommended build tools
|
||||
@@ -342,11 +342,8 @@ macro(configureCMake)
|
||||
|
||||
if (LD_LLD_PATH)
|
||||
set(CMAKE_LINKER ${LD_LLD_PATH})
|
||||
|
||||
if (NOT XCODE)
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=lld")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=lld")
|
||||
endif()
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fuse-ld=lld")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fuse-ld=lld")
|
||||
else ()
|
||||
message(WARNING "lld not found, using default linker!")
|
||||
endif ()
|
||||
@@ -381,18 +378,6 @@ macro(configureCMake)
|
||||
set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "Disable deprecated warnings" FORCE)
|
||||
endmacro()
|
||||
|
||||
function(configureProject)
|
||||
# Enable C and C++ languages
|
||||
enable_language(C CXX)
|
||||
|
||||
if (XCODE)
|
||||
# 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)
|
||||
else()
|
||||
set(IMHEX_MAIN_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
macro(setDefaultBuiltTypeIfUnset)
|
||||
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "Using RelWithDebInfo build type as it was left unset" FORCE)
|
||||
@@ -400,14 +385,12 @@ macro(setDefaultBuiltTypeIfUnset)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
function(loadVersion version plain_version)
|
||||
function(loadVersion version)
|
||||
set(VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${VERSION_FILE})
|
||||
file(READ "${VERSION_FILE}" read_version)
|
||||
string(STRIP ${read_version} read_version)
|
||||
string(REPLACE ".WIP" "" read_version_plain ${read_version})
|
||||
set(${version} ${read_version} PARENT_SCOPE)
|
||||
set(${plain_version} ${read_version_plain} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(detectBadClone)
|
||||
@@ -497,71 +480,20 @@ function(downloadImHexPatternsFiles dest)
|
||||
message(STATUS "Finished downloading ImHex-Patterns")
|
||||
|
||||
else ()
|
||||
set(imhex_patterns_SOURCE_DIR "")
|
||||
|
||||
# Maybe patterns are cloned to a subdirectory
|
||||
if (NOT EXISTS ${imhex_patterns_SOURCE_DIR})
|
||||
set(imhex_patterns_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ImHex-Patterns")
|
||||
endif()
|
||||
|
||||
# Or a sibling directory
|
||||
if (NOT EXISTS ${imhex_patterns_SOURCE_DIR})
|
||||
set(imhex_patterns_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../ImHex-Patterns")
|
||||
endif()
|
||||
set(imhex_patterns_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ImHex-Patterns")
|
||||
endif ()
|
||||
|
||||
if (NOT EXISTS ${imhex_patterns_SOURCE_DIR})
|
||||
message(WARNING "Failed to locate ImHex-Patterns repository, some resources will be missing during install!")
|
||||
elseif(XCODE)
|
||||
# The Xcode build has multiple configurations, which each need a copy of these files
|
||||
file(GLOB_RECURSE sourceFilePaths LIST_DIRECTORIES NO CONFIGURE_DEPENDS RELATIVE "${imhex_patterns_SOURCE_DIR}"
|
||||
"${imhex_patterns_SOURCE_DIR}/constants/*"
|
||||
"${imhex_patterns_SOURCE_DIR}/encodings/*"
|
||||
"${imhex_patterns_SOURCE_DIR}/includes/*"
|
||||
"${imhex_patterns_SOURCE_DIR}/patterns/*"
|
||||
"${imhex_patterns_SOURCE_DIR}/magic/*"
|
||||
"${imhex_patterns_SOURCE_DIR}/nodes/*"
|
||||
)
|
||||
list(FILTER sourceFilePaths EXCLUDE REGEX "_schema.json$")
|
||||
|
||||
foreach(relativePath IN LISTS sourceFilePaths)
|
||||
file(GENERATE OUTPUT "${dest}/${relativePath}" INPUT "${imhex_patterns_SOURCE_DIR}/${relativePath}")
|
||||
endforeach()
|
||||
else()
|
||||
if (EXISTS ${imhex_patterns_SOURCE_DIR})
|
||||
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic nodes)
|
||||
foreach (FOLDER ${PATTERNS_FOLDERS_TO_INSTALL})
|
||||
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION "${dest}" PATTERN "**/_schema.json" EXCLUDE)
|
||||
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION ${dest} PATTERN "**/_schema.json" EXCLUDE)
|
||||
endforeach ()
|
||||
endif ()
|
||||
|
||||
endfunction()
|
||||
|
||||
# Compress debug info. See https://github.com/WerWolv/ImHex/issues/1714 for relevant problem
|
||||
macro(setupDebugCompressionFlag)
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(CheckLinkerFlag)
|
||||
|
||||
check_cxx_compiler_flag(-gz=zstd ZSTD_AVAILABLE_COMPILER)
|
||||
check_linker_flag(CXX -gz=zstd ZSTD_AVAILABLE_LINKER)
|
||||
check_cxx_compiler_flag(-gz COMPRESS_AVAILABLE_COMPILER)
|
||||
check_linker_flag(CXX -gz COMPRESS_AVAILABLE_LINKER)
|
||||
|
||||
if (NOT DEBUG_COMPRESSION_FLAG) # Cache variable
|
||||
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")
|
||||
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")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(IMHEX_COMMON_FLAGS "${IMHEX_COMMON_FLAGS} ${DEBUG_COMPRESSION_FLAG}")
|
||||
endmacro()
|
||||
|
||||
macro(setupCompilerFlags target)
|
||||
# IMHEX_COMMON_FLAGS: flags common for C, C++, Objective C, etc.. compilers
|
||||
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
# Define strict compilation flags
|
||||
if (IMHEX_STRICT_WARNINGS)
|
||||
@@ -575,7 +507,7 @@ macro(setupCompilerFlags target)
|
||||
set(IMHEX_CXX_FLAGS "-fexceptions -frtti")
|
||||
|
||||
# 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()
|
||||
|
||||
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
@@ -584,13 +516,6 @@ macro(setupCompilerFlags target)
|
||||
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
|
||||
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")
|
||||
@@ -601,24 +526,11 @@ macro(setupCompilerFlags target)
|
||||
set(IMHEX_C_CXX_FLAGS "${IMHEX_C_CXX_FLAGS} -pthread -Wno-dollar-in-identifier-extension -Wno-pthreads-mem-growth")
|
||||
endif ()
|
||||
|
||||
if (IMHEX_COMPRESS_DEBUG_INFO)
|
||||
setupDebugCompressionFlag()
|
||||
endif()
|
||||
|
||||
# Set actual CMake flags
|
||||
set_target_properties(${target} PROPERTIES COMPILE_FLAGS "${IMHEX_COMMON_FLAGS} ${IMHEX_C_CXX_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${IMHEX_COMMON_FLAGS} ${IMHEX_C_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${IMHEX_COMMON_FLAGS} ${IMHEX_C_CXX_FLAGS} ${IMHEX_CXX_FLAGS}")
|
||||
set(CMAKE_OBJC_FLAGS "${CMAKE_OBJC_FLAGS} ${IMHEX_COMMON_FLAGS}")
|
||||
|
||||
# Only generate minimal debug information for stacktraces in RelWithDebInfo builds
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -g1")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -g1")
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||
# Add flags for debug info in inline functions
|
||||
set(CMAKE_C_FLAGS_RELWITHDEBINFO "${CMAKE_C_FLAGS_RELWITHDEBINFO} -gstatement-frontiers -ginline-points")
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -gstatement-frontiers -ginline-points")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# uninstall target
|
||||
@@ -684,14 +596,6 @@ macro(addBundledLibraries)
|
||||
set(NLOHMANN_JSON_LIBRARIES nlohmann_json::nlohmann_json)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_LUNASVG)
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/lunasvg EXCLUDE_FROM_ALL)
|
||||
set(LUNASVG_LIBRARIES lunasvg)
|
||||
else()
|
||||
find_package(LunaSVG REQUIRED)
|
||||
set(LUNASVG_LIBRARIES lunasvg)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_LLVM)
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/llvm-demangle EXCLUDE_FROM_ALL)
|
||||
else()
|
||||
@@ -710,14 +614,6 @@ macro(addBundledLibraries)
|
||||
set(JTHREAD_LIBRARIES jthread)
|
||||
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_ENABLE_PRECOMPILED_HEADERS ${IMHEX_ENABLE_PRECOMPILED_HEADERS} CACHE BOOL "" FORCE)
|
||||
|
||||
@@ -857,9 +753,6 @@ function(generateSDKDirectory)
|
||||
if (NOT USE_SYSTEM_NLOHMANN_JSON)
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/nlohmann_json DESTINATION "${SDK_PATH}/lib/third_party")
|
||||
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(FILES ${CMAKE_SOURCE_DIR}/cmake/build_helpers.cmake DESTINATION "${SDK_PATH}/cmake")
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
|
||||
option(IMHEX_IDE_HELPERS_OVERRIDE_XCODE_COMPILER "Enable choice of compiler for Xcode builds, despite CMake's best efforts" OFF)
|
||||
option(IMHEX_IDE_HELPERS_INTRUSIVE_IDE_TWEAKS "Enable intrusive CMake tweaks to better support IDEs with folder support" OFF)
|
||||
|
||||
# The CMake infrastructure silently ignores the CMAKE_<>_COMPILER settings when
|
||||
# using the `Xcode` generator.
|
||||
#
|
||||
# A particularly nasty (and potentially only) way of getting around this is to
|
||||
# temporarily lie about the generator being used, while CMake determines and
|
||||
# locks in the compiler to use.
|
||||
#
|
||||
# Needless to say, this is hacky and fragile. Use at your own risk!
|
||||
if (IMHEX_IDE_HELPERS_OVERRIDE_XCODE_COMPILER AND CMAKE_GENERATOR STREQUAL "Xcode")
|
||||
set(CMAKE_GENERATOR "Unknown")
|
||||
enable_language(C CXX)
|
||||
|
||||
set(CMAKE_GENERATOR "Xcode")
|
||||
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CC "${CMAKE_C_COMPILER}")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_CXX "${CMAKE_CXX_COMPILER}")
|
||||
|
||||
if (CLANG)
|
||||
set(CMAKE_XCODE_ATTRIBUTE_LD "${CMAKE_C_COMPILER}")
|
||||
set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS "${CMAKE_CXX_COMPILER}")
|
||||
endif()
|
||||
|
||||
# By default Xcode passes a `-index-store-path=<...>` parameter to the compiler
|
||||
# during builds to build code completion indexes. This is not supported by
|
||||
# anything other than AppleClang
|
||||
set(CMAKE_XCODE_ATTRIBUTE_COMPILER_INDEX_STORE_ENABLE "NO")
|
||||
endif()
|
||||
|
||||
# Generate a launch/build scheme for all targets
|
||||
set(CMAKE_XCODE_GENERATE_SCHEME YES)
|
||||
|
||||
# Utility function that helps avoid messing with non-standard targets
|
||||
macro(returnIfTargetIsNonTweakable target)
|
||||
get_target_property(targetIsAliased ${target} ALIASED_TARGET)
|
||||
get_target_property(targetIsImported ${target} IMPORTED)
|
||||
|
||||
if (targetIsAliased OR targetIsImported)
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_target_property(targetType ${target} TYPE)
|
||||
if (targetType MATCHES "INTERFACE_LIBRARY|UNKNOWN_LIBRARY")
|
||||
return()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
# Targets usually don't specify their private headers, nor group their source files
|
||||
# which results in very spotty coverage by IDEs with folders support
|
||||
#
|
||||
# Unfortunately, CMake does not have a `target_source_group` like construct yet, therefore
|
||||
# we have to play by the limitations of `source_group`.
|
||||
#
|
||||
# A particularly problematic part is that the function must be called within the directoryies
|
||||
# scope for the grouping to take effect.
|
||||
#
|
||||
# See: https://discourse.cmake.org/t/topic/7388
|
||||
function(tweakTargetForIDESupport target)
|
||||
returnIfTargetIsNonTweakable(${target})
|
||||
|
||||
# Don't assume directory structure of third parties
|
||||
get_target_property(targetSourceDir ${target} SOURCE_DIR)
|
||||
if (targetSourceDir MATCHES "third_party")
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Add headers to target
|
||||
get_target_property(targetSourceDir ${target} SOURCE_DIR)
|
||||
if (targetSourceDir)
|
||||
file(GLOB_RECURSE targetPrivateHeaders CONFIGURE_DEPENDS "${targetSourceDir}/include/*.hpp")
|
||||
|
||||
target_sources(${target} PRIVATE "${targetPrivateHeaders}")
|
||||
endif()
|
||||
|
||||
# Organize target sources into directory tree
|
||||
get_target_property(sources ${target} SOURCES)
|
||||
foreach(file IN LISTS sources)
|
||||
get_filename_component(path "${file}" ABSOLUTE)
|
||||
|
||||
if (NOT path MATCHES "^${targetSourceDir}")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
source_group(TREE "${targetSourceDir}" PREFIX "Source Tree" FILES "${file}")
|
||||
endforeach()
|
||||
endfunction()
|
||||
|
||||
if (IMHEX_IDE_HELPERS_INTRUSIVE_IDE_TWEAKS)
|
||||
# See tweakTargetForIDESupport for rationale
|
||||
|
||||
function(add_library target)
|
||||
_add_library(${target} ${ARGN})
|
||||
|
||||
tweakTargetForIDESupport(${target})
|
||||
endfunction()
|
||||
|
||||
function(add_executable target)
|
||||
_add_executable(${target} ${ARGN})
|
||||
|
||||
tweakTargetForIDESupport(${target})
|
||||
endfunction()
|
||||
endif()
|
||||
|
||||
# Adjust target's FOLDER property, which is an IDE only preference
|
||||
function(_tweakTarget target path)
|
||||
get_target_property(targetType ${target} TYPE)
|
||||
|
||||
if (TARGET generator-${target})
|
||||
set_target_properties(generator-${target} PROPERTIES FOLDER "romfs/${target}")
|
||||
endif()
|
||||
if (TARGET romfs_file_packer-${target})
|
||||
set_target_properties(romfs_file_packer-${target} PROPERTIES FOLDER "romfs/${target}")
|
||||
endif()
|
||||
if (TARGET libromfs-${target})
|
||||
set_target_properties(libromfs-${target} PROPERTIES FOLDER "romfs/${target}")
|
||||
endif()
|
||||
|
||||
if (${targetType} MATCHES "EXECUTABLE|LIBRARY")
|
||||
set_target_properties(${target} PROPERTIES FOLDER "${path}")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
macro(_tweakTargetsRecursive dir)
|
||||
get_property(subdirectories DIRECTORY ${dir} PROPERTY SUBDIRECTORIES)
|
||||
foreach(subdir IN LISTS subdirectories)
|
||||
_tweakTargetsRecursive("${subdir}")
|
||||
endforeach()
|
||||
|
||||
if(${dir} STREQUAL ${CMAKE_SOURCE_DIR})
|
||||
return()
|
||||
endif()
|
||||
|
||||
get_property(targets DIRECTORY "${dir}" PROPERTY BUILDSYSTEM_TARGETS)
|
||||
file(RELATIVE_PATH rdir ${CMAKE_SOURCE_DIR} "${dir}/..")
|
||||
|
||||
foreach(target ${targets})
|
||||
_tweakTarget(${target} "${rdir}")
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
# Tweak all targets this CMake build is aware about
|
||||
function(tweakTargetsForIDESupport)
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
_tweakTargetsRecursive("${CMAKE_SOURCE_DIR}")
|
||||
endfunction()
|
||||
@@ -11,14 +11,6 @@ if (UNIX)
|
||||
set(CORECLR_SUBARCH "arm64")
|
||||
endif()
|
||||
endif()
|
||||
if (APPLE)
|
||||
if (CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
|
||||
set(CORECLR_ARCH "osx-arm64")
|
||||
set(CORECLR_SUBARCH "arm64")
|
||||
else()
|
||||
set(CORECLR_ARCH "osx-x64")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (NOT DOTNET_EXECUTABLE)
|
||||
set(DOTNET_EXECUTABLE dotnet)
|
||||
@@ -89,5 +81,4 @@ if (CoreClrEmbed_INCLUDE_DIR AND CoreClrEmbed_LIBRARY)
|
||||
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_INCLUDE_DIRS "${CoreClrEmbed_INCLUDE_DIR}" CACHE STRING "CoreClrEmbed include directories" FORCE)
|
||||
set(CoreClrEmbed_VERSION "${CORECLR_RUNTIME_VERSION_FULL}" CACHE STRING "CoreClrEmbed version" FORCE)
|
||||
endif()
|
||||
@@ -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} )
|
||||
@@ -38,8 +38,4 @@ if (ZSTD_FOUND)
|
||||
message(STATUS "Found Zstd: ${ZSTD_LIBRARY}")
|
||||
endif()
|
||||
|
||||
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})
|
||||
mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)
|
||||
@@ -55,9 +55,9 @@ IF(MBEDTLS_FOUND)
|
||||
MESSAGE(STATUS " Crypto: ${MBEDCRYPTO_LIBRARY}")
|
||||
ENDIF(NOT MBEDTLS_FIND_QUIETLY)
|
||||
ELSE(MBEDTLS_FOUND)
|
||||
IF(mbedTLS_FIND_REQUIRED)
|
||||
IF(MBEDTLS_FIND_REQUIRED)
|
||||
MESSAGE(FATAL_ERROR "Could not find mbedTLS")
|
||||
ENDIF(mbedTLS_FIND_REQUIRED)
|
||||
ENDIF(MBEDTLS_FIND_REQUIRED)
|
||||
ENDIF(MBEDTLS_FOUND)
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
@@ -67,4 +67,4 @@ MARK_AS_ADVANCED(
|
||||
MBEDTLS_LIBRARY
|
||||
MBEDX509_LIBRARY
|
||||
MBEDCRYPTO_LIBRARY
|
||||
)
|
||||
)
|
||||
@@ -55,7 +55,7 @@ macro(add_imhex_plugin)
|
||||
# Configure build properties
|
||||
set_target_properties(${IMHEX_PLUGIN_NAME}
|
||||
PROPERTIES
|
||||
RUNTIME_OUTPUT_DIRECTORY "${IMHEX_MAIN_OUTPUT_DIRECTORY}/plugins"
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins
|
||||
CXX_STANDARD 23
|
||||
PREFIX ""
|
||||
SUFFIX ${IMHEX_PLUGIN_SUFFIX}
|
||||
@@ -72,23 +72,10 @@ macro(add_imhex_plugin)
|
||||
add_subdirectory(${IMHEX_BASE_FOLDER}/lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
|
||||
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE ${LIBROMFS_LIBRARY})
|
||||
|
||||
set(FEATURE_DEFINE_CONTENT)
|
||||
|
||||
if (IMHEX_PLUGIN_FEATURES)
|
||||
list(LENGTH IMHEX_PLUGIN_FEATURES IMHEX_FEATURE_COUNT)
|
||||
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})
|
||||
foreach(feature ${IMHEX_PLUGIN_FEATURES})
|
||||
string(TOUPPER ${feature} feature)
|
||||
add_definitions(-DIMHEX_PLUGIN_${IMHEX_PLUGIN_NAME}_FEATURE_${feature}=0)
|
||||
endforeach()
|
||||
|
||||
# Add the new plugin to the main dependency list so it gets built by default
|
||||
if (TARGET imhex_all)
|
||||
@@ -101,28 +88,12 @@ macro(add_imhex_plugin)
|
||||
|
||||
# Fix rpath
|
||||
if (APPLE)
|
||||
set_target_properties(
|
||||
${IMHEX_PLUGIN_NAME}
|
||||
PROPERTIES
|
||||
INSTALL_RPATH "@executable_path/../Frameworks;@executable_path/plugins"
|
||||
)
|
||||
set_target_properties(${IMHEX_PLUGIN_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks;@executable_path/plugins")
|
||||
elseif (UNIX)
|
||||
set(PLUGIN_RPATH "")
|
||||
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}"
|
||||
)
|
||||
set_target_properties(${IMHEX_PLUGIN_NAME} PROPERTIES INSTALL_RPATH_USE_ORIGIN ON INSTALL_RPATH "$ORIGIN/")
|
||||
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)
|
||||
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")
|
||||
@@ -130,10 +101,6 @@ macro(add_imhex_plugin)
|
||||
endmacro()
|
||||
|
||||
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)
|
||||
|
||||
list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/romfs)
|
||||
|
||||
@@ -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)
|
||||
|
||||
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)
|
||||
|
||||
set(LIBPL_ENABLE_CLI OFF CACHE BOOL "" FORCE)
|
||||
|
||||
21
dist/AppImageBuilder.yml
vendored
21
dist/AppImageBuilder.yml
vendored
@@ -14,23 +14,22 @@ AppDir:
|
||||
- amd64
|
||||
allow_unauthenticated: true
|
||||
sources:
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular main restricted
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-updates main restricted
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular universe
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-updates universe
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular multiverse
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-updates multiverse
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ oracular-backports main restricted
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy main restricted
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates main restricted
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy universe
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates universe
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy multiverse
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-updates multiverse
|
||||
- sourceline: deb http://us.archive.ubuntu.com/ubuntu/ jammy-backports main restricted
|
||||
universe multiverse
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu oracular-security main restricted
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu oracular-security universe
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu oracular-security multiverse
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security main restricted
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security universe
|
||||
- sourceline: deb http://security.ubuntu.com/ubuntu jammy-security multiverse
|
||||
include:
|
||||
- librsvg2-common
|
||||
- libbz2-1.0:amd64
|
||||
- libcap2:amd64
|
||||
- libdbus-1-3:amd64
|
||||
- libfontconfig1:amd64
|
||||
- libgpg-error0:amd64
|
||||
- liblzma5:amd64
|
||||
- libnss-mdns:amd64
|
||||
|
||||
1
dist/Arch/Dockerfile
vendored
1
dist/Arch/Dockerfile
vendored
@@ -13,7 +13,6 @@ RUN pacman -S --needed --noconfirm \
|
||||
glfw-x11 \
|
||||
file \
|
||||
mbedtls \
|
||||
fontconfig \
|
||||
freetype2 \
|
||||
curl \
|
||||
dbus \
|
||||
|
||||
4
dist/Arch/PKGBUILD
vendored
4
dist/Arch/PKGBUILD
vendored
@@ -8,7 +8,7 @@ pkgdesc="A Hex Editor for Reverse Engineers, Programmers and people who value th
|
||||
arch=("x86_64")
|
||||
url="https://github.com/WerWolv/ImHex"
|
||||
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)
|
||||
provides=(imhex)
|
||||
conflicts=(imhex)
|
||||
@@ -26,5 +26,5 @@ package() {
|
||||
|
||||
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/"{applications,licenses,pixmaps,mime} "$pkgdir/usr/share"
|
||||
cp -r "$srcdir/usr/share/"{applications,licenses,pixmaps} "$pkgdir/usr/share"
|
||||
}
|
||||
|
||||
1
dist/Brewfile
vendored
1
dist/Brewfile
vendored
@@ -6,6 +6,7 @@ brew "freetype2"
|
||||
brew "libmagic"
|
||||
brew "pkg-config"
|
||||
brew "curl"
|
||||
brew "gcc@12"
|
||||
brew "llvm"
|
||||
brew "glfw"
|
||||
brew "ninja"
|
||||
|
||||
2
dist/DEBIAN/control.in
vendored
2
dist/DEBIAN/control.in
vendored
@@ -4,7 +4,7 @@ Section: editors
|
||||
Priority: optional
|
||||
Architecture: amd64
|
||||
License: GNU GPL-2
|
||||
Depends: 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>
|
||||
Description: ImHex Hex Editor
|
||||
A Hex Editor for Reverse Engineers, Programmers and
|
||||
|
||||
13
dist/ImHex-9999.ebuild
vendored
13
dist/ImHex-9999.ebuild
vendored
@@ -20,14 +20,13 @@ DEPEND=""
|
||||
RDEPEND="${DEPEND}
|
||||
media-libs/glfw
|
||||
sys-apps/file
|
||||
net-libs/mbedtls
|
||||
dev-libs/mbedtls
|
||||
dev-cpp/nlohmann_json
|
||||
sys-apps/dbus
|
||||
sys-apps/xdg-desktop-portal
|
||||
dbus
|
||||
xdg-desktop-portal
|
||||
sys-libs/zlib
|
||||
app-arch/bzip2
|
||||
app-arch/lzma
|
||||
app-arch/zstd
|
||||
app-arch/lz4
|
||||
app-arch/bzip2
|
||||
app-arch/lzma
|
||||
app-arch/zstd
|
||||
"
|
||||
BDEPEND="${DEPEND}"
|
||||
|
||||
28
dist/appimage/Dockerfile
vendored
28
dist/appimage/Dockerfile
vendored
@@ -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
|
||||
# See https://github.com/moby/moby/issues/41715#issuecomment-733976493
|
||||
@@ -14,13 +14,24 @@ apt update
|
||||
# general deps
|
||||
apt install -y ccache git wget
|
||||
# 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
|
||||
|
||||
# imhex deps
|
||||
/tmp/get_deps_debian.sh
|
||||
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}"
|
||||
|
||||
# Copy Imhex source
|
||||
@@ -36,7 +47,7 @@ RUN <<EOF
|
||||
# Prepare ImHex build
|
||||
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_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
@@ -60,18 +71,9 @@ ccache -s
|
||||
EOF
|
||||
|
||||
RUN <<EOF
|
||||
# Download appimage-builder
|
||||
# Package ImHex as AppImage
|
||||
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)
|
||||
appimage-builder --recipe /imhex/dist/AppImageBuilder.yml
|
||||
EOF
|
||||
|
||||
48
dist/gen_release_notes.py
vendored
48
dist/gen_release_notes.py
vendored
@@ -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))
|
||||
4
dist/get_deps_archlinux.sh
vendored
4
dist/get_deps_archlinux.sh
vendored
@@ -5,7 +5,6 @@ pacman -S $@ --needed \
|
||||
gcc \
|
||||
lld \
|
||||
glfw \
|
||||
fontconfig \
|
||||
file \
|
||||
mbedtls \
|
||||
freetype2 \
|
||||
@@ -19,5 +18,4 @@ pacman -S $@ --needed \
|
||||
zlib \
|
||||
bzip2 \
|
||||
xz \
|
||||
zstd \
|
||||
lz4
|
||||
zstd
|
||||
|
||||
8
dist/get_deps_debian.sh
vendored
8
dist/get_deps_debian.sh
vendored
@@ -8,8 +8,8 @@ fi
|
||||
|
||||
apt install -y \
|
||||
build-essential \
|
||||
gcc-14 \
|
||||
g++-14 \
|
||||
gcc-12 \
|
||||
g++-12 \
|
||||
lld \
|
||||
${PKGCONF:-} \
|
||||
cmake \
|
||||
@@ -18,7 +18,6 @@ apt install -y \
|
||||
libglm-dev \
|
||||
libmagic-dev \
|
||||
libmbedtls-dev \
|
||||
libfontconfig-dev \
|
||||
libfreetype-dev \
|
||||
libdbus-1-dev \
|
||||
libcurl4-gnutls-dev \
|
||||
@@ -27,5 +26,4 @@ apt install -y \
|
||||
zlib1g-dev \
|
||||
libbz2-dev \
|
||||
liblzma-dev \
|
||||
libzstd-dev \
|
||||
liblz4-dev
|
||||
libzstd-dev
|
||||
|
||||
4
dist/get_deps_fedora.sh
vendored
4
dist/get_deps_fedora.sh
vendored
@@ -4,7 +4,6 @@ dnf install -y \
|
||||
cmake \
|
||||
dbus-devel \
|
||||
file-devel \
|
||||
fontconfig-devel \
|
||||
freetype-devel \
|
||||
libcurl-devel \
|
||||
gcc-c++ \
|
||||
@@ -17,5 +16,4 @@ dnf install -y \
|
||||
libzstd-devel \
|
||||
zlib-devel \
|
||||
bzip2-devel \
|
||||
xz-devel \
|
||||
lz4-devel
|
||||
xz-devel
|
||||
3
dist/get_deps_msys2.sh
vendored
3
dist/get_deps_msys2.sh
vendored
@@ -17,5 +17,4 @@ pacboy -S --needed --noconfirm \
|
||||
zlib:p \
|
||||
bzip2:p \
|
||||
xz:p \
|
||||
zstd:p \
|
||||
lz4:p
|
||||
zstd:p
|
||||
|
||||
21
dist/get_deps_tumbleweed.sh
vendored
21
dist/get_deps_tumbleweed.sh
vendored
@@ -1,21 +0,0 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
zypper install \
|
||||
cmake \
|
||||
ninja \
|
||||
gcc14 \
|
||||
gcc14-c++ \
|
||||
fontconfig-devel \
|
||||
freetype2-devel \
|
||||
libcurl-devel \
|
||||
dbus-1-devel \
|
||||
file-devel \
|
||||
Mesa-libGL-devel \
|
||||
libglfw-devel \
|
||||
mbedtls-devel \
|
||||
gtk3-devel \
|
||||
libzstd-devel \
|
||||
zlib-devel \
|
||||
bzip3-devel \
|
||||
xz-devel \
|
||||
lz4-dev
|
||||
2
dist/imhex.desktop
vendored
2
dist/imhex.desktop
vendored
@@ -8,5 +8,3 @@ Type=Application
|
||||
StartupNotify=true
|
||||
Categories=Development;IDE;
|
||||
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
8
dist/imhex.mime.xml
vendored
@@ -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>
|
||||
244
dist/langtool.py
vendored
Executable file → Normal file
244
dist/langtool.py
vendored
Executable file → Normal file
@@ -1,214 +1,104 @@
|
||||
#!/usr/bin/env python3
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
import sys
|
||||
import json
|
||||
|
||||
# This fixes a CJK full-width character input issue
|
||||
# which makes left halves of deleted characters displayed on screen
|
||||
# pylint: disable=unused-import
|
||||
import re
|
||||
import readline
|
||||
|
||||
DEFAULT_LANG = "en_US"
|
||||
DEFAULT_LANG_PATH = "plugins/*/romfs/lang/"
|
||||
INVALID_TRANSLATION = ""
|
||||
|
||||
|
||||
def handle_missing_key(command, lang_data, key, value):
|
||||
if command == "check":
|
||||
print(f"Error: Translation {lang_data['code']} is missing translation for key '{key}'")
|
||||
exit(2)
|
||||
elif command == "translate" or command == "create":
|
||||
print(f"Key \033[1m'{key}': '{value}'\033[0m is missing in translation '{lang_data['code']}'")
|
||||
new_value = input("Enter translation: ")
|
||||
lang_data["translations"][key] = new_value
|
||||
elif command == "update":
|
||||
lang_data["translations"][key] = INVALID_TRANSLATION
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="langtool",
|
||||
description="ImHex translate tool",
|
||||
)
|
||||
parser.add_argument(
|
||||
"command",
|
||||
choices=[
|
||||
"check",
|
||||
"translate",
|
||||
"update",
|
||||
"create",
|
||||
"retranslate",
|
||||
"untranslate",
|
||||
"fmtzh",
|
||||
],
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c", "--langdir", default=DEFAULT_LANG_PATH, help="Language folder glob"
|
||||
)
|
||||
parser.add_argument("-l", "--lang", default="", help="Language to translate")
|
||||
parser.add_argument(
|
||||
"-r", "--reflang", default="", help="Language for reference when translating"
|
||||
)
|
||||
parser.add_argument(
|
||||
"-k", "--keys", help="Keys to re-translate (only in re/untranslate mode)"
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
command = args.command
|
||||
lang = args.lang
|
||||
|
||||
print(f"Running in {command} mode")
|
||||
lang_files_glob = f"{lang}.json" if lang != "" else "*.json"
|
||||
|
||||
lang_folders = set(Path(".").glob(args.langdir))
|
||||
if len(lang_folders) == 0:
|
||||
print(f"Error: {args.langdir} matches nothing")
|
||||
if len(sys.argv) < 3:
|
||||
print(f"Usage: {Path(sys.argv[0]).name} <check|translate|update|create> <lang folder path> <language>")
|
||||
return 1
|
||||
|
||||
for lang_folder in lang_folders:
|
||||
if not lang_folder.is_dir():
|
||||
print(f"Error: {lang_folder} is not a folder")
|
||||
return 1
|
||||
command = sys.argv[1]
|
||||
if command not in ["check", "translate", "update", "create"]:
|
||||
print(f"Unknown command: {command}")
|
||||
return 1
|
||||
|
||||
default_lang_data = {}
|
||||
default_lang_path = lang_folder / Path(DEFAULT_LANG + ".json")
|
||||
if not default_lang_path.exists():
|
||||
print(
|
||||
f"Error: Default language file {default_lang_path} does not exist in {lang_folder}"
|
||||
)
|
||||
return 1
|
||||
with default_lang_path.open("r", encoding="utf-8") as file:
|
||||
default_lang_data = json.load(file)
|
||||
print(f"Using langtool in {command} mode")
|
||||
|
||||
reference_lang_data = None
|
||||
reference_lang_path = lang_folder / Path(args.reflang + ".json")
|
||||
if reference_lang_path.exists():
|
||||
with reference_lang_path.open("r", encoding="utf-8") as file:
|
||||
reference_lang_data = json.load(file)
|
||||
lang_folder_path = Path(sys.argv[2])
|
||||
if not lang_folder_path.exists():
|
||||
print(f"Error: {lang_folder_path} does not exist")
|
||||
return 1
|
||||
|
||||
if not lang_folder_path.is_dir():
|
||||
print(f"Error: {lang_folder_path} is not a folder")
|
||||
return 1
|
||||
|
||||
lang = sys.argv[3] if len(sys.argv) > 3 else ""
|
||||
|
||||
print(f"Processing language files in {lang_folder_path}...")
|
||||
|
||||
default_lang_file_path = lang_folder_path / Path(DEFAULT_LANG + ".json")
|
||||
if not default_lang_file_path.exists():
|
||||
print(f"Error: Default language file {default_lang_file_path} does not exist")
|
||||
return 1
|
||||
|
||||
print(f"Using file '{default_lang_file_path.name}' as template language file")
|
||||
|
||||
with default_lang_file_path.open("r", encoding="utf-8") as default_lang_file:
|
||||
default_lang_data = json.load(default_lang_file)
|
||||
|
||||
if command == "create" and lang != "":
|
||||
lang_file_path = lang_folder / Path(lang + ".json")
|
||||
lang_file_path = lang_folder_path / Path(lang + ".json")
|
||||
if lang_file_path.exists():
|
||||
continue
|
||||
print(f"Error: Language file {lang_file_path} already exists")
|
||||
return 1
|
||||
|
||||
exist_lang_data = None
|
||||
for lang_folder1 in lang_folders:
|
||||
lang_file_path1 = lang_folder1 / Path(lang + ".json")
|
||||
if lang_file_path1.exists():
|
||||
with lang_file_path1.open("r", encoding="utf-8") as file:
|
||||
exist_lang_data = json.load(file)
|
||||
break
|
||||
|
||||
print(f"Creating new language file '{lang_file_path}'")
|
||||
print(f"Creating new language file '{lang_file_path.name}'")
|
||||
|
||||
with lang_file_path.open("w", encoding="utf-8") as new_lang_file:
|
||||
new_lang_data = {
|
||||
"code": lang,
|
||||
"language": (
|
||||
exist_lang_data["language"]
|
||||
if exist_lang_data
|
||||
else input("Enter language name: ")
|
||||
),
|
||||
"country": (
|
||||
exist_lang_data["country"]
|
||||
if exist_lang_data
|
||||
else input("Enter country name: ")
|
||||
),
|
||||
"translations": {},
|
||||
"language": input("Enter language: "),
|
||||
"country": input("Enter country: "),
|
||||
"translations": {}
|
||||
}
|
||||
json.dump(new_lang_data, new_lang_file, indent=4, ensure_ascii=False)
|
||||
|
||||
lang_files = set(lang_folder.glob(lang_files_glob))
|
||||
if len(lang_files) == 0:
|
||||
print(f"Warn: Language file for '{lang}' does not exist in '{lang_folder}'")
|
||||
for lang_file_path in lang_files:
|
||||
if (
|
||||
lang_file_path.stem == f"{DEFAULT_LANG}.json"
|
||||
or lang_file_path.stem == f"{args.reflang}.json"
|
||||
):
|
||||
for additional_lang_file_path in lang_folder_path.glob("*.json"):
|
||||
if not lang == "" and not additional_lang_file_path.stem == lang:
|
||||
continue
|
||||
|
||||
print(f"\nProcessing '{lang_file_path}'")
|
||||
if not (command == "update" or command == "create"):
|
||||
print("\n----------------------------\n")
|
||||
if additional_lang_file_path.name.startswith(DEFAULT_LANG):
|
||||
continue
|
||||
|
||||
with lang_file_path.open("r+", encoding="utf-8") as target_lang_file:
|
||||
lang_data = json.load(target_lang_file)
|
||||
print(f"\nProcessing file '{additional_lang_file_path.name}'\n----------------------------\n")
|
||||
|
||||
with additional_lang_file_path.open("r+", encoding="utf-8") as additional_lang_file:
|
||||
additional_lang_data = json.load(additional_lang_file)
|
||||
|
||||
for key, value in default_lang_data["translations"].items():
|
||||
has_translation = (
|
||||
key in lang_data["translations"]
|
||||
and lang_data["translations"][key] != INVALID_TRANSLATION
|
||||
)
|
||||
if (
|
||||
has_translation
|
||||
and not (
|
||||
(command == "retranslate" or command == "untranslate")
|
||||
and re.compile(args.keys).fullmatch(key)
|
||||
)
|
||||
and not command == "fmtzh"
|
||||
):
|
||||
continue
|
||||
if command == "check":
|
||||
print(
|
||||
f"Error: Translation {lang_data['code']} is missing translation for key '{key}'"
|
||||
)
|
||||
elif (
|
||||
command == "translate"
|
||||
or command == "retranslate"
|
||||
or command == "untranslate"
|
||||
):
|
||||
if command == "untranslate" and not has_translation:
|
||||
continue
|
||||
reference_tranlsation = (
|
||||
" '%s'" % reference_lang_data["translations"][key]
|
||||
if (
|
||||
reference_lang_data
|
||||
and key in reference_lang_data["translations"]
|
||||
)
|
||||
else ""
|
||||
)
|
||||
print(
|
||||
f"\033[1m'{key}' '{value}'{reference_tranlsation}\033[0m => {lang_data['language']}",
|
||||
end="",
|
||||
)
|
||||
if has_translation:
|
||||
translation = lang_data["translations"][key]
|
||||
print(f" <= \033[1m'{translation}'\033[0m")
|
||||
print() # for a new line
|
||||
if command == "untranslate":
|
||||
lang_data["translations"][key] = INVALID_TRANSLATION
|
||||
continue
|
||||
try:
|
||||
new_value = input("=> ")
|
||||
lang_data["translations"][key] = new_value
|
||||
except KeyboardInterrupt:
|
||||
break
|
||||
elif command == "update" or command == "create":
|
||||
lang_data["translations"][key] = INVALID_TRANSLATION
|
||||
elif command == "fmtzh":
|
||||
if has_translation:
|
||||
lang_data["translations"][key] = fmtzh(
|
||||
lang_data["translations"][key]
|
||||
)
|
||||
if key not in additional_lang_data["translations"] or additional_lang_data["translations"][key] == INVALID_TRANSLATION:
|
||||
handle_missing_key(command, additional_lang_data, key, value)
|
||||
|
||||
keys_to_remove = []
|
||||
for key, value in lang_data["translations"].items():
|
||||
for key, value in additional_lang_data["translations"].items():
|
||||
if key not in default_lang_data["translations"]:
|
||||
keys_to_remove.append(key)
|
||||
|
||||
for key in keys_to_remove:
|
||||
lang_data["translations"].pop(key)
|
||||
print(
|
||||
f"Removed unused key '{key}' from translation '{lang_data['code']}'"
|
||||
)
|
||||
additional_lang_data["translations"].pop(key)
|
||||
print(f"Removed unused key '{key}' from translation '{additional_lang_data['code']}'")
|
||||
|
||||
target_lang_file.seek(0)
|
||||
target_lang_file.truncate()
|
||||
json.dump(
|
||||
lang_data,
|
||||
target_lang_file,
|
||||
indent=4,
|
||||
sort_keys=True,
|
||||
ensure_ascii=False,
|
||||
)
|
||||
additional_lang_file.seek(0)
|
||||
additional_lang_file.truncate()
|
||||
json.dump(additional_lang_data, additional_lang_file, indent=4, sort_keys=True, ensure_ascii=False)
|
||||
|
||||
|
||||
def fmtzh(text: str) -> str:
|
||||
text = re.sub(r"(\.{3}|\.{6})", "……", text)
|
||||
text = text.replace("!", "!")
|
||||
text = re.sub(r"([^\.\na-zA-Z\d])\.$", "\1。", text, flags=re.M)
|
||||
text = text.replace("?", "?")
|
||||
return text
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if __name__ == '__main__':
|
||||
exit(main())
|
||||
|
||||
12
dist/macOS/arm64.Dockerfile
vendored
12
dist/macOS/arm64.Dockerfile
vendored
@@ -1,7 +1,7 @@
|
||||
# This base image is also known as "crosscompile". See arm64.crosscompile.Dockerfile
|
||||
FROM ghcr.io/itrooz/macos-crosscompile:clang17-nosdk as build
|
||||
|
||||
ENV MACOSX_DEPLOYMENT_TARGET 13.0
|
||||
ENV MACOSX_DEPLOYMENT_TARGET 12.1
|
||||
|
||||
# -- DOWNLOADING STUFF
|
||||
|
||||
@@ -35,9 +35,9 @@ EOF
|
||||
|
||||
## Download libmagic
|
||||
### Clone libmagic
|
||||
RUN git clone --depth 1 --branch FILE5_45 https://github.com/file/file /mnt/file
|
||||
RUN git clone https://github.com/file/file /mnt/file
|
||||
### Download libmagic dependencies
|
||||
RUN --mount=type=cache,target=/var/lib/apt/lists/ apt update && apt install -y libtool autoconf
|
||||
RUN --mount=type=cache,target=/var/lib/apt/lists/ apt install -y libtool autoconf
|
||||
|
||||
# -- DOWNLOADING + BUILDING STUFF
|
||||
|
||||
@@ -118,7 +118,7 @@ if [ "$CUSTOM_GLFW" ]; then
|
||||
cd /mnt/glfw
|
||||
mkdir 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 \
|
||||
-DBUILD_SHARED_LIBS=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
@@ -126,7 +126,7 @@ if [ "$CUSTOM_GLFW" ]; then
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-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
|
||||
|
||||
@@ -148,7 +148,7 @@ RUN --mount=type=cache,target=/cache --mount=type=cache,target=/mnt/ImHex/build/
|
||||
`# ccache flags` \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_OBJC_COMPILER_LAUNCHER=ccache -DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
`# 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` \
|
||||
-DNATIVE_CMAKE_C_COMPILER=/usr/bin/clang -DNATIVE_CMAKE_CXX_COMPILER=/usr/bin/clang++ \
|
||||
`# Normal ImHex flags` \
|
||||
|
||||
13
dist/macOS/arm64.crosscompile.Dockerfile
vendored
13
dist/macOS/arm64.crosscompile.Dockerfile
vendored
@@ -68,6 +68,19 @@ RUN --mount=type=cache,target=/cache <<EOF
|
||||
|
||||
ccache -s
|
||||
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
|
||||
RUN <<EOF
|
||||
|
||||
19
dist/rpm/imhex.spec
vendored
19
dist/rpm/imhex.spec
vendored
@@ -1,5 +1,3 @@
|
||||
%define source_date_epoch_from_changelog 0
|
||||
|
||||
Name: imhex
|
||||
Version: VERSION
|
||||
Release: 0%{?dist}
|
||||
@@ -16,7 +14,6 @@ BuildRequires: cmake
|
||||
BuildRequires: desktop-file-utils
|
||||
BuildRequires: dbus-devel
|
||||
BuildRequires: file-devel
|
||||
BuildRequires: fontconfig-devel
|
||||
BuildRequires: freetype-devel
|
||||
BuildRequires: fmt-devel
|
||||
BuildRequires: gcc-c++
|
||||
@@ -35,7 +32,7 @@ BuildRequires: zlib-devel
|
||||
BuildRequires: bzip2-devel
|
||||
BuildRequires: xz-devel
|
||||
%if 0%{?rhel}
|
||||
BuildRequires: gcc-toolset-14
|
||||
BuildRequires: gcc-toolset-12
|
||||
%endif
|
||||
|
||||
Provides: bundled(gnulib)
|
||||
@@ -71,9 +68,9 @@ rm -rf lib/third_party/{fmt,nlohmann_json,yara}
|
||||
|
||||
%build
|
||||
%if 0%{?rhel}
|
||||
. /opt/rh/gcc-toolset-14/enable
|
||||
. /opt/rh/gcc-toolset-12/enable
|
||||
%set_build_flags
|
||||
CXXFLAGS+=" -std=gnu++23"
|
||||
CXXFLAGS+=" -std=gnu++2b"
|
||||
%endif
|
||||
%cmake \
|
||||
-D CMAKE_BUILD_TYPE=Release \
|
||||
@@ -94,9 +91,9 @@ CXXFLAGS+=" -std=gnu++23"
|
||||
|
||||
%check
|
||||
%if 0%{?rhel}
|
||||
. /opt/rh/gcc-toolset-14/enable
|
||||
. /opt/rh/gcc-toolset-12/enable
|
||||
%set_build_flags
|
||||
CXXFLAGS+=" -std=gnu++23"
|
||||
CXXFLAGS+=" -std=gnu++2b"
|
||||
%endif
|
||||
|
||||
|
||||
@@ -125,7 +122,9 @@ cp -a lib/third_party/xdgpp/LICENSE %{buildroot
|
||||
%{_bindir}/imhex-updater
|
||||
%{_datadir}/pixmaps/%{name}.png
|
||||
%{_datadir}/applications/%{name}.desktop
|
||||
%{_datadir}/mime/packages/%{name}.xml
|
||||
%{_libdir}/libimhex.so*
|
||||
%{_libdir}/%{name}/
|
||||
%{_metainfodir}/net.werwolv.%{name}.metainfo.xml
|
||||
%{_metainfodir}/net.werwolv.%{name}.metainfo.xml
|
||||
|
||||
|
||||
%changelog
|
||||
|
||||
6
dist/web/Dockerfile
vendored
6
dist/web/Dockerfile
vendored
@@ -5,7 +5,7 @@ FROM emscripten/emsdk:3.1.51 as build
|
||||
ARG UNIQUEKEY 1
|
||||
|
||||
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
|
||||
# Install vcpkg
|
||||
@@ -56,11 +56,9 @@ set -xe
|
||||
ccache -zs
|
||||
|
||||
cmake /imhex \
|
||||
-G "Ninja" \
|
||||
-DIMHEX_OFFLINE_BUILD=ON \
|
||||
-DIMHEX_STATIC_LINK_PLUGINS=ON \
|
||||
-DIMHEX_EXCLUDE_PLUGINS="script_loader" \
|
||||
-DIMHEX_COMPRESS_DEBUG_INFO=OFF \
|
||||
-DNATIVE_CMAKE_C_COMPILER=gcc \
|
||||
-DNATIVE_CMAKE_CXX_COMPILER=g++ \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
@@ -69,7 +67,7 @@ cmake /imhex
|
||||
-DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake \
|
||||
-DCMAKE_BUILD_TYPE=Release
|
||||
|
||||
ninja -j $JOBS
|
||||
make -j $JOBS
|
||||
|
||||
cp /imhex/dist/web/source/* /build
|
||||
ccache -s
|
||||
|
||||
2
dist/web/source/index.html
vendored
2
dist/web/source/index.html
vendored
@@ -62,7 +62,7 @@
|
||||
</head>
|
||||
<body>
|
||||
<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>
|
||||
<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>
|
||||
|
||||
13
dist/web/source/style.css
vendored
13
dist/web/source/style.css
vendored
@@ -137,7 +137,7 @@ a:hover {
|
||||
|
||||
|
||||
:root {
|
||||
--progress: 0%;
|
||||
--progress: 25%;
|
||||
}
|
||||
|
||||
.progress-bar-container {
|
||||
@@ -174,15 +174,4 @@ a:hover {
|
||||
.progress-moved .progress-bar {
|
||||
width: var(--progress);
|
||||
background-color: #3864cb;
|
||||
}
|
||||
|
||||
#logo {
|
||||
height: 25%;
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.canvas-fixed {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
142
dist/web/source/wasm-config.js
vendored
142
dist/web/source/wasm-config.js
vendored
@@ -100,77 +100,7 @@ var notWorkingTimer = setTimeout(() => {
|
||||
|
||||
var Module = {
|
||||
preRun: [],
|
||||
postRun: function() {
|
||||
// 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));
|
||||
}
|
||||
};
|
||||
},
|
||||
postRun: [],
|
||||
onRuntimeInitialized: function() {
|
||||
// Triggered when the wasm module is loaded and ready to use.
|
||||
document.getElementById("loading").style.display = "none"
|
||||
@@ -181,55 +111,13 @@ var Module = {
|
||||
print: (function() { })(),
|
||||
printErr: function(text) { },
|
||||
canvas: (function() {
|
||||
const canvas = document.getElementById('canvas');
|
||||
canvas.addEventListener("webglcontextlost", function(e) {
|
||||
alert('WebGL context lost, please reload the page');
|
||||
e.preventDefault();
|
||||
}, false);
|
||||
let canvas = document.getElementById('canvas');
|
||||
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
|
||||
// application robust, you may want to override this behavior before shipping!
|
||||
// See http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.15.2
|
||||
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
|
||||
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');
|
||||
}
|
||||
return canvas;
|
||||
})(),
|
||||
setStatus: function(text) { },
|
||||
totalDependencies: 0,
|
||||
@@ -256,16 +144,14 @@ if (urlParams.has("lang")) {
|
||||
window.addEventListener('resize', js_resizeCanvas, false);
|
||||
function js_resizeCanvas() {
|
||||
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.height = Math.min(document.documentElement.clientHeight, window.innerHeight || 0);
|
||||
}
|
||||
|
||||
// Prevent some default browser shortcuts from preventing ImHex ones to work
|
||||
document.addEventListener('keydown', e => {
|
||||
if (e.ctrlKey) {
|
||||
if (e.which == 83) e.preventDefault();
|
||||
canvas.classList.add("canvas_full_screen")
|
||||
|
||||
if (GLFW.active && GLFW.active.windowPosFunc) {
|
||||
getWasmTableEntry(GLFW.active.windowPosFunc)(GLFW.active.id, GLFW.active.x, GLFW.active.y);
|
||||
}
|
||||
})
|
||||
|
||||
GLFW.onWindowSizeChanged();
|
||||
}
|
||||
2
lib/external/libwolv
vendored
2
lib/external/libwolv
vendored
Submodule lib/external/libwolv updated: b9d7f4abaf...6b4a9c7ddd
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
Submodule lib/external/pattern_language updated: f45156a55c...7aa467c8be
@@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.16)
|
||||
project(libimhex)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_SHARED_LIBRARY_PREFIX "")
|
||||
|
||||
set(LIBIMHEX_SOURCES
|
||||
source/api/imhex_api.cpp
|
||||
@@ -36,9 +37,6 @@ set(LIBIMHEX_SOURCES
|
||||
source/helpers/logger.cpp
|
||||
source/helpers/tar.cpp
|
||||
source/helpers/debugging.cpp
|
||||
source/helpers/default_paths.cpp
|
||||
source/helpers/imgui_hooks.cpp
|
||||
source/helpers/semantic_version.cpp
|
||||
|
||||
source/test/tests.cpp
|
||||
|
||||
@@ -126,7 +124,7 @@ target_link_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${MBEDTLS_LIBRARY_DIR}
|
||||
|
||||
if (NOT EMSCRIPTEN)
|
||||
# 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()
|
||||
|
||||
|
||||
@@ -145,7 +143,7 @@ if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD)
|
||||
precompileHeaders(libimhex "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
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})
|
||||
|
||||
set_property(TARGET libimhex PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE)
|
||||
|
||||
@@ -153,4 +151,3 @@ add_dependencies(imhex_all libimhex)
|
||||
|
||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}" PERMISSIONS ${LIBRARY_PERMISSIONS})
|
||||
set_target_properties(libimhex PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
set_target_properties(libimhex PROPERTIES PREFIX "")
|
||||
@@ -1,3 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/helpers/types.hpp>
|
||||
#include <hex/helpers/intrinsics.hpp>
|
||||
@@ -151,7 +151,7 @@ namespace hex {
|
||||
if (m_icon.isValid())
|
||||
return m_icon;
|
||||
|
||||
m_icon = ImGuiExt::Texture::fromImage(m_iconData.data(), m_iconData.size(), ImGuiExt::Texture::Filter::Linear);
|
||||
m_icon = ImGuiExt::Texture(m_iconData.data(), m_iconData.size(), ImGuiExt::Texture::Filter::Linear);
|
||||
|
||||
return m_icon;
|
||||
}
|
||||
@@ -295,7 +295,6 @@ namespace hex {
|
||||
};
|
||||
|
||||
class AchievementManager {
|
||||
static bool s_initialized;
|
||||
public:
|
||||
AchievementManager() = delete;
|
||||
|
||||
|
||||
@@ -2,11 +2,10 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
#include <hex/api/shortcut_manager.hpp>
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
@@ -24,6 +23,7 @@ enum ImGuiCustomCol : int;
|
||||
namespace hex {
|
||||
|
||||
class View;
|
||||
class Shortcut;
|
||||
class Task;
|
||||
|
||||
namespace dp {
|
||||
@@ -98,7 +98,7 @@ namespace hex {
|
||||
bool m_requiresRestart = false;
|
||||
std::function<bool()> m_enabledCallback;
|
||||
std::function<void(Widget&)> m_changedCallback;
|
||||
std::optional<UnlocalizedString> m_tooltip;
|
||||
std::optional<std::string> m_tooltip;
|
||||
};
|
||||
|
||||
[[nodiscard]]
|
||||
@@ -112,7 +112,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const std::optional<UnlocalizedString>& getTooltip() const {
|
||||
const std::optional<std::string>& getTooltip() const {
|
||||
return m_interface.m_tooltip;
|
||||
}
|
||||
|
||||
@@ -175,21 +175,6 @@ namespace hex {
|
||||
float m_min, m_max;
|
||||
};
|
||||
|
||||
class SliderDataSize : public Widget {
|
||||
public:
|
||||
SliderDataSize(u64 defaultValue, u64 min, u64 max) : m_value(defaultValue), m_min(min), m_max(max) { }
|
||||
bool draw(const std::string &name) override;
|
||||
|
||||
void load(const nlohmann::json &data) override;
|
||||
nlohmann::json store() override;
|
||||
|
||||
[[nodiscard]] i32 getValue() const { return m_value; }
|
||||
|
||||
protected:
|
||||
u64 m_value;
|
||||
u64 m_min, m_max;
|
||||
};
|
||||
|
||||
class ColorPicker : public Widget {
|
||||
public:
|
||||
explicit ColorPicker(ImColor defaultColor);
|
||||
@@ -355,8 +340,6 @@ namespace hex {
|
||||
void write(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const std::common_type_t<T> &value) {
|
||||
impl::getSetting(unlocalizedCategory, unlocalizedName, value) = value;
|
||||
impl::runOnChangeHandlers(unlocalizedCategory, unlocalizedName, value);
|
||||
|
||||
impl::store();
|
||||
}
|
||||
|
||||
using OnChangeCallback = std::function<void(const SettingsValue &)>;
|
||||
@@ -380,7 +363,7 @@ namespace hex {
|
||||
};
|
||||
|
||||
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)>;
|
||||
|
||||
struct Entry {
|
||||
@@ -416,7 +399,7 @@ namespace hex {
|
||||
const std::string &command,
|
||||
const UnlocalizedString &unlocalizedDescription,
|
||||
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
|
||||
@@ -437,7 +420,7 @@ namespace hex {
|
||||
|
||||
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 {
|
||||
pl::api::Namespace ns;
|
||||
@@ -449,14 +432,6 @@ namespace hex {
|
||||
bool dangerous;
|
||||
};
|
||||
|
||||
struct TypeDefinition {
|
||||
pl::api::Namespace ns;
|
||||
std::string name;
|
||||
|
||||
pl::api::FunctionParameterCount parameterCount;
|
||||
pl::api::TypeCallback callback;
|
||||
};
|
||||
|
||||
struct Visualizer {
|
||||
pl::api::FunctionParameterCount parameterCount;
|
||||
VisualizerFunctionCallback callback;
|
||||
@@ -466,7 +441,6 @@ namespace hex {
|
||||
const std::map<std::string, Visualizer>& getInlineVisualizers();
|
||||
const std::map<std::string, pl::api::PragmaHandler>& getPragmas();
|
||||
const std::vector<FunctionDefinition>& getFunctions();
|
||||
const std::vector<TypeDefinition>& getTypes();
|
||||
|
||||
}
|
||||
|
||||
@@ -525,20 +499,6 @@ namespace hex {
|
||||
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
|
||||
* @note Visualizers are extensions to the [[hex::visualize]] attribute, used to visualize data
|
||||
@@ -770,7 +730,7 @@ namespace hex {
|
||||
struct MenuItem {
|
||||
std::vector<UnlocalizedString> unlocalizedNames;
|
||||
Icon icon;
|
||||
Shortcut shortcut;
|
||||
std::unique_ptr<Shortcut> shortcut;
|
||||
View *view;
|
||||
MenuCallback callback;
|
||||
EnabledCallback enabledCallback;
|
||||
@@ -796,7 +756,6 @@ namespace hex {
|
||||
const std::multimap<u32, MainMenuItem>& getMainMenuItems();
|
||||
|
||||
const std::multimap<u32, MenuItem>& getMenuItems();
|
||||
const std::vector<MenuItem*>& getToolbarMenuItems();
|
||||
std::multimap<u32, MenuItem>& getMenuItemsMutable();
|
||||
|
||||
const std::vector<DrawCallback>& getWelcomeScreenEntries();
|
||||
@@ -939,11 +898,6 @@ namespace hex {
|
||||
*/
|
||||
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
|
||||
* @param icon The icon to use for the item
|
||||
@@ -1009,34 +963,12 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
using Callback = std::function<std::string(prv::Provider *provider, u64 address, size_t size)>;
|
||||
struct ExportMenuEntry {
|
||||
struct Entry {
|
||||
UnlocalizedString unlocalizedName;
|
||||
Callback callback;
|
||||
};
|
||||
|
||||
struct FindOccurrence {
|
||||
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();
|
||||
const std::vector<Entry>& getEntries();
|
||||
|
||||
}
|
||||
|
||||
@@ -1046,14 +978,7 @@ namespace hex {
|
||||
* @param unlocalizedName The unlocalized name of the formatter
|
||||
* @param callback The function to call to format the data
|
||||
*/
|
||||
void addExportMenuEntry(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);
|
||||
void add(const UnlocalizedString &unlocalizedName, const impl::Callback &callback);
|
||||
|
||||
}
|
||||
|
||||
@@ -1114,7 +1039,7 @@ namespace hex {
|
||||
};
|
||||
|
||||
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;
|
||||
Callback callback;
|
||||
@@ -1295,7 +1220,7 @@ namespace hex {
|
||||
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 */
|
||||
|
||||
@@ -2,31 +2,29 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <map>
|
||||
#include <string_view>
|
||||
#include <functional>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/patches.hpp>
|
||||
|
||||
#include <wolv/types/type_name.hpp>
|
||||
|
||||
#define EVENT_DEF_IMPL(event_name, event_name_string, should_log, ...) \
|
||||
struct event_name final : public hex::impl::Event<__VA_ARGS__> { \
|
||||
constexpr static auto Id = [] { return hex::impl::EventId(event_name_string); }(); \
|
||||
constexpr static auto ShouldLog = (should_log); \
|
||||
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 void subscribe(void *token, Event::Callback function) { EventManager::subscribe<event_name>(token, std::move(function)); } \
|
||||
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 post(auto &&...args) { EventManager::post<event_name>(std::forward<decltype(args)>(args)...); } \
|
||||
}
|
||||
#define EVENT_DEF_IMPL(event_name, event_name_string, should_log, ...) \
|
||||
struct event_name final : public hex::impl::Event<__VA_ARGS__> { \
|
||||
constexpr static auto Id = [] { return hex::impl::EventId(event_name_string); }(); \
|
||||
constexpr static auto ShouldLog = (should_log); \
|
||||
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
|
||||
\
|
||||
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, function); } \
|
||||
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 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_NO_LOG(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, false, __VA_ARGS__)
|
||||
@@ -59,10 +57,6 @@ namespace hex {
|
||||
return m_hash == other.m_hash;
|
||||
}
|
||||
|
||||
constexpr auto operator<=>(const EventId &other) const {
|
||||
return m_hash <=> other.m_hash;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_hash;
|
||||
};
|
||||
@@ -78,12 +72,11 @@ namespace hex {
|
||||
|
||||
explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
|
||||
|
||||
template<typename E>
|
||||
void call(Params... params) const {
|
||||
void operator()(std::string_view eventName, Params... params) const {
|
||||
try {
|
||||
m_func(params...);
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
@@ -104,7 +97,7 @@ namespace hex {
|
||||
*/
|
||||
class EventManager {
|
||||
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
|
||||
@@ -117,7 +110,7 @@ namespace hex {
|
||||
std::scoped_lock lock(getEventMutex());
|
||||
|
||||
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 +123,15 @@ namespace hex {
|
||||
static void subscribe(void *token, typename E::Callback function) {
|
||||
std::scoped_lock lock(getEventMutex());
|
||||
|
||||
if (isAlreadyRegistered(token, E::Id)) {
|
||||
log::fatal("The token '{}' has already registered the same event ('{}')", token, wolv::type::getTypeName<E>());
|
||||
return;
|
||||
if (getTokenStore().contains(token)) {
|
||||
auto&& [begin, end] = getTokenStore().equal_range(token);
|
||||
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) });
|
||||
@@ -157,7 +156,16 @@ namespace hex {
|
||||
static void unsubscribe(void *token) noexcept {
|
||||
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 +177,14 @@ namespace hex {
|
||||
static void post(auto && ...args) {
|
||||
std::scoped_lock lock(getEventMutex());
|
||||
|
||||
auto [begin, end] = getEvents().equal_range(E::Id);
|
||||
for (auto it = begin; it != end; ++it) {
|
||||
const auto &[id, event] = *it;
|
||||
(*static_cast<E *const>(event.get())).template call<E>(std::forward<decltype(args)>(args)...);
|
||||
for (const auto &[id, event] : getEvents()) {
|
||||
if (id == E::Id) {
|
||||
(*static_cast<E *const>(event.get()))(wolv::type::getTypeName<E>(), std::forward<decltype(args)>(args)...);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (DEBUG)
|
||||
if constexpr (E::ShouldLog)
|
||||
if (E::ShouldLog)
|
||||
log::debug("Event posted: '{}'", wolv::type::getTypeName<E>());
|
||||
#endif
|
||||
}
|
||||
@@ -195,9 +203,6 @@ namespace hex {
|
||||
static std::multimap<void *, EventList::iterator>& getTokenStore();
|
||||
static EventList& getEvents();
|
||||
static std::recursive_mutex& getEventMutex();
|
||||
|
||||
static bool isAlreadyRegistered(void *token, impl::EventId id);
|
||||
static void unsubscribe(void *token, impl::EventId id);
|
||||
};
|
||||
|
||||
/* Default Events */
|
||||
@@ -215,9 +220,7 @@ namespace hex {
|
||||
EVENT_DEF(EventAbnormalTermination, int);
|
||||
EVENT_DEF(EventThemeChanged);
|
||||
EVENT_DEF(EventOSThemeChanged);
|
||||
EVENT_DEF(EventDPIChanged, float, float);
|
||||
EVENT_DEF(EventWindowFocused, bool);
|
||||
EVENT_DEF(EventImHexUpdated, SemanticVersion, SemanticVersion);
|
||||
|
||||
/**
|
||||
* @brief Called when the provider is created.
|
||||
@@ -243,12 +246,7 @@ namespace hex {
|
||||
EVENT_DEF(EventWindowInitialized);
|
||||
EVENT_DEF(EventWindowDeinitializing, GLFWwindow *);
|
||||
EVENT_DEF(EventBookmarkCreated, ImHexApi::Bookmarks::Entry&);
|
||||
|
||||
/**
|
||||
* @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(EventPatchCreated, u64, u8, u8);
|
||||
EVENT_DEF(EventPatternEvaluating);
|
||||
EVENT_DEF(EventPatternExecuted, const std::string&);
|
||||
EVENT_DEF(EventPatternEditorChanged, const std::string&);
|
||||
@@ -266,7 +264,6 @@ namespace hex {
|
||||
EVENT_DEF(EventProviderDataModified, prv::Provider *, u64, u64, const u8*);
|
||||
EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64);
|
||||
EVENT_DEF(EventProviderDataRemoved, prv::Provider *, u64, u64);
|
||||
EVENT_DEF(EventProviderDirtied, prv::Provider *);
|
||||
|
||||
/**
|
||||
* @brief Called when a project has been loaded
|
||||
@@ -276,7 +273,6 @@ namespace hex {
|
||||
EVENT_DEF_NO_LOG(EventFrameBegin);
|
||||
EVENT_DEF_NO_LOG(EventFrameEnd);
|
||||
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(RequestAddExitTask, std::string, std::function<bool()>);
|
||||
|
||||
@@ -2,15 +2,12 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
#include <hex/helpers/semantic_version.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
@@ -76,7 +73,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
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, HighlightingFunction>& getBackgroundHighlightingFunctions();
|
||||
@@ -294,7 +291,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
void resetClosingProvider();
|
||||
std::set<prv::Provider*> getClosingProviders();
|
||||
const std::vector<prv::Provider*>& getClosingProviders();
|
||||
|
||||
}
|
||||
|
||||
@@ -435,7 +432,6 @@ namespace hex {
|
||||
void setInitialWindowProperties(InitialWindowProperties properties);
|
||||
|
||||
void setGPUVendor(const std::string &vendor);
|
||||
void setGLRenderer(const std::string &renderer);
|
||||
|
||||
void addInitArgument(const std::string &key, const std::string &value = { });
|
||||
|
||||
@@ -575,12 +571,6 @@ namespace hex {
|
||||
*/
|
||||
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
|
||||
* @return Whether ImHex is running in portable mode
|
||||
@@ -605,21 +595,11 @@ namespace hex {
|
||||
*/
|
||||
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
|
||||
* @return ImHex version
|
||||
*/
|
||||
SemanticVersion getImHexVersion();
|
||||
std::string getImHexVersion(bool withBuildType = true);
|
||||
|
||||
/**
|
||||
* @brief Gets the current git commit hash
|
||||
@@ -640,12 +620,6 @@ namespace hex {
|
||||
*/
|
||||
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 {
|
||||
Stable,
|
||||
Nightly
|
||||
@@ -696,13 +670,6 @@ namespace hex {
|
||||
*/
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <wolv/types/static_string.hpp>
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -25,10 +22,8 @@ namespace hex {
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
|
||||
void setFallbackLanguage(const std::string &language);
|
||||
void resetLanguageStrings();
|
||||
|
||||
}
|
||||
|
||||
void loadLanguage(const std::string &language);
|
||||
@@ -37,18 +32,14 @@ namespace hex {
|
||||
[[nodiscard]] const std::map<std::string, std::string> &getSupportedLanguages();
|
||||
[[nodiscard]] const std::string &getFallbackLanguage();
|
||||
[[nodiscard]] const std::string &getSelectedLanguage();
|
||||
|
||||
}
|
||||
|
||||
struct UnlocalizedString;
|
||||
|
||||
class LangConst;
|
||||
|
||||
class Lang {
|
||||
public:
|
||||
explicit Lang(const char *unlocalizedString);
|
||||
explicit Lang(const std::string &unlocalizedString);
|
||||
explicit(false) Lang(const LangConst &localizedString);
|
||||
explicit Lang(const UnlocalizedString &unlocalizedString);
|
||||
explicit Lang(std::string_view unlocalizedString);
|
||||
|
||||
@@ -56,54 +47,30 @@ namespace hex {
|
||||
[[nodiscard]] operator std::string_view() const;
|
||||
[[nodiscard]] operator const char *() const;
|
||||
|
||||
const char* get() const;
|
||||
[[nodiscard]] const std::string &get() const;
|
||||
|
||||
private:
|
||||
std::size_t m_entryHash;
|
||||
std::string m_unlocalizedString;
|
||||
};
|
||||
|
||||
class LangConst {
|
||||
public:
|
||||
[[nodiscard]] operator std::string() const;
|
||||
[[nodiscard]] operator std::string_view() const;
|
||||
[[nodiscard]] operator const char *() const;
|
||||
[[nodiscard]] std::string operator+(const std::string &&left, const Lang &&right);
|
||||
[[nodiscard]] std::string operator+(const Lang &&left, const std::string &&right);
|
||||
[[nodiscard]] std::string operator+(const std::string_view &&left, const Lang &&right);
|
||||
[[nodiscard]] std::string operator+(const Lang &&left, const std::string_view &&right);
|
||||
[[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 {
|
||||
public:
|
||||
UnlocalizedString() = default;
|
||||
|
||||
template<typename T>
|
||||
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!");
|
||||
UnlocalizedString(auto && arg) : m_unlocalizedString(std::forward<decltype(arg)>(arg)) {
|
||||
static_assert(!std::same_as<std::remove_cvref_t<decltype(arg)>, Lang>, "Expected a unlocalized name, got a localized one!");
|
||||
}
|
||||
|
||||
[[nodiscard]] operator std::string() const {
|
||||
@@ -135,17 +102,12 @@ namespace hex {
|
||||
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);
|
||||
}
|
||||
};
|
||||
@@ -17,7 +17,7 @@ namespace hex {
|
||||
|
||||
class View;
|
||||
|
||||
enum class Keys : u32 {
|
||||
enum class Keys {
|
||||
Space = GLFW_KEY_SPACE,
|
||||
Apostrophe = GLFW_KEY_APOSTROPHE,
|
||||
Comma = GLFW_KEY_COMMA,
|
||||
@@ -138,7 +138,6 @@ namespace hex {
|
||||
constexpr Key() = default;
|
||||
constexpr Key(Keys key) : m_key(static_cast<u32>(key)) { }
|
||||
|
||||
bool operator==(const Key &) const = default;
|
||||
auto operator<=>(const Key &) const = default;
|
||||
|
||||
[[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 CurrentView = Key(static_cast<Keys>(0x1000'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 {
|
||||
public:
|
||||
Shortcut() = default;
|
||||
Shortcut(Keys key);
|
||||
explicit Shortcut(std::set<Key> keys);
|
||||
Shortcut(Keys key) : m_keys({ key }) { }
|
||||
explicit Shortcut(std::set<Key> keys) : m_keys(std::move(keys)) { }
|
||||
Shortcut(const Shortcut &other) = default;
|
||||
Shortcut(Shortcut &&) noexcept = default;
|
||||
|
||||
constexpr static auto None = Keys(0);
|
||||
|
||||
Shortcut& operator=(const Shortcut &other) = default;
|
||||
|
||||
Shortcut& operator=(Shortcut &&) noexcept = default;
|
||||
|
||||
Shortcut operator+(const Key &other) const;
|
||||
Shortcut &operator+=(const Key &other);
|
||||
bool operator<(const Shortcut &other) const;
|
||||
bool operator==(const Shortcut &other) const;
|
||||
constexpr static inline auto None = Keys(0);
|
||||
|
||||
bool isLocal() const;
|
||||
std::string toString() const;
|
||||
const std::set<Key>& getKeys() const;
|
||||
bool has(Key key) const;
|
||||
bool matches(const Shortcut &other) const;
|
||||
Shortcut operator+(const Key &other) const {
|
||||
Shortcut result = *this;
|
||||
result.m_keys.insert(other);
|
||||
|
||||
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:
|
||||
friend Shortcut operator+(const Key &lhs, const Key &rhs);
|
||||
@@ -185,7 +377,12 @@ namespace hex {
|
||||
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.
|
||||
@@ -196,7 +393,7 @@ namespace hex {
|
||||
using Callback = std::function<void()>;
|
||||
struct ShortcutEntry {
|
||||
Shortcut shortcut;
|
||||
std::vector<UnlocalizedString> unlocalizedName;
|
||||
UnlocalizedString unlocalizedName;
|
||||
Callback callback;
|
||||
};
|
||||
|
||||
@@ -206,7 +403,6 @@ namespace hex {
|
||||
* @param unlocalizedName The unlocalized name of the shortcut
|
||||
* @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);
|
||||
|
||||
/**
|
||||
@@ -216,7 +412,6 @@ namespace hex {
|
||||
* @param unlocalizedName The unlocalized name of the shortcut
|
||||
* @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);
|
||||
|
||||
|
||||
@@ -250,14 +445,12 @@ namespace hex {
|
||||
static void resumeShortcuts();
|
||||
static void pauseShortcuts();
|
||||
|
||||
static void enableMacOSMode();
|
||||
|
||||
[[nodiscard]] static std::optional<Shortcut> getPreviousShortcut();
|
||||
|
||||
[[nodiscard]] static std::vector<ShortcutEntry> getGlobalShortcuts();
|
||||
[[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);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -22,7 +22,7 @@ namespace hex {
|
||||
class Task {
|
||||
public:
|
||||
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(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
|
||||
* @param unlocalizedName Name of the task
|
||||
* @param name 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(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);
|
||||
static TaskHolder createTask(std::string name, u64 maxValue, 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 name 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(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);
|
||||
static TaskHolder createBackgroundTask(std::string name, std::function<void(Task &)> function);
|
||||
|
||||
/**
|
||||
* @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();
|
||||
|
||||
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);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -56,7 +56,6 @@ namespace hex {
|
||||
*/
|
||||
static void addStyleHandler(const std::string &name, const StyleMap &styleMap);
|
||||
|
||||
static void reapplyCurrentTheme();
|
||||
|
||||
static std::vector<std::string> getThemeNames();
|
||||
static const std::string &getImageTheme();
|
||||
|
||||
@@ -119,8 +119,6 @@ namespace hex {
|
||||
decltype(m_steps)::iterator m_currentStep, m_latestStep;
|
||||
};
|
||||
|
||||
static void init();
|
||||
|
||||
/**
|
||||
* @brief Gets a list of all tutorials
|
||||
* @return List of all tutorials
|
||||
@@ -147,10 +145,6 @@ namespace hex {
|
||||
*/
|
||||
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
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
||||
#include <hex/helpers/intrinsics.hpp>
|
||||
#include <hex/data_processor/attribute.hpp>
|
||||
|
||||
#include <set>
|
||||
@@ -11,7 +12,6 @@
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <imgui.h>
|
||||
#include <hex/providers/provider_data.hpp>
|
||||
|
||||
namespace hex::prv {
|
||||
class Provider;
|
||||
@@ -42,12 +42,11 @@ namespace hex::dp {
|
||||
m_overlay = overlay;
|
||||
}
|
||||
|
||||
void draw();
|
||||
virtual void drawNode() { }
|
||||
virtual void process() = 0;
|
||||
virtual void reset() { }
|
||||
|
||||
virtual void store(nlohmann::json &j) const { std::ignore = j; }
|
||||
virtual void load(const nlohmann::json &j) { std::ignore = j; }
|
||||
virtual void store(nlohmann::json &j) const { hex::unused(j); }
|
||||
virtual void load(const nlohmann::json &j) { hex::unused(j); }
|
||||
|
||||
struct NodeError {
|
||||
Node *node;
|
||||
@@ -81,11 +80,6 @@ namespace hex::dp {
|
||||
void setIntegerOnOutput(u32 index, i128 integer);
|
||||
void setFloatOnOutput(u32 index, double floatingPoint);
|
||||
|
||||
static void interrupt();
|
||||
|
||||
protected:
|
||||
virtual void drawNode() { }
|
||||
|
||||
private:
|
||||
int m_id;
|
||||
UnlocalizedString m_unlocalizedTitle, m_unlocalizedName;
|
||||
@@ -96,16 +90,45 @@ namespace hex::dp {
|
||||
|
||||
static int s_idCounter;
|
||||
|
||||
Attribute& getAttribute(u32 index);
|
||||
Attribute *getConnectedInputAttribute(u32 index);
|
||||
void markInputProcessed(u32 index);
|
||||
void unmarkInputProcessed(u32 index);
|
||||
Attribute& getAttribute(u32 index) {
|
||||
if (index >= this->getAttributes().size())
|
||||
throw std::runtime_error("Attribute index out of bounds!");
|
||||
|
||||
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:
|
||||
[[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 setAttributes(std::vector<Attribute> attributes);
|
||||
|
||||
void setAttributes(std::vector<Attribute> attributes) {
|
||||
m_attributes = std::move(attributes);
|
||||
|
||||
for (auto &attr : m_attributes)
|
||||
attr.setParentNode(this);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -50,23 +50,14 @@ namespace hex {
|
||||
|
||||
T& operator=(const T &value) {
|
||||
m_value = value;
|
||||
m_valid = true;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
T& operator=(T &&value) noexcept {
|
||||
m_value = std::move(value);
|
||||
m_valid = true;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
private:
|
||||
friend void ImHexApi::System::impl::cleanup();
|
||||
|
||||
void reset() override {
|
||||
if constexpr (requires { m_value.reset(); }) {
|
||||
m_value.reset();
|
||||
@@ -77,12 +68,9 @@ namespace hex {
|
||||
} else {
|
||||
m_value = { };
|
||||
}
|
||||
|
||||
m_valid = false;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_valid = true;
|
||||
T m_value;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,15 +2,10 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <wolv/utils/expected.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#define CRYPTO_ERROR_INVALID_KEY_LENGTH (-1)
|
||||
#define CRYPTO_ERROR_INVALID_MODE (-2)
|
||||
|
||||
namespace hex::prv {
|
||||
class Provider;
|
||||
}
|
||||
@@ -65,5 +60,5 @@ namespace hex::crypt {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/ranges.h>
|
||||
#include <fmt/format.h>
|
||||
|
||||
namespace hex {
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <filesystem>
|
||||
@@ -29,7 +31,36 @@ namespace hex::fs {
|
||||
void openFolderExternal(const std::fs::path &dirPath);
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
@@ -25,16 +25,13 @@
|
||||
|
||||
template<typename T>
|
||||
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(const std::fs::path &path, const std::string &mimeName) {
|
||||
std::ignore = path;
|
||||
std::ignore = mimeName;
|
||||
hex::unused(path, mimeName);
|
||||
throw std::logic_error("Not implemented");
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(std::vector<u8> data, const std::string &mimeName, const std::fs::path &fileName) {
|
||||
std::ignore = data;
|
||||
std::ignore = mimeName;
|
||||
std::ignore = fileName;
|
||||
hex::unused(data, mimeName, fileName);
|
||||
throw std::logic_error("Not implemented");
|
||||
}
|
||||
|
||||
|
||||
9
lib/libimhex/include/hex/helpers/intrinsics.hpp
Normal file
9
lib/libimhex/include/hex/helpers/intrinsics.hpp
Normal file
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
namespace hex {
|
||||
|
||||
void unused(auto && ... x) {
|
||||
((void)x, ...);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,11 +2,13 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <mutex>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/color.h>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
#include <wolv/utils/guards.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
|
||||
namespace hex::log {
|
||||
|
||||
@@ -18,12 +20,10 @@ namespace hex::log {
|
||||
[[maybe_unused]] void redirectToFile();
|
||||
[[maybe_unused]] void enableColorPrinting();
|
||||
|
||||
[[nodiscard]] std::recursive_mutex& getLoggerMutex();
|
||||
[[nodiscard]] bool isLoggingSuspended();
|
||||
[[nodiscard]] bool isDebugLoggingEnabled();
|
||||
|
||||
void lockLoggerMutex();
|
||||
void unlockLoggerMutex();
|
||||
|
||||
struct LogEntry {
|
||||
std::string project;
|
||||
std::string level;
|
||||
@@ -39,8 +39,7 @@ namespace hex::log {
|
||||
if (isLoggingSuspended()) [[unlikely]]
|
||||
return;
|
||||
|
||||
lockLoggerMutex();
|
||||
ON_SCOPE_EXIT { unlockLoggerMutex(); };
|
||||
std::scoped_lock lock(getLoggerMutex());
|
||||
|
||||
auto dest = getDestination();
|
||||
try {
|
||||
@@ -95,8 +94,7 @@ namespace hex::log {
|
||||
}
|
||||
|
||||
[[maybe_unused]] void print(const std::string &fmt, auto && ... args) {
|
||||
impl::lockLoggerMutex();
|
||||
ON_SCOPE_EXIT { impl::unlockLoggerMutex(); };
|
||||
std::scoped_lock lock(impl::getLoggerMutex());
|
||||
|
||||
try {
|
||||
auto dest = impl::getDestination();
|
||||
@@ -107,8 +105,7 @@ namespace hex::log {
|
||||
}
|
||||
|
||||
[[maybe_unused]] void println(const std::string &fmt, auto && ... args) {
|
||||
impl::lockLoggerMutex();
|
||||
ON_SCOPE_EXIT { impl::unlockLoggerMutex(); };
|
||||
std::scoped_lock lock(impl::getLoggerMutex());
|
||||
|
||||
try {
|
||||
auto dest = impl::getDestination();
|
||||
@@ -118,4 +115,4 @@ namespace hex::log {
|
||||
} catch (const std::exception&) { }
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -21,11 +21,6 @@ namespace hex {
|
||||
MissingEOF
|
||||
};
|
||||
|
||||
enum class PatchKind {
|
||||
IPS,
|
||||
IPS32
|
||||
};
|
||||
|
||||
class Patches {
|
||||
public:
|
||||
Patches() = default;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -29,7 +29,7 @@ namespace hex {
|
||||
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
|
||||
*/
|
||||
std::string getOpenErrorString() const;
|
||||
@@ -59,4 +59,4 @@ namespace hex {
|
||||
int m_fileOpenErrno = 0;
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <cstdint>
|
||||
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
|
||||
using u8 = std::uint8_t;
|
||||
using u16 = std::uint16_t;
|
||||
@@ -62,10 +61,6 @@ namespace hex {
|
||||
constexpr static Region Invalid() {
|
||||
return { 0, 0 };
|
||||
}
|
||||
|
||||
constexpr bool operator<(const Region &other) const {
|
||||
return this->address < other.address;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -34,29 +34,6 @@ namespace hex {
|
||||
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>
|
||||
[[nodiscard]] std::vector<T> sampleData(const std::vector<T> &data, size_t count) {
|
||||
size_t stride = std::max(1.0, double(data.size()) / count);
|
||||
@@ -175,7 +152,7 @@ namespace hex {
|
||||
using SizeType = typename SizeTypeImpl<Size>::Type;
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr T changeEndianness(const T &value, size_t size, std::endian endian) {
|
||||
[[nodiscard]] constexpr T changeEndianess(const T &value, size_t size, std::endian endian) {
|
||||
if (endian == std::endian::native)
|
||||
return value;
|
||||
|
||||
@@ -195,8 +172,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
[[nodiscard]] constexpr T changeEndianness(const T &value, std::endian endian) {
|
||||
return changeEndianness(value, sizeof(value), endian);
|
||||
[[nodiscard]] constexpr T changeEndianess(const T &value, std::endian endian) {
|
||||
return changeEndianess(value, sizeof(value), endian);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u128 bitmask(u8 bits) {
|
||||
@@ -285,13 +262,13 @@ namespace hex {
|
||||
|
||||
[[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 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) {
|
||||
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::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();
|
||||
|
||||
|
||||
@@ -15,10 +15,6 @@
|
||||
void setupMacosWindowStyle(GLFWwindow *window, bool borderlessWindowMode);
|
||||
|
||||
void enumerateFontsMacos();
|
||||
|
||||
void macosHandleTitlebarDoubleClickGesture(GLFWwindow *window);
|
||||
bool macosIsWindowBeingResizedByUser(GLFWwindow *window);
|
||||
void macosMarkContentEdited(GLFWwindow *window, bool edited = true);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -37,40 +37,21 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
[[maybe_unused]] static auto& getFeaturesImpl() {
|
||||
static std::vector<hex::Feature> features;
|
||||
return features;
|
||||
}
|
||||
|
||||
#if defined (IMHEX_STATIC_LINK_PLUGINS)
|
||||
#define IMHEX_PLUGIN_VISIBILITY_PREFIX static
|
||||
#else
|
||||
#define IMHEX_PLUGIN_VISIBILITY_PREFIX extern "C" [[gnu::visibility("default")]]
|
||||
#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.
|
||||
* 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_LIBRARY_SETUP(name) 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 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) { \
|
||||
@@ -104,7 +85,6 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
|
||||
ImGui::SetCurrentContext(ctx); \
|
||||
GImGui = ctx; \
|
||||
} \
|
||||
IMHEX_DEFINE_PLUGIN_FEATURES(); \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void* getFeatures() { \
|
||||
return PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures(); \
|
||||
} \
|
||||
@@ -149,3 +129,16 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
|
||||
return &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_PLUGIN_FEATURES() IMHEX_PLUGIN_FEATURES_IMPL()
|
||||
#define IMHEX_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
|
||||
|
||||
@@ -148,7 +148,7 @@ namespace hex::prv {
|
||||
* @brief Gets the type name of this provider
|
||||
* @note This is mainly used to be stored in project files and recents to be able to later on
|
||||
* recreate this exact provider type. This needs to be unique across all providers, this is usually something
|
||||
* like "hex.builtin.provider.mem_file" or "hex.builtin.provider.file"
|
||||
* like "hex.builtin.provider.memory" or "hex.builtin.provider.file"
|
||||
* @return The provider's type name
|
||||
*/
|
||||
[[nodiscard]] virtual std::string getTypeName() const = 0;
|
||||
@@ -165,7 +165,7 @@ namespace hex::prv {
|
||||
void insert(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 removeRaw(u64 offset, u64 size);
|
||||
|
||||
@@ -258,7 +258,7 @@ namespace hex::prv {
|
||||
*/
|
||||
bool m_skipLoadInterface = false;
|
||||
|
||||
std::string m_errorMessage = "Unspecified error";
|
||||
std::string m_errorMessage;
|
||||
|
||||
u64 m_pageSize = MaxPageSize;
|
||||
};
|
||||
|
||||
@@ -78,10 +78,6 @@ namespace hex {
|
||||
m_onCreateCallback = std::move(callback);
|
||||
}
|
||||
|
||||
void setOnDestroyCallback(std::function<void(prv::Provider *, T&)> callback) {
|
||||
m_onDestroyCallback = std::move(callback);
|
||||
}
|
||||
|
||||
private:
|
||||
void onCreate() {
|
||||
EventProviderOpened::subscribe(this, [this](prv::Provider *provider) {
|
||||
@@ -92,12 +88,7 @@ namespace hex {
|
||||
});
|
||||
|
||||
EventProviderDeleted::subscribe(this, [this](prv::Provider *provider){
|
||||
if (auto it = m_data.find(provider); it != m_data.end()) {
|
||||
if (m_onDestroyCallback)
|
||||
m_onDestroyCallback(provider, m_data.at(provider));
|
||||
|
||||
m_data.erase(it);
|
||||
}
|
||||
m_data.erase(provider);
|
||||
});
|
||||
|
||||
EventImHexClosing::subscribe(this, [this] {
|
||||
@@ -122,7 +113,6 @@ namespace hex {
|
||||
}
|
||||
|
||||
void onDestroy() {
|
||||
|
||||
EventProviderOpened::unsubscribe(this);
|
||||
EventProviderDeleted::unsubscribe(this);
|
||||
EventImHexClosing::unsubscribe(this);
|
||||
@@ -131,7 +121,7 @@ namespace hex {
|
||||
|
||||
private:
|
||||
std::map<const prv::Provider *, T> m_data;
|
||||
std::function<void(prv::Provider *, T&)> m_onCreateCallback, m_onDestroyCallback;
|
||||
std::function<void(prv::Provider *, T&)> m_onCreateCallback;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -76,51 +76,46 @@ namespace ImGuiExt {
|
||||
};
|
||||
|
||||
Texture() = default;
|
||||
Texture(const ImU8 *buffer, int size, Filter filter = Filter::Nearest, int width = 0, int height = 0);
|
||||
Texture(std::span<const std::byte> bytes, Filter filter = Filter::Nearest, int width = 0, int height = 0);
|
||||
explicit Texture(const char *path, Filter filter = Filter::Nearest);
|
||||
explicit Texture(const std::fs::path &path, Filter filter = Filter::Nearest);
|
||||
Texture(unsigned int texture, int width, int height);
|
||||
Texture(const Texture&) = delete;
|
||||
Texture(Texture&& other) noexcept;
|
||||
|
||||
static Texture fromImage(const ImU8 *buffer, int size, Filter filter = Filter::Nearest);
|
||||
static Texture fromImage(std::span<const std::byte> buffer, Filter filter = Filter::Nearest);
|
||||
static Texture fromImage(const char *path, Filter filter = Filter::Nearest);
|
||||
static Texture fromImage(const std::fs::path &path, Filter filter = Filter::Nearest);
|
||||
static Texture fromGLTexture(unsigned int texture, int width, int height);
|
||||
static Texture fromBitmap(const ImU8 *buffer, int size, int width, int height, Filter filter = Filter::Nearest);
|
||||
static Texture fromBitmap(std::span<const std::byte> buffer, int width, int height, Filter filter = Filter::Nearest);
|
||||
static Texture fromSVG(const char *path, int width = 0, int height = 0, Filter filter = Filter::Nearest);
|
||||
static Texture fromSVG(const std::fs::path &path, int width = 0, int height = 0, Filter filter = Filter::Nearest);
|
||||
static Texture fromSVG(std::span<const std::byte> buffer, int width = 0, int height = 0, Filter filter = Filter::Nearest);
|
||||
|
||||
|
||||
~Texture();
|
||||
|
||||
Texture& operator=(const Texture&) = delete;
|
||||
Texture& operator=(Texture&& other) noexcept;
|
||||
|
||||
[[nodiscard]] constexpr bool isValid() const noexcept {
|
||||
return m_textureId != 0;
|
||||
return m_textureId != nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] operator ImTextureID() const noexcept {
|
||||
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);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr float getAspectRatio() const noexcept {
|
||||
[[nodiscard]] constexpr auto getAspectRatio() const noexcept {
|
||||
if (m_height == 0) return 1.0F;
|
||||
|
||||
return float(m_width) / float(m_height);
|
||||
}
|
||||
|
||||
private:
|
||||
ImTextureID m_textureId = 0;
|
||||
ImTextureID m_textureId = nullptr;
|
||||
int m_width = 0, m_height = 0;
|
||||
};
|
||||
|
||||
float GetTextWrapPos();
|
||||
|
||||
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data);
|
||||
|
||||
bool IconHyperlink(const char *icon, const char *label, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
||||
@@ -129,12 +124,10 @@ namespace ImGuiExt {
|
||||
bool DescriptionButton(const char *label, const char *description, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
||||
bool DescriptionButtonProgress(const char *label, const char *description, float fraction, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
|
||||
|
||||
void HelpHover(const char *text, const char *icon = "(?)", ImU32 iconColor = ImGui::GetColorU32(ImGuiCol_ButtonActive));
|
||||
void HelpHover(const char *text);
|
||||
|
||||
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 Header(const char *label, bool firstEntry = false);
|
||||
@@ -150,8 +143,6 @@ namespace ImGuiExt {
|
||||
bool InputHexadecimal(const char* label, u32 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputHexadecimal(const char* label, u64 *value, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
|
||||
bool SliderBytes(const char *label, u64 *value, u64 min, u64 max, ImGuiSliderFlags flags = ImGuiSliderFlags_None);
|
||||
|
||||
inline bool HasSecondPassed() {
|
||||
return static_cast<ImU32>(ImGui::GetTime() * 100) % 100 <= static_cast<ImU32>(ImGui::GetIO().DeltaTime * 100);
|
||||
}
|
||||
@@ -163,7 +154,6 @@ namespace ImGuiExt {
|
||||
|
||||
struct Styles {
|
||||
float WindowBlur = 0.0F;
|
||||
float PopupWindowAlpha = 0.0F; // Alpha used by Popup tool windows when the user is not hovering over them
|
||||
} styles;
|
||||
};
|
||||
|
||||
@@ -185,16 +175,11 @@ namespace ImGuiExt {
|
||||
|
||||
void SmallProgressBar(float fraction, float yOffset = 0.0F);
|
||||
|
||||
inline void TextFormatted(std::string_view fmt, auto &&...args) {
|
||||
if constexpr (sizeof...(args) == 0) {
|
||||
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 TextFormatted(const std::string &fmt, auto &&...args) {
|
||||
ImGui::TextUnformatted(hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
|
||||
}
|
||||
|
||||
inline void TextFormattedSelectable(std::string_view fmt, auto &&...args) {
|
||||
inline void TextFormattedSelectable(const std::string &fmt, auto &&...args) {
|
||||
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
|
||||
|
||||
ImGui::PushID(text.c_str());
|
||||
@@ -202,8 +187,8 @@ namespace ImGuiExt {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2());
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4());
|
||||
|
||||
ImGui::PushItemWidth(ImGui::CalcTextSize(text.c_str()).x + ImGui::GetStyle().FramePadding.x * 2);
|
||||
ImGui::InputText("##", const_cast<char *>(text.c_str()), text.size(), ImGuiInputTextFlags_ReadOnly | ImGuiInputTextFlags_NoHorizontalScroll);
|
||||
ImGui::PushItemWidth(-FLT_MIN);
|
||||
ImGui::InputText("##", const_cast<char *>(text.c_str()), text.size(), ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::PopItemWidth();
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
@@ -212,28 +197,19 @@ namespace ImGuiExt {
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
inline void TextFormattedColored(ImColor color, std::string_view fmt, auto &&...args) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, color.Value);
|
||||
ImGuiExt::TextFormatted(fmt, std::forward<decltype(args)>(args)...);
|
||||
ImGui::PopStyleColor();
|
||||
inline void TextFormattedColored(ImColor color, const std::string &fmt, auto &&...args) {
|
||||
ImGui::TextColored(color, "%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
|
||||
}
|
||||
|
||||
inline void TextFormattedDisabled(std::string_view fmt, auto &&...args) {
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
|
||||
ImGuiExt::TextFormatted(fmt, std::forward<decltype(args)>(args)...);
|
||||
ImGui::PopStyleColor();
|
||||
inline void TextFormattedDisabled(const std::string &fmt, auto &&...args) {
|
||||
ImGui::TextDisabled("%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
|
||||
}
|
||||
|
||||
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
|
||||
if (need_backup)
|
||||
ImGui::PushTextWrapPos(0.0F);
|
||||
ImGuiExt::TextFormatted(fmt, std::forward<decltype(args)>(args)...);
|
||||
if (need_backup)
|
||||
ImGui::PopTextWrapPos();
|
||||
inline void TextFormattedWrapped(const std::string &fmt, auto &&...args) {
|
||||
ImGui::TextWrapped("%s", hex::format(fmt, std::forward<decltype(args)>(args)...).c_str());
|
||||
}
|
||||
|
||||
inline void TextFormattedWrappedSelectable(std::string_view fmt, auto &&...args) {
|
||||
inline void TextFormattedWrappedSelectable(const std::string &fmt, auto &&...args) {
|
||||
// Manually wrap text, using the letter M (generally the widest character in non-monospaced fonts) to calculate the character width to use.
|
||||
auto text = wolv::util::wrapMonospacedString(
|
||||
hex::format(fmt, std::forward<decltype(args)>(args)...),
|
||||
@@ -246,7 +222,7 @@ namespace ImGuiExt {
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2());
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4());
|
||||
|
||||
ImGui::PushItemWidth(ImGui::CalcTextSize(text.c_str()).x + ImGui::GetStyle().FramePadding.x * 2);
|
||||
ImGui::PushItemWidth(-FLT_MIN);
|
||||
ImGui::InputTextMultiline(
|
||||
"##",
|
||||
const_cast<char *>(text.c_str()),
|
||||
@@ -263,13 +239,13 @@ namespace ImGuiExt {
|
||||
}
|
||||
|
||||
void TextUnformattedCentered(const char *text);
|
||||
inline void TextFormattedCentered(std::string_view fmt, auto &&...args) {
|
||||
inline void TextFormattedCentered(const std::string &fmt, auto &&...args) {
|
||||
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
|
||||
TextUnformattedCentered(text.c_str());
|
||||
}
|
||||
|
||||
|
||||
inline void TextFormattedCenteredHorizontal(std::string_view fmt, auto &&...args) {
|
||||
inline void TextFormattedCenteredHorizontal(const std::string &fmt, auto &&...args) {
|
||||
auto text = hex::format(fmt, std::forward<decltype(args)>(args)...);
|
||||
auto availableSpace = ImGui::GetContentRegionAvail();
|
||||
auto textSize = ImGui::CalcTextSize(text.c_str(), nullptr, false, availableSpace.x * 0.75F);
|
||||
@@ -282,7 +258,6 @@ namespace ImGuiExt {
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@@ -296,12 +271,12 @@ namespace ImGuiExt {
|
||||
bool DimmedIconToggle(const char *icon, 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();
|
||||
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 ConfirmButtons(const char *textLeft, const char *textRight, const auto &leftButtonCallback, const auto &rightButtonCallback) {
|
||||
@@ -322,9 +297,6 @@ namespace ImGuiExt {
|
||||
bool ToggleSwitch(const char *label, bool *v);
|
||||
bool ToggleSwitch(const char *label, bool v);
|
||||
|
||||
bool PopupTitleBarButton(const char* label, bool p_enabled);
|
||||
void PopupTitleBarText(const char* text);
|
||||
|
||||
template<typename T>
|
||||
constexpr ImGuiDataType getImGuiDataType() {
|
||||
if constexpr (std::same_as<T, u8>) return ImGuiDataType_U8;
|
||||
|
||||
@@ -80,8 +80,6 @@ namespace hex {
|
||||
*/
|
||||
[[nodiscard]] virtual ImGuiWindowFlags getWindowFlags() const;
|
||||
|
||||
[[nodiscard]] virtual bool shouldStoreWindowState() const { return true; }
|
||||
|
||||
[[nodiscard]] const char *getIcon() const { return m_icon; }
|
||||
|
||||
[[nodiscard]] bool &getWindowOpenState();
|
||||
@@ -158,7 +156,6 @@ namespace hex {
|
||||
explicit Floating(UnlocalizedString unlocalizedName) : Window(std::move(unlocalizedName), "") {}
|
||||
|
||||
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const override { return ImGuiWindowFlags_NoDocking; }
|
||||
[[nodiscard]] bool shouldStoreWindowState() const override { return false; }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -181,13 +178,12 @@ namespace hex {
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_Escape))
|
||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape)))
|
||||
this->getWindowOpenState() = false;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual bool hasCloseButton() const { return true; }
|
||||
[[nodiscard]] bool shouldStoreWindowState() const override { return false; }
|
||||
virtual bool hasCloseButton() const { return true; }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -2,14 +2,9 @@
|
||||
#include <hex/api/event_manager.hpp>
|
||||
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#if defined(OS_WEB)
|
||||
#include <emscripten.h>
|
||||
#endif
|
||||
|
||||
namespace hex {
|
||||
|
||||
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";
|
||||
bool AchievementManager::s_initialized = false;
|
||||
|
||||
void AchievementManager::loadProgress() {
|
||||
if (s_initialized)
|
||||
return;
|
||||
for (const auto &directory : paths::Config.read()) {
|
||||
for (const auto &directory : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
auto path = directory / AchievementsFile;
|
||||
|
||||
if (!wolv::io::fs::exists(path)) {
|
||||
@@ -219,16 +211,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
try {
|
||||
#if defined(OS_WEB)
|
||||
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);
|
||||
auto json = nlohmann::json::parse(file.readString());
|
||||
|
||||
for (const auto &[categoryName, achievements] : getAchievements()) {
|
||||
for (const auto &[achievementName, achievement] : achievements) {
|
||||
@@ -243,8 +226,6 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s_initialized = true;
|
||||
} catch (const std::exception &e) {
|
||||
log::error("Failed to load achievements: {}", e.what());
|
||||
}
|
||||
@@ -253,8 +234,6 @@ namespace hex {
|
||||
}
|
||||
|
||||
void AchievementManager::storeProgress() {
|
||||
if (!s_initialized)
|
||||
loadProgress();
|
||||
nlohmann::json json;
|
||||
for (const auto &[categoryName, achievements] : getAchievements()) {
|
||||
json[categoryName] = nlohmann::json::object();
|
||||
@@ -267,23 +246,16 @@ namespace hex {
|
||||
if (json.empty())
|
||||
return;
|
||||
|
||||
#if defined(OS_WEB)
|
||||
auto data = json.dump();
|
||||
MAIN_THREAD_EM_ASM({
|
||||
localStorage.setItem("achievements", UTF8ToString($0));
|
||||
}, data.c_str());
|
||||
#else
|
||||
for (const auto &directory : paths::Config.write()) {
|
||||
auto path = directory / AchievementsFile;
|
||||
for (const auto &directory : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
auto path = directory / AchievementsFile;
|
||||
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||
if (!file.isValid())
|
||||
continue;
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||
if (!file.isValid())
|
||||
continue;
|
||||
|
||||
file.writeString(json.dump(4));
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
file.writeString(json.dump(4));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/data_processor/node.hpp>
|
||||
@@ -52,14 +51,10 @@ namespace hex {
|
||||
if (!settings[unlocalizedCategory].contains(unlocalizedName))
|
||||
settings[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
|
||||
if (settings[unlocalizedCategory][unlocalizedName].is_null())
|
||||
settings[unlocalizedCategory][unlocalizedName] = defaultValue;
|
||||
|
||||
return settings[unlocalizedCategory][unlocalizedName];
|
||||
}
|
||||
|
||||
#if defined(OS_WEB)
|
||||
|
||||
void load() {
|
||||
char *data = (char *) MAIN_THREAD_EM_ASM_INT({
|
||||
let data = localStorage.getItem("config");
|
||||
@@ -75,11 +70,7 @@ namespace hex {
|
||||
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
|
||||
for (const auto &[name, callbacks] : rest) {
|
||||
for (const auto &[id, callback] : callbacks) {
|
||||
try {
|
||||
callback(getSetting(category, name, {}));
|
||||
} catch (const std::exception &e) {
|
||||
log::error("Failed to load setting [{}/{}]: {}", category, name, e.what());
|
||||
}
|
||||
callback(getSetting(category, name, {}));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -102,7 +93,7 @@ namespace hex {
|
||||
|
||||
void load() {
|
||||
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);
|
||||
|
||||
if (file.isValid()) {
|
||||
@@ -118,21 +109,14 @@ namespace hex {
|
||||
for (const auto &[category, rest] : *impl::s_onChangeCallbacks) {
|
||||
for (const auto &[name, callbacks] : rest) {
|
||||
for (const auto &[id, callback] : callbacks) {
|
||||
try {
|
||||
callback(getSetting(category, name, {}));
|
||||
} catch (const std::exception &e) {
|
||||
log::error("Failed to load setting [{}/{}]: {}", category, name, e.what());
|
||||
}
|
||||
callback(getSetting(category, name, {}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void store() {
|
||||
if (!s_settings.isValid())
|
||||
return;
|
||||
|
||||
const auto &settingsData = *s_settings;
|
||||
const auto &settingsData = getSettingsData();
|
||||
|
||||
// During a crash settings can be empty, causing them to be overwritten.
|
||||
if (settingsData.empty()) {
|
||||
@@ -143,7 +127,7 @@ namespace hex {
|
||||
if (result.empty()) {
|
||||
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);
|
||||
|
||||
if (file.isValid()) {
|
||||
@@ -154,7 +138,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void clear() {
|
||||
for (const auto &dir : paths::Config.write()) {
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
wolv::io::fs::remove(dir / SettingsFile);
|
||||
}
|
||||
}
|
||||
@@ -191,17 +175,6 @@ namespace hex {
|
||||
const auto entry = insertOrGetEntry(subCategory->entries, unlocalizedName);
|
||||
|
||||
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();
|
||||
}
|
||||
@@ -324,23 +297,6 @@ namespace hex {
|
||||
}
|
||||
|
||||
|
||||
bool SliderDataSize::draw(const std::string &name) {
|
||||
return ImGuiExt::SliderBytes(name.c_str(), &m_value, m_min, m_max);
|
||||
}
|
||||
|
||||
void SliderDataSize::load(const nlohmann::json &data) {
|
||||
if (data.is_number_integer()) {
|
||||
m_value = data.get<u64>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for slider!");
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json SliderDataSize::store() {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
|
||||
ColorPicker::ColorPicker(ImColor defaultColor) {
|
||||
m_value = {
|
||||
defaultColor.Value.x,
|
||||
@@ -563,11 +519,6 @@ namespace hex {
|
||||
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) {
|
||||
@@ -612,7 +563,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()) {
|
||||
if (dangerous)
|
||||
@@ -621,16 +572,12 @@ namespace hex {
|
||||
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()) {
|
||||
runtime.addPragma(name, callback);
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -659,15 +606,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) {
|
||||
log::debug("Registered new pattern visualizer function: {}", name);
|
||||
@@ -850,12 +788,6 @@ namespace hex {
|
||||
return *s_menuItems;
|
||||
}
|
||||
|
||||
static AutoReset<std::vector<MenuItem*>> s_toolbarMenuItems;
|
||||
const std::vector<MenuItem*>& getToolbarMenuItems() {
|
||||
return s_toolbarMenuItems;
|
||||
}
|
||||
|
||||
|
||||
std::multimap<u32, MenuItem>& getMenuItemsMutable() {
|
||||
return *s_menuItems;
|
||||
}
|
||||
@@ -913,21 +845,14 @@ namespace hex {
|
||||
coloredIcon.color = ImGuiCustomCol_ToolbarGray;
|
||||
|
||||
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) {
|
||||
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)
|
||||
ShortcutManager::addShortcut(view, shortcut, unlocalizedShortcutName, callbackIfEnabled);
|
||||
ShortcutManager::addShortcut(view, shortcut, unlocalizedMainMenuNames.back(), function);
|
||||
else
|
||||
ShortcutManager::addGlobalShortcut(shortcut, unlocalizedShortcutName, callbackIfEnabled);
|
||||
ShortcutManager::addGlobalShortcut(shortcut, unlocalizedMainMenuNames.back(), function);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -940,14 +865,14 @@ namespace hex {
|
||||
|
||||
unlocalizedMainMenuNames.emplace_back(impl::SubMenuValue);
|
||||
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) {
|
||||
unlocalizedMainMenuNames.emplace_back(impl::SeparatorValue);
|
||||
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 +897,11 @@ namespace hex {
|
||||
if (menuItem.unlocalizedNames.back() == unlocalizedName) {
|
||||
menuItem.toolbarIndex = maxIndex + 1;
|
||||
menuItem.icon.color = color;
|
||||
updateToolbarItems();
|
||||
|
||||
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) {
|
||||
impl::s_sidebarItems->push_back({ icon, function, enabledCallback });
|
||||
@@ -1049,28 +950,17 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
static AutoReset<std::vector<ExportMenuEntry>> s_exportMenuEntries;
|
||||
const std::vector<ExportMenuEntry>& getExportMenuEntries() {
|
||||
return *s_exportMenuEntries;
|
||||
}
|
||||
|
||||
static AutoReset<std::vector<FindExporterEntry>> s_findExportEntries;
|
||||
const std::vector<FindExporterEntry>& getFindExporterEntries() {
|
||||
return *s_findExportEntries;
|
||||
static AutoReset<std::vector<Entry>> s_entries;
|
||||
const std::vector<Entry>& getEntries() {
|
||||
return *s_entries;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
impl::s_exportMenuEntries->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 });
|
||||
impl::s_entries->push_back({ unlocalizedName, callback });
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1235,7 +1125,7 @@ namespace hex {
|
||||
|
||||
class Service {
|
||||
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(Service &&) = default;
|
||||
~Service() {
|
||||
@@ -1247,8 +1137,8 @@ namespace hex {
|
||||
Service& operator=(const Service&) = delete;
|
||||
Service& operator=(Service &&) = default;
|
||||
|
||||
[[nodiscard]] const UnlocalizedString& getUnlocalizedName() const {
|
||||
return m_unlocalizedName;
|
||||
[[nodiscard]] const std::string& getName() const {
|
||||
return m_name;
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::jthread& getThread() const {
|
||||
@@ -1256,7 +1146,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
private:
|
||||
UnlocalizedString m_unlocalizedName;
|
||||
std::string m_name;
|
||||
std::jthread m_thread;
|
||||
};
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -14,8 +14,6 @@
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
@@ -184,24 +182,24 @@ namespace hex {
|
||||
impl::s_hoveringFunctions->erase(id);
|
||||
}
|
||||
|
||||
static u32 s_tooltipId = 0;
|
||||
static u32 tooltipId = 0;
|
||||
u32 addTooltip(Region region, std::string value, color_t color) {
|
||||
s_tooltipId++;
|
||||
impl::s_tooltips->insert({ s_tooltipId, { region, std::move(value), color } });
|
||||
tooltipId++;
|
||||
impl::s_tooltips->insert({ tooltipId, { region, std::move(value), color } });
|
||||
|
||||
return s_tooltipId;
|
||||
return tooltipId;
|
||||
}
|
||||
|
||||
void removeTooltip(u32 id) {
|
||||
impl::s_tooltips->erase(id);
|
||||
}
|
||||
|
||||
static u32 s_tooltipFunctionId;
|
||||
static u32 tooltipFunctionId;
|
||||
u32 addTooltipProvider(TooltipFunction function) {
|
||||
s_tooltipFunctionId++;
|
||||
impl::s_tooltipFunctions->insert({ s_tooltipFunctionId, std::move(function) });
|
||||
tooltipFunctionId++;
|
||||
impl::s_tooltipFunctions->insert({ tooltipFunctionId, std::move(function) });
|
||||
|
||||
return s_tooltipFunctionId;
|
||||
return tooltipFunctionId;
|
||||
}
|
||||
|
||||
void removeTooltipProvider(u32 id) {
|
||||
@@ -218,7 +216,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void clearSelection() {
|
||||
impl::s_currentSelection->reset();
|
||||
impl::s_currentSelection.reset();
|
||||
}
|
||||
|
||||
void setSelection(const Region ®ion, prv::Provider *provider) {
|
||||
@@ -268,20 +266,18 @@ namespace hex {
|
||||
|
||||
static i64 s_currentProvider = -1;
|
||||
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 {
|
||||
|
||||
static std::set<prv::Provider*> s_closingProviders;
|
||||
static std::vector<prv::Provider*> s_closingProviders;
|
||||
void resetClosingProvider() {
|
||||
s_closingProviders.clear();
|
||||
}
|
||||
|
||||
std::set<prv::Provider*> getClosingProviders() {
|
||||
const std::vector<prv::Provider*>& getClosingProviders() {
|
||||
return s_closingProviders;
|
||||
}
|
||||
|
||||
static std::recursive_mutex s_providerMutex;
|
||||
}
|
||||
|
||||
prv::Provider *get() {
|
||||
@@ -301,8 +297,6 @@ namespace hex {
|
||||
}
|
||||
|
||||
void setCurrentProvider(i64 index) {
|
||||
std::scoped_lock lock(impl::s_providerMutex);
|
||||
|
||||
if (TaskManager::getRunningTaskCount() > 0)
|
||||
return;
|
||||
|
||||
@@ -316,8 +310,6 @@ namespace hex {
|
||||
}
|
||||
|
||||
void setCurrentProvider(NonNull<prv::Provider*> provider) {
|
||||
std::scoped_lock lock(impl::s_providerMutex);
|
||||
|
||||
if (TaskManager::getRunningTaskCount() > 0)
|
||||
return;
|
||||
|
||||
@@ -337,11 +329,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void markDirty() {
|
||||
const auto provider = get();
|
||||
if (!provider->isDirty()) {
|
||||
provider->markDirty();
|
||||
EventProviderDirtied::post(provider);
|
||||
}
|
||||
get()->markDirty();
|
||||
}
|
||||
|
||||
void resetDirty() {
|
||||
@@ -356,8 +344,6 @@ namespace hex {
|
||||
}
|
||||
|
||||
void add(std::unique_ptr<prv::Provider> &&provider, bool skipLoadInterface, bool select) {
|
||||
std::scoped_lock lock(impl::s_providerMutex);
|
||||
|
||||
if (TaskManager::getRunningTaskCount() > 0)
|
||||
return;
|
||||
|
||||
@@ -372,8 +358,6 @@ namespace hex {
|
||||
}
|
||||
|
||||
void remove(prv::Provider *provider, bool noQuestions) {
|
||||
std::scoped_lock lock(impl::s_providerMutex);
|
||||
|
||||
if (provider == nullptr)
|
||||
return;
|
||||
|
||||
@@ -381,7 +365,7 @@ namespace hex {
|
||||
return;
|
||||
|
||||
if (!noQuestions) {
|
||||
impl::s_closingProviders.insert(provider);
|
||||
impl::s_closingProviders.push_back(provider);
|
||||
|
||||
bool shouldClose = true;
|
||||
EventProviderClosing::post(provider, &shouldClose);
|
||||
@@ -429,38 +413,20 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
static std::mutex eraseMutex;
|
||||
|
||||
// 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());
|
||||
provider->close();
|
||||
EventProviderClosed::post(provider);
|
||||
RequestUpdateWindowTitle::post();
|
||||
|
||||
// Do the destruction of the provider in the background once all tasks have finished
|
||||
TaskManager::runWhenTasksFinished([providerToRemove] {
|
||||
EventProviderDeleted::post(providerToRemove);
|
||||
TaskManager::createBackgroundTask("Closing Provider", [providerToRemove](Task &) {
|
||||
eraseMutex.lock();
|
||||
auto provider = std::move((*s_providersToRemove)[providerToRemove]);
|
||||
s_providersToRemove->erase(providerToRemove);
|
||||
eraseMutex.unlock();
|
||||
TaskManager::runWhenTasksFinished([it, provider] {
|
||||
EventProviderDeleted::post(provider);
|
||||
std::erase(impl::s_closingProviders, provider);
|
||||
|
||||
provider->close();
|
||||
});
|
||||
s_providers->erase(it);
|
||||
if (s_currentProvider >= i64(s_providers->size()))
|
||||
setCurrentProvider(0);
|
||||
|
||||
if (s_providers->empty())
|
||||
EventProviderChanged::post(provider, nullptr);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -475,6 +441,7 @@ namespace hex {
|
||||
|
||||
namespace ImHexApi::System {
|
||||
|
||||
|
||||
namespace impl {
|
||||
|
||||
// Default to true means we forward to ourselves by default
|
||||
@@ -536,11 +503,6 @@ namespace hex {
|
||||
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;
|
||||
void addInitArgument(const std::string &key, const std::string &value) {
|
||||
static std::mutex initArgumentsMutex;
|
||||
@@ -642,15 +604,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void* getLibImHexModuleHandle() {
|
||||
return hex::getContainingModule(reinterpret_cast<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();
|
||||
}
|
||||
});
|
||||
return hex::getContainingModule((void*)&getLibImHexModuleHandle);
|
||||
}
|
||||
|
||||
|
||||
@@ -693,10 +647,6 @@ namespace hex {
|
||||
return impl::s_gpuVendor;
|
||||
}
|
||||
|
||||
const std::string &getGLRenderer() {
|
||||
return impl::s_glRenderer;
|
||||
}
|
||||
|
||||
bool isPortableVersion() {
|
||||
static std::optional<bool> portable;
|
||||
if (portable.has_value())
|
||||
@@ -783,30 +733,16 @@ namespace hex {
|
||||
#endif
|
||||
}
|
||||
|
||||
std::optional<LinuxDistro> getLinuxDistro() {
|
||||
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() {
|
||||
std::string getImHexVersion(bool withBuildType) {
|
||||
#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
|
||||
return {};
|
||||
return "Unknown";
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -818,7 +754,7 @@ namespace hex {
|
||||
return std::string(GIT_COMMIT_HASH_LONG).substr(0, 7);
|
||||
}
|
||||
#else
|
||||
std::ignore = longHash;
|
||||
hex::unused(longHash);
|
||||
return "Unknown";
|
||||
#endif
|
||||
}
|
||||
@@ -839,10 +775,6 @@ namespace hex {
|
||||
#endif
|
||||
}
|
||||
|
||||
bool isNightlyBuild() {
|
||||
return getImHexVersion().nightly();
|
||||
}
|
||||
|
||||
bool updateImHex(UpdateType updateType) {
|
||||
// Get the path of the updater executable
|
||||
std::fs::path executablePath;
|
||||
@@ -869,7 +801,7 @@ namespace hex {
|
||||
|
||||
EventImHexClosing::subscribe([executablePath, updateTypeString] {
|
||||
hex::executeCommand(
|
||||
hex::format("\"{}\" \"{}\"",
|
||||
hex::format("{} {}",
|
||||
wolv::util::toUTF8String(executablePath),
|
||||
updateTypeString
|
||||
)
|
||||
@@ -948,9 +880,9 @@ namespace hex {
|
||||
s_fontSize = size;
|
||||
}
|
||||
|
||||
static AutoReset<ImFontAtlas*> s_fontAtlas;
|
||||
static AutoReset<std::unique_ptr<ImFontAtlas>> s_fontAtlas;
|
||||
void setFontAtlas(ImFontAtlas* fontAtlas) {
|
||||
s_fontAtlas = fontAtlas;
|
||||
s_fontAtlas = std::unique_ptr<ImFontAtlas>(fontAtlas);
|
||||
}
|
||||
|
||||
static ImFont *s_boldFont = nullptr;
|
||||
@@ -1033,7 +965,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
ImFontAtlas* getFontAtlas() {
|
||||
return impl::s_fontAtlas;
|
||||
return impl::s_fontAtlas->get();
|
||||
}
|
||||
|
||||
ImFont* Bold() {
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
#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/logger.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/ui/view.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -42,7 +40,10 @@ namespace hex {
|
||||
fileName += ".hexlyt";
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -70,15 +71,15 @@ namespace hex {
|
||||
void LayoutManager::removeLayout(const std::string& name) {
|
||||
for (const auto &layout : *s_layouts) {
|
||||
if (layout.name == name) {
|
||||
if (wolv::io::fs::remove(layout.path)) {
|
||||
if (wolv::io::File(layout.path, wolv::io::File::Mode::Write).remove()) {
|
||||
log::info("Removed layout '{}'", name);
|
||||
LayoutManager::reload();
|
||||
} else {
|
||||
log::error("Failed to remove layout '{}'", name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
LayoutManager::reload();
|
||||
}
|
||||
|
||||
|
||||
@@ -89,26 +90,28 @@ namespace hex {
|
||||
|
||||
void LayoutManager::process() {
|
||||
if (s_layoutPathToLoad->has_value()) {
|
||||
LayoutManager::closeAllViews();
|
||||
const auto pathString = wolv::util::toUTF8String(**s_layoutPathToLoad);
|
||||
|
||||
wolv::io::File file(**s_layoutPathToLoad, wolv::io::File::Mode::Read);
|
||||
s_layoutStringToLoad = file.readString();
|
||||
s_layoutPathToLoad->reset();
|
||||
LayoutManager::closeAllViews();
|
||||
ImGui::LoadIniSettingsFromDisk(pathString.c_str());
|
||||
|
||||
s_layoutPathToLoad = std::nullopt;
|
||||
log::info("Loaded layout from {}", pathString);
|
||||
}
|
||||
|
||||
if (s_layoutStringToLoad->has_value()) {
|
||||
LayoutManager::closeAllViews();
|
||||
ImGui::LoadIniSettingsFromMemory((*s_layoutStringToLoad)->c_str());
|
||||
|
||||
s_layoutStringToLoad->reset();
|
||||
log::info("Loaded new Layout");
|
||||
s_layoutStringToLoad = std::nullopt;
|
||||
log::info("Loaded layout from string");
|
||||
}
|
||||
}
|
||||
|
||||
void LayoutManager::reload() {
|
||||
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)) {
|
||||
const auto &path = entry.path();
|
||||
|
||||
@@ -131,8 +134,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
void LayoutManager::reset() {
|
||||
s_layoutPathToLoad->reset();
|
||||
s_layoutStringToLoad->reset();
|
||||
s_layoutPathToLoad.reset();
|
||||
s_layoutStringToLoad.reset();
|
||||
s_layouts->clear();
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ namespace hex {
|
||||
|
||||
AutoReset<std::string> s_fallbackLanguage;
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
auto &definitions = ContentRegistry::Language::impl::getLanguageDefinitions();
|
||||
|
||||
@@ -64,10 +49,14 @@ namespace hex {
|
||||
|
||||
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();
|
||||
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;
|
||||
}
|
||||
@@ -109,11 +98,11 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
Lang::Lang(const char *unlocalizedString) : m_entryHash(LangConst::hash(unlocalizedString)), m_unlocalizedString(unlocalizedString) { }
|
||||
Lang::Lang(const std::string &unlocalizedString) : m_entryHash(LangConst::hash(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_entryHash(LangConst::hash(unlocalizedString.get())), m_unlocalizedString(unlocalizedString.get()) { }
|
||||
Lang::Lang(std::string_view unlocalizedString) : m_entryHash(LangConst::hash(unlocalizedString)), m_unlocalizedString(unlocalizedString) { }
|
||||
Lang::Lang(const char *unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
|
||||
Lang::Lang(const std::string &unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
|
||||
Lang::Lang(const UnlocalizedString &unlocalizedString) : m_unlocalizedString(unlocalizedString.get()) { }
|
||||
Lang::Lang(std::string_view unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
|
||||
|
||||
|
||||
Lang::operator std::string() const {
|
||||
return get();
|
||||
@@ -124,41 +113,43 @@ namespace hex {
|
||||
}
|
||||
|
||||
Lang::operator const char *() const {
|
||||
return get();
|
||||
return get().c_str();
|
||||
}
|
||||
|
||||
const char *Lang::get() const {
|
||||
const auto &lang = *LocalizationManager::s_currStrings;
|
||||
|
||||
const auto it = lang.find(m_entryHash);
|
||||
if (it == lang.end()) {
|
||||
return m_unlocalizedString.c_str();
|
||||
} else {
|
||||
return it->second.c_str();
|
||||
}
|
||||
std::string operator+(const std::string &&left, const Lang &&right) {
|
||||
return left + static_cast<std::string>(right);
|
||||
}
|
||||
|
||||
LangConst::operator std::string() const {
|
||||
return get();
|
||||
std::string operator+(const Lang &&left, const std::string &&right) {
|
||||
return static_cast<std::string>(left) + right;
|
||||
}
|
||||
|
||||
LangConst::operator std::string_view() const {
|
||||
return get();
|
||||
std::string operator+(const Lang &&left, const Lang &&right) {
|
||||
return static_cast<std::string>(left) + static_cast<std::string>(right);
|
||||
}
|
||||
|
||||
LangConst::operator const char *() const {
|
||||
return get();
|
||||
std::string operator+(const std::string_view &&left, const Lang &&right) {
|
||||
return std::string(left) + static_cast<std::string>(right);
|
||||
}
|
||||
|
||||
const char *LangConst::get() const {
|
||||
const auto &lang = *LocalizationManager::s_currStrings;
|
||||
std::string operator+(const Lang &&left, const std::string_view &&right) {
|
||||
return static_cast<std::string>(left) + std::string(right);
|
||||
}
|
||||
|
||||
const auto it = lang.find(m_entryHash);
|
||||
if (it == lang.end()) {
|
||||
std::string operator+(const char *left, const Lang &&right) {
|
||||
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;
|
||||
} else {
|
||||
return it->second.c_str();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
@@ -112,6 +111,10 @@ namespace hex {
|
||||
}
|
||||
|
||||
Plugin::~Plugin() {
|
||||
if (isLoaded()) {
|
||||
log::info("Trying to unload plugin '{}'", getPluginName());
|
||||
}
|
||||
|
||||
unloadLibrary(m_handle, m_path);
|
||||
}
|
||||
|
||||
@@ -129,7 +132,7 @@ namespace hex {
|
||||
|
||||
|
||||
const auto requestedVersion = getCompatibleVersion();
|
||||
const auto imhexVersion = ImHexApi::System::getImHexVersion().get();
|
||||
const auto imhexVersion = ImHexApi::System::getImHexVersion();
|
||||
if (!imhexVersion.starts_with(requestedVersion)) {
|
||||
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()));
|
||||
@@ -303,7 +306,7 @@ namespace hex {
|
||||
|
||||
bool PluginManager::loadLibraries() {
|
||||
bool success = true;
|
||||
for (const auto &loadPath : paths::Libraries.read())
|
||||
for (const auto &loadPath : fs::getDefaultPaths(fs::ImHexPath::Libraries))
|
||||
success = PluginManager::loadLibraries(loadPath) && success;
|
||||
|
||||
return success;
|
||||
@@ -331,7 +334,7 @@ namespace hex {
|
||||
void PluginManager::initializeNewPlugins() {
|
||||
for (const auto &plugin : getPlugins()) {
|
||||
if (!plugin.isLoaded())
|
||||
std::ignore = plugin.initializePlugin();
|
||||
hex::unused(plugin.initializePlugin());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,265 +12,31 @@ namespace hex {
|
||||
AutoReset<std::map<Shortcut, ShortcutManager::ShortcutEntry>> s_globalShortcuts;
|
||||
std::atomic<bool> s_paused;
|
||||
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) {
|
||||
log::debug("Adding global shortcut {} for {}", shortcut.toString(), unlocalizedName.get());
|
||||
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!");
|
||||
s_globalShortcuts->insert({ shortcut, { shortcut, unlocalizedName, 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());
|
||||
auto [it, inserted] = view->m_shortcuts.insert({ shortcut + CurrentView, { shortcut, { unlocalizedName }, callback } });
|
||||
if (!inserted) log::error("Failed to add shortcut!");
|
||||
view->m_shortcuts.insert({ shortcut + CurrentView, { shortcut, unlocalizedName, callback } });
|
||||
}
|
||||
|
||||
static Shortcut getShortcut(bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode) {
|
||||
Shortcut pressedShortcut;
|
||||
|
||||
if (ctrl)
|
||||
pressedShortcut += s_macOSMode ? CTRL : CTRLCMD;
|
||||
pressedShortcut += CTRL;
|
||||
if (alt)
|
||||
pressedShortcut += ALT;
|
||||
if (shift)
|
||||
pressedShortcut += SHIFT;
|
||||
if (super)
|
||||
pressedShortcut += s_macOSMode ? CTRLCMD : SUPER;
|
||||
pressedShortcut += SUPER;
|
||||
if (focused)
|
||||
pressedShortcut += CurrentView;
|
||||
if (ImGui::GetIO().WantTextInput)
|
||||
pressedShortcut += AllowWhileTyping;
|
||||
|
||||
pressedShortcut += static_cast<Keys>(keyCode);
|
||||
|
||||
@@ -283,9 +49,11 @@ namespace hex {
|
||||
if (ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId))
|
||||
return;
|
||||
|
||||
if (auto it = shortcuts.find(shortcut); it != shortcuts.end()) {
|
||||
const auto &[foundShortcut, entry] = *it;
|
||||
entry.callback();
|
||||
if (shortcuts.contains(shortcut + AllowWhileTyping)) {
|
||||
shortcuts.at(shortcut + AllowWhileTyping).callback();
|
||||
} else if (shortcuts.contains(shortcut)) {
|
||||
if (!ImGui::GetIO().WantTextInput)
|
||||
shortcuts.at(shortcut).callback();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -354,13 +122,10 @@ namespace hex {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ShortcutManager::updateShortcut(const Shortcut &oldShortcut, Shortcut newShortcut, View *view) {
|
||||
if (oldShortcut.matches(newShortcut))
|
||||
bool ShortcutManager::updateShortcut(const Shortcut &oldShortcut, const Shortcut &newShortcut, View *view) {
|
||||
if (oldShortcut == newShortcut)
|
||||
return true;
|
||||
|
||||
if (oldShortcut.has(AllowWhileTyping))
|
||||
newShortcut += AllowWhileTyping;
|
||||
|
||||
bool result;
|
||||
if (view != nullptr) {
|
||||
result = updateShortcutImpl(oldShortcut + CurrentView, newShortcut + CurrentView , view->m_shortcuts);
|
||||
@@ -369,9 +134,9 @@ namespace hex {
|
||||
}
|
||||
|
||||
if (result) {
|
||||
for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItemsMutable()) {
|
||||
if (menuItem.view == view && menuItem.shortcut == oldShortcut) {
|
||||
menuItem.shortcut = newShortcut;
|
||||
for (auto &[priority, menuItem] : ContentRegistry::Interface::impl::getMenuItems()) {
|
||||
if (menuItem.view == view && *menuItem.shortcut == oldShortcut) {
|
||||
*menuItem.shortcut = newShortcut;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -380,9 +145,4 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
void ShortcutManager::enableMacOSMode() {
|
||||
s_macOSMode = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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) { }
|
||||
|
||||
Task::Task(hex::Task &&other) noexcept {
|
||||
@@ -327,11 +327,11 @@ namespace hex {
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
@@ -344,32 +344,14 @@ namespace hex {
|
||||
}
|
||||
|
||||
|
||||
TaskHolder TaskManager::createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void(Task &)> function) {
|
||||
log::debug("Creating task {}", unlocalizedName.get());
|
||||
return createTask(std::move(unlocalizedName), maxValue, false, std::move(function));
|
||||
TaskHolder TaskManager::createTask(std::string name, u64 maxValue, std::function<void(Task &)> function) {
|
||||
log::debug("Creating task {}", name);
|
||||
return createTask(std::move(name), maxValue, false, std::move(function));
|
||||
}
|
||||
|
||||
TaskHolder TaskManager::createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void()> function) {
|
||||
log::debug("Creating task {}", unlocalizedName.get());
|
||||
return createTask(std::move(unlocalizedName), maxValue, false,
|
||||
[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();
|
||||
}
|
||||
);
|
||||
TaskHolder TaskManager::createBackgroundTask(std::string name, std::function<void(Task &)> function) {
|
||||
log::debug("Creating background task {}", name);
|
||||
return createTask(std::move(name), 0, true, std::move(function));
|
||||
}
|
||||
|
||||
void TaskManager::collectGarbage() {
|
||||
@@ -444,10 +426,6 @@ namespace hex {
|
||||
void TaskManager::runWhenTasksFinished(const std::function<void()> &function) {
|
||||
std::scoped_lock lock(s_tasksFinishedMutex);
|
||||
|
||||
for (const auto &task : s_tasks) {
|
||||
task->interrupt();
|
||||
}
|
||||
|
||||
s_tasksFinishedCallbacks.push_back(function);
|
||||
}
|
||||
|
||||
@@ -461,7 +439,7 @@ namespace hex {
|
||||
static auto setThreadDescription = reinterpret_cast<SetThreadDescriptionFunc>(
|
||||
reinterpret_cast<uintptr_t>(
|
||||
::GetProcAddress(
|
||||
::GetModuleHandleW(L"Kernel32.dll"),
|
||||
::GetModuleHandle("Kernel32.dll"),
|
||||
"SetThreadDescription"
|
||||
)
|
||||
)
|
||||
@@ -490,7 +468,7 @@ namespace hex {
|
||||
#elif defined(OS_LINUX)
|
||||
pthread_setname_np(pthread_self(), name.c_str());
|
||||
#elif defined(OS_WEB)
|
||||
std::ignore = name;
|
||||
hex::unused(name);
|
||||
#elif defined(OS_MACOS)
|
||||
pthread_setname_np(name.c_str());
|
||||
#endif
|
||||
|
||||
@@ -17,30 +17,18 @@ namespace hex {
|
||||
AutoReset<std::string> s_imageTheme;
|
||||
AutoReset<std::string> s_currTheme;
|
||||
|
||||
std::recursive_mutex s_themeMutex;
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
std::unique_lock lock(s_themeMutex);
|
||||
|
||||
(*s_themeHandlers)[name] = { colorMap, getFunction, setFunction };
|
||||
}
|
||||
|
||||
void ThemeManager::addStyleHandler(const std::string &name, const StyleMap &styleMap) {
|
||||
std::unique_lock lock(s_themeMutex);
|
||||
|
||||
(*s_styleHandlers)[name] = { styleMap };
|
||||
}
|
||||
|
||||
void ThemeManager::addTheme(const std::string &content) {
|
||||
std::unique_lock lock(s_themeMutex);
|
||||
|
||||
try {
|
||||
auto theme = nlohmann::json::parse(content);
|
||||
|
||||
@@ -78,7 +66,7 @@ namespace hex {
|
||||
if (color == 0x00000000)
|
||||
return ImVec4(0, 0, 0, -1);
|
||||
|
||||
return ImColor(hex::changeEndianness(color, std::endian::big));
|
||||
return ImColor(hex::changeEndianess(color, std::endian::big));
|
||||
}
|
||||
|
||||
nlohmann::json ThemeManager::exportCurrentTheme(const std::string &name) {
|
||||
@@ -95,7 +83,7 @@ namespace hex {
|
||||
|
||||
for (const auto &[key, value] : handler.colorMap) {
|
||||
auto color = handler.getFunction(value);
|
||||
theme["colors"][type][key] = fmt::format("#{:08X}", hex::changeEndianness(u32(color), std::endian::big));
|
||||
theme["colors"][type][key] = fmt::format("#{:08X}", hex::changeEndianess(u32(color), std::endian::big));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -118,8 +106,6 @@ namespace hex {
|
||||
}
|
||||
|
||||
void ThemeManager::changeTheme(std::string name) {
|
||||
std::unique_lock lock(s_themeMutex);
|
||||
|
||||
if (!s_themes->contains(name)) {
|
||||
if (s_themes->empty()) {
|
||||
return;
|
||||
@@ -182,12 +168,12 @@ namespace hex {
|
||||
const float scale = style.needsScaling ? 1_scaled : 1.0F;
|
||||
|
||||
if (value.is_number_float()) {
|
||||
if (const auto newValue = std::get_if<float*>(&style.value); newValue != nullptr && *newValue != nullptr)
|
||||
if (const auto newValue = std::get_if<float*>(&style.value); newValue != nullptr)
|
||||
**newValue = value.get<float>() * scale;
|
||||
else
|
||||
log::warn("Style variable '{}' was of type ImVec2 but a float was expected.", name);
|
||||
} else if (value.is_array() && value.size() == 2 && value[0].is_number_float() && value[1].is_number_float()) {
|
||||
if (const auto newValue = std::get_if<ImVec2*>(&style.value); newValue != nullptr && *newValue != nullptr)
|
||||
if (const auto newValue = std::get_if<ImVec2*>(&style.value); newValue != nullptr)
|
||||
**newValue = ImVec2(value[0].get<float>() * scale, value[1].get<float>() * scale);
|
||||
else
|
||||
log::warn("Style variable '{}' was of type float but a ImVec2 was expected.", name);
|
||||
@@ -205,8 +191,6 @@ namespace hex {
|
||||
hex::log::error("Theme '{}' has invalid image theme!", name);
|
||||
s_imageTheme = "dark";
|
||||
}
|
||||
} else {
|
||||
s_imageTheme = "dark";
|
||||
}
|
||||
|
||||
s_currTheme = name;
|
||||
@@ -227,8 +211,6 @@ namespace hex {
|
||||
}
|
||||
|
||||
void ThemeManager::reset() {
|
||||
std::unique_lock lock(s_themeMutex);
|
||||
|
||||
s_themes->clear();
|
||||
s_styleHandlers->clear();
|
||||
s_themeHandlers->clear();
|
||||
|
||||
@@ -21,11 +21,6 @@ namespace hex {
|
||||
AutoReset<std::map<ImGuiID, std::string>> s_highlights;
|
||||
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 {
|
||||
public:
|
||||
@@ -33,13 +28,6 @@ namespace hex {
|
||||
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) {
|
||||
const ImGuiID seed = idStack.back();
|
||||
const ImGuiID id = ImHashStr(string.c_str(), string.length(), seed);
|
||||
@@ -68,46 +56,8 @@ namespace hex {
|
||||
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() {
|
||||
return s_tutorials;
|
||||
@@ -122,28 +72,6 @@ namespace hex {
|
||||
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) {
|
||||
s_currentTutorial = s_tutorials->find(unlocalizedName);
|
||||
if (s_currentTutorial == s_tutorials->end())
|
||||
@@ -153,30 +81,6 @@ namespace hex {
|
||||
}
|
||||
|
||||
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) {
|
||||
const auto drawList = ImGui::GetForegroundDrawList();
|
||||
|
||||
@@ -337,13 +241,39 @@ namespace hex {
|
||||
m_onAppear();
|
||||
|
||||
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 {
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -438,4 +368,15 @@ 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; }
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/auto_reset.hpp>
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
|
||||
@@ -26,7 +25,7 @@ namespace hex {
|
||||
.builtin = false
|
||||
}).first;
|
||||
|
||||
for (const auto &workspaceFolder : paths::Workspaces.write()) {
|
||||
for (const auto &workspaceFolder : fs::getDefaultPaths(fs::ImHexPath::Workspaces)) {
|
||||
const auto workspacePath = workspaceFolder / (name + ".hexws");
|
||||
if (exportToFile(workspacePath)) {
|
||||
s_currentWorkspace->second.path = workspacePath;
|
||||
@@ -44,9 +43,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
void WorkspaceManager::importFromFile(const std::fs::path& path) {
|
||||
if (std::ranges::any_of(*s_workspaces, [path](const auto &pair) { return pair.second.path == path; })) {
|
||||
if (std::ranges::any_of(*s_workspaces, [path](const auto &pair) { return pair.second.path == path; }))
|
||||
return;
|
||||
}
|
||||
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Read);
|
||||
if (!file.isValid()) {
|
||||
@@ -76,23 +74,19 @@ namespace hex {
|
||||
|
||||
bool WorkspaceManager::exportToFile(std::fs::path path, std::string workspaceName, bool builtin) {
|
||||
if (path.empty()) {
|
||||
if (s_currentWorkspace == s_workspaces->end()) {
|
||||
if (s_currentWorkspace == s_workspaces->end())
|
||||
return false;
|
||||
}
|
||||
|
||||
path = s_currentWorkspace->second.path;
|
||||
}
|
||||
|
||||
if (workspaceName.empty()) {
|
||||
if (workspaceName.empty())
|
||||
workspaceName = s_currentWorkspace->first;
|
||||
}
|
||||
|
||||
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||
|
||||
if (!file.isValid()) {
|
||||
if (!file.isValid())
|
||||
return false;
|
||||
}
|
||||
|
||||
nlohmann::json json;
|
||||
json["name"] = workspaceName;
|
||||
@@ -105,36 +99,28 @@ namespace hex {
|
||||
}
|
||||
|
||||
void WorkspaceManager::removeWorkspace(const std::string& name) {
|
||||
bool deletedCurrentWorkspace = false;
|
||||
for (const auto &[workspaceName, workspace] : *s_workspaces) {
|
||||
if (workspaceName == name) {
|
||||
log::info("Removing workspace file '{}'", wolv::util::toUTF8String(workspace.path));
|
||||
if (wolv::io::fs::remove(workspace.path)) {
|
||||
log::info("{}", wolv::util::toUTF8String(workspace.path));
|
||||
if (wolv::io::File(workspace.path, wolv::io::File::Mode::Write).remove()) {
|
||||
log::info("Removed workspace '{}'", name);
|
||||
|
||||
if (workspaceName == s_currentWorkspace->first) {
|
||||
deletedCurrentWorkspace = true;
|
||||
}
|
||||
switchWorkspace(s_workspaces->begin()->first);
|
||||
s_workspaces->erase(workspaceName);
|
||||
} else {
|
||||
log::error("Failed to remove workspace '{}'", name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
WorkspaceManager::reload();
|
||||
|
||||
if (deletedCurrentWorkspace && !s_workspaces->empty()) {
|
||||
s_currentWorkspace = s_workspaces->begin();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WorkspaceManager::process() {
|
||||
if (s_previousWorkspace != s_currentWorkspace) {
|
||||
log::info("Updating workspace");
|
||||
if (s_previousWorkspace != s_workspaces->end()) {
|
||||
if (s_previousWorkspace != s_workspaces->end())
|
||||
exportToFile(s_previousWorkspace->second.path, s_previousWorkspace->first, s_previousWorkspace->second.builtin);
|
||||
}
|
||||
|
||||
LayoutManager::closeAllViews();
|
||||
ImGui::LoadIniSettingsFromMemory(s_currentWorkspace->second.layout.c_str());
|
||||
@@ -158,16 +144,14 @@ namespace hex {
|
||||
void WorkspaceManager::reload() {
|
||||
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)) {
|
||||
if (!entry.is_regular_file()) {
|
||||
if (!entry.is_regular_file())
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto &path = entry.path();
|
||||
if (path.extension() != ".hexws") {
|
||||
if (path.extension() != ".hexws")
|
||||
continue;
|
||||
}
|
||||
|
||||
WorkspaceManager::importFromFile(path);
|
||||
}
|
||||
|
||||
@@ -8,18 +8,12 @@
|
||||
namespace hex::dp {
|
||||
|
||||
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)) {
|
||||
for (auto &attr : m_attributes)
|
||||
attr.setParentNode(this);
|
||||
}
|
||||
|
||||
void Node::draw() {
|
||||
this->drawNode();
|
||||
}
|
||||
|
||||
|
||||
const std::vector<u8>& Node::getBufferOnInput(u32 index) {
|
||||
auto attribute = this->getConnectedInputAttribute(index);
|
||||
|
||||
@@ -35,6 +29,9 @@ namespace hex::dp {
|
||||
|
||||
auto &outputData = attribute->getOutputData();
|
||||
|
||||
if (outputData.empty())
|
||||
throwNodeError("No data available at connected attribute");
|
||||
|
||||
return outputData;
|
||||
}
|
||||
|
||||
@@ -151,56 +148,9 @@ namespace hex::dp {
|
||||
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) {
|
||||
if (id > s_idCounter)
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,10 +1,8 @@
|
||||
#include <algorithm>
|
||||
#include <hex/helpers/crypto.hpp>
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <wolv/utils/guards.hpp>
|
||||
#include <wolv/utils/expected.hpp>
|
||||
|
||||
#include <mbedtls/version.h>
|
||||
#include <mbedtls/base64.h>
|
||||
@@ -498,8 +496,8 @@ namespace hex::crypt {
|
||||
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,
|
||||
std::array<u8, 8> nonce, std::array<u8, 8> iv, const std::span<const u8> &input) {
|
||||
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::vector<u8> output;
|
||||
|
||||
if (input.empty())
|
||||
return {};
|
||||
@@ -509,65 +507,38 @@ namespace hex::crypt {
|
||||
mbedtls_cipher_context_t ctx;
|
||||
auto cipherInfo = mbedtls_cipher_info_from_type(type);
|
||||
|
||||
if (cipherInfo == nullptr)
|
||||
return {};
|
||||
|
||||
int setupResult = mbedtls_cipher_setup(&ctx, cipherInfo);
|
||||
if (setupResult != 0)
|
||||
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);
|
||||
mbedtls_cipher_setup(&ctx, cipherInfo);
|
||||
mbedtls_cipher_setkey(&ctx, key.data(), key.size() * 8, operation);
|
||||
|
||||
std::array<u8, 16> nonceCounter = { 0 };
|
||||
|
||||
auto mode = mbedtls_cipher_get_cipher_mode(&ctx);
|
||||
|
||||
// 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);
|
||||
}
|
||||
std::copy(nonce.begin(), nonce.end(), nonceCounter.begin());
|
||||
std::copy(iv.begin(), iv.end(), nonceCounter.begin() + 8);
|
||||
|
||||
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);
|
||||
|
||||
if (cryptResult != 0) {
|
||||
return wolv::util::Unexpected(cryptResult);
|
||||
}
|
||||
|
||||
output.resize(input.size());
|
||||
|
||||
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) {
|
||||
case KeyLength::Key128Bits:
|
||||
if (key.size() != 128 / 8)
|
||||
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
|
||||
if (key.size() != 128 / 8) return {};
|
||||
break;
|
||||
case KeyLength::Key192Bits:
|
||||
if (key.size() != 192 / 8)
|
||||
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
|
||||
if (key.size() != 192 / 8) return {};
|
||||
break;
|
||||
case KeyLength::Key256Bits:
|
||||
if (key.size() != 256 / 8)
|
||||
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
|
||||
if (key.size() != 256 / 8) return {};
|
||||
break;
|
||||
default:
|
||||
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_KEY_LENGTH);
|
||||
return {};
|
||||
}
|
||||
|
||||
mbedtls_cipher_type_t type;
|
||||
@@ -597,7 +568,7 @@ namespace hex::crypt {
|
||||
type = MBEDTLS_CIPHER_AES_128_XTS;
|
||||
break;
|
||||
default:
|
||||
return wolv::util::Unexpected(CRYPTO_ERROR_INVALID_MODE);
|
||||
return {};
|
||||
}
|
||||
|
||||
type = mbedtls_cipher_type_t(type + u8(keyLength));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,7 +23,6 @@
|
||||
#if defined(OS_WEB)
|
||||
#include <emscripten.h>
|
||||
#else
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <nfd.hpp>
|
||||
#endif
|
||||
|
||||
@@ -33,9 +32,6 @@
|
||||
#include <wolv/io/fs.hpp>
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <fmt/xchar.h>
|
||||
|
||||
namespace hex::fs {
|
||||
|
||||
static AutoReset<std::function<void(const std::string&)>> s_fileBrowserErrorCallback;
|
||||
@@ -51,11 +47,13 @@ namespace hex::fs {
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
std::ignore = ShellExecuteW(nullptr, L"open", filePath.c_str(), nullptr, nullptr, SW_SHOWNORMAL);
|
||||
#elif defined(OS_MACOS)
|
||||
std::ignore = system(
|
||||
hex::format("open {}", wolv::util::toUTF8String(filePath)).c_str()
|
||||
hex::unused(
|
||||
ShellExecute(nullptr, "open", wolv::util::toUTF8String(filePath).c_str(), nullptr, nullptr, SW_SHOWNORMAL)
|
||||
);
|
||||
#elif defined(OS_MACOS)
|
||||
hex::unused(system(
|
||||
hex::format("open {}", wolv::util::toUTF8String(filePath)).c_str()
|
||||
));
|
||||
#elif defined(OS_LINUX)
|
||||
executeCmd({"xdg-open", wolv::util::toUTF8String(filePath)});
|
||||
#endif
|
||||
@@ -68,12 +66,13 @@ namespace hex::fs {
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
auto args = fmt::format(L"\"{}\"", dirPath.c_str());
|
||||
ShellExecuteW(nullptr, L"open", L"explorer.exe", args.c_str(), nullptr, SW_SHOWNORMAL);
|
||||
hex::unused(system(
|
||||
hex::format("explorer.exe {}", wolv::util::toUTF8String(dirPath)).c_str()
|
||||
));
|
||||
#elif defined(OS_MACOS)
|
||||
std::ignore = system(
|
||||
hex::unused(system(
|
||||
hex::format("open {}", wolv::util::toUTF8String(dirPath)).c_str()
|
||||
);
|
||||
));
|
||||
#elif defined(OS_LINUX)
|
||||
executeCmd({"xdg-open", wolv::util::toUTF8String(dirPath)});
|
||||
#endif
|
||||
@@ -86,15 +85,16 @@ namespace hex::fs {
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
auto args = fmt::format(L"/select,\"{}\"", selectedFilePath.c_str());
|
||||
ShellExecuteW(nullptr, L"open", L"explorer.exe", args.c_str(), nullptr, SW_SHOWNORMAL);
|
||||
hex::unused(system(
|
||||
hex::format(R"(explorer.exe /select,"{}")", wolv::util::toUTF8String(selectedFilePath)).c_str()
|
||||
));
|
||||
#elif defined(OS_MACOS)
|
||||
std::ignore = system(
|
||||
hex::unused(system(
|
||||
hex::format(
|
||||
R"(osascript -e 'tell application "Finder" to reveal POSIX file "{}"')",
|
||||
wolv::util::toUTF8String(selectedFilePath)
|
||||
).c_str()
|
||||
);
|
||||
));
|
||||
system(R"(osascript -e 'tell application "Finder" to activate')");
|
||||
#elif defined(OS_LINUX)
|
||||
// Fallback to only opening the folder for now
|
||||
@@ -123,13 +123,7 @@ namespace hex::fs {
|
||||
// Call callback that will write the file
|
||||
Module._fileBrowserCallback(stringToNewUTF8("/savedFiles/" + filename));
|
||||
|
||||
let data;
|
||||
try {
|
||||
data = FS.readFile("/savedFiles/" + filename);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
return;
|
||||
}
|
||||
let data = FS.readFile("/savedFiles/" + filename);
|
||||
|
||||
const reader = Object.assign(new FileReader(), {
|
||||
onload: () => {
|
||||
@@ -197,7 +191,6 @@ namespace hex::fs {
|
||||
else if (!validExtensions.empty())
|
||||
path = "file." + validExtensions[0].spec;
|
||||
|
||||
std::fs::create_directory("/savedFiles");
|
||||
callJs_saveFile(path.filename().string().c_str());
|
||||
break;
|
||||
}
|
||||
@@ -293,6 +286,170 @@ namespace hex::fs {
|
||||
|
||||
#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) {
|
||||
constexpr static auto TestFileName = "__imhex__tmp__";
|
||||
|
||||
|
||||
@@ -41,21 +41,17 @@ namespace hex {
|
||||
}
|
||||
|
||||
void HttpRequest::setProxyUrl(std::string proxy) {
|
||||
std::ignore = proxy;
|
||||
hex::unused(proxy);
|
||||
}
|
||||
|
||||
void HttpRequest::setProxyState(bool state) {
|
||||
std::ignore = state;
|
||||
hex::unused(state);
|
||||
}
|
||||
|
||||
void HttpRequest::checkProxyErrors() { }
|
||||
|
||||
int HttpRequest::progressCallback(void *contents, curl_off_t dlTotal, curl_off_t dlNow, curl_off_t ulTotal, curl_off_t ulNow) {
|
||||
std::ignore = contents;
|
||||
std::ignore = dlTotal;
|
||||
std::ignore = dlNow;
|
||||
std::ignore = ulTotal;
|
||||
std::ignore = ulNow;
|
||||
hex::unused(contents, dlTotal, dlNow, ulTotal, ulNow);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
@@ -1,17 +1,14 @@
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <hex/api/task_manager.hpp>
|
||||
#include <hex/api/event_manager.hpp>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
|
||||
#include <mutex>
|
||||
#include <chrono>
|
||||
#include <fmt/chrono.h>
|
||||
#include <hex/api/task_manager.hpp>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#include <Windows.h>
|
||||
@@ -43,15 +40,10 @@ namespace hex::log {
|
||||
|
||||
namespace impl {
|
||||
|
||||
void lockLoggerMutex() {
|
||||
s_loggerMutex.lock();
|
||||
std::recursive_mutex& getLoggerMutex() {
|
||||
return s_loggerMutex;
|
||||
}
|
||||
|
||||
void unlockLoggerMutex() {
|
||||
s_loggerMutex.unlock();
|
||||
}
|
||||
|
||||
|
||||
bool isLoggingSuspended() {
|
||||
return s_loggingSuspended;
|
||||
}
|
||||
@@ -82,7 +74,7 @@ namespace hex::log {
|
||||
void redirectToFile() {
|
||||
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);
|
||||
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();
|
||||
@@ -144,12 +136,14 @@ namespace hex::log {
|
||||
fmt::print(dest, "{0}", std::string(projectNameLength > MaxTagLength ? 0 : MaxTagLength - projectNameLength, ' '));
|
||||
}
|
||||
|
||||
void assertionHandler(const char* exprString, const char* file, int line) {
|
||||
log::error("Assertion failed: {} at {}:{}", exprString, file, line);
|
||||
void assertionHandler(bool expr, const char* exprString, const char* file, int line) {
|
||||
if (!expr) {
|
||||
log::error("Assertion failed: {} at {}:{}", exprString, file, line);
|
||||
|
||||
#if defined (DEBUG)
|
||||
std::abort();
|
||||
#endif
|
||||
#if defined (DEBUG)
|
||||
std::abort();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
namespace color {
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/default_paths.hpp>
|
||||
|
||||
#include <wolv/utils/guards.hpp>
|
||||
#include <wolv/utils/string.hpp>
|
||||
@@ -30,7 +29,7 @@ namespace hex::magic {
|
||||
std::string magicFiles;
|
||||
|
||||
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)) {
|
||||
auto path = std::fs::absolute(entry.path());
|
||||
|
||||
@@ -65,12 +64,12 @@ namespace hex::magic {
|
||||
if (magicFiles->empty())
|
||||
return true;
|
||||
|
||||
std::array<char, 1024> cwd = { };
|
||||
std::array<char, 1024> cwd = { 0x00 };
|
||||
if (getcwd(cwd.data(), cwd.size()) == nullptr)
|
||||
return false;
|
||||
|
||||
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)) {
|
||||
magicFolder = dir;
|
||||
break;
|
||||
@@ -106,13 +105,8 @@ namespace hex::magic {
|
||||
ON_SCOPE_EXIT { magic_close(ctx); };
|
||||
|
||||
if (magic_load(ctx, magicFiles->c_str()) == 0) {
|
||||
if (auto description = magic_buffer(ctx, data.data(), data.size()); description != nullptr) {
|
||||
auto result = wolv::util::replaceStrings(description, "\\012-", "\n-");
|
||||
if (result.ends_with("- data"))
|
||||
result = result.substr(0, result.size() - 6);
|
||||
|
||||
return result;
|
||||
}
|
||||
if (auto result = magic_buffer(ctx, data.data(), data.size()); result != nullptr)
|
||||
return wolv::util::replaceStrings(result, "\\012-", "\n-");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,13 +130,8 @@ namespace hex::magic {
|
||||
ON_SCOPE_EXIT { magic_close(ctx); };
|
||||
|
||||
if (magic_load(ctx, magicFiles->c_str()) == 0) {
|
||||
if (auto mimeType = magic_buffer(ctx, data.data(), data.size()); mimeType != nullptr) {
|
||||
auto result = wolv::util::replaceStrings(mimeType, "\\012-", "\n-");
|
||||
if (result.ends_with("- application/octet-stream"))
|
||||
result = result.substr(0, result.size() - 26);
|
||||
|
||||
return result;
|
||||
}
|
||||
if (auto result = magic_buffer(ctx, data.data(), data.size()); result != nullptr)
|
||||
return wolv::util::replaceStrings(result, "\\012-", "\n-");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -173,13 +162,8 @@ namespace hex::magic {
|
||||
ON_SCOPE_EXIT { magic_close(ctx); };
|
||||
|
||||
if (magic_load(ctx, magicFiles->c_str()) == 0) {
|
||||
if (auto extension = magic_buffer(ctx, data.data(), data.size()); extension != nullptr) {
|
||||
auto result = wolv::util::replaceStrings(extension, "\\012-", "\n-");
|
||||
if (result.ends_with("- ???"))
|
||||
result = result.substr(0, result.size() - 5);
|
||||
|
||||
return result;
|
||||
}
|
||||
if (auto result = magic_buffer(ctx, data.data(), data.size()); result != nullptr)
|
||||
return wolv::util::replaceStrings(result, "\\012-", "\n-");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -28,9 +28,7 @@ namespace hex {
|
||||
void close() override { }
|
||||
|
||||
void readRaw(u64 offset, void *buffer, size_t size) override {
|
||||
std::ignore = offset;
|
||||
std::ignore = buffer;
|
||||
std::ignore = size;
|
||||
hex::unused(offset, buffer, size);
|
||||
}
|
||||
|
||||
void writeRaw(u64 offset, const void *buffer, size_t size) override {
|
||||
@@ -46,7 +44,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void resizeRaw(u64 newSize) override {
|
||||
std::ignore = newSize;
|
||||
hex::unused(newSize);
|
||||
}
|
||||
|
||||
void insertRaw(u64 offset, u64 size) override {
|
||||
@@ -140,7 +138,7 @@ namespace hex {
|
||||
result.push_back(addressBytes[2]);
|
||||
result.push_back(addressBytes[1]);
|
||||
result.push_back(addressBytes[0]);
|
||||
pushBytesBack<u16>(result, changeEndianness<u16>(bytes.size(), std::endian::big));
|
||||
pushBytesBack<u16>(result, changeEndianess<u16>(bytes.size(), std::endian::big));
|
||||
|
||||
for (auto byte : bytes)
|
||||
result.push_back(byte);
|
||||
@@ -191,7 +189,7 @@ namespace hex {
|
||||
result.push_back(addressBytes[2]);
|
||||
result.push_back(addressBytes[1]);
|
||||
result.push_back(addressBytes[0]);
|
||||
pushBytesBack<u16>(result, changeEndianness<u16>(bytes.size(), std::endian::big));
|
||||
pushBytesBack<u16>(result, changeEndianess<u16>(bytes.size(), std::endian::big));
|
||||
|
||||
for (auto byte : bytes)
|
||||
result.push_back(byte);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -90,7 +90,11 @@ namespace hex {
|
||||
bool Tar::contains(const std::fs::path &path) const {
|
||||
mtar_header_t header;
|
||||
|
||||
const auto fixedPath = wolv::io::fs::toNormalizedPathString(path);
|
||||
auto fixedPath = path.string();
|
||||
#if defined(OS_WINDOWS)
|
||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
||||
#endif
|
||||
|
||||
return mtar_find(m_ctx.get(), fixedPath.c_str(), &header) == MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
@@ -111,7 +115,10 @@ namespace hex {
|
||||
std::vector<u8> Tar::readVector(const std::fs::path &path) const {
|
||||
mtar_header_t header;
|
||||
|
||||
const auto fixedPath = wolv::io::fs::toNormalizedPathString(path);
|
||||
auto fixedPath = path.string();
|
||||
#if defined(OS_WINDOWS)
|
||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
||||
#endif
|
||||
int ret = mtar_find(m_ctx.get(), fixedPath.c_str(), &header);
|
||||
if (ret != MTAR_ESUCCESS){
|
||||
log::debug("Failed to read vector from path {} in tarred file {}: {}",
|
||||
@@ -136,12 +143,18 @@ namespace hex {
|
||||
for (const auto &part : path.parent_path()) {
|
||||
pathPart /= part;
|
||||
|
||||
auto fixedPath = wolv::io::fs::toNormalizedPathString(pathPart);
|
||||
auto fixedPath = pathPart.string();
|
||||
#if defined(OS_WINDOWS)
|
||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
||||
#endif
|
||||
mtar_write_dir_header(m_ctx.get(), fixedPath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
const auto fixedPath = wolv::io::fs::toNormalizedPathString(path);
|
||||
auto fixedPath = path.string();
|
||||
#if defined(OS_WINDOWS)
|
||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
||||
#endif
|
||||
mtar_write_file_header(m_ctx.get(), fixedPath.c_str(), data.size());
|
||||
mtar_write_data(m_ctx.get(), data.data(), data.size());
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user