Compare commits

..

4 Commits

Author SHA1 Message Date
WerWolv
abd21637ce Add partial config UI, add more architectures 2023-12-04 22:05:34 +01:00
WerWolv
5b1f5c0dd8 Improve jump slot detection 2023-12-04 13:37:34 +01:00
WerWolv
fcdaf4685b Properly draw jump arrows when destination isn't on screen 2023-12-04 12:04:00 +01:00
WerWolv
2a55cd8a4f feat: Initial implementation of improved disassembler 2023-12-04 11:46:35 +01:00
563 changed files with 100588 additions and 142890 deletions

View File

@@ -7,10 +7,3 @@ skip -rfu ^ImGui::
# Trigger breakpoint when execution reaches triggerSafeShutdown() # Trigger breakpoint when execution reaches triggerSafeShutdown()
break triggerSafeShutdown break triggerSafeShutdown
# Print backtrace after execution jumped to an invalid address
define fixbt
set $pc = *(void **)$rsp
set $rsp = $rsp + 8
bt
end

3
.gitattributes vendored
View File

@@ -1,4 +1 @@
lib/external/** linguist-vendored lib/external/** linguist-vendored
dist/*.sh eol=lf
dist/**/*Dockerfile eol=lf

View File

@@ -16,7 +16,7 @@ jobs:
steps: steps:
- name: 🧰 Checkout - name: 🧰 Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
@@ -26,14 +26,14 @@ jobs:
languages: 'cpp' languages: 'cpp'
- name: 📜 Setup ccache - name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1 uses: hendrikmuhs/ccache-action@v1.2
with: with:
key: ${{ runner.os }}-analysis-build-${{ github.run_id }} key: ${{ runner.os }}-analysis-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-analysis-build restore-keys: ${{ runner.os }}-analysis-build
max-size: 50M max-size: 50M
- name: 📜 Restore CMakeCache - name: 📜 Restore CMakeCache
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: | path: |
build/CMakeCache.txt build/CMakeCache.txt

View File

@@ -2,9 +2,7 @@ name: Build
on: on:
push: push:
branches: branches: ["*"]
- 'master'
- 'releases/**'
pull_request: pull_request:
workflow_dispatch: workflow_dispatch:
@@ -24,30 +22,46 @@ jobs:
CCACHE_DIR: "${{ github.workspace }}/.ccache" CCACHE_DIR: "${{ github.workspace }}/.ccache"
steps: steps:
- name: 🧰 Checkout - name: 🧰 Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: 📜 Setup ccache - name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1 uses: hendrikmuhs/ccache-action@v1.2
id: cache-ccache id: cache-ccache
with: with:
key: ${{ runner.os }}-ccache-${{ github.run_id }} key: ${{ runner.os }}-ccache-${{ github.run_id }}
restore-keys: ${{ runner.os }}-ccache restore-keys: ${{ runner.os }}-ccache
max-size: 1G max-size: 1G
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
key: ${{ runner.os }}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
- name: 🟦 Install msys2 - name: 🟦 Install msys2
uses: msys2/setup-msys2@v2 uses: msys2/setup-msys2@v2
with: with:
msystem: mingw64 msystem: mingw64
pacboy: >-
- name: ⬇️ Install dependencies gcc:p
run: | lld:p
set -x cmake:p
dist/get_deps_msys2.sh ccache:p
glfw:p
file:p
mbedtls:p
freetype:p
dlfcn:p
libbacktrace:p
ninja:p
curl-winssl:p
capstone:p
- name: ⬇️ Install .NET - name: ⬇️ Install .NET
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v3
with: with:
dotnet-version: '8.0.100' dotnet-version: '8.0.100'
@@ -56,29 +70,24 @@ jobs:
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
# Windows cmake build # Windows cmake build
- name: 🛠️ Configure CMake - name: 🛠️ Build
run: | run: |
set -x set -x
mkdir -p build mkdir -p build
cd build cd build
cmake -G "Ninja" \ cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \ -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \ -DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DIMHEX_GENERATE_PACKAGE=ON \ -DIMHEX_GENERATE_PACKAGE=ON \
-DIMHEX_USE_DEFAULT_BUILD_SETTINGS=ON \ -DIMHEX_USE_DEFAULT_BUILD_SETTINGS=ON \
-DIMHEX_PATTERNS_PULL_MASTER=ON \ -DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \ -DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \ -DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DUSE_SYSTEM_CAPSTONE=ON \ -DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DIMHEX_GENERATE_PDBS=ON \ -DUSE_SYSTEM_CAPSTONE=ON \
-DIMHEX_REPLACE_DWARF_WITH_PDB=ON \
-DDOTNET_EXECUTABLE="C:/Program Files/dotnet/dotnet.exe" \ -DDOTNET_EXECUTABLE="C:/Program Files/dotnet/dotnet.exe" \
.. ..
- name: 🛠️ Build
run: |
cd build
ninja install ninja install
cpack cpack
mv ImHex-*.msi ../imhex-${{env.IMHEX_VERSION}}-Windows-x86_64.msi mv ImHex-*.msi ../imhex-${{env.IMHEX_VERSION}}-Windows-x86_64.msi
@@ -86,7 +95,7 @@ jobs:
echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE
- name: ⬆️ Upload Windows Installer - name: ⬆️ Upload Windows Installer
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
if-no-files-found: error if-no-files-found: error
name: Windows Installer x86_64 name: Windows Installer x86_64
@@ -94,7 +103,7 @@ jobs:
imhex-*.msi imhex-*.msi
- name: ⬆️ Upload Portable ZIP - name: ⬆️ Upload Portable ZIP
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
if-no-files-found: error if-no-files-found: error
name: Windows Portable x86_64 name: Windows Portable x86_64
@@ -111,7 +120,7 @@ jobs:
mv opengl32.dll build/install mv opengl32.dll build/install
- name: ⬆️ Upload NoGPU Portable ZIP - name: ⬆️ Upload NoGPU Portable ZIP
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
if-no-files-found: error if-no-files-found: error
name: Windows Portable NoGPU x86_64 name: Windows Portable NoGPU x86_64
@@ -135,7 +144,7 @@ jobs:
steps: steps:
- name: 🧰 Checkout - name: 🧰 Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
@@ -144,12 +153,19 @@ jobs:
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
- name: 📜 Setup ccache - name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1 uses: hendrikmuhs/ccache-action@v1.2
with: with:
key: ${{ runner.os }}${{ matrix.suffix }}-ccache-${{ github.run_id }} key: ${{ runner.os }}${{ matrix.suffix }}-ccache-${{ github.run_id }}
restore-keys: ${{ runner.os }}${{ matrix.suffix }}-ccache restore-keys: ${{ runner.os }}${{ matrix.suffix }}-ccache
max-size: 1G max-size: 1G
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
key: ${{ runner.os }}-${{ matrix.suffix }}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
- name: ⬇️ Install dependencies - name: ⬇️ Install dependencies
run: | run: |
set -x set -x
@@ -163,13 +179,13 @@ jobs:
brew install glfw brew install glfw
- name: ⬇️ Install .NET - name: ⬇️ Install .NET
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v3
with: with:
dotnet-version: '8.0.100' dotnet-version: '8.0.100'
- name: 🧰 Checkout glfw - name: 🧰 Checkout glfw
if: ${{matrix.custom_glfw}} if: ${{matrix.custom_glfw}}
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
repository: glfw/glfw repository: glfw/glfw
path: glfw path: glfw
@@ -196,7 +212,7 @@ jobs:
ninja install ninja install
# MacOS cmake build # MacOS cmake build
- name: 🛠️ Configure CMake - name: 🛠️ Build
run: | run: |
set -x set -x
mkdir -p build mkdir -p build
@@ -214,54 +230,49 @@ jobs:
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \ -DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \ -DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \ -DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \ -DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DCPACK_PACKAGE_FILE_NAME="imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}-x86_64" \ -DCPACK_PACKAGE_FILE_NAME="imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}-x86_64" \
.. ..
ninja package
- name: 🛠️ Build
run: cd build && ninja package
- name: ⬆️ Upload DMG - name: ⬆️ Upload DMG
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
if-no-files-found: error if-no-files-found: error
name: macOS DMG${{matrix.suffix}} x86_64 name: macOS DMG${{matrix.suffix}} x86_64
path: build/*.dmg path: build/*.dmg
macos-arm64-build: macos-arm64:
runs-on: ubuntu-22.04 runs-on: ubuntu-22.04
name: 🍎 macOS 12.1 arm64 name: 🍎 macOS 12.1 arm64
outputs:
IMHEX_VERSION: ${{ steps.build.outputs.IMHEX_VERSION }}
steps: steps:
- name: 🧰 Checkout - name: 🧰 Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: 📁 Restore docker /cache - name: 📁 Restore docker /cache
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: cache path: cache
key: build-macos-arm64-cache key: build-macos-arm64-cache
- name: 🐳 Inject /cache into docker - name: 🐳 Inject /cache into docker
uses: reproducible-containers/buildkit-cache-dance@v2 uses: reproducible-containers/buildkit-cache-dance@v2.1.2 # Doesn't work with a MacOS runner ?
with: with:
cache-source: cache cache-source: cache
cache-target: /cache cache-target: /cache
- name: 🛠️ Build using docker - name: 🛠️ Build using docker
id: build
run: | run: |
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_OUTPUT
docker buildx build . -f dist/macOS/arm64.Dockerfile --progress=plain --build-arg 'JOBS=4' --build-arg "BUILD_TYPE=$(BUILD_TYPE)" --build-context imhex=$(pwd) --output out docker buildx build . -f dist/macOS/arm64.Dockerfile --progress=plain --build-arg 'JOBS=4' --build-arg "BUILD_TYPE=$(BUILD_TYPE)" --build-context imhex=$(pwd) --output out
- name: ⬆️ Upload artifacts - name: ⬆️ Upload artifacts
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
name: macos_arm64_intermediate name: macOS ZIP arm64
path: out/ path: out/
# See https://github.com/actions/cache/issues/342#issuecomment-1711054115 # See https://github.com/actions/cache/issues/342#issuecomment-1711054115
@@ -271,56 +282,7 @@ jobs:
GH_TOKEN: ${{ github.token }} GH_TOKEN: ${{ github.token }}
run: | run: |
gh extension install actions/gh-actions-cache gh extension install actions/gh-actions-cache
gh actions-cache delete "build-macos-arm64-cache" --confirm || true gh actions-cache delete "build-macos-arm64-cache" --confirm
macos-arm64-package:
runs-on: macos-12
name: 🍎 macOS 12.1 arm64 Packaging
needs: macos-arm64-build
env:
IMHEX_VERSION: ${{ needs.macos-arm64-build.outputs.IMHEX_VERSION }}
steps:
- name: ⬇️ Download artifact
uses: actions/download-artifact@v4
with:
name: macos_arm64_intermediate
path: out
- name: 🗑️ Delete artifact
uses: geekyeggo/delete-artifact@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
name: macos_arm64_intermediate
- name: ✒️ Fix Signature
run: |
set -x
cd out
codesign --remove-signature ImHex.app
codesign --force --deep --sign - ImHex.app
- name: 📁 Fix permissions
run: |
set -x
cd out
chmod -R 755 ImHex.app/
- name: 📦 Create DMG
run: |
set -x
mkdir bundle
mv out/ImHex.app bundle
cd bundle
ln -s /Applications Applications
cd ..
hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{env.IMHEX_VERSION}}-macOS-arm64.dmg
- name: ⬆️ Upload DMG
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: macOS DMG arm64
path: ./*.dmg
# Ubuntu build # Ubuntu build
ubuntu: ubuntu:
@@ -345,30 +307,42 @@ jobs:
run: apt update && apt install -y git curl run: apt update && apt install -y git curl
- name: 🧰 Checkout - name: 🧰 Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: 📜 Setup ccache - name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1 uses: hendrikmuhs/ccache-action@v1.2
with: with:
key: Ubuntu-${{matrix.release_num}}-ccache-${{ github.run_id }} key: Ubuntu-${{matrix.release_num}}-ccache-${{ github.run_id }}
restore-keys: Ubuntu-${{matrix.release_num}}-ccache restore-keys: Ubuntu-${{matrix.release_num}}-ccache
max-size: 1G max-size: 1G
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
key: Ubuntu-${{matrix.release_num}}-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
- name: ⬇️ Install dependencies - name: ⬇️ Install dependencies
run: | run: |
apt update apt update
bash dist/get_deps_debian.sh bash dist/get_deps_debian.sh
- name: ⬇️ Install .NET - name: ⬇️ Install .NET
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v3
with: with:
dotnet-version: '8.0.100' dotnet-version: '8.0.100'
- name: 🏔️ Set Environment variables
run: |
echo COMMIT_SHA_SHORT=$(git rev-parse --short HEAD) >> $GITHUB_ENV
echo COMMIT_SHA_LONG=$(git rev-parse HEAD) >> $GITHUB_ENV
echo COMMIT_BRANCH=$(git rev-parse --abbrev-ref HEAD) >> $GITHUB_ENV
# Ubuntu cmake build # Ubuntu cmake build
- name: 🛠️ Configure CMake - name: 🛠️ Build
shell: bash
run: | run: |
set -x set -x
git config --global --add safe.directory '*' git config --global --add safe.directory '*'
@@ -380,15 +354,14 @@ jobs:
-DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \ -DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \ -DIMHEX_COMMIT_HASH_SHORT="${{ env.COMMIT_SHA_SHORT }}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \ -DIMHEX_COMMIT_HASH_LONG="${{ env.COMMIT_SHA_LONG }}" \
-DIMHEX_COMMIT_BRANCH="${{ env.COMMIT_BRANCH }}" \
-DIMHEX_ENABLE_LTO=ON \ -DIMHEX_ENABLE_LTO=ON \
-DIMHEX_USE_GTK_FILE_PICKER=ON \ -DIMHEX_USE_GTK_FILE_PICKER=ON \
-DDOTNET_EXECUTABLE="dotnet" \ -DDOTNET_EXECUTABLE="dotnet" \
.. ..
DESTDIR=DebDir ninja install
- name: 🛠️ Build
run: cd build && DESTDIR=DebDir ninja install
- name: 📜 Set version variable - name: 📜 Set version variable
run: | run: |
@@ -401,7 +374,7 @@ jobs:
mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-${{ matrix.release_num }}-x86_64.deb mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-${{ matrix.release_num }}-x86_64.deb
- name: ⬆️ Upload DEB - name: ⬆️ Upload DEB
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
if-no-files-found: error if-no-files-found: error
name: Ubuntu ${{ matrix.release_num }} DEB x86_64 name: Ubuntu ${{ matrix.release_num }} DEB x86_64
@@ -413,19 +386,19 @@ jobs:
name: ⬇️ AppImage name: ⬇️ AppImage
steps: steps:
- name: 🧰 Checkout - name: 🧰 Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: 📁 Restore docker /cache - name: 📁 Restore docker /cache
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: cache path: cache
key: appimage-ccache-${{ github.run_id }} key: appimage-ccache-${{ github.run_id }}
restore-keys: appimage-cache restore-keys: appimage-cache
- name: 🐳 Inject /cache into docker - name: 🐳 Inject /cache into docker
uses: reproducible-containers/buildkit-cache-dance@v2 uses: reproducible-containers/buildkit-cache-dance@v2.1.2
with: with:
cache-source: cache cache-source: cache
cache-target: /cache cache-target: /cache
@@ -437,14 +410,14 @@ jobs:
- name: ⬆️ Upload AppImage - name: ⬆️ Upload AppImage
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
if-no-files-found: error if-no-files-found: error
name: Linux AppImage x86_64 name: Linux AppImage x86_64
path: 'out/*.AppImage' path: 'out/*.AppImage'
- name: ⬆️ Upload AppImage zsync - name: ⬆️ Upload AppImage zsync
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
if-no-files-found: error if-no-files-found: error
name: Linux AppImage zsync x86_64 name: Linux AppImage zsync x86_64
@@ -468,7 +441,7 @@ jobs:
pacman -Syu git ccache --noconfirm pacman -Syu git ccache --noconfirm
- name: 🧰 Checkout - name: 🧰 Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
@@ -477,19 +450,26 @@ jobs:
dist/get_deps_archlinux.sh --noconfirm dist/get_deps_archlinux.sh --noconfirm
- name: ⬇️ Install .NET - name: ⬇️ Install .NET
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v3
with: with:
dotnet-version: '8.0.100' dotnet-version: '8.0.100'
- name: 📜 Setup ccache - name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1 uses: hendrikmuhs/ccache-action@v1.2
with: with:
key: archlinux-ccache-${{ github.run_id }} key: archlinux-ccache-${{ github.run_id }}
restore-keys: archlinux-ccache restore-keys: archlinux-ccache
max-size: 1G max-size: 1G
- name: 📜 Restore CMakeCache
uses: actions/cache@v3
with:
path: |
build/CMakeCache.txt
key: archlinux-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
# ArchLinux cmake build # ArchLinux cmake build
- name: 🛠️ Configure CMake - name: 🛠️ Build
run: | run: |
set -x set -x
mkdir -p build mkdir -p build
@@ -504,14 +484,13 @@ jobs:
-DUSE_SYSTEM_NLOHMANN_JSON=ON \ -DUSE_SYSTEM_NLOHMANN_JSON=ON \
-DUSE_SYSTEM_CAPSTONE=OFF \ -DUSE_SYSTEM_CAPSTONE=OFF \
-DIMHEX_PATTERNS_PULL_MASTER=ON \ -DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \ -DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \ -DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
-DIMHEX_ENABLE_LTO=ON \ -DIMHEX_ENABLE_LTO=ON \
-DIMHEX_USE_GTK_FILE_PICKER=ON \ -DIMHEX_USE_GTK_FILE_PICKER=ON \
.. ..
DESTDIR=installDir ninja install
- name: 🛠️ Build
run: cd build && DESTDIR=installDir ninja install
- name: 📜 Set version variable - name: 📜 Set version variable
run: | run: |
@@ -538,11 +517,10 @@ jobs:
# Replace the old file # Replace the old file
rm imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst rm imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
rm *imhex-bin-debug* # rm debug package which is created for some reason
mv *.pkg.tar.zst imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst mv *.pkg.tar.zst imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
- name: ⬆️ Upload imhex-archlinux.pkg.tar.zst - name: ⬆️ Upload imhex-archlinux.pkg.tar.zst
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
if-no-files-found: error if-no-files-found: error
name: ArchLinux .pkg.tar.zst x86_64 name: ArchLinux .pkg.tar.zst x86_64
@@ -559,14 +537,14 @@ jobs:
mock_release: rawhide mock_release: rawhide
release_num: rawhide release_num: rawhide
mock_config: fedora-rawhide mock_config: fedora-rawhide
- name: Fedora
mock_release: f39
release_num: 39
mock_config: fedora-39
- name: Fedora - name: Fedora
mock_release: f38 mock_release: f38
release_num: 38 release_num: 38
mock_config: fedora-38 mock_config: fedora-38
- name: Fedora
mock_release: f37
release_num: 37
mock_config: fedora-37
- name: RHEL-AlmaLinux - name: RHEL-AlmaLinux
mock_release: epel9 mock_release: epel9
release_num: 9 release_num: 9
@@ -584,13 +562,13 @@ jobs:
run: dnf install --disablerepo="*" --enablerepo="fedora" git-core -y run: dnf install --disablerepo="*" --enablerepo="fedora" git-core -y
- name: 🧰 Checkout - name: 🧰 Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
path: ImHex path: ImHex
submodules: recursive submodules: recursive
- name: 📜 Setup DNF Cache - name: 📜 Setup DNF Cache
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: /var/cache/dnf path: /var/cache/dnf
key: ${{ matrix.mock_release }}-dnf-${{ github.run_id }} key: ${{ matrix.mock_release }}-dnf-${{ github.run_id }}
@@ -606,12 +584,12 @@ jobs:
ccache ccache
- name: ⬇️ Install .NET - name: ⬇️ Install .NET
uses: actions/setup-dotnet@v4 uses: actions/setup-dotnet@v3
with: with:
dotnet-version: '8.0.100' dotnet-version: '8.0.100'
- name: 📜 Setup ccache - name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1 uses: hendrikmuhs/ccache-action@v1.2.5
with: with:
key: ${{ matrix.mock_release }}-rpm-${{ github.run_id }} key: ${{ matrix.mock_release }}-rpm-${{ github.run_id }}
restore-keys: ${{ matrix.mock_release }}-rpm restore-keys: ${{ matrix.mock_release }}-rpm
@@ -652,7 +630,7 @@ jobs:
EOT EOT
- name: 📜 Setup Mock Cache - name: 📜 Setup Mock Cache
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: /var/cache/mock path: /var/cache/mock
key: ${{ matrix.mock_release }}-mock-${{ github.run_id }} key: ${{ matrix.mock_release }}-mock-${{ github.run_id }}
@@ -670,7 +648,7 @@ jobs:
$GITHUB_WORKSPACE/imhex-${{env.IMHEX_VERSION}}-${{matrix.name}}-${{matrix.release_num}}-x86_64.rpm $GITHUB_WORKSPACE/imhex-${{env.IMHEX_VERSION}}-${{matrix.name}}-${{matrix.release_num}}-x86_64.rpm
- name: ⬆️ Upload RPM - name: ⬆️ Upload RPM
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v3
with: with:
if-no-files-found: error if-no-files-found: error
name: ${{ matrix.name }} ${{ matrix.release_num }} RPM x86_64 name: ${{ matrix.name }} ${{ matrix.release_num }} RPM x86_64

View File

@@ -2,9 +2,7 @@ name: Build for the web
on: on:
push: push:
branches: branches: ["*"]
- 'master'
- 'releases/**'
pull_request: pull_request:
workflow_dispatch: workflow_dispatch:
@@ -23,29 +21,31 @@ jobs:
name: 🌍 WebAssembly name: 🌍 WebAssembly
steps: steps:
- name: 🧰 Checkout - name: 🧰 Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: 📁 Restore docker /cache - name: 📁 Restore docker /cache
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: cache path: cache
key: web-cmakecache-${{ hashFiles('**/CMakeLists.txt') }} key: build-web-cache
- name: 🐳 Inject /cache into docker - name: 🐳 Inject /cache into docker
uses: reproducible-containers/buildkit-cache-dance@v2 uses: reproducible-containers/buildkit-cache-dance@v2.1.2
with: with:
cache-source: cache cache-source: cache
cache-target: /cache cache-target: /cache
- name: 🛠️ Build using docker - name: 🛠️ Build using docker
run: | run: |
docker buildx build . -f dist/web/Dockerfile --progress=plain --build-arg 'JOBS=4' --output out --target raw docker buildx build . -f dist/web/Dockerfile --progress=plain --build-arg 'JOBS=4' --output out
- name: 🔨 Fix permissions - name: 🔨 Fix permissions
run: | run: |
chmod -c -R +rX "out/" chmod -c -R +rX "out/" | while read line; do
echo "::warning title=Invalid file permissions automatically fixed::$line"
done
- name: ⬆️ Upload artifacts - name: ⬆️ Upload artifacts
uses: actions/upload-pages-artifact@v2 uses: actions/upload-pages-artifact@v2

View File

@@ -15,7 +15,7 @@ jobs:
steps: steps:
- name: 🧰 Checkout - name: 🧰 Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
path: ImHex path: ImHex
@@ -52,23 +52,13 @@ jobs:
repo: ImHex-Patterns repo: ImHex-Patterns
token: ${{ secrets.RELEASE_TOKEN }} token: ${{ secrets.RELEASE_TOKEN }}
- name: 🎫 Create imhex-download-sdk release
uses: ncipollo/release-action@v1
env:
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.RELEASE_TOKEN != '' }}"
with:
tag: v${{ env.IMHEX_VERSION }}
repo: imhex-download-sdk
token: ${{ secrets.RELEASE_TOKEN }}
release-upload-artifacts: release-upload-artifacts:
runs-on: ubuntu-latest runs-on: ubuntu-latest
name: Release Upload Artifacts name: Release Upload Artifacts
steps: steps:
- name: 🧰 Checkout - name: 🧰 Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
path: ImHex path: ImHex
submodules: recursive submodules: recursive
@@ -164,6 +154,7 @@ jobs:
WINGET_GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} WINGET_GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
if: "${{ env.WINGET_GITHUB_TOKEN != '' }}" if: "${{ env.WINGET_GITHUB_TOKEN != '' }}"
run: | run: |
set -x
$tagname = $env:GITHUB_REF.Replace("refs/tags/", "") $tagname = $env:GITHUB_REF.Replace("refs/tags/", "")
$version = $tagname.Replace("v", "") $version = $tagname.Replace("v", "")
$url = "https://github.com/WerWolv/ImHex/releases/download/${tagname}/imhex-${version}-Windows-x86_64.msi" $url = "https://github.com/WerWolv/ImHex/releases/download/${tagname}/imhex-${version}-Windows-x86_64.msi"

View File

@@ -2,13 +2,9 @@ name: "Unit Tests"
on: on:
push: push:
branches: branches: [ master ]
- 'master'
- 'releases/**'
pull_request: pull_request:
branches: branches: [ master ]
- 'master'
- 'releases/**'
workflow_dispatch: workflow_dispatch:
jobs: jobs:
@@ -22,12 +18,12 @@ jobs:
steps: steps:
- name: 🧰 Checkout - name: 🧰 Checkout
uses: actions/checkout@v4 uses: actions/checkout@v3
with: with:
submodules: recursive submodules: recursive
- name: 📜 Setup ccache - name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1 uses: hendrikmuhs/ccache-action@v1.2
with: with:
key: ${{ runner.os }}-tests-build-${{ github.run_id }} key: ${{ runner.os }}-tests-build-${{ github.run_id }}
restore-keys: ${{ runner.os }}-tests-build restore-keys: ${{ runner.os }}-tests-build
@@ -35,7 +31,7 @@ jobs:
- name: 📜 Restore CMakeCache - name: 📜 Restore CMakeCache
uses: actions/cache@v4 uses: actions/cache@v3
with: with:
path: | path: |
build/CMakeCache.txt build/CMakeCache.txt
@@ -65,17 +61,3 @@ jobs:
run: | run: |
cd build cd build
ctest --output-on-failure ctest --output-on-failure
langs:
name: 🧪 Langs
runs-on: ubuntu-22.04
steps:
- name: 🧰 Checkout
uses: actions/checkout@v4
with:
submodules: recursive
- name: Check langs
run:
python3 tests/check_langs.py

2
.gitignore vendored
View File

@@ -3,11 +3,9 @@
cmake-build-*/ cmake-build-*/
build*/ build*/
local/
venv/ venv/
*.mgc *.mgc
imgui.ini imgui.ini
.DS_Store .DS_Store
./CMakeUserPresets.json ./CMakeUserPresets.json
Brewfile.lock.json

8
.gitmodules vendored
View File

@@ -8,7 +8,7 @@
ignore = dirty ignore = dirty
[submodule "lib/third_party/xdgpp"] [submodule "lib/third_party/xdgpp"]
path = lib/third_party/xdgpp path = lib/third_party/xdgpp
url = https://github.com/WerWolv/xdgpp url = https://git.sr.ht/~danyspin97/xdgpp
ignore = dirty ignore = dirty
[submodule "lib/third_party/fmt"] [submodule "lib/third_party/fmt"]
path = lib/third_party/fmt path = lib/third_party/fmt
@@ -33,9 +33,3 @@
path = lib/external/libwolv path = lib/external/libwolv
url = https://github.com/WerWolv/libwolv url = https://github.com/WerWolv/libwolv
[submodule "lib/third_party/HashLibPlus"]
path = lib/third_party/HashLibPlus
url = https://github.com/WerWolv/HashLibPlus
[submodule "lib/third_party/edlib"]
path = lib/third_party/edlib
url = https://github.com/Martinsos/edlib

View File

@@ -1,31 +1,26 @@
cmake_minimum_required(VERSION 3.20) cmake_minimum_required(VERSION 3.20)
# Options # Options
option(IMHEX_PLUGINS_IN_SHARE "Put the plugins in share/imhex/plugins instead of lib[..]/imhex/plugins (Linux only)" OFF) option(IMHEX_PLUGINS_IN_SHARE "Put the plugins in share/imhex/plugins instead of lib[..]/imhex/plugins" OFF)
option(IMHEX_STRIP_RELEASE "Strip the release builds" ON ) option(IMHEX_STRIP_RELEASE "Strip the release builds" ON)
option(IMHEX_OFFLINE_BUILD "Enable offline build" OFF) option(IMHEX_OFFLINE_BUILD "Enable offline build" OFF)
option(IMHEX_IGNORE_BAD_CLONE "Disable the bad clone prevention checks" OFF) option(IMHEX_IGNORE_BAD_CLONE "Disable the bad clone prevention checks" OFF)
option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of the ImHex-Patterns repo" OFF) option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of the ImHex-Patterns repo" OFF)
option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler" OFF) option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler" OFF)
option(IMHEX_USE_GTK_FILE_PICKER "Use GTK file picker instead of xdg-desktop-portals (Linux only)" OFF) option(IMHEX_USE_GTK_FILE_PICKER "Use GTK file picker instead of xdg-desktop-portals" OFF)
option(IMHEX_DISABLE_STACKTRACE "Disables support for printing stack traces" OFF) option(IMHEX_DISABLE_STACKTRACE "Disables support for printing stack traces" OFF)
option(IMHEX_BUNDLE_DOTNET "Bundle .NET runtime" ON ) option(IMHEX_BUNDLE_DOTNET "Bundle .NET runtime" ON)
option(IMHEX_ENABLE_LTO "Enables Link Time Optimizations if possible" OFF) option(IMHEX_ENABLE_LTO "Enables Link Time Optimizations if possible" OFF)
option(IMHEX_USE_DEFAULT_BUILD_SETTINGS "Use default build settings" OFF) option(IMHEX_USE_DEFAULT_BUILD_SETTINGS "Use default build settings" OFF)
option(IMHEX_STRICT_WARNINGS "Enable most available warnings and treat them as errors" ON ) option(IMHEX_STRICT_WARNINGS "Enable most available warnings and treat them as errors" ON)
option(IMHEX_STATIC_LINK_PLUGINS "Statically link all plugins into the main executable" OFF) option(IMHEX_STATIC_LINK_PLUGINS "Statically link all plugins into the main executable" OFF)
option(IMHEX_GENERATE_PACKAGE "Specify if a native package should be built. (Windows and MacOS only)" OFF) option(IMHEX_GENERATE_PACKAGE "Specify if a native package should be built. Only usable on Windows and MacOS" OFF)
option(IMHEX_ENABLE_UNITY_BUILD "Enables building ImHex as a unity build." OFF) option(IMHEX_ENABLE_UNITY_BUILD "Enables building ImHex as a unity build." OFF)
option(IMHEX_GENERATE_PDBS "Enable generating PDB files in non-debug builds (Windows only)" OFF)
option(IMHEX_REPLACE_DWARF_WITH_PDB "Remove DWARF information from binaries when generating PDBS (Windows only)" OFF)
option(IMHEX_ENABLE_STD_ASSERTS "Enable debug asserts in the C++ std library. (Breaks Plugin ABI!)" OFF)
option(IMHEX_ENABLE_UNIT_TESTS "Enable building unit tests" OFF)
option(IMHEX_ENABLE_PRECOMPILED_HEADERS "Enable precompiled headers" OFF)
# Basic compiler and cmake configurations # Basic compiler and cmake configurations
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON) set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
set(IMHEX_BASE_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}") set(IMHEX_BASE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules") set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake") include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
@@ -34,10 +29,9 @@ loadVersion(IMHEX_VERSION)
setVariableInParent(IMHEX_VERSION ${IMHEX_VERSION}) setVariableInParent(IMHEX_VERSION ${IMHEX_VERSION})
configureCMake() configureCMake()
project(imhex project(imhex
LANGUAGES C CXX LANGUAGES C CXX VERSION ${IMHEX_VERSION}
VERSION ${IMHEX_VERSION} DESCRIPTION "The ImHex Hex Editor"
DESCRIPTION "The ImHex Hex Editor" HOMEPAGE_URL "https://imhex.werwolv.net"
HOMEPAGE_URL "https://imhex.werwolv.net"
) )
# Make sure project is configured correctly # Make sure project is configured correctly
@@ -45,13 +39,17 @@ setDefaultBuiltTypeIfUnset()
detectBadClone() detectBadClone()
verifyCompiler() verifyCompiler()
detectBundledPlugins() # List plugin names here. Project name must match folder name
set(PLUGINS
builtin
windows
script_loader
)
# Add various defines # Add various defines
detectOS() detectOS()
detectArch()
addDefines() addDefines()
# Configure packaging and install targets
configurePackingResources() configurePackingResources()
setUninstallTarget() setUninstallTarget()
addBundledLibraries() addBundledLibraries()
@@ -66,7 +64,6 @@ add_subdirectory(main)
enable_testing() enable_testing()
add_subdirectory(tests EXCLUDE_FROM_ALL) add_subdirectory(tests EXCLUDE_FROM_ALL)
# Configure more resources that will be added to the install package # Configure packaging
createPackage() createPackage()
generatePDBs() generatePDBs()
generateSDKDirectory()

343
README.md
View File

@@ -10,19 +10,33 @@
<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 Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</p>
<p align="center"> <p align="center">
<a title="'Build' workflow Status" href="https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild"><img alt="'Build' workflow Status" src="https://img.shields.io/github/actions/workflow/status/WerWolv/ImHex/build.yml?longCache=true&style=for-the-badge&label=Build&logoColor=fff&logo=GitHub%20Actions&branch=master"></a> <a title="'Build' workflow Status" href="https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild">
<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> <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 title="Total Downloads" href="https://github.com/WerWolv/ImHex/releases/latest"><img alt="Total Downloads" src="https://img.shields.io/github/downloads/WerWolv/ImHex/total?longCache=true&style=for-the-badge&label=Downloads&logoColor=fff&logo=GitHub"></a> </a>
<a title="Code Quality" href="https://www.codefactor.io/repository/github/werwolv/imhex"><img alt="Code Quality" src="https://img.shields.io/codefactor/grade/github/WerWolv/ImHex?longCache=true&style=for-the-badge&label=Code%20Quality&logoColor=fff&logo=CodeFactor&branch=master"></a> <a title="Discord Server" href="https://discord.gg/X63jZ36xBY">
<a title="Translation" href="https://weblate.werwolv.net/projects/imhex/"><img alt="Translation" src="https://img.shields.io/weblate/progress/imhex?logo=weblate&logoColor=%23FFFFFF&server=https%3A%2F%2Fweblate.werwolv.net&style=for-the-badge"></a> <img alt="Discord Server" src="https://img.shields.io/discord/789833418631675954?label=Discord&logo=Discord&logoColor=fff&style=for-the-badge">
<a title="Plugins" href="https://github.com/WerWolv/ImHex/blob/master/PLUGINS.md"><img alt="Plugins" src="https://img.shields.io/badge/Plugins-Supported-brightgreen?logo=stackedit&logoColor=%23FFFFFF&style=for-the-badge"></a> </a>
<a title="Total Downloads" href="https://github.com/WerWolv/ImHex/releases/latest">
<img alt="Total Downloads" src="https://img.shields.io/github/downloads/WerWolv/ImHex/total?longCache=true&style=for-the-badge&label=Downloads&logoColor=fff&logo=GitHub">
</a>
<a title="Code Quality" href="https://www.codefactor.io/repository/github/werwolv/imhex">
<img alt="Code Quality" src="https://img.shields.io/codefactor/grade/github/WerWolv/ImHex?longCache=true&style=for-the-badge&label=Code%20Quality&logoColor=fff&logo=CodeFactor&branch=master">
</a>
<a title="Translation" href="https://weblate.werwolv.net/projects/imhex/">
<img alt="Translation" src="https://img.shields.io/weblate/progress/imhex?logo=weblate&logoColor=%23FFFFFF&server=https%3A%2F%2Fweblate.werwolv.net&style=for-the-badge">
</a>
<a title="Documentation" href="https://imhex.werwolv.net/docs">
<img alt="Documentation" src="https://img.shields.io/badge/Docs-Available-brightgreen?logo=gitbook&logoColor=%23FFFFFF&style=for-the-badge">
</a>
<a title="Plugins" href="https://github.com/WerWolv/ImHex/blob/master/PLUGINS.md">
<img alt="Plugins" src="https://img.shields.io/badge/Plugins-Supported-brightgreen?logo=stackedit&logoColor=%23FFFFFF&style=for-the-badge">
</a>
</p> </p>
<p align="center"> <p align="center">
<a title="Download the latest version of ImHex" href="https://imhex.download"><img alt="Download the latest version of ImHex!" src="resources/dist/common/get_release_banner.png"></a> <a title="Use the Web version of ImHex right in your browser!" href="https://web.imhex.werwolv.net">
<a title="Download the latest nightly pre-release version of ImHex" href="https://imhex.download/#nightly"><img alt="Download the latest nightly pre-release version of ImHex" src="resources/dist/common/get_nightly_banner.png"></a> <img alt="Use the Web version of ImHex right in your browser!" src="resources/dist/common/try_online_banner.png">
<a title="Use the Web version of ImHex right in your browser!" href="https://web.imhex.werwolv.net"><img alt="Use the Web version of ImHex right in your browser!" src="resources/dist/common/try_online_banner.png"></a> </a>
<a title="Read the documentation of ImHex!" href="https://docs.werwolv.net"><img alt="Read the documentation of ImHex!" src="resources/dist/common/read_docs_banner.png"></a>
</p> </p>
## Supporting ## Supporting
@@ -30,265 +44,93 @@
If you like my work, please consider supporting me on GitHub Sponsors, Patreon or PayPal. Thanks a lot! If you like my work, please consider supporting me on GitHub Sponsors, Patreon or PayPal. Thanks a lot!
<p align="center"> <p align="center">
<a href="https://github.com/sponsors/WerWolv"><img src="https://werwolv.net/assets/github_banner.png" alt="GitHub donate button" /></a> <a href="https://github.com/sponsors/WerWolv"><img src="https://werwolv.net/assets/github_banner.png" alt="GitHub donate button" /> </a>
<a href="https://www.patreon.com/werwolv"><img src="https://c5.patreon.com/external/logo/become_a_patron_button.png" alt="Patreon donate button" /></a> <a href="https://www.patreon.com/werwolv"><img src="https://c5.patreon.com/external/logo/become_a_patron_button.png" alt="Patreon donate button" /> </a>
<a href="https://werwolv.net/donate"><img src="https://werwolv.net/assets/paypal_banner.png" alt="PayPal donate button" /></a> <a href="https://werwolv.net/donate"><img src="https://werwolv.net/assets/paypal_banner.png" alt="PayPal donate button" /> </a>
</p> </p>
## Screenshots ## Screenshots
![Hex editor, patterns and data information](https://github.com/WerWolv/ImHex/assets/10835354/4f358238-2d27-41aa-9015-a2c6cc3708cf)
![Bookmarks, disassembler and data processor](https://github.com/WerWolv/ImHex/assets/10835354/183bc2cc-2439-4ded-b4c5-b140e19fc92f)
<details> ![Hex editor, patterns and data information](https://user-images.githubusercontent.com/10835354/139717326-8044769d-527b-4d88-8adf-2d4ecafdca1f.png)
<summary><strong>More Screenshots</strong></summary> ![Bookmarks, disassembler and data processor](https://user-images.githubusercontent.com/10835354/139717323-1f8c9d52-f7eb-4f43-9f11-097ac728ed6c.png)
![Data Processor decrypting some data and displaying it as an image](https://github.com/WerWolv/ImHex/assets/10835354/d0623081-3094-4840-a8a8-647b38724db8)
![STL Parser written in the Pattern Language visualizing a 3D model](https://github.com/WerWolv/ImHex/assets/10835354/62cbcd18-1c3f-4dd6-a877-2bf2bf4bb2a5)
![Data Information view displaying various stats about the file](https://github.com/WerWolv/ImHex/assets/10835354/d4706c01-c258-45c9-80b8-fe7a10d5a1de)
</details>
## Features ## Features
<details> - Featureful hex view
<summary><strong>Featureful hex view</strong></summary>
- Byte patching - Byte patching
- Patch management - Patch management
- Infinite Undo/Redo - Copy bytes as feature
- "Copy bytes as..."
- Bytes - Bytes
- Hex string - Hex string
- C, C++, C#, Rust, Python, Java & JavaScript array - C, C++, C#, Rust, Python, Java & JavaScript array
- ASCII-Art hex view - ASCII-Art hex view
- HTML self-contained div - HTML self-contained div
- Simple string and hex search - String and hex search
- Goto from start, end and current cursor position
- Colorful highlighting - Colorful highlighting
- Configurable foreground highlighting rules - Goto from start, end and current cursor position
- Background highlighting using patterns, find results and bookmarks - Custom C++-like pattern language for parsing highlighting a file's content
- Displaying data as a list of many different types - Automatic loading based on MIME type
- Hexadecimal integers (8, 16, 32, 64 bit) - arrays, pointers, structs, unions, enums, bitfields, namespaces, little and big endian support, conditionals and much more!
- Signed and unsigned decimal integers (8, 16, 32, 64 bit)
- Floats (16, 32, 64 bit)
- RGBA8 Colors
- HexII
- Binary
- Decoding data as ASCII and custom encodings
- Built-in support for UTF-8, UTF-16, ShiftJIS, most Windows encodings and many more
- Paged data view
</details>
<details>
<summary><strong>Custom C++-like pattern language for parsing highlighting a file's content</strong></summary>
- Automatic loading based on MIME types and magic values
- Arrays, pointers, structs, unions, enums, bitfields, namespaces, little and big endian support, conditionals and much more!
- Useful error messages, syntax highlighting and error marking - Useful error messages, syntax highlighting and error marking
- Support for visualizing many different types of data - Doesn't burn out your retinas when used in late-night sessions
- Images - Dark mode by default, but a light mode is available as well
- Audio - Data importing
- 3D Models
- Coordinates
- Time stamps
</details>
<details>
<summary><strong>Theming support</strong></summary>
- Doesn't burn out your retinas when used in late-night sessions
- Dark mode by default, but a light mode is available as well
- Customizable colors and styles for all UI elements through shareable theme files
- Support for custom fonts
</details>
<details>
<summary><strong>Importing and Exporting data</strong></summary>
- Base64 files - Base64 files
- IPS and IPS32 patches - IPS and IPS32 patches
- Markdown reports - Data exporting
</details> - IPS and IPS32 patches
<details> - Data inspector allowing interpretation of data as many different types (little and big endian)
<summary><strong>Data Inspector</strong></summary> - Huge file support with fast and efficient loading
- String search
- Interpreting data as many different types with endianess, decimal, hexadecimal and octal support and bit inversion - Copying of strings
- Unsigned and signed integers (8, 16, 24, 32, 48, 64 bit) - Copying of demangled strings
- Floats (16, 32, 64 bit) - File hashing support
- Signed and Unsigned LEB128 - CRC16 and CRC32 with custom initial values and polynomials
- ASCII, Wide and UTF-8 characters and strings - MD4, MD5
- time32_t, time64_t, DOS date and time - SHA-1, SHA-224, SHA-256, SHA-384, SHA-512
- GUIDs - Disassembler supporting many architectures (frontend for Capstone)
- RGBA8 and RGB65 Colors - ARM32 (ARM, Thumb, Cortex-M, AArch32)
- Copying and modifying bytes through the inspector - ARM64
- Adding new data types through the pattern language - MIPS (MIPS32, MIPS64, MIPS32R6, Micro)
- Support for hiding rows that aren't used - x86 (16-bit, 32-bit, 64-bit)
</details> - PowerPC (32-bit, 64-bit)
<details> - SPARC
<summary><strong>Node-based data pre-processor</strong></summary> - IBM SystemZ
- xCORE
- Modify, decrypt and decode data before it's being displayed in the hex editor - M68K
- Modify data without touching the underlying source - TMS320C64X
- Support for adding custom nodes - M680X
</details> - Ethereum
<details> - RISC-V
<summary><strong>Loading data from many different data sources</strong></summary> - WebAssembly
- MOS65XX
- Local Files - Berkeley Packet Filter
- Support for huge files with fast and efficient loading - Bookmarks
- Raw Disks - Region highlighting
- Loading data from raw disks and partitions - Comments
- GDB Server - Data Analyzer
- Access the RAM of a running process or embedded devices through GDB
- Intel Hex and Motorola SREC data
- Process Memory
- Inspect the entire address space of a running process
</details>
<details>
<summary><strong>Data searching</strong></summary>
- Support for searching the entire file or only a selection
- String extraction
- Option to specify minimum length and character set (lower case, upper case, digits, symbols)
- Option to specify encoding (ASCII, UTF-8, UTF-16 big and little endian)
- Sequence search
- Search for a sequence of bytes or characters
- Option to ignore character case
- Regex search
- Search for strings using regular expressions
- Binary Pattern
- Search for sequences of bytes with optional wildcards
- Numeric Value search
- Search for signed/unsigned integers and floats
- Search for ranges of values
- Option to specify size and endianess
- Option to ignore unaligned values
</details>
<details>
<summary><strong>Data hashing support</strong></summary>
- Many different algorithms available
- CRC8, CRC16 and CRC32 with custom initial values and polynomials
- Many default polynomials available
- MD5
- SHA-1, SHA-224, SHA-256, SHA-384, SHA-512
- Adler32
- AP
- BKDR
- Bernstein, Bernstein1
- DEK, DJB, ELF, FNV1, FNV1a, JS, PJW, RS, SDBM
- OneAtTime, Rotating, ShiftAndXor, SuperFast
- Murmur2_32, MurmurHash3_x86_32, MurmurHash3_x86_128, MurmurHash3_x64_128
- SipHash64, SipHash128
- XXHash32, XXHash64
- Tiger, Tiger2
- Blake2B, Blake2S
- Hashing of specific regions of the loaded data
- Hashing of arbitrary strings
</details>
<details>
<summary><strong>Diffing support</strong></summary>
- Compare data of different data sources
- Difference highlighting
- Table view of differences
</details>
<details>
<summary><strong>Integrated disassembler</strong></summary>
- Support for all architectures supported by Capstone
- ARM32 (ARM, Thumb, Cortex-M, AArch32)
- ARM64
- MIPS (MIPS32, MIPS64, MIPS32R6, Micro)
- x86 (16-bit, 32-bit, 64-bit)
- PowerPC (32-bit, 64-bit)
- SPARC
- IBM SystemZ
- xCORE
- M68K
- TMS320C64X
- M680X
- Ethereum
- RISC-V
- WebAssembly
- MOS65XX
- Berkeley Packet Filter
</details>
<details>
<summary><strong>Bookmarks</strong></summary>
- Support for bookmarks with custom names and colors
- Highlighting of bookmarked region in the hex editor
- Jump to bookmarks
- Open content of bookmark in a new tab
- Add comments to bookmarks
</details>
<details>
<summary><strong>Featureful data analyzer and visualizer</strong></summary>
- File magic-based file parser and MIME type database - File magic-based file parser and MIME type database
- Byte type distribution graph - Byte distribution graph
- Entropy graph - Entropy graph
- Highest and average entropy - Highest and average entropy
- Encrypted / Compressed file detection - Encrypted / Compressed file detection
- Digram and Layered distribution graphs - Built-in Content Store
</details> - Download all files found in the database directly from within ImHex
<details> - Yara Rules support
<summary><strong>YARA Rule support</strong></summary> - Quickly scan a file for vulnerabilities with official yara rules
- Helpful tools
- Scan a file for vulnerabilities with official yara rules - Itanium and MSVC demangler
- Highlight matches in the hex editor
- Jump to matches
- Apply multiple rules at once
</details>
<details>
<summary><strong>Helpful tools</strong></summary>
- Itanium, MSVC, Rust and D-Lang demangler based on LLVM
- ASCII table - ASCII table
- Regex replacer - Regex replacer
- Mathematical expression evaluator (Calculator) - Mathematical expression evaluator (Calculator)
- Graphing calculator - Hexadecimal Color picker
- Hexadecimal Color picker with support for many different formats
- Base converter - Base converter
- Byte swapper
- UNIX Permissions calculator - UNIX Permissions calculator
- Wikipedia term definition finder - Wikipedia term definition finder
- File utilities - File utilities
- File splitter - File splitter
- File combiner - File combiner
- File shredder - File shredder
- IEEE754 Float visualizer
- Division by invariant multiplication calculator
- TCP Client/Server
- Euclidean algorithm calculator
</details>
<details>
<summary><strong>Built-in Content updater</strong></summary>
- Download all files found in the database directly from within ImHex
- Pattern files for decoding various file formats
- Libraries for the pattern language
- Magic files for file type detection
- Custom data processor nodes
- Custom encodings
- Custom themes
- Yara rules
</details>
<details>
<summary><strong>Modern Interface</strong></summary>
- Support for multiple workspaces
- Support for custom layouts
- Detachable windows
</details>
<details>
<summary><strong>Easy to get started</strong></summary>
- Support for many different languages
- Simplified mode for beginners
- Extensive documentation
- Many example files available on [the Database](https://github.com/WerWolv/ImHex-Patterns)
- Achievements guiding you through the features of ImHex
- Interactive tutorials
</details>
## Pattern Language ## Pattern Language
@@ -306,13 +148,7 @@ For format patterns, libraries, magic and constant files, check out the [ImHex-P
## Requirements ## Requirements
To use ImHex, the following minimal system requirements need to be met. To use ImHex, the following minimal system requirements need to be met:
> [!IMPORTANT]
> 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 (especially Intel HD GPUs are known to cause issues).
- **OS**: - **OS**:
- **Windows**: Windows 7 or higher (Windows 10/11 recommended) - **Windows**: Windows 7 or higher (Windows 10/11 recommended)
@@ -339,9 +175,8 @@ To compile ImHex on any platform, GCC (or Clang) is required with a version that
On macOS, Clang is also required to compile some ObjC code. On macOS, Clang is also required to compile some ObjC code.
All releases are being built using latest available GCC. All releases are being built using latest available GCC.
> [!NOTE] Many dependencies are bundled into the repository using submodules so make sure to clone it using the `--recurse-submodules` option.
> Many dependencies are bundled into the repository using submodules so make sure to clone it using the `--recurse-submodules` option. All dependencies that aren't bundled, can be installed using the dependency installer scripts found in the `/dist` folder.
> All dependencies that aren't bundled, can be installed using the dependency installer scripts found in the `/dist` folder.
For more information, check out the [Compiling](/dist/compiling) guide. For more information, check out the [Compiling](/dist/compiling) guide.
@@ -350,8 +185,9 @@ See [Contributing](/CONTRIBUTING.md)
## Plugin development ## Plugin development
To develop plugins for ImHex, use the following template project to get started. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content. To develop plugins for ImHex, use one of the following two templates projects to get started. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
- [ImHex Plugin Template](https://github.com/WerWolv/ImHex-Plugin-Template) - [C++ Plugin Template](https://github.com/WerWolv/ImHex-Cpp-Plugin-Template)
- [Rust Plugin Template](https://github.com/WerWolv/ImHex-Rust-Plugin-Template)
## Credits ## Credits
@@ -377,12 +213,3 @@ To develop plugins for ImHex, use the following template project to get started.
- Thanks to btzy for [nativefiledialog-extended](https://github.com/btzy/nativefiledialog-extended) - Thanks to btzy for [nativefiledialog-extended](https://github.com/btzy/nativefiledialog-extended)
- Thanks to danyspin97 for [xdgpp](https://sr.ht/~danyspin97/xdgpp) - Thanks to danyspin97 for [xdgpp](https://sr.ht/~danyspin97/xdgpp)
- Thanks to all other groups and organizations whose libraries are used in ImHex - Thanks to all other groups and organizations whose libraries are used in ImHex
### License
The biggest part of ImHex is under the GPLv2-only license.
Notable exceptions to this are the following parts which are under the LGPLv2.1 license:
- **/lib/libimhex**: The library that allows Plugins to interact with ImHex.
- **/plugins/ui**: The UI plugin library that contains some common UI elements that can be used by other plugins
The reason for this is to allow for proprietary plugins to be developed for ImHex.

View File

@@ -1 +1 @@
1.33.2 1.31.0

View File

@@ -22,7 +22,7 @@ macro(addDefines)
add_compile_definitions(NDEBUG) add_compile_definitions(NDEBUG)
elseif (CMAKE_BUILD_TYPE STREQUAL "Debug") elseif (CMAKE_BUILD_TYPE STREQUAL "Debug")
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-Debug) set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-Debug)
add_compile_definitions(DEBUG) add_compile_definitions(DEBUG _GLIBCXX_DEBUG _GLIBCXX_VERBOSE)
elseif (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo") elseif (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}) set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING})
add_compile_definitions(NDEBUG) add_compile_definitions(NDEBUG)
@@ -31,10 +31,6 @@ macro(addDefines)
add_compile_definitions(NDEBUG) add_compile_definitions(NDEBUG)
endif () endif ()
if (IMHEX_ENABLE_STD_ASSERTS)
add_compile_definitions(_GLIBCXX_DEBUG _GLIBCXX_VERBOSE)
endif()
if (IMHEX_STATIC_LINK_PLUGINS) if (IMHEX_STATIC_LINK_PLUGINS)
add_compile_definitions(IMHEX_STATIC_LINK_PLUGINS) add_compile_definitions(IMHEX_STATIC_LINK_PLUGINS)
endif () endif ()
@@ -46,9 +42,6 @@ function(addDefineToSource SOURCE DEFINE)
APPEND APPEND
PROPERTY COMPILE_DEFINITIONS "${DEFINE}" PROPERTY COMPILE_DEFINITIONS "${DEFINE}"
) )
# Disable precompiled headers for this file
set_source_files_properties(${SOURCE} PROPERTIES SKIP_PRECOMPILE_HEADERS ON)
endfunction() endfunction()
# Detect current OS / System # Detect current OS / System
@@ -58,7 +51,6 @@ macro(detectOS)
set(CMAKE_INSTALL_BINDIR ".") set(CMAKE_INSTALL_BINDIR ".")
set(CMAKE_INSTALL_LIBDIR ".") set(CMAKE_INSTALL_LIBDIR ".")
set(PLUGINS_INSTALL_LOCATION "plugins") set(PLUGINS_INSTALL_LOCATION "plugins")
add_compile_definitions(WIN32_LEAN_AND_MEAN)
elseif (APPLE) elseif (APPLE)
add_compile_definitions(OS_MACOS) add_compile_definitions(OS_MACOS)
set(CMAKE_INSTALL_BINDIR ".") set(CMAKE_INSTALL_BINDIR ".")
@@ -70,19 +62,14 @@ macro(detectOS)
add_compile_definitions(OS_WEB) add_compile_definitions(OS_WEB)
elseif (UNIX AND NOT APPLE) elseif (UNIX AND NOT APPLE)
add_compile_definitions(OS_LINUX) add_compile_definitions(OS_LINUX)
if (BSD AND BSD STREQUAL "FreeBSD")
add_compile_definitions(OS_FREEBSD)
endif()
include(GNUInstallDirs) include(GNUInstallDirs)
if(IMHEX_PLUGINS_IN_SHARE) if(IMHEX_PLUGINS_IN_SHARE)
set(PLUGINS_INSTALL_LOCATION "share/imhex/plugins") set(PLUGINS_INSTALL_LOCATION "share/imhex/plugins")
else() else()
set(PLUGINS_INSTALL_LOCATION "${CMAKE_INSTALL_LIBDIR}/imhex/plugins") set(PLUGINS_INSTALL_LOCATION "${CMAKE_INSTALL_LIBDIR}/imhex/plugins")
# Warning : Do not work with portable versions such as appimage (because the path is hardcoded)
# Add System plugin location for plugins to be loaded from add_compile_definitions(SYSTEM_PLUGINS_LOCATION="${CMAKE_INSTALL_FULL_LIBDIR}/imhex") # "plugins" will be appended from the app
# IMPORTANT: This does not work for Sandboxed or portable builds such as the Flatpak or AppImage release
add_compile_definitions(SYSTEM_PLUGINS_LOCATION="${CMAKE_INSTALL_FULL_LIBDIR}/imhex")
endif() endif()
else () else ()
@@ -91,6 +78,16 @@ macro(detectOS)
endmacro() endmacro()
# Detect 32 vs. 64 bit system
macro(detectArch)
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
add_compile_definitions(ARCH_64_BIT)
elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
add_compile_definitions(ARCH_32_BIT)
endif()
endmacro()
macro(configurePackingResources) macro(configurePackingResources)
if (WIN32) if (WIN32)
if (NOT (CMAKE_BUILD_TYPE STREQUAL "Debug")) if (NOT (CMAKE_BUILD_TYPE STREQUAL "Debug"))
@@ -111,12 +108,11 @@ macro(configurePackingResources)
set(CPACK_PACKAGE_INSTALL_DIRECTORY "ImHex") set(CPACK_PACKAGE_INSTALL_DIRECTORY "ImHex")
set_property(INSTALL "$<TARGET_FILE_NAME:main>" set_property(INSTALL "$<TARGET_FILE_NAME:main>"
PROPERTY CPACK_START_MENU_SHORTCUTS "ImHex" PROPERTY CPACK_START_MENU_SHORTCUTS "ImHex"
) )
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/resources/dist/windows/LICENSE.rtf") set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/resources/dist/windows/LICENSE.rtf")
endif() endif()
elseif (APPLE OR ${CMAKE_HOST_SYSTEM_NAME} MATCHES "Darwin") elseif (APPLE)
set(IMHEX_ICON "${IMHEX_BASE_FOLDER}/resources/dist/macos/AppIcon.icns") set (IMHEX_ICON "${IMHEX_BASE_FOLDER}/resources/dist/macos/AppIcon.icns")
set(BUNDLE_NAME "imhex.app")
if (IMHEX_GENERATE_PACKAGE) if (IMHEX_GENERATE_PACKAGE)
set(APPLICATION_TYPE MACOSX_BUNDLE) set(APPLICATION_TYPE MACOSX_BUNDLE)
@@ -127,16 +123,15 @@ macro(configurePackingResources)
set(MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/resources/dist/macos/Info.plist.in") set(MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/resources/dist/macos/Info.plist.in")
set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "net.WerWolv.ImHex") set(MACOSX_BUNDLE_GUI_IDENTIFIER "net.WerWolv.ImHex")
string(SUBSTRING "${IMHEX_COMMIT_HASH_LONG}" 0 7 COMMIT_HASH_SHORT) set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}-${IMHEX_COMMIT_HASH_SHORT}")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}-${COMMIT_HASH_SHORT}")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}") set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
string(TIMESTAMP CURR_YEAR "%Y") string(TIMESTAMP CURR_YEAR "%Y")
set(MACOSX_BUNDLE_COPYRIGHT "Copyright © 2020 - ${CURR_YEAR} WerWolv. All rights reserved." ) set(MACOSX_BUNDLE_COPYRIGHT "Copyright © 2020 - ${CURR_YEAR} WerWolv. All rights reserved." )
if ("${CMAKE_GENERATOR}" STREQUAL "Xcode") if ("${CMAKE_GENERATOR}" STREQUAL "Xcode")
set (IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${BUNDLE_NAME}") set (IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/imhex.app")
else () else ()
set (IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/${BUNDLE_NAME}") set (IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/imhex.app")
endif() endif()
set(PLUGINS_INSTALL_LOCATION "${IMHEX_BUNDLE_PATH}/Contents/MacOS/plugins") set(PLUGINS_INSTALL_LOCATION "${IMHEX_BUNDLE_PATH}/Contents/MacOS/plugins")
@@ -152,28 +147,28 @@ macro(createPackage)
foreach (plugin IN LISTS PLUGINS) foreach (plugin IN LISTS PLUGINS)
add_subdirectory("plugins/${plugin}") add_subdirectory("plugins/${plugin}")
if (TARGET ${plugin}) if (TARGET ${plugin})
get_target_property(IS_RUST_PROJECT ${plugin} RUST_PROJECT)
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins) set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins) set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
if (APPLE) if (IS_RUST_PROJECT)
if (IMHEX_GENERATE_PACKAGE) set_target_properties(${plugin} PROPERTIES CARGO_BUILD_TARGET_DIR ${CMAKE_BINARY_DIR}/plugins)
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)
get_target_property(target_type ${plugin} TYPE)
if (target_type STREQUAL "SHARED_LIBRARY")
install(TARGETS ${plugin} RUNTIME DESTINATION ${PLUGINS_INSTALL_LOCATION})
else ()
install(TARGETS ${plugin} LIBRARY DESTINATION ${PLUGINS_INSTALL_LOCATION})
endif()
else()
install(TARGETS ${plugin} LIBRARY DESTINATION ${PLUGINS_INSTALL_LOCATION})
endif()
endif() get_target_property(PLUGIN_LOCATION ${plugin} LOCATION)
install(FILES "${PLUGIN_LOCATION}/../${plugin}.hexplug" DESTINATION "${PLUGINS_INSTALL_LOCATION}" PERMISSIONS ${LIBRARY_PERMISSIONS})
else ()
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 ()
install(TARGETS ${plugin} LIBRARY DESTINATION ${PLUGINS_INSTALL_LOCATION})
endif ()
endif ()
add_dependencies(imhex_all ${plugin}) add_dependencies(imhex_all ${plugin})
endif () endif ()
@@ -185,17 +180,12 @@ macro(createPackage)
# Install binaries directly in the prefix, usually C:\Program Files\ImHex. # Install binaries directly in the prefix, usually C:\Program Files\ImHex.
set(CMAKE_INSTALL_BINDIR ".") set(CMAKE_INSTALL_BINDIR ".")
set(PLUGIN_TARGET_FILES "")
foreach (plugin IN LISTS PLUGINS)
list(APPEND PLUGIN_TARGET_FILES "$<TARGET_FILE:${plugin}>")
endforeach ()
# Grab all dynamically linked dependencies. # Grab all dynamically linked dependencies.
install(CODE "set(CMAKE_INSTALL_BINDIR \"${CMAKE_INSTALL_BINDIR}\")") INSTALL(CODE "set(CMAKE_INSTALL_BINDIR \"${CMAKE_INSTALL_BINDIR}\")")
install(CODE "set(PLUGIN_TARGET_FILES \"${PLUGIN_TARGET_FILES}\")") INSTALL(CODE "LIST(APPEND DEP_FOLDERS \${PY_PARENT})")
install(CODE [[ install(CODE [[
file(GET_RUNTIME_DEPENDENCIES file(GET_RUNTIME_DEPENDENCIES
EXECUTABLES ${PLUGIN_TARGET_FILES} $<TARGET_FILE:libimhex> $<TARGET_FILE:main> EXECUTABLES $<TARGET_FILE:builtin> $<TARGET_FILE:libimhex> $<TARGET_FILE:main>
RESOLVED_DEPENDENCIES_VAR _r_deps RESOLVED_DEPENDENCIES_VAR _r_deps
UNRESOLVED_DEPENDENCIES_VAR _u_deps UNRESOLVED_DEPENDENCIES_VAR _u_deps
CONFLICTING_DEPENDENCIES_PREFIX _c_deps CONFLICTING_DEPENDENCIES_PREFIX _c_deps
@@ -240,56 +230,43 @@ macro(createPackage)
endif() endif()
if (APPLE) if (IMHEX_GENERATE_PACKAGE AND APPLE)
if (IMHEX_GENERATE_PACKAGE) include(PostprocessBundle)
include(PostprocessBundle)
set_target_properties(libimhex PROPERTIES SOVERSION ${IMHEX_VERSION}) set_target_properties(libimhex PROPERTIES SOVERSION ${IMHEX_VERSION})
set_property(TARGET main PROPERTY MACOSX_BUNDLE_INFO_PLIST ${MACOSX_BUNDLE_INFO_PLIST}) set_property(TARGET main PROPERTY MACOSX_BUNDLE_INFO_PLIST ${MACOSX_BUNDLE_INFO_PLIST})
# Fix rpath # Fix rpath
add_custom_command(TARGET imhex_all POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $<TARGET_FILE:main> || true) add_custom_command(TARGET imhex_all POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $<TARGET_FILE:main>)
add_custom_target(build-time-make-plugins-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/MacOS/plugins") # FIXME: Remove this once we move/integrate the plugins directory.
add_custom_target(build-time-make-resources-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/Resources") add_custom_target(build-time-make-plugins-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/MacOS/plugins")
add_custom_target(build-time-make-resources-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/Resources")
downloadImHexPatternsFiles("${IMHEX_BUNDLE_PATH}/Contents/MacOS") downloadImHexPatternsFiles("${IMHEX_BUNDLE_PATH}/Contents/MacOS")
install(FILES ${IMHEX_ICON} DESTINATION "${IMHEX_BUNDLE_PATH}/Contents/Resources") install(FILES ${IMHEX_ICON} DESTINATION "${IMHEX_BUNDLE_PATH}/Contents/Resources")
install(TARGETS main BUNDLE DESTINATION ".") install(TARGETS main BUNDLE DESTINATION ".")
install(FILES $<TARGET_FILE:main> DESTINATION "${IMHEX_BUNDLE_PATH}") install(FILES $<TARGET_FILE:main> DESTINATION "${IMHEX_BUNDLE_PATH}")
install(FILES $<TARGET_FILE:updater> DESTINATION "${IMHEX_BUNDLE_PATH}")
# Update library references to make the bundle portable # Update library references to make the bundle portable
postprocess_bundle(imhex_all main) postprocess_bundle(imhex_all main)
# Enforce DragNDrop packaging. # Enforce DragNDrop packaging.
set(CPACK_GENERATOR "DragNDrop") set(CPACK_GENERATOR "DragNDrop")
set(CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/resources/dist/macos/AppIcon.icns") set (CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/resources/dist/macos/AppIcon.icns" )
set(CPACK_BUNDLE_PLIST "${CMAKE_BINARY_DIR}/${BUNDLE_NAME}/Contents/Info.plist") set (CPACK_BUNDLE_PLIST "${CMAKE_BINARY_DIR}/imhex.app/Contents/Info.plist")
if (IMHEX_RESIGN_BUNDLE)
message(STATUS "Resigning bundle...")
find_program(CODESIGN_PATH codesign)
if (CODESIGN_PATH)
add_custom_command(TARGET imhex_all POST_BUILD COMMAND "codesign" ARGS "--force" "--deep" "--sign" "-" "${CMAKE_BINARY_DIR}/${BUNDLE_NAME}")
endif()
endif()
endif()
else() else()
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
if (TARGET updater) if(WIN32) # Forwarder is only needed on Windows
install(TARGETS updater RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
if (TARGET main-forwarder)
install(TARGETS main-forwarder BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}) install(TARGETS main-forwarder BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR})
endif() endif()
endif() endif()
if (IMHEX_GENERATE_PACKAGE) if (IMHEX_GENERATE_PACKAGE)
set(CPACK_BUNDLE_NAME "ImHex") set (CPACK_BUNDLE_NAME "ImHex")
include(CPack) include(CPack)
endif() endif()
@@ -311,8 +288,6 @@ macro(configureCMake)
# Enable C and C++ languages # Enable C and C++ languages
enable_language(C CXX) 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 # Configure use of recommended build tools
if (IMHEX_USE_DEFAULT_BUILD_SETTINGS) if (IMHEX_USE_DEFAULT_BUILD_SETTINGS)
message(STATUS "Configuring CMake to use recommended build tools...") message(STATUS "Configuring CMake to use recommended build tools...")
@@ -374,10 +349,6 @@ macro(configureCMake)
# display a warning about options being set using set() instead of option(). # display a warning about options being set using set() instead of option().
# Explicitly set the policy to NEW to suppress the warning. # Explicitly set the policy to NEW to suppress the warning.
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
set(CMAKE_POLICY_DEFAULT_CMP0063 NEW)
set(CMAKE_WARN_DEPRECATED OFF CACHE BOOL "Disable deprecated warnings" FORCE)
endmacro() endmacro()
macro(setDefaultBuiltTypeIfUnset) macro(setDefaultBuiltTypeIfUnset)
@@ -424,35 +395,6 @@ function(verifyCompiler)
endif() endif()
endfunction() endfunction()
macro(detectBundledPlugins)
file(GLOB PLUGINS_DIRS "plugins/*")
if (NOT DEFINED IMHEX_INCLUDE_PLUGINS)
foreach(PLUGIN_DIR ${PLUGINS_DIRS})
if (EXISTS "${PLUGIN_DIR}/CMakeLists.txt")
get_filename_component(PLUGIN_NAME ${PLUGIN_DIR} NAME)
if (NOT (${PLUGIN_NAME} IN_LIST IMHEX_EXCLUDE_PLUGINS))
list(APPEND PLUGINS ${PLUGIN_NAME})
endif ()
endif()
endforeach()
else()
set(PLUGINS ${IMHEX_INCLUDE_PLUGINS})
endif()
foreach(PLUGIN_NAME ${PLUGINS})
message(STATUS "Enabled bundled plugin '${PLUGIN_NAME}'")
endforeach()
if (NOT PLUGINS)
message(FATAL_ERROR "No bundled plugins enabled")
endif()
if (NOT ("builtin" IN_LIST PLUGINS))
message(FATAL_ERROR "The 'builtin' plugin is required for ImHex to work!")
endif ()
endmacro()
macro(setVariableInParent variable value) macro(setVariableInParent variable value)
get_directory_property(hasParent PARENT_DIRECTORY) get_directory_property(hasParent PARENT_DIRECTORY)
@@ -472,9 +414,9 @@ function(downloadImHexPatternsFiles dest)
endif () endif ()
FetchContent_Declare( FetchContent_Declare(
imhex_patterns imhex_patterns
GIT_REPOSITORY https://github.com/WerWolv/ImHex-Patterns.git GIT_REPOSITORY https://github.com/WerWolv/ImHex-Patterns.git
GIT_TAG origin/master GIT_TAG origin/master
) )
message(STATUS "Downloading ImHex-Patterns repo branch ${PATTERNS_BRANCH}...") message(STATUS "Downloading ImHex-Patterns repo branch ${PATTERNS_BRANCH}...")
@@ -487,7 +429,7 @@ function(downloadImHexPatternsFiles dest)
endif () endif ()
if (EXISTS ${imhex_patterns_SOURCE_DIR}) if (EXISTS ${imhex_patterns_SOURCE_DIR})
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic nodes) set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic)
foreach (FOLDER ${PATTERNS_FOLDERS_TO_INSTALL}) 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 () endforeach ()
@@ -497,22 +439,17 @@ endfunction()
macro(setupCompilerFlags target) macro(setupCompilerFlags target)
if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") if(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
# Define strict compilation flags # Define strict compilation flags
if (IMHEX_STRICT_WARNINGS) if (IMHEX_STRICT_WARNINGS)
set(IMHEX_COMMON_FLAGS "${IMHEX_COMMON_FLAGS} -Wall -Wextra -Wpedantic -Werror") set(IMHEX_COMMON_FLAGS "${IMHEX_COMMON_FLAGS} -Wall -Wextra -Wpedantic -Werror")
endif() endif()
if (UNIX AND NOT APPLE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU")
set(IMHEX_COMMON_FLAGS "${IMHEX_COMMON_FLAGS} -rdynamic")
endif()
set(IMHEX_CXX_FLAGS "-fexceptions -frtti") set(IMHEX_CXX_FLAGS "-fexceptions -frtti")
# Disable some warnings # Disable some warnings
set(IMHEX_C_CXX_FLAGS "-Wno-unknown-warning-option -Wno-array-bounds -Wno-deprecated-declarations -Wno-unknown-pragmas") set(IMHEX_C_CXX_FLAGS "-Wno-array-bounds -Wno-deprecated-declarations")
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
if (IMHEX_ENABLE_UNITY_BUILD AND WIN32) if (IMHEX_ENABLE_UNITY_BUILD AND WIN32)
set(IMHEX_COMMON_FLAGS "${IMHEX_COMMON_FLAGS} -Wa,-mbig-obj") set(IMHEX_COMMON_FLAGS "${IMHEX_COMMON_FLAGS} -Wa,-mbig-obj")
endif () endif ()
@@ -529,7 +466,6 @@ macro(setupCompilerFlags target)
endif () endif ()
# Set actual CMake flags # 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_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_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}") set(CMAKE_OBJC_FLAGS "${CMAKE_OBJC_FLAGS} ${IMHEX_COMMON_FLAGS}")
@@ -539,16 +475,18 @@ endmacro()
macro(setUninstallTarget) macro(setUninstallTarget)
if(NOT TARGET uninstall) if(NOT TARGET uninstall)
configure_file( configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in" "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake" "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
IMMEDIATE @ONLY) IMMEDIATE @ONLY)
add_custom_target(uninstall add_custom_target(uninstall
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake) COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
endif() endif()
endmacro() endmacro()
macro(addBundledLibraries) macro(addBundledLibraries)
find_package(PkgConfig REQUIRED)
set(EXTERNAL_LIBS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/lib/external") set(EXTERNAL_LIBS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/lib/external")
set(THIRD_PARTY_LIBS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/lib/third_party") set(THIRD_PARTY_LIBS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/lib/third_party")
@@ -556,17 +494,28 @@ macro(addBundledLibraries)
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/imgui) add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/imgui)
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/microtar EXCLUDE_FROM_ALL) add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/microtar EXCLUDE_FROM_ALL)
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
add_subdirectory(${EXTERNAL_LIBS_FOLDER}/libwolv EXCLUDE_FROM_ALL) add_subdirectory(${EXTERNAL_LIBS_FOLDER}/libwolv EXCLUDE_FROM_ALL)
set_property(TARGET libwolv-types PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET libwolv-utils PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET libwolv-io PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET libwolv-hash PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET libwolv-containers PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET libwolv-net PROPERTY POSITION_INDEPENDENT_CODE ON)
set_property(TARGET libwolv-math_eval PROPERTY POSITION_INDEPENDENT_CODE ON)
set(XDGPP_INCLUDE_DIRS "${THIRD_PARTY_LIBS_FOLDER}/xdgpp") set(XDGPP_INCLUDE_DIRS "${THIRD_PARTY_LIBS_FOLDER}/xdgpp")
set(FPHSA_NAME_MISMATCHED ON CACHE BOOL "") set(FPHSA_NAME_MISMATCHED ON CACHE BOOL "")
find_package(PkgConfig REQUIRED)
if(NOT USE_SYSTEM_FMT) if(NOT USE_SYSTEM_FMT)
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/fmt EXCLUDE_FROM_ALL) add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/fmt EXCLUDE_FROM_ALL)
set_target_properties(fmt PROPERTIES POSITION_INDEPENDENT_CODE ON)
set(FMT_LIBRARIES fmt::fmt-header-only) set(FMT_LIBRARIES fmt::fmt-header-only)
else() else()
find_package(fmt REQUIRED) find_package(fmt 8.0.0 REQUIRED)
set(FMT_LIBRARIES fmt::fmt) set(FMT_LIBRARIES fmt::fmt)
endif() endif()
@@ -578,11 +527,13 @@ macro(addBundledLibraries)
if (NOT EMSCRIPTEN) if (NOT EMSCRIPTEN)
# curl # curl
find_package(CURL REQUIRED) find_package(PkgConfig REQUIRED)
pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl>=7.60.0)
# nfd # nfd
if (NOT USE_SYSTEM_NFD) if (NOT USE_SYSTEM_NFD)
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/nativefiledialog EXCLUDE_FROM_ALL) add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/nativefiledialog EXCLUDE_FROM_ALL)
set_target_properties(nfd PROPERTIES POSITION_INDEPENDENT_CODE ON)
set(NFD_LIBRARIES nfd) set(NFD_LIBRARIES nfd)
else() else()
find_package(nfd) find_package(nfd)
@@ -600,10 +551,29 @@ macro(addBundledLibraries)
if (NOT USE_SYSTEM_LLVM) if (NOT USE_SYSTEM_LLVM)
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/llvm-demangle EXCLUDE_FROM_ALL) add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/llvm-demangle EXCLUDE_FROM_ALL)
set_target_properties(LLVMDemangle PROPERTIES POSITION_INDEPENDENT_CODE ON)
else() else()
find_package(LLVM REQUIRED Demangle) find_package(LLVM REQUIRED Demangle)
endif() endif()
if (NOT USE_SYSTEM_YARA)
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/yara EXCLUDE_FROM_ALL)
set_target_properties(libyara PROPERTIES POSITION_INDEPENDENT_CODE ON)
set(YARA_LIBRARIES libyara)
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(YARA REQUIRED IMPORTED_TARGET yara)
endif()
if (NOT USE_SYSTEM_MINIAUDIO)
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/miniaudio EXCLUDE_FROM_ALL)
set_target_properties(miniaudio PROPERTIES POSITION_INDEPENDENT_CODE ON)
set(MINIAUDIO_LIBRARIES miniaudio)
else()
find_package(PkgConfig REQUIRED)
pkg_check_modules(miniaudio REQUIRED IMPORTED_TARGET miniaudio)
endif()
if (NOT USE_SYSTEM_JTHREAD) if (NOT USE_SYSTEM_JTHREAD)
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/jthread EXCLUDE_FROM_ALL) add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/jthread EXCLUDE_FROM_ALL)
set(JTHREAD_LIBRARIES jthread) set(JTHREAD_LIBRARIES jthread)
@@ -616,40 +586,32 @@ macro(addBundledLibraries)
set(JTHREAD_LIBRARIES jthread) set(JTHREAD_LIBRARIES jthread)
endif() endif()
set(LIBPL_BUILD_CLI_AS_EXECUTABLE OFF CACHE BOOL "" FORCE) if (NOT USE_SYSTEM_CAPSTONE)
set(LIBPL_ENABLE_PRECOMPILED_HEADERS ${IMHEX_ENABLE_PRECOMPILED_HEADERS} CACHE BOOL "" FORCE) set(CAPSTONE_BUILD_STATIC_RUNTIME OFF CACHE BOOL "Disable shared library building")
set(CAPSTONE_BUILD_SHARED OFF CACHE BOOL "Disable shared library building")
if (WIN32) set(CAPSTONE_BUILD_TESTS OFF CACHE BOOL "Disable tests")
set(LIBPL_SHARED_LIBRARY ON CACHE BOOL "" FORCE) add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/capstone EXCLUDE_FROM_ALL)
set_target_properties(capstone PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_compile_options(capstone PRIVATE -Wno-unused-function)
set(CAPSTONE_LIBRARIES "capstone")
set(CAPSTONE_INCLUDE_DIRS ${THIRD_PARTY_LIBS_FOLDER}/capstone/include)
else() else()
set(LIBPL_SHARED_LIBRARY OFF CACHE BOOL "" FORCE) find_package(PkgConfig REQUIRED)
pkg_search_module(CAPSTONE 4.0.2 REQUIRED capstone)
endif() endif()
set(LIBPL_BUILD_CLI_AS_EXECUTABLE OFF)
add_subdirectory(${EXTERNAL_LIBS_FOLDER}/pattern_language EXCLUDE_FROM_ALL) add_subdirectory(${EXTERNAL_LIBS_FOLDER}/pattern_language EXCLUDE_FROM_ALL)
set_target_properties(libpl PROPERTIES POSITION_INDEPENDENT_CODE ON)
if (LIBPL_SHARED_LIBRARY)
install(
TARGETS
libpl
DESTINATION
"${CMAKE_INSTALL_LIBDIR}"
PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE
)
endif()
if (WIN32)
set_target_properties(
libpl
PROPERTIES
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}
LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}
)
endif()
enableUnityBuild(libpl)
find_package(mbedTLS 3.4.0 REQUIRED) find_package(mbedTLS 3.4.0 REQUIRED)
find_package(Magic 5.39 REQUIRED)
pkg_search_module(MAGIC libmagic>=5.39)
if(NOT MAGIC_FOUND)
find_library(MAGIC 5.39 magic REQUIRED)
else()
set(MAGIC_INCLUDE_DIRS ${MAGIC_INCLUDEDIR})
endif()
if (NOT IMHEX_DISABLE_STACKTRACE) if (NOT IMHEX_DISABLE_STACKTRACE)
if (WIN32) if (WIN32)
@@ -683,10 +645,6 @@ function(enableUnityBuild TARGET)
endfunction() endfunction()
function(generatePDBs) function(generatePDBs)
if (NOT IMHEX_GENERATE_PDBS)
return()
endif ()
if (NOT WIN32 OR CMAKE_BUILD_TYPE STREQUAL "Debug") if (NOT WIN32 OR CMAKE_BUILD_TYPE STREQUAL "Debug")
return() return()
endif () endif ()
@@ -700,6 +658,7 @@ function(generatePDBs)
FetchContent_Populate(cv2pdb) FetchContent_Populate(cv2pdb)
set(PDBS_TO_GENERATE main main-forwarder libimhex ${PLUGINS}) set(PDBS_TO_GENERATE main main-forwarder libimhex ${PLUGINS})
add_custom_target(pdbs)
foreach (PDB ${PDBS_TO_GENERATE}) foreach (PDB ${PDBS_TO_GENERATE})
if (PDB STREQUAL "main") if (PDB STREQUAL "main")
set(GENERATED_PDB imhex) set(GENERATED_PDB imhex)
@@ -711,73 +670,26 @@ function(generatePDBs)
set(GENERATED_PDB plugins/${PDB}) set(GENERATED_PDB plugins/${PDB})
endif () endif ()
if (IMHEX_REPLACE_DWARF_WITH_PDB)
set(PDB_OUTPUT_PATH ${CMAKE_BINARY_DIR}/${GENERATED_PDB})
else ()
set(PDB_OUTPUT_PATH)
endif()
add_custom_target(${PDB}_pdb DEPENDS ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb)
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb
WORKING_DIRECTORY ${CMAKE_BINARY_DIR} WORKING_DIRECTORY ${cv2pdb_SOURCE_DIR}
COMMAND COMMAND
( (${CMAKE_COMMAND} -E remove -f ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb &&
${CMAKE_COMMAND} -E remove -f ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb && ${cv2pdb_SOURCE_DIR}/cv2pdb64.exe
${cv2pdb_SOURCE_DIR}/cv2pdb64.exe $<TARGET_FILE:${PDB}> ${PDB_OUTPUT_PATH} && $<TARGET_FILE:${PDB}>) || (exit 0)
${CMAKE_COMMAND} -E remove -f ${CMAKE_BINARY_DIR}/${GENERATED_PDB} DEPENDS $<TARGET_FILE:${PDB}>
) || (exit 0)
COMMAND_EXPAND_LISTS) COMMAND_EXPAND_LISTS)
target_sources(imhex_all PRIVATE ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb)
install(FILES ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb DESTINATION ".") install(FILES ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb DESTINATION ".")
add_dependencies(imhex_all ${PDB}_pdb)
endforeach () endforeach ()
endfunction() endfunction()
function(generateSDKDirectory) function(generateSDKDirectory)
if (WIN32) set(SDK_PATH "./sdk")
set(SDK_PATH "./sdk")
elseif (APPLE)
set(SDK_PATH "${BUNDLE_NAME}/Contents/Resources/sdk")
else()
set(SDK_PATH "share/imhex/sdk")
endif()
set(SDK_BUILD_PATH "${CMAKE_BINARY_DIR}/sdk") install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/libimhex/include DESTINATION "${SDK_PATH}")
install(FILES ${CMAKE_SOURCE_DIR}/cmake/modules/ImHexPlugin.cmake DESTINATION "${SDK_PATH}/cmake/modules")
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/libimhex DESTINATION "${SDK_PATH}/lib" PATTERN "**/source/*" EXCLUDE)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/external DESTINATION "${SDK_PATH}/lib")
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/imgui DESTINATION "${SDK_PATH}/lib/third_party" PATTERN "**/source/*" EXCLUDE)
if (NOT USE_SYSTEM_FMT)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/fmt DESTINATION "${SDK_PATH}/lib/third_party")
endif()
if (NOT USE_SYSTEM_NLOHMANN_JSON)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/nlohmann_json 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")
install(DIRECTORY ${CMAKE_SOURCE_DIR}/cmake/sdk/ DESTINATION "${SDK_PATH}")
install(TARGETS libimhex ARCHIVE DESTINATION "${SDK_PATH}/lib") install(TARGETS libimhex ARCHIVE DESTINATION "${SDK_PATH}/lib")
endfunction() install(TARGETS libimhex RUNTIME DESTINATION "${SDK_PATH}/lib")
function(addIncludesFromLibrary target library)
get_target_property(library_include_dirs ${library} INTERFACE_INCLUDE_DIRECTORIES)
target_include_directories(${target} PRIVATE ${library_include_dirs})
endfunction()
function(precompileHeaders target includeFolder)
if (NOT IMHEX_ENABLE_PRECOMPILED_HEADERS)
return()
endif()
file(GLOB_RECURSE TARGET_INCLUDES "${includeFolder}/**/*.hpp")
set(SYSTEM_INCLUDES "<algorithm>;<array>;<atomic>;<chrono>;<cmath>;<cstddef>;<cstdint>;<cstdio>;<cstdlib>;<cstring>;<exception>;<filesystem>;<functional>;<iterator>;<limits>;<list>;<map>;<memory>;<optional>;<ranges>;<set>;<stdexcept>;<string>;<string_view>;<thread>;<tuple>;<type_traits>;<unordered_map>;<unordered_set>;<utility>;<variant>;<vector>")
set(INCLUDES "${SYSTEM_INCLUDES};${TARGET_INCLUDES}")
string(REPLACE ">" "$<ANGLE-R>" INCLUDES "${INCLUDES}")
target_precompile_headers(${target}
PUBLIC
"$<$<COMPILE_LANGUAGE:CXX>:${INCLUDES}>"
)
endfunction() endfunction()

View File

@@ -1,8 +0,0 @@
find_path(CAPSTONE_INCLUDE_DIR capstone.h PATH_SUFFIXES capstone)
find_library(CAPSTONE_LIBRARY NAMES capstone)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Capstone DEFAULT_MSG CAPSTONE_LIBRARY CAPSTONE_INCLUDE_DIR)
mark_as_advanced(CAPSTONE_INCLUDE_DIR CAPSTONE_LIBRARY)

View File

@@ -49,16 +49,13 @@ endif()
set(CoreClrEmbed_ROOT_PATH "${CORECLR_RUNTIME_ROOT_PATH}") set(CoreClrEmbed_ROOT_PATH "${CORECLR_RUNTIME_ROOT_PATH}")
file(GLOB _CORECLR_HOST_ARCH_PATH_LIST "${CORECLR_RUNTIME_ROOT_PATH}/packs/Microsoft.NETCore.App.Host.*-${CORECLR_SUBARCH}") file(GLOB _CORECLR_HOST_ARCH_PATH "${CORECLR_RUNTIME_ROOT_PATH}/packs/Microsoft.NETCore.App.Host.*-${CORECLR_SUBARCH}")
if (_CORECLR_HOST_ARCH_PATH_LIST) if (_CORECLR_HOST_ARCH_PATH)
foreach(_CORECLR_HOST_ARCH_PATH ${_CORECLR_HOST_ARCH_PATH_LIST}) get_filename_component(_CORECLR_HOST_ARCH_FILENAME ${_CORECLR_HOST_ARCH_PATH} NAME)
get_filename_component(_CORECLR_HOST_ARCH_FILENAME ${_CORECLR_HOST_ARCH_PATH} NAME) string(REPLACE "Microsoft.NETCore.App.Host." "" _CORECLR_COMPUTED_ARCH "${_CORECLR_HOST_ARCH_FILENAME}")
string(REPLACE "Microsoft.NETCore.App.Host." "" _CORECLR_COMPUTED_ARCH "${_CORECLR_HOST_ARCH_FILENAME}") if (_CORECLR_COMPUTED_ARCH)
if (_CORECLR_COMPUTED_ARCH) set(CORECLR_ARCH "${_CORECLR_COMPUTED_ARCH}")
set(CORECLR_ARCH "${_CORECLR_COMPUTED_ARCH}") endif()
break()
endif()
endforeach()
endif() endif()
set(CORECLR_HOST_BASE_PATH "${CORECLR_RUNTIME_ROOT_PATH}/packs/Microsoft.NETCore.App.Host.${CORECLR_ARCH}/${CORECLR_RUNTIME_VERSION_FULL}") set(CORECLR_HOST_BASE_PATH "${CORECLR_RUNTIME_ROOT_PATH}/packs/Microsoft.NETCore.App.Host.${CORECLR_ARCH}/${CORECLR_RUNTIME_VERSION_FULL}")

View File

@@ -1,139 +0,0 @@
#.rst:
# Find GLFW
# ---------
#
# Finds the GLFW library using its cmake config if that exists, otherwise
# falls back to finding it manually. This module defines:
#
# GLFW_FOUND - True if GLFW library is found
# GLFW::GLFW - GLFW imported target
#
# Additionally, in case the config was not found, these variables are defined
# for internal usage:
#
# GLFW_LIBRARY - GLFW library
# GLFW_DLL_DEBUG - GLFW debug DLL on Windows, if found
# GLFW_DLL_RELEASE - GLFW release DLL on Windows, if found
# GLFW_INCLUDE_DIR - Root include dir
#
#
# This file is part of Magnum.
#
# Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
# 2020, 2021, 2022 Vladimír Vondruš <mosra@centrum.cz>
# Copyright © 2016 Jonathan Hale <squareys@googlemail.com>
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.
#
# GLFW installs cmake package config files which handles dependencies in case
# GLFW is built statically. Try to find first, quietly, so it doesn't print
# loud messages when it's not found, since that's okay. If the glfw target
# already exists, it means we're using it through a CMake subproject -- don't
# attempt to find the package in that case.
if(NOT TARGET glfw)
find_package(glfw3 CONFIG QUIET)
endif()
# If either a glfw config file was found or we have a subproject, point
# GLFW::GLFW to that and exit -- nothing else to do here.
if(TARGET glfw)
if(NOT TARGET GLFW::GLFW)
# Aliases of (global) targets are only supported in CMake 3.11, so we
# work around it by this. This is easier than fetching all possible
# properties (which are impossible to track of) and then attempting to
# rebuild them into a new target.
add_library(GLFW::GLFW INTERFACE IMPORTED)
set_target_properties(GLFW::GLFW PROPERTIES INTERFACE_LINK_LIBRARIES glfw)
endif()
# Just to make FPHSA print some meaningful location, nothing else
get_target_property(_GLFW_INTERFACE_INCLUDE_DIRECTORIES glfw INTERFACE_INCLUDE_DIRECTORIES)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args("GLFW" DEFAULT_MSG
_GLFW_INTERFACE_INCLUDE_DIRECTORIES)
if(CORRADE_TARGET_WINDOWS)
# .dll is in LOCATION, .lib is in IMPLIB. Yay, useful!
get_target_property(GLFW_DLL_DEBUG glfw IMPORTED_LOCATION_DEBUG)
get_target_property(GLFW_DLL_RELEASE glfw IMPORTED_LOCATION_RELEASE)
endif()
return()
endif()
if(CORRADE_TARGET_WINDOWS)
if(MSVC)
if(MSVC_VERSION VERSION_LESS 1910)
set(_GLFW_LIBRARY_PATH_SUFFIX lib-vc2015)
elseif(MSVC_VERSION VERSION_LESS 1920)
set(_GLFW_LIBRARY_PATH_SUFFIX lib-vc2017)
elseif(MSVC_VERSION VERSION_LESS 1930)
set(_GLFW_LIBRARY_PATH_SUFFIX lib-vc2019)
elseif(MSVC_VERSION VERSION_LESS 1940)
set(_GLFW_LIBRARY_PATH_SUFFIX lib-vc2022)
else()
message(FATAL_ERROR "Unsupported MSVC version")
endif()
elseif(MINGW)
set(_GLFW_LIBRARY_PATH_SUFFIX lib-mingw-w64)
else()
message(FATAL_ERROR "Unsupported compiler")
endif()
endif()
# In case no config file was found, try manually finding the library. Prefer
# the glfw3dll as it's a dynamic library.
find_library(GLFW_LIBRARY
NAMES glfw glfw3dll glfw3
PATH_SUFFIXES ${_GLFW_LIBRARY_PATH_SUFFIX})
if(CORRADE_TARGET_WINDOWS AND GLFW_LIBRARY MATCHES "glfw3dll.(lib|a)$")
# TODO: debug?
find_file(GLFW_DLL_RELEASE
NAMES glfw3.dll
PATH_SUFFIXES ${_GLFW_LIBRARY_PATH_SUFFIX})
endif()
# Include dir
find_path(GLFW_INCLUDE_DIR
NAMES GLFW/glfw3.h)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args("GLFW" DEFAULT_MSG
GLFW_LIBRARY
GLFW_INCLUDE_DIR)
if(NOT TARGET GLFW::GLFW)
add_library(GLFW::GLFW UNKNOWN IMPORTED)
# Work around BUGGY framework support on macOS
# https://cmake.org/Bug/view.php?id=14105
if(CORRADE_TARGET_APPLE AND GLFW_LIBRARY MATCHES "\\.framework$")
set_property(TARGET GLFW::GLFW PROPERTY IMPORTED_LOCATION ${GLFW_LIBRARY}/GLFW)
else()
set_property(TARGET GLFW::GLFW PROPERTY IMPORTED_LOCATION ${GLFW_LIBRARY})
endif()
set_property(TARGET GLFW::GLFW PROPERTY
INTERFACE_INCLUDE_DIRECTORIES ${GLFW_INCLUDE_DIR})
endif()
mark_as_advanced(GLFW_LIBRARY GLFW_INCLUDE_DIR)

View File

@@ -1,18 +0,0 @@
find_path(LIBMAGIC_INCLUDE_DIR magic.h)
find_library(LIBMAGIC_LIBRARY NAMES magic)
if (LIBMAGIC_INCLUDE_DIR AND LIBMAGIC_LIBRARY)
set(LIBMAGIC_FOUND TRUE)
endif (LIBMAGIC_INCLUDE_DIR AND LIBMAGIC_LIBRARY)
find_package_handle_standard_args("libmagic" DEFAULT_MSG
LIBMAGIC_LIBRARY
LIBMAGIC_INCLUDE_DIR
)
mark_as_advanced(
LIBMAGIC_INCLUDE_DIR
LIBMAGIC_LIBRARY
LIBMAGIC_FOUND
)

View File

@@ -1,4 +0,0 @@
find_library(YARA_LIBRARIES NAMES yara)
find_file(yara.h YARA_INCLUDE_DIRS)
mark_as_advanced(YARA_LIBRARIES YARA_INCLUDE_DIRS)

View File

@@ -1,41 +0,0 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# - Try to find Facebook zstd library
# This will define
# ZSTD_FOUND
# ZSTD_INCLUDE_DIR
# ZSTD_LIBRARY
#
find_path(ZSTD_INCLUDE_DIR NAMES zstd.h)
find_library(ZSTD_LIBRARY_DEBUG NAMES zstdd zstd_staticd)
find_library(ZSTD_LIBRARY_RELEASE NAMES zstd zstd_static)
include(SelectLibraryConfigurations)
SELECT_LIBRARY_CONFIGURATIONS(ZSTD)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(
ZSTD DEFAULT_MSG
ZSTD_LIBRARY ZSTD_INCLUDE_DIR
)
if (ZSTD_FOUND)
message(STATUS "Found Zstd: ${ZSTD_LIBRARY}")
endif()
mark_as_advanced(ZSTD_INCLUDE_DIR ZSTD_LIBRARY)

View File

@@ -1,15 +1,10 @@
macro(add_imhex_plugin) macro(add_imhex_plugin)
# Parse arguments # Parse arguments
set(options LIBRARY_PLUGIN) set(options "")
set(oneValueArgs NAME IMHEX_VERSION) set(oneValueArgs NAME)
set(multiValueArgs SOURCES INCLUDES LIBRARIES FEATURES) set(multiValueArgs SOURCES INCLUDES LIBRARIES)
cmake_parse_arguments(IMHEX_PLUGIN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) cmake_parse_arguments(IMHEX_PLUGIN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
if (IMHEX_PLUGIN_IMHEX_VERSION)
message(STATUS "Compiling plugin ${IMHEX_PLUGIN_NAME} for ImHex Version ${IMHEX_PLUGIN_IMHEX_VERSION}")
set(IMHEX_VERSION_STRING "${IMHEX_PLUGIN_IMHEX_VERSION}")
endif()
if (IMHEX_STATIC_LINK_PLUGINS) if (IMHEX_STATIC_LINK_PLUGINS)
set(IMHEX_PLUGIN_LIBRARY_TYPE STATIC) set(IMHEX_PLUGIN_LIBRARY_TYPE STATIC)
@@ -17,15 +12,8 @@ macro(add_imhex_plugin)
configure_file(${CMAKE_SOURCE_DIR}/dist/web/plugin-bundle.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/plugin-bundle.cpp @ONLY) configure_file(${CMAKE_SOURCE_DIR}/dist/web/plugin-bundle.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/plugin-bundle.cpp @ONLY)
target_sources(main PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/plugin-bundle.cpp) target_sources(main PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/plugin-bundle.cpp)
set(IMHEX_PLUGIN_SUFFIX ".hexplug")
else() else()
if (IMHEX_PLUGIN_LIBRARY_PLUGIN) set(IMHEX_PLUGIN_LIBRARY_TYPE MODULE)
set(IMHEX_PLUGIN_LIBRARY_TYPE SHARED)
set(IMHEX_PLUGIN_SUFFIX ".hexpluglib")
else()
set(IMHEX_PLUGIN_LIBRARY_TYPE MODULE)
set(IMHEX_PLUGIN_SUFFIX ".hexplug")
endif()
endif() endif()
# Define new project for plugin # Define new project for plugin
@@ -36,12 +24,7 @@ macro(add_imhex_plugin)
# Add include directories and link libraries # Add include directories and link libraries
target_include_directories(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_INCLUDES}) target_include_directories(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_INCLUDES})
target_link_libraries(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_LIBRARIES}) target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE libimhex ${FMT_LIBRARIES} ${IMHEX_PLUGIN_LIBRARIES})
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE libimhex ${FMT_LIBRARIES} imgui_all_includes libwolv)
addIncludesFromLibrary(${IMHEX_PLUGIN_NAME} libpl)
addIncludesFromLibrary(${IMHEX_PLUGIN_NAME} libpl-gen)
precompileHeaders(${IMHEX_PLUGIN_NAME} "${CMAKE_CURRENT_SOURCE_DIR}/include")
# Add IMHEX_PROJECT_NAME and IMHEX_VERSION define # Add IMHEX_PROJECT_NAME and IMHEX_VERSION define
target_compile_definitions(${IMHEX_PLUGIN_NAME} PRIVATE IMHEX_PROJECT_NAME="${IMHEX_PLUGIN_NAME}") target_compile_definitions(${IMHEX_PLUGIN_NAME} PRIVATE IMHEX_PROJECT_NAME="${IMHEX_PLUGIN_NAME}")
@@ -49,6 +32,7 @@ macro(add_imhex_plugin)
target_compile_definitions(${IMHEX_PLUGIN_NAME} PRIVATE IMHEX_PLUGIN_NAME=${IMHEX_PLUGIN_NAME}) target_compile_definitions(${IMHEX_PLUGIN_NAME} PRIVATE IMHEX_PLUGIN_NAME=${IMHEX_PLUGIN_NAME})
# Enable required compiler flags # Enable required compiler flags
set_target_properties(${IMHEX_PLUGIN_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
enableUnityBuild(${IMHEX_PLUGIN_NAME}) enableUnityBuild(${IMHEX_PLUGIN_NAME})
setupCompilerFlags(${IMHEX_PLUGIN_NAME}) setupCompilerFlags(${IMHEX_PLUGIN_NAME})
@@ -58,46 +42,18 @@ macro(add_imhex_plugin)
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins
CXX_STANDARD 23 CXX_STANDARD 23
PREFIX "" PREFIX ""
SUFFIX ${IMHEX_PLUGIN_SUFFIX} SUFFIX ".hexplug"
) )
# Set rpath of plugin libraries to the plugins folder
if (APPLE)
set_target_properties(${IMHEX_PLUGIN_NAME} PROPERTIES BUILD_RPATH "@executable_path/../Frameworks;@executable_path/plugins")
endif()
# Setup a romfs for the plugin # Setup a romfs for the plugin
list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/romfs) list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/romfs)
set(LIBROMFS_PROJECT_NAME ${IMHEX_PLUGIN_NAME}) set(LIBROMFS_PROJECT_NAME ${IMHEX_PLUGIN_NAME})
add_subdirectory(${IMHEX_BASE_FOLDER}/lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs) add_subdirectory(${IMHEX_BASE_FOLDER}/lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
set_target_properties(${LIBROMFS_LIBRARY} PROPERTIES POSITION_INDEPENDENT_CODE ON)
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE ${LIBROMFS_LIBRARY}) target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE ${LIBROMFS_LIBRARY})
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 # Add the new plugin to the main dependency list so it gets built by default
if (TARGET imhex_all) add_dependencies(imhex_all ${IMHEX_PLUGIN_NAME})
add_dependencies(imhex_all ${IMHEX_PLUGIN_NAME})
endif()
if (IMHEX_EXTERNAL_PLUGIN_BUILD)
install(TARGETS ${IMHEX_PLUGIN_NAME} DESTINATION ".")
endif()
# Fix rpath
if (APPLE)
set_target_properties(${IMHEX_PLUGIN_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks;@executable_path/plugins")
elseif (UNIX)
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)
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")
endif()
endmacro() endmacro()
macro(add_romfs_resource input output) macro(add_romfs_resource input output)
@@ -105,13 +61,3 @@ macro(add_romfs_resource input output)
list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/romfs) list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/romfs)
endmacro() endmacro()
macro (enable_plugin_feature feature)
string(TOUPPER ${feature} feature)
if (NOT (feature IN_LIST IMHEX_PLUGIN_FEATURES))
message(FATAL_ERROR "Feature ${feature} is not enabled for plugin ${IMHEX_PLUGIN_NAME}")
endif()
remove_definitions(-DIMHEX_PLUGIN_${IMHEX_PLUGIN_NAME}_FEATURE_${feature}=0)
add_definitions(-DIMHEX_PLUGIN_${IMHEX_PLUGIN_NAME}_FEATURE_${feature}=1)
endmacro()

View File

@@ -35,27 +35,26 @@ message(STATUS "Fixing up application bundle: ${BUNDLE_PATH}")
# Make sure to fix up any included ImHex plugin. # Make sure to fix up any included ImHex plugin.
file(GLOB_RECURSE plugins "${BUNDLE_PATH}/Contents/MacOS/plugins/*.hexplug") file(GLOB_RECURSE extra_libs "${BUNDLE_PATH}/Contents/MacOS/plugins/*.hexplug")
# BundleUtilities doesn't support DYLD_FALLBACK_LIBRARY_PATH behavior, which # BundleUtilities doesn't support DYLD_FALLBACK_LIBRARY_PATH behavior, which
# makes it sometimes break on libraries that do weird things with @rpath. Specify # makes it sometimes break on libraries that do weird things with @rpath. Specify
# equivalent search directories until https://gitlab.kitware.com/cmake/cmake/issues/16625 # equivalent search directories until https://gitlab.kitware.com/cmake/cmake/issues/16625
# is fixed and in our minimum CMake version. # is fixed and in our minimum CMake version.
set(extra_dirs "/usr/local/lib" "/lib" "/usr/lib" ${EXTRA_BUNDLE_LIBRARY_PATHS} "${BUNDLE_PATH}/Contents/MacOS/plugins") set(extra_dirs "/usr/local/lib" "/lib" "/usr/lib" ${EXTRA_BUNDLE_LIBRARY_PATHS})
message(STATUS "Fixing up application bundle: ${extra_dirs}") message(STATUS "Fixing up application bundle: ${extra_dirs}")
# BundleUtilities is overly verbose, so disable most of its messages # BundleUtilities is overly verbose, so disable most of its messages
#function(message) function(message)
# if(NOT ARGV MATCHES "^STATUS;") if(NOT ARGV MATCHES "^STATUS;")
# _message(${ARGV}) _message(${ARGV})
# endif() endif()
#endfunction() endfunction()
include(BundleUtilities) include(BundleUtilities)
set(BU_CHMOD_BUNDLE_ITEMS ON) set(BU_CHMOD_BUNDLE_ITEMS ON)
fixup_bundle("${BUNDLE_PATH}" "${extra_libs}" "${extra_dirs}")
fixup_bundle("${BUNDLE_PATH}" "${plugins}" "${extra_dirs}")
if (CODE_SIGN_CERTIFICATE_ID) if (CODE_SIGN_CERTIFICATE_ID)
# Hack around Apple Silicon signing bugs by copying the real app, signing it and moving it back. # Hack around Apple Silicon signing bugs by copying the real app, signing it and moving it back.
@@ -68,12 +67,3 @@ endif()
# Add a necessary rpath to the imhex binary # Add a necessary rpath to the imhex binary
get_bundle_main_executable("${BUNDLE_PATH}" IMHEX_EXECUTABLE) get_bundle_main_executable("${BUNDLE_PATH}" IMHEX_EXECUTABLE)
file(GLOB_RECURSE plugin_libs "${BUNDLE_PATH}/Contents/MacOS/*.hexpluglib")
foreach(plugin_lib ${plugin_libs})
get_filename_component(plugin_lib_name ${plugin_lib} NAME)
set(plugin_lib_dest "${BUNDLE_PATH}/Contents/MacOS/plugins/${plugin_lib_name}")
configure_file(${plugin_lib} "${plugin_lib_dest}" COPYONLY)
message(STATUS "Copying plugin library: ${plugin_lib} to ${plugin_lib_dest}")
endforeach ()

View File

@@ -1,58 +0,0 @@
cmake_minimum_required(VERSION 3.20)
project(ImHexSDK)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE BOOL "" FORCE)
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/build_helpers.cmake")
set(IMHEX_BASE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE)
include(ImHexPlugin)
function(add_subdirectory_if_exists folder)
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${folder}/CMakeLists.txt")
add_subdirectory("${folder}" EXCLUDE_FROM_ALL)
endif()
endfunction()
set(IMHEX_EXTERNAL_PLUGIN_BUILD ON PARENT_SCOPE)
set(IMHEX_EXTERNAL_PLUGIN_BUILD ON)
add_custom_target(imhex_all)
add_subdirectory(lib/third_party/imgui EXCLUDE_FROM_ALL)
set(FMT_INSTALL OFF CACHE BOOL "" FORCE)
add_subdirectory_if_exists(lib/third_party/fmt)
set(FMT_LIBRARIES fmt::fmt-header-only PARENT_SCOPE)
set(FMT_LIBRARIES fmt::fmt-header-only)
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(lib/external/libwolv EXCLUDE_FROM_ALL)
set(LIBPL_ENABLE_CLI OFF CACHE BOOL "" FORCE)
add_subdirectory(lib/external/pattern_language EXCLUDE_FROM_ALL)
find_package(CURL REQUIRED)
find_package(mbedTLS 3.4.0 REQUIRED)
set(CURL_LIBRARIES ${CURL_LIBRARIES} PARENT_SCOPE)
set(MBEDTLS_LIBRARIES ${MBEDTLS_LIBRARIES} PARENT_SCOPE)
add_subdirectory(lib/libimhex)
if (WIN32)
set_target_properties(libimhex PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../libimhex.dll"
IMPORTED_IMPLIB "${CMAKE_CURRENT_SOURCE_DIR}/lib/liblibimhex.dll.a"
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/lib/libimhex/include")
elseif (APPLE)
file(GLOB LIBIMHEX_DYLIB "${CMAKE_CURRENT_SOURCE_DIR}/../../Frameworks/libimhex.*.dylib")
set_target_properties(libimhex PROPERTIES
IMPORTED_LOCATION "${LIBIMHEX_DYLIB}"
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/lib/libimhex/include")
else()
set_target_properties(libimhex PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../libimhex.so"
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/lib/libimhex/include")
endif()

View File

@@ -1,60 +0,0 @@
# ImHex Plugin Template
# =====================
# This is the official CMake template for making your own ImHex plugins
# To use this template, copy the file into its own directory and modify it to your needs
# For the most part, this is a regular CMake project with some extra functions provided by the ImHex SDK
#
# [NOTE FOR NON-C++ PLUGINS]
# The template is laid out for a C++ plugin, however you can write your plugin in any language you want
# and just make the plugin statically link against your code. The only thing that's required is a .cpp file with
# the IMHEX_PLUGIN_SETUP() macro used in it. This macro is used to setup the plugin and register it with ImHex
#
# [CMAKE FUNCTIONS]
# add_imhex_plugin(): Registers a new plugin
# NAME: The name of the plugin
# IMHEX_VERSION: The ImHex version this plugin is compatible with. If unset, the plugin will be loaded on all versions (this may not work though)
# SOURCES: Source files of the plugin
# INCLUDES: Include directories of the plugin
# LIBRARIES: Libraries to link against
# FEATURES: Optional features that can be enabled or disabled
# LIBRARY_PLUGIN: If set, turns this plugin into a library plugin. Library plugins can be linked against by other plugins
#
# add_romfs_resource(filePath romfsPath): Adds a file to the romfs of the plugin
# The RomFS is a virtual filesystem whose files can be accessed by the plugin using the functions in the `romfs::` namespace
# This function is used to add a single file to the romfs. You can however also simply create a `romfs` directory in your plugin directory and place your files and folders in there
# filePath: The path to the file on the disk
# romfsPath: The path to the file in the romfs
#
# enable_plugin_feature(feature): Enables a plugin feature
# Features are optional parts of the plugin that may or may not be available depending on build settings
# When a feature is enabled, `IMHEX_FEATURE_ENABLED(feature)` will be defined to true. Otherwise, it will be defined to false
# Use the `IMHEX_PLUGIN_FEATURES` macro in the main plugin file to define names to each feature and have them be listed in the plugin list
# feature: The name of the feature to enable
cmake_minimum_required(VERSION 3.20)
project(ImHexPlugin)
# Include the ImHex SDK
# For this to work, you need to set the IMHEX_SDK_PATH environment variable to the path of the ImHex SDK
#
# On Windows, the SDK is next to the ImHex executable
# On Linux, the SDK is usually in /usr/share/imhex/sdk but this may vary depending on your distribution
# On MacOS, the SDK is located inside of the ImHex.app bundle under ImHex.app/Contents/Resources/sdk
if (NOT EXISTS $ENV{IMHEX_SDK_PATH})
message(FATAL_ERROR "The IMHEX_SDK_PATH environment variable is not set")
endif()
add_subdirectory($ENV{IMHEX_SDK_PATH} ImHexSDK)
# Register the plugin
# This will configure everything you need to make your plugin work
# Modify the arguments to your needs. Right now it defines a plugin called `example_plugin`
# with a single source file called `example_plugin.cpp` in the `source` directory
# By default you have access to the libimhex library to interact with ImHex
# as well as libwolv, libromfs, libfmt and ImGui, but you can link against any libraries you want
add_imhex_plugin(
NAME
example_plugin
SOURCES
source/example_plugin.cpp
)

View File

@@ -1,11 +0,0 @@
#include <hex/plugin.hpp>
// Browse through the headers in lib/libimhex/include/hex/api/ to see what you can do with the API.
// Most important ones are <hex/api/imhex_api.hpp> and <hex/api/content_registry.hpp>
// This is the main entry point of your plugin. The code in the body of this construct will be executed
// when ImHex starts up and loads the plugin.
// The strings in the header are used to display information about the plugin in the UI.
IMHEX_PLUGIN_SETUP("Example Plugin", "Author", "Description") {
// Put your init code here
}

5
dist/Arch/PKGBUILD vendored
View File

@@ -8,7 +8,7 @@ pkgdesc="A Hex Editor for Reverse Engineers, Programmers and people who value th
arch=("x86_64") arch=("x86_64")
url="https://github.com/WerWolv/ImHex" url="https://github.com/WerWolv/ImHex"
license=('GPL2') license=('GPL2')
depends=(glfw mbedtls 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)
makedepends=(git) makedepends=(git)
provides=(imhex) provides=(imhex)
conflicts=(imhex) conflicts=(imhex)
@@ -17,10 +17,9 @@ md5sums=(SKIP)
package() { package() {
install -Dm755 "$srcdir/usr/bin/imhex" "$pkgdir/usr/bin/imhex" install -Dm755 "$srcdir/usr/bin/imhex" "$pkgdir/usr/bin/imhex"
install -Dm755 "$srcdir/usr/bin/imhex-updater" "$pkgdir/usr/bin/imhex-updater"
install -Dm644 "$srcdir/usr/lib/libimhex.so.$pkgver" "$pkgdir/usr/lib/libimhex.so.$pkgver" install -Dm644 "$srcdir/usr/lib/libimhex.so.$pkgver" "$pkgdir/usr/lib/libimhex.so.$pkgver"
for plugin in "$srcdir/usr/lib/imhex/plugins/"*.hexplug*; do for plugin in "$srcdir/usr/lib/imhex/plugins/"*.hexplug; do
install -Dm644 "$plugin" "$pkgdir/usr/lib/imhex/plugins/${plugin##*/}" install -Dm644 "$plugin" "$pkgdir/usr/lib/imhex/plugins/${plugin##*/}"
done done

4
dist/Brewfile vendored
View File

@@ -10,7 +10,3 @@ brew "gcc@12"
brew "llvm" brew "llvm"
brew "glfw" brew "glfw"
brew "ninja" brew "ninja"
brew "zlib"
brew "xz"
brew "bzip2"
brew "zstd"

View File

@@ -4,7 +4,7 @@ Section: editors
Priority: optional Priority: optional
Architecture: amd64 Architecture: amd64
License: GNU GPL-2 License: GNU GPL-2
Depends: libglfw3 | libglfw3-wayland, libmagic1, libmbedtls14, libfreetype6, libopengl0, libdbus-1-3, xdg-desktop-portal Depends: libglfw3, libmagic1, libmbedtls14, libfreetype6, libopengl0, libdbus-1-3, xdg-desktop-portal
Maintainer: WerWolv <hey@werwolv.net> Maintainer: WerWolv <hey@werwolv.net>
Description: ImHex Hex Editor Description: ImHex Hex Editor
A Hex Editor for Reverse Engineers, Programmers and A Hex Editor for Reverse Engineers, Programmers and

View File

@@ -24,9 +24,5 @@ RDEPEND="${DEPEND}
dev-cpp/nlohmann_json dev-cpp/nlohmann_json
dbus dbus
xdg-desktop-portal xdg-desktop-portal
sys-libs/zlib
app-arch/bzip2
app-arch/lzma
app-arch/zstd
" "
BDEPEND="${DEPEND}" BDEPEND="${DEPEND}"

View File

@@ -53,6 +53,7 @@ CC=gcc-12 CXX=g++-12 cmake -G "Ninja" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \ -DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_SHORT="${GIT_COMMIT_HASH::7}" \
-DIMHEX_COMMIT_HASH_LONG="${GIT_COMMIT_HASH}" \ -DIMHEX_COMMIT_HASH_LONG="${GIT_COMMIT_HASH}" \
-DIMHEX_COMMIT_BRANCH="${GIT_BRANCH}" \ -DIMHEX_COMMIT_BRANCH="${GIT_BRANCH}" \
-DIMHEX_ENABLE_LTO=${LTO} \ -DIMHEX_ENABLE_LTO=${LTO} \

View File

@@ -9,10 +9,9 @@ On Linux, ImHex is built through regular GCC (or optionally Clang).
cd ImHex cd ImHex
mkdir -p build mkdir -p build
cd build cd build
CC=gcc-12 CXX=g++-12 \ CC=gcc-12 CXX=g++-12 cmake \
cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="/usr" \ -DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \ -DCMAKE_C_FLAGS="-fuse-ld=lld" \

View File

@@ -9,14 +9,23 @@ On macOS, ImHex is built through regular GCC and LLVM clang.
cd ImHex cd ImHex
mkdir -p build mkdir -p build
cd build cd build
CC=$(brew --prefix llvm)/bin/clang \ CC=$(brew --prefix gcc@12)/bin/gcc-12 \
CXX=$(brew --prefix llvm)/bin/clang++ \ CXX=$(brew --prefix gcc@12)/bin/g++-12 \
OBJC=$(brew --prefix llvm)/bin/clang \ OBJC=$(brew --prefix llvm)/bin/clang \
OBJCXX=$(brew --prefix llvm)/bin/clang++ \ OBJCXX=$(brew --prefix llvm)/bin/clang++ \
cmake -G "Ninja" \ PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
MACOSX_DEPLOYMENT_TARGET="10.15" \
cmake \
-DCMAKE_BUILD_TYPE=Release \ -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX=./install \
-DIMHEX_GENERATE_PACKAGE=ON \ -DIMHEX_GENERATE_PACKAGE=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
.. ..
ninja install make -j4 package
``` ```
If the build fails while trying to find the macOS libraries, make sure you have
Xcode installed with `xcode-select --install`. Homebrew will also help get the
most recent SDK installed and configured with `brew doctor`.

View File

@@ -1,21 +1,17 @@
#!/usr/bin/env sh #!/usr/bin/env sh
pacman -S $@ --needed \ pacman -S $@ --needed \
cmake \ cmake \
gcc \ gcc \
lld \ lld \
glfw \ glfw \
file \ file \
mbedtls \ mbedtls \
freetype2 \ freetype2 \
dbus \ dbus \
gtk3 \ gtk3 \
curl \ curl \
fmt \ fmt \
yara \ yara \
nlohmann-json \ nlohmann-json \
ninja \ ninja
zlib \
bzip2 \
xz \
zstd

View File

@@ -22,8 +22,4 @@ apt install -y \
libdbus-1-dev \ libdbus-1-dev \
libcurl4-gnutls-dev \ libcurl4-gnutls-dev \
libgtk-3-dev \ libgtk-3-dev \
ninja-build \ ninja-build
zlib1g-dev \
libbz2-dev \
liblzma-dev \
libzstd-dev

View File

@@ -12,8 +12,4 @@ dnf install -y \
glfw-devel \ glfw-devel \
lld \ lld \
mbedtls-devel \ mbedtls-devel \
gtk3-devel \ gtk3-devel
libzstd-devel \
zlib-devel \
bzip2-devel \
xz-devel

View File

@@ -1,20 +1,15 @@
#!/usr/bin/env sh #!/usr/bin/env sh
pacman -S --needed --noconfirm pactoys pacman -S --needed --noconfirm \
pacboy -S --needed --noconfirm \ mingw-w64-x86_64-gcc \
gcc:p \ mingw-w64-x86_64-lld \
lld:p \ mingw-w64-x86_64-cmake \
cmake:p \ mingw-w64-x86_64-ccache \
ccache:p \ mingw-w64-x86_64-glfw \
glfw:p \ mingw-w64-x86_64-file \
file:p \ mingw-w64-x86_64-curl-winssl \
curl-winssl:p \ mingw-w64-x86_64-mbedtls \
mbedtls:p \ mingw-w64-x86_64-freetype \
freetype:p \ mingw-w64-x86_64-dlfcn \
dlfcn:p \ mingw-w64-x86_64-ninja \
ninja:p \ mingw-w64-x86_64-capstone
capstone:p \
zlib:p \
bzip2:p \
xz:p \
zstd:p

View File

@@ -52,10 +52,6 @@ vcpkg install --triplet=arm-osx-mytriplet curl
vcpkg install --triplet=arm-osx-mytriplet mbedtls vcpkg install --triplet=arm-osx-mytriplet mbedtls
vcpkg install --triplet=arm-osx-mytriplet freetype vcpkg install --triplet=arm-osx-mytriplet freetype
vcpkg install --triplet=arm-osx-mytriplet josuttis-jthread vcpkg install --triplet=arm-osx-mytriplet josuttis-jthread
vcpkg install --triplet=arm-osx-mytriplet zlib
vcpkg install --triplet=arm-osx-mytriplet bzip2
vcpkg install --triplet=arm-osx-mytriplet liblzma
vcpkg install --triplet=arm-osx-mytriplet zstd
EOF EOF
## Install glfw3 dep ## Install glfw3 dep
@@ -106,9 +102,6 @@ if [ "$CUSTOM_GLFW" ]; then
fi fi
EOF EOF
RUN mkdir -p /vcpkg/installed/arm-osx-mytriplet/lib/pkgconfig
RUN mkdir -p /osxcross/target/macports/pkgs/vcpkg/installed/arm-osx-mytriplet/lib/pkgconfig
## Build glfw ## Build glfw
RUN --mount=type=cache,target=/cache <<EOF RUN --mount=type=cache,target=/cache <<EOF
set -xe set -xe
@@ -126,7 +119,7 @@ if [ "$CUSTOM_GLFW" ]; then
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \ -DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_INSTALL_PREFIX=/vcpkg/installed/arm-osx-mytriplet \ -DCMAKE_INSTALL_PREFIX=/vcpkg/installed/arm-osx-mytriplet \
-DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=12.1 \ -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=14.0 \
.. ..
ninja -j $JOBS install ninja -j $JOBS install
@@ -148,14 +141,13 @@ RUN --mount=type=cache,target=/cache --mount=type=cache,target=/mnt/ImHex/build/
`# ccache flags` \ `# ccache flags` \
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_OBJC_COMPILER_LAUNCHER=ccache -DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \ -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_OBJC_COMPILER_LAUNCHER=ccache -DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
`# MacOS cross-compiling flags` \ `# MacOS cross-compiling flags` \
-DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=12.1 \ -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=14.0 \
`# Override compilers for code generators` \ `# Override compilers for code generators` \
-DNATIVE_CMAKE_C_COMPILER=/usr/bin/clang -DNATIVE_CMAKE_CXX_COMPILER=/usr/bin/clang++ \ -DNATIVE_CMAKE_C_COMPILER=/usr/bin/clang -DNATIVE_CMAKE_CXX_COMPILER=/usr/bin/clang++ \
`# Normal ImHex flags` \ `# Normal ImHex flags` \
-DIMHEX_GENERATE_PACKAGE=ON -DCMAKE_BUILD_TYPE=$BUILD_TYPE \ -DIMHEX_GENERATE_PACKAGE=ON -DCMAKE_BUILD_TYPE=$BUILD_TYPE \
`# other flags` \ `# other flags` \
-DIMHEX_STRICT_WARNINGS=OFF \ -DIMHEX_STRICT_WARNINGS=OFF \
-DCMAKE_INSTALL_PREFIX=/mnt/ImHex/build/install \
-B build -B build
## Build ImHex ## Build ImHex
RUN --mount=type=cache,target=/cache --mount=type=cache,target=/mnt/ImHex/build/_deps <<EOF RUN --mount=type=cache,target=/cache --mount=type=cache,target=/mnt/ImHex/build/_deps <<EOF
@@ -163,11 +155,11 @@ RUN --mount=type=cache,target=/cache --mount=type=cache,target=/mnt/ImHex/build/
set -xe set -xe
cd /mnt/ImHex cd /mnt/ImHex
cmake --build build --parallel $JOBS --target install cmake --build build --parallel $JOBS
ccache -s ccache -s
EOF EOF
FROM scratch FROM scratch
COPY --from=build /mnt/ImHex/build/install/imhex.app ImHex.app COPY --from=build /mnt/ImHex/build/imhex.app imhex.app

6
dist/msys2/PKGBUILD vendored
View File

@@ -16,11 +16,7 @@ makedepends=("${MINGW_PACKAGE_PREFIX}-gcc"
"${MINGW_PACKAGE_PREFIX}-file" "${MINGW_PACKAGE_PREFIX}-file"
"${MINGW_PACKAGE_PREFIX}-mbedtls" "${MINGW_PACKAGE_PREFIX}-mbedtls"
"${MINGW_PACKAGE_PREFIX}-polly" "${MINGW_PACKAGE_PREFIX}-polly"
"${MINGW_PACKAGE_PREFIX}-freetype" "${MINGW_PACKAGE_PREFIX}-freetype")
"${MINGW_PACKAGE_PREFIX}-zlib"
"${MINGW_PACKAGE_PREFIX}-bzip2"
"${MINGW_PACKAGE_PREFIX}-xz"
"${MINGW_PACKAGE_PREFIX}-zstd")
source=() source=()
sha256sums=() sha256sums=()

View File

@@ -12,10 +12,49 @@ finish-args:
- --device=all - --device=all
modules: modules:
- name: imhex - name: libiconv
buildsystem: cmake sources:
- type: archive
url: https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.16.tar.gz
sha256: e6a1b1b589654277ee790cce3734f07876ac4ccfaecbee8afa0b649cf529cc04
- name: glfw
buildsystem: cmake-ninja
builddir: true
config-opts: config-opts:
- -DCMAKE_BUILD_TYPE=RelWithDebInfo - -DCMAKE_BUILD_TYPE=RelWithDebInfo
- -DBUILD_SHARED_LIBS:BOOL=ON
sources:
- type: archive
url: https://github.com/glfw/glfw/releases/download/3.3.2/glfw-3.3.2.zip
sha256: 08a33a512f29d7dbf78eab39bd7858576adcc95228c9efe8e4bc5f0f3261efc7
cleanup:
- /include
- /lib/pkgconfig
- name: mbedtls
buildsystem: cmake-ninja
config-opts:
- -DCMAKE_C_FLAGS=-fPIC
sources:
- type: archive
url: https://github.com/ARMmbed/mbedtls/archive/refs/tags/v2.27.0.tar.gz
sha256: 2a07856e541f0e5f6eaee4f78018c52f25bd244ed76f9020dea54a8b02cac6ea
- name: nlohmann-json
buildsystem: cmake-ninja
builddir: true
config-opts:
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
- -DBUILD_TESTING=OFF
sources:
- type: archive
url: https://github.com/nlohmann/json/archive/v3.9.1.tar.gz
sha256: 4cf0df69731494668bdd6460ed8cb269b68de9c19ad8c27abc24cd72605b2d5b
- name: imhex
buildsystem: cmake
sources: sources:
- type: git - type: git

8
dist/rpm/imhex.spec vendored
View File

@@ -26,11 +26,7 @@ BuildRequires: llvm-devel
BuildRequires: mbedtls-devel BuildRequires: mbedtls-devel
BuildRequires: yara-devel BuildRequires: yara-devel
BuildRequires: nativefiledialog-extended-devel BuildRequires: nativefiledialog-extended-devel
BuildRequires: dotnet-sdk-8.0 BuildRequires: dotnet-sdk-7.0
BuildRequires: libzstd-devel
BuildRequires: zlib-devel
BuildRequires: bzip2-devel
BuildRequires: xz-devel
%if 0%{?rhel} %if 0%{?rhel}
BuildRequires: gcc-toolset-12 BuildRequires: gcc-toolset-12
%endif %endif
@@ -40,6 +36,7 @@ Provides: bundled(capstone) = 5.0-rc2
Provides: bundled(imgui) Provides: bundled(imgui)
Provides: bundled(libromfs) Provides: bundled(libromfs)
Provides: bundled(microtar) Provides: bundled(microtar)
Provides: bundled(libpl)
Provides: bundled(xdgpp) Provides: bundled(xdgpp)
# ftbfs on these arches. armv7hl might compile when capstone 5.x # ftbfs on these arches. armv7hl might compile when capstone 5.x
@@ -123,7 +120,6 @@ cp -a lib/third_party/xdgpp/LICENSE %{buildroot
%license %{_datadir}/licenses/%{name}/ %license %{_datadir}/licenses/%{name}/
%doc README.md %doc README.md
%{_bindir}/imhex %{_bindir}/imhex
%{_bindir}/imhex-updater
%{_datadir}/pixmaps/%{name}.png %{_datadir}/pixmaps/%{name}.png
%{_datadir}/applications/%{name}.desktop %{_datadir}/applications/%{name}.desktop
%{_libdir}/libimhex.so* %{_libdir}/libimhex.so*

19
dist/web/Dockerfile vendored
View File

@@ -1,4 +1,4 @@
FROM emscripten/emsdk:3.1.51 as build FROM emscripten/emsdk:latest as build
# Used to invalidate layer cache but not mount cache # Used to invalidate layer cache but not mount cache
# See https://github.com/moby/moby/issues/41715#issuecomment-733976493 # See https://github.com/moby/moby/issues/41715#issuecomment-733976493
@@ -37,10 +37,6 @@ mkdir -p $VCPKG_DEFAULT_BINARY_CACHE
/vcpkg/vcpkg install --triplet=wasm32-emscripten libmagic /vcpkg/vcpkg install --triplet=wasm32-emscripten libmagic
/vcpkg/vcpkg install --triplet=wasm32-emscripten freetype /vcpkg/vcpkg install --triplet=wasm32-emscripten freetype
/vcpkg/vcpkg install --triplet=wasm32-emscripten mbedtls /vcpkg/vcpkg install --triplet=wasm32-emscripten mbedtls
/vcpkg/vcpkg install --triplet=wasm32-emscripten zlib
/vcpkg/vcpkg install --triplet=wasm32-emscripten bzip2
/vcpkg/vcpkg install --triplet=wasm32-emscripten liblzma
/vcpkg/vcpkg install --triplet=wasm32-emscripten zstd
EOF EOF
# Build ImHex # Build ImHex
@@ -58,7 +54,6 @@ ccache -zs
cmake /imhex \ cmake /imhex \
-DIMHEX_OFFLINE_BUILD=ON \ -DIMHEX_OFFLINE_BUILD=ON \
-DIMHEX_STATIC_LINK_PLUGINS=ON \ -DIMHEX_STATIC_LINK_PLUGINS=ON \
-DIMHEX_EXCLUDE_PLUGINS="script_loader" \
-DNATIVE_CMAKE_C_COMPILER=gcc \ -DNATIVE_CMAKE_C_COMPILER=gcc \
-DNATIVE_CMAKE_CXX_COMPILER=g++ \ -DNATIVE_CMAKE_CXX_COMPILER=g++ \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \ -DCMAKE_C_COMPILER_LAUNCHER=ccache \
@@ -73,15 +68,10 @@ cp /imhex/dist/web/source/* /build
ccache -s ccache -s
EOF EOF
# Create a file dedicated to store wasm size, because I know no way to get the wasm content length if the web server uses compression FROM scratch
# See https://stackoverflow.com/questions/41701849/cannot-modify-accept-encoding-with-fetch https://github.com/AnthumChris/fetch-progress-indicators/issues/13
RUN du -b /build/imhex.wasm | cut -f1 > imhex.wasm.size
FROM scratch as raw
COPY --from=build [ \ COPY --from=build [ \
# ImHex \ # ImHex \
"/build/imhex.wasm", \ "/build/imhex.wasm", \
"/build/imhex.wasm.size", \
"/build/imhex.js", \ "/build/imhex.js", \
"/build/imhex.worker.js", \ "/build/imhex.worker.js", \
\ \
@@ -93,12 +83,7 @@ COPY --from=build [ \
"/build/favicon.ico", \ "/build/favicon.ico", \
"/build/icon.png", \ "/build/icon.png", \
"/build/manifest.json", \ "/build/manifest.json", \
"/build/robots.txt", \
"/build/sitemap.xml", \
\ \
# Destination \ # Destination \
"./" \ "./" \
] ]
FROM nginx
COPY --from=raw . /usr/share/nginx/html

10
dist/web/compose.yml vendored
View File

@@ -1,10 +0,0 @@
# docker compose -f dist/web/compose.yml up --build
version: '3'
services:
imhex_web:
image: imhex_web:latest
build:
context: ../../ # ImHex folder
dockerfile: ./dist/web/Dockerfile
ports:
- 8080:80

View File

@@ -2,12 +2,10 @@
extern "C" void forceLinkPlugin_@IMHEX_PLUGIN_NAME@(); extern "C" void forceLinkPlugin_@IMHEX_PLUGIN_NAME@();
namespace {
struct StaticLoad { struct StaticLoad {
StaticLoad() { StaticLoad() {
forceLinkPlugin_@IMHEX_PLUGIN_NAME@(); forceLinkPlugin_@IMHEX_PLUGIN_NAME@();
} }
}; };
}
static StaticLoad staticLoad; static StaticLoad staticLoad;

View File

@@ -1,22 +1,23 @@
<!doctype html> <!doctype html>
<html lang="en-us"> <html lang="en-us">
<head> <head>
<title>ImHex Web - Free Online Hex Editor for Reverse Engineers</title> <link rel="manifest" href="manifest.json" />
<meta charset="utf-8">
<link rel="manifest" href="manifest.json">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<!-- Primary Meta Tags --> <!-- Primary Meta Tags -->
<title>ImHex Web - Online Hex Editor</title>
<meta name="title" content="ImHex"> <meta name="title" content="ImHex">
<meta name="description" content="Free and extremely powerful Online Hex Editor for your Web Browser. ImHex is a free and open source Hex Editor for Reverse Engineers and Developers and Data Analysts."> <meta name="description" content="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.">
<link rel="icon" type="image/x-icon" href="favicon.ico"> <link rel="icon" type="image/x-icon" href="favicon.ico">
<link rel="apple-touch-icon" href="icon.png">
<!-- Open Graph / Facebook --> <!-- Open Graph / Facebook -->
<meta property="og:type" content="website"> <meta property="og:type" content="website">
<meta property="og:url" content="https://imhex.werwolv.net/"> <meta property="og:url" content="https://imhex.werwolv.net/">
<meta property="og:title" content="ImHex Web - Online Hex Editor"> <meta property="og:title" content="ImHex Web - Online Hex Editor">
<meta property="og:description">
<meta name="description" content="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.">
<meta property="og:image" content="https://imhex.werwolv.net/assets/splash_wasm.png"> <meta property="og:image" content="https://imhex.werwolv.net/assets/splash_wasm.png">
<!-- Twitter --> <!-- Twitter -->
@@ -27,7 +28,9 @@
content="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM."> content="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.">
<meta property="twitter:image" content="https://imhex.werwolv.net/assets/splash_wasm.png"> <meta property="twitter:image" content="https://imhex.werwolv.net/assets/splash_wasm.png">
<link rel="stylesheet" type="text/css" href="style.css"> <meta name="viewport" content="width=device-width">
<link rel="stylesheet" type="text/css" href="style.css" />
<script type="application/ld+json"> <script type="application/ld+json">
{ {
@@ -57,48 +60,15 @@
} }
</script> </script>
<title>ImHex Web</title>
<script src="enable-threads.js"></script> <script src="enable-threads.js"></script>
<link rel="stylesheet" href="style.css"> <link rel="stylesheet" href="style.css">
</head> </head>
<body> <body>
<div id="loading" class="centered"> <p id="loading_text">ImHex is loading...</p>
<img src="https://raw.githubusercontent.com/WerWolv/ImHex/master/plugins/builtin/romfs/assets/dark/banner.png" id="logo" alt="ImHex Logo"> <canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
<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>
<div style="height: 50%"> <script type="text/javascript" src="wasm-config.js"></script>
<div style="height: 30%"> </div> <script async type="text/javascript" src="imhex.js"></script>
<h2 id="not_working">
Not loading in your Browser? <a href="https://imhex.werwolv.net">Try the native version</a>
</h2>
<div class="progress-bar-container">
<div class="progress progress-moved">
<div class="progress-bar" id="progress-bar-content">
</div>
</div>
</div>
</div>
<div class="loading_ripple">
<div class="lds-ripple"><div></div><div></div></div>
</div>
<div style="height: 10%">
</div>
<div class="footer">
<a href="https://imhex.werwolv.net">Homepage</a>
<p>Made with ♥️ by the ImHex Team</p>
<a href="https://github.com/WerWolv/ImHex">GitHub</a>
</div>
</div>
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
<script src="wasm-config.js"></script>
<script async src="imhex.js"></script>
</body> </body>
</html> </html>

View File

@@ -1,4 +0,0 @@
User-agent: *
Allow: /
Sitemap: https://imhex.werwolv.net/sitemap.xml

View File

@@ -1,62 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
<url>
<loc>https://web.imhex.werwolv.net/</loc>
<lastmod>2024-01-02T11:44:00+00:00</lastmod>
<priority>1.00</priority>
</url>
<url>
<title>English</title>
<loc>https://web.imhex.werwolv.net?lang=en-US</loc>
<lastmod>2024-01-02T11:44:00+00:00</lastmod>
<priority>1.00</priority>
</url>
<url>
<title>Deutsch</title>
<loc>https://web.imhex.werwolv.net?lang=de-DE</loc>
<lastmod>2024-01-02T11:44:00+00:00</lastmod>
<priority>1.00</priority>
</url>
<url>
<title>Português</title>
<loc>https://web.imhex.werwolv.net?lang=pt-BR</loc>
<lastmod>2024-01-02T11:44:00+00:00</lastmod>
</url>
<url>
<title>中国</title>
<loc>https://web.imhex.werwolv.net?lang=zh-CN</loc>
<lastmod>2024-01-02T11:44:00+00:00</lastmod>
</url>
<url>
<title>國語</title>
<loc>https://web.imhex.werwolv.net?lang=zh-TW</loc>
<lastmod>2024-01-02T11:44:00+00:00</lastmod>
</url>
<url>
<title>日本語</title>
<loc>https://web.imhex.werwolv.net?lang=ja-JP</loc>
<lastmod>2024-01-02T11:44:00+00:00</lastmod>
</url>
<url>
<title>한국어</title>
<loc>https://web.imhex.werwolv.net?lang=ko-KR</loc>
<lastmod>2024-01-02T11:44:00+00:00</lastmod>
</url>
<url>
<title>Español</title>
<loc>https://web.imhex.werwolv.net?lang=es-ES</loc>
<lastmod>2024-01-02T11:44:00+00:00</lastmod>
</url>
<url>
<title>Italiano</title>
<loc>https://web.imhex.werwolv.net?lang=it-IT</loc>
<lastmod>2024-01-02T11:44:00+00:00</lastmod>
</url>
</urlset>

View File

@@ -1,6 +1,6 @@
html, body { html, body {
height: 100%; height: 100%;
margin: 0; margin: 0px;
user-select: none; user-select: none;
} }
@@ -16,162 +16,21 @@ body {
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
display: none; display: none;
border: 0 none; border: 0px none;
image-rendering: smooth;
} }
h1, h2, h5 { .canvas_full_screen {
color: #F0F0F0;
font-size: 20px;
font-family: monospace;
width: 100%;
text-align: center;
margin-top: 60px;
margin-bottom: 10px;
}
h2 {
margin-top: 15px;
font-size: 17px;
}
h5 {
margin-top: 0;
font-size: 17px;
}
#not_working {
opacity: 0;
}
#not_working.visible {
opacity: 1;
transition: opacity 2s ease;
}
a {
color: #7893ff;
text-decoration: none;
}
a:hover {
text-shadow: #3a4677 0 0 10px;
}
.footer {
width: 100%;
height: 20px;
position: absolute;
bottom: 0;
text-align: center;
color: #F0F0F0;
background-color: #0A0A0A;
padding: 10px;
font-family: monospace;
font-size: 15px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: row;
gap: 10%;
}
.centered {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 100%; width: 100%;
height: 100%; height: 100%;
}
.lds-ripple {
display: inline-block;
position: relative;
width: 80px;
height: 80px;
}
.lds-ripple div {
position: absolute; position: absolute;
border: 4px solid #fff; top: 0;
opacity: 1; left: 0;
border-radius: 50%;
animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
}
.lds-ripple div:nth-child(2) {
animation-delay: -0.5s;
}
@keyframes lds-ripple {
0% {
top: 36px;
left: 36px;
width: 0;
height: 0;
opacity: 0;
}
4.9% {
top: 36px;
left: 36px;
width: 0;
height: 0;
opacity: 0;
}
5% {
top: 36px;
left: 36px;
width: 0;
height: 0;
opacity: 1;
}
100% {
top: 0;
left: 0;
width: 72px;
height: 72px;
opacity: 0;
}
} }
#loading_text {
:root { color: #F0F0F0;
--progress: 25%; font-size: 30px;
} font-family: monospace;
width: 100%;
.progress-bar-container {
margin: 100px auto;
width: 600px;
text-align: center; text-align: center;
} }
.progress {
padding: 6px;
border-radius: 30px;
background: rgba(0, 0, 0, 0.25);
box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.25),
0 1px rgba(255, 255, 255, 0.08);
}
.progress-bar {
color: rgba(240, 240, 240, 0.9);
height: 18px;
border-radius: 30px;
font-size: 13px;
font-family: monospace;
font-weight: bold;
text-wrap: avoid;
white-space: nowrap;
overflow: hidden;
background-image: linear-gradient(
to bottom,
rgba(255, 255, 255, 0.2),
rgba(255, 255, 255, 0.0)
);
}
.progress-moved .progress-bar {
width: var(--progress);
background-color: #3864cb;
}

View File

@@ -1,67 +1,3 @@
let wasmSize = null;
// See comment in dist/web/Dockerfile about imhex.wasm.size
fetch("imhex.wasm.size").then(async (resp) => {
wasmSize = parseInt((await resp.text()).trim());
console.log(`Real WASM binary size is ${wasmSize} bytes`);
});
// Monkeypatch WebAssembly to have a progress bar
// inspired from: https://github.com/WordPress/wordpress-playground/pull/46 (but had to be modified)
function monkeyPatch(progressFun) {
const _instantiateStreaming = WebAssembly.instantiateStreaming;
WebAssembly.instantiateStreaming = (response, ...args) => {
// Do not collect wasm content length here see above
const file = response.url.substring(
new URL(response.url).origin.length + 1
);
const reportingResponse = new Response(
new ReadableStream(
{
async start(controller) {
const reader = response.clone().body.getReader();
let loaded = 0;
for (; ;) {
const { done, value } = await reader.read();
if (done) {
if(wasmSize) progressFun(file, wasmSize);
break;
}
loaded += value.byteLength;
progressFun(file, loaded);
controller.enqueue(value);
}
controller.close();
}
},
{
status: response.status,
statusText: response.statusText
}
)
);
for (const pair of response.headers.entries()) {
reportingResponse.headers.set(pair[0], pair[1]);
}
return _instantiateStreaming(reportingResponse, ...args);
}
}
monkeyPatch((file, done) => {
if (!wasmSize) return;
if (done > wasmSize) {
console.warn(`Downloaded binary size ${done} is larger than expected WASM size ${wasmSize}`);
return;
}
const percent = ((done / wasmSize) * 100).toFixed(0);
const mibNow = (done / 1024**2).toFixed(1);
const mibTotal = (wasmSize / 1024**2).toFixed(1);
let root = document.querySelector(':root');
root.style.setProperty("--progress", `${percent}%`)
document.getElementById("progress-bar-content").innerHTML = `${percent}% &nbsp;[${mibNow} MiB / ${mibTotal} MiB]`;
});
function glfwSetCursorCustom(wnd, shape) { function glfwSetCursorCustom(wnd, shape) {
let body = document.getElementsByTagName("body")[0] let body = document.getElementsByTagName("body")[0]
switch (shape) { switch (shape) {
@@ -94,22 +30,16 @@ function glfwCreateStandardCursorCustom(shape) {
return shape return shape
} }
var notWorkingTimer = setTimeout(() => {
document.getElementById("not_working").classList.add("visible")
}, 5000);
var Module = { var Module = {
preRun: [], preRun: [],
postRun: [], postRun: [],
onRuntimeInitialized: function() { onRuntimeInitialized: function() {
// Triggered when the wasm module is loaded and ready to use. // Triggered when the wasm module is loaded and ready to use.
document.getElementById("loading").style.display = "none" document.getElementById("loading_text").style.display = "none"
document.getElementById("canvas").style.display = "initial" document.getElementById("canvas").style.display = "initial"
clearTimeout(notWorkingTimer);
}, },
print: (function() { })(), print: (function() { })(),
printErr: function(text) { }, printErr: function(text) { },
canvas: (function() { canvas: (function() {
let canvas = document.getElementById('canvas'); let canvas = document.getElementById('canvas');
// As a default initial behavior, pop up an alert when webgl context is lost. To make your // As a default initial behavior, pop up an alert when webgl context is lost. To make your
@@ -121,25 +51,14 @@ var Module = {
})(), })(),
setStatus: function(text) { }, setStatus: function(text) { },
totalDependencies: 0, totalDependencies: 0,
monitorRunDependencies: function(left) { monitorRunDependencies: function(left) { },
},
instantiateWasm: function(imports, successCallback) { instantiateWasm: function(imports, successCallback) {
imports.env.glfwSetCursor = glfwSetCursorCustom imports.env.glfwSetCursor = glfwSetCursorCustom
imports.env.glfwCreateStandardCursor = glfwCreateStandardCursorCustom imports.env.glfwCreateStandardCursor = glfwCreateStandardCursorCustom
instantiateAsync(wasmBinary, wasmBinaryFile, imports, (result) => { instantiateAsync(wasmBinary, wasmBinaryFile, imports, (result) => successCallback(result.instance, result.module));
successCallback(result.instance, result.module) }
});
},
arguments: []
}; };
// Handle passing arguments to the wasm module
const queryString = window.location.search;
const urlParams = new URLSearchParams(queryString);
if (urlParams.has("lang")) {
Module["arguments"].push("--language");
Module["arguments"].push(urlParams.get("lang"));
}
window.addEventListener('resize', js_resizeCanvas, false); window.addEventListener('resize', js_resizeCanvas, false);
function js_resizeCanvas() { function js_resizeCanvas() {
@@ -148,10 +67,4 @@ function js_resizeCanvas() {
canvas.height = Math.min(document.documentElement.clientHeight, window.innerHeight || 0); canvas.height = Math.min(document.documentElement.clientHeight, window.innerHeight || 0);
canvas.classList.add("canvas_full_screen") 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();
} }

View File

@@ -14,10 +14,8 @@ set(LIBIMHEX_SOURCES
source/api/project_file_manager.cpp source/api/project_file_manager.cpp
source/api/theme_manager.cpp source/api/theme_manager.cpp
source/api/layout_manager.cpp source/api/layout_manager.cpp
source/api/workspace_manager.cpp
source/api/achievement_manager.cpp source/api/achievement_manager.cpp
source/api/localization_manager.cpp source/api/localization_manager.cpp
source/api/tutorial_manager.cpp
source/data_processor/attribute.cpp source/data_processor/attribute.cpp
source/data_processor/link.cpp source/data_processor/link.cpp
@@ -35,17 +33,16 @@ set(LIBIMHEX_SOURCES
source/helpers/patches.cpp source/helpers/patches.cpp
source/helpers/encoding_file.cpp source/helpers/encoding_file.cpp
source/helpers/logger.cpp source/helpers/logger.cpp
source/helpers/stacktrace.cpp
source/helpers/tar.cpp source/helpers/tar.cpp
source/helpers/debugging.cpp source/helpers/debugging.cpp
source/providers/provider.cpp source/providers/provider.cpp
source/providers/memory_provider.cpp
source/providers/undo/stack.cpp source/providers/undo/stack.cpp
source/ui/imgui_imhex_extensions.cpp source/ui/imgui_imhex_extensions.cpp
source/ui/view.cpp source/ui/view.cpp
source/ui/popup.cpp source/ui/popup.cpp
source/ui/toast.cpp
source/subcommands/subcommands.cpp source/subcommands/subcommands.cpp
) )
@@ -63,23 +60,47 @@ if (APPLE)
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/utils_macos.m) set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/utils_macos.m)
endif () endif ()
if (IMHEX_EXTERNAL_PLUGIN_BUILD) add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
add_library(libimhex IMPORTED SHARED GLOBAL)
set(LIBIMHEX_LIBRARY_TYPE INTERFACE)
else()
if (IMHEX_STATIC_LINK_PLUGINS)
add_library(libimhex STATIC ${LIBIMHEX_SOURCES})
else()
add_library(libimhex SHARED ${LIBIMHEX_SOURCES})
endif()
set(LIBIMHEX_LIBRARY_TYPE PUBLIC) if (IMHEX_STATIC_LINK_PLUGINS)
target_compile_definitions(libimhex PRIVATE IMHEX_PROJECT_NAME="${PROJECT_NAME}") add_library(libimhex STATIC ${LIBIMHEX_SOURCES})
else()
add_library(libimhex SHARED ${LIBIMHEX_SOURCES})
endif()
set_target_properties(libimhex PROPERTIES POSITION_INDEPENDENT_CODE ON)
enableUnityBuild(libimhex)
setupCompilerFlags(libimhex)
include(GenerateExportHeader)
generate_export_header(libimhex)
target_include_directories(libimhex PUBLIC include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIR} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${YARA_INCLUDE_DIRS} ${LIBBACKTRACE_INCLUDE_DIRS})
target_link_directories(libimhex PUBLIC ${MBEDTLS_LIBRARY_DIR} ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS})
if (NOT EMSCRIPTEN)
# curl is only used in non-emscripten builds
target_include_directories(libimhex PUBLIC ${CURL_INCLUDE_DIRS})
target_link_libraries(libimhex PUBLIC ${LIBCURL_LIBRARIES})
endif() endif()
if (DEFINED IMHEX_COMMIT_HASH_LONG AND DEFINED IMHEX_COMMIT_BRANCH) if (WIN32)
set_target_properties(libimhex PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
target_link_options(libimhex PRIVATE -Wl,--export-all-symbols)
elseif (APPLE)
find_library(FOUNDATION NAMES Foundation)
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
endif ()
target_link_libraries(libimhex PRIVATE ${FMT_LIBRARIES})
target_link_libraries(libimhex PUBLIC dl ${IMGUI_LIBRARIES} ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} plcli libpl libpl-gen ${MINIAUDIO_LIBRARIES} ${JTHREAD_LIBRARIES} wolv::utils wolv::io wolv::hash wolv::net wolv::containers wolv::math_eval)
set_property(TARGET libimhex PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE)
if (DEFINED IMHEX_COMMIT_HASH_LONG AND DEFINED IMHEX_COMMIT_HASH_SHORT AND DEFINED IMHEX_COMMIT_BRANCH)
set(GIT_COMMIT_HASH_LONG "${IMHEX_COMMIT_HASH_LONG}") set(GIT_COMMIT_HASH_LONG "${IMHEX_COMMIT_HASH_LONG}")
set(GIT_COMMIT_HASH_SHORT "${IMHEX_COMMIT_HASH_SHORT}")
set(GIT_BRANCH "${IMHEX_COMMIT_BRANCH}") set(GIT_BRANCH "${IMHEX_COMMIT_BRANCH}")
else() else()
# Get the current working branch # Get the current working branch
@@ -89,7 +110,15 @@ else()
OUTPUT_VARIABLE GIT_BRANCH OUTPUT_VARIABLE GIT_BRANCH
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RESULT_BRANCH RESULT_VARIABLE RESULT_BRANCH
ERROR_QUIET )
# Get the latest abbreviated commit hash of the working branch
execute_process(
COMMAND git log -1 --format=%h --abbrev=7
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
OUTPUT_VARIABLE GIT_COMMIT_HASH_SHORT
OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RESULT_HASH_SHORT
) )
execute_process( execute_process(
@@ -98,51 +127,15 @@ else()
OUTPUT_VARIABLE GIT_COMMIT_HASH_LONG OUTPUT_VARIABLE GIT_COMMIT_HASH_LONG
OUTPUT_STRIP_TRAILING_WHITESPACE OUTPUT_STRIP_TRAILING_WHITESPACE
RESULT_VARIABLE RESULT_HASH_LONG RESULT_VARIABLE RESULT_HASH_LONG
ERROR_QUIET
) )
endif () endif ()
if (GIT_COMMIT_HASH_LONG STREQUAL "" OR GIT_BRANCH STREQUAL "") if ((NOT GIT_COMMIT_HASH_SHORT STREQUAL "") AND (NOT GIT_COMMIT_HASH_LONG STREQUAL "") AND (NOT GIT_BRANCH STREQUAL ""))
message(WARNING "Failed to to determine commit hash/branch") addDefineToSource(source/api/imhex_api.cpp "GIT_COMMIT_HASH_SHORT=\"${GIT_COMMIT_HASH_SHORT}\"")
else()
addDefineToSource(source/api/imhex_api.cpp "GIT_COMMIT_HASH_LONG=\"${GIT_COMMIT_HASH_LONG}\"") addDefineToSource(source/api/imhex_api.cpp "GIT_COMMIT_HASH_LONG=\"${GIT_COMMIT_HASH_LONG}\"")
addDefineToSource(source/api/imhex_api.cpp "GIT_BRANCH=\"${GIT_BRANCH}\"") addDefineToSource(source/api/imhex_api.cpp "GIT_BRANCH=\"${GIT_BRANCH}\"")
endif () endif ()
addDefineToSource(source/api/imhex_api.cpp "IMHEX_VERSION=\"${IMHEX_VERSION_STRING}\"") addDefineToSource(source/api/imhex_api.cpp "IMHEX_VERSION=\"${IMHEX_VERSION_STRING}\"")
enableUnityBuild(libimhex)
setupCompilerFlags(libimhex)
include(GenerateExportHeader)
generate_export_header(libimhex)
target_include_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIR} ${MAGIC_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${LIBBACKTRACE_INCLUDE_DIRS})
target_link_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${MBEDTLS_LIBRARY_DIR} ${MAGIC_LIBRARY_DIRS})
if (NOT EMSCRIPTEN)
# curl is only used in non-emscripten builds
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${CURL_LIBRARIES})
endif()
if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD)
if (WIN32)
set_target_properties(libimhex PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
target_link_options(libimhex PRIVATE -Wl,--export-all-symbols)
elseif (APPLE)
find_library(FOUNDATION NAMES Foundation)
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
endif ()
target_link_libraries(libimhex PRIVATE microtar libwolv ${NFD_LIBRARIES} magic dl ${JTHREAD_LIBRARIES})
target_link_libraries(libimhex PUBLIC libpl ${IMGUI_LIBRARIES})
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})
set_property(TARGET libimhex PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE)
add_dependencies(imhex_all libimhex) add_dependencies(imhex_all libimhex)

View File

@@ -1,502 +0,0 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!

View File

@@ -13,7 +13,6 @@
#include <imgui.h> #include <imgui.h>
#include <hex/ui/imgui_imhex_extensions.h> #include <hex/ui/imgui_imhex_extensions.h>
#include <hex/api/localization_manager.hpp>
namespace hex { namespace hex {
@@ -21,22 +20,22 @@ namespace hex {
class Achievement { class Achievement {
public: public:
explicit Achievement(UnlocalizedString unlocalizedCategory, UnlocalizedString unlocalizedName) : m_unlocalizedCategory(std::move(unlocalizedCategory)), m_unlocalizedName(std::move(unlocalizedName)) { } explicit Achievement(std::string unlocalizedCategory, std::string unlocalizedName) : m_unlocalizedCategory(std::move(unlocalizedCategory)), m_unlocalizedName(std::move(unlocalizedName)) { }
/** /**
* @brief Returns the unlocalized name of the achievement * @brief Returns the unlocalized name of the achievement
* @return Unlocalized name of the achievement * @return Unlocalized name of the achievement
*/ */
[[nodiscard]] const UnlocalizedString &getUnlocalizedName() const { [[nodiscard]] const std::string &getUnlocalizedName() const {
return m_unlocalizedName; return this->m_unlocalizedName;
} }
/** /**
* @brief Returns the unlocalized category of the achievement * @brief Returns the unlocalized category of the achievement
* @return Unlocalized category of the achievement * @return Unlocalized category of the achievement
*/ */
[[nodiscard]] const UnlocalizedString &getUnlocalizedCategory() const { [[nodiscard]] const std::string &getUnlocalizedCategory() const {
return m_unlocalizedCategory; return this->m_unlocalizedCategory;
} }
/** /**
@@ -44,7 +43,7 @@ namespace hex {
* @return Whether the achievement is unlocked * @return Whether the achievement is unlocked
*/ */
[[nodiscard]] bool isUnlocked() const { [[nodiscard]] bool isUnlocked() const {
return m_progress == m_maxProgress; return this->m_progress == this->m_maxProgress;
} }
/** /**
@@ -53,7 +52,7 @@ namespace hex {
* @return Reference to the achievement * @return Reference to the achievement
*/ */
Achievement& setDescription(std::string description) { Achievement& setDescription(std::string description) {
m_unlocalizedDescription = std::move(description); this->m_unlocalizedDescription = std::move(description);
return *this; return *this;
} }
@@ -64,7 +63,7 @@ namespace hex {
* @return Reference to the achievement * @return Reference to the achievement
*/ */
Achievement& addRequirement(std::string requirement) { Achievement& addRequirement(std::string requirement) {
m_requirements.emplace_back(std::move(requirement)); this->m_requirements.emplace_back(std::move(requirement));
return *this; return *this;
} }
@@ -75,7 +74,7 @@ namespace hex {
* @return Reference to the achievement * @return Reference to the achievement
*/ */
Achievement& addVisibilityRequirement(std::string requirement) { Achievement& addVisibilityRequirement(std::string requirement) {
m_visibilityRequirements.emplace_back(std::move(requirement)); this->m_visibilityRequirements.emplace_back(std::move(requirement));
return *this; return *this;
} }
@@ -85,7 +84,7 @@ namespace hex {
* @return Reference to the achievement * @return Reference to the achievement
*/ */
Achievement& setBlacked() { Achievement& setBlacked() {
m_blacked = true; this->m_blacked = true;
return *this; return *this;
} }
@@ -95,7 +94,7 @@ namespace hex {
* @return Reference to the achievement * @return Reference to the achievement
*/ */
Achievement& setInvisible() { Achievement& setInvisible() {
m_invisible = true; this->m_invisible = true;
return *this; return *this;
} }
@@ -105,7 +104,7 @@ namespace hex {
* @return Whether the achievement is blacked * @return Whether the achievement is blacked
*/ */
[[nodiscard]] bool isBlacked() const { [[nodiscard]] bool isBlacked() const {
return m_blacked; return this->m_blacked;
} }
/** /**
@@ -113,7 +112,7 @@ namespace hex {
* @return Whether the achievement is invisible * @return Whether the achievement is invisible
*/ */
[[nodiscard]] bool isInvisible() const { [[nodiscard]] bool isInvisible() const {
return m_invisible; return this->m_invisible;
} }
/** /**
@@ -121,7 +120,7 @@ namespace hex {
* @return List of requirements of the achievement * @return List of requirements of the achievement
*/ */
[[nodiscard]] const std::vector<std::string> &getRequirements() const { [[nodiscard]] const std::vector<std::string> &getRequirements() const {
return m_requirements; return this->m_requirements;
} }
/** /**
@@ -129,15 +128,15 @@ namespace hex {
* @return List of visibility requirements of the achievement * @return List of visibility requirements of the achievement
*/ */
[[nodiscard]] const std::vector<std::string> &getVisibilityRequirements() const { [[nodiscard]] const std::vector<std::string> &getVisibilityRequirements() const {
return m_visibilityRequirements; return this->m_visibilityRequirements;
} }
/** /**
* @brief Returns the unlocalized description of the achievement * @brief Returns the unlocalized description of the achievement
* @return Unlocalized description of the achievement * @return Unlocalized description of the achievement
*/ */
[[nodiscard]] const UnlocalizedString &getUnlocalizedDescription() const { [[nodiscard]] const std::string &getUnlocalizedDescription() const {
return m_unlocalizedDescription; return this->m_unlocalizedDescription;
} }
/** /**
@@ -145,15 +144,15 @@ namespace hex {
* @return Icon of the achievement * @return Icon of the achievement
*/ */
[[nodiscard]] const ImGuiExt::Texture &getIcon() const { [[nodiscard]] const ImGuiExt::Texture &getIcon() const {
if (m_iconData.empty()) if (this->m_iconData.empty())
return this->m_icon;
if (this->m_icon.isValid())
return m_icon; return m_icon;
if (m_icon.isValid()) this->m_icon = ImGuiExt::Texture(this->m_iconData.data(), this->m_iconData.size());
return m_icon;
m_icon = ImGuiExt::Texture(m_iconData.data(), m_iconData.size(), ImGuiExt::Texture::Filter::Linear); return this->m_icon;
return m_icon;
} }
/** /**
@@ -162,9 +161,9 @@ namespace hex {
* @return Reference to the achievement * @return Reference to the achievement
*/ */
Achievement& setIcon(std::span<const std::byte> data) { Achievement& setIcon(std::span<const std::byte> data) {
m_iconData.reserve(data.size()); this->m_iconData.reserve(data.size());
for (auto &byte : data) for (auto &byte : data)
m_iconData.emplace_back(static_cast<u8>(byte)); this->m_iconData.emplace_back(static_cast<u8>(byte));
return *this; return *this;
} }
@@ -175,7 +174,7 @@ namespace hex {
* @return Reference to the achievement * @return Reference to the achievement
*/ */
Achievement& setIcon(std::span<const u8> data) { Achievement& setIcon(std::span<const u8> data) {
m_iconData.assign(data.begin(), data.end()); this->m_iconData.assign(data.begin(), data.end());
return *this; return *this;
} }
@@ -186,7 +185,7 @@ namespace hex {
* @return Reference to the achievement * @return Reference to the achievement
*/ */
Achievement& setIcon(std::vector<u8> data) { Achievement& setIcon(std::vector<u8> data) {
m_iconData = std::move(data); this->m_iconData = std::move(data);
return *this; return *this;
} }
@@ -197,9 +196,9 @@ namespace hex {
* @return Reference to the achievement * @return Reference to the achievement
*/ */
Achievement& setIcon(const std::vector<std::byte> &data) { Achievement& setIcon(const std::vector<std::byte> &data) {
m_iconData.reserve(data.size()); this->m_iconData.reserve(data.size());
for (auto &byte : data) for (auto &byte : data)
m_iconData.emplace_back(static_cast<u8>(byte)); this->m_iconData.emplace_back(static_cast<u8>(byte));
return *this; return *this;
} }
@@ -210,7 +209,7 @@ namespace hex {
* @return Reference to the achievement * @return Reference to the achievement
*/ */
Achievement& setRequiredProgress(u32 progress) { Achievement& setRequiredProgress(u32 progress) {
m_maxProgress = progress; this->m_maxProgress = progress;
return *this; return *this;
} }
@@ -220,7 +219,7 @@ namespace hex {
* @return Required progress to unlock the achievement * @return Required progress to unlock the achievement
*/ */
[[nodiscard]] u32 getRequiredProgress() const { [[nodiscard]] u32 getRequiredProgress() const {
return m_maxProgress; return this->m_maxProgress;
} }
/** /**
@@ -228,7 +227,7 @@ namespace hex {
* @return Current progress of the achievement * @return Current progress of the achievement
*/ */
[[nodiscard]] u32 getProgress() const { [[nodiscard]] u32 getProgress() const {
return m_progress; return this->m_progress;
} }
/** /**
@@ -236,7 +235,7 @@ namespace hex {
* @param callback Callback to call when the achievement is clicked * @param callback Callback to call when the achievement is clicked
*/ */
void setClickCallback(const std::function<void(Achievement &)> &callback) { void setClickCallback(const std::function<void(Achievement &)> &callback) {
m_clickCallback = callback; this->m_clickCallback = callback;
} }
/** /**
@@ -244,7 +243,7 @@ namespace hex {
* @return Callback to call when the achievement is clicked * @return Callback to call when the achievement is clicked
*/ */
[[nodiscard]] const std::function<void(Achievement &)> &getClickCallback() const { [[nodiscard]] const std::function<void(Achievement &)> &getClickCallback() const {
return m_clickCallback; return this->m_clickCallback;
} }
/** /**
@@ -252,7 +251,7 @@ namespace hex {
* @return Whether the achievement is temporary * @return Whether the achievement is temporary
*/ */
[[nodiscard]] bool isTemporary() const { [[nodiscard]] bool isTemporary() const {
return m_temporary; return this->m_temporary;
} }
/** /**
@@ -261,21 +260,21 @@ namespace hex {
*/ */
void setUnlocked(bool unlocked) { void setUnlocked(bool unlocked) {
if (unlocked) { if (unlocked) {
if (m_progress < m_maxProgress) if (this->m_progress < this->m_maxProgress)
m_progress++; this->m_progress++;
} else { } else {
m_progress = 0; this->m_progress = 0;
} }
} }
protected: protected:
void setProgress(u32 progress) { void setProgress(u32 progress) {
m_progress = progress; this->m_progress = progress;
} }
private: private:
UnlocalizedString m_unlocalizedCategory, m_unlocalizedName; std::string m_unlocalizedCategory, m_unlocalizedName;
UnlocalizedString m_unlocalizedDescription; std::string m_unlocalizedDescription;
bool m_blacked = false; bool m_blacked = false;
bool m_invisible = false; bool m_invisible = false;
@@ -331,7 +330,18 @@ namespace hex {
static Achievement& addAchievement(auto && ... args) { static Achievement& addAchievement(auto && ... args) {
auto newAchievement = std::make_unique<T>(std::forward<decltype(args)>(args)...); auto newAchievement = std::make_unique<T>(std::forward<decltype(args)>(args)...);
return addAchievementImpl(std::move(newAchievement)); const auto &category = newAchievement->getUnlocalizedCategory();
const auto &name = newAchievement->getUnlocalizedName();
auto [categoryIter, categoryInserted] = getAchievements().insert({ category, std::unordered_map<std::string, std::unique_ptr<Achievement>>{} });
auto &[categoryKey, achievements] = *categoryIter;
auto [achievementIter, achievementInserted] = achievements.insert({ name, std::move(newAchievement) });
auto &[achievementKey, achievement] = *achievementIter;
achievementAdded();
return *achievement;
} }
/** /**
@@ -354,13 +364,13 @@ namespace hex {
* @param unlocalizedCategory Unlocalized category of the achievement * @param unlocalizedCategory Unlocalized category of the achievement
* @param unlocalizedName Unlocalized name of the achievement * @param unlocalizedName Unlocalized name of the achievement
*/ */
static void unlockAchievement(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName); static void unlockAchievement(const std::string &unlocalizedCategory, const std::string &unlocalizedName);
/** /**
* @brief Returns all registered achievements * @brief Returns all registered achievements
* @return All achievements * @return All achievements
*/ */
static const std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>>& getAchievements(); static std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>>& getAchievements();
/** /**
* @brief Returns all achievement start nodes * @brief Returns all achievement start nodes
@@ -368,14 +378,14 @@ namespace hex {
* @param rebuild Whether to rebuild the list of start nodes * @param rebuild Whether to rebuild the list of start nodes
* @return All achievement start nodes * @return All achievement start nodes
*/ */
static const std::unordered_map<std::string, std::vector<AchievementNode*>>& getAchievementStartNodes(bool rebuild = true); static std::unordered_map<std::string, std::vector<AchievementNode*>>& getAchievementStartNodes(bool rebuild = true);
/** /**
* @brief Returns all achievement nodes * @brief Returns all achievement nodes
* @param rebuild Whether to rebuild the list of nodes * @param rebuild Whether to rebuild the list of nodes
* @return All achievement nodes * @return All achievement nodes
*/ */
static const std::unordered_map<std::string, std::list<AchievementNode>>& getAchievementNodes(bool rebuild = true); static std::unordered_map<std::string, std::list<AchievementNode>>& getAchievementNodes(bool rebuild = true);
/** /**
* @brief Loads the progress of all achievements from the achievements save file * @brief Loads the progress of all achievements from the achievements save file
@@ -387,6 +397,11 @@ namespace hex {
*/ */
static void storeProgress(); static void storeProgress();
/**
* @brief Removes all registered achievements from the tree
*/
static void clear();
/** /**
* @brief Removes all temporary achievements from the tree * @brief Removes all temporary achievements from the tree
*/ */
@@ -400,8 +415,6 @@ namespace hex {
private: private:
static void achievementAdded(); static void achievementAdded();
static Achievement& addAchievementImpl(std::unique_ptr<Achievement> &&newAchievement);
}; };
} }

File diff suppressed because it is too large Load Diff

View File

@@ -8,22 +8,17 @@
#include <functional> #include <functional>
#include <hex/api/imhex_api.hpp> #include <hex/api/imhex_api.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/logger.hpp> #include <hex/helpers/logger.hpp>
#include <wolv/types/type_name.hpp> #include <wolv/types/type_name.hpp>
#define EVENT_DEF_IMPL(event_name, event_name_string, should_log, ...) \ #define EVENT_DEF_IMPL(event_name, event_name_string, should_log, ...) \
struct event_name final : public hex::impl::Event<__VA_ARGS__> { \ struct event_name final : public hex::impl::Event<__VA_ARGS__> { \
constexpr static auto Id = [] { return hex::impl::EventId(event_name_string); }(); \ constexpr static auto Id = [] { return hex::impl::EventId(event_name_string); }(); \
constexpr static auto ShouldLog = (should_log); \ constexpr static auto ShouldLog = (should_log); \
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \ explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
\ }
static EventManager::EventList::iterator subscribe(Event::Callback function) { return EventManager::subscribe<event_name>(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(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, true, __VA_ARGS__)
#define EVENT_DEF_NO_LOG(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, false, __VA_ARGS__) #define EVENT_DEF_NO_LOG(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, false, __VA_ARGS__)
@@ -31,12 +26,8 @@
/* Forward declarations */ /* Forward declarations */
struct GLFWwindow; struct GLFWwindow;
namespace hex { namespace hex { class Achievement; }
class Achievement;
class View;
}
namespace pl::ptrn { class Pattern; }
namespace hex { namespace hex {
@@ -45,15 +36,15 @@ namespace hex {
class EventId { class EventId {
public: public:
explicit constexpr EventId(const char *eventName) { explicit constexpr EventId(const char *eventName) {
m_hash = 0x811C'9DC5; this->m_hash = 0x811C'9DC5;
for (const char c : std::string_view(eventName)) { for (auto c : std::string_view(eventName)) {
m_hash = (m_hash >> 5) | (m_hash << 27); this->m_hash = (this->m_hash >> 5) | (this->m_hash << 27);
m_hash ^= c; this->m_hash ^= c;
} }
} }
constexpr bool operator==(const EventId &other) const { constexpr bool operator==(const EventId &other) const {
return m_hash == other.m_hash; return this->m_hash == other.m_hash;
} }
private: private:
@@ -62,7 +53,6 @@ namespace hex {
struct EventBase { struct EventBase {
EventBase() noexcept = default; EventBase() noexcept = default;
virtual ~EventBase() = default;
}; };
template<typename... Params> template<typename... Params>
@@ -71,13 +61,8 @@ namespace hex {
explicit Event(Callback func) noexcept : m_func(std::move(func)) { } explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
void operator()(std::string_view eventName, Params... params) const { void operator()(Params... params) const noexcept {
try { this->m_func(params...);
m_func(params...);
} catch (const std::exception &e) {
log::error("An exception occurred while handling event {}: {}", eventName, e.what());
throw;
}
} }
private: private:
@@ -124,7 +109,7 @@ namespace hex {
if (getTokenStore().contains(token)) { if (getTokenStore().contains(token)) {
auto&& [begin, end] = getTokenStore().equal_range(token); auto&& [begin, end] = getTokenStore().equal_range(token);
const auto eventRegistered = std::any_of(begin, end, [&](auto &item) { auto eventRegistered = std::any_of(begin, end, [&](auto &item) {
return item.second->first == E::Id; return item.second->first == E::Id;
}); });
if (eventRegistered) { if (eventRegistered) {
@@ -173,12 +158,16 @@ namespace hex {
* @param args Arguments to pass to the event * @param args Arguments to pass to the event
*/ */
template<impl::EventType E> template<impl::EventType E>
static void post(auto && ...args) { static void post(auto &&...args) noexcept {
std::scoped_lock lock(getEventMutex()); std::scoped_lock lock(getEventMutex());
for (const auto &[id, event] : getEvents()) { for (const auto &[id, event] : getEvents()) {
if (id == E::Id) { if (id == E::Id) {
(*static_cast<E *const>(event.get()))(wolv::type::getTypeName<E>(), std::forward<decltype(args)>(args)...); try {
(*static_cast<E *const>(event.get()))(std::forward<decltype(args)>(args)...);
} catch (const std::exception &e) {
log::error("Event '{}' threw {}: {}", wolv::type::getTypeName<decltype(e)>(), wolv::type::getTypeName<E>(), e.what());
}
} }
} }
@@ -212,14 +201,14 @@ namespace hex {
EVENT_DEF(EventImHexStartupFinished); EVENT_DEF(EventImHexStartupFinished);
EVENT_DEF(EventFileLoaded, std::fs::path); EVENT_DEF(EventFileLoaded, std::fs::path);
EVENT_DEF(EventDataChanged, prv::Provider *); EVENT_DEF(EventDataChanged);
EVENT_DEF(EventHighlightingChanged); EVENT_DEF(EventHighlightingChanged);
EVENT_DEF(EventWindowClosing, GLFWwindow *); EVENT_DEF(EventWindowClosing, GLFWwindow *);
EVENT_DEF(EventRegionSelected, ImHexApi::HexEditor::ProviderRegion); EVENT_DEF(EventRegionSelected, ImHexApi::HexEditor::ProviderRegion);
EVENT_DEF(EventSettingsChanged);
EVENT_DEF(EventAbnormalTermination, int); EVENT_DEF(EventAbnormalTermination, int);
EVENT_DEF(EventThemeChanged); EVENT_DEF(EventThemeChanged);
EVENT_DEF(EventOSThemeChanged); EVENT_DEF(EventOSThemeChanged);
EVENT_DEF(EventWindowFocused, bool);
/** /**
* @brief Called when the provider is created. * @brief Called when the provider is created.
@@ -243,7 +232,6 @@ namespace hex {
EVENT_DEF(EventProviderDeleted, prv::Provider *); EVENT_DEF(EventProviderDeleted, prv::Provider *);
EVENT_DEF(EventProviderSaved, prv::Provider *); EVENT_DEF(EventProviderSaved, prv::Provider *);
EVENT_DEF(EventWindowInitialized); EVENT_DEF(EventWindowInitialized);
EVENT_DEF(EventWindowDeinitializing, GLFWwindow *);
EVENT_DEF(EventBookmarkCreated, ImHexApi::Bookmarks::Entry&); EVENT_DEF(EventBookmarkCreated, ImHexApi::Bookmarks::Entry&);
EVENT_DEF(EventPatchCreated, u64, u8, u8); EVENT_DEF(EventPatchCreated, u64, u8, u8);
EVENT_DEF(EventPatternEvaluating); EVENT_DEF(EventPatternEvaluating);
@@ -253,12 +241,7 @@ namespace hex {
EVENT_DEF(EventStoreContentRemoved, const std::fs::path&); EVENT_DEF(EventStoreContentRemoved, const std::fs::path&);
EVENT_DEF(EventImHexClosing); EVENT_DEF(EventImHexClosing);
EVENT_DEF(EventAchievementUnlocked, const Achievement&); EVENT_DEF(EventAchievementUnlocked, const Achievement&);
EVENT_DEF(EventSearchBoxClicked, u32); EVENT_DEF(EventSearchBoxClicked);
EVENT_DEF(EventViewOpened, View*);
EVENT_DEF(EventFirstLaunch);
EVENT_DEF(EventFileDragged, bool);
EVENT_DEF(EventFileDropped, std::fs::path);
EVENT_DEF(EventProviderDataModified, prv::Provider *, u64, u64, const u8*); EVENT_DEF(EventProviderDataModified, prv::Provider *, u64, u64, const u8*);
EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64); EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64);
@@ -276,13 +259,10 @@ namespace hex {
EVENT_DEF(RequestAddInitTask, std::string, bool, std::function<bool()>); EVENT_DEF(RequestAddInitTask, std::string, bool, std::function<bool()>);
EVENT_DEF(RequestAddExitTask, std::string, std::function<bool()>); EVENT_DEF(RequestAddExitTask, std::string, std::function<bool()>);
EVENT_DEF(RequestOpenWindow, std::string); EVENT_DEF(RequestOpenWindow, std::string);
EVENT_DEF(RequestHexEditorSelectionChange, Region); EVENT_DEF(RequestSelectionChange, Region);
EVENT_DEF(RequestPatternEditorSelectionChange, u32, u32);
EVENT_DEF(RequestJumpToPattern, const pl::ptrn::Pattern*);
EVENT_DEF(RequestAddBookmark, Region, std::string, std::string, color_t, u64*); EVENT_DEF(RequestAddBookmark, Region, std::string, std::string, color_t, u64*);
EVENT_DEF(RequestRemoveBookmark, u64); EVENT_DEF(RequestRemoveBookmark, u64);
EVENT_DEF(RequestSetPatternLanguageCode, std::string); EVENT_DEF(RequestSetPatternLanguageCode, std::string);
EVENT_DEF(RequestRunPatternCode);
EVENT_DEF(RequestLoadPatternLanguageFile, std::fs::path); EVENT_DEF(RequestLoadPatternLanguageFile, std::fs::path);
EVENT_DEF(RequestSavePatternLanguageFile, std::fs::path); EVENT_DEF(RequestSavePatternLanguageFile, std::fs::path);
EVENT_DEF(RequestUpdateWindowTitle); EVENT_DEF(RequestUpdateWindowTitle);
@@ -291,7 +271,6 @@ namespace hex {
EVENT_DEF(RequestOpenFile, std::fs::path); EVENT_DEF(RequestOpenFile, std::fs::path);
EVENT_DEF(RequestChangeTheme, std::string); EVENT_DEF(RequestChangeTheme, std::string);
EVENT_DEF(RequestOpenPopup, std::string); EVENT_DEF(RequestOpenPopup, std::string);
EVENT_DEF(RequestAddVirtualFile, std::fs::path, std::vector<u8>, Region);
/** /**
* @brief Creates a provider from it's unlocalized name, and add it to the provider list * @brief Creates a provider from it's unlocalized name, and add it to the provider list
@@ -299,6 +278,11 @@ namespace hex {
EVENT_DEF(RequestCreateProvider, std::string, bool, bool, hex::prv::Provider **); EVENT_DEF(RequestCreateProvider, std::string, bool, bool, hex::prv::Provider **);
EVENT_DEF(RequestInitThemeHandlers); EVENT_DEF(RequestInitThemeHandlers);
EVENT_DEF(RequestOpenInfoPopup, const std::string);
EVENT_DEF(RequestOpenErrorPopup, const std::string);
EVENT_DEF(RequestOpenFatalPopup, const std::string);
/** /**
* @brief Send an event to the main Imhex instance * @brief Send an event to the main Imhex instance
*/ */
@@ -309,9 +293,4 @@ namespace hex {
* The 'from' provider should not have any per provider data after this, and should be immediately deleted * The 'from' provider should not have any per provider data after this, and should be immediately deleted
*/ */
EVENT_DEF(MovePerProviderData, prv::Provider *, prv::Provider *); EVENT_DEF(MovePerProviderData, prv::Provider *, prv::Provider *);
/**
* Called when ImHex managed to catch an error in a general try/catch to prevent/recover from a crash
*/
EVENT_DEF(EventCrashRecovered, const std::exception &);
} }

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include <hex.hpp> #include <hex.hpp>
#include <hex/api/localization_manager.hpp>
#include <optional> #include <optional>
#include <span> #include <span>
@@ -15,14 +14,9 @@ using ImGuiID = unsigned int;
struct ImVec2; struct ImVec2;
struct ImFontAtlas; struct ImFontAtlas;
struct ImFont; struct ImFont;
struct GLFWwindow;
namespace hex { namespace hex {
namespace impl {
class AutoResetBase;
}
namespace prv { namespace prv {
class Provider; class Provider;
} }
@@ -39,8 +33,8 @@ namespace hex {
Highlighting() = default; Highlighting() = default;
Highlighting(Region region, color_t color); Highlighting(Region region, color_t color);
[[nodiscard]] const Region& getRegion() const { return m_region; } [[nodiscard]] const Region &getRegion() const { return this->m_region; }
[[nodiscard]] const color_t& getColor() const { return m_color; } [[nodiscard]] const color_t &getColor() const { return this->m_color; }
private: private:
Region m_region = {}; Region m_region = {};
@@ -52,9 +46,9 @@ namespace hex {
Tooltip() = default; Tooltip() = default;
Tooltip(Region region, std::string value, color_t color); Tooltip(Region region, std::string value, color_t color);
[[nodiscard]] const Region& getRegion() const { return m_region; } [[nodiscard]] const Region &getRegion() const { return this->m_region; }
[[nodiscard]] const color_t& getColor() const { return m_color; } [[nodiscard]] const color_t &getColor() const { return this->m_color; }
[[nodiscard]] const std::string& getValue() const { return m_value; } [[nodiscard]] const std::string &getValue() const { return this->m_value; }
private: private:
Region m_region = {}; Region m_region = {};
@@ -73,18 +67,15 @@ namespace hex {
namespace impl { namespace impl {
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t, bool)>; using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t, bool)>;
using HoveringFunction = std::function<bool(const prv::Provider *, u64, const u8*, size_t)>;
const std::map<u32, Highlighting>& getBackgroundHighlights(); std::map<u32, Highlighting> &getBackgroundHighlights();
const std::map<u32, HighlightingFunction>& getBackgroundHighlightingFunctions(); std::map<u32, HighlightingFunction> &getBackgroundHighlightingFunctions();
const std::map<u32, Highlighting>& getForegroundHighlights(); std::map<u32, Highlighting> &getForegroundHighlights();
const std::map<u32, HighlightingFunction>& getForegroundHighlightingFunctions(); std::map<u32, HighlightingFunction> &getForegroundHighlightingFunctions();
const std::map<u32, HoveringFunction>& getHoveringFunctions(); std::map<u32, Tooltip> &getTooltips();
const std::map<u32, Tooltip>& getTooltips(); std::map<u32, TooltipFunction> &getTooltipFunctions();
const std::map<u32, TooltipFunction>& getTooltipFunctions();
void setCurrentSelection(const std::optional<ProviderRegion> &region); void setCurrentSelection(const std::optional<ProviderRegion> &region);
void setHoveredRegion(const prv::Provider *provider, const Region &region);
} }
/** /**
@@ -173,19 +164,6 @@ namespace hex {
*/ */
void removeForegroundHighlightingProvider(u32 id); void removeForegroundHighlightingProvider(u32 id);
/**
* @brief Adds a hovering provider to the Hex Editor using a callback function
* @param function Function that draws the highlighting based on the hovered region
* @return Unique ID used to remove the highlighting again later
*/
u32 addHoverHighlightProvider(const impl::HoveringFunction &function);
/**
* @brief Removes a hovering color highlighting from the Hex Editor
* @param id The ID of the highlighting to remove
*/
void removeHoverHighlightProvider(u32 id);
/** /**
* @brief Checks if there's a valid selection in the Hex Editor right now * @brief Checks if there's a valid selection in the Hex Editor right now
*/ */
@@ -223,20 +201,6 @@ namespace hex {
*/ */
void setSelection(u64 address, size_t size, prv::Provider *provider = nullptr); void setSelection(u64 address, size_t size, prv::Provider *provider = nullptr);
/**
* @brief Adds a virtual file to the list in the Hex Editor
* @param path The path of the file
* @param data The data of the file
* @param region The location of the file in the Hex Editor if available
*/
void addVirtualFile(const std::fs::path &path, std::vector<u8> data, Region region = Region::Invalid());
/**
* @brief Gets the currently hovered cell region in the Hex Editor
* @return
*/
const std::optional<Region>& getHoveredRegion(const prv::Provider *provider);
} }
/* Functions to interact with Bookmarks */ /* Functions to interact with Bookmarks */
@@ -305,19 +269,13 @@ namespace hex {
* @brief Gets a list of all currently loaded data providers * @brief Gets a list of all currently loaded data providers
* @return The currently loaded data providers * @return The currently loaded data providers
*/ */
std::vector<prv::Provider*> getProviders(); const std::vector<prv::Provider *> &getProviders();
/** /**
* @brief Sets the currently selected data provider * @brief Sets the currently selected data provider
* @param index Index of the provider to select * @param index Index of the provider to select
*/ */
void setCurrentProvider(i64 index); void setCurrentProvider(u32 index);
/**
* @brief Sets the currently selected data provider
* @param provider The provider to select
*/
void setCurrentProvider(NonNull<prv::Provider*> provider);
/** /**
* @brief Gets the index of the currently selected data provider * @brief Gets the index of the currently selected data provider
@@ -355,7 +313,7 @@ namespace hex {
* @param skipLoadInterface Whether to skip the provider's loading interface (see property documentation) * @param skipLoadInterface Whether to skip the provider's loading interface (see property documentation)
* @param select Whether to select the provider after adding it * @param select Whether to select the provider after adding it
*/ */
void add(std::unique_ptr<prv::Provider> &&provider, bool skipLoadInterface = false, bool select = true); void add(prv::Provider *provider, bool skipLoadInterface = false, bool select = true);
/** /**
* @brief Creates a new provider and adds it to the list of providers * @brief Creates a new provider and adds it to the list of providers
@@ -364,7 +322,7 @@ namespace hex {
*/ */
template<std::derived_from<prv::Provider> T> template<std::derived_from<prv::Provider> T>
void add(auto &&...args) { void add(auto &&...args) {
add(std::make_unique<T>(std::forward<decltype(args)>(args)...)); add(new T(std::forward<decltype(args)>(args)...));
} }
/** /**
@@ -380,29 +338,41 @@ namespace hex {
* @param skipLoadInterface Whether to skip the provider's loading interface (see property documentation) * @param skipLoadInterface Whether to skip the provider's loading interface (see property documentation)
* @param select Whether to select the provider after adding it * @param select Whether to select the provider after adding it
*/ */
prv::Provider* createProvider( prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface = false, bool select = true);
const UnlocalizedString &unlocalizedName,
bool skipLoadInterface = false,
bool select = true
);
} }
/* Functions to interact with various ImHex system settings */ /* Functions to interact with various ImHex system settings */
namespace System { namespace System {
bool isMainInstance();
namespace impl {
void setMainInstanceStatus(bool status);
void setMainWindowPosition(i32 x, i32 y);
void setMainWindowSize(u32 width, u32 height);
void setMainDockSpaceId(ImGuiID id);
void setGlobalScale(float scale);
void setNativeScale(float scale);
void setBorderlessWindowMode(bool enabled);
void setGPUVendor(const std::string &vendor);
void setPortableVersion(bool enabled);
void addInitArgument(const std::string &key, const std::string &value = { });
}
struct ProgramArguments { struct ProgramArguments {
int argc; int argc;
char **argv; char **argv;
char **envp; char **envp;
}; };
struct InitialWindowProperties {
i32 x, y;
u32 width, height;
bool maximized;
};
enum class TaskProgressState { enum class TaskProgressState {
Reset, Reset,
Progress, Progress,
@@ -415,35 +385,6 @@ namespace hex {
Error Error
}; };
namespace impl {
void setMainInstanceStatus(bool status);
void setMainWindowPosition(i32 x, i32 y);
void setMainWindowSize(u32 width, u32 height);
void setMainDockSpaceId(ImGuiID id);
void setMainWindowHandle(GLFWwindow *window);
void setGlobalScale(float scale);
void setNativeScale(float scale);
void setBorderlessWindowMode(bool enabled);
void setMultiWindowMode(bool enabled);
void setInitialWindowProperties(InitialWindowProperties properties);
void setGPUVendor(const std::string &vendor);
void addInitArgument(const std::string &key, const std::string &value = { });
void setLastFrameTime(double time);
bool isWindowResizable();
void addAutoResetObject(hex::impl::AutoResetBase *object);
void cleanup();
}
/** /**
* @brief Closes ImHex * @brief Closes ImHex
* @param noQuestions Whether to skip asking the user for confirmation * @param noQuestions Whether to skip asking the user for confirmation
@@ -508,11 +449,6 @@ namespace hex {
*/ */
ImGuiID getMainDockSpaceId(); ImGuiID getMainDockSpaceId();
/**
* @brief Gets the main window's GLFW window handle
* @return GLFW window handle
*/
GLFWwindow* getMainWindowHandle();
/** /**
* @brief Checks if borderless window mode is enabled currently * @brief Checks if borderless window mode is enabled currently
@@ -520,24 +456,11 @@ namespace hex {
*/ */
bool isBorderlessWindowModeEnabled(); bool isBorderlessWindowModeEnabled();
/**
* @brief Checks if multi-window mode is enabled currently
* @return Whether multi-window mode is enabled
*/
bool isMutliWindowModeEnabled();
/** /**
* @brief Gets the init arguments passed to ImHex from the splash screen * @brief Gets the init arguments passed to ImHex from the splash screen
* @return Init arguments * @return Init arguments
*/ */
const std::map<std::string, std::string>& getInitArguments(); std::map<std::string, std::string> &getInitArguments();
/**
* @brief Gets a init arguments passed to ImHex from the splash screen
* @param key The key of the init argument
* @return Init argument
*/
std::string getInitArgument(const std::string &key);
/** /**
* @brief Sets if ImHex should follow the system theme * @brief Sets if ImHex should follow the system theme
@@ -556,7 +479,7 @@ namespace hex {
* @brief Gets the currently set additional folder paths * @brief Gets the currently set additional folder paths
* @return The currently set additional folder paths * @return The currently set additional folder paths
*/ */
const std::vector<std::filesystem::path>& getAdditionalFolderPaths(); std::vector<std::filesystem::path> &getAdditionalFolderPaths();
/** /**
* @brief Sets the additional folder paths * @brief Sets the additional folder paths
@@ -569,7 +492,7 @@ namespace hex {
* @brief Gets the current GPU vendor * @brief Gets the current GPU vendor
* @return The current GPU vendor * @return The current GPU vendor
*/ */
const std::string& getGPUVendor(); const std::string &getGPUVendor();
/** /**
* @brief Checks if ImHex is running in portable mode * @brief Checks if ImHex is running in portable mode
@@ -632,38 +555,7 @@ namespace hex {
*/ */
bool updateImHex(UpdateType updateType); bool updateImHex(UpdateType updateType);
/**
* @brief Add a new startup task that will be run while ImHex's splash screen is shown
* @param name Name to be shown in the UI
* @param async Whether to run the task asynchronously
* @param function The function to run
*/
void addStartupTask(const std::string &name, bool async, const std::function<bool()> &function); void addStartupTask(const std::string &name, bool async, const std::function<bool()> &function);
/**
* @brief Gets the time the previous frame took
* @return Previous frame time
*/
double getLastFrameTime();
/**
* @brief Sets the window resizable
* @param resizable Whether the window should be resizable
*/
void setWindowResizable(bool resizable);
/**
* @brief Checks if this window is the main instance of ImHex
* @return True if this is the main instance, false if another instance is already running
*/
bool isMainInstance();
/**
* @brief Gets the initial window properties
* @return Initial window properties
*/
std::optional<InitialWindowProperties> getInitialWindowProperties();
} }
/** /**
@@ -673,12 +565,11 @@ namespace hex {
namespace Messaging { namespace Messaging {
namespace impl { namespace impl {
using MessagingHandler = std::function<void(const std::vector<u8> &)>; using MessagingHandler = std::function<void(const std::vector<u8> &)>;
const std::map<std::string, MessagingHandler>& getHandlers(); std::map<std::string, MessagingHandler> &getHandlers();
void runHandler(const std::string &eventName, const std::vector<u8> &args);
void runHandler(const std::string &eventName, const std::vector<u8> &args);
} }
/** /**
@@ -698,12 +589,11 @@ namespace hex {
std::vector<GlyphRange> glyphRanges; std::vector<GlyphRange> glyphRanges;
Offset offset; Offset offset;
u32 flags; u32 flags;
std::optional<u32> defaultSize;
}; };
namespace impl { namespace impl {
const std::vector<Font>& getFonts(); std::vector<Font>& getFonts();
void setCustomFontPath(const std::fs::path &path); void setCustomFontPath(const std::fs::path &path);
void setFontSize(float size); void setFontSize(float size);
@@ -717,8 +607,8 @@ namespace hex {
GlyphRange range(const char *glyphBegin, const char *glyphEnd); GlyphRange range(const char *glyphBegin, const char *glyphEnd);
GlyphRange range(u32 codepointBegin, u32 codepointEnd); GlyphRange range(u32 codepointBegin, u32 codepointEnd);
void loadFont(const std::fs::path &path, const std::vector<GlyphRange> &glyphRanges = {}, Offset offset = {}, u32 flags = 0, std::optional<u32> defaultSize = std::nullopt); void loadFont(const std::fs::path &path, const std::vector<GlyphRange> &glyphRanges = {}, Offset offset = {}, u32 flags = 0);
void loadFont(const std::string &name, const std::span<const u8> &data, const std::vector<GlyphRange> &glyphRanges = {}, Offset offset = {}, u32 flags = 0, std::optional<u32> defaultSize = std::nullopt); void loadFont(const std::string &name, const std::span<const u8> &data, const std::vector<GlyphRange> &glyphRanges = {}, Offset offset = {}, u32 flags = 0);
constexpr static float DefaultFontSize = 13.0; constexpr static float DefaultFontSize = 13.0;
@@ -729,7 +619,7 @@ namespace hex {
* @brief Gets the current custom font path * @brief Gets the current custom font path
* @return The current custom font path * @return The current custom font path
*/ */
const std::filesystem::path& getCustomFontPath(); std::filesystem::path &getCustomFontPath();
/** /**
* @brief Gets the current font size * @brief Gets the current font size

View File

@@ -4,7 +4,7 @@
#include <string> #include <string>
struct ImGuiTextBuffer; #include <nlohmann/json_fwd.hpp>
namespace hex { namespace hex {
@@ -15,9 +15,6 @@ namespace hex {
std::fs::path path; std::fs::path path;
}; };
using LoadCallback = std::function<void(std::string_view)>;
using StoreCallback = std::function<void(ImGuiTextBuffer *)>;
/** /**
* @brief Save the current layout * @brief Save the current layout
* @param name Name of the layout * @param name Name of the layout
@@ -30,17 +27,11 @@ namespace hex {
*/ */
static void load(const std::fs::path &path); static void load(const std::fs::path &path);
/**
* @brief Saves the current layout to a string
* @return String containing the layout
*/
static std::string saveToString();
/** /**
* @brief Load a layout from a string * @brief Load a layout from a string
* @param content Layout string * @param content Layout string
*/ */
static void loadFromString(const std::string &content); static void loadString(const std::string &content);
/** /**
* @brief Get a list of all layouts * @brief Get a list of all layouts
@@ -64,29 +55,6 @@ namespace hex {
*/ */
static void reset(); static void reset();
/**
* @brief Checks is the current layout is locked
*/
static bool isLayoutLocked();
/**
* @brief Locks or unlocks the current layout
* @note If the layout is locked, it cannot be modified by the user anymore
* @param locked True to lock the layout, false to unlock it
*/
static void lockLayout(bool locked);
/**
* @brief Closes all views
*/
static void closeAllViews();
static void registerLoadCallback(const LoadCallback &callback);
static void registerStoreCallback(const StoreCallback &callback);
static void onStore(ImGuiTextBuffer *buffer);
static void onLoad(std::string_view line);
private: private:
LayoutManager() = default; LayoutManager() = default;
}; };

View File

@@ -3,7 +3,6 @@
#include <map> #include <map>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <vector>
#include <fmt/format.h> #include <fmt/format.h>
@@ -27,20 +26,16 @@ namespace hex {
} }
void loadLanguage(const std::string &language); void loadLanguage(const std::string &language);
std::string getLocalizedString(const std::string &unlocalizedString, const std::string &language = "");
[[nodiscard]] const std::map<std::string, std::string> &getSupportedLanguages(); [[nodiscard]] const std::map<std::string, std::string> &getSupportedLanguages();
[[nodiscard]] const std::string &getFallbackLanguage(); [[nodiscard]] const std::string &getFallbackLanguage();
[[nodiscard]] const std::string &getSelectedLanguage(); [[nodiscard]] const std::string &getSelectedLanguage();
} }
struct UnlocalizedString;
class Lang { class Lang {
public: public:
explicit Lang(const char *unlocalizedString); explicit Lang(const char *unlocalizedString);
explicit Lang(const std::string &unlocalizedString); explicit Lang(std::string unlocalizedString);
explicit Lang(const UnlocalizedString &unlocalizedString);
explicit Lang(std::string_view unlocalizedString); explicit Lang(std::string_view unlocalizedString);
[[nodiscard]] operator std::string() const; [[nodiscard]] operator std::string() const;
@@ -65,43 +60,6 @@ namespace hex {
return Lang(string); return Lang(string);
} }
struct UnlocalizedString {
public:
UnlocalizedString() = default;
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 {
return m_unlocalizedString;
}
[[nodiscard]] operator std::string_view() const {
return m_unlocalizedString;
}
[[nodiscard]] operator const char *() const {
return m_unlocalizedString.c_str();
}
[[nodiscard]] const std::string &get() const {
return m_unlocalizedString;
}
[[nodiscard]] bool empty() const {
return m_unlocalizedString.empty();
}
auto operator<=>(const UnlocalizedString &) const = default;
auto operator<=>(const std::string &other) const {
return m_unlocalizedString <=> other;
}
private:
std::string m_unlocalizedString;
};
} }
template<> template<>

View File

@@ -1,15 +1,11 @@
#pragma once #pragma once
#include <functional> #include <functional>
#include <list>
#include <span> #include <span>
#include <string> #include <string>
#include <wolv/io/fs.hpp> #include <wolv/io/fs.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/helpers/auto_reset.hpp>
struct ImGuiContext; struct ImGuiContext;
namespace hex { namespace hex {
@@ -20,73 +16,54 @@ namespace hex {
std::function<void(const std::vector<std::string>&)> callback; std::function<void(const std::vector<std::string>&)> callback;
}; };
struct Feature {
std::string name;
bool enabled;
};
struct PluginFunctions { struct PluginFunctions {
using InitializePluginFunc = void (*)(); using InitializePluginFunc = void (*)();
using InitializeLibraryFunc = void (*)();
using GetPluginNameFunc = const char *(*)(); using GetPluginNameFunc = const char *(*)();
using GetLibraryNameFunc = const char *(*)();
using GetPluginAuthorFunc = const char *(*)(); using GetPluginAuthorFunc = const char *(*)();
using GetPluginDescriptionFunc = const char *(*)(); using GetPluginDescriptionFunc = const char *(*)();
using GetCompatibleVersionFunc = const char *(*)(); using GetCompatibleVersionFunc = const char *(*)();
using SetImGuiContextFunc = void (*)(ImGuiContext *); using SetImGuiContextFunc = void (*)(ImGuiContext *);
using IsBuiltinPluginFunc = bool (*)();
using GetSubCommandsFunc = void* (*)(); using GetSubCommandsFunc = void* (*)();
using GetFeaturesFunc = void* (*)();
InitializePluginFunc initializePluginFunction = nullptr; InitializePluginFunc initializePluginFunction = nullptr;
InitializeLibraryFunc initializeLibraryFunction = nullptr;
GetPluginNameFunc getPluginNameFunction = nullptr; GetPluginNameFunc getPluginNameFunction = nullptr;
GetLibraryNameFunc getLibraryNameFunction = nullptr;
GetPluginAuthorFunc getPluginAuthorFunction = nullptr; GetPluginAuthorFunc getPluginAuthorFunction = nullptr;
GetPluginDescriptionFunc getPluginDescriptionFunction = nullptr; GetPluginDescriptionFunc getPluginDescriptionFunction = nullptr;
GetCompatibleVersionFunc getCompatibleVersionFunction = nullptr; GetCompatibleVersionFunc getCompatibleVersionFunction = nullptr;
SetImGuiContextFunc setImGuiContextFunction = nullptr; SetImGuiContextFunc setImGuiContextFunction = nullptr;
SetImGuiContextFunc setImGuiContextLibraryFunction = nullptr; IsBuiltinPluginFunc isBuiltinPluginFunction = nullptr;
GetSubCommandsFunc getSubCommandsFunction = nullptr; GetSubCommandsFunc getSubCommandsFunction = nullptr;
GetFeaturesFunc getFeaturesFunction = nullptr;
}; };
class Plugin { class Plugin {
public: public:
explicit Plugin(const std::fs::path &path); explicit Plugin(const std::fs::path &path);
explicit Plugin(const std::string &name, const PluginFunctions &functions); explicit Plugin(PluginFunctions functions);
Plugin(const Plugin &) = delete; Plugin(const Plugin &) = delete;
Plugin(Plugin &&other) noexcept; Plugin(Plugin &&other) noexcept;
~Plugin(); ~Plugin();
Plugin& operator=(const Plugin &) = delete;
Plugin& operator=(Plugin &&other) noexcept;
[[nodiscard]] bool initializePlugin() const; [[nodiscard]] bool initializePlugin() const;
[[nodiscard]] std::string getPluginName() const; [[nodiscard]] std::string getPluginName() const;
[[nodiscard]] std::string getPluginAuthor() const; [[nodiscard]] std::string getPluginAuthor() const;
[[nodiscard]] std::string getPluginDescription() const; [[nodiscard]] std::string getPluginDescription() const;
[[nodiscard]] std::string getCompatibleVersion() const; [[nodiscard]] std::string getCompatibleVersion() const;
void setImGuiContext(ImGuiContext *ctx) const; void setImGuiContext(ImGuiContext *ctx) const;
[[nodiscard]] bool isBuiltinPlugin() const;
[[nodiscard]] const std::fs::path &getPath() const; [[nodiscard]] const std::fs::path &getPath() const;
[[nodiscard]] bool isValid() const;
[[nodiscard]] bool isLoaded() const; [[nodiscard]] bool isLoaded() const;
[[nodiscard]] std::span<SubCommand> getSubCommands() const; [[nodiscard]] std::span<SubCommand> getSubCommands() const;
[[nodiscard]] std::span<Feature> getFeatures() const;
[[nodiscard]] bool isLibraryPlugin() const;
[[nodiscard]] bool wasAddedManually() const;
private: private:
uintptr_t m_handle = 0; uintptr_t m_handle = 0;
std::fs::path m_path; std::fs::path m_path;
mutable bool m_initialized = false; mutable bool m_initialized = false;
bool m_addedManually = false;
PluginFunctions m_functions = {}; PluginFunctions m_functions = {};
@@ -102,25 +79,14 @@ namespace hex {
public: public:
PluginManager() = delete; PluginManager() = delete;
static bool load();
static bool load(const std::fs::path &pluginFolder); static bool load(const std::fs::path &pluginFolder);
static void unload(); static void unload();
static void reload(); static void reload();
static void initializeNewPlugins();
static void addLoadPath(const std::fs::path &path);
static void addPlugin(const std::string &name, PluginFunctions functions); static void addPlugin(PluginFunctions functions);
static const std::list<Plugin>& getPlugins(); static std::vector<Plugin> &getPlugins();
static const std::vector<std::fs::path>& getPluginPaths(); static std::vector<std::fs::path> &getPluginPaths();
static const std::vector<std::fs::path>& getPluginLoadPaths();
static bool isPluginLoaded(const std::fs::path &path);
private:
static std::list<Plugin>& getPluginsMutable();
static AutoReset<std::vector<std::fs::path>> s_pluginPaths, s_pluginLoadPaths;
}; };
} }

View File

@@ -93,26 +93,30 @@ namespace hex {
* *
* @param handler The handler to register * @param handler The handler to register
*/ */
static void registerHandler(const Handler &handler); static void registerHandler(const Handler &handler) {
getHandlers().push_back(handler);
}
/** /**
* @brief Register a handler for storing and loading per-provider data from a project file * @brief Register a handler for storing and loading per-provider data from a project file
* *
* @param handler The handler to register * @param handler The handler to register
*/ */
static void registerPerProviderHandler(const ProviderHandler &handler); static void registerPerProviderHandler(const ProviderHandler &handler) {
getProviderHandlers().push_back(handler);
}
/** /**
* @brief Get the list of registered handlers * @brief Get the list of registered handlers
* @return List of registered handlers * @return List of registered handlers
*/ */
static const std::vector<Handler>& getHandlers(); static std::vector<Handler>& getHandlers();
/** /**
* @brief Get the list of registered per-provider handlers * @brief Get the list of registered per-provider handlers
* @return List of registered per-provider handlers * @return List of registered per-provider handlers
*/ */
static const std::vector<ProviderHandler>& getProviderHandlers(); static std::vector<ProviderHandler>& getProviderHandlers();
private: private:
ProjectFile() = default; ProjectFile() = default;

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include <hex.hpp> #include <hex.hpp>
#include <hex/api/localization_manager.hpp> #include <GLFW/glfw3.h>
#include <functional> #include <functional>
#include <memory> #include <memory>
@@ -9,8 +9,6 @@
#include <set> #include <set>
#include <string> #include <string>
#include <GLFW/glfw3.h>
struct ImGuiWindow; struct ImGuiWindow;
namespace hex { namespace hex {
@@ -140,7 +138,7 @@ namespace hex {
auto operator<=>(const Key &) const = default; auto operator<=>(const Key &) const = default;
[[nodiscard]] constexpr u32 getKeyCode() const { return m_key; } [[nodiscard]] constexpr u32 getKeyCode() const { return this->m_key; }
private: private:
u32 m_key = 0; u32 m_key = 0;
}; };
@@ -181,17 +179,17 @@ namespace hex {
} }
Shortcut &operator+=(const Key &other) { Shortcut &operator+=(const Key &other) {
m_keys.insert(other); this->m_keys.insert(other);
return *this; return *this;
} }
bool operator<(const Shortcut &other) const { bool operator<(const Shortcut &other) const {
return m_keys < other.m_keys; return this->m_keys < other.m_keys;
} }
bool operator==(const Shortcut &other) const { bool operator==(const Shortcut &other) const {
auto thisKeys = m_keys; auto thisKeys = this->m_keys;
auto otherKeys = other.m_keys; auto otherKeys = other.m_keys;
thisKeys.erase(CurrentView); thisKeys.erase(CurrentView);
@@ -203,7 +201,7 @@ namespace hex {
} }
bool isLocal() const { bool isLocal() const {
return m_keys.contains(CurrentView); return this->m_keys.contains(CurrentView);
} }
std::string toString() const { std::string toString() const {
@@ -223,7 +221,7 @@ namespace hex {
constexpr static auto Concatination = " + "; constexpr static auto Concatination = " + ";
auto keys = m_keys; auto keys = this->m_keys;
if (keys.erase(CTRL) > 0) { if (keys.erase(CTRL) > 0) {
result += CTRL_NAME; result += CTRL_NAME;
result += Concatination; result += Concatination;
@@ -369,7 +367,7 @@ namespace hex {
return result; return result;
} }
const std::set<Key>& getKeys() const { return m_keys; } const std::set<Key>& getKeys() const { return this->m_keys; }
private: private:
friend Shortcut operator+(const Key &lhs, const Key &rhs); friend Shortcut operator+(const Key &lhs, const Key &rhs);
@@ -393,7 +391,7 @@ namespace hex {
using Callback = std::function<void()>; using Callback = std::function<void()>;
struct ShortcutEntry { struct ShortcutEntry {
Shortcut shortcut; Shortcut shortcut;
UnlocalizedString unlocalizedName; std::string unlocalizedName;
Callback callback; Callback callback;
}; };
@@ -403,7 +401,7 @@ namespace hex {
* @param unlocalizedName The unlocalized name of the shortcut * @param unlocalizedName The unlocalized name of the shortcut
* @param callback The callback to call when the shortcut is triggered. * @param callback The callback to call when the shortcut is triggered.
*/ */
static void addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback); static void addGlobalShortcut(const Shortcut &shortcut, const std::string &unlocalizedName, const Callback &callback);
/** /**
* @brief Add a view-specific shortcut. View-specific shortcuts can only be triggered when the specified view is focused. * @brief Add a view-specific shortcut. View-specific shortcuts can only be triggered when the specified view is focused.
@@ -412,7 +410,7 @@ namespace hex {
* @param unlocalizedName The unlocalized name of the shortcut * @param unlocalizedName The unlocalized name of the shortcut
* @param callback The callback to call when the shortcut is triggered. * @param callback The callback to call when the shortcut is triggered.
*/ */
static void addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback); static void addShortcut(View *view, const Shortcut &shortcut, const std::string &unlocalizedName, const Callback &callback);
/** /**
@@ -425,7 +423,7 @@ namespace hex {
* @param focused Whether the current view is focused * @param focused Whether the current view is focused
* @param keyCode The key code of the key that was pressed * @param keyCode The key code of the key that was pressed
*/ */
static void process(const View *currentView, bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode); static void process(const std::unique_ptr<View> &currentView, bool ctrl, bool alt, bool shift, bool super, bool focused, u32 keyCode);
/** /**
* @brief Process a key event. This should be called from the main loop. * @brief Process a key event. This should be called from the main loop.
@@ -448,7 +446,7 @@ namespace hex {
[[nodiscard]] static std::optional<Shortcut> getPreviousShortcut(); [[nodiscard]] static std::optional<Shortcut> getPreviousShortcut();
[[nodiscard]] static std::vector<ShortcutEntry> getGlobalShortcuts(); [[nodiscard]] static std::vector<ShortcutEntry> getGlobalShortcuts();
[[nodiscard]] static std::vector<ShortcutEntry> getViewShortcuts(const View *view); [[nodiscard]] static std::vector<ShortcutEntry> getViewShortcuts(View *view);
[[nodiscard]] static bool updateShortcut(const Shortcut &oldShortcut, const Shortcut &newShortcut, View *view = nullptr); [[nodiscard]] static bool updateShortcut(const Shortcut &oldShortcut, const Shortcut &newShortcut, View *view = nullptr);
}; };

View File

@@ -1,15 +1,16 @@
#pragma once #pragma once
#include <hex.hpp> #include <hex.hpp>
#include <hex/api/localization_manager.hpp>
#include <cstdio> #include <cstdio>
#include <thread>
#include <functional> #include <functional>
#include <mutex> #include <mutex>
#include <memory> #include <memory>
#include <list> #include <list>
#include <condition_variable> #include <condition_variable>
#include <source_location>
#include <jthread.hpp>
namespace hex { namespace hex {
@@ -22,7 +23,7 @@ namespace hex {
class Task { class Task {
public: public:
Task() = default; Task() = default;
Task(UnlocalizedString unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function); Task(std::string unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function);
Task(const Task&) = delete; Task(const Task&) = delete;
Task(Task &&other) noexcept; Task(Task &&other) noexcept;
@@ -32,9 +33,7 @@ namespace hex {
* @brief Updates the current process value of the task * @brief Updates the current process value of the task
* @param value Current value * @param value Current value
*/ */
void update(u64 value); void update(u64 value = 0);
void update() const;
void increment();
/** /**
* @brief Sets the maximum value of the task * @brief Sets the maximum value of the task
@@ -65,7 +64,7 @@ namespace hex {
void clearException(); void clearException();
[[nodiscard]] std::string getExceptionMessage() const; [[nodiscard]] std::string getExceptionMessage() const;
[[nodiscard]] const UnlocalizedString &getUnlocalizedName(); [[nodiscard]] const std::string &getUnlocalizedName();
[[nodiscard]] u64 getValue() const; [[nodiscard]] u64 getValue() const;
[[nodiscard]] u64 getMaxValue() const; [[nodiscard]] u64 getMaxValue() const;
@@ -77,7 +76,7 @@ namespace hex {
private: private:
mutable std::mutex m_mutex; mutable std::mutex m_mutex;
UnlocalizedString m_unlocalizedName; std::string m_unlocalizedName;
std::atomic<u64> m_currValue = 0, m_maxValue = 0; std::atomic<u64> m_currValue = 0, m_maxValue = 0;
std::function<void()> m_interruptCallback; std::function<void()> m_interruptCallback;
std::function<void(Task &)> m_function; std::function<void(Task &)> m_function;
@@ -151,46 +150,22 @@ namespace hex {
*/ */
static void doLater(const std::function<void()> &function); static void doLater(const std::function<void()> &function);
/**
* @brief Creates a new synchronous task that will execute the given function at the start of the next frame
* @param function Function to be executed
* @param location Source location of the function call. This is used to make sure repeated calls to the function at the same location are only executed once
*/
static void doLaterOnce(const std::function<void()> &function, std::source_location location = std::source_location::current());
/** /**
* @brief Creates a callback that will be executed when all tasks are finished * @brief Creates a callback that will be executed when all tasks are finished
* @param function Function to be executed * @param function Function to be executed
*/ */
static void runWhenTasksFinished(const std::function<void()> &function); static void runWhenTasksFinished(const std::function<void()> &function);
/**
* @brief Sets the name of the current thread
* @param name Name of the thread
*/
static void setCurrentThreadName(const std::string &name);
/**
* @brief Gets the name of the current thread
* @return Name of the thread
*/
static std::string getCurrentThreadName();
/**
* @brief Cleans up finished tasks
*/
static void collectGarbage(); static void collectGarbage();
static Task& getCurrentTask();
static size_t getRunningTaskCount(); static size_t getRunningTaskCount();
static size_t getRunningBackgroundTaskCount(); static size_t getRunningBackgroundTaskCount();
static const std::list<std::shared_ptr<Task>>& getRunningTasks(); static std::list<std::shared_ptr<Task>> &getRunningTasks();
static void runDeferredCalls(); static void runDeferredCalls();
private: private:
static TaskHolder createTask(std::string name, u64 maxValue, bool background, std::function<void(Task &)> function); static void runner(const std::stop_token &stopToken);
}; };
} }

View File

@@ -78,8 +78,8 @@ namespace hex {
StyleMap styleMap; StyleMap styleMap;
}; };
static const std::map<std::string, ThemeHandler>& getThemeHandlers(); static std::map<std::string, ThemeHandler>& getThemeHandlers();
static const std::map<std::string, StyleHandler>& getStyleHandlers(); static std::map<std::string, StyleHandler>& getStyleHandlers();
private: private:
ThemeManager() = default; ThemeManager() = default;

View File

@@ -1,175 +0,0 @@
#pragma once
#include <hex.hpp>
#include <hex/api/localization_manager.hpp>
#include <string>
#include <list>
#include <variant>
#include <hex/ui/imgui_imhex_extensions.h>
namespace hex {
class TutorialManager {
public:
enum class Position : u8 {
None = 0,
Top = 1,
Bottom = 2,
Left = 4,
Right = 8
};
struct Tutorial {
Tutorial() = delete;
Tutorial(const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedDescription) :
m_unlocalizedName(unlocalizedName),
m_unlocalizedDescription(unlocalizedDescription) { }
struct Step {
explicit Step(Tutorial *parent) : m_parent(parent) { }
/**
* @brief Adds a highlighting with text to a specific element
* @param unlocalizedText Unlocalized text to display next to the highlighting
* @param ids ID of the element to highlight
* @return Current step
*/
Step& addHighlight(const UnlocalizedString &unlocalizedText, std::initializer_list<std::variant<Lang, std::string, int>> &&ids);
/**
* @brief Adds a highlighting to a specific element
* @param ids ID of the element to highlight
* @return Current step
*/
Step& addHighlight(std::initializer_list<std::variant<Lang, std::string, int>> &&ids);
/**
* @brief Sets the text that will be displayed in the tutorial message box
* @param unlocalizedTitle Title of the message box
* @param unlocalizedMessage Main message of the message box
* @param position Position of the message box
* @return Current step
*/
Step& setMessage(const UnlocalizedString &unlocalizedTitle, const UnlocalizedString &unlocalizedMessage, Position position = Position::None);
/**
* @brief Allows this step to be skipped by clicking on the advance button
* @return Current step
*/
Step& allowSkip();
Step& onAppear(std::function<void()> callback);
Step& onComplete(std::function<void()> callback);
/**
* @brief Checks if this step is the current step
* @return True if this step is the current step
*/
bool isCurrent() const;
/**
* @brief Completes this step if it is the current step
*/
void complete() const;
private:
struct Highlight {
UnlocalizedString unlocalizedText;
std::vector<std::variant<Lang, std::string, int>> highlightIds;
};
struct Message {
Position position;
UnlocalizedString unlocalizedTitle;
UnlocalizedString unlocalizedMessage;
bool allowSkip;
};
private:
void addHighlights() const;
void removeHighlights() const;
void advance(i32 steps = 1) const;
friend class TutorialManager;
Tutorial *m_parent;
std::vector<Highlight> m_highlights;
std::optional<Message> m_message;
std::function<void()> m_onAppear, m_onComplete;
};
Step& addStep();
const UnlocalizedString& getUnlocalizedName() const { return m_unlocalizedName; }
const UnlocalizedString& getUnlocalizedDescription() const { return m_unlocalizedDescription; }
private:
friend class TutorialManager;
void start();
UnlocalizedString m_unlocalizedName;
UnlocalizedString m_unlocalizedDescription;
std::list<Step> m_steps;
decltype(m_steps)::iterator m_currentStep, m_latestStep;
};
/**
* @brief Gets a list of all tutorials
* @return List of all tutorials
*/
static const std::map<std::string, Tutorial>& getTutorials();
/**
* @brief Gets the currently running tutorial
* @return Iterator pointing to the current tutorial
*/
static std::map<std::string, Tutorial>::iterator getCurrentTutorial();
/**
* @brief Creates a new tutorial that can be started later
* @param unlocalizedName Name of the tutorial
* @param unlocalizedDescription
* @return Reference to created tutorial
*/
static Tutorial& createTutorial(const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedDescription);
/**
* @brief Starts the tutorial with the given name
* @param unlocalizedName Name of tutorial to start
*/
static void startTutorial(const UnlocalizedString &unlocalizedName);
/**
* @brief Draws the tutorial
* @note This function should only be called by the main GUI
*/
static void drawTutorial();
/**
* @brief Resets the tutorial manager
*/
static void reset();
private:
TutorialManager() = delete;
static void drawHighlights();
static void drawMessageBox(std::optional<Tutorial::Step::Message> message);
};
inline TutorialManager::Position operator|(TutorialManager::Position a, TutorialManager::Position b) {
return static_cast<TutorialManager::Position>(static_cast<u8>(a) | static_cast<u8>(b));
}
inline TutorialManager::Position operator&(TutorialManager::Position a, TutorialManager::Position b) {
return static_cast<TutorialManager::Position>(static_cast<u8>(a) & static_cast<u8>(b));
}
}

View File

@@ -1,38 +0,0 @@
#pragma once
#include <wolv/io/fs.hpp>
#include <hex/helpers/auto_reset.hpp>
#include <map>
#include <string>
namespace hex {
class WorkspaceManager {
public:
struct Workspace {
std::string layout;
std::fs::path path;
};
static void createWorkspace(const std::string &name, const std::string &layout = "");
static void switchWorkspace(const std::string &name);
static void importFromFile(const std::fs::path &path);
static bool exportToFile(std::fs::path path = {}, std::string workspaceName = {});
static const auto& getWorkspaces() { return *s_workspaces; }
static const auto& getCurrentWorkspace() { return s_currentWorkspace; }
static void reset();
static void process();
private:
WorkspaceManager() = default;
static AutoReset<std::map<std::string, Workspace>> s_workspaces;
static decltype(s_workspaces)::Type::iterator s_currentWorkspace, s_previousWorkspace;
};
}

View File

@@ -1,7 +1,5 @@
#pragma once #pragma once
#include <hex.hpp> #include <hex.hpp>
#include <hex/api/localization_manager.hpp>
#include <string> #include <string>
#include <string_view> #include <string_view>
@@ -25,32 +23,32 @@ namespace hex::dp {
Out Out
}; };
Attribute(IOType ioType, Type type, UnlocalizedString unlocalizedName); Attribute(IOType ioType, Type type, std::string unlocalizedName);
~Attribute(); ~Attribute();
[[nodiscard]] int getId() const { return m_id; } [[nodiscard]] int getId() const { return this->m_id; }
void setId(int id) { m_id = id; } void setId(int id) { this->m_id = id; }
[[nodiscard]] IOType getIOType() const { return m_ioType; } [[nodiscard]] IOType getIOType() const { return this->m_ioType; }
[[nodiscard]] Type getType() const { return m_type; } [[nodiscard]] Type getType() const { return this->m_type; }
[[nodiscard]] const UnlocalizedString &getUnlocalizedName() const { return m_unlocalizedName; } [[nodiscard]] const std::string &getUnlocalizedName() const { return this->m_unlocalizedName; }
void addConnectedAttribute(int linkId, Attribute *to) { m_connectedAttributes.insert({ linkId, to }); } void addConnectedAttribute(int linkId, Attribute *to) { this->m_connectedAttributes.insert({ linkId, to }); }
void removeConnectedAttribute(int linkId) { m_connectedAttributes.erase(linkId); } void removeConnectedAttribute(int linkId) { this->m_connectedAttributes.erase(linkId); }
[[nodiscard]] std::map<int, Attribute *> &getConnectedAttributes() { return m_connectedAttributes; } [[nodiscard]] std::map<int, Attribute *> &getConnectedAttributes() { return this->m_connectedAttributes; }
[[nodiscard]] Node *getParentNode() const { return m_parentNode; } [[nodiscard]] Node *getParentNode() const { return this->m_parentNode; }
[[nodiscard]] std::vector<u8>& getOutputData() { [[nodiscard]] std::vector<u8>& getOutputData() {
if (!m_outputData.empty()) if (!this->m_outputData.empty())
return m_outputData; return this->m_outputData;
else else
return m_defaultData; return this->m_defaultData;
} }
void clearOutputData() { m_outputData.clear(); } void clearOutputData() { this->m_outputData.clear(); }
[[nodiscard]] std::vector<u8>& getDefaultData() { return m_defaultData; } [[nodiscard]] std::vector<u8>& getDefaultData() { return this->m_defaultData; }
static void setIdCounter(int id); static void setIdCounter(int id);
@@ -58,7 +56,7 @@ namespace hex::dp {
int m_id; int m_id;
IOType m_ioType; IOType m_ioType;
Type m_type; Type m_type;
UnlocalizedString m_unlocalizedName; std::string m_unlocalizedName;
std::map<int, Attribute *> m_connectedAttributes; std::map<int, Attribute *> m_connectedAttributes;
Node *m_parentNode = nullptr; Node *m_parentNode = nullptr;
@@ -66,7 +64,7 @@ namespace hex::dp {
std::vector<u8> m_defaultData; std::vector<u8> m_defaultData;
friend class Node; friend class Node;
void setParentNode(Node *node) { m_parentNode = node; } void setParentNode(Node *node) { this->m_parentNode = node; }
static int s_idCounter; static int s_idCounter;
}; };

View File

@@ -6,11 +6,11 @@ namespace hex::dp {
public: public:
Link(int from, int to); Link(int from, int to);
[[nodiscard]] int getId() const { return m_id; } [[nodiscard]] int getId() const { return this->m_id; }
void setId(int id) { m_id = id; } void setId(int id) { this->m_id = id; }
[[nodiscard]] int getFromId() const { return m_from; } [[nodiscard]] int getFromId() const { return this->m_from; }
[[nodiscard]] int getToId() const { return m_to; } [[nodiscard]] int getToId() const { return this->m_to; }
static void setIdCounter(int id); static void setIdCounter(int id);

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include <hex.hpp> #include <hex.hpp>
#include <hex/api/localization_manager.hpp>
#include <hex/helpers/intrinsics.hpp> #include <hex/helpers/intrinsics.hpp>
#include <hex/data_processor/attribute.hpp> #include <hex/data_processor/attribute.hpp>
@@ -22,24 +21,24 @@ namespace hex::dp {
class Node { class Node {
public: public:
Node(UnlocalizedString unlocalizedTitle, std::vector<Attribute> attributes); Node(std::string unlocalizedTitle, std::vector<Attribute> attributes);
virtual ~Node() = default; virtual ~Node() = default;
[[nodiscard]] int getId() const { return m_id; } [[nodiscard]] int getId() const { return this->m_id; }
void setId(int id) { m_id = id; } void setId(int id) { this->m_id = id; }
[[nodiscard]] const UnlocalizedString &getUnlocalizedName() const { return m_unlocalizedName; } [[nodiscard]] const std::string &getUnlocalizedName() const { return this->m_unlocalizedName; }
void setUnlocalizedName(const UnlocalizedString &unlocalizedName) { m_unlocalizedName = unlocalizedName; } void setUnlocalizedName(const std::string &unlocalizedName) { this->m_unlocalizedName = unlocalizedName; }
[[nodiscard]] const UnlocalizedString &getUnlocalizedTitle() const { return m_unlocalizedTitle; } [[nodiscard]] const std::string &getUnlocalizedTitle() const { return this->m_unlocalizedTitle; }
void setUnlocalizedTitle(std::string title) { m_unlocalizedTitle = std::move(title); } void setUnlocalizedTitle(std::string title) { this->m_unlocalizedTitle = std::move(title); }
[[nodiscard]] std::vector<Attribute> &getAttributes() { return m_attributes; } [[nodiscard]] std::vector<Attribute> &getAttributes() { return this->m_attributes; }
[[nodiscard]] const std::vector<Attribute> &getAttributes() const { return m_attributes; } [[nodiscard]] const std::vector<Attribute> &getAttributes() const { return this->m_attributes; }
void setCurrentOverlay(prv::Overlay *overlay) { void setCurrentOverlay(prv::Overlay *overlay) {
m_overlay = overlay; this->m_overlay = overlay;
} }
virtual void drawNode() { } virtual void drawNode() { }
@@ -54,20 +53,20 @@ namespace hex::dp {
}; };
void resetOutputData() { void resetOutputData() {
for (auto &attribute : m_attributes) for (auto &attribute : this->m_attributes)
attribute.clearOutputData(); attribute.clearOutputData();
} }
void resetProcessedInputs() { void resetProcessedInputs() {
m_processedInputs.clear(); this->m_processedInputs.clear();
} }
void setPosition(ImVec2 pos) { void setPosition(ImVec2 pos) {
m_position = pos; this->m_position = pos;
} }
[[nodiscard]] ImVec2 getPosition() const { [[nodiscard]] ImVec2 getPosition() const {
return m_position; return this->m_position;
} }
static void setIdCounter(int id); static void setIdCounter(int id);
@@ -82,7 +81,7 @@ namespace hex::dp {
private: private:
int m_id; int m_id;
UnlocalizedString m_unlocalizedTitle, m_unlocalizedName; std::string m_unlocalizedTitle, m_unlocalizedName;
std::vector<Attribute> m_attributes; std::vector<Attribute> m_attributes;
std::set<u32> m_processedInputs; std::set<u32> m_processedInputs;
prv::Overlay *m_overlay = nullptr; prv::Overlay *m_overlay = nullptr;
@@ -107,13 +106,13 @@ namespace hex::dp {
} }
void markInputProcessed(u32 index) { void markInputProcessed(u32 index) {
const auto &[iter, inserted] = m_processedInputs.insert(index); const auto &[iter, inserted] = this->m_processedInputs.insert(index);
if (!inserted) if (!inserted)
throwNodeError("Recursion detected!"); throwNodeError("Recursion detected!");
} }
void unmarkInputProcessed(u32 index) { void unmarkInputProcessed(u32 index) {
m_processedInputs.erase(index); this->m_processedInputs.erase(index);
} }
protected: protected:
@@ -124,9 +123,9 @@ namespace hex::dp {
void setOverlayData(u64 address, const std::vector<u8> &data); void setOverlayData(u64 address, const std::vector<u8> &data);
void setAttributes(std::vector<Attribute> attributes) { void setAttributes(std::vector<Attribute> attributes) {
m_attributes = std::move(attributes); this->m_attributes = std::move(attributes);
for (auto &attr : m_attributes) for (auto &attr : this->m_attributes)
attr.setParentNode(this); attr.setParentNode(this);
} }
}; };

View File

@@ -1,77 +0,0 @@
#pragma once
#include <hex/api/event_manager.hpp>
#include <hex/api/imhex_api.hpp>
namespace hex {
namespace impl {
class AutoResetBase {
public:
virtual ~AutoResetBase() = default;
virtual void reset() = 0;
};
}
template<typename T>
class AutoReset : public impl::AutoResetBase {
public:
using Type = T;
AutoReset() {
ImHexApi::System::impl::addAutoResetObject(this);
}
T* operator->() {
return &m_value;
}
const T* operator->() const {
return &m_value;
}
T& operator*() {
return m_value;
}
const T& operator*() const {
return m_value;
}
operator T&() {
return m_value;
}
operator const T&() const {
return m_value;
}
T& operator=(const T &value) {
m_value = value;
return m_value;
}
T& operator=(T &&value) noexcept {
m_value = std::move(value);
return m_value;
}
void reset() override {
if constexpr (requires { m_value.reset(); }) {
m_value.reset();
} else if constexpr (requires { m_value.clear(); }) {
m_value.clear();
} else if constexpr (requires(T t) { t = nullptr; }) {
m_value = nullptr;
} else {
m_value = { };
}
}
private:
T m_value;
};
}

View File

@@ -17,13 +17,13 @@ namespace hex {
BinaryPattern() = default; BinaryPattern() = default;
explicit BinaryPattern(const std::string &pattern) : m_patterns(parseBinaryPatternString(pattern)) { } explicit BinaryPattern(const std::string &pattern) : m_patterns(parseBinaryPatternString(pattern)) { }
[[nodiscard]] bool isValid() const { return !m_patterns.empty(); } [[nodiscard]] bool isValid() const { return !this->m_patterns.empty(); }
[[nodiscard]] bool matches(const std::vector<u8> &bytes) const { [[nodiscard]] bool matches(const std::vector<u8> &bytes) const {
if (bytes.size() < m_patterns.size()) if (bytes.size() < this->m_patterns.size())
return false; return false;
for (u32 i = 0; i < m_patterns.size(); i++) { for (u32 i = 0; i < this->m_patterns.size(); i++) {
if (!this->matchesByte(bytes[i], i)) if (!this->matchesByte(bytes[i], i))
return false; return false;
} }
@@ -32,13 +32,13 @@ namespace hex {
} }
[[nodiscard]] bool matchesByte(u8 byte, u32 offset) const { [[nodiscard]] bool matchesByte(u8 byte, u32 offset) const {
const auto &pattern = m_patterns[offset]; const auto &pattern = this->m_patterns[offset];
return (byte & pattern.mask) == pattern.value; return (byte & pattern.mask) == pattern.value;
} }
[[nodiscard]] u64 getSize() const { [[nodiscard]] size_t getSize() const {
return m_patterns.size(); return this->m_patterns.size();
} }
private: private:

View File

@@ -29,9 +29,9 @@ namespace hex::dbg {
if constexpr (std::same_as<Type, bool>) { if constexpr (std::same_as<Type, bool>) {
ImGui::Checkbox(name.data(), &variable); ImGui::Checkbox(name.data(), &variable);
} else if constexpr (std::integral<Type> || std::floating_point<Type>) { } else if constexpr (std::integral<Type> || std::floating_point<Type>) {
ImGui::DragScalar(name.data(), ImGuiExt::getImGuiDataType<Type>(), &variable); ImGui::InputScalar(name.data(), ImGuiExt::getImGuiDataType<Type>(), &variable);
} else if constexpr (std::same_as<Type, ImVec2>) { } else if constexpr (std::same_as<Type, ImVec2>) {
ImGui::DragFloat2(name.data(), &variable.x); ImGui::InputFloat2(name.data(), &variable.x);
} else if constexpr (std::same_as<Type, std::string>) { } else if constexpr (std::same_as<Type, std::string>) {
ImGui::InputText(name.data(), variable); ImGui::InputText(name.data(), variable);
} else if constexpr (std::same_as<Type, ImColor>) { } else if constexpr (std::same_as<Type, ImColor>) {

View File

@@ -2,11 +2,9 @@
#include <hex.hpp> #include <hex.hpp>
#include <array>
#include <capstone/capstone.h> #include <capstone/capstone.h>
namespace hex::plugin::disasm { namespace hex {
enum class Architecture : i32 enum class Architecture : i32
{ {

View File

@@ -28,15 +28,14 @@ namespace hex {
EncodingFile& operator=(EncodingFile &&other) noexcept; EncodingFile& operator=(EncodingFile &&other) noexcept;
[[nodiscard]] std::pair<std::string_view, size_t> getEncodingFor(std::span<u8> buffer) const; [[nodiscard]] std::pair<std::string_view, size_t> getEncodingFor(std::span<u8> buffer) const;
[[nodiscard]] u64 getEncodingLengthFor(std::span<u8> buffer) const; [[nodiscard]] size_t getEncodingLengthFor(std::span<u8> buffer) const;
[[nodiscard]] u64 getShortestSequence() const { return m_shortestSequence; } [[nodiscard]] size_t getLongestSequence() const { return this->m_longestSequence; }
[[nodiscard]] u64 getLongestSequence() const { return m_longestSequence; }
[[nodiscard]] bool valid() const { return m_valid; } [[nodiscard]] bool valid() const { return this->m_valid; }
[[nodiscard]] const std::string& getTableContent() const { return m_tableContent; } [[nodiscard]] const std::string& getTableContent() const { return this->m_tableContent; }
[[nodiscard]] const std::string& getName() const { return m_name; } [[nodiscard]] const std::string& getName() const { return this->m_name; }
private: private:
void parse(const std::string &content); void parse(const std::string &content);
@@ -46,9 +45,7 @@ namespace hex {
std::string m_name; std::string m_name;
std::string m_tableContent; std::string m_tableContent;
std::unique_ptr<std::map<size_t, std::map<std::vector<u8>, std::string>>> m_mapping; std::unique_ptr<std::map<size_t, std::map<std::vector<u8>, std::string>>> m_mapping;
size_t m_longestSequence = 0;
u64 m_shortestSequence = std::numeric_limits<u64>::max();
u64 m_longestSequence = std::numeric_limits<u64>::min();
}; };
} }

View File

@@ -37,9 +37,7 @@ namespace hex::fs {
Magic, Magic,
Plugins, Plugins,
Yara, Yara,
YaraAdvancedAnalysis,
Config, Config,
Backups,
Resources, Resources,
Constants, Constants,
Encodings, Encodings,
@@ -51,7 +49,6 @@ namespace hex::fs {
Libraries, Libraries,
Nodes, Nodes,
Layouts, Layouts,
Workspaces,
END END
}; };

View File

@@ -31,7 +31,7 @@ namespace hex {
explicit ResultBase(u32 statusCode) : m_statusCode(statusCode), m_valid(true) { } explicit ResultBase(u32 statusCode) : m_statusCode(statusCode), m_valid(true) { }
[[nodiscard]] u32 getStatusCode() const { [[nodiscard]] u32 getStatusCode() const {
return m_statusCode; return this->m_statusCode;
} }
[[nodiscard]] bool isSuccess() const { [[nodiscard]] bool isSuccess() const {
@@ -39,7 +39,7 @@ namespace hex {
} }
[[nodiscard]] bool isValid() const { [[nodiscard]] bool isValid() const {
return m_valid; return this->m_valid;
} }
private: private:
@@ -55,7 +55,7 @@ namespace hex {
[[nodiscard]] [[nodiscard]]
const T& getData() const { const T& getData() const {
return m_data; return this->m_data;
} }
private: private:
@@ -76,31 +76,31 @@ namespace hex {
static void setProxyUrl(std::string proxy); static void setProxyUrl(std::string proxy);
void setMethod(std::string method) { void setMethod(std::string method) {
m_method = std::move(method); this->m_method = std::move(method);
} }
void setUrl(std::string url) { void setUrl(std::string url) {
m_url = std::move(url); this->m_url = std::move(url);
} }
void addHeader(std::string key, std::string value) { void addHeader(std::string key, std::string value) {
m_headers[std::move(key)] = std::move(value); this->m_headers[std::move(key)] = std::move(value);
} }
void setBody(std::string body) { void setBody(std::string body) {
m_body = std::move(body); this->m_body = std::move(body);
} }
void setTimeout(u32 timeout) { void setTimeout(u32 timeout) {
m_timeout = timeout; this->m_timeout = timeout;
} }
float getProgress() const { float getProgress() const {
return m_progress; return this->m_progress;
} }
void cancel() { void cancel() {
m_canceled = true; this->m_canceled = true;
} }
template<typename T = std::string> template<typename T = std::string>

View File

@@ -1,76 +1,72 @@
#pragma once #pragma once
#if defined(OS_WEB) #include <future>
#include <future> #include <emscripten/fetch.h>
#include <emscripten/fetch.h> namespace hex {
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::downloadFile(const std::fs::path &path) {
return std::async(std::launch::async, [this, path] {
std::vector<u8> response;
namespace hex { // Execute the request
template<typename T> auto result = this->executeImpl<T>(response);
std::future<HttpRequest::Result<T>> HttpRequest::downloadFile(const std::fs::path &path) {
return std::async(std::launch::async, [this, path] {
std::vector<u8> response;
// Execute the request // Write the result to the file
auto result = this->executeImpl<T>(response); wolv::io::File file(path, wolv::io::File::Mode::Create);
file.writeBuffer(reinterpret_cast<const u8*>(result.getData().data()), result.getData().size());
// Write the result to the file
wolv::io::File file(path, wolv::io::File::Mode::Create);
file.writeBuffer(reinterpret_cast<const u8*>(result.getData().data()), result.getData().size());
return result;
});
}
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(const std::fs::path &path, const std::string &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) {
hex::unused(data, mimeName, fileName);
throw std::logic_error("Not implemented");
}
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::execute() {
return std::async(std::launch::async, [this] {
std::vector<u8> responseData;
return this->executeImpl<T>(responseData);
});
}
template<typename T>
HttpRequest::Result<T> HttpRequest::executeImpl(std::vector<u8> &data) {
strcpy(m_attr.requestMethod, m_method.c_str());
m_attr.attributes = EMSCRIPTEN_FETCH_SYNCHRONOUS | EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
if (!m_body.empty()) {
m_attr.requestData = m_body.c_str();
m_attr.requestDataSize = m_body.size();
}
std::vector<const char*> headers;
for (auto it = m_headers.begin(); it != m_headers.end(); it++) {
headers.push_back(it->first.c_str());
headers.push_back(it->second.c_str());
}
headers.push_back(nullptr);
m_attr.requestHeaders = headers.data();
// Send request
emscripten_fetch_t* fetch = emscripten_fetch(&m_attr, m_url.c_str());
data.resize(fetch->numBytes);
std::copy(fetch->data, fetch->data + fetch->numBytes, data.begin());
return Result<T>(fetch->status, { data.begin(), data.end() });
}
return result;
});
} }
#endif template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(const std::fs::path &path, const std::string &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) {
hex::unused(data, mimeName, fileName);
throw std::logic_error("Not implemented");
}
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::execute() {
return std::async(std::launch::async, [this] {
std::vector<u8> responseData;
return this->executeImpl<T>(responseData);
});
}
template<typename T>
HttpRequest::Result<T> HttpRequest::executeImpl(std::vector<u8> &data) {
strcpy(this->m_attr.requestMethod, this->m_method.c_str());
this->m_attr.attributes = EMSCRIPTEN_FETCH_SYNCHRONOUS | EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
if (!this->m_body.empty()) {
this->m_attr.requestData = this->m_body.c_str();
this->m_attr.requestDataSize = this->m_body.size();
}
std::vector<const char*> headers;
for (auto it = this->m_headers.begin(); it != this->m_headers.end(); it++) {
headers.push_back(it->first.c_str());
headers.push_back(it->second.c_str());
}
headers.push_back(nullptr);
this->m_attr.requestHeaders = headers.data();
// Send request
emscripten_fetch_t* fetch = emscripten_fetch(&this->m_attr, this->m_url.c_str());
data.resize(fetch->numBytes);
std::copy(fetch->data, fetch->data + fetch->numBytes, data.begin());
return Result<T>(fetch->status, { data.begin(), data.end() });
}
}

View File

@@ -1,149 +1,145 @@
#pragma once #pragma once
#if !defined(OS_WEB) #include <string>
#include <future>
#include <string> #include <curl/curl.h>
#include <future>
#include <curl/curl.h> #include <hex/helpers/logger.hpp>
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/logger.hpp> #include <wolv/utils/string.hpp>
#include <hex/helpers/fmt.hpp>
#include <wolv/utils/string.hpp> namespace hex {
namespace hex { template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::downloadFile(const std::fs::path &path) {
return std::async(std::launch::async, [this, path] {
std::vector<u8> response;
template<typename T> wolv::io::File file(path, wolv::io::File::Mode::Create);
std::future<HttpRequest::Result<T>> HttpRequest::downloadFile(const std::fs::path &path) { curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToFile);
return std::async(std::launch::async, [this, path] { curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &file);
std::vector<u8> response;
wolv::io::File file(path, wolv::io::File::Mode::Create);
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToFile);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &file);
return this->executeImpl<T>(response);
});
}
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(const std::fs::path &path, const std::string &mimeName) {
return std::async(std::launch::async, [this, path, mimeName]{
auto fileName = wolv::util::toUTF8String(path.filename());
curl_mime *mime = curl_mime_init(m_curl);
curl_mimepart *part = curl_mime_addpart(mime);
wolv::io::File file(path, wolv::io::File::Mode::Read);
curl_mime_data_cb(part, file.getSize(),
[](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
auto handle = static_cast<FILE*>(arg);
return fread(buffer, size, nitems, handle);
},
[](void *arg, curl_off_t offset, int origin) -> int {
auto handle = static_cast<FILE*>(arg);
if (fseek(handle, offset, origin) != 0)
return CURL_SEEKFUNC_CANTSEEK;
else
return CURL_SEEKFUNC_OK;
},
[](void *arg) {
auto handle = static_cast<FILE*>(arg);
fclose(handle);
},
file.getHandle());
curl_mime_filename(part, fileName.c_str());
curl_mime_name(part, mimeName.c_str());
curl_easy_setopt(m_curl, CURLOPT_MIMEPOST, mime);
std::vector<u8> responseData;
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &responseData);
return this->executeImpl<T>(responseData);
});
}
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(std::vector<u8> data, const std::string &mimeName, const std::fs::path &fileName) {
return std::async(std::launch::async, [this, data = std::move(data), mimeName, fileName]{
curl_mime *mime = curl_mime_init(m_curl);
curl_mimepart *part = curl_mime_addpart(mime);
curl_mime_data(part, reinterpret_cast<const char *>(data.data()), data.size());
auto fileNameStr = wolv::util::toUTF8String(fileName.filename());
curl_mime_filename(part, fileNameStr.c_str());
curl_mime_name(part, mimeName.c_str());
curl_easy_setopt(m_curl, CURLOPT_MIMEPOST, mime);
std::vector<u8> responseData;
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &responseData);
return this->executeImpl<T>(responseData);
});
}
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::execute() {
return std::async(std::launch::async, [this] {
std::vector<u8> responseData;
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &responseData);
return this->executeImpl<T>(responseData);
});
}
template<typename T>
HttpRequest::Result<T> HttpRequest::executeImpl(std::vector<u8> &data) {
curl_easy_setopt(m_curl, CURLOPT_URL, m_url.c_str());
curl_easy_setopt(m_curl, CURLOPT_CUSTOMREQUEST, m_method.c_str());
setDefaultConfig();
if (!m_body.empty()) {
curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, m_body.c_str());
}
curl_slist *headers = nullptr;
headers = curl_slist_append(headers, "Cache-Control: no-cache");
ON_SCOPE_EXIT { curl_slist_free_all(headers); };
for (auto &[key, value] : m_headers) {
std::string header = hex::format("{}: {}", key, value);
headers = curl_slist_append(headers, header.c_str());
}
curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headers);
{
std::scoped_lock lock(m_transmissionMutex);
auto result = curl_easy_perform(m_curl);
if (result != CURLE_OK){
char *url = nullptr;
curl_easy_getinfo(m_curl, CURLINFO_EFFECTIVE_URL, &url);
log::error("Http request '{0} {1}' failed with error {2}: '{3}'", m_method, url, u32(result), curl_easy_strerror(result));
checkProxyErrors();
return { };
}
}
long statusCode = 0;
curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &statusCode);
return Result<T>(statusCode, { data.begin(), data.end() });
}
return this->executeImpl<T>(response);
});
} }
#endif template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(const std::fs::path &path, const std::string &mimeName) {
return std::async(std::launch::async, [this, path, mimeName]{
auto fileName = wolv::util::toUTF8String(path.filename());
curl_mime *mime = curl_mime_init(this->m_curl);
curl_mimepart *part = curl_mime_addpart(mime);
wolv::io::File file(path, wolv::io::File::Mode::Read);
curl_mime_data_cb(part, file.getSize(),
[](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
auto handle = static_cast<FILE*>(arg);
return fread(buffer, size, nitems, handle);
},
[](void *arg, curl_off_t offset, int origin) -> int {
auto handle = static_cast<FILE*>(arg);
if (fseek(handle, offset, origin) != 0)
return CURL_SEEKFUNC_CANTSEEK;
else
return CURL_SEEKFUNC_OK;
},
[](void *arg) {
auto handle = static_cast<FILE*>(arg);
fclose(handle);
},
file.getHandle());
curl_mime_filename(part, fileName.c_str());
curl_mime_name(part, mimeName.c_str());
curl_easy_setopt(this->m_curl, CURLOPT_MIMEPOST, mime);
std::vector<u8> responseData;
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
return this->executeImpl<T>(responseData);
});
}
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(std::vector<u8> data, const std::string &mimeName, const std::fs::path &fileName) {
return std::async(std::launch::async, [this, data = std::move(data), mimeName, fileName]{
curl_mime *mime = curl_mime_init(this->m_curl);
curl_mimepart *part = curl_mime_addpart(mime);
curl_mime_data(part, reinterpret_cast<const char *>(data.data()), data.size());
auto fileNameStr = wolv::util::toUTF8String(fileName.filename());
curl_mime_filename(part, fileNameStr.c_str());
curl_mime_name(part, mimeName.c_str());
curl_easy_setopt(this->m_curl, CURLOPT_MIMEPOST, mime);
std::vector<u8> responseData;
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
return this->executeImpl<T>(responseData);
});
}
template<typename T>
std::future<HttpRequest::Result<T>> HttpRequest::execute() {
return std::async(std::launch::async, [this] {
std::vector<u8> responseData;
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
return this->executeImpl<T>(responseData);
});
}
template<typename T>
HttpRequest::Result<T> HttpRequest::executeImpl(std::vector<u8> &data) {
curl_easy_setopt(this->m_curl, CURLOPT_URL, this->m_url.c_str());
curl_easy_setopt(this->m_curl, CURLOPT_CUSTOMREQUEST, this->m_method.c_str());
setDefaultConfig();
if (!this->m_body.empty()) {
curl_easy_setopt(this->m_curl, CURLOPT_POSTFIELDS, this->m_body.c_str());
}
curl_slist *headers = nullptr;
headers = curl_slist_append(headers, "Cache-Control: no-cache");
ON_SCOPE_EXIT { curl_slist_free_all(headers); };
for (auto &[key, value] : this->m_headers) {
std::string header = hex::format("{}: {}", key, value);
headers = curl_slist_append(headers, header.c_str());
}
curl_easy_setopt(this->m_curl, CURLOPT_HTTPHEADER, headers);
{
std::scoped_lock lock(this->m_transmissionMutex);
auto result = curl_easy_perform(this->m_curl);
if (result != CURLE_OK){
char *url = nullptr;
curl_easy_getinfo(this->m_curl, CURLINFO_EFFECTIVE_URL, &url);
log::error("Http request '{0} {1}' failed with error {2}: '{3}'", this->m_method, url, u32(result), curl_easy_strerror(result));
checkProxyErrors();
return { };
}
}
long statusCode = 0;
curl_easy_getinfo(this->m_curl, CURLINFO_RESPONSE_CODE, &statusCode);
return Result<T>(statusCode, { data.begin(), data.end() });
}
}

View File

@@ -19,8 +19,7 @@ namespace hex::log {
[[maybe_unused]] void redirectToFile(); [[maybe_unused]] void redirectToFile();
[[maybe_unused]] void enableColorPrinting(); [[maybe_unused]] void enableColorPrinting();
[[nodiscard]] std::recursive_mutex& getLoggerMutex(); extern std::mutex g_loggerMutex;
[[nodiscard]] bool isLoggingSuspended();
struct LogEntry { struct LogEntry {
std::string project; std::string project;
@@ -29,88 +28,65 @@ namespace hex::log {
}; };
std::vector<LogEntry>& getLogEntries(); std::vector<LogEntry>& getLogEntries();
void addLogEntry(std::string_view project, std::string_view level, std::string_view message);
[[maybe_unused]] void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level, const char *projectName); [[maybe_unused]] void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level);
[[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto && ... args) { [[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto && ... args) {
if (isLoggingSuspended()) [[unlikely]] std::scoped_lock lock(impl::g_loggerMutex);
return;
std::scoped_lock lock(getLoggerMutex()); auto dest = impl::getDestination();
printPrefix(dest, ts, level);
auto dest = getDestination(); auto message = fmt::format(fmt::runtime(fmt), args...);
try { fmt::print(dest, "{}\n", message);
printPrefix(dest, ts, level, IMHEX_PROJECT_NAME); fflush(dest);
auto message = fmt::format(fmt::runtime(fmt), args...);
fmt::print(dest, "{}\n", message);
fflush(dest);
addLogEntry(IMHEX_PROJECT_NAME, level, std::move(message));
} catch (const std::exception&) { }
}
namespace color {
fmt::color debug();
fmt::color info();
fmt::color warn();
fmt::color error();
fmt::color fatal();
impl::getLogEntries().push_back({ IMHEX_PROJECT_NAME, level, std::move(message) });
} }
} }
void suspendLogging();
void resumeLogging();
[[maybe_unused]] void debug(const std::string &fmt, auto && ... args) { [[maybe_unused]] void debug(const std::string &fmt, auto && ... args) {
#if defined(DEBUG) #if defined(DEBUG)
hex::log::impl::print(fg(impl::color::debug()) | fmt::emphasis::bold, "[DEBUG]", fmt, args...); hex::log::impl::print(fg(fmt::color::light_green) | fmt::emphasis::bold, "[DEBUG]", fmt, args...);
#else #else
impl::addLogEntry(IMHEX_PROJECT_NAME, "[DEBUG]", fmt::format(fmt::runtime(fmt), args...)); impl::getLogEntries().push_back({ IMHEX_PROJECT_NAME, "[DEBUG]", fmt::format(fmt::runtime(fmt), args...) });
#endif #endif
} }
[[maybe_unused]] void info(const std::string &fmt, auto && ... args) { [[maybe_unused]] void info(const std::string &fmt, auto && ... args) {
hex::log::impl::print(fg(impl::color::info()) | fmt::emphasis::bold, "[INFO] ", fmt, args...); hex::log::impl::print(fg(fmt::color::cadet_blue) | fmt::emphasis::bold, "[INFO] ", fmt, args...);
} }
[[maybe_unused]] void warn(const std::string &fmt, auto && ... args) { [[maybe_unused]] void warn(const std::string &fmt, auto && ... args) {
hex::log::impl::print(fg(impl::color::warn()) | fmt::emphasis::bold, "[WARN] ", fmt, args...); hex::log::impl::print(fg(fmt::color::orange) | fmt::emphasis::bold, "[WARN] ", fmt, args...);
} }
[[maybe_unused]] void error(const std::string &fmt, auto && ... args) { [[maybe_unused]] void error(const std::string &fmt, auto && ... args) {
hex::log::impl::print(fg(impl::color::error()) | fmt::emphasis::bold, "[ERROR]", fmt, args...); hex::log::impl::print(fg(fmt::color::red) | fmt::emphasis::bold, "[ERROR]", fmt, args...);
} }
[[maybe_unused]] void fatal(const std::string &fmt, auto && ... args) { [[maybe_unused]] void fatal(const std::string &fmt, auto && ... args) {
hex::log::impl::print(fg(impl::color::fatal()) | fmt::emphasis::bold, "[FATAL]", fmt, args...); hex::log::impl::print(fg(fmt::color::purple) | fmt::emphasis::bold, "[FATAL]", fmt, args...);
} }
[[maybe_unused]] void print(const std::string &fmt, auto && ... args) { [[maybe_unused]] void print(const std::string &fmt, auto && ... args) {
std::scoped_lock lock(impl::getLoggerMutex()); std::scoped_lock lock(impl::g_loggerMutex);
try { auto dest = impl::getDestination();
auto dest = impl::getDestination(); auto message = fmt::format(fmt::runtime(fmt), args...);
auto message = fmt::format(fmt::runtime(fmt), args...); fmt::print(dest, "{}", message);
fmt::print(dest, "{}", message); fflush(dest);
fflush(dest);
} catch (const std::exception&) { }
} }
[[maybe_unused]] void println(const std::string &fmt, auto && ... args) { [[maybe_unused]] void println(const std::string &fmt, auto && ... args) {
std::scoped_lock lock(impl::getLoggerMutex()); std::scoped_lock lock(impl::g_loggerMutex);
try { auto dest = impl::getDestination();
auto dest = impl::getDestination(); auto message = fmt::format(fmt::runtime(fmt), args...);
auto message = fmt::format(fmt::runtime(fmt), args...); fmt::print(dest, "{}\n", message);
fmt::print(dest, "{}\n", message); fflush(dest);
fflush(dest);
} catch (const std::exception&) { }
} }
} }

View File

@@ -16,14 +16,10 @@ namespace hex::magic {
using namespace hex::literals; using namespace hex::literals;
bool compile(); bool compile();
std::string getDescription(const std::vector<u8> &data, bool firstEntryOnly = false); std::string getDescription(const std::vector<u8> &data);
std::string getDescription(prv::Provider *provider, u64 address = 0x00, size_t size = 100_KiB, bool firstEntryOnly = false); std::string getDescription(prv::Provider *provider, size_t size = 100_KiB);
std::string getMIMEType(const std::vector<u8> &data, bool firstEntryOnly = false); std::string getMIMEType(const std::vector<u8> &data);
std::string getMIMEType(prv::Provider *provider, u64 address = 0x00, size_t size = 100_KiB, bool firstEntryOnly = false); std::string getMIMEType(prv::Provider *provider, size_t size = 100_KiB);
std::string getExtensions(const std::vector<u8> &data, bool firstEntryOnly = false);
std::string getExtensions(prv::Provider *provider, u64 address = 0x00, size_t size = 100_KiB, bool firstEntryOnly = false);
std::string getAppleCreatorType(const std::vector<u8> &data, bool firstEntryOnly = false);
std::string getAppleCreatorType(prv::Provider *provider, u64 address = 0x00, size_t size = 100_KiB, bool firstEntryOnly = false);
bool isValidMIMEType(const std::string &mimeType); bool isValidMIMEType(const std::string &mimeType);

File diff suppressed because it is too large Load Diff

View File

@@ -33,8 +33,8 @@ namespace hex {
wolv::util::Expected<std::vector<u8>, IPSError> toIPSPatch() const; wolv::util::Expected<std::vector<u8>, IPSError> toIPSPatch() const;
wolv::util::Expected<std::vector<u8>, IPSError> toIPS32Patch() const; wolv::util::Expected<std::vector<u8>, IPSError> toIPS32Patch() const;
const auto& get() const { return m_patches; } const auto& get() const { return this->m_patches; }
auto& get() { return m_patches; } auto& get() { return this->m_patches; }
private: private:
std::map<u64, u8> m_patches; std::map<u64, u8> m_patches;

View File

@@ -4,9 +4,7 @@
#include <hex/helpers/fs.hpp> #include <hex/helpers/fs.hpp>
#include <memory> #include <microtar.h>
struct mtar_t;
namespace hex { namespace hex {
@@ -34,28 +32,28 @@ namespace hex {
*/ */
std::string getOpenErrorString() const; std::string getOpenErrorString() const;
[[nodiscard]] std::vector<u8> readVector(const std::fs::path &path) const; [[nodiscard]] std::vector<u8> readVector(const std::fs::path &path);
[[nodiscard]] std::string readString(const std::fs::path &path) const; [[nodiscard]] std::string readString(const std::fs::path &path);
void writeVector(const std::fs::path &path, const std::vector<u8> &data) const; void writeVector(const std::fs::path &path, const std::vector<u8> &data);
void writeString(const std::fs::path &path, const std::string &data) const; void writeString(const std::fs::path &path, const std::string &data);
[[nodiscard]] std::vector<std::fs::path> listEntries(const std::fs::path &basePath = "/") const; [[nodiscard]] std::vector<std::fs::path> listEntries(const std::fs::path &basePath = "/");
[[nodiscard]] bool contains(const std::fs::path &path) const; [[nodiscard]] bool contains(const std::fs::path &path);
void extract(const std::fs::path &path, const std::fs::path &outputPath) const; void extract(const std::fs::path &path, const std::fs::path &outputPath);
void extractAll(const std::fs::path &outputPath) const; void extractAll(const std::fs::path &outputPath);
[[nodiscard]] bool isValid() const { return m_valid; } [[nodiscard]] bool isValid() const { return this->m_valid; }
private: private:
std::unique_ptr<mtar_t> m_ctx; mtar_t m_ctx = { };
std::fs::path m_path; std::fs::path m_path;
bool m_valid = false; bool m_valid = false;
// These will be updated when the constructor is called // These will be updated when the constructor is called
int m_tarOpenErrno = 0; int m_tarOpenErrno = MTAR_ESUCCESS;
int m_fileOpenErrno = 0; int m_fileOpenErrno = 0;
}; };

View File

@@ -3,8 +3,6 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <concepts>
using u8 = std::uint8_t; using u8 = std::uint8_t;
using u16 = std::uint16_t; using u16 = std::uint16_t;
using u32 = std::uint32_t; using u32 = std::uint32_t;
@@ -63,23 +61,4 @@ namespace hex {
} }
}; };
template<typename T>
concept Pointer = std::is_pointer_v<T>;
template<Pointer T>
struct NonNull {
NonNull(T ptr) : pointer(ptr) { }
NonNull(std::nullptr_t) = delete;
NonNull(std::integral auto) = delete;
NonNull(bool) = delete;
[[nodiscard]] T get() const { return pointer; }
[[nodiscard]] T operator->() const { return pointer; }
[[nodiscard]] T operator*() const { return *pointer; }
[[nodiscard]] operator T() const { return pointer; }
T pointer;
};
} }

View File

@@ -9,10 +9,8 @@
#include <bit> #include <bit>
#include <cstring> #include <cstring>
#include <cctype> #include <cctype>
#include <concepts>
#include <functional> #include <functional>
#include <limits> #include <limits>
#include <map>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <string> #include <string>
@@ -65,9 +63,6 @@ namespace hex {
[[nodiscard]] std::string to_string(u128 value); [[nodiscard]] std::string to_string(u128 value);
[[nodiscard]] std::string to_string(i128 value); [[nodiscard]] std::string to_string(i128 value);
[[nodiscard]] std::string toLower(std::string string);
[[nodiscard]] std::string toUpper(std::string string);
[[nodiscard]] std::vector<u8> parseHexString(std::string string); [[nodiscard]] std::vector<u8> parseHexString(std::string string);
[[nodiscard]] std::optional<u8> parseBinaryString(const std::string &string); [[nodiscard]] std::optional<u8> parseBinaryString(const std::string &string);
[[nodiscard]] std::string toByteString(u64 bytes); [[nodiscard]] std::string toByteString(u64 bytes);
@@ -77,15 +72,9 @@ namespace hex {
int executeCommand(const std::string &command); int executeCommand(const std::string &command);
void openWebpage(std::string url); void openWebpage(std::string url);
extern "C" void registerFont(const char *fontName, const char *fontPath);
const std::map<std::fs::path, std::string>& getFonts();
[[nodiscard]] std::string encodeByteString(const std::vector<u8> &bytes); [[nodiscard]] std::string encodeByteString(const std::vector<u8> &bytes);
[[nodiscard]] std::vector<u8> decodeByteString(const std::string &string); [[nodiscard]] std::vector<u8> decodeByteString(const std::string &string);
[[nodiscard]] std::wstring utf8ToUtf16(const std::string& utf8);
[[nodiscard]] std::string utf16ToUtf8(const std::wstring& utf16);
[[nodiscard]] constexpr u64 extract(u8 from, u8 to, const std::unsigned_integral auto &value) { [[nodiscard]] constexpr u64 extract(u8 from, u8 to, const std::unsigned_integral auto &value) {
if (from < to) std::swap(from, to); if (from < to) std::swap(from, to);
@@ -299,29 +288,10 @@ namespace hex {
[[nodiscard]] std::optional<std::string> getEnvironmentVariable(const std::string &env); [[nodiscard]] std::optional<std::string> getEnvironmentVariable(const std::string &env);
[[nodiscard]] inline 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.length() <= maxLength)
if (string.size() < maxLength)
return string; return string;
// If the string is longer than the max length, find the last space before the max length return string.substr(0, maxLength - 3) + "...";
auto it = string.begin() + maxLength;
while (it != string.begin() && !std::isspace(*it)) --it;
// If there's no space before the max length, just cut the string
if (it == string.begin()) {
it = string.begin() + maxLength;
// Try to find a UTF-8 character boundary
while (it != string.begin() && (*it & 0x80) != 0x00) --it;
++it;
}
// If we still didn't find a valid boundary, just return the string as is
if (it == string.begin())
return string;
// Append
return std::string(string.begin(), it) + "";
} }
[[nodiscard]] std::optional<std::fs::path> getInitialFilePath(); [[nodiscard]] std::optional<std::fs::path> getInitialFilePath();
@@ -329,6 +299,4 @@ namespace hex {
[[nodiscard]] std::string generateHexView(u64 offset, u64 size, prv::Provider *provider); [[nodiscard]] std::string generateHexView(u64 offset, u64 size, prv::Provider *provider);
[[nodiscard]] std::string generateHexView(u64 offset, const std::vector<u8> &data); [[nodiscard]] std::string generateHexView(u64 offset, const std::vector<u8> &data);
[[nodiscard]] std::string formatSystemError(i32 error);
} }

View File

@@ -2,19 +2,13 @@
#if defined(OS_MACOS) #if defined(OS_MACOS)
struct GLFWwindow;
extern "C" { extern "C" {
void errorMessageMacos(const char *message); void errorMessageMacos(const char *message);
void openWebpageMacos(const char *url); void openWebpageMacos(const char *url);
bool isMacosSystemDarkModeEnabled(); bool isMacosSystemDarkModeEnabled();
bool isMacosFullScreenModeEnabled(GLFWwindow *window);
float getBackingScaleFactor(); float getBackingScaleFactor();
void setupMacosWindowStyle(GLFWwindow *window, bool borderlessWindowMode);
void enumerateFontsMacos();
} }
#endif #endif

View File

@@ -2,7 +2,6 @@
#include <hex.hpp> #include <hex.hpp>
#include <hex/api/plugin_manager.hpp> #include <hex/api/plugin_manager.hpp>
#include <hex/helpers/logger.hpp>
#include <string> #include <string>
@@ -11,31 +10,6 @@
#include <wolv/utils/string.hpp> #include <wolv/utils/string.hpp>
#include <wolv/utils/preproc.hpp> #include <wolv/utils/preproc.hpp>
#include <wolv/utils/guards.hpp>
namespace {
struct PluginFunctionHelperInstantiation {};
}
template<typename T>
struct PluginFeatureFunctionHelper {
static void* getFeatures();
};
template<typename T>
struct PluginSubCommandsFunctionHelper {
static void* getSubCommands();
};
template<typename T>
void* PluginFeatureFunctionHelper<T>::getFeatures() {
return nullptr;
}
template<typename T>
void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
return nullptr;
}
#if defined (IMHEX_STATIC_LINK_PLUGINS) #if defined (IMHEX_STATIC_LINK_PLUGINS)
#define IMHEX_PLUGIN_VISIBILITY_PREFIX static #define IMHEX_PLUGIN_VISIBILITY_PREFIX static
@@ -48,65 +22,29 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
* Name, Author and Description will be displayed in the in the plugin list on the Welcome screen. * Name, Author and Description will be displayed in the in the plugin list on the Welcome screen.
*/ */
#define IMHEX_PLUGIN_SETUP(name, author, description) IMHEX_PLUGIN_SETUP_IMPL(name, author, description) #define IMHEX_PLUGIN_SETUP(name, author, description) IMHEX_PLUGIN_SETUP_IMPL(name, author, description)
#define IMHEX_LIBRARY_SETUP(name) IMHEX_LIBRARY_SETUP_IMPL(name)
#define IMHEX_LIBRARY_SETUP_IMPL(name) \ #define IMHEX_PLUGIN_SETUP_IMPL(name, author, description) \
namespace { static struct EXIT_HANDLER { ~EXIT_HANDLER() { hex::log::debug("Unloaded library '{}'", name); } } HANDLER; } \ IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getPluginName() { return name; } \
IMHEX_PLUGIN_VISIBILITY_PREFIX void WOLV_TOKEN_CONCAT(initializeLibrary_, IMHEX_PLUGIN_NAME)(); \ IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getPluginAuthor() { return author; } \
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *WOLV_TOKEN_CONCAT(getLibraryName_, IMHEX_PLUGIN_NAME)() { return name; } \ IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getPluginDescription() { return description; } \
IMHEX_PLUGIN_VISIBILITY_PREFIX void WOLV_TOKEN_CONCAT(setImGuiContext_, IMHEX_PLUGIN_NAME)(ImGuiContext *ctx) { \ IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getCompatibleVersion() { return IMHEX_VERSION; } \
ImGui::SetCurrentContext(ctx); \ IMHEX_PLUGIN_VISIBILITY_PREFIX void setImGuiContext(ImGuiContext *ctx) { \
GImGui = ctx; \ ImGui::SetCurrentContext(ctx); \
} \ GImGui = ctx; \
extern "C" [[gnu::visibility("default")]] void WOLV_TOKEN_CONCAT(forceLinkPlugin_, IMHEX_PLUGIN_NAME)() { \ } \
hex::PluginManager::addPlugin(name, hex::PluginFunctions { \ IMHEX_PLUGIN_VISIBILITY_PREFIX void initializePlugin(); \
nullptr, \ extern "C" [[gnu::visibility("default")]] void WOLV_TOKEN_CONCAT(forceLinkPlugin_, IMHEX_PLUGIN_NAME)() { \
WOLV_TOKEN_CONCAT(initializeLibrary_, IMHEX_PLUGIN_NAME), \ hex::PluginManager::addPlugin(hex::PluginFunctions { \
nullptr, \ initializePlugin, \
WOLV_TOKEN_CONCAT(getLibraryName_, IMHEX_PLUGIN_NAME), \ getPluginName, \
nullptr, \ getPluginAuthor, \
nullptr, \ getPluginDescription, \
nullptr, \ getCompatibleVersion, \
WOLV_TOKEN_CONCAT(setImGuiContext_, IMHEX_PLUGIN_NAME), \ setImGuiContext, \
nullptr, \ nullptr, \
nullptr, \ nullptr \
nullptr \ }); \
}); \ } \
} \
IMHEX_PLUGIN_VISIBILITY_PREFIX void WOLV_TOKEN_CONCAT(initializeLibrary_, IMHEX_PLUGIN_NAME)()
#define IMHEX_PLUGIN_SETUP_IMPL(name, author, description) \
namespace { static struct EXIT_HANDLER { ~EXIT_HANDLER() { hex::log::debug("Unloaded plugin '{}'", name); } } HANDLER; } \
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getPluginName() { return name; } \
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getPluginAuthor() { return author; } \
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getPluginDescription() { return description; } \
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getCompatibleVersion() { return IMHEX_VERSION; } \
IMHEX_PLUGIN_VISIBILITY_PREFIX void setImGuiContext(ImGuiContext *ctx) { \
ImGui::SetCurrentContext(ctx); \
GImGui = ctx; \
} \
IMHEX_PLUGIN_VISIBILITY_PREFIX void* getFeatures() { \
return PluginFeatureFunctionHelper<PluginFunctionHelperInstantiation>::getFeatures(); \
} \
IMHEX_PLUGIN_VISIBILITY_PREFIX void* getSubCommands() { \
return PluginSubCommandsFunctionHelper<PluginFunctionHelperInstantiation>::getSubCommands(); \
} \
IMHEX_PLUGIN_VISIBILITY_PREFIX void initializePlugin(); \
extern "C" [[gnu::visibility("default")]] void WOLV_TOKEN_CONCAT(forceLinkPlugin_, IMHEX_PLUGIN_NAME)() { \
hex::PluginManager::addPlugin(name, hex::PluginFunctions { \
initializePlugin, \
nullptr, \
getPluginName, \
nullptr, \
getPluginAuthor, \
getPluginDescription, \
getCompatibleVersion, \
setImGuiContext, \
nullptr, \
getSubCommands, \
getFeatures \
}); \
} \
IMHEX_PLUGIN_VISIBILITY_PREFIX void initializePlugin() IMHEX_PLUGIN_VISIBILITY_PREFIX void initializePlugin()
/** /**
@@ -119,26 +57,9 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
*/ */
#define IMHEX_PLUGIN_SUBCOMMANDS() IMHEX_PLUGIN_SUBCOMMANDS_IMPL() #define IMHEX_PLUGIN_SUBCOMMANDS() IMHEX_PLUGIN_SUBCOMMANDS_IMPL()
#define IMHEX_PLUGIN_SUBCOMMANDS_IMPL() \ #define IMHEX_PLUGIN_SUBCOMMANDS_IMPL() \
extern std::vector<hex::SubCommand> g_subCommands; \ extern std::vector<hex::SubCommand> g_subCommands; \
template<> \ extern "C" [[gnu::visibility("default")]] void* getSubCommands() { \
struct PluginSubCommandsFunctionHelper<PluginFunctionHelperInstantiation> { \ return &g_subCommands; \
static void* getSubCommands(); \ } \
}; \
void* PluginSubCommandsFunctionHelper<PluginFunctionHelperInstantiation>::getSubCommands() { \
return &g_subCommands; \
} \
std::vector<hex::SubCommand> g_subCommands std::vector<hex::SubCommand> g_subCommands
#define IMHEX_FEATURE_ENABLED(feature) WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(IMHEX_PLUGIN_, IMHEX_PLUGIN_NAME), _FEATURE_), feature)
#define IMHEX_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

View File

@@ -1,52 +0,0 @@
#pragma once
#include <hex/providers/provider.hpp>
namespace hex::prv {
/**
* This is a simple mock provider that can be used to pass in-memory data to APIs that require a provider.
* It's NOT a provider that can be loaded by the user.
*/
class MemoryProvider : public hex::prv::Provider {
public:
MemoryProvider() = default;
explicit MemoryProvider(std::vector<u8> data, std::string name = "") : m_data(std::move(data)), m_name(std::move(name)) { }
~MemoryProvider() override = default;
MemoryProvider(const MemoryProvider&) = delete;
MemoryProvider& operator=(const MemoryProvider&) = delete;
MemoryProvider(MemoryProvider &&provider) noexcept = default;
MemoryProvider& operator=(MemoryProvider &&provider) noexcept = default;
[[nodiscard]] bool isAvailable() const override { return true; }
[[nodiscard]] bool isReadable() const override { return true; }
[[nodiscard]] bool isWritable() const override { return true; }
[[nodiscard]] bool isResizable() const override { return true; }
[[nodiscard]] bool isSavable() const override { return m_name.empty(); }
[[nodiscard]] bool isSavableAsRecent() const override { return false; }
[[nodiscard]] bool open() override;
void close() override { }
void readRaw(u64 offset, void *buffer, size_t size) override;
void writeRaw(u64 offset, const void *buffer, size_t size) override;
[[nodiscard]] u64 getActualSize() const override { return m_data.size(); }
void resizeRaw(u64 newSize) override;
void insertRaw(u64 offset, u64 size) override;
void removeRaw(u64 offset, u64 size) override;
[[nodiscard]] std::string getName() const override { return m_name; }
[[nodiscard]] std::string getTypeName() const override { return "MemoryProvider"; }
private:
void renameFile();
private:
std::vector<u8> m_data;
std::string m_name;
};
}

View File

@@ -10,11 +10,11 @@ namespace hex::prv {
public: public:
Overlay() = default; Overlay() = default;
void setAddress(u64 address) { m_address = address; } void setAddress(u64 address) { this->m_address = address; }
[[nodiscard]] u64 getAddress() const { return m_address; } [[nodiscard]] u64 getAddress() const { return this->m_address; }
[[nodiscard]] u64 getSize() const { return m_data.size(); } [[nodiscard]] u64 getSize() const { return this->m_data.size(); }
[[nodiscard]] std::vector<u8> &getData() { return m_data; } [[nodiscard]] std::vector<u8> &getData() { return this->m_data; }
private: private:
u64 m_address = 0; u64 m_address = 0;

View File

@@ -33,15 +33,10 @@ namespace hex::prv {
std::function<void()> callback; std::function<void()> callback;
}; };
constexpr static u64 MaxPageSize = 0xFFFF'FFFF'FFFF'FFFF; constexpr static size_t MaxPageSize = 0x1000'0000;
Provider(); Provider();
virtual ~Provider(); virtual ~Provider();
Provider(const Provider&) = delete;
Provider& operator=(const Provider&) = delete;
Provider(Provider &&provider) noexcept = default;
Provider& operator=(Provider &&provider) noexcept = default;
/** /**
* @brief Opens this provider * @brief Opens this provider
@@ -142,7 +137,7 @@ namespace hex::prv {
* @brief Get the full size of the data in this provider * @brief Get the full size of the data in this provider
* @return The size of the entire available data of this provider * @return The size of the entire available data of this provider
*/ */
[[nodiscard]] virtual u64 getActualSize() const = 0; [[nodiscard]] virtual size_t getActualSize() const = 0;
/** /**
* @brief Gets the type name of this provider * @brief Gets the type name of this provider
@@ -161,13 +156,13 @@ namespace hex::prv {
*/ */
[[nodiscard]] virtual std::string getName() const = 0; [[nodiscard]] virtual std::string getName() const = 0;
void resize(u64 newSize); void resize(size_t newSize);
void insert(u64 offset, u64 size); void insert(u64 offset, size_t size);
void remove(u64 offset, u64 size); void remove(u64 offset, size_t size);
virtual void resizeRaw(u64 newSize) { hex::unused(newSize); } virtual void resizeRaw(size_t newSize) { hex::unused(newSize); }
virtual void insertRaw(u64 offset, u64 size) { hex::unused(offset, size); } virtual void insertRaw(u64 offset, size_t size) { hex::unused(offset, size); }
virtual void removeRaw(u64 offset, u64 size) { hex::unused(offset, size); } virtual void removeRaw(u64 offset, size_t size) { hex::unused(offset, size); }
virtual void save(); virtual void save();
virtual void saveAs(const std::fs::path &path); virtual void saveAs(const std::fs::path &path);
@@ -177,8 +172,8 @@ namespace hex::prv {
void applyOverlays(u64 offset, void *buffer, size_t size) const; void applyOverlays(u64 offset, void *buffer, size_t size) const;
[[nodiscard]] const std::list<std::unique_ptr<Overlay>> &getOverlays() const; [[nodiscard]] const std::list<std::unique_ptr<Overlay>> &getOverlays() const;
[[nodiscard]] u64 getPageSize() const; [[nodiscard]] size_t getPageSize() const;
void setPageSize(u64 pageSize); void setPageSize(size_t pageSize);
[[nodiscard]] u32 getPageCount() const; [[nodiscard]] u32 getPageCount() const;
[[nodiscard]] u32 getCurrentPage() const; [[nodiscard]] u32 getCurrentPage() const;
@@ -187,7 +182,7 @@ namespace hex::prv {
virtual void setBaseAddress(u64 address); virtual void setBaseAddress(u64 address);
[[nodiscard]] virtual u64 getBaseAddress() const; [[nodiscard]] virtual u64 getBaseAddress() const;
[[nodiscard]] virtual u64 getCurrentPageAddress() const; [[nodiscard]] virtual u64 getCurrentPageAddress() const;
[[nodiscard]] virtual u64 getSize() const; [[nodiscard]] virtual size_t getSize() const;
[[nodiscard]] virtual std::optional<u32> getPageOfAddress(u64 address) const; [[nodiscard]] virtual std::optional<u32> getPageOfAddress(u64 address) const;
[[nodiscard]] virtual std::vector<Description> getDataDescription() const; [[nodiscard]] virtual std::vector<Description> getDataDescription() const;
@@ -215,23 +210,23 @@ namespace hex::prv {
[[nodiscard]] virtual nlohmann::json storeSettings(nlohmann::json settings) const; [[nodiscard]] virtual nlohmann::json storeSettings(nlohmann::json settings) const;
virtual void loadSettings(const nlohmann::json &settings); virtual void loadSettings(const nlohmann::json &settings);
void markDirty(bool dirty = true) { m_dirty = dirty; } void markDirty(bool dirty = true) { this->m_dirty = dirty; }
[[nodiscard]] bool isDirty() const { return m_dirty; } [[nodiscard]] bool isDirty() const { return this->m_dirty; }
[[nodiscard]] virtual std::pair<Region, bool> getRegionValidity(u64 address) const; [[nodiscard]] virtual std::pair<Region, bool> getRegionValidity(u64 address) const;
void skipLoadInterface() { m_skipLoadInterface = true; } void skipLoadInterface() { this->m_skipLoadInterface = true; }
[[nodiscard]] bool shouldSkipLoadInterface() const { return m_skipLoadInterface; } [[nodiscard]] bool shouldSkipLoadInterface() const { return this->m_skipLoadInterface; }
void setErrorMessage(const std::string &errorMessage) { m_errorMessage = errorMessage; } void setErrorMessage(const std::string &errorMessage) { this->m_errorMessage = errorMessage; }
[[nodiscard]] const std::string& getErrorMessage() const { return m_errorMessage; } [[nodiscard]] const std::string& getErrorMessage() const { return this->m_errorMessage; }
template<std::derived_from<undo::Operation> T> template<std::derived_from<undo::Operation> T>
bool addUndoableOperation(auto && ... args) { bool addUndoableOperation(auto && ... args) {
return m_undoRedoStack.add<T>(std::forward<decltype(args)...>(args)...); return this->m_undoRedoStack.add<T>(std::forward<decltype(args)...>(args)...);
} }
[[nodiscard]] undo::Stack& getUndoStack() { return m_undoRedoStack; } [[nodiscard]] undo::Stack& getUndoStack() { return this->m_undoRedoStack; }
protected: protected:
u32 m_currPage = 0; u32 m_currPage = 0;
@@ -260,7 +255,7 @@ namespace hex::prv {
std::string m_errorMessage; std::string m_errorMessage;
u64 m_pageSize = MaxPageSize; size_t m_pageSize = MaxPageSize;
}; };
} }

View File

@@ -4,7 +4,6 @@
#include <hex/api/event_manager.hpp> #include <hex/api/event_manager.hpp>
#include <map> #include <map>
#include <ranges>
#include <utility> #include <utility>
namespace hex { namespace hex {
@@ -22,6 +21,8 @@ namespace hex {
PerProvider& operator=(const PerProvider&) = delete; PerProvider& operator=(const PerProvider&) = delete;
PerProvider& operator=(PerProvider &&) = delete; PerProvider& operator=(PerProvider &&) = delete;
PerProvider(T data) : m_data({ { ImHexApi::Provider::get(), std::move(data) } }) { this->onCreate(); }
~PerProvider() { this->onDestroy(); } ~PerProvider() { this->onDestroy(); }
T* operator->() { T* operator->() {
@@ -32,20 +33,20 @@ namespace hex {
return &this->get(); return &this->get();
} }
T& get(const prv::Provider *provider = ImHexApi::Provider::get()) { T& get(prv::Provider *provider = ImHexApi::Provider::get()) {
return m_data[provider]; return this->m_data[provider];
} }
const T& get(const prv::Provider *provider = ImHexApi::Provider::get()) const { const T& get(prv::Provider *provider = ImHexApi::Provider::get()) const {
return m_data.at(provider); return this->m_data[provider];
} }
void set(const T &data, const prv::Provider *provider = ImHexApi::Provider::get()) { void set(const T &data, prv::Provider *provider = ImHexApi::Provider::get()) {
m_data[provider] = data; this->m_data[provider] = data;
} }
void set(T &&data, const prv::Provider *provider = ImHexApi::Provider::get()) { void set(T &&data, prv::Provider *provider = ImHexApi::Provider::get()) {
m_data[provider] = std::move(data); this->m_data[provider] = std::move(data);
} }
T& operator*() { T& operator*() {
@@ -70,33 +71,22 @@ namespace hex {
return this->get(); return this->get();
} }
auto all() {
return m_data | std::views::values;
}
void setOnCreateCallback(std::function<void(prv::Provider *, T&)> callback) {
m_onCreateCallback = std::move(callback);
}
private: private:
void onCreate() { void onCreate() {
EventProviderOpened::subscribe(this, [this](prv::Provider *provider) { EventManager::subscribe<EventProviderOpened>(this, [this](prv::Provider *provider) {
auto [it, inserted] = m_data.emplace(provider, T()); this->m_data.emplace(provider, T());
auto &[key, value] = *it;
if (m_onCreateCallback)
m_onCreateCallback(provider, value);
}); });
EventProviderDeleted::subscribe(this, [this](prv::Provider *provider){ EventManager::subscribe<EventProviderDeleted>(this, [this](prv::Provider *provider){
m_data.erase(provider); this->m_data.erase(provider);
}); });
EventImHexClosing::subscribe(this, [this] { EventManager::subscribe<EventImHexClosing>(this, [this] {
m_data.clear(); this->m_data.clear();
}); });
// Moves the data of this PerProvider instance from one provider to another // Moves the data of this PerProvider instance from one provider to another
MovePerProviderData::subscribe(this, [this](prv::Provider *from, prv::Provider *to) { EventManager::subscribe<MovePerProviderData>(this, [this](prv::Provider *from, prv::Provider *to) {
// Get the value from the old provider, (removes it from the map) // Get the value from the old provider, (removes it from the map)
auto node = m_data.extract(from); auto node = m_data.extract(from);
@@ -104,24 +94,22 @@ namespace hex {
if (node.empty()) return; if (node.empty()) return;
// Delete the value from the new provider, that we want to replace // Delete the value from the new provider, that we want to replace
m_data.erase(to); this->m_data.erase(to);
// Re-insert it with the key of the new provider // Re-insert it with the key of the new provider
node.key() = to; node.key() = to;
m_data.insert(std::move(node)); this->m_data.insert(std::move(node));
}); });
} }
void onDestroy() { void onDestroy() {
EventProviderOpened::unsubscribe(this); EventManager::unsubscribe<EventProviderOpened>(this);
EventProviderDeleted::unsubscribe(this); EventManager::unsubscribe<EventProviderDeleted>(this);
EventImHexClosing::unsubscribe(this); EventManager::unsubscribe<EventImHexClosing>(this);
MovePerProviderData::unsubscribe(this);
} }
private: private:
std::map<const prv::Provider *, T> m_data; std::map<prv::Provider *, T> m_data;
std::function<void(prv::Provider *, T&)> m_onCreateCallback;
}; };
} }

View File

@@ -10,44 +10,44 @@ namespace hex::prv::undo {
class OperationGroup : public Operation { class OperationGroup : public Operation {
public: public:
explicit OperationGroup(UnlocalizedString unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {} explicit OperationGroup(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
OperationGroup(const OperationGroup &other) { OperationGroup(const OperationGroup &other) {
for (const auto &operation : other.m_operations) for (const auto &operation : other.m_operations)
m_operations.emplace_back(operation->clone()); this->m_operations.emplace_back(operation->clone());
} }
void undo(Provider *provider) override { void undo(Provider *provider) override {
for (auto &operation : m_operations) for (auto &operation : this->m_operations)
operation->undo(provider); operation->undo(provider);
} }
void redo(Provider *provider) override { void redo(Provider *provider) override {
for (auto &operation : m_operations) for (auto &operation : this->m_operations)
operation->redo(provider); operation->redo(provider);
} }
void addOperation(std::unique_ptr<Operation> &&newOperation) { void addOperation(std::unique_ptr<Operation> &&newOperation) {
auto newRegion = newOperation->getRegion(); auto newRegion = newOperation->getRegion();
if (newRegion.getStartAddress() < m_startAddress) if (newRegion.getStartAddress() < this->m_startAddress)
m_startAddress = newRegion.getStartAddress(); this->m_startAddress = newRegion.getStartAddress();
if (newRegion.getEndAddress() > m_endAddress) if (newRegion.getEndAddress() > this->m_endAddress)
m_endAddress = newRegion.getEndAddress(); this->m_endAddress = newRegion.getEndAddress();
if (m_formattedContent.size() <= 10) if (this->m_formattedContent.size() <= 10)
m_formattedContent.emplace_back(newOperation->format()); this->m_formattedContent.emplace_back(newOperation->format());
else else
m_formattedContent.back() = hex::format("[{}x] ...", (m_operations.size() - 10) + 1); this->m_formattedContent.back() = hex::format("[{}x] ...", (this->m_operations.size() - 10) + 1);
m_operations.emplace_back(std::move(newOperation)); this->m_operations.emplace_back(std::move(newOperation));
} }
[[nodiscard]] std::string format() const override { [[nodiscard]] std::string format() const override {
return hex::format("{}", Lang(m_unlocalizedName)); return hex::format("{}", Lang(this->m_unlocalizedName));
} }
[[nodiscard]] Region getRegion() const override { [[nodiscard]] Region getRegion() const override {
return Region { m_startAddress, (m_endAddress - m_startAddress) + 1 }; return Region { this->m_startAddress, (this->m_endAddress - this->m_startAddress) + 1 };
} }
std::unique_ptr<Operation> clone() const override { std::unique_ptr<Operation> clone() const override {
@@ -55,11 +55,11 @@ namespace hex::prv::undo {
} }
std::vector<std::string> formatContent() const override { std::vector<std::string> formatContent() const override {
return m_formattedContent; return this->m_formattedContent;
} }
private: private:
UnlocalizedString m_unlocalizedName; std::string m_unlocalizedName;
std::vector<std::unique_ptr<Operation>> m_operations; std::vector<std::unique_ptr<Operation>> m_operations;
u64 m_startAddress = std::numeric_limits<u64>::max(); u64 m_startAddress = std::numeric_limits<u64>::max();

View File

@@ -1,13 +1,12 @@
#pragma once #pragma once
#include <hex.hpp> #include <hex.hpp>
#include <hex/api/localization_manager.hpp>
#include <hex/api/event_manager.hpp>
#include <hex/providers/undo_redo/operations/operation.hpp> #include <hex/providers/undo_redo/operations/operation.hpp>
#include <atomic>
#include <map> #include <map>
#include <memory> #include <memory>
#include <mutex>
#include <vector> #include <vector>
namespace hex::prv { namespace hex::prv {
@@ -25,7 +24,7 @@ namespace hex::prv::undo {
void undo(u32 count = 1); void undo(u32 count = 1);
void redo(u32 count = 1); void redo(u32 count = 1);
void groupOperations(u32 count, const UnlocalizedString &unlocalizedName); void groupOperations(u32 count, const std::string &unlocalizedName);
void apply(const Stack &otherStack); void apply(const Stack &otherStack);
[[nodiscard]] bool canUndo() const; [[nodiscard]] bool canUndo() const;
@@ -33,30 +32,27 @@ namespace hex::prv::undo {
template<std::derived_from<Operation> T> template<std::derived_from<Operation> T>
bool add(auto && ... args) { bool add(auto && ... args) {
auto result = this->add(std::make_unique<T>(std::forward<decltype(args)>(args)...)); return this->add(std::make_unique<T>(std::forward<decltype(args)>(args)...));
EventDataChanged::post(m_provider);
return result;
} }
bool add(std::unique_ptr<Operation> &&operation); bool add(std::unique_ptr<Operation> &&operation);
const std::vector<std::unique_ptr<Operation>> &getAppliedOperations() const { const std::vector<std::unique_ptr<Operation>> &getAppliedOperations() const {
return m_undoStack; return this->m_undoStack;
} }
const std::vector<std::unique_ptr<Operation>> &getUndoneOperations() const { const std::vector<std::unique_ptr<Operation>> &getUndoneOperations() const {
return m_redoStack; return this->m_redoStack;
} }
void reset() { void reset() {
m_undoStack.clear(); this->m_undoStack.clear();
m_redoStack.clear(); this->m_redoStack.clear();
} }
private: private:
[[nodiscard]] Operation* getLastOperation() const { [[nodiscard]] Operation* getLastOperation() const {
return m_undoStack.back().get(); return this->m_undoStack.back().get();
} }
private: private:

View File

@@ -10,11 +10,10 @@
#include <hex/helpers/fmt.hpp> #include <hex/helpers/fmt.hpp>
#include <hex/helpers/concepts.hpp> #include <hex/helpers/concepts.hpp>
#include <hex/helpers/fs.hpp>
#include <wolv/utils/string.hpp> #include <wolv/utils/string.hpp>
enum ImGuiCustomCol : int { enum ImGuiCustomCol {
ImGuiCustomCol_DescButton, ImGuiCustomCol_DescButton,
ImGuiCustomCol_DescButtonHovered, ImGuiCustomCol_DescButtonHovered,
ImGuiCustomCol_DescButtonActive, ImGuiCustomCol_DescButtonActive,
@@ -70,16 +69,10 @@ namespace ImGuiExt {
class Texture { class Texture {
public: public:
enum class Filter : int {
Linear,
Nearest
};
Texture() = default; Texture() = default;
Texture(const ImU8 *buffer, int size, Filter filter = Filter::Nearest, int width = 0, int height = 0); Texture(const ImU8 *buffer, int size, int width = 0, int height = 0);
Texture(std::span<const std::byte> bytes, Filter filter = Filter::Nearest, int width = 0, int height = 0); Texture(std::span<const std::byte> bytes, int width = 0, int height = 0);
explicit Texture(const char *path, Filter filter = Filter::Nearest); explicit Texture(const char *path);
explicit Texture(const std::fs::path &path, Filter filter = Filter::Nearest);
Texture(unsigned int texture, int width, int height); Texture(unsigned int texture, int width, int height);
Texture(const Texture&) = delete; Texture(const Texture&) = delete;
Texture(Texture&& other) noexcept; Texture(Texture&& other) noexcept;
@@ -90,25 +83,21 @@ namespace ImGuiExt {
Texture& operator=(Texture&& other) noexcept; Texture& operator=(Texture&& other) noexcept;
[[nodiscard]] constexpr bool isValid() const noexcept { [[nodiscard]] constexpr bool isValid() const noexcept {
return m_textureId != nullptr; return this->m_textureId != nullptr;
} }
[[nodiscard]] operator ImTextureID() const noexcept { [[nodiscard]] constexpr operator ImTextureID() const noexcept {
return m_textureId; return this->m_textureId;
}
[[nodiscard]] operator intptr_t() const noexcept {
return reinterpret_cast<intptr_t>(m_textureId);
} }
[[nodiscard]] auto getSize() const noexcept { [[nodiscard]] auto getSize() const noexcept {
return ImVec2(m_width, m_height); return ImVec2(this->m_width, this->m_height);
} }
[[nodiscard]] constexpr auto getAspectRatio() const noexcept { [[nodiscard]] constexpr auto getAspectRatio() const noexcept {
if (m_height == 0) return 1.0F; if (this->m_height == 0) return 1.0F;
return float(m_width) / float(m_height); return float(this->m_width) / float(this->m_height);
} }
private: private:
@@ -133,7 +122,7 @@ namespace ImGuiExt {
void Header(const char *label, bool firstEntry = false); void Header(const char *label, bool firstEntry = false);
void HeaderColored(const char *label, ImColor color, bool firstEntry); void HeaderColored(const char *label, ImColor color, bool firstEntry);
bool InfoTooltip(const char *text = "",bool = false); bool InfoTooltip(const char *text = "");
bool TitleBarButton(const char *label, ImVec2 size_arg); bool TitleBarButton(const char *label, ImVec2 size_arg);
bool ToolBarButton(const char *symbol, ImVec4 color); bool ToolBarButton(const char *symbol, ImVec4 color);
@@ -269,7 +258,6 @@ namespace ImGuiExt {
bool DimmedIconButton(const char *symbol, ImVec4 color, ImVec2 size = ImVec2(0, 0)); bool DimmedIconButton(const char *symbol, ImVec4 color, ImVec2 size = ImVec2(0, 0));
bool DimmedButtonToggle(const char *icon, bool *v, ImVec2 size); bool DimmedButtonToggle(const char *icon, bool *v, ImVec2 size);
bool DimmedIconToggle(const char *icon, bool *v); bool DimmedIconToggle(const char *icon, bool *v);
bool DimmedIconToggle(const char *iconOn, const char *iconOff, bool *v);
void TextOverlay(const char *text, ImVec2 pos); void TextOverlay(const char *text, ImVec2 pos);
@@ -289,14 +277,6 @@ namespace ImGuiExt {
if (ImGui::Button(textRight, ImVec2(width / 3, 0))) if (ImGui::Button(textRight, ImVec2(width / 3, 0)))
rightButtonCallback(); rightButtonCallback();
} }
bool VSliderAngle(const char* label, ImVec2& size, float* v_rad, float v_degrees_min, float v_degrees_max, const char* format, ImGuiSliderFlags flags);
bool InputFilePicker(const char *label, std::fs::path &path, const std::vector<hex::fs::ItemFilter> &validExtensions);
bool ToggleSwitch(const char *label, bool *v);
bool ToggleSwitch(const char *label, bool v);
template<typename T> template<typename T>
constexpr ImGuiDataType getImGuiDataType() { constexpr ImGuiDataType getImGuiDataType() {
if constexpr (std::same_as<T, u8>) return ImGuiDataType_U8; if constexpr (std::same_as<T, u8>) return ImGuiDataType_U8;

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include <hex.hpp> #include <hex.hpp>
#include <hex/api/localization_manager.hpp>
#include <memory> #include <memory>
#include <string> #include <string>
@@ -18,7 +17,7 @@ namespace hex {
class PopupBase { class PopupBase {
public: public:
explicit PopupBase(UnlocalizedString unlocalizedName, bool closeButton, bool modal) explicit PopupBase(std::string unlocalizedName, bool closeButton, bool modal)
: m_unlocalizedName(std::move(unlocalizedName)), m_closeButton(closeButton), m_modal(modal) { } : m_unlocalizedName(std::move(unlocalizedName)), m_closeButton(closeButton), m_modal(modal) { }
virtual ~PopupBase() = default; virtual ~PopupBase() = default;
@@ -36,30 +35,29 @@ namespace hex {
[[nodiscard]] static std::vector<std::unique_ptr<PopupBase>> &getOpenPopups(); [[nodiscard]] static std::vector<std::unique_ptr<PopupBase>> &getOpenPopups();
[[nodiscard]] const UnlocalizedString &getUnlocalizedName() const { [[nodiscard]] const std::string &getUnlocalizedName() const {
return m_unlocalizedName; return this->m_unlocalizedName;
} }
[[nodiscard]] bool hasCloseButton() const { [[nodiscard]] bool hasCloseButton() const {
return m_closeButton; return this->m_closeButton;
} }
[[nodiscard]] bool isModal() const { [[nodiscard]] bool isModal() const {
return m_modal; return this->m_modal;
} }
void close() { void close() {
m_close = true; this->m_close = true;
} }
[[nodiscard]] bool shouldClose() const { [[nodiscard]] bool shouldClose() const {
return m_close; return this->m_close;
} }
protected:
static std::mutex& getMutex();
private: private:
UnlocalizedString m_unlocalizedName;
std::string m_unlocalizedName;
bool m_closeButton, m_modal; bool m_closeButton, m_modal;
std::atomic<bool> m_close = false; std::atomic<bool> m_close = false;
}; };
@@ -70,12 +68,13 @@ namespace hex {
template<typename T> template<typename T>
class Popup : public impl::PopupBase { class Popup : public impl::PopupBase {
protected: protected:
explicit Popup(UnlocalizedString unlocalizedName, bool closeButton = true, bool modal = true) : PopupBase(std::move(unlocalizedName), closeButton, modal) { } explicit Popup(std::string unlocalizedName, bool closeButton = true, bool modal = true) : PopupBase(std::move(unlocalizedName), closeButton, modal) { }
public: public:
template<typename ...Args> template<typename ...Args>
static void open(Args && ... args) { static void open(Args && ... args) {
std::lock_guard lock(getMutex()); static std::mutex mutex;
std::lock_guard lock(mutex);
auto popup = std::make_unique<T>(std::forward<Args>(args)...); auto popup = std::make_unique<T>(std::forward<Args>(args)...);

View File

@@ -1,61 +0,0 @@
#pragma once
#include <hex.hpp>
#include <imgui.h>
#include <list>
#include <memory>
#include <mutex>
namespace hex {
namespace impl {
class ToastBase {
public:
ToastBase(ImColor color) : m_color(color) {}
virtual ~ToastBase() = default;
virtual void draw() { drawContent(); }
virtual void drawContent() = 0;
[[nodiscard]] static std::list<std::unique_ptr<ToastBase>> &getQueuedToasts();
[[nodiscard]] const ImColor& getColor() const {
return m_color;
}
void setAppearTime(double appearTime) {
m_appearTime = appearTime;
}
[[nodiscard]] double getAppearTime() const {
return m_appearTime;
}
constexpr static double VisibilityTime = 4.0;
protected:
static std::mutex& getMutex();
double m_appearTime = 0;
ImColor m_color;
};
}
template<typename T>
class Toast : public impl::ToastBase {
public:
using impl::ToastBase::ToastBase;
template<typename ...Args>
static void open(Args && ... args) {
std::lock_guard lock(getMutex());
auto toast = std::make_unique<T>(std::forward<Args>(args)...);
getQueuedToasts().emplace_back(std::move(toast));
}
};
}

View File

@@ -6,15 +6,17 @@
#include <imgui_internal.h> #include <imgui_internal.h>
#include <hex/ui/imgui_imhex_extensions.h> #include <hex/ui/imgui_imhex_extensions.h>
#include <fonts/fontawesome_font.h>
#include <fonts/codicons_font.h>
#include <hex/api/imhex_api.hpp> #include <hex/api/imhex_api.hpp>
#include <hex/api/shortcut_manager.hpp> #include <hex/api/shortcut_manager.hpp>
#include <hex/api/event_manager.hpp> #include <hex/api/event_manager.hpp>
#include <hex/api/localization_manager.hpp>
#include <hex/providers/provider.hpp> #include <hex/providers/provider.hpp>
#include <hex/providers/provider_data.hpp> #include <hex/providers/provider_data.hpp>
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
#include <hex/api/localization_manager.hpp>
#include <map> #include <map>
#include <string> #include <string>
@@ -22,7 +24,7 @@
namespace hex { namespace hex {
class View { class View {
explicit View(UnlocalizedString unlocalizedName, const char *icon); explicit View(std::string unlocalizedName);
public: public:
virtual ~View() = default; virtual ~View() = default;
@@ -80,22 +82,20 @@ namespace hex {
*/ */
[[nodiscard]] virtual ImGuiWindowFlags getWindowFlags() const; [[nodiscard]] virtual ImGuiWindowFlags getWindowFlags() const;
[[nodiscard]] const char *getIcon() const { return m_icon; }
[[nodiscard]] bool &getWindowOpenState(); [[nodiscard]] bool &getWindowOpenState();
[[nodiscard]] const bool &getWindowOpenState() const; [[nodiscard]] const bool &getWindowOpenState() const;
[[nodiscard]] const UnlocalizedString &getUnlocalizedName() const; [[nodiscard]] const std::string &getUnlocalizedName() const;
[[nodiscard]] std::string getName() const; [[nodiscard]] std::string getName() const;
[[nodiscard]] bool didWindowJustOpen(); [[nodiscard]] bool didWindowJustOpen();
void setWindowJustOpened(bool state); void setWindowJustOpened(bool state);
void trackViewOpenState();
static void discardNavigationRequests(); static void discardNavigationRequests();
[[nodiscard]] static std::string toWindowName(const UnlocalizedString &unlocalizedName); [[nodiscard]] static std::string toWindowName(const std::string &unlocalizedName);
public: public:
class Window; class Window;
@@ -104,11 +104,10 @@ namespace hex {
class Modal; class Modal;
private: private:
UnlocalizedString m_unlocalizedViewName; std::string m_unlocalizedViewName;
bool m_windowOpen = false, m_prevWindowOpen = false; bool m_windowOpen = false;
std::map<Shortcut, ShortcutManager::ShortcutEntry> m_shortcuts; std::map<Shortcut, ShortcutManager::ShortcutEntry> m_shortcuts;
bool m_windowJustOpened = false; bool m_windowJustOpened = false;
const char *m_icon;
friend class ShortcutManager; friend class ShortcutManager;
}; };
@@ -119,7 +118,7 @@ namespace hex {
*/ */
class View::Window : public View { class View::Window : public View {
public: public:
explicit Window(UnlocalizedString unlocalizedName, const char *icon) : View(std::move(unlocalizedName), icon) {} explicit Window(std::string unlocalizedName) : View(std::move(unlocalizedName)) {}
void draw() final { void draw() final {
if (this->shouldDraw()) { if (this->shouldDraw()) {
@@ -138,7 +137,7 @@ namespace hex {
*/ */
class View::Special : public View { class View::Special : public View {
public: public:
explicit Special(UnlocalizedString unlocalizedName) : View(std::move(unlocalizedName), "") {} explicit Special(std::string unlocalizedName) : View(std::move(unlocalizedName)) {}
void draw() final { void draw() final {
if (this->shouldDraw()) { if (this->shouldDraw()) {
@@ -153,9 +152,9 @@ namespace hex {
*/ */
class View::Floating : public View::Window { class View::Floating : public View::Window {
public: public:
explicit Floating(UnlocalizedString unlocalizedName) : Window(std::move(unlocalizedName), "") {} explicit Floating(std::string unlocalizedName) : Window(std::move(unlocalizedName)) {}
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const override { return ImGuiWindowFlags_NoDocking; } [[nodiscard]] ImGuiWindowFlags getWindowFlags() const { return ImGuiWindowFlags_NoDocking; }
}; };
/** /**
@@ -163,27 +162,22 @@ namespace hex {
*/ */
class View::Modal : public View { class View::Modal : public View {
public: public:
explicit Modal(UnlocalizedString unlocalizedName) : View(std::move(unlocalizedName), "") {} explicit Modal(std::string unlocalizedName) : View(std::move(unlocalizedName)) {}
void draw() final { void draw() final {
if (this->shouldDraw()) { if (this->shouldDraw()) {
ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize());
if (this->getWindowOpenState()) if (this->getWindowOpenState())
ImGui::OpenPopup(View::toWindowName(this->getUnlocalizedName()).c_str()); ImGui::OpenPopup(View::toWindowName(this->getUnlocalizedName()).c_str());
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F)); if (ImGui::BeginPopupModal(View::toWindowName(this->getUnlocalizedName()).c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize | this->getWindowFlags())) {
ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize());
if (ImGui::BeginPopupModal(View::toWindowName(this->getUnlocalizedName()).c_str(), this->hasCloseButton() ? &this->getWindowOpenState() : nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize | this->getWindowFlags())) {
this->drawContent(); this->drawContent();
ImGui::EndPopup(); ImGui::EndPopup();
} }
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape)))
this->getWindowOpenState() = false;
} }
} }
virtual bool hasCloseButton() const { return true; }
}; };
} }

View File

@@ -21,34 +21,34 @@ namespace hex::ui {
} }
const std::vector<const T*> &draw(const auto &entries) { const std::vector<const T*> &draw(const auto &entries) {
if (m_filteredEntries.empty() && m_searchBuffer.empty()) { if (this->m_filteredEntries.empty() && this->m_searchBuffer.empty()) {
for (auto &entry : entries) for (auto &entry : entries)
m_filteredEntries.push_back(&entry); this->m_filteredEntries.push_back(&entry);
} }
if (ImGui::InputText("##search", m_searchBuffer)) { if (ImGui::InputText("##search", this->m_searchBuffer)) {
m_pendingUpdate = true; this->m_pendingUpdate = true;
} }
if (m_pendingUpdate && !m_updateTask.isRunning()) { if (this->m_pendingUpdate && !this->m_updateTask.isRunning()) {
m_pendingUpdate = false; this->m_pendingUpdate = false;
m_filteredEntries.clear(); this->m_filteredEntries.clear();
m_filteredEntries.reserve(entries.size()); this->m_filteredEntries.reserve(entries.size());
m_updateTask = TaskManager::createBackgroundTask("Searching", [this, &entries, searchBuffer = m_searchBuffer](Task&) { this->m_updateTask = TaskManager::createBackgroundTask("Searching", [this, &entries, searchBuffer = this->m_searchBuffer](Task&) {
for (auto &entry : entries) { for (auto &entry : entries) {
if (searchBuffer.empty() || m_comparator(searchBuffer, entry)) if (searchBuffer.empty() || this->m_comparator(searchBuffer, entry))
m_filteredEntries.push_back(&entry); this->m_filteredEntries.push_back(&entry);
} }
}); });
} }
return m_filteredEntries; return this->m_filteredEntries;
} }
void reset() { void reset() {
m_filteredEntries.clear(); this->m_filteredEntries.clear();
} }
private: private:
std::atomic<bool> m_pendingUpdate = false; std::atomic<bool> m_pendingUpdate = false;

View File

@@ -1,56 +1,52 @@
#include <hex/api/achievement_manager.hpp> #include <hex/api/achievement_manager.hpp>
#include <hex/api/event_manager.hpp> #include <hex/api/event_manager.hpp>
#include <hex/helpers/auto_reset.hpp>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
namespace hex { namespace hex {
static AutoReset<std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>>> s_achievements; std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>> &AchievementManager::getAchievements() {
const std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>> &AchievementManager::getAchievements() { static std::unordered_map<std::string, std::unordered_map<std::string, std::unique_ptr<Achievement>>> achievements;
return *s_achievements;
return achievements;
} }
static AutoReset<std::unordered_map<std::string, std::list<AchievementManager::AchievementNode>>> s_nodeCategoryStorage; std::unordered_map<std::string, std::list<AchievementManager::AchievementNode>>& AchievementManager::getAchievementNodes(bool rebuild) {
std::unordered_map<std::string, std::list<AchievementManager::AchievementNode>>& getAchievementNodesMutable(bool rebuild) { static std::unordered_map<std::string, std::list<AchievementNode>> nodeCategoryStorage;
if (!s_nodeCategoryStorage->empty() || !rebuild)
return s_nodeCategoryStorage;
s_nodeCategoryStorage->clear(); if (!nodeCategoryStorage.empty() || !rebuild)
return nodeCategoryStorage;
nodeCategoryStorage.clear();
// Add all achievements to the node storage // Add all achievements to the node storage
for (auto &[categoryName, achievements] : AchievementManager::getAchievements()) { for (auto &[categoryName, achievements] : getAchievements()) {
auto &nodes = (*s_nodeCategoryStorage)[categoryName]; auto &nodes = nodeCategoryStorage[categoryName];
for (auto &[achievementName, achievement] : achievements) { for (auto &[achievementName, achievement] : achievements) {
nodes.emplace_back(achievement.get()); nodes.emplace_back(achievement.get());
} }
} }
return s_nodeCategoryStorage; return nodeCategoryStorage;
} }
const std::unordered_map<std::string, std::list<AchievementManager::AchievementNode>>& AchievementManager::getAchievementNodes(bool rebuild) { std::unordered_map<std::string, std::vector<AchievementManager::AchievementNode*>>& AchievementManager::getAchievementStartNodes(bool rebuild) {
return getAchievementNodesMutable(rebuild); static std::unordered_map<std::string, std::vector<AchievementNode*>> startNodes;
}
static AutoReset<std::unordered_map<std::string, std::vector<AchievementManager::AchievementNode*>>> s_startNodes; if (!startNodes.empty() || !rebuild)
const std::unordered_map<std::string, std::vector<AchievementManager::AchievementNode*>>& AchievementManager::getAchievementStartNodes(bool rebuild) { return startNodes;
if (!s_startNodes->empty() || !rebuild) auto &nodeCategoryStorage = getAchievementNodes();
return s_startNodes;
auto &nodeCategoryStorage = getAchievementNodesMutable(rebuild); startNodes.clear();
s_startNodes->clear();
// Add all parents and children to the nodes // Add all parents and children to the nodes
for (auto &[categoryName, achievements] : nodeCategoryStorage) { for (auto &[categoryName, achievements] : nodeCategoryStorage) {
for (auto &achievementNode : achievements) { for (auto &achievementNode : achievements) {
for (auto &requirement : achievementNode.achievement->getRequirements()) { for (auto &requirement : achievementNode.achievement->getRequirements()) {
for (auto &[requirementCategoryName, requirementAchievements] : nodeCategoryStorage) { for (auto &[requirementCategoryName, requirementAchievements] : nodeCategoryStorage) {
auto iter = std::ranges::find_if(requirementAchievements, [&requirement](auto &node) { auto iter = std::find_if(requirementAchievements.begin(), requirementAchievements.end(), [&requirement](auto &node) {
return node.achievement->getUnlocalizedName() == requirement; return node.achievement->getUnlocalizedName() == requirement;
}); });
@@ -63,7 +59,7 @@ namespace hex {
for (auto &requirement : achievementNode.achievement->getVisibilityRequirements()) { for (auto &requirement : achievementNode.achievement->getVisibilityRequirements()) {
for (auto &[requirementCategoryName, requirementAchievements] : nodeCategoryStorage) { for (auto &[requirementCategoryName, requirementAchievements] : nodeCategoryStorage) {
auto iter = std::ranges::find_if(requirementAchievements, [&requirement](auto &node) { auto iter = std::find_if(requirementAchievements.begin(), requirementAchievements.end(), [&requirement](auto &node) {
return node.achievement->getUnlocalizedName() == requirement; return node.achievement->getUnlocalizedName() == requirement;
}); });
@@ -78,20 +74,20 @@ namespace hex {
for (auto &[categoryName, achievements] : nodeCategoryStorage) { for (auto &[categoryName, achievements] : nodeCategoryStorage) {
for (auto &achievementNode : achievements) { for (auto &achievementNode : achievements) {
if (!achievementNode.hasParents()) { if (!achievementNode.hasParents()) {
(*s_startNodes)[categoryName].emplace_back(&achievementNode); startNodes[categoryName].emplace_back(&achievementNode);
} }
for (const auto &parent : achievementNode.parents) { for (const auto &parent : achievementNode.parents) {
if (parent->achievement->getUnlocalizedCategory() != achievementNode.achievement->getUnlocalizedCategory()) if (parent->achievement->getUnlocalizedCategory() != achievementNode.achievement->getUnlocalizedCategory())
(*s_startNodes)[categoryName].emplace_back(&achievementNode); startNodes[categoryName].emplace_back(&achievementNode);
} }
} }
} }
return s_startNodes; return startNodes;
} }
void AchievementManager::unlockAchievement(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName) { void AchievementManager::unlockAchievement(const std::string &unlocalizedCategory, const std::string &unlocalizedName) {
auto &categories = getAchievements(); auto &categories = getAchievements();
auto categoryIter = categories.find(unlocalizedCategory); auto categoryIter = categories.find(unlocalizedCategory);
@@ -101,16 +97,15 @@ namespace hex {
auto &[categoryName, achievements] = *categoryIter; auto &[categoryName, achievements] = *categoryIter;
const auto achievementIter = achievements.find(unlocalizedName); auto achievementIter = achievements.find(unlocalizedName);
if (achievementIter == achievements.end()) { if (achievementIter == achievements.end()) {
return; return;
} }
const auto &nodes = getAchievementNodes(); auto &nodes = getAchievementNodes()[categoryName];
if (!nodes.contains(categoryName))
return;
for (const auto &node : nodes.at(categoryName)) { for (const auto &node : nodes) {
auto &achievement = node.achievement; auto &achievement = node.achievement;
if (achievement->getUnlocalizedCategory() != unlocalizedCategory) { if (achievement->getUnlocalizedCategory() != unlocalizedCategory) {
@@ -133,14 +128,20 @@ namespace hex {
achievement->setUnlocked(true); achievement->setUnlocked(true);
if (achievement->isUnlocked()) if (achievement->isUnlocked())
EventAchievementUnlocked::post(*achievement); EventManager::post<EventAchievementUnlocked>(*achievement);
return; return;
} }
} }
void AchievementManager::clear() {
getAchievements().clear();
getAchievementStartNodes(false).clear();
getAchievementNodes(false).clear();
}
void AchievementManager::clearTemporary() { void AchievementManager::clearTemporary() {
auto &categories = *s_achievements; auto &categories = getAchievements();
for (auto &[categoryName, achievements] : categories) { for (auto &[categoryName, achievements] : categories) {
std::erase_if(achievements, [](auto &data) { std::erase_if(achievements, [](auto &data) {
auto &[achievementName, achievement] = data; auto &[achievementName, achievement] = data;
@@ -153,8 +154,8 @@ namespace hex {
return achievements.empty(); return achievements.empty();
}); });
s_startNodes->clear(); getAchievementStartNodes(false).clear();
s_nodeCategoryStorage->clear(); getAchievementNodes(false).clear();
} }
std::pair<u32, u32> AchievementManager::getProgress() { std::pair<u32, u32> AchievementManager::getProgress() {
@@ -174,26 +175,10 @@ namespace hex {
} }
void AchievementManager::achievementAdded() { void AchievementManager::achievementAdded() {
s_startNodes->clear(); getAchievementStartNodes(false).clear();
s_nodeCategoryStorage->clear(); getAchievementNodes(false).clear();
} }
Achievement &AchievementManager::addAchievementImpl(std::unique_ptr<Achievement> &&newAchievement) {
const auto &category = newAchievement->getUnlocalizedCategory();
const auto &name = newAchievement->getUnlocalizedName();
auto [categoryIter, categoryInserted] = s_achievements->insert({ category, std::unordered_map<std::string, std::unique_ptr<Achievement>>{} });
auto &[categoryKey, achievements] = *categoryIter;
auto [achievementIter, achievementInserted] = achievements.insert({ name, std::move(newAchievement) });
auto &[achievementKey, achievement] = *achievementIter;
achievementAdded();
return *achievement;
}
constexpr static auto AchievementsFile = "achievements.json"; constexpr static auto AchievementsFile = "achievements.json";
void AchievementManager::loadProgress() { void AchievementManager::loadProgress() {
@@ -216,11 +201,7 @@ namespace hex {
for (const auto &[categoryName, achievements] : getAchievements()) { for (const auto &[categoryName, achievements] : getAchievements()) {
for (const auto &[achievementName, achievement] : achievements) { for (const auto &[achievementName, achievement] : achievements) {
try { try {
const auto &progress = json[categoryName][achievementName]; achievement->setProgress(json[categoryName][achievementName]);
if (progress.is_null())
continue;
achievement->setProgress(progress);
} catch (const std::exception &e) { } catch (const std::exception &e) {
log::warn("Failed to load achievement progress for '{}::{}': {}", categoryName, achievementName, e.what()); log::warn("Failed to load achievement progress for '{}::{}': {}", categoryName, achievementName, e.what());
} }
@@ -234,24 +215,24 @@ namespace hex {
} }
void AchievementManager::storeProgress() { void AchievementManager::storeProgress() {
nlohmann::json json;
for (const auto &[categoryName, achievements] : getAchievements()) {
json[categoryName] = nlohmann::json::object();
for (const auto &[achievementName, achievement] : achievements) {
json[categoryName][achievementName] = achievement->getProgress();
}
}
if (json.empty())
return;
for (const auto &directory : fs::getDefaultPaths(fs::ImHexPath::Config)) { for (const auto &directory : fs::getDefaultPaths(fs::ImHexPath::Config)) {
auto path = directory / AchievementsFile; auto path = directory / AchievementsFile;
wolv::io::File file(path, wolv::io::File::Mode::Create); wolv::io::File file(path, wolv::io::File::Mode::Create);
if (!file.isValid())
if (!file.isValid()) {
continue; continue;
}
nlohmann::json json;
for (const auto &[categoryName, achievements] : getAchievements()) {
json[categoryName] = nlohmann::json::object();
for (const auto &[achievementName, achievement] : achievements) {
json[categoryName][achievementName] = achievement->getProgress();
}
}
file.writeString(json.dump(4)); file.writeString(json.dump(4));
break; break;

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