Compare commits

...

76 Commits

Author SHA1 Message Date
WerWolv 5500faa57e fix: Inverted logic when opening files from the command line 2025-12-17 13:50:57 +01:00
WerWolv 89004574d3 impr: Handle provider opening more centrally, switch to existing provider if same file is being opened again 2025-12-17 12:55:34 +01:00
iTrooz c11c05a399
build: do not bundle SDK in snap and flatpak packages (#2567) 2025-12-17 11:31:35 +01:00
WerWolv baa3329e7f fix: Make sure providers returned by createProvider don't get deleted unexpectedly 2025-12-16 23:36:05 +01:00
WerWolv e696d384c2 feat: Add initial MCP Server support 2025-12-16 20:25:46 +01:00
WerWolv 932c281223 fix: Pattern files not getting truncated correctly when saving
Fixes #2566
2025-12-16 10:02:10 +01:00
WerWolv 858fe0384e impr: Make most windows non-scrolling by default 2025-12-15 21:06:44 +01:00
WerWolv e904cd749f fix: Inverted sorting of find view table
Fixes #2564
2025-12-15 20:13:19 +01:00
WerWolv 6b16f39be4 impr: Allow tutorials to use markdown formatted text 2025-12-15 20:07:43 +01:00
WerWolv 021c7e5fdb impr: Add localization option to store long, formatted texts in external files 2025-12-15 20:07:18 +01:00
WerWolv c161a5c71b fix: Typo in crash popup 2025-12-15 11:31:41 +01:00
WerWolv 76ccdbccea patterns: Update pattern language 2025-12-15 10:10:15 +01:00
WerWolv 553ee89787 fix: Only enable widgets in pattern data view when there's actually any patterns available 2025-12-15 10:00:29 +01:00
WerWolv cb6247b16e fix: Crash when using @ command palette command
Fixes #2563
2025-12-15 09:52:44 +01:00
WerWolv cfac7ff0ba impr: Unionize exception and assertion handling 2025-12-15 09:52:13 +01:00
iTrooz 49bbe7dc77
build: remove IMHEX_PLUGINS_IN_SHARE option + only allow AppImage to load plugins from inside itself
Rationale: The `IMHEX_PLUGINS_IN_SHARE` is a hack to prevent the appimage from loading plugin from system imhex installation, like /usr/lib/imhex/

In reality, I do not think people compile plugins specifically for the AppImage (plugins must be compiled for the specific imhex & compiler version the imhex binary is used), and this lets us remove the hack
2025-12-14 18:29:00 +01:00
iTrooz 07b6fa0e2e
build(web): add `BUILD_TYPE` arg to Dockerfile 2025-12-14 15:02:46 +01:00
iTrooz 67396f2009
chore: fix web Dockerfile ARG syntax 2025-12-14 15:02:46 +01:00
iTrooz a20ff87cc9
chore: update comment 2025-12-14 15:02:46 +01:00
iTrooz e02e57a729
chore: remove `version` attribute from web compose.yaml 2025-12-14 14:19:15 +01:00
iTrooz 225dc53795
build(appimage): use https when querying repos 2025-12-14 02:02:40 +01:00
iTrooz e7404376db
build: do not bundle plugin SDK in AppImage 2025-12-14 01:55:57 +01:00
iTrooz d6aec341fe
build(web): make a shallow clone of vcpkg 2025-12-14 01:43:40 +01:00
iTrooz 3a3c2fb204
build: add defaults to AppImage build for x86 2025-12-14 00:45:56 +01:00
iTrooz e9b5cdbccf
build: fix IMHEX_INCLUDE_PLUGINS defined check 2025-12-14 00:15:08 +01:00
iTrooz 3f30e63d95
chore(web): allow nginx to access files in development docker image 2025-12-14 00:08:11 +01:00
iTrooz f9c6866c7b
build: require all plugins that builtint depends on to be present 2025-12-13 23:54:58 +01:00
iTrooz 388dccfd9f
chore: organise cmake build flags 2025-12-13 23:46:13 +01:00
paxcut 1676342e28
Various fixes for pattern editor (#2561)
- Fix for vertical scroll bar being too far to the left.
- Fix constructor not initializing from const char pointer properly
- maxcolumn not being set for console text lines causing crashes on
empty pattern evaluation
- A replacement using replace all is now undone in one step.
- Find/replace no longer need to have enter or return key to accept
text. You can use arrows or shortcuts.
- More efficient search replace implementation with plans to add even
faster.
- Tooltips added to find/replace window
- Providers now save both horizontal and vertical scroll positions when
switching to another one and restore them when switching back. This is
independent to the cursor position which is also saved.
- Pattern editor no longer takes focus when changing providers via a tab
click. This has the effect that menus won't change by just clicking on a
tab.
- Small fixes and code refactoring.
2025-12-13 05:23:16 -07:00
WerWolv 62732de227 fix: Gaps in-between hex editor highlighting on specific scalings 2025-12-12 22:04:15 +01:00
WerWolv 63e777c84c impr: Intercept glibc++ assertion handler 2025-12-12 22:02:56 +01:00
WerWolv ab95cdf3e5 fix: Minimap not allowing scrolling as far as the scroll bar 2025-12-12 17:19:57 +01:00
WerWolv 827b5b01dd patterns: Update pattern language 2025-12-12 16:57:20 +01:00
paxcut bfa9788099
impr: Various fixes and improvements to the pattern editor (#2559)
- fixed crash when utf8 chars were present in text editor
- fixed unable to scroll when cursor at line 1
- removed dependencies on thext editor that were not being used.

I had to go back to the old code (old for me) and fit in the changes
that were applied to the new code.That was only possible by
incorporating some of the new structural differences to the text editor.
This created new bugs and crashes that I ve have fixed but there may be
ones that I couldn't find in the very small amount of time I could spend
testing so that this commit wouldn't be delayed. If more crashes are
found due to the mixing of old and new code they should be resolved when
the new code is brought in.
2025-12-12 16:27:26 +01:00
WerWolv de25ce7fbb feat: Add support for custom inspector edit widgets 2025-12-12 13:15:16 +01:00
WerWolv 21e61bfce6 fix: Extended ASCII display being enabled by default 2025-12-12 13:14:49 +01:00
WerWolv 82e168c438 build: Update libwolv 2025-12-12 13:14:27 +01:00
WerWolv 48583a2b6e build: Go back to WiX 4 again for ARM64 support 2025-12-11 23:41:37 +01:00
WerWolv 0db0982fa7 build: Update dependencies 2025-12-11 23:15:13 +01:00
WerWolv 6a28ce9e4b fix: Wrong variable access 2025-12-11 21:32:18 +01:00
WerWolv 1db79f6117 feat: Add command line arguments to process tooltips, exclude kthreads on Linux
Fixes #2558
2025-12-11 17:09:26 +01:00
WerWolv f234103320 fix: Off-by-one of starts of process memory regions 2025-12-11 16:27:36 +01:00
WerWolv 45c382a19a fix: Auto backup localization key names 2025-12-11 16:27:13 +01:00
WerWolv fb7ef61d06 fix: Crash when canceling creation of SSH provider
Fixes #2557
2025-12-11 16:24:43 +01:00
WerWolv 2586645d02 build: Force-set REINSTALLMODE=amus for WiX installer 2025-12-11 12:34:29 +01:00
WerWolv e23cb5509d build: Use WiX 3 for packaging 2025-12-11 11:13:26 +01:00
WerWolv 5cbd53ae7a build: Fix version stripping issues 2025-12-09 21:58:29 +01:00
WerWolv a4ee590875 build: Only build the version stripper on mingw 2025-12-09 21:31:50 +01:00
WerWolv 495608ed7c build: Force-remove all version information from libwinpthread 2025-12-09 21:25:35 +01:00
WerWolv 4d10d9a195 build: Manually set FILEVERSION of libwinpthread to 0.0.0.0
#2550
2025-12-08 23:54:33 +01:00
WerWolv 4914a34dd9 build: Fix WiX patch 2025-12-08 21:26:18 +01:00
WerWolv ab0fb3131d fix: Reset selected row after checking it 2025-12-08 21:10:49 +01:00
WerWolv 7922d3b3cb build: Try to force-overwrite libwinpthread 2025-12-08 18:17:33 +01:00
WerWolv 6427f53b5a feat: Add endian option to Sum hash 2025-12-07 22:18:34 +01:00
WerWolv 994df0a3a4 feat: Add shortcut to directly search for the selected bytes 2025-12-07 22:17:57 +01:00
WerWolv e6eee55810 fix: Editing of WString, String16, String32 in data inspector 2025-12-07 21:44:33 +01:00
WerWolv 855e4c4913 feat: Add option to create auto backups of files before they're modified 2025-12-07 21:37:14 +01:00
WerWolv c2e07bf7b2 feat: Added data inspector shortcut to toggle endianness 2025-12-07 20:58:30 +01:00
WerWolv 77b9e3eac8 impr: Allow Esc to clear editing and selected state in data inspector 2025-12-07 20:58:17 +01:00
WerWolv 790487eea6 impr: If there's multiple foreground highlighting providers, only evaluate until a color is found 2025-12-07 20:48:16 +01:00
WerWolv eb83354179 feat: Add option to automatically apply found pattern when a provider is opened 2025-12-07 20:47:33 +01:00
WerWolv 9ba8754f97 build: Remove file version from main executable to make msi installer not skip it 2025-12-07 17:57:21 +01:00
WerWolv 84346119b3 fix: Missing includes 2025-12-07 17:22:26 +01:00
WerWolv 2b3abd06db build: Fix deb package referring to incorrect md4c library package
Fixes #2548
2025-12-07 16:25:15 +01:00
WerWolv 8267aad79e feat: Add new Command Line data source 2025-12-07 16:24:36 +01:00
WerWolv 3f9ce561b9 fix: Post-pone file opening till everything has been initialized 2025-12-07 14:00:10 +01:00
WerWolv 347fc3ed9f impr: Show proper error message if nethost header can't be found 2025-12-07 13:35:08 +01:00
WerWolv 0488c996e9 impr: Make icons look slightly nicer at low resolutions 2025-12-07 11:48:14 +01:00
WerWolv 37bfd97d93 git: Make release CI more reliable 2025-12-07 10:36:03 +01:00
WerWolv c8652b0576 Merge branch 'feature/code-signing' 2025-12-07 00:01:54 +01:00
WerWolv 1208d2eb5e git: Fix issues with the release CI 2025-12-07 00:01:40 +01:00
WerWolv ab34fed0c5 build: Bump version to 1.39.0.WIP 2025-12-07 00:01:22 +01:00
WerWolv 0906e5f9cf git: Remove test signing, get release signing ready 2025-12-06 23:59:56 +01:00
WerWolv 47b1c603b3 git: Remove signpath parameters 2025-12-06 23:59:56 +01:00
WerWolv 4bda321e7a git: Fix version string 2025-12-06 23:59:56 +01:00
WerWolv 691ff11fbc git: Added Windows code signing 2025-12-06 23:59:56 +01:00
155 changed files with 3222 additions and 1331 deletions

View File

@ -95,7 +95,6 @@ jobs:
-DIMHEX_GENERATE_PDBS=ON \ -DIMHEX_GENERATE_PDBS=ON \
-DIMHEX_REPLACE_DWARF_WITH_PDB=ON \ -DIMHEX_REPLACE_DWARF_WITH_PDB=ON \
-DDOTNET_EXECUTABLE="C:/Program Files/dotnet/dotnet.exe" \ -DDOTNET_EXECUTABLE="C:/Program Files/dotnet/dotnet.exe" \
-DCPACK_WIX_VERSION="4" \
-DCPACK_WIX_ROOT="$(echo "$USERPROFILE" | tr '\\' '/')/.dotnet/tools" \ -DCPACK_WIX_ROOT="$(echo "$USERPROFILE" | tr '\\' '/')/.dotnet/tools" \
.. ..
@ -166,6 +165,7 @@ jobs:
- name: ⬆️ Upload Windows Installer - name: ⬆️ Upload Windows Installer
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
id: upload-installer
with: with:
if-no-files-found: error if-no-files-found: error
name: Windows Installer ${{ matrix.architecture_name }} name: Windows Installer ${{ matrix.architecture_name }}
@ -279,7 +279,6 @@ jobs:
-DIMHEX_COMMIT_HASH_LONG="$env:GITHUB_SHA" ` -DIMHEX_COMMIT_HASH_LONG="$env:GITHUB_SHA" `
-DIMHEX_COMMIT_BRANCH="$($env:GITHUB_REF -replace '.*/', '')" ` -DIMHEX_COMMIT_BRANCH="$($env:GITHUB_REF -replace '.*/', '')" `
-DDOTNET_EXECUTABLE="C:/Program Files/dotnet/dotnet.exe" ` -DDOTNET_EXECUTABLE="C:/Program Files/dotnet/dotnet.exe" `
-DCPACK_WIX_VERSION="4" `
-DCPACK_WIX_ROOT="$($env:USERPROFILE -replace '\\','/')/.dotnet/tools" ` -DCPACK_WIX_ROOT="$($env:USERPROFILE -replace '\\','/')/.dotnet/tools" `
. .

View File

@ -82,6 +82,43 @@ jobs:
git fetch --tags --recurse-submodules=no git fetch --tags --recurse-submodules=no
git log nightly..origin/master --oneline --no-merges --pretty=format:'* %s' >> changelog.md git log nightly..origin/master --oneline --no-merges --pretty=format:'* %s' >> changelog.md
- name: ⬆️ Upload Unsigned x86_64 Windows Installer
if: false
uses: actions/upload-artifact@v4
id: upload-installer-x86_64
with:
if-no-files-found: error
name: Windows Installer ${{ matrix.architecture_name }}
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 ${{ matrix.architecture_name }}
path: |
imhex-*-arm64.msi
- name: 🗑️ Delete unsigned installers
if: false
run: |
rm imhex-*.msi
- name: 🗝️ Sign 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.outputs.artifact-id }}'
wait-for-completion: true
output-artifact-directory: '.'
- name: 📦 Update Pre-Release - name: 📦 Update Pre-Release
if: ${{ steps.check_commits.outputs.should_run == 'true' }} if: ${{ steps.check_commits.outputs.should_run == 'true' }}
run: | run: |

View File

@ -7,6 +7,12 @@ on:
release: release:
types: [published] types: [published]
workflow_dispatch: 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: jobs:
release-update-repos: release-update-repos:
@ -41,6 +47,7 @@ jobs:
tag: ImHex-v${{ env.IMHEX_VERSION }} tag: ImHex-v${{ env.IMHEX_VERSION }}
repo: PatternLanguage repo: PatternLanguage
token: ${{ secrets.RELEASE_TOKEN }} token: ${{ secrets.RELEASE_TOKEN }}
skipIfReleaseExists: true
- name: 🎫 Create ImHex-Patterns release - name: 🎫 Create ImHex-Patterns release
uses: ncipollo/release-action@v1 uses: ncipollo/release-action@v1
@ -51,6 +58,7 @@ jobs:
tag: ImHex-v${{ env.IMHEX_VERSION }} tag: ImHex-v${{ env.IMHEX_VERSION }}
repo: ImHex-Patterns repo: ImHex-Patterns
token: ${{ secrets.RELEASE_TOKEN }} token: ${{ secrets.RELEASE_TOKEN }}
skipIfReleaseExists: true
- name: 🎫 Create imhex-download-sdk release - name: 🎫 Create imhex-download-sdk release
uses: ncipollo/release-action@v1 uses: ncipollo/release-action@v1
@ -61,11 +69,13 @@ jobs:
tag: v${{ env.IMHEX_VERSION }} tag: v${{ env.IMHEX_VERSION }}
repo: imhex-download-sdk repo: imhex-download-sdk
token: ${{ secrets.RELEASE_TOKEN }} token: ${{ secrets.RELEASE_TOKEN }}
skipIfReleaseExists: true
release-upload-artifacts: release-upload-artifacts:
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
name: Release Upload Artifacts name: Release Upload Artifacts
outputs:
IMHEX_VERSION: ${{ steps.verify_version.outputs.IMHEX_VERSION }}
steps: steps:
- name: 🧰 Checkout - name: 🧰 Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -74,6 +84,7 @@ jobs:
submodules: recursive submodules: recursive
- name: 📜 Verify version and set version variable - name: 📜 Verify version and set version variable
id: verify_version
run: | run: |
set -x set -x
project_version=`cat ImHex/VERSION` project_version=`cat ImHex/VERSION`
@ -85,6 +96,7 @@ jobs:
fi fi
echo "IMHEX_VERSION=$project_version" >> $GITHUB_ENV echo "IMHEX_VERSION=$project_version" >> $GITHUB_ENV
echo "IMHEX_VERSION=$project_version" >> $GITHUB_OUTPUT
- name: 🗜️ Create tarball from sources with dependencies - name: 🗜️ Create tarball from sources with dependencies
run: tar --exclude-vcs -czvf Full.Sources.tar.gz ImHex run: tar --exclude-vcs -czvf Full.Sources.tar.gz ImHex
@ -97,6 +109,7 @@ jobs:
branch: ${{ github.event.release.target_commitish }} branch: ${{ github.event.release.target_commitish }}
workflow_conclusion: success workflow_conclusion: success
skip_unpack: true skip_unpack: true
commit: ${{ github.event.inputs.commit_hash }}
- name: 🗜️ Unzip files when needed - name: 🗜️ Unzip files when needed
run: | run: |
@ -115,25 +128,80 @@ jobs:
- name: 🟩 Rename artifacts when needed - name: 🟩 Rename artifacts when needed
run: | run: |
mv "Windows Portable x86_64.zip" imhex-${{ env.IMHEX_VERSION }}-Windows-Portable-x86_64.zip 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 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 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 mv "ImHex Web.zip" imhex-${{ env.IMHEX_VERSION }}-Web.zip || true
rm artifact.tar || true 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 ${{ matrix.architecture_name }}
path: |
imhex-*-x86_64.msi
- name: ⬆️ Upload Unsigned ARM64 Windows Installer
uses: actions/upload-artifact@v4
id: upload-installer-arm64
with:
if-no-files-found: error
name: Windows Installer ${{ matrix.architecture_name }}
path: |
imhex-*-arm64.msi
- name: 🗑️ Delete unsigned installers
run: |
rm imhex-*.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
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 - name: ⬆️ Upload everything to release
uses: softprops/action-gh-release@4634c16e79c963813287e889244c50009e7f0981 uses: softprops/action-gh-release@4634c16e79c963813287e889244c50009e7f0981
with: with:
files: '*' files: '*'
release-update-aur:
name: Release update AUR package
needs: release-upload-artifacts
runs-on: ubuntu-24.04
steps:
- 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 - name: ✒️ Prepare PKGBUILD
run: | run: |
set -x set -x
cp ImHex/dist/Arch/PKGBUILD . cp ImHex/dist/Arch/PKGBUILD .
hash=`md5sum imhex-${{ env.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst | cut -d ' ' -f 1` hash=`md5sum imhex-${{ needs.release-upload-artifacts.outputs.IMHEX_VERSION }}-ArchLinux-x86_64.pkg.tar.zst | cut -d ' ' -f 1`
sed -i 's/%version%/${{ env.IMHEX_VERSION }}/g' PKGBUILD sed -i 's/%version%/${{ needs.release-upload-artifacts.outputs.IMHEX_VERSION }}/g' PKGBUILD
sed -i "s/(SKIP)/($hash)/g" PKGBUILD sed -i "s/(SKIP)/($hash)/g" PKGBUILD
- name: ⬆️ Publish AUR package - name: ⬆️ Publish AUR package
@ -149,7 +217,7 @@ jobs:
commit_username: iTrooz commit_username: iTrooz
commit_email: itrooz@protonmail.com commit_email: itrooz@protonmail.com
ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }} ssh_private_key: ${{ secrets.AUR_SSH_PRIVATE_KEY }}
commit_message: Bump to version ${{ env.IMHEX_VERSION }} commit_message: Bump to version ${{ needs.release-upload-artifacts.outputs.IMHEX_VERSION }}
ssh_keyscan_types: rsa,ecdsa,ed25519 ssh_keyscan_types: rsa,ecdsa,ed25519
release-update-winget: release-update-winget:
@ -161,6 +229,7 @@ jobs:
shell: pwsh shell: pwsh
run: | run: |
iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe iwr https://aka.ms/wingetcreate/latest -OutFile wingetcreate.exe
- name: ⬆️ Update winget manifest - name: ⬆️ Update winget manifest
shell: pwsh shell: pwsh
env: env:
@ -193,7 +262,7 @@ jobs:
env: env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_STORE_LOGIN }} SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_STORE_LOGIN }}
with: with:
snap: imhex-${{ env.IMHEX_VERSION }}-x86_64.snap snap: imhex-${{ needs.release-upload-artifacts.outputs.IMHEX_VERSION }}-x86_64.snap
release: stable release: stable
- name: ⬆️ Publish arm64 Snap package - name: ⬆️ Publish arm64 Snap package
@ -202,5 +271,5 @@ jobs:
env: env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_STORE_LOGIN }} SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_STORE_LOGIN }}
with: with:
snap: imhex-${{ env.IMHEX_VERSION }}-arm64.snap snap: imhex-${{ needs.release-upload-artifacts.outputs.IMHEX_VERSION }}-arm64.snap
release: stable release: stable

View File

@ -1,33 +1,38 @@
cmake_minimum_required(VERSION 3.25) cmake_minimum_required(VERSION 3.25)
# Options # Options
option(IMHEX_PLUGINS_IN_SHARE "Put the plugins in share/imhex/plugins instead of lib[..]/imhex/plugins (Linux only)" OFF) ## General
option(IMHEX_STRIP_RELEASE "Strip the release builds" ON ) option(IMHEX_STRIP_RELEASE "Strip the release builds" ON )
option(IMHEX_OFFLINE_BUILD "Enable offline build" OFF) option(IMHEX_OFFLINE_BUILD "Enable offline build" OFF)
option(IMHEX_IGNORE_BAD_CLONE "Disable the bad clone prevention checks" OFF) option(IMHEX_IGNORE_BAD_CLONE "Disable the bad clone prevention checks" OFF)
option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of the ImHex-Patterns repo" OFF) option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of the ImHex-Patterns repo" OFF)
option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler" OFF) option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler" OFF)
option(IMHEX_USE_GTK_FILE_PICKER "Use GTK file picker instead of xdg-desktop-portals (Linux only)" OFF) option(IMHEX_USE_GTK_FILE_PICKER "Use GTK file picker instead of xdg-desktop-portals (Linux only)" OFF)
option(IMHEX_DISABLE_STACKTRACE "Disables support for printing stack traces" OFF)
option(IMHEX_BUNDLE_DOTNET "Bundle .NET runtime" ON ) option(IMHEX_BUNDLE_DOTNET "Bundle .NET runtime" ON )
option(IMHEX_ENABLE_LTO "Enables Link Time Optimizations if possible" OFF) option(IMHEX_ENABLE_LTO "Enables Link Time Optimizations if possible" OFF)
option(IMHEX_USE_DEFAULT_BUILD_SETTINGS "Use default build settings" OFF) option(IMHEX_USE_DEFAULT_BUILD_SETTINGS "Use default build settings" OFF)
option(IMHEX_STRICT_WARNINGS "Enable most available warnings and treat them as errors" ON )
option(IMHEX_BUILD_HARDENING "Enable hardening flags for build" ON ) option(IMHEX_BUILD_HARDENING "Enable hardening flags for build" 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_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_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_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_CXX_MODULES "Enable C++20 Module compilation. Testing only!" OFF)
option(IMHEX_ENABLE_CPPCHECK "Enable cppcheck static analysis" OFF) option(IMHEX_ENABLE_CPPCHECK "Enable cppcheck static analysis" OFF)
option(IMHEX_BUNDLE_PLUGIN_SDK "Enable bundling of Plugin SDK into install package" ON ) 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(IMHEX_BASE_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}")
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules") set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")

View File

@ -1 +1 @@
1.38.0 1.39.0.WIP

View File

@ -175,15 +175,11 @@ macro(detectOS)
endif() endif()
include(GNUInstallDirs) include(GNUInstallDirs)
if(IMHEX_PLUGINS_IN_SHARE)
set(PLUGINS_INSTALL_LOCATION "share/imhex/plugins")
else()
set(PLUGINS_INSTALL_LOCATION "${CMAKE_INSTALL_LIBDIR}/imhex/plugins") set(PLUGINS_INSTALL_LOCATION "${CMAKE_INSTALL_LIBDIR}/imhex/plugins")
# Add System plugin location for plugins to be loaded from # 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 # 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_compile_definitions(SYSTEM_PLUGINS_LOCATION="${CMAKE_INSTALL_FULL_LIBDIR}/imhex")
endif()
else () else ()
message(FATAL_ERROR "Unknown / unsupported system!") message(FATAL_ERROR "Unknown / unsupported system!")
@ -205,11 +201,14 @@ macro(configurePackingResources)
set(CPACK_GENERATOR "WIX") set(CPACK_GENERATOR "WIX")
set(CPACK_PACKAGE_NAME "ImHex") set(CPACK_PACKAGE_NAME "ImHex")
set(CPACK_PACKAGE_VENDOR "WerWolv") set(CPACK_PACKAGE_VENDOR "WerWolv")
set(CPACK_WIX_VERSION 4)
set(CPACK_WIX_UPGRADE_GUID "05000E99-9659-42FD-A1CF-05C554B39285") 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_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_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_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_CULTURES "en-US;de-DE;ja-JP;it-IT;pt-BR;zh-CN;zh-TW;ru-RU")
set(CPACK_WIX_PATCH_FILE "${PROJECT_SOURCE_DIR}/resources/dist/windows/wix_patch.xml")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "ImHex") set(CPACK_PACKAGE_INSTALL_DIRECTORY "ImHex")
set_property(INSTALL "$<TARGET_FILE_NAME:main>" set_property(INSTALL "$<TARGET_FILE_NAME:main>"
PROPERTY CPACK_START_MENU_SHORTCUTS "ImHex" PROPERTY CPACK_START_MENU_SHORTCUTS "ImHex"
@ -312,7 +311,7 @@ macro(createPackage)
POST_EXCLUDE_REGEXES ".*system32/.*\\.dll" POST_EXCLUDE_REGEXES ".*system32/.*\\.dll"
) )
if(_c_deps_FILENAMES AND NOT _c_deps STREQUAL "") if(_c_deps_FILENAMES AND _c_deps AND NOT (_c_deps STREQUAL ""))
message(WARNING "Conflicting dependencies for library: \"${_c_deps}\"!") message(WARNING "Conflicting dependencies for library: \"${_c_deps}\"!")
endif() endif()
@ -587,7 +586,9 @@ endfunction()
macro(detectBundledPlugins) macro(detectBundledPlugins)
file(GLOB PLUGINS_DIRS "plugins/*") file(GLOB PLUGINS_DIRS "plugins/*")
if (NOT DEFINED IMHEX_INCLUDE_PLUGINS) if (IMHEX_INCLUDE_PLUGINS)
set(PLUGINS ${IMHEX_INCLUDE_PLUGINS})
else()
foreach(PLUGIN_DIR ${PLUGINS_DIRS}) foreach(PLUGIN_DIR ${PLUGINS_DIRS})
if (EXISTS "${PLUGIN_DIR}/CMakeLists.txt") if (EXISTS "${PLUGIN_DIR}/CMakeLists.txt")
get_filename_component(PLUGIN_NAME ${PLUGIN_DIR} NAME) get_filename_component(PLUGIN_NAME ${PLUGIN_DIR} NAME)
@ -596,8 +597,6 @@ macro(detectBundledPlugins)
endif () endif ()
endif() endif()
endforeach() endforeach()
else()
set(PLUGINS ${IMHEX_INCLUDE_PLUGINS})
endif() endif()
foreach(PLUGIN_NAME ${PLUGINS}) foreach(PLUGIN_NAME ${PLUGINS})
@ -608,9 +607,13 @@ macro(detectBundledPlugins)
message(FATAL_ERROR "No bundled plugins enabled") message(FATAL_ERROR "No bundled plugins enabled")
endif() endif()
if (NOT ("builtin" IN_LIST PLUGINS)) set(REQUIRED_PLUGINS builtin fonts ui)
message(FATAL_ERROR "The 'builtin' plugin is required for ImHex to work!") foreach(PLUGIN ${REQUIRED_PLUGINS})
endif () list(FIND PLUGINS ${PLUGIN} PLUGIN_INDEX)
if (PLUGIN_INDEX EQUAL -1)
message(FATAL_ERROR "Required plugin '${PLUGIN}' is not enabled!")
endif()
endforeach()
endmacro() endmacro()
macro(setVariableInParent variable value) macro(setVariableInParent variable value)

View File

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

View File

@ -30,9 +30,9 @@ ARG LTO=ON
ARG BUILD_TYPE=RelWithDebInfo ARG BUILD_TYPE=RelWithDebInfo
ARG GIT_COMMIT_HASH ARG GIT_COMMIT_HASH
ARG GIT_BRANCH ARG GIT_BRANCH
ARG ARCHITECTURE_PACKAGE ARG ARCHITECTURE_PACKAGE=x86_64
ARG ARCHITECTURE_FILE_NAME ARG ARCHITECTURE_FILE_NAME=amd64
ARG ARCHITECTURE_APPIMAGE_BUILDER ARG ARCHITECTURE_APPIMAGE_BUILDER=x86_64
WORKDIR /build WORKDIR /build
# Ubuntu sh doesnt support string substitution # Ubuntu sh doesnt support string substitution
@ -51,7 +51,9 @@ CC=gcc-14 CXX=g++-14 cmake -G "Ninja" \
-DIMHEX_COMMIT_HASH_LONG="${GIT_COMMIT_HASH}" \ -DIMHEX_COMMIT_HASH_LONG="${GIT_COMMIT_HASH}" \
-DIMHEX_COMMIT_BRANCH="${GIT_BRANCH}" \ -DIMHEX_COMMIT_BRANCH="${GIT_BRANCH}" \
-DIMHEX_ENABLE_LTO=${LTO} \ -DIMHEX_ENABLE_LTO=${LTO} \
-DIMHEX_PLUGINS_IN_SHARE=ON \ -DIMHEX_BUNDLE_PLUGIN_SDK=OFF \
`# To prevent using a libdir with an architecture-specific name` \
-DCMAKE_INSTALL_LIBDIR="lib" \
/imhex /imhex
EOF EOF

View File

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

2
dist/ImHex.run.xml vendored
View File

@ -1,5 +1,5 @@
<component name="ProjectRunConfigurationManager"> <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"> <configuration default="false" name="ImHex" type="CMakeRunConfiguration" factoryName="Application" PROGRAM_PARAMS=".ninja_log" 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> <envs>
<env name="NO_DEBUG_BANNER" value="1" /> <env name="NO_DEBUG_BANNER" value="1" />
</envs> </envs>

View File

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

View File

@ -41,6 +41,7 @@ parts:
- -DCMAKE_C_COMPILER_LAUNCHER=${CCACHE} - -DCMAKE_C_COMPILER_LAUNCHER=${CCACHE}
- -DCMAKE_CXX_COMPILER_LAUNCHER=${CCACHE} - -DCMAKE_CXX_COMPILER_LAUNCHER=${CCACHE}
- -DIMHEX_PATTERNS_PULL_MASTER=ON - -DIMHEX_PATTERNS_PULL_MASTER=ON
- -DIMHEX_BUNDLE_PLUGIN_SDK=OFF
cmake-generator: Ninja cmake-generator: Ninja
build-packages: build-packages:
- cmake - cmake

12
dist/web/Dockerfile vendored
View File

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

View File

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

@ -1 +1 @@
Subproject commit 5be84628dc4d7da6281c943888497f8b886b7f5a Subproject commit b0c9416568475a784838e3af8b0021a542e47cd7

@ -1 +1 @@
Subproject commit 33057885fdb8802245260e8b8de4eecf1819dc60 Subproject commit a06da46a3cf1694ccc785d21a37a2dca08deb56a

View File

@ -57,6 +57,9 @@ set(LIBIMHEX_SOURCES
source/ui/toast.cpp source/ui/toast.cpp
source/ui/banner.cpp source/ui/banner.cpp
source/mcp/client.cpp
source/mcp/server.cpp
source/subcommands/subcommands.cpp source/subcommands/subcommands.cpp
) )

View File

@ -7,6 +7,8 @@
#include <map> #include <map>
#include <string> #include <string>
#include <hex/mcp/server.hpp>
EXPORT_MODULE namespace hex { EXPORT_MODULE namespace hex {
/* Network Communication Interface Registry. Allows adding new communication interface endpoints */ /* Network Communication Interface Registry. Allows adding new communication interface endpoints */
@ -22,4 +24,19 @@ EXPORT_MODULE namespace hex {
} }
namespace ContentRegistry::MCP {
namespace impl {
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

@ -8,6 +8,7 @@
#include <optional> #include <optional>
#include <string> #include <string>
#include <vector> #include <vector>
#include <bit>
EXPORT_MODULE namespace hex { EXPORT_MODULE namespace hex {
@ -22,8 +23,10 @@ EXPORT_MODULE namespace hex {
namespace impl { namespace impl {
struct DoNotUseThisByItselfTag {};
using DisplayFunction = std::function<std::string()>; using DisplayFunction = std::function<std::string()>;
using EditingFunction = std::function<std::vector<u8>(std::string, std::endian)>; using EditingFunction = std::function<std::optional<std::vector<u8>>(std::string&, std::endian, DoNotUseThisByItselfTag)>;
using GeneratorFunction = std::function<DisplayFunction(const std::vector<u8> &, std::endian, NumberDisplayStyle)>; using GeneratorFunction = std::function<DisplayFunction(const std::vector<u8> &, std::endian, NumberDisplayStyle)>;
struct Entry { struct Entry {
@ -38,6 +41,35 @@ 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 * @brief Adds a new entry to the data inspector
* @param unlocalizedName The unlocalized name of the entry * @param unlocalizedName The unlocalized name of the entry

View File

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

View File

@ -239,6 +239,14 @@ EXPORT_MODULE namespace hex {
nlohmann::json store() override { return {}; } 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 { namespace impl {

View File

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

View File

@ -8,7 +8,12 @@ namespace hex {
/** /**
* @brief Creates a provider from its unlocalized name, and add it to the provider list * @brief Creates a provider from its unlocalized name, and add it to the provider list
*/ */
EVENT_DEF(RequestCreateProvider, std::string, bool, bool, hex::prv::Provider **); 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>);
/** /**
* @brief Move the data from all PerProvider instances from one provider to another * @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 skipLoadInterface Whether to skip the provider's loading interface (see property documentation)
* @param select Whether to select the provider after adding it * @param select Whether to select the provider after adding it
*/ */
void add(std::unique_ptr<prv::Provider> &&provider, bool skipLoadInterface = false, bool select = true); void add(std::shared_ptr<prv::Provider> &&provider, bool skipLoadInterface = false, bool select = true);
/** /**
* @brief Creates a new provider and adds it to the list of providers * @brief Creates a new provider and adds it to the list of providers
@ -111,12 +111,18 @@ EXPORT_MODULE namespace hex {
* @param skipLoadInterface Whether to skip the provider's loading interface (see property documentation) * @param skipLoadInterface Whether to skip the provider's loading interface (see property documentation)
* @param select Whether to select the provider after adding it * @param select Whether to select the provider after adding it
*/ */
prv::Provider* createProvider( std::shared_ptr<prv::Provider> createProvider(
const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedName,
bool skipLoadInterface = false, bool skipLoadInterface = false,
bool select = true 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

@ -10,6 +10,7 @@
#include <condition_variable> #include <condition_variable>
#include <source_location> #include <source_location>
#include <thread> #include <thread>
#include <hex/trace/exceptions.hpp>
EXPORT_MODULE namespace hex { EXPORT_MODULE namespace hex {
@ -94,7 +95,12 @@ EXPORT_MODULE namespace hex {
std::atomic_flag m_hadException; std::atomic_flag m_hadException;
std::string m_exceptionMessage; std::string m_exceptionMessage;
struct TaskInterruptor { virtual ~TaskInterruptor() = default; }; struct TaskInterruptor {
TaskInterruptor() {
trace::disableExceptionCaptureForCurrentThread();
}
virtual ~TaskInterruptor() = default;
};
friend class TaskHolder; friend class TaskHolder;
friend class TaskManager; friend class TaskManager;

View File

@ -22,6 +22,8 @@ EXPORT_MODULE namespace hex {
Right = 8 Right = 8
}; };
using DrawFunction = std::function<void()>;
struct Tutorial { struct Tutorial {
Tutorial() = delete; Tutorial() = delete;
Tutorial(const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedDescription) : Tutorial(const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedDescription) :
@ -101,6 +103,7 @@ EXPORT_MODULE namespace hex {
std::vector<Highlight> m_highlights; std::vector<Highlight> m_highlights;
std::optional<Message> m_message; std::optional<Message> m_message;
std::function<void()> m_onAppear, m_onComplete; std::function<void()> m_onAppear, m_onComplete;
DrawFunction m_drawFunction;
}; };
Step& addStep(); Step& addStep();
@ -166,6 +169,8 @@ EXPORT_MODULE namespace hex {
*/ */
static void reset(); static void reset();
static void setRenderer(std::function<DrawFunction(const std::string &)> renderer);
private: private:
TutorialManager() = delete; TutorialManager() = delete;

View File

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

View File

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

View File

@ -0,0 +1,38 @@
#pragma once
#include <functional>
#include <nlohmann/json.hpp>
#include <wolv/net/socket_server.hpp>
namespace hex::mcp {
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);
private:
nlohmann::json handleInitialize();
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;
};
}

View File

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

View File

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

View File

@ -72,6 +72,21 @@ namespace hex::prv {
[[nodiscard]] virtual std::vector<Description> getDataDescription() const = 0; [[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 * @brief Represent the data source for a tab in the UI
*/ */
@ -79,6 +94,65 @@ namespace hex::prv {
public: public:
constexpr static u64 MaxPageSize = 0xFFFF'FFFF'FFFF'FFFF; 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(); Provider();
virtual ~Provider(); virtual ~Provider();
Provider(const Provider&) = delete; Provider(const Provider&) = delete;
@ -94,7 +168,7 @@ namespace hex::prv {
* @note This is not related to the EventProviderOpened event * @note This is not related to the EventProviderOpened event
* @return true if the provider was opened successfully, else false * @return true if the provider was opened successfully, else false
*/ */
[[nodiscard]] virtual bool open() = 0; [[nodiscard]] virtual OpenResult open() = 0;
/** /**
* @brief Closes this provider * @brief Closes this provider
@ -262,9 +336,6 @@ namespace hex::prv {
void skipLoadInterface() { m_skipLoadInterface = true; } void skipLoadInterface() { m_skipLoadInterface = true; }
[[nodiscard]] bool shouldSkipLoadInterface() const { return m_skipLoadInterface; } [[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> template<std::derived_from<undo::Operation> T>
bool addUndoableOperation(auto && ... args) { bool addUndoableOperation(auto && ... args) {
return m_undoRedoStack.add<T>(std::forward<decltype(args)...>(args)...); return m_undoRedoStack.add<T>(std::forward<decltype(args)...>(args)...);
@ -296,8 +367,6 @@ namespace hex::prv {
*/ */
bool m_skipLoadInterface = false; bool m_skipLoadInterface = false;
std::string m_errorMessage = "Unspecified error";
u64 m_pageSize = MaxPageSize; u64 m_pageSize = MaxPageSize;
}; };

View File

@ -319,6 +319,7 @@ namespace ImGuiExt {
bool DimmedButtonToggle(const char *icon, bool *v, 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 *icon, bool *v);
bool DimmedIconToggle(const char *iconOn, const char *iconOff, 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); void TextOverlay(const char *text, ImVec2 pos, float maxWidth = -1);

View File

@ -14,7 +14,6 @@
#include <map> #include <map>
#include <string> #include <string>
#include <hex/api/tutorial_manager.hpp>
namespace hex { namespace hex {
@ -27,7 +26,7 @@ namespace hex {
* @brief Draws the view * @brief Draws the view
* @note Do not override this method. Override drawContent() instead * @note Do not override this method. Override drawContent() instead
*/ */
virtual void draw() = 0; virtual void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) = 0;
/** /**
* @brief Draws the content of the view * @brief Draws the content of the view
@ -126,6 +125,7 @@ namespace hex {
class Window; class Window;
class Special; class Special;
class Floating; class Floating;
class Scrolling;
class Modal; class Modal;
class FullScreen; class FullScreen;
@ -153,16 +153,10 @@ namespace hex {
*/ */
virtual void drawHelpText() = 0; virtual void drawHelpText() = 0;
void draw() final { void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) override;
if (this->shouldDraw()) {
ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize()); virtual bool allowScroll() const {
const auto title = fmt::format("{} {}", this->getIcon(), View::toWindowName(this->getUnlocalizedName())); return false;
if (ImGui::Begin(title.c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse | this->getWindowFlags())) {
TutorialManager::setLastItemInteractiveHelpPopup([this]{ this->drawHelpText(); });
this->drawContent();
}
ImGui::End();
}
} }
}; };
@ -174,12 +168,7 @@ namespace hex {
public: public:
explicit Special(UnlocalizedString unlocalizedName) : View(std::move(unlocalizedName), "") {} explicit Special(UnlocalizedString unlocalizedName) : View(std::move(unlocalizedName), "") {}
void draw() final { void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) final;
if (this->shouldDraw()) {
ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize());
this->drawContent();
}
}
}; };
/** /**
@ -189,7 +178,24 @@ namespace hex {
public: public:
explicit Floating(UnlocalizedString unlocalizedName, const char *icon) : Window(std::move(unlocalizedName), icon) {} explicit Floating(UnlocalizedString unlocalizedName, const char *icon) : Window(std::move(unlocalizedName), icon) {}
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const override { return ImGuiWindowFlags_NoDocking; } void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) final;
[[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;
bool allowScroll() const final {
return true;
}
[[nodiscard]] bool shouldStoreWindowState() const override { return false; } [[nodiscard]] bool shouldStoreWindowState() const override { return false; }
}; };
@ -200,24 +206,7 @@ namespace hex {
public: public:
explicit Modal(UnlocalizedString unlocalizedName, const char *icon) : View(std::move(unlocalizedName), icon) {} explicit Modal(UnlocalizedString unlocalizedName, const char *icon) : View(std::move(unlocalizedName), icon) {}
void draw() final { void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) 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]] virtual bool hasCloseButton() const { return true; }
[[nodiscard]] bool shouldStoreWindowState() const override { return false; } [[nodiscard]] bool shouldStoreWindowState() const override { return false; }
@ -227,10 +216,7 @@ namespace hex {
public: public:
explicit FullScreen() : View("FullScreen", "") {} explicit FullScreen() : View("FullScreen", "") {}
void draw() final { void draw(ImGuiWindowFlags extraFlags = ImGuiWindowFlags_None) final;
this->drawContent();
this->drawAlwaysVisibleContent();
}
}; };
} }

View File

@ -594,6 +594,12 @@ namespace hex {
return false; return false;
} }
bool Spacer::draw(const std::string& name) {
std::ignore = name;
ImGui::NewLine();
return false;
}
} }
@ -864,6 +870,18 @@ 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) { 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()); log::debug("Registered new data inspector format: {}", unlocalizedName.get());
@ -1101,13 +1119,13 @@ namespace hex {
namespace impl { namespace impl {
void add(const std::string &typeName, ProviderCreationFunction creationFunction) { void add(const std::string &typeName, ProviderCreationFunction creationFunction) {
(void)RequestCreateProvider::subscribe([expectedName = typeName, creationFunction](const std::string &name, bool skipLoadInterface, bool selectProvider, prv::Provider **provider) { (void)RequestCreateProvider::subscribe([expectedName = typeName, creationFunction](const std::string &name, bool skipLoadInterface, bool selectProvider, std::shared_ptr<prv::Provider> *provider) {
if (name != expectedName) return; if (name != expectedName) return;
auto newProvider = creationFunction(); auto newProvider = creationFunction();
if (provider != nullptr) { if (provider != nullptr) {
*provider = newProvider.get(); *provider = newProvider;
ImHexApi::Provider::add(std::move(newProvider), skipLoadInterface, selectProvider); ImHexApi::Provider::add(std::move(newProvider), skipLoadInterface, selectProvider);
} }
}); });
@ -1395,6 +1413,40 @@ namespace hex {
} }
namespace ContentRegistry::MCP {
namespace impl {
mcp::Server& getMcpServerInstance() {
static AutoReset<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 ContentRegistry::Experiments {
namespace impl { namespace impl {

View File

@ -294,8 +294,8 @@ namespace hex {
namespace ImHexApi::Provider { namespace ImHexApi::Provider {
static i64 s_currentProvider = -1; static i64 s_currentProvider = -1;
static AutoReset<std::vector<std::unique_ptr<prv::Provider>>> s_providers; static AutoReset<std::vector<std::shared_ptr<prv::Provider>>> s_providers;
static AutoReset<std::map<prv::Provider*, std::unique_ptr<prv::Provider>>> s_providersToRemove; static AutoReset<std::map<prv::Provider*, std::shared_ptr<prv::Provider>>> s_providersToRemove;
namespace impl { namespace impl {
@ -382,7 +382,7 @@ namespace hex {
}); });
} }
void add(std::unique_ptr<prv::Provider> &&provider, bool skipLoadInterface, bool select) { void add(std::shared_ptr<prv::Provider> &&provider, bool skipLoadInterface, bool select) {
std::scoped_lock lock(impl::s_providerMutex); std::scoped_lock lock(impl::s_providerMutex);
if (TaskManager::getRunningTaskCount() > 0) if (TaskManager::getRunningTaskCount() > 0)
@ -391,7 +391,7 @@ namespace hex {
if (skipLoadInterface) if (skipLoadInterface)
provider->skipLoadInterface(); provider->skipLoadInterface();
EventProviderCreated::post(provider.get()); EventProviderCreated::post(provider);
s_providers->emplace_back(std::move(provider)); s_providers->emplace_back(std::move(provider));
if (select || s_providers->size() == 1) if (select || s_providers->size() == 1)
@ -491,13 +491,17 @@ namespace hex {
}); });
} }
prv::Provider* createProvider(const UnlocalizedString &unlocalizedName, bool skipLoadInterface, bool select) { std::shared_ptr<prv::Provider> createProvider(const UnlocalizedString &unlocalizedName, bool skipLoadInterface, bool select) {
prv::Provider* result = nullptr; std::shared_ptr<prv::Provider> result = nullptr;
RequestCreateProvider::post(unlocalizedName, skipLoadInterface, select, &result); RequestCreateProvider::post(unlocalizedName, skipLoadInterface, select, &result);
return result; return result;
} }
void openProvider(std::shared_ptr<prv::Provider> provider) {
RequestOpenProvider::post(provider);
}
} }
namespace ImHexApi::System { namespace ImHexApi::System {

View File

@ -104,9 +104,21 @@ namespace hex {
for (const auto &entry : json.items()) { for (const auto &entry : json.items()) {
auto value = entry.value().get<std::string>(); auto value = entry.value().get<std::string>();
// Skip empty values
if (value.empty()) if (value.empty())
continue; 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)); localizations.try_emplace(LangConst::hash(entry.key()), std::move(value));
} }
} catch (std::exception &e) { } catch (std::exception &e) {

View File

@ -7,6 +7,8 @@
#include <ranges> #include <ranges>
#include <jthread.hpp> #include <jthread.hpp>
#include <hex/helpers/debugging.hpp>
#include <hex/trace/exceptions.hpp>
#if defined(OS_WINDOWS) #if defined(OS_WINDOWS)
#include <windows.h> #include <windows.h>
@ -310,6 +312,8 @@ namespace hex {
} }
try { try {
trace::enableExceptionCaptureForCurrentThread();
// Set the thread name to the name of the task // Set the thread name to the name of the task
TaskManager::setCurrentThreadName(Lang(task->m_unlocalizedName)); TaskManager::setCurrentThreadName(Lang(task->m_unlocalizedName));
@ -323,15 +327,21 @@ namespace hex {
} catch (const std::exception &e) { } catch (const std::exception &e) {
log::error("Exception in task '{}': {}", task->m_unlocalizedName.get(), e.what()); log::error("Exception in task '{}': {}", task->m_unlocalizedName.get(), e.what());
dbg::printStackTrace(trace::getStackTrace());
// Handle the task throwing an uncaught exception // Handle the task throwing an uncaught exception
task->exception(e.what()); task->exception(e.what());
} catch (...) { } catch (...) {
log::error("Exception in task '{}'", task->m_unlocalizedName.get()); log::error("Exception in task '{}'", task->m_unlocalizedName.get());
dbg::printStackTrace(trace::getStackTrace());
// Handle the task throwing an uncaught exception of unknown type // Handle the task throwing an uncaught exception of unknown type
task->exception("Unknown Exception"); task->exception("Unknown Exception");
} }
trace::disableExceptionCaptureForCurrentThread();
s_currentTask = nullptr; s_currentTask = nullptr;
task->finish(); task->finish();
} }

View File

@ -32,6 +32,8 @@ namespace hex {
ImGuiID s_activeHelpId; ImGuiID s_activeHelpId;
bool s_helpHoverActive = false; bool s_helpHoverActive = false;
AutoReset<std::function<std::function<void()>(const std::string &)>> s_renderer;
class IDStack { class IDStack {
public: public:
@ -126,6 +128,17 @@ namespace hex {
} }
} }
}); });
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();
};
};
}
} }
const std::map<std::string, TutorialManager::Tutorial>& TutorialManager::getTutorials() { const std::map<std::string, TutorialManager::Tutorial>& TutorialManager::getTutorials() {
@ -333,30 +346,29 @@ namespace hex {
ImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot); ImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);
ImGui::SetNextWindowViewport(ImGui::GetMainViewport()->ID); ImGui::SetNextWindowViewport(ImGui::GetMainViewport()->ID);
if (ImGui::Begin("##TutorialMessage", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing)) { ImGui::SetNextWindowSize(ImVec2(300_scaled, 0));
if (ImGui::Begin(message->unlocalizedTitle.empty() ? "##TutorialMessage" : Lang(message->unlocalizedTitle), nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoFocusOnAppearing)) {
ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindowRead()); ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindowRead());
if (!message->unlocalizedTitle.empty()) auto &step = s_currentTutorial->second.m_currentStep;
ImGuiExt::Header(Lang(message->unlocalizedTitle), true);
if (!message->unlocalizedMessage.empty()) { if (!message->unlocalizedMessage.empty()) {
ImGui::PushTextWrapPos(300_scaled); step->m_drawFunction();
ImGui::TextUnformatted(Lang(message->unlocalizedMessage)); ImGui::NewLine();
ImGui::PopTextWrapPos();
ImGui::NewLine(); ImGui::NewLine();
} }
ImGui::BeginDisabled(s_currentTutorial->second.m_currentStep == s_currentTutorial->second.m_steps.begin()); ImGui::BeginDisabled(step == s_currentTutorial->second.m_steps.begin());
if (ImGui::ArrowButton("Backwards", ImGuiDir_Left)) { if (ImGuiExt::DimmedArrowButton("Backwards", ImGuiDir_Left)) {
s_currentTutorial->second.m_currentStep->advance(-1); s_currentTutorial->second.m_currentStep->advance(-1);
} }
ImGui::EndDisabled(); ImGui::EndDisabled();
ImGui::SameLine(); ImGui::SameLine();
ImGui::BeginDisabled(!message->allowSkip && s_currentTutorial->second.m_currentStep == s_currentTutorial->second.m_latestStep); ImGui::SetCursorPosX(ImGui::GetWindowWidth() - ImGui::GetFrameHeight() - ImGui::GetStyle().WindowPadding.x);
if (ImGui::ArrowButton("Forwards", ImGuiDir_Right)) { ImGui::BeginDisabled(!message->allowSkip && step == s_currentTutorial->second.m_latestStep);
s_currentTutorial->second.m_currentStep->advance(1); if (ImGuiExt::DimmedArrowButton("Forwards", ImGuiDir_Right)) {
step->advance(1);
} }
ImGui::EndDisabled(); ImGui::EndDisabled();
} }
@ -387,6 +399,10 @@ namespace hex {
s_highlightDisplays->clear(); s_highlightDisplays->clear();
} }
void TutorialManager::setRenderer(std::function<DrawFunction(const std::string &)> renderer) {
s_renderer = std::move(renderer);
}
TutorialManager::Tutorial::Step& TutorialManager::Tutorial::addStep() { TutorialManager::Tutorial::Step& TutorialManager::Tutorial::addStep() {
auto &newStep = m_steps.emplace_back(this); auto &newStep = m_steps.emplace_back(this);
m_currentStep = m_steps.end(); m_currentStep = m_steps.end();
@ -402,6 +418,9 @@ namespace hex {
return; return;
m_currentStep->addHighlights(); 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 { void TutorialManager::Tutorial::Step::addHighlights() const {
@ -426,8 +445,12 @@ namespace hex {
std::advance(m_parent->m_latestStep, steps); std::advance(m_parent->m_latestStep, steps);
std::advance(m_parent->m_currentStep, 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(); 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 else
s_currentTutorial = s_tutorials->end(); s_currentTutorial = s_tutorials->end();
} }

View File

@ -1,4 +1,6 @@
#include <hex/helpers/debugging.hpp> #include <hex/helpers/debugging.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/trace/stacktrace.hpp>
namespace hex::dbg { namespace hex::dbg {
@ -21,4 +23,23 @@ namespace hex::dbg {
s_debugMode = enabled; s_debugMode = enabled;
} }
[[noreturn]] void assertionHandler(const char* file, int line, const char *function, const char* exprString) {
log::error("Assertion failed: {} at {}:{} => {}", exprString, file, line, function);
const auto stackTrace = trace::getStackTrace();
dbg::printStackTrace(stackTrace);
std::abort();
}
void printStackTrace(const trace::StackTraceResult &stackTrace) {
log::fatal("Printing stacktrace using implementation '{}'", stackTrace.implementationName);
for (const auto &stackFrame : stackTrace.stackFrames) {
if (stackFrame.line == 0)
log::fatal(" ({}) | {}", stackFrame.file, stackFrame.function);
else
log::fatal(" ({}:{}) | {}", stackFrame.file, stackFrame.line, stackFrame.function);
}
}
} }

View File

@ -97,6 +97,13 @@ namespace hex::paths {
} }
static std::vector<std::fs::path> getPluginPaths() { static std::vector<std::fs::path> getPluginPaths() {
// If running from an AppImage, only allow loaded plugins from inside it
#if defined(OS_LINUX)
if(const char* appdir = std::getenv("APPDIR")) { // check for AppImage environment
return {std::string(appdir) + "/usr/lib/imhex"};
}
#endif
std::vector<std::fs::path> paths = getDataPaths(true); std::vector<std::fs::path> paths = getDataPaths(true);
// Add the system plugin directory to the path if one was provided at compile time // Add the system plugin directory to the path if one was provided at compile time

View File

@ -12,6 +12,7 @@
#include <mutex> #include <mutex>
#include <chrono> #include <chrono>
#include <fmt/chrono.h> #include <fmt/chrono.h>
#include <hex/helpers/debugging.hpp>
#if defined(OS_WINDOWS) #if defined(OS_WINDOWS)
#include <Windows.h> #include <Windows.h>
@ -149,14 +150,6 @@ namespace hex::log {
); );
} }
void assertionHandler(const char* exprString, const char* file, int line) {
log::error("Assertion failed: {} at {}:{}", exprString, file, line);
#if defined (DEBUG)
std::abort();
#endif
}
namespace color { namespace color {
fmt::color debug() { return fmt::color::medium_sea_green; } fmt::color debug() { return fmt::color::medium_sea_green; }

View File

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

View File

@ -0,0 +1,38 @@
#include <hex/mcp/client.hpp>
#include <hex/mcp/server.hpp>
#include <hex.hpp>
#include <string>
#include <cstdlib>
#include <fmt/format.h>
#include <hex/helpers/logger.hpp>
#include <nlohmann/json.hpp>
#include <wolv/net/socket_client.hpp>
namespace hex::mcp {
int Client::run(std::istream &input, std::ostream &output) {
wolv::net::SocketClient client(wolv::net::SocketClient::Type::TCP, true);
client.connect("127.0.0.1", Server::McpInternalPort);
if (!client.isConnected()) {
log::resumeLogging();
log::error("Cannot connect to ImHex. Do you have an instance running and is the MCP server enabled?");
return EXIT_FAILURE;
}
while (true) {
std::string request;
std::getline(input, request);
client.writeString(request);
auto response = client.readString();
if (!response.empty() && response.front() != 0x00)
output << response << std::endl;
}
return EXIT_SUCCESS;
}
}

View File

@ -0,0 +1,226 @@
#include <hex/mcp/server.hpp>
#include <string>
#include <fmt/format.h>
#include <hex/helpers/logger.hpp>
#include <nlohmann/json.hpp>
#include <wolv/net/socket_client.hpp>
#include <hex/api/imhex_api/system.hpp>
namespace hex::mcp {
class JsonRpc {
public:
explicit JsonRpc(const std::string &request) : m_request(request) { }
struct MethodNotFoundException : std::exception {};
struct InvalidParametersException : std::exception {};
std::optional<std::string> execute(auto callback) {
try {
auto requestJson = nlohmann::json::parse(m_request);
if (requestJson.is_array()) {
return handleBatchedMessages(requestJson, callback).transform([](const auto &response) { return response.dump(); });
} else {
return handleMessage(requestJson, callback).transform([](const auto &response) { return response.dump(); });
}
} catch (const MethodNotFoundException &) {
return createErrorMessage(ErrorCode::MethodNotFound, "Method not found").dump();
} catch (const InvalidParametersException &) {
return createErrorMessage(ErrorCode::InvalidParams, "Invalid params").dump();
} catch (const nlohmann::json::parse_error &) {
return createErrorMessage(ErrorCode::ParseError, "Parse error").dump();
} catch (const std::exception &e) {
return createErrorMessage(ErrorCode::InternalError, e.what()).dump();
}
}
private:
std::optional<nlohmann::json> handleMessage(const nlohmann::json &request, auto callback) {
// Validate JSON-RPC request
if (!request.contains("jsonrpc") || request["jsonrpc"] != "2.0" ||
!request.contains("method") || !request["method"].is_string()) {
m_id = request.contains("id") ? std::optional(request["id"].get<int>()) : std::nullopt;
return createErrorMessage(ErrorCode::InvalidRequest, "Invalid Request").dump();
}
m_id = request.contains("id") ? std::optional(request["id"].get<int>()) : std::nullopt;
// Execute the method
auto result = callback(request["method"].get<std::string>(), request.value("params", nlohmann::json::object()));
if (!m_id.has_value())
return std::nullopt;
return createResponseMessage(result);
}
std::optional<nlohmann::json> handleBatchedMessages(const nlohmann::json &request, auto callback) {
if (!request.is_array()) {
return createErrorMessage(ErrorCode::InvalidRequest, "Invalid Request").dump();
}
nlohmann::json responses = nlohmann::json::array();
for (const auto &message : request) {
auto response = handleMessage(message, callback);
if (response.has_value())
responses.push_back(*response);
}
if (responses.empty())
return std::nullopt;
return responses.dump();
}
enum class ErrorCode {
ParseError = -32700,
InvalidRequest = -32600,
MethodNotFound = -32601,
InvalidParams = -32602,
InternalError = -32603,
};
nlohmann::json createDefaultMessage() {
nlohmann::json message;
message["jsonrpc"] = "2.0";
if (m_id.has_value())
message["id"] = m_id.value();
else
message["id"] = nullptr;
return message;
}
nlohmann::json createErrorMessage(ErrorCode code, const std::string &message) {
auto json = createDefaultMessage();
json["error"] = {
{ "code", int(code) },
{ "message", message }
};
return json;
}
nlohmann::json createResponseMessage(const nlohmann::json &result) {
auto json = createDefaultMessage();
json["result"] = result;
return json;
}
private:
std::string m_request;
std::optional<int> m_id;
};
Server::Server() : m_server(McpInternalPort, 1024, 1, true) {
}
Server::~Server() {
this->shutdown();
}
void Server::listen() {
m_server.accept([this](auto, const std::vector<u8> &data) -> std::vector<u8> {
std::string request(data.begin(), data.end());
log::debug("MCP ----> {}", request);
JsonRpc rpc(request);
auto response = rpc.execute([this](const std::string &method, const nlohmann::json &params) -> nlohmann::json {
if (method == "initialize") {
return handleInitialize();
} else if (method.starts_with("notifications/")) {
handleNotifications(method.substr(14), params);
return {};
} else if (method.ends_with("/list")) {
auto primitiveName = method.substr(0, method.size() - 5);
if (m_primitives.contains(primitiveName)) {
nlohmann::json capabilitiesList = nlohmann::json::array();
for (const auto &[name, primitive] : m_primitives[primitiveName]) {
capabilitiesList.push_back(primitive.capabilities);
}
nlohmann::json result;
result[primitiveName] = capabilitiesList;
return result;
}
} else if (method.ends_with("/call")) {
auto primitive = method.substr(0, method.size() - 5);
if (auto primitiveIt = m_primitives.find(primitive); primitiveIt != m_primitives.end()) {
auto name = params.value("name", "");
if (auto functionIt = primitiveIt->second.find(name); functionIt != primitiveIt->second.end()) {
return functionIt->second.function(params.value("arguments", nlohmann::json::object()));
}
}
}
throw JsonRpc::MethodNotFoundException();
});
log::debug("MCP <---- {}", response.value_or("<Nothing>"));
if (response.has_value())
return { response->begin(), response->end() };
else
return std::vector<u8>{ 0x00 };
}, [this](auto) {
log::info("MCP client disconnected");
m_connected = false;
}, true);
}
void Server::shutdown() {
m_server.shutdown();
}
void Server::disconnect() {
m_server.disconnectClients();
}
void Server::addPrimitive(std::string type, std::string_view capabilities, std::function<nlohmann::json(const nlohmann::json &params)> function) {
auto json = nlohmann::json::parse(capabilities);
auto name = json["name"].get<std::string>();
m_primitives[type][name] = {
json,
function
};
}
nlohmann::json Server::handleInitialize() {
constexpr static auto ServerName = "ImHex";
constexpr static auto ProtocolVersion = "2025-06-18";
return {
{ "protocolVersion", ProtocolVersion },
{
"capabilities",
{
{ "tools", nlohmann::json::object() },
},
},
{
"serverInfo", {
{ "name", ServerName },
{ "version", ImHexApi::System::getImHexVersion().get() }
}
}
};
}
void Server::handleNotifications(const std::string &method, [[maybe_unused]] const nlohmann::json &params) {
if (method == "initialized") {
m_connected = true;
}
}
bool Server::isConnected() {
return m_connected;
}
}

View File

@ -11,9 +11,9 @@ namespace hex::prv {
clearCache(); clearCache();
} }
bool CachedProvider::open() { Provider::OpenResult CachedProvider::open() {
clearCache(); clearCache();
return true; return {};
} }
void CachedProvider::close() { void CachedProvider::close() {

View File

@ -4,12 +4,12 @@
namespace hex::prv { namespace hex::prv {
bool MemoryProvider::open() { Provider::OpenResult MemoryProvider::open() {
if (m_data.empty()) { if (m_data.empty()) {
m_data.resize(1); m_data.resize(1);
} }
return true; return {};
} }
void MemoryProvider::readRaw(u64 offset, void *buffer, size_t size) { void MemoryProvider::readRaw(u64 offset, void *buffer, size_t size) {

View File

@ -7,12 +7,14 @@
#include <cmath> #include <cmath>
#include <cstring> #include <cstring>
#include <optional> #include <optional>
#include <hex/api/content_registry/settings.hpp>
#include <hex/helpers/magic.hpp> #include <hex/helpers/magic.hpp>
#include <wolv/io/file.hpp> #include <wolv/io/file.hpp>
#include <wolv/literals.hpp> #include <wolv/literals.hpp>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <wolv/utils/string.hpp>
namespace hex::prv { namespace hex::prv {
@ -24,6 +26,28 @@ namespace hex::prv {
} }
IProviderDataBackupable::IProviderDataBackupable(Provider* provider) : m_provider(provider) {
m_shouldCreateBackups = ContentRegistry::Settings::read<bool>("hex.builtin.setting.general", "hex.builtin.setting.general.backups.file_backup.enable", true);
m_maxSize = ContentRegistry::Settings::read<u32>("hex.builtin.setting.general", "hex.builtin.setting.general.backups.file_backup.max_size", 1_MiB);
m_backupExtension = ContentRegistry::Settings::read<std::string>("hex.builtin.setting.general", "hex.builtin.setting.general.backups.file_backup.extension", ".bak");
}
void IProviderDataBackupable::createBackupIfNeeded(const std::fs::path &inputFilePath) {
if (!m_shouldCreateBackups || m_backupCreated)
return;
if (m_provider->getActualSize() > m_maxSize)
return;
const std::fs::path backupFilePath = wolv::util::toUTF8String(inputFilePath) + m_backupExtension;
if (wolv::io::fs::copyFile(inputFilePath, backupFilePath, std::fs::copy_options::overwrite_existing)) {
if (wolv::io::fs::exists(backupFilePath)) {
m_backupCreated = true;
log::info("Created backup of provider data at '{}'", backupFilePath.string());
}
}
}
Provider::Provider() : m_undoRedoStack(this), m_id(s_idCounter++) { Provider::Provider() : m_undoRedoStack(this), m_id(s_idCounter++) {

View File

@ -1218,6 +1218,21 @@ namespace ImGuiExt {
return res; return res;
} }
bool DimmedArrowButton(const char *id, ImGuiDir dir, ImVec2 size) {
PushStyleColor(ImGuiCol_ButtonHovered, GetCustomColorU32(ImGuiCustomCol_DescButtonHovered));
PushStyleColor(ImGuiCol_Button, GetCustomColorU32(ImGuiCustomCol_DescButton));
PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_ButtonActive));
PushStyleColor(ImGuiCol_ButtonActive, GetCustomColorU32(ImGuiCustomCol_DescButtonActive));
PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.5 * hex::ImHexApi::System::getGlobalScale());
bool res = ArrowButtonEx(id, dir, size);
PopStyleColor(4);
PopStyleVar(1);
return res;
}
bool DimmedButtonToggle(const char *icon, bool *v, ImVec2 size, ImVec2 iconOffset) { bool DimmedButtonToggle(const char *icon, bool *v, ImVec2 size, ImVec2 iconOffset) {
bool pushed = false; bool pushed = false;
bool toggled = false; bool toggled = false;

View File

@ -1,8 +1,10 @@
#include <hex/ui/view.hpp> #include <hex/ui/view.hpp>
#include <hex/api/task_manager.hpp>
#include <hex/helpers/auto_reset.hpp> #include <hex/helpers/auto_reset.hpp>
#include <hex/api/imhex_api/provider.hpp> #include <hex/api/imhex_api/provider.hpp>
#include <hex/api/task_manager.hpp>
#include <hex/api/tutorial_manager.hpp>
#include <hex/providers/provider.hpp> #include <hex/providers/provider.hpp>
#include <imgui.h> #include <imgui.h>
@ -116,4 +118,63 @@ namespace hex {
} }
void View::Window::draw(ImGuiWindowFlags extraFlags) {
if (this->shouldDraw()) {
if (!allowScroll())
extraFlags |= ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
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 | extraFlags | this->getWindowFlags())) {
TutorialManager::setLastItemInteractiveHelpPopup([this]{ this->drawHelpText(); });
this->drawContent();
}
ImGui::End();
}
}
void View::Special::draw(ImGuiWindowFlags extraFlags) {
std::ignore = extraFlags;
if (this->shouldDraw()) {
ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize());
this->drawContent();
}
}
void View::Floating::draw(ImGuiWindowFlags extraFlags) {
Window::draw(extraFlags | ImGuiWindowFlags_NoDocking);
}
void View::Scrolling::draw(ImGuiWindowFlags extraFlags) {
Window::draw(extraFlags);
}
void View::Modal::draw(ImGuiWindowFlags extraFlags) {
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 | extraFlags | this->getWindowFlags())) {
this->drawContent();
ImGui::EndPopup();
}
if (ImGui::IsKeyPressed(ImGuiKey_Escape))
this->getWindowOpenState() = false;
}
}
void View::FullScreen::draw(ImGuiWindowFlags extraFlags) {
std::ignore = extraFlags;
this->drawContent();
this->drawAlwaysVisibleContent();
}
} }

View File

@ -25,10 +25,17 @@
// If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement. // If your macro uses multiple statements, make sure is enclosed in a 'do { .. } while (0)' block so it can be used as a single statement.
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR) //#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts //#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
namespace hex::log::impl { namespace hex::dbg {
void assertionHandler(const char* expr_str, const char* file, int line); [[noreturn]] void assertionHandler(const char* file, int line, const char *function, const char* exprString);
} }
#define IM_ASSERT(_EXPR) do { if (!(_EXPR)) [[unlikely]] { hex::log::impl::assertionHandler(#_EXPR, __FILE__, __LINE__); } } while(0)
#if defined(__PRETTY_FUNCTION__)
#define IM_ASSERT(_EXPR) do { if (!(_EXPR)) [[unlikely]] { hex::dbg::assertionHandler(__FILE__, __LINE__, __PRETTY_FUNCTION__, #_EXPR); } } while(0)
#elif defined(__FUNCSIG__)
#define IM_ASSERT(_EXPR) do { if (!(_EXPR)) [[unlikely]] { hex::dbg::assertionHandler(__FILE__, __LINE__, __FUNCSIG__, #_EXPR); } } while(0)
#else
#define IM_ASSERT(_EXPR) do { if (!(_EXPR)) [[unlikely]] { hex::dbg::assertionHandler(__FILE__, __LINE__, __FUNCTION__, #_EXPR); } } while(0)
#endif
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows //---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility. // Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.

View File

@ -81,6 +81,9 @@ if (IMHEX_TRACE_EXCEPTIONS)
if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") if (CMAKE_CXX_COMPILER_ID MATCHES "GNU")
target_link_options(tracing ${LIBIMHEX_LIBRARY_TYPE_PUBLIC} "-Wl,--wrap=__cxa_throw") target_link_options(tracing ${LIBIMHEX_LIBRARY_TYPE_PUBLIC} "-Wl,--wrap=__cxa_throw")
target_compile_definitions(tracing ${LIBIMHEX_LIBRARY_TYPE_PRIVATE} HEX_WRAP_CXA_THROW) target_compile_definitions(tracing ${LIBIMHEX_LIBRARY_TYPE_PRIVATE} HEX_WRAP_CXA_THROW)
target_link_options(tracing ${LIBIMHEX_LIBRARY_TYPE_PUBLIC} "-Wl,--wrap=_ZSt21__glibcxx_assert_failPKciS0_S0_")
target_compile_definitions(tracing ${LIBIMHEX_LIBRARY_TYPE_PRIVATE} HEX_WRAP_GLIBCXX_ASSERT_FAIL)
elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
# Not supported currently # Not supported currently
endif() endif()

View File

@ -6,7 +6,12 @@
namespace hex::trace { namespace hex::trace {
using AssertionHandler = void(*)(const char* file, int line, const char *function, const char* exprString);
std::optional<StackTraceResult> getLastExceptionStackTrace(); std::optional<StackTraceResult> getLastExceptionStackTrace();
void setAssertionHandler(AssertionHandler handler);
void enableExceptionCaptureForCurrentThread(); void enableExceptionCaptureForCurrentThread();
void disableExceptionCaptureForCurrentThread();
} }

View File

@ -2,8 +2,9 @@
namespace hex::trace { namespace hex::trace {
static std::optional<StackTraceResult> s_lastExceptionStackTrace; static thread_local std::optional<StackTraceResult> s_lastExceptionStackTrace;
static thread_local bool s_threadExceptionCaptureEnabled = false; static thread_local bool s_threadExceptionCaptureEnabled = false;
static AssertionHandler s_assertionHandler = nullptr;
std::optional<StackTraceResult> getLastExceptionStackTrace() { std::optional<StackTraceResult> getLastExceptionStackTrace() {
if (!s_lastExceptionStackTrace.has_value()) if (!s_lastExceptionStackTrace.has_value())
@ -15,18 +16,26 @@ namespace hex::trace {
return result; return result;
} }
void setAssertionHandler(AssertionHandler handler) {
s_assertionHandler = handler;
}
void enableExceptionCaptureForCurrentThread() { void enableExceptionCaptureForCurrentThread() {
s_threadExceptionCaptureEnabled = true; s_threadExceptionCaptureEnabled = true;
} }
void disableExceptionCaptureForCurrentThread() {
s_threadExceptionCaptureEnabled = false;
}
} }
#if defined(HEX_WRAP_CXA_THROW) #if defined(HEX_WRAP_CXA_THROW)
extern "C" { extern "C" {
[[noreturn]] void __real___cxa_throw(void* thrownException, void* type, void (*destructor)(void*)); [[noreturn]] void __real___cxa_throw(void* thrownException, std::type_info* type, void (*destructor)(void*));
[[noreturn]] void __wrap___cxa_throw(void* thrownException, void* type, void (*destructor)(void*)) { [[noreturn]] void __wrap___cxa_throw(void* thrownException, std::type_info* type, void (*destructor)(void*)) {
if (hex::trace::s_threadExceptionCaptureEnabled) if (hex::trace::s_threadExceptionCaptureEnabled)
hex::trace::s_lastExceptionStackTrace = hex::trace::getStackTrace(); hex::trace::s_lastExceptionStackTrace = hex::trace::getStackTrace();
@ -36,3 +45,22 @@ namespace hex::trace {
} }
#endif #endif
#if defined(HEX_WRAP_GLIBCXX_ASSERT_FAIL)
extern "C" {
[[noreturn]] void __real__ZSt21__glibcxx_assert_failPKciS0_S0_(const char* file, int line, const char* function, const char* condition);
[[noreturn]] void __wrap__ZSt21__glibcxx_assert_failPKciS0_S0_(const char* file, int line, const char* function, const char* condition) {
if (hex::trace::s_assertionHandler != nullptr) {
hex::trace::s_assertionHandler(file, line, function, condition);
} else {
__real__ZSt21__glibcxx_assert_failPKciS0_S0_(file, line, function, condition);
}
std::abort();
}
}
#endif

View File

@ -16,6 +16,7 @@
#include <csignal> #include <csignal>
#include <exception> #include <exception>
#include <typeinfo> #include <typeinfo>
#include <hex/helpers/debugging.hpp>
#include <hex/helpers/utils.hpp> #include <hex/helpers/utils.hpp>
#if defined(IMGUI_TEST_ENGINE) #if defined(IMGUI_TEST_ENGINE)
@ -71,23 +72,12 @@ namespace hex::crash {
log::warn("Could not write crash.json file!"); log::warn("Could not write crash.json file!");
} }
static void printStackTrace() {
auto stackTraceResult = trace::getStackTrace();
log::fatal("Printing stacktrace using implementation '{}'", stackTraceResult.implementationName);
for (const auto &stackFrame : stackTraceResult.stackFrames) {
if (stackFrame.line == 0)
log::fatal(" ({}) | {}", stackFrame.file, stackFrame.function);
else
log::fatal(" ({}:{}) | {}", stackFrame.file, stackFrame.line, stackFrame.function);
}
}
static void callCrashHandlers(const std::string &msg) { static void callCrashHandlers(const std::string &msg) {
// Call the crash callback // Call the crash callback
crashCallback(msg); crashCallback(msg);
// Print the stacktrace to the console or log file // Print the stacktrace to the console or log file
printStackTrace(); dbg::printStackTrace(trace::getStackTrace());
// Flush all streams // Flush all streams
std::fflush(stdout); std::fflush(stdout);
@ -188,6 +178,7 @@ namespace hex::crash {
// Setup functions to handle signals, uncaught exception, or similar stuff that will crash ImHex // Setup functions to handle signals, uncaught exception, or similar stuff that will crash ImHex
void setupCrashHandlers() { void setupCrashHandlers() {
trace::initialize(); trace::initialize();
trace::setAssertionHandler(dbg::assertionHandler);
// Register signal handlers // Register signal handlers
{ {

View File

@ -68,6 +68,7 @@ add_imhex_plugin(
source/content/providers/base64_provider.cpp source/content/providers/base64_provider.cpp
source/content/providers/view_provider.cpp source/content/providers/view_provider.cpp
source/content/providers/udp_provider.cpp source/content/providers/udp_provider.cpp
source/content/providers/command_provider.cpp
source/content/tools/ascii_table.cpp source/content/tools/ascii_table.cpp
source/content/tools/base_converter.cpp source/content/tools/base_converter.cpp

View File

@ -30,6 +30,7 @@ namespace hex::plugin::builtin {
void handleValidatePluginCommand(const std::vector<std::string> &args); void handleValidatePluginCommand(const std::vector<std::string> &args);
void handleSaveEditorCommand(const std::vector<std::string> &args); void handleSaveEditorCommand(const std::vector<std::string> &args);
void handleFileInfoCommand(const std::vector<std::string> &args); void handleFileInfoCommand(const std::vector<std::string> &args);
void handleMCPCommand(const std::vector<std::string> &args);
void registerCommandForwarders(); void registerCommandForwarders();

View File

@ -3,7 +3,6 @@
#include <content/views/view_hex_editor.hpp> #include <content/views/view_hex_editor.hpp>
#include <hex/api/localization_manager.hpp> #include <hex/api/localization_manager.hpp>
#include <ui/text_editor.hpp>
#include <string> #include <string>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
@ -21,6 +20,5 @@ namespace hex::plugin::builtin {
private: private:
std::string m_decodedString; std::string m_decodedString;
ui::TextEditor m_editor;
}; };
} }

View File

@ -0,0 +1,54 @@
#pragma once
#include <hex/providers/provider.hpp>
#include <wolv/net/socket_client.hpp>
#include <fonts/vscode_icons.hpp>
#include <hex/providers/cached_provider.hpp>
namespace hex::plugin::builtin {
class CommandProvider : public prv::CachedProvider,
public prv::IProviderLoadInterface {
public:
CommandProvider();
~CommandProvider() override = default;
[[nodiscard]] bool isAvailable() const override;
[[nodiscard]] bool isReadable() const override;
[[nodiscard]] bool isWritable() const override;
[[nodiscard]] bool isResizable() const override;
[[nodiscard]] bool isSavable() const override;
void readFromSource(u64 offset, void *buffer, size_t size) override;
void writeToSource(u64 offset, const void *buffer, size_t size) override;
[[nodiscard]] u64 getSourceSize() const override;
void save() override;
[[nodiscard]] std::string getName() const override;
[[nodiscard]] OpenResult open() override;
void close() override;
bool drawLoadInterface() override;
void loadSettings(const nlohmann::json &settings) override;
[[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override;
[[nodiscard]] UnlocalizedString getTypeName() const override {
return "hex.builtin.provider.command";
}
[[nodiscard]] const char* getIcon() const override {
return ICON_VS_TERMINAL_CMD;
}
protected:
std::string m_name;
std::string m_readCommand, m_writeCommand, m_sizeCommand, m_resizeCommand, m_saveCommand;
bool m_open = false;
};
}

View File

@ -30,7 +30,7 @@ namespace hex::plugin::builtin {
void setPath(const std::fs::path &path); void setPath(const std::fs::path &path);
[[nodiscard]] bool open() override; [[nodiscard]] OpenResult open() override;
void close() override; void close() override;
[[nodiscard]] std::string getName() const override; [[nodiscard]] std::string getName() const override;

View File

@ -13,9 +13,10 @@ namespace hex::plugin::builtin {
class FileProvider : public prv::Provider, class FileProvider : public prv::Provider,
public prv::IProviderDataDescription, public prv::IProviderDataDescription,
public prv::IProviderFilePicker, public prv::IProviderFilePicker,
public prv::IProviderMenuItems { public prv::IProviderMenuItems,
public prv::IProviderDataBackupable {
public: public:
FileProvider() = default; FileProvider() : IProviderDataBackupable(this) {}
~FileProvider() override = default; ~FileProvider() override = default;
[[nodiscard]] bool isAvailable() const override; [[nodiscard]] bool isAvailable() const override;
@ -43,7 +44,7 @@ namespace hex::plugin::builtin {
void setPath(const std::fs::path &path); void setPath(const std::fs::path &path);
[[nodiscard]] bool open() override; [[nodiscard]] OpenResult open() override;
void close() override; void close() override;
void loadSettings(const nlohmann::json &settings) override; void loadSettings(const nlohmann::json &settings) override;
@ -65,7 +66,7 @@ namespace hex::plugin::builtin {
private: private:
void handleFileChange(); void handleFileChange();
bool open(bool memoryMapped); OpenResult open(bool memoryMapped);
protected: protected:
std::fs::path m_path; std::fs::path m_path;

View File

@ -35,7 +35,7 @@ namespace hex::plugin::builtin {
[[nodiscard]] std::string getName() const override; [[nodiscard]] std::string getName() const override;
[[nodiscard]] std::vector<Description> getDataDescription() const override; [[nodiscard]] std::vector<Description> getDataDescription() const override;
[[nodiscard]] bool open() override; [[nodiscard]] OpenResult open() override;
void close() override; void close() override;
[[nodiscard]] bool isConnected() const; [[nodiscard]] bool isConnected() const;

View File

@ -39,7 +39,7 @@ namespace hex::plugin::builtin {
[[nodiscard]] u64 getActualSize() const override; [[nodiscard]] u64 getActualSize() const override;
void processMemoryRegions(wolv::util::Expected<std::map<u64, std::vector<u8>>, std::string> data); void processMemoryRegions(wolv::util::Expected<std::map<u64, std::vector<u8>>, std::string> data);
static bool memoryRegionFilter(const std::string &search, const MemoryRegion &memoryRegion); static bool memoryRegionFilter(const std::string &search, const MemoryRegion &memoryRegion);
bool open() override; OpenResult open() override;
void close() override; void close() override;
[[nodiscard]] std::string getName() const override; [[nodiscard]] std::string getName() const override;

View File

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

View File

@ -9,7 +9,7 @@ namespace hex::plugin::builtin {
MotorolaSRECProvider() = default; MotorolaSRECProvider() = default;
~MotorolaSRECProvider() override = default; ~MotorolaSRECProvider() override = default;
bool open() override; OpenResult open() override;
void close() override; void close() override;
[[nodiscard]] std::string getName() const override; [[nodiscard]] std::string getName() const override;

View File

@ -29,7 +29,7 @@ namespace hex::plugin::builtin {
[[nodiscard]] bool isResizable() const override { return false; } [[nodiscard]] bool isResizable() const override { return false; }
[[nodiscard]] bool isSavable() const override { return false; } [[nodiscard]] bool isSavable() const override { return false; }
[[nodiscard]] bool open() override { return true; } [[nodiscard]] OpenResult open() override { return {}; }
void close() override { } void close() override { }
void readRaw(u64 offset, void *buffer, size_t size) override { void readRaw(u64 offset, void *buffer, size_t size) override {

View File

@ -59,7 +59,7 @@ namespace hex::plugin::builtin {
}; };
} }
[[nodiscard]] bool open() override; [[nodiscard]] OpenResult open() override;
void close() override; void close() override;
bool drawLoadInterface() override; bool drawLoadInterface() override;
@ -86,6 +86,7 @@ namespace hex::plugin::builtin {
struct Process { struct Process {
u32 id; u32 id;
std::string name; std::string name;
std::string commandLine;
ImGuiExt::Texture icon; ImGuiExt::Texture icon;
}; };

View File

@ -30,7 +30,7 @@ namespace hex::plugin::builtin {
[[nodiscard]] bool drawLoadInterface() override; [[nodiscard]] bool drawLoadInterface() override;
void drawSidebarInterface() override; void drawSidebarInterface() override;
[[nodiscard]] bool open() override; [[nodiscard]] OpenResult open() override;
void close() override; void close() override;
void loadSettings(const nlohmann::json &) override; void loadSettings(const nlohmann::json &) override;

View File

@ -20,7 +20,7 @@ namespace hex::plugin::builtin {
[[nodiscard]] bool isSavableAsRecent() const override; [[nodiscard]] bool isSavableAsRecent() const override;
void save() override; void save() override;
[[nodiscard]] bool open() override; [[nodiscard]] OpenResult open() override;
void close() override; void close() override;
void resizeRaw(u64 newSize) override; void resizeRaw(u64 newSize) override;

View File

@ -3,8 +3,6 @@
#include <hex/ui/view.hpp> #include <hex/ui/view.hpp>
#include <hex/api/imhex_api/bookmarks.hpp> #include <hex/api/imhex_api/bookmarks.hpp>
#include <ui/text_editor.hpp>
#include <list> #include <list>
#include <ui/markdown.hpp> #include <ui/markdown.hpp>

View File

@ -57,10 +57,6 @@ namespace hex::plugin::builtin {
void reloadCustomNodes(); void reloadCustomNodes();
void updateNodePositions(); void updateNodePositions();
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const override {
return ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
}
std::vector<Workspace*> &getWorkspaceStack() { return *m_workspaceStack; } std::vector<Workspace*> &getWorkspaceStack() { return *m_workspaceStack; }
private: private:

View File

@ -13,7 +13,7 @@ namespace hex::plugin::builtin {
void drawContent() override; void drawContent() override;
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const override { [[nodiscard]] ImGuiWindowFlags getWindowFlags() const override {
return ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse; return ImGuiWindowFlags_NoNavInputs;
} }
bool shouldDefaultFocus() const override { return true; } bool shouldDefaultFocus() const override { return true; }

View File

@ -27,7 +27,7 @@ namespace hex::plugin::builtin {
} }
ImGuiWindowFlags getWindowFlags() const override { ImGuiWindowFlags getWindowFlags() const override {
return View::Floating::getWindowFlags() | ImGuiWindowFlags_NoResize; return ImGuiWindowFlags_NoResize;
} }
private: private:

View File

@ -7,7 +7,7 @@
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
class ViewInformation : public View::Window { class ViewInformation : public View::Scrolling {
public: public:
explicit ViewInformation(); explicit ViewInformation();
~ViewInformation() override = default; ~ViewInformation() override = default;

View File

@ -66,9 +66,6 @@ namespace hex::plugin::builtin {
} }
void drawContent() override; void drawContent() override;
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const override {
return ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
}
void setPopupWindowHeight(u32 height) { m_popupWindowHeight = height; } void setPopupWindowHeight(u32 height) { m_popupWindowHeight = height; }
u32 getPopupWindowHeight() const { return m_popupWindowHeight; } u32 getPopupWindowHeight() const { return m_popupWindowHeight; }
@ -140,7 +137,8 @@ namespace hex::plugin::builtin {
std::atomic<bool> m_dangerousFunctionCalled = false; std::atomic<bool> m_dangerousFunctionCalled = false;
std::atomic<DangerousFunctionPerms> m_dangerousFunctionsAllowed = DangerousFunctionPerms::Ask; std::atomic<DangerousFunctionPerms> m_dangerousFunctionsAllowed = DangerousFunctionPerms::Ask;
bool m_autoLoadPatterns = true; bool m_suggestSupportedPatterns = true;
bool m_autoApplyPatterns = false;
PerProvider<ui::VisualizerDrawer> m_visualizerDrawer; PerProvider<ui::VisualizerDrawer> m_visualizerDrawer;
bool m_tooltipJustOpened = false; bool m_tooltipJustOpened = false;
@ -152,12 +150,12 @@ namespace hex::plugin::builtin {
std::mutex m_logMutex; std::mutex m_logMutex;
PerProvider<ui::TextEditor::Coordinates> m_cursorPosition; PerProvider<ui::TextEditor::Coordinates> m_cursorPosition;
PerProvider<ImVec2> m_scroll;
PerProvider<ImVec2> m_consoleScroll;
PerProvider<ui::TextEditor::Coordinates> m_consoleCursorPosition; PerProvider<ui::TextEditor::Coordinates> m_consoleCursorPosition;
PerProvider<bool> m_cursorNeedsUpdate; PerProvider<ui::TextEditor::Range> m_selection;
PerProvider<bool> m_consoleCursorNeedsUpdate; PerProvider<ui::TextEditor::Range> m_consoleSelection;
PerProvider<ui::TextEditor::Selection> m_selection;
PerProvider<ui::TextEditor::Selection> m_consoleSelection;
PerProvider<size_t> m_consoleLongestLineLength; PerProvider<size_t> m_consoleLongestLineLength;
PerProvider<ui::TextEditor::Breakpoints> m_breakpoints; PerProvider<ui::TextEditor::Breakpoints> m_breakpoints;
PerProvider<std::optional<pl::core::err::PatternLanguageError>> m_lastEvaluationError; PerProvider<std::optional<pl::core::err::PatternLanguageError>> m_lastEvaluationError;

View File

@ -7,7 +7,7 @@
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
class ViewTools : public View::Window { class ViewTools : public View::Scrolling {
public: public:
ViewTools(); ViewTools();
~ViewTools() override = default; ~ViewTools() override = default;

View File

@ -26,7 +26,7 @@ namespace hex::plugin::builtin {
} }
ImGuiWindowFlags getWindowFlags() const override { ImGuiWindowFlags getWindowFlags() const override {
return Floating::getWindowFlags() | ImGuiWindowFlags_NoResize; return ImGuiWindowFlags_NoResize;
} }
private: private:

View File

@ -444,10 +444,10 @@
"hex.builtin.setting.folders.description": "Gib zusätzliche Orderpfade an, in welchen Pattern, Scripts, Yara Rules und anderes gesucht wird", "hex.builtin.setting.folders.description": "Gib zusätzliche Orderpfade an, in welchen Pattern, Scripts, Yara Rules und anderes gesucht wird",
"hex.builtin.setting.folders.remove_folder": "Ausgewählter Ordner von Liste entfernen", "hex.builtin.setting.folders.remove_folder": "Ausgewählter Ordner von Liste entfernen",
"hex.builtin.setting.general": "Allgemein", "hex.builtin.setting.general": "Allgemein",
"hex.builtin.setting.general.auto_backup_time": "Periodisches Projekt Backup", "hex.builtin.setting.general.backups.auto_backup_time": "Periodisches Projekt Backup",
"hex.builtin.setting.general.auto_backup_time.format.extended": "Alle {0}min {1}s", "hex.builtin.setting.general.backups.auto_backup_time.format.extended": "Alle {0}min {1}s",
"hex.builtin.setting.general.auto_backup_time.format.simple": "Alle {0}s", "hex.builtin.setting.general.backups.auto_backup_time.format.simple": "Alle {0}s",
"hex.builtin.setting.general.auto_load_patterns": "Automatisches Laden unterstützter Pattern", "hex.builtin.setting.general.auto_apply_patterns": "Automatisches Laden unterstützter Pattern",
"hex.builtin.setting.general.network": "Netzwerk", "hex.builtin.setting.general.network": "Netzwerk",
"hex.builtin.setting.general.network_interface": "Netzwerk Interface Aktivieren", "hex.builtin.setting.general.network_interface": "Netzwerk Interface Aktivieren",
"hex.builtin.setting.general.patterns": "Patterns", "hex.builtin.setting.general.patterns": "Patterns",

View File

@ -54,6 +54,7 @@
"hex.builtin.achievement.misc.download_from_store.name": "There's an app for that", "hex.builtin.achievement.misc.download_from_store.name": "There's an app for that",
"hex.builtin.achievement.misc.download_from_store.desc": "Download any item from the Content Store", "hex.builtin.achievement.misc.download_from_store.desc": "Download any item from the Content Store",
"hex.builtin.background_service.network_interface": "Network Interface", "hex.builtin.background_service.network_interface": "Network Interface",
"hex.builtin.setting.general.mcp_server": "MCP Server support",
"hex.builtin.background_service.auto_backup": "Auto Backup", "hex.builtin.background_service.auto_backup": "Auto Backup",
"hex.builtin.command.calc.desc": "Calculator", "hex.builtin.command.calc.desc": "Calculator",
"hex.builtin.command.convert.desc": "Unit conversion", "hex.builtin.command.convert.desc": "Unit conversion",
@ -123,6 +124,7 @@
"hex.builtin.layouts.none.restore_default": "Restore default layout", "hex.builtin.layouts.none.restore_default": "Restore default layout",
"hex.builtin.menu.edit": "Edit", "hex.builtin.menu.edit": "Edit",
"hex.builtin.menu.edit.bookmark.create": "Create Bookmark", "hex.builtin.menu.edit.bookmark.create": "Create Bookmark",
"hex.builtin.menu.edit.find.find_selection": "Find occurrences",
"hex.builtin.view.hex_editor.menu.edit.redo": "Redo", "hex.builtin.view.hex_editor.menu.edit.redo": "Redo",
"hex.builtin.view.hex_editor.menu.edit.undo": "Undo", "hex.builtin.view.hex_editor.menu.edit.undo": "Undo",
"hex.builtin.menu.extras": "Extras", "hex.builtin.menu.extras": "Extras",
@ -406,7 +408,7 @@
"hex.builtin.popup.exit_application.title": "Exit Application?", "hex.builtin.popup.exit_application.title": "Exit Application?",
"hex.builtin.popup.waiting_for_tasks.title": "Waiting for Tasks", "hex.builtin.popup.waiting_for_tasks.title": "Waiting for Tasks",
"hex.builtin.popup.crash_recover.title": "Crash recovery", "hex.builtin.popup.crash_recover.title": "Crash recovery",
"hex.builtin.popup.crash_recover.message": "An exception was thrown, but ImHex was able to catch it and advert a crash", "hex.builtin.popup.crash_recover.message": "An exception was thrown, but ImHex was able to catch it and avert a crash",
"hex.builtin.popup.foreground_task.title": "Please Wait...", "hex.builtin.popup.foreground_task.title": "Please Wait...",
"hex.builtin.popup.blocking_task.title": "Running Task", "hex.builtin.popup.blocking_task.title": "Running Task",
"hex.builtin.popup.blocking_task.desc": "A task is currently executing.", "hex.builtin.popup.blocking_task.desc": "A task is currently executing.",
@ -418,8 +420,18 @@
"hex.builtin.provider.rename": "Rename", "hex.builtin.provider.rename": "Rename",
"hex.builtin.provider.rename.desc": "Enter a name for this data source.", "hex.builtin.provider.rename.desc": "Enter a name for this data source.",
"hex.builtin.provider.tooltip.show_more": "Hold SHIFT for more information", "hex.builtin.provider.tooltip.show_more": "Hold SHIFT for more information",
"hex.builtin.provider.error.open": "Failed to open data provider: {}", "hex.builtin.provider.error.open": "Failed to open data source: {}",
"hex.builtin.provider.base64": "Base64 File", "hex.builtin.provider.base64": "Base64 File",
"hex.builtin.provider.command": "Terminal Command",
"hex.builtin.provider.command.name": "Command {0}",
"hex.builtin.provider.command.load.name": "Name",
"hex.builtin.provider.command.load.hint": "Enter commands to be executed for specific functions.\n\nThe {address} and {size} placeholders will be replaced with the respective value",
"hex.builtin.provider.command.load.read_command": "Read Data Command",
"hex.builtin.provider.command.load.write_command": "Write Data Command",
"hex.builtin.provider.command.load.size_command": "Get Data Size Command",
"hex.builtin.provider.command.load.resize_command": "Resize Data Command",
"hex.builtin.provider.command.load.save_command": "Save Data Command",
"hex.builtin.provider.command.optional": "Optional",
"hex.builtin.provider.disk": "Raw Disk", "hex.builtin.provider.disk": "Raw Disk",
"hex.builtin.provider.disk.disk_size": "Disk Size", "hex.builtin.provider.disk.disk_size": "Disk Size",
"hex.builtin.provider.disk.elevation": "Accessing raw disks most likely requires elevated privileges", "hex.builtin.provider.disk.elevation": "Accessing raw disks most likely requires elevated privileges",
@ -430,6 +442,7 @@
"hex.builtin.provider.disk.error.read_rw": "Failed to open disk {} in read/write mode: {}", "hex.builtin.provider.disk.error.read_rw": "Failed to open disk {} in read/write mode: {}",
"hex.builtin.provider.file": "Regular File", "hex.builtin.provider.file": "Regular File",
"hex.builtin.provider.file.error.open": "Failed to open file {}: {}", "hex.builtin.provider.file.error.open": "Failed to open file {}: {}",
"hex.builtin.provider.file.error.already_open": "Same file is already open",
"hex.builtin.provider.file.access": "Last access time", "hex.builtin.provider.file.access": "Last access time",
"hex.builtin.provider.file.creation": "Creation time", "hex.builtin.provider.file.creation": "Creation time",
"hex.builtin.provider.file.menu.direct_access": "Direct access file", "hex.builtin.provider.file.menu.direct_access": "Direct access file",
@ -448,6 +461,7 @@
"hex.builtin.provider.gdb.name": "GDB Server <{0}:{1}>", "hex.builtin.provider.gdb.name": "GDB Server <{0}:{1}>",
"hex.builtin.provider.gdb.port": "Port", "hex.builtin.provider.gdb.port": "Port",
"hex.builtin.provider.gdb.server": "Server", "hex.builtin.provider.gdb.server": "Server",
"hex.builtin.provider.gdb.server.error.not_connected": "Failed to open connection to GDB Server",
"hex.builtin.provider.intel_hex": "Intel Hex File", "hex.builtin.provider.intel_hex": "Intel Hex File",
"hex.builtin.provider.intel_hex.name": "Intel Hex {0}", "hex.builtin.provider.intel_hex.name": "Intel Hex {0}",
"hex.builtin.provider.mem_file": "In-Memory File", "hex.builtin.provider.mem_file": "In-Memory File",
@ -458,6 +472,8 @@
"hex.builtin.provider.opening": "Opening Data Source...", "hex.builtin.provider.opening": "Opening Data Source...",
"hex.builtin.provider.process_memory": "Process Memory", "hex.builtin.provider.process_memory": "Process Memory",
"hex.builtin.provider.process_memory.enumeration_failed": "Failed to enumerate processes", "hex.builtin.provider.process_memory.enumeration_failed": "Failed to enumerate processes",
"hex.builtin.provider.process_memory.error.no_process_selected": "No process selected",
"hex.builtin.provider.process_memory.error.open_process": "Failed to attach to process",
"hex.builtin.provider.process_memory.macos_limitations": "macOS doesn't properly allow reading memory from other processes, even when running as root. If System Integrity Protection (SIP) is enabled, it only works for applications that are unsigned or have the 'Get Task Allow' entitlement which generally only applies to applications compiled by yourself.", "hex.builtin.provider.process_memory.macos_limitations": "macOS doesn't properly allow reading memory from other processes, even when running as root. If System Integrity Protection (SIP) is enabled, it only works for applications that are unsigned or have the 'Get Task Allow' entitlement which generally only applies to applications compiled by yourself.",
"hex.builtin.provider.process_memory.memory_regions": "Memory Regions", "hex.builtin.provider.process_memory.memory_regions": "Memory Regions",
"hex.builtin.provider.process_memory.name": "'{0}' Process Memory", "hex.builtin.provider.process_memory.name": "'{0}' Process Memory",
@ -476,6 +492,7 @@
"hex.builtin.provider.udp.port": "Server Port", "hex.builtin.provider.udp.port": "Server Port",
"hex.builtin.provider.udp.timestamp": "Timestamp", "hex.builtin.provider.udp.timestamp": "Timestamp",
"hex.builtin.provider.view": "View", "hex.builtin.provider.view": "View",
"hex.builtin.provider.view.error.no_provider": "No data source has been attached to this view",
"hex.builtin.setting.experiments": "Experiments", "hex.builtin.setting.experiments": "Experiments",
"hex.builtin.setting.experiments.description": "Experiments are features that are still in development and may not work correctly yet.\n\nFeel free to try them out and report any issues you encounter!", "hex.builtin.setting.experiments.description": "Experiments are features that are still in development and may not work correctly yet.\n\nFeel free to try them out and report any issues you encounter!",
"hex.builtin.setting.folders": "Folders", "hex.builtin.setting.folders": "Folders",
@ -483,12 +500,17 @@
"hex.builtin.setting.folders.description": "Specify additional search paths for patterns, scripts, Yara rules and more", "hex.builtin.setting.folders.description": "Specify additional search paths for patterns, scripts, Yara rules and more",
"hex.builtin.setting.folders.remove_folder": "Remove currently selected folder from list", "hex.builtin.setting.folders.remove_folder": "Remove currently selected folder from list",
"hex.builtin.setting.general": "General", "hex.builtin.setting.general": "General",
"hex.builtin.setting.general.backups": "Backups",
"hex.builtin.setting.general.backups.auto_backup_time": "Periodically backup project",
"hex.builtin.setting.general.backups.auto_backup_time.format.simple": "Every {0}s",
"hex.builtin.setting.general.backups.auto_backup_time.format.extended": "Every {0}m {1}s",
"hex.builtin.setting.general.backups.file_backup.enable": "Backup data sources before modification if possible",
"hex.builtin.setting.general.backups.file_backup.max_size": "Max file size for file backups",
"hex.builtin.setting.general.backups.file_backup.extension": "Backup file extension",
"hex.builtin.setting.general.patterns": "Patterns", "hex.builtin.setting.general.patterns": "Patterns",
"hex.builtin.setting.general.network": "Network", "hex.builtin.setting.general.network": "Network",
"hex.builtin.setting.general.auto_backup_time": "Periodically backup project", "hex.builtin.setting.general.auto_apply_patterns": "Auto-load supported pattern",
"hex.builtin.setting.general.auto_backup_time.format.simple": "Every {0}s", "hex.builtin.setting.general.suggest_patterns": "Suggest patterns based on loaded data",
"hex.builtin.setting.general.auto_backup_time.format.extended": "Every {0}m {1}s",
"hex.builtin.setting.general.auto_load_patterns": "Auto-load supported pattern",
"hex.builtin.setting.general.server_contact": "Enable update checks and usage statistics", "hex.builtin.setting.general.server_contact": "Enable update checks and usage statistics",
"hex.builtin.setting.general.max_mem_file_size": "Max file size to load into RAM", "hex.builtin.setting.general.max_mem_file_size": "Max file size to load into RAM",
"hex.builtin.setting.general.max_mem_file_size.desc": "Small files are loaded into memory to prevent them from being modified directly on disk.\n\nIncreasing this size allows larger files to be loaded into memory before ImHex resorts to streaming in data from disk.", "hex.builtin.setting.general.max_mem_file_size.desc": "Small files are loaded into memory to prevent them from being modified directly on disk.\n\nIncreasing this size allows larger files to be loaded into memory before ImHex resorts to streaming in data from disk.",
@ -750,6 +772,7 @@
"hex.builtin.view.data_inspector.table.value": "Value", "hex.builtin.view.data_inspector.table.value": "Value",
"hex.builtin.view.data_inspector.custom_row.title": "Adding custom rows", "hex.builtin.view.data_inspector.custom_row.title": "Adding custom rows",
"hex.builtin.view.data_inspector.custom_row.hint": "It's possible to define custom data inspector rows by placing pattern language scripts in the <ImHex>/scripts/inspectors folder.\n\nCheck the documentation for more information.", "hex.builtin.view.data_inspector.custom_row.hint": "It's possible to define custom data inspector rows by placing pattern language scripts in the <ImHex>/scripts/inspectors folder.\n\nCheck the documentation for more information.",
"hex.builtin.view.data_inspector.toggle_endianness": "Toggle Endianness",
"hex.builtin.view.data_processor.continuous_evaluation": "Continuous Evaluation", "hex.builtin.view.data_processor.continuous_evaluation": "Continuous Evaluation",
"hex.builtin.view.data_processor.help_text": "Right click to add a new node", "hex.builtin.view.data_processor.help_text": "Right click to add a new node",
"hex.builtin.view.data_processor.menu.file.load_processor": "Load data processor...", "hex.builtin.view.data_processor.menu.file.load_processor": "Load data processor...",
@ -1031,6 +1054,9 @@
"hex.builtin.view.pattern_data.virtual_files.no_virtual_files": "Visualize regions of data as a virtual folder structure by adding them using the hex::core::add_virtual_file function.", "hex.builtin.view.pattern_data.virtual_files.no_virtual_files": "Visualize regions of data as a virtual folder structure by adding them using the hex::core::add_virtual_file function.",
"hex.builtin.view.pattern_editor.no_env_vars": "The content of Environment Variables created here can be accessed from Pattern scripts using the std::env function.", "hex.builtin.view.pattern_editor.no_env_vars": "The content of Environment Variables created here can be accessed from Pattern scripts using the std::env function.",
"hex.builtin.view.pattern_editor.no_results": "no results", "hex.builtin.view.pattern_editor.no_results": "no results",
"hex.builtin.view.pattern_editor.match_case_tooltip": "Match Case Alt-C",
"hex.builtin.view.pattern_editor.whole_word_tooltip": "Whole Word Alt-W",
"hex.builtin.view.pattern_editor.regex_tooltip": "Regex Alt-R",
"hex.builtin.view.pattern_editor.of": "of", "hex.builtin.view.pattern_editor.of": "of",
"hex.builtin.view.pattern_editor.open_pattern": "Open pattern", "hex.builtin.view.pattern_editor.open_pattern": "Open pattern",
"hex.builtin.view.pattern_editor.replace_hint": "Replace", "hex.builtin.view.pattern_editor.replace_hint": "Replace",

View File

@ -443,10 +443,10 @@
"hex.builtin.setting.folders.description": "Especifica rutas de búsqueda adicionales para patterns, scripts, Yara Rules y más", "hex.builtin.setting.folders.description": "Especifica rutas de búsqueda adicionales para patterns, scripts, Yara Rules y más",
"hex.builtin.setting.folders.remove_folder": "Eliminar la carpeta seleccionada de la lista", "hex.builtin.setting.folders.remove_folder": "Eliminar la carpeta seleccionada de la lista",
"hex.builtin.setting.general": "General", "hex.builtin.setting.general": "General",
"hex.builtin.setting.general.auto_backup_time": "", "hex.builtin.setting.general.backups.auto_backup_time": "",
"hex.builtin.setting.general.auto_backup_time.format.extended": "", "hex.builtin.setting.general.backups.auto_backup_time.format.extended": "",
"hex.builtin.setting.general.auto_backup_time.format.simple": "", "hex.builtin.setting.general.backups.auto_backup_time.format.simple": "",
"hex.builtin.setting.general.auto_load_patterns": "Cargar automáticamente patterns soportados", "hex.builtin.setting.general.auto_apply_patterns": "Cargar automáticamente patterns soportados",
"hex.builtin.setting.general.network": "", "hex.builtin.setting.general.network": "",
"hex.builtin.setting.general.network_interface": "", "hex.builtin.setting.general.network_interface": "",
"hex.builtin.setting.general.patterns": "", "hex.builtin.setting.general.patterns": "",

View File

@ -464,10 +464,10 @@
"hex.builtin.setting.general": "Général", "hex.builtin.setting.general": "Général",
"hex.builtin.setting.general.patterns": "Modèles", "hex.builtin.setting.general.patterns": "Modèles",
"hex.builtin.setting.general.network": "Réseau", "hex.builtin.setting.general.network": "Réseau",
"hex.builtin.setting.general.auto_backup_time": "Sauvegarder périodiquement le projet", "hex.builtin.setting.general.backups.auto_backup_time": "Sauvegarder périodiquement le projet",
"hex.builtin.setting.general.auto_backup_time.format.simple": "Toutes les {0}s", "hex.builtin.setting.general.backups.auto_backup_time.format.simple": "Toutes les {0}s",
"hex.builtin.setting.general.auto_backup_time.format.extended": "Toutes les {0}m {1}s", "hex.builtin.setting.general.backups.auto_backup_time.format.extended": "Toutes les {0}m {1}s",
"hex.builtin.setting.general.auto_load_patterns": "Charger automatiquement les modèles pris en charge", "hex.builtin.setting.general.auto_apply_patterns": "Charger automatiquement les modèles pris en charge",
"hex.builtin.setting.general.server_contact": "Activer les vérifications de mise à jour et les statistiques d'utilisation", "hex.builtin.setting.general.server_contact": "Activer les vérifications de mise à jour et les statistiques d'utilisation",
"hex.builtin.setting.general.max_mem_file_size": "Taille maximale du fichier à charger en mémoire", "hex.builtin.setting.general.max_mem_file_size": "Taille maximale du fichier à charger en mémoire",
"hex.builtin.setting.general.max_mem_file_size.desc": "Les petits fichiers sont chargés en mémoire pour éviter qu'ils ne soient modifiés directement sur le disque.\n\nL'augmentation de cette taille permet de charger des fichiers plus volumineux en mémoire avqu'ImHex ne se mette à diffuser les données depuis le disque.", "hex.builtin.setting.general.max_mem_file_size.desc": "Les petits fichiers sont chargés en mémoire pour éviter qu'ils ne soient modifiés directement sur le disque.\n\nL'augmentation de cette taille permet de charger des fichiers plus volumineux en mémoire avqu'ImHex ne se mette à diffuser les données depuis le disque.",

View File

@ -438,10 +438,10 @@
"hex.builtin.setting.general": "Általános", "hex.builtin.setting.general": "Általános",
"hex.builtin.setting.general.patterns": "Sablonok", "hex.builtin.setting.general.patterns": "Sablonok",
"hex.builtin.setting.general.network": "Hálózat", "hex.builtin.setting.general.network": "Hálózat",
"hex.builtin.setting.general.auto_backup_time": "A projekt automatikus mentése időközönként", "hex.builtin.setting.general.backups.auto_backup_time": "A projekt automatikus mentése időközönként",
"hex.builtin.setting.general.auto_backup_time.format.simple": "Minden {0}mp", "hex.builtin.setting.general.backups.auto_backup_time.format.simple": "Minden {0}mp",
"hex.builtin.setting.general.auto_backup_time.format.extended": "Minden {0}p {1}mp", "hex.builtin.setting.general.backups.auto_backup_time.format.extended": "Minden {0}p {1}mp",
"hex.builtin.setting.general.auto_load_patterns": "Támogatott sablonok automatikus betöltése", "hex.builtin.setting.general.auto_apply_patterns": "Támogatott sablonok automatikus betöltése",
"hex.builtin.setting.general.server_contact": "Frissítések ellenőrzésének és használati statisztikák gyűjtésének engedélyezése", "hex.builtin.setting.general.server_contact": "Frissítések ellenőrzésének és használati statisztikák gyűjtésének engedélyezése",
"hex.builtin.setting.general.network_interface": "Hálózati interfész engedélyezése", "hex.builtin.setting.general.network_interface": "Hálózati interfész engedélyezése",
"hex.builtin.setting.general.save_recent_providers": "Nemrég használt források mentése", "hex.builtin.setting.general.save_recent_providers": "Nemrég használt források mentése",

View File

@ -443,10 +443,10 @@
"hex.builtin.setting.folders.description": "", "hex.builtin.setting.folders.description": "",
"hex.builtin.setting.folders.remove_folder": "", "hex.builtin.setting.folders.remove_folder": "",
"hex.builtin.setting.general": "Generali", "hex.builtin.setting.general": "Generali",
"hex.builtin.setting.general.auto_backup_time": "", "hex.builtin.setting.general.backups.auto_backup_time": "",
"hex.builtin.setting.general.auto_backup_time.format.extended": "", "hex.builtin.setting.general.backups.auto_backup_time.format.extended": "",
"hex.builtin.setting.general.auto_backup_time.format.simple": "", "hex.builtin.setting.general.backups.auto_backup_time.format.simple": "",
"hex.builtin.setting.general.auto_load_patterns": "Auto-caricamento del pattern supportato", "hex.builtin.setting.general.auto_apply_patterns": "Auto-caricamento del pattern supportato",
"hex.builtin.setting.general.network": "", "hex.builtin.setting.general.network": "",
"hex.builtin.setting.general.network_interface": "", "hex.builtin.setting.general.network_interface": "",
"hex.builtin.setting.general.patterns": "", "hex.builtin.setting.general.patterns": "",

View File

@ -443,10 +443,10 @@
"hex.builtin.setting.folders.description": "パターン、スクリプト、ルールなどのための検索パスを指定して追加できます。", "hex.builtin.setting.folders.description": "パターン、スクリプト、ルールなどのための検索パスを指定して追加できます。",
"hex.builtin.setting.folders.remove_folder": "選択中のフォルダをリストから消去", "hex.builtin.setting.folders.remove_folder": "選択中のフォルダをリストから消去",
"hex.builtin.setting.general": "基本", "hex.builtin.setting.general": "基本",
"hex.builtin.setting.general.auto_backup_time": "", "hex.builtin.setting.general.backups.auto_backup_time": "",
"hex.builtin.setting.general.auto_backup_time.format.extended": "", "hex.builtin.setting.general.backups.auto_backup_time.format.extended": "",
"hex.builtin.setting.general.auto_backup_time.format.simple": "", "hex.builtin.setting.general.backups.auto_backup_time.format.simple": "",
"hex.builtin.setting.general.auto_load_patterns": "対応するパターンを自動で読み込む", "hex.builtin.setting.general.auto_apply_patterns": "対応するパターンを自動で読み込む",
"hex.builtin.setting.general.network": "", "hex.builtin.setting.general.network": "",
"hex.builtin.setting.general.network_interface": "", "hex.builtin.setting.general.network_interface": "",
"hex.builtin.setting.general.patterns": "", "hex.builtin.setting.general.patterns": "",

View File

@ -443,10 +443,10 @@
"hex.builtin.setting.folders.description": "패턴, 스크립트, YARA 규칙 등에 대한 추가 검색 경로를 지정합니다", "hex.builtin.setting.folders.description": "패턴, 스크립트, YARA 규칙 등에 대한 추가 검색 경로를 지정합니다",
"hex.builtin.setting.folders.remove_folder": "목록에서 현재 선택된 폴더 제거", "hex.builtin.setting.folders.remove_folder": "목록에서 현재 선택된 폴더 제거",
"hex.builtin.setting.general": "일반", "hex.builtin.setting.general": "일반",
"hex.builtin.setting.general.auto_backup_time": "", "hex.builtin.setting.general.backups.auto_backup_time": "",
"hex.builtin.setting.general.auto_backup_time.format.extended": "", "hex.builtin.setting.general.backups.auto_backup_time.format.extended": "",
"hex.builtin.setting.general.auto_backup_time.format.simple": "", "hex.builtin.setting.general.backups.auto_backup_time.format.simple": "",
"hex.builtin.setting.general.auto_load_patterns": "지원하는 패턴 자동으로 불러오기", "hex.builtin.setting.general.auto_apply_patterns": "지원하는 패턴 자동으로 불러오기",
"hex.builtin.setting.general.network": "네트워크", "hex.builtin.setting.general.network": "네트워크",
"hex.builtin.setting.general.network_interface": "네트워크 인터페이스 사용", "hex.builtin.setting.general.network_interface": "네트워크 인터페이스 사용",
"hex.builtin.setting.general.patterns": "패턴", "hex.builtin.setting.general.patterns": "패턴",

View File

@ -465,10 +465,10 @@
"hex.builtin.setting.general": "Ogólne", "hex.builtin.setting.general": "Ogólne",
"hex.builtin.setting.general.patterns": "Pattern", "hex.builtin.setting.general.patterns": "Pattern",
"hex.builtin.setting.general.network": "Sieć", "hex.builtin.setting.general.network": "Sieć",
"hex.builtin.setting.general.auto_backup_time": "Okresowe tworzenie kopii zapasowej projektu", "hex.builtin.setting.general.backups.auto_backup_time": "Okresowe tworzenie kopii zapasowej projektu",
"hex.builtin.setting.general.auto_backup_time.format.simple": "Co {0}s", "hex.builtin.setting.general.backups.auto_backup_time.format.simple": "Co {0}s",
"hex.builtin.setting.general.auto_backup_time.format.extended": "Co {0}m {1}s", "hex.builtin.setting.general.backups.auto_backup_time.format.extended": "Co {0}m {1}s",
"hex.builtin.setting.general.auto_load_patterns": "Automatycznie wczytaj obsługiwany pattern", "hex.builtin.setting.general.auto_apply_patterns": "Automatycznie wczytaj obsługiwany pattern",
"hex.builtin.setting.general.server_contact": "Włącz sprawdzanie aktualizacji i statystyki użytkowania", "hex.builtin.setting.general.server_contact": "Włącz sprawdzanie aktualizacji i statystyki użytkowania",
"hex.builtin.setting.general.max_mem_file_size": "Maksymalny rozmiar pliku do wczytania do RAM", "hex.builtin.setting.general.max_mem_file_size": "Maksymalny rozmiar pliku do wczytania do RAM",
"hex.builtin.setting.general.max_mem_file_size.desc": "Małe pliki są wczytywane do pamięci aby zapobiec ich bezpośredniej modyfikacji na dysku.\n\nZwiększenie tego rozmiaru pozwala większym plikom być wczytanym do pamięci zanim ImHex ucieknie się do strumieniowania danych z dysku.", "hex.builtin.setting.general.max_mem_file_size.desc": "Małe pliki są wczytywane do pamięci aby zapobiec ich bezpośredniej modyfikacji na dysku.\n\nZwiększenie tego rozmiaru pozwala większym plikom być wczytanym do pamięci zanim ImHex ucieknie się do strumieniowania danych z dysku.",

View File

@ -443,10 +443,10 @@
"hex.builtin.setting.folders.description": "Especifique caminhos de pesquisa adicionais para padrões, scripts, regras Yara e muito mais", "hex.builtin.setting.folders.description": "Especifique caminhos de pesquisa adicionais para padrões, scripts, regras Yara e muito mais",
"hex.builtin.setting.folders.remove_folder": "Remover a pasta atualmente selecionada da lista", "hex.builtin.setting.folders.remove_folder": "Remover a pasta atualmente selecionada da lista",
"hex.builtin.setting.general": "General", "hex.builtin.setting.general": "General",
"hex.builtin.setting.general.auto_backup_time": "", "hex.builtin.setting.general.backups.auto_backup_time": "",
"hex.builtin.setting.general.auto_backup_time.format.extended": "", "hex.builtin.setting.general.backups.auto_backup_time.format.extended": "",
"hex.builtin.setting.general.auto_backup_time.format.simple": "", "hex.builtin.setting.general.backups.auto_backup_time.format.simple": "",
"hex.builtin.setting.general.auto_load_patterns": "Padrão compatível com carregamento automático", "hex.builtin.setting.general.auto_apply_patterns": "Padrão compatível com carregamento automático",
"hex.builtin.setting.general.network": "", "hex.builtin.setting.general.network": "",
"hex.builtin.setting.general.network_interface": "", "hex.builtin.setting.general.network_interface": "",
"hex.builtin.setting.general.patterns": "", "hex.builtin.setting.general.patterns": "",

View File

@ -453,10 +453,10 @@
"hex.builtin.setting.general": "Основное", "hex.builtin.setting.general": "Основное",
"hex.builtin.setting.general.patterns": "Шаблоны", "hex.builtin.setting.general.patterns": "Шаблоны",
"hex.builtin.setting.general.network": "Сеть", "hex.builtin.setting.general.network": "Сеть",
"hex.builtin.setting.general.auto_backup_time": "Делать резервные копии каждые", "hex.builtin.setting.general.backups.auto_backup_time": "Делать резервные копии каждые",
"hex.builtin.setting.general.auto_backup_time.format.simple": "{0} секунд", "hex.builtin.setting.general.backups.auto_backup_time.format.simple": "{0} секунд",
"hex.builtin.setting.general.auto_backup_time.format.extended": "{0} минут {1} секунд", "hex.builtin.setting.general.backups.auto_backup_time.format.extended": "{0} минут {1} секунд",
"hex.builtin.setting.general.auto_load_patterns": "Автоматически подгружать распознанные шаблоны", "hex.builtin.setting.general.auto_apply_patterns": "Автоматически подгружать распознанные шаблоны",
"hex.builtin.setting.general.server_contact": "Включить проверку обновлений и статистики использования", "hex.builtin.setting.general.server_contact": "Включить проверку обновлений и статистики использования",
"hex.builtin.setting.general.max_mem_file_size": "Макс. размер файла для сохранения в RAM", "hex.builtin.setting.general.max_mem_file_size": "Макс. размер файла для сохранения в RAM",
"hex.builtin.setting.general.max_mem_file_size.desc": "Маленькие файлы загружаются в оперативную память, чтобы не сохранять изменения сразу на диск.\n\nУвеличение этого параметра позволит ImHex загружать более объёмные файлы в память.", "hex.builtin.setting.general.max_mem_file_size.desc": "Маленькие файлы загружаются в оперативную память, чтобы не сохранять изменения сразу на диск.\n\nУвеличение этого параметра позволит ImHex загружать более объёмные файлы в память.",

View File

@ -423,9 +423,9 @@
"hex.builtin.setting.folders.remove_folder": "Видалити поточну вибрану папку зі списку", "hex.builtin.setting.folders.remove_folder": "Видалити поточну вибрану папку зі списку",
"hex.builtin.setting.general": "Основне", "hex.builtin.setting.general": "Основне",
"hex.builtin.setting.general.patterns": "Шаблони", "hex.builtin.setting.general.patterns": "Шаблони",
"hex.builtin.setting.general.auto_backup_time.format.simple": "кожні {0} секунд", "hex.builtin.setting.general.backups.auto_backup_time.format.simple": "кожні {0} секунд",
"hex.builtin.setting.general.auto_backup_time.format.extended": "Кожні {0} хвилин {1} секунд", "hex.builtin.setting.general.backups.auto_backup_time.format.extended": "Кожні {0} хвилин {1} секунд",
"hex.builtin.setting.general.auto_load_patterns": "Автоматично завантажувати розпізнані шаблони", "hex.builtin.setting.general.auto_apply_patterns": "Автоматично завантажувати розпізнані шаблони",
"hex.builtin.setting.general.server_contact": "Увімкнути перевірку оновлень та статистику використання", "hex.builtin.setting.general.server_contact": "Увімкнути перевірку оновлень та статистику використання",
"hex.builtin.setting.general.network_interface": "Увімкнути мережевий інтерфейс", "hex.builtin.setting.general.network_interface": "Увімкнути мережевий інтерфейс",
"hex.builtin.setting.general.pattern_data_max_filter_items": "Максимальна кількість відфільтрованих елементів шаблону", "hex.builtin.setting.general.pattern_data_max_filter_items": "Максимальна кількість відфільтрованих елементів шаблону",
@ -585,7 +585,7 @@
"hex.builtin.provider.process_memory.macos_limitations": "macOS не дозволяє належним чином зчитувати пам'ять з інших процесів, навіть під час роботи як root. Якщо ввімкнено захист цілісності системи (SIP), він працює лише для програм, які не підписані або мають право \"Отримати дозвіл на завдання\", яке зазвичай застосовується лише до програм, скомпільованих вами самостійно.", "hex.builtin.provider.process_memory.macos_limitations": "macOS не дозволяє належним чином зчитувати пам'ять з інших процесів, навіть під час роботи як root. Якщо ввімкнено захист цілісності системи (SIP), він працює лише для програм, які не підписані або мають право \"Отримати дозвіл на завдання\", яке зазвичай застосовується лише до програм, скомпільованих вами самостійно.",
"hex.builtin.setting.experiments.description": "Експерименти — це функції, які ще знаходяться в стадії розробки і можуть працювати некоректно.\n\nНе соромтеся їх випробовувати та повідомляти про будь-які проблеми, з якими ви стикаєтеся!", "hex.builtin.setting.experiments.description": "Експерименти — це функції, які ще знаходяться в стадії розробки і можуть працювати некоректно.\n\nНе соромтеся їх випробовувати та повідомляти про будь-які проблеми, з якими ви стикаєтеся!",
"hex.builtin.setting.general.network": "Мережа", "hex.builtin.setting.general.network": "Мережа",
"hex.builtin.setting.general.auto_backup_time": "Робити резервні копії проекту", "hex.builtin.setting.general.backups.auto_backup_time": "Робити резервні копії проекту",
"hex.builtin.setting.general.max_mem_file_size": "Максимальний розмір файлу для завантаження в RAM", "hex.builtin.setting.general.max_mem_file_size": "Максимальний розмір файлу для завантаження в RAM",
"hex.builtin.setting.general.max_mem_file_size.desc": "Невеликі файли завантажуються в пам'ять, щоб запобігти їх безпосередній модифікації на диску.\n\nЗбільшення цього розміру дозволяє завантажувати в пам'ять більші файли, перш ніж ImHex вдається до потокової передачі даних із диску.", "hex.builtin.setting.general.max_mem_file_size.desc": "Невеликі файли завантажуються в пам'ять, щоб запобігти їх безпосередній модифікації на диску.\n\nЗбільшення цього розміру дозволяє завантажувати в пам'ять більші файли, перш ніж ImHex вдається до потокової передачі даних із диску.",
"hex.builtin.setting.general.sync_pattern_source": "Синхронізація вихідного коду шаблону між відкритими джерелами даних", "hex.builtin.setting.general.sync_pattern_source": "Синхронізація вихідного коду шаблону між відкритими джерелами даних",

View File

@ -467,10 +467,10 @@
"hex.builtin.setting.general": "通用", "hex.builtin.setting.general": "通用",
"hex.builtin.setting.general.patterns": "模式", "hex.builtin.setting.general.patterns": "模式",
"hex.builtin.setting.general.network": "网络", "hex.builtin.setting.general.network": "网络",
"hex.builtin.setting.general.auto_backup_time": "定期备份项目", "hex.builtin.setting.general.backups.auto_backup_time": "定期备份项目",
"hex.builtin.setting.general.auto_backup_time.format.simple": "每 {0}秒", "hex.builtin.setting.general.backups.auto_backup_time.format.simple": "每 {0}秒",
"hex.builtin.setting.general.auto_backup_time.format.extended": "每 {0}分 {1}秒", "hex.builtin.setting.general.backups.auto_backup_time.format.extended": "每 {0}分 {1}秒",
"hex.builtin.setting.general.auto_load_patterns": "自动加载支持的模式", "hex.builtin.setting.general.auto_apply_patterns": "自动加载支持的模式",
"hex.builtin.setting.general.server_contact": "启用更新检查和使用统计", "hex.builtin.setting.general.server_contact": "启用更新检查和使用统计",
"hex.builtin.setting.general.max_mem_file_size": "要加载到内存中的文件的最大大小", "hex.builtin.setting.general.max_mem_file_size": "要加载到内存中的文件的最大大小",
"hex.builtin.setting.general.max_mem_file_size.desc": "小文件会被加载到内存中,以防止直接在磁盘上修改它们。\n\n增大这个大小可以让更大的文件在ImHex从磁盘读取数据之前被加载到内存中。", "hex.builtin.setting.general.max_mem_file_size.desc": "小文件会被加载到内存中,以防止直接在磁盘上修改它们。\n\n增大这个大小可以让更大的文件在ImHex从磁盘读取数据之前被加载到内存中。",

View File

@ -443,10 +443,10 @@
"hex.builtin.setting.folders.description": "Specify additional search paths for patterns, scripts, Yara rules and more", "hex.builtin.setting.folders.description": "Specify additional search paths for patterns, scripts, Yara rules and more",
"hex.builtin.setting.folders.remove_folder": "從列表中移除目前選擇的資料夾", "hex.builtin.setting.folders.remove_folder": "從列表中移除目前選擇的資料夾",
"hex.builtin.setting.general": "一般", "hex.builtin.setting.general": "一般",
"hex.builtin.setting.general.auto_backup_time": "", "hex.builtin.setting.general.backups.auto_backup_time": "",
"hex.builtin.setting.general.auto_backup_time.format.extended": "", "hex.builtin.setting.general.backups.auto_backup_time.format.extended": "",
"hex.builtin.setting.general.auto_backup_time.format.simple": "", "hex.builtin.setting.general.backups.auto_backup_time.format.simple": "",
"hex.builtin.setting.general.auto_load_patterns": "自動載入支援的模式", "hex.builtin.setting.general.auto_apply_patterns": "自動載入支援的模式",
"hex.builtin.setting.general.network": "", "hex.builtin.setting.general.network": "",
"hex.builtin.setting.general.network_interface": "啟用網路介面", "hex.builtin.setting.general.network_interface": "啟用網路介面",
"hex.builtin.setting.general.patterns": "", "hex.builtin.setting.general.patterns": "",

View File

@ -17,6 +17,8 @@
#include <fmt/chrono.h> #include <fmt/chrono.h>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include <romfs/romfs.hpp>
#include <toasts/toast_notification.hpp>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
@ -103,6 +105,16 @@ namespace hex::plugin::builtin {
std::this_thread::sleep_for(std::chrono::seconds(1)); std::this_thread::sleep_for(std::chrono::seconds(1));
} }
void handleMCPServer() {
if (!ContentRegistry::MCP::isEnabled()) {
std::this_thread::sleep_for(std::chrono::milliseconds(100));
ContentRegistry::MCP::impl::getMcpServerInstance().disconnect();
return;
}
ContentRegistry::MCP::impl::getMcpServerInstance().listen();
}
} }
void registerBackgroundServices() { void registerBackgroundServices() {
@ -110,12 +122,17 @@ namespace hex::plugin::builtin {
s_networkInterfaceServiceEnabled = value.get<bool>(false); s_networkInterfaceServiceEnabled = value.get<bool>(false);
}); });
ContentRegistry::Settings::onChange("hex.builtin.setting.general", "hex.builtin.setting.general.auto_backup_time", [](const ContentRegistry::Settings::SettingsValue &value) { ContentRegistry::Settings::onChange("hex.builtin.setting.general", "hex.builtin.setting.general.mcp_server", [](const ContentRegistry::Settings::SettingsValue &value) {
ContentRegistry::MCP::impl::setEnabled(value.get<bool>(false));
});
ContentRegistry::Settings::onChange("hex.builtin.setting.general", "hex.builtin.setting.general.backups.auto_backup_time", [](const ContentRegistry::Settings::SettingsValue &value) {
s_autoBackupTime = value.get<int>(0) * 30; s_autoBackupTime = value.get<int>(0) * 30;
}); });
ContentRegistry::BackgroundServices::registerService("hex.builtin.background_service.network_interface", handleNetworkInterfaceService); ContentRegistry::BackgroundServices::registerService("hex.builtin.background_service.network_interface", handleNetworkInterfaceService);
ContentRegistry::BackgroundServices::registerService("hex.builtin.background_service.auto_backup", handleAutoBackup); ContentRegistry::BackgroundServices::registerService("hex.builtin.background_service.auto_backup", handleAutoBackup);
ContentRegistry::BackgroundServices::registerService("hex.builtin.background_service.mcp", handleMCPServer);
EventProviderDirtied::subscribe([](prv::Provider *) { EventProviderDirtied::subscribe([](prv::Provider *) {
s_dataDirty = true; s_dataDirty = true;

View File

@ -1,4 +1,6 @@
#include <iostream>
#include <content/command_line_interface.hpp> #include <content/command_line_interface.hpp>
#include <hex/mcp/client.hpp>
#include <hex/api/imhex_api/system.hpp> #include <hex/api/imhex_api/system.hpp>
#include <hex/api/imhex_api/hex_editor.hpp> #include <hex/api/imhex_api/hex_editor.hpp>
@ -358,10 +360,10 @@ namespace hex::plugin::builtin {
std::fs::path filePath = reinterpret_cast<const char8_t*>(args[0].data()); std::fs::path filePath = reinterpret_cast<const char8_t*>(args[0].data());
FileProvider provider; FileProvider provider;
provider.setPath(filePath); provider.setPath(filePath);
if (!provider.open()) { auto result = provider.open();
log::println("Failed to open file '{}'", args[0]); if (result.isFailure()) {
log::println("Failed to open file '{}': {}", args[0], result.getErrorMessage());
std::exit(EXIT_FAILURE); std::exit(EXIT_FAILURE);
} }
@ -530,6 +532,14 @@ namespace hex::plugin::builtin {
ContentRegistry::Views::setFullScreenView<ViewFullScreenFileInfo>(path); ContentRegistry::Views::setFullScreenView<ViewFullScreenFileInfo>(path);
} }
void handleMCPCommand(const std::vector<std::string> &) {
mcp::Client client;
auto result = client.run(std::cin, std::cout);
std::fprintf(stderr, "MCP Client disconnected!\n");
std::exit(result);
}
void registerCommandForwarders() { void registerCommandForwarders() {
hex::subcommands::registerSubCommand("open", [](const std::vector<std::string> &args){ hex::subcommands::registerSubCommand("open", [](const std::vector<std::string> &args){

View File

@ -287,23 +287,23 @@ namespace hex::plugin::builtin {
"@", "@",
"hex.builtin.command.goto.desc", "hex.builtin.command.goto.desc",
[](auto input) { [](auto input) {
wolv::math_eval::MathEvaluator<long double> evaluator; wolv::math_eval::MathEvaluator<i64> evaluator;
evaluator.registerStandardVariables(); evaluator.registerStandardVariables();
evaluator.registerStandardFunctions(); evaluator.registerStandardFunctions();
std::optional<long double> result = evaluator.evaluate(input); const auto result = evaluator.evaluate(input);
if (result.has_value()) if (result.has_value())
return fmt::format("hex.builtin.command.goto.result"_lang, result.value()); return fmt::format("hex.builtin.command.goto.result"_lang, static_cast<u64>(result.value()));
else if (evaluator.hasError()) else if (evaluator.hasError())
return fmt::format("Error: {}", *evaluator.getLastError()); return fmt::format("Error: {}", *evaluator.getLastError());
else else
return std::string("???"); return std::string("???");
}, [](auto input) -> std::optional<std::string> { }, [](auto input) -> std::optional<std::string> {
wolv::math_eval::MathEvaluator<long double> evaluator; wolv::math_eval::MathEvaluator<i64> evaluator;
evaluator.registerStandardVariables(); evaluator.registerStandardVariables();
evaluator.registerStandardFunctions(); evaluator.registerStandardFunctions();
std::optional<long double> result = evaluator.evaluate(input); const auto result = evaluator.evaluate(input);
if (result.has_value()) { if (result.has_value()) {
ImHexApi::HexEditor::setSelection(result.value(), 1); ImHexApi::HexEditor::setSelection(result.value(), 1);
} }

View File

@ -33,7 +33,8 @@ namespace hex::plugin::builtin {
}; };
template<std::unsigned_integral T, size_t Size = sizeof(T)> template<std::unsigned_integral T, size_t Size = sizeof(T)>
static std::vector<u8> stringToUnsigned(const std::string &value, std::endian endian) requires(sizeof(T) <= sizeof(u64)) { static ContentRegistry::DataInspector::impl::EditingFunction stringToUnsigned() requires(sizeof(T) <= sizeof(u64)) {
return ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
const auto result = wolv::util::from_chars<u64>(value).value_or(0); const auto result = wolv::util::from_chars<u64>(value).value_or(0);
if (result > std::numeric_limits<T>::max()) return {}; if (result > std::numeric_limits<T>::max()) return {};
@ -44,10 +45,12 @@ namespace hex::plugin::builtin {
std::reverse(bytes.begin(), bytes.end()); std::reverse(bytes.begin(), bytes.end());
return bytes; return bytes;
});
} }
template<std::signed_integral T, size_t Size = sizeof(T)> template<std::signed_integral T, size_t Size = sizeof(T)>
static std::vector<u8> stringToSigned(const std::string &value, std::endian endian) requires(sizeof(T) <= sizeof(u64)) { static ContentRegistry::DataInspector::impl::EditingFunction stringToSigned() requires(sizeof(T) <= sizeof(u64)) {
return ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
const auto result = wolv::util::from_chars<i64>(value).value_or(0); const auto result = wolv::util::from_chars<i64>(value).value_or(0);
if (result > std::numeric_limits<T>::max() || result < std::numeric_limits<T>::min()) return {}; if (result > std::numeric_limits<T>::max() || result < std::numeric_limits<T>::min()) return {};
@ -58,10 +61,12 @@ namespace hex::plugin::builtin {
std::reverse(bytes.begin(), bytes.end()); std::reverse(bytes.begin(), bytes.end());
return bytes; return bytes;
});
} }
template<std::floating_point T> template<std::floating_point T>
static std::vector<u8> stringToFloat(const std::string &value, std::endian endian) requires(sizeof(T) <= sizeof(long double)) { static ContentRegistry::DataInspector::impl::EditingFunction stringToFloat() requires(sizeof(T) <= sizeof(long double)) {
return ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
const T result = wolv::util::from_chars<double>(value).value_or(0); const T result = wolv::util::from_chars<double>(value).value_or(0);
std::vector<u8> bytes(sizeof(T), 0x00); std::vector<u8> bytes(sizeof(T), 0x00);
@ -71,16 +76,17 @@ namespace hex::plugin::builtin {
std::reverse(bytes.begin(), bytes.end()); std::reverse(bytes.begin(), bytes.end());
return bytes; return bytes;
});
} }
template<std::integral T, size_t Size = sizeof(T)> template<std::integral T, size_t Size = sizeof(T)>
static std::vector<u8> stringToInteger(const std::string &value, std::endian endian) requires(sizeof(T) <= sizeof(u64)) { static ContentRegistry::DataInspector::impl::EditingFunction stringToInteger() requires(sizeof(T) <= sizeof(u64)) {
if constexpr (std::unsigned_integral<T>) if constexpr (std::unsigned_integral<T>)
return stringToUnsigned<T, Size>(value, endian); return stringToUnsigned<T, Size>();
else if constexpr (std::signed_integral<T>) else if constexpr (std::signed_integral<T>)
return stringToSigned<T, Size>(value, endian); return stringToSigned<T, Size>();
else else
return {}; static_assert("Unsupported type for stringToInteger");
} }
template<std::unsigned_integral T, size_t Size = sizeof(T)> template<std::unsigned_integral T, size_t Size = sizeof(T)>
@ -154,7 +160,8 @@ namespace hex::plugin::builtin {
ImGui::TextUnformatted(binary.c_str()); ImGui::TextUnformatted(binary.c_str());
return binary; return binary;
}; };
}, [](const std::string &value, std::endian endian) -> std::vector<u8> { },
ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::ignore = endian; std::ignore = endian;
std::string binary = value; std::string binary = value;
@ -167,69 +174,69 @@ namespace hex::plugin::builtin {
return { result.value() }; return { result.value() };
else else
return { }; return { };
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.u8", sizeof(u8), ContentRegistry::DataInspector::add("hex.builtin.inspector.u8", sizeof(u8),
drawString<u8>(integerToString<u8>), drawString<u8>(integerToString<u8>),
stringToInteger<u8> stringToInteger<u8>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.i8", sizeof(i8), ContentRegistry::DataInspector::add("hex.builtin.inspector.i8", sizeof(i8),
drawString<i8>(integerToString<i8>), drawString<i8>(integerToString<i8>),
stringToInteger<i8> stringToInteger<i8>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.u16", sizeof(u16), ContentRegistry::DataInspector::add("hex.builtin.inspector.u16", sizeof(u16),
drawString<u16>(integerToString<u16>), drawString<u16>(integerToString<u16>),
stringToInteger<u16> stringToInteger<u16>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.i16", sizeof(i16), ContentRegistry::DataInspector::add("hex.builtin.inspector.i16", sizeof(i16),
drawString<i16>(integerToString<i16>), drawString<i16>(integerToString<i16>),
stringToInteger<i16> stringToInteger<i16>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.u24", 3, ContentRegistry::DataInspector::add("hex.builtin.inspector.u24", 3,
drawString<u32, 3>(integerToString<u32, 3>), drawString<u32, 3>(integerToString<u32, 3>),
stringToInteger<u32, 3> stringToInteger<u32, 3>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.i24", 3, ContentRegistry::DataInspector::add("hex.builtin.inspector.i24", 3,
drawString<i32, 3>(integerToString<i32, 3>), drawString<i32, 3>(integerToString<i32, 3>),
stringToInteger<i32, 3> stringToInteger<i32, 3>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.u32", sizeof(u32), ContentRegistry::DataInspector::add("hex.builtin.inspector.u32", sizeof(u32),
drawString<u32>(integerToString<u32>), drawString<u32>(integerToString<u32>),
stringToInteger<u32> stringToInteger<u32>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.i32", sizeof(i32), ContentRegistry::DataInspector::add("hex.builtin.inspector.i32", sizeof(i32),
drawString<i32>(integerToString<i32>), drawString<i32>(integerToString<i32>),
stringToInteger<i32> stringToInteger<i32>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.u48", 6, ContentRegistry::DataInspector::add("hex.builtin.inspector.u48", 6,
drawString<u64, 6>(integerToString<u64, 6>), drawString<u64, 6>(integerToString<u64, 6>),
stringToInteger<u64, 6> stringToInteger<u64, 6>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.i48", 6, ContentRegistry::DataInspector::add("hex.builtin.inspector.i48", 6,
drawString<i64, 6>(integerToString<i64, 6>), drawString<i64, 6>(integerToString<i64, 6>),
stringToInteger<i64, 6> stringToInteger<i64, 6>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.u64", sizeof(u64), ContentRegistry::DataInspector::add("hex.builtin.inspector.u64", sizeof(u64),
drawString<u64>(integerToString<u64>), drawString<u64>(integerToString<u64>),
stringToInteger<u64> stringToInteger<u64>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.i64", sizeof(i64), ContentRegistry::DataInspector::add("hex.builtin.inspector.i64", sizeof(i64),
drawString<i64>(integerToString<i64>), drawString<i64>(integerToString<i64>),
stringToInteger<i64> stringToInteger<i64>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.float16", sizeof(u16), ContentRegistry::DataInspector::add("hex.builtin.inspector.float16", sizeof(u16),
@ -255,7 +262,7 @@ namespace hex::plugin::builtin {
auto value = fmt::format(fmt::runtime(formatString), hex::changeEndianness(result, endian)); auto value = fmt::format(fmt::runtime(formatString), hex::changeEndianness(result, endian));
return [value] { ImGui::TextUnformatted(value.c_str()); return value; }; return [value] { ImGui::TextUnformatted(value.c_str()); return value; };
}, },
stringToFloat<float> stringToFloat<float>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.double", sizeof(double), ContentRegistry::DataInspector::add("hex.builtin.inspector.double", sizeof(double),
@ -268,7 +275,7 @@ namespace hex::plugin::builtin {
auto value = fmt::format(fmt::runtime(formatString), hex::changeEndianness(result, endian)); auto value = fmt::format(fmt::runtime(formatString), hex::changeEndianness(result, endian));
return [value] { ImGui::TextUnformatted(value.c_str()); return value; }; return [value] { ImGui::TextUnformatted(value.c_str()); return value; };
}, },
stringToFloat<double> stringToFloat<double>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.long_double", sizeof(long double), ContentRegistry::DataInspector::add("hex.builtin.inspector.long_double", sizeof(long double),
@ -281,7 +288,7 @@ namespace hex::plugin::builtin {
auto value = fmt::format(fmt::runtime(formatString), hex::changeEndianness(result, endian)); auto value = fmt::format(fmt::runtime(formatString), hex::changeEndianness(result, endian));
return [value] { ImGui::TextUnformatted(value.c_str()); return value; }; return [value] { ImGui::TextUnformatted(value.c_str()); return value; };
}, },
stringToFloat<long double> stringToFloat<long double>()
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.bfloat16", sizeof(u16), ContentRegistry::DataInspector::add("hex.builtin.inspector.bfloat16", sizeof(u16),
@ -359,11 +366,11 @@ namespace hex::plugin::builtin {
return [value] { ImGui::TextUnformatted(value.c_str()); return value; }; return [value] { ImGui::TextUnformatted(value.c_str()); return value; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::ignore = endian; std::ignore = endian;
return hex::crypt::encodeSleb128(wolv::util::from_chars<i64>(value).value_or(0)); return hex::crypt::encodeSleb128(wolv::util::from_chars<i64>(value).value_or(0));
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.uleb128", 1, (sizeof(u128) * 8 / 7) + 1, ContentRegistry::DataInspector::add("hex.builtin.inspector.uleb128", 1, (sizeof(u128) * 8 / 7) + 1,
@ -376,11 +383,11 @@ namespace hex::plugin::builtin {
return [value] { ImGui::TextUnformatted(value.c_str()); return value; }; return [value] { ImGui::TextUnformatted(value.c_str()); return value; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::ignore = endian; std::ignore = endian;
return hex::crypt::encodeUleb128(wolv::util::from_chars<u64>(value).value_or(0)); return hex::crypt::encodeUleb128(wolv::util::from_chars<u64>(value).value_or(0));
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.bool", sizeof(bool), ContentRegistry::DataInspector::add("hex.builtin.inspector.bool", sizeof(bool),
@ -411,13 +418,13 @@ namespace hex::plugin::builtin {
auto value = makePrintable(*reinterpret_cast<char8_t *>(buffer.data())); auto value = makePrintable(*reinterpret_cast<char8_t *>(buffer.data()));
return [value] { ImGuiExt::TextFormatted("'{0}'", value.c_str()); return value; }; return [value] { ImGuiExt::TextFormatted("'{0}'", value.c_str()); return value; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::ignore = endian; std::ignore = endian;
if (value.length() > 1) return { }; if (value.length() > 1) return { };
return { u8(value[0]) }; return { u8(value[0]) };
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.wide", sizeof(wchar_t), ContentRegistry::DataInspector::add("hex.builtin.inspector.wide", sizeof(wchar_t),
@ -432,7 +439,7 @@ namespace hex::plugin::builtin {
auto value = fmt::format("{0}", c <= 255 ? makePrintable(c) : wolv::util::wstringToUtf8(std::wstring(&c, 1)).value_or("???")); auto value = fmt::format("{0}", c <= 255 ? makePrintable(c) : wolv::util::wstringToUtf8(std::wstring(&c, 1)).value_or("???"));
return [value] { ImGuiExt::TextFormatted("L'{0}'", value.c_str()); return value; }; return [value] { ImGuiExt::TextFormatted("L'{0}'", value.c_str()); return value; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::vector<u8> bytes; std::vector<u8> bytes;
auto wideString = wolv::util::utf8ToWstring(value); auto wideString = wolv::util::utf8ToWstring(value);
if (!wideString.has_value()) if (!wideString.has_value())
@ -445,7 +452,7 @@ namespace hex::plugin::builtin {
std::reverse(bytes.begin(), bytes.end()); std::reverse(bytes.begin(), bytes.end());
return bytes; return bytes;
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.char16", sizeof(char16_t), ContentRegistry::DataInspector::add("hex.builtin.inspector.char16", sizeof(char16_t),
@ -460,7 +467,7 @@ namespace hex::plugin::builtin {
auto value = fmt::format("{0}", c <= 255 ? makePrintable(c) : wolv::util::utf16ToUtf8(std::u16string(&c, 1)).value_or("???")); auto value = fmt::format("{0}", c <= 255 ? makePrintable(c) : wolv::util::utf16ToUtf8(std::u16string(&c, 1)).value_or("???"));
return [value] { ImGuiExt::TextFormatted("u'{0}'", value.c_str()); return value; }; return [value] { ImGuiExt::TextFormatted("u'{0}'", value.c_str()); return value; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::vector<u8> bytes; std::vector<u8> bytes;
auto wideString = wolv::util::utf8ToUtf16(value); auto wideString = wolv::util::utf8ToUtf16(value);
if (!wideString.has_value()) if (!wideString.has_value())
@ -473,7 +480,7 @@ namespace hex::plugin::builtin {
std::reverse(bytes.begin(), bytes.end()); std::reverse(bytes.begin(), bytes.end());
return bytes; return bytes;
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.char32", sizeof(char32_t), ContentRegistry::DataInspector::add("hex.builtin.inspector.char32", sizeof(char32_t),
@ -488,7 +495,7 @@ namespace hex::plugin::builtin {
auto value = fmt::format("{0}", c <= 255 ? makePrintable(c) : wolv::util::utf32ToUtf8(std::u32string(&c, 1)).value_or("???")); auto value = fmt::format("{0}", c <= 255 ? makePrintable(c) : wolv::util::utf32ToUtf8(std::u32string(&c, 1)).value_or("???"));
return [value] { ImGuiExt::TextFormatted("U'{0}'", value.c_str()); return value; }; return [value] { ImGuiExt::TextFormatted("U'{0}'", value.c_str()); return value; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::vector<u8> bytes; std::vector<u8> bytes;
auto wideString = wolv::util::utf8ToUtf32(value); auto wideString = wolv::util::utf8ToUtf32(value);
if (!wideString.has_value()) if (!wideString.has_value())
@ -501,7 +508,7 @@ namespace hex::plugin::builtin {
std::reverse(bytes.begin(), bytes.end()); std::reverse(bytes.begin(), bytes.end());
return bytes; return bytes;
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.utf8", sizeof(char8_t) * 4, ContentRegistry::DataInspector::add("hex.builtin.inspector.utf8", sizeof(char8_t) * 4,
@ -551,11 +558,11 @@ namespace hex::plugin::builtin {
return [value, copyValue] { ImGuiExt::TextFormatted("\"{0}\"", value.c_str()); return copyValue; }; return [value, copyValue] { ImGuiExt::TextFormatted("\"{0}\"", value.c_str()); return copyValue; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::ignore = endian; std::ignore = endian;
return hex::decodeByteString(value); return hex::decodeByteString(value);
} })
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.wstring", sizeof(wchar_t), ContentRegistry::DataInspector::add("hex.builtin.inspector.wstring", sizeof(wchar_t),
@ -588,11 +595,20 @@ namespace hex::plugin::builtin {
return [value, copyValue] { ImGuiExt::TextFormatted("L\"{0}\"", value.c_str()); return copyValue; }; return [value, copyValue] { ImGuiExt::TextFormatted("L\"{0}\"", value.c_str()); return copyValue; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::ignore = endian; auto utf8 = hex::decodeByteString(value);
auto wstring = wolv::util::utf8ToWstring({ utf8.begin(), utf8.end() });
if (!wstring.has_value())
return {};
return hex::decodeByteString(value); for (auto &c : wstring.value()) {
c = hex::changeEndianness(c, endian);
} }
std::vector<u8> bytes(wstring->size() * sizeof(wchar_t), 0x00);
std::memcpy(bytes.data(), wstring->data(), bytes.size());
return bytes;
})
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.string16", sizeof(char16_t), ContentRegistry::DataInspector::add("hex.builtin.inspector.string16", sizeof(char16_t),
@ -625,11 +641,20 @@ namespace hex::plugin::builtin {
return [value, copyValue] { ImGuiExt::TextFormatted("u\"{0}\"", value.c_str()); return copyValue; }; return [value, copyValue] { ImGuiExt::TextFormatted("u\"{0}\"", value.c_str()); return copyValue; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::ignore = endian; auto utf8 = hex::decodeByteString(value);
auto utf16 = wolv::util::utf8ToUtf16({ utf8.begin(), utf8.end() });
if (!utf16.has_value())
return {};
return hex::decodeByteString(value); for (auto &c : utf16.value()) {
c = hex::changeEndianness(c, endian);
} }
std::vector<u8> bytes(utf16->size() * sizeof(char16_t), 0x00);
std::memcpy(bytes.data(), utf16->data(), bytes.size());
return bytes;
})
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.string32", sizeof(char32_t), ContentRegistry::DataInspector::add("hex.builtin.inspector.string32", sizeof(char32_t),
@ -662,11 +687,20 @@ namespace hex::plugin::builtin {
return [value, copyValue] { ImGuiExt::TextFormatted("U\"{0}\"", value.c_str()); return copyValue; }; return [value, copyValue] { ImGuiExt::TextFormatted("U\"{0}\"", value.c_str()); return copyValue; };
}, },
[](const std::string &value, std::endian endian) -> std::vector<u8> { ContentRegistry::DataInspector::EditWidget::TextInput([](const std::string &value, std::endian endian) -> std::vector<u8> {
std::ignore = endian; auto utf8 = hex::decodeByteString(value);
auto utf32 = wolv::util::utf8ToUtf32({ utf8.begin(), utf8.end() });
if (!utf32.has_value())
return {};
return hex::decodeByteString(value); for (auto &c : utf32.value()) {
c = hex::changeEndianness(c, endian);
} }
std::vector<u8> bytes(utf32->size() * sizeof(char32_t), 0x00);
std::memcpy(bytes.data(), utf32->data(), bytes.size());
return bytes;
})
); );
ContentRegistry::DataInspector::add("hex.builtin.inspector.custom_encoding", 1, [encodingFile = EncodingFile()](const std::vector<u8> &, std::endian, Style) mutable { ContentRegistry::DataInspector::add("hex.builtin.inspector.custom_encoding", 1, [encodingFile = EncodingFile()](const std::vector<u8> &, std::endian, Style) mutable {

View File

@ -40,6 +40,7 @@
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
static void openFile(const std::fs::path &path) { static void openFile(const std::fs::path &path) {
TaskManager::doLater([path] {
if (path.extension() == ".hexproj") { if (path.extension() == ".hexproj") {
if (!ProjectFile::load(path)) { if (!ProjectFile::load(path)) {
ui::ToastError::open(fmt::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path))); ui::ToastError::open(fmt::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path)));
@ -49,21 +50,17 @@ namespace hex::plugin::builtin {
} }
auto provider = ImHexApi::Provider::createProvider("hex.builtin.provider.file", true); auto provider = ImHexApi::Provider::createProvider("hex.builtin.provider.file", true);
if (auto *fileProvider = dynamic_cast<FileProvider*>(provider); fileProvider != nullptr) { if (auto *fileProvider = dynamic_cast<FileProvider*>(provider.get()); fileProvider != nullptr) {
fileProvider->setPath(path); fileProvider->setPath(path);
if (!provider->open() || !provider->isAvailable()) {
ui::ToastError::open(fmt::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage()));
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
return;
}
EventProviderOpened::post(fileProvider); ImHexApi::Provider::openProvider(provider);
AchievementManager::unlockAchievement("hex.builtin.achievement.starting_out", "hex.builtin.achievement.starting_out.open_file.name"); AchievementManager::unlockAchievement("hex.builtin.achievement.starting_out", "hex.builtin.achievement.starting_out.open_file.name");
ImHexApi::Provider::setCurrentProvider(provider);
glfwRequestWindowAttention(ImHexApi::System::getMainWindowHandle()); glfwRequestWindowAttention(ImHexApi::System::getMainWindowHandle());
glfwFocusWindow(ImHexApi::System::getMainWindowHandle()); glfwFocusWindow(ImHexApi::System::getMainWindowHandle());
} }
});
} }
void registerEventHandlers() { void registerEventHandlers() {
@ -180,11 +177,8 @@ namespace hex::plugin::builtin {
RequestOpenWindow::subscribe([](const std::string &name) { RequestOpenWindow::subscribe([](const std::string &name) {
if (name == "Create File") { if (name == "Create File") {
auto newProvider = hex::ImHexApi::Provider::createProvider("hex.builtin.provider.mem_file", true); auto newProvider = ImHexApi::Provider::createProvider("hex.builtin.provider.mem_file", true);
if (newProvider != nullptr && !newProvider->open()) ImHexApi::Provider::openProvider(newProvider);
hex::ImHexApi::Provider::remove(newProvider);
else
EventProviderOpened::post(newProvider);
} else if (name == "Open File") { } else if (name == "Open File") {
fs::openFileBrowser(fs::DialogMode::Open, { }, [](const auto &path) { fs::openFileBrowser(fs::DialogMode::Open, { }, [](const auto &path) {
if (path.extension() == ".hexproj") { if (path.extension() == ".hexproj") {
@ -195,20 +189,15 @@ namespace hex::plugin::builtin {
} }
} }
auto newProvider = static_cast<FileProvider*>( auto provider = ImHexApi::Provider::createProvider("hex.builtin.provider.file", true);
ImHexApi::Provider::createProvider("hex.builtin.provider.file", true) auto newProvider = static_cast<FileProvider*>(provider.get());
);
if (newProvider == nullptr) if (newProvider == nullptr)
return; return;
newProvider->setPath(path); newProvider->setPath(path);
if (!newProvider->open()) { ImHexApi::Provider::openProvider(provider);
hex::ImHexApi::Provider::remove(newProvider);
} else {
EventProviderOpened::post(newProvider);
AchievementManager::unlockAchievement("hex.builtin.achievement.starting_out", "hex.builtin.achievement.starting_out.open_file.name"); AchievementManager::unlockAchievement("hex.builtin.achievement.starting_out", "hex.builtin.achievement.starting_out.open_file.name");
}
}, {}, true); }, {}, true);
} else if (name == "Open Project") { } else if (name == "Open Project") {
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} }, fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} },
@ -225,34 +214,20 @@ namespace hex::plugin::builtin {
}); });
// Handles the provider initialization, and calls EventProviderOpened if successful // Handles the provider initialization, and calls EventProviderOpened if successful
EventProviderCreated::subscribe([](hex::prv::Provider *provider) { EventProviderCreated::subscribe([](std::shared_ptr<prv::Provider> provider) {
if (provider->shouldSkipLoadInterface()) if (provider->shouldSkipLoadInterface())
return; return;
if (auto *filePickerProvider = dynamic_cast<prv::IProviderFilePicker*>(provider); filePickerProvider != nullptr) { if (auto *filePickerProvider = dynamic_cast<prv::IProviderFilePicker*>(provider.get()); filePickerProvider != nullptr) {
if (!filePickerProvider->handleFilePicker()) { if (!filePickerProvider->handleFilePicker()) {
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); }); TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider.get()); });
return; return;
} }
TaskManager::createBlockingTask("hex.builtin.provider.opening", TaskManager::NoProgress, [provider]() { ImHexApi::Provider::openProvider(provider);
if (!provider->open()) {
ui::ToastError::open(fmt::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage()));
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
} else {
TaskManager::doLater([provider]{ EventProviderOpened::post(provider); });
} }
}); else if (dynamic_cast<prv::IProviderLoadInterface*>(provider.get()) == nullptr) {
} ImHexApi::Provider::openProvider(provider);
else if (dynamic_cast<prv::IProviderLoadInterface*>(provider) == nullptr) {
TaskManager::createBlockingTask("hex.builtin.provider.opening", TaskManager::NoProgress, [provider]() {
if (!provider->open() || !provider->isAvailable()) {
ui::ToastError::open(fmt::format("hex.builtin.provider.error.open"_lang, provider->getErrorMessage()));
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
} else {
TaskManager::doLater([provider]{ EventProviderOpened::post(provider); });
}
});
} }
}); });
@ -418,6 +393,25 @@ namespace hex::plugin::builtin {
}); });
}); });
RequestOpenProvider::subscribe([](std::shared_ptr<prv::Provider> provider) {
TaskManager::createBlockingTask("hex.builtin.provider.opening", TaskManager::NoProgress, [provider]() {
auto result = provider->open();
if (result.isFailure()) {
ui::ToastError::open(fmt::format("hex.builtin.provider.error.open"_lang, result.getErrorMessage()));
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider.get()); });
} else if (result.isRedirecting()) {
TaskManager::doLater([result, provider] {
ImHexApi::Provider::remove(provider.get());
ImHexApi::Provider::setCurrentProvider(result.getRedirectProvider());
});
} else {
if (result.isWarning())
ui::ToastWarning::open(std::string(result.getErrorMessage()));
TaskManager::doLater([provider]{ EventProviderOpened::post(provider.get()); });
}
});
});
fs::setFileBrowserErrorCallback([](const std::string& errMsg){ fs::setFileBrowserErrorCallback([](const std::string& errMsg){
#if defined(NFD_PORTAL) #if defined(NFD_PORTAL)
ui::PopupError::open(fmt::format("hex.builtin.popup.error.file_dialog.portal"_lang, errMsg)); ui::PopupError::open(fmt::format("hex.builtin.popup.error.file_dialog.portal"_lang, errMsg));

View File

@ -377,10 +377,10 @@ namespace hex::plugin::builtin {
/* Create File */ /* Create File */
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.create_file" }, ICON_VS_FILE, 1050, CTRLCMD + Keys::N + AllowWhileTyping + ShowOnWelcomeScreen, [] { ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.create_file" }, ICON_VS_FILE, 1050, CTRLCMD + Keys::N + AllowWhileTyping + ShowOnWelcomeScreen, [] {
auto newProvider = hex::ImHexApi::Provider::createProvider("hex.builtin.provider.mem_file", true); auto newProvider = hex::ImHexApi::Provider::createProvider("hex.builtin.provider.mem_file", true);
if (newProvider != nullptr && !newProvider->open()) if (newProvider != nullptr && newProvider->open().isFailure())
hex::ImHexApi::Provider::remove(newProvider); hex::ImHexApi::Provider::remove(newProvider.get());
else else
EventProviderOpened::post(newProvider); EventProviderOpened::post(newProvider.get());
}, noRunningTasks, ContentRegistry::Views::getViewByName("hex.builtin.view.hex_editor.name")); }, noRunningTasks, ContentRegistry::Views::getViewByName("hex.builtin.view.hex_editor.name"));
/* Open File */ /* Open File */
@ -401,7 +401,7 @@ namespace hex::plugin::builtin {
auto provider = ImHexApi::Provider::get(); auto provider = ImHexApi::Provider::get();
provider->close(); provider->close();
if (!provider->open()) if (provider->open().isFailure())
ImHexApi::Provider::remove(provider, true); ImHexApi::Provider::remove(provider, true);
EventDataChanged::post(provider); EventDataChanged::post(provider);

View File

@ -8,8 +8,6 @@
#include <popups/popup_file_chooser.hpp> #include <popups/popup_file_chooser.hpp>
#include <ui/text_editor.hpp>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
PopupDecodedString::PopupDecodedString(std::string decodedString) : m_decodedString(std::move(decodedString)) { PopupDecodedString::PopupDecodedString(std::string decodedString) : m_decodedString(std::move(decodedString)) {

View File

@ -13,7 +13,6 @@
#include <fonts/vscode_icons.hpp> #include <fonts/vscode_icons.hpp>
#include <ui/text_editor.hpp>
#include <wolv/literals.hpp> #include <wolv/literals.hpp>
using namespace wolv::literals; using namespace wolv::literals;

View File

@ -18,8 +18,6 @@
#include <popups/popup_file_chooser.hpp> #include <popups/popup_file_chooser.hpp>
#include <ui/text_editor.hpp>
namespace hex::plugin::builtin { namespace hex::plugin::builtin {
PerProvider<std::string> PopupFind::s_inputString; PerProvider<std::string> PopupFind::s_inputString;

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