mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-28 07:47:03 -05:00
Compare commits
254 Commits
disassembl
...
v1.32.2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a1edb1b896 | ||
|
|
b27e63586e | ||
|
|
d2bd5b5640 | ||
|
|
f91505ff09 | ||
|
|
464495987a | ||
|
|
27aef75e54 | ||
|
|
70e3b4dd1a | ||
|
|
556fd2bbc3 | ||
|
|
0097d1782e | ||
|
|
f03bdc5f45 | ||
|
|
ebf379f7c1 | ||
|
|
cd72ff1f84 | ||
|
|
eca41cac16 | ||
|
|
a8e2e132d1 | ||
|
|
499711b9af | ||
|
|
b0eec3a844 | ||
|
|
24e90f0f20 | ||
|
|
ff48d37598 | ||
|
|
c402d58685 | ||
|
|
ed8934882e | ||
|
|
62093a8dd8 | ||
|
|
4a5f1038e0 | ||
|
|
8cb833eca9 | ||
|
|
e2b7a69fc8 | ||
|
|
950eaea8af | ||
|
|
b22d90f9ca | ||
|
|
b76e7ff678 | ||
|
|
9c386e949d | ||
|
|
2b1688be31 | ||
|
|
3d9de1aaa6 | ||
|
|
5a0a5ad445 | ||
|
|
038b98eacf | ||
|
|
3592d17c93 | ||
|
|
4cbd84671c | ||
|
|
c3c9603ea1 | ||
|
|
af63b42eaf | ||
|
|
2f7da91a73 | ||
|
|
8fcf08132e | ||
|
|
db72ba295a | ||
|
|
2d7a6a7cb5 | ||
|
|
390b5a7925 | ||
|
|
5ca6ed30b4 | ||
|
|
9685b39969 | ||
|
|
03dc26d2d4 | ||
|
|
b64bb3bec9 | ||
|
|
8d3530a4f3 | ||
|
|
83b1416797 | ||
|
|
5adeac6bbc | ||
|
|
f44b44a881 | ||
|
|
1ed978f22e | ||
|
|
7ed06ae515 | ||
|
|
63042dbba8 | ||
|
|
144d8d8ed4 | ||
|
|
99ba47a554 | ||
|
|
0462dab170 | ||
|
|
258481b0ba | ||
|
|
cb35f456ed | ||
|
|
686f8f43c3 | ||
|
|
99dcd0a020 | ||
|
|
3c6f52f5ea | ||
|
|
874619f62e | ||
|
|
74b5c93caf | ||
|
|
ec45d1f564 | ||
|
|
42a75fe133 | ||
|
|
e414c1cf1e | ||
|
|
1cf692cecf | ||
|
|
af5b871383 | ||
|
|
37d60411bb | ||
|
|
d7ba2e7171 | ||
|
|
215be9255e | ||
|
|
9d0fd1f5b6 | ||
|
|
4e0a93fc20 | ||
|
|
a0fddd2953 | ||
|
|
40e66313a9 | ||
|
|
87155f98b3 | ||
|
|
483325990c | ||
|
|
83fa024fab | ||
|
|
96fe608d60 | ||
|
|
52192a3b26 | ||
|
|
75e575fc01 | ||
|
|
98bc89cb39 | ||
|
|
d2d244ebc7 | ||
|
|
9952854b53 | ||
|
|
3bb079216c | ||
|
|
b845dbb882 | ||
|
|
7eb92c68de | ||
|
|
24f8ce9d7f | ||
|
|
343e98c99a | ||
|
|
bc76eee847 | ||
|
|
91ae8ba410 | ||
|
|
e2489151f3 | ||
|
|
9066891ce2 | ||
|
|
65e2f1b5af | ||
|
|
020efefb25 | ||
|
|
83f8370e2a | ||
|
|
61accd9569 | ||
|
|
8a428df7df | ||
|
|
de6bb5dfb9 | ||
|
|
80561001b8 | ||
|
|
33d077e997 | ||
|
|
fe24db7c57 | ||
|
|
61bfe10bc2 | ||
|
|
84bfd10416 | ||
|
|
538e79183c | ||
|
|
ec64952cb4 | ||
|
|
b934ca6ad3 | ||
|
|
0da6c03a8f | ||
|
|
a54cbca6d2 | ||
|
|
ad8e3e38f0 | ||
|
|
ffc1aa6a91 | ||
|
|
6ee1e72021 | ||
|
|
5bc8e5c57c | ||
|
|
d48acf7fef | ||
|
|
72260b5323 | ||
|
|
e84b8cb96d | ||
|
|
adcaad791a | ||
|
|
b0490cfbbc | ||
|
|
86231d0154 | ||
|
|
6163f6c4a0 | ||
|
|
e3e117a14e | ||
|
|
e2ae567b9f | ||
|
|
a0c2dc43f7 | ||
|
|
f47163c4ad | ||
|
|
e951359a46 | ||
|
|
bf6b2db0cb | ||
|
|
1ea8269dec | ||
|
|
9bd1970371 | ||
|
|
5b3ae56912 | ||
|
|
2b5789631f | ||
|
|
a6025e72fb | ||
|
|
96db2074c6 | ||
|
|
c7ab4a4569 | ||
|
|
dd4be3b772 | ||
|
|
8fe490ed03 | ||
|
|
eb21a5992f | ||
|
|
a3f1a5b0a9 | ||
|
|
71763d108b | ||
|
|
dc9ab135c8 | ||
|
|
3dd33d0966 | ||
|
|
1cb2e0d765 | ||
|
|
b34fb2d225 | ||
|
|
4973556fc8 | ||
|
|
2948e57242 | ||
|
|
521ee5fe2d | ||
|
|
478d6118d8 | ||
|
|
1b43270ae9 | ||
|
|
ec4fdc44ef | ||
|
|
91f49e2c6e | ||
|
|
6bc4a7242e | ||
|
|
eeab529bfa | ||
|
|
d798713c60 | ||
|
|
edc4b18975 | ||
|
|
450c93e029 | ||
|
|
c1abbfad7d | ||
|
|
d2d36c2211 | ||
|
|
aaaa02dbd0 | ||
|
|
a844fb3731 | ||
|
|
8f83fe5135 | ||
|
|
978558649e | ||
|
|
3b5efb37e9 | ||
|
|
90abe982ed | ||
|
|
7a0680c2cb | ||
|
|
71dd349044 | ||
|
|
f2a795c51e | ||
|
|
7ad7ea061c | ||
|
|
a315ecb831 | ||
|
|
c3d99e29dc | ||
|
|
f90f4b00a8 | ||
|
|
b1aa4fd3f8 | ||
|
|
b5df20d7c6 | ||
|
|
b58463bbaf | ||
|
|
b71a776770 | ||
|
|
78ef5b0d07 | ||
|
|
c1f76be3b7 | ||
|
|
2ebd3c6f35 | ||
|
|
003f9619c3 | ||
|
|
710ceedf3d | ||
|
|
5b77f511d3 | ||
|
|
f000b6bc0a | ||
|
|
346f1362c6 | ||
|
|
92043a3d23 | ||
|
|
3bc5295eae | ||
|
|
5bcfe37b4e | ||
|
|
1a8a9e53e1 | ||
|
|
c32dad75cd | ||
|
|
045733d188 | ||
|
|
f618e634e9 | ||
|
|
1b457dae7d | ||
|
|
690b0df932 | ||
|
|
e080164305 | ||
|
|
1e4bb8c91e | ||
|
|
17a7621342 | ||
|
|
ce27cb11a5 | ||
|
|
b84b82c416 | ||
|
|
623e074ba0 | ||
|
|
91230ba438 | ||
|
|
cc4d61f8f5 | ||
|
|
7a4358a5ec | ||
|
|
e6796d1458 | ||
|
|
1ba34c233e | ||
|
|
ef7898ea8d | ||
|
|
e49c3182ce | ||
|
|
c58c3dd311 | ||
|
|
7738f8c831 | ||
|
|
27cd3cc83a | ||
|
|
2f5e04d07f | ||
|
|
15af0726f1 | ||
|
|
a60a45fb9d | ||
|
|
df03ba3883 | ||
|
|
09a148b8a5 | ||
|
|
350635d464 | ||
|
|
cf13404254 | ||
|
|
878f45dd80 | ||
|
|
48bc0985d9 | ||
|
|
e9bca123c2 | ||
|
|
6df3a9243f | ||
|
|
f1b40d0500 | ||
|
|
0cbaf40747 | ||
|
|
54c5d9debb | ||
|
|
411884966b | ||
|
|
ef25542220 | ||
|
|
b4813660b5 | ||
|
|
f08d1e265c | ||
|
|
470bc8a049 | ||
|
|
5c84ef5f72 | ||
|
|
8ab85a2af1 | ||
|
|
7f69f8bcdb | ||
|
|
3a016da549 | ||
|
|
7b3e13c748 | ||
|
|
f5cbcce112 | ||
|
|
5f8c813aa7 | ||
|
|
f68202a098 | ||
|
|
bfb2c6ab5f | ||
|
|
00a24bc84b | ||
|
|
9ba6d7ee1e | ||
|
|
60ff62d018 | ||
|
|
5d24f1b691 | ||
|
|
370ca740e3 | ||
|
|
ba8430d9e7 | ||
|
|
0b71568d97 | ||
|
|
37ac1b66dd | ||
|
|
1be9e8c5b1 | ||
|
|
c6b9b947fb | ||
|
|
a1ef567ecd | ||
|
|
2b22a15e8c | ||
|
|
760b8c7a88 | ||
|
|
13145bba03 | ||
|
|
f9a9ed4846 | ||
|
|
d5a40d46bc | ||
|
|
19f3da556c | ||
|
|
e8f0a3bd23 | ||
|
|
08fd09064a | ||
|
|
caee764af3 | ||
|
|
eae3cd99ee |
9
.gdbinit
9
.gdbinit
@@ -6,4 +6,11 @@ skip -rfu ^__gnu_debug::
|
||||
skip -rfu ^ImGui::
|
||||
|
||||
# Trigger breakpoint when execution reaches triggerSafeShutdown()
|
||||
break triggerSafeShutdown
|
||||
break triggerSafeShutdown
|
||||
|
||||
# Print backtrace after execution jumped to an invalid address
|
||||
define fixbt
|
||||
set $pc = *(void **)$rsp
|
||||
set $rsp = $rsp + 8
|
||||
bt
|
||||
end
|
||||
5
.gitattributes
vendored
5
.gitattributes
vendored
@@ -1 +1,4 @@
|
||||
lib/external/** linguist-vendored
|
||||
lib/external/** linguist-vendored
|
||||
|
||||
dist/*.sh eol=lf
|
||||
dist/**/*Dockerfile eol=lf
|
||||
100
.github/workflows/build.yml
vendored
100
.github/workflows/build.yml
vendored
@@ -95,7 +95,7 @@ jobs:
|
||||
echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE
|
||||
|
||||
- name: ⬆️ Upload Windows Installer
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: Windows Installer x86_64
|
||||
@@ -103,7 +103,7 @@ jobs:
|
||||
imhex-*.msi
|
||||
|
||||
- name: ⬆️ Upload Portable ZIP
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: Windows Portable x86_64
|
||||
@@ -120,7 +120,7 @@ jobs:
|
||||
mv opengl32.dll build/install
|
||||
|
||||
- name: ⬆️ Upload NoGPU Portable ZIP
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: Windows Portable NoGPU x86_64
|
||||
@@ -238,15 +238,17 @@ jobs:
|
||||
ninja package
|
||||
|
||||
- name: ⬆️ Upload DMG
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: macOS DMG${{matrix.suffix}} x86_64
|
||||
path: build/*.dmg
|
||||
|
||||
macos-arm64:
|
||||
macos-arm64-build:
|
||||
runs-on: ubuntu-22.04
|
||||
name: 🍎 macOS 12.1 arm64
|
||||
outputs:
|
||||
IMHEX_VERSION: ${{ steps.build.outputs.IMHEX_VERSION }}
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v3
|
||||
@@ -266,13 +268,15 @@ jobs:
|
||||
cache-target: /cache
|
||||
|
||||
- name: 🛠️ Build using docker
|
||||
id: build
|
||||
run: |
|
||||
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_OUTPUT
|
||||
docker buildx build . -f dist/macOS/arm64.Dockerfile --progress=plain --build-arg 'JOBS=4' --build-arg "BUILD_TYPE=$(BUILD_TYPE)" --build-context imhex=$(pwd) --output out
|
||||
|
||||
- name: ⬆️ Upload artifacts
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: macOS ZIP arm64
|
||||
name: macos_arm64_intermediate
|
||||
path: out/
|
||||
|
||||
# See https://github.com/actions/cache/issues/342#issuecomment-1711054115
|
||||
@@ -282,7 +286,56 @@ jobs:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
gh extension install actions/gh-actions-cache
|
||||
gh actions-cache delete "build-macos-arm64-cache" --confirm
|
||||
gh actions-cache delete "build-macos-arm64-cache" --confirm || true
|
||||
|
||||
macos-arm64-package:
|
||||
runs-on: macos-12
|
||||
name: 🍎 macOS 12.1 arm64 Packaging
|
||||
needs: macos-arm64-build
|
||||
env:
|
||||
IMHEX_VERSION: ${{ needs.macos-arm64-build.outputs.IMHEX_VERSION }}
|
||||
steps:
|
||||
- name: ⬇️ Download artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: macos_arm64_intermediate
|
||||
path: out
|
||||
|
||||
- name: 🗑️ Delete artifact
|
||||
uses: geekyeggo/delete-artifact@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
name: macos_arm64_intermediate
|
||||
|
||||
- name: ✒️ Fix Signature
|
||||
run: |
|
||||
set -x
|
||||
cd out
|
||||
codesign --remove-signature ImHex.app
|
||||
codesign --force --deep --sign - ImHex.app
|
||||
|
||||
- name: 📁 Fix permissions
|
||||
run: |
|
||||
set -x
|
||||
cd out
|
||||
chmod -R 755 ImHex.app/
|
||||
|
||||
- name: 📦 Create DMG
|
||||
run: |
|
||||
set -x
|
||||
mkdir bundle
|
||||
mv out/ImHex.app bundle
|
||||
cd bundle
|
||||
ln -s /Applications Applications
|
||||
cd ..
|
||||
hdiutil create -volname "ImHex" -srcfolder bundle -ov -format UDZO imhex-${{env.IMHEX_VERSION}}-macOS-arm64.dmg
|
||||
|
||||
- name: ⬆️ Upload DMG
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: macOS DMG arm64
|
||||
path: ./*.dmg
|
||||
|
||||
# Ubuntu build
|
||||
ubuntu:
|
||||
@@ -335,14 +388,9 @@ jobs:
|
||||
with:
|
||||
dotnet-version: '8.0.100'
|
||||
|
||||
- name: 🏔️ Set Environment variables
|
||||
run: |
|
||||
echo COMMIT_SHA_SHORT=$(git rev-parse --short HEAD) >> $GITHUB_ENV
|
||||
echo COMMIT_SHA_LONG=$(git rev-parse HEAD) >> $GITHUB_ENV
|
||||
echo COMMIT_BRANCH=$(git rev-parse --abbrev-ref HEAD) >> $GITHUB_ENV
|
||||
|
||||
# Ubuntu cmake build
|
||||
- name: 🛠️ Build
|
||||
shell: bash
|
||||
run: |
|
||||
set -x
|
||||
git config --global --add safe.directory '*'
|
||||
@@ -354,9 +402,9 @@ jobs:
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_COMMIT_HASH_SHORT="${{ env.COMMIT_SHA_SHORT }}" \
|
||||
-DIMHEX_COMMIT_HASH_LONG="${{ env.COMMIT_SHA_LONG }}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${{ env.COMMIT_BRANCH }}" \
|
||||
-DIMHEX_COMMIT_HASH_SHORT="${GITHUB_SHA::7}" \
|
||||
-DIMHEX_COMMIT_HASH_LONG="${GITHUB_SHA}" \
|
||||
-DIMHEX_COMMIT_BRANCH="${GITHUB_REF##*/}" \
|
||||
-DIMHEX_ENABLE_LTO=ON \
|
||||
-DIMHEX_USE_GTK_FILE_PICKER=ON \
|
||||
-DDOTNET_EXECUTABLE="dotnet" \
|
||||
@@ -374,7 +422,7 @@ jobs:
|
||||
mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-${{ matrix.release_num }}-x86_64.deb
|
||||
|
||||
- name: ⬆️ Upload DEB
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: Ubuntu ${{ matrix.release_num }} DEB x86_64
|
||||
@@ -410,14 +458,14 @@ jobs:
|
||||
|
||||
|
||||
- name: ⬆️ Upload AppImage
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: Linux AppImage x86_64
|
||||
path: 'out/*.AppImage'
|
||||
|
||||
- name: ⬆️ Upload AppImage zsync
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: Linux AppImage zsync x86_64
|
||||
@@ -520,7 +568,7 @@ jobs:
|
||||
mv *.pkg.tar.zst imhex-${{env.IMHEX_VERSION}}-ArchLinux-x86_64.pkg.tar.zst
|
||||
|
||||
- name: ⬆️ Upload imhex-archlinux.pkg.tar.zst
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: ArchLinux .pkg.tar.zst x86_64
|
||||
@@ -537,14 +585,14 @@ jobs:
|
||||
mock_release: rawhide
|
||||
release_num: rawhide
|
||||
mock_config: fedora-rawhide
|
||||
- name: Fedora
|
||||
mock_release: f39
|
||||
release_num: 39
|
||||
mock_config: fedora-39
|
||||
- name: Fedora
|
||||
mock_release: f38
|
||||
release_num: 38
|
||||
mock_config: fedora-38
|
||||
- name: Fedora
|
||||
mock_release: f37
|
||||
release_num: 37
|
||||
mock_config: fedora-37
|
||||
- name: RHEL-AlmaLinux
|
||||
mock_release: epel9
|
||||
release_num: 9
|
||||
@@ -648,7 +696,7 @@ jobs:
|
||||
$GITHUB_WORKSPACE/imhex-${{env.IMHEX_VERSION}}-${{matrix.name}}-${{matrix.release_num}}-x86_64.rpm
|
||||
|
||||
- name: ⬆️ Upload RPM
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
if-no-files-found: error
|
||||
name: ${{ matrix.name }} ${{ matrix.release_num }} RPM x86_64
|
||||
|
||||
6
.github/workflows/build_web.yml
vendored
6
.github/workflows/build_web.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: cache
|
||||
key: build-web-cache
|
||||
key: web-cmakecache-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: 🐳 Inject /cache into docker
|
||||
uses: reproducible-containers/buildkit-cache-dance@v2.1.2
|
||||
@@ -43,9 +43,7 @@ jobs:
|
||||
|
||||
- name: 🔨 Fix permissions
|
||||
run: |
|
||||
chmod -c -R +rX "out/" | while read line; do
|
||||
echo "::warning title=Invalid file permissions automatically fixed::$line"
|
||||
done
|
||||
chmod -c -R +rX "out/"
|
||||
|
||||
- name: ⬆️ Upload artifacts
|
||||
uses: actions/upload-pages-artifact@v2
|
||||
|
||||
1
.github/workflows/release.yml
vendored
1
.github/workflows/release.yml
vendored
@@ -154,7 +154,6 @@ jobs:
|
||||
WINGET_GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.WINGET_GITHUB_TOKEN != '' }}"
|
||||
run: |
|
||||
set -x
|
||||
$tagname = $env:GITHUB_REF.Replace("refs/tags/", "")
|
||||
$version = $tagname.Replace("v", "")
|
||||
$url = "https://github.com/WerWolv/ImHex/releases/download/${tagname}/imhex-${version}-Windows-x86_64.msi"
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -3,9 +3,11 @@
|
||||
|
||||
cmake-build-*/
|
||||
build*/
|
||||
local/
|
||||
venv/
|
||||
|
||||
*.mgc
|
||||
imgui.ini
|
||||
.DS_Store
|
||||
./CMakeUserPresets.json
|
||||
./CMakeUserPresets.json
|
||||
Brewfile.lock.json
|
||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -33,3 +33,6 @@
|
||||
path = lib/external/libwolv
|
||||
url = https://github.com/WerWolv/libwolv
|
||||
|
||||
[submodule "lib/third_party/HashLibPlus"]
|
||||
path = lib/third_party/HashLibPlus
|
||||
url = https://github.com/WerWolv/HashLibPlus
|
||||
|
||||
@@ -39,17 +39,13 @@ setDefaultBuiltTypeIfUnset()
|
||||
detectBadClone()
|
||||
verifyCompiler()
|
||||
|
||||
# List plugin names here. Project name must match folder name
|
||||
set(PLUGINS
|
||||
builtin
|
||||
windows
|
||||
script_loader
|
||||
)
|
||||
detectBundledPlugins()
|
||||
|
||||
# Add various defines
|
||||
detectOS()
|
||||
detectArch()
|
||||
addDefines()
|
||||
|
||||
# Configure packaging and install targets
|
||||
configurePackingResources()
|
||||
setUninstallTarget()
|
||||
addBundledLibraries()
|
||||
@@ -64,6 +60,7 @@ add_subdirectory(main)
|
||||
enable_testing()
|
||||
add_subdirectory(tests EXCLUDE_FROM_ALL)
|
||||
|
||||
# Configure packaging
|
||||
# Configure more resources that will be added to the install package
|
||||
createPackage()
|
||||
generatePDBs()
|
||||
generateSDKDirectory()
|
||||
288
README.md
288
README.md
@@ -51,86 +51,259 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
|
||||
## Screenshots
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
<details>
|
||||
<summary><strong>More Screenshots</strong></summary>
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
</details>
|
||||
|
||||
## Features
|
||||
|
||||
- Featureful hex view
|
||||
<details>
|
||||
<summary><strong>Featureful hex view</strong></summary>
|
||||
|
||||
- Byte patching
|
||||
- Patch management
|
||||
- Copy bytes as feature
|
||||
- Infinite Undo/Redo
|
||||
- "Copy bytes as..."
|
||||
- Bytes
|
||||
- Hex string
|
||||
- C, C++, C#, Rust, Python, Java & JavaScript array
|
||||
- ASCII-Art hex view
|
||||
- HTML self-contained div
|
||||
- String and hex search
|
||||
- Colorful highlighting
|
||||
- Simple string and hex search
|
||||
- Goto from start, end and current cursor position
|
||||
- Custom C++-like pattern language for parsing highlighting a file's content
|
||||
- Automatic loading based on MIME type
|
||||
- arrays, pointers, structs, unions, enums, bitfields, namespaces, little and big endian support, conditionals and much more!
|
||||
- Colorful highlighting
|
||||
- Configurable foreground highlighting rules
|
||||
- Background highlighting using patterns, find results and bookmarks
|
||||
- Displaying data as a list of many different types
|
||||
- Hexadecimal integers (8, 16, 32, 64 bit)
|
||||
- Signed and unsigned decimal integers (8, 16, 32, 64 bit)
|
||||
- Floats (16, 32, 64 bit)
|
||||
- RGBA8 Colors
|
||||
- HexII
|
||||
- Binary
|
||||
- Decoding data as ASCII and custom encodings
|
||||
- Built-in support for UTF-8, UTF-16, ShiftJIS, most Windows encodings and many more
|
||||
- Paged data view
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Custom C++-like pattern language for parsing highlighting a file's content</strong></summary>
|
||||
|
||||
- Automatic loading based on MIME types and magic values
|
||||
- Arrays, pointers, structs, unions, enums, bitfields, namespaces, little and big endian support, conditionals and much more!
|
||||
- Useful error messages, syntax highlighting and error marking
|
||||
- Doesn't burn out your retinas when used in late-night sessions
|
||||
- Dark mode by default, but a light mode is available as well
|
||||
- Data importing
|
||||
- Support for visualizing many different types of data
|
||||
- Images
|
||||
- Audio
|
||||
- 3D Models
|
||||
- Coordinates
|
||||
- Time stamps
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Theming support</strong></summary>
|
||||
|
||||
- Doesn't burn out your retinas when used in late-night sessions
|
||||
- Dark mode by default, but a light mode is available as well
|
||||
- Customizable colors and styles for all UI elements through shareable theme files
|
||||
- Support for custom fonts
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Importing and Exporting data</strong></summary>
|
||||
|
||||
- Base64 files
|
||||
- IPS and IPS32 patches
|
||||
- Data exporting
|
||||
- IPS and IPS32 patches
|
||||
- Data inspector allowing interpretation of data as many different types (little and big endian)
|
||||
- Huge file support with fast and efficient loading
|
||||
- String search
|
||||
- Copying of strings
|
||||
- Copying of demangled strings
|
||||
- File hashing support
|
||||
- CRC16 and CRC32 with custom initial values and polynomials
|
||||
- MD4, MD5
|
||||
- SHA-1, SHA-224, SHA-256, SHA-384, SHA-512
|
||||
- Disassembler supporting many architectures (frontend for Capstone)
|
||||
- ARM32 (ARM, Thumb, Cortex-M, AArch32)
|
||||
- ARM64
|
||||
- MIPS (MIPS32, MIPS64, MIPS32R6, Micro)
|
||||
- x86 (16-bit, 32-bit, 64-bit)
|
||||
- PowerPC (32-bit, 64-bit)
|
||||
- SPARC
|
||||
- IBM SystemZ
|
||||
- xCORE
|
||||
- M68K
|
||||
- TMS320C64X
|
||||
- M680X
|
||||
- Ethereum
|
||||
- RISC-V
|
||||
- WebAssembly
|
||||
- MOS65XX
|
||||
- Berkeley Packet Filter
|
||||
- Bookmarks
|
||||
- Region highlighting
|
||||
- Comments
|
||||
- Data Analyzer
|
||||
- Markdown reports
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Data Inspector</strong></summary>
|
||||
|
||||
- Interpreting data as many different types with endianess, decimal, hexadecimal and octal support and bit inversion
|
||||
- Unsigned and signed integers (8, 16, 24, 32, 48, 64 bit)
|
||||
- Floats (16, 32, 64 bit)
|
||||
- Signed and Unsigned LEB128
|
||||
- ASCII, Wide and UTF-8 characters and strings
|
||||
- time32_t, time64_t, DOS date and time
|
||||
- GUIDs
|
||||
- RGBA8 and RGB65 Colors
|
||||
- Copying and modifying bytes through the inspector
|
||||
- Adding new data types through the pattern language
|
||||
- Support for hiding rows that aren't used
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Node-based data pre-processor</strong></summary>
|
||||
|
||||
- Modify, decrypt and decode data before it's being displayed in the hex editor
|
||||
- Modify data without touching the underlying source
|
||||
- Support for adding custom nodes
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Loading data from many different data sources</strong></summary>
|
||||
|
||||
- Local Files
|
||||
- Support for huge files with fast and efficient loading
|
||||
- Raw Disks
|
||||
- Loading data from raw disks and partitions
|
||||
- GDB Server
|
||||
- Access the RAM of a running process or embedded devices through GDB
|
||||
- Intel Hex and Motorola SREC data
|
||||
- Process Memory
|
||||
- Inspect the entire address space of a running process
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Data searching</strong></summary>
|
||||
|
||||
- Support for searching the entire file or only a selection
|
||||
- String extraction
|
||||
- Option to specify minimum length and character set (lower case, upper case, digits, symbols)
|
||||
- Option to specify encoding (ASCII, UTF-8, UTF-16 big and little endian)
|
||||
- Sequence search
|
||||
- Search for a sequence of bytes or characters
|
||||
- Option to ignore character case
|
||||
- Regex search
|
||||
- Search for strings using regular expressions
|
||||
- Binary Pattern
|
||||
- Search for sequences of bytes with optional wildcards
|
||||
- Numeric Value search
|
||||
- Search for signed/unsigned integers and floats
|
||||
- Search for ranges of values
|
||||
- Option to specify size and endianess
|
||||
- Option to ignore unaligned values
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Data hashing support</strong></summary>
|
||||
|
||||
- Many different algorithms available
|
||||
- CRC8, CRC16 and CRC32 with custom initial values and polynomials
|
||||
- Many default polynomials available
|
||||
- MD5
|
||||
- SHA-1, SHA-224, SHA-256, SHA-384, SHA-512
|
||||
- Adler32
|
||||
- AP
|
||||
- BKDR
|
||||
- Bernstein, Bernstein1
|
||||
- DEK, DJB, ELF, FNV1, FNV1a, JS, PJW, RS, SDBM
|
||||
- OneAtTime, Rotating, ShiftAndXor, SuperFast
|
||||
- Murmur2_32, MurmurHash3_x86_32, MurmurHash3_x86_128, MurmurHash3_x64_128
|
||||
- SipHash64, SipHash128
|
||||
- XXHash32, XXHash64
|
||||
- Tiger, Tiger2
|
||||
- Blake2B, Blake2S
|
||||
- Hashing of specific regions of the loaded data
|
||||
- Hashing of arbitrary strings
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Diffing support</strong></summary>
|
||||
|
||||
- Compare data of different data sources
|
||||
- Difference highlighting
|
||||
- Table view of differences
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Integrated disassembler</strong></summary>
|
||||
|
||||
- Support for all architectures supported by Capstone
|
||||
- ARM32 (ARM, Thumb, Cortex-M, AArch32)
|
||||
- ARM64
|
||||
- MIPS (MIPS32, MIPS64, MIPS32R6, Micro)
|
||||
- x86 (16-bit, 32-bit, 64-bit)
|
||||
- PowerPC (32-bit, 64-bit)
|
||||
- SPARC
|
||||
- IBM SystemZ
|
||||
- xCORE
|
||||
- M68K
|
||||
- TMS320C64X
|
||||
- M680X
|
||||
- Ethereum
|
||||
- RISC-V
|
||||
- WebAssembly
|
||||
- MOS65XX
|
||||
- Berkeley Packet Filter
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Bookmarks</strong></summary>
|
||||
|
||||
- Support for bookmarks with custom names and colors
|
||||
- Highlighting of bookmarked region in the hex editor
|
||||
- Jump to bookmarks
|
||||
- Open content of bookmark in a new tab
|
||||
- Add comments to bookmarks
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Featureful data analyzer and visualizer</strong></summary>
|
||||
|
||||
- File magic-based file parser and MIME type database
|
||||
- Byte distribution graph
|
||||
- Byte type distribution graph
|
||||
- Entropy graph
|
||||
- Highest and average entropy
|
||||
- Encrypted / Compressed file detection
|
||||
- Built-in Content Store
|
||||
- Download all files found in the database directly from within ImHex
|
||||
- Yara Rules support
|
||||
- Quickly scan a file for vulnerabilities with official yara rules
|
||||
- Helpful tools
|
||||
- Itanium and MSVC demangler
|
||||
- Digram and Layered distribution graphs
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>YARA Rule support</strong></summary>
|
||||
|
||||
- Scan a file for vulnerabilities with official yara rules
|
||||
- Highlight matches in the hex editor
|
||||
- Jump to matches
|
||||
- Apply multiple rules at once
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Helpful tools</strong></summary>
|
||||
|
||||
- Itanium, MSVC, Rust and D-Lang demangler based on LLVM
|
||||
- ASCII table
|
||||
- Regex replacer
|
||||
- Mathematical expression evaluator (Calculator)
|
||||
- Hexadecimal Color picker
|
||||
- Graphing calculator
|
||||
- Hexadecimal Color picker with support for many different formats
|
||||
- Base converter
|
||||
- Byte swapper
|
||||
- UNIX Permissions calculator
|
||||
- Wikipedia term definition finder
|
||||
- File utilities
|
||||
- File splitter
|
||||
- File combiner
|
||||
- File shredder
|
||||
- IEEE754 Float visualizer
|
||||
- Division by invariant multiplication calculator
|
||||
- TCP Client/Server
|
||||
- Euclidean algorithm calculator
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Built-in Content updater</strong></summary>
|
||||
|
||||
- Download all files found in the database directly from within ImHex
|
||||
- Pattern files for decoding various file formats
|
||||
- Libraries for the pattern language
|
||||
- Magic files for file type detection
|
||||
- Custom data processor nodes
|
||||
- Custom encodings
|
||||
- Custom themes
|
||||
- Yara rules
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Modern Interface</strong></summary>
|
||||
|
||||
- Support for multiple workspaces
|
||||
- Support for custom layouts
|
||||
- Detachable windows
|
||||
</details>
|
||||
<details>
|
||||
<summary><strong>Easy to get started</strong></summary>
|
||||
|
||||
- Support for many different languages
|
||||
- Simplified mode for beginners
|
||||
- Extensive documentation
|
||||
- Many example files available on [the Database](https://github.com/WerWolv/ImHex-Patterns)
|
||||
- Achievements guiding you through the features of ImHex
|
||||
- Interactive tutorials
|
||||
</details>
|
||||
|
||||
## Pattern Language
|
||||
|
||||
@@ -148,7 +321,13 @@ For format patterns, libraries, magic and constant files, check out the [ImHex-P
|
||||
|
||||
## Requirements
|
||||
|
||||
To use ImHex, the following minimal system requirements need to be met:
|
||||
To use ImHex, the following minimal system requirements need to be met.
|
||||
|
||||
> [!IMPORTANT]
|
||||
> ImHex requires a GPU with OpenGL 3.0 support in general.
|
||||
> There are releases available (with the `-NoGPU` suffix) that are software rendered and don't require a GPU, however these can be a lot slower than the GPU accelerated versions.
|
||||
>
|
||||
> If possible at all, make ImHex use the dedicated GPU on your system instead of the integrated one (especially Intel HD GPUs are known to cause issues).
|
||||
|
||||
- **OS**:
|
||||
- **Windows**: Windows 7 or higher (Windows 10/11 recommended)
|
||||
@@ -175,8 +354,9 @@ To compile ImHex on any platform, GCC (or Clang) is required with a version that
|
||||
On macOS, Clang is also required to compile some ObjC code.
|
||||
All releases are being built using latest available GCC.
|
||||
|
||||
Many dependencies are bundled into the repository using submodules so make sure to clone it using the `--recurse-submodules` option.
|
||||
All dependencies that aren't bundled, can be installed using the dependency installer scripts found in the `/dist` folder.
|
||||
> [!NOTE]
|
||||
> Many dependencies are bundled into the repository using submodules so make sure to clone it using the `--recurse-submodules` option.
|
||||
> All dependencies that aren't bundled, can be installed using the dependency installer scripts found in the `/dist` folder.
|
||||
|
||||
For more information, check out the [Compiling](/dist/compiling) guide.
|
||||
|
||||
|
||||
@@ -68,8 +68,10 @@ macro(detectOS)
|
||||
set(PLUGINS_INSTALL_LOCATION "share/imhex/plugins")
|
||||
else()
|
||||
set(PLUGINS_INSTALL_LOCATION "${CMAKE_INSTALL_LIBDIR}/imhex/plugins")
|
||||
# Warning : Do not work with portable versions such as appimage (because the path is hardcoded)
|
||||
add_compile_definitions(SYSTEM_PLUGINS_LOCATION="${CMAKE_INSTALL_FULL_LIBDIR}/imhex") # "plugins" will be appended from the app
|
||||
|
||||
# Add System plugin location for plugins to be loaded from
|
||||
# IMPORTANT: This does not work for Sandboxed or portable builds such as the Flatpak or AppImage release
|
||||
add_compile_definitions(SYSTEM_PLUGINS_LOCATION="${CMAKE_INSTALL_FULL_LIBDIR}/imhex")
|
||||
endif()
|
||||
|
||||
else ()
|
||||
@@ -78,16 +80,6 @@ macro(detectOS)
|
||||
|
||||
endmacro()
|
||||
|
||||
# Detect 32 vs. 64 bit system
|
||||
macro(detectArch)
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||
add_compile_definitions(ARCH_64_BIT)
|
||||
elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||
add_compile_definitions(ARCH_32_BIT)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
|
||||
macro(configurePackingResources)
|
||||
if (WIN32)
|
||||
if (NOT (CMAKE_BUILD_TYPE STREQUAL "Debug"))
|
||||
@@ -108,11 +100,12 @@ macro(configurePackingResources)
|
||||
set(CPACK_PACKAGE_INSTALL_DIRECTORY "ImHex")
|
||||
set_property(INSTALL "$<TARGET_FILE_NAME:main>"
|
||||
PROPERTY CPACK_START_MENU_SHORTCUTS "ImHex"
|
||||
)
|
||||
)
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/resources/dist/windows/LICENSE.rtf")
|
||||
endif()
|
||||
elseif (APPLE)
|
||||
set (IMHEX_ICON "${IMHEX_BASE_FOLDER}/resources/dist/macos/AppIcon.icns")
|
||||
elseif (APPLE OR ${CMAKE_HOST_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(IMHEX_ICON "${IMHEX_BASE_FOLDER}/resources/dist/macos/AppIcon.icns")
|
||||
set(BUNDLE_NAME "imhex.app")
|
||||
|
||||
if (IMHEX_GENERATE_PACKAGE)
|
||||
set(APPLICATION_TYPE MACOSX_BUNDLE)
|
||||
@@ -129,9 +122,9 @@ macro(configurePackingResources)
|
||||
string(TIMESTAMP CURR_YEAR "%Y")
|
||||
set(MACOSX_BUNDLE_COPYRIGHT "Copyright © 2020 - ${CURR_YEAR} WerWolv. All rights reserved." )
|
||||
if ("${CMAKE_GENERATOR}" STREQUAL "Xcode")
|
||||
set (IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/imhex.app")
|
||||
set (IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/${BUNDLE_NAME}")
|
||||
else ()
|
||||
set (IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/imhex.app")
|
||||
set (IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/${BUNDLE_NAME}")
|
||||
endif()
|
||||
|
||||
set(PLUGINS_INSTALL_LOCATION "${IMHEX_BUNDLE_PATH}/Contents/MacOS/plugins")
|
||||
@@ -147,28 +140,28 @@ macro(createPackage)
|
||||
foreach (plugin IN LISTS PLUGINS)
|
||||
add_subdirectory("plugins/${plugin}")
|
||||
if (TARGET ${plugin})
|
||||
get_target_property(IS_RUST_PROJECT ${plugin} RUST_PROJECT)
|
||||
|
||||
set_target_properties(${plugin} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
|
||||
if (IS_RUST_PROJECT)
|
||||
set_target_properties(${plugin} PROPERTIES CARGO_BUILD_TARGET_DIR ${CMAKE_BINARY_DIR}/plugins)
|
||||
|
||||
get_target_property(PLUGIN_LOCATION ${plugin} LOCATION)
|
||||
|
||||
install(FILES "${PLUGIN_LOCATION}/../${plugin}.hexplug" DESTINATION "${PLUGINS_INSTALL_LOCATION}" PERMISSIONS ${LIBRARY_PERMISSIONS})
|
||||
else ()
|
||||
if (APPLE)
|
||||
if (IMHEX_GENERATE_PACKAGE)
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PLUGINS_INSTALL_LOCATION})
|
||||
else ()
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
endif ()
|
||||
if (APPLE)
|
||||
if (IMHEX_GENERATE_PACKAGE)
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${PLUGINS_INSTALL_LOCATION})
|
||||
else ()
|
||||
install(TARGETS ${plugin} LIBRARY DESTINATION ${PLUGINS_INSTALL_LOCATION})
|
||||
set_target_properties(${plugin} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins)
|
||||
endif ()
|
||||
endif ()
|
||||
else ()
|
||||
if (WIN32)
|
||||
get_target_property(target_type ${plugin} TYPE)
|
||||
if (target_type STREQUAL "SHARED_LIBRARY")
|
||||
install(TARGETS ${plugin} RUNTIME DESTINATION ${PLUGINS_INSTALL_LOCATION})
|
||||
else ()
|
||||
install(TARGETS ${plugin} LIBRARY DESTINATION ${PLUGINS_INSTALL_LOCATION})
|
||||
endif()
|
||||
else()
|
||||
install(TARGETS ${plugin} LIBRARY DESTINATION ${PLUGINS_INSTALL_LOCATION})
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
add_dependencies(imhex_all ${plugin})
|
||||
endif ()
|
||||
@@ -180,12 +173,17 @@ macro(createPackage)
|
||||
# Install binaries directly in the prefix, usually C:\Program Files\ImHex.
|
||||
set(CMAKE_INSTALL_BINDIR ".")
|
||||
|
||||
set(PLUGIN_TARGET_FILES "")
|
||||
foreach (plugin IN LISTS PLUGINS)
|
||||
list(APPEND PLUGIN_TARGET_FILES "$<TARGET_FILE:${plugin}>")
|
||||
endforeach ()
|
||||
|
||||
# Grab all dynamically linked dependencies.
|
||||
INSTALL(CODE "set(CMAKE_INSTALL_BINDIR \"${CMAKE_INSTALL_BINDIR}\")")
|
||||
INSTALL(CODE "LIST(APPEND DEP_FOLDERS \${PY_PARENT})")
|
||||
install(CODE "set(CMAKE_INSTALL_BINDIR \"${CMAKE_INSTALL_BINDIR}\")")
|
||||
install(CODE "set(PLUGIN_TARGET_FILES \"${PLUGIN_TARGET_FILES}\")")
|
||||
install(CODE [[
|
||||
file(GET_RUNTIME_DEPENDENCIES
|
||||
EXECUTABLES $<TARGET_FILE:builtin> $<TARGET_FILE:libimhex> $<TARGET_FILE:main>
|
||||
EXECUTABLES ${PLUGIN_TARGET_FILES} $<TARGET_FILE:libimhex> $<TARGET_FILE:main>
|
||||
RESOLVED_DEPENDENCIES_VAR _r_deps
|
||||
UNRESOLVED_DEPENDENCIES_VAR _u_deps
|
||||
CONFLICTING_DEPENDENCIES_PREFIX _c_deps
|
||||
@@ -212,61 +210,70 @@ macro(createPackage)
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
|
||||
set_target_properties(libimhex PROPERTIES SOVERSION ${IMHEX_VERSION})
|
||||
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/dist/DEBIAN/control.in ${CMAKE_BINARY_DIR}/DEBIAN/control)
|
||||
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_INSTALL_PREFIX}/share/licenses/imhex)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dist/imhex.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/icon.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.png)
|
||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}" PERMISSIONS ${LIBRARY_PERMISSIONS})
|
||||
downloadImHexPatternsFiles("./share/imhex")
|
||||
|
||||
|
||||
# install AppStream file
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dist/net.werwolv.imhex.metainfo.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/metainfo)
|
||||
|
||||
|
||||
# install symlink for the old standard name
|
||||
file(CREATE_LINK net.werwolv.imhex.metainfo.xml ${CMAKE_CURRENT_BINARY_DIR}/net.werwolv.imhex.appdata.xml SYMBOLIC)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/net.werwolv.imhex.appdata.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/metainfo)
|
||||
|
||||
endif()
|
||||
|
||||
if (IMHEX_GENERATE_PACKAGE AND APPLE)
|
||||
include(PostprocessBundle)
|
||||
|
||||
set_target_properties(libimhex PROPERTIES SOVERSION ${IMHEX_VERSION})
|
||||
|
||||
set_property(TARGET main PROPERTY MACOSX_BUNDLE_INFO_PLIST ${MACOSX_BUNDLE_INFO_PLIST})
|
||||
if (APPLE)
|
||||
if (IMHEX_GENERATE_PACKAGE)
|
||||
include(PostprocessBundle)
|
||||
|
||||
# Fix rpath
|
||||
add_custom_command(TARGET imhex_all POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $<TARGET_FILE:main>)
|
||||
set_target_properties(libimhex PROPERTIES SOVERSION ${IMHEX_VERSION})
|
||||
|
||||
# FIXME: Remove this once we move/integrate the plugins directory.
|
||||
add_custom_target(build-time-make-plugins-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/MacOS/plugins")
|
||||
add_custom_target(build-time-make-resources-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/Resources")
|
||||
set_property(TARGET main PROPERTY MACOSX_BUNDLE_INFO_PLIST ${MACOSX_BUNDLE_INFO_PLIST})
|
||||
|
||||
downloadImHexPatternsFiles("${IMHEX_BUNDLE_PATH}/Contents/MacOS")
|
||||
|
||||
install(FILES ${IMHEX_ICON} DESTINATION "${IMHEX_BUNDLE_PATH}/Contents/Resources")
|
||||
install(TARGETS main BUNDLE DESTINATION ".")
|
||||
install(FILES $<TARGET_FILE:main> DESTINATION "${IMHEX_BUNDLE_PATH}")
|
||||
# Fix rpath
|
||||
add_custom_command(TARGET imhex_all POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $<TARGET_FILE:main>)
|
||||
|
||||
# Update library references to make the bundle portable
|
||||
postprocess_bundle(imhex_all main)
|
||||
add_custom_target(build-time-make-plugins-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/MacOS/plugins")
|
||||
add_custom_target(build-time-make-resources-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/Resources")
|
||||
|
||||
# Enforce DragNDrop packaging.
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
downloadImHexPatternsFiles("${IMHEX_BUNDLE_PATH}/Contents/MacOS")
|
||||
|
||||
set (CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/resources/dist/macos/AppIcon.icns" )
|
||||
set (CPACK_BUNDLE_PLIST "${CMAKE_BINARY_DIR}/imhex.app/Contents/Info.plist")
|
||||
install(FILES ${IMHEX_ICON} DESTINATION "${IMHEX_BUNDLE_PATH}/Contents/Resources")
|
||||
install(TARGETS main BUNDLE DESTINATION ".")
|
||||
|
||||
# Update library references to make the bundle portable
|
||||
postprocess_bundle(imhex_all main)
|
||||
|
||||
# Enforce DragNDrop packaging.
|
||||
set(CPACK_GENERATOR "DragNDrop")
|
||||
|
||||
set(CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/resources/dist/macos/AppIcon.icns")
|
||||
set(CPACK_BUNDLE_PLIST "${CMAKE_BINARY_DIR}/${BUNDLE_NAME}/Contents/Info.plist")
|
||||
|
||||
# Sign the bundle
|
||||
find_program(CODESIGN_PATH codesign)
|
||||
if (CODESIGN_PATH)
|
||||
add_custom_command(TARGET imhex_all POST_BUILD COMMAND ${CODESIGN_PATH} --force --deep --sign - ${CMAKE_BINARY_DIR}/${BUNDLE_NAME})
|
||||
endif()
|
||||
endif()
|
||||
else()
|
||||
install(TARGETS main RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
if(WIN32) # Forwarder is only needed on Windows
|
||||
if (TARGET updater)
|
||||
install(TARGETS updater RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
if (TARGET main-forwarder)
|
||||
install(TARGETS main-forwarder BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (IMHEX_GENERATE_PACKAGE)
|
||||
set (CPACK_BUNDLE_NAME "ImHex")
|
||||
set(CPACK_BUNDLE_NAME "ImHex")
|
||||
|
||||
include(CPack)
|
||||
endif()
|
||||
@@ -395,6 +402,35 @@ function(verifyCompiler)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
macro(detectBundledPlugins)
|
||||
file(GLOB PLUGINS_DIRS "plugins/*")
|
||||
|
||||
if (NOT DEFINED IMHEX_INCLUDE_PLUGINS)
|
||||
foreach(PLUGIN_DIR ${PLUGINS_DIRS})
|
||||
if (EXISTS "${PLUGIN_DIR}/CMakeLists.txt")
|
||||
get_filename_component(PLUGIN_NAME ${PLUGIN_DIR} NAME)
|
||||
if (NOT (${PLUGIN_NAME} IN_LIST IMHEX_EXCLUDE_PLUGINS))
|
||||
list(APPEND PLUGINS ${PLUGIN_NAME})
|
||||
endif ()
|
||||
endif()
|
||||
endforeach()
|
||||
else()
|
||||
set(PLUGINS ${IMHEX_INCLUDE_PLUGINS})
|
||||
endif()
|
||||
|
||||
foreach(PLUGIN_NAME ${PLUGINS})
|
||||
message(STATUS "Enabled bundled plugin '${PLUGIN_NAME}'")
|
||||
endforeach()
|
||||
|
||||
if (NOT PLUGINS)
|
||||
message(FATAL_ERROR "No bundled plugins enabled")
|
||||
endif()
|
||||
|
||||
if (NOT ("builtin" IN_LIST PLUGINS))
|
||||
message(FATAL_ERROR "The 'builtin' plugin is required for ImHex to work!")
|
||||
endif ()
|
||||
endmacro()
|
||||
|
||||
macro(setVariableInParent variable value)
|
||||
get_directory_property(hasParent PARENT_DIRECTORY)
|
||||
|
||||
@@ -414,9 +450,9 @@ function(downloadImHexPatternsFiles dest)
|
||||
endif ()
|
||||
|
||||
FetchContent_Declare(
|
||||
imhex_patterns
|
||||
GIT_REPOSITORY https://github.com/WerWolv/ImHex-Patterns.git
|
||||
GIT_TAG origin/master
|
||||
imhex_patterns
|
||||
GIT_REPOSITORY https://github.com/WerWolv/ImHex-Patterns.git
|
||||
GIT_TAG origin/master
|
||||
)
|
||||
|
||||
message(STATUS "Downloading ImHex-Patterns repo branch ${PATTERNS_BRANCH}...")
|
||||
@@ -429,7 +465,7 @@ function(downloadImHexPatternsFiles dest)
|
||||
endif ()
|
||||
|
||||
if (EXISTS ${imhex_patterns_SOURCE_DIR})
|
||||
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic)
|
||||
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic nodes)
|
||||
foreach (FOLDER ${PATTERNS_FOLDERS_TO_INSTALL})
|
||||
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION ${dest} PATTERN "**/_schema.json" EXCLUDE)
|
||||
endforeach ()
|
||||
@@ -445,10 +481,14 @@ macro(setupCompilerFlags target)
|
||||
set(IMHEX_COMMON_FLAGS "${IMHEX_COMMON_FLAGS} -Wall -Wextra -Wpedantic -Werror")
|
||||
endif()
|
||||
|
||||
if (UNIX AND NOT APPLE AND CMAKE_CXX_COMPILER_ID MATCHES "GNU")
|
||||
set(IMHEX_COMMON_FLAGS "${IMHEX_COMMON_FLAGS} -rdynamic")
|
||||
endif()
|
||||
|
||||
set(IMHEX_CXX_FLAGS "-fexceptions -frtti")
|
||||
|
||||
# Disable some warnings
|
||||
set(IMHEX_C_CXX_FLAGS "-Wno-array-bounds -Wno-deprecated-declarations")
|
||||
set(IMHEX_C_CXX_FLAGS "-Wno-unknown-warning-option -Wno-array-bounds -Wno-deprecated-declarations")
|
||||
|
||||
if (IMHEX_ENABLE_UNITY_BUILD AND WIN32)
|
||||
set(IMHEX_COMMON_FLAGS "${IMHEX_COMMON_FLAGS} -Wa,-mbig-obj")
|
||||
@@ -466,6 +506,7 @@ macro(setupCompilerFlags target)
|
||||
endif ()
|
||||
|
||||
# Set actual CMake flags
|
||||
set_target_properties(${target} PROPERTIES COMPILE_FLAGS "${IMHEX_COMMON_FLAGS} ${IMHEX_C_CXX_FLAGS}")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${IMHEX_COMMON_FLAGS} ${IMHEX_C_CXX_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${IMHEX_COMMON_FLAGS} ${IMHEX_C_CXX_FLAGS} ${IMHEX_CXX_FLAGS}")
|
||||
set(CMAKE_OBJC_FLAGS "${CMAKE_OBJC_FLAGS} ${IMHEX_COMMON_FLAGS}")
|
||||
@@ -475,12 +516,12 @@ endmacro()
|
||||
macro(setUninstallTarget)
|
||||
if(NOT TARGET uninstall)
|
||||
configure_file(
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||
IMMEDIATE @ONLY)
|
||||
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake_uninstall.cmake.in"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
|
||||
IMMEDIATE @ONLY)
|
||||
|
||||
add_custom_target(uninstall
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
@@ -497,13 +538,13 @@ macro(addBundledLibraries)
|
||||
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_subdirectory(${EXTERNAL_LIBS_FOLDER}/libwolv EXCLUDE_FROM_ALL)
|
||||
set_property(TARGET libwolv-types PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-utils PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-io PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-hash PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-containers PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-net PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-math_eval PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-types PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-utils PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-io PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-hash PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-containers PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-net PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET libwolv-math_eval PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(XDGPP_INCLUDE_DIRS "${THIRD_PARTY_LIBS_FOLDER}/xdgpp")
|
||||
set(FPHSA_NAME_MISMATCHED ON CACHE BOOL "")
|
||||
@@ -556,24 +597,6 @@ macro(addBundledLibraries)
|
||||
find_package(LLVM REQUIRED Demangle)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_YARA)
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/yara EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libyara PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(YARA_LIBRARIES libyara)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(YARA REQUIRED IMPORTED_TARGET yara)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_MINIAUDIO)
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/miniaudio EXCLUDE_FROM_ALL)
|
||||
set_target_properties(miniaudio PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(MINIAUDIO_LIBRARIES miniaudio)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(miniaudio REQUIRED IMPORTED_TARGET miniaudio)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_JTHREAD)
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/jthread EXCLUDE_FROM_ALL)
|
||||
set(JTHREAD_LIBRARIES jthread)
|
||||
@@ -586,20 +609,6 @@ macro(addBundledLibraries)
|
||||
set(JTHREAD_LIBRARIES jthread)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_CAPSTONE)
|
||||
set(CAPSTONE_BUILD_STATIC_RUNTIME OFF CACHE BOOL "Disable shared library building")
|
||||
set(CAPSTONE_BUILD_SHARED OFF CACHE BOOL "Disable shared library building")
|
||||
set(CAPSTONE_BUILD_TESTS OFF CACHE BOOL "Disable tests")
|
||||
add_subdirectory(${THIRD_PARTY_LIBS_FOLDER}/capstone EXCLUDE_FROM_ALL)
|
||||
set_target_properties(capstone PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
target_compile_options(capstone PRIVATE -Wno-unused-function)
|
||||
set(CAPSTONE_LIBRARIES "capstone")
|
||||
set(CAPSTONE_INCLUDE_DIRS ${THIRD_PARTY_LIBS_FOLDER}/capstone/include)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_search_module(CAPSTONE 4.0.2 REQUIRED capstone)
|
||||
endif()
|
||||
|
||||
set(LIBPL_BUILD_CLI_AS_EXECUTABLE OFF)
|
||||
add_subdirectory(${EXTERNAL_LIBS_FOLDER}/pattern_language EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libpl PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
@@ -673,9 +682,11 @@ function(generatePDBs)
|
||||
add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb
|
||||
WORKING_DIRECTORY ${cv2pdb_SOURCE_DIR}
|
||||
COMMAND
|
||||
(${CMAKE_COMMAND} -E remove -f ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb &&
|
||||
${cv2pdb_SOURCE_DIR}/cv2pdb64.exe
|
||||
$<TARGET_FILE:${PDB}>) || (exit 0)
|
||||
(
|
||||
${CMAKE_COMMAND} -E remove -f ${CMAKE_BINARY_DIR}/${GENERATED_PDB}.pdb &&
|
||||
${cv2pdb_SOURCE_DIR}/cv2pdb64.exe
|
||||
$<TARGET_FILE:${PDB}>
|
||||
) || (exit 0)
|
||||
DEPENDS $<TARGET_FILE:${PDB}>
|
||||
COMMAND_EXPAND_LISTS)
|
||||
|
||||
@@ -686,10 +697,33 @@ function(generatePDBs)
|
||||
endfunction()
|
||||
|
||||
function(generateSDKDirectory)
|
||||
set(SDK_PATH "./sdk")
|
||||
if (WIN32)
|
||||
set(SDK_PATH "./sdk")
|
||||
elseif (APPLE)
|
||||
set(SDK_PATH "${BUNDLE_NAME}/Contents/Resources/sdk")
|
||||
else()
|
||||
set(SDK_PATH "share/imhex/sdk")
|
||||
endif()
|
||||
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/libimhex DESTINATION "${SDK_PATH}/lib")
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/external DESTINATION "${SDK_PATH}/lib")
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/imgui DESTINATION "${SDK_PATH}/lib/third_party")
|
||||
if (NOT USE_SYSTEM_FMT)
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/fmt DESTINATION "${SDK_PATH}/lib/third_party")
|
||||
endif()
|
||||
if (NOT USE_SYSTEM_NLOHMANN_JSON)
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/third_party/nlohmann_json DESTINATION "${SDK_PATH}/lib/third_party")
|
||||
endif()
|
||||
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/lib/libimhex/include DESTINATION "${SDK_PATH}")
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/cmake/modules/ImHexPlugin.cmake DESTINATION "${SDK_PATH}/cmake/modules")
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/cmake/build_helpers.cmake DESTINATION "${SDK_PATH}/cmake")
|
||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/cmake/sdk/ DESTINATION "${SDK_PATH}")
|
||||
install(TARGETS libimhex ARCHIVE DESTINATION "${SDK_PATH}/lib")
|
||||
install(TARGETS libimhex RUNTIME DESTINATION "${SDK_PATH}/lib")
|
||||
install(TARGETS libimhex LIBRARY DESTINATION "${SDK_PATH}/lib")
|
||||
endfunction()
|
||||
|
||||
function(addIncludesFromLibrary target library)
|
||||
get_target_property(library_include_dirs ${library} INTERFACE_INCLUDE_DIRECTORIES)
|
||||
target_include_directories(${target} PRIVATE ${library_include_dirs})
|
||||
endfunction()
|
||||
@@ -1,10 +1,15 @@
|
||||
macro(add_imhex_plugin)
|
||||
# Parse arguments
|
||||
set(options "")
|
||||
set(oneValueArgs NAME)
|
||||
set(multiValueArgs SOURCES INCLUDES LIBRARIES)
|
||||
set(options LIBRARY_PLUGIN)
|
||||
set(oneValueArgs NAME IMHEX_VERSION)
|
||||
set(multiValueArgs SOURCES INCLUDES LIBRARIES FEATURES)
|
||||
cmake_parse_arguments(IMHEX_PLUGIN "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
if (IMHEX_PLUGIN_IMHEX_VERSION)
|
||||
message(STATUS "Compiling plugin ${IMHEX_PLUGIN_NAME} for ImHex Version ${IMHEX_PLUGIN_IMHEX_VERSION}")
|
||||
set(IMHEX_VERSION_STRING "${IMHEX_PLUGIN_IMHEX_VERSION}")
|
||||
endif()
|
||||
|
||||
if (IMHEX_STATIC_LINK_PLUGINS)
|
||||
set(IMHEX_PLUGIN_LIBRARY_TYPE STATIC)
|
||||
|
||||
@@ -12,8 +17,15 @@ macro(add_imhex_plugin)
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/dist/web/plugin-bundle.cpp.in ${CMAKE_CURRENT_BINARY_DIR}/plugin-bundle.cpp @ONLY)
|
||||
target_sources(main PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/plugin-bundle.cpp)
|
||||
set(IMHEX_PLUGIN_SUFFIX ".hexplug")
|
||||
else()
|
||||
set(IMHEX_PLUGIN_LIBRARY_TYPE MODULE)
|
||||
if (IMHEX_PLUGIN_LIBRARY_PLUGIN)
|
||||
set(IMHEX_PLUGIN_LIBRARY_TYPE SHARED)
|
||||
set(IMHEX_PLUGIN_SUFFIX ".hexpluglib")
|
||||
else()
|
||||
set(IMHEX_PLUGIN_LIBRARY_TYPE MODULE)
|
||||
set(IMHEX_PLUGIN_SUFFIX ".hexplug")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Define new project for plugin
|
||||
@@ -24,7 +36,8 @@ macro(add_imhex_plugin)
|
||||
|
||||
# Add include directories and link libraries
|
||||
target_include_directories(${IMHEX_PLUGIN_NAME} PUBLIC ${IMHEX_PLUGIN_INCLUDES})
|
||||
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE libimhex ${FMT_LIBRARIES} ${IMHEX_PLUGIN_LIBRARIES})
|
||||
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE libimhex ${IMHEX_PLUGIN_LIBRARIES} ${FMT_LIBRARIES} imgui_all_includes libwolv)
|
||||
addIncludesFromLibrary(${IMHEX_PLUGIN_NAME} libpl)
|
||||
|
||||
# Add IMHEX_PROJECT_NAME and IMHEX_VERSION define
|
||||
target_compile_definitions(${IMHEX_PLUGIN_NAME} PRIVATE IMHEX_PROJECT_NAME="${IMHEX_PLUGIN_NAME}")
|
||||
@@ -42,7 +55,7 @@ macro(add_imhex_plugin)
|
||||
RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/plugins
|
||||
CXX_STANDARD 23
|
||||
PREFIX ""
|
||||
SUFFIX ".hexplug"
|
||||
SUFFIX ${IMHEX_PLUGIN_SUFFIX}
|
||||
)
|
||||
|
||||
# Setup a romfs for the plugin
|
||||
@@ -52,12 +65,38 @@ macro(add_imhex_plugin)
|
||||
set_target_properties(${LIBROMFS_LIBRARY} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
target_link_libraries(${IMHEX_PLUGIN_NAME} PRIVATE ${LIBROMFS_LIBRARY})
|
||||
|
||||
foreach(feature ${IMHEX_PLUGIN_FEATURES})
|
||||
string(TOUPPER ${feature} feature)
|
||||
add_definitions(-DIMHEX_PLUGIN_${IMHEX_PLUGIN_NAME}_FEATURE_${feature}=0)
|
||||
endforeach()
|
||||
|
||||
# Add the new plugin to the main dependency list so it gets built by default
|
||||
add_dependencies(imhex_all ${IMHEX_PLUGIN_NAME})
|
||||
if (TARGET imhex_all)
|
||||
add_dependencies(imhex_all ${IMHEX_PLUGIN_NAME})
|
||||
endif()
|
||||
|
||||
if (IMHEX_EXTERNAL_PLUGIN_BUILD)
|
||||
install(TARGETS ${IMHEX_PLUGIN_NAME} DESTINATION ".")
|
||||
|
||||
# Fix rpath
|
||||
if (APPLE)
|
||||
set_target_properties(${IMHEX_PLUGIN_NAME} PROPERTIES INSTALL_RPATH "@executable_path/../Frameworks")
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(add_romfs_resource input output)
|
||||
configure_file(${input} ${CMAKE_CURRENT_BINARY_DIR}/romfs/${output} COPYONLY)
|
||||
|
||||
list(APPEND LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_BINARY_DIR}/romfs)
|
||||
endmacro()
|
||||
|
||||
macro (enable_plugin_feature feature)
|
||||
string(TOUPPER ${feature} feature)
|
||||
if (NOT (feature IN_LIST IMHEX_PLUGIN_FEATURES))
|
||||
message(FATAL_ERROR "Feature ${feature} is not enabled for plugin ${IMHEX_PLUGIN_NAME}")
|
||||
endif()
|
||||
|
||||
remove_definitions(-DIMHEX_PLUGIN_${IMHEX_PLUGIN_NAME}_FEATURE_${feature}=0)
|
||||
add_definitions(-DIMHEX_PLUGIN_${IMHEX_PLUGIN_NAME}_FEATURE_${feature}=1)
|
||||
endmacro()
|
||||
@@ -35,26 +35,27 @@ message(STATUS "Fixing up application bundle: ${BUNDLE_PATH}")
|
||||
|
||||
|
||||
# Make sure to fix up any included ImHex plugin.
|
||||
file(GLOB_RECURSE extra_libs "${BUNDLE_PATH}/Contents/MacOS/plugins/*.hexplug")
|
||||
file(GLOB_RECURSE plugins "${BUNDLE_PATH}/Contents/MacOS/plugins/*.hexplug")
|
||||
file(GLOB_RECURSE plugin_libs "${BUNDLE_PATH}/Contents/MacOS/plugins/*.hexpluglib")
|
||||
|
||||
|
||||
# BundleUtilities doesn't support DYLD_FALLBACK_LIBRARY_PATH behavior, which
|
||||
# makes it sometimes break on libraries that do weird things with @rpath. Specify
|
||||
# equivalent search directories until https://gitlab.kitware.com/cmake/cmake/issues/16625
|
||||
# is fixed and in our minimum CMake version.
|
||||
set(extra_dirs "/usr/local/lib" "/lib" "/usr/lib" ${EXTRA_BUNDLE_LIBRARY_PATHS})
|
||||
set(extra_dirs "/usr/local/lib" "/lib" "/usr/lib" ${EXTRA_BUNDLE_LIBRARY_PATHS} "${BUNDLE_PATH}/Contents/MacOS/plugins")
|
||||
message(STATUS "Fixing up application bundle: ${extra_dirs}")
|
||||
|
||||
# BundleUtilities is overly verbose, so disable most of its messages
|
||||
function(message)
|
||||
if(NOT ARGV MATCHES "^STATUS;")
|
||||
_message(${ARGV})
|
||||
endif()
|
||||
endfunction()
|
||||
#function(message)
|
||||
# if(NOT ARGV MATCHES "^STATUS;")
|
||||
# _message(${ARGV})
|
||||
# endif()
|
||||
#endfunction()
|
||||
|
||||
include(BundleUtilities)
|
||||
set(BU_CHMOD_BUNDLE_ITEMS ON)
|
||||
fixup_bundle("${BUNDLE_PATH}" "${extra_libs}" "${extra_dirs}")
|
||||
fixup_bundle("${BUNDLE_PATH}" "${plugins};${plugin_libs}" "${extra_dirs}")
|
||||
|
||||
if (CODE_SIGN_CERTIFICATE_ID)
|
||||
# Hack around Apple Silicon signing bugs by copying the real app, signing it and moving it back.
|
||||
|
||||
48
cmake/sdk/CMakeLists.txt
Normal file
48
cmake/sdk/CMakeLists.txt
Normal file
@@ -0,0 +1,48 @@
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(ImHexSDK)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules")
|
||||
include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/build_helpers.cmake")
|
||||
|
||||
set(IMHEX_BASE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR} PARENT_SCOPE)
|
||||
include(ImHexPlugin)
|
||||
|
||||
function(add_subdirectory_if_exists folder)
|
||||
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${folder}/CMakeLists.txt")
|
||||
add_subdirectory("${folder}" EXCLUDE_FROM_ALL)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
set(IMHEX_EXTERNAL_PLUGIN_BUILD ON PARENT_SCOPE)
|
||||
set(IMHEX_EXTERNAL_PLUGIN_BUILD ON)
|
||||
add_custom_target(imhex_all)
|
||||
|
||||
add_subdirectory(lib/third_party/imgui EXCLUDE_FROM_ALL)
|
||||
|
||||
set(FMT_INSTALL OFF CACHE BOOL "" FORCE)
|
||||
add_subdirectory_if_exists(lib/third_party/fmt)
|
||||
set(FMT_LIBRARIES fmt::fmt-header-only PARENT_SCOPE)
|
||||
|
||||
add_subdirectory_if_exists(lib/third_party/nlohmann_json)
|
||||
|
||||
add_subdirectory(lib/external/libwolv EXCLUDE_FROM_ALL)
|
||||
|
||||
set(LIBPL_ENABLE_CLI OFF CACHE BOOL "" FORCE)
|
||||
add_subdirectory(lib/external/pattern_language EXCLUDE_FROM_ALL)
|
||||
|
||||
add_subdirectory(lib/libimhex)
|
||||
|
||||
if (WIN32)
|
||||
set_target_properties(libimhex PROPERTIES
|
||||
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/lib/libimhex.dll"
|
||||
IMPORTED_IMPLIB "${CMAKE_CURRENT_SOURCE_DIR}/lib/liblibimhex.dll.a"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/lib/libimhex/include")
|
||||
elseif (APPLE)
|
||||
set_target_properties(libimhex PROPERTIES
|
||||
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/lib/libimhex.dylib"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/lib/libimhex/include")
|
||||
else()
|
||||
set_target_properties(libimhex PROPERTIES
|
||||
IMPORTED_LOCATION "${CMAKE_CURRENT_SOURCE_DIR}/lib/libimhex.so"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_SOURCE_DIR}/lib/libimhex/include")
|
||||
endif()
|
||||
60
cmake/sdk/template/CMakeLists.txt
Normal file
60
cmake/sdk/template/CMakeLists.txt
Normal file
@@ -0,0 +1,60 @@
|
||||
# ImHex Plugin Template
|
||||
# =====================
|
||||
|
||||
# This is the official CMake template for making your own ImHex plugins
|
||||
# To use this template, copy the file into its own directory and modify it to your needs
|
||||
# For the most part, this is a regular CMake project with some extra functions provided by the ImHex SDK
|
||||
#
|
||||
# [NOTE FOR NON-C++ PLUGINS]
|
||||
# The template is laid out for a C++ plugin, however you can write your plugin in any language you want
|
||||
# and just make the plugin statically link against your code. The only thing that's required is a .cpp file with
|
||||
# the IMHEX_PLUGIN_SETUP() macro used in it. This macro is used to setup the plugin and register it with ImHex
|
||||
#
|
||||
# [CMAKE FUNCTIONS]
|
||||
# add_imhex_plugin(): Registers a new plugin
|
||||
# NAME: The name of the plugin
|
||||
# IMHEX_VERSION: The ImHex version this plugin is compatible with. If unset, the plugin will be loaded on all versions (this may not work though)
|
||||
# SOURCES: Source files of the plugin
|
||||
# INCLUDES: Include directories of the plugin
|
||||
# LIBRARIES: Libraries to link against
|
||||
# FEATURES: Optional features that can be enabled or disabled
|
||||
# LIBRARY_PLUGIN: If set, turns this plugin into a library plugin. Library plugins can be linked against by other plugins
|
||||
#
|
||||
# add_romfs_resource(filePath romfsPath): Adds a file to the romfs of the plugin
|
||||
# The RomFS is a virtual filesystem whose files can be accessed by the plugin using the functions in the `romfs::` namespace
|
||||
# This function is used to add a single file to the romfs. You can however also simply create a `romfs` directory in your plugin directory and place your files and folders in there
|
||||
# filePath: The path to the file on the disk
|
||||
# romfsPath: The path to the file in the romfs
|
||||
#
|
||||
# enable_plugin_feature(feature): Enables a plugin feature
|
||||
# Features are optional parts of the plugin that may or may not be available depending on build settings
|
||||
# When a feature is enabled, `IMHEX_FEATURE_ENABLED(feature)` will be defined to true. Otherwise, it will be defined to false
|
||||
# Use the `IMHEX_PLUGIN_FEATURES` macro in the main plugin file to define names to each feature and have them be listed in the plugin list
|
||||
# feature: The name of the feature to enable
|
||||
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
project(ImHexPlugin)
|
||||
|
||||
# Include the ImHex SDK
|
||||
# For this to work, you need to set the IMHEX_SDK_PATH environment variable to the path of the ImHex SDK
|
||||
#
|
||||
# On Windows, the SDK is next to the ImHex executable
|
||||
# On Linux, the SDK is usually in /usr/share/imhex/sdk but this may vary depending on your distribution
|
||||
# On MacOS, the SDK is located inside of the ImHex.app bundle under ImHex.app/Contents/Resources/sdk
|
||||
if (NOT EXISTS $ENV{IMHEX_SDK_PATH})
|
||||
message(FATAL_ERROR "The IMHEX_SDK_PATH environment variable is not set")
|
||||
endif()
|
||||
add_subdirectory($ENV{IMHEX_SDK_PATH} ImHexSDK)
|
||||
|
||||
# Register the plugin
|
||||
# This will configure everything you need to make your plugin work
|
||||
# Modify the arguments to your needs. Right now it defines a plugin called `example_plugin`
|
||||
# with a single source file called `example_plugin.cpp` in the `source` directory
|
||||
# By default you have access to the libimhex library to interact with ImHex
|
||||
# as well as libwolv, libromfs, libfmt and ImGui, but you can link against any libraries you want
|
||||
add_imhex_plugin(
|
||||
NAME
|
||||
example_plugin
|
||||
SOURCES
|
||||
source/example_plugin.cpp
|
||||
)
|
||||
11
cmake/sdk/template/source/example_plugin.cpp
Normal file
11
cmake/sdk/template/source/example_plugin.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#include <hex/plugin.hpp>
|
||||
|
||||
// Browse through the headers in lib/libimhex/include/hex/api/ to see what you can do with the API.
|
||||
// Most important ones are <hex/api/imhex_api.hpp> and <hex/api/content_registry.hpp>
|
||||
|
||||
// This is the main entry point of your plugin. The code in the body of this construct will be executed
|
||||
// when ImHex starts up and loads the plugin.
|
||||
// The strings in the header are used to display information about the plugin in the UI.
|
||||
IMHEX_PLUGIN_SETUP("Example Plugin", "Author", "Description") {
|
||||
// Put your init code here
|
||||
}
|
||||
5
dist/Arch/PKGBUILD
vendored
5
dist/Arch/PKGBUILD
vendored
@@ -8,7 +8,7 @@ pkgdesc="A Hex Editor for Reverse Engineers, Programmers and people who value th
|
||||
arch=("x86_64")
|
||||
url="https://github.com/WerWolv/ImHex"
|
||||
license=('GPL2')
|
||||
depends=(glfw mbedtls freetype2 libglvnd dbus gtk3 curl fmt yara nlohmann-json)
|
||||
depends=(glfw mbedtls freetype2 libglvnd dbus gtk3 curl fmt yara nlohmann-json zlib bzip2 xz zstd)
|
||||
makedepends=(git)
|
||||
provides=(imhex)
|
||||
conflicts=(imhex)
|
||||
@@ -17,9 +17,10 @@ md5sums=(SKIP)
|
||||
|
||||
package() {
|
||||
install -Dm755 "$srcdir/usr/bin/imhex" "$pkgdir/usr/bin/imhex"
|
||||
install -Dm755 "$srcdir/usr/bin/imhex-updater" "$pkgdir/usr/bin/imhex-updater"
|
||||
install -Dm644 "$srcdir/usr/lib/libimhex.so.$pkgver" "$pkgdir/usr/lib/libimhex.so.$pkgver"
|
||||
|
||||
for plugin in "$srcdir/usr/lib/imhex/plugins/"*.hexplug; do
|
||||
for plugin in "$srcdir/usr/lib/imhex/plugins/"*.hexplug*; do
|
||||
install -Dm644 "$plugin" "$pkgdir/usr/lib/imhex/plugins/${plugin##*/}"
|
||||
done
|
||||
|
||||
|
||||
6
dist/Brewfile
vendored
6
dist/Brewfile
vendored
@@ -9,4 +9,8 @@ brew "curl"
|
||||
brew "gcc@12"
|
||||
brew "llvm"
|
||||
brew "glfw"
|
||||
brew "ninja"
|
||||
brew "ninja"
|
||||
brew "zlib"
|
||||
brew "xz"
|
||||
brew "bzip2"
|
||||
brew "zstd"
|
||||
2
dist/DEBIAN/control.in
vendored
2
dist/DEBIAN/control.in
vendored
@@ -4,7 +4,7 @@ Section: editors
|
||||
Priority: optional
|
||||
Architecture: amd64
|
||||
License: GNU GPL-2
|
||||
Depends: libglfw3, libmagic1, libmbedtls14, libfreetype6, libopengl0, libdbus-1-3, xdg-desktop-portal
|
||||
Depends: libglfw3 | libglfw3-wayland, libmagic1, libmbedtls14, libfreetype6, libopengl0, libdbus-1-3, xdg-desktop-portal
|
||||
Maintainer: WerWolv <hey@werwolv.net>
|
||||
Description: ImHex Hex Editor
|
||||
A Hex Editor for Reverse Engineers, Programmers and
|
||||
|
||||
4
dist/ImHex-9999.ebuild
vendored
4
dist/ImHex-9999.ebuild
vendored
@@ -24,5 +24,9 @@ RDEPEND="${DEPEND}
|
||||
dev-cpp/nlohmann_json
|
||||
dbus
|
||||
xdg-desktop-portal
|
||||
sys-libs/zlib
|
||||
app-arch/bzip2
|
||||
app-arch/lzma
|
||||
app-arch/zstd
|
||||
"
|
||||
BDEPEND="${DEPEND}"
|
||||
|
||||
30
dist/get_deps_archlinux.sh
vendored
30
dist/get_deps_archlinux.sh
vendored
@@ -1,17 +1,21 @@
|
||||
#!/usr/bin/env sh
|
||||
|
||||
pacman -S $@ --needed \
|
||||
cmake \
|
||||
gcc \
|
||||
lld \
|
||||
glfw \
|
||||
file \
|
||||
mbedtls \
|
||||
freetype2 \
|
||||
dbus \
|
||||
gtk3 \
|
||||
curl \
|
||||
fmt \
|
||||
yara \
|
||||
cmake \
|
||||
gcc \
|
||||
lld \
|
||||
glfw \
|
||||
file \
|
||||
mbedtls \
|
||||
freetype2 \
|
||||
dbus \
|
||||
gtk3 \
|
||||
curl \
|
||||
fmt \
|
||||
yara \
|
||||
nlohmann-json \
|
||||
ninja
|
||||
ninja \
|
||||
zlib \
|
||||
bzip2 \
|
||||
xz \
|
||||
zstd
|
||||
|
||||
6
dist/get_deps_debian.sh
vendored
6
dist/get_deps_debian.sh
vendored
@@ -22,4 +22,8 @@ apt install -y \
|
||||
libdbus-1-dev \
|
||||
libcurl4-gnutls-dev \
|
||||
libgtk-3-dev \
|
||||
ninja-build
|
||||
ninja-build \
|
||||
zlib1g-dev \
|
||||
libbz2-dev \
|
||||
liblzma-dev \
|
||||
libzstd-dev
|
||||
|
||||
6
dist/get_deps_fedora.sh
vendored
6
dist/get_deps_fedora.sh
vendored
@@ -12,4 +12,8 @@ dnf install -y \
|
||||
glfw-devel \
|
||||
lld \
|
||||
mbedtls-devel \
|
||||
gtk3-devel
|
||||
gtk3-devel \
|
||||
libzstd-devel \
|
||||
zlib-devel \
|
||||
bzip2-devel \
|
||||
xz-devel
|
||||
6
dist/get_deps_msys2.sh
vendored
6
dist/get_deps_msys2.sh
vendored
@@ -12,4 +12,8 @@ pacman -S --needed --noconfirm \
|
||||
mingw-w64-x86_64-freetype \
|
||||
mingw-w64-x86_64-dlfcn \
|
||||
mingw-w64-x86_64-ninja \
|
||||
mingw-w64-x86_64-capstone
|
||||
mingw-w64-x86_64-capstone \
|
||||
mingw-w64-x86_64-zlib \
|
||||
mingw-w64-x86_64-bzip2 \
|
||||
mingw-w64-x86_64-xz \
|
||||
mingw-w64-x86_64-zstd
|
||||
|
||||
12
dist/macOS/arm64.Dockerfile
vendored
12
dist/macOS/arm64.Dockerfile
vendored
@@ -52,6 +52,10 @@ vcpkg install --triplet=arm-osx-mytriplet curl
|
||||
vcpkg install --triplet=arm-osx-mytriplet mbedtls
|
||||
vcpkg install --triplet=arm-osx-mytriplet freetype
|
||||
vcpkg install --triplet=arm-osx-mytriplet josuttis-jthread
|
||||
vcpkg install --triplet=arm-osx-mytriplet zlib
|
||||
vcpkg install --triplet=arm-osx-mytriplet bzip2
|
||||
vcpkg install --triplet=arm-osx-mytriplet liblzma
|
||||
vcpkg install --triplet=arm-osx-mytriplet zstd
|
||||
EOF
|
||||
|
||||
## Install glfw3 dep
|
||||
@@ -102,6 +106,9 @@ if [ "$CUSTOM_GLFW" ]; then
|
||||
fi
|
||||
EOF
|
||||
|
||||
RUN mkdir -p /vcpkg/installed/arm-osx-mytriplet/lib/pkgconfig
|
||||
RUN mkdir -p /osxcross/target/macports/pkgs/vcpkg/installed/arm-osx-mytriplet/lib/pkgconfig
|
||||
|
||||
## Build glfw
|
||||
RUN --mount=type=cache,target=/cache <<EOF
|
||||
set -xe
|
||||
@@ -148,6 +155,7 @@ RUN --mount=type=cache,target=/cache --mount=type=cache,target=/mnt/ImHex/build/
|
||||
-DIMHEX_GENERATE_PACKAGE=ON -DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
`# other flags` \
|
||||
-DIMHEX_STRICT_WARNINGS=OFF \
|
||||
-DCMAKE_INSTALL_PREFIX=/mnt/ImHex/build/install \
|
||||
-B build
|
||||
## Build ImHex
|
||||
RUN --mount=type=cache,target=/cache --mount=type=cache,target=/mnt/ImHex/build/_deps <<EOF
|
||||
@@ -155,11 +163,11 @@ RUN --mount=type=cache,target=/cache --mount=type=cache,target=/mnt/ImHex/build/
|
||||
set -xe
|
||||
|
||||
cd /mnt/ImHex
|
||||
cmake --build build --parallel $JOBS
|
||||
cmake --build build --parallel $JOBS --target install
|
||||
|
||||
ccache -s
|
||||
EOF
|
||||
|
||||
|
||||
FROM scratch
|
||||
COPY --from=build /mnt/ImHex/build/imhex.app imhex.app
|
||||
COPY --from=build /mnt/ImHex/build/install/imhex.app ImHex.app
|
||||
|
||||
6
dist/msys2/PKGBUILD
vendored
6
dist/msys2/PKGBUILD
vendored
@@ -16,7 +16,11 @@ makedepends=("${MINGW_PACKAGE_PREFIX}-gcc"
|
||||
"${MINGW_PACKAGE_PREFIX}-file"
|
||||
"${MINGW_PACKAGE_PREFIX}-mbedtls"
|
||||
"${MINGW_PACKAGE_PREFIX}-polly"
|
||||
"${MINGW_PACKAGE_PREFIX}-freetype")
|
||||
"${MINGW_PACKAGE_PREFIX}-freetype"
|
||||
"${MINGW_PACKAGE_PREFIX}-zlib"
|
||||
"${MINGW_PACKAGE_PREFIX}-bzip2"
|
||||
"${MINGW_PACKAGE_PREFIX}-xz"
|
||||
"${MINGW_PACKAGE_PREFIX}-zstd")
|
||||
|
||||
source=()
|
||||
sha256sums=()
|
||||
|
||||
43
dist/net.werwolv.ImHex.yaml
vendored
43
dist/net.werwolv.ImHex.yaml
vendored
@@ -12,49 +12,10 @@ finish-args:
|
||||
- --device=all
|
||||
|
||||
modules:
|
||||
- name: libiconv
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.16.tar.gz
|
||||
sha256: e6a1b1b589654277ee790cce3734f07876ac4ccfaecbee8afa0b649cf529cc04
|
||||
|
||||
- name: glfw
|
||||
buildsystem: cmake-ninja
|
||||
builddir: true
|
||||
config-opts:
|
||||
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
- -DBUILD_SHARED_LIBS:BOOL=ON
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://github.com/glfw/glfw/releases/download/3.3.2/glfw-3.3.2.zip
|
||||
sha256: 08a33a512f29d7dbf78eab39bd7858576adcc95228c9efe8e4bc5f0f3261efc7
|
||||
cleanup:
|
||||
- /include
|
||||
- /lib/pkgconfig
|
||||
|
||||
- name: mbedtls
|
||||
buildsystem: cmake-ninja
|
||||
config-opts:
|
||||
- -DCMAKE_C_FLAGS=-fPIC
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://github.com/ARMmbed/mbedtls/archive/refs/tags/v2.27.0.tar.gz
|
||||
sha256: 2a07856e541f0e5f6eaee4f78018c52f25bd244ed76f9020dea54a8b02cac6ea
|
||||
|
||||
- name: nlohmann-json
|
||||
buildsystem: cmake-ninja
|
||||
builddir: true
|
||||
config-opts:
|
||||
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
- -DBUILD_TESTING=OFF
|
||||
|
||||
sources:
|
||||
- type: archive
|
||||
url: https://github.com/nlohmann/json/archive/v3.9.1.tar.gz
|
||||
sha256: 4cf0df69731494668bdd6460ed8cb269b68de9c19ad8c27abc24cd72605b2d5b
|
||||
|
||||
- name: imhex
|
||||
buildsystem: cmake
|
||||
config-opts:
|
||||
- -DCMAKE_BUILD_TYPE=RelWithDebInfo
|
||||
|
||||
sources:
|
||||
- type: git
|
||||
|
||||
5
dist/rpm/imhex.spec
vendored
5
dist/rpm/imhex.spec
vendored
@@ -27,6 +27,10 @@ BuildRequires: mbedtls-devel
|
||||
BuildRequires: yara-devel
|
||||
BuildRequires: nativefiledialog-extended-devel
|
||||
BuildRequires: dotnet-sdk-7.0
|
||||
BuildRequires: libzstd-devel
|
||||
BuildRequires: zlib-devel
|
||||
BuildRequires: bzip2-devel
|
||||
BuildRequires: xz-devel
|
||||
%if 0%{?rhel}
|
||||
BuildRequires: gcc-toolset-12
|
||||
%endif
|
||||
@@ -120,6 +124,7 @@ cp -a lib/third_party/xdgpp/LICENSE %{buildroot
|
||||
%license %{_datadir}/licenses/%{name}/
|
||||
%doc README.md
|
||||
%{_bindir}/imhex
|
||||
%{_bindir}/imhex-updater
|
||||
%{_datadir}/pixmaps/%{name}.png
|
||||
%{_datadir}/applications/%{name}.desktop
|
||||
%{_libdir}/libimhex.so*
|
||||
|
||||
7
dist/web/Dockerfile
vendored
7
dist/web/Dockerfile
vendored
@@ -37,6 +37,10 @@ mkdir -p $VCPKG_DEFAULT_BINARY_CACHE
|
||||
/vcpkg/vcpkg install --triplet=wasm32-emscripten libmagic
|
||||
/vcpkg/vcpkg install --triplet=wasm32-emscripten freetype
|
||||
/vcpkg/vcpkg install --triplet=wasm32-emscripten mbedtls
|
||||
/vcpkg/vcpkg install --triplet=wasm32-emscripten zlib
|
||||
/vcpkg/vcpkg install --triplet=wasm32-emscripten bzip2
|
||||
/vcpkg/vcpkg install --triplet=wasm32-emscripten liblzma
|
||||
/vcpkg/vcpkg install --triplet=wasm32-emscripten zstd
|
||||
EOF
|
||||
|
||||
# Build ImHex
|
||||
@@ -54,6 +58,7 @@ ccache -zs
|
||||
cmake /imhex \
|
||||
-DIMHEX_OFFLINE_BUILD=ON \
|
||||
-DIMHEX_STATIC_LINK_PLUGINS=ON \
|
||||
-DIMHEX_EXCLUDE_PLUGINS="script_loader" \
|
||||
-DNATIVE_CMAKE_C_COMPILER=gcc \
|
||||
-DNATIVE_CMAKE_CXX_COMPILER=g++ \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
@@ -83,6 +88,8 @@ COPY --from=build [ \
|
||||
"/build/favicon.ico", \
|
||||
"/build/icon.png", \
|
||||
"/build/manifest.json", \
|
||||
"/build/robots.txt", \
|
||||
"/build/sitemap.xml", \
|
||||
\
|
||||
# Destination \
|
||||
"./" \
|
||||
|
||||
51
dist/web/source/index.html
vendored
51
dist/web/source/index.html
vendored
@@ -1,23 +1,22 @@
|
||||
<!doctype html>
|
||||
<html lang="en-us">
|
||||
<head>
|
||||
<link rel="manifest" href="manifest.json" />
|
||||
<meta charset="utf-8">
|
||||
<title>ImHex Web - Free Online Hex Editor for Reverse Engineers</title>
|
||||
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
|
||||
<!-- Primary Meta Tags -->
|
||||
<title>ImHex Web - Online Hex Editor</title>
|
||||
<meta name="title" content="ImHex">
|
||||
<meta name="description" content="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.">
|
||||
<meta name="description" content="Free and extremely powerful Online Hex Editor for your Web Browser. ImHex is a free and open source Hex Editor for Reverse Engineers and Developers and Data Analysts.">
|
||||
<link rel="icon" type="image/x-icon" href="favicon.ico">
|
||||
<link rel="apple-touch-icon" href="icon.png">
|
||||
|
||||
<!-- Open Graph / Facebook -->
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:url" content="https://imhex.werwolv.net/">
|
||||
<meta property="og:title" content="ImHex Web - Online Hex Editor">
|
||||
<meta property="og:description">
|
||||
<meta name="description" content="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.">
|
||||
<meta property="og:image" content="https://imhex.werwolv.net/assets/splash_wasm.png">
|
||||
|
||||
<!-- Twitter -->
|
||||
@@ -28,9 +27,7 @@
|
||||
content="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.">
|
||||
<meta property="twitter:image" content="https://imhex.werwolv.net/assets/splash_wasm.png">
|
||||
|
||||
<meta name="viewport" content="width=device-width">
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="style.css" />
|
||||
<link rel="stylesheet" type="text/css" href="style.css">
|
||||
|
||||
<script type="application/ld+json">
|
||||
{
|
||||
@@ -60,15 +57,41 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<title>ImHex Web</title>
|
||||
<script src="enable-threads.js"></script>
|
||||
<link rel="stylesheet" href="style.css">
|
||||
</head>
|
||||
<body>
|
||||
<p id="loading_text">ImHex is loading...</p>
|
||||
<div id="loading" class="centered">
|
||||
<img src="https://raw.githubusercontent.com/WerWolv/ImHex/master/plugins/builtin/romfs/assets/dark/banner.png" id="logo" alt="ImHex Logo">
|
||||
<h1>A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</h1>
|
||||
<h2>Available both natively and on the web</h2>
|
||||
<h5>ImHex runs directly in your web browser with the help of Emscripten and WebAssembly.</h5>
|
||||
|
||||
<div style="height: 50%">
|
||||
<div style="height: 30%"> </div>
|
||||
<h2 id="not_working">
|
||||
Not loading in your Browser? <a href="https://imhex.werwolv.net">Try the native version</a>
|
||||
</h2>
|
||||
<div style="height: 50%"></div>
|
||||
</div>
|
||||
|
||||
<div class="loading_ripple">
|
||||
<div class="lds-ripple"><div></div><div></div></div>
|
||||
</div>
|
||||
|
||||
<div style="height: 10%">
|
||||
</div>
|
||||
|
||||
<div class="footer">
|
||||
<a href="https://imhex.werwolv.net">Homepage</a>
|
||||
<p>Made with ♥️ by the ImHex Team</p>
|
||||
<a href="https://github.com/WerWolv/ImHex">GitHub</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
|
||||
|
||||
<script type="text/javascript" src="wasm-config.js"></script>
|
||||
<script async type="text/javascript" src="imhex.js"></script>
|
||||
<script src="wasm-config.js"></script>
|
||||
<script async src="imhex.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
4
dist/web/source/robots.txt
vendored
Normal file
4
dist/web/source/robots.txt
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Sitemap: https://imhex.werwolv.net/sitemap.xml
|
||||
14
dist/web/source/sitemap.xml
vendored
Normal file
14
dist/web/source/sitemap.xml
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset
|
||||
xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.sitemaps.org/schemas/sitemap/0.9
|
||||
http://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd">
|
||||
|
||||
<url>
|
||||
<loc>https://web.imhex.werwolv.net/</loc>
|
||||
<lastmod>2023-12-07T22:53:06+00:00</lastmod>
|
||||
</url>
|
||||
|
||||
|
||||
</urlset>
|
||||
123
dist/web/source/style.css
vendored
123
dist/web/source/style.css
vendored
@@ -1,6 +1,6 @@
|
||||
html, body {
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
margin: 0;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
@@ -16,21 +16,120 @@ body {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
display: none;
|
||||
border: 0px none;
|
||||
border: 0 none;
|
||||
}
|
||||
|
||||
.canvas_full_screen {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
#loading_text {
|
||||
h1, h2, h5 {
|
||||
color: #F0F0F0;
|
||||
font-size: 30px;
|
||||
font-size: 20px;
|
||||
font-family: monospace;
|
||||
width: 100%;
|
||||
text-align: center;
|
||||
margin-top: 60px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 15px;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin-top: 0;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
#not_working {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
#not_working.visible {
|
||||
opacity: 1;
|
||||
transition: opacity 2s ease;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #7893ff;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
text-shadow: #3a4677 0 0 10px;
|
||||
}
|
||||
|
||||
.footer {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
text-align: center;
|
||||
color: #F0F0F0;
|
||||
background-color: #0A0A0A;
|
||||
padding: 10px;
|
||||
font-family: monospace;
|
||||
font-size: 15px;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: row;
|
||||
gap: 10%;
|
||||
}
|
||||
|
||||
.centered {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
.lds-ripple {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
}
|
||||
.lds-ripple div {
|
||||
position: absolute;
|
||||
border: 4px solid #fff;
|
||||
opacity: 1;
|
||||
border-radius: 50%;
|
||||
animation: lds-ripple 1s cubic-bezier(0, 0.2, 0.8, 1) infinite;
|
||||
}
|
||||
.lds-ripple div:nth-child(2) {
|
||||
animation-delay: -0.5s;
|
||||
}
|
||||
@keyframes lds-ripple {
|
||||
0% {
|
||||
top: 36px;
|
||||
left: 36px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
4.9% {
|
||||
top: 36px;
|
||||
left: 36px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
5% {
|
||||
top: 36px;
|
||||
left: 36px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 72px;
|
||||
height: 72px;
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
16
dist/web/source/wasm-config.js
vendored
16
dist/web/source/wasm-config.js
vendored
@@ -30,16 +30,22 @@ function glfwCreateStandardCursorCustom(shape) {
|
||||
return shape
|
||||
}
|
||||
|
||||
var notWorkingTimer = setTimeout(() => {
|
||||
document.getElementById("not_working").classList.add("visible")
|
||||
}, 5000);
|
||||
|
||||
var Module = {
|
||||
preRun: [],
|
||||
postRun: [],
|
||||
onRuntimeInitialized: function() {
|
||||
// Triggered when the wasm module is loaded and ready to use.
|
||||
document.getElementById("loading_text").style.display = "none"
|
||||
document.getElementById("loading").style.display = "none"
|
||||
document.getElementById("canvas").style.display = "initial"
|
||||
|
||||
clearTimeout(notWorkingTimer);
|
||||
},
|
||||
print: (function() { })(),
|
||||
printErr: function(text) { },
|
||||
printErr: function(text) { },
|
||||
canvas: (function() {
|
||||
let canvas = document.getElementById('canvas');
|
||||
// As a default initial behavior, pop up an alert when webgl context is lost. To make your
|
||||
@@ -67,4 +73,10 @@ function js_resizeCanvas() {
|
||||
canvas.height = Math.min(document.documentElement.clientHeight, window.innerHeight || 0);
|
||||
|
||||
canvas.classList.add("canvas_full_screen")
|
||||
|
||||
if (GLFW.active && GLFW.active.windowPosFunc) {
|
||||
getWasmTableEntry(GLFW.active.windowPosFunc)(GLFW.active.id, GLFW.active.x, GLFW.active.y);
|
||||
}
|
||||
|
||||
GLFW.onWindowSizeChanged();
|
||||
}
|
||||
2
lib/external/libromfs
vendored
2
lib/external/libromfs
vendored
Submodule lib/external/libromfs updated: 04ba8ba5cd...0a72f7bb33
2
lib/external/libwolv
vendored
2
lib/external/libwolv
vendored
Submodule lib/external/libwolv updated: e4891c89b6...7efd66f817
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
Submodule lib/external/pattern_language updated: b5de2d2f8a...78cdc3e7fd
@@ -14,8 +14,10 @@ set(LIBIMHEX_SOURCES
|
||||
source/api/project_file_manager.cpp
|
||||
source/api/theme_manager.cpp
|
||||
source/api/layout_manager.cpp
|
||||
source/api/workspace_manager.cpp
|
||||
source/api/achievement_manager.cpp
|
||||
source/api/localization_manager.cpp
|
||||
source/api/tutorial_manager.cpp
|
||||
|
||||
source/data_processor/attribute.cpp
|
||||
source/data_processor/link.cpp
|
||||
@@ -33,16 +35,17 @@ set(LIBIMHEX_SOURCES
|
||||
source/helpers/patches.cpp
|
||||
source/helpers/encoding_file.cpp
|
||||
source/helpers/logger.cpp
|
||||
source/helpers/stacktrace.cpp
|
||||
source/helpers/tar.cpp
|
||||
source/helpers/debugging.cpp
|
||||
|
||||
source/providers/provider.cpp
|
||||
source/providers/memory_provider.cpp
|
||||
source/providers/undo/stack.cpp
|
||||
|
||||
source/ui/imgui_imhex_extensions.cpp
|
||||
source/ui/view.cpp
|
||||
source/ui/popup.cpp
|
||||
source/ui/toast.cpp
|
||||
|
||||
source/subcommands/subcommands.cpp
|
||||
)
|
||||
@@ -60,12 +63,18 @@ if (APPLE)
|
||||
set(LIBIMHEX_SOURCES ${LIBIMHEX_SOURCES} source/helpers/utils_macos.m)
|
||||
endif ()
|
||||
|
||||
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||
|
||||
if (IMHEX_STATIC_LINK_PLUGINS)
|
||||
add_library(libimhex STATIC ${LIBIMHEX_SOURCES})
|
||||
if (IMHEX_EXTERNAL_PLUGIN_BUILD)
|
||||
add_library(libimhex IMPORTED SHARED GLOBAL)
|
||||
set(LIBIMHEX_LIBRARY_TYPE INTERFACE)
|
||||
else()
|
||||
add_library(libimhex SHARED ${LIBIMHEX_SOURCES})
|
||||
if (IMHEX_STATIC_LINK_PLUGINS)
|
||||
add_library(libimhex STATIC ${LIBIMHEX_SOURCES})
|
||||
else()
|
||||
add_library(libimhex SHARED ${LIBIMHEX_SOURCES})
|
||||
endif()
|
||||
|
||||
set(LIBIMHEX_LIBRARY_TYPE PUBLIC)
|
||||
target_compile_definitions(libimhex PRIVATE IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||
endif()
|
||||
|
||||
set_target_properties(libimhex PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
@@ -75,26 +84,30 @@ setupCompilerFlags(libimhex)
|
||||
include(GenerateExportHeader)
|
||||
generate_export_header(libimhex)
|
||||
|
||||
target_include_directories(libimhex PUBLIC include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIR} ${CAPSTONE_INCLUDE_DIRS} ${MAGIC_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${YARA_INCLUDE_DIRS} ${LIBBACKTRACE_INCLUDE_DIRS})
|
||||
target_link_directories(libimhex PUBLIC ${MBEDTLS_LIBRARY_DIR} ${CAPSTONE_LIBRARY_DIRS} ${MAGIC_LIBRARY_DIRS})
|
||||
target_include_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} include ${XDGPP_INCLUDE_DIRS} ${MBEDTLS_INCLUDE_DIR} ${MAGIC_INCLUDE_DIRS} ${LLVM_INCLUDE_DIRS} ${FMT_INCLUDE_DIRS} ${CURL_INCLUDE_DIRS} ${LIBBACKTRACE_INCLUDE_DIRS})
|
||||
target_link_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${MBEDTLS_LIBRARY_DIR} ${MAGIC_LIBRARY_DIRS})
|
||||
|
||||
if (NOT EMSCRIPTEN)
|
||||
# curl is only used in non-emscripten builds
|
||||
target_include_directories(libimhex PUBLIC ${CURL_INCLUDE_DIRS})
|
||||
target_link_libraries(libimhex PUBLIC ${LIBCURL_LIBRARIES})
|
||||
target_include_directories(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${CURL_INCLUDE_DIRS})
|
||||
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${LIBCURL_LIBRARIES})
|
||||
endif()
|
||||
|
||||
|
||||
if (WIN32)
|
||||
set_target_properties(libimhex PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
|
||||
target_link_options(libimhex PRIVATE -Wl,--export-all-symbols)
|
||||
elseif (APPLE)
|
||||
find_library(FOUNDATION NAMES Foundation)
|
||||
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
|
||||
endif ()
|
||||
if (NOT IMHEX_EXTERNAL_PLUGIN_BUILD)
|
||||
if (WIN32)
|
||||
set_target_properties(libimhex PROPERTIES WINDOWS_EXPORT_ALL_SYMBOLS TRUE)
|
||||
target_link_options(libimhex PRIVATE -Wl,--export-all-symbols)
|
||||
elseif (APPLE)
|
||||
find_library(FOUNDATION NAMES Foundation)
|
||||
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
|
||||
endif ()
|
||||
|
||||
target_link_libraries(libimhex PRIVATE ${FMT_LIBRARIES})
|
||||
target_link_libraries(libimhex PUBLIC dl ${IMGUI_LIBRARIES} ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} plcli libpl libpl-gen ${MINIAUDIO_LIBRARIES} ${JTHREAD_LIBRARIES} wolv::utils wolv::io wolv::hash wolv::net wolv::containers wolv::math_eval)
|
||||
target_link_libraries(libimhex PRIVATE microtar libpl plcli libpl-gen libwolv ${NFD_LIBRARIES} magic dl ${NLOHMANN_JSON_LIBRARIES} ${MBEDTLS_LIBRARIES} ${LIBBACKTRACE_LIBRARIES} ${JTHREAD_LIBRARIES})
|
||||
target_link_libraries(libimhex PUBLIC ${IMGUI_LIBRARIES})
|
||||
endif()
|
||||
|
||||
target_link_libraries(libimhex ${LIBIMHEX_LIBRARY_TYPE} ${NLOHMANN_JSON_LIBRARIES} imgui_all_includes ${FMT_LIBRARIES})
|
||||
|
||||
set_property(TARGET libimhex PROPERTY INTERPROCEDURAL_OPTIMIZATION FALSE)
|
||||
|
||||
@@ -110,6 +123,7 @@ else()
|
||||
OUTPUT_VARIABLE GIT_BRANCH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE RESULT_BRANCH
|
||||
ERROR_QUIET
|
||||
)
|
||||
|
||||
# Get the latest abbreviated commit hash of the working branch
|
||||
@@ -119,6 +133,7 @@ else()
|
||||
OUTPUT_VARIABLE GIT_COMMIT_HASH_SHORT
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE RESULT_HASH_SHORT
|
||||
ERROR_QUIET
|
||||
)
|
||||
|
||||
execute_process(
|
||||
@@ -127,6 +142,7 @@ else()
|
||||
OUTPUT_VARIABLE GIT_COMMIT_HASH_LONG
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
RESULT_VARIABLE RESULT_HASH_LONG
|
||||
ERROR_QUIET
|
||||
)
|
||||
endif ()
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -20,22 +21,22 @@ namespace hex {
|
||||
|
||||
class Achievement {
|
||||
public:
|
||||
explicit Achievement(std::string unlocalizedCategory, std::string unlocalizedName) : m_unlocalizedCategory(std::move(unlocalizedCategory)), m_unlocalizedName(std::move(unlocalizedName)) { }
|
||||
explicit Achievement(UnlocalizedString unlocalizedCategory, UnlocalizedString unlocalizedName) : m_unlocalizedCategory(std::move(unlocalizedCategory)), m_unlocalizedName(std::move(unlocalizedName)) { }
|
||||
|
||||
/**
|
||||
* @brief Returns the unlocalized name of the achievement
|
||||
* @return Unlocalized name of the achievement
|
||||
*/
|
||||
[[nodiscard]] const std::string &getUnlocalizedName() const {
|
||||
return this->m_unlocalizedName;
|
||||
[[nodiscard]] const UnlocalizedString &getUnlocalizedName() const {
|
||||
return m_unlocalizedName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the unlocalized category of the achievement
|
||||
* @return Unlocalized category of the achievement
|
||||
*/
|
||||
[[nodiscard]] const std::string &getUnlocalizedCategory() const {
|
||||
return this->m_unlocalizedCategory;
|
||||
[[nodiscard]] const UnlocalizedString &getUnlocalizedCategory() const {
|
||||
return m_unlocalizedCategory;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -43,7 +44,7 @@ namespace hex {
|
||||
* @return Whether the achievement is unlocked
|
||||
*/
|
||||
[[nodiscard]] bool isUnlocked() const {
|
||||
return this->m_progress == this->m_maxProgress;
|
||||
return m_progress == m_maxProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -52,7 +53,7 @@ namespace hex {
|
||||
* @return Reference to the achievement
|
||||
*/
|
||||
Achievement& setDescription(std::string description) {
|
||||
this->m_unlocalizedDescription = std::move(description);
|
||||
m_unlocalizedDescription = std::move(description);
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -63,7 +64,7 @@ namespace hex {
|
||||
* @return Reference to the achievement
|
||||
*/
|
||||
Achievement& addRequirement(std::string requirement) {
|
||||
this->m_requirements.emplace_back(std::move(requirement));
|
||||
m_requirements.emplace_back(std::move(requirement));
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -74,7 +75,7 @@ namespace hex {
|
||||
* @return Reference to the achievement
|
||||
*/
|
||||
Achievement& addVisibilityRequirement(std::string requirement) {
|
||||
this->m_visibilityRequirements.emplace_back(std::move(requirement));
|
||||
m_visibilityRequirements.emplace_back(std::move(requirement));
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -84,7 +85,7 @@ namespace hex {
|
||||
* @return Reference to the achievement
|
||||
*/
|
||||
Achievement& setBlacked() {
|
||||
this->m_blacked = true;
|
||||
m_blacked = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -94,7 +95,7 @@ namespace hex {
|
||||
* @return Reference to the achievement
|
||||
*/
|
||||
Achievement& setInvisible() {
|
||||
this->m_invisible = true;
|
||||
m_invisible = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -104,7 +105,7 @@ namespace hex {
|
||||
* @return Whether the achievement is blacked
|
||||
*/
|
||||
[[nodiscard]] bool isBlacked() const {
|
||||
return this->m_blacked;
|
||||
return m_blacked;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -112,7 +113,7 @@ namespace hex {
|
||||
* @return Whether the achievement is invisible
|
||||
*/
|
||||
[[nodiscard]] bool isInvisible() const {
|
||||
return this->m_invisible;
|
||||
return m_invisible;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -120,7 +121,7 @@ namespace hex {
|
||||
* @return List of requirements of the achievement
|
||||
*/
|
||||
[[nodiscard]] const std::vector<std::string> &getRequirements() const {
|
||||
return this->m_requirements;
|
||||
return m_requirements;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -128,15 +129,15 @@ namespace hex {
|
||||
* @return List of visibility requirements of the achievement
|
||||
*/
|
||||
[[nodiscard]] const std::vector<std::string> &getVisibilityRequirements() const {
|
||||
return this->m_visibilityRequirements;
|
||||
return m_visibilityRequirements;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Returns the unlocalized description of the achievement
|
||||
* @return Unlocalized description of the achievement
|
||||
*/
|
||||
[[nodiscard]] const std::string &getUnlocalizedDescription() const {
|
||||
return this->m_unlocalizedDescription;
|
||||
[[nodiscard]] const UnlocalizedString &getUnlocalizedDescription() const {
|
||||
return m_unlocalizedDescription;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -144,15 +145,15 @@ namespace hex {
|
||||
* @return Icon of the achievement
|
||||
*/
|
||||
[[nodiscard]] const ImGuiExt::Texture &getIcon() const {
|
||||
if (this->m_iconData.empty())
|
||||
return this->m_icon;
|
||||
|
||||
if (this->m_icon.isValid())
|
||||
if (m_iconData.empty())
|
||||
return m_icon;
|
||||
|
||||
this->m_icon = ImGuiExt::Texture(this->m_iconData.data(), this->m_iconData.size());
|
||||
if (m_icon.isValid())
|
||||
return m_icon;
|
||||
|
||||
return this->m_icon;
|
||||
m_icon = ImGuiExt::Texture(m_iconData.data(), m_iconData.size(), ImGuiExt::Texture::Filter::Linear);
|
||||
|
||||
return m_icon;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -161,9 +162,9 @@ namespace hex {
|
||||
* @return Reference to the achievement
|
||||
*/
|
||||
Achievement& setIcon(std::span<const std::byte> data) {
|
||||
this->m_iconData.reserve(data.size());
|
||||
m_iconData.reserve(data.size());
|
||||
for (auto &byte : data)
|
||||
this->m_iconData.emplace_back(static_cast<u8>(byte));
|
||||
m_iconData.emplace_back(static_cast<u8>(byte));
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -174,7 +175,7 @@ namespace hex {
|
||||
* @return Reference to the achievement
|
||||
*/
|
||||
Achievement& setIcon(std::span<const u8> data) {
|
||||
this->m_iconData.assign(data.begin(), data.end());
|
||||
m_iconData.assign(data.begin(), data.end());
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -185,7 +186,7 @@ namespace hex {
|
||||
* @return Reference to the achievement
|
||||
*/
|
||||
Achievement& setIcon(std::vector<u8> data) {
|
||||
this->m_iconData = std::move(data);
|
||||
m_iconData = std::move(data);
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -196,9 +197,9 @@ namespace hex {
|
||||
* @return Reference to the achievement
|
||||
*/
|
||||
Achievement& setIcon(const std::vector<std::byte> &data) {
|
||||
this->m_iconData.reserve(data.size());
|
||||
m_iconData.reserve(data.size());
|
||||
for (auto &byte : data)
|
||||
this->m_iconData.emplace_back(static_cast<u8>(byte));
|
||||
m_iconData.emplace_back(static_cast<u8>(byte));
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -209,7 +210,7 @@ namespace hex {
|
||||
* @return Reference to the achievement
|
||||
*/
|
||||
Achievement& setRequiredProgress(u32 progress) {
|
||||
this->m_maxProgress = progress;
|
||||
m_maxProgress = progress;
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -219,7 +220,7 @@ namespace hex {
|
||||
* @return Required progress to unlock the achievement
|
||||
*/
|
||||
[[nodiscard]] u32 getRequiredProgress() const {
|
||||
return this->m_maxProgress;
|
||||
return m_maxProgress;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -227,7 +228,7 @@ namespace hex {
|
||||
* @return Current progress of the achievement
|
||||
*/
|
||||
[[nodiscard]] u32 getProgress() const {
|
||||
return this->m_progress;
|
||||
return m_progress;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -235,7 +236,7 @@ namespace hex {
|
||||
* @param callback Callback to call when the achievement is clicked
|
||||
*/
|
||||
void setClickCallback(const std::function<void(Achievement &)> &callback) {
|
||||
this->m_clickCallback = callback;
|
||||
m_clickCallback = callback;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,7 +244,7 @@ namespace hex {
|
||||
* @return Callback to call when the achievement is clicked
|
||||
*/
|
||||
[[nodiscard]] const std::function<void(Achievement &)> &getClickCallback() const {
|
||||
return this->m_clickCallback;
|
||||
return m_clickCallback;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -251,7 +252,7 @@ namespace hex {
|
||||
* @return Whether the achievement is temporary
|
||||
*/
|
||||
[[nodiscard]] bool isTemporary() const {
|
||||
return this->m_temporary;
|
||||
return m_temporary;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -260,21 +261,21 @@ namespace hex {
|
||||
*/
|
||||
void setUnlocked(bool unlocked) {
|
||||
if (unlocked) {
|
||||
if (this->m_progress < this->m_maxProgress)
|
||||
this->m_progress++;
|
||||
if (m_progress < m_maxProgress)
|
||||
m_progress++;
|
||||
} else {
|
||||
this->m_progress = 0;
|
||||
m_progress = 0;
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
void setProgress(u32 progress) {
|
||||
this->m_progress = progress;
|
||||
m_progress = progress;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_unlocalizedCategory, m_unlocalizedName;
|
||||
std::string m_unlocalizedDescription;
|
||||
UnlocalizedString m_unlocalizedCategory, m_unlocalizedName;
|
||||
UnlocalizedString m_unlocalizedDescription;
|
||||
|
||||
bool m_blacked = false;
|
||||
bool m_invisible = false;
|
||||
@@ -364,7 +365,7 @@ namespace hex {
|
||||
* @param unlocalizedCategory Unlocalized category of the achievement
|
||||
* @param unlocalizedName Unlocalized name of the achievement
|
||||
*/
|
||||
static void unlockAchievement(const std::string &unlocalizedCategory, const std::string &unlocalizedName);
|
||||
static void unlockAchievement(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName);
|
||||
|
||||
/**
|
||||
* @brief Returns all registered achievements
|
||||
|
||||
@@ -1,21 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
|
||||
#include <pl/pattern_language.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <span>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <jthread.hpp>
|
||||
|
||||
#include <pl/pattern_language.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
using ImGuiDataType = int;
|
||||
using ImGuiInputTextFlags = int;
|
||||
@@ -63,32 +61,32 @@ namespace hex {
|
||||
friend class Widget;
|
||||
|
||||
Interface& requiresRestart() {
|
||||
this->m_requiresRestart = true;
|
||||
m_requiresRestart = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Interface& setEnabledCallback(std::function<bool()> callback) {
|
||||
this->m_enabledCallback = std::move(callback);
|
||||
m_enabledCallback = std::move(callback);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Interface& setChangedCallback(std::function<void(Widget&)> callback) {
|
||||
this->m_changedCallback = std::move(callback);
|
||||
m_changedCallback = std::move(callback);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Interface& setTooltip(const std::string &tooltip) {
|
||||
this->m_tooltip = tooltip;
|
||||
m_tooltip = tooltip;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
Widget& getWidget() const {
|
||||
return *this->m_widget;
|
||||
return *m_widget;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -103,34 +101,34 @@ namespace hex {
|
||||
|
||||
[[nodiscard]]
|
||||
bool doesRequireRestart() const {
|
||||
return this->m_interface.m_requiresRestart;
|
||||
return m_interface.m_requiresRestart;
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
bool isEnabled() const {
|
||||
return !this->m_interface.m_enabledCallback || this->m_interface.m_enabledCallback();
|
||||
return !m_interface.m_enabledCallback || m_interface.m_enabledCallback();
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
const std::optional<std::string>& getTooltip() const {
|
||||
return this->m_interface.m_tooltip;
|
||||
return m_interface.m_tooltip;
|
||||
}
|
||||
|
||||
void onChanged() {
|
||||
if (this->m_interface.m_changedCallback)
|
||||
this->m_interface.m_changedCallback(*this);
|
||||
if (m_interface.m_changedCallback)
|
||||
m_interface.m_changedCallback(*this);
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
Interface& getInterface() {
|
||||
return this->m_interface;
|
||||
return m_interface;
|
||||
}
|
||||
|
||||
private:
|
||||
Interface m_interface = Interface(this);
|
||||
};
|
||||
|
||||
class Checkbox : public Widget {
|
||||
class Checkbox : public Widget {
|
||||
public:
|
||||
explicit Checkbox(bool defaultValue) : m_value(defaultValue) { }
|
||||
|
||||
@@ -139,11 +137,12 @@ namespace hex {
|
||||
void load(const nlohmann::json &data) override;
|
||||
nlohmann::json store() override;
|
||||
|
||||
[[nodiscard]] bool isChecked() const { return this->m_value; }
|
||||
[[nodiscard]] bool isChecked() const { return m_value; }
|
||||
|
||||
private:
|
||||
bool m_value;
|
||||
};
|
||||
|
||||
class SliderInteger : public Widget {
|
||||
public:
|
||||
SliderInteger(i32 defaultValue, i32 min, i32 max) : m_value(defaultValue), m_min(min), m_max(max) { }
|
||||
@@ -152,13 +151,14 @@ namespace hex {
|
||||
void load(const nlohmann::json &data) override;
|
||||
nlohmann::json store() override;
|
||||
|
||||
[[nodiscard]] i32 getValue() const { return this->m_value; }
|
||||
[[nodiscard]] i32 getValue() const { return m_value; }
|
||||
|
||||
private:
|
||||
int m_value;
|
||||
i32 m_min, m_max;
|
||||
};
|
||||
class SliderFloat : public Widget {
|
||||
|
||||
class SliderFloat : public Widget {
|
||||
public:
|
||||
SliderFloat(float defaultValue, float min, float max) : m_value(defaultValue), m_min(min), m_max(max) { }
|
||||
bool draw(const std::string &name) override;
|
||||
@@ -166,13 +166,14 @@ namespace hex {
|
||||
void load(const nlohmann::json &data) override;
|
||||
nlohmann::json store() override;
|
||||
|
||||
[[nodiscard]] float getValue() const { return this->m_value; }
|
||||
[[nodiscard]] float getValue() const { return m_value; }
|
||||
|
||||
private:
|
||||
float m_value;
|
||||
float m_min, m_max;
|
||||
};
|
||||
class ColorPicker : public Widget {
|
||||
|
||||
class ColorPicker : public Widget {
|
||||
public:
|
||||
explicit ColorPicker(ImColor defaultColor);
|
||||
|
||||
@@ -186,7 +187,8 @@ namespace hex {
|
||||
private:
|
||||
std::array<float, 4> m_value{};
|
||||
};
|
||||
class DropDown : public Widget {
|
||||
|
||||
class DropDown : public Widget {
|
||||
public:
|
||||
explicit DropDown(const std::vector<std::string> &items, const std::vector<nlohmann::json> &settingsValues, const nlohmann::json &defaultItem) : m_items(items), m_settingsValues(settingsValues), m_defaultItem(defaultItem) { }
|
||||
|
||||
@@ -205,7 +207,8 @@ namespace hex {
|
||||
|
||||
int m_value = -1;
|
||||
};
|
||||
class TextBox : public Widget {
|
||||
|
||||
class TextBox : public Widget {
|
||||
public:
|
||||
explicit TextBox(std::string defaultValue) : m_value(std::move(defaultValue)) { }
|
||||
|
||||
@@ -215,43 +218,52 @@ namespace hex {
|
||||
nlohmann::json store() override;
|
||||
|
||||
[[nodiscard]]
|
||||
const std::string& getValue() const { return this->m_value; }
|
||||
const std::string& getValue() const { return m_value; }
|
||||
|
||||
private:
|
||||
std::string m_value;
|
||||
};
|
||||
class FilePicker : public Widget {
|
||||
|
||||
class FilePicker : public Widget {
|
||||
public:
|
||||
bool draw(const std::string &name) override;
|
||||
|
||||
void load(const nlohmann::json &data) override;
|
||||
nlohmann::json store() override;
|
||||
|
||||
[[nodiscard]]
|
||||
std::fs::path getPath() const { return this->m_value; }
|
||||
[[nodiscard]] std::fs::path getPath() const {
|
||||
return m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_value;
|
||||
};
|
||||
|
||||
class Label : public Widget {
|
||||
public:
|
||||
bool draw(const std::string &name) override;
|
||||
|
||||
void load(const nlohmann::json &) override {}
|
||||
nlohmann::json store() override { return {}; }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace impl {
|
||||
|
||||
struct Entry {
|
||||
std::string unlocalizedName;
|
||||
UnlocalizedString unlocalizedName;
|
||||
std::unique_ptr<Widgets::Widget> widget;
|
||||
};
|
||||
|
||||
struct SubCategory {
|
||||
std::string unlocalizedName;
|
||||
UnlocalizedString unlocalizedName;
|
||||
std::vector<Entry> entries;
|
||||
};
|
||||
|
||||
struct Category {
|
||||
std::string unlocalizedName;
|
||||
std::string unlocalizedDescription;
|
||||
UnlocalizedString unlocalizedName;
|
||||
UnlocalizedString unlocalizedDescription;
|
||||
std::vector<SubCategory> subCategories;
|
||||
};
|
||||
|
||||
@@ -260,14 +272,14 @@ namespace hex {
|
||||
void clear();
|
||||
|
||||
std::vector<Category> &getSettings();
|
||||
nlohmann::json& getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &defaultValue);
|
||||
nlohmann::json& getSetting(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const nlohmann::json &defaultValue);
|
||||
nlohmann::json &getSettingsData();
|
||||
|
||||
Widgets::Widget* add(const std::string &unlocalizedCategory, const std::string &unlocalizedSubCategory, const std::string &unlocalizedName, std::unique_ptr<Widgets::Widget> &&widget);
|
||||
Widgets::Widget* add(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedSubCategory, const UnlocalizedString &unlocalizedName, std::unique_ptr<Widgets::Widget> &&widget);
|
||||
}
|
||||
|
||||
template<std::derived_from<Widgets::Widget> T>
|
||||
Widgets::Widget::Interface& add(const std::string &unlocalizedCategory, const std::string &unlocalizedSubCategory, const std::string &unlocalizedName, auto && ... args) {
|
||||
Widgets::Widget::Interface& add(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedSubCategory, const UnlocalizedString &unlocalizedName, auto && ... args) {
|
||||
return impl::add(
|
||||
unlocalizedCategory,
|
||||
unlocalizedSubCategory,
|
||||
@@ -276,10 +288,10 @@ namespace hex {
|
||||
)->getInterface();
|
||||
}
|
||||
|
||||
void setCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedDescription);
|
||||
void setCategoryDescription(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedDescription);
|
||||
|
||||
nlohmann::json read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &defaultValue);
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &value);
|
||||
[[nodiscard]] nlohmann::json read(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const nlohmann::json &defaultValue);
|
||||
void write(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const nlohmann::json &value);
|
||||
}
|
||||
|
||||
/* Command Palette Command Registry. Allows adding of new commands to the command palette */
|
||||
@@ -304,7 +316,7 @@ namespace hex {
|
||||
struct Entry {
|
||||
Type type;
|
||||
std::string command;
|
||||
std::string unlocalizedDescription;
|
||||
UnlocalizedString unlocalizedDescription;
|
||||
DisplayCallback displayCallback;
|
||||
ExecuteCallback executeCallback;
|
||||
};
|
||||
@@ -332,7 +344,7 @@ namespace hex {
|
||||
void add(
|
||||
Type type,
|
||||
const std::string &command,
|
||||
const std::string &unlocalizedDescription,
|
||||
const UnlocalizedString &unlocalizedDescription,
|
||||
const impl::DisplayCallback &displayCallback,
|
||||
const impl::ExecuteCallback &executeCallback = [](auto) {});
|
||||
|
||||
@@ -470,7 +482,7 @@ namespace hex {
|
||||
* @param unlocalizedName The unlocalized name of the view
|
||||
* @return The view if it exists, nullptr otherwise
|
||||
*/
|
||||
View* getViewByName(const std::string &unlocalizedName);
|
||||
View* getViewByName(const UnlocalizedString &unlocalizedName);
|
||||
}
|
||||
|
||||
/* Tools Registry. Allows adding new entries to the tools window */
|
||||
@@ -495,7 +507,7 @@ namespace hex {
|
||||
* @param unlocalizedName The unlocalized name of the tool
|
||||
* @param function The function that will be called to draw the tool
|
||||
*/
|
||||
void add(const std::string &unlocalizedName, const impl::Callback &function);
|
||||
void add(const UnlocalizedString &unlocalizedName, const impl::Callback &function);
|
||||
}
|
||||
|
||||
/* Data Inspector Registry. Allows adding of new types to the data inspector */
|
||||
@@ -515,7 +527,7 @@ namespace hex {
|
||||
using GeneratorFunction = std::function<DisplayFunction(const std::vector<u8> &, std::endian, NumberDisplayStyle)>;
|
||||
|
||||
struct Entry {
|
||||
std::string unlocalizedName;
|
||||
UnlocalizedString unlocalizedName;
|
||||
size_t requiredSize;
|
||||
size_t maxSize;
|
||||
GeneratorFunction generatorFunction;
|
||||
@@ -533,7 +545,7 @@ namespace hex {
|
||||
* @param displayGeneratorFunction The function that will be called to generate the display function
|
||||
* @param editingFunction The function that will be called to edit the data
|
||||
*/
|
||||
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
|
||||
void add(const UnlocalizedString &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
|
||||
|
||||
/**
|
||||
* @brief Adds a new entry to the data inspector
|
||||
@@ -543,7 +555,7 @@ namespace hex {
|
||||
* @param displayGeneratorFunction The function that will be called to generate the display function
|
||||
* @param editingFunction The function that will be called to edit the data
|
||||
*/
|
||||
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
|
||||
void add(const UnlocalizedString &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction = std::nullopt);
|
||||
}
|
||||
|
||||
/* Data Processor Node Registry. Allows adding new processor nodes to be used in the data processor */
|
||||
@@ -554,8 +566,8 @@ namespace hex {
|
||||
using CreatorFunction = std::function<std::unique_ptr<dp::Node>()>;
|
||||
|
||||
struct Entry {
|
||||
std::string category;
|
||||
std::string name;
|
||||
UnlocalizedString unlocalizedCategory;
|
||||
UnlocalizedString unlocalizedName;
|
||||
CreatorFunction creatorFunction;
|
||||
};
|
||||
|
||||
@@ -574,10 +586,10 @@ namespace hex {
|
||||
* @param args Arguments passed to the constructor of the node
|
||||
*/
|
||||
template<std::derived_from<dp::Node> T, typename... Args>
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, Args &&...args) {
|
||||
void add(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, Args &&...args) {
|
||||
add(impl::Entry {
|
||||
unlocalizedCategory.c_str(),
|
||||
unlocalizedName.c_str(),
|
||||
unlocalizedCategory,
|
||||
unlocalizedName,
|
||||
[=, ...args = std::forward<Args>(args)] mutable {
|
||||
auto node = std::make_unique<T>(std::forward<Args>(args)...);
|
||||
node->setUnlocalizedName(unlocalizedName);
|
||||
@@ -622,11 +634,11 @@ namespace hex {
|
||||
using ClickCallback = std::function<void()>;
|
||||
|
||||
struct MainMenuItem {
|
||||
std::string unlocalizedName;
|
||||
UnlocalizedString unlocalizedName;
|
||||
};
|
||||
|
||||
struct MenuItem {
|
||||
std::vector<std::string> unlocalizedNames;
|
||||
std::vector<UnlocalizedString> unlocalizedNames;
|
||||
std::unique_ptr<Shortcut> shortcut;
|
||||
View *view;
|
||||
MenuCallback callback;
|
||||
@@ -641,7 +653,7 @@ namespace hex {
|
||||
|
||||
struct TitleBarButton {
|
||||
std::string icon;
|
||||
std::string unlocalizedTooltip;
|
||||
UnlocalizedString unlocalizedTooltip;
|
||||
ClickCallback callback;
|
||||
};
|
||||
|
||||
@@ -664,7 +676,7 @@ namespace hex {
|
||||
* @param unlocalizedName The unlocalized name of the entry
|
||||
* @param priority The priority of the entry. Lower values are displayed first
|
||||
*/
|
||||
void registerMainMenuItem(const std::string &unlocalizedName, u32 priority);
|
||||
void registerMainMenuItem(const UnlocalizedString &unlocalizedName, u32 priority);
|
||||
|
||||
/**
|
||||
* @brief Adds a new main menu entry
|
||||
@@ -675,7 +687,7 @@ namespace hex {
|
||||
* @param enabledCallback The function to call to determine if the entry is enabled
|
||||
* @param view The view to use for the entry. If nullptr, the shortcut will work globally
|
||||
*/
|
||||
void addMenuItem(const std::vector<std::string> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback = []{ return true; }, View *view = nullptr);
|
||||
void addMenuItem(const std::vector<UnlocalizedString> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback = []{ return true; }, View *view = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Adds a new main menu sub-menu entry
|
||||
@@ -684,14 +696,14 @@ namespace hex {
|
||||
* @param function The function to call when the entry is clicked
|
||||
* @param enabledCallback The function to call to determine if the entry is enabled
|
||||
*/
|
||||
void addMenuItemSubMenu(std::vector<std::string> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback = []{ return true; });
|
||||
void addMenuItemSubMenu(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback = []{ return true; });
|
||||
|
||||
/**
|
||||
* @brief Adds a new main menu separator
|
||||
* @param unlocalizedMainMenuNames The unlocalized names of the main menu entries
|
||||
* @param priority The priority of the entry. Lower values are displayed first
|
||||
*/
|
||||
void addMenuItemSeparator(std::vector<std::string> unlocalizedMainMenuNames, u32 priority);
|
||||
void addMenuItemSeparator(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority);
|
||||
|
||||
|
||||
/**
|
||||
@@ -726,7 +738,7 @@ namespace hex {
|
||||
* @param unlocalizedTooltip The unlocalized tooltip to use for the button
|
||||
* @param function The function to call when the button is clicked
|
||||
*/
|
||||
void addTitleBarButton(const std::string &icon, const std::string &unlocalizedTooltip, const impl::ClickCallback &function);
|
||||
void addTitleBarButton(const std::string &icon, const UnlocalizedString &unlocalizedTooltip, const impl::ClickCallback &function);
|
||||
|
||||
}
|
||||
|
||||
@@ -735,7 +747,7 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
void addProviderName(const std::string &unlocalizedName);
|
||||
void addProviderName(const UnlocalizedString &unlocalizedName);
|
||||
|
||||
using ProviderCreationFunction = prv::Provider*(*)();
|
||||
void add(const std::string &typeName, ProviderCreationFunction creationFunction);
|
||||
@@ -770,7 +782,7 @@ namespace hex {
|
||||
|
||||
using Callback = std::function<std::string(prv::Provider *provider, u64 address, size_t size)>;
|
||||
struct Entry {
|
||||
std::string unlocalizedName;
|
||||
UnlocalizedString unlocalizedName;
|
||||
Callback callback;
|
||||
};
|
||||
|
||||
@@ -784,7 +796,7 @@ namespace hex {
|
||||
* @param unlocalizedName The unlocalized name of the formatter
|
||||
* @param callback The function to call to format the data
|
||||
*/
|
||||
void add(const std::string &unlocalizedName, const impl::Callback &callback);
|
||||
void add(const UnlocalizedString &unlocalizedName, const impl::Callback &callback);
|
||||
|
||||
}
|
||||
|
||||
@@ -817,7 +829,7 @@ namespace hex {
|
||||
|
||||
class DataVisualizer {
|
||||
public:
|
||||
DataVisualizer(std::string unlocalizedName, u16 bytesPerCell, u16 maxCharsPerCell)
|
||||
DataVisualizer(UnlocalizedString unlocalizedName, u16 bytesPerCell, u16 maxCharsPerCell)
|
||||
: m_unlocalizedName(std::move(unlocalizedName)),
|
||||
m_bytesPerCell(bytesPerCell),
|
||||
m_maxCharsPerCell(maxCharsPerCell) { }
|
||||
@@ -827,10 +839,10 @@ namespace hex {
|
||||
virtual void draw(u64 address, const u8 *data, size_t size, bool upperCase) = 0;
|
||||
virtual bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) = 0;
|
||||
|
||||
[[nodiscard]] u16 getBytesPerCell() const { return this->m_bytesPerCell; }
|
||||
[[nodiscard]] u16 getMaxCharsPerCell() const { return this->m_maxCharsPerCell; }
|
||||
[[nodiscard]] u16 getBytesPerCell() const { return m_bytesPerCell; }
|
||||
[[nodiscard]] u16 getMaxCharsPerCell() const { return m_maxCharsPerCell; }
|
||||
|
||||
[[nodiscard]] const std::string& getUnlocalizedName() const { return this->m_unlocalizedName; }
|
||||
[[nodiscard]] const UnlocalizedString& getUnlocalizedName() const { return m_unlocalizedName; }
|
||||
|
||||
protected:
|
||||
const static int TextInputFlags;
|
||||
@@ -839,7 +851,7 @@ namespace hex {
|
||||
bool drawDefaultTextEditingTextBox(u64 address, std::string &data, ImGuiInputTextFlags flags) const;
|
||||
|
||||
private:
|
||||
std::string m_unlocalizedName;
|
||||
UnlocalizedString m_unlocalizedName;
|
||||
u16 m_bytesPerCell;
|
||||
u16 m_maxCharsPerCell;
|
||||
};
|
||||
@@ -867,7 +879,7 @@ namespace hex {
|
||||
* @param unlocalizedName Unlocalized name of the data visualizer
|
||||
* @return The data visualizer, or nullptr if it doesn't exist
|
||||
*/
|
||||
std::shared_ptr<DataVisualizer> getVisualizerByName(const std::string &unlocalizedName);
|
||||
std::shared_ptr<DataVisualizer> getVisualizerByName(const UnlocalizedString &unlocalizedName);
|
||||
|
||||
}
|
||||
|
||||
@@ -876,7 +888,7 @@ namespace hex {
|
||||
|
||||
class Hash {
|
||||
public:
|
||||
explicit Hash(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
|
||||
explicit Hash(UnlocalizedString unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
|
||||
virtual ~Hash() = default;
|
||||
|
||||
class Function {
|
||||
@@ -888,20 +900,20 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
[[nodiscard]] Hash *getType() { return this->m_type; }
|
||||
[[nodiscard]] const Hash *getType() const { return this->m_type; }
|
||||
[[nodiscard]] const std::string &getName() const { return this->m_name; }
|
||||
[[nodiscard]] Hash *getType() { return m_type; }
|
||||
[[nodiscard]] const Hash *getType() const { return m_type; }
|
||||
[[nodiscard]] const std::string &getName() const { return m_name; }
|
||||
|
||||
const std::vector<u8>& get(const Region& region, prv::Provider *provider) {
|
||||
if (this->m_cache.empty()) {
|
||||
this->m_cache = this->m_callback(region, provider);
|
||||
if (m_cache.empty()) {
|
||||
m_cache = m_callback(region, provider);
|
||||
}
|
||||
|
||||
return this->m_cache;
|
||||
return m_cache;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
this->m_cache.clear();
|
||||
m_cache.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -918,8 +930,8 @@ namespace hex {
|
||||
[[nodiscard]] virtual nlohmann::json store() const = 0;
|
||||
virtual void load(const nlohmann::json &json) = 0;
|
||||
|
||||
[[nodiscard]] const std::string &getUnlocalizedName() const {
|
||||
return this->m_unlocalizedName;
|
||||
[[nodiscard]] const UnlocalizedString &getUnlocalizedName() const {
|
||||
return m_unlocalizedName;
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -928,7 +940,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_unlocalizedName;
|
||||
UnlocalizedString m_unlocalizedName;
|
||||
};
|
||||
|
||||
namespace impl {
|
||||
@@ -957,16 +969,10 @@ namespace hex {
|
||||
namespace impl {
|
||||
using Callback = std::function<void()>;
|
||||
|
||||
struct Service {
|
||||
std::string name;
|
||||
std::jthread thread;
|
||||
};
|
||||
|
||||
std::vector<Service> &getServices();
|
||||
void stopServices();
|
||||
}
|
||||
|
||||
void registerService(const std::string &unlocalizedName, const impl::Callback &callback);
|
||||
void registerService(const UnlocalizedString &unlocalizedName, const impl::Callback &callback);
|
||||
}
|
||||
|
||||
/* Network Communication Interface Registry. Allows adding new communication interface endpoints */
|
||||
@@ -988,14 +994,14 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
struct Experiment {
|
||||
std::string unlocalizedName, unlocalizedDescription;
|
||||
UnlocalizedString unlocalizedName, unlocalizedDescription;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
std::map<std::string, Experiment> &getExperiments();
|
||||
}
|
||||
|
||||
void addExperiment(const std::string &experimentName, const std::string &unlocalizedName, const std::string &unlocalizedDescription = "");
|
||||
void addExperiment(const std::string &experimentName, const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedDescription = "");
|
||||
void enableExperiement(const std::string &experimentName, bool enabled);
|
||||
|
||||
[[nodiscard]] bool isExperimentEnabled(const std::string &experimentName);
|
||||
|
||||
@@ -13,12 +13,18 @@
|
||||
|
||||
#include <wolv/types/type_name.hpp>
|
||||
|
||||
#define EVENT_DEF_IMPL(event_name, event_name_string, should_log, ...) \
|
||||
struct event_name final : public hex::impl::Event<__VA_ARGS__> { \
|
||||
constexpr static auto Id = [] { return hex::impl::EventId(event_name_string); }(); \
|
||||
constexpr static auto ShouldLog = (should_log); \
|
||||
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
|
||||
}
|
||||
#define EVENT_DEF_IMPL(event_name, event_name_string, should_log, ...) \
|
||||
struct event_name final : public hex::impl::Event<__VA_ARGS__> { \
|
||||
constexpr static auto Id = [] { return hex::impl::EventId(event_name_string); }(); \
|
||||
constexpr static auto ShouldLog = (should_log); \
|
||||
explicit event_name(Callback func) noexcept : Event(std::move(func)) { } \
|
||||
\
|
||||
static EventManager::EventList::iterator subscribe(Event::Callback function) { return EventManager::subscribe<event_name>(function); } \
|
||||
static void subscribe(void *token, Event::Callback function) { EventManager::subscribe<event_name>(token, function); } \
|
||||
static void unsubscribe(const EventManager::EventList::iterator &token) noexcept { EventManager::unsubscribe(token); } \
|
||||
static void unsubscribe(void *token) noexcept { EventManager::unsubscribe<event_name>(token); } \
|
||||
static void post(auto &&...args) noexcept { EventManager::post<event_name>(std::forward<decltype(args)>(args)...); } \
|
||||
};
|
||||
|
||||
#define EVENT_DEF(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, true, __VA_ARGS__)
|
||||
#define EVENT_DEF_NO_LOG(event_name, ...) EVENT_DEF_IMPL(event_name, #event_name, false, __VA_ARGS__)
|
||||
@@ -26,7 +32,10 @@
|
||||
|
||||
/* Forward declarations */
|
||||
struct GLFWwindow;
|
||||
namespace hex { class Achievement; }
|
||||
namespace hex {
|
||||
class Achievement;
|
||||
class View;
|
||||
}
|
||||
|
||||
|
||||
namespace hex {
|
||||
@@ -36,15 +45,15 @@ namespace hex {
|
||||
class EventId {
|
||||
public:
|
||||
explicit constexpr EventId(const char *eventName) {
|
||||
this->m_hash = 0x811C'9DC5;
|
||||
m_hash = 0x811C'9DC5;
|
||||
for (auto c : std::string_view(eventName)) {
|
||||
this->m_hash = (this->m_hash >> 5) | (this->m_hash << 27);
|
||||
this->m_hash ^= c;
|
||||
m_hash = (m_hash >> 5) | (m_hash << 27);
|
||||
m_hash ^= c;
|
||||
}
|
||||
}
|
||||
|
||||
constexpr bool operator==(const EventId &other) const {
|
||||
return this->m_hash == other.m_hash;
|
||||
return m_hash == other.m_hash;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -62,7 +71,7 @@ namespace hex {
|
||||
explicit Event(Callback func) noexcept : m_func(std::move(func)) { }
|
||||
|
||||
void operator()(Params... params) const noexcept {
|
||||
this->m_func(params...);
|
||||
m_func(params...);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -241,7 +250,8 @@ namespace hex {
|
||||
EVENT_DEF(EventStoreContentRemoved, const std::fs::path&);
|
||||
EVENT_DEF(EventImHexClosing);
|
||||
EVENT_DEF(EventAchievementUnlocked, const Achievement&);
|
||||
EVENT_DEF(EventSearchBoxClicked);
|
||||
EVENT_DEF(EventSearchBoxClicked, u32);
|
||||
EVENT_DEF(EventViewOpened, View*);
|
||||
|
||||
EVENT_DEF(EventProviderDataModified, prv::Provider *, u64, u64, const u8*);
|
||||
EVENT_DEF(EventProviderDataInserted, prv::Provider *, u64, u64);
|
||||
@@ -263,6 +273,7 @@ namespace hex {
|
||||
EVENT_DEF(RequestAddBookmark, Region, std::string, std::string, color_t, u64*);
|
||||
EVENT_DEF(RequestRemoveBookmark, u64);
|
||||
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
|
||||
EVENT_DEF(RequestRunPatternCode);
|
||||
EVENT_DEF(RequestLoadPatternLanguageFile, std::fs::path);
|
||||
EVENT_DEF(RequestSavePatternLanguageFile, std::fs::path);
|
||||
EVENT_DEF(RequestUpdateWindowTitle);
|
||||
@@ -278,11 +289,6 @@ namespace hex {
|
||||
EVENT_DEF(RequestCreateProvider, std::string, bool, bool, hex::prv::Provider **);
|
||||
EVENT_DEF(RequestInitThemeHandlers);
|
||||
|
||||
EVENT_DEF(RequestOpenInfoPopup, const std::string);
|
||||
EVENT_DEF(RequestOpenErrorPopup, const std::string);
|
||||
EVENT_DEF(RequestOpenFatalPopup, const std::string);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Send an event to the main Imhex instance
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <span>
|
||||
@@ -33,8 +34,8 @@ namespace hex {
|
||||
Highlighting() = default;
|
||||
Highlighting(Region region, color_t color);
|
||||
|
||||
[[nodiscard]] const Region &getRegion() const { return this->m_region; }
|
||||
[[nodiscard]] const color_t &getColor() const { return this->m_color; }
|
||||
[[nodiscard]] const Region &getRegion() const { return m_region; }
|
||||
[[nodiscard]] const color_t &getColor() const { return m_color; }
|
||||
|
||||
private:
|
||||
Region m_region = {};
|
||||
@@ -46,9 +47,9 @@ namespace hex {
|
||||
Tooltip() = default;
|
||||
Tooltip(Region region, std::string value, color_t color);
|
||||
|
||||
[[nodiscard]] const Region &getRegion() const { return this->m_region; }
|
||||
[[nodiscard]] const color_t &getColor() const { return this->m_color; }
|
||||
[[nodiscard]] const std::string &getValue() const { return this->m_value; }
|
||||
[[nodiscard]] const Region &getRegion() const { return m_region; }
|
||||
[[nodiscard]] const color_t &getColor() const { return m_color; }
|
||||
[[nodiscard]] const std::string &getValue() const { return m_value; }
|
||||
|
||||
private:
|
||||
Region m_region = {};
|
||||
@@ -338,7 +339,7 @@ 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(const std::string &unlocalizedName, bool skipLoadInterface = false, bool select = true);
|
||||
prv::Provider* createProvider(const UnlocalizedString &unlocalizedName, bool skipLoadInterface = false, bool select = true);
|
||||
|
||||
}
|
||||
|
||||
@@ -365,6 +366,7 @@ namespace hex {
|
||||
|
||||
void addInitArgument(const std::string &key, const std::string &value = { });
|
||||
|
||||
void setLastFrameTime(double time);
|
||||
}
|
||||
|
||||
struct ProgramArguments {
|
||||
@@ -556,6 +558,8 @@ namespace hex {
|
||||
bool updateImHex(UpdateType updateType);
|
||||
|
||||
void addStartupTask(const std::string &name, bool async, const std::function<bool()> &function);
|
||||
|
||||
double getLastFrameTime();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class LayoutManager {
|
||||
@@ -27,11 +25,17 @@ namespace hex {
|
||||
*/
|
||||
static void load(const std::fs::path &path);
|
||||
|
||||
/**
|
||||
* @brief Saves the current layout to a string
|
||||
* @return String containing the layout
|
||||
*/
|
||||
static std::string saveToString();
|
||||
|
||||
/**
|
||||
* @brief Load a layout from a string
|
||||
* @param content Layout string
|
||||
*/
|
||||
static void loadString(const std::string &content);
|
||||
static void loadFromString(const std::string &content);
|
||||
|
||||
/**
|
||||
* @brief Get a list of all layouts
|
||||
@@ -55,6 +59,23 @@ namespace hex {
|
||||
*/
|
||||
static void reset();
|
||||
|
||||
/**
|
||||
* @brief Checks is the current layout is locked
|
||||
*/
|
||||
static bool isLayoutLocked();
|
||||
|
||||
/**
|
||||
* @brief Locks or unlocks the current layout
|
||||
* @note If the layout is locked, it cannot be modified by the user anymore
|
||||
* @param locked True to lock the layout, false to unlock it
|
||||
*/
|
||||
static void lockLayout(bool locked);
|
||||
|
||||
/**
|
||||
* @brief Closes all views
|
||||
*/
|
||||
static void closeAllViews();
|
||||
|
||||
private:
|
||||
LayoutManager() = default;
|
||||
};
|
||||
|
||||
@@ -32,10 +32,13 @@ namespace hex {
|
||||
[[nodiscard]] const std::string &getSelectedLanguage();
|
||||
}
|
||||
|
||||
struct UnlocalizedString;
|
||||
|
||||
class Lang {
|
||||
public:
|
||||
explicit Lang(const char *unlocalizedString);
|
||||
explicit Lang(std::string unlocalizedString);
|
||||
explicit Lang(const std::string &unlocalizedString);
|
||||
explicit Lang(const UnlocalizedString &unlocalizedString);
|
||||
explicit Lang(std::string_view unlocalizedString);
|
||||
|
||||
[[nodiscard]] operator std::string() const;
|
||||
@@ -60,6 +63,43 @@ namespace hex {
|
||||
return Lang(string);
|
||||
}
|
||||
|
||||
|
||||
struct UnlocalizedString {
|
||||
public:
|
||||
UnlocalizedString() = default;
|
||||
UnlocalizedString(auto && arg) : m_unlocalizedString(std::forward<decltype(arg)>(arg)) {
|
||||
static_assert(!std::same_as<std::remove_cvref_t<decltype(arg)>, Lang>, "Expected a unlocalized name, got a localized one!");
|
||||
}
|
||||
|
||||
[[nodiscard]] operator std::string() const {
|
||||
return m_unlocalizedString;
|
||||
}
|
||||
|
||||
[[nodiscard]] operator std::string_view() const {
|
||||
return m_unlocalizedString;
|
||||
}
|
||||
|
||||
[[nodiscard]] operator const char *() const {
|
||||
return m_unlocalizedString.c_str();
|
||||
}
|
||||
|
||||
[[nodiscard]] const std::string &get() const {
|
||||
return m_unlocalizedString;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool empty() const {
|
||||
return m_unlocalizedString.empty();
|
||||
}
|
||||
|
||||
auto operator<=>(const UnlocalizedString &) const = default;
|
||||
auto operator<=>(const std::string &other) const {
|
||||
return m_unlocalizedString <=> other;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_unlocalizedString;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <string>
|
||||
|
||||
#include <wolv/io/fs.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
struct ImGuiContext;
|
||||
|
||||
@@ -16,8 +17,14 @@ namespace hex {
|
||||
std::function<void(const std::vector<std::string>&)> callback;
|
||||
};
|
||||
|
||||
struct Feature {
|
||||
std::string name;
|
||||
bool enabled;
|
||||
};
|
||||
|
||||
struct PluginFunctions {
|
||||
using InitializePluginFunc = void (*)();
|
||||
using InitializeLibraryFunc = void (*)();
|
||||
using GetPluginNameFunc = const char *(*)();
|
||||
using GetPluginAuthorFunc = const char *(*)();
|
||||
using GetPluginDescriptionFunc = const char *(*)();
|
||||
@@ -25,8 +32,10 @@ namespace hex {
|
||||
using SetImGuiContextFunc = void (*)(ImGuiContext *);
|
||||
using IsBuiltinPluginFunc = bool (*)();
|
||||
using GetSubCommandsFunc = void* (*)();
|
||||
using GetFeaturesFunc = void* (*)();
|
||||
|
||||
InitializePluginFunc initializePluginFunction = nullptr;
|
||||
InitializeLibraryFunc initializeLibraryFunction = nullptr;
|
||||
GetPluginNameFunc getPluginNameFunction = nullptr;
|
||||
GetPluginAuthorFunc getPluginAuthorFunction = nullptr;
|
||||
GetPluginDescriptionFunc getPluginDescriptionFunction = nullptr;
|
||||
@@ -34,17 +43,21 @@ namespace hex {
|
||||
SetImGuiContextFunc setImGuiContextFunction = nullptr;
|
||||
IsBuiltinPluginFunc isBuiltinPluginFunction = nullptr;
|
||||
GetSubCommandsFunc getSubCommandsFunction = nullptr;
|
||||
GetFeaturesFunc getFeaturesFunction = nullptr;
|
||||
};
|
||||
|
||||
class Plugin {
|
||||
public:
|
||||
explicit Plugin(const std::fs::path &path);
|
||||
explicit Plugin(PluginFunctions functions);
|
||||
explicit Plugin(const PluginFunctions &functions);
|
||||
|
||||
Plugin(const Plugin &) = delete;
|
||||
Plugin(Plugin &&other) noexcept;
|
||||
~Plugin();
|
||||
|
||||
Plugin& operator=(const Plugin &) = delete;
|
||||
Plugin& operator=(Plugin &&other) noexcept;
|
||||
|
||||
[[nodiscard]] bool initializePlugin() const;
|
||||
[[nodiscard]] std::string getPluginName() const;
|
||||
[[nodiscard]] std::string getPluginAuthor() const;
|
||||
@@ -55,9 +68,13 @@ namespace hex {
|
||||
|
||||
[[nodiscard]] const std::fs::path &getPath() const;
|
||||
|
||||
[[nodiscard]] bool isValid() const;
|
||||
[[nodiscard]] bool isLoaded() const;
|
||||
|
||||
[[nodiscard]] std::span<SubCommand> getSubCommands() const;
|
||||
[[nodiscard]] std::span<Feature> getFeatures() const;
|
||||
|
||||
[[nodiscard]] bool isLibraryPlugin() const;
|
||||
|
||||
private:
|
||||
uintptr_t m_handle = 0;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <GLFW/glfw3.h>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
@@ -9,6 +9,8 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
struct ImGuiWindow;
|
||||
|
||||
namespace hex {
|
||||
@@ -138,7 +140,7 @@ namespace hex {
|
||||
|
||||
auto operator<=>(const Key &) const = default;
|
||||
|
||||
[[nodiscard]] constexpr u32 getKeyCode() const { return this->m_key; }
|
||||
[[nodiscard]] constexpr u32 getKeyCode() const { return m_key; }
|
||||
private:
|
||||
u32 m_key = 0;
|
||||
};
|
||||
@@ -179,17 +181,17 @@ namespace hex {
|
||||
}
|
||||
|
||||
Shortcut &operator+=(const Key &other) {
|
||||
this->m_keys.insert(other);
|
||||
m_keys.insert(other);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator<(const Shortcut &other) const {
|
||||
return this->m_keys < other.m_keys;
|
||||
return m_keys < other.m_keys;
|
||||
}
|
||||
|
||||
bool operator==(const Shortcut &other) const {
|
||||
auto thisKeys = this->m_keys;
|
||||
auto thisKeys = m_keys;
|
||||
auto otherKeys = other.m_keys;
|
||||
|
||||
thisKeys.erase(CurrentView);
|
||||
@@ -201,7 +203,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
bool isLocal() const {
|
||||
return this->m_keys.contains(CurrentView);
|
||||
return m_keys.contains(CurrentView);
|
||||
}
|
||||
|
||||
std::string toString() const {
|
||||
@@ -221,7 +223,7 @@ namespace hex {
|
||||
|
||||
constexpr static auto Concatination = " + ";
|
||||
|
||||
auto keys = this->m_keys;
|
||||
auto keys = m_keys;
|
||||
if (keys.erase(CTRL) > 0) {
|
||||
result += CTRL_NAME;
|
||||
result += Concatination;
|
||||
@@ -367,7 +369,7 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
const std::set<Key>& getKeys() const { return this->m_keys; }
|
||||
const std::set<Key>& getKeys() const { return m_keys; }
|
||||
|
||||
private:
|
||||
friend Shortcut operator+(const Key &lhs, const Key &rhs);
|
||||
@@ -391,7 +393,7 @@ namespace hex {
|
||||
using Callback = std::function<void()>;
|
||||
struct ShortcutEntry {
|
||||
Shortcut shortcut;
|
||||
std::string unlocalizedName;
|
||||
UnlocalizedString unlocalizedName;
|
||||
Callback callback;
|
||||
};
|
||||
|
||||
@@ -401,7 +403,7 @@ namespace hex {
|
||||
* @param unlocalizedName The unlocalized name of the shortcut
|
||||
* @param callback The callback to call when the shortcut is triggered.
|
||||
*/
|
||||
static void addGlobalShortcut(const Shortcut &shortcut, const std::string &unlocalizedName, const Callback &callback);
|
||||
static void addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback);
|
||||
|
||||
/**
|
||||
* @brief Add a view-specific shortcut. View-specific shortcuts can only be triggered when the specified view is focused.
|
||||
@@ -410,7 +412,7 @@ namespace hex {
|
||||
* @param unlocalizedName The unlocalized name of the shortcut
|
||||
* @param callback The callback to call when the shortcut is triggered.
|
||||
*/
|
||||
static void addShortcut(View *view, const Shortcut &shortcut, const std::string &unlocalizedName, const Callback &callback);
|
||||
static void addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const Callback &callback);
|
||||
|
||||
|
||||
/**
|
||||
@@ -446,7 +448,7 @@ namespace hex {
|
||||
[[nodiscard]] static std::optional<Shortcut> getPreviousShortcut();
|
||||
|
||||
[[nodiscard]] static std::vector<ShortcutEntry> getGlobalShortcuts();
|
||||
[[nodiscard]] static std::vector<ShortcutEntry> getViewShortcuts(View *view);
|
||||
[[nodiscard]] static std::vector<ShortcutEntry> getViewShortcuts(const View *view);
|
||||
|
||||
[[nodiscard]] static bool updateShortcut(const Shortcut &oldShortcut, const Shortcut &newShortcut, View *view = nullptr);
|
||||
};
|
||||
|
||||
@@ -1,17 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
||||
#include <cstdio>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <condition_variable>
|
||||
|
||||
#include <jthread.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class TaskHolder;
|
||||
@@ -23,7 +21,7 @@ namespace hex {
|
||||
class Task {
|
||||
public:
|
||||
Task() = default;
|
||||
Task(std::string unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function);
|
||||
Task(UnlocalizedString unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function);
|
||||
|
||||
Task(const Task&) = delete;
|
||||
Task(Task &&other) noexcept;
|
||||
@@ -64,7 +62,7 @@ namespace hex {
|
||||
void clearException();
|
||||
[[nodiscard]] std::string getExceptionMessage() const;
|
||||
|
||||
[[nodiscard]] const std::string &getUnlocalizedName();
|
||||
[[nodiscard]] const UnlocalizedString &getUnlocalizedName();
|
||||
[[nodiscard]] u64 getValue() const;
|
||||
[[nodiscard]] u64 getMaxValue() const;
|
||||
|
||||
@@ -76,7 +74,7 @@ namespace hex {
|
||||
private:
|
||||
mutable std::mutex m_mutex;
|
||||
|
||||
std::string m_unlocalizedName;
|
||||
UnlocalizedString m_unlocalizedName;
|
||||
std::atomic<u64> m_currValue = 0, m_maxValue = 0;
|
||||
std::function<void()> m_interruptCallback;
|
||||
std::function<void(Task &)> m_function;
|
||||
@@ -165,7 +163,7 @@ namespace hex {
|
||||
static void runDeferredCalls();
|
||||
|
||||
private:
|
||||
static void runner(const std::stop_token &stopToken);
|
||||
static TaskHolder createTask(std::string name, u64 maxValue, bool background, std::function<void(Task &)> function);
|
||||
};
|
||||
|
||||
}
|
||||
175
lib/libimhex/include/hex/api/tutorial_manager.hpp
Normal file
175
lib/libimhex/include/hex/api/tutorial_manager.hpp
Normal file
@@ -0,0 +1,175 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
#include <variant>
|
||||
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class TutorialManager {
|
||||
public:
|
||||
enum class Position : u8 {
|
||||
None = 0,
|
||||
Top = 1,
|
||||
Bottom = 2,
|
||||
Left = 4,
|
||||
Right = 8
|
||||
};
|
||||
|
||||
struct Tutorial {
|
||||
Tutorial() = delete;
|
||||
Tutorial(const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedDescription) :
|
||||
m_unlocalizedName(unlocalizedName),
|
||||
m_unlocalizedDescription(unlocalizedDescription) { }
|
||||
|
||||
struct Step {
|
||||
explicit Step(Tutorial *parent) : m_parent(parent) { }
|
||||
|
||||
/**
|
||||
* @brief Adds a highlighting with text to a specific element
|
||||
* @param unlocalizedText Unlocalized text to display next to the highlighting
|
||||
* @param ids ID of the element to highlight
|
||||
* @return Current step
|
||||
*/
|
||||
Step& addHighlight(const UnlocalizedString &unlocalizedText, std::initializer_list<std::variant<Lang, std::string, int>> &&ids);
|
||||
|
||||
/**
|
||||
* @brief Adds a highlighting to a specific element
|
||||
* @param ids ID of the element to highlight
|
||||
* @return Current step
|
||||
*/
|
||||
Step& addHighlight(std::initializer_list<std::variant<Lang, std::string, int>> &&ids);
|
||||
|
||||
/**
|
||||
* @brief Sets the text that will be displayed in the tutorial message box
|
||||
* @param unlocalizedTitle Title of the message box
|
||||
* @param unlocalizedMessage Main message of the message box
|
||||
* @param position Position of the message box
|
||||
* @return Current step
|
||||
*/
|
||||
Step& setMessage(const UnlocalizedString &unlocalizedTitle, const UnlocalizedString &unlocalizedMessage, Position position = Position::None);
|
||||
|
||||
/**
|
||||
* @brief Allows this step to be skipped by clicking on the advance button
|
||||
* @return Current step
|
||||
*/
|
||||
Step& allowSkip();
|
||||
|
||||
Step& onAppear(std::function<void()> callback);
|
||||
Step& onComplete(std::function<void()> callback);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Checks if this step is the current step
|
||||
* @return True if this step is the current step
|
||||
*/
|
||||
bool isCurrent() const;
|
||||
|
||||
/**
|
||||
* @brief Completes this step if it is the current step
|
||||
*/
|
||||
void complete() const;
|
||||
|
||||
private:
|
||||
struct Highlight {
|
||||
UnlocalizedString unlocalizedText;
|
||||
std::vector<std::variant<Lang, std::string, int>> highlightIds;
|
||||
};
|
||||
|
||||
struct Message {
|
||||
Position position;
|
||||
UnlocalizedString unlocalizedTitle;
|
||||
UnlocalizedString unlocalizedMessage;
|
||||
bool allowSkip;
|
||||
};
|
||||
|
||||
private:
|
||||
void addHighlights() const;
|
||||
void removeHighlights() const;
|
||||
|
||||
void advance(i32 steps = 1) const;
|
||||
|
||||
friend class TutorialManager;
|
||||
|
||||
Tutorial *m_parent;
|
||||
std::vector<Highlight> m_highlights;
|
||||
std::optional<Message> m_message;
|
||||
std::function<void()> m_onAppear, m_onComplete;
|
||||
};
|
||||
|
||||
Step& addStep();
|
||||
|
||||
const UnlocalizedString& getUnlocalizedName() const { return m_unlocalizedName; }
|
||||
const UnlocalizedString& getUnlocalizedDescription() const { return m_unlocalizedDescription; }
|
||||
|
||||
private:
|
||||
friend class TutorialManager;
|
||||
|
||||
void start();
|
||||
|
||||
UnlocalizedString m_unlocalizedName;
|
||||
UnlocalizedString m_unlocalizedDescription;
|
||||
std::list<Step> m_steps;
|
||||
decltype(m_steps)::iterator m_currentStep, m_latestStep;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Gets a list of all tutorials
|
||||
* @return List of all tutorials
|
||||
*/
|
||||
static const std::map<std::string, Tutorial>& getTutorials();
|
||||
|
||||
/**
|
||||
* @brief Gets the currently running tutorial
|
||||
* @return Iterator pointing to the current tutorial
|
||||
*/
|
||||
static std::map<std::string, Tutorial>::iterator getCurrentTutorial();
|
||||
|
||||
/**
|
||||
* @brief Creates a new tutorial that can be started later
|
||||
* @param unlocalizedName Name of the tutorial
|
||||
* @param unlocalizedDescription
|
||||
* @return Reference to created tutorial
|
||||
*/
|
||||
static Tutorial& createTutorial(const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedDescription);
|
||||
|
||||
/**
|
||||
* @brief Starts the tutorial with the given name
|
||||
* @param unlocalizedName Name of tutorial to start
|
||||
*/
|
||||
static void startTutorial(const UnlocalizedString &unlocalizedName);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Draws the tutorial
|
||||
* @note This function should only be called by the main GUI
|
||||
*/
|
||||
static void drawTutorial();
|
||||
|
||||
/**
|
||||
* @brief Resets the tutorial manager
|
||||
*/
|
||||
static void reset();
|
||||
|
||||
private:
|
||||
TutorialManager() = delete;
|
||||
|
||||
static void drawHighlights();
|
||||
static void drawMessageBox(std::optional<Tutorial::Step::Message> message);
|
||||
};
|
||||
|
||||
inline TutorialManager::Position operator|(TutorialManager::Position a, TutorialManager::Position b) {
|
||||
return static_cast<TutorialManager::Position>(static_cast<u8>(a) | static_cast<u8>(b));
|
||||
}
|
||||
|
||||
inline TutorialManager::Position operator&(TutorialManager::Position a, TutorialManager::Position b) {
|
||||
return static_cast<TutorialManager::Position>(static_cast<u8>(a) & static_cast<u8>(b));
|
||||
}
|
||||
|
||||
}
|
||||
37
lib/libimhex/include/hex/api/workspace_manager.hpp
Normal file
37
lib/libimhex/include/hex/api/workspace_manager.hpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include <wolv/io/fs.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class WorkspaceManager {
|
||||
public:
|
||||
struct Workspace {
|
||||
std::string layout;
|
||||
std::fs::path path;
|
||||
};
|
||||
|
||||
static void createWorkspace(const std::string &name, const std::string &layout = "");
|
||||
static void switchWorkspace(const std::string &name);
|
||||
|
||||
static void importFromFile(const std::fs::path &path);
|
||||
static bool exportToFile(std::fs::path path = {}, std::string workspaceName = {});
|
||||
|
||||
static const auto& getWorkspaces() { return s_workspaces; }
|
||||
static const auto& getCurrentWorkspace() { return s_currentWorkspace; }
|
||||
|
||||
static void reset();
|
||||
|
||||
static void process();
|
||||
|
||||
private:
|
||||
WorkspaceManager() = default;
|
||||
|
||||
static std::map<std::string, Workspace> s_workspaces;
|
||||
static decltype(s_workspaces)::iterator s_currentWorkspace, s_previousWorkspace;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
@@ -23,32 +25,32 @@ namespace hex::dp {
|
||||
Out
|
||||
};
|
||||
|
||||
Attribute(IOType ioType, Type type, std::string unlocalizedName);
|
||||
Attribute(IOType ioType, Type type, UnlocalizedString unlocalizedName);
|
||||
~Attribute();
|
||||
|
||||
[[nodiscard]] int getId() const { return this->m_id; }
|
||||
void setId(int id) { this->m_id = id; }
|
||||
[[nodiscard]] int getId() const { return m_id; }
|
||||
void setId(int id) { m_id = id; }
|
||||
|
||||
[[nodiscard]] IOType getIOType() const { return this->m_ioType; }
|
||||
[[nodiscard]] Type getType() const { return this->m_type; }
|
||||
[[nodiscard]] const std::string &getUnlocalizedName() const { return this->m_unlocalizedName; }
|
||||
[[nodiscard]] IOType getIOType() const { return m_ioType; }
|
||||
[[nodiscard]] Type getType() const { return m_type; }
|
||||
[[nodiscard]] const UnlocalizedString &getUnlocalizedName() const { return m_unlocalizedName; }
|
||||
|
||||
void addConnectedAttribute(int linkId, Attribute *to) { this->m_connectedAttributes.insert({ linkId, to }); }
|
||||
void removeConnectedAttribute(int linkId) { this->m_connectedAttributes.erase(linkId); }
|
||||
[[nodiscard]] std::map<int, Attribute *> &getConnectedAttributes() { return this->m_connectedAttributes; }
|
||||
void addConnectedAttribute(int linkId, Attribute *to) { m_connectedAttributes.insert({ linkId, to }); }
|
||||
void removeConnectedAttribute(int linkId) { m_connectedAttributes.erase(linkId); }
|
||||
[[nodiscard]] std::map<int, Attribute *> &getConnectedAttributes() { return m_connectedAttributes; }
|
||||
|
||||
[[nodiscard]] Node *getParentNode() const { return this->m_parentNode; }
|
||||
[[nodiscard]] Node *getParentNode() const { return m_parentNode; }
|
||||
|
||||
[[nodiscard]] std::vector<u8>& getOutputData() {
|
||||
if (!this->m_outputData.empty())
|
||||
return this->m_outputData;
|
||||
if (!m_outputData.empty())
|
||||
return m_outputData;
|
||||
else
|
||||
return this->m_defaultData;
|
||||
return m_defaultData;
|
||||
}
|
||||
|
||||
void clearOutputData() { this->m_outputData.clear(); }
|
||||
void clearOutputData() { m_outputData.clear(); }
|
||||
|
||||
[[nodiscard]] std::vector<u8>& getDefaultData() { return this->m_defaultData; }
|
||||
[[nodiscard]] std::vector<u8>& getDefaultData() { return m_defaultData; }
|
||||
|
||||
static void setIdCounter(int id);
|
||||
|
||||
@@ -56,7 +58,7 @@ namespace hex::dp {
|
||||
int m_id;
|
||||
IOType m_ioType;
|
||||
Type m_type;
|
||||
std::string m_unlocalizedName;
|
||||
UnlocalizedString m_unlocalizedName;
|
||||
std::map<int, Attribute *> m_connectedAttributes;
|
||||
Node *m_parentNode = nullptr;
|
||||
|
||||
@@ -64,7 +66,7 @@ namespace hex::dp {
|
||||
std::vector<u8> m_defaultData;
|
||||
|
||||
friend class Node;
|
||||
void setParentNode(Node *node) { this->m_parentNode = node; }
|
||||
void setParentNode(Node *node) { m_parentNode = node; }
|
||||
|
||||
static int s_idCounter;
|
||||
};
|
||||
|
||||
@@ -6,11 +6,11 @@ namespace hex::dp {
|
||||
public:
|
||||
Link(int from, int to);
|
||||
|
||||
[[nodiscard]] int getId() const { return this->m_id; }
|
||||
void setId(int id) { this->m_id = id; }
|
||||
[[nodiscard]] int getId() const { return m_id; }
|
||||
void setId(int id) { m_id = id; }
|
||||
|
||||
[[nodiscard]] int getFromId() const { return this->m_from; }
|
||||
[[nodiscard]] int getToId() const { return this->m_to; }
|
||||
[[nodiscard]] int getFromId() const { return m_from; }
|
||||
[[nodiscard]] int getToId() const { return m_to; }
|
||||
|
||||
static void setIdCounter(int id);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
||||
#include <hex/helpers/intrinsics.hpp>
|
||||
#include <hex/data_processor/attribute.hpp>
|
||||
@@ -21,24 +22,24 @@ namespace hex::dp {
|
||||
|
||||
class Node {
|
||||
public:
|
||||
Node(std::string unlocalizedTitle, std::vector<Attribute> attributes);
|
||||
Node(UnlocalizedString unlocalizedTitle, std::vector<Attribute> attributes);
|
||||
|
||||
virtual ~Node() = default;
|
||||
|
||||
[[nodiscard]] int getId() const { return this->m_id; }
|
||||
void setId(int id) { this->m_id = id; }
|
||||
[[nodiscard]] int getId() const { return m_id; }
|
||||
void setId(int id) { m_id = id; }
|
||||
|
||||
[[nodiscard]] const std::string &getUnlocalizedName() const { return this->m_unlocalizedName; }
|
||||
void setUnlocalizedName(const std::string &unlocalizedName) { this->m_unlocalizedName = unlocalizedName; }
|
||||
[[nodiscard]] const UnlocalizedString &getUnlocalizedName() const { return m_unlocalizedName; }
|
||||
void setUnlocalizedName(const UnlocalizedString &unlocalizedName) { m_unlocalizedName = unlocalizedName; }
|
||||
|
||||
[[nodiscard]] const std::string &getUnlocalizedTitle() const { return this->m_unlocalizedTitle; }
|
||||
void setUnlocalizedTitle(std::string title) { this->m_unlocalizedTitle = std::move(title); }
|
||||
[[nodiscard]] const UnlocalizedString &getUnlocalizedTitle() const { return m_unlocalizedTitle; }
|
||||
void setUnlocalizedTitle(std::string title) { m_unlocalizedTitle = std::move(title); }
|
||||
|
||||
[[nodiscard]] std::vector<Attribute> &getAttributes() { return this->m_attributes; }
|
||||
[[nodiscard]] const std::vector<Attribute> &getAttributes() const { return this->m_attributes; }
|
||||
[[nodiscard]] std::vector<Attribute> &getAttributes() { return m_attributes; }
|
||||
[[nodiscard]] const std::vector<Attribute> &getAttributes() const { return m_attributes; }
|
||||
|
||||
void setCurrentOverlay(prv::Overlay *overlay) {
|
||||
this->m_overlay = overlay;
|
||||
m_overlay = overlay;
|
||||
}
|
||||
|
||||
virtual void drawNode() { }
|
||||
@@ -53,20 +54,20 @@ namespace hex::dp {
|
||||
};
|
||||
|
||||
void resetOutputData() {
|
||||
for (auto &attribute : this->m_attributes)
|
||||
for (auto &attribute : m_attributes)
|
||||
attribute.clearOutputData();
|
||||
}
|
||||
|
||||
void resetProcessedInputs() {
|
||||
this->m_processedInputs.clear();
|
||||
m_processedInputs.clear();
|
||||
}
|
||||
|
||||
void setPosition(ImVec2 pos) {
|
||||
this->m_position = pos;
|
||||
m_position = pos;
|
||||
}
|
||||
|
||||
[[nodiscard]] ImVec2 getPosition() const {
|
||||
return this->m_position;
|
||||
return m_position;
|
||||
}
|
||||
|
||||
static void setIdCounter(int id);
|
||||
@@ -81,7 +82,7 @@ namespace hex::dp {
|
||||
|
||||
private:
|
||||
int m_id;
|
||||
std::string m_unlocalizedTitle, m_unlocalizedName;
|
||||
UnlocalizedString m_unlocalizedTitle, m_unlocalizedName;
|
||||
std::vector<Attribute> m_attributes;
|
||||
std::set<u32> m_processedInputs;
|
||||
prv::Overlay *m_overlay = nullptr;
|
||||
@@ -106,13 +107,13 @@ namespace hex::dp {
|
||||
}
|
||||
|
||||
void markInputProcessed(u32 index) {
|
||||
const auto &[iter, inserted] = this->m_processedInputs.insert(index);
|
||||
const auto &[iter, inserted] = m_processedInputs.insert(index);
|
||||
if (!inserted)
|
||||
throwNodeError("Recursion detected!");
|
||||
}
|
||||
|
||||
void unmarkInputProcessed(u32 index) {
|
||||
this->m_processedInputs.erase(index);
|
||||
m_processedInputs.erase(index);
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -123,9 +124,9 @@ namespace hex::dp {
|
||||
void setOverlayData(u64 address, const std::vector<u8> &data);
|
||||
|
||||
void setAttributes(std::vector<Attribute> attributes) {
|
||||
this->m_attributes = std::move(attributes);
|
||||
m_attributes = std::move(attributes);
|
||||
|
||||
for (auto &attr : this->m_attributes)
|
||||
for (auto &attr : m_attributes)
|
||||
attr.setParentNode(this);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -17,13 +17,13 @@ namespace hex {
|
||||
BinaryPattern() = default;
|
||||
explicit BinaryPattern(const std::string &pattern) : m_patterns(parseBinaryPatternString(pattern)) { }
|
||||
|
||||
[[nodiscard]] bool isValid() const { return !this->m_patterns.empty(); }
|
||||
[[nodiscard]] bool isValid() const { return !m_patterns.empty(); }
|
||||
|
||||
[[nodiscard]] bool matches(const std::vector<u8> &bytes) const {
|
||||
if (bytes.size() < this->m_patterns.size())
|
||||
if (bytes.size() < m_patterns.size())
|
||||
return false;
|
||||
|
||||
for (u32 i = 0; i < this->m_patterns.size(); i++) {
|
||||
for (u32 i = 0; i < m_patterns.size(); i++) {
|
||||
if (!this->matchesByte(bytes[i], i))
|
||||
return false;
|
||||
}
|
||||
@@ -32,13 +32,13 @@ namespace hex {
|
||||
}
|
||||
|
||||
[[nodiscard]] bool matchesByte(u8 byte, u32 offset) const {
|
||||
const auto &pattern = this->m_patterns[offset];
|
||||
const auto &pattern = m_patterns[offset];
|
||||
|
||||
return (byte & pattern.mask) == pattern.value;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t getSize() const {
|
||||
return this->m_patterns.size();
|
||||
[[nodiscard]] u64 getSize() const {
|
||||
return m_patterns.size();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -29,9 +29,9 @@ namespace hex::dbg {
|
||||
if constexpr (std::same_as<Type, bool>) {
|
||||
ImGui::Checkbox(name.data(), &variable);
|
||||
} else if constexpr (std::integral<Type> || std::floating_point<Type>) {
|
||||
ImGui::InputScalar(name.data(), ImGuiExt::getImGuiDataType<Type>(), &variable);
|
||||
ImGui::DragScalar(name.data(), ImGuiExt::getImGuiDataType<Type>(), &variable);
|
||||
} else if constexpr (std::same_as<Type, ImVec2>) {
|
||||
ImGui::InputFloat2(name.data(), &variable.x);
|
||||
ImGui::DragFloat2(name.data(), &variable.x);
|
||||
} else if constexpr (std::same_as<Type, std::string>) {
|
||||
ImGui::InputText(name.data(), variable);
|
||||
} else if constexpr (std::same_as<Type, ImColor>) {
|
||||
|
||||
@@ -29,13 +29,13 @@ namespace hex {
|
||||
|
||||
[[nodiscard]] std::pair<std::string_view, size_t> getEncodingFor(std::span<u8> buffer) const;
|
||||
[[nodiscard]] size_t getEncodingLengthFor(std::span<u8> buffer) const;
|
||||
[[nodiscard]] size_t getLongestSequence() const { return this->m_longestSequence; }
|
||||
[[nodiscard]] size_t getLongestSequence() const { return m_longestSequence; }
|
||||
|
||||
[[nodiscard]] bool valid() const { return this->m_valid; }
|
||||
[[nodiscard]] bool valid() const { return m_valid; }
|
||||
|
||||
[[nodiscard]] const std::string& getTableContent() const { return this->m_tableContent; }
|
||||
[[nodiscard]] const std::string& getTableContent() const { return m_tableContent; }
|
||||
|
||||
[[nodiscard]] const std::string& getName() const { return this->m_name; }
|
||||
[[nodiscard]] const std::string& getName() const { return m_name; }
|
||||
|
||||
private:
|
||||
void parse(const std::string &content);
|
||||
|
||||
@@ -38,6 +38,7 @@ namespace hex::fs {
|
||||
Plugins,
|
||||
Yara,
|
||||
Config,
|
||||
Backups,
|
||||
Resources,
|
||||
Constants,
|
||||
Encodings,
|
||||
@@ -49,6 +50,7 @@ namespace hex::fs {
|
||||
Libraries,
|
||||
Nodes,
|
||||
Layouts,
|
||||
Workspaces,
|
||||
|
||||
END
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace hex {
|
||||
explicit ResultBase(u32 statusCode) : m_statusCode(statusCode), m_valid(true) { }
|
||||
|
||||
[[nodiscard]] u32 getStatusCode() const {
|
||||
return this->m_statusCode;
|
||||
return m_statusCode;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isSuccess() const {
|
||||
@@ -39,7 +39,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isValid() const {
|
||||
return this->m_valid;
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -55,7 +55,7 @@ namespace hex {
|
||||
|
||||
[[nodiscard]]
|
||||
const T& getData() const {
|
||||
return this->m_data;
|
||||
return m_data;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -76,31 +76,31 @@ namespace hex {
|
||||
static void setProxyUrl(std::string proxy);
|
||||
|
||||
void setMethod(std::string method) {
|
||||
this->m_method = std::move(method);
|
||||
m_method = std::move(method);
|
||||
}
|
||||
|
||||
void setUrl(std::string url) {
|
||||
this->m_url = std::move(url);
|
||||
m_url = std::move(url);
|
||||
}
|
||||
|
||||
void addHeader(std::string key, std::string value) {
|
||||
this->m_headers[std::move(key)] = std::move(value);
|
||||
m_headers[std::move(key)] = std::move(value);
|
||||
}
|
||||
|
||||
void setBody(std::string body) {
|
||||
this->m_body = std::move(body);
|
||||
m_body = std::move(body);
|
||||
}
|
||||
|
||||
void setTimeout(u32 timeout) {
|
||||
this->m_timeout = timeout;
|
||||
m_timeout = timeout;
|
||||
}
|
||||
|
||||
float getProgress() const {
|
||||
return this->m_progress;
|
||||
return m_progress;
|
||||
}
|
||||
|
||||
void cancel() {
|
||||
this->m_canceled = true;
|
||||
m_canceled = true;
|
||||
}
|
||||
|
||||
template<typename T = std::string>
|
||||
|
||||
@@ -44,24 +44,24 @@ namespace hex {
|
||||
|
||||
template<typename T>
|
||||
HttpRequest::Result<T> HttpRequest::executeImpl(std::vector<u8> &data) {
|
||||
strcpy(this->m_attr.requestMethod, this->m_method.c_str());
|
||||
this->m_attr.attributes = EMSCRIPTEN_FETCH_SYNCHRONOUS | EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
|
||||
strcpy(m_attr.requestMethod, m_method.c_str());
|
||||
m_attr.attributes = EMSCRIPTEN_FETCH_SYNCHRONOUS | EMSCRIPTEN_FETCH_LOAD_TO_MEMORY;
|
||||
|
||||
if (!this->m_body.empty()) {
|
||||
this->m_attr.requestData = this->m_body.c_str();
|
||||
this->m_attr.requestDataSize = this->m_body.size();
|
||||
if (!m_body.empty()) {
|
||||
m_attr.requestData = m_body.c_str();
|
||||
m_attr.requestDataSize = m_body.size();
|
||||
}
|
||||
|
||||
std::vector<const char*> headers;
|
||||
for (auto it = this->m_headers.begin(); it != this->m_headers.end(); it++) {
|
||||
for (auto it = m_headers.begin(); it != m_headers.end(); it++) {
|
||||
headers.push_back(it->first.c_str());
|
||||
headers.push_back(it->second.c_str());
|
||||
}
|
||||
headers.push_back(nullptr);
|
||||
this->m_attr.requestHeaders = headers.data();
|
||||
m_attr.requestHeaders = headers.data();
|
||||
|
||||
// Send request
|
||||
emscripten_fetch_t* fetch = emscripten_fetch(&this->m_attr, this->m_url.c_str());
|
||||
emscripten_fetch_t* fetch = emscripten_fetch(&m_attr, m_url.c_str());
|
||||
|
||||
data.resize(fetch->numBytes);
|
||||
std::copy(fetch->data, fetch->data + fetch->numBytes, data.begin());
|
||||
|
||||
@@ -18,8 +18,8 @@ namespace hex {
|
||||
std::vector<u8> response;
|
||||
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToFile);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &file);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToFile);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &file);
|
||||
|
||||
return this->executeImpl<T>(response);
|
||||
});
|
||||
@@ -30,7 +30,7 @@ namespace hex {
|
||||
return std::async(std::launch::async, [this, path, mimeName]{
|
||||
auto fileName = wolv::util::toUTF8String(path.filename());
|
||||
|
||||
curl_mime *mime = curl_mime_init(this->m_curl);
|
||||
curl_mime *mime = curl_mime_init(m_curl);
|
||||
curl_mimepart *part = curl_mime_addpart(mime);
|
||||
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Read);
|
||||
@@ -58,11 +58,11 @@ namespace hex {
|
||||
curl_mime_filename(part, fileName.c_str());
|
||||
curl_mime_name(part, mimeName.c_str());
|
||||
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_MIMEPOST, mime);
|
||||
curl_easy_setopt(m_curl, CURLOPT_MIMEPOST, mime);
|
||||
|
||||
std::vector<u8> responseData;
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &responseData);
|
||||
|
||||
return this->executeImpl<T>(responseData);
|
||||
});
|
||||
@@ -71,7 +71,7 @@ namespace hex {
|
||||
template<typename T>
|
||||
std::future<HttpRequest::Result<T>> HttpRequest::uploadFile(std::vector<u8> data, const std::string &mimeName, const std::fs::path &fileName) {
|
||||
return std::async(std::launch::async, [this, data = std::move(data), mimeName, fileName]{
|
||||
curl_mime *mime = curl_mime_init(this->m_curl);
|
||||
curl_mime *mime = curl_mime_init(m_curl);
|
||||
curl_mimepart *part = curl_mime_addpart(mime);
|
||||
|
||||
curl_mime_data(part, reinterpret_cast<const char *>(data.data()), data.size());
|
||||
@@ -79,11 +79,11 @@ namespace hex {
|
||||
curl_mime_filename(part, fileNameStr.c_str());
|
||||
curl_mime_name(part, mimeName.c_str());
|
||||
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_MIMEPOST, mime);
|
||||
curl_easy_setopt(m_curl, CURLOPT_MIMEPOST, mime);
|
||||
|
||||
std::vector<u8> responseData;
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &responseData);
|
||||
|
||||
return this->executeImpl<T>(responseData);
|
||||
});
|
||||
@@ -94,8 +94,8 @@ namespace hex {
|
||||
return std::async(std::launch::async, [this] {
|
||||
|
||||
std::vector<u8> responseData;
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &responseData);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &responseData);
|
||||
|
||||
return this->executeImpl<T>(responseData);
|
||||
});
|
||||
@@ -103,33 +103,33 @@ namespace hex {
|
||||
|
||||
template<typename T>
|
||||
HttpRequest::Result<T> HttpRequest::executeImpl(std::vector<u8> &data) {
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_URL, this->m_url.c_str());
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_CUSTOMREQUEST, this->m_method.c_str());
|
||||
curl_easy_setopt(m_curl, CURLOPT_URL, m_url.c_str());
|
||||
curl_easy_setopt(m_curl, CURLOPT_CUSTOMREQUEST, m_method.c_str());
|
||||
|
||||
setDefaultConfig();
|
||||
|
||||
if (!this->m_body.empty()) {
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_POSTFIELDS, this->m_body.c_str());
|
||||
if (!m_body.empty()) {
|
||||
curl_easy_setopt(m_curl, CURLOPT_POSTFIELDS, m_body.c_str());
|
||||
}
|
||||
|
||||
curl_slist *headers = nullptr;
|
||||
headers = curl_slist_append(headers, "Cache-Control: no-cache");
|
||||
ON_SCOPE_EXIT { curl_slist_free_all(headers); };
|
||||
|
||||
for (auto &[key, value] : this->m_headers) {
|
||||
for (auto &[key, value] : m_headers) {
|
||||
std::string header = hex::format("{}: {}", key, value);
|
||||
headers = curl_slist_append(headers, header.c_str());
|
||||
}
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_HTTPHEADER, headers);
|
||||
curl_easy_setopt(m_curl, CURLOPT_HTTPHEADER, headers);
|
||||
|
||||
{
|
||||
std::scoped_lock lock(this->m_transmissionMutex);
|
||||
std::scoped_lock lock(m_transmissionMutex);
|
||||
|
||||
auto result = curl_easy_perform(this->m_curl);
|
||||
auto result = curl_easy_perform(m_curl);
|
||||
if (result != CURLE_OK){
|
||||
char *url = nullptr;
|
||||
curl_easy_getinfo(this->m_curl, CURLINFO_EFFECTIVE_URL, &url);
|
||||
log::error("Http request '{0} {1}' failed with error {2}: '{3}'", this->m_method, url, u32(result), curl_easy_strerror(result));
|
||||
curl_easy_getinfo(m_curl, CURLINFO_EFFECTIVE_URL, &url);
|
||||
log::error("Http request '{0} {1}' failed with error {2}: '{3}'", m_method, url, u32(result), curl_easy_strerror(result));
|
||||
checkProxyErrors();
|
||||
|
||||
return { };
|
||||
@@ -137,7 +137,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
long statusCode = 0;
|
||||
curl_easy_getinfo(this->m_curl, CURLINFO_RESPONSE_CODE, &statusCode);
|
||||
curl_easy_getinfo(m_curl, CURLINFO_RESPONSE_CODE, &statusCode);
|
||||
|
||||
return Result<T>(statusCode, { data.begin(), data.end() });
|
||||
}
|
||||
|
||||
@@ -29,19 +29,19 @@ namespace hex::log {
|
||||
|
||||
std::vector<LogEntry>& getLogEntries();
|
||||
|
||||
[[maybe_unused]] void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level);
|
||||
[[maybe_unused]] void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level, const char *projectName);
|
||||
|
||||
[[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto && ... args) {
|
||||
std::scoped_lock lock(impl::g_loggerMutex);
|
||||
std::scoped_lock lock(g_loggerMutex);
|
||||
|
||||
auto dest = impl::getDestination();
|
||||
printPrefix(dest, ts, level);
|
||||
auto dest = getDestination();
|
||||
printPrefix(dest, ts, level, IMHEX_PROJECT_NAME);
|
||||
|
||||
auto message = fmt::format(fmt::runtime(fmt), args...);
|
||||
fmt::print(dest, "{}\n", message);
|
||||
fflush(dest);
|
||||
|
||||
impl::getLogEntries().push_back({ IMHEX_PROJECT_NAME, level, std::move(message) });
|
||||
getLogEntries().push_back({ IMHEX_PROJECT_NAME, level, std::move(message) });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -33,8 +33,8 @@ namespace hex {
|
||||
wolv::util::Expected<std::vector<u8>, IPSError> toIPSPatch() const;
|
||||
wolv::util::Expected<std::vector<u8>, IPSError> toIPS32Patch() const;
|
||||
|
||||
const auto& get() const { return this->m_patches; }
|
||||
auto& get() { return this->m_patches; }
|
||||
const auto& get() const { return m_patches; }
|
||||
auto& get() { return m_patches; }
|
||||
|
||||
private:
|
||||
std::map<u64, u8> m_patches;
|
||||
|
||||
@@ -4,7 +4,9 @@
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <microtar.h>
|
||||
#include <memory>
|
||||
|
||||
struct mtar_t;
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -32,28 +34,28 @@ namespace hex {
|
||||
*/
|
||||
std::string getOpenErrorString() const;
|
||||
|
||||
[[nodiscard]] std::vector<u8> readVector(const std::fs::path &path);
|
||||
[[nodiscard]] std::string readString(const std::fs::path &path);
|
||||
[[nodiscard]] std::vector<u8> readVector(const std::fs::path &path) const;
|
||||
[[nodiscard]] std::string readString(const std::fs::path &path) const;
|
||||
|
||||
void writeVector(const std::fs::path &path, const std::vector<u8> &data);
|
||||
void writeString(const std::fs::path &path, const std::string &data);
|
||||
void writeVector(const std::fs::path &path, const std::vector<u8> &data) const;
|
||||
void writeString(const std::fs::path &path, const std::string &data) const;
|
||||
|
||||
[[nodiscard]] std::vector<std::fs::path> listEntries(const std::fs::path &basePath = "/");
|
||||
[[nodiscard]] bool contains(const std::fs::path &path);
|
||||
[[nodiscard]] std::vector<std::fs::path> listEntries(const std::fs::path &basePath = "/") const;
|
||||
[[nodiscard]] bool contains(const std::fs::path &path) const;
|
||||
|
||||
void extract(const std::fs::path &path, const std::fs::path &outputPath);
|
||||
void extractAll(const std::fs::path &outputPath);
|
||||
void extract(const std::fs::path &path, const std::fs::path &outputPath) const;
|
||||
void extractAll(const std::fs::path &outputPath) const;
|
||||
|
||||
[[nodiscard]] bool isValid() const { return this->m_valid; }
|
||||
[[nodiscard]] bool isValid() const { return m_valid; }
|
||||
|
||||
private:
|
||||
mtar_t m_ctx = { };
|
||||
std::unique_ptr<mtar_t> m_ctx;
|
||||
std::fs::path m_path;
|
||||
|
||||
bool m_valid = false;
|
||||
|
||||
// These will be updated when the constructor is called
|
||||
int m_tarOpenErrno = MTAR_ESUCCESS;
|
||||
int m_tarOpenErrno = 0;
|
||||
int m_fileOpenErrno = 0;
|
||||
};
|
||||
|
||||
|
||||
@@ -63,6 +63,9 @@ namespace hex {
|
||||
[[nodiscard]] std::string to_string(u128 value);
|
||||
[[nodiscard]] std::string to_string(i128 value);
|
||||
|
||||
[[nodiscard]] std::string toLower(std::string string);
|
||||
[[nodiscard]] std::string toUpper(std::string string);
|
||||
|
||||
[[nodiscard]] std::vector<u8> parseHexString(std::string string);
|
||||
[[nodiscard]] std::optional<u8> parseBinaryString(const std::string &string);
|
||||
[[nodiscard]] std::string toByteString(u64 bytes);
|
||||
@@ -75,6 +78,8 @@ namespace hex {
|
||||
[[nodiscard]] std::string encodeByteString(const std::vector<u8> &bytes);
|
||||
[[nodiscard]] std::vector<u8> decodeByteString(const std::string &string);
|
||||
|
||||
std::wstring utf8ToUtf16(const std::string& utf8);
|
||||
|
||||
[[nodiscard]] constexpr u64 extract(u8 from, u8 to, const std::unsigned_integral auto &value) {
|
||||
if (from < to) std::swap(from, to);
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
#if defined(OS_MACOS)
|
||||
|
||||
struct GLFWwindow;
|
||||
|
||||
extern "C" {
|
||||
|
||||
void errorMessageMacos(const char *message);
|
||||
@@ -9,6 +11,8 @@
|
||||
bool isMacosSystemDarkModeEnabled();
|
||||
float getBackingScaleFactor();
|
||||
|
||||
void setupMacosWindowStyle(GLFWwindow *window);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/plugin_manager.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -22,29 +23,57 @@
|
||||
* Name, Author and Description will be displayed in the in the plugin list on the Welcome screen.
|
||||
*/
|
||||
#define IMHEX_PLUGIN_SETUP(name, author, description) IMHEX_PLUGIN_SETUP_IMPL(name, author, description)
|
||||
#define IMHEX_LIBRARY_SETUP() IMHEX_LIBRARY_SETUP_IMPL()
|
||||
|
||||
#define IMHEX_PLUGIN_SETUP_IMPL(name, author, description) \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getPluginName() { return name; } \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getPluginAuthor() { return author; } \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getPluginDescription() { return description; } \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getCompatibleVersion() { return IMHEX_VERSION; } \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void setImGuiContext(ImGuiContext *ctx) { \
|
||||
ImGui::SetCurrentContext(ctx); \
|
||||
GImGui = ctx; \
|
||||
} \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void initializePlugin(); \
|
||||
extern "C" [[gnu::visibility("default")]] void WOLV_TOKEN_CONCAT(forceLinkPlugin_, IMHEX_PLUGIN_NAME)() { \
|
||||
hex::PluginManager::addPlugin(hex::PluginFunctions { \
|
||||
initializePlugin, \
|
||||
getPluginName, \
|
||||
getPluginAuthor, \
|
||||
getPluginDescription, \
|
||||
getCompatibleVersion, \
|
||||
setImGuiContext, \
|
||||
nullptr, \
|
||||
nullptr \
|
||||
}); \
|
||||
} \
|
||||
#define IMHEX_LIBRARY_SETUP_IMPL() \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void initializeLibrary(); \
|
||||
static auto WOLV_TOKEN_CONCAT(libraryInitializer_, IMHEX_PLUGIN_NAME) = [] { \
|
||||
initializeLibrary(); \
|
||||
hex::log::info("Library plugin '{}' initialized successfully", WOLV_STRINGIFY(IMHEX_PLUGIN_NAME)); \
|
||||
return 0; \
|
||||
}(); \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void setImGuiContext(ImGuiContext *ctx) { \
|
||||
ImGui::SetCurrentContext(ctx); \
|
||||
GImGui = ctx; \
|
||||
} \
|
||||
extern "C" [[gnu::visibility("default")]] void WOLV_TOKEN_CONCAT(forceLinkPlugin_, IMHEX_PLUGIN_NAME)() { \
|
||||
hex::PluginManager::addPlugin(hex::PluginFunctions { \
|
||||
nullptr, \
|
||||
initializeLibrary, \
|
||||
nullptr, \
|
||||
nullptr, \
|
||||
nullptr, \
|
||||
nullptr, \
|
||||
setImGuiContext, \
|
||||
nullptr, \
|
||||
nullptr \
|
||||
}); \
|
||||
} \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void initializeLibrary()
|
||||
|
||||
#define IMHEX_PLUGIN_SETUP_IMPL(name, author, description) \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getPluginName() { return name; } \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getPluginAuthor() { return author; } \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getPluginDescription() { return description; } \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX const char *getCompatibleVersion() { return IMHEX_VERSION; } \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void setImGuiContext(ImGuiContext *ctx) { \
|
||||
ImGui::SetCurrentContext(ctx); \
|
||||
GImGui = ctx; \
|
||||
} \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void initializePlugin(); \
|
||||
extern "C" [[gnu::visibility("default")]] void WOLV_TOKEN_CONCAT(forceLinkPlugin_, IMHEX_PLUGIN_NAME)() { \
|
||||
hex::PluginManager::addPlugin(hex::PluginFunctions { \
|
||||
initializePlugin, \
|
||||
nullptr, \
|
||||
getPluginName, \
|
||||
getPluginAuthor, \
|
||||
getPluginDescription, \
|
||||
getCompatibleVersion, \
|
||||
setImGuiContext, \
|
||||
nullptr, \
|
||||
nullptr \
|
||||
}); \
|
||||
} \
|
||||
IMHEX_PLUGIN_VISIBILITY_PREFIX void initializePlugin()
|
||||
|
||||
/**
|
||||
@@ -63,3 +92,12 @@
|
||||
return &g_subCommands; \
|
||||
} \
|
||||
std::vector<hex::SubCommand> g_subCommands
|
||||
|
||||
#define IMHEX_FEATURE_ENABLED(feature) WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(WOLV_TOKEN_CONCAT(IMHEX_PLUGIN_, IMHEX_PLUGIN_NAME), _FEATURE_), feature)
|
||||
#define IMHEX_PLUGIN_FEATURES() IMHEX_PLUGIN_FEATURES_IMPL()
|
||||
#define IMHEX_PLUGIN_FEATURES_IMPL() \
|
||||
extern std::vector<hex::Feature> g_features; \
|
||||
extern "C" [[gnu::visibility("default")]] void* getFeatures() { \
|
||||
return &g_features; \
|
||||
} \
|
||||
std::vector<hex::Feature> g_features
|
||||
|
||||
46
lib/libimhex/include/hex/providers/memory_provider.hpp
Normal file
46
lib/libimhex/include/hex/providers/memory_provider.hpp
Normal file
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
/**
|
||||
* This is a simple mock provider that can be used to pass in-memory data to APIs that require a provider.
|
||||
* It's NOT a provider that can be loaded by the user.
|
||||
*/
|
||||
class MemoryProvider : public hex::prv::Provider {
|
||||
public:
|
||||
MemoryProvider() = default;
|
||||
explicit MemoryProvider(std::vector<u8> data) : m_data(std::move(data)) { }
|
||||
~MemoryProvider() override = default;
|
||||
|
||||
[[nodiscard]] bool isAvailable() const override { return true; }
|
||||
[[nodiscard]] bool isReadable() const override { return true; }
|
||||
[[nodiscard]] bool isWritable() const override { return true; }
|
||||
[[nodiscard]] bool isResizable() const override { return true; }
|
||||
[[nodiscard]] bool isSavable() const override { return m_name.empty(); }
|
||||
[[nodiscard]] bool isSavableAsRecent() const override { return false; }
|
||||
|
||||
[[nodiscard]] bool open() override;
|
||||
void close() override { }
|
||||
|
||||
void readRaw(u64 offset, void *buffer, size_t size) override;
|
||||
void writeRaw(u64 offset, const void *buffer, size_t size) override;
|
||||
[[nodiscard]] u64 getActualSize() const override { return m_data.size(); }
|
||||
|
||||
void resizeRaw(u64 newSize) override;
|
||||
void insertRaw(u64 offset, u64 size) override;
|
||||
void removeRaw(u64 offset, u64 size) override;
|
||||
|
||||
[[nodiscard]] std::string getName() const override { return ""; }
|
||||
|
||||
[[nodiscard]] std::string getTypeName() const override { return "MemoryProvider"; }
|
||||
private:
|
||||
void renameFile();
|
||||
|
||||
private:
|
||||
std::vector<u8> m_data;
|
||||
std::string m_name;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -10,11 +10,11 @@ namespace hex::prv {
|
||||
public:
|
||||
Overlay() = default;
|
||||
|
||||
void setAddress(u64 address) { this->m_address = address; }
|
||||
[[nodiscard]] u64 getAddress() const { return this->m_address; }
|
||||
void setAddress(u64 address) { m_address = address; }
|
||||
[[nodiscard]] u64 getAddress() const { return m_address; }
|
||||
|
||||
[[nodiscard]] u64 getSize() const { return this->m_data.size(); }
|
||||
[[nodiscard]] std::vector<u8> &getData() { return this->m_data; }
|
||||
[[nodiscard]] u64 getSize() const { return m_data.size(); }
|
||||
[[nodiscard]] std::vector<u8> &getData() { return m_data; }
|
||||
|
||||
private:
|
||||
u64 m_address = 0;
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace hex::prv {
|
||||
std::function<void()> callback;
|
||||
};
|
||||
|
||||
constexpr static size_t MaxPageSize = 0x1000'0000;
|
||||
constexpr static u64 MaxPageSize = 0xFFFF'FFFF'FFFF'FFFF;
|
||||
|
||||
Provider();
|
||||
virtual ~Provider();
|
||||
@@ -137,7 +137,7 @@ namespace hex::prv {
|
||||
* @brief Get the full size of the data in this provider
|
||||
* @return The size of the entire available data of this provider
|
||||
*/
|
||||
[[nodiscard]] virtual size_t getActualSize() const = 0;
|
||||
[[nodiscard]] virtual u64 getActualSize() const = 0;
|
||||
|
||||
/**
|
||||
* @brief Gets the type name of this provider
|
||||
@@ -156,13 +156,13 @@ namespace hex::prv {
|
||||
*/
|
||||
[[nodiscard]] virtual std::string getName() const = 0;
|
||||
|
||||
void resize(size_t newSize);
|
||||
void insert(u64 offset, size_t size);
|
||||
void remove(u64 offset, size_t size);
|
||||
void resize(u64 newSize);
|
||||
void insert(u64 offset, u64 size);
|
||||
void remove(u64 offset, u64 size);
|
||||
|
||||
virtual void resizeRaw(size_t newSize) { hex::unused(newSize); }
|
||||
virtual void insertRaw(u64 offset, size_t size) { hex::unused(offset, size); }
|
||||
virtual void removeRaw(u64 offset, size_t size) { hex::unused(offset, size); }
|
||||
virtual void resizeRaw(u64 newSize) { hex::unused(newSize); }
|
||||
virtual void insertRaw(u64 offset, u64 size) { hex::unused(offset, size); }
|
||||
virtual void removeRaw(u64 offset, u64 size) { hex::unused(offset, size); }
|
||||
|
||||
virtual void save();
|
||||
virtual void saveAs(const std::fs::path &path);
|
||||
@@ -172,8 +172,8 @@ namespace hex::prv {
|
||||
void applyOverlays(u64 offset, void *buffer, size_t size) const;
|
||||
[[nodiscard]] const std::list<std::unique_ptr<Overlay>> &getOverlays() const;
|
||||
|
||||
[[nodiscard]] size_t getPageSize() const;
|
||||
void setPageSize(size_t pageSize);
|
||||
[[nodiscard]] u64 getPageSize() const;
|
||||
void setPageSize(u64 pageSize);
|
||||
|
||||
[[nodiscard]] u32 getPageCount() const;
|
||||
[[nodiscard]] u32 getCurrentPage() const;
|
||||
@@ -182,7 +182,7 @@ namespace hex::prv {
|
||||
virtual void setBaseAddress(u64 address);
|
||||
[[nodiscard]] virtual u64 getBaseAddress() const;
|
||||
[[nodiscard]] virtual u64 getCurrentPageAddress() const;
|
||||
[[nodiscard]] virtual size_t getSize() const;
|
||||
[[nodiscard]] virtual u64 getSize() const;
|
||||
[[nodiscard]] virtual std::optional<u32> getPageOfAddress(u64 address) const;
|
||||
|
||||
[[nodiscard]] virtual std::vector<Description> getDataDescription() const;
|
||||
@@ -210,23 +210,23 @@ namespace hex::prv {
|
||||
[[nodiscard]] virtual nlohmann::json storeSettings(nlohmann::json settings) const;
|
||||
virtual void loadSettings(const nlohmann::json &settings);
|
||||
|
||||
void markDirty(bool dirty = true) { this->m_dirty = dirty; }
|
||||
[[nodiscard]] bool isDirty() const { return this->m_dirty; }
|
||||
void markDirty(bool dirty = true) { m_dirty = dirty; }
|
||||
[[nodiscard]] bool isDirty() const { return m_dirty; }
|
||||
|
||||
[[nodiscard]] virtual std::pair<Region, bool> getRegionValidity(u64 address) const;
|
||||
|
||||
void skipLoadInterface() { this->m_skipLoadInterface = true; }
|
||||
[[nodiscard]] bool shouldSkipLoadInterface() const { return this->m_skipLoadInterface; }
|
||||
void skipLoadInterface() { m_skipLoadInterface = true; }
|
||||
[[nodiscard]] bool shouldSkipLoadInterface() const { return m_skipLoadInterface; }
|
||||
|
||||
void setErrorMessage(const std::string &errorMessage) { this->m_errorMessage = errorMessage; }
|
||||
[[nodiscard]] const std::string& getErrorMessage() const { return this->m_errorMessage; }
|
||||
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 this->m_undoRedoStack.add<T>(std::forward<decltype(args)...>(args)...);
|
||||
return m_undoRedoStack.add<T>(std::forward<decltype(args)...>(args)...);
|
||||
}
|
||||
|
||||
[[nodiscard]] undo::Stack& getUndoStack() { return this->m_undoRedoStack; }
|
||||
[[nodiscard]] undo::Stack& getUndoStack() { return m_undoRedoStack; }
|
||||
|
||||
protected:
|
||||
u32 m_currPage = 0;
|
||||
@@ -255,7 +255,7 @@ namespace hex::prv {
|
||||
|
||||
std::string m_errorMessage;
|
||||
|
||||
size_t m_pageSize = MaxPageSize;
|
||||
u64 m_pageSize = MaxPageSize;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -34,19 +34,19 @@ namespace hex {
|
||||
}
|
||||
|
||||
T& get(prv::Provider *provider = ImHexApi::Provider::get()) {
|
||||
return this->m_data[provider];
|
||||
return m_data[provider];
|
||||
}
|
||||
|
||||
const T& get(prv::Provider *provider = ImHexApi::Provider::get()) const {
|
||||
return this->m_data[provider];
|
||||
return m_data.at(provider);
|
||||
}
|
||||
|
||||
void set(const T &data, prv::Provider *provider = ImHexApi::Provider::get()) {
|
||||
this->m_data[provider] = data;
|
||||
m_data[provider] = data;
|
||||
}
|
||||
|
||||
void set(T &&data, prv::Provider *provider = ImHexApi::Provider::get()) {
|
||||
this->m_data[provider] = std::move(data);
|
||||
m_data[provider] = std::move(data);
|
||||
}
|
||||
|
||||
T& operator*() {
|
||||
@@ -73,20 +73,20 @@ namespace hex {
|
||||
|
||||
private:
|
||||
void onCreate() {
|
||||
EventManager::subscribe<EventProviderOpened>(this, [this](prv::Provider *provider) {
|
||||
this->m_data.emplace(provider, T());
|
||||
EventProviderOpened::subscribe(this, [this](prv::Provider *provider) {
|
||||
m_data.emplace(provider, T());
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderDeleted>(this, [this](prv::Provider *provider){
|
||||
this->m_data.erase(provider);
|
||||
EventProviderDeleted::subscribe(this, [this](prv::Provider *provider){
|
||||
m_data.erase(provider);
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventImHexClosing>(this, [this] {
|
||||
this->m_data.clear();
|
||||
EventImHexClosing::subscribe(this, [this] {
|
||||
m_data.clear();
|
||||
});
|
||||
|
||||
// Moves the data of this PerProvider instance from one provider to another
|
||||
EventManager::subscribe<MovePerProviderData>(this, [this](prv::Provider *from, prv::Provider *to) {
|
||||
MovePerProviderData::subscribe(this, [this](prv::Provider *from, prv::Provider *to) {
|
||||
// Get the value from the old provider, (removes it from the map)
|
||||
auto node = m_data.extract(from);
|
||||
|
||||
@@ -94,18 +94,19 @@ namespace hex {
|
||||
if (node.empty()) return;
|
||||
|
||||
// Delete the value from the new provider, that we want to replace
|
||||
this->m_data.erase(to);
|
||||
m_data.erase(to);
|
||||
|
||||
// Re-insert it with the key of the new provider
|
||||
node.key() = to;
|
||||
this->m_data.insert(std::move(node));
|
||||
m_data.insert(std::move(node));
|
||||
});
|
||||
}
|
||||
|
||||
void onDestroy() {
|
||||
EventManager::unsubscribe<EventProviderOpened>(this);
|
||||
EventManager::unsubscribe<EventProviderDeleted>(this);
|
||||
EventManager::unsubscribe<EventImHexClosing>(this);
|
||||
EventProviderOpened::unsubscribe(this);
|
||||
EventProviderDeleted::unsubscribe(this);
|
||||
EventImHexClosing::unsubscribe(this);
|
||||
MovePerProviderData::unsubscribe(this);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -10,44 +10,44 @@ namespace hex::prv::undo {
|
||||
|
||||
class OperationGroup : public Operation {
|
||||
public:
|
||||
explicit OperationGroup(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
|
||||
explicit OperationGroup(UnlocalizedString unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
|
||||
|
||||
OperationGroup(const OperationGroup &other) {
|
||||
for (const auto &operation : other.m_operations)
|
||||
this->m_operations.emplace_back(operation->clone());
|
||||
m_operations.emplace_back(operation->clone());
|
||||
}
|
||||
|
||||
void undo(Provider *provider) override {
|
||||
for (auto &operation : this->m_operations)
|
||||
for (auto &operation : m_operations)
|
||||
operation->undo(provider);
|
||||
}
|
||||
|
||||
void redo(Provider *provider) override {
|
||||
for (auto &operation : this->m_operations)
|
||||
for (auto &operation : m_operations)
|
||||
operation->redo(provider);
|
||||
}
|
||||
|
||||
void addOperation(std::unique_ptr<Operation> &&newOperation) {
|
||||
auto newRegion = newOperation->getRegion();
|
||||
if (newRegion.getStartAddress() < this->m_startAddress)
|
||||
this->m_startAddress = newRegion.getStartAddress();
|
||||
if (newRegion.getEndAddress() > this->m_endAddress)
|
||||
this->m_endAddress = newRegion.getEndAddress();
|
||||
if (newRegion.getStartAddress() < m_startAddress)
|
||||
m_startAddress = newRegion.getStartAddress();
|
||||
if (newRegion.getEndAddress() > m_endAddress)
|
||||
m_endAddress = newRegion.getEndAddress();
|
||||
|
||||
if (this->m_formattedContent.size() <= 10)
|
||||
this->m_formattedContent.emplace_back(newOperation->format());
|
||||
if (m_formattedContent.size() <= 10)
|
||||
m_formattedContent.emplace_back(newOperation->format());
|
||||
else
|
||||
this->m_formattedContent.back() = hex::format("[{}x] ...", (this->m_operations.size() - 10) + 1);
|
||||
m_formattedContent.back() = hex::format("[{}x] ...", (m_operations.size() - 10) + 1);
|
||||
|
||||
this->m_operations.emplace_back(std::move(newOperation));
|
||||
m_operations.emplace_back(std::move(newOperation));
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string format() const override {
|
||||
return hex::format("{}", Lang(this->m_unlocalizedName));
|
||||
return hex::format("{}", Lang(m_unlocalizedName));
|
||||
}
|
||||
|
||||
[[nodiscard]] Region getRegion() const override {
|
||||
return Region { this->m_startAddress, (this->m_endAddress - this->m_startAddress) + 1 };
|
||||
return Region { m_startAddress, (m_endAddress - m_startAddress) + 1 };
|
||||
}
|
||||
|
||||
std::unique_ptr<Operation> clone() const override {
|
||||
@@ -55,11 +55,11 @@ namespace hex::prv::undo {
|
||||
}
|
||||
|
||||
std::vector<std::string> formatContent() const override {
|
||||
return this->m_formattedContent;
|
||||
return m_formattedContent;
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_unlocalizedName;
|
||||
UnlocalizedString m_unlocalizedName;
|
||||
std::vector<std::unique_ptr<Operation>> m_operations;
|
||||
|
||||
u64 m_startAddress = std::numeric_limits<u64>::max();
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
||||
#include <hex/providers/undo_redo/operations/operation.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
@@ -24,7 +25,7 @@ namespace hex::prv::undo {
|
||||
void undo(u32 count = 1);
|
||||
void redo(u32 count = 1);
|
||||
|
||||
void groupOperations(u32 count, const std::string &unlocalizedName);
|
||||
void groupOperations(u32 count, const UnlocalizedString &unlocalizedName);
|
||||
void apply(const Stack &otherStack);
|
||||
|
||||
[[nodiscard]] bool canUndo() const;
|
||||
@@ -38,21 +39,21 @@ namespace hex::prv::undo {
|
||||
bool add(std::unique_ptr<Operation> &&operation);
|
||||
|
||||
const std::vector<std::unique_ptr<Operation>> &getAppliedOperations() const {
|
||||
return this->m_undoStack;
|
||||
return m_undoStack;
|
||||
}
|
||||
|
||||
const std::vector<std::unique_ptr<Operation>> &getUndoneOperations() const {
|
||||
return this->m_redoStack;
|
||||
return m_redoStack;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
this->m_undoStack.clear();
|
||||
this->m_redoStack.clear();
|
||||
m_undoStack.clear();
|
||||
m_redoStack.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
[[nodiscard]] Operation* getLastOperation() const {
|
||||
return this->m_undoStack.back().get();
|
||||
return m_undoStack.back().get();
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
@@ -69,10 +70,16 @@ namespace ImGuiExt {
|
||||
|
||||
class Texture {
|
||||
public:
|
||||
enum class Filter {
|
||||
Linear,
|
||||
Nearest
|
||||
};
|
||||
|
||||
Texture() = default;
|
||||
Texture(const ImU8 *buffer, int size, int width = 0, int height = 0);
|
||||
Texture(std::span<const std::byte> bytes, int width = 0, int height = 0);
|
||||
explicit Texture(const char *path);
|
||||
Texture(const ImU8 *buffer, int size, Filter filter = Filter::Nearest, int width = 0, int height = 0);
|
||||
Texture(std::span<const std::byte> bytes, Filter filter = Filter::Nearest, int width = 0, int height = 0);
|
||||
explicit Texture(const char *path, Filter filter = Filter::Nearest);
|
||||
explicit Texture(const std::fs::path &path, Filter filter = Filter::Nearest);
|
||||
Texture(unsigned int texture, int width, int height);
|
||||
Texture(const Texture&) = delete;
|
||||
Texture(Texture&& other) noexcept;
|
||||
@@ -83,21 +90,25 @@ namespace ImGuiExt {
|
||||
Texture& operator=(Texture&& other) noexcept;
|
||||
|
||||
[[nodiscard]] constexpr bool isValid() const noexcept {
|
||||
return this->m_textureId != nullptr;
|
||||
return m_textureId != nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr operator ImTextureID() const noexcept {
|
||||
return this->m_textureId;
|
||||
[[nodiscard]] operator ImTextureID() const noexcept {
|
||||
return m_textureId;
|
||||
}
|
||||
|
||||
[[nodiscard]] operator intptr_t() const noexcept {
|
||||
return reinterpret_cast<intptr_t>(m_textureId);
|
||||
}
|
||||
|
||||
[[nodiscard]] auto getSize() const noexcept {
|
||||
return ImVec2(this->m_width, this->m_height);
|
||||
return ImVec2(m_width, m_height);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto getAspectRatio() const noexcept {
|
||||
if (this->m_height == 0) return 1.0F;
|
||||
if (m_height == 0) return 1.0F;
|
||||
|
||||
return float(this->m_width) / float(this->m_height);
|
||||
return float(m_width) / float(m_height);
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -122,7 +133,7 @@ namespace ImGuiExt {
|
||||
void Header(const char *label, bool firstEntry = false);
|
||||
void HeaderColored(const char *label, ImColor color, bool firstEntry);
|
||||
|
||||
bool InfoTooltip(const char *text = "");
|
||||
bool InfoTooltip(const char *text = "",bool = false);
|
||||
|
||||
bool TitleBarButton(const char *label, ImVec2 size_arg);
|
||||
bool ToolBarButton(const char *symbol, ImVec4 color);
|
||||
@@ -258,6 +269,7 @@ namespace ImGuiExt {
|
||||
bool DimmedIconButton(const char *symbol, ImVec4 color, ImVec2 size = ImVec2(0, 0));
|
||||
bool DimmedButtonToggle(const char *icon, bool *v, ImVec2 size);
|
||||
bool DimmedIconToggle(const char *icon, bool *v);
|
||||
bool DimmedIconToggle(const char *iconOn, const char *iconOff, bool *v);
|
||||
|
||||
void TextOverlay(const char *text, ImVec2 pos);
|
||||
|
||||
@@ -277,6 +289,14 @@ namespace ImGuiExt {
|
||||
if (ImGui::Button(textRight, ImVec2(width / 3, 0)))
|
||||
rightButtonCallback();
|
||||
}
|
||||
|
||||
bool VSliderAngle(const char* label, ImVec2& size, float* v_rad, float v_degrees_min, float v_degrees_max, const char* format, ImGuiSliderFlags flags);
|
||||
|
||||
bool InputFilePicker(const char *label, std::fs::path &path, const std::vector<hex::fs::ItemFilter> &validExtensions);
|
||||
|
||||
bool ToggleSwitch(const char *label, bool *v);
|
||||
bool ToggleSwitch(const char *label, bool v);
|
||||
|
||||
template<typename T>
|
||||
constexpr ImGuiDataType getImGuiDataType() {
|
||||
if constexpr (std::same_as<T, u8>) return ImGuiDataType_U8;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@@ -17,7 +18,7 @@ namespace hex {
|
||||
|
||||
class PopupBase {
|
||||
public:
|
||||
explicit PopupBase(std::string unlocalizedName, bool closeButton, bool modal)
|
||||
explicit PopupBase(UnlocalizedString unlocalizedName, bool closeButton, bool modal)
|
||||
: m_unlocalizedName(std::move(unlocalizedName)), m_closeButton(closeButton), m_modal(modal) { }
|
||||
|
||||
virtual ~PopupBase() = default;
|
||||
@@ -35,29 +36,30 @@ namespace hex {
|
||||
|
||||
[[nodiscard]] static std::vector<std::unique_ptr<PopupBase>> &getOpenPopups();
|
||||
|
||||
[[nodiscard]] const std::string &getUnlocalizedName() const {
|
||||
return this->m_unlocalizedName;
|
||||
[[nodiscard]] const UnlocalizedString &getUnlocalizedName() const {
|
||||
return m_unlocalizedName;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool hasCloseButton() const {
|
||||
return this->m_closeButton;
|
||||
return m_closeButton;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isModal() const {
|
||||
return this->m_modal;
|
||||
return m_modal;
|
||||
}
|
||||
|
||||
void close() {
|
||||
this->m_close = true;
|
||||
m_close = true;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool shouldClose() const {
|
||||
return this->m_close;
|
||||
return m_close;
|
||||
}
|
||||
|
||||
protected:
|
||||
static std::mutex& getMutex();
|
||||
private:
|
||||
|
||||
std::string m_unlocalizedName;
|
||||
UnlocalizedString m_unlocalizedName;
|
||||
bool m_closeButton, m_modal;
|
||||
std::atomic<bool> m_close = false;
|
||||
};
|
||||
@@ -68,13 +70,12 @@ namespace hex {
|
||||
template<typename T>
|
||||
class Popup : public impl::PopupBase {
|
||||
protected:
|
||||
explicit Popup(std::string unlocalizedName, bool closeButton = true, bool modal = true) : PopupBase(std::move(unlocalizedName), closeButton, modal) { }
|
||||
explicit Popup(UnlocalizedString unlocalizedName, bool closeButton = true, bool modal = true) : PopupBase(std::move(unlocalizedName), closeButton, modal) { }
|
||||
|
||||
public:
|
||||
template<typename ...Args>
|
||||
static void open(Args && ... args) {
|
||||
static std::mutex mutex;
|
||||
std::lock_guard lock(mutex);
|
||||
std::lock_guard lock(getMutex());
|
||||
|
||||
auto popup = std::make_unique<T>(std::forward<Args>(args)...);
|
||||
|
||||
|
||||
61
lib/libimhex/include/hex/ui/toast.hpp
Normal file
61
lib/libimhex/include/hex/ui/toast.hpp
Normal file
@@ -0,0 +1,61 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <imgui.h>
|
||||
|
||||
#include <list>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
class ToastBase {
|
||||
public:
|
||||
ToastBase(ImColor color) : m_color(color) {}
|
||||
virtual ~ToastBase() = default;
|
||||
|
||||
virtual void draw() { drawContent(); }
|
||||
virtual void drawContent() = 0;
|
||||
|
||||
[[nodiscard]] static std::list<std::unique_ptr<ToastBase>> &getQueuedToasts();
|
||||
|
||||
[[nodiscard]] const ImColor& getColor() const {
|
||||
return m_color;
|
||||
}
|
||||
|
||||
void setAppearTime(double appearTime) {
|
||||
m_appearTime = appearTime;
|
||||
}
|
||||
|
||||
[[nodiscard]] double getAppearTime() const {
|
||||
return m_appearTime;
|
||||
}
|
||||
|
||||
constexpr static double VisibilityTime = 4.0;
|
||||
|
||||
protected:
|
||||
static std::mutex& getMutex();
|
||||
|
||||
double m_appearTime = 0;
|
||||
ImColor m_color;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class Toast : public impl::ToastBase {
|
||||
public:
|
||||
using impl::ToastBase::ToastBase;
|
||||
|
||||
template<typename ...Args>
|
||||
static void open(Args && ... args) {
|
||||
std::lock_guard lock(getMutex());
|
||||
|
||||
auto toast = std::make_unique<T>(std::forward<Args>(args)...);
|
||||
getQueuedToasts().emplace_back(std::move(toast));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -6,17 +6,17 @@
|
||||
#include <imgui_internal.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
#include <fonts/fontawesome_font.h>
|
||||
#include <fonts/codicons_font.h>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/shortcut_manager.hpp>
|
||||
#include <hex/api/event_manager.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/providers/provider_data.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
@@ -24,7 +24,7 @@
|
||||
namespace hex {
|
||||
|
||||
class View {
|
||||
explicit View(std::string unlocalizedName);
|
||||
explicit View(UnlocalizedString unlocalizedName);
|
||||
public:
|
||||
virtual ~View() = default;
|
||||
|
||||
@@ -87,15 +87,17 @@ namespace hex {
|
||||
[[nodiscard]] bool &getWindowOpenState();
|
||||
[[nodiscard]] const bool &getWindowOpenState() const;
|
||||
|
||||
[[nodiscard]] const std::string &getUnlocalizedName() const;
|
||||
[[nodiscard]] const UnlocalizedString &getUnlocalizedName() const;
|
||||
[[nodiscard]] std::string getName() const;
|
||||
|
||||
[[nodiscard]] bool didWindowJustOpen();
|
||||
void setWindowJustOpened(bool state);
|
||||
|
||||
void trackViewOpenState();
|
||||
|
||||
static void discardNavigationRequests();
|
||||
|
||||
[[nodiscard]] static std::string toWindowName(const std::string &unlocalizedName);
|
||||
[[nodiscard]] static std::string toWindowName(const UnlocalizedString &unlocalizedName);
|
||||
|
||||
public:
|
||||
class Window;
|
||||
@@ -104,8 +106,8 @@ namespace hex {
|
||||
class Modal;
|
||||
|
||||
private:
|
||||
std::string m_unlocalizedViewName;
|
||||
bool m_windowOpen = false;
|
||||
UnlocalizedString m_unlocalizedViewName;
|
||||
bool m_windowOpen = false, m_prevWindowOpen = false;
|
||||
std::map<Shortcut, ShortcutManager::ShortcutEntry> m_shortcuts;
|
||||
bool m_windowJustOpened = false;
|
||||
|
||||
@@ -118,7 +120,7 @@ namespace hex {
|
||||
*/
|
||||
class View::Window : public View {
|
||||
public:
|
||||
explicit Window(std::string unlocalizedName) : View(std::move(unlocalizedName)) {}
|
||||
explicit Window(UnlocalizedString unlocalizedName) : View(std::move(unlocalizedName)) {}
|
||||
|
||||
void draw() final {
|
||||
if (this->shouldDraw()) {
|
||||
@@ -137,7 +139,7 @@ namespace hex {
|
||||
*/
|
||||
class View::Special : public View {
|
||||
public:
|
||||
explicit Special(std::string unlocalizedName) : View(std::move(unlocalizedName)) {}
|
||||
explicit Special(UnlocalizedString unlocalizedName) : View(std::move(unlocalizedName)) {}
|
||||
|
||||
void draw() final {
|
||||
if (this->shouldDraw()) {
|
||||
@@ -152,9 +154,9 @@ namespace hex {
|
||||
*/
|
||||
class View::Floating : public View::Window {
|
||||
public:
|
||||
explicit Floating(std::string unlocalizedName) : Window(std::move(unlocalizedName)) {}
|
||||
explicit Floating(UnlocalizedString unlocalizedName) : Window(std::move(unlocalizedName)) {}
|
||||
|
||||
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const { return ImGuiWindowFlags_NoDocking; }
|
||||
[[nodiscard]] ImGuiWindowFlags getWindowFlags() const override { return ImGuiWindowFlags_NoDocking; }
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -162,22 +164,27 @@ namespace hex {
|
||||
*/
|
||||
class View::Modal : public View {
|
||||
public:
|
||||
explicit Modal(std::string unlocalizedName) : View(std::move(unlocalizedName)) {}
|
||||
explicit Modal(UnlocalizedString unlocalizedName) : View(std::move(unlocalizedName)) {}
|
||||
|
||||
void draw() final {
|
||||
if (this->shouldDraw()) {
|
||||
ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize());
|
||||
|
||||
if (this->getWindowOpenState())
|
||||
ImGui::OpenPopup(View::toWindowName(this->getUnlocalizedName()).c_str());
|
||||
|
||||
if (ImGui::BeginPopupModal(View::toWindowName(this->getUnlocalizedName()).c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize | this->getWindowFlags())) {
|
||||
ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F));
|
||||
ImGui::SetNextWindowSizeConstraints(this->getMinSize(), this->getMaxSize());
|
||||
if (ImGui::BeginPopupModal(View::toWindowName(this->getUnlocalizedName()).c_str(), this->hasCloseButton() ? &this->getWindowOpenState() : nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize | this->getWindowFlags())) {
|
||||
this->drawContent();
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGui::GetKeyIndex(ImGuiKey_Escape)))
|
||||
this->getWindowOpenState() = false;
|
||||
}
|
||||
}
|
||||
|
||||
virtual bool hasCloseButton() const { return true; }
|
||||
};
|
||||
|
||||
}
|
||||
@@ -21,34 +21,34 @@ namespace hex::ui {
|
||||
}
|
||||
|
||||
const std::vector<const T*> &draw(const auto &entries) {
|
||||
if (this->m_filteredEntries.empty() && this->m_searchBuffer.empty()) {
|
||||
if (m_filteredEntries.empty() && m_searchBuffer.empty()) {
|
||||
for (auto &entry : entries)
|
||||
this->m_filteredEntries.push_back(&entry);
|
||||
m_filteredEntries.push_back(&entry);
|
||||
}
|
||||
|
||||
if (ImGui::InputText("##search", this->m_searchBuffer)) {
|
||||
this->m_pendingUpdate = true;
|
||||
if (ImGui::InputText("##search", m_searchBuffer)) {
|
||||
m_pendingUpdate = true;
|
||||
}
|
||||
|
||||
if (this->m_pendingUpdate && !this->m_updateTask.isRunning()) {
|
||||
this->m_pendingUpdate = false;
|
||||
this->m_filteredEntries.clear();
|
||||
this->m_filteredEntries.reserve(entries.size());
|
||||
if (m_pendingUpdate && !m_updateTask.isRunning()) {
|
||||
m_pendingUpdate = false;
|
||||
m_filteredEntries.clear();
|
||||
m_filteredEntries.reserve(entries.size());
|
||||
|
||||
this->m_updateTask = TaskManager::createBackgroundTask("Searching", [this, &entries, searchBuffer = this->m_searchBuffer](Task&) {
|
||||
m_updateTask = TaskManager::createBackgroundTask("Searching", [this, &entries, searchBuffer = m_searchBuffer](Task&) {
|
||||
for (auto &entry : entries) {
|
||||
if (searchBuffer.empty() || this->m_comparator(searchBuffer, entry))
|
||||
this->m_filteredEntries.push_back(&entry);
|
||||
if (searchBuffer.empty() || m_comparator(searchBuffer, entry))
|
||||
m_filteredEntries.push_back(&entry);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return this->m_filteredEntries;
|
||||
return m_filteredEntries;
|
||||
}
|
||||
|
||||
void reset() {
|
||||
this->m_filteredEntries.clear();
|
||||
m_filteredEntries.clear();
|
||||
}
|
||||
private:
|
||||
std::atomic<bool> m_pendingUpdate = false;
|
||||
|
||||
@@ -87,7 +87,7 @@ namespace hex {
|
||||
return startNodes;
|
||||
}
|
||||
|
||||
void AchievementManager::unlockAchievement(const std::string &unlocalizedCategory, const std::string &unlocalizedName) {
|
||||
void AchievementManager::unlockAchievement(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName) {
|
||||
auto &categories = getAchievements();
|
||||
|
||||
auto categoryIter = categories.find(unlocalizedCategory);
|
||||
@@ -128,7 +128,7 @@ namespace hex {
|
||||
achievement->setUnlocked(true);
|
||||
|
||||
if (achievement->isUnlocked())
|
||||
EventManager::post<EventAchievementUnlocked>(*achievement);
|
||||
EventAchievementUnlocked::post(*achievement);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -201,7 +201,11 @@ namespace hex {
|
||||
for (const auto &[categoryName, achievements] : getAchievements()) {
|
||||
for (const auto &[achievementName, achievement] : achievements) {
|
||||
try {
|
||||
achievement->setProgress(json[categoryName][achievementName]);
|
||||
const auto &progress = json[categoryName][achievementName];
|
||||
if (progress.is_null())
|
||||
continue;
|
||||
|
||||
achievement->setProgress(progress);
|
||||
} catch (const std::exception &e) {
|
||||
log::warn("Failed to load achievement progress for '{}::{}': {}", categoryName, achievementName, e.what());
|
||||
}
|
||||
@@ -218,7 +222,7 @@ namespace hex {
|
||||
for (const auto &directory : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
auto path = directory / AchievementsFile;
|
||||
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Write);
|
||||
|
||||
if (!file.isValid()) {
|
||||
continue;
|
||||
@@ -234,7 +238,9 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
file.writeString(json.dump(4));
|
||||
auto result = json.dump(4);
|
||||
file.setSize(0);
|
||||
file.writeString(result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <hex/data_processor/node.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <thread>
|
||||
#include <jthread.hpp>
|
||||
|
||||
#if defined(OS_WEB)
|
||||
@@ -28,7 +27,7 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
nlohmann::json& getSetting(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &defaultValue) {
|
||||
nlohmann::json& getSetting(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const nlohmann::json &defaultValue) {
|
||||
auto &settings = getSettingsData();
|
||||
|
||||
if (!settings.contains(unlocalizedCategory))
|
||||
@@ -90,16 +89,21 @@ namespace hex {
|
||||
}
|
||||
|
||||
void store() {
|
||||
auto settingsData = getSettingsData();
|
||||
|
||||
// During a crash settings can be empty, causing them to be overwritten.
|
||||
if(getSettingsData().empty()) {
|
||||
if (settingsData.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Create);
|
||||
wolv::io::File file(dir / SettingsFile, wolv::io::File::Mode::Write);
|
||||
|
||||
if (file.isValid()) {
|
||||
file.writeString(getSettingsData().dump(4));
|
||||
auto result = settingsData.dump(4);
|
||||
|
||||
file.setSize(0);
|
||||
file.writeString(result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -113,7 +117,7 @@ namespace hex {
|
||||
#endif
|
||||
|
||||
template<typename T>
|
||||
static T* insertOrGetEntry(std::vector<T> &vector, const std::string &unlocalizedName) {
|
||||
static T* insertOrGetEntry(std::vector<T> &vector, const UnlocalizedString &unlocalizedName) {
|
||||
T *foundEntry = nullptr;
|
||||
for (auto &entry : vector) {
|
||||
if (entry.unlocalizedName == unlocalizedName) {
|
||||
@@ -138,7 +142,7 @@ namespace hex {
|
||||
return categories;
|
||||
}
|
||||
|
||||
Widgets::Widget* add(const std::string &unlocalizedCategory, const std::string &unlocalizedSubCategory, const std::string &unlocalizedName, std::unique_ptr<Widgets::Widget> &&widget) {
|
||||
Widgets::Widget* add(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedSubCategory, const UnlocalizedString &unlocalizedName, std::unique_ptr<Widgets::Widget> &&widget) {
|
||||
const auto category = insertOrGetEntry(getSettings(), unlocalizedCategory);
|
||||
const auto subCategory = insertOrGetEntry(category->subCategories, unlocalizedSubCategory);
|
||||
const auto entry = insertOrGetEntry(subCategory->entries, unlocalizedName);
|
||||
@@ -152,13 +156,13 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
void setCategoryDescription(const std::string &unlocalizedCategory, const std::string &unlocalizedDescription) {
|
||||
void setCategoryDescription(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedDescription) {
|
||||
const auto category = insertOrGetEntry(impl::getSettings(), unlocalizedCategory);
|
||||
|
||||
category->unlocalizedDescription = unlocalizedDescription;
|
||||
}
|
||||
|
||||
nlohmann::json read(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &defaultValue) {
|
||||
nlohmann::json read(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const nlohmann::json &defaultValue) {
|
||||
auto setting = impl::getSetting(unlocalizedCategory, unlocalizedName, defaultValue);
|
||||
|
||||
if (setting.is_number() && defaultValue.is_boolean())
|
||||
@@ -169,67 +173,67 @@ namespace hex {
|
||||
return setting;
|
||||
}
|
||||
|
||||
void write(const std::string &unlocalizedCategory, const std::string &unlocalizedName, const nlohmann::json &value) {
|
||||
void write(const UnlocalizedString &unlocalizedCategory, const UnlocalizedString &unlocalizedName, const nlohmann::json &value) {
|
||||
impl::getSetting(unlocalizedCategory, unlocalizedName, value) = value;
|
||||
}
|
||||
|
||||
namespace Widgets {
|
||||
|
||||
bool Checkbox::draw(const std::string &name) {
|
||||
return ImGui::Checkbox(name.c_str(), &this->m_value);
|
||||
return ImGui::Checkbox(name.c_str(), &m_value);
|
||||
}
|
||||
|
||||
void Checkbox::load(const nlohmann::json &data) {
|
||||
if (data.is_number()) {
|
||||
this->m_value = data.get<int>() != 0;
|
||||
m_value = data.get<int>() != 0;
|
||||
} else if (data.is_boolean()) {
|
||||
this->m_value = data.get<bool>();
|
||||
m_value = data.get<bool>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for checkbox!");
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json Checkbox::store() {
|
||||
return this->m_value;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
|
||||
bool SliderInteger::draw(const std::string &name) {
|
||||
return ImGui::SliderInt(name.c_str(), &this->m_value, this->m_min, this->m_max);
|
||||
return ImGui::SliderInt(name.c_str(), &m_value, m_min, m_max);
|
||||
}
|
||||
|
||||
void SliderInteger::load(const nlohmann::json &data) {
|
||||
if (data.is_number_integer()) {
|
||||
this->m_value = data.get<int>();
|
||||
m_value = data.get<int>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for slider!");
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json SliderInteger::store() {
|
||||
return this->m_value;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
|
||||
bool SliderFloat::draw(const std::string &name) {
|
||||
return ImGui::SliderFloat(name.c_str(), &this->m_value, this->m_min, this->m_max);
|
||||
return ImGui::SliderFloat(name.c_str(), &m_value, m_min, m_max);
|
||||
}
|
||||
|
||||
void SliderFloat::load(const nlohmann::json &data) {
|
||||
if (data.is_number()) {
|
||||
this->m_value = data.get<float>();
|
||||
m_value = data.get<float>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for slider!");
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json SliderFloat::store() {
|
||||
return this->m_value;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
|
||||
ColorPicker::ColorPicker(ImColor defaultColor) {
|
||||
this->m_value = {
|
||||
m_value = {
|
||||
defaultColor.Value.x,
|
||||
defaultColor.Value.y,
|
||||
defaultColor.Value.z,
|
||||
@@ -238,43 +242,43 @@ namespace hex {
|
||||
}
|
||||
|
||||
bool ColorPicker::draw(const std::string &name) {
|
||||
return ImGui::ColorEdit4(name.c_str(), this->m_value.data(), ImGuiColorEditFlags_NoInputs);
|
||||
return ImGui::ColorEdit4(name.c_str(), m_value.data(), ImGuiColorEditFlags_NoInputs);
|
||||
}
|
||||
|
||||
void ColorPicker::load(const nlohmann::json &data) {
|
||||
if (data.is_number()) {
|
||||
ImColor color(data.get<u32>());
|
||||
this->m_value = { color.Value.x, color.Value.y, color.Value.z, color.Value.w };
|
||||
m_value = { color.Value.x, color.Value.y, color.Value.z, color.Value.w };
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for color picker!");
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json ColorPicker::store() {
|
||||
const ImColor color(this->m_value[0], this->m_value[1], this->m_value[2], this->m_value[3]);
|
||||
const ImColor color(m_value[0], m_value[1], m_value[2], m_value[3]);
|
||||
|
||||
return static_cast<ImU32>(color);
|
||||
}
|
||||
|
||||
ImColor ColorPicker::getColor() const {
|
||||
return { this->m_value[0], this->m_value[1], this->m_value[2], this->m_value[3] };
|
||||
return { m_value[0], m_value[1], m_value[2], m_value[3] };
|
||||
}
|
||||
|
||||
|
||||
bool DropDown::draw(const std::string &name) {
|
||||
const char *preview = "";
|
||||
if (static_cast<size_t>(this->m_value) < this->m_items.size())
|
||||
preview = this->m_items[this->m_value].c_str();
|
||||
if (static_cast<size_t>(m_value) < m_items.size())
|
||||
preview = m_items[m_value].c_str();
|
||||
|
||||
bool changed = false;
|
||||
if (ImGui::BeginCombo(name.c_str(), Lang(preview))) {
|
||||
|
||||
int index = 0;
|
||||
for (const auto &item : this->m_items) {
|
||||
const bool selected = index == this->m_value;
|
||||
for (const auto &item : m_items) {
|
||||
const bool selected = index == m_value;
|
||||
|
||||
if (ImGui::Selectable(Lang(item), selected)) {
|
||||
this->m_value = index;
|
||||
m_value = index;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
@@ -291,60 +295,60 @@ namespace hex {
|
||||
}
|
||||
|
||||
void DropDown::load(const nlohmann::json &data) {
|
||||
this->m_value = 0;
|
||||
m_value = 0;
|
||||
|
||||
int defaultItemIndex = 0;
|
||||
|
||||
int index = 0;
|
||||
for (const auto &item : this->m_settingsValues) {
|
||||
if (item == this->m_defaultItem)
|
||||
for (const auto &item : m_settingsValues) {
|
||||
if (item == m_defaultItem)
|
||||
defaultItemIndex = index;
|
||||
|
||||
if (item == data) {
|
||||
this->m_value = index;
|
||||
m_value = index;
|
||||
return;
|
||||
}
|
||||
|
||||
index += 1;
|
||||
}
|
||||
|
||||
this->m_value = defaultItemIndex;
|
||||
m_value = defaultItemIndex;
|
||||
}
|
||||
|
||||
nlohmann::json DropDown::store() {
|
||||
if (this->m_value == -1)
|
||||
return this->m_defaultItem;
|
||||
if (static_cast<size_t>(this->m_value) >= this->m_items.size())
|
||||
return this->m_defaultItem;
|
||||
if (m_value == -1)
|
||||
return m_defaultItem;
|
||||
if (static_cast<size_t>(m_value) >= m_items.size())
|
||||
return m_defaultItem;
|
||||
|
||||
return this->m_settingsValues[this->m_value];
|
||||
return m_settingsValues[m_value];
|
||||
}
|
||||
|
||||
const nlohmann::json& DropDown::getValue() const {
|
||||
return this->m_settingsValues[this->m_value];
|
||||
return m_settingsValues[m_value];
|
||||
}
|
||||
|
||||
|
||||
bool TextBox::draw(const std::string &name) {
|
||||
return ImGui::InputText(name.c_str(), this->m_value);
|
||||
return ImGui::InputText(name.c_str(), m_value);
|
||||
}
|
||||
|
||||
void TextBox::load(const nlohmann::json &data) {
|
||||
if (data.is_string()) {
|
||||
this->m_value = data.get<std::string>();
|
||||
m_value = data.get<std::string>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for text box!");
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json TextBox::store() {
|
||||
return this->m_value;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
|
||||
bool FilePicker::draw(const std::string &name) {
|
||||
bool changed = false;
|
||||
if (ImGui::InputText("##font_path", this->m_value)) {
|
||||
if (ImGui::InputText("##font_path", m_value)) {
|
||||
changed = true;
|
||||
}
|
||||
|
||||
@@ -353,7 +357,7 @@ namespace hex {
|
||||
if (ImGuiExt::IconButton(ICON_VS_FOLDER_OPENED, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
|
||||
return fs::openFileBrowser(fs::DialogMode::Open, { { "TTF Font", "ttf" }, { "OTF Font", "otf" } },
|
||||
[&](const std::fs::path &path) {
|
||||
this->m_value = wolv::util::toUTF8String(path);
|
||||
m_value = wolv::util::toUTF8String(path);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -366,16 +370,24 @@ namespace hex {
|
||||
|
||||
void FilePicker::load(const nlohmann::json &data) {
|
||||
if (data.is_string()) {
|
||||
this->m_value = data.get<std::string>();
|
||||
m_value = data.get<std::string>();
|
||||
} else {
|
||||
log::warn("Invalid data type loaded from settings for file picker!");
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json FilePicker::store() {
|
||||
return this->m_value;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
bool Label::draw(const std::string& name) {
|
||||
ImGui::NewLine();
|
||||
ImGui::TextUnformatted(name.c_str());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -383,7 +395,7 @@ namespace hex {
|
||||
|
||||
namespace ContentRegistry::CommandPaletteCommands {
|
||||
|
||||
void add(Type type, const std::string &command, const std::string &unlocalizedDescription, const impl::DisplayCallback &displayCallback, const impl::ExecuteCallback &executeCallback) {
|
||||
void add(Type type, const std::string &command, const UnlocalizedString &unlocalizedDescription, const impl::DisplayCallback &displayCallback, const impl::ExecuteCallback &executeCallback) {
|
||||
log::debug("Registered new command palette command: {}", command);
|
||||
|
||||
impl::getEntries().push_back(impl::Entry { type, command, unlocalizedDescription, displayCallback, executeCallback });
|
||||
@@ -553,12 +565,12 @@ namespace hex {
|
||||
}
|
||||
|
||||
void impl::add(std::unique_ptr<View> &&view) {
|
||||
log::debug("Registered new view: {}", view->getUnlocalizedName());
|
||||
log::debug("Registered new view: {}", view->getUnlocalizedName().get());
|
||||
|
||||
getEntries().insert({ view->getUnlocalizedName(), std::move(view) });
|
||||
}
|
||||
|
||||
View* getViewByName(const std::string &unlocalizedName) {
|
||||
View* getViewByName(const UnlocalizedString &unlocalizedName) {
|
||||
auto &views = impl::getEntries();
|
||||
|
||||
if (views.contains(unlocalizedName))
|
||||
@@ -571,8 +583,8 @@ namespace hex {
|
||||
|
||||
namespace ContentRegistry::Tools {
|
||||
|
||||
void add(const std::string &unlocalizedName, const impl::Callback &function) {
|
||||
log::debug("Registered new tool: {}", unlocalizedName);
|
||||
void add(const UnlocalizedString &unlocalizedName, const impl::Callback &function) {
|
||||
log::debug("Registered new tool: {}", unlocalizedName.get());
|
||||
|
||||
impl::getEntries().emplace_back(impl::Entry { unlocalizedName, function, false });
|
||||
}
|
||||
@@ -591,14 +603,14 @@ namespace hex {
|
||||
|
||||
namespace ContentRegistry::DataInspector {
|
||||
|
||||
void add(const std::string &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
|
||||
log::debug("Registered new data inspector format: {}", unlocalizedName);
|
||||
void add(const UnlocalizedString &unlocalizedName, size_t requiredSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
|
||||
log::debug("Registered new data inspector format: {}", unlocalizedName.get());
|
||||
|
||||
impl::getEntries().push_back({ unlocalizedName, requiredSize, requiredSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
|
||||
}
|
||||
|
||||
void add(const std::string &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
|
||||
log::debug("Registered new data inspector format: {}", unlocalizedName);
|
||||
void add(const UnlocalizedString &unlocalizedName, size_t requiredSize, size_t maxSize, impl::GeneratorFunction displayGeneratorFunction, std::optional<impl::EditingFunction> editingFunction) {
|
||||
log::debug("Registered new data inspector format: {}", unlocalizedName.get());
|
||||
|
||||
impl::getEntries().push_back({ unlocalizedName, requiredSize, maxSize, std::move(displayGeneratorFunction), std::move(editingFunction) });
|
||||
}
|
||||
@@ -619,7 +631,7 @@ namespace hex {
|
||||
namespace ContentRegistry::DataProcessorNode {
|
||||
|
||||
void impl::add(const Entry &entry) {
|
||||
log::debug("Registered new data processor node type: [{}]: {}", entry.category, entry.name);
|
||||
log::debug("Registered new data processor node type: [{}]: {}", entry.unlocalizedCategory.get(), entry.unlocalizedName.get());
|
||||
|
||||
getEntries().push_back(entry);
|
||||
}
|
||||
@@ -704,14 +716,14 @@ namespace hex {
|
||||
|
||||
namespace ContentRegistry::Interface {
|
||||
|
||||
void registerMainMenuItem(const std::string &unlocalizedName, u32 priority) {
|
||||
log::debug("Registered new main menu item: {}", unlocalizedName);
|
||||
void registerMainMenuItem(const UnlocalizedString &unlocalizedName, u32 priority) {
|
||||
log::debug("Registered new main menu item: {}", unlocalizedName.get());
|
||||
|
||||
impl::getMainMenuItems().insert({ priority, { unlocalizedName } });
|
||||
}
|
||||
|
||||
void addMenuItem(const std::vector<std::string> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, View *view) {
|
||||
log::debug("Added new menu item to menu {} with priority {}", wolv::util::combineStrings(unlocalizedMainMenuNames, " -> "), priority);
|
||||
void addMenuItem(const std::vector<UnlocalizedString> &unlocalizedMainMenuNames, u32 priority, const Shortcut &shortcut, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback, View *view) {
|
||||
log::debug("Added new menu item to menu {} with priority {}", unlocalizedMainMenuNames[0].get(), priority);
|
||||
|
||||
impl::getMenuItems().insert({
|
||||
priority, impl::MenuItem { unlocalizedMainMenuNames, std::make_unique<Shortcut>(shortcut), view, function, enabledCallback }
|
||||
@@ -725,8 +737,8 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
void addMenuItemSubMenu(std::vector<std::string> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback) {
|
||||
log::debug("Added new menu item sub menu to menu {} with priority {}", wolv::util::combineStrings(unlocalizedMainMenuNames, " -> "), priority);
|
||||
void addMenuItemSubMenu(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority, const impl::MenuCallback &function, const impl::EnabledCallback& enabledCallback) {
|
||||
log::debug("Added new menu item sub menu to menu {} with priority {}", unlocalizedMainMenuNames[0].get(), priority);
|
||||
|
||||
unlocalizedMainMenuNames.emplace_back(impl::SubMenuValue);
|
||||
impl::getMenuItems().insert({
|
||||
@@ -734,7 +746,7 @@ namespace hex {
|
||||
});
|
||||
}
|
||||
|
||||
void addMenuItemSeparator(std::vector<std::string> unlocalizedMainMenuNames, u32 priority) {
|
||||
void addMenuItemSeparator(std::vector<UnlocalizedString> unlocalizedMainMenuNames, u32 priority) {
|
||||
unlocalizedMainMenuNames.emplace_back(impl::SeparatorValue);
|
||||
impl::getMenuItems().insert({
|
||||
priority, impl::MenuItem { unlocalizedMainMenuNames, std::make_unique<Shortcut>(), nullptr, []{}, []{ return true; } }
|
||||
@@ -757,7 +769,7 @@ namespace hex {
|
||||
impl::getSidebarItems().push_back({ icon, function, enabledCallback });
|
||||
}
|
||||
|
||||
void addTitleBarButton(const std::string &icon, const std::string &unlocalizedTooltip, const impl::ClickCallback &function) {
|
||||
void addTitleBarButton(const std::string &icon, const UnlocalizedString &unlocalizedTooltip, const impl::ClickCallback &function) {
|
||||
impl::getTitleBarButtons().push_back({ icon, unlocalizedTooltip, function });
|
||||
}
|
||||
|
||||
@@ -809,7 +821,7 @@ namespace hex {
|
||||
namespace impl {
|
||||
|
||||
void add(const std::string &typeName, ProviderCreationFunction creationFunction) {
|
||||
(void)EventManager::subscribe<RequestCreateProvider>([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, prv::Provider **provider) {
|
||||
if (name != expectedName) return;
|
||||
|
||||
prv::Provider *newProvider = creationFunction();
|
||||
@@ -827,8 +839,8 @@ namespace hex {
|
||||
return providerNames;
|
||||
}
|
||||
|
||||
void addProviderName(const std::string &unlocalizedName) {
|
||||
log::debug("Registered new provider: {}", unlocalizedName);
|
||||
void addProviderName(const UnlocalizedString &unlocalizedName) {
|
||||
log::debug("Registered new provider: {}", unlocalizedName.get());
|
||||
|
||||
getEntries().push_back(unlocalizedName);
|
||||
}
|
||||
@@ -840,8 +852,8 @@ namespace hex {
|
||||
|
||||
namespace ContentRegistry::DataFormatter {
|
||||
|
||||
void add(const std::string &unlocalizedName, const impl::Callback &callback) {
|
||||
log::debug("Registered new data formatter: {}", unlocalizedName);
|
||||
void add(const UnlocalizedString &unlocalizedName, const impl::Callback &callback) {
|
||||
log::debug("Registered new data formatter: {}", unlocalizedName.get());
|
||||
|
||||
impl::getEntries().push_back({ unlocalizedName, callback });
|
||||
}
|
||||
@@ -958,7 +970,7 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
std::shared_ptr<DataVisualizer> getVisualizerByName(const std::string &unlocalizedName) {
|
||||
std::shared_ptr<DataVisualizer> getVisualizerByName(const UnlocalizedString &unlocalizedName) {
|
||||
for (const auto &visualizer : impl::getVisualizers()) {
|
||||
if (visualizer->getUnlocalizedName() == unlocalizedName)
|
||||
return visualizer;
|
||||
@@ -992,6 +1004,11 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
struct Service {
|
||||
std::string name;
|
||||
std::jthread thread;
|
||||
};
|
||||
|
||||
std::vector<Service> &getServices() {
|
||||
static std::vector<Service> services;
|
||||
|
||||
@@ -999,20 +1016,24 @@ namespace hex {
|
||||
}
|
||||
|
||||
void stopServices() {
|
||||
for (auto &service : getServices()) {
|
||||
auto &services = getServices();
|
||||
|
||||
for (auto &service : services) {
|
||||
service.thread.request_stop();
|
||||
}
|
||||
|
||||
for (auto &service : getServices()) {
|
||||
for (auto &service : services) {
|
||||
if (service.thread.joinable())
|
||||
service.thread.join();
|
||||
}
|
||||
|
||||
services.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void registerService(const std::string &unlocalizedName, const impl::Callback &callback) {
|
||||
log::debug("Registered new background service: {}", unlocalizedName);
|
||||
void registerService(const UnlocalizedString &unlocalizedName, const impl::Callback &callback) {
|
||||
log::debug("Registered new background service: {}", unlocalizedName.get());
|
||||
|
||||
impl::getServices().push_back(impl::Service {
|
||||
unlocalizedName,
|
||||
@@ -1059,7 +1080,7 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
void addExperiment(const std::string &experimentName, const std::string &unlocalizedName, const std::string &unlocalizedDescription) {
|
||||
void addExperiment(const std::string &experimentName, const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedDescription) {
|
||||
auto &experiments = impl::getExperiments();
|
||||
|
||||
if (experiments.contains(experimentName)) {
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace hex {
|
||||
id, Highlighting {region, color}
|
||||
});
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
EventHighlightingChanged::post();
|
||||
|
||||
return id;
|
||||
}
|
||||
@@ -90,7 +90,7 @@ namespace hex {
|
||||
void removeBackgroundHighlight(u32 id) {
|
||||
impl::getBackgroundHighlights().erase(id);
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
EventHighlightingChanged::post();
|
||||
}
|
||||
|
||||
u32 addBackgroundHighlightingProvider(const impl::HighlightingFunction &function) {
|
||||
@@ -100,7 +100,7 @@ namespace hex {
|
||||
|
||||
impl::getBackgroundHighlightingFunctions().insert({ id, function });
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
EventHighlightingChanged::post();
|
||||
|
||||
return id;
|
||||
}
|
||||
@@ -108,7 +108,7 @@ namespace hex {
|
||||
void removeBackgroundHighlightingProvider(u32 id) {
|
||||
impl::getBackgroundHighlightingFunctions().erase(id);
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
EventHighlightingChanged::post();
|
||||
}
|
||||
|
||||
u32 addForegroundHighlight(const Region ®ion, color_t color) {
|
||||
@@ -120,7 +120,7 @@ namespace hex {
|
||||
id, Highlighting {region, color}
|
||||
});
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
EventHighlightingChanged::post();
|
||||
|
||||
return id;
|
||||
}
|
||||
@@ -128,7 +128,7 @@ namespace hex {
|
||||
void removeForegroundHighlight(u32 id) {
|
||||
impl::getForegroundHighlights().erase(id);
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
EventHighlightingChanged::post();
|
||||
}
|
||||
|
||||
u32 addForegroundHighlightingProvider(const impl::HighlightingFunction &function) {
|
||||
@@ -138,7 +138,7 @@ namespace hex {
|
||||
|
||||
impl::getForegroundHighlightingFunctions().insert({ id, function });
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
EventHighlightingChanged::post();
|
||||
|
||||
return id;
|
||||
}
|
||||
@@ -146,7 +146,7 @@ namespace hex {
|
||||
void removeForegroundHighlightingProvider(u32 id) {
|
||||
impl::getForegroundHighlightingFunctions().erase(id);
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
EventHighlightingChanged::post();
|
||||
}
|
||||
|
||||
static u32 tooltipId = 0;
|
||||
@@ -190,7 +190,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void setSelection(const ProviderRegion ®ion) {
|
||||
EventManager::post<RequestSelectionChange>(region);
|
||||
RequestSelectionChange::post(region);
|
||||
}
|
||||
|
||||
void setSelection(u64 address, size_t size, prv::Provider *provider) {
|
||||
@@ -204,7 +204,7 @@ namespace hex {
|
||||
|
||||
u64 add(Region region, const std::string &name, const std::string &comment, u32 color) {
|
||||
u64 id = 0;
|
||||
EventManager::post<RequestAddBookmark>(region, name, comment, color, &id);
|
||||
RequestAddBookmark::post(region, name, comment, color, &id);
|
||||
|
||||
return id;
|
||||
}
|
||||
@@ -214,7 +214,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void remove(u64 id) {
|
||||
EventManager::post<RequestRemoveBookmark>(id);
|
||||
RequestRemoveBookmark::post(id);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -256,7 +256,7 @@ namespace hex {
|
||||
if (index < s_providers.size() && s_currentProvider != index) {
|
||||
auto oldProvider = get();
|
||||
s_currentProvider = index;
|
||||
EventManager::post<EventProviderChanged>(oldProvider, get());
|
||||
EventProviderChanged::post(oldProvider, get());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -291,7 +291,7 @@ namespace hex {
|
||||
provider->skipLoadInterface();
|
||||
|
||||
s_providers.push_back(provider);
|
||||
EventManager::post<EventProviderCreated>(provider);
|
||||
EventProviderCreated::post(provider);
|
||||
|
||||
if (select || s_providers.size() == 1)
|
||||
setCurrentProvider(s_providers.size() - 1);
|
||||
@@ -308,7 +308,7 @@ namespace hex {
|
||||
impl::s_closingProviders.push_back(provider);
|
||||
|
||||
bool shouldClose = true;
|
||||
EventManager::post<EventProviderClosing>(provider, &shouldClose);
|
||||
EventProviderClosing::post(provider, &shouldClose);
|
||||
if (!shouldClose)
|
||||
return;
|
||||
}
|
||||
@@ -321,6 +321,9 @@ namespace hex {
|
||||
if (it == s_providers.begin()) {
|
||||
// If the first provider is being closed, select the one that's the first one now
|
||||
setCurrentProvider(0);
|
||||
|
||||
if (s_providers.size() > 1)
|
||||
EventProviderChanged::post(s_providers[0], s_providers[1]);
|
||||
}
|
||||
else if (std::distance(s_providers.begin(), it) == s_currentProvider) {
|
||||
// If the current provider is being closed, select the one that's before it
|
||||
@@ -350,21 +353,21 @@ namespace hex {
|
||||
setCurrentProvider(0);
|
||||
|
||||
if (s_providers.empty())
|
||||
EventManager::post<EventProviderChanged>(provider, nullptr);
|
||||
EventProviderChanged::post(provider, nullptr);
|
||||
|
||||
provider->close();
|
||||
EventManager::post<EventProviderClosed>(provider);
|
||||
EventProviderClosed::post(provider);
|
||||
|
||||
TaskManager::runWhenTasksFinished([provider] {
|
||||
EventManager::post<EventProviderDeleted>(provider);
|
||||
EventProviderDeleted::post(provider);
|
||||
std::erase(impl::s_closingProviders, provider);
|
||||
delete provider;
|
||||
});
|
||||
}
|
||||
|
||||
prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface, bool select) {
|
||||
prv::Provider* createProvider(const UnlocalizedString &unlocalizedName, bool skipLoadInterface, bool select) {
|
||||
prv::Provider* result = nullptr;
|
||||
EventManager::post<RequestCreateProvider>(unlocalizedName, skipLoadInterface, select, &result);
|
||||
RequestCreateProvider::post(unlocalizedName, skipLoadInterface, select, &result);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -378,7 +381,6 @@ namespace hex {
|
||||
|
||||
// Default to true means we forward to ourselves by default
|
||||
static bool s_isMainInstance = true;
|
||||
|
||||
void setMainInstanceStatus(bool status) {
|
||||
s_isMainInstance = status;
|
||||
}
|
||||
@@ -433,6 +435,12 @@ namespace hex {
|
||||
getInitArguments()[key] = value;
|
||||
}
|
||||
|
||||
static double s_lastFrameTime;
|
||||
void setLastFrameTime(double time) {
|
||||
s_lastFrameTime = time;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
bool isMainInstance() {
|
||||
@@ -440,16 +448,16 @@ namespace hex {
|
||||
}
|
||||
|
||||
void closeImHex(bool noQuestions) {
|
||||
EventManager::post<RequestCloseImHex>(noQuestions);
|
||||
RequestCloseImHex::post(noQuestions);
|
||||
}
|
||||
|
||||
void restartImHex() {
|
||||
EventManager::post<RequestRestartImHex>();
|
||||
EventManager::post<RequestCloseImHex>(false);
|
||||
RequestRestartImHex::post();
|
||||
RequestCloseImHex::post(false);
|
||||
}
|
||||
|
||||
void setTaskBarProgress(TaskProgressState state, TaskProgressType type, u32 progress) {
|
||||
EventManager::post<EventSetTaskBarIconState>(u32(state), u32(type), progress);
|
||||
EventSetTaskBarIconState::post(u32(state), u32(type), progress);
|
||||
}
|
||||
|
||||
|
||||
@@ -503,8 +511,8 @@ namespace hex {
|
||||
void enableSystemThemeDetection(bool enabled) {
|
||||
s_systemThemeDetection = enabled;
|
||||
|
||||
EventManager::post<EventSettingsChanged>();
|
||||
EventManager::post<EventOSThemeChanged>();
|
||||
EventSettingsChanged::post();
|
||||
EventOSThemeChanged::post();
|
||||
}
|
||||
|
||||
bool usesSystemThemeDetection() {
|
||||
@@ -598,9 +606,9 @@ namespace hex {
|
||||
|
||||
std::string getImHexVersion(bool withBuildType) {
|
||||
#if defined IMHEX_VERSION
|
||||
if (withBuildType)
|
||||
if (withBuildType) {
|
||||
return IMHEX_VERSION;
|
||||
else {
|
||||
} else {
|
||||
auto version = std::string(IMHEX_VERSION);
|
||||
return version.substr(0, version.find('-'));
|
||||
}
|
||||
@@ -666,7 +674,7 @@ namespace hex {
|
||||
break;
|
||||
}
|
||||
|
||||
EventManager::subscribe<EventImHexClosing>([executablePath, updateTypeString] {
|
||||
EventImHexClosing::subscribe([executablePath, updateTypeString] {
|
||||
hex::executeCommand(
|
||||
hex::format("{} {}",
|
||||
wolv::util::toUTF8String(executablePath),
|
||||
@@ -681,9 +689,14 @@ namespace hex {
|
||||
}
|
||||
|
||||
void addStartupTask(const std::string &name, bool async, const std::function<bool()> &function) {
|
||||
EventManager::post<RequestAddInitTask>(name, async, function);
|
||||
RequestAddInitTask::post(name, async, function);
|
||||
}
|
||||
|
||||
double getLastFrameTime() {
|
||||
return impl::s_lastFrameTime;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
namespace ImHexApi::Messaging {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#include <hex/api/layout_manager.hpp>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <wolv/utils/string.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/ui/view.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -15,6 +17,8 @@ namespace hex {
|
||||
std::optional<std::string> s_layoutStringToLoad;
|
||||
std::vector<LayoutManager::Layout> s_layouts;
|
||||
|
||||
bool s_layoutLocked = false;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +26,7 @@ namespace hex {
|
||||
s_layoutPathToLoad = path;
|
||||
}
|
||||
|
||||
void LayoutManager::loadString(const std::string &content) {
|
||||
void LayoutManager::loadFromString(const std::string &content) {
|
||||
s_layoutStringToLoad = content;
|
||||
}
|
||||
|
||||
@@ -32,25 +36,57 @@ namespace hex {
|
||||
std::transform(fileName.begin(), fileName.end(), fileName.begin(), tolower);
|
||||
fileName += ".hexlyt";
|
||||
|
||||
const auto path = hex::fs::getDefaultPaths(fs::ImHexPath::Layouts).front() / fileName;
|
||||
ImGui::SaveIniSettingsToDisk(wolv::util::toUTF8String(path).c_str());
|
||||
std::fs::path layoutPath;
|
||||
for (const auto &path : hex::fs::getDefaultPaths(fs::ImHexPath::Layouts)) {
|
||||
if (!hex::fs::isPathWritable(layoutPath))
|
||||
continue;
|
||||
|
||||
layoutPath = path / fileName;
|
||||
}
|
||||
|
||||
if (layoutPath.empty()) {
|
||||
log::error("Failed to save layout '{}'. No writable path found", name);
|
||||
return;
|
||||
}
|
||||
|
||||
const auto pathString = wolv::util::toUTF8String(layoutPath);
|
||||
ImGui::SaveIniSettingsToDisk(pathString.c_str());
|
||||
log::info("Layout '{}' saved to {}", name, pathString);
|
||||
|
||||
LayoutManager::reload();
|
||||
}
|
||||
|
||||
std::string LayoutManager::saveToString() {
|
||||
return ImGui::SaveIniSettingsToMemory();
|
||||
}
|
||||
|
||||
|
||||
std::vector<LayoutManager::Layout> LayoutManager::getLayouts() {
|
||||
return s_layouts;
|
||||
}
|
||||
|
||||
void LayoutManager::closeAllViews() {
|
||||
for (const auto &[name, view] : ContentRegistry::Views::impl::getEntries())
|
||||
view->getWindowOpenState() = false;
|
||||
}
|
||||
|
||||
void LayoutManager::process() {
|
||||
if (s_layoutPathToLoad.has_value()) {
|
||||
ImGui::LoadIniSettingsFromDisk(wolv::util::toUTF8String(*s_layoutPathToLoad).c_str());
|
||||
const auto pathString = wolv::util::toUTF8String(*s_layoutPathToLoad);
|
||||
|
||||
LayoutManager::closeAllViews();
|
||||
ImGui::LoadIniSettingsFromDisk(pathString.c_str());
|
||||
|
||||
s_layoutPathToLoad = std::nullopt;
|
||||
log::info("Loaded layout from {}", pathString);
|
||||
}
|
||||
|
||||
if (s_layoutStringToLoad.has_value()) {
|
||||
LayoutManager::closeAllViews();
|
||||
ImGui::LoadIniSettingsFromMemory(s_layoutStringToLoad->c_str());
|
||||
|
||||
s_layoutStringToLoad = std::nullopt;
|
||||
log::info("Loaded layout from string");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,4 +121,13 @@ namespace hex {
|
||||
s_layouts.clear();
|
||||
}
|
||||
|
||||
}
|
||||
bool LayoutManager::isLayoutLocked() {
|
||||
return s_layoutLocked;
|
||||
}
|
||||
|
||||
void LayoutManager::lockLayout(bool locked) {
|
||||
log::info("Layout {}", locked ? "locked" : "unlocked");
|
||||
s_layoutLocked = locked;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,13 +31,13 @@ namespace hex {
|
||||
if (value.empty())
|
||||
continue;
|
||||
|
||||
this->m_entries.insert({ key, value });
|
||||
m_entries.insert({ key, value });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const std::map<std::string, std::string> &LanguageDefinition::getEntries() const {
|
||||
return this->m_entries;
|
||||
return m_entries;
|
||||
}
|
||||
|
||||
void loadLanguage(const std::string &language) {
|
||||
@@ -75,7 +75,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
Lang::Lang(const char *unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
|
||||
Lang::Lang(std::string unlocalizedString) : m_unlocalizedString(std::move(unlocalizedString)) { }
|
||||
Lang::Lang(const std::string &unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
|
||||
Lang::Lang(const UnlocalizedString &unlocalizedString) : m_unlocalizedString(unlocalizedString.get()) { }
|
||||
Lang::Lang(std::string_view unlocalizedString) : m_unlocalizedString(unlocalizedString) { }
|
||||
|
||||
Lang::operator std::string() const {
|
||||
@@ -120,10 +121,10 @@ namespace hex {
|
||||
|
||||
const std::string &Lang::get() const {
|
||||
auto &lang = LocalizationManager::s_currStrings;
|
||||
if (lang.contains(this->m_unlocalizedString))
|
||||
return lang[this->m_unlocalizedString];
|
||||
if (lang.contains(m_unlocalizedString))
|
||||
return lang[m_unlocalizedString];
|
||||
else
|
||||
return this->m_unlocalizedString;
|
||||
return m_unlocalizedString;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,76 +17,94 @@
|
||||
namespace hex {
|
||||
|
||||
Plugin::Plugin(const std::fs::path &path) : m_path(path) {
|
||||
log::info("Loading plugin '{}'", wolv::util::toUTF8String(path.filename()));
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
this->m_handle = uintptr_t(LoadLibraryW(path.c_str()));
|
||||
m_handle = uintptr_t(LoadLibraryW(path.c_str()));
|
||||
|
||||
if (this->m_handle == uintptr_t(INVALID_HANDLE_VALUE) || this->m_handle == 0) {
|
||||
log::error("LoadLibraryW failed: {}!", std::system_category().message(::GetLastError()));
|
||||
if (m_handle == uintptr_t(INVALID_HANDLE_VALUE) || m_handle == 0) {
|
||||
log::error("Loading plugin '{}' failed: {} {}!", wolv::util::toUTF8String(path.filename()), ::GetLastError(), std::system_category().message(::GetLastError()));
|
||||
return;
|
||||
}
|
||||
#else
|
||||
this->m_handle = uintptr_t(dlopen(wolv::util::toUTF8String(path).c_str(), RTLD_LAZY));
|
||||
m_handle = uintptr_t(dlopen(wolv::util::toUTF8String(path).c_str(), RTLD_LAZY));
|
||||
|
||||
if (this->m_handle == 0) {
|
||||
log::error("dlopen failed: {}!", dlerror());
|
||||
if (m_handle == 0) {
|
||||
log::error("Loading plugin '{}' failed: {}!", wolv::util::toUTF8String(path.filename()), dlerror());
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
this->m_functions.initializePluginFunction = getPluginFunction<PluginFunctions::InitializePluginFunc>("initializePlugin");
|
||||
this->m_functions.getPluginNameFunction = getPluginFunction<PluginFunctions::GetPluginNameFunc>("getPluginName");
|
||||
this->m_functions.getPluginAuthorFunction = getPluginFunction<PluginFunctions::GetPluginAuthorFunc>("getPluginAuthor");
|
||||
this->m_functions.getPluginDescriptionFunction = getPluginFunction<PluginFunctions::GetPluginDescriptionFunc>("getPluginDescription");
|
||||
this->m_functions.getCompatibleVersionFunction = getPluginFunction<PluginFunctions::GetCompatibleVersionFunc>("getCompatibleVersion");
|
||||
this->m_functions.setImGuiContextFunction = getPluginFunction<PluginFunctions::SetImGuiContextFunc>("setImGuiContext");
|
||||
this->m_functions.isBuiltinPluginFunction = getPluginFunction<PluginFunctions::IsBuiltinPluginFunc>("isBuiltinPlugin");
|
||||
this->m_functions.getSubCommandsFunction = getPluginFunction<PluginFunctions::GetSubCommandsFunc>("getSubCommands");
|
||||
|
||||
log::info("Loaded plugin '{}'", wolv::util::toUTF8String(path.filename()));
|
||||
m_functions.initializePluginFunction = getPluginFunction<PluginFunctions::InitializePluginFunc>("initializePlugin");
|
||||
m_functions.initializeLibraryFunction = getPluginFunction<PluginFunctions::InitializePluginFunc>("initializeLibrary");
|
||||
m_functions.getPluginNameFunction = getPluginFunction<PluginFunctions::GetPluginNameFunc>("getPluginName");
|
||||
m_functions.getPluginAuthorFunction = getPluginFunction<PluginFunctions::GetPluginAuthorFunc>("getPluginAuthor");
|
||||
m_functions.getPluginDescriptionFunction = getPluginFunction<PluginFunctions::GetPluginDescriptionFunc>("getPluginDescription");
|
||||
m_functions.getCompatibleVersionFunction = getPluginFunction<PluginFunctions::GetCompatibleVersionFunc>("getCompatibleVersion");
|
||||
m_functions.setImGuiContextFunction = getPluginFunction<PluginFunctions::SetImGuiContextFunc>("setImGuiContext");
|
||||
m_functions.isBuiltinPluginFunction = getPluginFunction<PluginFunctions::IsBuiltinPluginFunc>("isBuiltinPlugin");
|
||||
m_functions.getSubCommandsFunction = getPluginFunction<PluginFunctions::GetSubCommandsFunc>("getSubCommands");
|
||||
m_functions.getFeaturesFunction = getPluginFunction<PluginFunctions::GetSubCommandsFunc>("getFeatures");
|
||||
}
|
||||
|
||||
Plugin::Plugin(hex::PluginFunctions functions) {
|
||||
this->m_handle = 0;
|
||||
this->m_functions = functions;
|
||||
Plugin::Plugin(const hex::PluginFunctions &functions) {
|
||||
m_handle = 0;
|
||||
m_functions = functions;
|
||||
}
|
||||
|
||||
|
||||
Plugin::Plugin(Plugin &&other) noexcept {
|
||||
this->m_handle = other.m_handle;
|
||||
m_handle = other.m_handle;
|
||||
other.m_handle = 0;
|
||||
|
||||
this->m_path = std::move(other.m_path);
|
||||
m_path = std::move(other.m_path);
|
||||
|
||||
this->m_functions = other.m_functions;
|
||||
m_functions = other.m_functions;
|
||||
other.m_functions = {};
|
||||
}
|
||||
|
||||
Plugin& Plugin::operator=(Plugin &&other) noexcept {
|
||||
m_handle = other.m_handle;
|
||||
other.m_handle = 0;
|
||||
|
||||
m_path = std::move(other.m_path);
|
||||
|
||||
m_functions = other.m_functions;
|
||||
other.m_functions = {};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Plugin::~Plugin() {
|
||||
#if defined(OS_WINDOWS)
|
||||
if (this->m_handle != 0)
|
||||
FreeLibrary(HMODULE(this->m_handle));
|
||||
if (m_handle != 0)
|
||||
FreeLibrary(HMODULE(m_handle));
|
||||
#else
|
||||
dlclose(reinterpret_cast<void*>(this->m_handle));
|
||||
if (m_handle != 0)
|
||||
dlclose(reinterpret_cast<void*>(m_handle));
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Plugin::initializePlugin() const {
|
||||
const auto pluginName = wolv::util::toUTF8String(this->m_path.filename());
|
||||
const auto pluginName = wolv::util::toUTF8String(m_path.filename());
|
||||
|
||||
if (this->isLibraryPlugin()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const auto requestedVersion = getCompatibleVersion();
|
||||
if (requestedVersion != ImHexApi::System::getImHexVersion()) {
|
||||
if (requestedVersion.empty()) {
|
||||
log::warn("Plugin '{}' did not specify a compatible version, assuming it is compatible with the current version of ImHex.", wolv::util::toUTF8String(this->m_path.filename()));
|
||||
log::warn("Plugin '{}' did not specify a compatible version, assuming it is compatible with the current version of ImHex.", wolv::util::toUTF8String(m_path.filename()));
|
||||
} else {
|
||||
log::error("Refused to load plugin '{}' which was built for a different version of ImHex: '{}'", wolv::util::toUTF8String(this->m_path.filename()), requestedVersion);
|
||||
log::error("Refused to load plugin '{}' which was built for a different version of ImHex: '{}'", wolv::util::toUTF8String(m_path.filename()), requestedVersion);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->m_functions.initializePluginFunction != nullptr) {
|
||||
if (m_functions.initializePluginFunction != nullptr) {
|
||||
try {
|
||||
this->m_functions.initializePluginFunction();
|
||||
m_functions.initializePluginFunction();
|
||||
} catch (const std::exception &e) {
|
||||
log::error("Plugin '{}' threw an exception on init: {}", pluginName, e.what());
|
||||
return false;
|
||||
@@ -101,72 +119,97 @@ namespace hex {
|
||||
|
||||
log::info("Plugin '{}' initialized successfully", pluginName);
|
||||
|
||||
this->m_initialized = true;
|
||||
m_initialized = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string Plugin::getPluginName() const {
|
||||
if (this->m_functions.getPluginNameFunction != nullptr)
|
||||
return this->m_functions.getPluginNameFunction();
|
||||
else
|
||||
return hex::format("Unknown Plugin @ 0x{0:016X}", this->m_handle);
|
||||
if (m_functions.getPluginNameFunction != nullptr) {
|
||||
return m_functions.getPluginNameFunction();
|
||||
} else {
|
||||
if (this->isLibraryPlugin())
|
||||
return "Library Plugin";
|
||||
else
|
||||
return hex::format("Unknown Plugin @ 0x{0:016X}", m_handle);
|
||||
}
|
||||
}
|
||||
|
||||
std::string Plugin::getPluginAuthor() const {
|
||||
if (this->m_functions.getPluginAuthorFunction != nullptr)
|
||||
return this->m_functions.getPluginAuthorFunction();
|
||||
if (m_functions.getPluginAuthorFunction != nullptr)
|
||||
return m_functions.getPluginAuthorFunction();
|
||||
else
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
std::string Plugin::getPluginDescription() const {
|
||||
if (this->m_functions.getPluginDescriptionFunction != nullptr)
|
||||
return this->m_functions.getPluginDescriptionFunction();
|
||||
if (m_functions.getPluginDescriptionFunction != nullptr)
|
||||
return m_functions.getPluginDescriptionFunction();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
std::string Plugin::getCompatibleVersion() const {
|
||||
if (this->m_functions.getCompatibleVersionFunction != nullptr)
|
||||
return this->m_functions.getCompatibleVersionFunction();
|
||||
if (m_functions.getCompatibleVersionFunction != nullptr)
|
||||
return m_functions.getCompatibleVersionFunction();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
void Plugin::setImGuiContext(ImGuiContext *ctx) const {
|
||||
if (this->m_functions.setImGuiContextFunction != nullptr)
|
||||
this->m_functions.setImGuiContextFunction(ctx);
|
||||
if (m_functions.setImGuiContextFunction != nullptr)
|
||||
m_functions.setImGuiContextFunction(ctx);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool Plugin::isBuiltinPlugin() const {
|
||||
if (this->m_functions.isBuiltinPluginFunction != nullptr)
|
||||
return this->m_functions.isBuiltinPluginFunction();
|
||||
if (m_functions.isBuiltinPluginFunction != nullptr)
|
||||
return m_functions.isBuiltinPluginFunction();
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::fs::path &Plugin::getPath() const {
|
||||
return this->m_path;
|
||||
return m_path;
|
||||
}
|
||||
|
||||
bool Plugin::isValid() const {
|
||||
return m_handle != 0 || m_functions.initializeLibraryFunction != nullptr || m_functions.initializePluginFunction != nullptr;
|
||||
}
|
||||
|
||||
bool Plugin::isLoaded() const {
|
||||
return this->m_initialized;
|
||||
return m_initialized;
|
||||
}
|
||||
|
||||
std::span<SubCommand> Plugin::getSubCommands() const {
|
||||
if (this->m_functions.getSubCommandsFunction != nullptr) {
|
||||
auto result = this->m_functions.getSubCommandsFunction();
|
||||
if (m_functions.getSubCommandsFunction != nullptr) {
|
||||
auto result = m_functions.getSubCommandsFunction();
|
||||
return *static_cast<std::vector<SubCommand>*>(result);
|
||||
} else
|
||||
} else {
|
||||
return { };
|
||||
}
|
||||
}
|
||||
|
||||
std::span<Feature> Plugin::getFeatures() const {
|
||||
if (m_functions.getFeaturesFunction != nullptr) {
|
||||
auto result = m_functions.getFeaturesFunction();
|
||||
return *static_cast<std::vector<Feature>*>(result);
|
||||
} else {
|
||||
return { };
|
||||
}
|
||||
}
|
||||
|
||||
bool Plugin::isLibraryPlugin() const {
|
||||
return m_functions.initializeLibraryFunction != nullptr &&
|
||||
m_functions.initializePluginFunction == nullptr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void *Plugin::getPluginFunction(const std::string &symbol) const {
|
||||
#if defined(OS_WINDOWS)
|
||||
return reinterpret_cast<void *>(GetProcAddress(HMODULE(this->m_handle), symbol.c_str()));
|
||||
return reinterpret_cast<void *>(GetProcAddress(HMODULE(m_handle), symbol.c_str()));
|
||||
#else
|
||||
return dlsym(reinterpret_cast<void*>(this->m_handle), symbol.c_str());
|
||||
return dlsym(reinterpret_cast<void*>(m_handle), symbol.c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -176,11 +219,22 @@ namespace hex {
|
||||
|
||||
getPluginPaths().push_back(pluginFolder);
|
||||
|
||||
// Load library plugins first
|
||||
for (auto &pluginPath : std::fs::directory_iterator(pluginFolder)) {
|
||||
if (pluginPath.is_regular_file() && pluginPath.path().extension() == ".hexpluglib")
|
||||
getPlugins().emplace_back(pluginPath.path());
|
||||
}
|
||||
|
||||
// Load regular plugins afterwards
|
||||
for (auto &pluginPath : std::fs::directory_iterator(pluginFolder)) {
|
||||
if (pluginPath.is_regular_file() && pluginPath.path().extension() == ".hexplug")
|
||||
getPlugins().emplace_back(pluginPath.path());
|
||||
}
|
||||
|
||||
std::erase_if(getPlugins(), [](const Plugin &plugin) {
|
||||
return !plugin.isValid();
|
||||
});
|
||||
|
||||
if (getPlugins().empty())
|
||||
return false;
|
||||
|
||||
|
||||
@@ -15,11 +15,11 @@ namespace hex {
|
||||
}
|
||||
|
||||
|
||||
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const std::string &unlocalizedName, const std::function<void()> &callback) {
|
||||
void ShortcutManager::addGlobalShortcut(const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback) {
|
||||
s_globalShortcuts.insert({ shortcut, { shortcut, unlocalizedName, callback } });
|
||||
}
|
||||
|
||||
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const std::string &unlocalizedName, const std::function<void()> &callback) {
|
||||
void ShortcutManager::addShortcut(View *view, const Shortcut &shortcut, const UnlocalizedString &unlocalizedName, const std::function<void()> &callback) {
|
||||
view->m_shortcuts.insert({ shortcut + CurrentView, { shortcut, unlocalizedName, callback } });
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::vector<ShortcutManager::ShortcutEntry> ShortcutManager::getViewShortcuts(View *view) {
|
||||
std::vector<ShortcutManager::ShortcutEntry> ShortcutManager::getViewShortcuts(const View *view) {
|
||||
std::vector<ShortcutManager::ShortcutEntry> result;
|
||||
|
||||
for (auto &[shortcut, entry] : view->m_shortcuts)
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <jthread.hpp>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#include <windows.h>
|
||||
#include <processthreadsapi.h>
|
||||
@@ -55,25 +57,25 @@ namespace hex {
|
||||
#endif
|
||||
}
|
||||
|
||||
Task::Task(std::string unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function)
|
||||
Task::Task(UnlocalizedString unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function)
|
||||
: m_unlocalizedName(std::move(unlocalizedName)), m_maxValue(maxValue), m_function(std::move(function)), m_background(background) { }
|
||||
|
||||
Task::Task(hex::Task &&other) noexcept {
|
||||
{
|
||||
std::scoped_lock thisLock(this->m_mutex);
|
||||
std::scoped_lock thisLock(m_mutex);
|
||||
std::scoped_lock otherLock(other.m_mutex);
|
||||
|
||||
this->m_function = std::move(other.m_function);
|
||||
this->m_unlocalizedName = std::move(other.m_unlocalizedName);
|
||||
m_function = std::move(other.m_function);
|
||||
m_unlocalizedName = std::move(other.m_unlocalizedName);
|
||||
}
|
||||
|
||||
this->m_maxValue = u64(other.m_maxValue);
|
||||
this->m_currValue = u64(other.m_currValue);
|
||||
m_maxValue = u64(other.m_maxValue);
|
||||
m_currValue = u64(other.m_currValue);
|
||||
|
||||
this->m_finished = bool(other.m_finished);
|
||||
this->m_hadException = bool(other.m_hadException);
|
||||
this->m_interrupted = bool(other.m_interrupted);
|
||||
this->m_shouldInterrupt = bool(other.m_shouldInterrupt);
|
||||
m_finished = bool(other.m_finished);
|
||||
m_hadException = bool(other.m_hadException);
|
||||
m_interrupted = bool(other.m_interrupted);
|
||||
m_shouldInterrupt = bool(other.m_shouldInterrupt);
|
||||
}
|
||||
|
||||
Task::~Task() {
|
||||
@@ -82,131 +84,141 @@ namespace hex {
|
||||
}
|
||||
|
||||
void Task::update(u64 value) {
|
||||
this->m_currValue.store(value, std::memory_order_relaxed);
|
||||
// Update the current progress value of the task
|
||||
m_currValue.store(value, std::memory_order_relaxed);
|
||||
|
||||
if (this->m_shouldInterrupt.load(std::memory_order_relaxed)) [[unlikely]]
|
||||
// Check if the task has been interrupted by the main thread and if yes,
|
||||
// throw an exception that is generally not caught by the task
|
||||
if (m_shouldInterrupt.load(std::memory_order_relaxed)) [[unlikely]]
|
||||
throw TaskInterruptor();
|
||||
}
|
||||
|
||||
void Task::setMaxValue(u64 value) {
|
||||
this->m_maxValue = value;
|
||||
m_maxValue = value;
|
||||
}
|
||||
|
||||
|
||||
void Task::interrupt() {
|
||||
this->m_shouldInterrupt = true;
|
||||
m_shouldInterrupt = true;
|
||||
|
||||
if (this->m_interruptCallback)
|
||||
this->m_interruptCallback();
|
||||
// Call the interrupt callback on the current thread if one is set
|
||||
if (m_interruptCallback)
|
||||
m_interruptCallback();
|
||||
}
|
||||
|
||||
void Task::setInterruptCallback(std::function<void()> callback) {
|
||||
this->m_interruptCallback = std::move(callback);
|
||||
m_interruptCallback = std::move(callback);
|
||||
}
|
||||
|
||||
bool Task::isBackgroundTask() const {
|
||||
return this->m_background;
|
||||
return m_background;
|
||||
}
|
||||
|
||||
bool Task::isFinished() const {
|
||||
return this->m_finished;
|
||||
return m_finished;
|
||||
}
|
||||
|
||||
bool Task::hadException() const {
|
||||
return this->m_hadException;
|
||||
return m_hadException;
|
||||
}
|
||||
|
||||
bool Task::shouldInterrupt() const {
|
||||
return this->m_shouldInterrupt;
|
||||
return m_shouldInterrupt;
|
||||
}
|
||||
|
||||
bool Task::wasInterrupted() const {
|
||||
return this->m_interrupted;
|
||||
return m_interrupted;
|
||||
}
|
||||
|
||||
void Task::clearException() {
|
||||
this->m_hadException = false;
|
||||
m_hadException = false;
|
||||
}
|
||||
|
||||
std::string Task::getExceptionMessage() const {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
return this->m_exceptionMessage;
|
||||
return m_exceptionMessage;
|
||||
}
|
||||
|
||||
const std::string &Task::getUnlocalizedName() {
|
||||
return this->m_unlocalizedName;
|
||||
const UnlocalizedString &Task::getUnlocalizedName() {
|
||||
return m_unlocalizedName;
|
||||
}
|
||||
|
||||
u64 Task::getValue() const {
|
||||
return this->m_currValue;
|
||||
return m_currValue;
|
||||
}
|
||||
|
||||
u64 Task::getMaxValue() const {
|
||||
return this->m_maxValue;
|
||||
return m_maxValue;
|
||||
}
|
||||
|
||||
void Task::finish() {
|
||||
this->m_finished = true;
|
||||
m_finished = true;
|
||||
}
|
||||
|
||||
void Task::interruption() {
|
||||
this->m_interrupted = true;
|
||||
m_interrupted = true;
|
||||
}
|
||||
|
||||
void Task::exception(const char *message) {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
this->m_exceptionMessage = message;
|
||||
this->m_hadException = true;
|
||||
// Store information about the caught exception
|
||||
m_exceptionMessage = message;
|
||||
m_hadException = true;
|
||||
}
|
||||
|
||||
|
||||
bool TaskHolder::isRunning() const {
|
||||
if (this->m_task.expired())
|
||||
auto task = m_task.lock();
|
||||
if (!task)
|
||||
return false;
|
||||
|
||||
auto task = this->m_task.lock();
|
||||
return !task->isFinished();
|
||||
}
|
||||
|
||||
bool TaskHolder::hadException() const {
|
||||
if (this->m_task.expired())
|
||||
auto task = m_task.lock();
|
||||
if (!task)
|
||||
return false;
|
||||
|
||||
auto task = this->m_task.lock();
|
||||
return !task->hadException();
|
||||
}
|
||||
|
||||
bool TaskHolder::shouldInterrupt() const {
|
||||
if (this->m_task.expired())
|
||||
auto task = m_task.lock();
|
||||
if (!task)
|
||||
return false;
|
||||
|
||||
auto task = this->m_task.lock();
|
||||
return !task->shouldInterrupt();
|
||||
}
|
||||
|
||||
bool TaskHolder::wasInterrupted() const {
|
||||
if (this->m_task.expired())
|
||||
auto task = m_task.lock();
|
||||
if (!task)
|
||||
return false;
|
||||
|
||||
auto task = this->m_task.lock();
|
||||
return !task->wasInterrupted();
|
||||
}
|
||||
|
||||
void TaskHolder::interrupt() const {
|
||||
if (this->m_task.expired())
|
||||
auto task = m_task.lock();
|
||||
if (!task)
|
||||
return;
|
||||
|
||||
auto task = this->m_task.lock();
|
||||
task->interrupt();
|
||||
}
|
||||
|
||||
u32 TaskHolder::getProgress() const {
|
||||
if (this->m_task.expired())
|
||||
auto task = m_task.lock();
|
||||
if (!task)
|
||||
return false;
|
||||
|
||||
// If the max value is 0, the task has no progress
|
||||
if (task->getMaxValue() == 0)
|
||||
return 0;
|
||||
|
||||
auto task = this->m_task.lock();
|
||||
// Calculate the progress of the task from 0 to 100
|
||||
return u32((task->getValue() * 100) / task->getMaxValue());
|
||||
}
|
||||
|
||||
@@ -216,89 +228,120 @@ namespace hex {
|
||||
|
||||
log::debug("Initializing task manager thread pool with {} workers.", threadCount);
|
||||
|
||||
for (u32 i = 0; i < threadCount; i++)
|
||||
s_workers.emplace_back(TaskManager::runner);
|
||||
}
|
||||
// Create worker threads
|
||||
for (u32 i = 0; i < threadCount; i++) {
|
||||
s_workers.emplace_back([](const std::stop_token &stopToken) {
|
||||
while (true) {
|
||||
std::shared_ptr<Task> task;
|
||||
|
||||
void TaskManager::exit() {
|
||||
for (auto &task : s_tasks)
|
||||
task->interrupt();
|
||||
// Set the thread name to "Idle Task" while waiting for a task
|
||||
setThreadName("Idle Task");
|
||||
|
||||
for (auto &thread : s_workers)
|
||||
thread.request_stop();
|
||||
{
|
||||
// Wait for a task to be added to the queue
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
s_jobCondVar.wait(lock, [&] {
|
||||
return !s_taskQueue.empty() || stopToken.stop_requested();
|
||||
});
|
||||
|
||||
s_jobCondVar.notify_all();
|
||||
// Check if the thread should exit
|
||||
if (stopToken.stop_requested())
|
||||
break;
|
||||
|
||||
s_workers.clear();
|
||||
}
|
||||
// Grab the next task from the queue
|
||||
task = std::move(s_taskQueue.front());
|
||||
s_taskQueue.pop_front();
|
||||
}
|
||||
|
||||
void TaskManager::runner(const std::stop_token &stopToken) {
|
||||
while (true) {
|
||||
std::shared_ptr<Task> task;
|
||||
{
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
s_jobCondVar.wait(lock, [&] {
|
||||
return !s_taskQueue.empty() || stopToken.stop_requested();
|
||||
});
|
||||
if (stopToken.stop_requested())
|
||||
break;
|
||||
try {
|
||||
// Set the thread name to the name of the task
|
||||
setThreadName(Lang(task->m_unlocalizedName));
|
||||
|
||||
task = std::move(s_taskQueue.front());
|
||||
s_taskQueue.pop_front();
|
||||
}
|
||||
// Execute the task
|
||||
task->m_function(*task);
|
||||
|
||||
try {
|
||||
setThreadName(Lang(task->m_unlocalizedName));
|
||||
task->m_function(*task);
|
||||
setThreadName("Idle Task");
|
||||
log::debug("Finished task {}", task->m_unlocalizedName);
|
||||
} catch (const Task::TaskInterruptor &) {
|
||||
task->interruption();
|
||||
} catch (const std::exception &e) {
|
||||
log::error("Exception in task {}: {}", task->m_unlocalizedName, e.what());
|
||||
task->exception(e.what());
|
||||
} catch (...) {
|
||||
log::error("Exception in task {}", task->m_unlocalizedName);
|
||||
task->exception("Unknown Exception");
|
||||
}
|
||||
log::debug("Task '{}' finished", task->m_unlocalizedName.get());
|
||||
} catch (const Task::TaskInterruptor &) {
|
||||
// Handle the task being interrupted by user request
|
||||
task->interruption();
|
||||
} catch (const std::exception &e) {
|
||||
log::error("Exception in task '{}': {}", task->m_unlocalizedName.get(), e.what());
|
||||
|
||||
task->finish();
|
||||
// Handle the task throwing an uncaught exception
|
||||
task->exception(e.what());
|
||||
} catch (...) {
|
||||
log::error("Exception in task '{}'", task->m_unlocalizedName.get());
|
||||
|
||||
// Handle the task throwing an uncaught exception of unknown type
|
||||
task->exception("Unknown Exception");
|
||||
}
|
||||
|
||||
task->finish();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
TaskHolder TaskManager::createTask(std::string name, u64 maxValue, std::function<void(Task &)> function) {
|
||||
log::debug("Creating task {}", name);
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
auto task = std::make_shared<Task>(std::move(name), maxValue, false, std::move(function));
|
||||
void TaskManager::exit() {
|
||||
// Interrupt all tasks
|
||||
for (auto &task : s_tasks) {
|
||||
task->interrupt();
|
||||
}
|
||||
|
||||
// Ask worker threads to exit after finishing their task
|
||||
for (auto &thread : s_workers)
|
||||
thread.request_stop();
|
||||
|
||||
// Wake up all the idle worker threads so they can exit
|
||||
s_jobCondVar.notify_all();
|
||||
|
||||
// Wait for all worker threads to exit
|
||||
s_workers.clear();
|
||||
|
||||
s_tasks.clear();
|
||||
s_taskQueue.clear();
|
||||
|
||||
s_deferredCalls.clear();
|
||||
s_tasksFinishedCallbacks.clear();
|
||||
}
|
||||
|
||||
TaskHolder TaskManager::createTask(std::string name, u64 maxValue, bool background, std::function<void(Task&)> function) {
|
||||
std::scoped_lock lock(s_queueMutex);
|
||||
|
||||
// Construct new task
|
||||
auto task = std::make_shared<Task>(std::move(name), maxValue, background, std::move(function));
|
||||
|
||||
s_tasks.emplace_back(task);
|
||||
s_taskQueue.emplace_back(task);
|
||||
|
||||
// Add task to the queue for the worker to pick up
|
||||
s_taskQueue.emplace_back(std::move(task));
|
||||
|
||||
s_jobCondVar.notify_one();
|
||||
|
||||
return TaskHolder(s_tasks.back());
|
||||
}
|
||||
|
||||
|
||||
TaskHolder TaskManager::createTask(std::string name, u64 maxValue, std::function<void(Task &)> function) {
|
||||
log::debug("Creating task {}", name);
|
||||
return createTask(std::move(name), maxValue, false, std::move(function));
|
||||
}
|
||||
|
||||
TaskHolder TaskManager::createBackgroundTask(std::string name, std::function<void(Task &)> function) {
|
||||
log::debug("Creating background task {}", name);
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
|
||||
auto task = std::make_shared<Task>(std::move(name), 0, true, std::move(function));
|
||||
s_tasks.emplace_back(task);
|
||||
s_taskQueue.emplace_back(task);
|
||||
|
||||
s_jobCondVar.notify_one();
|
||||
|
||||
return TaskHolder(s_tasks.back());
|
||||
return createTask(std::move(name), 0, true, std::move(function));
|
||||
}
|
||||
|
||||
void TaskManager::collectGarbage() {
|
||||
{
|
||||
std::unique_lock lock1(s_queueMutex);
|
||||
std::erase_if(s_tasks, [](const auto &task) { return task->isFinished() && !task->hadException(); });
|
||||
std::scoped_lock lock(s_queueMutex);
|
||||
std::erase_if(s_tasks, [](const auto &task) {
|
||||
return task->isFinished() && !task->hadException();
|
||||
});
|
||||
}
|
||||
|
||||
if (s_tasks.empty()) {
|
||||
std::unique_lock lock2(s_deferredCallsMutex);
|
||||
std::scoped_lock lock(s_deferredCallsMutex);
|
||||
for (auto &call : s_tasksFinishedCallbacks)
|
||||
call();
|
||||
s_tasksFinishedCallbacks.clear();
|
||||
@@ -311,7 +354,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
size_t TaskManager::getRunningTaskCount() {
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
std::scoped_lock lock(s_queueMutex);
|
||||
|
||||
return std::count_if(s_tasks.begin(), s_tasks.end(), [](const auto &task){
|
||||
return !task->isBackgroundTask();
|
||||
@@ -319,7 +362,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
size_t TaskManager::getRunningBackgroundTaskCount() {
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
std::scoped_lock lock(s_queueMutex);
|
||||
|
||||
return std::count_if(s_tasks.begin(), s_tasks.end(), [](const auto &task){
|
||||
return task->isBackgroundTask();
|
||||
|
||||
@@ -90,9 +90,9 @@ namespace hex {
|
||||
theme["styles"][type] = {};
|
||||
|
||||
for (const auto &[key, style] : handler.styleMap) {
|
||||
if (std::holds_alternative<float*>(style.value))
|
||||
if (std::holds_alternative<float*>(style.value)) {
|
||||
theme["styles"][type][key] = *std::get<float*>(style.value);
|
||||
else if (std::holds_alternative<ImVec2*>(style.value)) {
|
||||
} else if (std::holds_alternative<ImVec2*>(style.value)) {
|
||||
theme["styles"][type][key] = {
|
||||
std::get<ImVec2*>(style.value)->x,
|
||||
std::get<ImVec2*>(style.value)->y
|
||||
@@ -194,7 +194,7 @@ namespace hex {
|
||||
|
||||
s_currTheme = name;
|
||||
|
||||
EventManager::post<EventThemeChanged>();
|
||||
EventThemeChanged::post();
|
||||
}
|
||||
|
||||
const std::string &ThemeManager::getImageTheme() {
|
||||
|
||||
379
lib/libimhex/source/api/tutorial_manager.cpp
Normal file
379
lib/libimhex/source/api/tutorial_manager.cpp
Normal file
@@ -0,0 +1,379 @@
|
||||
#include <hex/api/tutorial_manager.hpp>
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/localization_manager.hpp>
|
||||
#include <hex/api/task_manager.hpp>
|
||||
|
||||
#include <imgui_internal.h>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <wolv/utils/core.hpp>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace {
|
||||
|
||||
std::map<std::string, TutorialManager::Tutorial> s_tutorials;
|
||||
decltype(s_tutorials)::iterator s_currentTutorial = s_tutorials.end();
|
||||
|
||||
std::map<ImGuiID, std::string> s_highlights;
|
||||
std::vector<std::pair<ImRect, std::string>> s_highlightDisplays;
|
||||
|
||||
|
||||
class IDStack {
|
||||
public:
|
||||
IDStack() {
|
||||
idStack.push_back(0);
|
||||
}
|
||||
|
||||
void add(const std::string &string) {
|
||||
const ImGuiID seed = idStack.back();
|
||||
const ImGuiID id = ImHashStr(string.c_str(), string.length(), seed);
|
||||
|
||||
idStack.push_back(id);
|
||||
}
|
||||
|
||||
void add(const void *pointer) {
|
||||
const ImGuiID seed = idStack.back();
|
||||
const ImGuiID id = ImHashData(&pointer, sizeof(pointer), seed);
|
||||
|
||||
idStack.push_back(id);
|
||||
}
|
||||
|
||||
void add(int value) {
|
||||
const ImGuiID seed = idStack.back();
|
||||
const ImGuiID id = ImHashData(&value, sizeof(value), seed);
|
||||
|
||||
idStack.push_back(id);
|
||||
}
|
||||
|
||||
ImGuiID get() {
|
||||
return idStack.back();
|
||||
}
|
||||
private:
|
||||
ImVector<ImGuiID> idStack;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
const std::map<std::string, TutorialManager::Tutorial>& TutorialManager::getTutorials() {
|
||||
return s_tutorials;
|
||||
}
|
||||
|
||||
std::map<std::string, TutorialManager::Tutorial>::iterator TutorialManager::getCurrentTutorial() {
|
||||
return s_currentTutorial;
|
||||
}
|
||||
|
||||
|
||||
TutorialManager::Tutorial& TutorialManager::createTutorial(const UnlocalizedString &unlocalizedName, const UnlocalizedString &unlocalizedDescription) {
|
||||
return s_tutorials.try_emplace(unlocalizedName, Tutorial(unlocalizedName, unlocalizedDescription)).first->second;
|
||||
}
|
||||
|
||||
void TutorialManager::startTutorial(const UnlocalizedString &unlocalizedName) {
|
||||
s_currentTutorial = s_tutorials.find(unlocalizedName);
|
||||
if (s_currentTutorial == s_tutorials.end())
|
||||
return;
|
||||
|
||||
s_currentTutorial->second.start();
|
||||
}
|
||||
|
||||
void TutorialManager::drawHighlights() {
|
||||
for (const auto &[rect, unlocalizedText] : s_highlightDisplays) {
|
||||
const auto drawList = ImGui::GetForegroundDrawList();
|
||||
|
||||
drawList->PushClipRectFullScreen();
|
||||
{
|
||||
auto highlightColor = ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_Highlight);
|
||||
highlightColor.w *= ImSin(ImGui::GetTime() * 6.0F) / 4.0F + 0.75F;
|
||||
|
||||
drawList->AddRect(rect.Min - ImVec2(5, 5), rect.Max + ImVec2(5, 5), ImColor(highlightColor), 5.0F, ImDrawFlags_None, 2.0F);
|
||||
}
|
||||
|
||||
{
|
||||
if (!unlocalizedText.empty()) {
|
||||
const auto mainWindowPos = ImHexApi::System::getMainWindowPosition();
|
||||
const auto mainWindowSize = ImHexApi::System::getMainWindowSize();
|
||||
|
||||
const auto margin = ImGui::GetStyle().WindowPadding;
|
||||
|
||||
ImVec2 windowPos = { rect.Min.x + 20_scaled, rect.Max.y + 10_scaled };
|
||||
ImVec2 windowSize = { std::max<float>(rect.Max.x - rect.Min.x - 40_scaled, 300_scaled), 0 };
|
||||
|
||||
const char* text = Lang(unlocalizedText);
|
||||
const auto textSize = ImGui::CalcTextSize(text, nullptr, false, windowSize.x - margin.x * 2);
|
||||
windowSize.y = textSize.y + margin.y * 2;
|
||||
|
||||
if (windowPos.y + windowSize.y > mainWindowPos.y + mainWindowSize.y)
|
||||
windowPos.y = rect.Min.y - windowSize.y - 10_scaled;
|
||||
if (windowPos.y < mainWindowPos.y)
|
||||
windowPos.y = mainWindowPos.y + 10_scaled;
|
||||
|
||||
auto &style = ImGui::GetStyle();
|
||||
|
||||
ImVec2 shadowOffset = ImVec2(ImCos(style.WindowShadowOffsetAngle), ImSin(style.WindowShadowOffsetAngle)) * style.WindowShadowOffsetDist;
|
||||
drawList->AddRectFilled(windowPos, windowPos + windowSize, ImGui::GetColorU32(ImGuiCol_WindowBg) | 0xFF000000);
|
||||
drawList->AddRect(windowPos, windowPos + windowSize, ImGui::GetColorU32(ImGuiCol_Border));
|
||||
drawList->AddShadowRect(windowPos, windowPos + windowSize, ImGui::GetColorU32(ImGuiCol_WindowShadow), style.WindowShadowSize, shadowOffset, ImDrawFlags_ShadowCutOutShapeBackground);
|
||||
drawList->AddText(nullptr, 0.0F, windowPos + margin, ImGui::GetColorU32(ImGuiCol_Text), text, nullptr, windowSize.x - margin.x * 2);
|
||||
}
|
||||
}
|
||||
drawList->PopClipRect();
|
||||
|
||||
}
|
||||
s_highlightDisplays.clear();
|
||||
}
|
||||
|
||||
void TutorialManager::drawMessageBox(std::optional<Tutorial::Step::Message> message) {
|
||||
const auto windowStart = ImHexApi::System::getMainWindowPosition() + scaled({ 10, 10 });
|
||||
const auto windowEnd = ImHexApi::System::getMainWindowPosition() + ImHexApi::System::getMainWindowSize() - scaled({ 10, 10 });
|
||||
|
||||
ImVec2 position = ImHexApi::System::getMainWindowPosition() + ImHexApi::System::getMainWindowSize() / 2.0F;
|
||||
ImVec2 pivot = { 0.5F, 0.5F };
|
||||
|
||||
if (!message.has_value()) {
|
||||
message = Tutorial::Step::Message {
|
||||
Position::None,
|
||||
"",
|
||||
"",
|
||||
false
|
||||
};
|
||||
}
|
||||
|
||||
if (message->position == Position::None) {
|
||||
message->position = Position::Bottom | Position::Right;
|
||||
}
|
||||
|
||||
if ((message->position & Position::Top) == Position::Top) {
|
||||
position.y = windowStart.y;
|
||||
pivot.y = 0.0F;
|
||||
}
|
||||
if ((message->position & Position::Bottom) == Position::Bottom) {
|
||||
position.y = windowEnd.y;
|
||||
pivot.y = 1.0F;
|
||||
}
|
||||
if ((message->position & Position::Left) == Position::Left) {
|
||||
position.x = windowStart.x;
|
||||
pivot.x = 0.0F;
|
||||
}
|
||||
if ((message->position & Position::Right) == Position::Right) {
|
||||
position.x = windowEnd.x;
|
||||
pivot.x = 1.0F;
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowPos(position, ImGuiCond_Always, pivot);
|
||||
if (ImGui::Begin("##TutorialMessage", nullptr, ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing)) {
|
||||
ImGui::BringWindowToDisplayFront(ImGui::GetCurrentWindowRead());
|
||||
|
||||
if (!message->unlocalizedTitle.empty())
|
||||
ImGuiExt::Header(Lang(message->unlocalizedTitle), true);
|
||||
|
||||
if (!message->unlocalizedMessage.empty()) {
|
||||
ImGui::PushTextWrapPos(300_scaled);
|
||||
ImGui::TextUnformatted(Lang(message->unlocalizedMessage));
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::NewLine();
|
||||
}
|
||||
|
||||
ImGui::BeginDisabled(s_currentTutorial->second.m_currentStep == s_currentTutorial->second.m_steps.begin());
|
||||
if (ImGui::ArrowButton("Backwards", ImGuiDir_Left)) {
|
||||
s_currentTutorial->second.m_currentStep->advance(-1);
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::BeginDisabled(!message->allowSkip && s_currentTutorial->second.m_currentStep == s_currentTutorial->second.m_latestStep);
|
||||
if (ImGui::ArrowButton("Forwards", ImGuiDir_Right)) {
|
||||
s_currentTutorial->second.m_currentStep->advance(1);
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
void TutorialManager::drawTutorial() {
|
||||
drawHighlights();
|
||||
|
||||
if (s_currentTutorial == s_tutorials.end())
|
||||
return;
|
||||
|
||||
const auto ¤tStep = s_currentTutorial->second.m_currentStep;
|
||||
if (currentStep == s_currentTutorial->second.m_steps.end())
|
||||
return;
|
||||
|
||||
const auto &message = currentStep->m_message;
|
||||
drawMessageBox(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TutorialManager::reset() {
|
||||
s_tutorials.clear();
|
||||
s_currentTutorial = s_tutorials.end();
|
||||
|
||||
s_highlights.clear();
|
||||
s_highlightDisplays.clear();
|
||||
}
|
||||
|
||||
TutorialManager::Tutorial::Step& TutorialManager::Tutorial::addStep() {
|
||||
auto &newStep = m_steps.emplace_back(this);
|
||||
m_currentStep = m_steps.end();
|
||||
m_latestStep = m_currentStep;
|
||||
|
||||
return newStep;
|
||||
}
|
||||
|
||||
void TutorialManager::Tutorial::start() {
|
||||
m_currentStep = m_steps.begin();
|
||||
m_latestStep = m_currentStep;
|
||||
if (m_currentStep == m_steps.end())
|
||||
return;
|
||||
|
||||
m_currentStep->addHighlights();
|
||||
}
|
||||
|
||||
void TutorialManager::Tutorial::Step::addHighlights() const {
|
||||
if (m_onAppear)
|
||||
m_onAppear();
|
||||
|
||||
for (const auto &[text, ids] : m_highlights) {
|
||||
IDStack idStack;
|
||||
|
||||
for (const auto &id : ids) {
|
||||
std::visit(wolv::util::overloaded {
|
||||
[&idStack](const Lang &id) {
|
||||
idStack.add(id.get());
|
||||
},
|
||||
[&idStack](const auto &id) {
|
||||
idStack.add(id);
|
||||
}
|
||||
}, id);
|
||||
}
|
||||
|
||||
s_highlights.emplace(idStack.get(), text);
|
||||
}
|
||||
}
|
||||
|
||||
void TutorialManager::Tutorial::Step::removeHighlights() const {
|
||||
for (const auto &[text, ids] : m_highlights) {
|
||||
IDStack idStack;
|
||||
|
||||
for (const auto &id : ids) {
|
||||
std::visit(wolv::util::overloaded {
|
||||
[&idStack](const Lang &id) {
|
||||
idStack.add(id.get());
|
||||
},
|
||||
[&idStack](const auto &id) {
|
||||
idStack.add(id);
|
||||
}
|
||||
}, id);
|
||||
}
|
||||
|
||||
s_highlights.erase(idStack.get());
|
||||
}
|
||||
}
|
||||
|
||||
void TutorialManager::Tutorial::Step::advance(i32 steps) const {
|
||||
m_parent->m_currentStep->removeHighlights();
|
||||
|
||||
if (m_parent->m_currentStep == m_parent->m_latestStep && steps > 0)
|
||||
std::advance(m_parent->m_latestStep, steps);
|
||||
std::advance(m_parent->m_currentStep, steps);
|
||||
|
||||
if (m_parent->m_currentStep != m_parent->m_steps.end())
|
||||
m_parent->m_currentStep->addHighlights();
|
||||
else
|
||||
s_currentTutorial = s_tutorials.end();
|
||||
}
|
||||
|
||||
|
||||
TutorialManager::Tutorial::Step& TutorialManager::Tutorial::Step::addHighlight(const UnlocalizedString &unlocalizedText, std::initializer_list<std::variant<Lang, std::string, int>>&& ids) {
|
||||
m_highlights.emplace_back(
|
||||
unlocalizedText,
|
||||
ids
|
||||
);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TutorialManager::Tutorial::Step& TutorialManager::Tutorial::Step::addHighlight(std::initializer_list<std::variant<Lang, std::string, int>>&& ids) {
|
||||
return this->addHighlight("", std::forward<decltype(ids)>(ids));
|
||||
}
|
||||
|
||||
|
||||
|
||||
TutorialManager::Tutorial::Step& TutorialManager::Tutorial::Step::setMessage(const UnlocalizedString &unlocalizedTitle, const UnlocalizedString &unlocalizedMessage, Position position) {
|
||||
m_message = Message {
|
||||
position,
|
||||
unlocalizedTitle,
|
||||
unlocalizedMessage,
|
||||
false
|
||||
};
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TutorialManager::Tutorial::Step& TutorialManager::Tutorial::Step::allowSkip() {
|
||||
if (m_message.has_value()) {
|
||||
m_message->allowSkip = true;
|
||||
} else {
|
||||
m_message = Message {
|
||||
Position::Bottom | Position::Right,
|
||||
"",
|
||||
"",
|
||||
true
|
||||
};
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TutorialManager::Tutorial::Step& TutorialManager::Tutorial::Step::onAppear(std::function<void()> callback) {
|
||||
m_onAppear = std::move(callback);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
TutorialManager::Tutorial::Step& TutorialManager::Tutorial::Step::onComplete(std::function<void()> callback) {
|
||||
m_onComplete = std::move(callback);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool TutorialManager::Tutorial::Step::isCurrent() const {
|
||||
const auto ¤tStep = m_parent->m_currentStep;
|
||||
|
||||
if (currentStep == m_parent->m_steps.end())
|
||||
return false;
|
||||
|
||||
return &*currentStep == this;
|
||||
}
|
||||
|
||||
void TutorialManager::Tutorial::Step::complete() const {
|
||||
if (this->isCurrent()) {
|
||||
this->advance();
|
||||
|
||||
if (m_onComplete) {
|
||||
TaskManager::doLater([this] {
|
||||
m_onComplete();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void ImGuiTestEngineHook_ItemAdd(ImGuiContext*, ImGuiID id, const ImRect& bb, const ImGuiLastItemData*) {
|
||||
const auto element = hex::s_highlights.find(id);
|
||||
if (element != hex::s_highlights.end()) {
|
||||
hex::s_highlightDisplays.emplace_back(bb, element->second);
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiTestEngineHook_ItemInfo(ImGuiContext*, ImGuiID, const char*, ImGuiItemStatusFlags) {}
|
||||
void ImGuiTestEngineHook_Log(ImGuiContext*, const char*, ...) {}
|
||||
const char* ImGuiTestEngine_FindItemDebugLabel(ImGuiContext*, ImGuiID) { return nullptr; }
|
||||
108
lib/libimhex/source/api/workspace_manager.cpp
Normal file
108
lib/libimhex/source/api/workspace_manager.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
#include <hex/api/workspace_manager.hpp>
|
||||
#include <hex/api/layout_manager.hpp>
|
||||
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
namespace hex {
|
||||
|
||||
std::map<std::string, WorkspaceManager::Workspace> WorkspaceManager::s_workspaces;
|
||||
decltype(WorkspaceManager::s_workspaces)::iterator WorkspaceManager::s_currentWorkspace = s_workspaces.end();
|
||||
decltype(WorkspaceManager::s_workspaces)::iterator WorkspaceManager::s_previousWorkspace = s_workspaces.end();
|
||||
|
||||
void WorkspaceManager::createWorkspace(const std::string& name, const std::string &layout) {
|
||||
s_workspaces[name] = Workspace {
|
||||
.layout = layout.empty() ? LayoutManager::saveToString() : layout,
|
||||
.path = {}
|
||||
};
|
||||
|
||||
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Workspaces)) {
|
||||
if (exportToFile(path / (name + ".hexws")))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void WorkspaceManager::switchWorkspace(const std::string& name) {
|
||||
const auto newWorkspace = s_workspaces.find(name);
|
||||
if (newWorkspace != s_workspaces.end()) {
|
||||
s_currentWorkspace = newWorkspace;
|
||||
log::info("Switching to workspace '{}'", name);
|
||||
}
|
||||
}
|
||||
|
||||
void WorkspaceManager::importFromFile(const std::fs::path& path) {
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Read);
|
||||
if (!file.isValid()) {
|
||||
log::error("Failed to load workspace from file '{}'", path.string());
|
||||
return;
|
||||
}
|
||||
|
||||
auto content = file.readString();
|
||||
try {
|
||||
auto json = nlohmann::json::parse(content.begin(), content.end());
|
||||
|
||||
std::string name = json["name"];
|
||||
std::string layout = json["layout"];
|
||||
|
||||
s_workspaces[name] = Workspace {
|
||||
.layout = std::move(layout),
|
||||
.path = path
|
||||
};
|
||||
} catch (nlohmann::json::exception &e) {
|
||||
log::error("Failed to load workspace from file '{}': {}", path.string(), e.what());
|
||||
}
|
||||
}
|
||||
|
||||
bool WorkspaceManager::exportToFile(std::fs::path path, std::string workspaceName) {
|
||||
if (path.empty()) {
|
||||
if (s_currentWorkspace == s_workspaces.end())
|
||||
return false;
|
||||
|
||||
path = s_currentWorkspace->second.path;
|
||||
}
|
||||
|
||||
if (workspaceName.empty())
|
||||
workspaceName = s_currentWorkspace->first;
|
||||
|
||||
wolv::io::File file(path, wolv::io::File::Mode::Create);
|
||||
|
||||
if (!file.isValid())
|
||||
return false;
|
||||
|
||||
nlohmann::json json;
|
||||
json["name"] = workspaceName;
|
||||
json["layout"] = LayoutManager::saveToString();
|
||||
|
||||
file.writeString(json.dump(4));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void WorkspaceManager::process() {
|
||||
if (s_previousWorkspace != s_currentWorkspace) {
|
||||
if (s_previousWorkspace != s_workspaces.end())
|
||||
exportToFile(s_previousWorkspace->second.path, s_previousWorkspace->first);
|
||||
|
||||
LayoutManager::closeAllViews();
|
||||
ImGui::LoadIniSettingsFromMemory(s_currentWorkspace->second.layout.c_str());
|
||||
|
||||
s_previousWorkspace = s_currentWorkspace;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WorkspaceManager::reset() {
|
||||
s_workspaces.clear();
|
||||
s_currentWorkspace = s_workspaces.end();
|
||||
s_previousWorkspace = s_workspaces.end();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace hex::dp {
|
||||
int Attribute::s_idCounter = 1;
|
||||
|
||||
|
||||
Attribute::Attribute(IOType ioType, Type type, std::string unlocalizedName) : m_id(s_idCounter++), m_ioType(ioType), m_type(type), m_unlocalizedName(std::move(unlocalizedName)) {
|
||||
Attribute::Attribute(IOType ioType, Type type, UnlocalizedString unlocalizedName) : m_id(s_idCounter++), m_ioType(ioType), m_type(type), m_unlocalizedName(std::move(unlocalizedName)) {
|
||||
}
|
||||
|
||||
Attribute::~Attribute() {
|
||||
|
||||
@@ -9,8 +9,8 @@ namespace hex::dp {
|
||||
|
||||
int Node::s_idCounter = 1;
|
||||
|
||||
Node::Node(std::string unlocalizedTitle, std::vector<Attribute> attributes) : m_id(s_idCounter++), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_attributes(std::move(attributes)) {
|
||||
for (auto &attr : this->m_attributes)
|
||||
Node::Node(UnlocalizedString unlocalizedTitle, std::vector<Attribute> attributes) : m_id(s_idCounter++), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_attributes(std::move(attributes)) {
|
||||
for (auto &attr : m_attributes)
|
||||
attr.setParentNode(this);
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace hex::dp {
|
||||
auto attribute = this->getConnectedInputAttribute(index);
|
||||
|
||||
if (attribute == nullptr)
|
||||
throwNodeError(hex::format("Nothing connected to input '{0}'", Lang(this->m_attributes[index].getUnlocalizedName())));
|
||||
throwNodeError(hex::format("Nothing connected to input '{0}'", Lang(m_attributes[index].getUnlocalizedName())));
|
||||
|
||||
if (attribute->getType() != Attribute::Type::Buffer)
|
||||
throwNodeError("Tried to read buffer from non-buffer attribute");
|
||||
@@ -141,11 +141,11 @@ namespace hex::dp {
|
||||
}
|
||||
|
||||
void Node::setOverlayData(u64 address, const std::vector<u8> &data) {
|
||||
if (this->m_overlay == nullptr)
|
||||
if (m_overlay == nullptr)
|
||||
throwNodeError("Tried setting overlay data on a node that's not the end of a chain!");
|
||||
|
||||
this->m_overlay->setAddress(address);
|
||||
this->m_overlay->getData() = data;
|
||||
m_overlay->setAddress(address);
|
||||
m_overlay->getData() = data;
|
||||
}
|
||||
|
||||
void Node::setIdCounter(int id) {
|
||||
|
||||
@@ -110,27 +110,27 @@ namespace hex::crypt {
|
||||
}
|
||||
|
||||
constexpr void reset() {
|
||||
this->m_value = reflect(m_init, NumBits);
|
||||
m_value = reflect(m_init, NumBits);
|
||||
}
|
||||
|
||||
constexpr void processBytes(const unsigned char *data, std::size_t size) {
|
||||
for (std::size_t i = 0; i < size; i++) {
|
||||
u8 byte;
|
||||
if (this->m_reflectInput)
|
||||
if (m_reflectInput)
|
||||
byte = data[i];
|
||||
else
|
||||
byte = reflect(data[i]);
|
||||
|
||||
this->m_value = this->m_table[(this->m_value ^ byte) & 0xFFL] ^ (this->m_value >> 8);
|
||||
m_value = m_table[(m_value ^ byte) & 0xFFL] ^ (m_value >> 8);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]]
|
||||
constexpr u64 checksum() const {
|
||||
if (this->m_reflectOutput)
|
||||
return this->m_value ^ m_xorOut;
|
||||
if (m_reflectOutput)
|
||||
return m_value ^ m_xorOut;
|
||||
else
|
||||
return reflect(this->m_value, NumBits) ^ m_xorOut;
|
||||
return reflect(m_value, NumBits) ^ m_xorOut;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -12,19 +12,19 @@ namespace hex {
|
||||
}
|
||||
|
||||
EncodingFile::EncodingFile(const hex::EncodingFile &other) {
|
||||
this->m_mapping = std::make_unique<std::map<size_t, std::map<std::vector<u8>, std::string>>>(*other.m_mapping);
|
||||
this->m_tableContent = other.m_tableContent;
|
||||
this->m_longestSequence = other.m_longestSequence;
|
||||
this->m_valid = other.m_valid;
|
||||
this->m_name = other.m_name;
|
||||
m_mapping = std::make_unique<std::map<size_t, std::map<std::vector<u8>, std::string>>>(*other.m_mapping);
|
||||
m_tableContent = other.m_tableContent;
|
||||
m_longestSequence = other.m_longestSequence;
|
||||
m_valid = other.m_valid;
|
||||
m_name = other.m_name;
|
||||
}
|
||||
|
||||
EncodingFile::EncodingFile(EncodingFile &&other) noexcept {
|
||||
this->m_mapping = std::move(other.m_mapping);
|
||||
this->m_tableContent = std::move(other.m_tableContent);
|
||||
this->m_longestSequence = other.m_longestSequence;
|
||||
this->m_valid = other.m_valid;
|
||||
this->m_name = std::move(other.m_name);
|
||||
m_mapping = std::move(other.m_mapping);
|
||||
m_tableContent = std::move(other.m_tableContent);
|
||||
m_longestSequence = other.m_longestSequence;
|
||||
m_valid = other.m_valid;
|
||||
m_name = std::move(other.m_name);
|
||||
}
|
||||
|
||||
EncodingFile::EncodingFile(Type type, const std::fs::path &path) : EncodingFile() {
|
||||
@@ -38,14 +38,14 @@ namespace hex {
|
||||
}
|
||||
|
||||
{
|
||||
this->m_name = path.stem().string();
|
||||
this->m_name = wolv::util::replaceStrings(this->m_name, "_", " ");
|
||||
m_name = path.stem().string();
|
||||
m_name = wolv::util::replaceStrings(m_name, "_", " ");
|
||||
|
||||
if (!this->m_name.empty())
|
||||
this->m_name[0] = std::toupper(this->m_name[0]);
|
||||
if (!m_name.empty())
|
||||
m_name[0] = std::toupper(m_name[0]);
|
||||
}
|
||||
|
||||
this->m_valid = true;
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
EncodingFile::EncodingFile(Type type, const std::string &content) : EncodingFile() {
|
||||
@@ -57,27 +57,27 @@ namespace hex {
|
||||
return;
|
||||
}
|
||||
|
||||
this->m_name = "Unknown";
|
||||
this->m_valid = true;
|
||||
m_name = "Unknown";
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
|
||||
EncodingFile &EncodingFile::operator=(const hex::EncodingFile &other) {
|
||||
this->m_mapping = std::make_unique<std::map<size_t, std::map<std::vector<u8>, std::string>>>(*other.m_mapping);
|
||||
this->m_tableContent = other.m_tableContent;
|
||||
this->m_longestSequence = other.m_longestSequence;
|
||||
this->m_valid = other.m_valid;
|
||||
this->m_name = other.m_name;
|
||||
m_mapping = std::make_unique<std::map<size_t, std::map<std::vector<u8>, std::string>>>(*other.m_mapping);
|
||||
m_tableContent = other.m_tableContent;
|
||||
m_longestSequence = other.m_longestSequence;
|
||||
m_valid = other.m_valid;
|
||||
m_name = other.m_name;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
EncodingFile &EncodingFile::operator=(EncodingFile &&other) noexcept {
|
||||
this->m_mapping = std::move(other.m_mapping);
|
||||
this->m_tableContent = std::move(other.m_tableContent);
|
||||
this->m_longestSequence = other.m_longestSequence;
|
||||
this->m_valid = other.m_valid;
|
||||
this->m_name = std::move(other.m_name);
|
||||
m_mapping = std::move(other.m_mapping);
|
||||
m_tableContent = std::move(other.m_tableContent);
|
||||
m_longestSequence = other.m_longestSequence;
|
||||
m_valid = other.m_valid;
|
||||
m_name = std::move(other.m_name);
|
||||
|
||||
return *this;
|
||||
}
|
||||
@@ -85,7 +85,7 @@ namespace hex {
|
||||
|
||||
|
||||
std::pair<std::string_view, size_t> EncodingFile::getEncodingFor(std::span<u8> buffer) const {
|
||||
for (auto riter = this->m_mapping->crbegin(); riter != this->m_mapping->crend(); ++riter) {
|
||||
for (auto riter = m_mapping->crbegin(); riter != m_mapping->crend(); ++riter) {
|
||||
const auto &[size, mapping] = *riter;
|
||||
|
||||
if (size > buffer.size()) continue;
|
||||
@@ -99,7 +99,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
size_t EncodingFile::getEncodingLengthFor(std::span<u8> buffer) const {
|
||||
for (auto riter = this->m_mapping->crbegin(); riter != this->m_mapping->crend(); ++riter) {
|
||||
for (auto riter = m_mapping->crbegin(); riter != m_mapping->crend(); ++riter) {
|
||||
const auto &[size, mapping] = *riter;
|
||||
|
||||
if (size > buffer.size()) continue;
|
||||
@@ -113,8 +113,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
void EncodingFile::parse(const std::string &content) {
|
||||
this->m_tableContent = content;
|
||||
for (const auto &line : splitString(this->m_tableContent, "\n")) {
|
||||
m_tableContent = content;
|
||||
for (const auto &line : splitString(m_tableContent, "\n")) {
|
||||
|
||||
std::string from, to;
|
||||
{
|
||||
@@ -137,13 +137,13 @@ namespace hex {
|
||||
if (to.empty())
|
||||
to = " ";
|
||||
|
||||
if (!this->m_mapping->contains(fromBytes.size()))
|
||||
this->m_mapping->insert({ fromBytes.size(), {} });
|
||||
if (!m_mapping->contains(fromBytes.size()))
|
||||
m_mapping->insert({ fromBytes.size(), {} });
|
||||
|
||||
auto keySize = fromBytes.size();
|
||||
(*this->m_mapping)[keySize].insert({ std::move(fromBytes), to });
|
||||
(*m_mapping)[keySize].insert({ std::move(fromBytes), to });
|
||||
|
||||
this->m_longestSequence = std::max(this->m_longestSequence, keySize);
|
||||
m_longestSequence = std::max(m_longestSequence, keySize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -375,6 +375,9 @@ namespace hex::fs {
|
||||
case ImHexPath::Config:
|
||||
result = appendPath(getConfigPaths(), "config");
|
||||
break;
|
||||
case ImHexPath::Backups:
|
||||
result = appendPath(getDataPaths(), "backups");
|
||||
break;
|
||||
case ImHexPath::Encodings:
|
||||
result = appendPath(getDataPaths(), "encodings");
|
||||
break;
|
||||
@@ -420,6 +423,9 @@ namespace hex::fs {
|
||||
case ImHexPath::Layouts:
|
||||
result = appendPath(getDataPaths(), "layouts");
|
||||
break;
|
||||
case ImHexPath::Workspaces:
|
||||
result = appendPath(getDataPaths(), "workspaces");
|
||||
break;
|
||||
}
|
||||
|
||||
// Remove all paths that don't exist if requested
|
||||
|
||||
@@ -5,25 +5,25 @@
|
||||
namespace hex {
|
||||
|
||||
HttpRequest::HttpRequest(std::string method, std::string url) : m_method(std::move(method)), m_url(std::move(url)) {
|
||||
emscripten_fetch_attr_init(&this->m_attr);
|
||||
emscripten_fetch_attr_init(&m_attr);
|
||||
}
|
||||
|
||||
HttpRequest::HttpRequest(HttpRequest &&other) noexcept {
|
||||
this->m_attr = other.m_attr;
|
||||
m_attr = other.m_attr;
|
||||
|
||||
this->m_method = std::move(other.m_method);
|
||||
this->m_url = std::move(other.m_url);
|
||||
this->m_headers = std::move(other.m_headers);
|
||||
this->m_body = std::move(other.m_body);
|
||||
m_method = std::move(other.m_method);
|
||||
m_url = std::move(other.m_url);
|
||||
m_headers = std::move(other.m_headers);
|
||||
m_body = std::move(other.m_body);
|
||||
}
|
||||
|
||||
HttpRequest& HttpRequest::operator=(HttpRequest &&other) noexcept {
|
||||
this->m_attr = other.m_attr;
|
||||
m_attr = other.m_attr;
|
||||
|
||||
this->m_method = std::move(other.m_method);
|
||||
this->m_url = std::move(other.m_url);
|
||||
this->m_headers = std::move(other.m_headers);
|
||||
this->m_body = std::move(other.m_body);
|
||||
m_method = std::move(other.m_method);
|
||||
m_url = std::move(other.m_url);
|
||||
m_headers = std::move(other.m_headers);
|
||||
m_body = std::move(other.m_body);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -20,60 +20,60 @@ namespace hex {
|
||||
curl_global_cleanup();
|
||||
};
|
||||
|
||||
this->m_curl = curl_easy_init();
|
||||
m_curl = curl_easy_init();
|
||||
}
|
||||
|
||||
HttpRequest::~HttpRequest() {
|
||||
curl_easy_cleanup(this->m_curl);
|
||||
curl_easy_cleanup(m_curl);
|
||||
}
|
||||
|
||||
HttpRequest::HttpRequest(HttpRequest &&other) noexcept {
|
||||
this->m_curl = other.m_curl;
|
||||
m_curl = other.m_curl;
|
||||
other.m_curl = nullptr;
|
||||
|
||||
this->m_method = std::move(other.m_method);
|
||||
this->m_url = std::move(other.m_url);
|
||||
this->m_headers = std::move(other.m_headers);
|
||||
this->m_body = std::move(other.m_body);
|
||||
m_method = std::move(other.m_method);
|
||||
m_url = std::move(other.m_url);
|
||||
m_headers = std::move(other.m_headers);
|
||||
m_body = std::move(other.m_body);
|
||||
}
|
||||
|
||||
HttpRequest& HttpRequest::operator=(HttpRequest &&other) noexcept {
|
||||
this->m_curl = other.m_curl;
|
||||
m_curl = other.m_curl;
|
||||
other.m_curl = nullptr;
|
||||
|
||||
this->m_method = std::move(other.m_method);
|
||||
this->m_url = std::move(other.m_url);
|
||||
this->m_headers = std::move(other.m_headers);
|
||||
this->m_body = std::move(other.m_body);
|
||||
m_method = std::move(other.m_method);
|
||||
m_url = std::move(other.m_url);
|
||||
m_headers = std::move(other.m_headers);
|
||||
m_body = std::move(other.m_body);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void HttpRequest::setDefaultConfig() {
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_USERAGENT, "ImHex/1.0");
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_DEFAULT_PROTOCOL, "https");
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_SSL_VERIFYPEER, 1L);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_SSL_VERIFYHOST, 2L);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_TIMEOUT_MS, 0L);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_CONNECTTIMEOUT_MS, this->m_timeout);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_NOPROGRESS, 0L);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_XFERINFODATA, this);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_XFERINFOFUNCTION, progressCallback);
|
||||
curl_easy_setopt(m_curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_2TLS);
|
||||
curl_easy_setopt(m_curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2);
|
||||
curl_easy_setopt(m_curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
curl_easy_setopt(m_curl, CURLOPT_USERAGENT, "ImHex/1.0");
|
||||
curl_easy_setopt(m_curl, CURLOPT_DEFAULT_PROTOCOL, "https");
|
||||
curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYPEER, 1L);
|
||||
curl_easy_setopt(m_curl, CURLOPT_SSL_VERIFYHOST, 2L);
|
||||
curl_easy_setopt(m_curl, CURLOPT_TIMEOUT_MS, 0L);
|
||||
curl_easy_setopt(m_curl, CURLOPT_CONNECTTIMEOUT_MS, m_timeout);
|
||||
curl_easy_setopt(m_curl, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_setopt(m_curl, CURLOPT_NOPROGRESS, 0L);
|
||||
curl_easy_setopt(m_curl, CURLOPT_XFERINFODATA, this);
|
||||
curl_easy_setopt(m_curl, CURLOPT_XFERINFOFUNCTION, progressCallback);
|
||||
|
||||
if (s_proxyState)
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_PROXY, s_proxyUrl.c_str());
|
||||
curl_easy_setopt(m_curl, CURLOPT_PROXY, s_proxyUrl.c_str());
|
||||
}
|
||||
|
||||
std::future<HttpRequest::Result<std::vector<u8>>> HttpRequest::downloadFile() {
|
||||
return std::async(std::launch::async, [this] {
|
||||
std::vector<u8> response;
|
||||
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(this->m_curl, CURLOPT_WRITEDATA, &response);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, writeToVector);
|
||||
curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &response);
|
||||
|
||||
return this->executeImpl<std::vector<u8>>(response);
|
||||
});
|
||||
@@ -85,8 +85,8 @@ namespace hex {
|
||||
s_proxyUrl = std::move(proxy);
|
||||
}
|
||||
|
||||
void HttpRequest::setProxyState(bool state) {
|
||||
s_proxyState = state;
|
||||
void HttpRequest::setProxyState(bool enabled) {
|
||||
s_proxyState = enabled;
|
||||
}
|
||||
|
||||
void HttpRequest::checkProxyErrors() {
|
||||
|
||||
@@ -62,20 +62,20 @@ namespace hex::log::impl {
|
||||
return logEntries;
|
||||
}
|
||||
|
||||
void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level) {
|
||||
void printPrefix(FILE *dest, const fmt::text_style &ts, const std::string &level, const char *projectName) {
|
||||
const auto now = fmt::localtime(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()));
|
||||
|
||||
fmt::print(dest, "[{0:%H:%M:%S}] ", now);
|
||||
|
||||
if (impl::isRedirected())
|
||||
if (isRedirected())
|
||||
fmt::print(dest, "{0} ", level);
|
||||
else
|
||||
fmt::print(dest, ts, "{0} ", level);
|
||||
|
||||
fmt::print(dest, "[{0}] ", IMHEX_PROJECT_NAME);
|
||||
fmt::print(dest, "[{0}] ", projectName);
|
||||
|
||||
constexpr static auto ProjectNameLength = std::char_traits<char>::length(IMHEX_PROJECT_NAME);
|
||||
fmt::print(dest, "{}", std::string(ProjectNameLength > 10 ? 0 : 10 - ProjectNameLength, ' '));
|
||||
auto projectNameLength = std::string_view(projectName).length();
|
||||
fmt::print(dest, "{}", std::string(projectNameLength > 10 ? 0 : 10 - projectNameLength, ' '));
|
||||
}
|
||||
|
||||
void assertionHandler(bool expr, const char* exprString, const char* file, int line) {
|
||||
|
||||
@@ -112,7 +112,7 @@ namespace hex::magic {
|
||||
}
|
||||
|
||||
std::string getDescription(prv::Provider *provider, size_t size) {
|
||||
std::vector<u8> buffer(std::min(provider->getSize(), size), 0x00);
|
||||
std::vector<u8> buffer(std::min<u64>(provider->getSize(), size), 0x00);
|
||||
provider->read(provider->getBaseAddress(), buffer.data(), buffer.size());
|
||||
|
||||
return getDescription(buffer);
|
||||
@@ -135,7 +135,7 @@ namespace hex::magic {
|
||||
}
|
||||
|
||||
std::string getMIMEType(prv::Provider *provider, size_t size) {
|
||||
std::vector<u8> buffer(std::min(provider->getSize(), size), 0x00);
|
||||
std::vector<u8> buffer(std::min<u64>(provider->getSize(), size), 0x00);
|
||||
provider->read(provider->getBaseAddress(), buffer.data(), buffer.size());
|
||||
|
||||
return getMIMEType(buffer);
|
||||
|
||||
@@ -6,9 +6,60 @@
|
||||
|
||||
#include <wolv/utils/guards.hpp>
|
||||
|
||||
#include <numbers>
|
||||
|
||||
namespace hex::gl {
|
||||
|
||||
Matrix<float,4,4> GetOrthographicMatrix( float viewWidth, float viewHeight, float nearVal,float farVal, bool actionType)
|
||||
{
|
||||
int sign =1;
|
||||
if (actionType)
|
||||
sign=-1;
|
||||
//float left = leftRight.x;
|
||||
//float right = leftRight.y;
|
||||
//float down = upDown.x;
|
||||
//float up = upDown.y;
|
||||
Matrix<float,4,4> result(0);
|
||||
//result.updateElement(0,0,sign /(right-left))
|
||||
result.updateElement(0,0,sign / viewWidth);
|
||||
//result.updateElement(0,3,sign * (right + left)/(right - left));
|
||||
//result.updateElement(1,1, sign /(up-down));
|
||||
result.updateElement(1,1, sign / viewHeight);
|
||||
//result.updateElement(1,3, sign * (up + down)/(up - down));
|
||||
|
||||
result.updateElement(2,2,-sign * 2/(farVal - nearVal));
|
||||
result.updateElement(3,2,-sign * (farVal + nearVal)/(farVal - nearVal));
|
||||
|
||||
result.updateElement(3,3,sign);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
Matrix<float,4,4> GetPerspectiveMatrix( float viewWidth, float viewHeight, float nearVal,float farVal, bool actionType)
|
||||
{
|
||||
int sign =1;
|
||||
if (actionType)
|
||||
sign=-1;
|
||||
//float left = leftRight.x;
|
||||
//float right = leftRight.y;
|
||||
//float down = upDown.x;
|
||||
//float up = upDown.y;
|
||||
//T aspect=(right-left)/(top-bottom);
|
||||
//T f = nearVal/top;
|
||||
Matrix<float,4,4> result(0);
|
||||
// T f = 1.0 / tan(fovy / 2.0); tan(fovy / 2.0) = top / near; fovy = 2 * atan2(top,near)
|
||||
|
||||
//result.updateElement(0,0,sign * nearVal/(right-left));
|
||||
//result.updateElement(1,1, sign * nearVal/(up-down));
|
||||
result.updateElement(0,0,sign * nearVal/viewWidth);
|
||||
result.updateElement(1,1, sign * nearVal/viewHeight);
|
||||
result.updateElement(2,2,-sign * (farVal + nearVal)/(farVal - nearVal));
|
||||
result.updateElement(3,2,-sign * 2*farVal*nearVal/(farVal - nearVal));
|
||||
result.updateElement(2,3,-sign);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Shader::Shader(std::string_view vertexSource, std::string_view fragmentSource) {
|
||||
auto vertexShader = glCreateShader(GL_VERTEX_SHADER);
|
||||
this->compile(vertexShader, vertexSource);
|
||||
@@ -18,70 +69,71 @@ namespace hex::gl {
|
||||
|
||||
ON_SCOPE_EXIT { glDeleteShader(vertexShader); glDeleteShader(fragmentShader); };
|
||||
|
||||
this->m_program = glCreateProgram();
|
||||
m_program = glCreateProgram();
|
||||
|
||||
glAttachShader(this->m_program, vertexShader);
|
||||
glAttachShader(this->m_program, fragmentShader);
|
||||
glLinkProgram(this->m_program);
|
||||
glAttachShader(m_program, vertexShader);
|
||||
glAttachShader(m_program, fragmentShader);
|
||||
glLinkProgram(m_program);
|
||||
|
||||
int result = false;
|
||||
glGetProgramiv(this->m_program, GL_LINK_STATUS, &result);
|
||||
glGetProgramiv(m_program, GL_LINK_STATUS, &result);
|
||||
if (!result) {
|
||||
std::vector<char> log(512);
|
||||
glGetShaderInfoLog(this->m_program, log.size(), nullptr, log.data());
|
||||
glGetShaderInfoLog(m_program, log.size(), nullptr, log.data());
|
||||
log::error("Failed to link shader: {}", log.data());
|
||||
}
|
||||
}
|
||||
|
||||
Shader::~Shader() {
|
||||
if (this->m_program != 0)
|
||||
glDeleteProgram(this->m_program);
|
||||
if (m_program != 0)
|
||||
glDeleteProgram(m_program);
|
||||
}
|
||||
|
||||
Shader::Shader(Shader &&other) noexcept {
|
||||
this->m_program = other.m_program;
|
||||
m_program = other.m_program;
|
||||
other.m_program = 0;
|
||||
}
|
||||
|
||||
Shader& Shader::operator=(Shader &&other) noexcept {
|
||||
this->m_program = other.m_program;
|
||||
m_program = other.m_program;
|
||||
other.m_program = 0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Shader::bind() const {
|
||||
glUseProgram(this->m_program);
|
||||
glUseProgram(m_program);
|
||||
}
|
||||
|
||||
void Shader::unbind() const {
|
||||
glUseProgram(0);
|
||||
}
|
||||
|
||||
void Shader::setUniform(std::string_view name, const int &value) {
|
||||
glUniform1i(getUniformLocation(name), value);
|
||||
}
|
||||
|
||||
void Shader::setUniform(std::string_view name, const float &value) {
|
||||
glUniform1f(getUniformLocation(name), value);
|
||||
}
|
||||
|
||||
void Shader::setUniform(std::string_view name, const Vector<float, 3> &value) {
|
||||
glUniform3f(getUniformLocation(name), value[0], value[1], value[2]);
|
||||
}
|
||||
|
||||
GLint Shader::getUniformLocation(std::string_view name) {
|
||||
auto uniform = this->m_uniforms.find(name.data());
|
||||
if (uniform == this->m_uniforms.end()) {
|
||||
auto location = glGetUniformLocation(this->m_program, name.data());
|
||||
auto uniform = m_uniforms.find(name.data());
|
||||
if (uniform == m_uniforms.end()) {
|
||||
auto location = glGetUniformLocation(m_program, name.data());
|
||||
if (location == -1) {
|
||||
log::warn("Uniform '{}' not found in shader", name);
|
||||
return -1;
|
||||
}
|
||||
|
||||
this->m_uniforms[name.data()] = location;
|
||||
uniform = this->m_uniforms.find(name.data());
|
||||
m_uniforms[name.data()] = location;
|
||||
uniform = m_uniforms.find(name.data());
|
||||
}
|
||||
|
||||
return uniform->second;
|
||||
}
|
||||
|
||||
void Shader::compile(GLuint shader, std::string_view source) {
|
||||
void Shader::compile(GLuint shader, std::string_view source) const {
|
||||
auto sourcePtr = source.data();
|
||||
|
||||
glShaderSource(shader, 1, &sourcePtr, nullptr);
|
||||
@@ -98,87 +150,95 @@ namespace hex::gl {
|
||||
|
||||
|
||||
template<typename T>
|
||||
Buffer<T>::Buffer(BufferType type, std::span<T> data) : m_size(data.size()), m_type(GLuint(type)) {
|
||||
glGenBuffers(1, &this->m_buffer);
|
||||
glBindBuffer(this->m_type, this->m_buffer);
|
||||
glBufferData(this->m_type, data.size_bytes(), data.data(), GL_STATIC_DRAW);
|
||||
glBindBuffer(this->m_type, 0);
|
||||
Buffer<T>::Buffer(BufferType type, std::span<const T> data) : m_size(data.size()), m_type(GLuint(type)) {
|
||||
glGenBuffers(1, &m_buffer);
|
||||
glBindBuffer(m_type, m_buffer);
|
||||
glBufferData(m_type, data.size_bytes(), data.data(), GL_STATIC_DRAW);
|
||||
glBindBuffer(m_type, 0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Buffer<T>::~Buffer() {
|
||||
glDeleteBuffers(1, &this->m_buffer);
|
||||
glDeleteBuffers(1, &m_buffer);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Buffer<T>::Buffer(Buffer &&other) noexcept {
|
||||
this->m_buffer = other.m_buffer;
|
||||
this->m_size = other.m_size;
|
||||
this->m_type = other.m_type;
|
||||
m_buffer = other.m_buffer;
|
||||
m_size = other.m_size;
|
||||
m_type = other.m_type;
|
||||
other.m_buffer = -1;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
Buffer<T>& Buffer<T>::operator=(Buffer &&other) noexcept {
|
||||
this->m_buffer = other.m_buffer;
|
||||
this->m_size = other.m_size;
|
||||
this->m_type = other.m_type;
|
||||
m_buffer = other.m_buffer;
|
||||
m_size = other.m_size;
|
||||
m_type = other.m_type;
|
||||
other.m_buffer = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Buffer<T>::bind() const {
|
||||
glBindBuffer(this->m_type, this->m_buffer);
|
||||
glBindBuffer(m_type, m_buffer);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Buffer<T>::unbind() const {
|
||||
glBindBuffer(this->m_type, 0);
|
||||
glBindBuffer(m_type, 0);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
size_t Buffer<T>::getSize() const {
|
||||
return this->m_size;
|
||||
return m_size;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Buffer<T>::draw() const {
|
||||
switch (this->m_type) {
|
||||
void Buffer<T>::draw(unsigned primitive) const {
|
||||
switch (m_type) {
|
||||
case GL_ARRAY_BUFFER:
|
||||
glDrawArrays(GL_TRIANGLES, 0, this->m_size);
|
||||
glDrawArrays(primitive, 0, m_size);
|
||||
break;
|
||||
case GL_ELEMENT_ARRAY_BUFFER:
|
||||
glDrawElements(GL_TRIANGLES, this->m_size, impl::getType<T>(), nullptr);
|
||||
break;
|
||||
glDrawElements(primitive, m_size, impl::getType<T>(), nullptr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Buffer<T>::update(std::span<const T> data) {
|
||||
glBindBuffer(m_type, m_buffer);
|
||||
glBufferSubData(m_type, 0, data.size_bytes(), data.data());
|
||||
glBindBuffer(m_type, 0);
|
||||
}
|
||||
|
||||
template class Buffer<float>;
|
||||
template class Buffer<u32>;
|
||||
|
||||
template class Buffer<u16>;
|
||||
template class Buffer<u8>;
|
||||
|
||||
VertexArray::VertexArray() {
|
||||
glGenVertexArrays(1, &this->m_array);
|
||||
glGenVertexArrays(1, &m_array);
|
||||
}
|
||||
|
||||
VertexArray::~VertexArray() {
|
||||
glDeleteVertexArrays(1, &this->m_array);
|
||||
glDeleteVertexArrays(1, &m_array);
|
||||
}
|
||||
|
||||
VertexArray::VertexArray(VertexArray &&other) noexcept {
|
||||
this->m_array = other.m_array;
|
||||
m_array = other.m_array;
|
||||
other.m_array = -1;
|
||||
}
|
||||
|
||||
VertexArray& VertexArray::operator=(VertexArray &&other) noexcept {
|
||||
this->m_array = other.m_array;
|
||||
m_array = other.m_array;
|
||||
other.m_array = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void VertexArray::bind() const {
|
||||
glBindVertexArray(this->m_array);
|
||||
glBindVertexArray(m_array);
|
||||
}
|
||||
|
||||
void VertexArray::unbind() const {
|
||||
@@ -187,8 +247,8 @@ namespace hex::gl {
|
||||
|
||||
|
||||
Texture::Texture(u32 width, u32 height) : m_texture(0), m_width(width), m_height(height) {
|
||||
glGenTextures(1, &this->m_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, this->m_texture);
|
||||
glGenTextures(1, &m_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, m_texture);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
|
||||
|
||||
@@ -199,26 +259,26 @@ namespace hex::gl {
|
||||
}
|
||||
|
||||
Texture::~Texture() {
|
||||
if (this->m_texture != 0)
|
||||
glDeleteTextures(1, &this->m_texture);
|
||||
if (m_texture != 0)
|
||||
glDeleteTextures(1, &m_texture);
|
||||
}
|
||||
|
||||
Texture::Texture(Texture &&other) noexcept {
|
||||
this->m_texture = other.m_texture;
|
||||
m_texture = other.m_texture;
|
||||
other.m_texture = -1;
|
||||
|
||||
this->m_width = other.m_width;
|
||||
this->m_height = other.m_height;
|
||||
m_width = other.m_width;
|
||||
m_height = other.m_height;
|
||||
}
|
||||
|
||||
Texture& Texture::operator=(Texture &&other) noexcept {
|
||||
this->m_texture = other.m_texture;
|
||||
m_texture = other.m_texture;
|
||||
other.m_texture = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Texture::bind() const {
|
||||
glBindTexture(GL_TEXTURE_2D, this->m_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, m_texture);
|
||||
}
|
||||
|
||||
void Texture::unbind() const {
|
||||
@@ -226,60 +286,59 @@ namespace hex::gl {
|
||||
}
|
||||
|
||||
GLuint Texture::getTexture() const {
|
||||
return this->m_texture;
|
||||
return m_texture;
|
||||
}
|
||||
|
||||
u32 Texture::getWidth() const {
|
||||
return this->m_width;
|
||||
return m_width;
|
||||
}
|
||||
|
||||
u32 Texture::getHeight() const {
|
||||
return this->m_height;
|
||||
return m_height;
|
||||
}
|
||||
|
||||
GLuint Texture::release() {
|
||||
auto copy = this->m_texture;
|
||||
this->m_texture = -1;
|
||||
auto copy = m_texture;
|
||||
m_texture = -1;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
FrameBuffer::FrameBuffer(u32 width, u32 height) {
|
||||
glGenFramebuffers(1, &m_frameBuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer);
|
||||
|
||||
FrameBuffer::FrameBuffer() {
|
||||
glGenFramebuffers(1, &this->m_frameBuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, this->m_frameBuffer);
|
||||
|
||||
glGenRenderbuffers(1, &this->m_renderBuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, this->m_renderBuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, 1280, 720);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, this->m_renderBuffer);
|
||||
glGenRenderbuffers(1, &m_renderBuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, m_renderBuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, m_renderBuffer);
|
||||
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, 0);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
FrameBuffer::~FrameBuffer() {
|
||||
glDeleteFramebuffers(1, &this->m_frameBuffer);
|
||||
glDeleteRenderbuffers(1, &this->m_renderBuffer);
|
||||
glDeleteFramebuffers(1, &m_frameBuffer);
|
||||
glDeleteRenderbuffers(1, &m_renderBuffer);
|
||||
}
|
||||
|
||||
FrameBuffer::FrameBuffer(FrameBuffer &&other) noexcept {
|
||||
this->m_frameBuffer = other.m_frameBuffer;
|
||||
m_frameBuffer = other.m_frameBuffer;
|
||||
other.m_frameBuffer = -1;
|
||||
this->m_renderBuffer = other.m_renderBuffer;
|
||||
m_renderBuffer = other.m_renderBuffer;
|
||||
other.m_renderBuffer = -1;
|
||||
}
|
||||
|
||||
FrameBuffer& FrameBuffer::operator=(FrameBuffer &&other) noexcept {
|
||||
this->m_frameBuffer = other.m_frameBuffer;
|
||||
m_frameBuffer = other.m_frameBuffer;
|
||||
other.m_frameBuffer = -1;
|
||||
this->m_renderBuffer = other.m_renderBuffer;
|
||||
m_renderBuffer = other.m_renderBuffer;
|
||||
other.m_renderBuffer = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void FrameBuffer::bind() const {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, this->m_frameBuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer);
|
||||
}
|
||||
|
||||
void FrameBuffer::unbind() const {
|
||||
@@ -287,7 +346,7 @@ namespace hex::gl {
|
||||
}
|
||||
|
||||
void FrameBuffer::attachTexture(const Texture &texture) const {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, this->m_frameBuffer);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer);
|
||||
texture.bind();
|
||||
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture.getTexture(), 0);
|
||||
@@ -295,4 +354,335 @@ namespace hex::gl {
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
|
||||
}
|
||||
AxesVectors::AxesVectors() {
|
||||
m_vertices.resize(36);
|
||||
m_colors.resize(48);
|
||||
m_indices.resize(18);
|
||||
|
||||
// Vertices are x,y,z. Colors are RGBA. Indices are for the ends of each segment
|
||||
// Entries with value zero are unneeded but kept to help keep track of location
|
||||
// x-axis
|
||||
//vertices[0]=0.0F; vertices[1]= 0.0F vertices[2] = 0.0F; // shaft base
|
||||
m_vertices[3] = 1.0F;//vertices[4]= 0.0F vertices[5] = 0.0F; // shaft tip
|
||||
m_vertices[6] = 0.9F; m_vertices[8] = 0.05F; // arrow base
|
||||
m_vertices[9] = 0.9F; m_vertices[11]=-0.05F; // arrow base
|
||||
// y-axis
|
||||
//vertices[12]=0.0F; vertices[13] = 0.0F; vertices[14]=0.0F;// shaft base
|
||||
m_vertices[16] = 1.0F;//vertices[17]=0.0F;// shaft tip
|
||||
m_vertices[18] = 0.05F; m_vertices[19] = 0.9F;//vertices[20]=0.0F;// arrow base
|
||||
m_vertices[21] =-0.05F; m_vertices[22] = 0.9F;//vertices[23]=0.0F;// arrow base
|
||||
// z-axis
|
||||
//vertices[24]=0.0F; vertices[25]=0.0F vertices[26] = 0.0F; // shaft base
|
||||
m_vertices[29] = 1.0F; // shaft tip
|
||||
m_vertices[30] = 0.05F; m_vertices[32] = 0.9F; // arrow base
|
||||
m_vertices[33] =-0.05F; m_vertices[35] = 0.9F; // arrow base
|
||||
// x-axis colors
|
||||
m_colors[0] = 0.7F; m_colors[3] = 1.0F;
|
||||
m_colors[4] = 0.7F; m_colors[7] = 1.0F;
|
||||
m_colors[8] = 0.7F; m_colors[11] = 1.0F;
|
||||
m_colors[12] = 0.7F; m_colors[15] = 1.0F;
|
||||
// y-axis colors
|
||||
m_colors[17] = 0.7F; m_colors[19] = 1.0F;
|
||||
m_colors[21] = 0.7F; m_colors[23] = 1.0F;
|
||||
m_colors[25] = 0.7F; m_colors[27] = 1.0F;
|
||||
m_colors[29] = 0.7F; m_colors[31] = 1.0F;
|
||||
// z-axis colors
|
||||
m_colors[34] = 0.7F; m_colors[35] = 1.0F;
|
||||
m_colors[38] = 0.7F; m_colors[39] = 1.0F;
|
||||
m_colors[42] = 0.7F; m_colors[43] = 1.0F;
|
||||
m_colors[46] = 0.7F; m_colors[47] = 1.0F;
|
||||
// indices for x
|
||||
m_indices[0] = 0; m_indices[1] = 1;
|
||||
m_indices[2] = 2; m_indices[3] = 1;
|
||||
m_indices[4] = 3; m_indices[5] = 1;
|
||||
// indices for y
|
||||
m_indices[6] = 4; m_indices[7] = 5;
|
||||
m_indices[8] = 6; m_indices[9] = 5;
|
||||
m_indices[10] = 7; m_indices[11] = 5;
|
||||
// indices for z
|
||||
m_indices[12] = 8; m_indices[13] = 9;
|
||||
m_indices[14] = 10; m_indices[15] = 9;
|
||||
m_indices[16] = 11; m_indices[17] = 9;
|
||||
}
|
||||
|
||||
AxesBuffers::AxesBuffers(const VertexArray& axesVertexArray, const AxesVectors &axesVectors) {
|
||||
m_vertices = {};
|
||||
m_colors = {};
|
||||
m_indices = {};
|
||||
|
||||
axesVertexArray.bind();
|
||||
|
||||
m_vertices = gl::Buffer<float>(gl::BufferType::Vertex, axesVectors.getVertices());
|
||||
m_colors = gl::Buffer<float>(gl::BufferType::Vertex, axesVectors.getColors());
|
||||
m_indices = gl::Buffer<u8>(gl::BufferType::Index, axesVectors.getIndices());
|
||||
|
||||
axesVertexArray.addBuffer(0, m_vertices);
|
||||
axesVertexArray.addBuffer(1, m_colors, 4);
|
||||
|
||||
m_vertices.unbind();
|
||||
m_colors.unbind();
|
||||
m_indices.unbind();
|
||||
axesVertexArray.unbind();
|
||||
}
|
||||
|
||||
|
||||
GridVectors::GridVectors(int sliceCount) {
|
||||
m_slices = sliceCount;
|
||||
m_vertices.resize((m_slices + 1) * (m_slices + 1) * 3);
|
||||
m_colors.resize((m_slices + 1) * (m_slices + 1) * 4);
|
||||
m_indices.resize(m_slices * m_slices * 6 + m_slices * 2);
|
||||
int k = 0;
|
||||
int l = 0;
|
||||
for (u32 j = 0; j <= m_slices; ++j) {
|
||||
float z = 2.0f * float(j) / float(m_slices) - 1.0f;
|
||||
for (u32 i = 0; i <= m_slices; ++i) {
|
||||
m_vertices[k ] = 2.0f * float(i) / float(m_slices) - 1.0f;
|
||||
m_vertices[k + 1] = 0.0f;
|
||||
m_vertices[k + 2] = z;
|
||||
k += 3;
|
||||
m_colors[l ] = 0.5f;
|
||||
m_colors[l + 1] = 0.5f;
|
||||
m_colors[l + 2] = 0.5f;
|
||||
m_colors[l + 3] = 0.3f;
|
||||
l += 4;
|
||||
}
|
||||
}
|
||||
k = 0;
|
||||
for (u32 j = 0; j < m_slices; ++j) {
|
||||
int row1 = j * (m_slices + 1);
|
||||
int row2 = (j + 1) * (m_slices + 1);
|
||||
|
||||
for (u32 i = 0; i < m_slices; ++i) {
|
||||
m_indices[k ] = row1 + i;
|
||||
m_indices[k + 1] = row1 + i + 1;
|
||||
m_indices[k + 2] = row1 + i + 1;
|
||||
m_indices[k + 3] = row2 + i + 1;
|
||||
m_indices[k + 4] = row2 + i + 1;
|
||||
m_indices[k + 5] = row2 + i;
|
||||
k += 6;
|
||||
|
||||
if (i == 0) {
|
||||
m_indices[k ] = row2 + i;
|
||||
m_indices[k + 1] = row1 + i;
|
||||
k += 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GridBuffers::GridBuffers(const VertexArray& gridVertexArray, const GridVectors &gridVectors) {
|
||||
m_vertices = {};
|
||||
m_colors = {};
|
||||
m_indices = {};
|
||||
|
||||
gridVertexArray.bind();
|
||||
|
||||
m_vertices = gl::Buffer<float>(gl::BufferType::Vertex, gridVectors.getVertices());
|
||||
m_indices = gl::Buffer<u8>(gl::BufferType::Index, gridVectors.getIndices());
|
||||
m_colors = gl::Buffer<float>(gl::BufferType::Vertex, gridVectors.getColors());
|
||||
|
||||
gridVertexArray.addBuffer(0, m_vertices);
|
||||
gridVertexArray.addBuffer(1, m_colors,4);
|
||||
|
||||
m_vertices.unbind();
|
||||
m_colors.unbind();
|
||||
m_indices.unbind();
|
||||
gridVertexArray.unbind();
|
||||
}
|
||||
|
||||
hex::gl::LightSourceVectors::LightSourceVectors(int res) {
|
||||
m_resolution = res;
|
||||
auto res_sq = m_resolution * m_resolution;
|
||||
m_radius = 0.05f;
|
||||
m_vertices.resize((res_sq + 2) * 3);
|
||||
m_normals.resize((res_sq + 2) * 3);
|
||||
m_colors.resize((res_sq + 2) * 4);
|
||||
m_indices.resize(res_sq * 6);
|
||||
|
||||
|
||||
constexpr auto TwoPi = std::numbers::pi_v<float> * 2.0F;
|
||||
constexpr auto HalfPi = std::numbers::pi_v<float> / 2.0F;
|
||||
const auto dv = TwoPi / m_resolution;
|
||||
const auto du = std::numbers::pi_v<float> / (m_resolution + 1);
|
||||
|
||||
m_normals[0] = 0;
|
||||
m_normals[1] = 0;
|
||||
m_normals[2] = 1;
|
||||
|
||||
m_vertices[0] = 0;
|
||||
m_vertices[1] = 0;
|
||||
m_vertices[2] = m_radius;
|
||||
|
||||
m_colors[0] = 1.0;
|
||||
m_colors[1] = 1.0;
|
||||
m_colors[2] = 1.0;
|
||||
m_colors[3] = 1.0;
|
||||
|
||||
// Vertical: pi/2 to -pi/2
|
||||
for (int i = 0; i < m_resolution; i += 1) {
|
||||
float u = HalfPi - (i + 1) * du;
|
||||
float z = std::sin(u);
|
||||
float xy = std::cos(u);
|
||||
|
||||
// Horizontal: 0 to 2pi
|
||||
for (int j = 0; j < m_resolution; j += 1) {
|
||||
float v = j * dv;
|
||||
float x = xy * std::cos(v);
|
||||
float y = xy * std::sin(v);
|
||||
|
||||
i32 n = (i * m_resolution + j + 1) * 3;
|
||||
m_normals[n] = x;
|
||||
m_normals[n + 1] = y;
|
||||
m_normals[n + 2] = z;
|
||||
|
||||
m_vertices[n] = m_radius * x;
|
||||
m_vertices[n + 1] = m_radius * y;
|
||||
m_vertices[n + 2] = m_radius * z;
|
||||
|
||||
n = (i * m_resolution + j + 1) * 4;
|
||||
m_colors[n] = 1.0f;
|
||||
m_colors[n + 1] = 1.0f;
|
||||
m_colors[n + 2] = 1.0f;
|
||||
m_colors[n + 3] = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
i32 n = ((res_sq + 1) * 3);
|
||||
m_normals[n ] = 0;
|
||||
m_normals[n + 1] = 0;
|
||||
m_normals[n + 2] = -1;
|
||||
|
||||
m_vertices[n ] = 0;
|
||||
m_vertices[n + 1] = 0;
|
||||
m_vertices[n + 2] = -m_radius;
|
||||
|
||||
n = ((res_sq + 1) * 4);
|
||||
m_colors[n ] = 1.0;
|
||||
m_colors[n + 1] = 1.0;
|
||||
m_colors[n + 2] = 1.0;
|
||||
m_colors[n + 3] = 1.0;
|
||||
|
||||
// that was the easy part, indices are a bit more complicated
|
||||
// and may need some explaining. The RxR grid slices the globe
|
||||
// into longitudes which are the vertical slices and latitudes
|
||||
// which are the horizontal slices. The latitudes are all full
|
||||
// circles except for the poles, so we don't count them as part
|
||||
// of the grid. That means that there are R+2 latitudes and R
|
||||
// longitudes.Between consecutive latitudes we have 2*R triangles.
|
||||
// Since we have R true latitudes there are R-1 spaces between them so
|
||||
// between the top and the bottom we have 2*R*(R-1) triangles.
|
||||
// the top and bottom have R triangles each, so we have a total of
|
||||
// 2*R*(R-1) + 2*R = 2*R*R triangles. Each triangle has 3 vertices,
|
||||
// so we have 6*R*R indices.
|
||||
|
||||
// The North Pole is index 0 and the South Pole is index 6*res*res -1
|
||||
// The first row of vertices is 1 to res, the second row is res+1 to 2*res etc.
|
||||
|
||||
// First, the North Pole
|
||||
for (int i = 0; i < m_resolution; i += 1) {
|
||||
m_indices[i * 3] = 0;
|
||||
m_indices[i * 3 + 1] = i + 1;
|
||||
if (i == m_resolution - 1)
|
||||
m_indices[i * 3 + 2] = 1;
|
||||
else
|
||||
m_indices[i * 3 + 2] = (i + 2);
|
||||
}
|
||||
// Now the spaces between true latitudes
|
||||
for (int i = 0; i < m_resolution - 1; i += 1) {
|
||||
// k is the index of the first vertex of the i-th latitude
|
||||
i32 k = i * m_resolution + 1;
|
||||
// When we go a full circle we need to connect the last vertex to the first, so
|
||||
// we do R-1 first because their indices can be computed easily
|
||||
for (int j = 0; j < m_resolution - 1; j += 1) {
|
||||
// We store the indices of the array where the vertices were store
|
||||
// in the triplets that make the triangles. These triplets are stored in
|
||||
// an array that has indices itself which can be confusing.
|
||||
// l keeps track of the indices of the array that stores the triplets
|
||||
// each i brings 6R and each j 6. 3R from the North Pole.
|
||||
i32 l = (i * m_resolution + j) * 6 + 3 * m_resolution;
|
||||
|
||||
m_indices[l ] = k + j;
|
||||
m_indices[l + 1] = k + j + m_resolution + 1;
|
||||
m_indices[l + 2] = k + j + 1;
|
||||
|
||||
m_indices[l + 3] = k + j;
|
||||
m_indices[l + 4] = k + j + m_resolution;
|
||||
m_indices[l + 5] = k + j + m_resolution + 1;
|
||||
}
|
||||
// Now the last vertex of the i-th latitude is connected to the first
|
||||
i32 l = (( i + 1) * m_resolution - 1) * 6 + 3 * m_resolution;
|
||||
|
||||
m_indices[l ] = k + m_resolution - 1;
|
||||
m_indices[l + 1] = k + m_resolution;
|
||||
m_indices[l + 2] = k;
|
||||
|
||||
m_indices[l + 3] = k + m_resolution - 1;
|
||||
m_indices[l + 4] = k + 2 * m_resolution - 1;
|
||||
m_indices[l + 5] = k + m_resolution;
|
||||
|
||||
}
|
||||
// Now the South Pole
|
||||
i32 k = (m_resolution-1) * m_resolution + 1;
|
||||
i32 l = 3 * m_resolution * ( 2 * m_resolution - 1);
|
||||
for (int i = 0; i < m_resolution; i += 1) {
|
||||
if (i == m_resolution -1)
|
||||
m_indices[l + i * 3] = k;
|
||||
else
|
||||
m_indices[l + i * 3] = k + i + 1;
|
||||
|
||||
m_indices[l + i * 3 + 1] = k + i;
|
||||
m_indices[l + i * 3 + 2] = k + m_resolution;
|
||||
}
|
||||
}
|
||||
|
||||
void LightSourceVectors::moveTo(const Vector<float, 3> &position) {
|
||||
auto vertexCount = m_vertices.size();
|
||||
|
||||
for (unsigned k = 0; k < vertexCount; k += 3) {
|
||||
m_vertices[k ] = m_radius * m_normals[k ] + position[0];
|
||||
m_vertices[k + 1] = m_radius * m_normals[k + 1] + position[1];
|
||||
m_vertices[k + 2] = m_radius * m_normals[k + 2] + position[2];
|
||||
}
|
||||
}
|
||||
|
||||
LightSourceBuffers::LightSourceBuffers(const VertexArray &sourceVertexArray, const LightSourceVectors &sourceVectors) {
|
||||
sourceVertexArray.bind();
|
||||
|
||||
m_vertices = gl::Buffer<float>(gl::BufferType::Vertex, sourceVectors.getVertices());
|
||||
m_indices = gl::Buffer<u16>(gl::BufferType::Index, sourceVectors.getIndices());
|
||||
m_normals = gl::Buffer<float>(gl::BufferType::Vertex, sourceVectors.getNormals());
|
||||
m_colors = gl::Buffer<float>(gl::BufferType::Vertex, sourceVectors.getColors());
|
||||
|
||||
sourceVertexArray.addBuffer(0, m_vertices);
|
||||
sourceVertexArray.addBuffer(1, m_normals);
|
||||
sourceVertexArray.addBuffer(2, m_colors, 4);
|
||||
|
||||
m_vertices.unbind();
|
||||
m_normals.unbind();
|
||||
m_colors.unbind();
|
||||
m_indices.unbind();
|
||||
sourceVertexArray.unbind();
|
||||
}
|
||||
|
||||
void LightSourceBuffers::moveVertices(const VertexArray& sourceVertexArray, const LightSourceVectors& sourceVectors) {
|
||||
sourceVertexArray.bind();
|
||||
|
||||
m_vertices.update(sourceVectors.getVertices());
|
||||
sourceVertexArray.addBuffer(0, m_vertices);
|
||||
|
||||
sourceVertexArray.unbind();
|
||||
}
|
||||
|
||||
void LightSourceBuffers::updateColors(const VertexArray& sourceVertexArray, const LightSourceVectors& sourceVectors) {
|
||||
sourceVertexArray.bind();
|
||||
|
||||
m_colors.update(sourceVectors.getColors());
|
||||
sourceVertexArray.addBuffer(2, m_colors, 4);
|
||||
|
||||
sourceVertexArray.unbind();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -33,46 +33,46 @@ namespace hex {
|
||||
|
||||
void writeRaw(u64 offset, const void *buffer, size_t size) override {
|
||||
for (u64 i = 0; i < size; i += 1)
|
||||
this->m_patches[offset] = static_cast<const u8*>(buffer)[i];
|
||||
m_patches[offset] = static_cast<const u8*>(buffer)[i];
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t getActualSize() const override {
|
||||
if (this->m_patches.empty())
|
||||
[[nodiscard]] u64 getActualSize() const override {
|
||||
if (m_patches.empty())
|
||||
return 0;
|
||||
else
|
||||
return this->m_patches.rbegin()->first;
|
||||
return m_patches.rbegin()->first;
|
||||
}
|
||||
|
||||
void resizeRaw(size_t newSize) override {
|
||||
void resizeRaw(u64 newSize) override {
|
||||
hex::unused(newSize);
|
||||
}
|
||||
|
||||
void insertRaw(u64 offset, size_t size) override {
|
||||
void insertRaw(u64 offset, u64 size) override {
|
||||
std::vector<std::pair<u64, u8>> patchesToMove;
|
||||
|
||||
for (auto &[address, value] : this->m_patches) {
|
||||
for (auto &[address, value] : m_patches) {
|
||||
if (address > offset)
|
||||
patchesToMove.emplace_back(address, value);
|
||||
}
|
||||
|
||||
for (const auto &[address, value] : patchesToMove)
|
||||
this->m_patches.erase(address);
|
||||
m_patches.erase(address);
|
||||
for (const auto &[address, value] : patchesToMove)
|
||||
this->m_patches.insert({ address + size, value });
|
||||
m_patches.insert({ address + size, value });
|
||||
}
|
||||
|
||||
void removeRaw(u64 offset, size_t size) override {
|
||||
void removeRaw(u64 offset, u64 size) override {
|
||||
std::vector<std::pair<u64, u8>> patchesToMove;
|
||||
|
||||
for (auto &[address, value] : this->m_patches) {
|
||||
for (auto &[address, value] : m_patches) {
|
||||
if (address > offset)
|
||||
patchesToMove.emplace_back(address, value);
|
||||
}
|
||||
|
||||
for (const auto &[address, value] : patchesToMove)
|
||||
this->m_patches.erase(address);
|
||||
m_patches.erase(address);
|
||||
for (const auto &[address, value] : patchesToMove)
|
||||
this->m_patches.insert({ address - size, value });
|
||||
m_patches.insert({ address - size, value });
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string getName() const override {
|
||||
@@ -82,7 +82,7 @@ namespace hex {
|
||||
[[nodiscard]] std::string getTypeName() const override { return ""; }
|
||||
|
||||
const std::map<u64, u8>& getPatches() const {
|
||||
return this->m_patches;
|
||||
return m_patches;
|
||||
}
|
||||
private:
|
||||
std::map<u64, u8> m_patches;
|
||||
@@ -111,7 +111,7 @@ namespace hex {
|
||||
std::vector<u64> addresses;
|
||||
std::vector<u8> values;
|
||||
|
||||
for (const auto &[address, value] : this->m_patches) {
|
||||
for (const auto &[address, value] : m_patches) {
|
||||
addresses.push_back(address);
|
||||
values.push_back(value);
|
||||
}
|
||||
@@ -161,7 +161,7 @@ namespace hex {
|
||||
std::vector<u64> addresses;
|
||||
std::vector<u8> values;
|
||||
|
||||
for (const auto &[address, value] : this->m_patches) {
|
||||
for (const auto &[address, value] : m_patches) {
|
||||
addresses.push_back(address);
|
||||
values.push_back(value);
|
||||
}
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
|
||||
#include <wolv/io/file.hpp>
|
||||
|
||||
#include <microtar.h>
|
||||
|
||||
namespace hex {
|
||||
|
||||
using namespace hex::literals;
|
||||
|
||||
Tar::Tar(const std::fs::path &path, Mode mode) {
|
||||
int tar_error = MTAR_ESUCCESS;
|
||||
int tarError = MTAR_ESUCCESS;
|
||||
|
||||
// Explicitly create file so a short path gets generated
|
||||
if (mode == Mode::Create) {
|
||||
@@ -18,24 +20,26 @@ namespace hex {
|
||||
file.flush();
|
||||
}
|
||||
|
||||
m_ctx = std::make_unique<mtar_t>();
|
||||
|
||||
auto shortPath = wolv::io::fs::toShortPath(path);
|
||||
if (mode == Tar::Mode::Read)
|
||||
tar_error = mtar_open(&this->m_ctx, shortPath.string().c_str(), "r");
|
||||
tarError = mtar_open(m_ctx.get(), shortPath.string().c_str(), "r");
|
||||
else if (mode == Tar::Mode::Write)
|
||||
tar_error = mtar_open(&this->m_ctx, shortPath.string().c_str(), "a");
|
||||
tarError = mtar_open(m_ctx.get(), shortPath.string().c_str(), "a");
|
||||
else if (mode == Tar::Mode::Create)
|
||||
tar_error = mtar_open(&this->m_ctx, shortPath.string().c_str(), "w");
|
||||
tarError = mtar_open(m_ctx.get(), shortPath.string().c_str(), "w");
|
||||
else
|
||||
tar_error = MTAR_EFAILURE;
|
||||
tarError = MTAR_EFAILURE;
|
||||
|
||||
this->m_path = path;
|
||||
this->m_valid = (tar_error == MTAR_ESUCCESS);
|
||||
m_path = path;
|
||||
m_valid = (tarError == MTAR_ESUCCESS);
|
||||
|
||||
if (!this->m_valid) {
|
||||
this->m_tarOpenErrno = tar_error;
|
||||
if (!m_valid) {
|
||||
m_tarOpenErrno = tarError;
|
||||
|
||||
// Hopefully this errno corresponds to the file open call in mtar_open
|
||||
this->m_fileOpenErrno = errno;
|
||||
m_fileOpenErrno = errno;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,48 +48,46 @@ namespace hex {
|
||||
}
|
||||
|
||||
Tar::Tar(hex::Tar &&other) noexcept {
|
||||
this->m_ctx = other.m_ctx;
|
||||
this->m_path = other.m_path;
|
||||
this->m_valid = other.m_valid;
|
||||
this->m_tarOpenErrno = other.m_tarOpenErrno;
|
||||
this->m_fileOpenErrno = other.m_fileOpenErrno;
|
||||
m_ctx = std::move(other.m_ctx);
|
||||
m_path = other.m_path;
|
||||
m_valid = other.m_valid;
|
||||
m_tarOpenErrno = other.m_tarOpenErrno;
|
||||
m_fileOpenErrno = other.m_fileOpenErrno;
|
||||
|
||||
other.m_ctx = { };
|
||||
other.m_valid = false;
|
||||
}
|
||||
|
||||
Tar &Tar::operator=(Tar &&other) noexcept {
|
||||
this->m_ctx = other.m_ctx;
|
||||
other.m_ctx = { };
|
||||
m_ctx = std::move(other.m_ctx);
|
||||
m_path = std::move(other.m_path);
|
||||
|
||||
this->m_path = other.m_path;
|
||||
|
||||
this->m_valid = other.m_valid;
|
||||
m_valid = other.m_valid;
|
||||
other.m_valid = false;
|
||||
|
||||
this->m_tarOpenErrno = other.m_tarOpenErrno;
|
||||
this->m_fileOpenErrno = other.m_fileOpenErrno;
|
||||
m_tarOpenErrno = other.m_tarOpenErrno;
|
||||
m_fileOpenErrno = other.m_fileOpenErrno;
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> Tar::listEntries(const std::fs::path &basePath) {
|
||||
std::vector<std::fs::path> Tar::listEntries(const std::fs::path &basePath) const {
|
||||
std::vector<std::fs::path> result;
|
||||
|
||||
const std::string PaxHeaderName = "@PaxHeader";
|
||||
mtar_header_t header;
|
||||
while (mtar_read_header(&this->m_ctx, &header) != MTAR_ENULLRECORD) {
|
||||
while (mtar_read_header(m_ctx.get(), &header) != MTAR_ENULLRECORD) {
|
||||
std::fs::path path = header.name;
|
||||
if (header.name != PaxHeaderName && wolv::io::fs::isSubPath(basePath, path)) {
|
||||
result.emplace_back(header.name);
|
||||
}
|
||||
|
||||
mtar_next(&this->m_ctx);
|
||||
mtar_next(m_ctx.get());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Tar::contains(const std::fs::path &path) {
|
||||
bool Tar::contains(const std::fs::path &path) const {
|
||||
mtar_header_t header;
|
||||
|
||||
auto fixedPath = path.string();
|
||||
@@ -93,49 +95,49 @@ namespace hex {
|
||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
||||
#endif
|
||||
|
||||
return mtar_find(&this->m_ctx, fixedPath.c_str(), &header) == MTAR_ESUCCESS;
|
||||
return mtar_find(m_ctx.get(), fixedPath.c_str(), &header) == MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
std::string Tar::getOpenErrorString() const {
|
||||
return hex::format("{}: {}", mtar_strerror(this->m_tarOpenErrno), std::strerror(this->m_fileOpenErrno));
|
||||
return hex::format("{}: {}", mtar_strerror(m_tarOpenErrno), std::strerror(m_fileOpenErrno));
|
||||
}
|
||||
|
||||
void Tar::close() {
|
||||
if (this->m_valid) {
|
||||
mtar_finalize(&this->m_ctx);
|
||||
mtar_close(&this->m_ctx);
|
||||
if (m_valid) {
|
||||
mtar_finalize(m_ctx.get());
|
||||
mtar_close(m_ctx.get());
|
||||
}
|
||||
|
||||
this->m_ctx = { };
|
||||
this->m_valid = false;
|
||||
m_ctx.reset();
|
||||
m_valid = false;
|
||||
}
|
||||
|
||||
std::vector<u8> Tar::readVector(const std::fs::path &path) {
|
||||
std::vector<u8> Tar::readVector(const std::fs::path &path) const {
|
||||
mtar_header_t header;
|
||||
|
||||
auto fixedPath = path.string();
|
||||
#if defined(OS_WINDOWS)
|
||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
||||
#endif
|
||||
int ret = mtar_find(&this->m_ctx, fixedPath.c_str(), &header);
|
||||
int ret = mtar_find(m_ctx.get(), fixedPath.c_str(), &header);
|
||||
if (ret != MTAR_ESUCCESS){
|
||||
log::debug("Failed to read vector from path {} in tarred file {}: {}",
|
||||
path.string(), this->m_path.string(), mtar_strerror(ret));
|
||||
path.string(), m_path.string(), mtar_strerror(ret));
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<u8> result(header.size, 0x00);
|
||||
mtar_read_data(&this->m_ctx, result.data(), result.size());
|
||||
mtar_read_data(m_ctx.get(), result.data(), result.size());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Tar::readString(const std::fs::path &path) {
|
||||
std::string Tar::readString(const std::fs::path &path) const {
|
||||
auto result = this->readVector(path);
|
||||
return { result.begin(), result.end() };
|
||||
}
|
||||
|
||||
void Tar::writeVector(const std::fs::path &path, const std::vector<u8> &data) {
|
||||
void Tar::writeVector(const std::fs::path &path, const std::vector<u8> &data) const {
|
||||
if (path.has_parent_path()) {
|
||||
std::fs::path pathPart;
|
||||
for (const auto &part : path.parent_path()) {
|
||||
@@ -145,7 +147,7 @@ namespace hex {
|
||||
#if defined(OS_WINDOWS)
|
||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
||||
#endif
|
||||
mtar_write_dir_header(&this->m_ctx, fixedPath.c_str());
|
||||
mtar_write_dir_header(m_ctx.get(), fixedPath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,11 +155,11 @@ namespace hex {
|
||||
#if defined(OS_WINDOWS)
|
||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
||||
#endif
|
||||
mtar_write_file_header(&this->m_ctx, fixedPath.c_str(), data.size());
|
||||
mtar_write_data(&this->m_ctx, data.data(), data.size());
|
||||
mtar_write_file_header(m_ctx.get(), fixedPath.c_str(), data.size());
|
||||
mtar_write_data(m_ctx.get(), data.data(), data.size());
|
||||
}
|
||||
|
||||
void Tar::writeString(const std::fs::path &path, const std::string &data) {
|
||||
void Tar::writeString(const std::fs::path &path, const std::string &data) const {
|
||||
this->writeVector(path, { data.begin(), data.end() });
|
||||
}
|
||||
|
||||
@@ -175,26 +177,26 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
void Tar::extract(const std::fs::path &path, const std::fs::path &outputPath) {
|
||||
void Tar::extract(const std::fs::path &path, const std::fs::path &outputPath) const {
|
||||
mtar_header_t header;
|
||||
mtar_find(&this->m_ctx, path.string().c_str(), &header);
|
||||
mtar_find(m_ctx.get(), path.string().c_str(), &header);
|
||||
|
||||
writeFile(&this->m_ctx, &header, outputPath);
|
||||
writeFile(m_ctx.get(), &header, outputPath);
|
||||
}
|
||||
|
||||
void Tar::extractAll(const std::fs::path &outputPath) {
|
||||
void Tar::extractAll(const std::fs::path &outputPath) const {
|
||||
mtar_header_t header;
|
||||
while (mtar_read_header(&this->m_ctx, &header) != MTAR_ENULLRECORD) {
|
||||
while (mtar_read_header(m_ctx.get(), &header) != MTAR_ENULLRECORD) {
|
||||
const auto filePath = std::fs::absolute(outputPath / std::fs::path(header.name));
|
||||
|
||||
if (filePath.filename() != "@PaxHeader") {
|
||||
|
||||
std::fs::create_directories(filePath.parent_path());
|
||||
|
||||
writeFile(&this->m_ctx, &header, filePath);
|
||||
writeFile(m_ctx.get(), &header, filePath);
|
||||
}
|
||||
|
||||
mtar_next(&this->m_ctx);
|
||||
mtar_next(m_ctx.get());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user