Compare commits

...

76 Commits

Author SHA1 Message Date
WerWolv
76cf877115 build: Disable ARM msi signing because it doesn't work 2025-12-21 16:04:44 +01:00
WerWolv
8e4ccef52f build: Don't fail release CI if tag is empty 2025-12-21 14:54:33 +01:00
WerWolv
b78a1024c1 fix: Duplicate artifact name in release CI 2025-12-21 14:33:16 +01:00
WerWolv
fbae871d65 build: Bump version to 1.38.1 2025-12-21 14:00:33 +01:00
WerWolv
1a9fa0875b patterns: Update pattern language 2025-12-21 13:02:07 +01:00
WerWolv
96232c2d80 impr: Better updater experience on macOS
(cherry picked from commit 428fbddbbb)
2025-12-21 12:53:31 +01:00
WerWolv
6405c75242 fix: Updater architecture check on MSVC
(cherry picked from commit 5774837a6e)
2025-12-21 12:51:59 +01:00
WerWolv
5a853569e6 fix: Fedora 43 not being updatable 2025-12-19 19:16:57 +01:00
WerWolv
ea9d965ffe fix: Linux aarch64 detection in the updater
(cherry picked from commit 155465b8c6)
2025-12-19 19:08:05 +01:00
WerWolv
8b84c47b73 fix: Updater not detecting architecture on Windows correctly
(cherry picked from commit 6f49bbdd41)
2025-12-19 18:15:26 +01:00
iTrooz
a3cd6e6a40 ci: cancel old workflows when pushing a new commit
(cherry picked from commit 3badaa5cba)
2025-12-19 18:15:26 +01:00
iTrooz
2f707afa67 ci: build dependencies in different step than configuring cmake (#2574)
<!--
Please provide as much information as possible about what your PR aims
to do.
PRs with no description will most likely be closed until more
information is provided.
If you're planing on changing fundamental behaviour or add big new
features, please open a GitHub Issue first before starting to work on
it.
If it's not something big and you still want to contact us about it,
feel free to do so !
-->

### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->

### Implementation description
<!-- Explain what you did to correct the problem -->

### Screenshots
<!-- If your change is visual, take a screenshot showing it. Ideally,
make before/after sceenshots -->

### Additional things
<!-- Anything else you would like to say -->

(cherry picked from commit a66747a0d0)
2025-12-19 18:15:26 +01:00
iTrooz
765c8f4fe2 chore: update invalid comments in arm64 Dockerfile
(cherry picked from commit c376759be0)
2025-12-19 18:15:26 +01:00
iTrooz
4120e10a95 fix: DiskProvider::open() default result on Windows (#2573)
<!--
Please provide as much information as possible about what your PR aims
to do.
PRs with no description will most likely be closed until more
information is provided.
If you're planing on changing fundamental behaviour or add big new
features, please open a GitHub Issue first before starting to work on
it.
If it's not something big and you still want to contact us about it,
feel free to do so !
-->

### Problem description
<!-- Describe the bug that you fixed/feature request that you
implemented, or link to an existing issue describing it -->

### Implementation description
<!-- Explain what you did to correct the problem -->

### Screenshots
<!-- If your change is visual, take a screenshot showing it. Ideally,
make before/after sceenshots -->

### Additional things
<!-- Anything else you would like to say -->

(cherry picked from commit 1c17f3ee43)
2025-12-19 18:15:26 +01:00
paxcut
67ec26b22a patterns: update pattern language (#2572)
for the ghost break point bug

(cherry picked from commit 5f549cc8aa)
2025-12-19 18:15:26 +01:00
WerWolv
937ca4a327 fix: Disk provider still using old open() api on windows
(cherry picked from commit 2d82776e62)
2025-12-18 00:15:53 +01:00
WerWolv
96587415f6 fix: Test Provider still using old open function signature
(cherry picked from commit fdee0ac3e3)
2025-12-18 00:15:53 +01:00
iTrooz
b2f062cf10 chore: use cleaner yaml format for clang-tidy
(cherry picked from commit 2047a41498)
2025-12-18 00:15:53 +01:00
iTrooz
91ef40ec99 chore: disable all clang-tidy checks in third_party libraries
(cherry picked from commit f88890a052)
2025-12-18 00:15:53 +01:00
WerWolv
684a9b3009 fix: Inverted logic when opening files from the command line
(cherry picked from commit 5500faa57e)
2025-12-18 00:15:53 +01:00
WerWolv
51d773cf14 impr: Handle provider opening more centrally, switch to existing provider if same file is being opened again
(cherry picked from commit 89004574d3)
2025-12-18 00:15:53 +01:00
iTrooz
cae063985a build: do not bundle SDK in snap and flatpak packages (#2567)
(cherry picked from commit c11c05a399)
2025-12-18 00:11:23 +01:00
WerWolv
798bd25202 fix: Make sure providers returned by createProvider don't get deleted unexpectedly
(cherry picked from commit baa3329e7f)
2025-12-18 00:11:23 +01:00
WerWolv
11df253fd3 fix: Pattern files not getting truncated correctly when saving
Fixes #2566

(cherry picked from commit 932c281223)
2025-12-16 10:03:26 +01:00
WerWolv
a44278b1fe impr: Make most windows non-scrolling by default
(cherry picked from commit 858fe0384e)
2025-12-16 10:03:22 +01:00
WerWolv
cd7705664d fix: Inverted sorting of find view table
Fixes #2564

(cherry picked from commit e904cd749f)
2025-12-16 10:03:17 +01:00
WerWolv
23e484c468 fix: Typo in crash popup
(cherry picked from commit c161a5c71b)
2025-12-16 10:03:05 +01:00
WerWolv
c4c8c46c11 patterns: Update pattern language
(cherry picked from commit 76ccdbccea)
2025-12-15 10:11:09 +01:00
WerWolv
f633c3f33a fix: Only enable widgets in pattern data view when there's actually any patterns available
(cherry picked from commit 553ee89787)
2025-12-15 10:11:09 +01:00
WerWolv
b8bcb815c8 fix: Crash when using @ command palette command
Fixes #2563

(cherry picked from commit cb6247b16e)
2025-12-15 10:11:09 +01:00
WerWolv
81826df897 impr: Unionize exception and assertion handling
(cherry picked from commit cfac7ff0ba)
2025-12-15 10:11:09 +01:00
iTrooz
f6b2251205 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

(cherry picked from commit 49bbe7dc77)
2025-12-15 10:11:09 +01:00
iTrooz
1a7fefbc22 build(web): add BUILD_TYPE arg to Dockerfile
(cherry picked from commit 07b6fa0e2e)
2025-12-15 10:11:09 +01:00
iTrooz
fdc1434cc6 chore: fix web Dockerfile ARG syntax
(cherry picked from commit 67396f2009)
2025-12-15 10:11:09 +01:00
iTrooz
230568f681 chore: update comment
(cherry picked from commit a20ff87cc9)
2025-12-15 10:11:09 +01:00
iTrooz
48c869fc89 chore: remove version attribute from web compose.yaml
(cherry picked from commit e02e57a729)
2025-12-15 10:11:09 +01:00
iTrooz
4222904be9 build(appimage): use https when querying repos
(cherry picked from commit 225dc53795)
2025-12-15 10:11:09 +01:00
iTrooz
20b4630faa build: do not bundle plugin SDK in AppImage
(cherry picked from commit e7404376db)
2025-12-15 10:11:09 +01:00
iTrooz
6ddf2bb9fd build(web): make a shallow clone of vcpkg
(cherry picked from commit d6aec341fe)
2025-12-15 10:11:09 +01:00
iTrooz
77f049f0aa build: add defaults to AppImage build for x86
(cherry picked from commit 3a3c2fb204)
2025-12-15 10:11:09 +01:00
iTrooz
588412543c build: fix IMHEX_INCLUDE_PLUGINS defined check
(cherry picked from commit e9b5cdbccf)
2025-12-15 10:11:09 +01:00
iTrooz
9939007fcf chore(web): allow nginx to access files in development docker image
(cherry picked from commit 3f30e63d95)
2025-12-15 10:11:09 +01:00
iTrooz
119f6f78b9 build: require all plugins that builtint depends on to be present
(cherry picked from commit f9c6866c7b)
2025-12-15 10:11:09 +01:00
iTrooz
e2e397f188 chore: organise cmake build flags
(cherry picked from commit 388dccfd9f)
2025-12-15 10:11:09 +01:00
paxcut
60e2c32ae0 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.

(cherry picked from commit 1676342e28)
2025-12-15 10:11:09 +01:00
WerWolv
febd46ec58 fix: Gaps in-between hex editor highlighting on specific scalings
(cherry picked from commit 62732de227)
2025-12-15 10:11:09 +01:00
WerWolv
bb9a0517fe impr: Intercept glibc++ assertion handler
(cherry picked from commit 63e777c84c)
2025-12-15 10:11:09 +01:00
WerWolv
e03d3d9f36 fix: Minimap not allowing scrolling as far as the scroll bar
(cherry picked from commit ab95cdf3e5)
2025-12-15 10:11:09 +01:00
WerWolv
08daaec380 patterns: Update pattern language
(cherry picked from commit 827b5b01dd)
2025-12-15 10:11:09 +01:00
paxcut
5a9f44e696 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.

(cherry picked from commit bfa9788099)
2025-12-15 10:11:09 +01:00
WerWolv
c95cbc5933 fix: Extended ASCII display being enabled by default
(cherry picked from commit 21e61bfce6)
2025-12-12 13:15:32 +01:00
WerWolv
516a2f119e build: Update libwolv
(cherry picked from commit 82e168c438)
2025-12-12 13:15:32 +01:00
WerWolv
99e81b53af build: Go back to WiX 4 again for ARM64 support
(cherry picked from commit 48583a2b6e)
2025-12-11 23:41:57 +01:00
WerWolv
8bce2b072c build: Update dependencies
(cherry picked from commit 0db0982fa7)
2025-12-11 23:24:33 +01:00
WerWolv
539a00ae5d fix: Off-by-one of starts of process memory regions
(cherry picked from commit f234103320)
2025-12-11 23:23:51 +01:00
WerWolv
38075a1438 fix: Crash when canceling creation of SSH provider
Fixes #2557

(cherry picked from commit fb7ef61d06)
2025-12-11 23:23:51 +01:00
WerWolv
2c82d561c0 build: Force-set REINSTALLMODE=amus for WiX installer
(cherry picked from commit 2586645d02)
2025-12-11 23:23:51 +01:00
WerWolv
48e72a88c2 build: Use WiX 3 for packaging
(cherry picked from commit e23cb5509d)
2025-12-11 23:23:51 +01:00
WerWolv
95c9168e25 build: Fix version stripping issues
(cherry picked from commit 5cbd53ae7a)
2025-12-11 23:23:51 +01:00
WerWolv
64cbc16f78 build: Only build the version stripper on mingw
(cherry picked from commit a4ee590875)
2025-12-11 23:23:51 +01:00
WerWolv
b5f63e899c build: Force-remove all version information from libwinpthread
(cherry picked from commit 495608ed7c)
2025-12-11 23:23:51 +01:00
WerWolv
0a994d61b3 build: Manually set FILEVERSION of libwinpthread to 0.0.0.0
#2550

(cherry picked from commit 4d10d9a195)
2025-12-11 23:23:51 +01:00
WerWolv
a8237326ad build: Fix WiX patch
(cherry picked from commit 4914a34dd9)
2025-12-11 23:23:51 +01:00
WerWolv
1253d68256 fix: Reset selected row after checking it
(cherry picked from commit ab0fb3131d)
2025-12-11 23:23:51 +01:00
WerWolv
c944750f4d build: Try to force-overwrite libwinpthread
(cherry picked from commit 7922d3b3cb)
2025-12-11 23:23:51 +01:00
WerWolv
fb21f11554 fix: Editing of WString, String16, String32 in data inspector
(cherry picked from commit e6eee55810)
2025-12-11 23:23:51 +01:00
WerWolv
d8e54e535b impr: Allow Esc to clear editing and selected state in data inspector
(cherry picked from commit 77b9e3eac8)
2025-12-11 23:23:51 +01:00
WerWolv
59afa06bf4 impr: If there's multiple foreground highlighting providers, only evaluate until a color is found
(cherry picked from commit 790487eea6)
2025-12-11 23:23:51 +01:00
WerWolv
358f961f50 build: Remove file version from main executable to make msi installer not skip it
(cherry picked from commit 9ba8754f97)
2025-12-11 23:23:51 +01:00
WerWolv
fc1b30eef2 build: Fix deb package referring to incorrect md4c library package
Fixes #2548

(cherry picked from commit 2b3abd06db)
2025-12-07 16:26:54 +01:00
WerWolv
596564ec48 fix: Post-pone file opening till everything has been initialized
(cherry picked from commit 3f9ce561b9)
2025-12-07 16:26:54 +01:00
WerWolv
a652b95816 impr: Show proper error message if nethost header can't be found
(cherry picked from commit 347fc3ed9f)
2025-12-07 16:26:54 +01:00
WerWolv
0e3ce90db7 impr: Make icons look slightly nicer at low resolutions
(cherry picked from commit 0488c996e9)
2025-12-07 16:26:54 +01:00
WerWolv
a3f31da365 git: Make release CI more reliable
(cherry picked from commit 37bfd97d93)
2025-12-07 16:26:54 +01:00
WerWolv
27518cc584 Merge branch 'feature/code-signing'
(cherry picked from commit c8652b0576)
2025-12-07 16:26:42 +01:00
WerWolv
3bcce0a243 git: Fix issues with the release CI
(cherry picked from commit 1208d2eb5e)
2025-12-07 16:26:36 +01:00
120 changed files with 2043 additions and 1188 deletions

View File

@@ -1,69 +1,68 @@
# Generated from CLion Inspection settings
---
Checks: '-*,
mpi-*,
bugprone-*,
-bugprone-signal-handler,
-bugprone-narrowing-conversions,
-bugprone-redundant-branch-condition,
-bugprone-exception-escape,
-bugprone-shared-ptr-array-mismatch,
-bugprone-implicit-widening-of-multiplication-result,
-bugprone-signed-char-misuse,
-bugprone-unhandled-exception-at-new,
-bugprone-infinite-loop,
-bugprone-easily-swappable-parameters,
cert-err52-cpp,
cert-err60-cpp,
cert-err34-c,
cert-str34-c,
cert-dcl21-cpp,
cert-msc50-cpp,
cert-msc51-cpp,
cert-dcl58-cpp,
cert-flp30-c,
cppcoreguidelines-avoid-const-or-ref-data-members,
cppcoreguidelines-pro-type-member-init,
cppcoreguidelines-slicing,
cppcoreguidelines-interfaces-global-init,
cppcoreguidelines-pro-type-static-cast-downcast,
cppcoreguidelines-narrowing-conversions,
google-default-arguments,
google-runtime-operator,
google-explicit-constructor,
hicpp-multiway-paths-covered,
hicpp-exception-baseclass,
misc-*,
-misc-definitions-in-headers,
-misc-unused-parameters,
-misc-unused-alias-decls,
-misc-use-anonymous-namespace,
-misc-misleading-identifier,
-misc-confusable-identifiers,
-misc-misleading-bidirectional,
-misc-static-assert,
-misc-no-recursion,
-misc-const-correctness,
modernize-*,
-modernize-use-trailing-return-type,
openmp-use-default-none,
performance-*,
-performance-no-int-to-ptr,
portability-*,
-portability-restrict-system-includes,
readability-*,
-readability-redundant-preprocessor,
-readability-named-parameter,
-readability-function-size,
-readability-use-anyofallof,
-readability-identifier-length,
-readability-magic-numbers,
-readability-braces-around-statements,
-readability-suspicious-call-argument,
-readability-isolate-declaration,
-readability-else-after-return,
-readability-redundant-access-specifiers,
-readability-function-cognitive-complexity,
-readability-identifier-naming,
*-include-cleaner,
-readability-qualified-auto'
Checks:
- -*
- mpi-*
- bugprone-*
- -bugprone-signal-handler
- -bugprone-narrowing-conversions
- -bugprone-redundant-branch-condition
- -bugprone-exception-escape
- -bugprone-shared-ptr-array-mismatch
- -bugprone-implicit-widening-of-multiplication-result
- -bugprone-signed-char-misuse
- -bugprone-unhandled-exception-at-new
- -bugprone-infinite-loop
- -bugprone-easily-swappable-parameters
- cert-err52-cpp
- cert-err60-cpp
- cert-err34-c
- cert-str34-c
- cert-dcl21-cpp
- cert-msc50-cpp
- cert-msc51-cpp
- cert-dcl58-cpp
- cert-flp30-c
- cppcoreguidelines-avoid-const-or-ref-data-members
- cppcoreguidelines-pro-type-member-init
- cppcoreguidelines-slicing
- cppcoreguidelines-interfaces-global-init
- cppcoreguidelines-pro-type-static-cast-downcast
- cppcoreguidelines-narrowing-conversions
- google-default-arguments
- google-runtime-operator
- google-explicit-constructor
- hicpp-multiway-paths-covered
- hicpp-exception-baseclass
- misc-*
- -misc-definitions-in-headers
- -misc-unused-parameters
- -misc-unused-alias-decls
- -misc-use-anonymous-namespace
- -misc-misleading-identifier
- -misc-confusable-identifiers
- -misc-misleading-bidirectional
- -misc-static-assert
- -misc-no-recursion
- -misc-const-correctness
- modernize-*
- -modernize-use-trailing-return-type
- openmp-use-default-none
- performance-*
- -performance-no-int-to-ptr
- portability-*
- -portability-restrict-system-includes
- readability-*
- -readability-redundant-preprocessor
- -readability-named-parameter
- -readability-function-size
- -readability-use-anyofallof
- -readability-identifier-length
- -readability-magic-numbers
- -readability-braces-around-statements
- -readability-suspicious-call-argument
- -readability-isolate-declaration
- -readability-else-after-return
- -readability-redundant-access-specifiers
- -readability-function-cognitive-complexity
- -readability-identifier-naming
- '*-include-cleaner'
- -readability-qualified-auto

View File

@@ -1,5 +1,9 @@
name: Build
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
on:
push:
branches:
@@ -95,7 +99,6 @@ jobs:
-DIMHEX_GENERATE_PDBS=ON \
-DIMHEX_REPLACE_DWARF_WITH_PDB=ON \
-DDOTNET_EXECUTABLE="C:/Program Files/dotnet/dotnet.exe" \
-DCPACK_WIX_VERSION="4" \
-DCPACK_WIX_ROOT="$(echo "$USERPROFILE" | tr '\\' '/')/.dotnet/tools" \
..
@@ -166,6 +169,7 @@ jobs:
- name: ⬆️ Upload Windows Installer
uses: actions/upload-artifact@v4
id: upload-installer
with:
if-no-files-found: error
name: Windows Installer ${{ matrix.architecture_name }}
@@ -247,6 +251,7 @@ jobs:
- name: ⬇️ Install dependencies
run: |
cp dist/vcpkg.json vcpkg.json
vcpkg install
- name: ⬇️ Install CMake and Ninja
uses: lukka/get-cmake@latest
@@ -279,7 +284,6 @@ jobs:
-DIMHEX_COMMIT_HASH_LONG="$env:GITHUB_SHA" `
-DIMHEX_COMMIT_BRANCH="$($env:GITHUB_REF -replace '.*/', '')" `
-DDOTNET_EXECUTABLE="C:/Program Files/dotnet/dotnet.exe" `
-DCPACK_WIX_VERSION="4" `
-DCPACK_WIX_ROOT="$($env:USERPROFILE -replace '\\','/')/.dotnet/tools" `
.

View File

@@ -82,6 +82,43 @@ jobs:
git fetch --tags --recurse-submodules=no
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
if: ${{ steps.check_commits.outputs.should_run == 'true' }}
run: |

View File

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

View File

@@ -1,33 +1,38 @@
cmake_minimum_required(VERSION 3.25)
# 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_OFFLINE_BUILD "Enable offline build" OFF)
option(IMHEX_IGNORE_BAD_CLONE "Disable the bad clone prevention checks" OFF)
option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of the ImHex-Patterns repo" OFF)
option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler" OFF)
option(IMHEX_USE_GTK_FILE_PICKER "Use GTK file picker instead of xdg-desktop-portals (Linux only)" OFF)
option(IMHEX_DISABLE_STACKTRACE "Disables support for printing stack traces" OFF)
option(IMHEX_BUNDLE_DOTNET "Bundle .NET runtime" ON )
option(IMHEX_ENABLE_LTO "Enables Link Time Optimizations if possible" OFF)
option(IMHEX_USE_DEFAULT_BUILD_SETTINGS "Use default build settings" OFF)
option(IMHEX_STRICT_WARNINGS "Enable most available warnings and treat them as errors" ON )
option(IMHEX_BUILD_HARDENING "Enable hardening flags for build" ON )
option(IMHEX_STATIC_LINK_PLUGINS "Statically link all plugins into the main executable" OFF)
option(IMHEX_GENERATE_PACKAGE "Specify if a native package should be built. (Windows and MacOS only)" OFF)
option(IMHEX_ENABLE_UNITY_BUILD "Enables building ImHex as a unity build." OFF)
option(IMHEX_GENERATE_PDBS "Enable generating PDB files in non-debug builds (Windows only)" OFF)
option(IMHEX_REPLACE_DWARF_WITH_PDB "Remove DWARF information from binaries when generating PDBS (Windows only)" OFF)
option(IMHEX_ENABLE_STD_ASSERTS "Enable debug asserts in the C++ std library. (Breaks Plugin ABI!)" OFF)
option(IMHEX_ENABLE_UNIT_TESTS "Enable building unit tests" ON )
option(IMHEX_ENABLE_PLUGIN_TESTS "Enable building plugin tests" ON )
option(IMHEX_ENABLE_IMGUI_TEST_ENGINE "Enable the ImGui Test Engine" OFF)
option(IMHEX_ENABLE_PRECOMPILED_HEADERS "Enable precompiled headers" OFF)
option(IMHEX_COMPRESS_DEBUG_INFO "Compress debug information" ON )
option(IMHEX_ENABLE_CXX_MODULES "Enable C++20 Module compilation. Testing only!" OFF)
option(IMHEX_ENABLE_CPPCHECK "Enable cppcheck static analysis" OFF)
option(IMHEX_BUNDLE_PLUGIN_SDK "Enable bundling of Plugin SDK into install package" ON )
## Testing
option(IMHEX_ENABLE_UNIT_TESTS "Enable building unit tests" ON )
option(IMHEX_ENABLE_IMGUI_TEST_ENGINE "Enable the ImGui Test Engine" OFF)
option(IMHEX_ENABLE_STD_ASSERTS "Enable debug asserts in the C++ std library. (Breaks Plugin ABI!)" OFF)
## Debug info
option(IMHEX_COMPRESS_DEBUG_INFO "Compress debug information" ON )
option(IMHEX_GENERATE_PDBS "Enable generating PDB files in non-debug builds (Windows only)" OFF)
option(IMHEX_REPLACE_DWARF_WITH_PDB "Remove DWARF information from binaries when generating PDBS (Windows only)" OFF)
option(IMHEX_STRICT_WARNINGS "Enable most available warnings and treat them as errors" ON )
option(IMHEX_DISABLE_STACKTRACE "Disables support for printing stack traces" OFF)
## Plugins
option(IMHEX_STATIC_LINK_PLUGINS "Statically link all plugins into the main executable" OFF)
option(IMHEX_ENABLE_PLUGIN_TESTS "Enable building plugin tests" ON )
option(IMHEX_INCLUDE_PLUGINS "Semicolon-separated list of plugins to include in the build (empty = build all)" "" )
option(IMHEX_EXCLUDE_PLUGINS "Semicolon-separated list of plugins to exclude from the build" "" )
set(IMHEX_BASE_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}")
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")

View File

@@ -1 +1 @@
1.38.0
1.38.1

View File

@@ -175,15 +175,11 @@ macro(detectOS)
endif()
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
# IMPORTANT: This does not work for Sandboxed or portable builds such as the Flatpak or AppImage release
add_compile_definitions(SYSTEM_PLUGINS_LOCATION="${CMAKE_INSTALL_FULL_LIBDIR}/imhex")
endif()
# Add System plugin location for plugins to be loaded from
# IMPORTANT: This does not work for Sandboxed or portable builds such as the Flatpak or AppImage release
add_compile_definitions(SYSTEM_PLUGINS_LOCATION="${CMAKE_INSTALL_FULL_LIBDIR}/imhex")
else ()
message(FATAL_ERROR "Unknown / unsupported system!")
@@ -205,11 +201,14 @@ macro(configurePackingResources)
set(CPACK_GENERATOR "WIX")
set(CPACK_PACKAGE_NAME "ImHex")
set(CPACK_PACKAGE_VENDOR "WerWolv")
set(CPACK_WIX_VERSION 4)
set(CPACK_WIX_UPGRADE_GUID "05000E99-9659-42FD-A1CF-05C554B39285")
set(CPACK_WIX_PRODUCT_ICON "${PROJECT_SOURCE_DIR}/resources/dist/windows/icon.ico")
set(CPACK_WIX_UI_BANNER "${PROJECT_SOURCE_DIR}/resources/dist/windows/wix_banner.png")
set(CPACK_WIX_UI_DIALOG "${PROJECT_SOURCE_DIR}/resources/dist/windows/wix_dialog.png")
set(CPACK_WIX_CULTURES "en-US;de-DE;ja-JP;it-IT;pt-BR;zh-CN;zh-TW;ru-RU")
set(CPACK_WIX_PATCH_FILE "${PROJECT_SOURCE_DIR}/resources/dist/windows/wix_patch.xml")
set(CPACK_PACKAGE_INSTALL_DIRECTORY "ImHex")
set_property(INSTALL "$<TARGET_FILE_NAME:main>"
PROPERTY CPACK_START_MENU_SHORTCUTS "ImHex"
@@ -312,7 +311,7 @@ macro(createPackage)
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}\"!")
endif()
@@ -560,6 +559,9 @@ function(detectBadClone)
file (GLOB EXTERNAL_DIRS "lib/external/*" "lib/third_party/*")
foreach (EXTERNAL_DIR ${EXTERNAL_DIRS})
if(NOT IS_DIRECTORY "${EXTERNAL_DIR}")
continue()
endif()
file(GLOB_RECURSE RESULT "${EXTERNAL_DIR}/*")
list(LENGTH RESULT ENTRY_COUNT)
if(ENTRY_COUNT LESS_EQUAL 1)
@@ -587,7 +589,9 @@ endfunction()
macro(detectBundledPlugins)
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})
if (EXISTS "${PLUGIN_DIR}/CMakeLists.txt")
get_filename_component(PLUGIN_NAME ${PLUGIN_DIR} NAME)
@@ -596,8 +600,6 @@ macro(detectBundledPlugins)
endif ()
endif()
endforeach()
else()
set(PLUGINS ${IMHEX_INCLUDE_PLUGINS})
endif()
foreach(PLUGIN_NAME ${PLUGINS})
@@ -608,9 +610,13 @@ macro(detectBundledPlugins)
message(FATAL_ERROR "No bundled plugins enabled")
endif()
if (NOT ("builtin" IN_LIST PLUGINS))
message(FATAL_ERROR "The 'builtin' plugin is required for ImHex to work!")
endif ()
set(REQUIRED_PLUGINS builtin fonts ui)
foreach(PLUGIN ${REQUIRED_PLUGINS})
list(FIND PLUGINS ${PLUGIN} PLUGIN_INDEX)
if (PLUGIN_INDEX EQUAL -1)
message(FATAL_ERROR "Required plugin '${PLUGIN}' is not enabled!")
endif()
endforeach()
endmacro()
macro(setVariableInParent variable value)

View File

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

View File

@@ -30,9 +30,9 @@ ARG LTO=ON
ARG BUILD_TYPE=RelWithDebInfo
ARG GIT_COMMIT_HASH
ARG GIT_BRANCH
ARG ARCHITECTURE_PACKAGE
ARG ARCHITECTURE_FILE_NAME
ARG ARCHITECTURE_APPIMAGE_BUILDER
ARG ARCHITECTURE_PACKAGE=x86_64
ARG ARCHITECTURE_FILE_NAME=amd64
ARG ARCHITECTURE_APPIMAGE_BUILDER=x86_64
WORKDIR /build
# Ubuntu sh doesnt support string substitution
@@ -42,16 +42,18 @@ RUN <<EOF
# Prepare ImHex build
set -xe
CC=gcc-14 CXX=g++-14 cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_LONG="${GIT_COMMIT_HASH}" \
-DIMHEX_COMMIT_BRANCH="${GIT_BRANCH}" \
-DIMHEX_ENABLE_LTO=${LTO} \
-DIMHEX_PLUGINS_IN_SHARE=ON \
CC=gcc-14 CXX=g++-14 cmake -G "Ninja" \
-DCMAKE_BUILD_TYPE=${BUILD_TYPE} \
-DCMAKE_INSTALL_PREFIX="/usr" \
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
-DIMHEX_PATTERNS_PULL_MASTER=ON \
-DIMHEX_COMMIT_HASH_LONG="${GIT_COMMIT_HASH}" \
-DIMHEX_COMMIT_BRANCH="${GIT_BRANCH}" \
-DIMHEX_ENABLE_LTO=${LTO} \
-DIMHEX_BUNDLE_PLUGIN_SDK=OFF \
`# To prevent using a libdir with an architecture-specific name` \
-DCMAKE_INSTALL_LIBDIR="lib" \
/imhex
EOF

View File

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

View File

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

View File

@@ -150,9 +150,7 @@ EOF
# Build ImHex
## Copy ImHex
COPY --from=imhex / /mnt/ImHex
## Patch ImHex with hacks
# COPY toolchain.cmake.2 /osxcross/target/toolchain.cmake
# Configure ImHex build
## Configure ImHex build
RUN --mount=type=cache,target=/cache --mount=type=cache,target=/mnt/ImHex/build/_deps \
cd /mnt/ImHex && \
# compilers

View File

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

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
# See https://github.com/moby/moby/issues/41715#issuecomment-733976493
ARG UNIQUEKEY 1
ARG UNIQUEKEY=1
RUN apt update
RUN apt install -y git ccache autoconf automake libtool pkg-config ninja-build
@@ -12,13 +12,13 @@ RUN <<EOF
# Note: we are a patch on the libmagic port
set -xe
git clone https://github.com/microsoft/vcpkg /vcpkg
git -C /vcpkg pull
git clone --depth 1 https://github.com/microsoft/vcpkg /vcpkg
/vcpkg/bootstrap-vcpkg.sh
sed -i 's/vcpkg_install_make(${EXTRA_ARGS})/vcpkg_install_make(${EXTRA_ARGS} SUBPATH src)/g' /vcpkg/ports/libmagic/portfile.cmake
EOF
# Patch vcpkg build instructions to add -pthread
# 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
set -xe
@@ -50,6 +50,7 @@ ENV CCACHE_DIR=/cache/ccache
RUN mkdir /build
WORKDIR /build
ARG BUILD_TYPE=Release
RUN --mount=type=cache,target=/cache \
--mount=type=bind,source=.,target=/imhex <<EOF
@@ -70,7 +71,7 @@ ccache -zs
-DVCPKG_CHAINLOAD_TOOLCHAIN_FILE=/emsdk/upstream/emscripten/cmake/Modules/Platform/Emscripten.cmake \
-DLIBROMFS_COMPRESS_RESOURCES=OFF \
-DIMHEX_ENABLE_PLUGIN_TESTS=OFF \
-DCMAKE_BUILD_TYPE=Release
-DCMAKE_BUILD_TYPE=${BUILD_TYPE}
ninja -j $JOBS
@@ -106,3 +107,4 @@ COPY --from=build [ \
FROM nginx
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
version: '3'
services:
imhex_web:
image: imhex_web:latest

View File

@@ -19,7 +19,7 @@ EXPORT_MODULE namespace hex {
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);
struct Entry {

View File

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

View File

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

View File

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

View File

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

View File

@@ -98,6 +98,7 @@ namespace hex {
void startProgram(const std::vector<std::string> &command);
int executeCommand(const std::string &command);
std::optional<std::string> executeCommandWithOutput(const std::string &command);
void openWebpage(std::string url);
extern "C" void registerFont(const char *fontName, const char *fontPath);

View File

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

View File

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

View File

@@ -79,6 +79,65 @@ namespace hex::prv {
public:
constexpr static u64 MaxPageSize = 0xFFFF'FFFF'FFFF'FFFF;
class OpenResult {
public:
OpenResult() : m_result(std::monostate{}) {}
[[nodiscard]] static OpenResult failure(std::string errorMessage) {
OpenResult result;
result.m_result = std::move(errorMessage);
return result;
}
[[nodiscard]] static OpenResult warning(std::string warningMessage) {
OpenResult result;
result.m_result = std::move(warningMessage);
result.m_warning = true;
return result;
}
[[nodiscard]] static OpenResult redirect(Provider *provider) {
OpenResult result;
result.m_result = provider;
return result;
}
[[nodiscard]] bool isSuccess() const {
return std::holds_alternative<std::monostate>(m_result);
}
[[nodiscard]] bool isFailure() const {
return std::holds_alternative<std::string>(m_result) && !m_warning;
}
[[nodiscard]] bool isWarning() const {
return std::holds_alternative<std::string>(m_result) && m_warning;
}
[[nodiscard]] bool isRedirecting() const {
return std::holds_alternative<Provider*>(m_result);
}
[[nodiscard]] Provider* getRedirectProvider() const {
if (std::holds_alternative<Provider*>(m_result)) {
return std::get<Provider*>(m_result);
}
return nullptr;
}
[[nodiscard]] std::string_view getErrorMessage() const {
if (std::holds_alternative<std::string>(m_result)) {
return std::get<std::string>(m_result);
}
return "";
}
private:
std::variant<std::monostate, std::string, Provider*> m_result;
bool m_warning = false;
};
Provider();
virtual ~Provider();
Provider(const Provider&) = delete;
@@ -94,7 +153,7 @@ namespace hex::prv {
* @note This is not related to the EventProviderOpened event
* @return true if the provider was opened successfully, else false
*/
[[nodiscard]] virtual bool open() = 0;
[[nodiscard]] virtual OpenResult open() = 0;
/**
* @brief Closes this provider
@@ -262,9 +321,6 @@ namespace hex::prv {
void skipLoadInterface() { m_skipLoadInterface = true; }
[[nodiscard]] bool shouldSkipLoadInterface() const { return m_skipLoadInterface; }
void setErrorMessage(const std::string &errorMessage) { m_errorMessage = errorMessage; }
[[nodiscard]] const std::string& getErrorMessage() const { return m_errorMessage; }
template<std::derived_from<undo::Operation> T>
bool addUndoableOperation(auto && ... args) {
return m_undoRedoStack.add<T>(std::forward<decltype(args)...>(args)...);
@@ -296,8 +352,6 @@ namespace hex::prv {
*/
bool m_skipLoadInterface = false;
std::string m_errorMessage = "Unspecified error";
u64 m_pageSize = MaxPageSize;
};

View File

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

View File

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

View File

@@ -1101,13 +1101,13 @@ namespace hex {
namespace impl {
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;
auto newProvider = creationFunction();
if (provider != nullptr) {
*provider = newProvider.get();
*provider = newProvider;
ImHexApi::Provider::add(std::move(newProvider), skipLoadInterface, selectProvider);
}
});

View File

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

View File

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

View File

@@ -1,4 +1,6 @@
#include <hex/helpers/debugging.hpp>
#include <hex/helpers/logger.hpp>
#include <hex/trace/stacktrace.hpp>
namespace hex::dbg {
@@ -21,4 +23,23 @@ namespace hex::dbg {
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() {
// 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);
// Add the system plugin directory to the path if one was provided at compile time

View File

@@ -12,6 +12,7 @@
#include <mutex>
#include <chrono>
#include <fmt/chrono.h>
#include <hex/helpers/debugging.hpp>
#if defined(OS_WINDOWS)
#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 {
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 isSavableAsRecent() const override { return false; }
[[nodiscard]] bool open() override { return true; }
[[nodiscard]] OpenResult open() override { return {}; }
void close() override { }
void readRaw(u64 offset, void *buffer, size_t size) override {

View File

@@ -309,6 +309,50 @@ namespace hex {
return ::system(command.c_str());
}
std::optional<std::string> executeCommandWithOutput(const std::string &command) {
std::array<char, 256> buffer = {};
std::string result;
#if defined(OS_WINDOWS)
FILE* pipe = _popen(command.c_str(), "r");
#else
FILE* pipe = popen(command.c_str(), "r");
#endif
if (!pipe) {
hex::log::error("Failed to open pipe for command: {}", command);
return std::nullopt;
}
try {
while (fgets(buffer.data(), buffer.size(), pipe) != nullptr) {
result += buffer.data();
}
} catch (const std::exception &e) {
hex::log::error("Exception while reading command output: {}", e.what());
#if defined(OS_WINDOWS)
_pclose(pipe);
#else
pclose(pipe);
#endif
return std::nullopt;
}
#if defined(OS_WINDOWS)
int exitCode = _pclose(pipe);
#else
int exitCode = pclose(pipe);
#endif
if (exitCode != 0) {
hex::log::debug("Command exited with code {}: {}", exitCode, command);
}
return result;
}
void openWebpage(std::string url) {
if (!url.contains("://"))
url = "https://" + url;

View File

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

View File

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

View File

@@ -1,8 +1,10 @@
#include <hex/ui/view.hpp>
#include <hex/api/task_manager.hpp>
#include <hex/helpers/auto_reset.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 <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();
}
}

2
lib/third_party/.clang-tidy vendored Normal file
View File

@@ -0,0 +1,2 @@
# Disable all checks
Checks: '-*'

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.
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
namespace hex::log::impl {
void assertionHandler(const char* expr_str, const char* file, int line);
namespace hex::dbg {
[[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
// 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")
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_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")
# Not supported currently
endif()

View File

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

View File

@@ -2,8 +2,9 @@
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 AssertionHandler s_assertionHandler = nullptr;
std::optional<StackTraceResult> getLastExceptionStackTrace() {
if (!s_lastExceptionStackTrace.has_value())
@@ -15,18 +16,26 @@ namespace hex::trace {
return result;
}
void setAssertionHandler(AssertionHandler handler) {
s_assertionHandler = handler;
}
void enableExceptionCaptureForCurrentThread() {
s_threadExceptionCaptureEnabled = true;
}
void disableExceptionCaptureForCurrentThread() {
s_threadExceptionCaptureEnabled = false;
}
}
#if defined(HEX_WRAP_CXA_THROW)
extern "C" {
[[noreturn]] void __real___cxa_throw(void* thrownException, void* type, void (*destructor)(void*));
[[noreturn]] void __wrap___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, std::type_info* type, void (*destructor)(void*)) {
if (hex::trace::s_threadExceptionCaptureEnabled)
hex::trace::s_lastExceptionStackTrace = hex::trace::getStackTrace();
@@ -35,4 +44,23 @@ namespace hex::trace {
}
#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 <exception>
#include <typeinfo>
#include <hex/helpers/debugging.hpp>
#include <hex/helpers/utils.hpp>
#if defined(IMGUI_TEST_ENGINE)
@@ -71,23 +72,12 @@ namespace hex::crash {
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) {
// Call the crash callback
crashCallback(msg);
// Print the stacktrace to the console or log file
printStackTrace();
dbg::printStackTrace(trace::getStackTrace());
// Flush all streams
std::fflush(stdout);
@@ -188,6 +178,7 @@ namespace hex::crash {
// Setup functions to handle signals, uncaught exception, or similar stuff that will crash ImHex
void setupCrashHandlers() {
trace::initialize();
trace::setAssertionHandler(dbg::assertionHandler);
// Register signal handlers
{

View File

@@ -102,12 +102,12 @@ std::optional<std::fs::path> downloadUpdate(const std::string &url) {
return filePath;
}
#if defined(__x86_64__)
#if defined(__x86_64__) || defined(_X86_) || defined(_AMD64_) || defined(_M_X64)
#define ARCH_DEPENDENT(x86_64, arm64) x86_64
#elif defined(__arm64__)
#elif defined(__arm64__) || defined(_ARM64_) || defined(__aarch64__) || defined(_M_ARM64)
#define ARCH_DEPENDENT(x86_64, arm64) arm64
#else
#define ARCH_DEPENDENT(x86_64, arm64) ""
#error "Unsupported architecture for updater"
#endif
std::string_view getUpdateArtifactEnding() {
@@ -134,6 +134,8 @@ std::string_view getUpdateArtifactEnding() {
return ARCH_DEPENDENT("Fedora-41-x86_64.rpm", "");
else if (hex::executeCommand("grep -q 'VERSION_ID=\"42\"' /etc/os-release") == 0)
return ARCH_DEPENDENT("Fedora-42-x86_64.rpm", "");
else if (hex::executeCommand("grep -q 'VERSION_ID=\"43\"' /etc/os-release") == 0)
return ARCH_DEPENDENT("Fedora-43-x86_64.rpm", "");
else if (hex::executeCommand("grep -q 'VERSION_ID=\"rawhide\"' /etc/os-release") == 0)
return ARCH_DEPENDENT("Fedora-rawhide-x86_64.rpm", "");
} else if (hex::executeCommand("grep -q '^NAME=\"Arch Linux\"' /etc/os-release") == 0) {
@@ -144,33 +146,103 @@ std::string_view getUpdateArtifactEnding() {
return "";
}
auto updateCommand(std::string command) {
return [command](const std::fs::path &updatePath) -> bool {
const auto formattedCommand = fmt::format(fmt::runtime(command), updatePath.string());
hex::log::info("Starting update process with command: '{}'", formattedCommand);
return hex::executeCommand(formattedCommand) == 0;
};
}
auto updateMacOSBundle(const std::fs::path &updatePath) {
// Mount the DMG
auto mountCmd = fmt::format("hdiutil attach \"{}\" -nobrowse", updatePath.string());
auto mountOutput = hex::executeCommandWithOutput(mountCmd);
if (!mountOutput.has_value()) {
hex::log::error("Failed to mount DMG");
return false;
}
// Extract mount point from output
std::string mountPoint;
for (const auto &line : wolv::util::splitString(*mountOutput, "\n")) {
if (line.contains("/Volumes/")) {
auto parts = wolv::util::splitString(line, "\t");
mountPoint = parts.back();
break;
}
}
if (mountPoint.empty()) {
hex::log::error("Failed to find mount point");
return false;
}
ON_SCOPE_EXIT {
hex::executeCommand(fmt::format("hdiutil detach \"{}\"", mountPoint));
};
// Find the .app bundle in the mounted DMG
auto findCmd = fmt::format("find \"{}\" -name '*.app' -maxdepth 1", mountPoint);
auto appPath = hex::executeCommandWithOutput(findCmd);
if (!appPath.has_value()) {
hex::log::error("Failed to find .app in DMG");
hex::executeCommand(fmt::format("hdiutil detach \"{}\"", mountPoint));
return false;
}
appPath = wolv::util::trim(*appPath);
if (appPath->empty()) {
hex::log::error("Failed to find .app in DMG");
return false;
}
// Get the app name
auto appName = std::fs::path(*appPath).filename().string();
auto installPath = fmt::format("/Applications/{}", appName);
// Use AppleScript to copy with elevated privileges
auto installScript = fmt::format(
R"(osascript -e 'do shell script "rm -rf \"{}\" && cp -R \"{}\" /Applications/" with administrator privileges')",
installPath, *appPath
);
if (hex::executeCommand(installScript) != 0) {
hex::log::error("Failed to install update");
return false;
}
// Launch the new version
hex::executeCommand(fmt::format("open \"{}\"", installPath));
return true;
}
bool installUpdate(const std::fs::path &updatePath) {
using UpdaterFunction = std::function<bool(const std::fs::path &updatePath)>;
struct UpdateHandler {
std::string ending;
std::string command;
UpdaterFunction func;
};
const static auto UpdateHandlers = {
UpdateHandler { ".msi", "msiexec /i \"{}\" /qb" },
UpdateHandler { ".dmg", "hdiutil attach -autoopen \"{}\"" },
UpdateHandler { ".deb", "zenity --password | sudo -S apt install -y --fix-broken \"{}\"" },
UpdateHandler { ".rpm", "zenity --password | sudo -S rpm -i \"{}\"" },
UpdateHandler { ".pkg.tar.zst", "zenity --password | sudo -S pacman -Syy && sudo pacman -U --noconfirm \"{}\"" },
UpdateHandler { ".AppImage", fmt::format("zenity --password | sudo -S cp \"{{}}\" \"{}\"", hex::getEnvironmentVariable("APPIMAGE").value_or("")) },
UpdateHandler { ".flatpak", "zenity --password | sudo -S flatpak install -y --reinstall \"{}\"" },
UpdateHandler { ".snap", "zenity --password | sudo -S snap install --dangerous \"{}\"" },
UpdateHandler { .ending=".msi", .func=updateCommand("msiexec /i \"{}\" /qb") },
UpdateHandler { .ending=".dmg", .func=updateMacOSBundle },
UpdateHandler { .ending=".deb", .func=updateCommand("zenity --password | sudo -S apt install -y --fix-broken \"{}\"") },
UpdateHandler { .ending=".rpm", .func=updateCommand("zenity --password | sudo -S rpm -i \"{}\"") },
UpdateHandler { .ending=".pkg.tar.zst", .func=updateCommand("zenity --password | sudo -S pacman -Syy && sudo pacman -U --noconfirm \"{}\"") },
UpdateHandler { .ending=".AppImage", .func=updateCommand(fmt::format(R"(zenity --password | sudo -S cp "{{}}" "{}")", hex::getEnvironmentVariable("APPIMAGE").value_or(""))) },
UpdateHandler { .ending=".flatpak", .func=updateCommand("zenity --password | sudo -S flatpak install -y --reinstall \"{}\"") },
UpdateHandler { .ending=".snap", .func=updateCommand("zenity --password | sudo -S snap install --dangerous \"{}\"") },
};
const auto updateFileName = wolv::util::toUTF8String(updatePath.filename());
for (const auto &handler : UpdateHandlers) {
if (updateFileName.ends_with(handler.ending)) {
// Install the update using the correct command
const auto command = fmt::format(fmt::runtime(handler.command), updatePath.string());
hex::log::info("Starting update process with command: '{}'", command);
hex::executeCommand(command);
return true;
return handler.func(updatePath);
}
}
@@ -198,9 +270,11 @@ int main(int argc, char **argv) {
return EXIT_FAILURE;
}
hex::log::info("Updating ImHex...");
// Read the version type from the arguments
const std::string_view versionTypeString = argv[1];
hex::log::info("Updater started with version type: {}", versionTypeString);
hex::log::info("Installing '{}' version of ImHex", versionTypeString);
// Convert the version type string to the enum value
hex::ImHexApi::System::UpdateType updateType;

View File

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

View File

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

View File

@@ -43,7 +43,7 @@ namespace hex::plugin::builtin {
void setPath(const std::fs::path &path);
[[nodiscard]] bool open() override;
[[nodiscard]] OpenResult open() override;
void close() override;
void loadSettings(const nlohmann::json &settings) override;
@@ -65,7 +65,7 @@ namespace hex::plugin::builtin {
private:
void handleFileChange();
bool open(bool memoryMapped);
OpenResult open(bool memoryMapped);
protected:
std::fs::path m_path;

View File

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

View File

@@ -39,7 +39,7 @@ namespace hex::plugin::builtin {
[[nodiscard]] u64 getActualSize() const override;
void processMemoryRegions(wolv::util::Expected<std::map<u64, std::vector<u8>>, std::string> data);
static bool memoryRegionFilter(const std::string &search, const MemoryRegion &memoryRegion);
bool open() override;
OpenResult open() override;
void close() 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 isSavableAsRecent() const override { return false; }
[[nodiscard]] bool open() override;
[[nodiscard]] OpenResult open() override;
void close() override { }
void readRaw(u64 offset, void *buffer, size_t size) override;

View File

@@ -9,7 +9,7 @@ namespace hex::plugin::builtin {
MotorolaSRECProvider() = default;
~MotorolaSRECProvider() override = default;
bool open() override;
OpenResult open() override;
void close() 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 isSavable() const override { return false; }
[[nodiscard]] bool open() override { return true; }
[[nodiscard]] OpenResult open() override { return {}; }
void close() 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;
bool drawLoadInterface() override;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -66,9 +66,6 @@ namespace hex::plugin::builtin {
}
void drawContent() override;
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const override {
return ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse;
}
void setPopupWindowHeight(u32 height) { m_popupWindowHeight = height; }
u32 getPopupWindowHeight() const { return m_popupWindowHeight; }
@@ -152,12 +149,12 @@ namespace hex::plugin::builtin {
std::mutex m_logMutex;
PerProvider<ui::TextEditor::Coordinates> m_cursorPosition;
PerProvider<ImVec2> m_scroll;
PerProvider<ImVec2> m_consoleScroll;
PerProvider<ui::TextEditor::Coordinates> m_consoleCursorPosition;
PerProvider<bool> m_cursorNeedsUpdate;
PerProvider<bool> m_consoleCursorNeedsUpdate;
PerProvider<ui::TextEditor::Selection> m_selection;
PerProvider<ui::TextEditor::Selection> m_consoleSelection;
PerProvider<ui::TextEditor::Range> m_selection;
PerProvider<ui::TextEditor::Range> m_consoleSelection;
PerProvider<size_t> m_consoleLongestLineLength;
PerProvider<ui::TextEditor::Breakpoints> m_breakpoints;
PerProvider<std::optional<pl::core::err::PatternLanguageError>> m_lastEvaluationError;

View File

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

View File

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

View File

@@ -406,7 +406,7 @@
"hex.builtin.popup.exit_application.title": "Exit Application?",
"hex.builtin.popup.waiting_for_tasks.title": "Waiting for Tasks",
"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.blocking_task.title": "Running Task",
"hex.builtin.popup.blocking_task.desc": "A task is currently executing.",
@@ -418,7 +418,7 @@
"hex.builtin.provider.rename": "Rename",
"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.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.disk": "Raw Disk",
"hex.builtin.provider.disk.disk_size": "Disk Size",
@@ -430,6 +430,7 @@
"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.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.creation": "Creation time",
"hex.builtin.provider.file.menu.direct_access": "Direct access file",
@@ -448,6 +449,7 @@
"hex.builtin.provider.gdb.name": "GDB Server <{0}:{1}>",
"hex.builtin.provider.gdb.port": "Port",
"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.name": "Intel Hex {0}",
"hex.builtin.provider.mem_file": "In-Memory File",
@@ -458,6 +460,8 @@
"hex.builtin.provider.opening": "Opening Data Source...",
"hex.builtin.provider.process_memory": "Process Memory",
"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.memory_regions": "Memory Regions",
"hex.builtin.provider.process_memory.name": "'{0}' Process Memory",
@@ -476,6 +480,7 @@
"hex.builtin.provider.udp.port": "Server Port",
"hex.builtin.provider.udp.timestamp": "Timestamp",
"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.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",
@@ -1031,6 +1036,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_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.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.open_pattern": "Open pattern",
"hex.builtin.view.pattern_editor.replace_hint": "Replace",

View File

@@ -358,10 +358,10 @@ namespace hex::plugin::builtin {
std::fs::path filePath = reinterpret_cast<const char8_t*>(args[0].data());
FileProvider provider;
provider.setPath(filePath);
if (!provider.open()) {
log::println("Failed to open file '{}'", args[0]);
auto result = provider.open();
if (result.isFailure()) {
log::println("Failed to open file '{}': {}", args[0], result.getErrorMessage());
std::exit(EXIT_FAILURE);
}

View File

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

View File

@@ -589,9 +589,18 @@ namespace hex::plugin::builtin {
return [value, copyValue] { ImGuiExt::TextFormatted("L\"{0}\"", value.c_str()); return copyValue; };
},
[](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;
}
);
@@ -626,9 +635,18 @@ namespace hex::plugin::builtin {
return [value, copyValue] { ImGuiExt::TextFormatted("u\"{0}\"", value.c_str()); return copyValue; };
},
[](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;
}
);
@@ -663,9 +681,18 @@ namespace hex::plugin::builtin {
return [value, copyValue] { ImGuiExt::TextFormatted("U\"{0}\"", value.c_str()); return copyValue; };
},
[](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;
}
);

View File

@@ -40,30 +40,27 @@
namespace hex::plugin::builtin {
static void openFile(const std::fs::path &path) {
if (path.extension() == ".hexproj") {
if (!ProjectFile::load(path)) {
ui::ToastError::open(fmt::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path)));
}
TaskManager::doLater([path] {
if (path.extension() == ".hexproj") {
if (!ProjectFile::load(path)) {
ui::ToastError::open(fmt::format("hex.builtin.popup.error.project.load"_lang, wolv::util::toUTF8String(path)));
}
return;
}
auto provider = ImHexApi::Provider::createProvider("hex.builtin.provider.file", true);
if (auto *fileProvider = dynamic_cast<FileProvider*>(provider); fileProvider != nullptr) {
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);
AchievementManager::unlockAchievement("hex.builtin.achievement.starting_out", "hex.builtin.achievement.starting_out.open_file.name");
ImHexApi::Provider::setCurrentProvider(provider);
auto provider = ImHexApi::Provider::createProvider("hex.builtin.provider.file", true);
if (auto *fileProvider = dynamic_cast<FileProvider*>(provider.get()); fileProvider != nullptr) {
fileProvider->setPath(path);
glfwRequestWindowAttention(ImHexApi::System::getMainWindowHandle());
glfwFocusWindow(ImHexApi::System::getMainWindowHandle());
}
ImHexApi::Provider::openProvider(provider);
AchievementManager::unlockAchievement("hex.builtin.achievement.starting_out", "hex.builtin.achievement.starting_out.open_file.name");
glfwRequestWindowAttention(ImHexApi::System::getMainWindowHandle());
glfwFocusWindow(ImHexApi::System::getMainWindowHandle());
}
});
}
void registerEventHandlers() {
@@ -180,11 +177,8 @@ namespace hex::plugin::builtin {
RequestOpenWindow::subscribe([](const std::string &name) {
if (name == "Create File") {
auto newProvider = hex::ImHexApi::Provider::createProvider("hex.builtin.provider.mem_file", true);
if (newProvider != nullptr && !newProvider->open())
hex::ImHexApi::Provider::remove(newProvider);
else
EventProviderOpened::post(newProvider);
auto newProvider = ImHexApi::Provider::createProvider("hex.builtin.provider.mem_file", true);
ImHexApi::Provider::openProvider(newProvider);
} else if (name == "Open File") {
fs::openFileBrowser(fs::DialogMode::Open, { }, [](const auto &path) {
if (path.extension() == ".hexproj") {
@@ -195,20 +189,15 @@ namespace hex::plugin::builtin {
}
}
auto newProvider = static_cast<FileProvider*>(
ImHexApi::Provider::createProvider("hex.builtin.provider.file", true)
);
auto provider = ImHexApi::Provider::createProvider("hex.builtin.provider.file", true);
auto newProvider = static_cast<FileProvider*>(provider.get());
if (newProvider == nullptr)
return;
newProvider->setPath(path);
if (!newProvider->open()) {
hex::ImHexApi::Provider::remove(newProvider);
} else {
EventProviderOpened::post(newProvider);
AchievementManager::unlockAchievement("hex.builtin.achievement.starting_out", "hex.builtin.achievement.starting_out.open_file.name");
}
ImHexApi::Provider::openProvider(provider);
AchievementManager::unlockAchievement("hex.builtin.achievement.starting_out", "hex.builtin.achievement.starting_out.open_file.name");
}, {}, true);
} else if (name == "Open Project") {
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
EventProviderCreated::subscribe([](hex::prv::Provider *provider) {
EventProviderCreated::subscribe([](std::shared_ptr<prv::Provider> provider) {
if (provider->shouldSkipLoadInterface())
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()) {
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider.get()); });
return;
}
TaskManager::createBlockingTask("hex.builtin.provider.opening", TaskManager::NoProgress, [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); });
}
});
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); });
}
});
else if (dynamic_cast<prv::IProviderLoadInterface*>(provider.get()) == nullptr) {
ImHexApi::Provider::openProvider(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){
#if defined(NFD_PORTAL)
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 */
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);
if (newProvider != nullptr && !newProvider->open())
hex::ImHexApi::Provider::remove(newProvider);
if (newProvider != nullptr && newProvider->open().isFailure())
hex::ImHexApi::Provider::remove(newProvider.get());
else
EventProviderOpened::post(newProvider);
EventProviderOpened::post(newProvider.get());
}, noRunningTasks, ContentRegistry::Views::getViewByName("hex.builtin.view.hex_editor.name"));
/* Open File */
@@ -401,7 +401,7 @@ namespace hex::plugin::builtin {
auto provider = ImHexApi::Provider::get();
provider->close();
if (!provider->open())
if (provider->open().isFailure())
ImHexApi::Provider::remove(provider, true);
EventDataChanged::post(provider);

View File

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

View File

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

View File

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

View File

@@ -3,8 +3,6 @@
#include <hex/api/content_registry/settings.hpp>
#include <ui/text_editor.hpp>
namespace hex::plugin::builtin {
PopupPasteBehaviour::PopupPasteBehaviour(const Region &selection, const std::function<void(const Region &selection, bool selectionCheck)> &pasteCallback)

View File

@@ -6,8 +6,6 @@
#include <content/differing_byte_searcher.hpp>
#include <ui/text_editor.hpp>
namespace hex::plugin::builtin {
PopupRemove::PopupRemove(u64 address, size_t size) : m_address(address), m_size(size) {}

View File

@@ -87,13 +87,14 @@ namespace hex::plugin::builtin {
newProvider->loadSettings(providerSettings.at("settings"));
loaded = true;
} catch (const std::exception &e){
providerWarnings[newProvider] = e.what();
providerWarnings[newProvider.get()] = e.what();
}
if (loaded) {
if (!newProvider->open() || !newProvider->isAvailable() || !newProvider->isReadable()) {
providerWarnings[newProvider] = newProvider->getErrorMessage();
auto result = newProvider->open();
if (result.isFailure() || !newProvider->isAvailable() || !newProvider->isReadable()) {
providerWarnings[newProvider.get()] = result.getErrorMessage();
} else {
EventProviderOpened::post(newProvider);
EventProviderOpened::post(newProvider.get());
}
}
}

View File

@@ -157,7 +157,8 @@ namespace hex::plugin::builtin {
}
#endif
bool DiskProvider::open() {
prv::Provider::OpenResult DiskProvider::open() {
OpenResult result;
m_readable = true;
m_writable = true;
@@ -171,8 +172,7 @@ namespace hex::plugin::builtin {
m_writable = false;
if (m_diskHandle == INVALID_HANDLE_VALUE) {
this->setErrorMessage(hex::formatSystemError(::GetLastError()));
return false;
return OpenResult::failure(hex::formatSystemError(::GetLastError()));
}
}
@@ -194,12 +194,12 @@ namespace hex::plugin::builtin {
}
if (m_diskHandle == nullptr || m_diskHandle == INVALID_HANDLE_VALUE) {
this->setErrorMessage(hex::formatSystemError(::GetLastError()));
auto error = ::GetLastError();
m_readable = false;
m_diskHandle = nullptr;
CloseHandle(m_diskHandle);
return false;
return OpenResult::failure(hex::formatSystemError(error));
}
#else
@@ -208,17 +208,14 @@ namespace hex::plugin::builtin {
m_diskHandle = ::open(path.c_str(), O_RDWR);
if (m_diskHandle == -1) {
this->setErrorMessage(fmt::format("hex.builtin.provider.disk.error.read_rw"_lang, path, formatSystemError(errno)));
log::warn("{}", this->getErrorMessage());
result = OpenResult::warning(fmt::format("hex.builtin.provider.disk.error.read_rw"_lang, path, formatSystemError(errno)));
m_diskHandle = ::open(path.c_str(), O_RDONLY);
m_writable = false;
}
if (m_diskHandle == -1) {
this->setErrorMessage(fmt::format("hex.builtin.provider.disk.error.read_ro"_lang, path, formatSystemError(errno)));
log::warn("{}", this->getErrorMessage());
m_readable = false;
return false;
return OpenResult::failure(fmt::format("hex.builtin.provider.disk.error.read_ro"_lang, path, formatSystemError(errno)));
}
u64 diskSize = 0;
@@ -228,7 +225,7 @@ namespace hex::plugin::builtin {
#endif
return true;
return result;
}
void DiskProvider::close() {

View File

@@ -198,24 +198,23 @@ namespace hex::plugin::builtin {
m_path.make_preferred();
}
bool FileProvider::open() {
prv::Provider::OpenResult FileProvider::open() {
const size_t maxMemoryFileSize = ContentRegistry::Settings::read<u64>("hex.builtin.setting.general", "hex.builtin.setting.general.max_mem_file_size", 128_MiB);
size_t fileSize = 0x00;
{
wolv::io::File file(m_path, wolv::io::File::Mode::Read);
if (!file.isValid()) {
this->setErrorMessage(fmt::format("hex.builtin.provider.file.error.open"_lang, m_path.string(), formatSystemError(file.getOpenError().value_or(0))));
return false;
return OpenResult::failure(fmt::format("hex.builtin.provider.file.error.open"_lang, m_path.string(), formatSystemError(file.getOpenError().value_or(0))));
}
fileSize = file.getSize();
}
const bool directAccess = fileSize >= maxMemoryFileSize;
const bool result = open(directAccess);
const auto result = open(directAccess);
if (result && directAccess) {
if (result.isSuccess() && directAccess) {
m_writable = false;
ui::BannerButton::open(ICON_VS_WARNING, "hex.builtin.provider.file.too_large", ImColor(135, 116, 66), "hex.builtin.provider.file.too_large.allow_write", [this]{
@@ -227,7 +226,7 @@ namespace hex::plugin::builtin {
return result;
}
bool FileProvider::open(bool directAccess) {
prv::Provider::OpenResult FileProvider::open(bool directAccess) {
m_readable = true;
m_writable = true;
@@ -238,8 +237,7 @@ namespace hex::plugin::builtin {
file = wolv::io::File(m_path, wolv::io::File::Mode::Read);
if (!file.isValid()) {
m_readable = false;
this->setErrorMessage(fmt::format("hex.builtin.provider.file.error.open"_lang, m_path.string(), formatSystemError(file.getOpenError().value_or(0))));
return false;
return OpenResult::failure(fmt::format("hex.builtin.provider.file.error.open"_lang, m_path.string(), formatSystemError(file.getOpenError().value_or(0))));
}
ui::ToastInfo::open("hex.builtin.popup.error.read_only"_lang);
@@ -258,8 +256,7 @@ namespace hex::plugin::builtin {
});
if (alreadyOpenedFileProvider != s_openedFiles.end()) {
ImHexApi::Provider::setCurrentProvider(*alreadyOpenedFileProvider);
return false;
return OpenResult::redirect(*alreadyOpenedFileProvider);
} else {
s_openedFiles.insert(this);
}
@@ -281,7 +278,7 @@ namespace hex::plugin::builtin {
m_changeEventAcknowledgementPending = false;
return true;
return {};
}
@@ -313,10 +310,6 @@ namespace hex::plugin::builtin {
if (!wolv::io::fs::exists(fullPath))
fullPath = path;
if (!wolv::io::fs::exists(fullPath)) {
this->setErrorMessage(fmt::format("hex.builtin.provider.file.error.open"_lang, m_path.string(), formatSystemError(ENOENT)));
}
path = std::move(fullPath);
}

View File

@@ -254,7 +254,7 @@ namespace hex::plugin::builtin {
};
}
bool GDBProvider::open() {
prv::Provider::OpenResult GDBProvider::open() {
std::scoped_lock lock(m_mutex);
CachedProvider::open();
@@ -264,11 +264,11 @@ namespace hex::plugin::builtin {
gdb::sendReceivePackage(m_socket, gdb::createPacket("!"));
gdb::sendReceivePackage(m_socket, gdb::createPacket("Hg0"));
if (m_socket.isConnected()) {
return true;
} else {
return false;
if (!m_socket.isConnected()) {
return OpenResult::failure("hex.builtin.provider.gdb.server.error.not_connected"_lang);
}
return {};
}
void GDBProvider::close() {

View File

@@ -245,21 +245,19 @@ namespace hex::plugin::builtin {
});
}
bool IntelHexProvider::open() {
prv::Provider::OpenResult IntelHexProvider::open() {
auto file = wolv::io::File(m_sourceFilePath, wolv::io::File::Mode::Read);
if (!file.isValid()) {
this->setErrorMessage(fmt::format("hex.builtin.provider.file.error.open"_lang, m_sourceFilePath.string(), formatSystemError(errno)));
return false;
return OpenResult::failure(fmt::format("hex.builtin.provider.file.error.open"_lang, m_sourceFilePath.string(), formatSystemError(errno)));
}
auto data = intel_hex::parseIntelHex(file.readString());
if (!data.has_value()) {
this->setErrorMessage(data.error());
return false;
return OpenResult::failure(data.error());
}
processMemoryRegions(data);
return true;
return {};
}
void IntelHexProvider::close() {

View File

@@ -16,12 +16,12 @@
namespace hex::plugin::builtin {
bool MemoryFileProvider::open() {
prv::Provider::OpenResult MemoryFileProvider::open() {
if (m_data.empty()) {
m_data.resize(1);
}
return true;
return {};
}
void MemoryFileProvider::readRaw(u64 offset, void *buffer, size_t size) {
@@ -51,16 +51,16 @@ namespace hex::plugin::builtin {
auto newProvider = hex::ImHexApi::Provider::createProvider("hex.builtin.provider.file", true);
if (auto fileProvider = dynamic_cast<FileProvider*>(newProvider); fileProvider != nullptr) {
if (auto fileProvider = dynamic_cast<FileProvider*>(newProvider.get()); fileProvider != nullptr) {
fileProvider->setPath(path);
if (!fileProvider->open()) {
ImHexApi::Provider::remove(newProvider);
if (fileProvider->open().isFailure()) {
ImHexApi::Provider::remove(newProvider.get());
} else {
MovePerProviderData::post(this, fileProvider);
fileProvider->markDirty(false);
EventProviderOpened::post(newProvider);
EventProviderOpened::post(newProvider.get());
ImHexApi::Provider::remove(this, true);
}
}

View File

@@ -170,21 +170,19 @@ namespace hex::plugin::builtin {
}
bool MotorolaSRECProvider::open() {
prv::Provider::OpenResult MotorolaSRECProvider::open() {
auto file = wolv::io::File(m_sourceFilePath, wolv::io::File::Mode::Read);
if (!file.isValid()) {
this->setErrorMessage(fmt::format("hex.builtin.provider.file.error.open"_lang, m_sourceFilePath.string(), formatSystemError(errno)));
return false;
return OpenResult::failure(fmt::format("hex.builtin.provider.file.error.open"_lang, m_sourceFilePath.string(), formatSystemError(errno)));
}
auto data = motorola_srec::parseMotorolaSREC(file.readString());
if (!data.has_value()) {
this->setErrorMessage(data.error());
return false;
return OpenResult::failure(data.error());
}
processMemoryRegions(data);
return true;
return {};
}
void MotorolaSRECProvider::close() {

View File

@@ -33,21 +33,21 @@
namespace hex::plugin::builtin {
bool ProcessMemoryProvider::open() {
prv::Provider::OpenResult ProcessMemoryProvider::open() {
if (m_selectedProcess == nullptr)
return false;
return OpenResult::failure("hex.builtin.provider.process_memory.error.no_process_selected"_lang);
#if defined(OS_WINDOWS)
m_processHandle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, m_selectedProcess->id);
if (m_processHandle == nullptr)
return false;
return OpenResult::failure("hex.builtin.provider.process_memory.error.open_process"_lang);
#else
m_processId = pid_t(m_selectedProcess->id);
#endif
this->reloadProcessModules();
return true;
return {};
}
void ProcessMemoryProvider::close() {
@@ -125,7 +125,7 @@ namespace hex::plugin::builtin {
for (const auto &memoryRegion : m_memoryRegions) {
if (address < memoryRegion.region.getStartAddress())
return { Region { lastRegion.getEndAddress() + 1LLU, memoryRegion.region.getStartAddress() - lastRegion.getEndAddress() }, false };
return { Region { lastRegion.getEndAddress(), memoryRegion.region.getStartAddress() - lastRegion.getEndAddress() }, false };
lastRegion = memoryRegion.region;
}

View File

@@ -7,13 +7,13 @@
namespace hex::plugin::builtin {
bool UDPProvider::open() {
prv::Provider::OpenResult UDPProvider::open() {
m_udpServer = UDPServer(m_port, [this](std::span<const u8> data) {
this->receive(data);
});
m_udpServer.start();
return true;
return {};
}
void UDPProvider::close() {

View File

@@ -48,9 +48,9 @@ namespace hex::plugin::builtin {
m_provider->save();
}
[[nodiscard]] bool ViewProvider::open() {
[[nodiscard]] prv::Provider::OpenResult ViewProvider::open() {
if (m_provider == this)
return false;
return OpenResult::failure("hex.builtin.provider.view.error.no_provider"_lang);
EventProviderClosing::subscribe(this, [this](const prv::Provider *provider, bool*) {
if (m_provider == provider) {
@@ -59,7 +59,7 @@ namespace hex::plugin::builtin {
}
});
return true;
return {};
}
void ViewProvider::close() {
EventProviderClosing::unsubscribe(this);

View File

@@ -279,18 +279,11 @@ namespace hex::plugin::builtin::recent {
return;
}
auto *provider = ImHexApi::Provider::createProvider(recentEntry.type, true);
auto provider = ImHexApi::Provider::createProvider(recentEntry.type, true);
if (provider != nullptr) {
provider->loadSettings(recentEntry.data);
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); });
}
});
ImHexApi::Provider::openProvider(provider);
updateRecentEntries();
}

View File

@@ -1247,7 +1247,7 @@ namespace hex::plugin::builtin {
if (isLocationValid(error.getLocation())) {
auto key = ui::TextEditor::Coordinates(error.getLocation().line, error.getLocation().column);
if (!errorMarkers.contains(key) || errorMarkers[key].first < error.getLocation().length)
if (!errorMarkers.contains(key) || errorMarkers[key].first < (i32) error.getLocation().length)
errorMarkers[key] = std::make_pair(error.getLocation().length, processMessage(error.getMessage()));
}
}

View File

@@ -3,6 +3,7 @@
#include <hex/api/imhex_api/system.hpp>
#include <hex/api/localization_manager.hpp>
#include <hex/api/task_manager.hpp>
#include <hex/api/tutorial_manager.hpp>
#include <hex/api/events/events_provider.hpp>
#include <hex/api/events/events_gui.hpp>
@@ -523,7 +524,6 @@ namespace hex::plugin::builtin {
flags |= ImGuiTabItemFlags_UnsavedDocument;
if (i64(i) == selectedProviderIndex && providerJustChanged) {
flags |= ImGuiTabItemFlags_SetSelected;
providerJustChanged = false;
}
static size_t lastSelectedProvider = 0;
@@ -534,7 +534,7 @@ namespace hex::plugin::builtin {
ImGui::EndTabItem();
}
if (isSelected && lastSelectedProvider != i) {
if (isSelected && lastSelectedProvider != i && !providerJustChanged) {
ImHexApi::Provider::setCurrentProvider(i);
lastSelectedProvider = i;
}
@@ -554,6 +554,8 @@ namespace hex::plugin::builtin {
}
}
ImGui::EndTabBar();
providerJustChanged = false;
}
}
ImGui::EndDisabled();

View File

@@ -15,8 +15,9 @@ namespace hex::plugin::builtin {
ViewFullScreenFileInfo::ViewFullScreenFileInfo(std::fs::path filePath) : m_filePath(std::move(filePath)) {
this->m_provider.setPath(m_filePath);
if (!this->m_provider.open()) {
if (this->m_provider.open().isFailure()) {
ui::ToastError::open("hex.builtin.view.fullscreen.file_info.error.file_not_readable"_lang);
return;
}
m_analysisTask = TaskManager::createBlockingTask("hex.builtin.view.fullscreen.file_info.analyzing", TaskManager::NoProgress, [this](Task &task) {

View File

@@ -67,8 +67,9 @@ namespace hex::plugin::builtin {
if (ImGuiExt::DimmedButton(fmt::format("{} {}", ICON_VS_OPEN_PREVIEW, "hex.builtin.view.fullscreen.save_editor.select_file"_lang).c_str(), ImVec2(-1, 0))) {
fs::openFileBrowser(fs::DialogMode::Open, {}, [this](const std::fs::path &path) {
this->m_provider.setPath(path);
if (!this->m_provider.open()) {
if (this->m_provider.open().isFailure()) {
ui::ToastError::open("hex.builtin.view.fullscreen.save_editor.error.not_readable"_lang);
return;
}
ContentRegistry::PatternLanguage::configureRuntime(m_runtime, &m_provider);

View File

@@ -20,6 +20,7 @@
#include <wolv/io/file.hpp>
#include <wolv/utils/guards.hpp>
#include "imgui_internal.h"
namespace hex::plugin::builtin {
@@ -389,14 +390,13 @@ namespace hex::plugin::builtin {
auto provider = ImHexApi::Provider::get();
TaskManager::doLater([region, provider, name]{
auto newProvider = ImHexApi::Provider::createProvider("hex.builtin.provider.view", true);
if (auto *viewProvider = dynamic_cast<ViewProvider*>(newProvider); viewProvider != nullptr) {
if (auto *viewProvider = dynamic_cast<ViewProvider*>(newProvider.get()); viewProvider != nullptr) {
viewProvider->setProvider(region.getStartAddress(), region.getSize(), provider);
viewProvider->setName(fmt::format("'{}' View", name));
if (viewProvider->open()) {
EventProviderOpened::post(viewProvider);
AchievementManager::unlockAchievement("hex.builtin.achievement.hex_editor", "hex.builtin.achievement.hex_editor.open_new_view.name");
}
ImHexApi::Provider::openProvider(newProvider);
AchievementManager::unlockAchievement("hex.builtin.achievement.hex_editor", "hex.builtin.achievement.hex_editor.open_new_view.name");
}
});
}

View File

@@ -441,6 +441,10 @@ namespace hex::plugin::builtin {
}
}
if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
m_selectedEntryName.reset();
}
// Enter editing mode when double-clicking the row
const bool editable = entry.editingFunction.has_value() && m_selectedProvider->isWritable();
if (ImGui::IsItemHovered()) {
@@ -469,6 +473,10 @@ namespace hex::plugin::builtin {
return;
}
if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
entry.editing = false;
}
// Handle editing mode
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
ImGui::SetNextItemWidth(-1);

View File

@@ -1187,7 +1187,7 @@ namespace hex::plugin::builtin {
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableSetupColumn("hex.ui.common.offset"_lang, 0, -1, ImGui::GetID("offset"));
ImGui::TableSetupColumn("hex.ui.common.size"_lang, 0, -1, ImGui::GetID("size"));
ImGui::TableSetupColumn("hex.ui.common.value"_lang, 0, -1, ImGui::GetID("value"));
ImGui::TableSetupColumn("hex.ui.common.value"_lang, ImGuiTableColumnFlags_WidthStretch, -1, ImGui::GetID("value"));
auto sortSpecs = ImGui::TableGetSortSpecs();
@@ -1197,22 +1197,22 @@ namespace hex::plugin::builtin {
}
if (sortSpecs->SpecsDirty) {
std::sort(currOccurrences.begin(), currOccurrences.end(), [this, &sortSpecs, provider](const Occurrence &left, const Occurrence &right) -> bool {
std::ranges::stable_sort(currOccurrences, [this, &sortSpecs, provider](const Occurrence &left, const Occurrence &right) -> bool {
if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("offset")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return left.region.getStartAddress() > right.region.getStartAddress();
else
return left.region.getStartAddress() < right.region.getStartAddress();
else
return left.region.getStartAddress() > right.region.getStartAddress();
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("size")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return left.region.getSize() > right.region.getSize();
else
return left.region.getSize() < right.region.getSize();
else
return left.region.getSize() > right.region.getSize();
} else if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("value")) {
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
return this->decodeValue(provider, left) > this->decodeValue(provider, right);
else
return this->decodeValue(provider, left) < this->decodeValue(provider, right);
else
return this->decodeValue(provider, left) > this->decodeValue(provider, right);
}
return false;

View File

@@ -43,7 +43,6 @@
#include <content/popups/hex_editor/popup_hex_editor_find.hpp>
#include <pl/patterns/pattern.hpp>
#include <hex/helpers/menu_items.hpp>
#include <ui/text_editor.hpp>
#include <wolv/literals.hpp>
using namespace std::literals::string_literals;
@@ -60,8 +59,10 @@ namespace hex::plugin::builtin {
std::optional<color_t> result;
for (const auto &[id, callback] : ImHexApi::HexEditor::impl::getForegroundHighlightingFunctions()) {
if (auto color = callback(address, data, size, result.has_value()); color.has_value())
if (auto color = callback(address, data, size, result.has_value()); color.has_value()) {
result = color;
break;
}
}
if (!result.has_value()) {
@@ -95,7 +96,7 @@ namespace hex::plugin::builtin {
});
ContentRegistry::Settings::onChange("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.show_extended_ascii", [this](const ContentRegistry::Settings::SettingsValue &value) {
m_hexEditor.enableShowExtendedAscii(value.get<bool>(true));
m_hexEditor.enableShowExtendedAscii(value.get<bool>(false));
});
ContentRegistry::Settings::onChange("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.minimap", [this](const ContentRegistry::Settings::SettingsValue &value) {
@@ -1167,10 +1168,9 @@ namespace hex::plugin::builtin {
auto selection = ImHexApi::HexEditor::getSelection();
auto newProvider = ImHexApi::Provider::createProvider("hex.builtin.provider.view", true);
if (auto *viewProvider = dynamic_cast<ViewProvider*>(newProvider); viewProvider != nullptr) {
if (auto *viewProvider = dynamic_cast<ViewProvider*>(newProvider.get()); viewProvider != nullptr) {
viewProvider->setProvider(selection->getStartAddress(), selection->getSize(), selection->getProvider());
if (viewProvider->open())
EventProviderOpened::post(viewProvider);
ImHexApi::Provider::openProvider(newProvider);
}
},
[] { return ImHexApi::HexEditor::isSelectionValid() && ImHexApi::Provider::isValid(); },

View File

@@ -181,7 +181,7 @@ namespace hex::plugin::builtin {
// Draw a table containing all the existing highlighting rules
if (ImGui::BeginTable("RulesList", 2, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_ScrollY, ImGui::GetContentRegionAvail() - ImVec2(0, ImGui::GetTextLineHeightWithSpacing() + ImGui::GetStyle().WindowPadding.y))) {
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 1);
ImGui::TableSetupColumn("Enabled", ImGuiTableColumnFlags_WidthFixed, 10_scaled);
ImGui::TableSetupColumn("Enabled", ImGuiTableColumnFlags_WidthFixed, 15_scaled);
for (auto it = m_rules->begin(); it != m_rules->end(); ++it) {
auto &rule = *it;
@@ -197,6 +197,9 @@ namespace hex::plugin::builtin {
}
ImGui::EndDisabled();
if (m_selectedRule == it && !rule.enabled)
m_selectedRule = m_rules->end();
// Draw enabled checkbox
ImGui::TableNextColumn();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2());

View File

@@ -15,7 +15,7 @@ namespace hex::plugin::builtin {
using namespace hex::literals;
ViewInformation::ViewInformation() : View::Window("hex.builtin.view.information.name", ICON_VS_GRAPH_LINE) {
ViewInformation::ViewInformation() : View::Scrolling("hex.builtin.view.information.name", ICON_VS_GRAPH_LINE) {
m_analysisData.setOnCreateCallback([](const prv::Provider *provider, AnalysisData &data) {
data.analyzedProvider = provider;

View File

@@ -213,7 +213,7 @@ namespace hex::plugin::builtin {
bool patternsValid = false;
auto &runtime = ContentRegistry::PatternLanguage::getRuntime();
if (TRY_LOCK(ContentRegistry::PatternLanguage::getRuntimeLock())) {
patternsValid = runtime.arePatternsValid();
patternsValid = runtime.getCreatedPatternCount() > 0 && runtime.arePatternsValid();
}
if (ImGui::BeginTabBar("##SectionSelector")) {

View File

@@ -477,11 +477,6 @@ namespace hex::plugin::builtin {
m_textEditor.get(provider).selectWordUnderCursor();
}
if (m_cursorNeedsUpdate.get(provider)) {
m_textEditor.get(provider).setFocusAtCoords(m_cursorPosition.get(provider));
m_cursorNeedsUpdate.get(provider) = false;
}
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr) {
setupFindReplace(editor);
setupGotoLine(editor);
@@ -716,7 +711,7 @@ namespace hex::plugin::builtin {
ImGui::TableNextColumn();
static int findFlags = ImGuiInputTextFlags_EnterReturnsTrue;
static int findFlags = ImGuiInputTextFlags_None;
std::string hint = "hex.builtin.view.pattern_editor.find_hint"_lang.operator std::string();
if (m_findHistorySize > 0) {
@@ -724,6 +719,8 @@ namespace hex::plugin::builtin {
hint += ICON_BI_DATA_TRANSFER_BOTH;
hint += "hex.builtin.view.pattern_editor.find_hint_history"_lang.operator std::string();
}
static bool enterPressedReplace = false;
static bool enterPressedFind = false;
ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
if (ImGui::InputTextWithHint("###findInputTextWidget", hint.c_str(), findWord, findFlags) || enter ) {
@@ -775,6 +772,12 @@ namespace hex::plugin::builtin {
updateCount = true;
requestFocusFind = true;
}
if (ImGui::IsItemHovered()) {
if (ImGui::BeginTooltip()) {
ImGui::TextUnformatted("hex.builtin.view.pattern_editor.match_case_tooltip"_lang);
ImGui::EndTooltip();
}
}
ImGui::SameLine();
@@ -791,7 +794,12 @@ namespace hex::plugin::builtin {
updateCount = true;
requestFocusFind = true;
}
if (ImGui::IsItemHovered()) {
if (ImGui::BeginTooltip()) {
ImGui::TextUnformatted("hex.builtin.view.pattern_editor.whole_word_tooltip"_lang);
ImGui::EndTooltip();
}
}
ImGui::SameLine();
bool useRegex = findReplaceHandler->getFindRegEx();
@@ -807,6 +815,13 @@ namespace hex::plugin::builtin {
updateCount = true;
requestFocusFind = true;
}
if (ImGui::IsItemHovered()) {
if (ImGui::BeginTooltip()) {
ImGui::TextUnformatted("hex.builtin.view.pattern_editor.regex_tooltip"_lang);
ImGui::EndTooltip();
}
}
static std::string counterString;
@@ -852,12 +867,15 @@ namespace hex::plugin::builtin {
if (ImGuiExt::IconButton(ICON_VS_ARROW_UP, ImVec4(1, 1, 1, 1)))
upArrowFind = true;
static bool downArrowReplace = false;
static bool upArrowReplace = false;
static std::string replaceWord;
if (m_replaceMode) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TableNextColumn();
static int replaceFlags = ImGuiInputTextFlags_EnterReturnsTrue;
static int replaceFlags = ImGuiInputTextFlags_None;
hint = "hex.builtin.view.pattern_editor.replace_hint"_lang.operator std::string();
if (m_replaceHistorySize > 0) {
@@ -867,31 +885,13 @@ namespace hex::plugin::builtin {
}
ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
static std::string replaceWord;
static bool downArrowReplace = false;
static bool upArrowReplace = false;
if (ImGui::InputTextWithHint("###replaceInputTextWidget", hint.c_str(), replaceWord, replaceFlags) || downArrowReplace || upArrowReplace) {
findReplaceHandler->setReplaceWord(replaceWord);
historyInsert(m_replaceHistory, m_replaceHistorySize, m_replaceHistoryIndex, replaceWord);
if (ImGui::InputTextWithHint("###replaceInputTextWidget", hint.c_str(), replaceWord, replaceFlags) || enter) {
if (enter)
enterPressedReplace = true;
bool textReplaced = findReplaceHandler->replace(textEditor, !shift && !upArrowReplace);
if (textReplaced) {
if (count > 0) {
if (position == count)
position -= 1;
count -= 1;
}
updateCount = true;
}
downArrowReplace = false;
upArrowReplace = false;
if (enterPressedFind) {
enterPressedFind = false;
requestFocusFind = false;
}
updateCount = true;
requestFocusReplace = true;
findReplaceHandler->setReplaceWord(replaceWord);
}
if (requestFocus || requestFocusReplace) {
@@ -947,6 +947,31 @@ namespace hex::plugin::builtin {
requestFocusFind = true;
enterPressedFind = false;
}
if (downArrowReplace || upArrowReplace || enterPressedReplace) {
historyInsert(m_replaceHistory, m_replaceHistorySize, m_replaceHistoryIndex, replaceWord);
findReplaceHandler->m_undoBuffer.clear();
bool textReplaced = findReplaceHandler->replace(textEditor, !shift && !upArrowReplace);
textEditor->addUndo(findReplaceHandler->m_undoBuffer);
if (textReplaced) {
if (count > 0) {
if (position == count)
position -= 1;
count -= 1;
}
updateCount = true;
}
downArrowReplace = false;
upArrowReplace = false;
if (enterPressedFind) {
enterPressedFind = false;
requestFocusFind = false;
}
requestFocusReplace = true;
enterPressedReplace = false;
}
}
// Escape key to close the popup
if (ImGui::IsKeyPressed(ImGuiKey_Escape, false)) {
@@ -1045,10 +1070,6 @@ namespace hex::plugin::builtin {
m_consoleEditor.get(provider).clearRaiseContextMenu();
}
if (m_consoleCursorNeedsUpdate.get(provider)) {
m_consoleEditor.get(provider).setFocusAtCoords(m_consoleCursorPosition.get(provider));
m_consoleCursorNeedsUpdate.get(provider) = false;
}
if (m_consoleNeedsUpdate) {
std::scoped_lock lock(m_logMutex);
@@ -1352,7 +1373,7 @@ namespace hex::plugin::builtin {
auto source = error.getLocation().source;
if (source != nullptr && source->mainSource) {
auto key = ui::TextEditor::Coordinates(error.getLocation().line, error.getLocation().column);
if (!errorMarkers.contains(key) ||errorMarkers[key].first < error.getLocation().length)
if (!errorMarkers.contains(key) || (u32) errorMarkers[key].first < error.getLocation().length)
errorMarkers[key] = std::make_pair(u32(error.getLocation().length), processMessage(error.getMessage()));
}
}
@@ -1679,6 +1700,9 @@ namespace hex::plugin::builtin {
EventHighlightingChanged::post();
TaskManager::createTask("hex.builtin.view.pattern_editor.evaluating", TaskManager::NoProgress, [this, code, provider](auto &task) {
// Disable exception tracing to speed up evaluation
trace::disableExceptionCaptureForCurrentThread();
auto runtimeLock = std::scoped_lock(ContentRegistry::PatternLanguage::getRuntimeLock());
auto &runtime = ContentRegistry::PatternLanguage::getRuntime();
@@ -1836,31 +1860,30 @@ namespace hex::plugin::builtin {
EventProviderChanged::subscribe(this, [this](prv::Provider *oldProvider, prv::Provider *newProvider) {
if (oldProvider != nullptr) {
m_sourceCode.get(oldProvider) = m_textEditor.get(oldProvider).getText();
m_scroll.get(oldProvider) = m_textEditor.get(oldProvider).getScroll();
m_cursorPosition.get(oldProvider) = m_textEditor.get(oldProvider).getCursorPosition();
m_selection.get(oldProvider) = m_textEditor.get(oldProvider).getSelection();
m_breakpoints.get(oldProvider) = m_textEditor.get(oldProvider).getBreakpoints();
m_consoleCursorPosition.get(oldProvider) = m_consoleEditor.get(oldProvider).getCursorPosition();
m_consoleSelection.get(oldProvider) = m_consoleEditor.get(oldProvider).getSelection();
m_consoleLongestLineLength.get(oldProvider) = m_consoleEditor.get(oldProvider).getLongestLineLength();
m_breakpoints.get(oldProvider) = m_textEditor.get(oldProvider).getBreakpoints();
m_cursorNeedsUpdate.get(oldProvider) = false;
m_consoleCursorNeedsUpdate.get(oldProvider) = false;
m_consoleScroll.get(oldProvider) = m_consoleEditor.get(oldProvider).getScroll();
}
if (newProvider != nullptr) {
m_textEditor.get(newProvider).setText(wolv::util::preprocessText(m_sourceCode.get(newProvider)));
m_textEditor.get(newProvider).setCursorPosition(m_cursorPosition.get(newProvider));
ui::TextEditor::Selection selection = m_selection.get(newProvider);
m_textEditor.get(newProvider).setSelection(selection);
m_textEditor.get(newProvider).setCursorPosition(m_cursorPosition.get(newProvider),false);
m_textEditor.get(newProvider).setScroll(m_scroll.get(newProvider));
m_textEditor.get(newProvider).setSelection(m_selection.get(newProvider));
m_textEditor.get(newProvider).setBreakpoints(m_breakpoints.get(newProvider));
m_textEditor.get(newProvider).setTextChanged(false);
m_hasUnevaluatedChanges.get(newProvider) = true;
m_consoleEditor.get(newProvider).setText(wolv::util::combineStrings(m_console.get(newProvider), "\n"));
m_consoleEditor.get(newProvider).setCursorPosition(m_consoleCursorPosition.get(newProvider));
m_consoleEditor.get(newProvider).setLongestLineLength(m_consoleLongestLineLength.get(newProvider));
selection = m_consoleSelection.get(newProvider);
m_consoleEditor.get(newProvider).setSelection(selection);
m_cursorNeedsUpdate.get(newProvider) = true;
m_consoleCursorNeedsUpdate.get(newProvider) = true;
m_textEditor.get(newProvider).setTextChanged(false);
m_hasUnevaluatedChanges.get(newProvider) = true;
m_consoleEditor.get(newProvider).setSelection(m_consoleSelection.get(newProvider));
m_consoleEditor.get(newProvider).setScroll(m_consoleScroll.get(newProvider));
}
m_textHighlighter.m_needsToUpdateColors = false;
@@ -1959,7 +1982,7 @@ namespace hex::plugin::builtin {
ui::TextEditor::FindReplaceHandler *findReplaceHandler = editor->getFindReplaceHandler();
findReplaceHandler->findMatch(editor, 1);
} else {
m_textEditor->getFindReplaceHandler()->findMatch(&*m_textEditor, 1);
m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->findMatch(&m_textEditor.get(ImHexApi::Provider::get()), 1);
}
}, [this] {
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr) {
@@ -1977,11 +2000,11 @@ namespace hex::plugin::builtin {
ui::TextEditor::FindReplaceHandler *findReplaceHandler = editor->getFindReplaceHandler();
findReplaceHandler->findMatch(editor, -1);
} else {
m_textEditor->getFindReplaceHandler()->findMatch(&*m_textEditor, -1);
m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->findMatch(&m_textEditor.get(ImHexApi::Provider::get()), -1);
}
}, [this] {
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr) {
return ImHexApi::Provider::isValid() && !m_textEditor->getFindReplaceHandler()->getFindWord().empty();
return ImHexApi::Provider::isValid() && !m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->getFindWord().empty();
} else {
return false;
}
@@ -1998,22 +2021,22 @@ namespace hex::plugin::builtin {
/* Replace Next */
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.view.pattern_editor.menu.replace_next" }, 1550, Shortcut::None, [this] {
m_textEditor->getFindReplaceHandler()->replace(&*m_textEditor, true);
}, [this] { return ImHexApi::Provider::isValid() && !m_textEditor->getFindReplaceHandler()->getReplaceWord().empty() && m_focusedSubWindowName.contains(TextEditorView); },
m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->replace(&m_textEditor.get(ImHexApi::Provider::get()), true);
}, [this] { return ImHexApi::Provider::isValid() && !m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->getReplaceWord().empty() && m_focusedSubWindowName.contains(TextEditorView); },
[]{ return false; },
this);
/* Replace Previous */
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.view.pattern_editor.menu.replace_previous" }, 1560, Shortcut::None, [this] {
m_textEditor->getFindReplaceHandler()->replace(&*m_textEditor, false);
}, [this] { return ImHexApi::Provider::isValid() && !m_textEditor->getFindReplaceHandler()->getReplaceWord().empty() && m_focusedSubWindowName.contains(TextEditorView); },
m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->replace(&m_textEditor.get(ImHexApi::Provider::get()), false);
}, [this] { return ImHexApi::Provider::isValid() && !m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->getReplaceWord().empty() && m_focusedSubWindowName.contains(TextEditorView); },
[]{ return false; },
this);
/* Replace All */
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.view.pattern_editor.menu.replace_all" }, ICON_VS_REPLACE_ALL, 1570, Shortcut::None, [this] {
m_textEditor->getFindReplaceHandler()->replaceAll(&*m_textEditor);
}, [this] { return ImHexApi::Provider::isValid() && !m_textEditor->getFindReplaceHandler()->getReplaceWord().empty() && m_focusedSubWindowName.contains(TextEditorView); },
m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->replaceAll(&m_textEditor.get(ImHexApi::Provider::get()));
}, [this] { return ImHexApi::Provider::isValid() && !m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->getReplaceWord().empty() && m_focusedSubWindowName.contains(TextEditorView); },
this);
@@ -2032,19 +2055,19 @@ namespace hex::plugin::builtin {
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.export", "hex.builtin.menu.file.export.pattern" }, ICON_VS_FILE_CODE, 7050, Shortcut::None, [this] {
savePatternAsNewFile(false);
}, [this] {
return ImHexApi::Provider::isValid() && !wolv::util::trim(m_textEditor->getText()).empty();
return ImHexApi::Provider::isValid() && !wolv::util::trim(m_textEditor.get(ImHexApi::Provider::get()).getText()).empty();
});
/* Undo */
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.pattern_editor.menu.edit.undo" }, ICON_VS_DISCARD, 1250, AllowWhileTyping + CTRLCMD + Keys::Z, [this] {
m_textEditor->undo();
}, [this] { return ImHexApi::Provider::isValid() && m_textEditor->canUndo() && m_focusedSubWindowName.contains(TextEditorView); },
m_textEditor.get(ImHexApi::Provider::get()).undo();
}, [this] { return ImHexApi::Provider::isValid() && m_textEditor.get(ImHexApi::Provider::get()).canUndo() && m_focusedSubWindowName.contains(TextEditorView); },
this);
/* Redo */
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.pattern_editor.menu.edit.redo" }, ICON_VS_REDO, 1275, AllowWhileTyping + CTRLCMD + Keys::Y, [this] {
m_textEditor->redo();
}, [this] { return ImHexApi::Provider::isValid() && m_textEditor->canRedo() && m_focusedSubWindowName.contains(TextEditorView); },
m_textEditor.get(ImHexApi::Provider::get()).redo();
}, [this] { return ImHexApi::Provider::isValid() && m_textEditor.get(ImHexApi::Provider::get()).canRedo() && m_focusedSubWindowName.contains(TextEditorView); },
this);
ContentRegistry::UserInterface::addMenuItemSeparator({ "hex.builtin.menu.edit" }, 1280, this);
@@ -2052,8 +2075,8 @@ namespace hex::plugin::builtin {
/* Cut */
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.pattern_editor.menu.edit.cut" }, ICON_VS_COMBINE, 1300, AllowWhileTyping + CTRLCMD + Keys::X, [this] {
m_textEditor->cut();
}, [this] { return ImHexApi::Provider::isValid() && m_textEditor->hasSelection() && m_focusedSubWindowName.contains(TextEditorView); },
m_textEditor.get(ImHexApi::Provider::get()).cut();
}, [this] { return ImHexApi::Provider::isValid() && m_textEditor.get(ImHexApi::Provider::get()).hasSelection() && m_focusedSubWindowName.contains(TextEditorView); },
this);
/* Copy */
@@ -2061,7 +2084,7 @@ namespace hex::plugin::builtin {
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr) {
editor->copy();
} else {
m_textEditor->copy();
m_textEditor.get(ImHexApi::Provider::get()).copy();
}
}, [this] {
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr)
@@ -2073,7 +2096,7 @@ namespace hex::plugin::builtin {
/* Paste */
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.pattern_editor.menu.edit.paste" }, ICON_VS_OUTPUT, 1500, AllowWhileTyping + CTRLCMD + Keys::V, [this] {
m_textEditor->paste();
m_textEditor.get(ImHexApi::Provider::get()).paste();
}, [this] { return m_focusedSubWindowName.contains(TextEditorView); },
this);
@@ -2089,7 +2112,7 @@ namespace hex::plugin::builtin {
/* Add Breakpoint */
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.pattern_editor.menu.edit.add_breakpoint"}, ICON_VS_DEBUG_BREAKPOINT_DATA, 1750, Keys::F8 + AllowWhileTyping, [this] {
const auto line = m_textEditor.get(ImHexApi::Provider::get()).getCursorPosition().m_line + 1;
const auto line = m_textEditor.get(ImHexApi::Provider::get()).getCursorPosition().getLine() + 1;
const auto &runtime = ContentRegistry::PatternLanguage::getRuntime();
auto &evaluator = runtime.getInternals().evaluator;
@@ -2618,7 +2641,7 @@ namespace hex::plugin::builtin {
if (provider == nullptr)
return;
auto path = m_changeTracker.get(provider).getPath();
wolv::io::File file(path, wolv::io::File::Mode::Write);
wolv::io::File file(path, wolv::io::File::Mode::Create);
if (file.isValid() && trackFile) {
if (isPatternDirty(provider)) {
file.writeString(wolv::util::trim(m_textEditor.get(provider).getText()));

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