mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-31 05:15:55 -05:00
Compare commits
207 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fd7beb642f | ||
|
|
b766cf0807 | ||
|
|
6c9469961b | ||
|
|
d8844236d0 | ||
|
|
60eb59c605 | ||
|
|
6a7bbb8752 | ||
|
|
e4431749e1 | ||
|
|
c587b357eb | ||
|
|
7357c26d54 | ||
|
|
73ca45ad3d | ||
|
|
bf00503d1f | ||
|
|
44a90f5c7d | ||
|
|
5c3ee9f499 | ||
|
|
03f357efd1 | ||
|
|
5462575f5c | ||
|
|
120e2bc300 | ||
|
|
c3137df83c | ||
|
|
737155a226 | ||
|
|
66d64cf020 | ||
|
|
42f5c0f484 | ||
|
|
75047e26e2 | ||
|
|
9fa6d82775 | ||
|
|
d1468984e7 | ||
|
|
20a2331504 | ||
|
|
5b00c8ee08 | ||
|
|
bda4aadc54 | ||
|
|
9d7e2eccac | ||
|
|
8c219b981c | ||
|
|
7d87c8bb98 | ||
|
|
13afd96806 | ||
|
|
4fb74a1769 | ||
|
|
aa658b7dbc | ||
|
|
7e3601989a | ||
|
|
3a1c0f8d66 | ||
|
|
91160b4311 | ||
|
|
83f4093796 | ||
|
|
f219395b25 | ||
|
|
ae6a7ad8e5 | ||
|
|
d990ee102a | ||
|
|
cfde9939b4 | ||
|
|
a22725bb67 | ||
|
|
7a4040f6ec | ||
|
|
2fbb351314 | ||
|
|
96e85c0685 | ||
|
|
50577c9ea0 | ||
|
|
073323b517 | ||
|
|
37cc8f3aae | ||
|
|
6367152650 | ||
|
|
ffbaef3872 | ||
|
|
a0b2473bf4 | ||
|
|
95a3104a56 | ||
|
|
2d5f77730b | ||
|
|
033a0dfbb9 | ||
|
|
cb682b6e21 | ||
|
|
7312908d4d | ||
|
|
b44f6035b3 | ||
|
|
b6bc8abf83 | ||
|
|
c60c1154b9 | ||
|
|
219afb6244 | ||
|
|
22b6bdb5cf | ||
|
|
d9a47fe815 | ||
|
|
45e987b413 | ||
|
|
a920696d03 | ||
|
|
f72b153fe0 | ||
|
|
d240b4ed49 | ||
|
|
1a21627cdb | ||
|
|
0a115a3c03 | ||
|
|
7ef11f566b | ||
|
|
7f6aa9f9a6 | ||
|
|
4df1496a0f | ||
|
|
b68eb0bb5e | ||
|
|
7c0fb7c4f2 | ||
|
|
ede8048680 | ||
|
|
b10ba8fea0 | ||
|
|
3eb2cca286 | ||
|
|
721ac837e0 | ||
|
|
f6fef35d3d | ||
|
|
0569770239 | ||
|
|
6689b8ebfa | ||
|
|
3cb6c4f775 | ||
|
|
b687eb88f9 | ||
|
|
33a375910a | ||
|
|
a620400e4e | ||
|
|
cc7dc3597b | ||
|
|
60b5842e94 | ||
|
|
2b9c6ec447 | ||
|
|
742a4e53b5 | ||
|
|
0cd10b6b70 | ||
|
|
aabf718e60 | ||
|
|
03116c4ab8 | ||
|
|
38162c0129 | ||
|
|
f62edea450 | ||
|
|
940f1e30c5 | ||
|
|
af32d68c3f | ||
|
|
eb874ac810 | ||
|
|
a79bf4c3ec | ||
|
|
90adacab9f | ||
|
|
e86ca29b8c | ||
|
|
4f1f9a718c | ||
|
|
cc09014e6e | ||
|
|
de98b40c93 | ||
|
|
a6eaa34f6d | ||
|
|
dacb64ae66 | ||
|
|
c0a5e2012f | ||
|
|
389e53a8a0 | ||
|
|
928fbe235a | ||
|
|
7d85a8b6fc | ||
|
|
d004962e3a | ||
|
|
1462a4689d | ||
|
|
93be4c8ed1 | ||
|
|
536c6df438 | ||
|
|
f8a089a61f | ||
|
|
491ee6aa2f | ||
|
|
6a88c7cbaa | ||
|
|
be82ee15b7 | ||
|
|
1ddd3ea2b9 | ||
|
|
a56a8c1d6c | ||
|
|
9c4e314bb6 | ||
|
|
ea26722a18 | ||
|
|
5aee359700 | ||
|
|
5d11fc960e | ||
|
|
707fec0e2a | ||
|
|
55b877d5e0 | ||
|
|
e779285be4 | ||
|
|
cf6ae52889 | ||
|
|
caad705975 | ||
|
|
0c3fc6f858 | ||
|
|
0529155faa | ||
|
|
aa01d58b33 | ||
|
|
0c0caf6942 | ||
|
|
7e01ff451f | ||
|
|
e0e4b0a5a9 | ||
|
|
0e2c1f1355 | ||
|
|
0ed7341f71 | ||
|
|
29e970fd81 | ||
|
|
43ab72dcb8 | ||
|
|
07dc77f13d | ||
|
|
9b2ee998de | ||
|
|
e1c5cd1e86 | ||
|
|
0d0301f4f6 | ||
|
|
29adeae6a3 | ||
|
|
6b62a1963e | ||
|
|
fb2af5593f | ||
|
|
e938b75acd | ||
|
|
03daf0c95b | ||
|
|
189ea1c3c7 | ||
|
|
8448c3367b | ||
|
|
cc29707bb1 | ||
|
|
eff9ecf7cd | ||
|
|
21b22e7667 | ||
|
|
7d5b17d5c9 | ||
|
|
49d47a0eed | ||
|
|
78785ddc3c | ||
|
|
dea6caccf1 | ||
|
|
b917bfca07 | ||
|
|
85f0e04d0e | ||
|
|
440ba3823e | ||
|
|
b580691871 | ||
|
|
72c4f50871 | ||
|
|
7bc2c4a0d4 | ||
|
|
128551e193 | ||
|
|
72f7c72094 | ||
|
|
568b7f5139 | ||
|
|
164cb1285b | ||
|
|
e16be09f9a | ||
|
|
d55c59c796 | ||
|
|
5c13cf9dbf | ||
|
|
19a0dc80db | ||
|
|
683018a9d2 | ||
|
|
4c331341e5 | ||
|
|
ceb26add15 | ||
|
|
4b720ee3a2 | ||
|
|
d4af07ed51 | ||
|
|
a3132b7d13 | ||
|
|
0192c791ce | ||
|
|
f1ec2ef0c4 | ||
|
|
b1e93fda4b | ||
|
|
f349aafc37 | ||
|
|
8ebbe6fb4e | ||
|
|
e38b6ecd2c | ||
|
|
966f3b8597 | ||
|
|
f0756bceb8 | ||
|
|
423e23e3c0 | ||
|
|
2c740cab06 | ||
|
|
519a9edb60 | ||
|
|
e16216b39e | ||
|
|
f221d0f430 | ||
|
|
1aa497cb7b | ||
|
|
738a537723 | ||
|
|
d8d3a315a4 | ||
|
|
f62ca307b0 | ||
|
|
edfac4ef60 | ||
|
|
916962cf83 | ||
|
|
189766ceb4 | ||
|
|
2200e11e85 | ||
|
|
69d000488e | ||
|
|
88f8bb9848 | ||
|
|
4f37345324 | ||
|
|
31fcf86008 | ||
|
|
7d93c54444 | ||
|
|
b2b753c2b3 | ||
|
|
a97f853110 | ||
|
|
3dc5f0e2be | ||
|
|
d7accb6916 | ||
|
|
9c01f3efe3 | ||
|
|
49cc85dd3b | ||
|
|
974b9c77e0 |
149
.github/workflows/build.yml
vendored
149
.github/workflows/build.yml
vendored
@@ -99,14 +99,7 @@ jobs:
|
||||
..
|
||||
mingw32-make -j4 install
|
||||
cpack
|
||||
touch $PWD/install/PORTABLE
|
||||
|
||||
- name: ⬆️ Upload Portable ZIP
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Portable
|
||||
path: |
|
||||
build/install/*
|
||||
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
|
||||
@@ -115,23 +108,59 @@ jobs:
|
||||
path: |
|
||||
build/*.msi
|
||||
|
||||
- name: ⬆️ Upload Portable ZIP
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Portable
|
||||
path: |
|
||||
build/install/*
|
||||
|
||||
- name: ⬇️ Download Mesa3D for NoGPU version
|
||||
shell: bash
|
||||
run: |
|
||||
echo "NoGPU version Powered by Mesa 3D : https://fdossena.com/?p=mesa%2Findex.frag" > build/install/MESA.md
|
||||
curl https://downloads.fdossena.com/geth.php?r=mesa64-latest -L -o mesa.7z
|
||||
7z e mesa.7z
|
||||
mv opengl32.dll build/install
|
||||
|
||||
|
||||
- name: ⬆️ Upload NoGPU Portable ZIP
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Windows Portable NoGPU
|
||||
path: |
|
||||
build/install/*
|
||||
|
||||
# MacOS build
|
||||
macos:
|
||||
runs-on: macos-11
|
||||
name: 🍎 macOS 11.0
|
||||
steps:
|
||||
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- suffix: "-NoGPU"
|
||||
custom_glfw: true
|
||||
- suffix: ""
|
||||
custom_glfw: false
|
||||
|
||||
name: 🍎 macOS 11.0${{matrix.suffix}}
|
||||
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
- name: 📜 Restore ccache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/Library/Caches/ccache
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
key: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build
|
||||
|
||||
|
||||
@@ -140,12 +169,43 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
key: ${{ runner.os }}-${{ matrix.suffix }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
brew bundle --no-lock --file dist/Brewfile
|
||||
|
||||
- name: ⬇️ Install classic glfw
|
||||
if: ${{! matrix.custom_glfw}}
|
||||
run: |
|
||||
brew install glfw
|
||||
|
||||
|
||||
- name: 🧰 Checkout glfw
|
||||
if: ${{matrix.custom_glfw}}
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
repository: glfw/glfw
|
||||
path: glfw
|
||||
|
||||
- name: ⬇️ Patch and install custom glfw
|
||||
if: ${{matrix.custom_glfw}}
|
||||
run: |
|
||||
cd glfw
|
||||
git apply ../dist/macOS/0001-glfw-SW.patch
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
|
||||
cmake \
|
||||
-DBUILD_SHARED_LIBS=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
..
|
||||
make -j 4 install
|
||||
|
||||
# MacOS cmake build
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
@@ -167,13 +227,14 @@ jobs:
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DCMAKE_OSX_DEPLOYMENT_TARGET="10.10" \
|
||||
-DCPACK_PACKAGE_FILE_NAME="imhex-${{env.IMHEX_VERSION}}-macOS${{matrix.suffix}}" \
|
||||
..
|
||||
make -j4 package
|
||||
|
||||
- name: ⬆️ Upload DMG
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: macOS DMG
|
||||
name: macOS DMG${{matrix.suffix}}
|
||||
path: build/*.dmg
|
||||
|
||||
# Ubuntu build
|
||||
@@ -187,7 +248,7 @@ jobs:
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: 📜 Restore cache
|
||||
- name: 📜 Restore ccache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
@@ -200,6 +261,7 @@ jobs:
|
||||
with:
|
||||
path: |
|
||||
build/CMakeCache.txt
|
||||
build-appimage/CMakeCache.txt
|
||||
.flatpak-builder
|
||||
key: ${{ runner.os }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
@@ -225,13 +287,14 @@ jobs:
|
||||
$HOME/.cargo/bin/rustup target add x86_64-unknown-linux-gnu
|
||||
$HOME/.cargo/bin/rustup default nightly
|
||||
|
||||
# Ubuntu cmake build
|
||||
- name: 🛠️ Build
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
@@ -239,7 +302,7 @@ jobs:
|
||||
-DRUST_PATH="$HOME/.cargo/bin/" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
..
|
||||
make -j 4 install DESTDIR=AppDir
|
||||
make -j 4 install DESTDIR=DebDir
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
@@ -256,29 +319,34 @@ jobs:
|
||||
|
||||
- name: 📦 Bundle DEB
|
||||
run: |
|
||||
cp -r build/DEBIAN build/AppDir
|
||||
dpkg-deb --build build/AppDir
|
||||
mv build/AppDir.deb imhex-${{env.IMHEX_VERSION}}.deb
|
||||
rm -rf build/AppDir/DEBIAN
|
||||
cp -r build/DEBIAN build/DebDir
|
||||
dpkg-deb -Zgzip --build build/DebDir
|
||||
mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-22.04.deb
|
||||
|
||||
# AppImage cmake build
|
||||
- name: 🛠️ Reconfigure build for AppImage
|
||||
run: |
|
||||
# Reconfigure CMake to include a flag needed for AppImage
|
||||
# Other flags are kept from old configuration
|
||||
|
||||
cd build
|
||||
cmake \
|
||||
-DIMHEX_PLUGINS_IN_SHARE=ON \
|
||||
..
|
||||
|
||||
rm -rf AppDir
|
||||
mkdir -p build-appimage
|
||||
cd build-appimage
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="/usr" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DRUST_PATH="$HOME/.cargo/bin/" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
-DIMHEX_PLUGINS_IN_SHARE=ON \
|
||||
-DIMHEX_USE_BUNDLED_CA=ON \
|
||||
..
|
||||
make -j 4 install DESTDIR=AppDir
|
||||
|
||||
- name: 📦 Bundle AppImage
|
||||
run: |
|
||||
cd build
|
||||
cd build-appimage
|
||||
export VERSION=${{env.IMHEX_VERSION}}
|
||||
appimage-builder --recipe ../dist/AppImageBuilder.yml
|
||||
mv ImHex-AppImage-x86_64.AppImage ../imhex-${{env.IMHEX_VERSION}}.AppImage
|
||||
cd ..
|
||||
|
||||
#- name: ⬆️ Upload Flatpak
|
||||
@@ -291,14 +359,20 @@ jobs:
|
||||
- name: ⬆️ Upload DEB
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Linux DEB (Ubuntu 22.04)
|
||||
name: Ubuntu 22.04 DEB
|
||||
path: '*.deb'
|
||||
|
||||
- name: ⬆️ Upload AppImage
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Linux AppImage
|
||||
path: '*.AppImage'
|
||||
path: 'build-appimage/*.AppImage'
|
||||
|
||||
- name: ⬆️ Upload AppImage zsync
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Linux AppImage zsync
|
||||
path: 'build-appimage/*.AppImage.zsync'
|
||||
|
||||
# ArchLinux build
|
||||
archlinux-build:
|
||||
@@ -448,14 +522,7 @@ jobs:
|
||||
~/.cache/ccache
|
||||
key: fedora-${{ matrix.release }}-${{ secrets.CACHE_VERSION }}-build-${{ github.run_id }}
|
||||
restore-keys: fedora-${{ matrix.release }}-${{ secrets.CACHE_VERSION }}-build
|
||||
|
||||
- name: 📜 Restore CMakeCache
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/rpmbuild/BUILDROOT/CMakeCache.txt
|
||||
key: fedora-${{ matrix.release }}-${{ secrets.CACHE_VERSION }}-build-${{ hashFiles('**/CMakeLists.txt') }}
|
||||
|
||||
|
||||
- name: 📜 Set version variable
|
||||
run: |
|
||||
echo "IMHEX_VERSION=`cat VERSION`" >> $GITHUB_ENV
|
||||
|
||||
45
.github/workflows/release.yml
vendored
45
.github/workflows/release.yml
vendored
@@ -6,11 +6,12 @@ name: Release
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
release:
|
||||
release-common:
|
||||
runs-on: ubuntu-latest
|
||||
name: Release
|
||||
name: Release Common
|
||||
|
||||
steps:
|
||||
- name: 🧰 Checkout
|
||||
@@ -57,8 +58,10 @@ jobs:
|
||||
fi
|
||||
done
|
||||
|
||||
- name: 🟩 Rename Windows Portable Zip
|
||||
run: mv "Windows Portable.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable.zip
|
||||
- name: 🟩 Rename artifacts when needed
|
||||
run: |
|
||||
mv "Windows Portable.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable.zip
|
||||
mv "Windows Portable NoGPU.zip" imhex-${{env.IMHEX_VERSION}}-Windows-Portable-NoGPU.zip
|
||||
|
||||
- name: ⬆️ Upload everything to release
|
||||
uses: softprops/action-gh-release@v1
|
||||
@@ -110,3 +113,37 @@ jobs:
|
||||
tag: ImHex-v${{env.IMHEX_VERSION}}
|
||||
repo: ImHex-Patterns
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
- name: ✉️ Update C++ Plugin Template
|
||||
uses: mvasigh/dispatch-action@main
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
repo: ImHex-Cpp-Plugin-Template
|
||||
owner: WerWolv
|
||||
event_type: update_submodule
|
||||
|
||||
release-windows:
|
||||
name: Release Windows
|
||||
needs: release-common
|
||||
runs-on: windows-2022
|
||||
steps:
|
||||
- name: ⬇️ Download dependencies
|
||||
shell: pwsh
|
||||
run: |
|
||||
iwr https://github.com/microsoft/winget-create/releases/download/v1.1.2.0/wingetcreate.exe -OutFile wingetcreate.exe
|
||||
- name: ⬆️ Update winget manifest
|
||||
shell: pwsh
|
||||
env:
|
||||
WINGET_GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.WINGET_GITHUB_TOKEN != '' }}"
|
||||
run: |
|
||||
$tagname = $env:GITHUB_REF.Replace("refs/tags/", "")
|
||||
$version = $tagname.Replace("v", "")
|
||||
$url = "https://github.com/WerWolv/ImHex/releases/download/${tagname}/imhex-${version}-win64.msi"
|
||||
.\wingetcreate.exe update WerWolv.ImHex -u $url --version $version
|
||||
if ($version -notmatch "-") {
|
||||
.\wingetcreate.exe submit .\manifests\w\WerWolv\ImHex\${version}\ --token $env:WINGET_GITHUB_TOKEN
|
||||
}
|
||||
|
||||
18
.github/workflows/tests.yml
vendored
18
.github/workflows/tests.yml
vendored
@@ -47,18 +47,18 @@ jobs:
|
||||
run: |
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DIMHEX_PATTERNS_PULL_MASTER=ON \
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DCMAKE_INSTALL_PREFIX="$PWD/install" \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_C_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld -fsanitize=address,leak,undefined -fno-sanitize-recover=all" \
|
||||
-DIMHEX_OFFLINE_BUILD=ON \
|
||||
..
|
||||
make -j4 unit_tests install
|
||||
|
||||
- name: 🧪 Perform Unit Tests
|
||||
run: |
|
||||
cd build
|
||||
ctest
|
||||
ctest --output-on-failure
|
||||
|
||||
1
.idea/vcs.xml
generated
1
.idea/vcs.xml
generated
@@ -8,6 +8,7 @@
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/libromfs" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/nativefiledialog" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language/external/cli11" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language/external/fmt" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/xdgpp" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/yara/yara" vcs="Git" />
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
# Options
|
||||
option(IMHEX_USE_BUNDLED_CA "Use the CA bundle in romfs instead of the system one" OFF)
|
||||
option(IMHEX_PLUGINS_IN_SHARE "Put the plugins in share/imhex/plugins instead of lib[..]/imhex/plugins" OFF)
|
||||
option(IMHEX_STRIP_RELEASE "Strip the release builds" ON)
|
||||
option(IMHEX_OFFLINE_BUILD "Enable offline build" OFF)
|
||||
option(IMHEX_IGNORE_BAD_CLONE "Disabled the bad clone prevention checks" OFF)
|
||||
option(IMHEX_IGNORE_BAD_CLONE "Disable the bad clone prevention checks" OFF)
|
||||
option(IMHEX_PATTERNS_PULL_MASTER "Download latest files from master branch of the ImHex-Patterns repo" OFF)
|
||||
option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler" OFF)
|
||||
|
||||
|
||||
52
INSTALL.md
Normal file
52
INSTALL.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Installing ImHex
|
||||
|
||||
## Official Releases
|
||||
|
||||
The easiest way to install ImHex is to download the latest release from the [GitHub releases page](github.com/WerWolv/ImHex/releases/latest).
|
||||
|
||||
There's also a NoGPU version available for users who don't have a GPU or want to run ImHex in a VM without GPU passthrough.
|
||||
|
||||
## Nighly Builds
|
||||
|
||||
The GitHub Actions CI builds a new release package on every commit made to repository. These builds are available on the [GitHub Actions page](https://github.com/WerWolv/ImHex/actions?query=workflow%3A%22Build%22).
|
||||
These builds are not guaranteed to be stable and may contain bugs, however they also contain new features that are not yet available in the official releases.
|
||||
|
||||
## Building from source
|
||||
|
||||
Build instructions for Windows, Linux and macOS can be found under `/dist/compiling`:
|
||||
- Windows: [Link](dist/compiling/windows.md)
|
||||
- macOS: [Link](dist/compiling/macos.md)
|
||||
- Linux: [Link](dist/compiling/linux.md)
|
||||
|
||||
## Package managers
|
||||
|
||||
ImHex is also available on various package managers. The officially supported ones are listed here:
|
||||
|
||||
### Windows
|
||||
|
||||
- **Cocolatey**
|
||||
- [imhex](https://community.chocolatey.org/packages/imhex) (Thanks to @Jarcho)
|
||||
- `choco install imhex`
|
||||
- **winget**
|
||||
- [WerWolv.ImHex](https://github.com/microsoft/winget-pkgs/tree/master/manifests/w/WerWolv/ImHex)
|
||||
- `winget install WerWolv.ImHex`
|
||||
|
||||
### Linux
|
||||
- **Arch Linux AUR**
|
||||
- [imhex-bin](https://aur.archlinux.org/packages/imhex-bin/) (Thanks to @iTrooz)
|
||||
- `yay -S imhex-bin`
|
||||
- [imhex](https://aur.archlinux.org/packages/imhex/) (Thanks to @KokaKiwi)
|
||||
- `yay -S imhex`
|
||||
- **Fedora**
|
||||
- [imhex](https://src.fedoraproject.org/rpms/imhex/) (Thanks to @jonathanspw)
|
||||
- `dnf install imhex`
|
||||
- **Flatpak**
|
||||
- [net.werwolv.Imhex](https://flathub.org/apps/details/net.werwolv.ImHex) (Thanks to @Mailaender)
|
||||
- `flatpak install flathub net.werwolv.ImHex`
|
||||
|
||||
### Available on other package managers
|
||||
|
||||
Packages that aren't explicitly mentioned above are not officially supported but they will most likely still work.
|
||||
Contact the maintainer of the package if you have any issues.
|
||||
|
||||
[](https://repology.org/project/imhex/versions)
|
||||
55
README.md
55
README.md
@@ -1,4 +1,4 @@
|
||||
<a href="https://imhex.werwolv.net"><h1 align="center" >:mag: ImHex</h1></a>
|
||||
<a href="https://imhex.werwolv.net"><h1 align="center" ><img height="100px" src="resources/projects/logo_text.svg"></h1></a>
|
||||
|
||||
<p align="center">A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</p>
|
||||
|
||||
@@ -104,7 +104,11 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
|
||||
## Pattern Language
|
||||
|
||||
The custom C-like Pattern Language developed and used by ImHex is easy to read, understand and learn. A guide with all features of the language can be found [on the docs page](http://imhex.werwolv.net/docs).
|
||||
The Pattern Language is the completely custom programming language developed for ImHex.
|
||||
It allows you to define structures and data types in a C-like syntax and then use them to parse and highlight a file's content.
|
||||
|
||||
- Source Code: [Link](https://github.com/WerWolv/PatternLanguage/)
|
||||
- Documentation: [Link](https://imhex.werwolv.net/docs/)
|
||||
|
||||
## Database
|
||||
|
||||
@@ -116,12 +120,27 @@ For format patterns, libraries, magic and constant files, check out the [ImHex-P
|
||||
|
||||
To use ImHex, the following minimal system requirements need to be met:
|
||||
|
||||
- **OS**: Windows 10 or higher, macOS 11 (Big Sur) or higher, "Modern" Linux (Ubuntu 22.04+, Fedora and Arch Linux are officially supported)
|
||||
- **OS**: Windows 7 or higher, macOS 10.15 (Catalina) or higher, "Modern" Linux (Ubuntu 22.04, Fedora Stable/Rawhide, and Arch Linux have official packages, other distributions can use the AppImage)
|
||||
- **CPU**: x86_64 (64 Bit)
|
||||
- **GPU**: OpenGL 3.0 or higher (preferable a dedicated GPU and not Intel HD Graphics)
|
||||
- **RAM**: 512MB, more may be required for more complicated analysis
|
||||
- **Storage**: 100MB
|
||||
|
||||
## Installing
|
||||
|
||||
Information on how to install ImHex can be found in the [Install](/INSTALL.md) guide
|
||||
|
||||
## Compiling
|
||||
|
||||
To compile ImHex on any platform, GCC (or Clang) is required with a version that supports C++23 or higher.
|
||||
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.
|
||||
|
||||
For more information, check out the [Compiling](/dist/compiling) guide.
|
||||
|
||||
## Plugin development
|
||||
|
||||
To develop plugins for ImHex, use one of the following two templates projects to get started. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
|
||||
@@ -129,36 +148,6 @@ To develop plugins for ImHex, use one of the following two templates projects to
|
||||
- [Rust Plugin Template](https://github.com/WerWolv/ImHex-Rust-Plugin-Template)
|
||||
|
||||
|
||||
## Nightly builds
|
||||
|
||||
Nightlies are available via GitHub Actions [here](https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild).
|
||||
|
||||
- Windows • __x86_64__
|
||||
- [Installer](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Installer.zip)
|
||||
- [Portable](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Portable.zip)
|
||||
- MacOS • __x86_64__
|
||||
- [DMG](https://nightly.link/WerWolv/ImHex/workflows/build/master/macOS%20DMG.zip)
|
||||
- Linux • __x86_64__
|
||||
- [Ubuntu DEB](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20DEB%20%28Ubuntu%2022.04%29.zip)
|
||||
- [AppImage](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20AppImage.zip)
|
||||
- [Arch Package](https://nightly.link/WerWolv/ImHex/workflows/build/master/ArchLinux%20.pkg.tar.zst.zip)
|
||||
- [Fedora Rawhide RPM](https://nightly.link/WerWolv/ImHex/workflows/build/master/Fedora%20Rawhide%20RPM.zip)
|
||||
- [Fedora Stable RPM](https://nightly.link/WerWolv/ImHex/workflows/build/master/Fedora%20Latest%20RPM.zip)
|
||||
|
||||
## Third party repositories
|
||||
|
||||
ImHex is available in various third party repositories.
|
||||
|
||||
[](https://repology.org/project/imhex/versions)
|
||||
|
||||
## Compiling
|
||||
|
||||
To compile ImHex on any platform, GCC is required with a version that supports C++23 or higher.
|
||||
On macOS, Clang is also required to compile some ObjC code.
|
||||
|
||||
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.
|
||||
|
||||
## Credits
|
||||
|
||||
### Contributors
|
||||
|
||||
@@ -36,15 +36,16 @@ macro(addVersionDefines)
|
||||
|
||||
set(CMAKE_RC_FLAGS "${CMAKE_RC_FLAGS} -DPROJECT_VERSION_MAJOR=${PROJECT_VERSION_MAJOR} -DPROJECT_VERSION_MINOR=${PROJECT_VERSION_MINOR} -DPROJECT_VERSION_PATCH=${PROJECT_VERSION_PATCH} ")
|
||||
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION})
|
||||
if (CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION})
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING})
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "Debug")
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION}-Debug)
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-Debug)
|
||||
add_compile_definitions(DEBUG)
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "RelWithDebInfo")
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION}-RelWithDebInfo)
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-RelWithDebInfo)
|
||||
elseif (CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION}-MinSizeRel)
|
||||
set(IMHEX_VERSION_STRING ${IMHEX_VERSION_STRING}-MinSizeRel)
|
||||
endif ()
|
||||
|
||||
add_compile_definitions(IMHEX_VERSION="${IMHEX_VERSION_STRING}")
|
||||
@@ -83,6 +84,8 @@ macro(detectOS)
|
||||
set(CMAKE_INSTALL_BINDIR ".")
|
||||
set(CMAKE_INSTALL_LIBDIR ".")
|
||||
set(PLUGINS_INSTALL_LOCATION "plugins")
|
||||
|
||||
SET(IMHEX_USE_BUNDLED_CA ON)
|
||||
elseif (APPLE)
|
||||
add_compile_definitions(OS_MACOS)
|
||||
set(CMAKE_INSTALL_BINDIR ".")
|
||||
@@ -101,10 +104,15 @@ macro(detectOS)
|
||||
# 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
|
||||
endif()
|
||||
|
||||
|
||||
else ()
|
||||
message(FATAL_ERROR "Unknown / unsupported system!")
|
||||
endif()
|
||||
|
||||
if(IMHEX_USE_BUNDLED_CA)
|
||||
add_compile_definitions(IMHEX_USE_BUNDLED_CA)
|
||||
endif()
|
||||
|
||||
endmacro()
|
||||
|
||||
# Detect 32 vs. 64 bit system
|
||||
@@ -132,18 +140,21 @@ macro(configurePackingResources)
|
||||
|
||||
if (CREATE_PACKAGE)
|
||||
set(CPACK_GENERATOR "WIX")
|
||||
set(CPACK_PACKAGE_NAME "ImHex")
|
||||
set(CPACK_PACKAGE_NAME "imhex")
|
||||
set(CPACK_PACKAGE_VENDOR "WerWolv")
|
||||
set(CPACK_WIX_UPGRADE_GUID "05000E99-9659-42FD-A1CF-05C554B39285")
|
||||
set(CPACK_WIX_PRODUCT_ICON "${PROJECT_SOURCE_DIR}/resources/icon.ico")
|
||||
set(CPACK_WIX_PRODUCT_ICON "${PROJECT_SOURCE_DIR}/resources/dist/windows/icon.ico")
|
||||
set(CPACK_WIX_UI_BANNER "${PROJECT_SOURCE_DIR}/resources/dist/windows/wix_banner.png")
|
||||
set(CPACK_WIX_UI_DIALOG "${PROJECT_SOURCE_DIR}/resources/dist/windows/wix_dialog.png")
|
||||
set(CPACK_WIX_CULTURES "en-US;de-DE;ja-JP;it-IT;pt-BR;zh-CN;zh-TW")
|
||||
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/LICENSE.rtf")
|
||||
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/resources/dist/windows/LICENSE.rtf")
|
||||
endif()
|
||||
elseif (APPLE)
|
||||
set (IMHEX_ICON "${IMHEX_BASE_FOLDER}/resources/AppIcon.icns")
|
||||
set (IMHEX_ICON "${IMHEX_BASE_FOLDER}/resources/dist/macos/AppIcon.icns")
|
||||
|
||||
if (CREATE_BUNDLE)
|
||||
set(APPLICATION_TYPE MACOSX_BUNDLE)
|
||||
@@ -151,21 +162,26 @@ macro(configurePackingResources)
|
||||
set(MACOSX_BUNDLE_ICON_FILE "AppIcon.icns")
|
||||
set(MACOSX_BUNDLE_INFO_STRING "WerWolv")
|
||||
set(MACOSX_BUNDLE_BUNDLE_NAME "ImHex")
|
||||
set(MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/resources/dist/macos/Info.plist.in")
|
||||
set(MACOSX_BUNDLE_BUNDLE_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
|
||||
set(MACOSX_BUNDLE_GUI_IDENTIFIER "net.WerWolv.ImHex")
|
||||
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_VERSION}-${GIT_COMMIT_HASH}")
|
||||
set(MACOSX_BUNDLE_SHORT_VERSION_STRING "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}")
|
||||
set(MACOSX_BUNDLE_COPYRIGHT "Copyright © 2020 WerWolv and Thog. All rights reserved." )
|
||||
|
||||
string(TIMESTAMP CURR_YEAR "%Y")
|
||||
set(MACOSX_BUNDLE_COPYRIGHT "Copyright © 2020 - ${CURR_YEAR} WerWolv. All rights reserved." )
|
||||
if ("${CMAKE_GENERATOR}" STREQUAL "Xcode")
|
||||
set ( bundle_path "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/ImHex.app" )
|
||||
set (IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/${CMAKE_BUILD_TYPE}/ImHex.app")
|
||||
else ()
|
||||
set ( bundle_path "${CMAKE_BINARY_DIR}/ImHex.app" )
|
||||
set (IMHEX_BUNDLE_PATH "${CMAKE_BINARY_DIR}/ImHex.app")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(createPackage)
|
||||
set(LIBRARY_PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE GROUP_READ GROUP_EXECUTE WORLD_READ WORLD_EXECUTE)
|
||||
|
||||
file(MAKE_DIRECTORY "plugins")
|
||||
foreach (plugin IN LISTS PLUGINS)
|
||||
add_subdirectory("plugins/${plugin}")
|
||||
@@ -180,7 +196,7 @@ macro(createPackage)
|
||||
|
||||
get_target_property(PLUGIN_LOCATION ${plugin} LOCATION)
|
||||
|
||||
install(FILES "${PLUGIN_LOCATION}/../${plugin}.hexplug" DESTINATION "${PLUGINS_INSTALL_LOCATION}")
|
||||
install(FILES "${PLUGIN_LOCATION}/../${plugin}.hexplug" DESTINATION "${PLUGINS_INSTALL_LOCATION}" PERMISSIONS ${LIBRARY_PERMISSIONS})
|
||||
else ()
|
||||
if (WIN32)
|
||||
install(TARGETS ${plugin} RUNTIME DESTINATION ${PLUGINS_INSTALL_LOCATION})
|
||||
@@ -236,39 +252,48 @@ macro(createPackage)
|
||||
endforeach()
|
||||
]])
|
||||
|
||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}" PERMISSIONS ${LIBRARY_PERMISSIONS})
|
||||
downloadImHexPatternsFiles("./")
|
||||
elseif(UNIX AND NOT APPLE)
|
||||
|
||||
set_target_properties(libimhex PROPERTIES SOVERSION ${IMHEX_VERSION})
|
||||
|
||||
configure_file(${CMAKE_SOURCE_DIR}/dist/DEBIAN/control.in ${CMAKE_BINARY_DIR}/DEBIAN/control)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/dist/DEBIAN/control.in ${CMAKE_BINARY_DIR}/DEBIAN/control)
|
||||
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION ${CMAKE_INSTALL_PREFIX}/share/licenses/imhex)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/dist/imhex.desktop DESTINATION ${CMAKE_INSTALL_PREFIX}/share/applications)
|
||||
install(FILES ${CMAKE_SOURCE_DIR}/resources/icon.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.png)
|
||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}")
|
||||
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 (CREATE_BUNDLE)
|
||||
include(PostprocessBundle)
|
||||
|
||||
set_target_properties(libimhex PROPERTIES SOVERSION ${IMHEX_VERSION})
|
||||
|
||||
|
||||
set_property(TARGET main PROPERTY MACOSX_BUNDLE_INFO_PLIST ${MACOSX_BUNDLE_INFO_PLIST})
|
||||
|
||||
# Fix rpath
|
||||
add_custom_command(TARGET imhex_all POST_BUILD COMMAND ${CMAKE_INSTALL_NAME_TOOL} -add_rpath "@executable_path/../Frameworks/" $<TARGET_FILE:main>)
|
||||
|
||||
# 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 "${bundle_path}/Contents/MacOS/plugins")
|
||||
add_custom_target(build-time-make-resources-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${bundle_path}/Contents/Resources")
|
||||
add_custom_target(build-time-make-plugins-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/MacOS/plugins")
|
||||
add_custom_target(build-time-make-resources-directory ALL COMMAND ${CMAKE_COMMAND} -E make_directory "${IMHEX_BUNDLE_PATH}/Contents/Resources")
|
||||
|
||||
downloadImHexPatternsFiles("${bundle_path}/Contents/MacOS")
|
||||
downloadImHexPatternsFiles("${IMHEX_BUNDLE_PATH}/Contents/MacOS")
|
||||
|
||||
install(FILES ${IMHEX_ICON} DESTINATION "${bundle_path}/Contents/Resources")
|
||||
install(FILES ${IMHEX_ICON} DESTINATION "${IMHEX_BUNDLE_PATH}/Contents/Resources")
|
||||
install(TARGETS main BUNDLE DESTINATION ".")
|
||||
install(FILES $<TARGET_FILE:main> DESTINATION "${bundle_path}")
|
||||
install(FILES $<TARGET_FILE:main> DESTINATION "${IMHEX_BUNDLE_PATH}")
|
||||
|
||||
# Update library references to make the bundle portable
|
||||
postprocess_bundle(imhex_all main)
|
||||
@@ -280,7 +305,10 @@ macro(createPackage)
|
||||
endif()
|
||||
|
||||
if (CREATE_PACKAGE)
|
||||
include(apple)
|
||||
set (CPACK_BUNDLE_NAME "ImHex")
|
||||
set (CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/resources/dist/macos/AppIcon.icns" )
|
||||
set (CPACK_BUNDLE_PLIST "${CMAKE_BINARY_DIR}/ImHex.app/Contents/Info.plist")
|
||||
|
||||
include(CPack)
|
||||
endif()
|
||||
endmacro()
|
||||
@@ -303,7 +331,9 @@ macro(setDefaultBuiltTypeIfUnset)
|
||||
endmacro()
|
||||
|
||||
function(loadVersion version)
|
||||
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" read_version)
|
||||
set(VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${VERSION_FILE})
|
||||
file(READ "${VERSION_FILE}" read_version)
|
||||
set(${version} ${read_version} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
@@ -322,15 +352,17 @@ function(detectBadClone)
|
||||
endforeach ()
|
||||
endfunction()
|
||||
|
||||
set(IMHEX_REQUIRED_COMPILER "GNU")
|
||||
set(IMHEX_MIN_COMPILER_VERSION "12.0.0")
|
||||
function(verifyCompiler)
|
||||
if (IMHEX_IGNORE_BAD_COMPILER)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (NOT CMAKE_CXX_COMPILER_ID STREQUAL ${IMHEX_REQUIRED_COMPILER} OR CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${IMHEX_MIN_COMPILER_VERSION})
|
||||
message(FATAL_ERROR "ImHex requires GCC ${IMHEX_MIN_COMPILER_VERSION} or newer. Please use the latest GCC version.")
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "12.0.0")
|
||||
message(FATAL_ERROR "ImHex requires GCC 12.0.0 or newer. Please use the latest GCC version.")
|
||||
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "14.0.0")
|
||||
message(FATAL_ERROR "ImHex requires Clang 14.0.0 or newer. Please use the latest Clang version.")
|
||||
elseif (NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang"))
|
||||
message(FATAL_ERROR "ImHex can only be compiled with GCC or Clang. ${CMAKE_CXX_COMPILER_ID} is not supported.")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
@@ -360,6 +392,12 @@ function(downloadImHexPatternsFiles dest)
|
||||
|
||||
FetchContent_Populate(imhex_patterns)
|
||||
|
||||
else ()
|
||||
# Maybe patterns are cloned to a subdirectory
|
||||
set(imhex_patterns_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ImHex-Patterns")
|
||||
endif ()
|
||||
|
||||
if (EXISTS ${imhex_patterns_SOURCE_DIR})
|
||||
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic)
|
||||
foreach (FOLDER ${PATTERNS_FOLDERS_TO_INSTALL})
|
||||
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION ${dest})
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
set (CPACK_BUNDLE_NAME "ImHex")
|
||||
set (CPACK_BUNDLE_ICON "${CMAKE_SOURCE_DIR}/resources/AppIcon.icns" )
|
||||
set (CPACK_BUNDLE_PLIST "${CMAKE_BINARY_DIR}/ImHex.app/Contents/Info.plist")
|
||||
5
dist/AppImageBuilder.yml
vendored
5
dist/AppImageBuilder.yml
vendored
@@ -6,7 +6,7 @@ AppDir:
|
||||
id: imhex
|
||||
name: ImHex
|
||||
icon: imhex
|
||||
version: AppImage
|
||||
version: "{{VERSION}}"
|
||||
exec: usr/bin/imhex
|
||||
exec_args: $@
|
||||
apt:
|
||||
@@ -136,4 +136,5 @@ AppDir:
|
||||
- usr/share/doc/*/TODO.*
|
||||
AppImage:
|
||||
arch: x86_64
|
||||
update-information: guess
|
||||
update-information: gh-releases-zsync|WerWolv|ImHex|latest|imhex-*.AppImage.zsync
|
||||
file_name: imhex-{{VERSION}}.AppImage
|
||||
|
||||
33
dist/Arch/PKGBUILD
vendored
33
dist/Arch/PKGBUILD
vendored
@@ -1,40 +1,29 @@
|
||||
# Maintainer: iTrooz_ <itrooz at protonmail dot com>
|
||||
# Contributor: Morten Linderud <foxboron@archlinux.org>
|
||||
|
||||
pkgname=imhex-bin
|
||||
pkgver=%version%
|
||||
pkgrel=1
|
||||
pkgdesc="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM. "
|
||||
arch=("x86_64")
|
||||
url="https://github.com/WerWolv/ImHex"
|
||||
repo=$url
|
||||
license=('GPL 2.0')
|
||||
groups=()
|
||||
license=('GPL2')
|
||||
depends=(glfw mbedtls python freetype2 libglvnd dbus xdg-desktop-portal curl fmt yara nlohmann-json)
|
||||
makedepends=(git)
|
||||
checkdepends=()
|
||||
optdepends=()
|
||||
provides=(imhex)
|
||||
conflicts=(imhex)
|
||||
replaces=()
|
||||
backup=()
|
||||
options=()
|
||||
source=($repo"/releases/download/v$pkgver/imhex-$pkgver-ArchLinux.pkg.tar.zst")
|
||||
noextract=()
|
||||
source=("$url/releases/download/v$pkgver/imhex-$pkgver-ArchLinux.pkg.tar.zst")
|
||||
md5sums=(SKIP)
|
||||
validpgpkeys=()
|
||||
|
||||
package() {
|
||||
tar -xf imhex-$pkgver-ArchLinux.pkg.tar.zst
|
||||
install -Dm755 "$srcdir/usr/bin/imhex" "$pkgdir/usr/bin/imhex"
|
||||
install -Dm644 "$srcdir/usr/lib/libimhex.so.$pkgver" "$pkgdir/usr/lib/libimhex.so.$pkgver"
|
||||
|
||||
install -DT $srcdir/usr/bin/imhex $pkgdir/usr/bin/imhex
|
||||
install -DT $srcdir/usr/lib/libimhex.so.$pkgver $pkgdir/usr/lib/libimhex.so.$pkgver
|
||||
|
||||
for plugin in $srcdir/usr/lib/imhex/plugins/*.hexplug;
|
||||
do
|
||||
install -DT $plugin $pkgdir/usr/lib/imhex/plugins/`basename $plugin`
|
||||
for plugin in "$srcdir/usr/lib/imhex/plugins/"*.hexplug; do
|
||||
install -Dm644 "$plugin" "$pkgdir/usr/lib/imhex/plugins/${plugin##*/}"
|
||||
done
|
||||
|
||||
mkdir -p $pkgdir/usr/share/imhex
|
||||
cp -r $srcdir/usr/share/imhex/{constants,encodings,includes,magic,patterns} $pkgdir/usr/share/imhex
|
||||
cp -r $srcdir/usr/share/{applications,licenses} $pkgdir/usr/share
|
||||
install -d $pkgdir/usr/share
|
||||
install -d "$pkgdir/usr/share/imhex"
|
||||
cp -r "$srcdir/usr/share/imhex/"{constants,encodings,includes,magic,patterns} "$pkgdir/usr/share/imhex"
|
||||
cp -r "$srcdir/usr/share/"{applications,licenses} "$pkgdir/usr/share"
|
||||
}
|
||||
|
||||
1
dist/Brewfile
vendored
1
dist/Brewfile
vendored
@@ -1,4 +1,3 @@
|
||||
brew "glfw"
|
||||
brew "mbedtls"
|
||||
brew "nlohmann-json"
|
||||
brew "cmake"
|
||||
|
||||
24
dist/compiling/linux.md
vendored
24
dist/compiling/linux.md
vendored
@@ -1,9 +1,12 @@
|
||||
### Compiling ImHex on Linux
|
||||
|
||||
Dependency installation scripts are available for many common Linux distributions in the [/dist](dist) folder.
|
||||
After all the dependencies are installed, run the following commands to build ImHex:
|
||||
On Linux, ImHex is built through regular GCC (or optionally Clang).
|
||||
|
||||
1. Clone the repo using `git clone https://github.com/WerWolv/ImHex --recurse-submodules`
|
||||
2. Install the dependencies using one of the `dist/get_deps_*.sh` scripts. Choose the one that matches your distro.
|
||||
3. Build ImHex itself using the following commands:
|
||||
```sh
|
||||
cd ImHex
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=gcc-12 CXX=g++-12 cmake \
|
||||
@@ -15,27 +18,10 @@ CC=gcc-12 CXX=g++-12 cmake \
|
||||
-DCMAKE_CXX_FLAGS="-fuse-ld=lld" \
|
||||
-DCMAKE_OBJC_COMPILER_LAUNCHER=ccache \
|
||||
-DCMAKE_OBJCXX_COMPILER_LAUNCHER=ccache \
|
||||
-DRUST_PATH="$HOME/.cargo/bin/" \
|
||||
..
|
||||
make -j 4 install
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Put the ImHex executable into the `/usr/bin` folder.
|
||||
Put libimhex.so into the `/usr/lib` folder.
|
||||
Configuration files go to `/usr/etc/imhex` or `~/.config/imhex`.
|
||||
All other files belong in `/usr/share/imhex` or `~/.local/share/imhex`:
|
||||
|
||||
```
|
||||
Patterns: /usr/share/imhex/patterns
|
||||
Pattern Includes: /usr/share/imhex/includes
|
||||
Magic files: /usr/share/imhex/magic
|
||||
Python: /usr/share/imhex/lib/pythonX.X
|
||||
Plugins: /usr/share/imhex/plugins
|
||||
Configuration: /etc/xdg/imhex/config
|
||||
```
|
||||
|
||||
All paths follow the XDG Base Directories standard, and can thus be modified
|
||||
with the environment variables `XDG_CONFIG_HOME`, `XDG_CONFIG_DIRS`,
|
||||
`XDG_DATA_HOME` and `XDG_DATA_DIRS`.
|
||||
19
dist/compiling/macOS.md
vendored
19
dist/compiling/macOS.md
vendored
@@ -1,9 +1,12 @@
|
||||
### Compiling ImHex on macOS
|
||||
|
||||
To build ImHex on macOS, run the following commands:
|
||||
On macOS, ImHex is built through regular GCC and AppleClang.
|
||||
|
||||
1. Clone the repo using `git clone https://github.com/WerWolv/ImHex --recurse-submodules`
|
||||
2. Install all the dependencies using `brew bundle --no-lock --file dist/Brewfile`
|
||||
3. Build ImHex itself using the following commands:
|
||||
```sh
|
||||
brew bundle --no-lock --file dist/Brewfile
|
||||
cd ImHex
|
||||
mkdir -p build
|
||||
cd build
|
||||
CC=$(brew --prefix gcc@12)/bin/gcc-12 \
|
||||
@@ -24,18 +27,6 @@ cmake \
|
||||
make -j4 package
|
||||
```
|
||||
|
||||
Open the generated .dmg file and drag-n-drop the ImHex executable to the Applications folder
|
||||
|
||||
All other files belong in `~/Library/Application Support/imhex`:
|
||||
```
|
||||
Patterns: ~/Library/Application Support/imhex/patterns
|
||||
Pattern Includes: ~/Library/Application Support/imhex/includes
|
||||
Magic files: ~/Library/Application Support/imhex/magic
|
||||
Python: ~/Library/Application Support/imhex/lib/pythonX.X
|
||||
Plugins: ~/Library/Application Support/imhex/plugins
|
||||
Configuration: ~/Library/Application Support/imhex/config
|
||||
```
|
||||
|
||||
If the build fails while trying to find the macOS libraries, make sure you have
|
||||
XCode installed with `xcode-select --install`. Homebrew will also help get the
|
||||
most recent SDK installed and configured with `brew doctor`.
|
||||
9
dist/compiling/windows.md
vendored
9
dist/compiling/windows.md
vendored
@@ -1,9 +1,14 @@
|
||||
### Compiling ImHex on Windows
|
||||
|
||||
On Windows, ImHex is built through msys2 / mingw. To install all dependencies, open a msys2 window and run the PKGCONFIG script in the [dist/msys2](dist/msys2) folder.
|
||||
After all the dependencies are installed, run the following commands to build ImHex:
|
||||
On Windows, ImHex is built through [msys2 / mingw](https://www.msys2.org/)'s gcc.
|
||||
|
||||
1. Download and install msys2 from their [website](https://www.msys2.org/).
|
||||
2. Open the `MSYS2 MinGW x64` shell
|
||||
3. Clone the repo using `git clone https://github.com/WerWolv/ImHex --recurse-submodules`
|
||||
4. Install all the dependencies using `./ImHex/dist/get_deps_msys2.sh`
|
||||
5. Build ImHex itself using the following commands:
|
||||
```sh
|
||||
cd ImHex
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -G "MinGW Makefiles" \
|
||||
|
||||
25
dist/macOS/0001-glfw-SW.patch
vendored
Normal file
25
dist/macOS/0001-glfw-SW.patch
vendored
Normal file
@@ -0,0 +1,25 @@
|
||||
From 9c8665af4c2e2ce66555c15c05c72027bfdf0cb6 Mon Sep 17 00:00:00 2001
|
||||
From: iTrooz <itrooz@protonmail.com>
|
||||
Date: Mon, 29 Aug 2022 17:29:38 +0200
|
||||
Subject: [PATCH] Use software rendering on MacOS
|
||||
|
||||
---
|
||||
src/nsgl_context.m | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/nsgl_context.m b/src/nsgl_context.m
|
||||
index fc1f7521..e5906575 100644
|
||||
--- a/src/nsgl_context.m
|
||||
+++ b/src/nsgl_context.m
|
||||
@@ -198,7 +198,7 @@ GLFWbool _glfwCreateContextNSGL(_GLFWwindow* window,
|
||||
NSOpenGLPixelFormatAttribute attribs[40];
|
||||
int index = 0;
|
||||
|
||||
- ADD_ATTRIB(NSOpenGLPFAAccelerated);
|
||||
+ ADD_ATTRIB(NSOpenGLPFARendererID);ADD_ATTRIB(kCGLRendererGenericFloatID);
|
||||
ADD_ATTRIB(NSOpenGLPFAClosestPolicy);
|
||||
|
||||
if (ctxconfig->nsgl.offline)
|
||||
--
|
||||
2.37.2
|
||||
|
||||
34
dist/net.werwolv.imhex.metainfo.xml
vendored
Normal file
34
dist/net.werwolv.imhex.metainfo.xml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>imhex</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-2.0</project_license>
|
||||
<name>ImHex</name>
|
||||
<developer_name>WerWolv</developer_name>
|
||||
<update_contact>hey@werwolv.net</update_contact>
|
||||
<summary>A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM</summary>
|
||||
<description>
|
||||
<p>ImHex is a feature-rich Hex Editor aimed towards Reverse Engineers working with foreign data formats, malware, executables and raw memory.
|
||||
Besides all the features a common Hex Editor has, ImHex also features a custom scripting language used to declare and dissect data structures, support for running YARA rules, a node-based graphical data pre-processor and support for various data sources such as files, raw disks or GDB Servers.</p>
|
||||
</description>
|
||||
<launchable type="desktop-id">imhex.desktop</launchable>
|
||||
<url type="homepage">https://imhex.werwolv.net</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://user-images.githubusercontent.com/10835354/139717326-8044769d-527b-4d88-8adf-2d4ecafdca1f.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://user-images.githubusercontent.com/10835354/139717323-1f8c9d52-f7eb-4f43-9f11-097ac728ed6c.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
|
||||
<provides>
|
||||
<id>imhex.desktop</id>
|
||||
</provides>
|
||||
|
||||
<categories>
|
||||
<category>Development</category>
|
||||
</categories>
|
||||
|
||||
|
||||
</component>
|
||||
4
dist/rpm/imhex.spec
vendored
4
dist/rpm/imhex.spec
vendored
@@ -1,7 +1,7 @@
|
||||
# ftbfs without this
|
||||
%global _lto_cflags %{nil}
|
||||
|
||||
Name: ImHex
|
||||
Name: imhex
|
||||
Version: %{_version}
|
||||
Release: 0%{?dist}
|
||||
Summary: A hex editor for reverse engineers and programmers
|
||||
@@ -84,5 +84,7 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/imhex.desktop
|
||||
%{_datadir}/applications/imhex.desktop
|
||||
%{_prefix}/lib64/libimhex.so.%{_version}
|
||||
%{_prefix}/lib64/imhex/plugins/*
|
||||
%{_metainfodir}/net.werwolv.imhex.metainfo.xml
|
||||
%{_metainfodir}/net.werwolv.imhex.appdata.xml
|
||||
|
||||
%changelog
|
||||
|
||||
2
lib/external/imgui/include/imconfig.h
vendored
2
lib/external/imgui/include/imconfig.h
vendored
@@ -99,7 +99,7 @@
|
||||
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||
//#define ImDrawIdx unsigned int
|
||||
#define ImDrawIdx unsigned int
|
||||
|
||||
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||
//struct ImDrawList;
|
||||
|
||||
9
lib/external/intervaltree/CMakeLists.txt
vendored
Normal file
9
lib/external/intervaltree/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(intervaltree)
|
||||
|
||||
set(CMAKE_CXX_STANDARD20)
|
||||
|
||||
add_library(intervaltree INTERFACE)
|
||||
|
||||
target_include_directories(intervaltree INTERFACE include)
|
||||
target_compile_options(intervaltree INTERFACE "-DUSE_INTERVAL_TREE_NAMESPACE")
|
||||
19
lib/external/intervaltree/LICENSE
vendored
Normal file
19
lib/external/intervaltree/LICENSE
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
Copyright (c) 2011 Erik Garrison
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
37
lib/external/intervaltree/README.md
vendored
Normal file
37
lib/external/intervaltree/README.md
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
# intervaltree
|
||||
|
||||
## Overview
|
||||
|
||||
An interval tree can be used to efficiently find a set of numeric intervals overlapping or containing another interval.
|
||||
|
||||
This library provides a basic implementation of an interval tree using C++ templates, allowing the insertion of arbitrary types into the tree.
|
||||
|
||||
## Usage
|
||||
|
||||
Add `#include "IntervalTree.h"` to the source files in which you will use the interval tree.
|
||||
|
||||
To make an IntervalTree to contain objects of class T, use:
|
||||
|
||||
```c++
|
||||
vector<Interval<T> > intervals;
|
||||
T a, b, c;
|
||||
intervals.push_back(Interval<T>(2, 10, a));
|
||||
intervals.push_back(Interval<T>(3, 4, b));
|
||||
intervals.push_back(Interval<T>(20, 100, c));
|
||||
IntervalTree<T> tree;
|
||||
tree = IntervalTree<T>(intervals);
|
||||
```
|
||||
|
||||
Now, it's possible to query the tree and obtain a set of intervals which are contained within the start and stop coordinates.
|
||||
|
||||
```c++
|
||||
vector<Interval<T> > results;
|
||||
tree.findContained(start, stop, results);
|
||||
cout << "found " << results.size() << " overlapping intervals" << endl;
|
||||
```
|
||||
|
||||
The function IntervalTree::findOverlapping provides a method to find all those intervals which are contained or partially overlap the interval (start, stop).
|
||||
|
||||
### Author: Erik Garrison <erik.garrison@gmail.com>
|
||||
|
||||
### License: MIT
|
||||
325
lib/external/intervaltree/include/IntervalTree.h
vendored
Normal file
325
lib/external/intervaltree/include/IntervalTree.h
vendored
Normal file
@@ -0,0 +1,325 @@
|
||||
#ifndef __INTERVAL_TREE_H
|
||||
#define __INTERVAL_TREE_H
|
||||
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
|
||||
#ifdef USE_INTERVAL_TREE_NAMESPACE
|
||||
namespace interval_tree {
|
||||
#endif
|
||||
template <class Scalar, typename Value>
|
||||
class Interval {
|
||||
public:
|
||||
Scalar start;
|
||||
Scalar stop;
|
||||
Value value;
|
||||
Interval(const Scalar& s, const Scalar& e, const Value& v)
|
||||
: start(std::min(s, e))
|
||||
, stop(std::max(s, e))
|
||||
, value(v)
|
||||
{}
|
||||
};
|
||||
|
||||
template <class Scalar, typename Value>
|
||||
Value intervalStart(const Interval<Scalar,Value>& i) {
|
||||
return i.start;
|
||||
}
|
||||
|
||||
template <class Scalar, typename Value>
|
||||
Value intervalStop(const Interval<Scalar, Value>& i) {
|
||||
return i.stop;
|
||||
}
|
||||
|
||||
template <class Scalar, typename Value>
|
||||
std::ostream& operator<<(std::ostream& out, const Interval<Scalar, Value>& i) {
|
||||
out << "Interval(" << i.start << ", " << i.stop << "): " << i.value;
|
||||
return out;
|
||||
}
|
||||
|
||||
template <class Scalar, class Value>
|
||||
class IntervalTree {
|
||||
public:
|
||||
typedef Interval<Scalar, Value> interval;
|
||||
typedef std::vector<interval> interval_vector;
|
||||
|
||||
|
||||
struct IntervalStartCmp {
|
||||
bool operator()(const interval& a, const interval& b) {
|
||||
return a.start < b.start;
|
||||
}
|
||||
};
|
||||
|
||||
struct IntervalStopCmp {
|
||||
bool operator()(const interval& a, const interval& b) {
|
||||
return a.stop < b.stop;
|
||||
}
|
||||
};
|
||||
|
||||
IntervalTree()
|
||||
: left(nullptr)
|
||||
, right(nullptr)
|
||||
, center(0)
|
||||
{}
|
||||
|
||||
~IntervalTree() = default;
|
||||
|
||||
std::unique_ptr<IntervalTree> clone() const {
|
||||
return std::unique_ptr<IntervalTree>(new IntervalTree(*this));
|
||||
}
|
||||
|
||||
IntervalTree(const IntervalTree& other)
|
||||
: intervals(other.intervals),
|
||||
left(other.left ? other.left->clone() : nullptr),
|
||||
right(other.right ? other.right->clone() : nullptr),
|
||||
center(other.center)
|
||||
{}
|
||||
|
||||
IntervalTree& operator=(IntervalTree&&) = default;
|
||||
IntervalTree(IntervalTree&&) = default;
|
||||
|
||||
IntervalTree& operator=(const IntervalTree& other) {
|
||||
center = other.center;
|
||||
intervals = other.intervals;
|
||||
left = other.left ? other.left->clone() : nullptr;
|
||||
right = other.right ? other.right->clone() : nullptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
IntervalTree(
|
||||
interval_vector&& ivals,
|
||||
std::size_t depth = 16,
|
||||
std::size_t minbucket = 64,
|
||||
std::size_t maxbucket = 512,
|
||||
Scalar leftextent = 0,
|
||||
Scalar rightextent = 0)
|
||||
: left(nullptr)
|
||||
, right(nullptr)
|
||||
{
|
||||
--depth;
|
||||
const auto minmaxStop = std::minmax_element(ivals.begin(), ivals.end(),
|
||||
IntervalStopCmp());
|
||||
const auto minmaxStart = std::minmax_element(ivals.begin(), ivals.end(),
|
||||
IntervalStartCmp());
|
||||
if (!ivals.empty()) {
|
||||
center = (minmaxStart.first->start + minmaxStop.second->stop) / 2;
|
||||
}
|
||||
if (leftextent == 0 && rightextent == 0) {
|
||||
// sort intervals by start
|
||||
std::sort(ivals.begin(), ivals.end(), IntervalStartCmp());
|
||||
} else {
|
||||
assert(std::is_sorted(ivals.begin(), ivals.end(), IntervalStartCmp()));
|
||||
}
|
||||
if (depth == 0 || (ivals.size() < minbucket && ivals.size() < maxbucket)) {
|
||||
std::sort(ivals.begin(), ivals.end(), IntervalStartCmp());
|
||||
intervals = std::move(ivals);
|
||||
assert(is_valid().first);
|
||||
return;
|
||||
} else {
|
||||
Scalar leftp = 0;
|
||||
Scalar rightp = 0;
|
||||
|
||||
if (leftextent || rightextent) {
|
||||
leftp = leftextent;
|
||||
rightp = rightextent;
|
||||
} else {
|
||||
leftp = ivals.front().start;
|
||||
rightp = std::max_element(ivals.begin(), ivals.end(),
|
||||
IntervalStopCmp())->stop;
|
||||
}
|
||||
|
||||
interval_vector lefts;
|
||||
interval_vector rights;
|
||||
|
||||
for (typename interval_vector::const_iterator i = ivals.begin();
|
||||
i != ivals.end(); ++i) {
|
||||
const interval& interval = *i;
|
||||
if (interval.stop < center) {
|
||||
lefts.push_back(interval);
|
||||
} else if (interval.start > center) {
|
||||
rights.push_back(interval);
|
||||
} else {
|
||||
assert(interval.start <= center);
|
||||
assert(center <= interval.stop);
|
||||
intervals.push_back(interval);
|
||||
}
|
||||
}
|
||||
|
||||
if (!lefts.empty()) {
|
||||
left.reset(new IntervalTree(std::move(lefts),
|
||||
depth, minbucket, maxbucket,
|
||||
leftp, center));
|
||||
}
|
||||
if (!rights.empty()) {
|
||||
right.reset(new IntervalTree(std::move(rights),
|
||||
depth, minbucket, maxbucket,
|
||||
center, rightp));
|
||||
}
|
||||
}
|
||||
assert(is_valid().first);
|
||||
}
|
||||
|
||||
// Call f on all intervals near the range [start, stop]:
|
||||
template <class UnaryFunction>
|
||||
void visit_near(const Scalar& start, const Scalar& stop, UnaryFunction f) const {
|
||||
if (!intervals.empty() && ! (stop < intervals.front().start)) {
|
||||
for (auto & i : intervals) {
|
||||
f(i);
|
||||
}
|
||||
}
|
||||
if (left && start <= center) {
|
||||
left->visit_near(start, stop, f);
|
||||
}
|
||||
if (right && stop >= center) {
|
||||
right->visit_near(start, stop, f);
|
||||
}
|
||||
}
|
||||
|
||||
// Call f on all intervals crossing pos
|
||||
template <class UnaryFunction>
|
||||
void visit_overlapping(const Scalar& pos, UnaryFunction f) const {
|
||||
visit_overlapping(pos, pos, f);
|
||||
}
|
||||
|
||||
// Call f on all intervals overlapping [start, stop]
|
||||
template <class UnaryFunction>
|
||||
void visit_overlapping(const Scalar& start, const Scalar& stop, UnaryFunction f) const {
|
||||
auto filterF = [&](const interval& interval) {
|
||||
if (interval.stop >= start && interval.start <= stop) {
|
||||
// Only apply f if overlapping
|
||||
f(interval);
|
||||
}
|
||||
};
|
||||
visit_near(start, stop, filterF);
|
||||
}
|
||||
|
||||
// Call f on all intervals contained within [start, stop]
|
||||
template <class UnaryFunction>
|
||||
void visit_contained(const Scalar& start, const Scalar& stop, UnaryFunction f) const {
|
||||
auto filterF = [&](const interval& interval) {
|
||||
if (start <= interval.start && interval.stop <= stop) {
|
||||
f(interval);
|
||||
}
|
||||
};
|
||||
visit_near(start, stop, filterF);
|
||||
}
|
||||
|
||||
interval_vector findOverlapping(const Scalar& start, const Scalar& stop) const {
|
||||
interval_vector result;
|
||||
visit_overlapping(start, stop,
|
||||
[&](const interval& interval) {
|
||||
result.emplace_back(interval);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
interval_vector findContained(const Scalar& start, const Scalar& stop) const {
|
||||
interval_vector result;
|
||||
visit_contained(start, stop,
|
||||
[&](const interval& interval) {
|
||||
result.push_back(interval);
|
||||
});
|
||||
return result;
|
||||
}
|
||||
bool empty() const {
|
||||
if (left && !left->empty()) {
|
||||
return false;
|
||||
}
|
||||
if (!intervals.empty()) {
|
||||
return false;
|
||||
}
|
||||
if (right && !right->empty()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class UnaryFunction>
|
||||
void visit_all(UnaryFunction f) const {
|
||||
if (left) {
|
||||
left->visit_all(f);
|
||||
}
|
||||
std::for_each(intervals.begin(), intervals.end(), f);
|
||||
if (right) {
|
||||
right->visit_all(f);
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<Scalar, Scalar> extentBruitForce() const {
|
||||
struct Extent {
|
||||
std::pair<Scalar, Scalar> x = {std::numeric_limits<Scalar>::max(),
|
||||
std::numeric_limits<Scalar>::min() };
|
||||
void operator()(const interval & interval) {
|
||||
x.first = std::min(x.first, interval.start);
|
||||
x.second = std::max(x.second, interval.stop);
|
||||
}
|
||||
};
|
||||
Extent extent;
|
||||
|
||||
visit_all([&](const interval & interval) { extent(interval); });
|
||||
return extent.x;
|
||||
}
|
||||
|
||||
// Check all constraints.
|
||||
// If first is false, second is invalid.
|
||||
std::pair<bool, std::pair<Scalar, Scalar>> is_valid() const {
|
||||
const auto minmaxStop = std::minmax_element(intervals.begin(), intervals.end(),
|
||||
IntervalStopCmp());
|
||||
const auto minmaxStart = std::minmax_element(intervals.begin(), intervals.end(),
|
||||
IntervalStartCmp());
|
||||
|
||||
std::pair<bool, std::pair<Scalar, Scalar>> result = {true, { std::numeric_limits<Scalar>::max(),
|
||||
std::numeric_limits<Scalar>::min() }};
|
||||
if (!intervals.empty()) {
|
||||
result.second.first = std::min(result.second.first, minmaxStart.first->start);
|
||||
result.second.second = std::min(result.second.second, minmaxStop.second->stop);
|
||||
}
|
||||
if (left) {
|
||||
auto valid = left->is_valid();
|
||||
result.first &= valid.first;
|
||||
result.second.first = std::min(result.second.first, valid.second.first);
|
||||
result.second.second = std::min(result.second.second, valid.second.second);
|
||||
if (!result.first) { return result; }
|
||||
if (valid.second.second >= center) {
|
||||
result.first = false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (right) {
|
||||
auto valid = right->is_valid();
|
||||
result.first &= valid.first;
|
||||
result.second.first = std::min(result.second.first, valid.second.first);
|
||||
result.second.second = std::min(result.second.second, valid.second.second);
|
||||
if (!result.first) { return result; }
|
||||
if (valid.second.first <= center) {
|
||||
result.first = false;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
if (!std::is_sorted(intervals.begin(), intervals.end(), IntervalStartCmp())) {
|
||||
result.first = false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
left.reset();
|
||||
right.reset();
|
||||
intervals.clear();
|
||||
center = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
interval_vector intervals;
|
||||
std::unique_ptr<IntervalTree> left;
|
||||
std::unique_ptr<IntervalTree> right;
|
||||
Scalar center;
|
||||
};
|
||||
#ifdef USE_INTERVAL_TREE_NAMESPACE
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
2
lib/external/libromfs
vendored
2
lib/external/libromfs
vendored
Submodule lib/external/libromfs updated: 58757f6cad...8c8556dd6b
15
lib/external/llvm-demangle/CMakeLists.txt
vendored
Normal file
15
lib/external/llvm-demangle/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(LLVMDemangle)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
add_library(LLVMDemangle STATIC
|
||||
source/Demangle.cpp
|
||||
source/DLangDemangle.cpp
|
||||
source/ItaniumDemangle.cpp
|
||||
source/MicrosoftDemangle.cpp
|
||||
source/MicrosoftDemangleNodes.cpp
|
||||
source/RustDemangle.cpp
|
||||
)
|
||||
|
||||
target_include_directories(LLVMDemangle PUBLIC include)
|
||||
279
lib/external/llvm-demangle/LICENSE.TXT
vendored
Normal file
279
lib/external/llvm-demangle/LICENSE.TXT
vendored
Normal file
@@ -0,0 +1,279 @@
|
||||
==============================================================================
|
||||
The LLVM Project is under the Apache License v2.0 with LLVM Exceptions:
|
||||
==============================================================================
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
|
||||
---- LLVM Exceptions to the Apache 2.0 License ----
|
||||
|
||||
As an exception, if, as a result of your compiling your source code, portions
|
||||
of this Software are embedded into an Object form of such source code, you
|
||||
may redistribute such embedded portions in such Object form without complying
|
||||
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
|
||||
|
||||
In addition, if you combine or link compiled forms of this Software with
|
||||
software that is licensed under the GPLv2 ("Combined Software") and if a
|
||||
court of competent jurisdiction determines that the patent provision (Section
|
||||
3), the indemnity provision (Section 9) or other Section of the License
|
||||
conflicts with the conditions of the GPLv2, you may retroactively and
|
||||
prospectively choose to deem waived or otherwise exclude such Section(s) of
|
||||
the License, but only in their entirety and only with respect to the Combined
|
||||
Software.
|
||||
|
||||
==============================================================================
|
||||
Software from third parties included in the LLVM Project:
|
||||
==============================================================================
|
||||
The LLVM Project contains third party software which is under different license
|
||||
terms. All such code will be identified clearly using at least one of two
|
||||
mechanisms:
|
||||
1) It will be in a separate directory tree with its own `LICENSE.txt` or
|
||||
`LICENSE` file at the top containing the specific license and restrictions
|
||||
which apply to that software, or
|
||||
2) It will contain specific license and restriction terms at the top of every
|
||||
file.
|
||||
|
||||
==============================================================================
|
||||
Legacy LLVM License (https://llvm.org/docs/DeveloperPolicy.html#legacy):
|
||||
==============================================================================
|
||||
University of Illinois/NCSA
|
||||
Open Source License
|
||||
|
||||
Copyright (c) 2003-2019 University of Illinois at Urbana-Champaign.
|
||||
All rights reserved.
|
||||
|
||||
Developed by:
|
||||
|
||||
LLVM Team
|
||||
|
||||
University of Illinois at Urbana-Champaign
|
||||
|
||||
http://llvm.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal with
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimers.
|
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimers in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
* Neither the names of the LLVM Team, University of Illinois at
|
||||
Urbana-Champaign, nor the names of its contributors may be used to
|
||||
endorse or promote products derived from this Software without specific
|
||||
prior written permission.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
||||
SOFTWARE.
|
||||
|
||||
@@ -31,7 +31,6 @@ enum : int {
|
||||
char *itaniumDemangle(const char *mangled_name, char *buf, size_t *n,
|
||||
int *status);
|
||||
|
||||
|
||||
enum MSDemangleFlags {
|
||||
MSDF_None = 0,
|
||||
MSDF_DumpBackrefs = 1 << 0,
|
||||
@@ -39,6 +38,7 @@ enum MSDemangleFlags {
|
||||
MSDF_NoCallingConvention = 1 << 2,
|
||||
MSDF_NoReturnType = 1 << 3,
|
||||
MSDF_NoMemberType = 1 << 4,
|
||||
MSDF_NoVariableType = 1 << 5,
|
||||
};
|
||||
|
||||
/// Demangles the Microsoft symbol pointed at by mangled_name and returns it.
|
||||
@@ -53,9 +53,15 @@ enum MSDemangleFlags {
|
||||
/// receives the size of the demangled string on output if n_buf is not nullptr.
|
||||
/// status receives one of the demangle_ enum entries above if it's not nullptr.
|
||||
/// Flags controls various details of the demangled representation.
|
||||
char *microsoftDemangle(const char *mangled_name, size_t *n_read,
|
||||
char *buf, size_t *n_buf,
|
||||
int *status, MSDemangleFlags Flags = MSDF_None);
|
||||
char *microsoftDemangle(const char *mangled_name, size_t *n_read, char *buf,
|
||||
size_t *n_buf, int *status,
|
||||
MSDemangleFlags Flags = MSDF_None);
|
||||
|
||||
// Demangles a Rust v0 mangled symbol.
|
||||
char *rustDemangle(const char *MangledName);
|
||||
|
||||
// Demangles a D mangled symbol.
|
||||
char *dlangDemangle(const char *MangledName);
|
||||
|
||||
/// Attempt to demangle a string using different demangling schemes.
|
||||
/// The function uses heuristics to determine which demangling scheme to use.
|
||||
@@ -64,6 +70,8 @@ char *microsoftDemangle(const char *mangled_name, size_t *n_read,
|
||||
/// demangling occurred.
|
||||
std::string demangle(const std::string &MangledName);
|
||||
|
||||
bool nonMicrosoftDemangle(const char *MangledName, std::string &Result);
|
||||
|
||||
/// "Partial" demangler. This supports demangling a string into an AST
|
||||
/// (typically an intermediate stage in itaniumDemangle) and querying certain
|
||||
/// properties or partially printing the demangled name.
|
||||
@@ -115,6 +123,7 @@ struct ItaniumPartialDemangler {
|
||||
bool isSpecialName() const;
|
||||
|
||||
~ItaniumPartialDemangler();
|
||||
|
||||
private:
|
||||
void *RootNode;
|
||||
void *Context;
|
||||
@@ -12,8 +12,8 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEMANGLE_COMPILER_H
|
||||
#define LLVM_DEMANGLE_COMPILER_H
|
||||
#ifndef LLVM_DEMANGLE_DEMANGLECONFIG_H
|
||||
#define LLVM_DEMANGLE_DEMANGLECONFIG_H
|
||||
|
||||
#ifndef __has_feature
|
||||
#define __has_feature(x) 0
|
||||
File diff suppressed because it is too large
Load Diff
95
lib/external/llvm-demangle/include/llvm/Demangle/ItaniumNodes.def
vendored
Normal file
95
lib/external/llvm-demangle/include/llvm/Demangle/ItaniumNodes.def
vendored
Normal file
@@ -0,0 +1,95 @@
|
||||
//===--- ItaniumNodes.def ------------*- mode:c++;eval:(read-only-mode) -*-===//
|
||||
// Do not edit! See README.txt.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Define the demangler's node names
|
||||
|
||||
#ifndef NODE
|
||||
#error Define NODE to handle nodes
|
||||
#endif
|
||||
|
||||
NODE(NodeArrayNode)
|
||||
NODE(DotSuffix)
|
||||
NODE(VendorExtQualType)
|
||||
NODE(QualType)
|
||||
NODE(ConversionOperatorType)
|
||||
NODE(PostfixQualifiedType)
|
||||
NODE(ElaboratedTypeSpefType)
|
||||
NODE(NameType)
|
||||
NODE(AbiTagAttr)
|
||||
NODE(EnableIfAttr)
|
||||
NODE(ObjCProtoName)
|
||||
NODE(PointerType)
|
||||
NODE(ReferenceType)
|
||||
NODE(PointerToMemberType)
|
||||
NODE(ArrayType)
|
||||
NODE(FunctionType)
|
||||
NODE(NoexceptSpec)
|
||||
NODE(DynamicExceptionSpec)
|
||||
NODE(FunctionEncoding)
|
||||
NODE(LiteralOperator)
|
||||
NODE(SpecialName)
|
||||
NODE(CtorVtableSpecialName)
|
||||
NODE(QualifiedName)
|
||||
NODE(NestedName)
|
||||
NODE(LocalName)
|
||||
NODE(ModuleName)
|
||||
NODE(ModuleEntity)
|
||||
NODE(VectorType)
|
||||
NODE(PixelVectorType)
|
||||
NODE(BinaryFPType)
|
||||
NODE(BitIntType)
|
||||
NODE(SyntheticTemplateParamName)
|
||||
NODE(TypeTemplateParamDecl)
|
||||
NODE(NonTypeTemplateParamDecl)
|
||||
NODE(TemplateTemplateParamDecl)
|
||||
NODE(TemplateParamPackDecl)
|
||||
NODE(ParameterPack)
|
||||
NODE(TemplateArgumentPack)
|
||||
NODE(ParameterPackExpansion)
|
||||
NODE(TemplateArgs)
|
||||
NODE(ForwardTemplateReference)
|
||||
NODE(NameWithTemplateArgs)
|
||||
NODE(GlobalQualifiedName)
|
||||
NODE(ExpandedSpecialSubstitution)
|
||||
NODE(SpecialSubstitution)
|
||||
NODE(CtorDtorName)
|
||||
NODE(DtorName)
|
||||
NODE(UnnamedTypeName)
|
||||
NODE(ClosureTypeName)
|
||||
NODE(StructuredBindingName)
|
||||
NODE(BinaryExpr)
|
||||
NODE(ArraySubscriptExpr)
|
||||
NODE(PostfixExpr)
|
||||
NODE(ConditionalExpr)
|
||||
NODE(MemberExpr)
|
||||
NODE(SubobjectExpr)
|
||||
NODE(EnclosingExpr)
|
||||
NODE(CastExpr)
|
||||
NODE(SizeofParamPackExpr)
|
||||
NODE(CallExpr)
|
||||
NODE(NewExpr)
|
||||
NODE(DeleteExpr)
|
||||
NODE(PrefixExpr)
|
||||
NODE(FunctionParam)
|
||||
NODE(ConversionExpr)
|
||||
NODE(PointerToMemberConversionExpr)
|
||||
NODE(InitListExpr)
|
||||
NODE(FoldExpr)
|
||||
NODE(ThrowExpr)
|
||||
NODE(BoolExpr)
|
||||
NODE(StringLiteral)
|
||||
NODE(LambdaExpr)
|
||||
NODE(EnumLiteral)
|
||||
NODE(IntegerLiteral)
|
||||
NODE(FloatLiteral)
|
||||
NODE(DoubleLiteral)
|
||||
NODE(LongDoubleLiteral)
|
||||
NODE(BracedExpr)
|
||||
NODE(BracedRangeExpr)
|
||||
|
||||
#undef NODE
|
||||
@@ -6,13 +6,11 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H
|
||||
#define LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H
|
||||
#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
|
||||
#define LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
|
||||
|
||||
#include "llvm/Demangle/DemangleConfig.h"
|
||||
#include "llvm/Demangle/MicrosoftDemangleNodes.h"
|
||||
#include "llvm/Demangle/StringView.h"
|
||||
#include "llvm/Demangle/Utility.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
@@ -275,4 +273,4 @@ private:
|
||||
} // namespace ms_demangle
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_DEMANGLE_MICROSOFT_DEMANGLE_H
|
||||
#endif // LLVM_DEMANGLE_MICROSOFTDEMANGLE_H
|
||||
@@ -10,10 +10,9 @@
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H
|
||||
#define LLVM_SUPPORT_MICROSOFTDEMANGLENODES_H
|
||||
#ifndef LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H
|
||||
#define LLVM_DEMANGLE_MICROSOFTDEMANGLENODES_H
|
||||
|
||||
#include "llvm/Demangle/DemangleConfig.h"
|
||||
#include "llvm/Demangle/StringView.h"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
@@ -21,11 +20,11 @@
|
||||
|
||||
namespace llvm {
|
||||
namespace itanium_demangle {
|
||||
class OutputStream;
|
||||
class OutputBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
using llvm::itanium_demangle::OutputStream;
|
||||
using llvm::itanium_demangle::OutputBuffer;
|
||||
using llvm::itanium_demangle::StringView;
|
||||
|
||||
namespace llvm {
|
||||
@@ -67,6 +66,8 @@ enum class CallingConv : uint8_t {
|
||||
Eabi,
|
||||
Vectorcall,
|
||||
Regcall,
|
||||
Swift, // Clang-only
|
||||
SwiftAsync, // Clang-only
|
||||
};
|
||||
|
||||
enum class ReferenceKind : uint8_t { None, LValueRef, RValueRef };
|
||||
@@ -78,6 +79,7 @@ enum OutputFlags {
|
||||
OF_NoAccessSpecifier = 4,
|
||||
OF_NoMemberType = 8,
|
||||
OF_NoReturnType = 16,
|
||||
OF_NoVariableType = 32,
|
||||
};
|
||||
|
||||
// Types
|
||||
@@ -259,7 +261,7 @@ struct Node {
|
||||
|
||||
NodeKind kind() const { return Kind; }
|
||||
|
||||
virtual void output(OutputStream &OS, OutputFlags Flags) const = 0;
|
||||
virtual void output(OutputBuffer &OB, OutputFlags Flags) const = 0;
|
||||
|
||||
std::string toString(OutputFlags Flags = OF_Default) const;
|
||||
|
||||
@@ -280,9 +282,7 @@ struct StructorIdentifierNode;
|
||||
struct ThunkSignatureNode;
|
||||
struct PointerTypeNode;
|
||||
struct ArrayTypeNode;
|
||||
struct CustomNode;
|
||||
struct TagTypeNode;
|
||||
struct IntrinsicTypeNode;
|
||||
struct NodeArrayNode;
|
||||
struct QualifiedNameNode;
|
||||
struct TemplateParameterReferenceNode;
|
||||
@@ -298,12 +298,12 @@ struct SpecialTableSymbolNode;
|
||||
struct TypeNode : public Node {
|
||||
explicit TypeNode(NodeKind K) : Node(K) {}
|
||||
|
||||
virtual void outputPre(OutputStream &OS, OutputFlags Flags) const = 0;
|
||||
virtual void outputPost(OutputStream &OS, OutputFlags Flags) const = 0;
|
||||
virtual void outputPre(OutputBuffer &OB, OutputFlags Flags) const = 0;
|
||||
virtual void outputPost(OutputBuffer &OB, OutputFlags Flags) const = 0;
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override {
|
||||
outputPre(OS, Flags);
|
||||
outputPost(OS, Flags);
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override {
|
||||
outputPre(OB, Flags);
|
||||
outputPost(OB, Flags);
|
||||
}
|
||||
|
||||
Qualifiers Quals = Q_None;
|
||||
@@ -313,8 +313,8 @@ struct PrimitiveTypeNode : public TypeNode {
|
||||
explicit PrimitiveTypeNode(PrimitiveKind K)
|
||||
: TypeNode(NodeKind::PrimitiveType), PrimKind(K) {}
|
||||
|
||||
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void outputPost(OutputStream &OS, OutputFlags Flags) const override {}
|
||||
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override {}
|
||||
|
||||
PrimitiveKind PrimKind;
|
||||
};
|
||||
@@ -323,8 +323,8 @@ struct FunctionSignatureNode : public TypeNode {
|
||||
explicit FunctionSignatureNode(NodeKind K) : TypeNode(K) {}
|
||||
FunctionSignatureNode() : TypeNode(NodeKind::FunctionSignature) {}
|
||||
|
||||
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
// Valid if this FunctionTypeNode is the Pointee of a PointerType or
|
||||
// MemberPointerType.
|
||||
@@ -357,13 +357,13 @@ struct IdentifierNode : public Node {
|
||||
NodeArrayNode *TemplateParams = nullptr;
|
||||
|
||||
protected:
|
||||
void outputTemplateParameters(OutputStream &OS, OutputFlags Flags) const;
|
||||
void outputTemplateParameters(OutputBuffer &OB, OutputFlags Flags) const;
|
||||
};
|
||||
|
||||
struct VcallThunkIdentifierNode : public IdentifierNode {
|
||||
VcallThunkIdentifierNode() : IdentifierNode(NodeKind::VcallThunkIdentifier) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
uint64_t OffsetInVTable = 0;
|
||||
};
|
||||
@@ -372,7 +372,7 @@ struct DynamicStructorIdentifierNode : public IdentifierNode {
|
||||
DynamicStructorIdentifierNode()
|
||||
: IdentifierNode(NodeKind::DynamicStructorIdentifier) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
VariableSymbolNode *Variable = nullptr;
|
||||
QualifiedNameNode *Name = nullptr;
|
||||
@@ -382,7 +382,7 @@ struct DynamicStructorIdentifierNode : public IdentifierNode {
|
||||
struct NamedIdentifierNode : public IdentifierNode {
|
||||
NamedIdentifierNode() : IdentifierNode(NodeKind::NamedIdentifier) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
StringView Name;
|
||||
};
|
||||
@@ -392,7 +392,7 @@ struct IntrinsicFunctionIdentifierNode : public IdentifierNode {
|
||||
: IdentifierNode(NodeKind::IntrinsicFunctionIdentifier),
|
||||
Operator(Operator) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
IntrinsicFunctionKind Operator;
|
||||
};
|
||||
@@ -401,7 +401,7 @@ struct LiteralOperatorIdentifierNode : public IdentifierNode {
|
||||
LiteralOperatorIdentifierNode()
|
||||
: IdentifierNode(NodeKind::LiteralOperatorIdentifier) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
StringView Name;
|
||||
};
|
||||
@@ -410,7 +410,7 @@ struct LocalStaticGuardIdentifierNode : public IdentifierNode {
|
||||
LocalStaticGuardIdentifierNode()
|
||||
: IdentifierNode(NodeKind::LocalStaticGuardIdentifier) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
bool IsThread = false;
|
||||
uint32_t ScopeIndex = 0;
|
||||
@@ -420,7 +420,7 @@ struct ConversionOperatorIdentifierNode : public IdentifierNode {
|
||||
ConversionOperatorIdentifierNode()
|
||||
: IdentifierNode(NodeKind::ConversionOperatorIdentifier) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
// The type that this operator converts too.
|
||||
TypeNode *TargetType = nullptr;
|
||||
@@ -432,7 +432,7 @@ struct StructorIdentifierNode : public IdentifierNode {
|
||||
: IdentifierNode(NodeKind::StructorIdentifier),
|
||||
IsDestructor(IsDestructor) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
// The name of the class that this is a structor of.
|
||||
IdentifierNode *Class = nullptr;
|
||||
@@ -442,8 +442,8 @@ struct StructorIdentifierNode : public IdentifierNode {
|
||||
struct ThunkSignatureNode : public FunctionSignatureNode {
|
||||
ThunkSignatureNode() : FunctionSignatureNode(NodeKind::ThunkSignature) {}
|
||||
|
||||
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
struct ThisAdjustor {
|
||||
uint32_t StaticOffset = 0;
|
||||
@@ -457,8 +457,8 @@ struct ThunkSignatureNode : public FunctionSignatureNode {
|
||||
|
||||
struct PointerTypeNode : public TypeNode {
|
||||
PointerTypeNode() : TypeNode(NodeKind::PointerType) {}
|
||||
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
// Is this a pointer, reference, or rvalue-reference?
|
||||
PointerAffinity Affinity = PointerAffinity::None;
|
||||
@@ -474,8 +474,8 @@ struct PointerTypeNode : public TypeNode {
|
||||
struct TagTypeNode : public TypeNode {
|
||||
explicit TagTypeNode(TagKind Tag) : TypeNode(NodeKind::TagType), Tag(Tag) {}
|
||||
|
||||
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
QualifiedNameNode *QualifiedName = nullptr;
|
||||
TagKind Tag;
|
||||
@@ -484,11 +484,11 @@ struct TagTypeNode : public TypeNode {
|
||||
struct ArrayTypeNode : public TypeNode {
|
||||
ArrayTypeNode() : TypeNode(NodeKind::ArrayType) {}
|
||||
|
||||
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
void outputDimensionsImpl(OutputStream &OS, OutputFlags Flags) const;
|
||||
void outputOneDimension(OutputStream &OS, OutputFlags Flags, Node *N) const;
|
||||
void outputDimensionsImpl(OutputBuffer &OB, OutputFlags Flags) const;
|
||||
void outputOneDimension(OutputBuffer &OB, OutputFlags Flags, Node *N) const;
|
||||
|
||||
// A list of array dimensions. e.g. [3,4,5] in `int Foo[3][4][5]`
|
||||
NodeArrayNode *Dimensions = nullptr;
|
||||
@@ -499,14 +499,14 @@ struct ArrayTypeNode : public TypeNode {
|
||||
|
||||
struct IntrinsicNode : public TypeNode {
|
||||
IntrinsicNode() : TypeNode(NodeKind::IntrinsicType) {}
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override {}
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override {}
|
||||
};
|
||||
|
||||
struct CustomTypeNode : public TypeNode {
|
||||
CustomTypeNode() : TypeNode(NodeKind::Custom) {}
|
||||
|
||||
void outputPre(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void outputPost(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void outputPre(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
void outputPost(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
IdentifierNode *Identifier = nullptr;
|
||||
};
|
||||
@@ -514,9 +514,9 @@ struct CustomTypeNode : public TypeNode {
|
||||
struct NodeArrayNode : public Node {
|
||||
NodeArrayNode() : Node(NodeKind::NodeArray) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags, StringView Separator) const;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags, StringView Separator) const;
|
||||
|
||||
Node **Nodes = nullptr;
|
||||
size_t Count = 0;
|
||||
@@ -525,7 +525,7 @@ struct NodeArrayNode : public Node {
|
||||
struct QualifiedNameNode : public Node {
|
||||
QualifiedNameNode() : Node(NodeKind::QualifiedName) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
NodeArrayNode *Components = nullptr;
|
||||
|
||||
@@ -539,7 +539,7 @@ struct TemplateParameterReferenceNode : public Node {
|
||||
TemplateParameterReferenceNode()
|
||||
: Node(NodeKind::TemplateParameterReference) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
SymbolNode *Symbol = nullptr;
|
||||
|
||||
@@ -554,7 +554,7 @@ struct IntegerLiteralNode : public Node {
|
||||
IntegerLiteralNode(uint64_t Value, bool IsNegative)
|
||||
: Node(NodeKind::IntegerLiteral), Value(Value), IsNegative(IsNegative) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
uint64_t Value = 0;
|
||||
bool IsNegative = false;
|
||||
@@ -564,7 +564,7 @@ struct RttiBaseClassDescriptorNode : public IdentifierNode {
|
||||
RttiBaseClassDescriptorNode()
|
||||
: IdentifierNode(NodeKind::RttiBaseClassDescriptor) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
uint32_t NVOffset = 0;
|
||||
int32_t VBPtrOffset = 0;
|
||||
@@ -574,7 +574,7 @@ struct RttiBaseClassDescriptorNode : public IdentifierNode {
|
||||
|
||||
struct SymbolNode : public Node {
|
||||
explicit SymbolNode(NodeKind K) : Node(K) {}
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
QualifiedNameNode *Name = nullptr;
|
||||
};
|
||||
|
||||
@@ -582,7 +582,7 @@ struct SpecialTableSymbolNode : public SymbolNode {
|
||||
explicit SpecialTableSymbolNode()
|
||||
: SymbolNode(NodeKind::SpecialTableSymbol) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
QualifiedNameNode *TargetName = nullptr;
|
||||
Qualifiers Quals = Qualifiers::Q_None;
|
||||
};
|
||||
@@ -591,7 +591,7 @@ struct LocalStaticGuardVariableNode : public SymbolNode {
|
||||
LocalStaticGuardVariableNode()
|
||||
: SymbolNode(NodeKind::LocalStaticGuardVariable) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
bool IsVisible = false;
|
||||
};
|
||||
@@ -599,7 +599,7 @@ struct LocalStaticGuardVariableNode : public SymbolNode {
|
||||
struct EncodedStringLiteralNode : public SymbolNode {
|
||||
EncodedStringLiteralNode() : SymbolNode(NodeKind::EncodedStringLiteral) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
StringView DecodedString;
|
||||
bool IsTruncated = false;
|
||||
@@ -609,7 +609,7 @@ struct EncodedStringLiteralNode : public SymbolNode {
|
||||
struct VariableSymbolNode : public SymbolNode {
|
||||
VariableSymbolNode() : SymbolNode(NodeKind::VariableSymbol) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
StorageClass SC = StorageClass::None;
|
||||
TypeNode *Type = nullptr;
|
||||
@@ -618,7 +618,7 @@ struct VariableSymbolNode : public SymbolNode {
|
||||
struct FunctionSymbolNode : public SymbolNode {
|
||||
FunctionSymbolNode() : SymbolNode(NodeKind::FunctionSymbol) {}
|
||||
|
||||
void output(OutputStream &OS, OutputFlags Flags) const override;
|
||||
void output(OutputBuffer &OB, OutputFlags Flags) const override;
|
||||
|
||||
FunctionSignatureNode *Signature = nullptr;
|
||||
};
|
||||
61
lib/external/llvm-demangle/include/llvm/Demangle/README.txt
vendored
Normal file
61
lib/external/llvm-demangle/include/llvm/Demangle/README.txt
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
Itanium Name Demangler Library
|
||||
==============================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
This directory contains the generic itanium name demangler
|
||||
library. The main purpose of the library is to demangle C++ symbols,
|
||||
i.e. convert the string "_Z1fv" into "f()". You can also use the CRTP
|
||||
base ManglingParser to perform some simple analysis on the mangled
|
||||
name, or (in LLVM) use the opaque ItaniumPartialDemangler to query the
|
||||
demangled AST.
|
||||
|
||||
Why are there multiple copies of the this library in the source tree?
|
||||
---------------------------------------------------------------------
|
||||
|
||||
The canonical sources are in libcxxabi/src/demangle and some of the
|
||||
files are copied to llvm/include/llvm/Demangle. The simple reason for
|
||||
this comes from before the monorepo, and both [sub]projects need to
|
||||
demangle symbols, but neither can depend on each other.
|
||||
|
||||
* libcxxabi needs the demangler to implement __cxa_demangle, which is
|
||||
part of the itanium ABI spec.
|
||||
|
||||
* LLVM needs a copy for a bunch of places, and cannot rely on the
|
||||
system's __cxa_demangle because it a) might not be available (i.e.,
|
||||
on Windows), and b) may not be up-to-date on the latest language
|
||||
features.
|
||||
|
||||
The copy of the demangler in LLVM has some extra stuff that aren't
|
||||
needed in libcxxabi (ie, the MSVC demangler, ItaniumPartialDemangler),
|
||||
which depend on the shared generic components. Despite these
|
||||
differences, we want to keep the "core" generic demangling library
|
||||
identical between both copies to simplify development and testing.
|
||||
|
||||
If you're working on the generic library, then do the work first in
|
||||
libcxxabi, then run the cp-to-llvm.sh script in src/demangle. This
|
||||
script takes as an optional argument the path to llvm, and copies the
|
||||
changes you made to libcxxabi over. Note that this script just
|
||||
blindly overwrites all changes to the generic library in llvm, so be
|
||||
careful.
|
||||
|
||||
Because the core demangler needs to work in libcxxabi, everything
|
||||
needs to be declared in an anonymous namespace (see
|
||||
DEMANGLE_NAMESPACE_BEGIN), and you can't introduce any code that
|
||||
depends on the libcxx dylib.
|
||||
|
||||
FIXME: Now that LLVM is a monorepo, it should be possible to
|
||||
de-duplicate this code, and have both LLVM and libcxxabi depend on a
|
||||
shared demangler library.
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
The tests are split up between libcxxabi/test/{unit,}test_demangle.cpp, and
|
||||
llvm/unittest/Demangle. The llvm directory should only get tests for stuff not
|
||||
included in the core library. In the future though, we should probably move all
|
||||
the tests to LLVM.
|
||||
|
||||
It is also a really good idea to run libFuzzer after non-trivial changes, see
|
||||
libcxxabi/fuzz/cxa_demangle_fuzzer.cpp and https://llvm.org/docs/LibFuzzer.html.
|
||||
@@ -1,5 +1,5 @@
|
||||
//===--- StringView.h -------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
//===--- StringView.h ----------------*- mode:c++;eval:(read-only-mode) -*-===//
|
||||
// Do not edit! See README.txt.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
@@ -7,14 +7,16 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// FIXME: Use std::string_view instead when we support C++17.
|
||||
// There are two copies of this file in the source tree. The one under
|
||||
// libcxxabi is the original and the one under llvm is the copy. Use
|
||||
// cp-to-llvm.sh to update the copy. See README.txt for more details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef DEMANGLE_STRINGVIEW_H
|
||||
#define DEMANGLE_STRINGVIEW_H
|
||||
#ifndef LLVM_DEMANGLE_STRINGVIEW_H
|
||||
#define LLVM_DEMANGLE_STRINGVIEW_H
|
||||
|
||||
#include "DemangleConfig.h"
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
@@ -36,29 +38,23 @@ public:
|
||||
StringView(const char *Str) : First(Str), Last(Str + std::strlen(Str)) {}
|
||||
StringView() : First(nullptr), Last(nullptr) {}
|
||||
|
||||
StringView substr(size_t From) const {
|
||||
return StringView(begin() + From, size() - From);
|
||||
StringView substr(size_t Pos, size_t Len = npos) const {
|
||||
assert(Pos <= size());
|
||||
if (Len > size() - Pos)
|
||||
Len = size() - Pos;
|
||||
return StringView(begin() + Pos, Len);
|
||||
}
|
||||
|
||||
size_t find(char C, size_t From = 0) const {
|
||||
size_t FindBegin = std::min(From, size());
|
||||
// Avoid calling memchr with nullptr.
|
||||
if (FindBegin < size()) {
|
||||
if (From < size()) {
|
||||
// Just forward to memchr, which is faster than a hand-rolled loop.
|
||||
if (const void *P = ::memchr(First + FindBegin, C, size() - FindBegin))
|
||||
if (const void *P = ::memchr(First + From, C, size() - From))
|
||||
return size_t(static_cast<const char *>(P) - First);
|
||||
}
|
||||
return npos;
|
||||
}
|
||||
|
||||
StringView substr(size_t From, size_t To) const {
|
||||
if (To >= size())
|
||||
To = size() - 1;
|
||||
if (From >= size())
|
||||
From = size() - 1;
|
||||
return StringView(First + From, First + To);
|
||||
}
|
||||
|
||||
StringView dropFront(size_t N = 1) const {
|
||||
if (N >= size())
|
||||
N = size();
|
||||
@@ -105,7 +101,7 @@ public:
|
||||
bool startsWith(StringView Str) const {
|
||||
if (Str.size() > size())
|
||||
return false;
|
||||
return std::equal(Str.begin(), Str.end(), begin());
|
||||
return std::strncmp(Str.begin(), begin(), Str.size()) == 0;
|
||||
}
|
||||
|
||||
const char &operator[](size_t Idx) const { return *(begin() + Idx); }
|
||||
@@ -118,7 +114,7 @@ public:
|
||||
|
||||
inline bool operator==(const StringView &LHS, const StringView &RHS) {
|
||||
return LHS.size() == RHS.size() &&
|
||||
std::equal(LHS.begin(), LHS.end(), RHS.begin());
|
||||
std::strncmp(LHS.begin(), RHS.begin(), LHS.size()) == 0;
|
||||
}
|
||||
|
||||
DEMANGLE_NAMESPACE_END
|
||||
218
lib/external/llvm-demangle/include/llvm/Demangle/Utility.h
vendored
Normal file
218
lib/external/llvm-demangle/include/llvm/Demangle/Utility.h
vendored
Normal file
@@ -0,0 +1,218 @@
|
||||
//===--- Utility.h -------------------*- mode:c++;eval:(read-only-mode) -*-===//
|
||||
// Do not edit! See README.txt.
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Provide some utility classes for use in the demangler.
|
||||
// There are two copies of this file in the source tree. The one in libcxxabi
|
||||
// is the original and the one in llvm is the copy. Use cp-to-llvm.sh to update
|
||||
// the copy. See README.txt for more details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_DEMANGLE_UTILITY_H
|
||||
#define LLVM_DEMANGLE_UTILITY_H
|
||||
|
||||
#include "StringView.h"
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <exception>
|
||||
#include <limits>
|
||||
|
||||
DEMANGLE_NAMESPACE_BEGIN
|
||||
|
||||
// Stream that AST nodes write their string representation into after the AST
|
||||
// has been parsed.
|
||||
class OutputBuffer {
|
||||
char *Buffer = nullptr;
|
||||
size_t CurrentPosition = 0;
|
||||
size_t BufferCapacity = 0;
|
||||
|
||||
// Ensure there are at least N more positions in the buffer.
|
||||
void grow(size_t N) {
|
||||
size_t Need = N + CurrentPosition;
|
||||
if (Need > BufferCapacity) {
|
||||
// Reduce the number of reallocations, with a bit of hysteresis. The
|
||||
// number here is chosen so the first allocation will more-than-likely not
|
||||
// allocate more than 1K.
|
||||
Need += 1024 - 32;
|
||||
BufferCapacity *= 2;
|
||||
if (BufferCapacity < Need)
|
||||
BufferCapacity = Need;
|
||||
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
|
||||
if (Buffer == nullptr)
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
OutputBuffer &writeUnsigned(uint64_t N, bool isNeg = false) {
|
||||
std::array<char, 21> Temp;
|
||||
char *TempPtr = Temp.data() + Temp.size();
|
||||
|
||||
// Output at least one character.
|
||||
do {
|
||||
*--TempPtr = char('0' + N % 10);
|
||||
N /= 10;
|
||||
} while (N);
|
||||
|
||||
// Add negative sign.
|
||||
if (isNeg)
|
||||
*--TempPtr = '-';
|
||||
|
||||
return operator+=(StringView(TempPtr, Temp.data() + Temp.size()));
|
||||
}
|
||||
|
||||
public:
|
||||
OutputBuffer(char *StartBuf, size_t Size)
|
||||
: Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
|
||||
OutputBuffer() = default;
|
||||
// Non-copyable
|
||||
OutputBuffer(const OutputBuffer &) = delete;
|
||||
OutputBuffer &operator=(const OutputBuffer &) = delete;
|
||||
|
||||
operator StringView() const { return StringView(Buffer, CurrentPosition); }
|
||||
|
||||
void reset(char *Buffer_, size_t BufferCapacity_) {
|
||||
CurrentPosition = 0;
|
||||
Buffer = Buffer_;
|
||||
BufferCapacity = BufferCapacity_;
|
||||
}
|
||||
|
||||
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
|
||||
/// into the pack that we're currently printing.
|
||||
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
|
||||
unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
|
||||
|
||||
/// When zero, we're printing template args and '>' needs to be parenthesized.
|
||||
/// Use a counter so we can simply increment inside parentheses.
|
||||
unsigned GtIsGt = 1;
|
||||
|
||||
bool isGtInsideTemplateArgs() const { return GtIsGt == 0; }
|
||||
|
||||
void printOpen(char Open = '(') {
|
||||
GtIsGt++;
|
||||
*this += Open;
|
||||
}
|
||||
void printClose(char Close = ')') {
|
||||
GtIsGt--;
|
||||
*this += Close;
|
||||
}
|
||||
|
||||
OutputBuffer &operator+=(StringView R) {
|
||||
if (size_t Size = R.size()) {
|
||||
grow(Size);
|
||||
std::memcpy(Buffer + CurrentPosition, R.begin(), Size);
|
||||
CurrentPosition += Size;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputBuffer &operator+=(char C) {
|
||||
grow(1);
|
||||
Buffer[CurrentPosition++] = C;
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputBuffer &prepend(StringView R) {
|
||||
size_t Size = R.size();
|
||||
|
||||
grow(Size);
|
||||
std::memmove(Buffer + Size, Buffer, CurrentPosition);
|
||||
std::memcpy(Buffer, R.begin(), Size);
|
||||
CurrentPosition += Size;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputBuffer &operator<<(StringView R) { return (*this += R); }
|
||||
|
||||
OutputBuffer &operator<<(char C) { return (*this += C); }
|
||||
|
||||
OutputBuffer &operator<<(long long N) {
|
||||
return writeUnsigned(static_cast<unsigned long long>(std::abs(N)), N < 0);
|
||||
}
|
||||
|
||||
OutputBuffer &operator<<(unsigned long long N) {
|
||||
return writeUnsigned(N, false);
|
||||
}
|
||||
|
||||
OutputBuffer &operator<<(long N) {
|
||||
return this->operator<<(static_cast<long long>(N));
|
||||
}
|
||||
|
||||
OutputBuffer &operator<<(unsigned long N) {
|
||||
return this->operator<<(static_cast<unsigned long long>(N));
|
||||
}
|
||||
|
||||
OutputBuffer &operator<<(int N) {
|
||||
return this->operator<<(static_cast<long long>(N));
|
||||
}
|
||||
|
||||
OutputBuffer &operator<<(unsigned int N) {
|
||||
return this->operator<<(static_cast<unsigned long long>(N));
|
||||
}
|
||||
|
||||
void insert(size_t Pos, const char *S, size_t N) {
|
||||
assert(Pos <= CurrentPosition);
|
||||
if (N == 0)
|
||||
return;
|
||||
grow(N);
|
||||
std::memmove(Buffer + Pos + N, Buffer + Pos, CurrentPosition - Pos);
|
||||
std::memcpy(Buffer + Pos, S, N);
|
||||
CurrentPosition += N;
|
||||
}
|
||||
|
||||
size_t getCurrentPosition() const { return CurrentPosition; }
|
||||
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
|
||||
|
||||
char back() const {
|
||||
assert(CurrentPosition);
|
||||
return Buffer[CurrentPosition - 1];
|
||||
}
|
||||
|
||||
bool empty() const { return CurrentPosition == 0; }
|
||||
|
||||
char *getBuffer() { return Buffer; }
|
||||
char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
|
||||
size_t getBufferCapacity() const { return BufferCapacity; }
|
||||
};
|
||||
|
||||
template <class T> class ScopedOverride {
|
||||
T &Loc;
|
||||
T Original;
|
||||
|
||||
public:
|
||||
ScopedOverride(T &Loc_) : ScopedOverride(Loc_, Loc_) {}
|
||||
|
||||
ScopedOverride(T &Loc_, T NewVal) : Loc(Loc_), Original(Loc_) {
|
||||
Loc_ = std::move(NewVal);
|
||||
}
|
||||
~ScopedOverride() { Loc = std::move(Original); }
|
||||
|
||||
ScopedOverride(const ScopedOverride &) = delete;
|
||||
ScopedOverride &operator=(const ScopedOverride &) = delete;
|
||||
};
|
||||
|
||||
inline bool initializeOutputBuffer(char *Buf, size_t *N, OutputBuffer &OB,
|
||||
size_t InitSize) {
|
||||
size_t BufferSize;
|
||||
if (Buf == nullptr) {
|
||||
Buf = static_cast<char *>(std::malloc(InitSize));
|
||||
if (Buf == nullptr)
|
||||
return false;
|
||||
BufferSize = InitSize;
|
||||
} else
|
||||
BufferSize = *N;
|
||||
|
||||
OB.reset(Buf, BufferSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
DEMANGLE_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
578
lib/external/llvm-demangle/source/DLangDemangle.cpp
vendored
Normal file
578
lib/external/llvm-demangle/source/DLangDemangle.cpp
vendored
Normal file
@@ -0,0 +1,578 @@
|
||||
//===--- DLangDemangle.cpp ------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file defines a demangler for the D programming language as specified
|
||||
/// in the ABI specification, available at:
|
||||
/// https://dlang.org/spec/abi.html#name_mangling
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Demangle/Demangle.h"
|
||||
#include "llvm/Demangle/StringView.h"
|
||||
#include "llvm/Demangle/Utility.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
|
||||
using namespace llvm;
|
||||
using llvm::itanium_demangle::OutputBuffer;
|
||||
using llvm::itanium_demangle::StringView;
|
||||
|
||||
namespace {
|
||||
|
||||
/// Demangle information structure.
|
||||
struct Demangler {
|
||||
/// Initialize the information structure we use to pass around information.
|
||||
///
|
||||
/// \param Mangled String to demangle.
|
||||
Demangler(const char *Mangled);
|
||||
|
||||
/// Extract and demangle the mangled symbol and append it to the output
|
||||
/// string.
|
||||
///
|
||||
/// \param Demangled Output buffer to write the demangled name.
|
||||
///
|
||||
/// \return The remaining string on success or nullptr on failure.
|
||||
///
|
||||
/// \see https://dlang.org/spec/abi.html#name_mangling .
|
||||
/// \see https://dlang.org/spec/abi.html#MangledName .
|
||||
const char *parseMangle(OutputBuffer *Demangled);
|
||||
|
||||
private:
|
||||
/// Extract and demangle a given mangled symbol and append it to the output
|
||||
/// string.
|
||||
///
|
||||
/// \param Demangled output buffer to write the demangled name.
|
||||
/// \param Mangled mangled symbol to be demangled.
|
||||
///
|
||||
/// \return The remaining string on success or nullptr on failure.
|
||||
///
|
||||
/// \see https://dlang.org/spec/abi.html#name_mangling .
|
||||
/// \see https://dlang.org/spec/abi.html#MangledName .
|
||||
const char *parseMangle(OutputBuffer *Demangled, const char *Mangled);
|
||||
|
||||
/// Extract the number from a given string.
|
||||
///
|
||||
/// \param Mangled string to extract the number.
|
||||
/// \param Ret assigned result value.
|
||||
///
|
||||
/// \return The remaining string on success or nullptr on failure.
|
||||
///
|
||||
/// \note A result larger than UINT_MAX is considered a failure.
|
||||
///
|
||||
/// \see https://dlang.org/spec/abi.html#Number .
|
||||
const char *decodeNumber(const char *Mangled, unsigned long &Ret);
|
||||
|
||||
/// Extract the back reference position from a given string.
|
||||
///
|
||||
/// \param Mangled string to extract the back reference position.
|
||||
/// \param Ret assigned result value.
|
||||
///
|
||||
/// \return the remaining string on success or nullptr on failure.
|
||||
///
|
||||
/// \note Ret is always >= 0 on success, and unspecified on failure
|
||||
///
|
||||
/// \see https://dlang.org/spec/abi.html#back_ref .
|
||||
/// \see https://dlang.org/spec/abi.html#NumberBackRef .
|
||||
const char *decodeBackrefPos(const char *Mangled, long &Ret);
|
||||
|
||||
/// Extract the symbol pointed by the back reference form a given string.
|
||||
///
|
||||
/// \param Mangled string to extract the back reference position.
|
||||
/// \param Ret assigned result value.
|
||||
///
|
||||
/// \return the remaining string on success or nullptr on failure.
|
||||
///
|
||||
/// \see https://dlang.org/spec/abi.html#back_ref .
|
||||
const char *decodeBackref(const char *Mangled, const char *&Ret);
|
||||
|
||||
/// Extract and demangle backreferenced symbol from a given mangled symbol
|
||||
/// and append it to the output string.
|
||||
///
|
||||
/// \param Demangled output buffer to write the demangled name.
|
||||
/// \param Mangled mangled symbol to be demangled.
|
||||
///
|
||||
/// \return the remaining string on success or nullptr on failure.
|
||||
///
|
||||
/// \see https://dlang.org/spec/abi.html#back_ref .
|
||||
/// \see https://dlang.org/spec/abi.html#IdentifierBackRef .
|
||||
const char *parseSymbolBackref(OutputBuffer *Demangled, const char *Mangled);
|
||||
|
||||
/// Extract and demangle backreferenced type from a given mangled symbol
|
||||
/// and append it to the output string.
|
||||
///
|
||||
/// \param Mangled mangled symbol to be demangled.
|
||||
///
|
||||
/// \return the remaining string on success or nullptr on failure.
|
||||
///
|
||||
/// \see https://dlang.org/spec/abi.html#back_ref .
|
||||
/// \see https://dlang.org/spec/abi.html#TypeBackRef .
|
||||
const char *parseTypeBackref(const char *Mangled);
|
||||
|
||||
/// Check whether it is the beginning of a symbol name.
|
||||
///
|
||||
/// \param Mangled string to extract the symbol name.
|
||||
///
|
||||
/// \return true on success, false otherwise.
|
||||
///
|
||||
/// \see https://dlang.org/spec/abi.html#SymbolName .
|
||||
bool isSymbolName(const char *Mangled);
|
||||
|
||||
/// Extract and demangle an identifier from a given mangled symbol append it
|
||||
/// to the output string.
|
||||
///
|
||||
/// \param Demangled Output buffer to write the demangled name.
|
||||
/// \param Mangled Mangled symbol to be demangled.
|
||||
///
|
||||
/// \return The remaining string on success or nullptr on failure.
|
||||
///
|
||||
/// \see https://dlang.org/spec/abi.html#SymbolName .
|
||||
const char *parseIdentifier(OutputBuffer *Demangled, const char *Mangled);
|
||||
|
||||
/// Extract and demangle the plain identifier from a given mangled symbol and
|
||||
/// prepend/append it to the output string, with a special treatment for some
|
||||
/// magic compiler generated symbols.
|
||||
///
|
||||
/// \param Demangled Output buffer to write the demangled name.
|
||||
/// \param Mangled Mangled symbol to be demangled.
|
||||
/// \param Len Length of the mangled symbol name.
|
||||
///
|
||||
/// \return The remaining string on success or nullptr on failure.
|
||||
///
|
||||
/// \see https://dlang.org/spec/abi.html#LName .
|
||||
const char *parseLName(OutputBuffer *Demangled, const char *Mangled,
|
||||
unsigned long Len);
|
||||
|
||||
/// Extract and demangle the qualified symbol from a given mangled symbol
|
||||
/// append it to the output string.
|
||||
///
|
||||
/// \param Demangled Output buffer to write the demangled name.
|
||||
/// \param Mangled Mangled symbol to be demangled.
|
||||
///
|
||||
/// \return The remaining string on success or nullptr on failure.
|
||||
///
|
||||
/// \see https://dlang.org/spec/abi.html#QualifiedName .
|
||||
const char *parseQualified(OutputBuffer *Demangled, const char *Mangled);
|
||||
|
||||
/// Extract and demangle a type from a given mangled symbol append it to
|
||||
/// the output string.
|
||||
///
|
||||
/// \param Mangled mangled symbol to be demangled.
|
||||
///
|
||||
/// \return the remaining string on success or nullptr on failure.
|
||||
///
|
||||
/// \see https://dlang.org/spec/abi.html#Type .
|
||||
const char *parseType(const char *Mangled);
|
||||
|
||||
/// The string we are demangling.
|
||||
const char *Str;
|
||||
/// The index of the last back reference.
|
||||
int LastBackref;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
const char *Demangler::decodeNumber(const char *Mangled, unsigned long &Ret) {
|
||||
// Return nullptr if trying to extract something that isn't a digit.
|
||||
if (Mangled == nullptr || !std::isdigit(*Mangled))
|
||||
return nullptr;
|
||||
|
||||
unsigned long Val = 0;
|
||||
|
||||
do {
|
||||
unsigned long Digit = Mangled[0] - '0';
|
||||
|
||||
// Check for overflow.
|
||||
if (Val > (std::numeric_limits<unsigned int>::max() - Digit) / 10)
|
||||
return nullptr;
|
||||
|
||||
Val = Val * 10 + Digit;
|
||||
++Mangled;
|
||||
} while (std::isdigit(*Mangled));
|
||||
|
||||
if (*Mangled == '\0')
|
||||
return nullptr;
|
||||
|
||||
Ret = Val;
|
||||
return Mangled;
|
||||
}
|
||||
|
||||
const char *Demangler::decodeBackrefPos(const char *Mangled, long &Ret) {
|
||||
// Return nullptr if trying to extract something that isn't a digit
|
||||
if (Mangled == nullptr || !std::isalpha(*Mangled))
|
||||
return nullptr;
|
||||
|
||||
// Any identifier or non-basic type that has been emitted to the mangled
|
||||
// symbol before will not be emitted again, but is referenced by a special
|
||||
// sequence encoding the relative position of the original occurrence in the
|
||||
// mangled symbol name.
|
||||
// Numbers in back references are encoded with base 26 by upper case letters
|
||||
// A-Z for higher digits but lower case letters a-z for the last digit.
|
||||
// NumberBackRef:
|
||||
// [a-z]
|
||||
// [A-Z] NumberBackRef
|
||||
// ^
|
||||
unsigned long Val = 0;
|
||||
|
||||
while (std::isalpha(*Mangled)) {
|
||||
// Check for overflow
|
||||
if (Val > (std::numeric_limits<unsigned long>::max() - 25) / 26)
|
||||
break;
|
||||
|
||||
Val *= 26;
|
||||
|
||||
if (Mangled[0] >= 'a' && Mangled[0] <= 'z') {
|
||||
Val += Mangled[0] - 'a';
|
||||
if ((long)Val <= 0)
|
||||
break;
|
||||
Ret = Val;
|
||||
return Mangled + 1;
|
||||
}
|
||||
|
||||
Val += Mangled[0] - 'A';
|
||||
++Mangled;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *Demangler::decodeBackref(const char *Mangled, const char *&Ret) {
|
||||
assert(Mangled != nullptr && *Mangled == 'Q' && "Invalid back reference!");
|
||||
Ret = nullptr;
|
||||
|
||||
// Position of 'Q'
|
||||
const char *Qpos = Mangled;
|
||||
long RefPos;
|
||||
++Mangled;
|
||||
|
||||
Mangled = decodeBackrefPos(Mangled, RefPos);
|
||||
if (Mangled == nullptr)
|
||||
return nullptr;
|
||||
|
||||
if (RefPos > Qpos - Str)
|
||||
return nullptr;
|
||||
|
||||
// Set the position of the back reference.
|
||||
Ret = Qpos - RefPos;
|
||||
|
||||
return Mangled;
|
||||
}
|
||||
|
||||
const char *Demangler::parseSymbolBackref(OutputBuffer *Demangled,
|
||||
const char *Mangled) {
|
||||
// An identifier back reference always points to a digit 0 to 9.
|
||||
// IdentifierBackRef:
|
||||
// Q NumberBackRef
|
||||
// ^
|
||||
const char *Backref;
|
||||
unsigned long Len;
|
||||
|
||||
// Get position of the back reference
|
||||
Mangled = decodeBackref(Mangled, Backref);
|
||||
|
||||
// Must point to a simple identifier
|
||||
Backref = decodeNumber(Backref, Len);
|
||||
if (Backref == nullptr || strlen(Backref) < Len)
|
||||
return nullptr;
|
||||
|
||||
Backref = parseLName(Demangled, Backref, Len);
|
||||
if (Backref == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return Mangled;
|
||||
}
|
||||
|
||||
const char *Demangler::parseTypeBackref(const char *Mangled) {
|
||||
// A type back reference always points to a letter.
|
||||
// TypeBackRef:
|
||||
// Q NumberBackRef
|
||||
// ^
|
||||
const char *Backref;
|
||||
|
||||
// If we appear to be moving backwards through the mangle string, then
|
||||
// bail as this may be a recursive back reference.
|
||||
if (Mangled - Str >= LastBackref)
|
||||
return nullptr;
|
||||
|
||||
int SaveRefPos = LastBackref;
|
||||
LastBackref = Mangled - Str;
|
||||
|
||||
// Get position of the back reference.
|
||||
Mangled = decodeBackref(Mangled, Backref);
|
||||
|
||||
// Can't decode back reference.
|
||||
if (Backref == nullptr)
|
||||
return nullptr;
|
||||
|
||||
// TODO: Add support for function type back references.
|
||||
Backref = parseType(Backref);
|
||||
|
||||
LastBackref = SaveRefPos;
|
||||
|
||||
if (Backref == nullptr)
|
||||
return nullptr;
|
||||
|
||||
return Mangled;
|
||||
}
|
||||
|
||||
bool Demangler::isSymbolName(const char *Mangled) {
|
||||
long Ret;
|
||||
const char *Qref = Mangled;
|
||||
|
||||
if (std::isdigit(*Mangled))
|
||||
return true;
|
||||
|
||||
// TODO: Handle template instances.
|
||||
|
||||
if (*Mangled != 'Q')
|
||||
return false;
|
||||
|
||||
Mangled = decodeBackrefPos(Mangled + 1, Ret);
|
||||
if (Mangled == nullptr || Ret > Qref - Str)
|
||||
return false;
|
||||
|
||||
return std::isdigit(Qref[-Ret]);
|
||||
}
|
||||
|
||||
const char *Demangler::parseMangle(OutputBuffer *Demangled,
|
||||
const char *Mangled) {
|
||||
// A D mangled symbol is comprised of both scope and type information.
|
||||
// MangleName:
|
||||
// _D QualifiedName Type
|
||||
// _D QualifiedName Z
|
||||
// ^
|
||||
// The caller should have guaranteed that the start pointer is at the
|
||||
// above location.
|
||||
// Note that type is never a function type, but only the return type of
|
||||
// a function or the type of a variable.
|
||||
Mangled += 2;
|
||||
|
||||
Mangled = parseQualified(Demangled, Mangled);
|
||||
|
||||
if (Mangled != nullptr) {
|
||||
// Artificial symbols end with 'Z' and have no type.
|
||||
if (*Mangled == 'Z')
|
||||
++Mangled;
|
||||
else {
|
||||
Mangled = parseType(Mangled);
|
||||
}
|
||||
}
|
||||
|
||||
return Mangled;
|
||||
}
|
||||
|
||||
const char *Demangler::parseQualified(OutputBuffer *Demangled,
|
||||
const char *Mangled) {
|
||||
// Qualified names are identifiers separated by their encoded length.
|
||||
// Nested functions also encode their argument types without specifying
|
||||
// what they return.
|
||||
// QualifiedName:
|
||||
// SymbolFunctionName
|
||||
// SymbolFunctionName QualifiedName
|
||||
// ^
|
||||
// SymbolFunctionName:
|
||||
// SymbolName
|
||||
// SymbolName TypeFunctionNoReturn
|
||||
// SymbolName M TypeFunctionNoReturn
|
||||
// SymbolName M TypeModifiers TypeFunctionNoReturn
|
||||
// The start pointer should be at the above location.
|
||||
|
||||
// Whether it has more than one symbol
|
||||
size_t NotFirst = false;
|
||||
do {
|
||||
// Skip over anonymous symbols.
|
||||
if (*Mangled == '0') {
|
||||
do
|
||||
++Mangled;
|
||||
while (*Mangled == '0');
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (NotFirst)
|
||||
*Demangled << '.';
|
||||
NotFirst = true;
|
||||
|
||||
Mangled = parseIdentifier(Demangled, Mangled);
|
||||
|
||||
} while (Mangled && isSymbolName(Mangled));
|
||||
|
||||
return Mangled;
|
||||
}
|
||||
|
||||
const char *Demangler::parseIdentifier(OutputBuffer *Demangled,
|
||||
const char *Mangled) {
|
||||
unsigned long Len;
|
||||
|
||||
if (Mangled == nullptr || *Mangled == '\0')
|
||||
return nullptr;
|
||||
|
||||
if (*Mangled == 'Q')
|
||||
return parseSymbolBackref(Demangled, Mangled);
|
||||
|
||||
// TODO: Parse lengthless template instances.
|
||||
|
||||
const char *Endptr = decodeNumber(Mangled, Len);
|
||||
|
||||
if (Endptr == nullptr || Len == 0)
|
||||
return nullptr;
|
||||
|
||||
if (strlen(Endptr) < Len)
|
||||
return nullptr;
|
||||
|
||||
Mangled = Endptr;
|
||||
|
||||
// TODO: Parse template instances with a length prefix.
|
||||
|
||||
// There can be multiple different declarations in the same function that
|
||||
// have the same mangled name. To make the mangled names unique, a fake
|
||||
// parent in the form `__Sddd' is added to the symbol.
|
||||
if (Len >= 4 && Mangled[0] == '_' && Mangled[1] == '_' && Mangled[2] == 'S') {
|
||||
const char *NumPtr = Mangled + 3;
|
||||
while (NumPtr < (Mangled + Len) && std::isdigit(*NumPtr))
|
||||
++NumPtr;
|
||||
|
||||
if (Mangled + Len == NumPtr) {
|
||||
// Skip over the fake parent.
|
||||
Mangled += Len;
|
||||
return parseIdentifier(Demangled, Mangled);
|
||||
}
|
||||
|
||||
// Else demangle it as a plain identifier.
|
||||
}
|
||||
|
||||
return parseLName(Demangled, Mangled, Len);
|
||||
}
|
||||
|
||||
const char *Demangler::parseType(const char *Mangled) {
|
||||
if (*Mangled == '\0')
|
||||
return nullptr;
|
||||
|
||||
switch (*Mangled) {
|
||||
// TODO: Parse type qualifiers.
|
||||
// TODO: Parse function types.
|
||||
// TODO: Parse compound types.
|
||||
// TODO: Parse delegate types.
|
||||
// TODO: Parse tuple types.
|
||||
|
||||
// Basic types.
|
||||
case 'i':
|
||||
++Mangled;
|
||||
// TODO: Add type name dumping
|
||||
return Mangled;
|
||||
|
||||
// TODO: Add support for the rest of the basic types.
|
||||
|
||||
// Back referenced type.
|
||||
case 'Q':
|
||||
return parseTypeBackref(Mangled);
|
||||
|
||||
default: // unhandled.
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
const char *Demangler::parseLName(OutputBuffer *Demangled, const char *Mangled,
|
||||
unsigned long Len) {
|
||||
switch (Len) {
|
||||
case 6:
|
||||
if (strncmp(Mangled, "__initZ", Len + 1) == 0) {
|
||||
// The static initializer for a given symbol.
|
||||
Demangled->prepend("initializer for ");
|
||||
Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
|
||||
Mangled += Len;
|
||||
return Mangled;
|
||||
}
|
||||
if (strncmp(Mangled, "__vtblZ", Len + 1) == 0) {
|
||||
// The vtable symbol for a given class.
|
||||
Demangled->prepend("vtable for ");
|
||||
Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
|
||||
Mangled += Len;
|
||||
return Mangled;
|
||||
}
|
||||
break;
|
||||
|
||||
case 7:
|
||||
if (strncmp(Mangled, "__ClassZ", Len + 1) == 0) {
|
||||
// The classinfo symbol for a given class.
|
||||
Demangled->prepend("ClassInfo for ");
|
||||
Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
|
||||
Mangled += Len;
|
||||
return Mangled;
|
||||
}
|
||||
break;
|
||||
|
||||
case 11:
|
||||
if (strncmp(Mangled, "__InterfaceZ", Len + 1) == 0) {
|
||||
// The interface symbol for a given class.
|
||||
Demangled->prepend("Interface for ");
|
||||
Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
|
||||
Mangled += Len;
|
||||
return Mangled;
|
||||
}
|
||||
break;
|
||||
|
||||
case 12:
|
||||
if (strncmp(Mangled, "__ModuleInfoZ", Len + 1) == 0) {
|
||||
// The ModuleInfo symbol for a given module.
|
||||
Demangled->prepend("ModuleInfo for ");
|
||||
Demangled->setCurrentPosition(Demangled->getCurrentPosition() - 1);
|
||||
Mangled += Len;
|
||||
return Mangled;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
*Demangled << StringView(Mangled, Len);
|
||||
Mangled += Len;
|
||||
|
||||
return Mangled;
|
||||
}
|
||||
|
||||
Demangler::Demangler(const char *Mangled)
|
||||
: Str(Mangled), LastBackref(strlen(Mangled)) {}
|
||||
|
||||
const char *Demangler::parseMangle(OutputBuffer *Demangled) {
|
||||
return parseMangle(Demangled, this->Str);
|
||||
}
|
||||
|
||||
char *llvm::dlangDemangle(const char *MangledName) {
|
||||
if (MangledName == nullptr || strncmp(MangledName, "_D", 2) != 0)
|
||||
return nullptr;
|
||||
|
||||
OutputBuffer Demangled;
|
||||
if (!initializeOutputBuffer(nullptr, nullptr, Demangled, 1024))
|
||||
return nullptr;
|
||||
|
||||
if (strcmp(MangledName, "_Dmain") == 0) {
|
||||
Demangled << "D main";
|
||||
} else {
|
||||
|
||||
Demangler D = Demangler(MangledName);
|
||||
MangledName = D.parseMangle(&Demangled);
|
||||
|
||||
// Check that the entire symbol was successfully demangled.
|
||||
if (MangledName == nullptr || *MangledName != '\0') {
|
||||
std::free(Demangled.getBuffer());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// OutputBuffer's internal buffer is not null terminated and therefore we need
|
||||
// to add it to comply with C null terminated strings.
|
||||
if (Demangled.getCurrentPosition() > 0) {
|
||||
Demangled << '\0';
|
||||
Demangled.setCurrentPosition(Demangled.getCurrentPosition() - 1);
|
||||
return Demangled.getBuffer();
|
||||
}
|
||||
|
||||
std::free(Demangled.getBuffer());
|
||||
return nullptr;
|
||||
}
|
||||
64
lib/external/llvm-demangle/source/Demangle.cpp
vendored
Normal file
64
lib/external/llvm-demangle/source/Demangle.cpp
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
//===-- Demangle.cpp - Common demangling functions ------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file This file contains definitions of common demangling functions.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Demangle/Demangle.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
|
||||
static bool isItaniumEncoding(const char *S) {
|
||||
// Itanium encoding requires 1 or 3 leading underscores, followed by 'Z'.
|
||||
return std::strncmp(S, "_Z", 2) == 0 || std::strncmp(S, "___Z", 4) == 0;
|
||||
}
|
||||
|
||||
static bool isRustEncoding(const char *S) { return S[0] == '_' && S[1] == 'R'; }
|
||||
|
||||
static bool isDLangEncoding(const std::string &MangledName) {
|
||||
return MangledName.size() >= 2 && MangledName[0] == '_' &&
|
||||
MangledName[1] == 'D';
|
||||
}
|
||||
|
||||
std::string llvm::demangle(const std::string &MangledName) {
|
||||
std::string Result;
|
||||
const char *S = MangledName.c_str();
|
||||
|
||||
if (nonMicrosoftDemangle(S, Result))
|
||||
return Result;
|
||||
|
||||
if (S[0] == '_' && nonMicrosoftDemangle(S + 1, Result))
|
||||
return Result;
|
||||
|
||||
if (char *Demangled =
|
||||
microsoftDemangle(S, nullptr, nullptr, nullptr, nullptr)) {
|
||||
Result = Demangled;
|
||||
std::free(Demangled);
|
||||
return Result;
|
||||
}
|
||||
|
||||
return MangledName;
|
||||
}
|
||||
|
||||
bool llvm::nonMicrosoftDemangle(const char *MangledName, std::string &Result) {
|
||||
char *Demangled = nullptr;
|
||||
if (isItaniumEncoding(MangledName))
|
||||
Demangled = itaniumDemangle(MangledName, nullptr, nullptr, nullptr);
|
||||
else if (isRustEncoding(MangledName))
|
||||
Demangled = rustDemangle(MangledName);
|
||||
else if (isDLangEncoding(MangledName))
|
||||
Demangled = dlangDemangle(MangledName);
|
||||
|
||||
if (!Demangled)
|
||||
return false;
|
||||
|
||||
Result = Demangled;
|
||||
std::free(Demangled);
|
||||
return true;
|
||||
}
|
||||
@@ -19,9 +19,7 @@
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <numeric>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
using namespace llvm;
|
||||
using namespace llvm::itanium_demangle;
|
||||
@@ -174,6 +172,50 @@ struct DumpVisitor {
|
||||
return printStr("TemplateParamKind::Template");
|
||||
}
|
||||
}
|
||||
void print(Node::Prec P) {
|
||||
switch (P) {
|
||||
case Node::Prec::Primary:
|
||||
return printStr("Node::Prec::Primary");
|
||||
case Node::Prec::Postfix:
|
||||
return printStr("Node::Prec::Postfix");
|
||||
case Node::Prec::Unary:
|
||||
return printStr("Node::Prec::Unary");
|
||||
case Node::Prec::Cast:
|
||||
return printStr("Node::Prec::Cast");
|
||||
case Node::Prec::PtrMem:
|
||||
return printStr("Node::Prec::PtrMem");
|
||||
case Node::Prec::Multiplicative:
|
||||
return printStr("Node::Prec::Multiplicative");
|
||||
case Node::Prec::Additive:
|
||||
return printStr("Node::Prec::Additive");
|
||||
case Node::Prec::Shift:
|
||||
return printStr("Node::Prec::Shift");
|
||||
case Node::Prec::Spaceship:
|
||||
return printStr("Node::Prec::Spaceship");
|
||||
case Node::Prec::Relational:
|
||||
return printStr("Node::Prec::Relational");
|
||||
case Node::Prec::Equality:
|
||||
return printStr("Node::Prec::Equality");
|
||||
case Node::Prec::And:
|
||||
return printStr("Node::Prec::And");
|
||||
case Node::Prec::Xor:
|
||||
return printStr("Node::Prec::Xor");
|
||||
case Node::Prec::Ior:
|
||||
return printStr("Node::Prec::Ior");
|
||||
case Node::Prec::AndIf:
|
||||
return printStr("Node::Prec::AndIf");
|
||||
case Node::Prec::OrIf:
|
||||
return printStr("Node::Prec::OrIf");
|
||||
case Node::Prec::Conditional:
|
||||
return printStr("Node::Prec::Conditional");
|
||||
case Node::Prec::Assign:
|
||||
return printStr("Node::Prec::Assign");
|
||||
case Node::Prec::Comma:
|
||||
return printStr("Node::Prec::Comma");
|
||||
case Node::Prec::Default:
|
||||
return printStr("Node::Prec::Default");
|
||||
}
|
||||
}
|
||||
|
||||
void newLine() {
|
||||
printStr("\n");
|
||||
@@ -333,21 +375,21 @@ char *llvm::itaniumDemangle(const char *MangledName, char *Buf,
|
||||
|
||||
int InternalStatus = demangle_success;
|
||||
Demangler Parser(MangledName, MangledName + std::strlen(MangledName));
|
||||
OutputStream S;
|
||||
OutputBuffer OB;
|
||||
|
||||
Node *AST = Parser.parse();
|
||||
|
||||
if (AST == nullptr)
|
||||
InternalStatus = demangle_invalid_mangled_name;
|
||||
else if (!initializeOutputStream(Buf, N, S, 1024))
|
||||
else if (!initializeOutputBuffer(Buf, N, OB, 1024))
|
||||
InternalStatus = demangle_memory_alloc_failure;
|
||||
else {
|
||||
assert(Parser.ForwardTemplateRefs.empty());
|
||||
AST->print(S);
|
||||
S += '\0';
|
||||
AST->print(OB);
|
||||
OB += '\0';
|
||||
if (N != nullptr)
|
||||
*N = S.getCurrentPosition();
|
||||
Buf = S.getBuffer();
|
||||
*N = OB.getCurrentPosition();
|
||||
Buf = OB.getBuffer();
|
||||
}
|
||||
|
||||
if (Status)
|
||||
@@ -385,14 +427,14 @@ bool ItaniumPartialDemangler::partialDemangle(const char *MangledName) {
|
||||
}
|
||||
|
||||
static char *printNode(const Node *RootNode, char *Buf, size_t *N) {
|
||||
OutputStream S;
|
||||
if (!initializeOutputStream(Buf, N, S, 128))
|
||||
OutputBuffer OB;
|
||||
if (!initializeOutputBuffer(Buf, N, OB, 128))
|
||||
return nullptr;
|
||||
RootNode->print(S);
|
||||
S += '\0';
|
||||
RootNode->print(OB);
|
||||
OB += '\0';
|
||||
if (N != nullptr)
|
||||
*N = S.getCurrentPosition();
|
||||
return S.getBuffer();
|
||||
*N = OB.getCurrentPosition();
|
||||
return OB.getBuffer();
|
||||
}
|
||||
|
||||
char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
|
||||
@@ -406,8 +448,8 @@ char *ItaniumPartialDemangler::getFunctionBaseName(char *Buf, size_t *N) const {
|
||||
case Node::KAbiTagAttr:
|
||||
Name = static_cast<const AbiTagAttr *>(Name)->Base;
|
||||
continue;
|
||||
case Node::KStdQualifiedName:
|
||||
Name = static_cast<const StdQualifiedName *>(Name)->Child;
|
||||
case Node::KModuleEntity:
|
||||
Name = static_cast<const ModuleEntity *>(Name)->Name;
|
||||
continue;
|
||||
case Node::KNestedName:
|
||||
Name = static_cast<const NestedName *>(Name)->Name;
|
||||
@@ -430,8 +472,8 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
|
||||
return nullptr;
|
||||
const Node *Name = static_cast<const FunctionEncoding *>(RootNode)->getName();
|
||||
|
||||
OutputStream S;
|
||||
if (!initializeOutputStream(Buf, N, S, 128))
|
||||
OutputBuffer OB;
|
||||
if (!initializeOutputBuffer(Buf, N, OB, 128))
|
||||
return nullptr;
|
||||
|
||||
KeepGoingLocalFunction:
|
||||
@@ -447,27 +489,27 @@ char *ItaniumPartialDemangler::getFunctionDeclContextName(char *Buf,
|
||||
break;
|
||||
}
|
||||
|
||||
if (Name->getKind() == Node::KModuleEntity)
|
||||
Name = static_cast<const ModuleEntity *>(Name)->Name;
|
||||
|
||||
switch (Name->getKind()) {
|
||||
case Node::KStdQualifiedName:
|
||||
S += "std";
|
||||
break;
|
||||
case Node::KNestedName:
|
||||
static_cast<const NestedName *>(Name)->Qual->print(S);
|
||||
static_cast<const NestedName *>(Name)->Qual->print(OB);
|
||||
break;
|
||||
case Node::KLocalName: {
|
||||
auto *LN = static_cast<const LocalName *>(Name);
|
||||
LN->Encoding->print(S);
|
||||
S += "::";
|
||||
LN->Encoding->print(OB);
|
||||
OB += "::";
|
||||
Name = LN->Entity;
|
||||
goto KeepGoingLocalFunction;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
S += '\0';
|
||||
OB += '\0';
|
||||
if (N != nullptr)
|
||||
*N = S.getCurrentPosition();
|
||||
return S.getBuffer();
|
||||
*N = OB.getCurrentPosition();
|
||||
return OB.getBuffer();
|
||||
}
|
||||
|
||||
char *ItaniumPartialDemangler::getFunctionName(char *Buf, size_t *N) const {
|
||||
@@ -483,17 +525,17 @@ char *ItaniumPartialDemangler::getFunctionParameters(char *Buf,
|
||||
return nullptr;
|
||||
NodeArray Params = static_cast<FunctionEncoding *>(RootNode)->getParams();
|
||||
|
||||
OutputStream S;
|
||||
if (!initializeOutputStream(Buf, N, S, 128))
|
||||
OutputBuffer OB;
|
||||
if (!initializeOutputBuffer(Buf, N, OB, 128))
|
||||
return nullptr;
|
||||
|
||||
S += '(';
|
||||
Params.printWithComma(S);
|
||||
S += ')';
|
||||
S += '\0';
|
||||
OB += '(';
|
||||
Params.printWithComma(OB);
|
||||
OB += ')';
|
||||
OB += '\0';
|
||||
if (N != nullptr)
|
||||
*N = S.getCurrentPosition();
|
||||
return S.getBuffer();
|
||||
*N = OB.getCurrentPosition();
|
||||
return OB.getBuffer();
|
||||
}
|
||||
|
||||
char *ItaniumPartialDemangler::getFunctionReturnType(
|
||||
@@ -501,18 +543,18 @@ char *ItaniumPartialDemangler::getFunctionReturnType(
|
||||
if (!isFunction())
|
||||
return nullptr;
|
||||
|
||||
OutputStream S;
|
||||
if (!initializeOutputStream(Buf, N, S, 128))
|
||||
OutputBuffer OB;
|
||||
if (!initializeOutputBuffer(Buf, N, OB, 128))
|
||||
return nullptr;
|
||||
|
||||
if (const Node *Ret =
|
||||
static_cast<const FunctionEncoding *>(RootNode)->getReturnType())
|
||||
Ret->print(S);
|
||||
Ret->print(OB);
|
||||
|
||||
S += '\0';
|
||||
OB += '\0';
|
||||
if (N != nullptr)
|
||||
*N = S.getCurrentPosition();
|
||||
return S.getBuffer();
|
||||
*N = OB.getCurrentPosition();
|
||||
return OB.getBuffer();
|
||||
}
|
||||
|
||||
char *ItaniumPartialDemangler::finishDemangle(char *Buf, size_t *N) const {
|
||||
@@ -552,8 +594,8 @@ bool ItaniumPartialDemangler::isCtorOrDtor() const {
|
||||
case Node::KNestedName:
|
||||
N = static_cast<const NestedName *>(N)->Name;
|
||||
break;
|
||||
case Node::KStdQualifiedName:
|
||||
N = static_cast<const StdQualifiedName *>(N)->Child;
|
||||
case Node::KModuleEntity:
|
||||
N = static_cast<const ModuleEntity *>(N)->Name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -245,8 +245,8 @@ demanglePointerCVQualifiers(StringView &MangledName) {
|
||||
}
|
||||
|
||||
StringView Demangler::copyString(StringView Borrowed) {
|
||||
char *Stable = Arena.allocUnalignedBuffer(Borrowed.size() + 1);
|
||||
std::strcpy(Stable, Borrowed.begin());
|
||||
char *Stable = Arena.allocUnalignedBuffer(Borrowed.size());
|
||||
std::memcpy(Stable, Borrowed.begin(), Borrowed.size());
|
||||
|
||||
return {Stable, Borrowed.size()};
|
||||
}
|
||||
@@ -823,11 +823,15 @@ SymbolNode *Demangler::parse(StringView &MangledName) {
|
||||
}
|
||||
|
||||
TagTypeNode *Demangler::parseTagUniqueName(StringView &MangledName) {
|
||||
if (!MangledName.consumeFront(".?A"))
|
||||
if (!MangledName.consumeFront(".?A")) {
|
||||
Error = true;
|
||||
return nullptr;
|
||||
}
|
||||
MangledName.consumeFront(".?A");
|
||||
if (MangledName.empty())
|
||||
if (MangledName.empty()) {
|
||||
Error = true;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return demangleClassType(MangledName);
|
||||
}
|
||||
@@ -965,17 +969,14 @@ NamedIdentifierNode *Demangler::demangleBackRefName(StringView &MangledName) {
|
||||
void Demangler::memorizeIdentifier(IdentifierNode *Identifier) {
|
||||
// Render this class template name into a string buffer so that we can
|
||||
// memorize it for the purpose of back-referencing.
|
||||
OutputStream OS;
|
||||
if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
|
||||
OutputBuffer OB;
|
||||
if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024))
|
||||
// FIXME: Propagate out-of-memory as an error?
|
||||
std::terminate();
|
||||
Identifier->output(OS, OF_Default);
|
||||
OS << '\0';
|
||||
char *Name = OS.getBuffer();
|
||||
|
||||
StringView Owned = copyString(Name);
|
||||
Identifier->output(OB, OF_Default);
|
||||
StringView Owned = copyString(OB);
|
||||
memorizeString(Owned);
|
||||
std::free(Name);
|
||||
std::free(OB.getBuffer());
|
||||
}
|
||||
|
||||
IdentifierNode *
|
||||
@@ -1107,7 +1108,7 @@ static void writeHexDigit(char *Buffer, uint8_t Digit) {
|
||||
*Buffer = (Digit < 10) ? ('0' + Digit) : ('A' + Digit - 10);
|
||||
}
|
||||
|
||||
static void outputHex(OutputStream &OS, unsigned C) {
|
||||
static void outputHex(OutputBuffer &OB, unsigned C) {
|
||||
assert (C != 0);
|
||||
|
||||
// It's easier to do the math if we can work from right to left, but we need
|
||||
@@ -1130,43 +1131,43 @@ static void outputHex(OutputStream &OS, unsigned C) {
|
||||
TempBuffer[Pos--] = 'x';
|
||||
assert(Pos >= 0);
|
||||
TempBuffer[Pos--] = '\\';
|
||||
OS << StringView(&TempBuffer[Pos + 1]);
|
||||
OB << StringView(&TempBuffer[Pos + 1]);
|
||||
}
|
||||
|
||||
static void outputEscapedChar(OutputStream &OS, unsigned C) {
|
||||
static void outputEscapedChar(OutputBuffer &OB, unsigned C) {
|
||||
switch (C) {
|
||||
case '\0': // nul
|
||||
OS << "\\0";
|
||||
OB << "\\0";
|
||||
return;
|
||||
case '\'': // single quote
|
||||
OS << "\\\'";
|
||||
OB << "\\\'";
|
||||
return;
|
||||
case '\"': // double quote
|
||||
OS << "\\\"";
|
||||
OB << "\\\"";
|
||||
return;
|
||||
case '\\': // backslash
|
||||
OS << "\\\\";
|
||||
OB << "\\\\";
|
||||
return;
|
||||
case '\a': // bell
|
||||
OS << "\\a";
|
||||
OB << "\\a";
|
||||
return;
|
||||
case '\b': // backspace
|
||||
OS << "\\b";
|
||||
OB << "\\b";
|
||||
return;
|
||||
case '\f': // form feed
|
||||
OS << "\\f";
|
||||
OB << "\\f";
|
||||
return;
|
||||
case '\n': // new line
|
||||
OS << "\\n";
|
||||
OB << "\\n";
|
||||
return;
|
||||
case '\r': // carriage return
|
||||
OS << "\\r";
|
||||
OB << "\\r";
|
||||
return;
|
||||
case '\t': // tab
|
||||
OS << "\\t";
|
||||
OB << "\\t";
|
||||
return;
|
||||
case '\v': // vertical tab
|
||||
OS << "\\v";
|
||||
OB << "\\v";
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
@@ -1174,11 +1175,11 @@ static void outputEscapedChar(OutputStream &OS, unsigned C) {
|
||||
|
||||
if (C > 0x1F && C < 0x7F) {
|
||||
// Standard ascii char.
|
||||
OS << (char)C;
|
||||
OB << (char)C;
|
||||
return;
|
||||
}
|
||||
|
||||
outputHex(OS, C);
|
||||
outputHex(OB, C);
|
||||
}
|
||||
|
||||
static unsigned countTrailingNullBytes(const uint8_t *StringBytes, int Length) {
|
||||
@@ -1273,18 +1274,17 @@ FunctionSymbolNode *Demangler::demangleVcallThunkNode(StringView &MangledName) {
|
||||
EncodedStringLiteralNode *
|
||||
Demangler::demangleStringLiteral(StringView &MangledName) {
|
||||
// This function uses goto, so declare all variables up front.
|
||||
OutputStream OS;
|
||||
OutputBuffer OB;
|
||||
StringView CRC;
|
||||
uint64_t StringByteSize;
|
||||
bool IsWcharT = false;
|
||||
bool IsNegative = false;
|
||||
size_t CrcEndPos = 0;
|
||||
char *ResultBuffer = nullptr;
|
||||
|
||||
EncodedStringLiteralNode *Result = Arena.alloc<EncodedStringLiteralNode>();
|
||||
|
||||
// Must happen before the first `goto StringLiteralError`.
|
||||
if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
|
||||
if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024))
|
||||
// FIXME: Propagate out-of-memory as an error?
|
||||
std::terminate();
|
||||
|
||||
@@ -1329,7 +1329,7 @@ Demangler::demangleStringLiteral(StringView &MangledName) {
|
||||
goto StringLiteralError;
|
||||
wchar_t W = demangleWcharLiteral(MangledName);
|
||||
if (StringByteSize != 2 || Result->IsTruncated)
|
||||
outputEscapedChar(OS, W);
|
||||
outputEscapedChar(OB, W);
|
||||
StringByteSize -= 2;
|
||||
if (Error)
|
||||
goto StringLiteralError;
|
||||
@@ -1371,19 +1371,17 @@ Demangler::demangleStringLiteral(StringView &MangledName) {
|
||||
unsigned NextChar =
|
||||
decodeMultiByteChar(StringBytes, CharIndex, CharBytes);
|
||||
if (CharIndex + 1 < NumChars || Result->IsTruncated)
|
||||
outputEscapedChar(OS, NextChar);
|
||||
outputEscapedChar(OB, NextChar);
|
||||
}
|
||||
}
|
||||
|
||||
OS << '\0';
|
||||
ResultBuffer = OS.getBuffer();
|
||||
Result->DecodedString = copyString(ResultBuffer);
|
||||
std::free(ResultBuffer);
|
||||
Result->DecodedString = copyString(OB);
|
||||
std::free(OB.getBuffer());
|
||||
return Result;
|
||||
|
||||
StringLiteralError:
|
||||
Error = true;
|
||||
std::free(OS.getBuffer());
|
||||
std::free(OB.getBuffer());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -1447,18 +1445,17 @@ Demangler::demangleLocallyScopedNamePiece(StringView &MangledName) {
|
||||
return nullptr;
|
||||
|
||||
// Render the parent symbol's name into a buffer.
|
||||
OutputStream OS;
|
||||
if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
|
||||
OutputBuffer OB;
|
||||
if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024))
|
||||
// FIXME: Propagate out-of-memory as an error?
|
||||
std::terminate();
|
||||
OS << '`';
|
||||
Scope->output(OS, OF_Default);
|
||||
OS << '\'';
|
||||
OS << "::`" << Number << "'";
|
||||
OS << '\0';
|
||||
char *Result = OS.getBuffer();
|
||||
Identifier->Name = copyString(Result);
|
||||
std::free(Result);
|
||||
OB << '`';
|
||||
Scope->output(OB, OF_Default);
|
||||
OB << '\'';
|
||||
OB << "::`" << Number << "'";
|
||||
|
||||
Identifier->Name = copyString(OB);
|
||||
std::free(OB.getBuffer());
|
||||
return Identifier;
|
||||
}
|
||||
|
||||
@@ -1711,6 +1708,10 @@ CallingConv Demangler::demangleCallingConvention(StringView &MangledName) {
|
||||
return CallingConv::Eabi;
|
||||
case 'Q':
|
||||
return CallingConv::Vectorcall;
|
||||
case 'S':
|
||||
return CallingConv::Swift;
|
||||
case 'W':
|
||||
return CallingConv::SwiftAsync;
|
||||
}
|
||||
|
||||
return CallingConv::None;
|
||||
@@ -2309,19 +2310,19 @@ void Demangler::dumpBackReferences() {
|
||||
(int)Backrefs.FunctionParamCount);
|
||||
|
||||
// Create an output stream so we can render each type.
|
||||
OutputStream OS;
|
||||
if (!initializeOutputStream(nullptr, nullptr, OS, 1024))
|
||||
OutputBuffer OB;
|
||||
if (!initializeOutputBuffer(nullptr, nullptr, OB, 1024))
|
||||
std::terminate();
|
||||
for (size_t I = 0; I < Backrefs.FunctionParamCount; ++I) {
|
||||
OS.setCurrentPosition(0);
|
||||
OB.setCurrentPosition(0);
|
||||
|
||||
TypeNode *T = Backrefs.FunctionParams[I];
|
||||
T->output(OS, OF_Default);
|
||||
T->output(OB, OF_Default);
|
||||
|
||||
std::printf(" [%d] - %.*s\n", (int)I, (int)OS.getCurrentPosition(),
|
||||
OS.getBuffer());
|
||||
StringView B = OB;
|
||||
std::printf(" [%d] - %.*s\n", (int)I, (int)B.size(), B.begin());
|
||||
}
|
||||
std::free(OS.getBuffer());
|
||||
std::free(OB.getBuffer());
|
||||
|
||||
if (Backrefs.FunctionParamCount > 0)
|
||||
std::printf("\n");
|
||||
@@ -2338,7 +2339,7 @@ char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled,
|
||||
char *Buf, size_t *N,
|
||||
int *Status, MSDemangleFlags Flags) {
|
||||
Demangler D;
|
||||
OutputStream S;
|
||||
OutputBuffer OB;
|
||||
|
||||
StringView Name{MangledName};
|
||||
SymbolNode *AST = D.parse(Name);
|
||||
@@ -2357,18 +2358,20 @@ char *llvm::microsoftDemangle(const char *MangledName, size_t *NMangled,
|
||||
OF = OutputFlags(OF | OF_NoReturnType);
|
||||
if (Flags & MSDF_NoMemberType)
|
||||
OF = OutputFlags(OF | OF_NoMemberType);
|
||||
if (Flags & MSDF_NoVariableType)
|
||||
OF = OutputFlags(OF | OF_NoVariableType);
|
||||
|
||||
int InternalStatus = demangle_success;
|
||||
if (D.Error)
|
||||
InternalStatus = demangle_invalid_mangled_name;
|
||||
else if (!initializeOutputStream(Buf, N, S, 1024))
|
||||
else if (!initializeOutputBuffer(Buf, N, OB, 1024))
|
||||
InternalStatus = demangle_memory_alloc_failure;
|
||||
else {
|
||||
AST->output(S, OF);
|
||||
S += '\0';
|
||||
AST->output(OB, OF);
|
||||
OB += '\0';
|
||||
if (N != nullptr)
|
||||
*N = S.getCurrentPosition();
|
||||
Buf = S.getBuffer();
|
||||
*N = OB.getCurrentPosition();
|
||||
Buf = OB.getBuffer();
|
||||
}
|
||||
|
||||
if (Status)
|
||||
@@ -11,7 +11,6 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Demangle/MicrosoftDemangleNodes.h"
|
||||
#include "llvm/Demangle/DemangleConfig.h"
|
||||
#include "llvm/Demangle/Utility.h"
|
||||
#include <cctype>
|
||||
#include <string>
|
||||
@@ -21,91 +20,97 @@ using namespace ms_demangle;
|
||||
|
||||
#define OUTPUT_ENUM_CLASS_VALUE(Enum, Value, Desc) \
|
||||
case Enum::Value: \
|
||||
OS << Desc; \
|
||||
OB << Desc; \
|
||||
break;
|
||||
|
||||
// Writes a space if the last token does not end with a punctuation.
|
||||
static void outputSpaceIfNecessary(OutputStream &OS) {
|
||||
if (OS.empty())
|
||||
static void outputSpaceIfNecessary(OutputBuffer &OB) {
|
||||
if (OB.empty())
|
||||
return;
|
||||
|
||||
char C = OS.back();
|
||||
char C = OB.back();
|
||||
if (std::isalnum(C) || C == '>')
|
||||
OS << " ";
|
||||
OB << " ";
|
||||
}
|
||||
|
||||
static void outputSingleQualifier(OutputStream &OS, Qualifiers Q) {
|
||||
static void outputSingleQualifier(OutputBuffer &OB, Qualifiers Q) {
|
||||
switch (Q) {
|
||||
case Q_Const:
|
||||
OS << "const";
|
||||
OB << "const";
|
||||
break;
|
||||
case Q_Volatile:
|
||||
OS << "volatile";
|
||||
OB << "volatile";
|
||||
break;
|
||||
case Q_Restrict:
|
||||
OS << "__restrict";
|
||||
OB << "__restrict";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static bool outputQualifierIfPresent(OutputStream &OS, Qualifiers Q,
|
||||
static bool outputQualifierIfPresent(OutputBuffer &OB, Qualifiers Q,
|
||||
Qualifiers Mask, bool NeedSpace) {
|
||||
if (!(Q & Mask))
|
||||
return NeedSpace;
|
||||
|
||||
if (NeedSpace)
|
||||
OS << " ";
|
||||
OB << " ";
|
||||
|
||||
outputSingleQualifier(OS, Mask);
|
||||
outputSingleQualifier(OB, Mask);
|
||||
return true;
|
||||
}
|
||||
|
||||
static void outputQualifiers(OutputStream &OS, Qualifiers Q, bool SpaceBefore,
|
||||
static void outputQualifiers(OutputBuffer &OB, Qualifiers Q, bool SpaceBefore,
|
||||
bool SpaceAfter) {
|
||||
if (Q == Q_None)
|
||||
return;
|
||||
|
||||
size_t Pos1 = OS.getCurrentPosition();
|
||||
SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Const, SpaceBefore);
|
||||
SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Volatile, SpaceBefore);
|
||||
SpaceBefore = outputQualifierIfPresent(OS, Q, Q_Restrict, SpaceBefore);
|
||||
size_t Pos2 = OS.getCurrentPosition();
|
||||
size_t Pos1 = OB.getCurrentPosition();
|
||||
SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Const, SpaceBefore);
|
||||
SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Volatile, SpaceBefore);
|
||||
SpaceBefore = outputQualifierIfPresent(OB, Q, Q_Restrict, SpaceBefore);
|
||||
size_t Pos2 = OB.getCurrentPosition();
|
||||
if (SpaceAfter && Pos2 > Pos1)
|
||||
OS << " ";
|
||||
OB << " ";
|
||||
}
|
||||
|
||||
static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
|
||||
outputSpaceIfNecessary(OS);
|
||||
static void outputCallingConvention(OutputBuffer &OB, CallingConv CC) {
|
||||
outputSpaceIfNecessary(OB);
|
||||
|
||||
switch (CC) {
|
||||
case CallingConv::Cdecl:
|
||||
OS << "__cdecl";
|
||||
OB << "__cdecl";
|
||||
break;
|
||||
case CallingConv::Fastcall:
|
||||
OS << "__fastcall";
|
||||
OB << "__fastcall";
|
||||
break;
|
||||
case CallingConv::Pascal:
|
||||
OS << "__pascal";
|
||||
OB << "__pascal";
|
||||
break;
|
||||
case CallingConv::Regcall:
|
||||
OS << "__regcall";
|
||||
OB << "__regcall";
|
||||
break;
|
||||
case CallingConv::Stdcall:
|
||||
OS << "__stdcall";
|
||||
OB << "__stdcall";
|
||||
break;
|
||||
case CallingConv::Thiscall:
|
||||
OS << "__thiscall";
|
||||
OB << "__thiscall";
|
||||
break;
|
||||
case CallingConv::Eabi:
|
||||
OS << "__eabi";
|
||||
OB << "__eabi";
|
||||
break;
|
||||
case CallingConv::Vectorcall:
|
||||
OS << "__vectorcall";
|
||||
OB << "__vectorcall";
|
||||
break;
|
||||
case CallingConv::Clrcall:
|
||||
OS << "__clrcall";
|
||||
OB << "__clrcall";
|
||||
break;
|
||||
case CallingConv::Swift:
|
||||
OB << "__attribute__((__swiftcall__)) ";
|
||||
break;
|
||||
case CallingConv::SwiftAsync:
|
||||
OB << "__attribute__((__swiftasynccall__)) ";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -113,14 +118,16 @@ static void outputCallingConvention(OutputStream &OS, CallingConv CC) {
|
||||
}
|
||||
|
||||
std::string Node::toString(OutputFlags Flags) const {
|
||||
OutputStream OS;
|
||||
initializeOutputStream(nullptr, nullptr, OS, 1024);
|
||||
this->output(OS, Flags);
|
||||
OS << '\0';
|
||||
return {OS.getBuffer()};
|
||||
OutputBuffer OB;
|
||||
initializeOutputBuffer(nullptr, nullptr, OB, 1024);
|
||||
this->output(OB, Flags);
|
||||
StringView SV = OB;
|
||||
std::string Owned(SV.begin(), SV.end());
|
||||
std::free(OB.getBuffer());
|
||||
return Owned;
|
||||
}
|
||||
|
||||
void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
|
||||
void PrimitiveTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
switch (PrimKind) {
|
||||
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Void, "void");
|
||||
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Bool, "bool");
|
||||
@@ -144,107 +151,107 @@ void PrimitiveTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
|
||||
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Ldouble, "long double");
|
||||
OUTPUT_ENUM_CLASS_VALUE(PrimitiveKind, Nullptr, "std::nullptr_t");
|
||||
}
|
||||
outputQualifiers(OS, Quals, true, false);
|
||||
outputQualifiers(OB, Quals, true, false);
|
||||
}
|
||||
|
||||
void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags) const {
|
||||
output(OS, Flags, ", ");
|
||||
void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
output(OB, Flags, ", ");
|
||||
}
|
||||
|
||||
void NodeArrayNode::output(OutputStream &OS, OutputFlags Flags,
|
||||
void NodeArrayNode::output(OutputBuffer &OB, OutputFlags Flags,
|
||||
StringView Separator) const {
|
||||
if (Count == 0)
|
||||
return;
|
||||
if (Nodes[0])
|
||||
Nodes[0]->output(OS, Flags);
|
||||
Nodes[0]->output(OB, Flags);
|
||||
for (size_t I = 1; I < Count; ++I) {
|
||||
OS << Separator;
|
||||
Nodes[I]->output(OS, Flags);
|
||||
OB << Separator;
|
||||
Nodes[I]->output(OB, Flags);
|
||||
}
|
||||
}
|
||||
|
||||
void EncodedStringLiteralNode::output(OutputStream &OS,
|
||||
void EncodedStringLiteralNode::output(OutputBuffer &OB,
|
||||
OutputFlags Flags) const {
|
||||
switch (Char) {
|
||||
case CharKind::Wchar:
|
||||
OS << "L\"";
|
||||
OB << "L\"";
|
||||
break;
|
||||
case CharKind::Char:
|
||||
OS << "\"";
|
||||
OB << "\"";
|
||||
break;
|
||||
case CharKind::Char16:
|
||||
OS << "u\"";
|
||||
OB << "u\"";
|
||||
break;
|
||||
case CharKind::Char32:
|
||||
OS << "U\"";
|
||||
OB << "U\"";
|
||||
break;
|
||||
}
|
||||
OS << DecodedString << "\"";
|
||||
OB << DecodedString << "\"";
|
||||
if (IsTruncated)
|
||||
OS << "...";
|
||||
OB << "...";
|
||||
}
|
||||
|
||||
void IntegerLiteralNode::output(OutputStream &OS, OutputFlags Flags) const {
|
||||
void IntegerLiteralNode::output(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
if (IsNegative)
|
||||
OS << '-';
|
||||
OS << Value;
|
||||
OB << '-';
|
||||
OB << Value;
|
||||
}
|
||||
|
||||
void TemplateParameterReferenceNode::output(OutputStream &OS,
|
||||
void TemplateParameterReferenceNode::output(OutputBuffer &OB,
|
||||
OutputFlags Flags) const {
|
||||
if (ThunkOffsetCount > 0)
|
||||
OS << "{";
|
||||
OB << "{";
|
||||
else if (Affinity == PointerAffinity::Pointer)
|
||||
OS << "&";
|
||||
OB << "&";
|
||||
|
||||
if (Symbol) {
|
||||
Symbol->output(OS, Flags);
|
||||
Symbol->output(OB, Flags);
|
||||
if (ThunkOffsetCount > 0)
|
||||
OS << ", ";
|
||||
OB << ", ";
|
||||
}
|
||||
|
||||
if (ThunkOffsetCount > 0)
|
||||
OS << ThunkOffsets[0];
|
||||
OB << ThunkOffsets[0];
|
||||
for (int I = 1; I < ThunkOffsetCount; ++I) {
|
||||
OS << ", " << ThunkOffsets[I];
|
||||
OB << ", " << ThunkOffsets[I];
|
||||
}
|
||||
if (ThunkOffsetCount > 0)
|
||||
OS << "}";
|
||||
OB << "}";
|
||||
}
|
||||
|
||||
void IdentifierNode::outputTemplateParameters(OutputStream &OS,
|
||||
void IdentifierNode::outputTemplateParameters(OutputBuffer &OB,
|
||||
OutputFlags Flags) const {
|
||||
if (!TemplateParams)
|
||||
return;
|
||||
OS << "<";
|
||||
TemplateParams->output(OS, Flags);
|
||||
OS << ">";
|
||||
OB << "<";
|
||||
TemplateParams->output(OB, Flags);
|
||||
OB << ">";
|
||||
}
|
||||
|
||||
void DynamicStructorIdentifierNode::output(OutputStream &OS,
|
||||
void DynamicStructorIdentifierNode::output(OutputBuffer &OB,
|
||||
OutputFlags Flags) const {
|
||||
if (IsDestructor)
|
||||
OS << "`dynamic atexit destructor for ";
|
||||
OB << "`dynamic atexit destructor for ";
|
||||
else
|
||||
OS << "`dynamic initializer for ";
|
||||
OB << "`dynamic initializer for ";
|
||||
|
||||
if (Variable) {
|
||||
OS << "`";
|
||||
Variable->output(OS, Flags);
|
||||
OS << "''";
|
||||
OB << "`";
|
||||
Variable->output(OB, Flags);
|
||||
OB << "''";
|
||||
} else {
|
||||
OS << "'";
|
||||
Name->output(OS, Flags);
|
||||
OS << "''";
|
||||
OB << "'";
|
||||
Name->output(OB, Flags);
|
||||
OB << "''";
|
||||
}
|
||||
}
|
||||
|
||||
void NamedIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
|
||||
OS << Name;
|
||||
outputTemplateParameters(OS, Flags);
|
||||
void NamedIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
OB << Name;
|
||||
outputTemplateParameters(OB, Flags);
|
||||
}
|
||||
|
||||
void IntrinsicFunctionIdentifierNode::output(OutputStream &OS,
|
||||
void IntrinsicFunctionIdentifierNode::output(OutputBuffer &OB,
|
||||
OutputFlags Flags) const {
|
||||
switch (Operator) {
|
||||
OUTPUT_ENUM_CLASS_VALUE(IntrinsicFunctionKind, New, "operator new");
|
||||
@@ -342,188 +349,188 @@ void IntrinsicFunctionIdentifierNode::output(OutputStream &OS,
|
||||
case IntrinsicFunctionKind::None:
|
||||
break;
|
||||
}
|
||||
outputTemplateParameters(OS, Flags);
|
||||
outputTemplateParameters(OB, Flags);
|
||||
}
|
||||
|
||||
void LocalStaticGuardIdentifierNode::output(OutputStream &OS,
|
||||
void LocalStaticGuardIdentifierNode::output(OutputBuffer &OB,
|
||||
OutputFlags Flags) const {
|
||||
if (IsThread)
|
||||
OS << "`local static thread guard'";
|
||||
OB << "`local static thread guard'";
|
||||
else
|
||||
OS << "`local static guard'";
|
||||
OB << "`local static guard'";
|
||||
if (ScopeIndex > 0)
|
||||
OS << "{" << ScopeIndex << "}";
|
||||
OB << "{" << ScopeIndex << "}";
|
||||
}
|
||||
|
||||
void ConversionOperatorIdentifierNode::output(OutputStream &OS,
|
||||
void ConversionOperatorIdentifierNode::output(OutputBuffer &OB,
|
||||
OutputFlags Flags) const {
|
||||
OS << "operator";
|
||||
outputTemplateParameters(OS, Flags);
|
||||
OS << " ";
|
||||
TargetType->output(OS, Flags);
|
||||
OB << "operator";
|
||||
outputTemplateParameters(OB, Flags);
|
||||
OB << " ";
|
||||
TargetType->output(OB, Flags);
|
||||
}
|
||||
|
||||
void StructorIdentifierNode::output(OutputStream &OS, OutputFlags Flags) const {
|
||||
void StructorIdentifierNode::output(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
if (IsDestructor)
|
||||
OS << "~";
|
||||
Class->output(OS, Flags);
|
||||
outputTemplateParameters(OS, Flags);
|
||||
OB << "~";
|
||||
Class->output(OB, Flags);
|
||||
outputTemplateParameters(OB, Flags);
|
||||
}
|
||||
|
||||
void LiteralOperatorIdentifierNode::output(OutputStream &OS,
|
||||
void LiteralOperatorIdentifierNode::output(OutputBuffer &OB,
|
||||
OutputFlags Flags) const {
|
||||
OS << "operator \"\"" << Name;
|
||||
outputTemplateParameters(OS, Flags);
|
||||
OB << "operator \"\"" << Name;
|
||||
outputTemplateParameters(OB, Flags);
|
||||
}
|
||||
|
||||
void FunctionSignatureNode::outputPre(OutputStream &OS,
|
||||
void FunctionSignatureNode::outputPre(OutputBuffer &OB,
|
||||
OutputFlags Flags) const {
|
||||
if (!(Flags & OF_NoAccessSpecifier)) {
|
||||
if (FunctionClass & FC_Public)
|
||||
OS << "public: ";
|
||||
OB << "public: ";
|
||||
if (FunctionClass & FC_Protected)
|
||||
OS << "protected: ";
|
||||
OB << "protected: ";
|
||||
if (FunctionClass & FC_Private)
|
||||
OS << "private: ";
|
||||
OB << "private: ";
|
||||
}
|
||||
|
||||
if (!(Flags & OF_NoMemberType)) {
|
||||
if (!(FunctionClass & FC_Global)) {
|
||||
if (FunctionClass & FC_Static)
|
||||
OS << "static ";
|
||||
OB << "static ";
|
||||
}
|
||||
if (FunctionClass & FC_Virtual)
|
||||
OS << "virtual ";
|
||||
OB << "virtual ";
|
||||
|
||||
if (FunctionClass & FC_ExternC)
|
||||
OS << "extern \"C\" ";
|
||||
OB << "extern \"C\" ";
|
||||
}
|
||||
|
||||
if (!(Flags & OF_NoReturnType) && ReturnType) {
|
||||
ReturnType->outputPre(OS, Flags);
|
||||
OS << " ";
|
||||
ReturnType->outputPre(OB, Flags);
|
||||
OB << " ";
|
||||
}
|
||||
|
||||
if (!(Flags & OF_NoCallingConvention))
|
||||
outputCallingConvention(OS, CallConvention);
|
||||
outputCallingConvention(OB, CallConvention);
|
||||
}
|
||||
|
||||
void FunctionSignatureNode::outputPost(OutputStream &OS,
|
||||
void FunctionSignatureNode::outputPost(OutputBuffer &OB,
|
||||
OutputFlags Flags) const {
|
||||
if (!(FunctionClass & FC_NoParameterList)) {
|
||||
OS << "(";
|
||||
OB << "(";
|
||||
if (Params)
|
||||
Params->output(OS, Flags);
|
||||
Params->output(OB, Flags);
|
||||
else
|
||||
OS << "void";
|
||||
OB << "void";
|
||||
|
||||
if (IsVariadic) {
|
||||
if (OS.back() != '(')
|
||||
OS << ", ";
|
||||
OS << "...";
|
||||
if (OB.back() != '(')
|
||||
OB << ", ";
|
||||
OB << "...";
|
||||
}
|
||||
OS << ")";
|
||||
OB << ")";
|
||||
}
|
||||
|
||||
if (Quals & Q_Const)
|
||||
OS << " const";
|
||||
OB << " const";
|
||||
if (Quals & Q_Volatile)
|
||||
OS << " volatile";
|
||||
OB << " volatile";
|
||||
if (Quals & Q_Restrict)
|
||||
OS << " __restrict";
|
||||
OB << " __restrict";
|
||||
if (Quals & Q_Unaligned)
|
||||
OS << " __unaligned";
|
||||
OB << " __unaligned";
|
||||
|
||||
if (IsNoexcept)
|
||||
OS << " noexcept";
|
||||
OB << " noexcept";
|
||||
|
||||
if (RefQualifier == FunctionRefQualifier::Reference)
|
||||
OS << " &";
|
||||
OB << " &";
|
||||
else if (RefQualifier == FunctionRefQualifier::RValueReference)
|
||||
OS << " &&";
|
||||
OB << " &&";
|
||||
|
||||
if (!(Flags & OF_NoReturnType) && ReturnType)
|
||||
ReturnType->outputPost(OS, Flags);
|
||||
ReturnType->outputPost(OB, Flags);
|
||||
}
|
||||
|
||||
void ThunkSignatureNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
|
||||
OS << "[thunk]: ";
|
||||
void ThunkSignatureNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
OB << "[thunk]: ";
|
||||
|
||||
FunctionSignatureNode::outputPre(OS, Flags);
|
||||
FunctionSignatureNode::outputPre(OB, Flags);
|
||||
}
|
||||
|
||||
void ThunkSignatureNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
|
||||
void ThunkSignatureNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
if (FunctionClass & FC_StaticThisAdjust) {
|
||||
OS << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
|
||||
OB << "`adjustor{" << ThisAdjust.StaticOffset << "}'";
|
||||
} else if (FunctionClass & FC_VirtualThisAdjust) {
|
||||
if (FunctionClass & FC_VirtualThisAdjustEx) {
|
||||
OS << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
|
||||
OB << "`vtordispex{" << ThisAdjust.VBPtrOffset << ", "
|
||||
<< ThisAdjust.VBOffsetOffset << ", " << ThisAdjust.VtordispOffset
|
||||
<< ", " << ThisAdjust.StaticOffset << "}'";
|
||||
} else {
|
||||
OS << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
|
||||
OB << "`vtordisp{" << ThisAdjust.VtordispOffset << ", "
|
||||
<< ThisAdjust.StaticOffset << "}'";
|
||||
}
|
||||
}
|
||||
|
||||
FunctionSignatureNode::outputPost(OS, Flags);
|
||||
FunctionSignatureNode::outputPost(OB, Flags);
|
||||
}
|
||||
|
||||
void PointerTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
|
||||
void PointerTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
if (Pointee->kind() == NodeKind::FunctionSignature) {
|
||||
// If this is a pointer to a function, don't output the calling convention.
|
||||
// It needs to go inside the parentheses.
|
||||
const FunctionSignatureNode *Sig =
|
||||
static_cast<const FunctionSignatureNode *>(Pointee);
|
||||
Sig->outputPre(OS, OF_NoCallingConvention);
|
||||
Sig->outputPre(OB, OF_NoCallingConvention);
|
||||
} else
|
||||
Pointee->outputPre(OS, Flags);
|
||||
Pointee->outputPre(OB, Flags);
|
||||
|
||||
outputSpaceIfNecessary(OS);
|
||||
outputSpaceIfNecessary(OB);
|
||||
|
||||
if (Quals & Q_Unaligned)
|
||||
OS << "__unaligned ";
|
||||
OB << "__unaligned ";
|
||||
|
||||
if (Pointee->kind() == NodeKind::ArrayType) {
|
||||
OS << "(";
|
||||
OB << "(";
|
||||
} else if (Pointee->kind() == NodeKind::FunctionSignature) {
|
||||
OS << "(";
|
||||
OB << "(";
|
||||
const FunctionSignatureNode *Sig =
|
||||
static_cast<const FunctionSignatureNode *>(Pointee);
|
||||
outputCallingConvention(OS, Sig->CallConvention);
|
||||
OS << " ";
|
||||
outputCallingConvention(OB, Sig->CallConvention);
|
||||
OB << " ";
|
||||
}
|
||||
|
||||
if (ClassParent) {
|
||||
ClassParent->output(OS, Flags);
|
||||
OS << "::";
|
||||
ClassParent->output(OB, Flags);
|
||||
OB << "::";
|
||||
}
|
||||
|
||||
switch (Affinity) {
|
||||
case PointerAffinity::Pointer:
|
||||
OS << "*";
|
||||
OB << "*";
|
||||
break;
|
||||
case PointerAffinity::Reference:
|
||||
OS << "&";
|
||||
OB << "&";
|
||||
break;
|
||||
case PointerAffinity::RValueReference:
|
||||
OS << "&&";
|
||||
OB << "&&";
|
||||
break;
|
||||
default:
|
||||
assert(false);
|
||||
}
|
||||
outputQualifiers(OS, Quals, false, false);
|
||||
outputQualifiers(OB, Quals, false, false);
|
||||
}
|
||||
|
||||
void PointerTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
|
||||
void PointerTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
if (Pointee->kind() == NodeKind::ArrayType ||
|
||||
Pointee->kind() == NodeKind::FunctionSignature)
|
||||
OS << ")";
|
||||
OB << ")";
|
||||
|
||||
Pointee->outputPost(OS, Flags);
|
||||
Pointee->outputPost(OB, Flags);
|
||||
}
|
||||
|
||||
void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
|
||||
void TagTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
if (!(Flags & OF_NoTagSpecifier)) {
|
||||
switch (Tag) {
|
||||
OUTPUT_ENUM_CLASS_VALUE(TagKind, Class, "class");
|
||||
@@ -531,59 +538,59 @@ void TagTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
|
||||
OUTPUT_ENUM_CLASS_VALUE(TagKind, Union, "union");
|
||||
OUTPUT_ENUM_CLASS_VALUE(TagKind, Enum, "enum");
|
||||
}
|
||||
OS << " ";
|
||||
OB << " ";
|
||||
}
|
||||
QualifiedName->output(OS, Flags);
|
||||
outputQualifiers(OS, Quals, true, false);
|
||||
QualifiedName->output(OB, Flags);
|
||||
outputQualifiers(OB, Quals, true, false);
|
||||
}
|
||||
|
||||
void TagTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
|
||||
void TagTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {}
|
||||
|
||||
void ArrayTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
|
||||
ElementType->outputPre(OS, Flags);
|
||||
outputQualifiers(OS, Quals, true, false);
|
||||
void ArrayTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
ElementType->outputPre(OB, Flags);
|
||||
outputQualifiers(OB, Quals, true, false);
|
||||
}
|
||||
|
||||
void ArrayTypeNode::outputOneDimension(OutputStream &OS, OutputFlags Flags,
|
||||
void ArrayTypeNode::outputOneDimension(OutputBuffer &OB, OutputFlags Flags,
|
||||
Node *N) const {
|
||||
assert(N->kind() == NodeKind::IntegerLiteral);
|
||||
IntegerLiteralNode *ILN = static_cast<IntegerLiteralNode *>(N);
|
||||
if (ILN->Value != 0)
|
||||
ILN->output(OS, Flags);
|
||||
ILN->output(OB, Flags);
|
||||
}
|
||||
|
||||
void ArrayTypeNode::outputDimensionsImpl(OutputStream &OS,
|
||||
void ArrayTypeNode::outputDimensionsImpl(OutputBuffer &OB,
|
||||
OutputFlags Flags) const {
|
||||
if (Dimensions->Count == 0)
|
||||
return;
|
||||
|
||||
outputOneDimension(OS, Flags, Dimensions->Nodes[0]);
|
||||
outputOneDimension(OB, Flags, Dimensions->Nodes[0]);
|
||||
for (size_t I = 1; I < Dimensions->Count; ++I) {
|
||||
OS << "][";
|
||||
outputOneDimension(OS, Flags, Dimensions->Nodes[I]);
|
||||
OB << "][";
|
||||
outputOneDimension(OB, Flags, Dimensions->Nodes[I]);
|
||||
}
|
||||
}
|
||||
|
||||
void ArrayTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {
|
||||
OS << "[";
|
||||
outputDimensionsImpl(OS, Flags);
|
||||
OS << "]";
|
||||
void ArrayTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
OB << "[";
|
||||
outputDimensionsImpl(OB, Flags);
|
||||
OB << "]";
|
||||
|
||||
ElementType->outputPost(OS, Flags);
|
||||
ElementType->outputPost(OB, Flags);
|
||||
}
|
||||
|
||||
void SymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
|
||||
Name->output(OS, Flags);
|
||||
void SymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
Name->output(OB, Flags);
|
||||
}
|
||||
|
||||
void FunctionSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
|
||||
Signature->outputPre(OS, Flags);
|
||||
outputSpaceIfNecessary(OS);
|
||||
Name->output(OS, Flags);
|
||||
Signature->outputPost(OS, Flags);
|
||||
void FunctionSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
Signature->outputPre(OB, Flags);
|
||||
outputSpaceIfNecessary(OB);
|
||||
Name->output(OB, Flags);
|
||||
Signature->outputPost(OB, Flags);
|
||||
}
|
||||
|
||||
void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
|
||||
void VariableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
const char *AccessSpec = nullptr;
|
||||
bool IsStatic = true;
|
||||
switch (SC) {
|
||||
@@ -601,53 +608,52 @@ void VariableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
|
||||
break;
|
||||
}
|
||||
if (!(Flags & OF_NoAccessSpecifier) && AccessSpec)
|
||||
OS << AccessSpec << ": ";
|
||||
OB << AccessSpec << ": ";
|
||||
if (!(Flags & OF_NoMemberType) && IsStatic)
|
||||
OS << "static ";
|
||||
OB << "static ";
|
||||
|
||||
if (Type) {
|
||||
Type->outputPre(OS, Flags);
|
||||
outputSpaceIfNecessary(OS);
|
||||
if (!(Flags & OF_NoVariableType) && Type) {
|
||||
Type->outputPre(OB, Flags);
|
||||
outputSpaceIfNecessary(OB);
|
||||
}
|
||||
Name->output(OS, Flags);
|
||||
if (Type)
|
||||
Type->outputPost(OS, Flags);
|
||||
Name->output(OB, Flags);
|
||||
if (!(Flags & OF_NoVariableType) && Type)
|
||||
Type->outputPost(OB, Flags);
|
||||
}
|
||||
|
||||
void CustomTypeNode::outputPre(OutputStream &OS, OutputFlags Flags) const {
|
||||
Identifier->output(OS, Flags);
|
||||
void CustomTypeNode::outputPre(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
Identifier->output(OB, Flags);
|
||||
}
|
||||
void CustomTypeNode::outputPost(OutputStream &OS, OutputFlags Flags) const {}
|
||||
void CustomTypeNode::outputPost(OutputBuffer &OB, OutputFlags Flags) const {}
|
||||
|
||||
void QualifiedNameNode::output(OutputStream &OS, OutputFlags Flags) const {
|
||||
Components->output(OS, Flags, "::");
|
||||
void QualifiedNameNode::output(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
Components->output(OB, Flags, "::");
|
||||
}
|
||||
|
||||
void RttiBaseClassDescriptorNode::output(OutputStream &OS,
|
||||
void RttiBaseClassDescriptorNode::output(OutputBuffer &OB,
|
||||
OutputFlags Flags) const {
|
||||
OS << "`RTTI Base Class Descriptor at (";
|
||||
OS << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
|
||||
OB << "`RTTI Base Class Descriptor at (";
|
||||
OB << NVOffset << ", " << VBPtrOffset << ", " << VBTableOffset << ", "
|
||||
<< this->Flags;
|
||||
OS << ")'";
|
||||
OB << ")'";
|
||||
}
|
||||
|
||||
void LocalStaticGuardVariableNode::output(OutputStream &OS,
|
||||
void LocalStaticGuardVariableNode::output(OutputBuffer &OB,
|
||||
OutputFlags Flags) const {
|
||||
Name->output(OS, Flags);
|
||||
Name->output(OB, Flags);
|
||||
}
|
||||
|
||||
void VcallThunkIdentifierNode::output(OutputStream &OS,
|
||||
void VcallThunkIdentifierNode::output(OutputBuffer &OB,
|
||||
OutputFlags Flags) const {
|
||||
OS << "`vcall'{" << OffsetInVTable << ", {flat}}";
|
||||
OB << "`vcall'{" << OffsetInVTable << ", {flat}}";
|
||||
}
|
||||
|
||||
void SpecialTableSymbolNode::output(OutputStream &OS, OutputFlags Flags) const {
|
||||
outputQualifiers(OS, Quals, false, true);
|
||||
Name->output(OS, Flags);
|
||||
void SpecialTableSymbolNode::output(OutputBuffer &OB, OutputFlags Flags) const {
|
||||
outputQualifiers(OB, Quals, false, true);
|
||||
Name->output(OB, Flags);
|
||||
if (TargetName) {
|
||||
OS << "{for `";
|
||||
TargetName->output(OS, Flags);
|
||||
OS << "'}";
|
||||
OB << "{for `";
|
||||
TargetName->output(OB, Flags);
|
||||
OB << "'}";
|
||||
}
|
||||
return;
|
||||
}
|
||||
1265
lib/external/llvm-demangle/source/RustDemangle.cpp
vendored
Normal file
1265
lib/external/llvm-demangle/source/RustDemangle.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
13
lib/external/llvm/CMakeLists.txt
vendored
13
lib/external/llvm/CMakeLists.txt
vendored
@@ -1,13 +0,0 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
project(LLVMDemangle)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
add_library(LLVMDemangle STATIC
|
||||
Demangle/Demangle.cpp
|
||||
Demangle/ItaniumDemangle.cpp
|
||||
Demangle/MicrosoftDemangle.cpp
|
||||
Demangle/MicrosoftDemangleNodes.cpp
|
||||
)
|
||||
|
||||
target_include_directories(LLVMDemangle PUBLIC include)
|
||||
36
lib/external/llvm/Demangle/Demangle.cpp
vendored
36
lib/external/llvm/Demangle/Demangle.cpp
vendored
@@ -1,36 +0,0 @@
|
||||
//===-- Demangle.cpp - Common demangling functions ------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file This file contains definitions of common demangling functions.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Demangle/Demangle.h"
|
||||
#include <cstdlib>
|
||||
|
||||
static bool isItaniumEncoding(const std::string &MangledName) {
|
||||
size_t Pos = MangledName.find_first_not_of('_');
|
||||
// A valid Itanium encoding requires 1-4 leading underscores, followed by 'Z'.
|
||||
return Pos > 0 && Pos <= 4 && MangledName[Pos] == 'Z';
|
||||
}
|
||||
|
||||
std::string llvm::demangle(const std::string &MangledName) {
|
||||
char *Demangled;
|
||||
if (isItaniumEncoding(MangledName))
|
||||
Demangled = itaniumDemangle(MangledName.c_str(), nullptr, nullptr, nullptr);
|
||||
else
|
||||
Demangled = microsoftDemangle(MangledName.c_str(), nullptr, nullptr,
|
||||
nullptr, nullptr);
|
||||
|
||||
if (!Demangled)
|
||||
return MangledName;
|
||||
|
||||
std::string Ret = Demangled;
|
||||
free(Demangled);
|
||||
return Ret;
|
||||
}
|
||||
191
lib/external/llvm/include/llvm/Demangle/Utility.h
vendored
191
lib/external/llvm/include/llvm/Demangle/Utility.h
vendored
@@ -1,191 +0,0 @@
|
||||
//===--- Utility.h ----------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Provide some utility classes for use in the demangler(s).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef DEMANGLE_UTILITY_H
|
||||
#define DEMANGLE_UTILITY_H
|
||||
|
||||
#include "StringView.h"
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
|
||||
DEMANGLE_NAMESPACE_BEGIN
|
||||
|
||||
// Stream that AST nodes write their string representation into after the AST
|
||||
// has been parsed.
|
||||
class OutputStream {
|
||||
char *Buffer = nullptr;
|
||||
size_t CurrentPosition = 0;
|
||||
size_t BufferCapacity = 0;
|
||||
|
||||
// Ensure there is at least n more positions in buffer.
|
||||
void grow(size_t N) {
|
||||
if (N + CurrentPosition >= BufferCapacity) {
|
||||
BufferCapacity *= 2;
|
||||
if (BufferCapacity < N + CurrentPosition)
|
||||
BufferCapacity = N + CurrentPosition;
|
||||
Buffer = static_cast<char *>(std::realloc(Buffer, BufferCapacity));
|
||||
if (Buffer == nullptr)
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
void writeUnsigned(uint64_t N, bool isNeg = false) {
|
||||
// Handle special case...
|
||||
if (N == 0) {
|
||||
*this << '0';
|
||||
return;
|
||||
}
|
||||
|
||||
char Temp[21];
|
||||
char *TempPtr = std::end(Temp);
|
||||
|
||||
while (N) {
|
||||
*--TempPtr = '0' + char(N % 10);
|
||||
N /= 10;
|
||||
}
|
||||
|
||||
// Add negative sign...
|
||||
if (isNeg)
|
||||
*--TempPtr = '-';
|
||||
this->operator<<(StringView(TempPtr, std::end(Temp)));
|
||||
}
|
||||
|
||||
public:
|
||||
OutputStream(char *StartBuf, size_t Size)
|
||||
: Buffer(StartBuf), CurrentPosition(0), BufferCapacity(Size) {}
|
||||
OutputStream() = default;
|
||||
void reset(char *Buffer_, size_t BufferCapacity_) {
|
||||
CurrentPosition = 0;
|
||||
Buffer = Buffer_;
|
||||
BufferCapacity = BufferCapacity_;
|
||||
}
|
||||
|
||||
/// If a ParameterPackExpansion (or similar type) is encountered, the offset
|
||||
/// into the pack that we're currently printing.
|
||||
unsigned CurrentPackIndex = std::numeric_limits<unsigned>::max();
|
||||
unsigned CurrentPackMax = std::numeric_limits<unsigned>::max();
|
||||
|
||||
OutputStream &operator+=(StringView R) {
|
||||
size_t Size = R.size();
|
||||
if (Size == 0)
|
||||
return *this;
|
||||
grow(Size);
|
||||
std::memmove(Buffer + CurrentPosition, R.begin(), Size);
|
||||
CurrentPosition += Size;
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputStream &operator+=(char C) {
|
||||
grow(1);
|
||||
Buffer[CurrentPosition++] = C;
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputStream &operator<<(StringView R) { return (*this += R); }
|
||||
|
||||
OutputStream &operator<<(char C) { return (*this += C); }
|
||||
|
||||
OutputStream &operator<<(long long N) {
|
||||
if (N < 0)
|
||||
writeUnsigned(static_cast<unsigned long long>(-N), true);
|
||||
else
|
||||
writeUnsigned(static_cast<unsigned long long>(N));
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputStream &operator<<(unsigned long long N) {
|
||||
writeUnsigned(N, false);
|
||||
return *this;
|
||||
}
|
||||
|
||||
OutputStream &operator<<(long N) {
|
||||
return this->operator<<(static_cast<long long>(N));
|
||||
}
|
||||
|
||||
OutputStream &operator<<(unsigned long N) {
|
||||
return this->operator<<(static_cast<unsigned long long>(N));
|
||||
}
|
||||
|
||||
OutputStream &operator<<(int N) {
|
||||
return this->operator<<(static_cast<long long>(N));
|
||||
}
|
||||
|
||||
OutputStream &operator<<(unsigned int N) {
|
||||
return this->operator<<(static_cast<unsigned long long>(N));
|
||||
}
|
||||
|
||||
size_t getCurrentPosition() const { return CurrentPosition; }
|
||||
void setCurrentPosition(size_t NewPos) { CurrentPosition = NewPos; }
|
||||
|
||||
char back() const {
|
||||
return CurrentPosition ? Buffer[CurrentPosition - 1] : '\0';
|
||||
}
|
||||
|
||||
bool empty() const { return CurrentPosition == 0; }
|
||||
|
||||
char *getBuffer() { return Buffer; }
|
||||
char *getBufferEnd() { return Buffer + CurrentPosition - 1; }
|
||||
size_t getBufferCapacity() const { return BufferCapacity; }
|
||||
};
|
||||
|
||||
template <class T> class SwapAndRestore {
|
||||
T &Restore;
|
||||
T OriginalValue;
|
||||
bool ShouldRestore = true;
|
||||
|
||||
public:
|
||||
SwapAndRestore(T &Restore_) : SwapAndRestore(Restore_, Restore_) {}
|
||||
|
||||
SwapAndRestore(T &Restore_, T NewVal)
|
||||
: Restore(Restore_), OriginalValue(Restore) {
|
||||
Restore = std::move(NewVal);
|
||||
}
|
||||
~SwapAndRestore() {
|
||||
if (ShouldRestore)
|
||||
Restore = std::move(OriginalValue);
|
||||
}
|
||||
|
||||
void shouldRestore(bool ShouldRestore_) { ShouldRestore = ShouldRestore_; }
|
||||
|
||||
void restoreNow(bool Force) {
|
||||
if (!Force && !ShouldRestore)
|
||||
return;
|
||||
|
||||
Restore = std::move(OriginalValue);
|
||||
ShouldRestore = false;
|
||||
}
|
||||
|
||||
SwapAndRestore(const SwapAndRestore &) = delete;
|
||||
SwapAndRestore &operator=(const SwapAndRestore &) = delete;
|
||||
};
|
||||
|
||||
inline bool initializeOutputStream(char *Buf, size_t *N, OutputStream &S,
|
||||
size_t InitSize) {
|
||||
size_t BufferSize;
|
||||
if (Buf == nullptr) {
|
||||
Buf = static_cast<char *>(std::malloc(InitSize));
|
||||
if (Buf == nullptr)
|
||||
return false;
|
||||
BufferSize = InitSize;
|
||||
} else
|
||||
BufferSize = *N;
|
||||
|
||||
S.reset(Buf, BufferSize);
|
||||
return true;
|
||||
}
|
||||
|
||||
DEMANGLE_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
2
lib/external/nativefiledialog
vendored
2
lib/external/nativefiledialog
vendored
Submodule lib/external/nativefiledialog updated: 3311592818...6967d28b06
2
lib/external/pattern_language
vendored
2
lib/external/pattern_language
vendored
Submodule lib/external/pattern_language updated: a8c44795db...0798f36a04
@@ -10,16 +10,13 @@ set_target_properties(imgui PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/microtar ${CMAKE_CURRENT_BINARY_DIR}/external/microtar EXCLUDE_FROM_ALL)
|
||||
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(NFD_PORTAL ON CACHE BOOL "Use Portals for Linux file dialogs" FORCE)
|
||||
set(NFD_USE_ALLOWEDCONTENTTYPES OFF CACHE BOOL "Disable allowedContentTypes for macOS file dialogs" FORCE)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/nativefiledialog ${CMAKE_CURRENT_BINARY_DIR}/external/nativefiledialog EXCLUDE_FROM_ALL)
|
||||
set_target_properties(nfd PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
target_compile_definitions(nfd PUBLIC NFD_MACOS_ALLOWEDCONTENTTYPES=0)
|
||||
|
||||
set(LIBROMFS_RESOURCE_LOCATION ${IMHEX_BASE_FOLDER}/resources/romfs)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/external/libromfs EXCLUDE_FROM_ALL)
|
||||
set_target_properties(libromfs PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/intervaltree ${CMAKE_CURRENT_BINARY_DIR}/external/intervaltree EXCLUDE_FROM_ALL)
|
||||
set_target_properties(intervaltree PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(XDGPP_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}/../external/xdgpp")
|
||||
set(CURL_USE_MBEDTLS ON)
|
||||
set(BUILD_CURL_EXE OFF)
|
||||
@@ -28,6 +25,16 @@ set(FPHSA_NAME_MISMATCHED ON CACHE BOOL "")
|
||||
# Find packages
|
||||
find_package(PkgConfig REQUIRED)
|
||||
|
||||
if (NOT USE_SYSTEM_NFD)
|
||||
set(NFD_PORTAL ON CACHE BOOL "Use Portals for Linux file dialogs" FORCE)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/nativefiledialog ${CMAKE_CURRENT_BINARY_DIR}/external/nativefiledialog EXCLUDE_FROM_ALL)
|
||||
set_target_properties(nfd PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
set(NFD_LIBRARIES nfd)
|
||||
else()
|
||||
find_package(nfd)
|
||||
set(NFD_LIBRARIES nfd)
|
||||
endif()
|
||||
|
||||
if(NOT USE_SYSTEM_NLOHMANN_JSON)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/nlohmann_json ${CMAKE_CURRENT_BINARY_DIR}/external/nlohmann_json EXCLUDE_FROM_ALL)
|
||||
set(NLOHMANN_JSON_LIBRARIES nlohmann_json)
|
||||
@@ -51,11 +58,11 @@ if(NOT USE_SYSTEM_CURL)
|
||||
set(LIBCURL_LIBRARIES libcurl)
|
||||
else()
|
||||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl>=7.78.0)
|
||||
pkg_check_modules(LIBCURL REQUIRED IMPORTED_TARGET libcurl>=7.76.1)
|
||||
endif()
|
||||
|
||||
if (NOT USE_SYSTEM_LLVM)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/llvm ${CMAKE_CURRENT_BINARY_DIR}/external/llvm EXCLUDE_FROM_ALL)
|
||||
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/llvm-demangle ${CMAKE_CURRENT_BINARY_DIR}/external/llvm-demangle EXCLUDE_FROM_ALL)
|
||||
set_target_properties(LLVMDemangle PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
else()
|
||||
find_package(LLVM REQUIRED Demangle)
|
||||
@@ -112,6 +119,7 @@ set(LIBIMHEX_SOURCES
|
||||
source/api/keybinding.cpp
|
||||
source/api/plugin_manager.cpp
|
||||
source/api/localization.cpp
|
||||
source/api/project_file_manager.cpp
|
||||
|
||||
source/data_processor/attribute.cpp
|
||||
source/data_processor/link.cpp
|
||||
@@ -125,7 +133,6 @@ set(LIBIMHEX_SOURCES
|
||||
source/helpers/file.cpp
|
||||
source/helpers/socket.cpp
|
||||
source/helpers/patches.cpp
|
||||
source/helpers/project_file_handler.cpp
|
||||
source/helpers/encoding_file.cpp
|
||||
source/helpers/logger.cpp
|
||||
source/helpers/tar.cpp
|
||||
@@ -165,4 +172,4 @@ if (APPLE)
|
||||
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
|
||||
endif ()
|
||||
|
||||
target_link_libraries(libimhex PUBLIC dl imgui nfd magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs libpl)
|
||||
target_link_libraries(libimhex PUBLIC dl imgui ${NFD_LIBRARIES} magic ${CAPSTONE_LIBRARIES} LLVMDemangle microtar ${NLOHMANN_JSON_LIBRARIES} ${YARA_LIBRARIES} ${LIBCURL_LIBRARIES} ${MBEDTLS_LIBRARIES} ${FMT_LIBRARIES} ${Python_LIBRARIES} libromfs libpl intervaltree)
|
||||
|
||||
@@ -136,7 +136,7 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<pl::PatternLanguage> createDefaultRuntime(prv::Provider *provider);
|
||||
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider);
|
||||
|
||||
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler);
|
||||
|
||||
@@ -224,7 +224,7 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
using CreatorFunction = std::function<dp::Node *()>;
|
||||
using CreatorFunction = std::function<std::unique_ptr<dp::Node>()>;
|
||||
|
||||
struct Entry {
|
||||
std::string category;
|
||||
@@ -239,11 +239,15 @@ namespace hex {
|
||||
|
||||
template<std::derived_from<dp::Node> T, typename... Args>
|
||||
void add(const std::string &unlocalizedCategory, const std::string &unlocalizedName, Args &&...args) {
|
||||
add(impl::Entry { unlocalizedCategory.c_str(), unlocalizedName.c_str(), [=] {
|
||||
auto node = new T(std::forward<Args>(args)...);
|
||||
node->setUnlocalizedName(unlocalizedName);
|
||||
return node;
|
||||
} });
|
||||
add(impl::Entry {
|
||||
unlocalizedCategory.c_str(),
|
||||
unlocalizedName.c_str(),
|
||||
[=] {
|
||||
auto node = std::make_unique<T>(std::forward<Args>(args)...);
|
||||
node->setUnlocalizedName(unlocalizedName);
|
||||
return node;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void addSeparator();
|
||||
@@ -330,20 +334,22 @@ namespace hex {
|
||||
}
|
||||
|
||||
template<std::derived_from<hex::prv::Provider> T>
|
||||
void add(const std::string &unlocalizedName, bool addToList = true) {
|
||||
(void)EventManager::subscribe<RequestCreateProvider>([expectedName = unlocalizedName](const std::string &name, hex::prv::Provider **provider) {
|
||||
void add(bool addToList = true) {
|
||||
auto typeName = T().getTypeName();
|
||||
|
||||
(void)EventManager::subscribe<RequestCreateProvider>([expectedName = typeName](const std::string &name, bool skipLoadInterface, hex::prv::Provider **provider) {
|
||||
if (name != expectedName) return;
|
||||
|
||||
auto newProvider = new T();
|
||||
prv::Provider *newProvider = new T();
|
||||
|
||||
hex::ImHexApi::Provider::add(newProvider);
|
||||
hex::ImHexApi::Provider::add(newProvider, skipLoadInterface);
|
||||
|
||||
if (provider != nullptr)
|
||||
*provider = newProvider;
|
||||
});
|
||||
|
||||
if (addToList)
|
||||
impl::addProviderName(unlocalizedName);
|
||||
impl::addProviderName(typeName);
|
||||
}
|
||||
|
||||
std::vector<std::string> &getEntries();
|
||||
|
||||
@@ -18,16 +18,12 @@
|
||||
|
||||
struct GLFWwindow;
|
||||
|
||||
namespace pl {
|
||||
class Pattern;
|
||||
}
|
||||
|
||||
namespace hex {
|
||||
|
||||
class EventId {
|
||||
public:
|
||||
explicit constexpr EventId(const char *func = __builtin_FUNCTION(), u32 line = __builtin_LINE()) {
|
||||
this->m_hash = line ^ 123456789;
|
||||
this->m_hash = line ^ 987654321;
|
||||
for (auto c : std::string_view(func)) {
|
||||
this->m_hash = (this->m_hash >> 5) | (this->m_hash << 27);
|
||||
this->m_hash ^= c;
|
||||
@@ -111,13 +107,14 @@ namespace hex {
|
||||
EVENT_DEF(EventHighlightingChanged);
|
||||
EVENT_DEF(EventWindowClosing, GLFWwindow *);
|
||||
EVENT_DEF(EventRegionSelected, Region);
|
||||
EVENT_DEF(EventProjectFileStore);
|
||||
EVENT_DEF(EventProjectFileLoad);
|
||||
EVENT_DEF(EventSettingsChanged);
|
||||
EVENT_DEF(EventAbnormalTermination, int);
|
||||
EVENT_DEF(EventOSThemeChanged);
|
||||
EVENT_DEF(EventProviderCreated, prv::Provider *);
|
||||
EVENT_DEF(EventProviderChanged, prv::Provider *, prv::Provider *);
|
||||
EVENT_DEF(EventProviderOpened, prv::Provider *);
|
||||
EVENT_DEF(EventProviderClosing, prv::Provider *, bool *);
|
||||
EVENT_DEF(EventProviderClosed, prv::Provider *);
|
||||
EVENT_DEF(EventProviderDeleted, prv::Provider *);
|
||||
EVENT_DEF(EventFrameBegin);
|
||||
EVENT_DEF(EventFrameEnd);
|
||||
@@ -129,10 +126,11 @@ namespace hex {
|
||||
EVENT_DEF(RequestSetPatternLanguageCode, std::string);
|
||||
EVENT_DEF(RequestChangeWindowTitle, std::string);
|
||||
EVENT_DEF(RequestCloseImHex, bool);
|
||||
EVENT_DEF(RequestRestartImHex);
|
||||
EVENT_DEF(RequestOpenFile, std::fs::path);
|
||||
EVENT_DEF(RequestChangeTheme, u32);
|
||||
EVENT_DEF(RequestOpenPopup, std::string);
|
||||
EVENT_DEF(RequestCreateProvider, std::string, hex::prv::Provider **);
|
||||
EVENT_DEF(RequestCreateProvider, std::string, bool, hex::prv::Provider **);
|
||||
|
||||
EVENT_DEF(RequestShowInfoPopup, std::string);
|
||||
EVENT_DEF(RequestShowErrorPopup, std::string);
|
||||
|
||||
@@ -119,6 +119,13 @@ namespace hex {
|
||||
|
||||
namespace Provider {
|
||||
|
||||
namespace impl {
|
||||
|
||||
void resetClosingProvider();
|
||||
prv::Provider* getClosingProvider();
|
||||
|
||||
}
|
||||
|
||||
prv::Provider *get();
|
||||
const std::vector<prv::Provider *> &getProviders();
|
||||
|
||||
@@ -126,23 +133,20 @@ namespace hex {
|
||||
|
||||
bool isValid();
|
||||
|
||||
void add(prv::Provider *provider);
|
||||
void markDirty();
|
||||
void resetDirty();
|
||||
bool isDirty();
|
||||
|
||||
void add(prv::Provider *provider, bool skipLoadInterface = false);
|
||||
|
||||
template<std::derived_from<prv::Provider> T>
|
||||
void add(auto &&...args) {
|
||||
add(new T(std::forward<decltype(args)>(args)...));
|
||||
}
|
||||
|
||||
void remove(prv::Provider *provider);
|
||||
void remove(prv::Provider *provider, bool noQuestions = false);
|
||||
|
||||
}
|
||||
|
||||
namespace Tasks {
|
||||
|
||||
Task createTask(const std::string &unlocalizedName, u64 maxValue);
|
||||
|
||||
void doLater(const std::function<void()> &function);
|
||||
std::vector<std::function<void()>> &getDeferredCalls();
|
||||
prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface = false);
|
||||
|
||||
}
|
||||
|
||||
@@ -197,6 +201,7 @@ namespace hex {
|
||||
|
||||
std::map<std::string, std::string> &getInitArguments();
|
||||
|
||||
constexpr static float DefaultFontSize = 13.0;
|
||||
const std::fs::path &getCustomFontPath();
|
||||
float getFontSize();
|
||||
|
||||
|
||||
@@ -179,10 +179,10 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
static constexpr auto CTRL = Key(static_cast<Keys>(0x1000'0000));
|
||||
static constexpr auto ALT = Key(static_cast<Keys>(0x2000'0000));
|
||||
static constexpr auto SHIFT = Key(static_cast<Keys>(0x3000'0000));
|
||||
static constexpr auto SUPER = Key(static_cast<Keys>(0x4000'0000));
|
||||
constexpr static auto CTRL = Key(static_cast<Keys>(0x1000'0000));
|
||||
constexpr static auto ALT = Key(static_cast<Keys>(0x2000'0000));
|
||||
constexpr static auto SHIFT = Key(static_cast<Keys>(0x4000'0000));
|
||||
constexpr static auto SUPER = Key(static_cast<Keys>(0x8000'0000));
|
||||
|
||||
class ShortcutManager {
|
||||
public:
|
||||
|
||||
58
lib/libimhex/include/hex/api/project_file_manager.hpp
Normal file
58
lib/libimhex/include/hex/api/project_file_manager.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/helpers/tar.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class ProjectFile {
|
||||
public:
|
||||
struct Handler {
|
||||
using Function = std::function<bool(const std::fs::path &, Tar &tar)>;
|
||||
std::fs::path basePath;
|
||||
Function load, store;
|
||||
};
|
||||
|
||||
struct ProviderHandler {
|
||||
using Function = std::function<bool(prv::Provider *provider, const std::fs::path &, Tar &tar)>;
|
||||
std::fs::path basePath;
|
||||
Function load, store;
|
||||
};
|
||||
|
||||
static bool load(const std::fs::path &filePath);
|
||||
static bool store(std::optional<std::fs::path> filePath = std::nullopt);
|
||||
|
||||
static void registerHandler(const Handler &handler) {
|
||||
getHandlers().push_back(handler);
|
||||
}
|
||||
|
||||
static void registerPerProviderHandler(const ProviderHandler &handler) {
|
||||
getProviderHandlers().push_back(handler);
|
||||
}
|
||||
|
||||
static std::vector<Handler>& getHandlers() {
|
||||
return s_handlers;
|
||||
}
|
||||
|
||||
static std::vector<ProviderHandler>& getProviderHandlers() {
|
||||
return s_providerHandlers;
|
||||
}
|
||||
|
||||
private:
|
||||
ProjectFile() = default;
|
||||
|
||||
static std::fs::path s_currProjectPath;
|
||||
static std::vector<Handler> s_handlers;
|
||||
static std::vector<ProviderHandler> s_providerHandlers;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -2,40 +2,105 @@
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <list>
|
||||
#include <cstdio>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
#include <cstdint>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class TaskHolder;
|
||||
class TaskManager;
|
||||
|
||||
class Task {
|
||||
public:
|
||||
Task() = default;
|
||||
Task(const std::string &unlocalizedName, u64 maxValue);
|
||||
Task(std::string unlocalizedName, u64 maxValue, std::function<void(Task &)> function);
|
||||
|
||||
Task(const Task&) = delete;
|
||||
Task(Task &&other) noexcept;
|
||||
~Task();
|
||||
|
||||
Task(Task &&other) noexcept;
|
||||
void update(u64 value = 0);
|
||||
void setMaxValue(u64 value);
|
||||
|
||||
void setMaxValue(u64 maxValue);
|
||||
void update(u64 currValue);
|
||||
void finish();
|
||||
[[nodiscard]] bool isFinished() const;
|
||||
[[nodiscard]] bool hadException() const;
|
||||
[[nodiscard]] bool wasInterrupted() const;
|
||||
void clearException();
|
||||
[[nodiscard]] std::string getExceptionMessage() const;
|
||||
|
||||
[[nodiscard]] double getProgress() const;
|
||||
[[nodiscard]] const std::string &getUnlocalizedName();
|
||||
[[nodiscard]] u64 getValue() const;
|
||||
[[nodiscard]] u64 getMaxValue() const;
|
||||
|
||||
[[nodiscard]] const std::string &getName() const;
|
||||
void interrupt();
|
||||
|
||||
[[nodiscard]] bool isPending() const;
|
||||
|
||||
static size_t getRunningTaskCount();
|
||||
static std::list<Task *> &getRunningTasks() { return Task::s_runningTasks; }
|
||||
static std::mutex &getTaskMutex() { return Task::s_taskMutex; }
|
||||
void setInterruptCallback(std::function<void()> callback);
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
u64 m_maxValue = 0, m_currValue = 0;
|
||||
void finish();
|
||||
void interruption();
|
||||
void exception(const char *message);
|
||||
|
||||
static std::list<Task *> s_runningTasks;
|
||||
static std::mutex s_taskMutex;
|
||||
private:
|
||||
mutable std::mutex m_mutex;
|
||||
|
||||
std::string m_unlocalizedName;
|
||||
u64 m_currValue, m_maxValue;
|
||||
std::thread m_thread;
|
||||
std::function<void()> m_interruptCallback;
|
||||
|
||||
bool m_shouldInterrupt = false;
|
||||
|
||||
bool m_interrupted = false;
|
||||
bool m_finished = false;
|
||||
bool m_hadException = false;
|
||||
std::string m_exceptionMessage;
|
||||
|
||||
struct TaskInterruptor { virtual ~TaskInterruptor() = default; };
|
||||
|
||||
friend class TaskHolder;
|
||||
friend class TaskManager;
|
||||
};
|
||||
|
||||
class TaskHolder {
|
||||
public:
|
||||
TaskHolder() = default;
|
||||
explicit TaskHolder(std::weak_ptr<Task> task) : m_task(std::move(task)) { }
|
||||
|
||||
[[nodiscard]] bool isRunning() const;
|
||||
[[nodiscard]] bool hadException() const;
|
||||
[[nodiscard]] bool wasInterrupted() const;
|
||||
|
||||
void interrupt();
|
||||
private:
|
||||
std::weak_ptr<Task> m_task;
|
||||
};
|
||||
|
||||
class TaskManager {
|
||||
public:
|
||||
TaskManager() = delete;
|
||||
|
||||
constexpr static auto NoProgress = 0;
|
||||
|
||||
static TaskHolder createTask(std::string name, u64 maxValue, std::function<void(Task &)> function);
|
||||
static void collectGarbage();
|
||||
|
||||
static size_t getRunningTaskCount();
|
||||
static std::list<std::shared_ptr<Task>> &getRunningTasks();
|
||||
|
||||
static void doLater(const std::function<void()> &function);
|
||||
static void runDeferredCalls();
|
||||
private:
|
||||
static std::mutex s_deferredCallsMutex;
|
||||
|
||||
static std::list<std::shared_ptr<Task>> s_tasks;
|
||||
static std::list<std::function<void()>> s_deferredCalls;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -42,7 +42,10 @@ namespace hex::dp {
|
||||
virtual void store(nlohmann::json &j) { hex::unused(j); }
|
||||
virtual void load(nlohmann::json &j) { hex::unused(j); }
|
||||
|
||||
using NodeError = std::pair<Node *, std::string>;
|
||||
struct NodeError {
|
||||
Node *node;
|
||||
std::string message;
|
||||
};
|
||||
|
||||
void resetOutputData() {
|
||||
for (auto &attribute : this->m_attributes)
|
||||
@@ -87,7 +90,7 @@ namespace hex::dp {
|
||||
|
||||
protected:
|
||||
[[noreturn]] void throwNodeError(const std::string &message) {
|
||||
throw NodeError(this, message);
|
||||
throw NodeError { this, message };
|
||||
}
|
||||
|
||||
std::vector<u8> getBufferOnInput(u32 index);
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace hex {
|
||||
|
||||
class Disassembler {
|
||||
public:
|
||||
static constexpr cs_arch toCapstoneArchitecture(Architecture architecture) {
|
||||
constexpr static cs_arch toCapstoneArchitecture(Architecture architecture) {
|
||||
return static_cast<cs_arch>(architecture);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,6 +65,12 @@ namespace hex::fs {
|
||||
else return size;
|
||||
}
|
||||
|
||||
static inline bool isSubPath(const std::fs::path& base, const std::fs::path& destination) {
|
||||
const auto relative = std::fs::relative(destination, base).string();
|
||||
|
||||
return relative.size() == 1 || (relative[0] != '.' && relative[1] != '.');
|
||||
}
|
||||
|
||||
bool isPathWritable(const std::fs::path &path);
|
||||
|
||||
std::fs::path toShortPath(const std::fs::path &path);
|
||||
@@ -90,7 +96,8 @@ namespace hex::fs {
|
||||
Resources,
|
||||
Constants,
|
||||
Encodings,
|
||||
Logs
|
||||
Logs,
|
||||
Recent
|
||||
};
|
||||
|
||||
std::optional<std::fs::path> getExecutablePath();
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace hex {
|
||||
Net();
|
||||
~Net();
|
||||
|
||||
static constexpr u32 DefaultTimeout = 2'000;
|
||||
constexpr static u32 DefaultTimeout = 2'000;
|
||||
|
||||
std::future<Response<std::string>> getString(const std::string &url, u32 timeout = DefaultTimeout);
|
||||
std::future<Response<nlohmann::json>> getJson(const std::string &url, u32 timeout = DefaultTimeout);
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "patches.hpp"
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class ProjectFile {
|
||||
public:
|
||||
ProjectFile() = delete;
|
||||
|
||||
static bool load(const std::fs::path &filePath);
|
||||
static bool store(std::fs::path filePath = {});
|
||||
|
||||
[[nodiscard]] static bool hasUnsavedChanges() {
|
||||
return ProjectFile::s_hasUnsavedChanged;
|
||||
}
|
||||
|
||||
static void markDirty() {
|
||||
bool setWindowTitle = !hasUnsavedChanges();
|
||||
|
||||
ProjectFile::s_hasUnsavedChanged = true;
|
||||
|
||||
if (setWindowTitle)
|
||||
EventManager::post<RequestChangeWindowTitle>(std::fs::path(getFilePath()).filename().string());
|
||||
}
|
||||
|
||||
[[nodiscard]] static const std::fs::path &getProjectFilePath() {
|
||||
return ProjectFile::s_currProjectFilePath;
|
||||
}
|
||||
|
||||
static void clearProjectFilePath() {
|
||||
ProjectFile::s_currProjectFilePath.clear();
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] static const std::fs::path &getFilePath() {
|
||||
return ProjectFile::s_filePath;
|
||||
}
|
||||
|
||||
static void setFilePath(const std::fs::path &filePath) {
|
||||
ProjectFile::s_filePath = filePath;
|
||||
|
||||
EventManager::post<RequestChangeWindowTitle>(filePath.filename().string());
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] static const std::string &getPattern() {
|
||||
return ProjectFile::s_pattern;
|
||||
}
|
||||
|
||||
static void setPattern(const std::string &pattern) {
|
||||
markDirty();
|
||||
ProjectFile::s_pattern = pattern;
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] static const Patches &getPatches() {
|
||||
return ProjectFile::s_patches;
|
||||
}
|
||||
|
||||
static void setPatches(const Patches &patches) {
|
||||
markDirty();
|
||||
ProjectFile::s_patches = patches;
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] static const std::list<ImHexApi::Bookmarks::Entry> &getBookmarks() {
|
||||
return ProjectFile::s_bookmarks;
|
||||
}
|
||||
|
||||
static void setBookmarks(const std::list<ImHexApi::Bookmarks::Entry> &bookmarks) {
|
||||
markDirty();
|
||||
ProjectFile::s_bookmarks = bookmarks;
|
||||
}
|
||||
|
||||
|
||||
[[nodiscard]] static const std::string &getDataProcessorContent() {
|
||||
return ProjectFile::s_dataProcessorContent;
|
||||
}
|
||||
|
||||
static void setDataProcessorContent(const std::string &json) {
|
||||
markDirty();
|
||||
ProjectFile::s_dataProcessorContent = json;
|
||||
}
|
||||
|
||||
private:
|
||||
static std::fs::path s_currProjectFilePath;
|
||||
static bool s_hasUnsavedChanged;
|
||||
|
||||
static std::fs::path s_filePath;
|
||||
static std::string s_pattern;
|
||||
static Patches s_patches;
|
||||
static std::list<ImHexApi::Bookmarks::Entry> s_bookmarks;
|
||||
static std::string s_dataProcessorContent;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -19,17 +19,31 @@ namespace hex {
|
||||
Tar() = default;
|
||||
Tar(const std::fs::path &path, Mode mode);
|
||||
~Tar();
|
||||
Tar(const Tar&) = delete;
|
||||
Tar(Tar&&) noexcept;
|
||||
|
||||
Tar &operator=(Tar &&other) noexcept;
|
||||
|
||||
void close();
|
||||
|
||||
[[nodiscard]] std::vector<u8> read(const std::fs::path &path);
|
||||
[[nodiscard]] std::string readString(const std::fs::path &path);
|
||||
|
||||
std::vector<u8> read(const std::fs::path &path);
|
||||
void write(const std::fs::path &path, const std::vector<u8> &data);
|
||||
void write(const std::fs::path &path, const std::string &data);
|
||||
|
||||
std::vector<std::fs::path> listEntries();
|
||||
[[nodiscard]] std::vector<std::fs::path> listEntries(const std::fs::path &basePath = "/");
|
||||
[[nodiscard]] bool contains(const std::fs::path &path);
|
||||
|
||||
void extract(const std::fs::path &path, const std::fs::path &outputPath);
|
||||
void extractAll(const std::fs::path &outputPath);
|
||||
|
||||
[[nodiscard]] bool isValid() const { return this->m_valid; }
|
||||
|
||||
private:
|
||||
mtar_t m_ctx = { };
|
||||
|
||||
bool m_valid = false;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -21,11 +21,11 @@ namespace hex {
|
||||
size_t size;
|
||||
|
||||
[[nodiscard]] constexpr bool isWithin(const Region &other) const {
|
||||
return (this->getStartAddress() >= other.getStartAddress()) && (this->getEndAddress() <= other.getEndAddress());
|
||||
return (this->getStartAddress() >= other.getStartAddress()) && (this->getEndAddress() <= other.getEndAddress()) && *this != Invalid() && other != Invalid();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool overlaps(const Region &other) const {
|
||||
return (this->getEndAddress() >= other.getStartAddress()) && (this->getStartAddress() < other.getEndAddress());
|
||||
return (this->getEndAddress() >= other.getStartAddress()) && (this->getStartAddress() < other.getEndAddress()) && *this != Invalid() && other != Invalid();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u64 getStartAddress() const {
|
||||
@@ -39,6 +39,14 @@ namespace hex {
|
||||
[[nodiscard]] constexpr size_t getSize() const {
|
||||
return this->size;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const Region &other) const {
|
||||
return this->address == other.address && this->size == other.size;
|
||||
}
|
||||
|
||||
constexpr static Region Invalid() {
|
||||
return { 0, 0 };
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -31,6 +31,16 @@ namespace hex {
|
||||
long double operator""_scaled(unsigned long long value);
|
||||
ImVec2 scaled(const ImVec2 &vector);
|
||||
|
||||
template<typename T>
|
||||
std::vector<T> operator|(const std::vector<T> &lhs, const std::vector<T> &rhs) {
|
||||
std::vector<T> result;
|
||||
|
||||
std::copy(lhs.begin(), lhs.end(), std::back_inserter(result));
|
||||
std::copy(rhs.begin(), rhs.end(), std::back_inserter(result));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string to_string(u128 value);
|
||||
std::string to_string(i128 value);
|
||||
|
||||
@@ -68,7 +78,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
constexpr inline i128 signExtend(size_t numBits, i128 value) {
|
||||
i128 mask = 1U << (numBits - 1);
|
||||
i128 mask = 1ULL << (numBits - 1);
|
||||
return (value ^ mask) - mask;
|
||||
}
|
||||
|
||||
@@ -84,6 +94,13 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
constexpr inline size_t strnlen(const char *s, size_t n) {
|
||||
size_t i = 0;
|
||||
while (i < n && s[i] != '\x00') i++;
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
template<class... Ts>
|
||||
struct overloaded : Ts... { using Ts::operator()...; };
|
||||
template<class... Ts>
|
||||
|
||||
@@ -4,14 +4,17 @@
|
||||
#include <vector>
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/helpers/literals.hpp>
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
using namespace hex::literals;
|
||||
|
||||
class BufferedReader {
|
||||
public:
|
||||
explicit BufferedReader(Provider *provider, size_t bufferSize = 0xFF'FFFF)
|
||||
explicit BufferedReader(Provider *provider, size_t bufferSize = 16_MiB)
|
||||
: m_provider(provider), m_bufferAddress(provider->getBaseAddress()), m_maxBufferSize(bufferSize),
|
||||
m_startAddress(0x00), m_endAddress(provider->getActualSize()),
|
||||
m_startAddress(0x00), m_endAddress(provider->getActualSize() - 1),
|
||||
m_buffer(bufferSize) {
|
||||
|
||||
}
|
||||
@@ -21,6 +24,9 @@ namespace hex::prv {
|
||||
}
|
||||
|
||||
void setEndAddress(u64 address) {
|
||||
if (address >= this->m_provider->getActualSize())
|
||||
address = this->m_provider->getActualSize() - 1;
|
||||
|
||||
this->m_endAddress = address;
|
||||
}
|
||||
|
||||
@@ -81,6 +87,19 @@ namespace hex::prv {
|
||||
return copy;
|
||||
}
|
||||
|
||||
Iterator& operator--() {
|
||||
this->m_address--;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator--(int) {
|
||||
auto copy = *this;
|
||||
this->m_address--;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
Iterator& operator+=(i64 offset) {
|
||||
this->m_address += offset;
|
||||
|
||||
@@ -101,6 +120,10 @@ namespace hex::prv {
|
||||
return this->m_address;
|
||||
}
|
||||
|
||||
void setAddress(u64 address) {
|
||||
this->m_address = address;
|
||||
}
|
||||
|
||||
difference_type operator-(const Iterator &other) const {
|
||||
return this->m_address - other.m_address;
|
||||
}
|
||||
@@ -152,6 +175,19 @@ namespace hex::prv {
|
||||
return copy;
|
||||
}
|
||||
|
||||
ReverseIterator& operator--() {
|
||||
this->m_address++;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
ReverseIterator operator--(int) {
|
||||
auto copy = *this;
|
||||
this->m_address++;
|
||||
|
||||
return copy;
|
||||
}
|
||||
|
||||
ReverseIterator& operator+=(i64 offset) {
|
||||
this->m_address -= offset;
|
||||
|
||||
@@ -172,6 +208,10 @@ namespace hex::prv {
|
||||
return this->m_address;
|
||||
}
|
||||
|
||||
void setAddress(u64 address) {
|
||||
this->m_address = address;
|
||||
}
|
||||
|
||||
difference_type operator-(const ReverseIterator &other) const {
|
||||
return other.m_address - this->m_address;
|
||||
}
|
||||
@@ -181,7 +221,7 @@ namespace hex::prv {
|
||||
}
|
||||
|
||||
value_type operator[](i64 offset) const {
|
||||
auto result = this->m_reader->readReverse(this->m_address + offset, 1);
|
||||
auto result = this->m_reader->readReverse(this->m_address - offset, 1);
|
||||
if (result.empty())
|
||||
return 0x00;
|
||||
|
||||
@@ -205,7 +245,7 @@ namespace hex::prv {
|
||||
}
|
||||
|
||||
Iterator end() {
|
||||
return { this, this->m_endAddress };
|
||||
return { this, this->m_endAddress + 1 };
|
||||
}
|
||||
|
||||
ReverseIterator rbegin() {
|
||||
@@ -213,15 +253,17 @@ namespace hex::prv {
|
||||
}
|
||||
|
||||
ReverseIterator rend() {
|
||||
return { this, std::numeric_limits<u64>::max() };
|
||||
return { this, 0 };
|
||||
}
|
||||
|
||||
private:
|
||||
void updateBuffer(u64 address, size_t size) {
|
||||
if (!this->m_bufferValid || address < this->m_bufferAddress || address + size > (this->m_bufferAddress + this->m_buffer.size())) {
|
||||
const auto remainingBytes = this->m_endAddress - address;
|
||||
const auto remainingBytes = (this->m_endAddress - address) + 1;
|
||||
if (remainingBytes < this->m_maxBufferSize)
|
||||
this->m_buffer.resize(remainingBytes);
|
||||
else
|
||||
this->m_buffer.resize(this->m_maxBufferSize);
|
||||
|
||||
this->m_provider->read(address, this->m_buffer.data(), this->m_buffer.size());
|
||||
this->m_bufferAddress = address;
|
||||
|
||||
@@ -8,12 +8,11 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/providers/overlay.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
namespace pl {
|
||||
class PatternLanguage;
|
||||
}
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
@@ -68,7 +67,7 @@ namespace hex::prv {
|
||||
[[nodiscard]] virtual std::vector<std::pair<std::string, std::string>> getDataInformation() const = 0;
|
||||
|
||||
[[nodiscard]] virtual bool open() = 0;
|
||||
virtual void close() = 0;
|
||||
virtual void close() = 0;
|
||||
|
||||
void addPatch(u64 offset, const void *buffer, size_t size, bool createUndo = false);
|
||||
void createUndoPoint();
|
||||
@@ -79,13 +78,30 @@ namespace hex::prv {
|
||||
[[nodiscard]] bool canUndo() const;
|
||||
[[nodiscard]] bool canRedo() const;
|
||||
|
||||
[[nodiscard]] virtual bool hasFilePicker() const;
|
||||
virtual bool handleFilePicker();
|
||||
|
||||
[[nodiscard]] virtual bool hasLoadInterface() const;
|
||||
[[nodiscard]] virtual bool hasInterface() const;
|
||||
virtual void drawLoadInterface();
|
||||
virtual void drawInterface();
|
||||
|
||||
pl::PatternLanguage &getPatternLanguageRuntime() { return *this->m_patternLanguageRuntime; }
|
||||
std::string &getPatternLanguageSourceCode() { return this->m_patternLanguageSourceCode; }
|
||||
[[nodiscard]] u32 getID() const {
|
||||
return this->m_id;
|
||||
}
|
||||
|
||||
[[nodiscard]] virtual nlohmann::json storeSettings(nlohmann::json settings = { }) const;
|
||||
virtual void loadSettings(const nlohmann::json &settings);
|
||||
|
||||
[[nodiscard]] virtual std::string getTypeName() const = 0;
|
||||
|
||||
void markDirty(bool dirty = true) { this->m_dirty = dirty; }
|
||||
[[nodiscard]] bool isDirty() const { return this->m_dirty; }
|
||||
|
||||
virtual std::pair<Region, bool> getRegionValidity(u64 address) const;
|
||||
|
||||
void skipLoadInterface() { this->m_skipLoadInterface = true; }
|
||||
[[nodiscard]] bool shouldSkipLoadInterface() const { return this->m_skipLoadInterface; }
|
||||
|
||||
protected:
|
||||
u32 m_currPage = 0;
|
||||
@@ -95,8 +111,13 @@ namespace hex::prv {
|
||||
std::list<std::map<u64, u8>> m_patches;
|
||||
std::list<Overlay *> m_overlays;
|
||||
|
||||
std::unique_ptr<pl::PatternLanguage> m_patternLanguageRuntime;
|
||||
std::string m_patternLanguageSourceCode;
|
||||
u32 m_id;
|
||||
|
||||
bool m_dirty = false;
|
||||
bool m_skipLoadInterface = false;
|
||||
|
||||
private:
|
||||
static u32 s_idCounter;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -139,4 +139,5 @@ namespace ImGui {
|
||||
void HideTooltip();
|
||||
|
||||
bool BitCheckbox(const char* label, bool* v);
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
@@ -10,6 +11,8 @@
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <hex/data_processor/node.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace ContentRegistry::Settings {
|
||||
@@ -19,10 +22,10 @@ namespace hex {
|
||||
void load() {
|
||||
bool loaded = false;
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
std::ifstream settingsFile(dir / SettingsFile);
|
||||
fs::File file(dir / SettingsFile, fs::File::Mode::Read);
|
||||
|
||||
if (settingsFile.good()) {
|
||||
settingsFile >> getSettingsData();
|
||||
if (file.isValid()) {
|
||||
getSettingsData() = nlohmann::json::parse(file.readString());
|
||||
loaded = true;
|
||||
break;
|
||||
}
|
||||
@@ -34,10 +37,10 @@ namespace hex {
|
||||
|
||||
void store() {
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
std::ofstream settingsFile(dir / SettingsFile, std::ios::trunc);
|
||||
fs::File file(dir / SettingsFile, fs::File::Mode::Create);
|
||||
|
||||
if (settingsFile.good()) {
|
||||
settingsFile << getSettingsData();
|
||||
if (file.isValid()) {
|
||||
file.write(getSettingsData().dump(4));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -238,27 +241,30 @@ namespace hex {
|
||||
return functionName;
|
||||
}
|
||||
|
||||
std::unique_ptr<pl::PatternLanguage> createDefaultRuntime(prv::Provider *provider) {
|
||||
auto runtime = std::make_unique<pl::PatternLanguage>();
|
||||
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider) {
|
||||
runtime.reset();
|
||||
|
||||
runtime->setDataSource([provider](u64 offset, u8 *buffer, size_t size) {
|
||||
provider->read(offset, buffer, size);
|
||||
}, 0, 0);
|
||||
if (provider != nullptr) {
|
||||
runtime.setDataSource([provider](u64 offset, u8 *buffer, size_t size) {
|
||||
provider->read(offset, buffer, size);
|
||||
}, provider->getBaseAddress(), provider->getActualSize());
|
||||
}
|
||||
|
||||
runtime->setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude));
|
||||
runtime.setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude) | fs::getDefaultPaths(fs::ImHexPath::Patterns));
|
||||
|
||||
for (const auto &func : getFunctions()) {
|
||||
if (func.dangerous)
|
||||
runtime->addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
runtime.addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
else
|
||||
runtime->addFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
runtime.addFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
}
|
||||
|
||||
for (const auto &[name, callback] : getPragmas()) {
|
||||
runtime->addPragma(name, callback);
|
||||
runtime.addPragma(name, callback);
|
||||
}
|
||||
|
||||
return runtime;
|
||||
runtime.addDefine("__IMHEX__");
|
||||
runtime.addDefine("__IMHEX_VERSION__", IMHEX_VERSION);
|
||||
}
|
||||
|
||||
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
|
||||
|
||||
@@ -20,11 +20,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
void restartImHex() {
|
||||
EventManager::post<RequestRestartImHex>();
|
||||
EventManager::post<RequestCloseImHex>(false);
|
||||
std::atexit([] {
|
||||
auto &programArgs = ImHexApi::System::getProgramArguments();
|
||||
execve(programArgs.argv[0], programArgs.argv, programArgs.envp);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -211,9 +208,22 @@ namespace hex {
|
||||
|
||||
namespace ImHexApi::Provider {
|
||||
|
||||
static u32 s_currentProvider;
|
||||
static i64 s_currentProvider = -1;
|
||||
static std::vector<prv::Provider *> s_providers;
|
||||
|
||||
namespace impl {
|
||||
|
||||
static prv::Provider *s_closingProvider = nullptr;
|
||||
void resetClosingProvider() {
|
||||
s_closingProvider = nullptr;
|
||||
}
|
||||
|
||||
prv::Provider* getClosingProvider() {
|
||||
return s_closingProvider;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
prv::Provider *get() {
|
||||
if (!ImHexApi::Provider::isValid())
|
||||
return nullptr;
|
||||
@@ -226,7 +236,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void setCurrentProvider(u32 index) {
|
||||
if (Task::getRunningTaskCount() > 0)
|
||||
if (TaskManager::getRunningTaskCount() > 0)
|
||||
return;
|
||||
|
||||
if (index < s_providers.size() && s_currentProvider != index) {
|
||||
@@ -237,26 +247,53 @@ namespace hex {
|
||||
}
|
||||
|
||||
bool isValid() {
|
||||
return !s_providers.empty() && s_currentProvider < s_providers.size();
|
||||
return !s_providers.empty() && s_currentProvider >= 0 && s_currentProvider < i64(s_providers.size());
|
||||
}
|
||||
|
||||
void add(prv::Provider *provider) {
|
||||
if (Task::getRunningTaskCount() > 0)
|
||||
void markDirty() {
|
||||
get()->markDirty();
|
||||
}
|
||||
|
||||
void resetDirty() {
|
||||
for (auto &provider : s_providers)
|
||||
provider->markDirty(false);
|
||||
}
|
||||
|
||||
bool isDirty() {
|
||||
return std::ranges::any_of(s_providers, [](const auto &provider) {
|
||||
return provider->isDirty();
|
||||
});
|
||||
}
|
||||
|
||||
void add(prv::Provider *provider, bool skipLoadInterface) {
|
||||
if (TaskManager::getRunningTaskCount() > 0)
|
||||
return;
|
||||
|
||||
if (skipLoadInterface)
|
||||
provider->skipLoadInterface();
|
||||
|
||||
s_providers.push_back(provider);
|
||||
EventManager::post<EventProviderCreated>(provider);
|
||||
|
||||
setCurrentProvider(s_providers.size() - 1);
|
||||
}
|
||||
|
||||
void remove(prv::Provider *provider) {
|
||||
void remove(prv::Provider *provider, bool noQuestions) {
|
||||
if (provider == nullptr)
|
||||
return;
|
||||
|
||||
if (Task::getRunningTaskCount() > 0)
|
||||
if (TaskManager::getRunningTaskCount() > 0)
|
||||
return;
|
||||
|
||||
if (!noQuestions) {
|
||||
impl::s_closingProvider = provider;
|
||||
|
||||
bool shouldClose = true;
|
||||
EventManager::post<EventProviderClosing>(provider, &shouldClose);
|
||||
if (!shouldClose)
|
||||
return;
|
||||
}
|
||||
|
||||
auto it = std::find(s_providers.begin(), s_providers.end(), provider);
|
||||
if (it == s_providers.end())
|
||||
return;
|
||||
@@ -265,37 +302,26 @@ namespace hex {
|
||||
|
||||
s_providers.erase(it);
|
||||
|
||||
if (it - s_providers.begin() == s_currentProvider && !s_providers.empty())
|
||||
if (s_providers.empty())
|
||||
EventManager::post<EventProviderChanged>(provider, nullptr);
|
||||
else if (it - s_providers.begin() == s_currentProvider)
|
||||
setCurrentProvider(0);
|
||||
|
||||
provider->close();
|
||||
EventManager::post<EventProviderClosed>(provider);
|
||||
|
||||
delete provider;
|
||||
}
|
||||
|
||||
}
|
||||
prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface) {
|
||||
prv::Provider* result = nullptr;
|
||||
EventManager::post<RequestCreateProvider>(unlocalizedName, skipLoadInterface, &result);
|
||||
|
||||
|
||||
namespace ImHexApi::Tasks {
|
||||
|
||||
Task createTask(const std::string &unlocalizedName, u64 maxValue) {
|
||||
return { unlocalizedName, maxValue };
|
||||
}
|
||||
|
||||
void doLater(const std::function<void()> &function) {
|
||||
static std::mutex tasksMutex;
|
||||
std::scoped_lock lock(tasksMutex);
|
||||
|
||||
getDeferredCalls().push_back(function);
|
||||
}
|
||||
|
||||
std::vector<std::function<void()>> &getDeferredCalls() {
|
||||
static std::vector<std::function<void()>> deferredCalls;
|
||||
|
||||
return deferredCalls;
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
namespace ImHexApi::System {
|
||||
|
||||
namespace impl {
|
||||
@@ -344,7 +370,7 @@ namespace hex {
|
||||
s_customFontPath = path;
|
||||
}
|
||||
|
||||
static float s_fontSize = 13.0;
|
||||
static float s_fontSize = DefaultFontSize;
|
||||
void setFontSize(float size) {
|
||||
s_fontSize = size;
|
||||
}
|
||||
@@ -436,6 +462,7 @@ namespace hex {
|
||||
s_systemThemeDetection = enabled;
|
||||
|
||||
EventManager::post<EventSettingsChanged>();
|
||||
EventManager::post<EventOSThemeChanged>();
|
||||
}
|
||||
|
||||
bool usesSystemThemeDetection() {
|
||||
|
||||
109
lib/libimhex/source/api/project_file_manager.cpp
Normal file
109
lib/libimhex/source/api/project_file_manager.cpp
Normal file
@@ -0,0 +1,109 @@
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
|
||||
#include <hex/helpers/tar.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
constexpr static auto MetadataHeaderMagic = "HEX";
|
||||
constexpr static auto MetadataPath = "IMHEX_METADATA";
|
||||
|
||||
std::vector<ProjectFile::Handler> ProjectFile::s_handlers;
|
||||
std::vector<ProjectFile::ProviderHandler> ProjectFile::s_providerHandlers;
|
||||
|
||||
std::fs::path ProjectFile::s_currProjectPath;
|
||||
|
||||
bool ProjectFile::load(const std::fs::path &filePath) {
|
||||
if (!fs::exists(filePath) || !fs::isRegularFile(filePath))
|
||||
return false;
|
||||
if (filePath.extension() != ".hexproj")
|
||||
return false;
|
||||
|
||||
Tar tar(filePath, Tar::Mode::Read);
|
||||
if (!tar.isValid())
|
||||
return false;
|
||||
|
||||
if (!tar.contains(MetadataPath))
|
||||
return false;
|
||||
|
||||
{
|
||||
const auto metadataContent = tar.read(MetadataPath);
|
||||
|
||||
if (!std::string(metadataContent.begin(), metadataContent.end()).starts_with(MetadataHeaderMagic))
|
||||
return false;
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
for (const auto &handler : ProjectFile::getHandlers()) {
|
||||
try {
|
||||
if (!handler.load(handler.basePath, tar))
|
||||
result = false;
|
||||
} catch (std::exception &e) {
|
||||
log::info("{}", e.what());
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||
const auto basePath = std::fs::path(std::to_string(provider->getID()));
|
||||
for (const auto &handler: ProjectFile::getProviderHandlers()) {
|
||||
try {
|
||||
if (!handler.load(provider, basePath / handler.basePath, tar))
|
||||
result = false;
|
||||
} catch (std::exception &e) {
|
||||
log::info("{}", e.what());
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProjectFile::s_currProjectPath = filePath;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ProjectFile::store(std::optional<std::fs::path> filePath) {
|
||||
if (!filePath.has_value())
|
||||
filePath = ProjectFile::s_currProjectPath;
|
||||
|
||||
Tar tar(*filePath, Tar::Mode::Create);
|
||||
if (!tar.isValid())
|
||||
return false;
|
||||
|
||||
bool result = true;
|
||||
for (const auto &handler : ProjectFile::getHandlers()) {
|
||||
try {
|
||||
if (!handler.store(handler.basePath, tar))
|
||||
result = false;
|
||||
} catch (std::exception &e) {
|
||||
log::info("{}", e.what());
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||
const auto basePath = std::fs::path(std::to_string(provider->getID()));
|
||||
for (const auto &handler: ProjectFile::getProviderHandlers()) {
|
||||
try {
|
||||
if (!handler.store(provider, basePath / handler.basePath, tar))
|
||||
result = false;
|
||||
} catch (std::exception &e) {
|
||||
log::info("{}", e.what());
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const auto metadataContent = hex::format("{}\n{}", MetadataHeaderMagic, IMHEX_VERSION);
|
||||
tar.write(MetadataPath, metadataContent);
|
||||
}
|
||||
|
||||
ImHexApi::Provider::resetDirty();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,71 +1,200 @@
|
||||
#include <hex/api/task.hpp>
|
||||
|
||||
#include <hex/api/localization.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace hex {
|
||||
|
||||
std::list<Task *> Task::s_runningTasks;
|
||||
std::mutex Task::s_taskMutex;
|
||||
std::mutex TaskManager::s_deferredCallsMutex;
|
||||
|
||||
Task::Task(const std::string &unlocalizedName, u64 maxValue) : m_name(LangEntry(unlocalizedName)), m_maxValue(maxValue), m_currValue(0) {
|
||||
std::scoped_lock lock(Task::s_taskMutex);
|
||||
std::list<std::shared_ptr<Task>> TaskManager::s_tasks;
|
||||
std::list<std::function<void()>> TaskManager::s_deferredCalls;
|
||||
|
||||
Task::s_runningTasks.push_back(this);
|
||||
}
|
||||
Task::Task(std::string unlocalizedName, u64 maxValue, std::function<void(Task &)> function)
|
||||
: m_unlocalizedName(std::move(unlocalizedName)), m_currValue(0), m_maxValue(maxValue) {
|
||||
this->m_thread = std::thread([this, func = std::move(function)] {
|
||||
try {
|
||||
func(*this);
|
||||
} catch (const TaskInterruptor &) {
|
||||
this->interruption();
|
||||
} catch (const std::exception &e) {
|
||||
log::error("Exception in task {}: {}", this->m_unlocalizedName, e.what());
|
||||
this->exception(e.what());
|
||||
} catch (...) {
|
||||
log::error("Exception in task {}", this->m_unlocalizedName);
|
||||
this->exception("Unknown Exception");
|
||||
}
|
||||
|
||||
Task::~Task() {
|
||||
this->finish();
|
||||
this->finish();
|
||||
});
|
||||
}
|
||||
|
||||
Task::Task(hex::Task &&other) noexcept {
|
||||
std::scoped_lock lock(Task::s_taskMutex);
|
||||
std::scoped_lock thisLock(this->m_mutex);
|
||||
std::scoped_lock otherLock(other.m_mutex);
|
||||
|
||||
this->m_thread = std::move(other.m_thread);
|
||||
this->m_unlocalizedName = std::move(other.m_unlocalizedName);
|
||||
|
||||
this->m_name = other.m_name;
|
||||
this->m_maxValue = other.m_maxValue;
|
||||
this->m_currValue = other.m_currValue;
|
||||
|
||||
auto it = std::find(Task::s_runningTasks.begin(), Task::s_runningTasks.end(), &other);
|
||||
if (it != Task::s_runningTasks.end()) {
|
||||
*it = this;
|
||||
}
|
||||
this->m_finished = other.m_finished;
|
||||
this->m_hadException = other.m_hadException;
|
||||
this->m_interrupted = other.m_interrupted;
|
||||
this->m_shouldInterrupt = other.m_shouldInterrupt;
|
||||
}
|
||||
|
||||
Task::~Task() {
|
||||
if (!this->isFinished())
|
||||
this->interrupt();
|
||||
|
||||
this->m_thread.join();
|
||||
}
|
||||
|
||||
void Task::update(u64 value) {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
this->m_currValue = value;
|
||||
|
||||
if (this->m_shouldInterrupt)
|
||||
throw TaskInterruptor();
|
||||
}
|
||||
|
||||
void Task::setMaxValue(u64 value) {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
this->m_maxValue = value;
|
||||
}
|
||||
|
||||
|
||||
void Task::interrupt() {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
this->m_shouldInterrupt = true;
|
||||
|
||||
if (this->m_interruptCallback)
|
||||
this->m_interruptCallback();
|
||||
}
|
||||
|
||||
void Task::setInterruptCallback(std::function<void()> callback) {
|
||||
this->m_interruptCallback = std::move(callback);
|
||||
}
|
||||
|
||||
bool Task::isFinished() const {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
return this->m_finished;
|
||||
}
|
||||
|
||||
bool Task::hadException() const {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
return this->m_hadException;
|
||||
}
|
||||
|
||||
bool Task::wasInterrupted() const {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
return this->m_interrupted;
|
||||
}
|
||||
|
||||
void Task::clearException() {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
this->m_hadException = false;
|
||||
}
|
||||
|
||||
std::string Task::getExceptionMessage() const {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
return this->m_exceptionMessage;
|
||||
}
|
||||
|
||||
const std::string &Task::getUnlocalizedName() {
|
||||
return this->m_unlocalizedName;
|
||||
}
|
||||
|
||||
u64 Task::getValue() const {
|
||||
return this->m_currValue;
|
||||
}
|
||||
|
||||
u64 Task::getMaxValue() const {
|
||||
return this->m_maxValue;
|
||||
}
|
||||
|
||||
void Task::finish() {
|
||||
std::scoped_lock lock(Task::s_taskMutex);
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
Task::s_runningTasks.remove(this);
|
||||
this->m_finished = true;
|
||||
}
|
||||
|
||||
void Task::setMaxValue(u64 maxValue) {
|
||||
this->m_maxValue = maxValue;
|
||||
void Task::interruption() {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
this->m_interrupted = true;
|
||||
}
|
||||
|
||||
void Task::update(u64 currValue) {
|
||||
if (this->m_currValue < this->m_maxValue)
|
||||
this->m_currValue = currValue;
|
||||
void Task::exception(const char *message) {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
this->m_exceptionMessage = message;
|
||||
this->m_hadException = true;
|
||||
}
|
||||
|
||||
double Task::getProgress() const {
|
||||
if (this->m_maxValue == 0)
|
||||
return 100;
|
||||
|
||||
return static_cast<double>(this->m_currValue) / static_cast<double>(this->m_maxValue);
|
||||
bool TaskHolder::isRunning() const {
|
||||
return !m_task.expired() && !m_task.lock()->isFinished();
|
||||
}
|
||||
|
||||
bool Task::isPending() const {
|
||||
return this->m_maxValue == 0;
|
||||
bool TaskHolder::hadException() const {
|
||||
return m_task.expired() || m_task.lock()->hadException();
|
||||
}
|
||||
|
||||
const std::string &Task::getName() const {
|
||||
return this->m_name;
|
||||
bool TaskHolder::wasInterrupted() const {
|
||||
return m_task.expired() || m_task.lock()->wasInterrupted();
|
||||
}
|
||||
|
||||
size_t Task::getRunningTaskCount() {
|
||||
std::scoped_lock lock(Task::s_taskMutex);
|
||||
void TaskHolder::interrupt() {
|
||||
if (!this->m_task.expired())
|
||||
this->m_task.lock()->interrupt();
|
||||
}
|
||||
|
||||
return Task::s_runningTasks.size();
|
||||
|
||||
TaskHolder TaskManager::createTask(std::string name, u64 maxValue, std::function<void(Task &)> function) {
|
||||
s_tasks.emplace_back(std::make_shared<Task>(std::move(name), maxValue, std::move(function)));
|
||||
|
||||
return TaskHolder(s_tasks.back());
|
||||
}
|
||||
|
||||
void TaskManager::collectGarbage() {
|
||||
std::erase_if(s_tasks, [](const auto &task) { return task->isFinished() && !task->hadException(); });
|
||||
}
|
||||
|
||||
std::list<std::shared_ptr<Task>> &TaskManager::getRunningTasks() {
|
||||
return s_tasks;
|
||||
}
|
||||
|
||||
size_t TaskManager::getRunningTaskCount() {
|
||||
return s_tasks.size();
|
||||
}
|
||||
|
||||
|
||||
void TaskManager::doLater(const std::function<void()> &function) {
|
||||
std::scoped_lock lock(s_deferredCallsMutex);
|
||||
|
||||
s_deferredCalls.push_back(function);
|
||||
}
|
||||
|
||||
void TaskManager::runDeferredCalls() {
|
||||
std::scoped_lock lock(s_deferredCallsMutex);
|
||||
|
||||
for (const auto &call : s_deferredCalls)
|
||||
call();
|
||||
|
||||
s_deferredCalls.clear();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
#include <hex/helpers/file.hpp>
|
||||
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
|
||||
namespace hex::fs {
|
||||
|
||||
@@ -90,7 +91,7 @@ namespace hex::fs {
|
||||
return "";
|
||||
|
||||
auto cString = reinterpret_cast<const char *>(bytes.data());
|
||||
return { cString, std::min(bytes.size(), std::strlen(cString)) };
|
||||
return { cString, hex::strnlen(cString, bytes.size()) };
|
||||
}
|
||||
|
||||
std::u8string File::readU8String(size_t numBytes) {
|
||||
@@ -104,7 +105,7 @@ namespace hex::fs {
|
||||
return u8"";
|
||||
|
||||
auto cString = reinterpret_cast<const char8_t *>(bytes.data());
|
||||
return { cString, std::min(bytes.size(), std::strlen(reinterpret_cast<const char*>(bytes.data()))) };
|
||||
return { cString, hex::strnlen(reinterpret_cast<const char*>(bytes.data()), bytes.size()) };
|
||||
}
|
||||
|
||||
void File::write(const u8 *buffer, size_t size) {
|
||||
|
||||
@@ -137,11 +137,8 @@ namespace hex::fs {
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
for (auto &path : paths) {
|
||||
for (auto &path : paths)
|
||||
path = path / "imhex";
|
||||
}
|
||||
|
||||
|
||||
#if defined(OS_MACOS)
|
||||
|
||||
@@ -175,6 +172,9 @@ namespace hex::fs {
|
||||
auto dataDirs = xdg::DataDirs();
|
||||
std::copy(dataDirs.begin(), dataDirs.end(), std::back_inserter(paths));
|
||||
|
||||
for (auto &path : paths)
|
||||
path = path / "imhex";
|
||||
|
||||
return paths;
|
||||
#endif
|
||||
}
|
||||
@@ -232,6 +232,9 @@ namespace hex::fs {
|
||||
case ImHexPath::Yara:
|
||||
result = appendPath(getDataPaths(), "yara");
|
||||
break;
|
||||
case ImHexPath::Recent:
|
||||
result = appendPath(getConfigPaths(), "recent");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!listNonExisting) {
|
||||
|
||||
@@ -109,7 +109,7 @@ namespace hex {
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_NOPROGRESS, 0L);
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#if defined(IMHEX_USE_BUNDLED_CA)
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_CAINFO, nullptr);
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_CAPATH, nullptr);
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_SSLCERTTYPE, "PEM");
|
||||
@@ -124,7 +124,7 @@ namespace hex {
|
||||
if (result != CURLE_OK)
|
||||
log::error("Net request failed with error {0}: '{1}'", u32(result), curl_easy_strerror(result));
|
||||
|
||||
i32 responseCode = 0;
|
||||
long responseCode = 0;
|
||||
curl_easy_getinfo(this->m_ctx, CURLINFO_RESPONSE_CODE, &responseCode);
|
||||
|
||||
curl_slist_free_all(this->m_headers);
|
||||
@@ -135,7 +135,7 @@ namespace hex {
|
||||
if (result != CURLE_OK)
|
||||
return std::nullopt;
|
||||
else
|
||||
return responseCode;
|
||||
return i32(responseCode);
|
||||
}
|
||||
|
||||
std::future<Response<std::string>> Net::getString(const std::string &url, u32 timeout) {
|
||||
@@ -167,8 +167,10 @@ namespace hex {
|
||||
setCommonSettings(response, url, timeout);
|
||||
|
||||
auto responseCode = execute();
|
||||
|
||||
return Response<nlohmann::json> { responseCode.value_or(0), nlohmann::json::parse(response) };
|
||||
if (!responseCode.has_value())
|
||||
return Response<nlohmann::json> { 0, { } };
|
||||
else
|
||||
return Response<nlohmann::json> { responseCode.value_or(0), nlohmann::json::parse(response, nullptr, false, true) };
|
||||
});
|
||||
}
|
||||
|
||||
@@ -188,15 +190,26 @@ namespace hex {
|
||||
curl_mimepart *part = curl_mime_addpart(mime);
|
||||
|
||||
auto fileName = filePath.filename().string();
|
||||
curl_mime_data_cb(
|
||||
part, file.getSize(), [](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
|
||||
curl_mime_data_cb(part, file.getSize(),
|
||||
[](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
|
||||
auto file = static_cast<FILE*>(arg);
|
||||
return fread(buffer, size, nitems, file); }, [](void *arg, curl_off_t offset, int origin) -> int {
|
||||
|
||||
return fread(buffer, size, nitems, file);
|
||||
},
|
||||
[](void *arg, curl_off_t offset, int origin) -> int {
|
||||
auto file = static_cast<FILE*>(arg);
|
||||
fseek(file, offset, origin);
|
||||
return CURL_SEEKFUNC_OK; }, [](void *arg) {
|
||||
|
||||
if (fseek(file, offset, origin) != 0)
|
||||
return CURL_SEEKFUNC_CANTSEEK;
|
||||
else
|
||||
return CURL_SEEKFUNC_OK;
|
||||
},
|
||||
[](void *arg) {
|
||||
auto file = static_cast<FILE*>(arg);
|
||||
fclose(file); }, file.getHandle());
|
||||
|
||||
fclose(file);
|
||||
},
|
||||
file.getHandle());
|
||||
curl_mime_filename(part, fileName.c_str());
|
||||
curl_mime_name(part, "file");
|
||||
|
||||
|
||||
@@ -1,115 +0,0 @@
|
||||
#include <hex/helpers/project_file_handler.hpp>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
|
||||
#include <fstream>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
namespace hex {
|
||||
|
||||
std::fs::path ProjectFile::s_currProjectFilePath;
|
||||
bool ProjectFile::s_hasUnsavedChanged = false;
|
||||
|
||||
std::fs::path ProjectFile::s_filePath;
|
||||
std::string ProjectFile::s_pattern;
|
||||
Patches ProjectFile::s_patches;
|
||||
std::list<ImHexApi::Bookmarks::Entry> ProjectFile::s_bookmarks;
|
||||
std::string ProjectFile::s_dataProcessorContent;
|
||||
|
||||
void to_json(json &j, const ImHexApi::Bookmarks::Entry &b) {
|
||||
j = json {
|
||||
{"address", b.region.address},
|
||||
{ "size", b.region.size },
|
||||
{ "name", b.name.data() },
|
||||
{ "comment", b.comment.data()},
|
||||
{ "locked", b.locked },
|
||||
{ "color", b.color }
|
||||
};
|
||||
}
|
||||
|
||||
void from_json(const json &j, ImHexApi::Bookmarks::Entry &b) {
|
||||
std::string name, comment;
|
||||
|
||||
if (j.contains("address")) j.at("address").get_to(b.region.address);
|
||||
if (j.contains("size")) j.at("size").get_to(b.region.size);
|
||||
if (j.contains("name")) j.at("name").get_to(name);
|
||||
if (j.contains("comment")) j.at("comment").get_to(comment);
|
||||
if (j.contains("locked")) j.at("locked").get_to(b.locked);
|
||||
if (j.contains("color")) j.at("color").get_to(b.color);
|
||||
|
||||
std::copy(name.begin(), name.end(), std::back_inserter(b.name));
|
||||
b.name.push_back('\0');
|
||||
std::copy(comment.begin(), comment.end(), std::back_inserter(b.comment));
|
||||
b.comment.push_back('\0');
|
||||
}
|
||||
|
||||
|
||||
bool ProjectFile::load(const std::fs::path &filePath) {
|
||||
ProjectFile::s_hasUnsavedChanged = false;
|
||||
|
||||
json projectFileData;
|
||||
|
||||
try {
|
||||
std::ifstream projectFile(filePath);
|
||||
projectFile >> projectFileData;
|
||||
|
||||
ProjectFile::s_filePath = std::fs::path(projectFileData["filePath"].get<std::u8string>());
|
||||
ProjectFile::s_pattern = projectFileData["pattern"];
|
||||
ProjectFile::s_patches = projectFileData["patches"].get<Patches>();
|
||||
ProjectFile::s_dataProcessorContent = projectFileData["dataProcessor"];
|
||||
|
||||
ProjectFile::s_bookmarks.clear();
|
||||
for (auto &element : projectFileData["bookmarks"].items()) {
|
||||
ImHexApi::Bookmarks::Entry entry;
|
||||
from_json(element.value(), entry);
|
||||
ProjectFile::s_bookmarks.emplace_back(std::move(entry));
|
||||
}
|
||||
|
||||
} catch (json::exception &e) {
|
||||
return false;
|
||||
} catch (std::ofstream::failure &e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ProjectFile::s_currProjectFilePath = filePath;
|
||||
|
||||
EventManager::post<EventProjectFileLoad>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProjectFile::store(std::fs::path filePath) {
|
||||
EventManager::post<EventProjectFileStore>();
|
||||
|
||||
json projectFileData;
|
||||
|
||||
if (filePath.empty())
|
||||
filePath = ProjectFile::s_currProjectFilePath;
|
||||
|
||||
try {
|
||||
projectFileData["filePath"] = ProjectFile::s_filePath.u8string();
|
||||
projectFileData["pattern"] = ProjectFile::s_pattern;
|
||||
projectFileData["patches"] = ProjectFile::s_patches;
|
||||
projectFileData["dataProcessor"] = ProjectFile::s_dataProcessorContent;
|
||||
|
||||
for (auto &bookmark : ProjectFile::s_bookmarks) {
|
||||
to_json(projectFileData["bookmarks"].emplace_back(), bookmark);
|
||||
}
|
||||
|
||||
std::ofstream projectFile(filePath.c_str(), std::fstream::trunc);
|
||||
projectFile << projectFileData;
|
||||
} catch (json::exception &e) {
|
||||
return false;
|
||||
} catch (std::ifstream::failure &e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ProjectFile::s_hasUnsavedChanged = false;
|
||||
ProjectFile::s_currProjectFilePath = filePath;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,26 +7,50 @@ namespace hex {
|
||||
using namespace hex::literals;
|
||||
|
||||
Tar::Tar(const std::fs::path &path, Mode mode) {
|
||||
int error = MTAR_ESUCCESS;
|
||||
|
||||
if (mode == Tar::Mode::Read)
|
||||
mtar_open(&this->m_ctx, path.string().c_str(), "r");
|
||||
error = mtar_open(&this->m_ctx, path.string().c_str(), "r");
|
||||
else if (mode == Tar::Mode::Write)
|
||||
mtar_open(&this->m_ctx, path.string().c_str(), "a");
|
||||
error = mtar_open(&this->m_ctx, path.string().c_str(), "a");
|
||||
else if (mode == Tar::Mode::Create)
|
||||
mtar_open(&this->m_ctx, path.string().c_str(), "w");
|
||||
error = mtar_open(&this->m_ctx, path.string().c_str(), "w");
|
||||
else
|
||||
error = MTAR_EFAILURE;
|
||||
|
||||
this->m_valid = (error == MTAR_ESUCCESS);
|
||||
}
|
||||
|
||||
Tar::~Tar() {
|
||||
mtar_finalize(&this->m_ctx);
|
||||
mtar_close(&this->m_ctx);
|
||||
this->close();
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> Tar::listEntries() {
|
||||
Tar::Tar(hex::Tar &&other) noexcept {
|
||||
this->m_ctx = other.m_ctx;
|
||||
this->m_valid = other.m_valid;
|
||||
|
||||
other.m_ctx = { };
|
||||
other.m_valid = false;
|
||||
}
|
||||
|
||||
Tar &Tar::operator=(Tar &&other) noexcept {
|
||||
this->m_ctx = other.m_ctx;
|
||||
other.m_ctx = { };
|
||||
|
||||
this->m_valid = other.m_valid;
|
||||
other.m_valid = false;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> Tar::listEntries(const std::fs::path &basePath) {
|
||||
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) {
|
||||
if (header.name != PaxHeaderName) {
|
||||
std::fs::path path = header.name;
|
||||
if (header.name != PaxHeaderName && fs::isSubPath(basePath, path)) {
|
||||
result.emplace_back(header.name);
|
||||
}
|
||||
|
||||
@@ -36,9 +60,29 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool Tar::contains(const std::fs::path &path) {
|
||||
mtar_header_t header;
|
||||
return mtar_find(&this->m_ctx, path.string().c_str(), &header) == MTAR_ESUCCESS;
|
||||
}
|
||||
|
||||
void Tar::close() {
|
||||
if (this->m_valid) {
|
||||
mtar_finalize(&this->m_ctx);
|
||||
mtar_close(&this->m_ctx);
|
||||
}
|
||||
|
||||
this->m_ctx = { };
|
||||
this->m_valid = false;
|
||||
}
|
||||
|
||||
std::vector<u8> Tar::read(const std::fs::path &path) {
|
||||
mtar_header_t header;
|
||||
mtar_find(&this->m_ctx, path.string().c_str(), &header);
|
||||
|
||||
auto fixedPath = path.string();
|
||||
#if defined(OS_WINDOWS)
|
||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
||||
#endif
|
||||
mtar_find(&this->m_ctx, fixedPath.c_str(), &header);
|
||||
|
||||
std::vector<u8> result(header.size, 0x00);
|
||||
mtar_read_data(&this->m_ctx, result.data(), result.size());
|
||||
@@ -46,19 +90,37 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string Tar::readString(const std::fs::path &path) {
|
||||
auto result = this->read(path);
|
||||
return { result.begin(), result.end() };
|
||||
}
|
||||
|
||||
void Tar::write(const std::fs::path &path, const std::vector<u8> &data) {
|
||||
if (path.has_parent_path()) {
|
||||
std::fs::path pathPart;
|
||||
for (const auto &part : path.parent_path()) {
|
||||
pathPart /= part;
|
||||
mtar_write_dir_header(&this->m_ctx, pathPart.string().c_str());
|
||||
|
||||
auto fixedPath = pathPart.string();
|
||||
#if defined(OS_WINDOWS)
|
||||
std::replace(fixedPath.begin(), fixedPath.end(), '\\', '/');
|
||||
#endif
|
||||
mtar_write_dir_header(&this->m_ctx, fixedPath.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
mtar_write_file_header(&this->m_ctx, path.string().c_str(), data.size());
|
||||
auto fixedPath = path.string();
|
||||
#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());
|
||||
}
|
||||
|
||||
void Tar::write(const std::fs::path &path, const std::string &data) {
|
||||
this->write(path, std::vector<u8>(data.begin(), data.end()));
|
||||
}
|
||||
|
||||
static void writeFile(mtar_t *ctx, mtar_header_t *header, const std::fs::path &path) {
|
||||
constexpr static u64 BufferSize = 1_MiB;
|
||||
|
||||
|
||||
@@ -233,7 +233,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
std::string toEngineeringString(double value) {
|
||||
constexpr std::array Suffixes = { "a", "f", "p", "n", "u", "m", "", "k", "M", "G", "T", "P", "E" };
|
||||
constexpr static std::array Suffixes = { "a", "f", "p", "n", "u", "m", "", "k", "M", "G", "T", "P", "E" };
|
||||
|
||||
int8_t suffixIndex = 6;
|
||||
|
||||
@@ -339,7 +339,7 @@ namespace hex {
|
||||
auto c = [&] { return string[offset]; };
|
||||
|
||||
if (c() == '\\') {
|
||||
if ((offset + 2) >= string.length()) return {};
|
||||
if ((offset + 2) > string.length()) return {};
|
||||
|
||||
offset++;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <hex.hpp>
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
@@ -10,9 +10,10 @@
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
Provider::Provider() {
|
||||
u32 Provider::s_idCounter = 0;
|
||||
|
||||
Provider::Provider() : m_id(s_idCounter++) {
|
||||
this->m_patches.emplace_back();
|
||||
this->m_patternLanguageRuntime = ContentRegistry::PatternLanguage::createDefaultRuntime(this);
|
||||
}
|
||||
|
||||
Provider::~Provider() {
|
||||
@@ -28,6 +29,7 @@ namespace hex::prv {
|
||||
|
||||
void Provider::write(u64 offset, const void *buffer, size_t size) {
|
||||
this->writeRaw(offset - this->getBaseAddress(), buffer, size);
|
||||
this->markDirty();
|
||||
}
|
||||
|
||||
void Provider::save() { }
|
||||
@@ -36,7 +38,9 @@ namespace hex::prv {
|
||||
}
|
||||
|
||||
void Provider::resize(size_t newSize) {
|
||||
this->m_patternLanguageRuntime->setDataSize(newSize);
|
||||
hex::unused(newSize);
|
||||
|
||||
this->markDirty();
|
||||
}
|
||||
|
||||
void Provider::insert(u64 offset, size_t size) {
|
||||
@@ -53,6 +57,8 @@ namespace hex::prv {
|
||||
patches.erase(address);
|
||||
for (const auto &[address, value] : patchesToMove)
|
||||
patches.insert({ address + size, value });
|
||||
|
||||
this->markDirty();
|
||||
}
|
||||
|
||||
void Provider::remove(u64 offset, size_t size) {
|
||||
@@ -69,6 +75,8 @@ namespace hex::prv {
|
||||
patches.erase(address);
|
||||
for (const auto &[address, value] : patchesToMove)
|
||||
patches.insert({ address - size, value });
|
||||
|
||||
this->markDirty();
|
||||
}
|
||||
|
||||
void Provider::applyOverlays(u64 offset, void *buffer, size_t size) {
|
||||
@@ -104,6 +112,7 @@ namespace hex::prv {
|
||||
for (auto &[patchAddress, patch] : getPatches()) {
|
||||
this->writeRaw(patchAddress - this->getBaseAddress(), &patch, 1);
|
||||
}
|
||||
this->markDirty();
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +131,7 @@ namespace hex::prv {
|
||||
|
||||
|
||||
u32 Provider::getPageCount() const {
|
||||
return std::ceil(this->getActualSize() / double(PageSize));
|
||||
return std::max(1.0, std::ceil(this->getActualSize() / double(PageSize)));
|
||||
}
|
||||
|
||||
u32 Provider::getCurrentPage() const {
|
||||
@@ -137,7 +146,7 @@ namespace hex::prv {
|
||||
|
||||
void Provider::setBaseAddress(u64 address) {
|
||||
this->m_baseAddress = address;
|
||||
this->m_patternLanguageRuntime->setDataBaseAddress(address);
|
||||
this->markDirty();
|
||||
}
|
||||
|
||||
u64 Provider::getBaseAddress() const {
|
||||
@@ -184,6 +193,8 @@ namespace hex::prv {
|
||||
else
|
||||
getPatches()[offset + i] = patch;
|
||||
}
|
||||
|
||||
this->markDirty();
|
||||
}
|
||||
|
||||
void Provider::createUndoPoint() {
|
||||
@@ -208,6 +219,13 @@ namespace hex::prv {
|
||||
return this->m_patchTreeOffset > 0;
|
||||
}
|
||||
|
||||
bool Provider::hasFilePicker() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Provider::handleFilePicker() {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Provider::hasLoadInterface() const {
|
||||
return false;
|
||||
@@ -223,4 +241,51 @@ namespace hex::prv {
|
||||
void Provider::drawInterface() {
|
||||
}
|
||||
|
||||
nlohmann::json Provider::storeSettings(nlohmann::json settings) const {
|
||||
settings["displayName"] = this->getName();
|
||||
settings["type"] = this->getTypeName();
|
||||
|
||||
settings["baseAddress"] = this->m_baseAddress;
|
||||
settings["currPage"] = this->m_currPage;
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
void Provider::loadSettings(const nlohmann::json &settings) {
|
||||
this->m_baseAddress = settings["baseAddress"];
|
||||
this->m_currPage = settings["currPage"];
|
||||
}
|
||||
|
||||
std::pair<Region, bool> Provider::getRegionValidity(u64 address) const {
|
||||
if ((address - this->getBaseAddress()) > this->getActualSize())
|
||||
return { Region::Invalid(), false };
|
||||
|
||||
bool insideValidRegion = false;
|
||||
|
||||
std::optional<u64> nextRegionAddress;
|
||||
for (const auto &overlay : this->m_overlays) {
|
||||
Region overlayRegion = { overlay->getAddress(), overlay->getSize() };
|
||||
if (!nextRegionAddress.has_value() || overlay->getAddress() < nextRegionAddress) {
|
||||
nextRegionAddress = overlayRegion.getStartAddress();
|
||||
}
|
||||
|
||||
if (Region { address, 1 }.overlaps(overlayRegion)) {
|
||||
insideValidRegion = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &[patchAddress, value] : this->m_patches.back()) {
|
||||
if (!nextRegionAddress.has_value() || patchAddress < nextRegionAddress)
|
||||
nextRegionAddress = patchAddress;
|
||||
|
||||
if (address == patchAddress)
|
||||
insideValidRegion = true;
|
||||
}
|
||||
|
||||
if (!nextRegionAddress.has_value())
|
||||
return { Region::Invalid(), false };
|
||||
else
|
||||
return { Region { address, *nextRegionAddress - address }, insideValidRegion };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@
|
||||
|
||||
#include <imgui_impl_opengl3_loader.h>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
|
||||
namespace ImGui {
|
||||
|
||||
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data) {
|
||||
@@ -536,7 +538,7 @@ namespace ImGui {
|
||||
const ImGuiStyle &style = g.Style;
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos + ImVec2(0, yOffset);
|
||||
ImVec2 size = CalcItemSize(ImVec2(100, 5), 100, g.FontSize + style.FramePadding.y * 2.0f);
|
||||
ImVec2 size = CalcItemSize(ImVec2(100, 5) * hex::ImHexApi::System::getGlobalScale(), 100, g.FontSize + style.FramePadding.y * 2.0f);
|
||||
ImRect bb(pos, pos + size);
|
||||
ItemSize(size, 0);
|
||||
if (!ItemAdd(bb, 0))
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
ImVec2 View::getMinSize() const {
|
||||
return scaled(ImVec2(480, 720));
|
||||
return scaled(ImVec2(10, 10));
|
||||
}
|
||||
|
||||
ImVec2 View::getMaxSize() const {
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <imgui_freetype.h>
|
||||
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/helpers/net.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
@@ -59,18 +60,20 @@ namespace hex::init {
|
||||
bool createDirectories() {
|
||||
bool result = true;
|
||||
|
||||
using enum fs::ImHexPath;
|
||||
constexpr std::array paths = {
|
||||
fs::ImHexPath::Patterns,
|
||||
fs::ImHexPath::PatternsInclude,
|
||||
fs::ImHexPath::Magic,
|
||||
fs::ImHexPath::Plugins,
|
||||
fs::ImHexPath::Resources,
|
||||
fs::ImHexPath::Config,
|
||||
fs::ImHexPath::Constants,
|
||||
fs::ImHexPath::Yara,
|
||||
fs::ImHexPath::Encodings,
|
||||
fs::ImHexPath::Python,
|
||||
fs::ImHexPath::Logs
|
||||
Patterns,
|
||||
PatternsInclude,
|
||||
Magic,
|
||||
Plugins,
|
||||
Resources,
|
||||
Config,
|
||||
Constants,
|
||||
Yara,
|
||||
Encodings,
|
||||
Python,
|
||||
Logs,
|
||||
Recent
|
||||
};
|
||||
|
||||
// Check if ImHex is installed in portable mode
|
||||
@@ -171,7 +174,6 @@ namespace hex::init {
|
||||
ContentRegistry::Provider::getEntries().clear();
|
||||
|
||||
ImHexApi::System::getInitArguments().clear();
|
||||
ImHexApi::Tasks::getDeferredCalls().clear();
|
||||
ImHexApi::HexEditor::impl::getBackgroundHighlights().clear();
|
||||
ImHexApi::HexEditor::impl::getForegroundHighlights().clear();
|
||||
ImHexApi::HexEditor::impl::getBackgroundHighlightingFunctions().clear();
|
||||
@@ -213,12 +215,13 @@ namespace hex::init {
|
||||
|
||||
ShortcutManager::clearShortcuts();
|
||||
|
||||
hex::Task::getRunningTasks().clear();
|
||||
TaskManager::getRunningTasks().clear();
|
||||
|
||||
ContentRegistry::DataProcessorNode::getEntries().clear();
|
||||
|
||||
ContentRegistry::DataFormatter::getEntries().clear();
|
||||
ContentRegistry::FileHandler::getEntries().clear();
|
||||
ContentRegistry::Hashes::impl::getHashes().clear();
|
||||
|
||||
{
|
||||
auto &visualizers = ContentRegistry::HexEditor::impl::getVisualizers();
|
||||
@@ -227,6 +230,9 @@ namespace hex::init {
|
||||
visualizers.clear();
|
||||
}
|
||||
|
||||
ProjectFile::getHandlers().clear();
|
||||
ProjectFile::getProviderHandlers().clear();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,51 +8,59 @@
|
||||
#include "init/splash_window.hpp"
|
||||
#include "init/tasks.hpp"
|
||||
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
|
||||
int main(int argc, char **argv, char **envp) {
|
||||
using namespace hex;
|
||||
ImHexApi::System::impl::setProgramArguments(argc, argv, envp);
|
||||
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
ImHexApi::System::impl::setBorderlessWindowMode(true);
|
||||
#endif
|
||||
|
||||
// Initialization
|
||||
{
|
||||
Window::initNative();
|
||||
bool shouldRestart = false;
|
||||
|
||||
hex::log::info("Welcome to ImHex!");
|
||||
EventManager::subscribe<RequestRestartImHex>([&]{ shouldRestart = true; });
|
||||
|
||||
init::WindowSplash splashWindow;
|
||||
do {
|
||||
shouldRestart = false;
|
||||
|
||||
for (const auto &[name, task] : init::getInitTasks())
|
||||
splashWindow.addStartupTask(name, task);
|
||||
// Initialization
|
||||
{
|
||||
Window::initNative();
|
||||
|
||||
if (!splashWindow.loop())
|
||||
ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} });
|
||||
}
|
||||
hex::log::info("Welcome to ImHex!");
|
||||
|
||||
// Clean up
|
||||
ON_SCOPE_EXIT {
|
||||
for (const auto &[name, task] : init::getExitTasks())
|
||||
task();
|
||||
};
|
||||
init::WindowSplash splashWindow;
|
||||
|
||||
// Main window
|
||||
{
|
||||
Window window;
|
||||
for (const auto &[name, task] : init::getInitTasks())
|
||||
splashWindow.addStartupTask(name, task);
|
||||
|
||||
if (argc == 1)
|
||||
; // No arguments provided
|
||||
else if (argc == 2)
|
||||
EventManager::post<RequestOpenFile>(argv[1]);
|
||||
else {
|
||||
hex::log::fatal("Usage: {} [<file_name>]", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
if (!splashWindow.loop())
|
||||
ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} });
|
||||
}
|
||||
|
||||
window.loop();
|
||||
}
|
||||
// Clean up
|
||||
ON_SCOPE_EXIT {
|
||||
for (const auto &[name, task] : init::getExitTasks())
|
||||
task();
|
||||
};
|
||||
|
||||
// Main window
|
||||
{
|
||||
Window window;
|
||||
|
||||
if (argc == 1)
|
||||
; // No arguments provided
|
||||
else if (argc >= 2) {
|
||||
for (auto i = 1; i < argc; i++)
|
||||
EventManager::post<RequestOpenFile>(argv[i]);
|
||||
}
|
||||
|
||||
window.loop();
|
||||
}
|
||||
|
||||
} while (shouldRestart);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include <dwmapi.h>
|
||||
#include <windowsx.h>
|
||||
|
||||
#include <csignal>
|
||||
|
||||
#include <imgui_impl_glfw.h>
|
||||
|
||||
namespace hex {
|
||||
@@ -30,7 +32,39 @@ namespace hex {
|
||||
static float g_titleBarHeight;
|
||||
static ImGuiMouseCursor g_mouseCursorIcon;
|
||||
|
||||
static LRESULT windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
static LRESULT commonWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (uMsg) {
|
||||
case WM_COPYDATA:
|
||||
{
|
||||
auto message = reinterpret_cast<COPYDATASTRUCT *>(lParam);
|
||||
if (message == nullptr) break;
|
||||
|
||||
auto data = reinterpret_cast<const char8_t *>(message->lpData);
|
||||
if (data == nullptr) break;
|
||||
|
||||
std::fs::path path = data;
|
||||
log::info("Opening file in existing instance: {}", path.string());
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
break;
|
||||
}
|
||||
case WM_SETTINGCHANGE:
|
||||
{
|
||||
if (lParam == 0) break;
|
||||
|
||||
if (LPCTSTR(lParam) == std::string_view("ImmersiveColorSet")) {
|
||||
EventManager::post<EventOSThemeChanged>();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CallWindowProc((WNDPROC)g_oldWndProc, hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static LRESULT borderlessWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (uMsg) {
|
||||
case WM_NCACTIVATE:
|
||||
case WM_NCPAINT:
|
||||
@@ -104,11 +138,11 @@ namespace hex {
|
||||
return HTNOWHERE;
|
||||
}
|
||||
|
||||
constexpr auto RegionClient = 0b0000;
|
||||
constexpr auto RegionLeft = 0b0001;
|
||||
constexpr auto RegionRight = 0b0010;
|
||||
constexpr auto RegionTop = 0b0100;
|
||||
constexpr auto RegionBottom = 0b1000;
|
||||
constexpr static auto RegionClient = 0b0000;
|
||||
constexpr static auto RegionLeft = 0b0001;
|
||||
constexpr static auto RegionRight = 0b0010;
|
||||
constexpr static auto RegionTop = 0b0100;
|
||||
constexpr static auto RegionBottom = 0b1000;
|
||||
|
||||
const auto result =
|
||||
RegionLeft * (cursor.x < (window.left + border.x)) |
|
||||
@@ -144,34 +178,11 @@ namespace hex {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_SETTINGCHANGE:
|
||||
{
|
||||
if (lParam == 0) break;
|
||||
|
||||
if (LPCTSTR(lParam) == std::string_view("ImmersiveColorSet")) {
|
||||
EventManager::post<EventOSThemeChanged>();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WM_COPYDATA:
|
||||
{
|
||||
auto message = reinterpret_cast<COPYDATASTRUCT *>(lParam);
|
||||
if (message == nullptr) break;
|
||||
|
||||
auto path = reinterpret_cast<const char *>(message->lpData);
|
||||
if (path == nullptr) break;
|
||||
|
||||
log::info("Opening file in existing instance: {}", path);
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CallWindowProc((WNDPROC)g_oldWndProc, hwnd, uMsg, wParam, lParam);
|
||||
return commonWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
|
||||
@@ -252,7 +263,7 @@ namespace hex {
|
||||
|
||||
|
||||
if (borderlessWindowMode) {
|
||||
g_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)windowProc);
|
||||
g_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)borderlessWindowProc);
|
||||
|
||||
MARGINS borderless = { 1, 1, 1, 1 };
|
||||
::DwmExtendFrameIntoClientArea(hwnd, &borderless);
|
||||
@@ -262,6 +273,23 @@ namespace hex {
|
||||
|
||||
::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE);
|
||||
::SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_OVERLAPPEDWINDOW);
|
||||
} else {
|
||||
g_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)commonWindowProc);
|
||||
}
|
||||
|
||||
// Catch heap corruption
|
||||
{
|
||||
::AddVectoredExceptionHandler(TRUE, [](PEXCEPTION_POINTERS exception) -> LONG {
|
||||
if ((exception->ExceptionRecord->ExceptionCode & 0xF000'0000) == 0xC000'0000) {
|
||||
log::fatal("Exception raised: 0x{:08X}", exception->ExceptionRecord->ExceptionCode);
|
||||
if (exception->ExceptionRecord->ExceptionCode == STATUS_HEAP_CORRUPTION) {
|
||||
log::fatal("Heap corruption detected!");
|
||||
std::raise(SIGABRT);
|
||||
}
|
||||
}
|
||||
|
||||
return EXCEPTION_CONTINUE_SEARCH;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
|
||||
#include <fonts/codicons_font.h>
|
||||
|
||||
#include <hex/helpers/project_file_handler.hpp>
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
@@ -63,15 +63,34 @@ namespace hex {
|
||||
buf->append("\n");
|
||||
}
|
||||
|
||||
static void signalHandler(int signalNumber) {
|
||||
log::fatal("Terminating with signal {}", signalNumber);
|
||||
|
||||
EventManager::post<EventAbnormalTermination>(signalNumber);
|
||||
|
||||
if (std::uncaught_exceptions() > 0) {
|
||||
log::fatal("Uncaught exception thrown!");
|
||||
}
|
||||
|
||||
// Let's not loop on this...
|
||||
std::signal(signalNumber, nullptr);
|
||||
|
||||
#if defined(DEBUG)
|
||||
assert(false);
|
||||
#else
|
||||
std::raise(signalNumber);
|
||||
#endif
|
||||
};
|
||||
|
||||
Window::Window() {
|
||||
{
|
||||
for (const auto &[argument, value] : ImHexApi::System::getInitArguments()) {
|
||||
if (argument == "no-plugins") {
|
||||
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("No Plugins"); });
|
||||
TaskManager::doLater([] { ImGui::OpenPopup("No Plugins"); });
|
||||
} else if (argument == "no-builtin-plugin") {
|
||||
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("No Builtin Plugin"); });
|
||||
TaskManager::doLater([] { ImGui::OpenPopup("No Builtin Plugin"); });
|
||||
} else if (argument == "multiple-builtin-plugins") {
|
||||
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("Multiple Builtin Plugins"); });
|
||||
TaskManager::doLater([] { ImGui::OpenPopup("Multiple Builtin Plugins"); });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,45 +99,46 @@ namespace hex {
|
||||
this->initImGui();
|
||||
this->setupNativeWindow();
|
||||
|
||||
// Initialize default theme
|
||||
EventManager::post<RequestChangeTheme>(1);
|
||||
|
||||
EventManager::subscribe<RequestCloseImHex>(this, [this](bool noQuestions) {
|
||||
glfwSetWindowShouldClose(this->m_window, true);
|
||||
glfwSetWindowShouldClose(this->m_window, GLFW_TRUE);
|
||||
|
||||
if (!noQuestions)
|
||||
EventManager::post<EventWindowClosing>(this->m_window);
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderDeleted>(this, [](const auto*) {
|
||||
EventManager::post<RequestChangeWindowTitle>("");
|
||||
});
|
||||
|
||||
EventManager::subscribe<RequestChangeWindowTitle>(this, [this](const std::string &windowTitle) {
|
||||
std::string title = "ImHex";
|
||||
|
||||
if (ImHexApi::Provider::isValid()) {
|
||||
if (!windowTitle.empty())
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
if (!windowTitle.empty() && provider != nullptr) {
|
||||
title += " - " + windowTitle;
|
||||
|
||||
if (ProjectFile::hasUnsavedChanges())
|
||||
title += " (*)";
|
||||
if (provider->isDirty())
|
||||
title += " (*)";
|
||||
|
||||
if (!ImHexApi::Provider::get()->isWritable())
|
||||
title += " (Read Only)";
|
||||
if (!provider->isWritable())
|
||||
title += " (Read Only)";
|
||||
}
|
||||
}
|
||||
|
||||
this->m_windowTitle = title;
|
||||
glfwSetWindowTitle(this->m_window, title.c_str());
|
||||
});
|
||||
|
||||
constexpr auto CrashBackupFileName = "crash_backup.hexproj";
|
||||
constexpr static auto CrashBackupFileName = "crash_backup.hexproj";
|
||||
|
||||
EventManager::subscribe<EventAbnormalTermination>(this, [this, CrashBackupFileName](int) {
|
||||
EventManager::subscribe<EventAbnormalTermination>(this, [this](int) {
|
||||
ImGui::SaveIniSettingsToDisk(this->m_imguiSettingsPath.string().c_str());
|
||||
|
||||
if (!ProjectFile::hasUnsavedChanges())
|
||||
if (!ImHexApi::Provider::isDirty())
|
||||
return;
|
||||
|
||||
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
if (ProjectFile::store(std::fs::path(path) / CrashBackupFileName))
|
||||
if (ProjectFile::store((std::fs::path(path) / CrashBackupFileName).string()))
|
||||
break;
|
||||
}
|
||||
});
|
||||
@@ -127,29 +147,11 @@ namespace hex {
|
||||
this->m_popupsToOpen.push_back(name);
|
||||
});
|
||||
|
||||
auto signalHandler = [](int signalNumber) {
|
||||
EventManager::post<EventAbnormalTermination>(signalNumber);
|
||||
|
||||
if (std::uncaught_exceptions() > 0) {
|
||||
log::fatal("Uncaught exception thrown!");
|
||||
}
|
||||
|
||||
// Let's not loop on this...
|
||||
std::signal(signalNumber, nullptr);
|
||||
|
||||
#if defined(DEBUG)
|
||||
assert(false);
|
||||
#else
|
||||
std::raise(signalNumber);
|
||||
#endif
|
||||
};
|
||||
|
||||
std::signal(SIGTERM, signalHandler);
|
||||
std::signal(SIGSEGV, signalHandler);
|
||||
std::signal(SIGINT, signalHandler);
|
||||
std::signal(SIGILL, signalHandler);
|
||||
std::signal(SIGABRT, signalHandler);
|
||||
std::signal(SIGFPE, signalHandler);
|
||||
std::signal(SIGSEGV, signalHandler);
|
||||
std::signal(SIGILL, signalHandler);
|
||||
std::signal(SIGABRT, signalHandler);
|
||||
std::signal(SIGFPE, signalHandler);
|
||||
std::set_terminate([]{ signalHandler(SIGABRT); });
|
||||
|
||||
auto imhexLogo = romfs::get("logo.png");
|
||||
this->m_logoTexture = ImGui::LoadImageFromMemory(reinterpret_cast<const ImU8 *>(imhexLogo.data()), imhexLogo.size());
|
||||
@@ -178,7 +180,7 @@ namespace hex {
|
||||
} else {
|
||||
glfwPollEvents();
|
||||
|
||||
bool frameRateUnlocked = ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) || Task::getRunningTaskCount() > 0 || this->m_mouseButtonDown || this->m_hadEvent || !this->m_pressedKeys.empty();
|
||||
bool frameRateUnlocked = ImGui::IsPopupOpen(ImGuiID(0), ImGuiPopupFlags_AnyPopupId) || TaskManager::getRunningTaskCount() > 0 || this->m_mouseButtonDown || this->m_hadEvent || !this->m_pressedKeys.empty();
|
||||
const double timeout = std::max(0.0, (1.0 / 5.0) - (glfwGetTime() - this->m_lastFrameTime));
|
||||
|
||||
if ((this->m_lastFrameTime - this->m_frameRateUnlockTime) > 5 && this->m_frameRateTemporarilyUnlocked && !frameRateUnlocked) {
|
||||
@@ -199,6 +201,16 @@ namespace hex {
|
||||
this->frameBegin();
|
||||
this->frame();
|
||||
this->frameEnd();
|
||||
|
||||
const auto targetFps = ImHexApi::System::getTargetFPS();
|
||||
if (targetFps <= 200) {
|
||||
auto leftoverFrameTime = i64((this->m_lastFrameTime + 1 / targetFps - glfwGetTime()) * 1000);
|
||||
if (leftoverFrameTime > 0)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(leftoverFrameTime));
|
||||
}
|
||||
|
||||
this->m_lastFrameTime = glfwGetTime();
|
||||
|
||||
this->m_hadEvent = false;
|
||||
}
|
||||
}
|
||||
@@ -413,7 +425,6 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this->m_popupsToOpen.remove_if([](const auto &name) {
|
||||
if (ImGui::IsPopupOpen(name.c_str()))
|
||||
return true;
|
||||
@@ -423,17 +434,12 @@ namespace hex {
|
||||
return false;
|
||||
});
|
||||
|
||||
TaskManager::runDeferredCalls();
|
||||
|
||||
EventManager::post<EventFrameBegin>();
|
||||
}
|
||||
|
||||
void Window::frame() {
|
||||
{
|
||||
auto &calls = ImHexApi::Tasks::getDeferredCalls();
|
||||
for (const auto &callback : calls)
|
||||
callback();
|
||||
calls.clear();
|
||||
}
|
||||
|
||||
auto &io = ImGui::GetIO();
|
||||
for (auto &[name, view] : ContentRegistry::Views::getEntries()) {
|
||||
ImGui::GetCurrentContext()->NextWindowData.ClearFlags();
|
||||
@@ -444,7 +450,8 @@ namespace hex {
|
||||
continue;
|
||||
|
||||
if (view->isAvailable()) {
|
||||
ImGui::SetNextWindowSizeConstraints(scaled(view->getMinSize()), scaled(view->getMaxSize()));
|
||||
float fontScaling = std::max(1.0F, ImHexApi::System::getFontSize() / ImHexApi::System::DefaultFontSize);
|
||||
ImGui::SetNextWindowSizeConstraints(view->getMinSize() * fontScaling, view->getMaxSize() * fontScaling);
|
||||
view->drawContent();
|
||||
}
|
||||
|
||||
@@ -477,6 +484,8 @@ namespace hex {
|
||||
void Window::frameEnd() {
|
||||
EventManager::post<EventFrameEnd>();
|
||||
|
||||
TaskManager::collectGarbage();
|
||||
|
||||
this->endNativeWindowFrame();
|
||||
ImGui::Render();
|
||||
|
||||
@@ -493,12 +502,6 @@ namespace hex {
|
||||
glfwMakeContextCurrent(backup_current_context);
|
||||
|
||||
glfwSwapBuffers(this->m_window);
|
||||
|
||||
const auto targetFps = ImHexApi::System::getTargetFPS();
|
||||
if (targetFps <= 200)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(u64((this->m_lastFrameTime + 1 / targetFps - glfwGetTime()) * 1000)));
|
||||
|
||||
this->m_lastFrameTime = glfwGetTime();
|
||||
}
|
||||
|
||||
void Window::initGLFW() {
|
||||
|
||||
@@ -28,6 +28,8 @@ add_library(${PROJECT_NAME} SHARED
|
||||
source/content/providers/file_provider.cpp
|
||||
source/content/providers/gdb_provider.cpp
|
||||
source/content/providers/disk_provider.cpp
|
||||
source/content/providers/intel_hex_provider.cpp
|
||||
source/content/providers/motorola_srec_provider.cpp
|
||||
|
||||
source/content/views/view_hex_editor.cpp
|
||||
source/content/views/view_pattern_editor.cpp
|
||||
@@ -50,16 +52,16 @@ add_library(${PROJECT_NAME} SHARED
|
||||
source/content/views/view_provider_settings.cpp
|
||||
source/content/views/view_find.cpp
|
||||
|
||||
source/content/helpers/math_evaluator.cpp
|
||||
source/content/helpers/pattern_drawer.cpp
|
||||
|
||||
source/math_evaluator.cpp
|
||||
source/pattern_drawer.cpp
|
||||
|
||||
source/lang/en_US.cpp
|
||||
source/lang/de_DE.cpp
|
||||
source/lang/en_US.cpp
|
||||
source/lang/it_IT.cpp
|
||||
source/lang/zh_CN.cpp
|
||||
source/lang/ja_JP.cpp
|
||||
source/lang/ko_KR.cpp
|
||||
source/lang/pt_BR.cpp
|
||||
source/lang/zh_CN.cpp
|
||||
source/lang/zh_TW.cpp
|
||||
)
|
||||
|
||||
@@ -67,7 +69,7 @@ add_library(${PROJECT_NAME} SHARED
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE include)
|
||||
|
||||
# Add additional libraries here #
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE libimhex LLVMDemangle)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE libimhex)
|
||||
|
||||
# ---- No need to change anything from here downwards unless you know what you're doing ---- #
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace hex {
|
||||
};
|
||||
|
||||
static i16 comparePrecedence(const Operator &a, const Operator &b);
|
||||
static bool isLeftAssociative(const Operator op);
|
||||
static bool isLeftAssociative(const Operator &op);
|
||||
static std::pair<Operator, size_t> toOperator(const std::string &input);
|
||||
|
||||
private:
|
||||
62
plugins/builtin/include/content/helpers/pattern_drawer.hpp
Normal file
62
plugins/builtin/include/content/helpers/pattern_drawer.hpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#pragma once
|
||||
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
#include <pl/pattern_visitor.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
template<typename T>
|
||||
concept ArrayPattern = requires(u64 displayEnd, T pattern, std::function<void(int, pl::ptrn::Pattern&)> fn) {
|
||||
{ pattern.forEachArrayEntry(displayEnd, fn) } -> std::same_as<void>;
|
||||
};
|
||||
|
||||
class PatternDrawer : public pl::PatternVisitor {
|
||||
public:
|
||||
PatternDrawer() = default;
|
||||
|
||||
void visit(pl::ptrn::PatternArrayDynamic& pattern) override;
|
||||
void visit(pl::ptrn::PatternArrayStatic& pattern) override;
|
||||
void visit(pl::ptrn::PatternBitfieldField& pattern) override;
|
||||
void visit(pl::ptrn::PatternBitfield& pattern) override;
|
||||
void visit(pl::ptrn::PatternBoolean& pattern) override;
|
||||
void visit(pl::ptrn::PatternCharacter& pattern) override;
|
||||
void visit(pl::ptrn::PatternEnum& pattern) override;
|
||||
void visit(pl::ptrn::PatternFloat& pattern) override;
|
||||
void visit(pl::ptrn::PatternPadding& pattern) override;
|
||||
void visit(pl::ptrn::PatternPointer& pattern) override;
|
||||
void visit(pl::ptrn::PatternSigned& pattern) override;
|
||||
void visit(pl::ptrn::PatternString& pattern) override;
|
||||
void visit(pl::ptrn::PatternStruct& pattern) override;
|
||||
void visit(pl::ptrn::PatternUnion& pattern) override;
|
||||
void visit(pl::ptrn::PatternUnsigned& pattern) override;
|
||||
void visit(pl::ptrn::PatternWideCharacter& pattern) override;
|
||||
void visit(pl::ptrn::PatternWideString& pattern) override;
|
||||
|
||||
private:
|
||||
void draw(pl::ptrn::Pattern& pattern);
|
||||
|
||||
template<ArrayPattern T>
|
||||
void drawArray(T& pattern) {
|
||||
bool opened = this->drawArrayRoot(pattern, pattern.getEntryCount(), pattern.isInlined());
|
||||
|
||||
if (opened) {
|
||||
auto& displayEnd = this->getDisplayEnd(pattern);
|
||||
pattern.forEachArrayEntry(displayEnd, [&] (u64 idx, auto &entry){
|
||||
this->drawArrayNode(idx, displayEnd, entry);
|
||||
});
|
||||
}
|
||||
|
||||
this->drawArrayEnd(pattern, opened, pattern.isInlined());
|
||||
}
|
||||
|
||||
bool drawArrayRoot(pl::ptrn::Pattern& pattern, size_t entryCount, bool isInlined);
|
||||
void drawArrayNode(u64 idx, u64& displayEnd, pl::ptrn::Pattern& pattern);
|
||||
void drawArrayEnd(pl::ptrn::Pattern& pattern, bool opened, bool inlined);
|
||||
|
||||
u64& getDisplayEnd(const pl::ptrn::Pattern& pattern);
|
||||
|
||||
private:
|
||||
std::map<const pl::ptrn::Pattern*, u64> m_displayEnd;
|
||||
};
|
||||
};
|
||||
@@ -15,7 +15,7 @@ namespace hex::plugin::builtin::prv {
|
||||
class DiskProvider : public hex::prv::Provider {
|
||||
public:
|
||||
DiskProvider();
|
||||
~DiskProvider() override;
|
||||
~DiskProvider() override = default;
|
||||
|
||||
[[nodiscard]] bool isAvailable() const override;
|
||||
[[nodiscard]] bool isReadable() const override;
|
||||
@@ -38,6 +38,15 @@ namespace hex::plugin::builtin::prv {
|
||||
[[nodiscard]] bool hasLoadInterface() const override { return true; }
|
||||
void drawLoadInterface() override;
|
||||
|
||||
void loadSettings(const nlohmann::json &settings) override;
|
||||
[[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings = { }) const override;
|
||||
|
||||
[[nodiscard]] std::string getTypeName() const override {
|
||||
return "hex.builtin.provider.disk";
|
||||
}
|
||||
|
||||
std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
|
||||
protected:
|
||||
void reloadDrives();
|
||||
|
||||
|
||||
@@ -7,19 +7,23 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
||||
#endif
|
||||
|
||||
namespace hex::plugin::builtin::prv {
|
||||
|
||||
class FileProvider : public hex::prv::Provider {
|
||||
public:
|
||||
explicit FileProvider();
|
||||
~FileProvider() override;
|
||||
FileProvider() = default;;
|
||||
~FileProvider() override = default;;
|
||||
|
||||
[[nodiscard]] bool isAvailable() const override;
|
||||
[[nodiscard]] bool isReadable() const override;
|
||||
@@ -45,18 +49,34 @@ namespace hex::plugin::builtin::prv {
|
||||
[[nodiscard]] std::string getName() const override;
|
||||
[[nodiscard]] std::vector<std::pair<std::string, std::string>> getDataInformation() const override;
|
||||
|
||||
bool hasFilePicker() const override { return true; }
|
||||
bool handleFilePicker() override;
|
||||
|
||||
void setPath(const std::fs::path &path);
|
||||
|
||||
[[nodiscard]] bool open() override;
|
||||
void close() override;
|
||||
|
||||
void loadSettings(const nlohmann::json &settings) override;
|
||||
[[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override;
|
||||
|
||||
[[nodiscard]] std::string getTypeName() const override {
|
||||
return "hex.builtin.provider.file";
|
||||
}
|
||||
|
||||
std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
|
||||
protected:
|
||||
#if defined(OS_WINDOWS)
|
||||
HANDLE m_file = INVALID_HANDLE_VALUE;
|
||||
HANDLE m_mapping = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
int m_file = -1;
|
||||
#endif
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
HANDLE m_file = INVALID_HANDLE_VALUE;
|
||||
HANDLE m_mapping = INVALID_HANDLE_VALUE;
|
||||
|
||||
#else
|
||||
|
||||
int m_file = -1;
|
||||
|
||||
#endif
|
||||
|
||||
std::fs::path m_path;
|
||||
void *m_mappedFile = nullptr;
|
||||
|
||||
@@ -12,8 +12,8 @@ namespace hex::plugin::builtin::prv {
|
||||
|
||||
class GDBProvider : public hex::prv::Provider {
|
||||
public:
|
||||
explicit GDBProvider();
|
||||
~GDBProvider() override;
|
||||
GDBProvider();
|
||||
~GDBProvider() override = default;;
|
||||
|
||||
[[nodiscard]] bool isAvailable() const override;
|
||||
[[nodiscard]] bool isReadable() const override;
|
||||
@@ -42,6 +42,15 @@ namespace hex::plugin::builtin::prv {
|
||||
[[nodiscard]] bool hasLoadInterface() const override { return true; }
|
||||
void drawLoadInterface() override;
|
||||
|
||||
void loadSettings(const nlohmann::json &settings) override;
|
||||
[[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override;
|
||||
|
||||
[[nodiscard]] std::string getTypeName() const override {
|
||||
return "hex.builtin.provider.gdb";
|
||||
}
|
||||
|
||||
std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
|
||||
protected:
|
||||
hex::Socket m_socket;
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <IntervalTree.h>
|
||||
|
||||
namespace hex::plugin::builtin::prv {
|
||||
|
||||
class IntelHexProvider : public hex::prv::Provider {
|
||||
public:
|
||||
IntelHexProvider() = default;
|
||||
~IntelHexProvider() override = default;
|
||||
|
||||
[[nodiscard]] bool isAvailable() const override { return this->m_dataValid; }
|
||||
[[nodiscard]] bool isReadable() const override { return true; }
|
||||
[[nodiscard]] bool isWritable() const override { return false; }
|
||||
[[nodiscard]] bool isResizable() const override { return false; }
|
||||
[[nodiscard]] bool isSavable() const override { return false; }
|
||||
|
||||
void setBaseAddress(u64 address) override;
|
||||
|
||||
void readRaw(u64 offset, void *buffer, size_t size) override;
|
||||
void writeRaw(u64 offset, const void *buffer, size_t size) override;
|
||||
[[nodiscard]] size_t getActualSize() const override;
|
||||
|
||||
bool open() override;
|
||||
void close() override;
|
||||
|
||||
[[nodiscard]] std::string getName() const override;
|
||||
[[nodiscard]] std::vector<std::pair<std::string, std::string>> getDataInformation() const override { return { }; }
|
||||
|
||||
void loadSettings(const nlohmann::json &settings) override;
|
||||
[[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override;
|
||||
|
||||
[[nodiscard]] std::string getTypeName() const override {
|
||||
return "hex.builtin.provider.intel_hex";
|
||||
}
|
||||
|
||||
bool hasFilePicker() const override { return true; }
|
||||
bool handleFilePicker() override;
|
||||
|
||||
std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
|
||||
protected:
|
||||
bool m_dataValid = false;
|
||||
size_t m_dataSize = 0x00;
|
||||
interval_tree::IntervalTree<u64, std::vector<u8>> m_data;
|
||||
|
||||
std::fs::path m_sourceFilePath;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <content/providers/intel_hex_provider.hpp>
|
||||
|
||||
namespace hex::plugin::builtin::prv {
|
||||
|
||||
class MotorolaSRECProvider : public IntelHexProvider {
|
||||
public:
|
||||
MotorolaSRECProvider() = default;
|
||||
~MotorolaSRECProvider() override = default;
|
||||
|
||||
bool open() override;
|
||||
void close() override;
|
||||
|
||||
[[nodiscard]] std::string getName() const override;
|
||||
|
||||
[[nodiscard]] std::string getTypeName() const override {
|
||||
return "hex.builtin.provider.motorola_srec";
|
||||
}
|
||||
|
||||
bool handleFilePicker() override;
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
36
plugins/builtin/include/content/providers/null_provider.hpp
Normal file
36
plugins/builtin/include/content/providers/null_provider.hpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
namespace hex::plugin::builtin::prv {
|
||||
|
||||
class NullProvider : public hex::prv::Provider {
|
||||
public:
|
||||
explicit NullProvider() = default;
|
||||
~NullProvider() override = default;
|
||||
|
||||
[[nodiscard]] bool isAvailable() const override { return true; }
|
||||
[[nodiscard]] bool isReadable() const override { return true; }
|
||||
[[nodiscard]] bool isWritable() const override { return false; }
|
||||
[[nodiscard]] bool isResizable() const override { return false; }
|
||||
[[nodiscard]] bool isSavable() const override { return false; }
|
||||
|
||||
[[nodiscard]] bool open() override { return true; }
|
||||
void close() override { }
|
||||
|
||||
void readRaw(u64 offset, void *buffer, size_t size) override { hex::unused(offset, buffer, size); }
|
||||
void writeRaw(u64 offset, const void *buffer, size_t size) override { hex::unused(offset, buffer, size); }
|
||||
[[nodiscard]] size_t getActualSize() const override { return 0x00; }
|
||||
|
||||
[[nodiscard]] std::string getName() const override { return "None"; }
|
||||
[[nodiscard]] std::vector<std::pair<std::string, std::string>> getDataInformation() const override { return { }; }
|
||||
|
||||
void loadSettings(const nlohmann::json &settings) override { hex::unused(settings); }
|
||||
[[nodiscard]] nlohmann::json storeSettings(nlohmann::json settings) const override { return settings; }
|
||||
|
||||
[[nodiscard]] std::string getTypeName() const override {
|
||||
return "hex.builtin.provider.null";
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -15,7 +15,11 @@ namespace hex::plugin::builtin {
|
||||
void drawContent() override;
|
||||
|
||||
private:
|
||||
std::list<ImHexApi::Bookmarks::Entry> m_bookmarks;
|
||||
static bool importBookmarks(prv::Provider *provider, const nlohmann::json &json);
|
||||
static bool exportBookmarks(prv::Provider *provider, nlohmann::json &json);
|
||||
|
||||
void registerMenuItems();
|
||||
private:
|
||||
std::string m_currFilter;
|
||||
};
|
||||
|
||||
|
||||
@@ -20,25 +20,17 @@ namespace hex::plugin::builtin {
|
||||
void drawContent() override;
|
||||
|
||||
private:
|
||||
std::list<dp::Node *> m_endNodes;
|
||||
std::list<dp::Node *> m_nodes;
|
||||
std::list<dp::Link> m_links;
|
||||
|
||||
std::vector<hex::prv::Overlay *> m_dataOverlays;
|
||||
|
||||
int m_rightClickedId = -1;
|
||||
ImVec2 m_rightClickedCoords;
|
||||
|
||||
std::optional<dp::Node::NodeError> m_currNodeError;
|
||||
|
||||
bool m_continuousEvaluation = false;
|
||||
|
||||
void eraseLink(u32 id);
|
||||
void eraseNodes(const std::vector<int> &ids);
|
||||
void processNodes();
|
||||
|
||||
std::string saveNodes();
|
||||
void loadNodes(const std::string &data);
|
||||
std::string saveNodes(prv::Provider *provider);
|
||||
void loadNodes(prv::Provider *provider, const std::string &data);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <ui/widgets.hpp>
|
||||
|
||||
#include <hex/helpers/disassembler.hpp>
|
||||
|
||||
@@ -27,11 +28,11 @@ namespace hex::plugin::builtin {
|
||||
void drawContent() override;
|
||||
|
||||
private:
|
||||
bool m_disassembling = false;
|
||||
TaskHolder m_disassemblerTask;
|
||||
|
||||
u64 m_baseAddress = 0;
|
||||
u64 m_codeRegion[2] = { 0 };
|
||||
bool m_shouldMatchSelection = false;
|
||||
u64 m_baseAddress = 0;
|
||||
ui::SelectedRegion m_range = ui::SelectedRegion::EntireData;
|
||||
Region m_codeRegion = { 0, 0 };
|
||||
|
||||
Architecture m_architecture = Architecture::ARM;
|
||||
cs_mode m_mode = cs_mode(0);
|
||||
|
||||
@@ -4,10 +4,13 @@
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <ui/widgets.hpp>
|
||||
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
#include <IntervalTree.h>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
class ViewFind : public View {
|
||||
@@ -29,7 +32,7 @@ namespace hex::plugin::builtin {
|
||||
};
|
||||
|
||||
struct SearchSettings {
|
||||
int range = 0;
|
||||
ui::SelectedRegion range = ui::SelectedRegion::EntireData;
|
||||
|
||||
enum class Mode : int {
|
||||
Strings,
|
||||
@@ -58,6 +61,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
struct Regex {
|
||||
std::string pattern;
|
||||
bool fullMatch = true;
|
||||
} regex;
|
||||
|
||||
struct BinaryPattern {
|
||||
@@ -66,11 +70,15 @@ namespace hex::plugin::builtin {
|
||||
} binaryPattern;
|
||||
} m_searchSettings, m_decodeSettings;
|
||||
|
||||
using OccurrenceTree = interval_tree::IntervalTree<u64, Occurrence>;
|
||||
|
||||
std::map<prv::Provider*, std::vector<Occurrence>> m_foundOccurrences, m_sortedOccurrences;
|
||||
std::atomic<bool> m_searchRunning;
|
||||
std::map<prv::Provider*, OccurrenceTree> m_occurrenceTree;
|
||||
std::map<prv::Provider*, std::string> m_currFilter;
|
||||
|
||||
TaskHolder m_searchTask;
|
||||
bool m_settingsValid = false;
|
||||
|
||||
std::string m_currFilter;
|
||||
private:
|
||||
static std::vector<Occurrence> searchStrings(Task &task, prv::Provider *provider, Region searchRegion, SearchSettings::Strings settings);
|
||||
static std::vector<Occurrence> searchSequence(Task &task, prv::Provider *provider, Region searchRegion, SearchSettings::Bytes settings);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/api/task.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
@@ -27,7 +28,7 @@ namespace hex::plugin::builtin {
|
||||
double m_entropyHandlePosition;
|
||||
|
||||
std::array<ImU64, 256> m_valueCounts = { 0 };
|
||||
bool m_analyzing = false;
|
||||
TaskHolder m_analyzerTask;
|
||||
|
||||
Region m_analyzedRegion = { 0, 0 };
|
||||
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "pattern_drawer.hpp"
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/view.hpp>
|
||||
|
||||
#include <content/helpers/pattern_drawer.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <cstdio>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
@@ -21,7 +18,7 @@ namespace hex::plugin::builtin {
|
||||
void drawContent() override;
|
||||
|
||||
private:
|
||||
std::map<prv::Provider *, std::vector<pl::Pattern*>> m_sortedPatterns;
|
||||
std::map<prv::Provider *, std::vector<pl::ptrn::Pattern*>> m_sortedPatterns;
|
||||
hex::PatternDrawer m_patternDrawer;
|
||||
};
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <pl/pattern_language.hpp>
|
||||
#include <pl/core/errors/error.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <cstring>
|
||||
@@ -12,7 +13,7 @@
|
||||
|
||||
#include <TextEditor.h>
|
||||
|
||||
namespace pl { class Pattern; }
|
||||
namespace pl::ptrn { class Pattern; }
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
@@ -29,8 +30,8 @@ namespace hex::plugin::builtin {
|
||||
bool inVariable;
|
||||
bool outVariable;
|
||||
|
||||
pl::Token::ValueType type;
|
||||
pl::Token::Literal value;
|
||||
pl::core::Token::ValueType type;
|
||||
pl::core::Token::Literal value;
|
||||
};
|
||||
|
||||
enum class EnvVarType
|
||||
@@ -44,7 +45,7 @@ namespace hex::plugin::builtin {
|
||||
struct EnvVar {
|
||||
u64 id;
|
||||
std::string name;
|
||||
pl::Token::Literal value;
|
||||
pl::core::Token::Literal value;
|
||||
EnvVarType type;
|
||||
|
||||
bool operator==(const EnvVar &other) const {
|
||||
@@ -67,9 +68,9 @@ namespace hex::plugin::builtin {
|
||||
|
||||
bool m_lastEvaluationProcessed = true;
|
||||
bool m_lastEvaluationResult = false;
|
||||
std::optional<pl::PatternLanguageError> m_lastEvaluationError;
|
||||
std::vector<std::pair<pl::LogConsole::Level, std::string>> m_lastEvaluationLog;
|
||||
std::map<std::string, pl::Token::Literal> m_lastEvaluationOutVars;
|
||||
std::optional<pl::core::err::PatternLanguageError> m_lastEvaluationError;
|
||||
std::vector<std::pair<pl::core::LogConsole::Level, std::string>> m_lastEvaluationLog;
|
||||
std::map<std::string, pl::core::Token::Literal> m_lastEvaluationOutVars;
|
||||
|
||||
std::atomic<u32> m_runningEvaluators = 0;
|
||||
std::atomic<u32> m_runningParsers = 0;
|
||||
@@ -79,7 +80,7 @@ namespace hex::plugin::builtin {
|
||||
bool m_acceptPatternWindowOpen = false;
|
||||
|
||||
TextEditor m_textEditor;
|
||||
std::vector<std::pair<pl::LogConsole::Level, std::string>> m_console;
|
||||
std::vector<std::pair<pl::core::LogConsole::Level, std::string>> m_console;
|
||||
|
||||
std::map<std::string, PatternVariable> m_patternVariables;
|
||||
|
||||
@@ -97,7 +98,7 @@ namespace hex::plugin::builtin {
|
||||
void drawEnvVars(ImVec2 size);
|
||||
void drawVariableSettings(ImVec2 size);
|
||||
|
||||
void drawPatternTooltip(pl::Pattern *pattern);
|
||||
void drawPatternTooltip(pl::ptrn::Pattern *pattern);
|
||||
|
||||
void loadPatternFile(const std::fs::path &path);
|
||||
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/view.hpp>
|
||||
|
||||
#include <hex/api/task.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
class ViewYara : public View {
|
||||
@@ -29,7 +31,7 @@ namespace hex::plugin::builtin {
|
||||
std::vector<std::pair<std::fs::path, std::fs::path>> m_rules;
|
||||
std::vector<YaraMatch> m_matches;
|
||||
u32 m_selectedRule = 0;
|
||||
bool m_matching = false;
|
||||
TaskHolder m_matcherTask;
|
||||
|
||||
std::vector<std::string> m_consoleMessages;
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
#include <pl/pattern_visitor.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
template<typename T>
|
||||
concept ArrayPattern = requires(u64 displayEnd, T pattern, std::function<void(int, pl::Pattern&)> fn) {
|
||||
{ pattern.forEachArrayEntry(displayEnd, fn) } -> std::same_as<void>;
|
||||
};
|
||||
|
||||
class PatternDrawer : public pl::PatternVisitor {
|
||||
public:
|
||||
PatternDrawer() = default;
|
||||
|
||||
void visit(pl::PatternArrayDynamic& pattern) override;
|
||||
void visit(pl::PatternArrayStatic& pattern) override;
|
||||
void visit(pl::PatternBitfieldField& pattern) override;
|
||||
void visit(pl::PatternBitfield& pattern) override;
|
||||
void visit(pl::PatternBoolean& pattern) override;
|
||||
void visit(pl::PatternCharacter& pattern) override;
|
||||
void visit(pl::PatternEnum& pattern) override;
|
||||
void visit(pl::PatternFloat& pattern) override;
|
||||
void visit(pl::PatternPadding& pattern) override;
|
||||
void visit(pl::PatternPointer& pattern) override;
|
||||
void visit(pl::PatternSigned& pattern) override;
|
||||
void visit(pl::PatternString& pattern) override;
|
||||
void visit(pl::PatternStruct& pattern) override;
|
||||
void visit(pl::PatternUnion& pattern) override;
|
||||
void visit(pl::PatternUnsigned& pattern) override;
|
||||
void visit(pl::PatternWideCharacter& pattern) override;
|
||||
void visit(pl::PatternWideString& pattern) override;
|
||||
|
||||
private:
|
||||
void createDefaultEntry(const pl::Pattern &pattern, const std::string &value, pl::Token::Literal &&literal) const;
|
||||
void createLeafNode(const pl::Pattern& pattern) const;
|
||||
bool createTreeNode(const pl::Pattern& pattern) const;
|
||||
|
||||
void makeSelectable(const pl::Pattern &pattern) const;
|
||||
|
||||
void draw(pl::Pattern& pattern);
|
||||
|
||||
template<ArrayPattern T>
|
||||
void drawArray(T& pattern) {
|
||||
bool opened = this->drawArrayRoot(pattern, pattern.getEntryCount(), pattern.isInlined());
|
||||
|
||||
if (opened) {
|
||||
auto& displayEnd = this->getDisplayEnd(pattern);
|
||||
pattern.forEachArrayEntry(displayEnd, [&] (u64 idx, auto &entry){
|
||||
this->drawArrayNode(idx, displayEnd, entry);
|
||||
});
|
||||
}
|
||||
|
||||
this->drawArrayEnd(pattern, opened);
|
||||
}
|
||||
|
||||
bool drawArrayRoot(pl::Pattern& pattern, size_t entryCount, bool isInlined);
|
||||
void drawArrayNode(u64 idx, u64& displayEnd, pl::Pattern& pattern);
|
||||
void drawArrayEnd(pl::Pattern& pattern, bool opened);
|
||||
|
||||
void drawCommentTooltip(const pl::Pattern &pattern) const;
|
||||
void drawTypenameColumn(const pl::Pattern& pattern, const std::string& pattern_name) const;
|
||||
void drawNameColumn(const pl::Pattern& pattern) const;
|
||||
void drawColorColumn(const pl::Pattern& pattern) const;
|
||||
void drawOffsetColumn(const pl::Pattern& pattern) const;
|
||||
void drawSizeColumn(const pl::Pattern& pattern) const;
|
||||
|
||||
u64& getDisplayEnd(const pl::Pattern& pattern);
|
||||
|
||||
private:
|
||||
std::map<const pl::Pattern*, u64> m_displayEnd;
|
||||
};
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user