Compare commits

..

2 Commits

Author SHA1 Message Date
WerWolv
5caefcc9f2 git: Configure runners better 2025-08-22 20:15:03 +02:00
WerWolv
cb38d98f5c git: Switch over to runs-on 2025-08-22 20:03:32 +02:00
509 changed files with 11894 additions and 27668 deletions

View File

@@ -1,97 +1,69 @@
# All rules should have a comment associated
# Directives that do not have any effect (e.g. disabling a rule that is not enabled) can be done to add an explanation comment.
# Or at least an empty comment # to show they were put here explicitely,
# and not as part of the historical CLion-generated rules
# Note: `- -X` means disable X
# CLI usage: go to the build directory and run: `run-clang-tidy -allow-no-checks -source-filter ".*/lib/.*" -fix -j`
Checks:
- -*
- mpi-*
- bugprone-*
- -bugprone-signal-handler
- -bugprone-narrowing-conversions
- -bugprone-redundant-branch-condition
- -bugprone-exception-escape
- -bugprone-shared-ptr-array-mismatch
- -bugprone-implicit-widening-of-multiplication-result
- -bugprone-signed-char-misuse
- -bugprone-unhandled-exception-at-new
- -bugprone-infinite-loop
- -bugprone-easily-swappable-parameters
- -bugprone-float-loop-counter #
- -bugprone-unchecked-string-to-number-conversion # Unfortunately no alternative
- -bugprone-branch-clone # Mostly warns about one-line duplicates
- cert-err52-cpp
- cert-err60-cpp
- cert-str34-c
- cert-dcl21-cpp
- cert-msc50-cpp
- cert-msc51-cpp
- cert-dcl58-cpp
- cppcoreguidelines-avoid-const-or-ref-data-members
- cppcoreguidelines-pro-type-member-init # We want to use default member initializers
- cppcoreguidelines-slicing
- cppcoreguidelines-interfaces-global-init
- -cppcoreguidelines-pro-type-static-cast-downcast # dynamic_cast has a runtime overhead
- -cppcoreguidelines-narrowing-conversions #
- google-runtime-operator
- google-explicit-constructor
- -google-default-arguments # Provider and ViewProvider read() is a good example of why this is useful
- hicpp-multiway-paths-covered
- hicpp-exception-baseclass
- misc-*
- -misc-definitions-in-headers
- -misc-unused-parameters
- -misc-unused-alias-decls
- -misc-use-anonymous-namespace
- -misc-misleading-identifier
- -misc-confusable-identifiers
- -misc-misleading-bidirectional
- -misc-static-assert
- -misc-no-recursion
- -misc-const-correctness
- -misc-use-internal-linkage # False positives if header where function is defined is not included
- -misc-include-cleaner # Allow indirect includes
- -misc-non-private-member-variables-in-classes #
- modernize-*
- -modernize-use-trailing-return-type
- -modernize-use-std-print # We want to use fmt::print instead
- -modernize-use-integer-sign-comparison # Too much occurrences to change
- openmp-use-default-none
- performance-*
- -performance-no-int-to-ptr
- portability-*
- -portability-restrict-system-includes
- readability-*
- -readability-redundant-preprocessor
- -readability-named-parameter
- -readability-function-size
- -readability-use-anyofallof
- -readability-identifier-length
- -readability-magic-numbers
- -readability-braces-around-statements
- -readability-suspicious-call-argument
- -readability-isolate-declaration
- -readability-else-after-return
- -readability-redundant-access-specifiers
- -readability-function-cognitive-complexity
- -readability-identifier-naming
- -readability-qualified-auto
- -readability-use-std-min-max # Less readable imo
- -readability-math-missing-parentheses # Basic math
- -readability-implicit-bool-conversion # Not much of a problem ?
- -readability-convert-member-functions-to-static #
- -readability-use-concise-preprocessor-directives # We do not use #ifdef
- -readability-uppercase-literal-suffix # Not important enough
- -readability-redundant-string-cstr # Sometimes used to stop at first null byte
- -readability-static-accessed-through-instance #
- -readability-ambiguous-smartptr-reset-call # Fix is hard to read
# Will fix later
- -modernize-avoid-c-arrays
- -readability-make-member-function-const # idk + lots of occurences
- -readability-misleading-indentation # We need to handle cases with #if defined()
- -bugprone-unchecked-optional-access
- -performance-unnecessary-value-param # idk
- -readability-avoid-nested-conditional-operator
# Generated from CLion Inspection settings
---
Checks: '-*,
mpi-*,
bugprone-*,
-bugprone-signal-handler,
-bugprone-narrowing-conversions,
-bugprone-redundant-branch-condition,
-bugprone-exception-escape,
-bugprone-shared-ptr-array-mismatch,
-bugprone-implicit-widening-of-multiplication-result,
-bugprone-signed-char-misuse,
-bugprone-unhandled-exception-at-new,
-bugprone-infinite-loop,
-bugprone-easily-swappable-parameters,
cert-err52-cpp,
cert-err60-cpp,
cert-err34-c,
cert-str34-c,
cert-dcl21-cpp,
cert-msc50-cpp,
cert-msc51-cpp,
cert-dcl58-cpp,
cert-flp30-c,
cppcoreguidelines-avoid-const-or-ref-data-members,
cppcoreguidelines-pro-type-member-init,
cppcoreguidelines-slicing,
cppcoreguidelines-interfaces-global-init,
cppcoreguidelines-pro-type-static-cast-downcast,
cppcoreguidelines-narrowing-conversions,
google-default-arguments,
google-runtime-operator,
google-explicit-constructor,
hicpp-multiway-paths-covered,
hicpp-exception-baseclass,
misc-*,
-misc-definitions-in-headers,
-misc-unused-parameters,
-misc-unused-alias-decls,
-misc-use-anonymous-namespace,
-misc-misleading-identifier,
-misc-confusable-identifiers,
-misc-misleading-bidirectional,
-misc-static-assert,
-misc-no-recursion,
-misc-const-correctness,
modernize-*,
-modernize-use-trailing-return-type,
openmp-use-default-none,
performance-*,
-performance-no-int-to-ptr,
portability-*,
-portability-restrict-system-includes,
readability-*,
-readability-redundant-preprocessor,
-readability-named-parameter,
-readability-function-size,
-readability-use-anyofallof,
-readability-identifier-length,
-readability-magic-numbers,
-readability-braces-around-statements,
-readability-suspicious-call-argument,
-readability-isolate-declaration,
-readability-else-after-return,
-readability-redundant-access-specifiers,
-readability-function-cognitive-complexity,
-readability-identifier-naming,
*-include-cleaner,
-readability-qualified-auto'

4
.github/FUNDING.yml vendored
View File

@@ -1,5 +1,5 @@
# Sponsor links
patreon: werwolv
custom: https://werwolv.net/donate
github: WerWolv
ko_fi: WerWolv
custom: "https://werwolv.net/donate"

View File

@@ -1,7 +0,0 @@
#!/bin/sh
set -xe
ARTIFACT_NAME="$1"
ARTIFACT_ID=$(gh api repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/artifacts --jq ".artifacts[] | select(.name==\"$ARTIFACT_NAME\") | .id")
gh api -X DELETE repos/$GITHUB_REPOSITORY/actions/artifacts/$ARTIFACT_ID
echo "Deleted artifact $ARTIFACT_NAME with ID $ARTIFACT_ID"

View File

@@ -49,16 +49,15 @@ jobs:
set -x
mkdir -p build
cd build
CC=gcc-14 CXX=g++-14 cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_EXCLUDE_PLUGINS="script_loader" \
-G Ninja \
CC=gcc-14 CXX=g++-14 cmake \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-G Ninja \
..
ninja install

View File

@@ -1,9 +1,5 @@
name: Build
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches:
@@ -27,10 +23,10 @@ jobs:
include:
- architecture_name: "x86_64"
msystem: "mingw64"
runner_os: "windows-2025"
runner_os: runs-on=${{ github.run_id }}/image=windows22-base-x64/family=c7a.16xlarge
- architecture_name: "arm64"
msystem: "clangarm64"
runner_os: "windows-11-arm"
runner_os: windows-11-arm
runs-on: ${{ matrix.runner_os }}
name: 🪟 Windows MSYS2 ${{ matrix.architecture_name }}
@@ -53,7 +49,7 @@ jobs:
submodules: recursive
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1
uses: hendrikmuhs/ccache-action@main
id: cache-ccache
with:
key: ${{ runner.os }}-mingw-ccache-${{ github.run_id }}
@@ -99,6 +95,7 @@ jobs:
-DIMHEX_GENERATE_PDBS=ON \
-DIMHEX_REPLACE_DWARF_WITH_PDB=ON \
-DDOTNET_EXECUTABLE="C:/Program Files/dotnet/dotnet.exe" \
-DCPACK_WIX_VERSION="4" \
-DCPACK_WIX_ROOT="$(echo "$USERPROFILE" | tr '\\' '/')/.dotnet/tools" \
..
@@ -109,8 +106,8 @@ jobs:
- name: 🕯️ Install WiX Toolkit
run: |
"C:/Program Files/dotnet/dotnet.exe" tool install --global wix@6.0.2
"$(echo "$USERPROFILE" | tr '\\' '/')/.dotnet/tools/wix" extension add --global WixToolset.UI.wixext/6.0.2
"C:/Program Files/dotnet/dotnet.exe" tool install --global wix
"$(echo "$USERPROFILE" | tr '\\' '/')/.dotnet/tools/wix" extension add -g WixToolset.UI.wixext
- name: 🪲 Create PDBs for MSI
run: |
@@ -169,7 +166,6 @@ jobs:
- name: ⬆️ Upload Windows Installer
uses: actions/upload-artifact@v4
id: upload-installer
with:
if-no-files-found: error
name: Windows Installer ${{ matrix.architecture_name }}
@@ -190,7 +186,7 @@ jobs:
run: |
set -x
echo "NoGPU version Powered by Mesa 3D : https://fdossena.com/?p=mesa%2Findex.frag" > build/install/MESA.md
curl --connect-timeout 30 --retry 5 --retry-delay 0 --retry-max-time 30 https://downloads.fdossena.com/geth.php?r=mesa64-latest -L -o mesa.7z
curl https://downloads.fdossena.com/geth.php?r=mesa64-latest -L -o mesa.7z
7z e mesa.7z
mv opengl32.dll build/install
@@ -210,10 +206,10 @@ jobs:
include:
- architecture_name: "x86_64"
vs_arch: "amd64"
runner_os: "windows-2025"
runner_os: runs-on=${{ github.run_id }}/image=windows22-base-x64/family=c7a.16xlarge
- architecture_name: "arm64"
vs_arch: "amd64_arm64"
runner_os: "windows-11-arm"
runner_os: windows-11-arm
runs-on: ${{ matrix.runner_os }}
name: 🪟 Windows MSVC ${{ matrix.architecture_name }}
@@ -237,7 +233,7 @@ jobs:
arch: ${{ matrix.vs_arch }}
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1
uses: hendrikmuhs/ccache-action@main
id: cache-ccache
with:
key: ${{ runner.os }}-msvc-${{ matrix.vs_arch }}-ccache-${{ github.run_id }}
@@ -246,7 +242,7 @@ jobs:
- name: 📦 Install vcpkg
uses: friendlyanon/setup-vcpkg@v1
with: { committish: 66c0373dc7fca549e5803087b9487edfe3aca0a1 }
with: { committish: ef7dbf94b9198bc58f45951adcf1f041fcbc5ea0 }
- name: ⬇️ Install dependencies
run: |
@@ -283,6 +279,7 @@ jobs:
-DIMHEX_COMMIT_HASH_LONG="$env:GITHUB_SHA" `
-DIMHEX_COMMIT_BRANCH="$($env:GITHUB_REF -replace '.*/', '')" `
-DDOTNET_EXECUTABLE="C:/Program Files/dotnet/dotnet.exe" `
-DCPACK_WIX_VERSION="4" `
-DCPACK_WIX_ROOT="$($env:USERPROFILE -replace '\\','/')/.dotnet/tools" `
.
@@ -293,8 +290,8 @@ jobs:
- name: 🕯️ Install WiX Toolkit
run: |
& "C:/Program Files/dotnet/dotnet.exe" tool install --global wix@6.0.2
& "$($env:USERPROFILE -replace '\\','/')/.dotnet/tools/wix" extension add --global WixToolset.UI.wixext/6.0.2
& "C:/Program Files/dotnet/dotnet.exe" tool install --global wix
& "$($env:USERPROFILE -replace '\\','/')/.dotnet/tools/wix" extension add -g WixToolset.UI.wixext
- name: 📦 Bundle MSI
run: |
@@ -319,7 +316,7 @@ jobs:
imhex-*.msi
win-plugin-template-test:
runs-on: windows-2022
runs-on: runs-on=${{ github.run_id }}/image=windows22-base-x64/family=c7a.16xlarge
name: 🧪 Plugin Template Test
defaults:
@@ -383,13 +380,24 @@ jobs:
# MacOS build
macos-x86:
runs-on: macos-15-intel
runs-on: macos-13
permissions:
id-token: write
attestations: write
name: 🍎 macOS 10.15 x86_64
strategy:
fail-fast: false
matrix:
include:
- file_suffix: "-NoGPU"
name_suffix: "NoGPU"
custom_glfw: true
- file_suffix: ""
name_suffix: ""
custom_glfw: false
name: 🍎 macOS 13 x86_64 ${{ matrix.name_suffix }}
steps:
- name: 🧰 Checkout
@@ -404,55 +412,76 @@ jobs:
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ runner.os }}-ccache-${{ github.run_id }}
restore-keys: ${{ runner.os }}-ccache
key: ${{ runner.os }}${{ matrix.file_suffix }}-ccache-${{ github.run_id }}
restore-keys: ${{ runner.os }}${{ matrix.file_suffix }}-ccache
max-size: 1G
- name: Set Xcode version
run: |
sudo xcode-select --install || true
sudo xcode-select -s /Library/Developer/CommandLineTools
- name: 📦 Install MacPorts
run: |
wget https://github.com/macports/macports-base/releases/download/v2.11.6/MacPorts-2.11.6-15-Sequoia.pkg
sudo installer -pkg MacPorts-2.11.6-15-Sequoia.pkg -target /
export PATH=/opt/local/bin:/opt/local/sbin:$PATH
echo "PATH=/opt/local/bin:/opt/local/sbin:$PATH" >> $GITHUB_ENV
echo "MACOSX_DEPLOYMENT_TARGET=10.15" >> $GITHUB_ENV
echo "universal_target 10.15" | sudo tee -a /opt/local/etc/macports/macports.conf
echo "macos_deployment_target 10.15" | sudo tee -a /opt/local/etc/macports/macports.conf
echo "macosx_sdk_version 10.15" | sudo tee -a /opt/local/etc/macports/macports.conf
sudo port selfupdate
run: sudo xcode-select -s /Library/Developer/CommandLineTools
- name: ⬇️ Install dependencies
env:
# Make brew not display useless errors
HOMEBREW_TESTS: 1
run: |
brew install llvm@21 automake
sudo -E port install mbedtls3 nlohmann-json ccache freetype libmagic pkgconfig curl glfw ninja zlib xz bzip2 zstd libssh2 md4c
brew reinstall python --quiet || true
brew link --overwrite --quiet python 2>/dev/null || true
brew bundle --quiet --file dist/macOS/Brewfile || true
rm -rf /usr/local/Cellar/capstone
- name: ⬇️ Install classic glfw
if: ${{! matrix.custom_glfw }}
run: |
brew install --quiet glfw || true
- name: ⬇️ Install .NET
uses: actions/setup-dotnet@v4
with:
dotnet-version: '8.0.100'
- name: 🧰 Checkout glfw
if: ${{ matrix.custom_glfw }}
uses: actions/checkout@v4
with:
repository: glfw/glfw
path: glfw
# GLFW custom build (to allow software rendering)
- name: ⬇️ Patch and install custom glfw
if: ${{ matrix.custom_glfw }}
run: |
set -x
cd glfw
git apply ../dist/macOS/0001-glfw-SW.patch
mkdir build
cd build
cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
..
ninja install
# MacOS cmake build
- name: 🛠️ Configure CMake
run: |
set -x
mkdir -p build
cd build
CC=$(brew --prefix llvm@21)/bin/clang \
CXX=$(brew --prefix llvm@21)/bin/clang++ \
OBJC=$(brew --prefix llvm@21)/bin/clang \
OBJCXX=$(brew --prefix llvm@21)/bin/clang++ \
CC=$(brew --prefix llvm)/bin/clang \
CXX=$(brew --prefix llvm)/bin/clang++ \
OBJC=$(brew --prefix llvm)/bin/clang \
OBJCXX=$(brew --prefix llvm)/bin/clang++ \
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
cmake -G "Ninja" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=10.15 \
-DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \
-DIMHEX_GENERATE_PACKAGE=ON \
-DIMHEX_SYSTEM_LIBRARY_PATH="$(brew --prefix llvm@21)/lib;$(brew --prefix llvm@21)/lib/unwind;$(brew --prefix llvm@21)/lib/c++;$(brew --prefix)/lib" \
-DIMHEX_SYSTEM_LIBRARY_PATH="$(brew --prefix llvm)/lib;$(brew --prefix llvm)/lib/unwind;$(brew --prefix llvm)/lib/c++;$(brew --prefix)/lib" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
@@ -470,6 +499,7 @@ jobs:
run: |
set -x
cd build/install
mv imhex.app ImHex.app
codesign --remove-signature ImHex.app
codesign --force --deep --sign - ImHex.app
@@ -498,7 +528,7 @@ jobs:
break;
fi
done
mv *.dmg ../../imhex-${{ env.IMHEX_VERSION }}-macOS-x86_64.dmg
mv *.dmg ../../imhex-${{ env.IMHEX_VERSION }}-macOS${{ matrix.file_suffix }}-x86_64.dmg
- name: 🗝️ Generate build provenance attestations
uses: actions/attest-build-provenance@v2
@@ -511,12 +541,12 @@ jobs:
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: macOS DMG x86_64
name: macOS DMG ${{ matrix.name_suffix }} x86_64
path: ./*.dmg
macos-arm64:
runs-on: ubuntu-24.04
name: 🍎 macOS 11 arm64
runs-on: runs-on=${{ github.run_id }}/runner=16cpu-linux-x64/image=ubuntu24-full-x64
name: 🍎 macOS 13 arm64
outputs:
IMHEX_VERSION: ${{ steps.build.outputs.IMHEX_VERSION }}
@@ -560,11 +590,11 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: |
gh extension install actions/gh-actions-cache
gh cache delete "macos-arm64-cache" --confirm || true
gh actions-cache delete "build-macos-arm64-cache" --confirm || true
macos-arm64-package:
runs-on: macos-15-intel
name: 🍎 macOS 11 arm64 Packaging
runs-on: macos-13
name: 🍎 macOS 13 arm64 Packaging
needs: macos-arm64
env:
@@ -590,6 +620,7 @@ jobs:
run: |
set -x
cd out
mv imhex.app ImHex.app
codesign --remove-signature ImHex.app
codesign --force --deep --entitlements Entitlements.plist --sign - ImHex.app
@@ -640,21 +671,15 @@ jobs:
fail-fast: false
matrix:
include:
- name: "Ubuntu"
release_num: "24.04"
image: "ubuntu:24.04"
- name: "Ubuntu"
release_num: "25.10"
image: "ubuntu:25.10"
- name: "Debian"
release_num: "13"
image: "debian:13"
- release_num: "24.04"
- release_num: "24.10"
- release_num: "25.04"
name: 🐧 ${{ matrix.name }} ${{ matrix.release_num }} x86_64
runs-on: ubuntu-24.04
name: 🐧 Ubuntu ${{ matrix.release_num }}
runs-on: runs-on=${{ github.run_id }}/runner=16cpu-linux-x64/image=ubuntu24-full-x64
container:
image: "${{ matrix.image }}"
image: "ubuntu:${{ matrix.release_num }}"
options: --privileged
permissions:
@@ -673,8 +698,8 @@ jobs:
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1
with:
key: ${{ matrix.image }}-ccache-${{ github.run_id }}
restore-keys: ${{ matrix.image }}-ccache
key: Ubuntu-${{ matrix.release_num }}-ccache-${{ github.run_id }}
restore-keys: Ubuntu-${{ matrix.release_num }}-ccache
max-size: 1G
- name: ⬇️ Install dependencies
@@ -719,7 +744,7 @@ jobs:
run: |
cp -r build/DEBIAN build/DebDir
dpkg-deb -Zzstd --build build/DebDir
mv build/DebDir.deb imhex-${{ env.IMHEX_VERSION }}-${{ matrix.name }}-${{ matrix.release_num }}-x86_64.deb
mv build/DebDir.deb imhex-${{ env.IMHEX_VERSION }}-Ubuntu-${{ matrix.release_num }}-x86_64.deb
- name: 🗝️ Generate build provenance attestations
uses: actions/attest-build-provenance@v2
@@ -732,7 +757,7 @@ jobs:
uses: actions/upload-artifact@v4
with:
if-no-files-found: error
name: ${{ matrix.name }} ${{ matrix.release_num }} DEB x86_64
name: Ubuntu ${{ matrix.release_num }} DEB x86_64
path: '*.deb'
# AppImage build
@@ -744,11 +769,11 @@ jobs:
- architecture: "x86_64"
architecture_package: "amd64"
architecture_appimage_builder: "x86_64"
image: ubuntu-24.04
image: runs-on=${{ github.run_id }}/runner=16cpu-linux-x64/image=ubuntu24-full-x64
- architecture: "arm64"
architecture_package: "arm64"
architecture_appimage_builder: "aarch64"
image: ubuntu-24.04-arm
image: runs-on=${{ github.run_id }}/runner=16cpu-linux-arm64/image=ubuntu24-full-arm64
runs-on: ${{ matrix.image }}
name: ⬇️ AppImage ${{ matrix.architecture }}
@@ -807,8 +832,8 @@ jobs:
# ArchLinux build
archlinux-build:
name: 🐧 ArchLinux x86_64
runs-on: ubuntu-24.04
name: 🐧 ArchLinux
runs-on: runs-on=${{ github.run_id }}/runner=16cpu-linux-x64/image=ubuntu24-full-x64
container:
image: archlinux:base-devel
@@ -923,11 +948,20 @@ jobs:
matrix:
include:
- name: Fedora
release_num: 43
mock_config: fedora-43
release_num: rawhide
mock_config: fedora-rawhide
- name: Fedora
release_num: 42
mock_config: fedora-42
- name: Fedora
release_num: 41
mock_config: fedora-41
- name: RHEL-AlmaLinux
release_num: 9
mock_config: "alma+epel-9"
name: 🐧 ${{ matrix.name }} ${{ matrix.release_num }} x86_64
runs-on: ubuntu-24.04
name: 🐧 ${{ matrix.name }} ${{ matrix.release_num }}
runs-on: runs-on=${{ github.run_id }}/runner=16cpu-linux-x64/image=ubuntu24-full-x64
container:
image: "almalinux:10"
@@ -1052,9 +1086,9 @@ jobs:
matrix:
include:
- architecture: "x86_64"
image: ubuntu-24.04
image: runs-on=${{ github.run_id }}/runner=16cpu-linux-x64/image=ubuntu24-full-x64
- architecture: "arm64"
image: ubuntu-24.04-arm
image: runs-on=${{ github.run_id }}/runner=16cpu-linux-arm64/image=ubuntu24-full-arm64
name: 🐧 Snap ${{ matrix.architecture }}
runs-on: ${{ matrix.image }}
@@ -1083,18 +1117,12 @@ jobs:
run: |
export IMHEX_VERSION=$(cat VERSION)
echo "IMHEX_VERSION=$IMHEX_VERSION" >> $GITHUB_ENV
if [[ "$IMHEX_VERSION" == *.WIP ]]; then
echo "IMHEX_VERSION_STRING=$IMHEX_VERSION-${GITHUB_RUN_NUMBER}" >> $GITHUB_ENV
else
echo "IMHEX_VERSION_STRING=$IMHEX_VERSION" >> $GITHUB_ENV
fi
echo "CCACHE=ccache" >> $GITHUB_ENV
- name: 📜 Move snap directory to root
run: |
mkdir -p ./snap
envsubst '${IMHEX_VERSION_STRING},${CCACHE}' < ./dist/snap/snapcraft.yaml > ./snap/snapcraft.yaml
envsubst '${IMHEX_VERSION},${CCACHE}' < ./dist/snap/snapcraft.yaml > ./snap/snapcraft.yaml
- name: 📜 Setup ccache
uses: hendrikmuhs/ccache-action@v1
@@ -1107,10 +1135,6 @@ jobs:
run: |
sudo snapcraft --destructive-mode
- name: 🟩 Rename Snap
run: |
mv *.snap imhex-${{ env.IMHEX_VERSION }}-${{ matrix.architecture }}.snap
- name: 🗝️ Generate build provenance attestations
uses: actions/attest-build-provenance@v2
if: ${{ github.event.repository.fork == false && github.event_name != 'pull_request' }}
@@ -1133,10 +1157,10 @@ jobs:
include:
- architecture: "x86_64"
flatpak_arch: "x86_64"
image: ubuntu-24.04
image: runs-on=${{ github.run_id }}/runner=16cpu-linux-x64/image=ubuntu24-full-x64
- architecture: "arm64"
flatpak_arch: "aarch64"
image: ubuntu-24.04-arm
image: runs-on=${{ github.run_id }}/runner=16cpu-linux-arm64/image=ubuntu24-full-arm64
name: 🐧 Flatpak ${{ matrix.architecture }}
runs-on: ${{ matrix.image }}
@@ -1187,8 +1211,12 @@ jobs:
imhex-${{ env.IMHEX_VERSION }}-${{ matrix.architecture }}.flatpak
webassembly-build:
runs-on: ubuntu-24.04
runs-on: runs-on=${{ github.run_id }}/runner=16cpu-linux-x64/image=ubuntu24-full-x64
name: 🌍 Web
permissions:
pages: write
id-token: write
actions: write
steps:
- name: 🧰 Checkout
uses: actions/checkout@v4
@@ -1208,20 +1236,17 @@ jobs:
cache-source: cache
cache-target: /cache
- name: 🔨 Copy necessary files
run: |
mkdir -p out/nightly
cp dist/web/serve.py out/nightly/start_imhex_web.py
- name: 🛠️ Build using docker
run: |
mkdir -p out/nightly
docker buildx build . -f dist/web/Dockerfile --progress=plain --build-arg 'JOBS=4' --output out/nightly --target raw
- name: ⬇️ Download Release artifact
- name: ⬇️ Download Release
if: ${{ github.event.repository.fork == false }}
env:
GH_TOKEN: ${{ github.token }}
run: gh --repo $GITHUB_REPOSITORY release download --pattern "imhex-*-Web.zip"
uses: robinraju/release-downloader@v1
with:
latest: true
fileName: 'imhex-*-Web.zip'
- name: 🔨 Fix permissions
if: ${{ github.event.repository.fork == false }}
@@ -1234,6 +1259,10 @@ jobs:
with:
path: out/
- name: 🔨 Copy necessary files
run: |
cp dist/web/serve.py out/nightly/start_imhex_web.py
- name: ⬆️ Upload package
uses: actions/upload-artifact@v4
with:
@@ -1252,7 +1281,7 @@ jobs:
webassembly-deploy:
environment:
name: ImHex Web
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
permissions:
pages: write
@@ -1265,64 +1294,11 @@ jobs:
needs: webassembly-build
steps:
- name: 🧰 Checkout
uses: actions/checkout@v4
- name: 🌍 Deploy WebAssembly Build to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
- name: 🗑️ Delete artifact
env:
GH_TOKEN: ${{ github.token }}
run: |
.github/scripts/delete-artifact.sh "github-pages"
webassembly-docker-image-deploy:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/master'
needs: webassembly-build
name: 🐋 Deploy to ghcr.io
permissions:
contents: read
packages: write
steps:
- name: 🧰 Checkout
uses: actions/checkout@v4
- name: ⬇️ Download artifact
uses: actions/download-artifact@v4
uses: geekyeggo/delete-artifact@v5
with:
name: ImHex Web
path: out
- name: 📜 Login to ghcr.io
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: ⛓️ Extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}/imhex-web
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha
- name: 🔨 Build and push Docker image
uses: docker/build-push-action@v6
env:
DOCKER_BUILD_RECORD_UPLOAD: false
with:
context: .
file: dist/web/Host.Dockerfile
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
name: github-pages

View File

@@ -1,47 +0,0 @@
# https://gist.github.com/iTrooz/d5bacca32c0974edc6c1ac3ad3ee82f3
# See https://github.com/cli/cli/issues/9125
# Extract archive with `tar -xf cache.tzst --transform 's@\.\./@#@g' -P` to avoid ../ errors
name: Download cache key
on:
workflow_dispatch:
inputs:
cache_key:
description: 'Cache key'
required: true
type: string
jobs:
cache-download:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Query cache version
id: version
env:
GH_TOKEN: ${{ github.token }}
run: |
VERSION=$(gh api repos/$GITHUB_REPOSITORY/actions/caches \
--jq "
.actions_caches[]
| select(.ref == \"refs/heads/$GITHUB_REF_NAME\")
| select(.key == \"${{ github.event.inputs.cache_key }}\")
| .version
")
echo "version=$VERSION" | tee $GITHUB_OUTPUT
- name: Restore cache
uses: iTrooz/cache/restore@restore_with_version
with:
# Path won't be actually used, we will match by 'version'.
path: .
key: ${{ github.event.inputs.cache_key }}
version: ${{ steps.version.outputs.version }}
- name: Upload cached folder as artifact
uses: actions/upload-artifact@v4
with:
name: cache-artifact
path: |
/home/runner/work/**/*.tzst

View File

@@ -11,7 +11,8 @@ on:
jobs:
nightly-release:
runs-on: ubuntu-24.04
name: 🌃 Update Nightly Release
name: Update Nightly Release
steps:
- name: 🧰 Checkout
uses: actions/checkout@v4
@@ -21,35 +22,27 @@ jobs:
fetch-tags: true
- name: 🌃 Check for new commits
id: check_commits
run: |
cd ImHex
git config --global --add safe.directory $(pwd)
if [ -z "$(git log nightly..HEAD --oneline)" ]; then
echo "No new commits since last nightly. Exiting."
echo "::set-output name=should_run::false"
else
echo "::set-output name=should_run::true"
exit 0
fi
- name: 📜 Set version variable
if: ${{ steps.check_commits.outputs.should_run == 'true' }}
run: |
project_version=`cat ImHex/VERSION`
echo "IMHEX_VERSION=$project_version" >> $GITHUB_ENV
# TODO: Replace by Github CLI when github.com/cli/cli/pull/12435 is closed
- name: ⬇️ Download artifacts from latest workflow
uses: dawidd6/action-download-artifact@v6
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
workflow: build.yml
branch: master
branch: ${{ github.event.release.target_commitish }}
workflow_conclusion: success
skip_unpack: true
- name: 🗜️ Unzip files when needed
if: ${{ steps.check_commits.outputs.should_run == 'true' }}
run: |
set -x
for zipfile in ./*.zip
@@ -65,33 +58,32 @@ jobs:
done
- name: 🟩 Rename artifacts when needed
if: ${{ steps.check_commits.outputs.should_run == 'true' }}
run: |
mv "Windows Portable x86_64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-x86_64.zip
mv "Windows Portable arm64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-arm64.zip
mv "Windows Portable NoGPU x86_64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-NoGPU-x86_64.zip
mv "ImHex Web.zip" imhex-${{ env.IMHEX_VERSION }}-Web.zip
mv ./*_amd64.snap $(echo ./*_amd64.snap | sed 's/_amd64\.snap$/-x86_64.snap/' | sed 's/_/-/1')
mv ./*_arm64.snap $(echo ./*_arm64.snap | sed 's/_arm64\.snap$/-arm64.snap/' | sed 's/_/-/1')
rm artifact.tar || true
- name: 📖 Generate Release Notes
if: ${{ steps.check_commits.outputs.should_run == 'true' }}
id: release_notes
continue-on-error: true
run: |
cd ImHex
echo "## Nightly ${GITHUB_SHA::7} Changelog" > changelog.md
git fetch --tags --recurse-submodules=no
git log nightly..origin/master --oneline --no-merges --pretty=format:'* %s' >> changelog.md
git log nightly..HEAD --oneline --no-merges --pretty=format:'* %s' >> changelog.md
- name: 📦 Update Pre-Release
if: ${{ steps.check_commits.outputs.should_run == 'true' }}
run: |
set -e
cd ImHex
# Move nightly tag to latest commit
git tag -f nightly origin/master
git tag -f nightly HEAD
git push origin nightly --force
# Auth for GitHub CLI
@@ -109,8 +101,6 @@ jobs:
gh release upload nightly ../*.* --clobber
- name: ⬆️ Publish x86_64 Snap package
if: ${{ steps.check_commits.outputs.should_run == 'true' }}
continue-on-error: true
uses: snapcore/action-publish@v1
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_STORE_LOGIN }}
@@ -119,26 +109,9 @@ jobs:
release: edge
- name: ⬆️ Publish arm64 Snap package
if: ${{ steps.check_commits.outputs.should_run == 'true' }}
continue-on-error: true
uses: snapcore/action-publish@v1
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_STORE_LOGIN }}
with:
snap: imhex-${{ env.IMHEX_VERSION }}-arm64.snap
release: edge
website_update:
name: 🌍 Update ImHex Landing Website
needs: nightly-release
runs-on: ubuntu-24.04
env:
WEBSITE_DISPATCH_TOKEN: ${{ secrets.WEBSITE_DISPATCH_TOKEN }}
steps:
- name: ✉️ Dispatch Landing page update
if: ${{ env.WEBSITE_DISPATCH_TOKEN != '' }}
uses: peter-evans/repository-dispatch@v4
with:
token: ${{ secrets.WEBSITE_DISPATCH_TOKEN }}
repository: WerWolv/ImHexWebsite
event-type: update_page
release: edge

View File

@@ -7,12 +7,6 @@ on:
release:
types: [published]
workflow_dispatch:
inputs:
commit_hash:
type: string
description: 'The commit hash to build (defaults to the latest commit on the default branch)'
required: false
default: ''
jobs:
release-update-repos:
@@ -31,7 +25,7 @@ jobs:
project_version=`cat ImHex/VERSION`
tag_version="${{github.event.release.tag_name}}"
tag_version="${tag_version:1}"
if [ "$project_version" != "$tag_version" ] && [ ! -z "$tag_version" ]; then
if [ "$project_version" != "$tag_version" ]; then
echo "::warning::$project_version and $tag_version are not the same ! Refusing to populate release"
exit 1
fi
@@ -47,7 +41,6 @@ jobs:
tag: ImHex-v${{ env.IMHEX_VERSION }}
repo: PatternLanguage
token: ${{ secrets.RELEASE_TOKEN }}
skipIfReleaseExists: true
- name: 🎫 Create ImHex-Patterns release
uses: ncipollo/release-action@v1
@@ -58,7 +51,6 @@ jobs:
tag: ImHex-v${{ env.IMHEX_VERSION }}
repo: ImHex-Patterns
token: ${{ secrets.RELEASE_TOKEN }}
skipIfReleaseExists: true
- name: 🎫 Create imhex-download-sdk release
uses: ncipollo/release-action@v1
@@ -69,13 +61,11 @@ jobs:
tag: v${{ env.IMHEX_VERSION }}
repo: imhex-download-sdk
token: ${{ secrets.RELEASE_TOKEN }}
skipIfReleaseExists: true
release-upload-artifacts:
runs-on: ubuntu-24.04
name: Release Upload Artifacts
outputs:
IMHEX_VERSION: ${{ steps.verify_version.outputs.IMHEX_VERSION }}
steps:
- name: 🧰 Checkout
uses: actions/checkout@v4
@@ -84,19 +74,17 @@ jobs:
submodules: recursive
- name: 📜 Verify version and set version variable
id: verify_version
run: |
set -x
project_version=`cat ImHex/VERSION`
tag_version="${{github.event.release.tag_name}}"
tag_version="${tag_version:1}"
if [ "$project_version" != "$tag_version" ] && [ ! -z "$tag_version" ]; then
if [ "$project_version" != "$tag_version" ]; then
echo "::warning::$project_version and $tag_version are not the same ! Refusing to populate release"
exit 1
fi
echo "IMHEX_VERSION=$project_version" >> $GITHUB_ENV
echo "IMHEX_VERSION=$project_version" >> $GITHUB_OUTPUT
- name: 🗜️ Create tarball from sources with dependencies
run: tar --exclude-vcs -czvf Full.Sources.tar.gz ImHex
@@ -109,7 +97,6 @@ jobs:
branch: ${{ github.event.release.target_commitish }}
workflow_conclusion: success
skip_unpack: true
commit: ${{ github.event.inputs.commit_hash }}
- name: 🗜️ Unzip files when needed
run: |
@@ -128,87 +115,27 @@ jobs:
- name: 🟩 Rename artifacts when needed
run: |
mv "Windows Portable x86_64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-x86_64.zip || true
mv "Windows Portable arm64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-arm64.zip || true
mv "Windows Portable NoGPU x86_64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-NoGPU-x86_64.zip || true
mv "ImHex Web.zip" imhex-${{ env.IMHEX_VERSION }}-Web.zip || true
mv "Windows Portable x86_64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-x86_64.zip
mv "Windows Portable arm64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-arm64.zip
mv "Windows Portable NoGPU x86_64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-NoGPU-x86_64.zip
mv ./*_amd64.snap $(echo ./*_amd64.snap | sed 's/_amd64\.snap$/-x86_64.snap/' | sed 's/_/-/1')
mv ./*_arm64.snap $(echo ./*_arm64.snap | sed 's/_arm64\.snap$/-arm64.snap/' | sed 's/_/-/1')
mv "ImHex Web.zip" imhex-${{ env.IMHEX_VERSION }}-Web.zip
rm artifact.tar || true
- name: ⬆️ Upload Unsigned x86_64 Windows Installer
uses: actions/upload-artifact@v4
id: upload-installer-x86_64
with:
if-no-files-found: error
name: Windows Installer x86_64
path: |
imhex-*-x86_64.msi
- name: ⬆️ Upload Unsigned ARM64 Windows Installer
if: false
uses: actions/upload-artifact@v4
id: upload-installer-arm64
with:
if-no-files-found: error
name: Windows Installer ARM64
path: |
imhex-*-arm64.msi
- name: 🗑️ Delete unsigned installers
run: |
rm imhex-*-x86_64.msi
- name: 🗝️ Sign x86_64 Installer
uses: signpath/github-action-submit-signing-request@v1
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: 'f605a0e8-86cd-411c-bb6f-e05025afcc33'
project-slug: 'ImHex'
signing-policy-slug: 'release-signing'
github-artifact-id: '${{ steps.upload-installer-x86_64.outputs.artifact-id }}'
wait-for-completion: true
output-artifact-directory: '.'
- name: 🗝️ Sign ARM64 Installer
if: false
uses: signpath/github-action-submit-signing-request@v1
with:
api-token: '${{ secrets.SIGNPATH_API_TOKEN }}'
organization-id: 'f605a0e8-86cd-411c-bb6f-e05025afcc33'
project-slug: 'ImHex'
signing-policy-slug: 'release-signing'
github-artifact-id: '${{ steps.upload-installer-arm64.outputs.artifact-id }}'
wait-for-completion: true
output-artifact-directory: '.'
- name: ⬆️ Upload everything to release
uses: softprops/action-gh-release@4634c16e79c963813287e889244c50009e7f0981
with:
files: '*'
release-update-aur:
name: Release update AUR package
needs: release-upload-artifacts
runs-on: ubuntu-24.04
steps:
- name: 🧰 Checkout
uses: actions/checkout@v4
with:
path: ImHex
- name: ⬇️ Download artifacts
run: |
tagname=${GITHUB_REF#refs/tags/}
version=${tagname#v}
wget https://github.com/WerWolv/ImHex/releases/download/${tagname}/imhex-${version}-ArchLinux-x86_64.pkg.tar.zst
- name: ✒️ Prepare PKGBUILD
run: |
set -x
cp ImHex/dist/Arch/PKGBUILD .
hash=`md5sum imhex-${{ needs.release-upload-artifacts.outputs.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst | cut -d ' ' -f 1`
hash=`md5sum imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst | cut -d ' ' -f 1`
sed -i 's/%version%/${{ needs.release-upload-artifacts.outputs.IMHEX_VERSION }}/g' PKGBUILD
sed -i 's/%version%/${{ env.IMHEX_VERSION }}/g' PKGBUILD
sed -i "s/(SKIP)/($hash)/g" PKGBUILD
- name: ⬆️ Publish AUR package
@@ -222,9 +149,9 @@ jobs:
pkgname: imhex-bin
pkgbuild: ./PKGBUILD
commit_username: iTrooz
commit_email: hey@itrooz.fr
commit_email: itrooz@protonmail.com
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
commit_message: Bump to version ${{ needs.release-upload-artifacts.outputs.IMHEX_VERSION }}
commit_message: Bump to version ${{ env.IMHEX_VERSION }}
ssh_keyscan_types: rsa,ecdsa,ed25519
release-update-winget:
@@ -236,7 +163,6 @@ jobs:
shell: pwsh
run: |
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
- name: ⬆️ Update winget manifest
shell: pwsh
env:
@@ -254,7 +180,7 @@ jobs:
release-update-snapstore:
name: Release update snapstore package
needs: release-upload-artifacts
runs-on: ubuntu-24.04
runs-on: ubuntu-20.04
steps:
- name: ⬇️ Download artifacts
run: |
@@ -264,19 +190,17 @@ jobs:
wget https://github.com/WerWolv/ImHex/releases/download/${tagname}/imhex-${version}-arm64.snap
- name: ⬆️ Publish x86_64 Snap package
continue-on-error: true
uses: snapcore/action-publish@v1
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_STORE_LOGIN }}
with:
snap: imhex-${{ needs.release-upload-artifacts.outputs.IMHEX_VERSION }}-x86_64.snap
snap: imhex-${{ env.IMHEX_VERSION }}-x86_64.snap
release: stable
- name: ⬆️ Publish arm64 Snap package
continue-on-error: true
uses: snapcore/action-publish@v1
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_STORE_LOGIN }}
with:
snap: imhex-${{ needs.release-upload-artifacts.outputs.IMHEX_VERSION }}-arm64.snap
snap: imhex-${{ env.IMHEX_VERSION }}-arm64.snap
release: stable

2
.gitignore vendored
View File

@@ -12,8 +12,6 @@
/install/
/out/
/dist/ImHex.run.xml
*.mgc
*.kdev4
imgui.ini

6
.gitmodules vendored
View File

@@ -18,6 +18,10 @@
path = lib/third_party/capstone
url = https://github.com/capstone-engine/capstone
ignore = dirty
[submodule "lib/third_party/jthread/jthread"]
path = lib/third_party/jthread/jthread
url = https://github.com/josuttis/jthread
ignore = dirty
[submodule "lib/third_party/edlib"]
path = lib/third_party/edlib
url = https://github.com/Martinsos/edlib
@@ -45,4 +49,4 @@
url = https://github.com/WerWolv/Disassembler
[submodule "lib/third_party/md4c"]
path = lib/third_party/md4c
url = https://github.com/mity/md4c
url = https://github.com/mity/md4c

View File

@@ -1,39 +1,33 @@
cmake_minimum_required(VERSION 3.25)
# Options
## General
option(IMHEX_PLUGINS_IN_SHARE "Put the plugins in share/imhex/plugins instead of lib[..]/imhex/plugins (Linux only)" OFF)
option(IMHEX_STRIP_RELEASE "Strip the release builds" ON )
option(IMHEX_OFFLINE_BUILD "Enable offline build" 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_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_DISABLE_STACKTRACE "Disables support for printing stack traces" OFF)
option(IMHEX_BUNDLE_DOTNET "Bundle .NET runtime" ON )
option(IMHEX_ENABLE_LTO "Enables Link Time Optimizations if possible" 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_BUILD_HARDENING "Enable hardening flags for build" ON )
option(IMHEX_GENERATE_PACKAGE "Specify if a cpack package should be built. (Windows only)" OFF)
option(IMHEX_MACOS_CREATE_BUNDLE "Creates a macOS .app bundle when building (macOS only)" ON )
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_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" ON )
option(IMHEX_ENABLE_PLUGIN_TESTS "Enable building plugin tests" ON )
option(IMHEX_ENABLE_IMGUI_TEST_ENGINE "Enable the ImGui Test Engine" OFF)
option(IMHEX_ENABLE_PRECOMPILED_HEADERS "Enable precompiled headers" OFF)
option(IMHEX_COMPRESS_DEBUG_INFO "Compress debug information" ON )
option(IMHEX_ENABLE_CXX_MODULES "Enable C++20 Module compilation. Testing only!" OFF)
option(IMHEX_ENABLE_CPPCHECK "Enable cppcheck static analysis" OFF)
option(IMHEX_BUNDLE_PLUGIN_SDK "Enable bundling of Plugin SDK into install package" ON )
## Testing
option(IMHEX_ENABLE_UNIT_TESTS "Enable building unit tests" ON )
option(IMHEX_ENABLE_IMGUI_TEST_ENGINE "Enable the ImGui Test Engine" OFF)
option(IMHEX_ENABLE_STD_ASSERTS "Enable debug asserts in the C++ std library. (Breaks Plugin ABI!)" OFF)
## Debug info
option(IMHEX_COMPRESS_DEBUG_INFO "Compress debug information" ON )
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_STRICT_WARNINGS "Enable most available warnings and treat them as errors" ON )
option(IMHEX_DISABLE_STACKTRACE "Disables support for printing stack traces" OFF)
## Plugins
option(IMHEX_STATIC_LINK_PLUGINS "Statically link all plugins into the main executable" OFF)
option(IMHEX_ENABLE_PLUGIN_TESTS "Enable building plugin tests" ON )
option(IMHEX_INCLUDE_PLUGINS "Semicolon-separated list of plugins to include in the build (empty = build all)" "" )
option(IMHEX_EXCLUDE_PLUGINS "Semicolon-separated list of plugins to exclude from the build" "" )
set(IMHEX_BASE_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}")
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
@@ -53,7 +47,7 @@ loadVersion(IMHEX_VERSION IMHEX_VERSION_PLAIN)
setVariableInParent(IMHEX_VERSION ${IMHEX_VERSION})
configureCMake()
project(ImHex
project(imhex
LANGUAGES C CXX
VERSION ${IMHEX_VERSION_PLAIN}
DESCRIPTION "The ImHex Hex Editor"

View File

@@ -59,14 +59,13 @@
{
"name": "vs2022-x86",
"displayName": "Visual Studio 2022 x86",
"generator": "Ninja",
"generator": "Visual Studio 17 2022",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_BUILD_TYPE": "Debug",
"CMAKE_GENERATOR_PLATFORM": "Win32",
"CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake",
"VCPKG_MANIFEST_DIR": "${sourceDir}/dist"
},
"environment": {
"VSCMD_ARG_TGT_ARCH": "x86"
}
}
],

View File

@@ -29,23 +29,14 @@
## Supporting
If you like my work, please consider supporting me on GitHub Sponsors, Ko-Fi 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">
<a href="https://github.com/sponsors/WerWolv"><img src="https://werwolv.net/assets/github_banner.png" alt="GitHub donate button" /></a>
<a href="https://ko-fi.com/WerWolv"><img src="https://werwolv.net/assets/kofi_banner.png" alt="Ko-Fi 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>
</p>
### Notable Sponsors
| | |
|:---------------------------------------------------------------------------------------------------:|-----------------------------------------------------------------------------------|
| [![JetBrains logo](https://avatars.githubusercontent.com/u/878437?s=48)](https://www.jetbrains.com) | JetBrains, providing us with free All Products Pack licenses for development |
| [![SignPath logo](https://avatars.githubusercontent.com/u/34448643?s=48)](https://signpath.io/) | SignPath, providing us with free Code Signing Certificates for our Windows builds |
| [![AWS logo](https://avatars.githubusercontent.com/u/2232217?s=48)](https://aws.amazon.com) | Amazon, providing us with free AWS Cloud Credits for our CI |
Would you like to appear here as well? Contact us at [imhex@werwolv.net](mailto:imhex@werwolv.net)!
## Screenshots
![Hex editor, patterns and data information](https://github.com/user-attachments/assets/902a7c4c-410d-490f-999e-14c856fec027)
![Bookmarks, data information, find view and data processor](https://github.com/user-attachments/assets/58eefa1f-31c9-4bb8-a1c1-8cdd8ddbd29f)
@@ -336,8 +327,8 @@ To use ImHex, the following minimal system requirements need to be met.
- **OS**:
- **Windows**: Windows 7 or higher (Windows 10/11 recommended)
- **macOS**: macOS 15 (Sequoia) or higher,
- Lower versions should still work too, but you'll need to compile ImHex yourself. The release binaries will NOT work due to GitHub not having any macOS 15 or lower CI runners available.
- **macOS**: macOS 13 (Ventura) or higher,
- Lower versions should still work too, but you'll need to compile ImHex yourself. The release binaries will NOT work due to GitHub not having any macOS 12 or lower CI runners available.
- The macOS build is not signed and will require you to manually allow them in the Security & Privacy settings.
- **Linux**: "Modern" Linux. The following distributions have official releases available. Other distros are supported through the AppImage, Flatpak and Snap releases.
- Ubuntu and Debian
@@ -375,20 +366,9 @@ For more information, check out the [Compiling](/dist/compiling) guide.
## Contributing
See [Contributing](/CONTRIBUTING.md)
## 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 build a plugin, you will need to use our SDK
### Getting the SDK locally
You can build the SDK by compiling ImHex like this:
- `cmake -G Ninja -DIMHEX_BUNDLE_PLUGIN_SDK=ON -B build`
- `cd build`
- `DESTDIR=install ninja install`
The SDK will then be available at `install/usr/local/share/imhex/sdk`. You will need to set the variable `IMHEX_SDK_PATH` to that (absolute) path.
### Getting the SDK in a Github Actions CI
You can use [this action](https://github.com/WerWolv/imhex-download-sdk) to automatically download the SDK to your Github Runner
- [ImHex Plugin Template](https://github.com/WerWolv/ImHex-Plugin-Template)
@@ -430,18 +410,3 @@ Notable exceptions to this are the following parts which are under the LGPLv2.1
- **/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.
### Code Signing Policy
Free code signing provided by [SignPath.io](https://about.signpath.io/),
certificate by [SignPath Foundation](https://signpath.org/).
This program will not transfer any information to other networked systems
unless specifically requested by the user or the person installing or
operating it.
#### People with direct push access
- [WerWolv](https://github.com/WerWolv)
- [iTrooz](https://github.com/iTrooz)
- [jumanji144](https://github.com/jumanji144)
- [AxCut](https://github.com/paxcut)

View File

@@ -1 +1 @@
1.39.0.WIP
1.38.0.WIP

View File

View File

@@ -175,11 +175,15 @@ macro(detectOS)
endif()
include(GNUInstallDirs)
set(PLUGINS_INSTALL_LOCATION "${CMAKE_INSTALL_LIBDIR}/imhex/plugins")
if(IMHEX_PLUGINS_IN_SHARE)
set(PLUGINS_INSTALL_LOCATION "share/imhex/plugins")
else()
set(PLUGINS_INSTALL_LOCATION "${CMAKE_INSTALL_LIBDIR}/imhex/plugins")
# Add System plugin location for plugins to be loaded from
# 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")
# Add System plugin location for plugins to be loaded from
# 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()
else ()
message(FATAL_ERROR "Unknown / unsupported system!")
@@ -201,18 +205,11 @@ macro(configurePackingResources)
set(CPACK_GENERATOR "WIX")
set(CPACK_PACKAGE_NAME "ImHex")
set(CPACK_PACKAGE_VENDOR "WerWolv")
set(CPACK_WIX_VERSION 4)
set(CPACK_WIX_PRODUCT_GUID "*")
set(CPACK_WIX_UPGRADE_GUID "05000E99-9659-42FD-A1CF-05C554B39285")
set(CPACK_WIX_PRODUCT_ICON "${PROJECT_SOURCE_DIR}/resources/dist/windows/icon.ico")
set(CPACK_WIX_UI_BANNER "${PROJECT_SOURCE_DIR}/resources/dist/windows/wix_banner.png")
set(CPACK_WIX_UI_DIALOG "${PROJECT_SOURCE_DIR}/resources/dist/windows/wix_dialog.png")
set(CPACK_WIX_CULTURES "en-US;de-DE;ja-JP;it-IT;pt-BR;zh-CN;zh-TW;ru-RU")
set(CPACK_WIX_TEMPLATE "${PROJECT_SOURCE_DIR}/resources/dist/windows/WIX.template.in")
set(CPACK_WIX_EXTENSIONS "WixToolset.UI.wixext")
file(GLOB_RECURSE CPACK_WIX_EXTRA_SOURCES "${PROJECT_SOURCE_DIR}/resources/dist/windows/wix/*.wxs")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "ImHex")
set_property(INSTALL "$<TARGET_FILE_NAME:main>"
PROPERTY CPACK_START_MENU_SHORTCUTS "ImHex"
@@ -221,9 +218,9 @@ macro(configurePackingResources)
endif()
elseif (APPLE OR ${CMAKE_HOST_SYSTEM_NAME} MATCHES "Darwin")
set(IMHEX_ICON "${IMHEX_BASE_FOLDER}/resources/dist/macos/AppIcon.icns")
set(BUNDLE_NAME "ImHex.app")
set(BUNDLE_NAME "imhex.app")
if (IMHEX_MACOS_CREATE_BUNDLE)
if (IMHEX_GENERATE_PACKAGE)
set(APPLICATION_TYPE MACOSX_BUNDLE)
set_source_files_properties(${IMHEX_ICON} PROPERTIES MACOSX_PACKAGE_LOCATION "Resources")
set(MACOSX_BUNDLE_ICON_FILE "AppIcon.icns")
@@ -239,9 +236,9 @@ macro(configurePackingResources)
string(TIMESTAMP CURR_YEAR "%Y")
set(MACOSX_BUNDLE_COPYRIGHT "Copyright © 2020 - ${CURR_YEAR} WerWolv. All rights reserved." )
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}/${BUNDLE_NAME}")
else ()
set(IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/${BUNDLE_NAME}")
set (IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/${BUNDLE_NAME}")
endif()
set(PLUGINS_INSTALL_LOCATION "${IMHEX_BUNDLE_PATH}/Contents/MacOS/plugins")
@@ -259,7 +256,7 @@ macro(addPluginDirectories)
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${IMHEX_MAIN_OUTPUT_DIRECTORY}/plugins")
if (APPLE)
if (IMHEX_MACOS_CREATE_BUNDLE)
if (IMHEX_GENERATE_PACKAGE)
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PLUGINS_INSTALL_LOCATION})
endif ()
else ()
@@ -315,7 +312,7 @@ macro(createPackage)
POST_EXCLUDE_REGEXES ".*system32/.*\\.dll"
)
if(_c_deps_FILENAMES AND _c_deps AND NOT (_c_deps STREQUAL ""))
if(_c_deps_FILENAMES AND NOT _c_deps STREQUAL "")
message(WARNING "Conflicting dependencies for library: \"${_c_deps}\"!")
endif()
@@ -336,47 +333,41 @@ macro(createPackage)
downloadImHexPatternsFiles(".")
elseif(UNIX AND NOT APPLE)
set_target_properties(libimhex PROPERTIES SOVERSION ${IMHEX_VERSION})
configure_file(${IMHEX_BASE_FOLDER}/dist/DEBIAN/control.in ${CMAKE_BINARY_DIR}/DEBIAN/control)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/dist/DEBIAN/control.in ${CMAKE_BINARY_DIR}/DEBIAN/control)
install(FILES ${IMHEX_BASE_FOLDER}/LICENSE DESTINATION ${CMAKE_INSTALL_PREFIX}/share/licenses/imhex)
install(FILES ${IMHEX_BASE_FOLDER}/dist/imhex.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
install(FILES ${IMHEX_BASE_FOLDER}/dist/imhex.mime.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/mime/packages RENAME imhex.xml)
install(FILES ${IMHEX_BASE_FOLDER}/resources/icon.svg DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.svg)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_INSTALL_PREFIX}/share/licenses/imhex)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dist/imhex.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dist/imhex.mime.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/mime/packages RENAME imhex.xml)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/icon.svg DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.svg)
downloadImHexPatternsFiles("./share/imhex")
# install AppStream file
install(FILES ${IMHEX_BASE_FOLDER}/dist/net.werwolv.ImHex.metainfo.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/metainfo)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dist/net.werwolv.ImHex.metainfo.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/metainfo)
endif()
if (APPLE)
if (IMHEX_MACOS_CREATE_BUNDLE)
if (IMHEX_GENERATE_PACKAGE)
set(EXTRA_BUNDLE_LIBRARY_PATHS ${EXTRA_BUNDLE_LIBRARY_PATHS} "${IMHEX_SYSTEM_LIBRARY_PATH}")
include(PostprocessBundle)
set_target_properties(libimhex PROPERTIES SOVERSION ${IMHEX_VERSION})
set_property(TARGET main PROPERTY MACOSX_BUNDLE_INFO_PLIST ${MACOSX_BUNDLE_INFO_PLIST})
set_property(TARGET main PROPERTY MACOSX_BUNDLE_BUNDLE_NAME "${MACOSX_BUNDLE_BUNDLE_NAME}")
# Fix rpath
install(CODE "execute_process(COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath \"@executable_path/../Frameworks/\" $<TARGET_FILE:main>)")
install(CODE "execute_process(COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath \"@executable_path/../Frameworks/\" $<TARGET_FILE:updater>)")
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("${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}/Contents/MacOS")
install(FILES ${IMHEX_ICON} DESTINATION "${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}/Contents/Resources")
install(TARGETS main BUNDLE DESTINATION ".")
install(TARGETS updater DESTINATION "${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}/Contents/MacOS")
install(
FILES ${IMHEX_BASE_FOLDER}/dist/cli/imhex.sh
DESTINATION "${CMAKE_INSTALL_PREFIX}/${BUNDLE_NAME}/Contents/MacOS/cli"
RENAME imhex
PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE
)
install(TARGETS updater BUNDLE DESTINATION ".")
# Update library references to make the bundle portable
postprocess_bundle(imhex_all main)
@@ -407,31 +398,9 @@ macro(createPackage)
if (TARGET main-forwarder)
install(TARGETS main-forwarder BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR})
endif()
if (WIN32)
install(
FILES ${IMHEX_BASE_FOLDER}/dist/cli/imhex.bat
DESTINATION ${CMAKE_INSTALL_BINDIR}/cli
RENAME imhex.bat
PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE
)
else()
install(
FILES ${IMHEX_BASE_FOLDER}/dist/cli/imhex.sh
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/imhex
RENAME imhex
PERMISSIONS
OWNER_READ OWNER_WRITE OWNER_EXECUTE
GROUP_READ GROUP_EXECUTE
WORLD_READ WORLD_EXECUTE
)
endif()
endif()
if (IMHEX_MACOS_CREATE_BUNDLE)
if (IMHEX_GENERATE_PACKAGE)
set(CPACK_BUNDLE_NAME "ImHex")
include(CPack)
@@ -560,9 +529,6 @@ function(detectBadClone)
file (GLOB EXTERNAL_DIRS "lib/external/*" "lib/third_party/*")
foreach (EXTERNAL_DIR ${EXTERNAL_DIRS})
if(NOT IS_DIRECTORY "${EXTERNAL_DIR}")
continue()
endif()
file(GLOB_RECURSE RESULT "${EXTERNAL_DIR}/*")
list(LENGTH RESULT ENTRY_COUNT)
if(ENTRY_COUNT LESS_EQUAL 1)
@@ -590,9 +556,7 @@ endfunction()
macro(detectBundledPlugins)
file(GLOB PLUGINS_DIRS "plugins/*")
if (IMHEX_INCLUDE_PLUGINS)
set(PLUGINS ${IMHEX_INCLUDE_PLUGINS})
else()
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)
@@ -601,6 +565,8 @@ macro(detectBundledPlugins)
endif ()
endif()
endforeach()
else()
set(PLUGINS ${IMHEX_INCLUDE_PLUGINS})
endif()
foreach(PLUGIN_NAME ${PLUGINS})
@@ -611,13 +577,9 @@ macro(detectBundledPlugins)
message(FATAL_ERROR "No bundled plugins enabled")
endif()
set(REQUIRED_PLUGINS builtin fonts ui)
foreach(PLUGIN ${REQUIRED_PLUGINS})
list(FIND PLUGINS ${PLUGIN} PLUGIN_INDEX)
if (PLUGIN_INDEX EQUAL -1)
message(FATAL_ERROR "Required plugin '${PLUGIN}' is not enabled!")
endif()
endforeach()
if (NOT ("builtin" IN_LIST PLUGINS))
message(FATAL_ERROR "The 'builtin' plugin is required for ImHex to work!")
endif ()
endmacro()
macro(setVariableInParent variable value)
@@ -643,15 +605,17 @@ function(downloadImHexPatternsFiles dest)
install(CODE "set(imhex_patterns_SOURCE_DIR \"${imhex_patterns_SOURCE_DIR}\")")
install(CODE [[
message(STATUS "Downloading ImHex patterns from branch '${PATTERNS_BRANCH}'...")
if (NOT EXISTS "${imhex_patterns_SOURCE_DIR}")
if (EXISTS "${imhex_patterns_SOURCE_DIR}")
file(REMOVE_RECURSE "${imhex_patterns_SOURCE_DIR}")
else ()
file(MAKE_DIRECTORY "${imhex_patterns_SOURCE_DIR}")
execute_process(
COMMAND
git clone --recurse-submodules --branch ${PATTERNS_BRANCH} https://github.com/WerWolv/ImHex-Patterns.git "${imhex_patterns_SOURCE_DIR}"
COMMAND_ERROR_IS_FATAL ANY
)
endif()
execute_process(
COMMAND
git clone --recurse-submodules --branch ${PATTERNS_BRANCH} https://github.com/WerWolv/ImHex-Patterns.git "${imhex_patterns_SOURCE_DIR}"
COMMAND_ERROR_IS_FATAL ANY
)
]])
else ()
set(imhex_patterns_SOURCE_DIR "")
@@ -781,19 +745,15 @@ macro(setupCompilerFlags target)
endif()
if (CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND APPLE)
addCCXXFlag("-Wno-unknown-warning-option" ${target})
# On macOS, when using clang from Homebrew, properly setup the libc++ library path so
# it's using the one from Homebrew instead of the system one.
execute_process(COMMAND brew --prefix llvm OUTPUT_VARIABLE LLVM_PREFIX OUTPUT_STRIP_TRAILING_WHITESPACE)
if (NOT LLVM_PREFIX STREQUAL "" AND ${CMAKE_CXX_COMPILER} STREQUAL "${LLVM_PREFIX}/bin/clang++")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${LLVM_PREFIX}/lib/c++")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -L${LLVM_PREFIX}/lib/c++")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -L${LLVM_PREFIX}/lib/c++")
endif()
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${LLVM_PREFIX}/lib/c++")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -L${LLVM_PREFIX}/lib/c++")
addCCXXFlag("-Wno-unknown-warning-option" ${target})
if (CMAKE_BUILD_TYPE STREQUAL "Debug")
add_compile_definitions(_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_DEBUG)
else()
add_compile_definitions(_LIBCPP_HARDENING_MODE=_LIBCPP_HARDENING_MODE_EXTENSIVE)
endif()
endif()
@@ -850,13 +810,6 @@ macro(setUninstallTarget)
endmacro()
macro(addBundledLibraries)
# Make sure the build is using vcpkg on Windows and Emscripten, otherwise none of these dependencies will be found
if (MSVC OR EMSCRIPTEN)
if (NOT (CMAKE_TOOLCHAIN_FILE MATCHES "vcpkg"))
message(AUTHOR_WARNING "Your current environment probably needs to be setup to use vcpkg, otherwise none of the dependencies will be found!")
endif()
endif()
set(EXTERNAL_LIBS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/lib/external")
set(THIRD_PARTY_LIBS_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/lib/third_party")
set(BUILD_SHARED_LIBS OFF)
@@ -930,6 +883,18 @@ macro(addBundledLibraries)
find_package(LLVM REQUIRED Demangle)
endif()
if (NOT USE_SYSTEM_JTHREAD)
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/jthread EXCLUDE_FROM_ALL)
set(JTHREAD_LIBRARIES jthread)
else()
find_path(JOSUTTIS_JTHREAD_INCLUDE_DIRS "condition_variable_any2.hpp")
include_directories(${JOSUTTIS_JTHREAD_INCLUDE_DIRS})
add_library(jthread INTERFACE)
target_include_directories(jthread INTERFACE ${JOSUTTIS_JTHREAD_INCLUDE_DIRS})
set(JTHREAD_LIBRARIES jthread)
endif()
if (USE_SYSTEM_BOOST)
find_package(Boost REQUIRED CONFIG COMPONENTS regex)
set(BOOST_LIBRARIES Boost::regex)

View File

@@ -2,7 +2,11 @@ find_path(LIBMAGIC_INCLUDE_DIR magic.h)
find_library(LIBMAGIC_LIBRARY NAMES magic)
find_package_handle_standard_args(Magic DEFAULT_MSG
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
)
@@ -10,5 +14,5 @@ find_package_handle_standard_args(Magic DEFAULT_MSG
mark_as_advanced(
LIBMAGIC_INCLUDE_DIR
LIBMAGIC_LIBRARY
Magic_FOUND
)
LIBMAGIC_FOUND
)

View File

@@ -26,9 +26,8 @@ SET(MBEDTLS_FIND_QUIETLY TRUE)
FIND_LIBRARY(MBEDTLS_LIBRARY NAMES mbedtls libmbedtls libmbedx509)
FIND_LIBRARY(MBEDX509_LIBRARY NAMES mbedx509 libmbedx509)
FIND_LIBRARY(MBEDCRYPTO_LIBRARY NAMES mbedcrypto libmbedcrypto)
FIND_LIBRARY(TFPSACRYPTO_LIBRARY NAMES libtfpsacrypto tfpsacrypto)
IF(MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARY AND MBEDX509_LIBRARY AND (MBEDCRYPTO_LIBRARY OR TFPSACRYPTO_LIBRARY))
IF(MBEDTLS_INCLUDE_DIR AND MBEDTLS_LIBRARY AND MBEDX509_LIBRARY AND MBEDCRYPTO_LIBRARY)
SET(MBEDTLS_FOUND TRUE)
ENDIF()
@@ -38,24 +37,14 @@ IF(MBEDTLS_FOUND)
GET_FILENAME_COMPONENT(MBEDTLS_LIBRARY_FILE ${MBEDTLS_LIBRARY} NAME_WE)
GET_FILENAME_COMPONENT(MBEDX509_LIBRARY_FILE ${MBEDX509_LIBRARY} NAME_WE)
GET_FILENAME_COMPONENT(MBEDCRYPTO_LIBRARY_FILE ${MBEDCRYPTO_LIBRARY} NAME_WE)
GET_FILENAME_COMPONENT(TFPSACRYPTO_LIBRARY_FILE ${TFPSACRYPTO_LIBRARY} NAME_WE)
STRING(REGEX REPLACE "^lib" "" MBEDTLS_LIBRARY_FILE ${MBEDTLS_LIBRARY_FILE})
STRING(REGEX REPLACE "^lib" "" MBEDX509_LIBRARY_FILE ${MBEDX509_LIBRARY_FILE})
STRING(REGEX REPLACE "^lib" "" MBEDCRYPTO_LIBRARY_FILE ${MBEDCRYPTO_LIBRARY_FILE})
STRING(REGEX REPLACE "^lib" "" TFPSACRYPTO_LIBRARY_FILE ${TFPSACRYPTO_LIBRARY_FILE})
if (TFPSACRYPTO_LIBRARY)
SET(MBEDTLS_CRYPTO_LIBRARY_FILE ${TFPSACRYPTO_LIBRARY_FILE})
elseif (MBEDCRYPTO_LIBRARY)
SET(MBEDTLS_CRYPTO_LIBRARY_FILE ${MBEDCRYPTO_LIBRARY_FILE})
else ()
MESSAGE(FATAL_ERROR "Could not find mbedTLS Crypto library")
endif()
if (MSVC)
SET(MBEDTLS_LIBRARIES ${MBEDTLS_LIBRARY_FILE}.lib ${MBEDX509_LIBRARY_FILE}.lib ${MBEDTLS_CRYPTO_LIBRARY_FILE}.lib)
SET(MBEDTLS_LIBRARIES ${MBEDTLS_LIBRARY_FILE}.lib ${MBEDX509_LIBRARY_FILE}.lib ${MBEDCRYPTO_LIBRARY_FILE}.lib)
else()
SET(MBEDTLS_LIBRARIES "-L${MBEDTLS_LIBRARY_DIR} -l${MBEDTLS_LIBRARY_FILE} -l${MBEDX509_LIBRARY_FILE} -l${MBEDTLS_CRYPTO_LIBRARY_FILE}")
SET(MBEDTLS_LIBRARIES "-L${MBEDTLS_LIBRARY_DIR} -l${MBEDTLS_LIBRARY_FILE} -l${MBEDX509_LIBRARY_FILE} -l${MBEDCRYPTO_LIBRARY_FILE}")
endif()
IF(NOT MBEDTLS_FIND_QUIETLY)

View File

@@ -65,9 +65,9 @@ elseif (APPLE)
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/lib/trace/include")
else()
set_target_properties(libimhex PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../../../lib/libimhex.so"
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../libimhex.so"
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/lib/libimhex/include")
set_target_properties(tracing PROPERTIES
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/lib/libtracing.a"
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/../libtracing.a"
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/lib/trace/include")
endif()

View File

@@ -15,8 +15,8 @@ AppDir:
- "{{ARCHITECTURE_PACKAGE}}"
allow_unauthenticated: true
sources:
- sourceline: 'deb [arch=amd64] https://us.archive.ubuntu.com/ubuntu/ noble main restricted universe multiverse'
- sourceline: 'deb [arch=arm64] https://ports.ubuntu.com/ubuntu-ports/ noble main restricted universe multiverse'
- sourceline: 'deb [arch=amd64] http://us.archive.ubuntu.com/ubuntu/ oracular main restricted universe multiverse'
- sourceline: 'deb [arch=arm64] http://ports.ubuntu.com/ubuntu-ports/ oracular main restricted universe multiverse'
include:
- libgdk-pixbuf2.0-0
- libgdk-pixbuf2.0-common

View File

@@ -1,4 +1,4 @@
FROM ubuntu:24.04 as build
FROM ubuntu:24.10 as build
# Used to invalidate layer cache but not mount cache
# See https://github.com/moby/moby/issues/41715#issuecomment-733976493
@@ -30,9 +30,9 @@ ARG LTO=ON
ARG BUILD_TYPE=RelWithDebInfo
ARG GIT_COMMIT_HASH
ARG GIT_BRANCH
ARG ARCHITECTURE_PACKAGE=x86_64
ARG ARCHITECTURE_FILE_NAME=amd64
ARG ARCHITECTURE_APPIMAGE_BUILDER=x86_64
ARG ARCHITECTURE_PACKAGE
ARG ARCHITECTURE_FILE_NAME
ARG ARCHITECTURE_APPIMAGE_BUILDER
WORKDIR /build
# Ubuntu sh doesnt support string substitution
@@ -42,18 +42,16 @@ RUN <<EOF
# Prepare ImHex build
set -xe
CC=gcc-14 CXX=g++-14 cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_LONG="${GIT_COMMIT_HASH}" \
-DIMHEX_COMMIT_BRANCH="${GIT_BRANCH}" \
-DIMHEX_ENABLE_LTO=${LTO} \
-DIMHEX_BUNDLE_PLUGIN_SDK=OFF \
`# To prevent using a libdir with an architecture-specific name` \
-DCMAKE_INSTALL_LIBDIR="lib" \
CC=gcc-14 CXX=g++-14 cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_LONG="${GIT_COMMIT_HASH}" \
-DIMHEX_COMMIT_BRANCH="${GIT_BRANCH}" \
-DIMHEX_ENABLE_LTO=${LTO} \
-DIMHEX_PLUGINS_IN_SHARE=ON \
/imhex
EOF

View File

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

13
dist/ImHex.run.xml vendored
View File

@@ -1,13 +0,0 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="ImHex" type="CMakeRunConfiguration" factoryName="Application" REDIRECT_INPUT="false" ELEVATE="false" USE_EXTERNAL_CONSOLE="false" EMULATE_TERMINAL="false" WORKING_DIR="file://$CMakeCurrentBuildDir$" PASS_PARENT_ENVS_2="true" PROJECT_NAME="ImHex" TARGET_NAME="imhex_all" CONFIG_NAME="Debug" RUN_TARGET_PROJECT_NAME="ImHex" RUN_TARGET_NAME="main">
<envs>
<env name="NO_DEBUG_BANNER" value="1" />
</envs>
<method v="2">
<option name="com.jetbrains.cidr.execution.CidrBuildBeforeRunTaskProvider$BuildBeforeRunTask" enabled="true" />
</method>
</configuration>
<configuration default="false" name="CMake Debug" type="CMakeListConfigurationType" factoryName="CMakeListConfigurationFactory">
<method v="2" />
</configuration>
</component>

3
dist/cli/imhex.bat vendored
View File

@@ -1,3 +0,0 @@
@echo off
start "" "%~dp0..\imhex.exe" %*

5
dist/cli/imhex.sh vendored
View File

@@ -1,5 +0,0 @@
#!/bin/sh
script_path=$(readlink -f "$0")
script_dir=$(dirname "${script_path}")
"${script_dir}/../imhex" "$@" > /dev/null 2>&1 &

View File

@@ -3,7 +3,7 @@
On macOS, ImHex is built through regular GCC and LLVM clang.
1. Clone the repo using `git clone https://github.com/WerWolv/ImHex --recurse-submodules`
2. Install all the dependencies using `brew bundle --file dist/macOS/Brewfile`
2. Install all the dependencies using `brew bundle --no-lock --file dist/macOS/Brewfile`
3. Build ImHex itself using the following commands:
```sh
cd ImHex
@@ -20,5 +20,3 @@ cmake -G "Ninja" \
..
ninja install
```
If your MacOS installation doesn't have graphic acceleration, you can check the [MacOS NoGPU guide](./macos_nogpu.md)

View File

@@ -1,10 +0,0 @@
### Compiling and running ImHex on macOS without a GPU
In order to run ImHex on a macOS installation without a GPU, you need a custom build of GLFW. You can build it this way:
Note: only tested on macOS x86
1. `git clone --depth 1 https://github.com/glfw/glfw`
2. `git apply {IMHEX_DIR}/dist/macOS/0001-glfw-SW.patch` (file is [here](../macOS/0001-glfw-SW.patch) in the ImHex repository. [Source](https://github.com/glfw/glfw/issues/2080).)
3. `cmake -G "Ninja" -DBUILD_SHARED_LIBS=ON ..`
4. `ninja install`, or `ninja` and figure out how to make ImHex detect the shared library

54
dist/flake.nix vendored
View File

@@ -1,54 +0,0 @@
{
description = "ImHex";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs }:
let
supportedSystems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ];
forAllSystems = f: nixpkgs.lib.genAttrs supportedSystems (system: f system);
in {
devShells = forAllSystems (system:
let
pkgs = import nixpkgs { inherit system; };
in
{
default = pkgs.mkShell {
buildInputs = [
pkgs.cmake
pkgs.clang
pkgs.lld
pkgs.nghttp3
pkgs.pkg-config
pkgs.glfw
pkgs.fontconfig
pkgs.file
pkgs.mbedtls
pkgs.freetype
pkgs.dbus
pkgs.gtk3
pkgs.curl
pkgs.fmt
pkgs.yara
pkgs.nlohmann_json
pkgs.ninja
pkgs.zlib
pkgs.bzip2
pkgs.xz
pkgs.zstd
pkgs.lz4
pkgs.libssh2
pkgs.md4c
];
shellHook = ''
export CC=${pkgs.clang}/bin/clang
export CXX=${pkgs.clang}/bin/clang++
'';
};
});
};
}

View File

@@ -120,7 +120,6 @@ modules:
- -DUSE_SYSTEM_FMT=ON
- -DUSE_SYSTEM_YARA=ON
- -DIMHEX_OFFLINE_BUILD=ON
- -DIMHEX_BUNDLE_PLUGIN_SDK=OFF
- -DCMAKE_INSTALL_LIBDIR=lib
- -DCMAKE_INSTALL_RPATH='$ORIGIN/../lib:$ORIGIN/../lib64'
sources:

View File

@@ -1,5 +1,5 @@
From 9c8665af4c2e2ce66555c15c05c72027bfdf0cb6 Mon Sep 17 00:00:00 2001
From: iTrooz <hey@itrooz.fr>
From: iTrooz <itrooz@protonmail.com>
Date: Mon, 29 Aug 2022 17:29:38 +0200
Subject: [PATCH] Use software rendering on MacOS

View File

@@ -1,7 +1,7 @@
# This base image is also known as "crosscompile". See arm64.crosscompile.Dockerfile
FROM ghcr.io/werwolv/macos-crosscompile:6d89b20ac5ebedb6f680f94637591c94cb36f40b as build
FROM ghcr.io/werwolv/macos-crosscompile:clang20-nosdk as build
ENV MACOSX_DEPLOYMENT_TARGET 11.0
ENV MACOSX_DEPLOYMENT_TARGET 13.0
# -- DOWNLOADING STUFF
@@ -17,13 +17,13 @@ cp /tmp/arm-osx-mytriplet.cmake /vcpkg/triplets/community/arm-osx-mytriplet.cmak
EOF
## Install make
RUN --mount=type=cache,target=/var/lib/apt/lists/ apt update && apt install -y make cmake
RUN --mount=type=cache,target=/var/lib/apt/lists/ apt update && apt install -y make
## fix environment
### add install_name_tool for cmake command that won't have the right env set (see PostprocessBundle.cmake function postprocess_bundle())
RUN cp /osxcross/build/cctools-port/cctools/misc/install_name_tool /usr/bin/install_name_tool
### a cmake thing wants 'otool' and not '' apparently
RUN cp /osxcross/target/bin/aarch64-apple-darwin24-otool /usr/bin/otool
RUN cp /osxcross/target/bin/aarch64-apple-darwin23-otool /usr/bin/otool
## Clone glfw
RUN <<EOF
@@ -36,10 +36,10 @@ EOF
RUN --mount=type=cache,target=/cache <<EOF
## Download SDK is missing (it may have been removed from the image)
set -xe
if [ ! -d /osxcross/target/SDK/MacOSX15.0.sdk ]; then
wget https://github.com/joseluisq/macosx-sdks/releases/download/15.0/MacOSX15.0.sdk.tar.xz -O /cache/MacOSX15.0.sdk.tar.xz -nc || true
if [ ! -d /osxcross/target/SDK/MacOSX14.0.sdk ]; then
wget https://github.com/joseluisq/macosx-sdks/releases/download/14.0/MacOSX14.0.sdk.tar.xz -O /cache/MacOSX14.0.sdk.tar.xz -nc || true
mkdir -p /osxcross/target/SDK
tar -C /osxcross/target/SDK -xf /cache/MacOSX15.0.sdk.tar.xz
tar -C /osxcross/target/SDK -xf /cache/MacOSX14.0.sdk.tar.xz
fi
EOF
@@ -101,7 +101,7 @@ RUN --mount=type=cache,target=/cache <<EOF
make -j $JOBS install
# Now, we cross-compile it and install it in the libraries folder
CC=/osxcross/target/bin/aarch64-apple-darwin24-clang CXX=/osxcross/target/bin/aarch64-apple-darwin24-clang++ ./configure --prefix /vcpkg/installed/arm-osx-mytriplet --host $OSXCROSS_HOST
CC=/osxcross/target/bin/aarch64-apple-darwin23-clang CXX=/osxcross/target/bin/aarch64-apple-darwin23-clang++ ./configure --prefix /vcpkg/installed/arm-osx-mytriplet --host $OSXCROSS_HOST
make -j $JOBS
make install
@@ -132,7 +132,6 @@ if [ "$CUSTOM_GLFW" ]; then
mkdir build
cd build
CC=o64-clang CXX=o64-clang++ cmake -G "Ninja" \
-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 \
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
-DBUILD_SHARED_LIBS=ON \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
@@ -140,7 +139,7 @@ if [ "$CUSTOM_GLFW" ]; then
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
-DCMAKE_INSTALL_PREFIX=/vcpkg/installed/arm-osx-mytriplet \
-DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=13.3 \
-DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0 \
..
ninja -j $JOBS install
@@ -151,25 +150,25 @@ EOF
# Build ImHex
## Copy ImHex
COPY --from=imhex / /mnt/ImHex
## Configure ImHex build
## Patch ImHex with hacks
# COPY toolchain.cmake.2 /osxcross/target/toolchain.cmake
# Configure ImHex build
RUN --mount=type=cache,target=/cache --mount=type=cache,target=/mnt/ImHex/build/_deps \
cd /mnt/ImHex && \
# compilers
CC=o64-clang CXX=o64-clang++ OBJC=/osxcross/target/bin/aarch64-apple-darwin24-clang OBJCXX=/osxcross/target/bin/aarch64-apple-darwin24-clang++ \
CC=o64-clang CXX=o64-clang++ OBJC=/osxcross/target/bin/aarch64-apple-darwin23-clang OBJCXX=/osxcross/target/bin/aarch64-apple-darwin23-clang++ \
cmake -G "Ninja" \
`# ccache flags` \
-DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_OBJC_COMPILER_LAUNCHER=ccache -DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
`# MacOS cross-compiling flags` \
-DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=13.3 \
-DVCPKG_TARGET_TRIPLET=arm-osx-mytriplet -DCMAKE_TOOLCHAIN_FILE=/vcpkg/scripts/buildsystems/vcpkg.cmake -DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/osxcross/target/toolchain.cmake -DCMAKE_OSX_SYSROOT=/osxcross/target/SDK/MacOSX14.0.sdk -DCMAKE_OSX_DEPLOYMENT_TARGET=13.0 \
`# Override compilers for code generators` \
-DNATIVE_CMAKE_C_COMPILER=/usr/bin/clang -DNATIVE_CMAKE_CXX_COMPILER=/usr/bin/clang++ \
`# Normal ImHex flags` \
-DIMHEX_GENERATE_PACKAGE=ON -DCMAKE_BUILD_TYPE=$BUILD_TYPE \
`# other flags` \
-DIMHEX_STRICT_WARNINGS=OFF \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DCMAKE_INSTALL_PREFIX=/mnt/ImHex/build/install \
-DCMAKE_OSX_DEPLOYMENT_TARGET=11.0 \
-B build
## Build ImHex
RUN --mount=type=cache,target=/cache --mount=type=cache,target=/mnt/ImHex/build/_deps <<EOF
@@ -184,4 +183,4 @@ EOF
FROM scratch
COPY --from=build /mnt/ImHex/build/install/ImHex.app ImHex.app
COPY --from=build /mnt/ImHex/build/install/imhex.app imhex.app

View File

@@ -4,9 +4,9 @@ FROM ubuntu:22.04
ENV PATH $PATH:/osxcross/target/bin
ENV LD_LIBRARY_PATH /osxcross/target/lib
ENV OSXCROSS_SDK /osxcross/target/SDK/MacOSX14.0.sdk
ENV OSXCROSS_TARGET darwin24
ENV OSXCROSS_TARGET darwin23
ENV OSXCROSS_TARGET_DIR /osxcross/target
ENV OSXCROSS_HOST aarch64-apple-darwin24
ENV OSXCROSS_HOST aarch64-apple-darwin23
# -- DOWNLOADING STUFF

View File

@@ -1,11 +0,0 @@
set(VCPKG_TARGET_ARCHITECTURE x64)
set(VCPKG_BUILD_TYPE release)
set(VCPKG_CRT_LINKAGE dynamic)
set(VCPKG_LIBRARY_LINKAGE static)
set(VCPKG_CMAKE_SYSTEM_NAME Darwin)
set(VCPKG_OSX_ARCHITECTURES x86_64)
set(VCPKG_OSX_DEPLOYMENT_TARGET "10.15" CACHE STRING "" FORCE)
set(VCPKG_C_FLAGS "-mmacosx-version-min=10.15")
set(VCPKG_CXX_FLAGS "-mmacosx-version-min=10.15")
set(ENV{MACOSX_DEPLOYMENT_TARGET} "10.15")

View File

@@ -38,7 +38,7 @@
<url type="homepage">https://imhex.werwolv.net</url>
<url type="bugtracker">https://github.com/WerWolv/ImHex/issues</url>
<url type="help">https://docs.werwolv.net/imhex</url>
<url type="donation">https://github.com/sponsors/WerWolv</url>
<url type="donation">https://www.patreon.com/werwolv</url>
<url type="contact">https://imhex.werwolv.net/discord</url>
<url type="vcs-browser">https://github.com/WerWolv/ImHex</url>
<url type="contribute">https://github.com/WerWolv/ImHex/blob/master/CONTRIBUTING.md</url>
@@ -64,8 +64,4 @@
</release>
</releases>
<update_contact>hey@werwolv.net</update_contact>
<recommends>
<control>keyboard</control>
<control>pointing</control>
</recommends>
</component>

4
dist/rpm/imhex.spec vendored
View File

@@ -145,7 +145,8 @@ appstream-util validate-relax --nonet %{buildroot}%{_metainfodir}/net.werwolv.Im
# install licenses
%if 0%{?rhel} == 9
cp -a lib/third_party/capstone/LICENSES/LICENSE.TXT %{buildroot}%{_datadir}/licenses/%{name}/capstone-LICENSE
cp -a lib/third_party/capstone/LICENSE.TXT %{buildroot}%{_datadir}/licenses/%{name}/capstone-LICENSE
cp -a lib/third_party/capstone/suite/regress/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/capstone-regress-LICENSE
%endif
cp -a lib/third_party/microtar/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/microtar-LICENSE
cp -a lib/third_party/xdgpp/LICENSE %{buildroot}%{_datadir}/licenses/%{name}/xdgpp-LICENSE
@@ -155,7 +156,6 @@ cp -a lib/third_party/xdgpp/LICENSE %{buildroot
%license %{_datadir}/licenses/%{name}/
%doc README.md
%{_bindir}/imhex
%{_datadir}/imhex/imhex
%{_datadir}/pixmaps/%{name}.*
%{_datadir}/applications/%{name}.desktop
%{_libdir}/libimhex.so.*

View File

@@ -1,7 +1,7 @@
name: imhex
title: ImHex
base: core24
version: ${IMHEX_VERSION_STRING}
version: ${IMHEX_VERSION}
summary: Hex editor for reverse engineering
description: ImHex is a hex editor for reverse engineering, reverse engineering, and analyzing binary files. It provides a powerful and flexible interface for working with binary data, including features like pattern matching, scripting, and a customizable user interface.
grade: stable
@@ -40,8 +40,6 @@ parts:
- -DCMAKE_BUILD_TYPE=Release
- -DCMAKE_C_COMPILER_LAUNCHER=${CCACHE}
- -DCMAKE_CXX_COMPILER_LAUNCHER=${CCACHE}
- -DIMHEX_PATTERNS_PULL_MASTER=ON
- -DIMHEX_BUNDLE_PLUGIN_SDK=OFF
cmake-generator: Ninja
build-packages:
- cmake

2
dist/vcpkg.json vendored
View File

@@ -1,7 +1,7 @@
{
"name": "vcpkg",
"version": "1.0.0",
"builtin-baseline": "66c0373dc7fca549e5803087b9487edfe3aca0a1",
"builtin-baseline": "7e21420f775f72ae938bdeb5e6068f722088f06a",
"dependencies": [
"libmagic",
"freetype",

14
dist/web/Dockerfile vendored
View File

@@ -1,8 +1,8 @@
FROM emscripten/emsdk:4.0.21 AS build
FROM emscripten/emsdk:4.0.8 AS build
# Used to invalidate layer cache but not mount cache
# See https://github.com/moby/moby/issues/41715#issuecomment-733976493
ARG UNIQUEKEY=1
ARG UNIQUEKEY 1
RUN apt update
RUN apt install -y git ccache autoconf automake libtool pkg-config ninja-build
@@ -12,13 +12,13 @@ RUN <<EOF
# Note: we are a patch on the libmagic port
set -xe
git clone --depth 1 https://github.com/microsoft/vcpkg /vcpkg
git clone https://github.com/microsoft/vcpkg /vcpkg
git -C /vcpkg pull
/vcpkg/bootstrap-vcpkg.sh
sed -i 's/vcpkg_install_make(${EXTRA_ARGS})/vcpkg_install_make(${EXTRA_ARGS} SUBPATH src)/g' /vcpkg/ports/libmagic/portfile.cmake
EOF
# Patch vcpkg build instructions to add -pthread flag
# Even dependencies must be built with -pthread to be able to use USE_PTHREADS=1
# Patch vcpkg build instructions to add -pthread
RUN <<EOF
set -xe
@@ -50,7 +50,6 @@ ENV CCACHE_DIR=/cache/ccache
RUN mkdir /build
WORKDIR /build
ARG BUILD_TYPE=Release
RUN --mount=type=cache,target=/cache \
--mount=type=bind,source=.,target=/imhex <<EOF
@@ -71,7 +70,7 @@ ccache -zs
-DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake \
-DLIBROMFS_COMPRESS_RESOURCES=OFF \
-DIMHEX_ENABLE_PLUGIN_TESTS=OFF \
-DCMAKE_BUILD_TYPE=${BUILD_TYPE}
-DCMAKE_BUILD_TYPE=Release
ninja -j $JOBS
@@ -107,4 +106,3 @@ COPY --from=build [ \
FROM nginx
COPY --from=raw . /usr/share/nginx/html
RUN chmod -R 755 /usr/share/nginx/html

View File

@@ -1,9 +0,0 @@
FROM python:3.12-slim
WORKDIR /imhex
COPY ./out/ .
EXPOSE 9090
CMD [ "python", "/imhex/start_imhex_web.py" ]

View File

@@ -1,4 +1,5 @@
# docker compose -f dist/web/compose.yml up --build
version: '3'
services:
imhex_web:
image: imhex_web:latest

2
dist/web/serve.py vendored
View File

@@ -10,6 +10,6 @@ class MyHttpRequestHandler(http.server.SimpleHTTPRequestHandler):
if __name__ == '__main__':
os.chdir(".")
httpd = http.server.HTTPServer(("0.0.0.0", 9090), MyHttpRequestHandler)
httpd = http.server.HTTPServer(("localhost", 9090), MyHttpRequestHandler)
print(f"Serving {os.getcwd()} on http://{httpd.server_address[0]}:{httpd.server_address[1]}")
httpd.serve_forever()

View File

@@ -15,17 +15,17 @@
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="https://web.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:image" content="splash_wasm.png">
<meta property="og:image" content="https://imhex.werwolv.net/assets/splash_wasm.png">
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image">
<meta property="twitter:url" content="https://web.imhex.werwolv.net/">
<meta property="twitter:url" content="https://imhex.werwolv.net/">
<meta property="twitter:title" content="ImHex Web - Online Hex Editor">
<meta property="twitter:description"
content="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.">
<meta property="twitter:image" content="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">
@@ -37,8 +37,8 @@
"email": "hey@werwolv.net",
"founder": "WerWolv",
"slogan": "A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.",
"url": "https://web.imhex.werwolv.net",
"logo": "https://web.imhex.werwolv.net/icon.svg"
"url": "https://imhex.werwolv.net",
"logo": "https://imhex.werwolv.net/assets/logos/logo.svg"
}
</script>
@@ -96,9 +96,7 @@
</div>
</div>
<div id="canvas-wrapper" class="imhex-web-canvas-wrapper">
<canvas class="imhex-web-canvas canvas-fixed" id="canvas" ></canvas>
</div>
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
<script src="wasm-config.js"></script>
<script async src="imhex.js"></script>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 478 KiB

View File

@@ -185,23 +185,4 @@ a:hover {
position: absolute;
top: 0;
left: 0;
}
.imhex-web-canvas {
width: 100%;
height: 100%;
display: block;
overflow: hidden;
image-rendering: smooth;
margin: 0;
padding: 0;
z-index: 1;
}
.imhex-web-canvas-wrapper {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
background-size: 100% 100%;
}

View File

@@ -59,14 +59,8 @@ monkeyPatch((file, done) => {
const mibTotal = (wasmSize / 1024**2).toFixed(1);
let root = document.querySelector(':root');
if (root != null) {
root.style.setProperty("--progress", `${percent}%`)
let progressBar = document.getElementById("progress-bar-content");
if (progressBar != null) {
progressBar.innerHTML = `${percent}% &nbsp;[${mibNow} MiB / ${mibTotal} MiB]`;
}
}
root.style.setProperty("--progress", `${percent}%`)
document.getElementById("progress-bar-content").innerHTML = `${percent}% &nbsp;[${mibNow} MiB / ${mibTotal} MiB]`;
});
function glfwSetCursorCustom(wnd, shape) {
@@ -106,17 +100,81 @@ var notWorkingTimer = setTimeout(() => {
}, 5000);
var Module = {
preRun: () => {
ENV.IMHEX_SKIP_SPLASH_SCREEN = "1";
},
preRun: [],
postRun: function() {
// Patch the emscripten GLFW module to send mouse and touch events in the right order
// For ImGui interactions to correctly work with touch input, MousePos events need
// to be processed first and then MouseButton events in the next frame. By default,
// GLFW does the exact opposite, which causes buttons to require two taps to register
// and windows get "stuck" to the cursor when dragged or resized
GLFW.onMousemove = event => {
if (event.type === "touchmove") {
event.preventDefault();
let primaryChanged = false;
for (let i of event.changedTouches) {
if (GLFW.primaryTouchId === i.identifier) {
Browser.setMouseCoords(i.pageX, i.pageY);
primaryChanged = true;
break;
}
}
if (!primaryChanged) {
return;
}
} else {
Browser.calculateMouseEvent(event);
}
};
GLFW.onMouseButtonChanged = (event, status) => {
if (!GLFW.active) return;
if (event.target != Module["canvas"]) return;
const isTouchType = event.type === "touchstart" || event.type === "touchend" || event.type === "touchcancel";
let eventButton = 0;
if (isTouchType) {
event.preventDefault();
let primaryChanged = false;
if (GLFW.primaryTouchId === null && event.type === "touchstart" && event.targetTouches.length > 0) {
const chosenTouch = event.targetTouches[0];
GLFW.primaryTouchId = chosenTouch.identifier;
Browser.setMouseCoords(chosenTouch.pageX, chosenTouch.pageY);
primaryChanged = true;
} else if (event.type === "touchend" || event.type === "touchcancel") {
for (let i of event.changedTouches) {
if (GLFW.primaryTouchId === i.identifier) {
GLFW.primaryTouchId = null;
primaryChanged = true;
break;
}
}
}
if (!primaryChanged) {
return;
}
} else {
Browser.calculateMouseEvent(event);
eventButton = GLFW.DOMToGLFWMouseButton(event);
}
if (status == 1) {
GLFW.active.buttons |= (1 << eventButton);
try {
event.target.setCapture();
} catch (e) {}
} else {
GLFW.active.buttons &= ~(1 << eventButton);
}
if (GLFW.active.cursorPosFunc) {
getWasmTableEntry(GLFW.active.cursorPosFunc)(GLFW.active.id, Browser.mouseX, Browser.mouseY);
}
if (GLFW.active.mouseButtonFunc) {
getWasmTableEntry(GLFW.active.mouseButtonFunc)(GLFW.active.id, eventButton, status, GLFW.getModBits(GLFW.active));
}
};
},
onRuntimeInitialized: function() {
// Triggered when the wasm module is loaded and ready to use.
let loading = document.getElementById("loading");
if (loading != null)
document.getElementById("loading").style.display = "none"
document.getElementById("loading").style.display = "none"
document.getElementById("canvas").style.display = "initial"
clearTimeout(notWorkingTimer);
@@ -199,6 +257,16 @@ if (urlParams.has("lang")) {
Module["arguments"].push(urlParams.get("save-editor"));
}
window.addEventListener('resize', js_resizeCanvas, false);
function js_resizeCanvas() {
let canvas = document.getElementById('canvas');
canvas.top = document.documentElement.clientTop;
canvas.left = document.documentElement.clientLeft;
canvas.width = Math.min(document.documentElement.clientWidth, window.innerWidth || 0);
canvas.height = Math.min(document.documentElement.clientHeight, window.innerHeight || 0);
}
// Prevent some default browser shortcuts from preventing ImHex ones to work
document.addEventListener('keydown', e => {
if (e.ctrlKey) {

View File

@@ -42,7 +42,6 @@ set(LIBIMHEX_SOURCES
source/helpers/keys.cpp
source/helpers/udp_server.cpp
source/helpers/scaling.cpp
source/helpers/binary_pattern.cpp
source/test/tests.cpp
@@ -57,13 +56,19 @@ set(LIBIMHEX_SOURCES
source/ui/toast.cpp
source/ui/banner.cpp
source/mcp/client.cpp
source/mcp/server.cpp
source/subcommands/subcommands.cpp
)
if (APPLE)
set(OSX_SDK_PATH /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.sdk)
if (NOT CMAKE_OSX_SYSROOT)
if (IS_DIRECTORY ${OSX_SDK_PATH})
set(CMAKE_OSX_SYSROOT ${OSX_SDK_PATH})
else ()
message(WARNING "CMAKE_OSX_SYSROOT not set and macOS SDK not found! Using default one.")
endif ()
endif ()
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES}
source/helpers/utils_macos.m
source/helpers/macos_menu.m

View File

@@ -145,17 +145,62 @@ EXPORT_MODULE namespace hex {
* @brief Returns the icon of the achievement
* @return Icon of the achievement
*/
[[nodiscard]] const char* getIcon() const {
return m_icon.c_str();
[[nodiscard]] const ImGuiExt::Texture &getIcon() const {
if (m_iconData.empty())
return m_icon;
if (m_icon.isValid())
return m_icon;
m_icon = ImGuiExt::Texture::fromImage(m_iconData.data(), m_iconData.size(), ImGuiExt::Texture::Filter::Linear);
return m_icon;
}
/**
* @brief Sets the icon of the achievement
* @param icon Icon glyph
* @param data Icon data
* @return Reference to the achievement
*/
Achievement& setIcon(std::string icon) {
m_icon = std::move(icon);
Achievement& setIcon(std::span<const std::byte> data) {
m_iconData.reserve(data.size());
for (auto &byte : data)
m_iconData.emplace_back(static_cast<u8>(byte));
return *this;
}
/**
* @brief Sets the icon of the achievement
* @param data Icon data
* @return Reference to the achievement
*/
Achievement& setIcon(std::span<const u8> data) {
m_iconData.assign(data.begin(), data.end());
return *this;
}
/**
* @brief Sets the icon of the achievement
* @param data Icon data
* @return Reference to the achievement
*/
Achievement& setIcon(std::vector<u8> data) {
m_iconData = std::move(data);
return *this;
}
/**
* @brief Sets the icon of the achievement
* @param data Icon data
* @return Reference to the achievement
*/
Achievement& setIcon(const std::vector<std::byte> &data) {
m_iconData.reserve(data.size());
for (auto &byte : data)
m_iconData.emplace_back(static_cast<u8>(byte));
return *this;
}
@@ -239,7 +284,8 @@ EXPORT_MODULE namespace hex {
std::function<void(Achievement &)> m_clickCallback;
std::string m_icon;
std::vector<u8> m_iconData;
mutable ImGuiExt::Texture m_icon;
u32 m_progress = 0;
u32 m_maxProgress = 1;

View File

@@ -16,7 +16,7 @@ EXPORT_MODULE namespace hex {
void stopServices();
}
void registerService(const UnlocalizedString &unlocalizedName, const impl::Callback &callback);
void registerService(const UnlocalizedString &unlocalizedString, const impl::Callback &callback);
}
}

View File

@@ -7,8 +7,6 @@
#include <map>
#include <string>
#include <hex/mcp/server.hpp>
EXPORT_MODULE namespace hex {
/* Network Communication Interface Registry. Allows adding new communication interface endpoints */
@@ -24,19 +22,4 @@ EXPORT_MODULE namespace hex {
}
namespace ContentRegistry::MCP {
namespace impl {
std::unique_ptr<mcp::Server>& getMcpServerInstance();
void setEnabled(bool enabled);
}
bool isEnabled();
bool isConnected();
void registerTool(std::string_view capabilities, std::function<nlohmann::json(const nlohmann::json &params)> function);
}
}

View File

@@ -27,10 +27,9 @@ EXPORT_MODULE namespace hex {
struct FindOccurrence {
Region region;
enum class DecodeType { ASCII, UTF8, Binary, UTF16, Unsigned, Signed, Float, Double } decodeType;
std::endian endian = std::endian::native;
enum class DecodeType : u8 { ASCII, UTF8, Binary, UTF16, Unsigned, Signed, Float, Double } decodeType;
bool selected;
std::string string;
};
using FindExporterCallback = std::function<std::vector<u8>(const std::vector<FindOccurrence>&, std::function<std::string(FindOccurrence)>)>;

View File

@@ -8,7 +8,6 @@
#include <optional>
#include <string>
#include <vector>
#include <bit>
EXPORT_MODULE namespace hex {
@@ -23,10 +22,8 @@ EXPORT_MODULE namespace hex {
namespace impl {
struct DoNotUseThisByItselfTag {};
using DisplayFunction = std::function<std::string()>;
using EditingFunction = std::function<std::optional<std::vector<u8>>(std::string&, std::endian, DoNotUseThisByItselfTag)>;
using EditingFunction = std::function<std::vector<u8>(std::string, std::endian)>;
using GeneratorFunction = std::function<DisplayFunction(const std::vector<u8> &, std::endian, NumberDisplayStyle)>;
struct Entry {
@@ -41,35 +38,6 @@ EXPORT_MODULE namespace hex {
}
namespace EditWidget {
class Widget {
public:
using Function = std::function<std::vector<u8>(const std::string&, std::endian)>;
explicit Widget(const Function &function) : m_function(function) {}
virtual ~Widget() = default;
virtual std::optional<std::vector<u8>> draw(std::string &value, std::endian endian) = 0;
std::optional<std::vector<u8>> operator()(std::string &value, std::endian endian, impl::DoNotUseThisByItselfTag) {
return draw(value, endian);
}
std::vector<u8> getBytes(const std::string &value, std::endian endian) const {
return m_function(value, endian);
}
private:
Function m_function;
};
struct TextInput : Widget {
explicit TextInput(const Function &function) : Widget(function) {}
std::optional<std::vector<u8>> draw(std::string &value, std::endian endian) override;
};
}
/**
* @brief Adds a new entry to the data inspector
* @param unlocalizedName The unlocalized name of the entry

View File

@@ -38,14 +38,24 @@ EXPORT_MODULE namespace hex {
[[nodiscard]] const Hash *getType() const { return m_type; }
[[nodiscard]] const std::string& getName() const { return m_name; }
std::vector<u8> get(const Region& region, prv::Provider *provider) const {
return m_callback(region, provider);
const std::vector<u8>& get(const Region& region, prv::Provider *provider) {
if (m_cache.empty()) {
m_cache = m_callback(region, provider);
}
return m_cache;
}
void reset() {
m_cache.clear();
}
private:
Hash *m_type;
std::string m_name;
Callback m_callback;
std::vector<u8> m_cache;
};
virtual void draw() { }

View File

@@ -19,7 +19,7 @@ EXPORT_MODULE namespace hex {
void addProviderName(const UnlocalizedString &unlocalizedName, const char *icon);
using ProviderCreationFunction = std::function<std::shared_ptr<prv::Provider>()>;
using ProviderCreationFunction = std::function<std::unique_ptr<prv::Provider>()>;
void add(const std::string &typeName, ProviderCreationFunction creationFunction);
struct Entry {

View File

@@ -52,7 +52,7 @@ EXPORT_MODULE namespace hex {
return *this;
}
Interface& setTooltip(const UnlocalizedString &tooltip) {
Interface& setTooltip(const std::string &tooltip) {
m_tooltip = tooltip;
return *this;
@@ -239,14 +239,6 @@ EXPORT_MODULE namespace hex {
nlohmann::json store() override { return {}; }
};
class Spacer : public Widget {
public:
bool draw(const std::string &name) override;
void load(const nlohmann::json &) override {}
nlohmann::json store() override { return {}; }
};
}
namespace impl {
@@ -298,8 +290,8 @@ EXPORT_MODULE namespace hex {
public:
SettingsValue(nlohmann::json value) : m_value(std::move(value)) {}
template<typename T> requires (!(std::is_reference_v<T> || std::is_const_v<T>))
[[nodiscard]] T get(T defaultValue) const {
template<typename T>
T get(std::common_type_t<T> defaultValue) const {
try {
auto result = m_value;
if (result.is_number() && std::same_as<T, bool>)
@@ -316,8 +308,8 @@ EXPORT_MODULE namespace hex {
nlohmann::json m_value;
};
template<typename T> requires (!(std::is_reference_v<T> || std::is_const_v<T>))
[[nodiscard]] T read(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, T defaultValue) {
template<typename T>
[[nodiscard]] T read(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const std::common_type_t<T> &defaultValue) {
auto setting = impl::getSetting(unlocalizedCategory, unlocalizedName, defaultValue);
try {
@@ -334,8 +326,8 @@ EXPORT_MODULE namespace hex {
}
}
template<typename T> requires (!(std::is_reference_v<T> || std::is_const_v<T>))
void write(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, T value) {
template<typename T>
void write(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const std::common_type_t<T> &value) {
impl::getSetting(unlocalizedCategory, unlocalizedName, value) = value;
impl::runOnChangeHandlers(unlocalizedCategory, unlocalizedName, value);
@@ -344,75 +336,10 @@ EXPORT_MODULE namespace hex {
using OnChangeCallback = std::function<void(const SettingsValue &)>;
u64 onChange(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const OnChangeCallback &callback);
void removeOnChangeHandler(u64 id);
using OnSaveCallback = std::function<void()>;
u64 onSave(const OnSaveCallback &callback);
template<typename T, wolv::type::StaticString UnlocalizedCategory, wolv::type::StaticString UnlocalizedName>
requires (!(std::is_reference_v<T> || std::is_const_v<T>))
class SettingsVariable {
public:
explicit(false) SettingsVariable(T defaultValue) noexcept : m_defaultValue(std::move(defaultValue)) { }
SettingsVariable(const SettingsVariable&) = delete;
SettingsVariable& operator=(const SettingsVariable&) = delete;
SettingsVariable(SettingsVariable&&) = delete;
SettingsVariable& operator=(SettingsVariable&&) = delete;
~SettingsVariable() {
if (m_onChangeId > 0)
removeOnChangeHandler(m_onChangeId);
}
[[nodiscard]] T get() const {
registerChangeHandler();
if (!m_value.has_value()) {
m_value = read<T>(
UnlocalizedCategory.value.data(),
UnlocalizedName.value.data(),
m_defaultValue
);
}
return m_value.value_or(m_defaultValue);
}
void set(T value) {
registerChangeHandler();
write<T>(
UnlocalizedCategory.value.data(),
UnlocalizedName.value.data(),
std::move(value)
);
}
explicit(false) operator T() const {
return get();
}
SettingsVariable& operator=(T value) {
set(std::move(value));
return *this;
}
private:
void registerChangeHandler() const {
if (m_onChangeId > 0)
return;
m_onChangeId = onChange(UnlocalizedCategory.value.data(), UnlocalizedName.value.data(), [this](const SettingsValue &value) {
m_value = value.get<T>(m_defaultValue);
});
}
private:
mutable std::optional<T> m_value;
T m_defaultValue;
mutable u64 m_onChangeId = 0;
};
}
}

View File

@@ -68,7 +68,6 @@ EXPORT_MODULE namespace hex {
constexpr static auto SeparatorValue = "$SEPARATOR$";
constexpr static auto SubMenuValue = "$SUBMENU$";
constexpr static auto TaskBarMenuValue = "$TASKBAR$";
const std::multimap<u32, MainMenuItem>& getMainMenuItems();
@@ -160,15 +159,13 @@ EXPORT_MODULE namespace hex {
* @param function The function to call when the entry is clicked
* @param enabledCallback The function to call to determine if the entry is enabled
* @param view The view to use for the entry. If nullptr, the item will always be visible
* @param showOnWelcomeScreen If this entry should be shown on the welcome screen
*/
void addMenuItemSubMenu(
std::vector<UnlocalizedString> unlocalizedMainMenuNames,
u32 priority,
const impl::MenuCallback &function,
const impl::EnabledCallback& enabledCallback = []{ return true; },
View *view = nullptr,
bool showOnWelcomeScreen = false
View *view = nullptr
);
/**
@@ -179,7 +176,6 @@ EXPORT_MODULE namespace hex {
* @param function The function to call when the entry is clicked
* @param enabledCallback The function to call to determine if the entry is enabled
* @param view The view to use for the entry. If nullptr, the item will always be visible
* @param showOnWelcomeScreen If this entry should be shown on the welcome screen
*/
void addMenuItemSubMenu(
std::vector<UnlocalizedString> unlocalizedMainMenuNames,
@@ -187,8 +183,7 @@ EXPORT_MODULE namespace hex {
u32 priority,
const impl::MenuCallback &function,
const impl::EnabledCallback& enabledCallback = []{ return true; },
View *view = nullptr,
bool showOnWelcomeScreen = false
View *view = nullptr
);
@@ -200,19 +195,6 @@ EXPORT_MODULE namespace hex {
*/
void addMenuItemSeparator(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority, View *view = nullptr);
/**
* @brief Adds a new main menu entry
* @param unlocalizedMainMenuNames The unlocalized names of the main menu entries
* @param priority The priority of the entry. Lower values are displayed first
* @param function The function to call when the entry is clicked
* @param enabledCallback The function to call to determine if the entry is enabled
*/
void addTaskBarMenuItem(
std::vector<UnlocalizedString> unlocalizedMainMenuNames,
u32 priority,
const impl::MenuCallback &function,
const impl::EnabledCallback& enabledCallback
);
/**
* @brief Adds a new welcome screen entry
@@ -234,10 +216,10 @@ EXPORT_MODULE namespace hex {
/**
* @brief Adds a menu item to the toolbar
* @param unlocalizedNames Unlocalized name of the menu item
* @param unlocalizedName Unlocalized name of the menu item
* @param color Color of the toolbar icon
*/
void addMenuItemToToolbar(const std::vector<UnlocalizedString> &unlocalizedNames, ImGuiCustomCol color);
void addMenuItemToToolbar(const UnlocalizedString &unlocalizedName, ImGuiCustomCol color);
/**
* @brief Reconstructs the toolbar items list after they have been modified

View File

@@ -79,11 +79,6 @@ namespace hex {
*/
EVENT_DEF(EventProjectOpened);
/**
* @brief Called when a project is saved/saved as
*/
EVENT_DEF(EventProjectSaved);
/**
* @brief Called when a native message was received from another ImHex instance
* @param rawData Raw bytes received from other instance

View File

@@ -15,7 +15,7 @@ namespace hex {
* This event is responsible for (optionally) initializing the provider and calling EventProviderOpened
* (although the event can also be called manually without problem)
*/
EVENT_DEF(EventProviderCreated, std::shared_ptr<prv::Provider>);
EVENT_DEF(EventProviderCreated, prv::Provider *);
/**
* @brief Called as a continuation of EventProviderCreated

View File

@@ -8,12 +8,7 @@ namespace hex {
/**
* @brief Creates a provider from its unlocalized name, and add it to the provider list
*/
EVENT_DEF(RequestCreateProvider, std::string, bool, bool, std::shared_ptr<hex::prv::Provider> *);
/**
* @brief Used internally when opening a provider through the API
*/
EVENT_DEF(RequestOpenProvider, std::shared_ptr<prv::Provider>);
EVENT_DEF(RequestCreateProvider, std::string, bool, bool, hex::prv::Provider **);
/**
* @brief Move the data from all PerProvider instances from one provider to another

View File

@@ -86,7 +86,7 @@ EXPORT_MODULE namespace hex {
* @param skipLoadInterface Whether to skip the provider's loading interface (see property documentation)
* @param select Whether to select the provider after adding it
*/
void add(std::shared_ptr<prv::Provider> &&provider, bool skipLoadInterface = false, bool select = true);
void add(std::unique_ptr<prv::Provider> &&provider, bool skipLoadInterface = false, bool select = true);
/**
* @brief Creates a new provider and adds it to the list of providers
@@ -111,18 +111,12 @@ EXPORT_MODULE namespace hex {
* @param skipLoadInterface Whether to skip the provider's loading interface (see property documentation)
* @param select Whether to select the provider after adding it
*/
std::shared_ptr<prv::Provider> createProvider(
prv::Provider* createProvider(
const UnlocalizedString &unlocalizedName,
bool skipLoadInterface = false,
bool select = true
);
/**
* @brief Opens a provider, making its data available to ImHex and handling any error that may occur
* @param provider The provider to open
*/
void openProvider(std::shared_ptr<prv::Provider> provider);
}
}

View File

@@ -62,7 +62,6 @@ EXPORT_MODULE namespace hex {
void setMainWindowSize(u32 width, u32 height);
void setMainDockSpaceId(ImGuiID id);
void setMainWindowHandle(GLFWwindow *window);
void setMainWindowFocusState(bool focused);
void setGlobalScale(float scale);
void setNativeScale(float scale);
@@ -162,12 +161,6 @@ EXPORT_MODULE namespace hex {
*/
GLFWwindow* getMainWindowHandle();
/**
* @brief Checks if the main window is currently focused
* @return Whether the main window is focused
*/
bool isMainWindowFocused();
/**
* @brief Checks if borderless window mode is enabled currently
* @return Whether borderless window mode is enabled
@@ -178,7 +171,7 @@ EXPORT_MODULE namespace hex {
* @brief Checks if multi-window mode is enabled currently
* @return Whether multi-window mode is enabled
*/
bool isMultiWindowModeEnabled();
bool isMutliWindowModeEnabled();
/**
* @brief Gets the init arguments passed to ImHex from the splash screen
@@ -283,7 +276,7 @@ EXPORT_MODULE namespace hex {
* @brief Gets the current ImHex version
* @return ImHex version
*/
const SemanticVersion& getImHexVersion();
SemanticVersion getImHexVersion();
/**
* @brief Gets the current git commit hash

View File

@@ -27,7 +27,6 @@ EXPORT_MODULE namespace hex {
LanguageId id;
std::string name, nativeName;
LanguageId fallbackLanguageId;
bool hidden;
std::vector<PathEntry> languageFilePaths;
};
@@ -59,6 +58,7 @@ EXPORT_MODULE namespace hex {
private:
std::size_t m_entryHash;
std::string m_unlocalizedString;
};
class LangConst {
@@ -102,14 +102,6 @@ EXPORT_MODULE namespace hex {
UnlocalizedString(const std::string &string) : m_unlocalizedString(string) { }
UnlocalizedString(const char *string) : m_unlocalizedString(string) { }
UnlocalizedString(const Lang& arg) = delete;
UnlocalizedString(std::string &&string) : m_unlocalizedString(std::move(string)) { }
UnlocalizedString(UnlocalizedString &&) = default;
UnlocalizedString(const UnlocalizedString &) = default;
UnlocalizedString &operator=(const UnlocalizedString &) = default;
UnlocalizedString &operator=(UnlocalizedString &&) = default;
UnlocalizedString &operator=(const std::string &string) { m_unlocalizedString = string; return *this; }
UnlocalizedString &operator=(std::string &&string) { m_unlocalizedString = std::move(string); return *this; }
[[nodiscard]] operator std::string() const {
return m_unlocalizedString;

View File

@@ -151,8 +151,6 @@ EXPORT_MODULE namespace hex {
*/
static void clearShortcuts();
static Shortcut getShortcutByName(const std::vector<UnlocalizedString> &unlocalizedName, const View *view = nullptr);
static void resumeShortcuts();
static void pauseShortcuts();

View File

@@ -10,7 +10,6 @@
#include <condition_variable>
#include <source_location>
#include <thread>
#include <hex/trace/exceptions.hpp>
EXPORT_MODULE namespace hex {
@@ -23,7 +22,7 @@ EXPORT_MODULE namespace hex {
class Task {
public:
Task() = default;
Task(UnlocalizedString unlocalizedName, u64 maxValue, bool background, bool blocking, std::function<void(Task &)> function);
Task(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, bool blocking, std::function<void(Task &)> function);
Task(const Task&) = delete;
Task(Task &&other) noexcept;
@@ -71,8 +70,6 @@ EXPORT_MODULE namespace hex {
[[nodiscard]] u64 getValue() const;
[[nodiscard]] u64 getMaxValue() const;
void wait() const;
private:
void finish();
void interruption();
@@ -90,21 +87,12 @@ EXPORT_MODULE namespace hex {
std::atomic<bool> m_background = true;
std::atomic<bool> m_blocking = false;
std::atomic_flag m_interrupted;
std::atomic_flag m_finished;
std::atomic_flag m_hadException;
std::atomic<bool> m_interrupted = false;
std::atomic<bool> m_finished = false;
std::atomic<bool> m_hadException = false;
std::string m_exceptionMessage;
struct TaskInterruptor: public std::exception {
TaskInterruptor() {
trace::disableExceptionCaptureForCurrentThread();
}
virtual ~TaskInterruptor() = default;
[[nodiscard]] const char* what() const noexcept override {
return "Task Interrupted";
}
};
struct TaskInterruptor { virtual ~TaskInterruptor() = default; };
friend class TaskHolder;
friend class TaskManager;
@@ -126,7 +114,6 @@ EXPORT_MODULE namespace hex {
[[nodiscard]] u32 getProgress() const;
void interrupt() const;
void wait() const;
private:
std::weak_ptr<Task> m_task;
};
@@ -252,8 +239,6 @@ EXPORT_MODULE namespace hex {
static const std::list<std::shared_ptr<Task>>& getRunningTasks();
static void runDeferredCalls();
static void addTaskCompletionCallback(const std::function<void(Task&)>& function);
private:
static TaskHolder createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, bool blocking, std::function<void(Task &)> function);
};

View File

@@ -10,8 +10,6 @@
#include <hex/ui/imgui_imhex_extensions.h>
struct ImRect;
EXPORT_MODULE namespace hex {
class TutorialManager {
@@ -24,8 +22,6 @@ EXPORT_MODULE namespace hex {
Right = 8
};
using DrawFunction = std::function<void()>;
struct Tutorial {
Tutorial() = delete;
Tutorial(const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedDescription) :
@@ -105,7 +101,6 @@ EXPORT_MODULE namespace hex {
std::vector<Highlight> m_highlights;
std::optional<Message> m_message;
std::function<void()> m_onAppear, m_onComplete;
DrawFunction m_drawFunction;
};
Step& addStep();
@@ -151,7 +146,6 @@ EXPORT_MODULE namespace hex {
* @param unlocalizedName Name of tutorial to start
*/
static void startTutorial(const UnlocalizedString &unlocalizedName);
static void stopCurrentTutorial();
static void startHelpHover();
static void addInteractiveHelpText(std::initializer_list<std::variant<Lang, std::string, int>> &&ids, UnlocalizedString unlocalizedString);
@@ -172,10 +166,6 @@ EXPORT_MODULE namespace hex {
*/
static void reset();
static void setRenderer(std::function<DrawFunction(const std::string &)> renderer);
static void postElementRendered(ImGuiID id, const ImRect &boundingBox);
private:
TutorialManager() = delete;

View File

@@ -7,7 +7,6 @@
#include <set>
#include <span>
#include <utility>
#include <vector>
#include <nlohmann/json_fwd.hpp>
@@ -50,15 +49,9 @@ namespace hex::dp {
virtual void store(nlohmann::json &j) const { std::ignore = j; }
virtual void load(const nlohmann::json &j) { std::ignore = j; }
struct NodeError: public std::exception {
struct NodeError {
Node *node;
std::string message;
NodeError(Node *node, std::string message) : node(node), message(std::move(message)) {}
[[nodiscard]] const char* what() const noexcept override {
return this->message.c_str();
}
};
void resetOutputData() {
@@ -109,7 +102,7 @@ namespace hex::dp {
void unmarkInputProcessed(u32 index);
protected:
[[noreturn]] void throwNodeError(const std::string &msg);
[[noreturn]] void throwNodeError(const std::string &message);
void setOverlayData(u64 address, const std::vector<u8> &data);
void setAttributes(std::vector<Attribute> attributes);

View File

@@ -1,7 +1,6 @@
#pragma once
#include <hex/api/imhex_api/system.hpp>
#include <hex/helpers/logger.hpp>
namespace hex {
@@ -10,9 +9,6 @@ namespace hex {
class AutoResetBase {
public:
virtual ~AutoResetBase() = default;
private:
friend void ImHexApi::System::impl::cleanup();
virtual void reset() = 0;
};
@@ -23,20 +19,16 @@ namespace hex {
public:
using Type = T;
AutoReset() noexcept {
try {
ImHexApi::System::impl::addAutoResetObject(this);
} catch (std::exception &e) {
log::error("Failed to register AutoReset object: {}", e.what());
}
AutoReset() {
ImHexApi::System::impl::addAutoResetObject(this);
}
explicit(false) AutoReset(const T &value) : AutoReset() {
AutoReset(const T &value) : AutoReset() {
m_value = value;
m_valid = true;
}
explicit(false) AutoReset(T &&value) noexcept : AutoReset() {
AutoReset(T &&value) noexcept : AutoReset() {
m_value = std::move(value);
m_valid = true;
}
@@ -69,27 +61,29 @@ namespace hex {
return m_value;
}
AutoReset& operator=(const T &value) {
T& operator=(const T &value) {
m_value = value;
m_valid = true;
return *this;
return m_value;
}
AutoReset& operator=(T &&value) noexcept {
T& operator=(T &&value) noexcept {
m_value = std::move(value);
m_valid = true;
return *this;
return m_value;
}
[[nodiscard]] bool isValid() const {
bool isValid() const {
return m_valid;
}
private:
friend void ImHexApi::System::impl::cleanup();
void reset() override {
if constexpr (requires(T t) { t.reset(); }) {
if constexpr (requires { m_value.reset(); }) {
m_value.reset();
} else if constexpr (requires(T t) { t.clear(); }) {
} else if constexpr (requires { m_value.clear(); }) {
m_value.clear();
} else if constexpr (std::is_pointer_v<T>) {
m_value = nullptr; // cppcheck-suppress nullPointer

View File

@@ -10,19 +10,92 @@ namespace hex {
class BinaryPattern {
public:
BinaryPattern() = default;
explicit BinaryPattern(const std::string &pattern);
[[nodiscard]] bool isValid() const;
[[nodiscard]] u64 getSize() const;
[[nodiscard]] bool matches(const std::vector<u8> &bytes) const;
[[nodiscard]] bool matchesByte(u8 byte, u32 offset) const;
struct Pattern {
u8 mask, value;
};
BinaryPattern() = default;
explicit BinaryPattern(const std::string &pattern) : m_patterns(parseBinaryPatternString(pattern)) { }
[[nodiscard]] bool isValid() const { return !m_patterns.empty(); }
[[nodiscard]] bool matches(const std::vector<u8> &bytes) const {
if (bytes.size() < m_patterns.size())
return false;
for (u32 i = 0; i < m_patterns.size(); i++) {
if (!this->matchesByte(bytes[i], i))
return false;
}
return true;
}
[[nodiscard]] bool matchesByte(u8 byte, u32 offset) const {
const auto &pattern = m_patterns[offset];
return (byte & pattern.mask) == pattern.value;
}
[[nodiscard]] u64 getSize() const {
return m_patterns.size();
}
private:
static std::vector<Pattern> parseBinaryPatternString(std::string string) {
std::vector<Pattern> result;
if (string.length() < 2)
return { };
bool inString = false;
while (string.length() > 0) {
Pattern pattern = { 0, 0 };
if (string.starts_with("\"")) {
inString = !inString;
string = string.substr(1);
continue;
} else if (inString) {
pattern = { 0xFF, u8(string.front()) };
string = string.substr(1);
} else if (string.starts_with("??")) {
pattern = { 0x00, 0x00 };
string = string.substr(2);
} else if ((std::isxdigit(string.front()) || string.front() == '?') && string.length() >= 2) {
const auto hex = string.substr(0, 2);
for (const auto &c : hex) {
pattern.mask <<= 4;
pattern.value <<= 4;
if (std::isxdigit(c)) {
pattern.mask |= 0x0F;
if (auto hexValue = hex::hexCharToValue(c); hexValue.has_value())
pattern.value |= hexValue.value();
else
return { };
} else if (c != '?') {
return { };
}
}
string = string.substr(2);
} else if (std::isspace(string.front())) {
string = string.substr(1);
continue;
} else {
return { };
}
result.push_back(pattern);
}
if (inString)
return { };
return result;
}
private:
std::vector<Pattern> m_patterns;
};

View File

@@ -14,10 +14,6 @@
static_assert(false, "Debug variables are only intended for use during development.");
#endif
namespace hex::trace {
struct StackTraceResult;
}
namespace hex::dbg {
namespace impl {
@@ -51,6 +47,4 @@ namespace hex::dbg {
bool debugModeEnabled();
void setDebugModeEnabled(bool enabled);
void printStackTrace(const trace::StackTraceResult &stackTrace);
}

View File

@@ -27,11 +27,10 @@ namespace hex {
EncodingFile& operator=(const EncodingFile &other);
EncodingFile& operator=(EncodingFile &&other) noexcept;
[[nodiscard]] std::pair<std::string_view, size_t> getEncodingFor(std::span<const 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]] u64 getShortestSequence() const { return m_shortestSequence; }
[[nodiscard]] u64 getLongestSequence() const { return m_longestSequence; }
[[nodiscard]] std::string decodeAll(std::span<const u8> buffer) const;
[[nodiscard]] bool valid() const { return m_valid; }

View File

@@ -2,9 +2,7 @@
#include <hex.hpp>
#include <hex/api/task_manager.hpp>
#include <hex/helpers/literals.hpp>
#include <hex/helpers/fs.hpp>
#include <string>
#include <vector>
@@ -29,14 +27,4 @@ namespace hex::magic {
bool isValidMIMEType(const std::string &mimeType);
struct FoundPattern {
std::fs::path patternFilePath;
std::string author;
std::string description;
std::optional<std::string> mimeType;
std::optional<u64> magicOffset;
};
std::vector<FoundPattern> findViablePatterns(prv::Provider *provider, Task* task = nullptr);
}

View File

@@ -12,9 +12,6 @@ namespace hex::menu {
bool beginMenu(const char *label, bool enabled = true);
void endMenu();
bool beginTaskBarMenu();
void endTaskBarMenu();
bool beginMenuEx(const char* label, const char* icon, bool enabled = true);
bool menuItem(const char *label, const Shortcut &shortcut = Shortcut::None, bool selected = false, bool enabled = true);

View File

@@ -10,7 +10,6 @@
#include <span>
#include <string>
#include <numbers>
#include <array>
#include <opengl_support.h>
#include "imgui.h"
@@ -936,7 +935,7 @@ namespace hex::gl {
void attachTexture(const Texture &texture) const;
private:
GLuint m_frameBuffer = 0, m_renderBuffer = 0;
GLuint m_frameBuffer, m_renderBuffer;
};
class AxesVectors {

View File

@@ -28,8 +28,6 @@
#include <imgui.h>
#include <wolv/utils/charconv.hpp>
namespace hex {
#if !defined(HEX_MODULE_EXPORT)
@@ -98,8 +96,6 @@ namespace hex {
void startProgram(const std::vector<std::string> &command);
int executeCommand(const std::string &command);
std::optional<std::string> executeCommandWithOutput(const std::string &command);
void executeCommandDetach(const std::string &command);
void openWebpage(std::string url);
extern "C" void registerFont(const char *fontName, const char *fontPath);
@@ -265,11 +261,7 @@ namespace hex {
if (!std::isxdigit(byteString[i]) || !std::isxdigit(byteString[i + 1]))
return {};
auto value = wolv::util::from_chars<u64>(byteString.substr(i, 2), 16);
if (!value.has_value())
return {};
result.push_back(*value);
result.push_back(std::strtoul(byteString.substr(i, 2).c_str(), nullptr, 16));
}
return result;
@@ -370,7 +362,7 @@ namespace hex {
[[nodiscard]] std::optional<std::string> getEnvironmentVariable(const std::string &env);
[[nodiscard]] std::string limitStringLength(const std::string &string, size_t maxLength, bool fromBothEnds = true);
[[nodiscard]] std::string limitStringLength(const std::string &string, size_t maxLength);
[[nodiscard]] std::optional<std::fs::path> getInitialFilePath();

View File

@@ -32,7 +32,6 @@
void macosInstallEventListener();
void toastMessageMacos(const char *title, const char *message);
void macosSetupDockMenu(void);
}
#endif

View File

@@ -1,15 +0,0 @@
#pragma once
#include <iostream>
namespace hex::mcp {
class Client {
public:
Client() = default;
~Client() = default;
int run(std::istream &input, std::ostream &output);
};
}

View File

@@ -1,123 +0,0 @@
#pragma once
#include <hex.hpp>
#include <functional>
#include <nlohmann/json.hpp>
#include <wolv/net/socket_server.hpp>
namespace hex::mcp {
class JsonRpc {
public:
explicit JsonRpc(std::string request) : m_request(std::move(request)){ }
struct MethodNotFoundException : std::exception {};
struct InvalidParametersException : std::exception {};
enum class ErrorCode: i16 {
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603,
};
using Callback = std::function<nlohmann::json(const std::string &method, const nlohmann::json &params)>;
std::optional<std::string> execute(const Callback &callback);
void setError(ErrorCode code, std::string message);
private:
std::optional<nlohmann::json> handleMessage(const nlohmann::json &request, const Callback &callback);
std::optional<nlohmann::json> handleBatchedMessages(const nlohmann::json &request, const Callback &callback);
nlohmann::json createDefaultMessage();
nlohmann::json createErrorMessage(ErrorCode code, const std::string &message);
nlohmann::json createResponseMessage(const nlohmann::json &result);
private:
std::string m_request;
std::optional<int> m_id;
struct Error {
ErrorCode code;
std::string message;
};
std::optional<Error> m_error;
};
struct TextContent {
std::string text;
operator nlohmann::json() const {
nlohmann::json result;
result["content"] = nlohmann::json::array({
nlohmann::json::object({
{ "type", "text" },
{ "text", text }
})
});
return result;
}
};
struct StructuredContent {
std::string text;
nlohmann::json data;
operator nlohmann::json() const {
nlohmann::json result;
result["content"] = nlohmann::json::array({
nlohmann::json::object({
{ "type", "text" },
{ "text", text }
})
});
result["structuredContent"] = data;
return result;
}
};
class Server {
public:
constexpr static auto McpInternalPort = 19743;
Server();
~Server();
void listen();
void shutdown();
void disconnect();
bool isConnected();
void addPrimitive(std::string type, std::string_view capabilities, std::function<nlohmann::json(const nlohmann::json &params)> function);
struct ClientInfo {
std::string name;
std::string version;
std::string protocolVersion;
};
const ClientInfo& getClientInfo() const {
return m_clientInfo;
}
private:
nlohmann::json handleInitialize(const nlohmann::json &params);
void handleNotifications(const std::string &method, const nlohmann::json &params);
struct Primitive {
nlohmann::json capabilities;
std::function<nlohmann::json(const nlohmann::json &params)> function;
};
std::map<std::string, std::map<std::string, Primitive>> m_primitives;
wolv::net::SocketServer m_server;
bool m_connected = false;
ClientInfo m_clientInfo;
};
}

View File

@@ -46,7 +46,7 @@ void* PluginSubCommandsFunctionHelper<T>::getSubCommands() {
[[maybe_unused]] static auto& getFeaturesImpl() {
static hex::AutoReset<std::vector<hex::Feature>> features;
return *features;
return features;
}
#if defined (IMHEX_STATIC_LINK_PLUGINS)

View File

@@ -21,7 +21,7 @@ namespace hex::prv {
CachedProvider(size_t cacheBlockSize = 4096, size_t maxBlocks = 1024);
~CachedProvider() override;
OpenResult open() override;
bool open() override;
void close() override;
void readRaw(u64 offset, void *buffer, size_t size) override;

View File

@@ -27,7 +27,7 @@ namespace hex::prv {
[[nodiscard]] bool isSavable() const override { return m_name.empty(); }
[[nodiscard]] bool isSavableAsRecent() const override { return false; }
[[nodiscard]] OpenResult open() override;
[[nodiscard]] bool open() override;
void close() override { }
void readRaw(u64 offset, void *buffer, size_t size) override;

View File

@@ -72,21 +72,6 @@ namespace hex::prv {
[[nodiscard]] virtual std::vector<Description> getDataDescription() const = 0;
};
class IProviderDataBackupable {
public:
explicit IProviderDataBackupable(Provider *provider);
virtual ~IProviderDataBackupable() = default;
void createBackupIfNeeded(const std::fs::path &inputFilePath);
private:
Provider *m_provider = nullptr;
bool m_backupCreated = false;
bool m_shouldCreateBackups = true;
u64 m_maxSize;
std::string m_backupExtension;
};
/**
* @brief Represent the data source for a tab in the UI
*/
@@ -94,65 +79,6 @@ namespace hex::prv {
public:
constexpr static u64 MaxPageSize = 0xFFFF'FFFF'FFFF'FFFF;
class OpenResult {
public:
OpenResult() : m_result(std::monostate{}) {}
[[nodiscard]] static OpenResult failure(std::string errorMessage) {
OpenResult result;
result.m_result = std::move(errorMessage);
return result;
}
[[nodiscard]] static OpenResult warning(std::string warningMessage) {
OpenResult result;
result.m_result = std::move(warningMessage);
result.m_warning = true;
return result;
}
[[nodiscard]] static OpenResult redirect(Provider *provider) {
OpenResult result;
result.m_result = provider;
return result;
}
[[nodiscard]] bool isSuccess() const {
return std::holds_alternative<std::monostate>(m_result);
}
[[nodiscard]] bool isFailure() const {
return std::holds_alternative<std::string>(m_result) && !m_warning;
}
[[nodiscard]] bool isWarning() const {
return std::holds_alternative<std::string>(m_result) && m_warning;
}
[[nodiscard]] bool isRedirecting() const {
return std::holds_alternative<Provider*>(m_result);
}
[[nodiscard]] Provider* getRedirectProvider() const {
if (std::holds_alternative<Provider*>(m_result)) {
return std::get<Provider*>(m_result);
}
return nullptr;
}
[[nodiscard]] std::string_view getErrorMessage() const {
if (std::holds_alternative<std::string>(m_result)) {
return std::get<std::string>(m_result);
}
return "";
}
private:
std::variant<std::monostate, std::string, Provider*> m_result;
bool m_warning = false;
};
Provider();
virtual ~Provider();
Provider(const Provider&) = delete;
@@ -168,7 +94,7 @@ namespace hex::prv {
* @note This is not related to the EventProviderOpened event
* @return true if the provider was opened successfully, else false
*/
[[nodiscard]] virtual OpenResult open() = 0;
[[nodiscard]] virtual bool open() = 0;
/**
* @brief Closes this provider
@@ -336,6 +262,9 @@ namespace hex::prv {
void skipLoadInterface() { m_skipLoadInterface = true; }
[[nodiscard]] bool shouldSkipLoadInterface() const { return m_skipLoadInterface; }
void setErrorMessage(const std::string &errorMessage) { m_errorMessage = errorMessage; }
[[nodiscard]] const std::string& getErrorMessage() const { return m_errorMessage; }
template<std::derived_from<undo::Operation> T>
bool addUndoableOperation(auto && ... args) {
return m_undoRedoStack.add<T>(std::forward<decltype(args)...>(args)...);
@@ -367,6 +296,8 @@ namespace hex::prv {
*/
bool m_skipLoadInterface = false;
std::string m_errorMessage = "Unspecified error";
u64 m_pageSize = MaxPageSize;
};

View File

@@ -7,7 +7,6 @@
#include <map>
#include <memory>
#include <mutex>
#include <vector>
namespace hex::prv {
@@ -41,8 +40,6 @@ namespace hex::prv::undo {
bool add(std::unique_ptr<Operation> &&operation);
static std::recursive_mutex& getMutex();
const std::vector<std::unique_ptr<Operation>> &getAppliedOperations() const {
return m_undoStack;
}

View File

@@ -49,7 +49,7 @@ namespace hex::test {
[[nodiscard]] UnlocalizedString getTypeName() const override { return "hex.test.provider.test"; }
OpenResult open() override { return {}; }
bool open() override { return true; }
void close() override { }
nlohmann::json storeSettings(nlohmann::json) const override { return {}; }

View File

@@ -11,7 +11,6 @@
#include <hex/helpers/fmt.hpp>
#include <hex/helpers/concepts.hpp>
#include <hex/helpers/fs.hpp>
#include <hex/helpers/scaling.hpp>
#include <wolv/utils/string.hpp>
@@ -134,8 +133,8 @@ namespace ImGuiExt {
bool IconHyperlink(const char *icon, const char *label, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
bool Hyperlink(const char *label, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
bool BulletHyperlink(const char *label, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
bool DescriptionButton(const char *label, const char *description, const char *icon, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
bool DescriptionButtonProgress(const char *label, const char *description, const char *icon, float fraction, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
bool DescriptionButton(const char *label, const char *description, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
bool DescriptionButtonProgress(const char *label, const char *description, float fraction, const ImVec2 &size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
void HelpHover(const char *text, const char *icon = "(?)", ImU32 iconColor = ImGui::GetColorU32(ImGuiCol_ButtonActive));
@@ -254,12 +253,11 @@ namespace ImGuiExt {
}
void TextFormattedWrappedSelectable(std::string_view fmt, auto &&...args) {
using namespace hex;
// Manually wrap text, using the letter M (generally the widest character in non-monospaced fonts) to calculate the character width to use.
auto text = wolv::util::trim(wolv::util::wrapMonospacedString(
fmt::format(fmt::runtime(fmt), std::forward<decltype(args)>(args)...),
ImGui::CalcTextSize("M").x,
std::max(100_scaled, ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ScrollbarSize - ImGui::GetStyle().FrameBorderSize)
ImGui::GetContentRegionAvail().x - ImGui::GetStyle().ScrollbarSize - ImGui::GetStyle().FrameBorderSize
));
auto textSize = ImGui::CalcTextSize(text.c_str());
@@ -270,7 +268,7 @@ namespace ImGuiExt {
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 0.0F);
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4());
ImGui::PushItemWidth(textSize.x + ImGui::GetStyle().FramePadding.x * 2);
ImGui::PushItemWidth(ImGui::CalcTextSize(text.c_str()).x + ImGui::GetStyle().FramePadding.x * 2);
ImGui::InputTextMultiline(
"##",
const_cast<char *>(text.c_str()),
@@ -314,12 +312,11 @@ namespace ImGuiExt {
bool BitCheckbox(const char* label, bool* v);
bool DimmedButton(const char* label, ImVec2 size = ImVec2(0, 0), ImGuiButtonFlags flags = ImGuiButtonFlags_None);
bool DimmedButton(const char* label, ImVec2 size = ImVec2(0, 0));
bool DimmedIconButton(const char *symbol, ImVec4 color, ImVec2 size = ImVec2(0, 0), ImVec2 iconOffset = ImVec2(0, 0));
bool DimmedButtonToggle(const char *icon, bool *v, ImVec2 size = ImVec2(0, 0), ImVec2 iconOffset = ImVec2(0, 0));
bool DimmedIconToggle(const char *icon, bool *v);
bool DimmedIconToggle(const char *iconOn, const char *iconOff, bool *v);
bool DimmedArrowButton(const char *id, ImGuiDir dir, ImVec2 size = ImVec2(ImGui::GetFrameHeight(), ImGui::GetFrameHeight()));
void TextOverlay(const char *text, ImVec2 pos, float maxWidth = -1);

View File

@@ -6,7 +6,6 @@
#include <list>
#include <memory>
#include <mutex>
#include <hex/api/task_manager.hpp>
namespace hex {
@@ -52,11 +51,11 @@ namespace hex {
template<typename ...Args>
static void open(Args && ... args) {
TaskManager::doLater([=] {
auto toast = std::make_unique<T>(args...);
getQueuedToasts().emplace_back(std::move(toast));
});
std::lock_guard lock(getMutex());
auto toast = std::make_unique<T>(std::forward<Args>(args)...);
getQueuedToasts().emplace_back(std::move(toast));
}
};
}
}

View File

@@ -26,7 +26,7 @@ namespace hex {
* @brief Draws the view
* @note Do not override this method. Override drawContent() instead
*/
virtual void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) = 0;
virtual void draw() = 0;
/**
* @brief Draws the content of the view
@@ -82,12 +82,10 @@ namespace hex {
*/
[[nodiscard]] virtual View* getMenuItemInheritView() const { return nullptr; }
[[nodiscard]] const char *getIcon() const { return m_icon; }
[[nodiscard]] const UnlocalizedString& getUnlocalizedName() const;
[[nodiscard]] std::string getName() const;
[[nodiscard]] virtual bool shouldDefaultFocus() const { return false; }
[[nodiscard]] virtual bool shouldStoreWindowState() const { return true; }
[[nodiscard]] bool &getWindowOpenState();
@@ -110,22 +108,10 @@ namespace hex {
void trackViewState();
void setFocused(bool focused);
protected:
/**
* @brief Called when this view is opened (i.e. made visible).
*/
virtual void onOpen() {}
/**
* @brief Called when this view is closed (i.e. made invisible).
*/
virtual void onClose() {}
public:
class Window;
class Special;
class Floating;
class Scrolling;
class Modal;
class FullScreen;
@@ -147,24 +133,17 @@ namespace hex {
class View::Window : public View {
public:
explicit Window(UnlocalizedString unlocalizedName, const char *icon) : View(std::move(unlocalizedName), icon) {}
[[nodiscard]] ImGuiWindow *getFocusedSubWindow() const { return m_focusedSubWindow; }
/**
* @brief Draws help text for the view
*/
virtual void drawHelpText() = 0;
void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) override;
[[nodiscard]] virtual bool allowScroll() const {
return false;
void draw() final {
if (this->shouldDraw()) {
ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize());
const auto title = fmt::format("{} {}", this->getIcon(), View::toWindowName(this->getUnlocalizedName()));
if (ImGui::Begin(title.c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse | this->getWindowFlags())) {
this->drawContent();
}
ImGui::End();
}
}
private:
void handleFocusRestoration();
private:
ImGuiWindow *m_focusedSubWindow{nullptr};
};
/**
@@ -175,7 +154,12 @@ namespace hex {
public:
explicit Special(UnlocalizedString unlocalizedName) : View(std::move(unlocalizedName), "") {}
void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) final;
void draw() final {
if (this->shouldDraw()) {
ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize());
this->drawContent();
}
}
};
/**
@@ -185,25 +169,10 @@ namespace hex {
public:
explicit Floating(UnlocalizedString unlocalizedName, const char *icon) : Window(std::move(unlocalizedName), icon) {}
void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) final;
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const override { return ImGuiWindowFlags_NoDocking; }
[[nodiscard]] bool shouldStoreWindowState() const override { return false; }
};
/**
* @brief A view that draws all its content at once without any scrolling being done by the window itself
*/
class View::Scrolling : public View::Window {
public:
explicit Scrolling(UnlocalizedString unlocalizedName, const char *icon) : Window(std::move(unlocalizedName), icon) {}
void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) final;
[[nodiscard]] bool allowScroll() const final {
return true;
}
};
/**
* @brief A view that draws a modal window. The window will always be drawn on top and will block input to other windows
*/
@@ -211,7 +180,24 @@ namespace hex {
public:
explicit Modal(UnlocalizedString unlocalizedName, const char *icon) : View(std::move(unlocalizedName), icon) {}
void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) final;
void draw() final {
if (this->shouldDraw()) {
if (this->getWindowOpenState())
ImGui::OpenPopup(View::toWindowName(this->getUnlocalizedName()).c_str());
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F));
ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize());
const auto title = fmt::format("{} {}", this->getIcon(), View::toWindowName(this->getUnlocalizedName()));
if (ImGui::BeginPopupModal(title.c_str(), this->hasCloseButton() ? &this->getWindowOpenState() : nullptr, ImGuiWindowFlags_NoCollapse | this->getWindowFlags())) {
this->drawContent();
ImGui::EndPopup();
}
if (ImGui::IsKeyPressed(ImGuiKey_Escape))
this->getWindowOpenState() = false;
}
}
[[nodiscard]] virtual bool hasCloseButton() const { return true; }
[[nodiscard]] bool shouldStoreWindowState() const override { return false; }
@@ -221,7 +207,10 @@ namespace hex {
public:
explicit FullScreen() : View("FullScreen", "") {}
void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) final;
void draw() final {
this->drawContent();
this->drawAlwaysVisibleContent();
}
};
}
}

View File

@@ -264,7 +264,8 @@ namespace hex {
}
}
if (json.empty()) return;
if (json.empty())
return;
#if defined(OS_WEB)
auto data = json.dump();

View File

@@ -594,12 +594,6 @@ namespace hex {
return false;
}
bool Spacer::draw(const std::string& name) {
std::ignore = name;
ImGui::NewLine();
return false;
}
}
@@ -630,22 +624,22 @@ namespace hex {
void add(Type type, const std::string &command, const UnlocalizedString &unlocalizedDescription, const impl::DisplayCallback &displayCallback, const impl::ExecuteCallback &executeCallback) {
log::debug("Registered new command palette command: {}", command);
impl::s_entries->push_back(impl::Entry { .type=type, .command=command, .unlocalizedDescription=unlocalizedDescription, .displayCallback=displayCallback, .executeCallback=executeCallback });
impl::s_entries->push_back(impl::Entry { type, command, unlocalizedDescription, displayCallback, executeCallback });
}
void addHandler(Type type, const std::string &command, const impl::QueryCallback &queryCallback, const impl::DisplayCallback &displayCallback) {
log::debug("Registered new command palette command handler: {}", command);
impl::s_handlers->push_back(impl::Handler { .type=type, .command=command, .queryCallback=queryCallback, .displayCallback=displayCallback });
impl::s_handlers->push_back(impl::Handler { type, command, queryCallback, displayCallback });
}
void setDisplayedContent(const impl::ContentDisplayCallback &displayCallback) {
impl::s_displayedContent = impl::ContentDisplay { .showSearchBox=true, .callback=displayCallback };
impl::s_displayedContent = impl::ContentDisplay { true, displayCallback };
}
void openWithContent(const impl::ContentDisplayCallback &displayCallback) {
RequestOpenCommandPalette::post();
impl::s_displayedContent = impl::ContentDisplay { .showSearchBox=false, .callback=displayCallback };
impl::s_displayedContent = impl::ContentDisplay { false, displayCallback };
}
}
@@ -783,12 +777,12 @@ namespace hex {
void addVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, pl::api::FunctionParameterCount parameterCount) {
log::debug("Registered new pattern visualizer function: {}", name);
(*impl::s_visualizers)[name] = impl::Visualizer { .parameterCount=parameterCount, .callback=function };
(*impl::s_visualizers)[name] = impl::Visualizer { parameterCount, function };
}
void addInlineVisualizer(const std::string &name, const impl::VisualizerFunctionCallback &function, pl::api::FunctionParameterCount parameterCount) {
log::debug("Registered new inline pattern visualizer function: {}", name);
(*impl::s_inlineVisualizers)[name] = impl::Visualizer { .parameterCount=parameterCount, .callback=function };
(*impl::s_inlineVisualizers)[name] = impl::Visualizer { parameterCount, function };
}
}
@@ -854,7 +848,7 @@ namespace hex {
void add(const UnlocalizedString &unlocalizedName, const char *icon, const impl::Callback &function) {
log::debug("Registered new tool: {}", unlocalizedName.get());
impl::s_tools->emplace_back(impl::Entry { .unlocalizedName=unlocalizedName, .icon=icon, .function=function });
impl::s_tools->emplace_back(impl::Entry { unlocalizedName, icon, function });
}
}
@@ -870,18 +864,6 @@ namespace hex {
}
namespace EditWidget {
std::optional<std::vector<u8>> TextInput::draw(std::string &value, std::endian endian) {
if (ImGui::InputText("##InspectorLineEditing", value,
ImGuiInputTextFlags_EnterReturnsTrue |
ImGuiInputTextFlags_AutoSelectAll)) {
return getBytes(value, endian);
}
return std::nullopt;
}
}
void add(const UnlocalizedString &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
log::debug("Registered new data inspector format: {}", unlocalizedName.get());
@@ -1009,7 +991,7 @@ namespace hex {
coloredIcon.color = ImGuiCustomCol_ToolbarGray;
impl::s_menuItems->insert({
priority, impl::MenuItem { .unlocalizedNames=unlocalizedMainMenuNames, .icon=coloredIcon, .shortcut=shortcut, .view=view, .callback=function, .enabledCallback=enabledCallback, .selectedCallback=selectedCallback, .toolbarIndex=-1 }
priority, impl::MenuItem { unlocalizedMainMenuNames, coloredIcon, shortcut, view, function, enabledCallback, selectedCallback, -1 }
});
if (shortcut != Shortcut::None) {
@@ -1024,32 +1006,23 @@ namespace hex {
}
}
void addMenuItemSubMenu(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, View *view, bool showOnWelcomeScreen) {
addMenuItemSubMenu(std::move(unlocalizedMainMenuNames), "", priority, function, enabledCallback, view, showOnWelcomeScreen);
void addMenuItemSubMenu(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, View *view) {
addMenuItemSubMenu(std::move(unlocalizedMainMenuNames), "", priority, function, enabledCallback, view);
}
void addMenuItemSubMenu(std::vector<UnlocalizedString> unlocalizedMainMenuNames, const char *icon, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, View *view, bool showOnWelcomeScreen) {
void addMenuItemSubMenu(std::vector<UnlocalizedString> unlocalizedMainMenuNames, const char *icon, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, View *view) {
log::debug("Added new menu item sub menu to menu {} with priority {}", unlocalizedMainMenuNames[0].get(), priority);
unlocalizedMainMenuNames.emplace_back(impl::SubMenuValue);
impl::s_menuItems->insert({
priority, impl::MenuItem { .unlocalizedNames=unlocalizedMainMenuNames, .icon=icon, .shortcut=showOnWelcomeScreen ? Shortcut({ ShowOnWelcomeScreen }) : Shortcut::None, .view=view, .callback=function, .enabledCallback=enabledCallback, .selectedCallback=[]{ return false; }, .toolbarIndex=-1 }
priority, impl::MenuItem { unlocalizedMainMenuNames, icon, Shortcut::None, view, function, enabledCallback, []{ return false; }, -1 }
});
}
void addMenuItemSeparator(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority, View *view) {
unlocalizedMainMenuNames.emplace_back(impl::SeparatorValue);
impl::s_menuItems->insert({
priority, impl::MenuItem { .unlocalizedNames=unlocalizedMainMenuNames, .icon="", .shortcut=Shortcut::None, .view=view, .callback=[]{}, .enabledCallback=[]{ return true; }, .selectedCallback=[]{ return false; }, .toolbarIndex=-1 }
});
}
void addTaskBarMenuItem(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback) {
log::debug("Added new taskbar menu item to menu {} ", unlocalizedMainMenuNames[0].get());
unlocalizedMainMenuNames.insert(unlocalizedMainMenuNames.begin(), impl::TaskBarMenuValue);
impl::s_menuItems->insert({
priority, impl::MenuItem { .unlocalizedNames=unlocalizedMainMenuNames, .icon="", .shortcut=Shortcut::None, .view=nullptr, .callback=function, .enabledCallback=enabledCallback, .selectedCallback=[]{ return false; }, .toolbarIndex=-1 }
priority, impl::MenuItem { unlocalizedMainMenuNames, "", Shortcut::None, view, []{}, []{ return true; }, []{ return false; }, -1 }
});
}
@@ -1065,13 +1038,13 @@ namespace hex {
impl::s_toolbarItems->push_back(function);
}
void addMenuItemToToolbar(const std::vector<UnlocalizedString>& unlocalizedNames, ImGuiCustomCol color) {
void addMenuItemToToolbar(const UnlocalizedString& unlocalizedName, ImGuiCustomCol color) {
const auto maxIndex = std::ranges::max_element(impl::getMenuItems(), [](const auto &a, const auto &b) {
return a.second.toolbarIndex < b.second.toolbarIndex;
})->second.toolbarIndex;
for (auto &[priority, menuItem] : *impl::s_menuItems) {
if (menuItem.unlocalizedNames == unlocalizedNames) {
if (menuItem.unlocalizedNames.back() == unlocalizedName) {
menuItem.toolbarIndex = maxIndex + 1;
menuItem.icon.color = color;
updateToolbarItems();
@@ -1123,18 +1096,18 @@ namespace hex {
}
namespace ContentRegistry::Provider {
namespace ContentRegistry::Provider::impl {
namespace impl {
void add(const std::string &typeName, ProviderCreationFunction creationFunction) {
(void)RequestCreateProvider::subscribe([expectedName = typeName, creationFunction](const std::string &name, bool skipLoadInterface, bool selectProvider, std::shared_ptr<prv::Provider> *provider) {
(void)RequestCreateProvider::subscribe([expectedName = typeName, creationFunction](const std::string &name, bool skipLoadInterface, bool selectProvider, prv::Provider **provider) {
if (name != expectedName) return;
auto newProvider = creationFunction();
if (provider != nullptr) {
*provider = newProvider;
*provider = newProvider.get();
ImHexApi::Provider::add(std::move(newProvider), skipLoadInterface, selectProvider);
}
});
@@ -1154,7 +1127,7 @@ namespace hex {
}
}
namespace ContentRegistry::DataFormatter {
@@ -1310,42 +1283,47 @@ namespace hex {
}
namespace ContentRegistry::Diffing {
namespace ContentRegistry::Diffing::impl {
namespace impl {
static AutoReset<std::vector<std::unique_ptr<Algorithm>>> s_algorithms;
const std::vector<std::unique_ptr<Algorithm>>& getAlgorithms() {
return *s_algorithms;
}
static AutoReset<std::vector<std::unique_ptr<Algorithm>>> s_algorithms;
const std::vector<std::unique_ptr<Algorithm>>& getAlgorithms() {
return *s_algorithms;
}
void addAlgorithm(std::unique_ptr<Algorithm> &&hash) {
s_algorithms->emplace_back(std::move(hash));
}
void addAlgorithm(std::unique_ptr<Algorithm> &&hash) {
s_algorithms->emplace_back(std::move(hash));
}
}
namespace ContentRegistry::Hashes {
namespace ContentRegistry::Hashes::impl {
namespace impl {
static AutoReset<std::vector<std::unique_ptr<Hash>>> s_hashes;
const std::vector<std::unique_ptr<Hash>>& getHashes() {
return *s_hashes;
}
static AutoReset<std::vector<std::unique_ptr<Hash>>> s_hashes;
const std::vector<std::unique_ptr<Hash>>& getHashes() {
return *s_hashes;
}
void add(std::unique_ptr<Hash> &&hash) {
s_hashes->emplace_back(std::move(hash));
}
void add(std::unique_ptr<Hash> &&hash) {
s_hashes->emplace_back(std::move(hash));
}
}
namespace ContentRegistry::BackgroundServices {
namespace impl {
class Service {
public:
Service(UnlocalizedString unlocalizedName, std::jthread thread) : m_unlocalizedName(std::move(unlocalizedName)), m_thread(std::move(thread)) { }
Service(const UnlocalizedString &unlocalizedName, std::jthread thread) : m_unlocalizedName(std::move(unlocalizedName)), m_thread(std::move(thread)) { }
Service(const Service&) = delete;
Service(Service &&) = default;
~Service() {
@@ -1417,40 +1395,6 @@ namespace hex {
}
namespace ContentRegistry::MCP {
namespace impl {
std::unique_ptr<mcp::Server>& getMcpServerInstance() {
static std::unique_ptr<mcp::Server> server;
if (server == nullptr)
server = std::make_unique<mcp::Server>();
return server;
}
static bool s_mcpEnabled = false;
void setEnabled(bool enabled) {
s_mcpEnabled = enabled;
}
}
bool isEnabled() {
return impl::s_mcpEnabled;
}
bool isConnected() {
return impl::getMcpServerInstance()->isConnected();
}
void registerTool(std::string_view capabilities, std::function<nlohmann::json(const nlohmann::json &params)> function) {
impl::getMcpServerInstance()->addPrimitive("tools", capabilities, function);
}
}
namespace ContentRegistry::Experiments {
namespace impl {
@@ -1544,19 +1488,22 @@ namespace hex {
}
}
namespace ContentRegistry::Disassemblers::impl {
namespace ContentRegistry::Disassemblers {
static AutoReset<std::map<std::string, impl::CreatorFunction>> s_architectures;
namespace impl {
void addArchitectureCreator(impl::CreatorFunction function) {
const auto arch = function();
(*s_architectures)[arch->getName()] = std::move(function);
}
static AutoReset<std::map<std::string, impl::CreatorFunction>> s_architectures;
void addArchitectureCreator(impl::CreatorFunction function) {
const auto arch = function();
(*s_architectures)[arch->getName()] = std::move(function);
}
const std::map<std::string, impl::CreatorFunction>& getArchitectures() {
return *s_architectures;
}
const std::map<std::string, impl::CreatorFunction>& getArchitectures() {
return *s_architectures;
}
}

View File

@@ -1,4 +1,3 @@
#include <algorithm>
#include <hex/api/event_manager.hpp>
namespace hex {
@@ -36,7 +35,7 @@ namespace hex {
void EventManager::unsubscribe(void *token, impl::EventId id) {
auto &tokenStore = getTokenStore();
auto iter = std::ranges::find_if(tokenStore, [&](auto &item) {
auto iter = std::find_if(tokenStore.begin(), tokenStore.end(), [&](auto &item) {
return item.first == token && item.second->first == id;
});

View File

@@ -47,10 +47,6 @@
#if defined(OS_WEB)
#include <emscripten.h>
#elif defined(OS_MACOS)
extern "C" {
void macosRegisterFont(const unsigned char *data, size_t size);
}
#endif
namespace hex {
@@ -261,7 +257,7 @@ namespace hex {
}
void setSelection(u64 address, size_t size, prv::Provider *provider) {
setSelection({ { .address=address, .size=size }, provider == nullptr ? Provider::get() : provider });
setSelection({ { address, size }, provider == nullptr ? Provider::get() : provider });
}
void addVirtualFile(const std::string &path, std::vector<u8> data, Region region) {
@@ -285,7 +281,7 @@ namespace hex {
}
u64 add(u64 address, size_t size, const std::string &name, const std::string &comment, u32 color) {
return add(Region { .address=address, .size=size }, name, comment, color);
return add(Region { address, size }, name, comment, color);
}
void remove(u64 id) {
@@ -298,8 +294,8 @@ namespace hex {
namespace ImHexApi::Provider {
static i64 s_currentProvider = -1;
static AutoReset<std::vector<std::shared_ptr<prv::Provider>>> s_providers;
static AutoReset<std::map<prv::Provider*, std::shared_ptr<prv::Provider>>> s_providersToRemove;
static AutoReset<std::vector<std::unique_ptr<prv::Provider>>> s_providers;
static AutoReset<std::map<prv::Provider*, std::unique_ptr<prv::Provider>>> s_providersToRemove;
namespace impl {
@@ -386,7 +382,7 @@ namespace hex {
});
}
void add(std::shared_ptr<prv::Provider> &&provider, bool skipLoadInterface, bool select) {
void add(std::unique_ptr<prv::Provider> &&provider, bool skipLoadInterface, bool select) {
std::scoped_lock lock(impl::s_providerMutex);
if (TaskManager::getRunningTaskCount() > 0)
@@ -395,7 +391,7 @@ namespace hex {
if (skipLoadInterface)
provider->skipLoadInterface();
EventProviderCreated::post(provider);
EventProviderCreated::post(provider.get());
s_providers->emplace_back(std::move(provider));
if (select || s_providers->size() == 1)
@@ -495,17 +491,13 @@ namespace hex {
});
}
std::shared_ptr<prv::Provider> createProvider(const UnlocalizedString &unlocalizedName, bool skipLoadInterface, bool select) {
std::shared_ptr<prv::Provider> result = nullptr;
prv::Provider* createProvider(const UnlocalizedString &unlocalizedName, bool skipLoadInterface, bool select) {
prv::Provider* result = nullptr;
RequestCreateProvider::post(unlocalizedName, skipLoadInterface, select, &result);
return result;
}
void openProvider(std::shared_ptr<prv::Provider> provider) {
RequestOpenProvider::post(provider);
}
}
namespace ImHexApi::System {
@@ -538,11 +530,6 @@ namespace hex {
s_mainWindowHandle = window;
}
static bool s_mainWindowFocused = false;
void setMainWindowFocusState(bool focused) {
s_mainWindowFocused = focused;
}
static float s_globalScale = 1.0;
void setGlobalScale(float scale) {
@@ -680,15 +667,13 @@ namespace hex {
if (!sessionType.has_value() || sessionType == "x11")
return 1.0F;
else {
int windowW, windowH;
int displayW, displayH;
glfwGetWindowSize(getMainWindowHandle(), &windowW, &windowH);
glfwGetFramebufferSize(getMainWindowHandle(), &displayW, &displayH);
float xScale = 0, yScale = 0;
glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xScale, &yScale);
return (windowW > 0) ? float(displayW) / windowW : 1.0f;
return std::midpoint(xScale, yScale);
}
#elif defined(OS_WEB)
return emscripten_get_device_pixel_ratio();
return 1.0F;
#else
return 1.0F;
#endif
@@ -715,15 +700,11 @@ namespace hex {
return impl::s_mainWindowHandle;
}
bool isMainWindowFocused() {
return impl::s_mainWindowFocused;
}
bool isBorderlessWindowModeEnabled() {
return impl::s_borderlessWindowMode;
}
bool isMultiWindowModeEnabled() {
bool isMutliWindowModeEnabled() {
return impl::s_multiWindowMode;
}
@@ -915,16 +896,15 @@ namespace hex {
}
}
return { { .name=name, .version=version } };
return { { name, version } };
}
const SemanticVersion& getImHexVersion() {
SemanticVersion getImHexVersion() {
#if defined(IMHEX_VERSION)
static auto version = SemanticVersion(IMHEX_VERSION);
return version;
#else
static auto version = SemanticVersion();
return version;
return {};
#endif
}
@@ -966,9 +946,7 @@ namespace hex {
}
bool isNightlyBuild() {
const static bool isNightly = getImHexVersion().nightly();
return isNightly;
return getImHexVersion().nightly();
}
std::optional<std::string> checkForUpdate() {
@@ -1001,13 +979,7 @@ namespace hex {
const auto nightlyUpdateTime = hex::parseTime("%Y-%m-%dT%H:%M:%SZ", firstAsset["updated_at"].get<std::string>());
const auto imhexBuildTime = ImHexApi::System::getBuildTime();
// Give a bit of time leniency for the update time check
// We're comparing here the binary build time to the release upload time. If we were to strictly compare
// upload time to be greater than current build time, the check would always be true since the CI
// takes a few minutes after the build to actually upload the artifact.
// TODO: Is there maybe a better way to handle this without downloading the artifact just to check the build time?
if (nightlyUpdateTime.has_value() && imhexBuildTime.has_value() && *nightlyUpdateTime > *imhexBuildTime + std::chrono::hours(1)) {
if (nightlyUpdateTime.has_value() && imhexBuildTime.has_value() && *nightlyUpdateTime > *imhexBuildTime) {
return "Nightly";
}
} else {
@@ -1220,10 +1192,6 @@ namespace hex {
offset,
fontSizeMultiplier
);
#if defined(OS_MACOS)
macosRegisterFont(data.data(), data.size_bytes());
#endif
}
void registerFont(const Font& font) {
@@ -1235,7 +1203,7 @@ namespace hex {
if (it == impl::s_fontDefinitions->end()) {
const auto defaultFont = ImGui::GetDefaultFont();
return { .regular=defaultFont, .bold=defaultFont, .italic=defaultFont };
return { defaultFont, defaultFont, defaultFont };
} else
return it->second;
}

View File

@@ -146,7 +146,7 @@ namespace hex {
}
void LayoutManager::lockLayout(bool locked) {
log::debug("Layout {}", locked ? "locked" : "unlocked");
log::info("Layout {}", locked ? "locked" : "unlocked");
s_layoutLocked = locked;
}

View File

@@ -7,7 +7,6 @@
#include <nlohmann/json.hpp>
#include <mutex>
#include <hex/helpers/debugging.hpp>
namespace hex {
@@ -50,13 +49,9 @@ namespace hex {
definition.fallbackLanguageId = item["fallback"].get<std::string>();
}
if (item.contains("hidden") && item["hidden"].get<bool>()) {
definition.hidden = true;
}
const auto path = item["path"].get<std::string>();
definition.languageFilePaths.emplace_back(PathEntry{ .path=path, .callback=callback });
definition.languageFilePaths.emplace_back(PathEntry{ path, callback });
}
}
@@ -104,21 +99,9 @@ namespace hex {
for (const auto &entry : json.items()) {
auto value = entry.value().get<std::string>();
// Skip empty values
if (value.empty())
continue;
// Handle references to files
if (value.starts_with("#@")) {
try {
value = path.callback(value.substr(2));
} catch (std::exception &e) {
log::error("Failed to load localization file reference '{}': {}", entry.key(), e.what());
continue;
}
}
localizations.try_emplace(LangConst::hash(entry.key()), std::move(value));
}
} catch (std::exception &e) {
@@ -155,7 +138,7 @@ namespace hex {
static AutoReset<std::unordered_map<std::size_t, std::string>> loadedLocalization;
static std::mutex mutex;
std::scoped_lock lock(mutex);
std::lock_guard lock(mutex);
if (*currentLanguageId != languageId) {
currentLanguageId = languageId;
loadedLocalization->clear();
@@ -171,33 +154,16 @@ namespace hex {
const LanguageDefinition& getLanguageDefinition(const LanguageId &languageId) {
const auto bestMatch = findBestLanguageMatch(languageId);
const auto &result = (*s_languageDefinitions)[bestMatch];
if (!dbg::debugModeEnabled()) {
if (result.hidden)
return getLanguageDefinition(result.fallbackLanguageId);
}
return result;
return (*s_languageDefinitions)[bestMatch];
}
}
static AutoReset<std::map<std::size_t, std::string>> s_unlocalizedNames;
Lang::Lang(std::string_view unlocalizedString) : m_entryHash(LangConst::hash(unlocalizedString)) {
if (!s_unlocalizedNames->contains(m_entryHash)) [[unlikely]] {
s_unlocalizedNames->emplace(m_entryHash, unlocalizedString);
}
}
Lang::Lang(const char *unlocalizedString) : Lang(std::string_view(unlocalizedString)) { }
Lang::Lang(const std::string &unlocalizedString) : Lang(std::string_view(unlocalizedString)) { }
Lang::Lang(const LangConst &localizedString) : m_entryHash(localizedString.m_entryHash) {
if (!s_unlocalizedNames->contains(m_entryHash)) [[unlikely]] {
s_unlocalizedNames->emplace(m_entryHash, localizedString.m_unlocalizedString);
}
}
Lang::Lang(const UnlocalizedString &unlocalizedString) : Lang(unlocalizedString.get()) { }
Lang::Lang(const char *unlocalizedString) : m_entryHash(LangConst::hash(unlocalizedString)), m_unlocalizedString(unlocalizedString) { }
Lang::Lang(const std::string &unlocalizedString) : m_entryHash(LangConst::hash(unlocalizedString)), m_unlocalizedString(unlocalizedString) { }
Lang::Lang(const LangConst &localizedString) : m_entryHash(localizedString.m_entryHash), m_unlocalizedString(localizedString.m_unlocalizedString) { }
Lang::Lang(const UnlocalizedString &unlocalizedString) : m_entryHash(LangConst::hash(unlocalizedString.get())), m_unlocalizedString(unlocalizedString.get()) { }
Lang::Lang(std::string_view unlocalizedString) : m_entryHash(LangConst::hash(unlocalizedString)), m_unlocalizedString(unlocalizedString) { }
Lang::operator std::string() const {
return get();
@@ -216,11 +182,7 @@ namespace hex {
const auto it = lang.find(m_entryHash);
if (it == lang.end()) {
if (auto unlocalizedIt = s_unlocalizedNames->find(m_entryHash); unlocalizedIt != s_unlocalizedNames->end()) {
return unlocalizedIt->second.c_str();
} else {
return "<unlocalized>";
}
return m_unlocalizedString.c_str();
} else {
return it->second.c_str();
}
@@ -249,4 +211,4 @@ namespace hex {
}
}
}
}

View File

@@ -85,7 +85,7 @@ namespace hex {
}
Plugin::Plugin(const std::string &name, const hex::PluginFunctions &functions) :
m_path(name), m_addedManually(true), m_functions(functions) { }
m_handle(0), m_path(name), m_addedManually(true), m_functions(functions) { }
Plugin::Plugin(Plugin &&other) noexcept {

View File

@@ -44,7 +44,7 @@ namespace hex {
}
std::fs::path ProjectFile::getPath() {
return *s_currProjectPath;
return s_currProjectPath;
}
void ProjectFile::setPath(const std::fs::path &path) {

View File

@@ -260,11 +260,8 @@ namespace hex {
case CTRLCMD.getKeyCode():
result.cmd = true;
break;
case CurrentView.getKeyCode():
case AllowWhileTyping.getKeyCode():
case ShowOnWelcomeScreen.getKeyCode():
// Ignore flags that are only used internally by the ShortcutManager
break;
case CurrentView.getKeyCode(): break;
case AllowWhileTyping.getKeyCode(): break;
default:
macosGetKey(Keys(key.getKeyCode()), &result.key);
break;
@@ -281,25 +278,25 @@ namespace hex {
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const std::function<void()> &callback, const EnabledCallback &enabledCallback) {
log::debug("Adding global shortcut {} for {}", shortcut.toString(), unlocalizedName.back().get());
auto [it, inserted] = s_globalShortcuts->insert({ shortcut, { .shortcut=shortcut, .unlocalizedName=unlocalizedName, .callback=callback, .enabledCallback=enabledCallback } });
auto [it, inserted] = s_globalShortcuts->insert({ shortcut, { shortcut, unlocalizedName, callback, enabledCallback } });
if (!inserted) log::error("Failed to add shortcut!");
}
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback, const EnabledCallback &enabledCallback) {
log::debug("Adding global shortcut {} for {}", shortcut.toString(), unlocalizedName.get());
auto [it, inserted] = s_globalShortcuts->insert({ shortcut, { .shortcut=shortcut, .unlocalizedName={ unlocalizedName }, .callback=callback, .enabledCallback=enabledCallback } });
auto [it, inserted] = s_globalShortcuts->insert({ shortcut, { shortcut, { unlocalizedName }, callback, enabledCallback } });
if (!inserted) log::error("Failed to add shortcut!");
}
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const std::vector<UnlocalizedString> &unlocalizedName, const std::function<void()> &callback, const EnabledCallback &enabledCallback) {
log::debug("Adding shortcut {} for {}", shortcut.toString(), unlocalizedName.back().get());
auto [it, inserted] = view->m_shortcuts.insert({ shortcut + CurrentView, { .shortcut=shortcut, .unlocalizedName=unlocalizedName, .callback=callback, .enabledCallback=enabledCallback } });
auto [it, inserted] = view->m_shortcuts.insert({ shortcut + CurrentView, { shortcut, unlocalizedName, callback, enabledCallback } });
if (!inserted) log::error("Failed to add shortcut!");
}
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback, const EnabledCallback &enabledCallback) {
log::debug("Adding shortcut {} for {}", shortcut.toString(), unlocalizedName.get());
auto [it, inserted] = view->m_shortcuts.insert({ shortcut + CurrentView, { .shortcut=shortcut, .unlocalizedName={ unlocalizedName }, .callback=callback, .enabledCallback=enabledCallback } });
auto [it, inserted] = view->m_shortcuts.insert({ shortcut + CurrentView, { shortcut, { unlocalizedName }, callback, enabledCallback } });
if (!inserted) log::error("Failed to add shortcut!");
}
@@ -329,13 +326,12 @@ namespace hex {
if (ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId))
return true;
auto it = shortcuts.end();
if (ImGui::GetIO().WantTextInput) {
it = shortcuts.find(shortcut + AllowWhileTyping);
} else {
it = shortcuts.find(shortcut);
const bool currentlyTyping = ImGui::GetIO().WantTextInput;
auto it = shortcuts.find(shortcut + AllowWhileTyping);
if (!currentlyTyping && it == shortcuts.end()) {
if (it == shortcuts.end())
it = shortcuts.find(shortcut + AllowWhileTyping);
it = shortcuts.find(shortcut);
}
if (it != shortcuts.end()) {
@@ -367,17 +363,7 @@ namespace hex {
if (keyCode != 0)
s_prevShortcut = Shortcut(pressedShortcut.getKeys());
std::set<const View*> processedViews;
while (true) {
if (runShortcut(pressedShortcut, currentView)) {
break;
}
processedViews.insert(currentView);
currentView = currentView->getMenuItemInheritView();
if (currentView == nullptr || processedViews.contains(currentView))
break;
}
runShortcut(pressedShortcut, currentView);
}
void ShortcutManager::processGlobals(bool ctrl, bool alt, bool shift, bool super, u32 keyCode) {
@@ -401,24 +387,6 @@ namespace hex {
s_globalShortcuts->clear();
}
Shortcut ShortcutManager::getShortcutByName(const std::vector<UnlocalizedString> &unlocalizedName, const View *view) {
if (view != nullptr) {
for (const auto &[shortcut, entry] : view->m_shortcuts) {
if (entry.unlocalizedName == unlocalizedName) {
return entry.shortcut;
}
}
} else {
for (const auto &[shortcut, entry] : *s_globalShortcuts) {
if (entry.unlocalizedName == unlocalizedName) {
return entry.shortcut;
}
}
}
return Shortcut::None;
}
void ShortcutManager::resumeShortcuts() {
s_paused = false;
}

View File

@@ -7,9 +7,6 @@
#include <ranges>
#include <jthread.hpp>
#include <hex/helpers/debugging.hpp>
#include <hex/trace/exceptions.hpp>
#include <utility>
#if defined(OS_WINDOWS)
#include <windows.h>
@@ -55,7 +52,6 @@ namespace hex {
std::list<std::function<void()>> s_deferredCalls;
std::unordered_map<SourceLocationWrapper, std::function<void()>> s_onceDeferredCalls;
std::list<std::function<void()>> s_tasksFinishedCallbacks;
std::list<std::function<void(Task&)>> s_taskCompletionCallbacks;
std::mutex s_queueMutex;
std::condition_variable s_jobCondVar;
@@ -68,7 +64,7 @@ namespace hex {
}
Task::Task(UnlocalizedString unlocalizedName, u64 maxValue, bool background, bool blocking, std::function<void(Task &)> function)
Task::Task(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, bool blocking, std::function<void(Task &)> function)
: m_unlocalizedName(std::move(unlocalizedName)),
m_maxValue(maxValue),
m_function(std::move(function)),
@@ -86,17 +82,9 @@ namespace hex {
m_maxValue = u64(other.m_maxValue);
m_currValue = u64(other.m_currValue);
if (other.m_finished.test())
m_finished.test_and_set();
if (other.m_hadException.test())
m_hadException.test_and_set();
if (other.m_interrupted.test())
m_interrupted.test_and_set();
m_finished.notify_all();
m_hadException.notify_all();
m_interrupted.notify_all();
m_finished = bool(other.m_finished);
m_hadException = bool(other.m_hadException);
m_interrupted = bool(other.m_interrupted);
m_shouldInterrupt = bool(other.m_shouldInterrupt);
}
@@ -155,11 +143,11 @@ namespace hex {
bool Task::isFinished() const {
return m_finished.test();
return m_finished;
}
bool Task::hadException() const {
return m_hadException.test();
return m_hadException;
}
bool Task::shouldInterrupt() const {
@@ -167,11 +155,11 @@ namespace hex {
}
bool Task::wasInterrupted() const {
return m_interrupted.test();
return m_interrupted;
}
void Task::clearException() {
m_hadException.clear();
m_hadException = false;
}
std::string Task::getExceptionMessage() const {
@@ -192,18 +180,12 @@ namespace hex {
return m_maxValue;
}
void Task::wait() const {
m_finished.wait(false);
}
void Task::finish() {
m_finished.test_and_set();
m_finished.notify_all();
m_finished = true;
}
void Task::interruption() {
m_interrupted.test_and_set();
m_interrupted.notify_all();
m_interrupted = true;
}
void Task::exception(const char *message) {
@@ -211,8 +193,7 @@ namespace hex {
// Store information about the caught exception
m_exceptionMessage = message;
m_hadException.test_and_set();
m_hadException.notify_all();
m_hadException = true;
// Call the interrupt callback on the current thread if one is set
if (m_interruptCallback)
@@ -260,14 +241,6 @@ namespace hex {
task->interrupt();
}
void TaskHolder::wait() const {
const auto &task = m_task.lock();
if (!task)
return;
task->wait();
}
u32 TaskHolder::getProgress() const {
const auto &task = m_task.lock();
if (!task)
@@ -314,8 +287,6 @@ namespace hex {
}
try {
trace::enableExceptionCaptureForCurrentThread();
// Set the thread name to the name of the task
TaskManager::setCurrentThreadName(Lang(task->m_unlocalizedName));
@@ -323,34 +294,21 @@ namespace hex {
task->m_function(*task);
log::debug("Task '{}' finished", task->m_unlocalizedName.get());
{
std::scoped_lock lock(s_tasksFinishedMutex);
for (const auto &callback : s_taskCompletionCallbacks)
callback(*task);
}
} catch (const Task::TaskInterruptor &) {
// Handle the task being interrupted by user request
task->interruption();
} catch (const std::exception &e) {
log::error("Exception in task '{}': {}", task->m_unlocalizedName.get(), e.what());
dbg::printStackTrace(trace::getStackTrace());
// Handle the task throwing an uncaught exception
task->exception(e.what());
} catch (...) {
log::error("Exception in task '{}'", task->m_unlocalizedName.get());
dbg::printStackTrace(trace::getStackTrace());
// Handle the task throwing an uncaught exception of unknown type
task->exception("Unknown Exception");
}
trace::disableExceptionCaptureForCurrentThread();
s_currentTask = nullptr;
task->finish();
}
@@ -369,10 +327,7 @@ namespace hex {
thread.request_stop();
// Wake up all the idle worker threads so they can exit
{
std::unique_lock lock(s_queueMutex);
s_jobCondVar.notify_all();
}
s_jobCondVar.notify_all();
// Wait for all worker threads to exit
s_workers.clear();
@@ -383,14 +338,13 @@ namespace hex {
s_deferredCalls.clear();
s_onceDeferredCalls.clear();
s_tasksFinishedCallbacks.clear();
s_taskCompletionCallbacks.clear();
}
TaskHolder TaskManager::createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, bool background, bool blocking, std::function<void(Task&)> function) {
std::scoped_lock lock(s_queueMutex);
// Construct new task
auto task = std::make_shared<Task>(unlocalizedName, maxValue, background, blocking, std::move(function));
auto task = std::make_shared<Task>(std::move(unlocalizedName), maxValue, background, blocking, std::move(function));
s_tasks.emplace_back(task);
@@ -405,12 +359,12 @@ namespace hex {
TaskHolder TaskManager::createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void(Task &)> function) {
log::debug("Creating task {}", unlocalizedName.get());
return createTask(unlocalizedName, maxValue, false, false, std::move(function));
return createTask(std::move(unlocalizedName), maxValue, false, false, std::move(function));
}
TaskHolder TaskManager::createTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void()> function) {
log::debug("Creating task {}", unlocalizedName.get());
return createTask(unlocalizedName, maxValue, false, false,
return createTask(std::move(unlocalizedName), maxValue, false, false,
[function = std::move(function)](Task&) {
function();
}
@@ -419,12 +373,12 @@ namespace hex {
TaskHolder TaskManager::createBackgroundTask(const UnlocalizedString &unlocalizedName, std::function<void(Task &)> function) {
log::debug("Creating background task {}", unlocalizedName.get());
return createTask(unlocalizedName, 0, true, false, std::move(function));
return createTask(std::move(unlocalizedName), 0, true, false, std::move(function));
}
TaskHolder TaskManager::createBackgroundTask(const UnlocalizedString &unlocalizedName, std::function<void()> function) {
log::debug("Creating background task {}", unlocalizedName.get());
return createTask(unlocalizedName, 0, true, false,
return createTask(std::move(unlocalizedName), 0, true, false,
[function = std::move(function)](Task&) {
function();
}
@@ -433,12 +387,12 @@ namespace hex {
TaskHolder TaskManager::createBlockingTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void(Task &)> function) {
log::debug("Creating blocking task {}", unlocalizedName.get());
return createTask(unlocalizedName, maxValue, true, true, std::move(function));
return createTask(std::move(unlocalizedName), maxValue, true, true, std::move(function));
}
TaskHolder TaskManager::createBlockingTask(const UnlocalizedString &unlocalizedName, u64 maxValue, std::function<void()> function) {
log::debug("Creating blocking task {}", unlocalizedName.get());
return createTask(unlocalizedName, maxValue, true, true,
return createTask(std::move(unlocalizedName), maxValue, true, true,
[function = std::move(function)](Task&) {
function();
}
@@ -592,13 +546,5 @@ namespace hex {
return s_mainThreadId == std::this_thread::get_id();
}
void TaskManager::addTaskCompletionCallback(const std::function<void(Task &)> &function) {
std::scoped_lock lock(s_tasksFinishedMutex);
for (const auto &task : s_tasks) {
task->interrupt();
}
s_taskCompletionCallbacks.push_back(function);
}
}

View File

@@ -31,7 +31,7 @@ namespace hex {
void ThemeManager::addThemeHandler(const std::string &name, const ColorMap &colorMap, const std::function<ImColor(u32)> &getFunction, const std::function<void(u32, ImColor)> &setFunction) {
std::unique_lock lock(s_themeMutex);
(*s_themeHandlers)[name] = { .colorMap=colorMap, .getFunction=getFunction, .setFunction=setFunction };
(*s_themeHandlers)[name] = { colorMap, getFunction, setFunction };
}
void ThemeManager::addStyleHandler(const std::string &name, const StyleMap &styleMap) {

View File

@@ -32,8 +32,6 @@ namespace hex {
ImGuiID s_activeHelpId;
bool s_helpHoverActive = false;
AutoReset<std::function<std::function<void()>(const std::string &)>> s_renderer;
class IDStack {
public:
@@ -57,7 +55,7 @@ namespace hex {
void add(const void *pointer) {
const ImGuiID seed = idStack.back();
const ImGuiID id = ImHashData((const void*) &pointer, sizeof(pointer), seed);
const ImGuiID id = ImHashData(&pointer, sizeof(pointer), seed);
idStack.push_back(id);
}
@@ -96,47 +94,35 @@ namespace hex {
}
void TutorialManager::init() {
if (*s_renderer == nullptr) {
*s_renderer = [](const std::string &message) {
return [message] {
ImGui::PushTextWrapPos(300_scaled);
ImGui::TextUnformatted(message.c_str());
ImGui::PopTextWrapPos();
ImGui::NewLine();
};
};
}
}
EventImGuiElementRendered::subscribe([](ImGuiID id, const std::array<float, 4> bb){
const auto boundingBox = ImRect(bb[0], bb[1], bb[2], bb[3]);
void TutorialManager::postElementRendered(ImGuiID id, const ImRect &boundingBox) {
if (!ImGui::IsRectVisible(boundingBox.Min, boundingBox.Max))
return;
{
const auto element = hex::s_highlights->find(id);
if (element != hex::s_highlights->end()) {
hex::s_highlightDisplays->emplace_back(boundingBox, element->second);
{
const auto element = hex::s_highlights->find(id);
if (element != hex::s_highlights->end()) {
hex::s_highlightDisplays->emplace_back(boundingBox, element->second);
const auto window = ImGui::GetCurrentWindow();
if (window != nullptr && window->DockNode != nullptr && window->DockNode->TabBar != nullptr)
window->DockNode->TabBar->NextSelectedTabId = window->TabId;
}
}
{
const auto element = s_interactiveHelpItems->find(id);
if (element != s_interactiveHelpItems->end()) {
(*s_interactiveHelpDisplays)[id] = boundingBox;
const auto window = ImGui::GetCurrentWindow();
if (window != nullptr && window->DockNode != nullptr && window->DockNode->TabBar != nullptr)
window->DockNode->TabBar->NextSelectedTabId = window->TabId;
}
}
}
{
const auto element = s_interactiveHelpItems->find(id);
if (element != s_interactiveHelpItems->end()) {
(*s_interactiveHelpDisplays)[id] = boundingBox;
}
if (id != 0 && boundingBox.Contains(ImGui::GetMousePos())) {
if ((s_hoveredRect.GetArea() == 0 || boundingBox.GetArea() < s_hoveredRect.GetArea()) && s_interactiveHelpItems->contains(id)) {
s_hoveredRect = boundingBox;
s_hoveredId = id;
}
}
if (id != 0 && boundingBox.Contains(ImGui::GetMousePos())) {
if ((s_hoveredRect.GetArea() == 0 || boundingBox.GetArea() < s_hoveredRect.GetArea()) && s_interactiveHelpItems->contains(id)) {
s_hoveredRect = boundingBox;
s_hoveredId = id;
}
}
});
}
const std::map<std::string, TutorialManager::Tutorial>& TutorialManager::getTutorials() {
@@ -215,13 +201,9 @@ namespace hex {
s_currentTutorial->second.start();
}
void TutorialManager::stopCurrentTutorial() {
s_currentTutorial = s_tutorials->end();
}
void TutorialManager::drawHighlights() {
if (s_helpHoverActive) {
const auto &drawList = ImGui::GetForegroundDrawList(ImGui::GetMainViewport());
const auto &drawList = ImGui::GetForegroundDrawList();
drawList->AddText(ImGui::GetMousePos() + scaled({ 10, -5, }), ImGui::GetColorU32(ImGuiCol_Text), "?");
for (const auto &[id, boundingBox] : *s_interactiveHelpDisplays) {
@@ -269,7 +251,6 @@ namespace hex {
{
auto highlightColor = ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_Highlight);
highlightColor.w *= ImSin(ImGui::GetTime() * 6.0F) / 4.0F + 0.75F;
ImHexApi::System::unlockFrameRate();
drawList->AddRect(rect.Min - ImVec2(5, 5), rect.Max + ImVec2(5, 5), ImColor(highlightColor), 5.0F, ImDrawFlags_None, 2.0F);
}
@@ -318,10 +299,10 @@ namespace hex {
if (!message.has_value()) {
message = Tutorial::Step::Message {
.position=Position::None,
.unlocalizedTitle="",
.unlocalizedMessage="",
.allowSkip=false
Position::None,
"",
"",
false
};
}
@@ -348,39 +329,34 @@ namespace hex {
ImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);
ImGui::SetNextWindowViewport(ImGui::GetMainViewport()->ID);
ImGui::SetNextWindowSize(ImVec2(300_scaled, 0));
bool open = true;
if (ImGui::Begin(message->unlocalizedTitle.empty() ? "##TutorialMessage" : Lang(message->unlocalizedTitle), &open, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoFocusOnAppearing)) {
if (ImGui::Begin("##TutorialMessage", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing)) {
ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindowRead());
auto &step = s_currentTutorial->second.m_currentStep;
if (!message->unlocalizedTitle.empty())
ImGuiExt::Header(Lang(message->unlocalizedTitle), true);
if (!message->unlocalizedMessage.empty()) {
step->m_drawFunction();
ImGui::NewLine();
ImGui::PushTextWrapPos(300_scaled);
ImGui::TextUnformatted(Lang(message->unlocalizedMessage));
ImGui::PopTextWrapPos();
ImGui::NewLine();
}
ImGui::BeginDisabled(step == s_currentTutorial->second.m_steps.begin());
if (ImGuiExt::DimmedArrowButton("Backwards", ImGuiDir_Left)) {
ImGui::BeginDisabled(s_currentTutorial->second.m_currentStep == s_currentTutorial->second.m_steps.begin());
if (ImGui::ArrowButton("Backwards", ImGuiDir_Left)) {
s_currentTutorial->second.m_currentStep->advance(-1);
}
ImGui::EndDisabled();
ImGui::SameLine();
ImGui::SetCursorPosX(ImGui::GetWindowWidth() - ImGui::GetFrameHeight() - ImGui::GetStyle().WindowPadding.x);
ImGui::BeginDisabled(!message->allowSkip && step == s_currentTutorial->second.m_latestStep);
if (ImGuiExt::DimmedArrowButton("Forwards", ImGuiDir_Right)) {
step->advance(1);
ImGui::BeginDisabled(!message->allowSkip && s_currentTutorial->second.m_currentStep == s_currentTutorial->second.m_latestStep);
if (ImGui::ArrowButton("Forwards", ImGuiDir_Right)) {
s_currentTutorial->second.m_currentStep->advance(1);
}
ImGui::EndDisabled();
}
ImGui::End();
if (!open) {
stopCurrentTutorial();
}
}
void TutorialManager::drawTutorial() {
@@ -407,10 +383,6 @@ namespace hex {
s_highlightDisplays->clear();
}
void TutorialManager::setRenderer(std::function<DrawFunction(const std::string &)> renderer) {
s_renderer = std::move(renderer);
}
TutorialManager::Tutorial::Step& TutorialManager::Tutorial::addStep() {
auto &newStep = m_steps.emplace_back(this);
m_currentStep = m_steps.end();
@@ -426,9 +398,6 @@ namespace hex {
return;
m_currentStep->addHighlights();
if (m_currentStep->m_message.has_value())
m_currentStep->m_drawFunction = (*s_renderer)(Lang(m_currentStep->m_message->unlocalizedMessage));
}
void TutorialManager::Tutorial::Step::addHighlights() const {
@@ -453,12 +422,8 @@ namespace hex {
std::advance(m_parent->m_latestStep, steps);
std::advance(m_parent->m_currentStep, steps);
if (m_parent->m_currentStep != m_parent->m_steps.end()) {
if (m_parent->m_currentStep != m_parent->m_steps.end())
m_parent->m_currentStep->addHighlights();
if (m_message.has_value())
m_parent->m_currentStep->m_drawFunction = (*s_renderer)(Lang(m_parent->m_currentStep->m_message->unlocalizedMessage));
}
else
s_currentTutorial = s_tutorials->end();
}
@@ -481,10 +446,10 @@ namespace hex {
TutorialManager::Tutorial::Step& TutorialManager::Tutorial::Step::setMessage(const UnlocalizedString &unlocalizedTitle, const UnlocalizedString &unlocalizedMessage, Position position) {
m_message = Message {
.position=position,
.unlocalizedTitle=unlocalizedTitle,
.unlocalizedMessage=unlocalizedMessage,
.allowSkip=false
position,
unlocalizedTitle,
unlocalizedMessage,
false
};
return *this;
@@ -495,10 +460,10 @@ namespace hex {
m_message->allowSkip = true;
} else {
m_message = Message {
.position=Position::Bottom | Position::Right,
.unlocalizedTitle="",
.unlocalizedMessage="",
.allowSkip=true
Position::Bottom | Position::Right,
"",
"",
true
};
}

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