mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-31 13:26:02 -05:00
Compare commits
90 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
11
.github/workflows/build.yml
vendored
11
.github/workflows/build.yml
vendored
@@ -257,7 +257,7 @@ jobs:
|
||||
- name: 📦 Bundle DEB
|
||||
run: |
|
||||
cp -r build/DEBIAN build/AppDir
|
||||
dpkg-deb --build build/AppDir
|
||||
dpkg-deb -Zgzip --build build/AppDir
|
||||
mv build/AppDir.deb imhex-${{env.IMHEX_VERSION}}.deb
|
||||
rm -rf build/AppDir/DEBIAN
|
||||
|
||||
@@ -448,14 +448,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
|
||||
|
||||
35
.github/workflows/release.yml
vendored
35
.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
|
||||
@@ -110,3 +111,33 @@ jobs:
|
||||
tag: ImHex-v${{env.IMHEX_VERSION}}
|
||||
repo: ImHex-Patterns
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
|
||||
- name: ✉️ Update C++ Plugin Template
|
||||
uses: mvasigh/dispatch-action@main
|
||||
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.0.4.0/wingetcreate.exe -OutFile wingetcreate.exe
|
||||
- name: ⬆️ Update winget manifest
|
||||
shell: pwsh
|
||||
env:
|
||||
WINGET_GITHUB_TOKEN: ${{ secrets.RELEASE_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,4 +1,4 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
cmake_minimum_required(VERSION 3.20)
|
||||
|
||||
# Options
|
||||
option(IMHEX_PLUGINS_IN_SHARE "Put the plugins in share/imhex/plugins instead of lib[..]/imhex/plugins" OFF)
|
||||
|
||||
@@ -116,7 +116,7 @@ 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.10 (Yosemite) or higher, "Modern" Linux (Ubuntu 22.04+, Fedora Stable/Rawhide and Arch Linux are officially supported)
|
||||
- **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
|
||||
@@ -153,8 +153,9 @@ ImHex is available in various third party repositories.
|
||||
|
||||
## 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.
|
||||
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.
|
||||
|
||||
@@ -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}")
|
||||
@@ -132,18 +133,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 +155,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 +189,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,18 +245,18 @@ 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")
|
||||
endif()
|
||||
|
||||
@@ -255,20 +264,21 @@ macro(createPackage)
|
||||
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 +290,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()
|
||||
@@ -322,15 +335,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" AND 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()
|
||||
|
||||
|
||||
@@ -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")
|
||||
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" \
|
||||
|
||||
2
dist/rpm/imhex.spec
vendored
2
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
|
||||
|
||||
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
|
||||
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...ec8ed47d66
@@ -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)
|
||||
@@ -55,7 +62,7 @@ else()
|
||||
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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -181,8 +181,8 @@ namespace hex {
|
||||
|
||||
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));
|
||||
static constexpr auto SHIFT = Key(static_cast<Keys>(0x4000'0000));
|
||||
static constexpr 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,100 @@
|
||||
|
||||
#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]] double getProgress() const;
|
||||
[[nodiscard]] const std::string &getUnlocalizedName();
|
||||
[[nodiscard]] u64 getValue() const;
|
||||
[[nodiscard]] u64 getMaxValue() const;
|
||||
|
||||
[[nodiscard]] const std::string &getName() const;
|
||||
|
||||
[[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 interrupt();
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
u64 m_maxValue = 0, m_currValue = 0;
|
||||
void finish();
|
||||
void interruption();
|
||||
void exception();
|
||||
|
||||
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;
|
||||
|
||||
bool m_shouldInterrupt = false;
|
||||
|
||||
bool m_interrupted = false;
|
||||
bool m_finished = false;
|
||||
bool m_hadException = false;
|
||||
|
||||
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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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 };
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -68,7 +68,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 +84,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>
|
||||
|
||||
@@ -81,6 +81,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 +114,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 +169,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 +202,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;
|
||||
}
|
||||
@@ -205,7 +239,7 @@ namespace hex::prv {
|
||||
}
|
||||
|
||||
Iterator end() {
|
||||
return { this, this->m_endAddress };
|
||||
return { this, this->m_endAddress + 1 };
|
||||
}
|
||||
|
||||
ReverseIterator rbegin() {
|
||||
@@ -219,7 +253,7 @@ namespace hex::prv {
|
||||
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);
|
||||
|
||||
|
||||
@@ -8,9 +8,12 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/providers/overlay.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace pl {
|
||||
class PatternLanguage;
|
||||
}
|
||||
@@ -67,8 +70,8 @@ namespace hex::prv {
|
||||
[[nodiscard]] virtual std::string getName() const = 0;
|
||||
[[nodiscard]] virtual std::vector<std::pair<std::string, std::string>> getDataInformation() const = 0;
|
||||
|
||||
[[nodiscard]] virtual bool open() = 0;
|
||||
virtual void close() = 0;
|
||||
[[nodiscard]] virtual bool open();
|
||||
virtual void close();
|
||||
|
||||
void addPatch(u64 offset, const void *buffer, size_t size, bool createUndo = false);
|
||||
void createUndoPoint();
|
||||
@@ -79,13 +82,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 +115,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;
|
||||
}
|
||||
}
|
||||
@@ -241,9 +244,11 @@ namespace hex {
|
||||
std::unique_ptr<pl::PatternLanguage> createDefaultRuntime(prv::Provider *provider) {
|
||||
auto runtime = std::make_unique<pl::PatternLanguage>();
|
||||
|
||||
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));
|
||||
|
||||
|
||||
@@ -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 u32 s_currentProvider = std::numeric_limits<u32>::max();
|
||||
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) {
|
||||
@@ -240,23 +250,50 @@ namespace hex {
|
||||
return !s_providers.empty() && s_currentProvider < 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,23 @@ 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);
|
||||
|
||||
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 +367,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 +459,7 @@ namespace hex {
|
||||
s_systemThemeDetection = enabled;
|
||||
|
||||
EventManager::post<EventSettingsChanged>();
|
||||
EventManager::post<EventOSThemeChanged>();
|
||||
}
|
||||
|
||||
bool usesSystemThemeDetection() {
|
||||
|
||||
107
lib/libimhex/source/api/project_file_manager.cpp
Normal file
107
lib/libimhex/source/api/project_file_manager.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
#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);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,66 +6,174 @@
|
||||
|
||||
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 (...) {
|
||||
this->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() {
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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() {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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,14 +10,16 @@
|
||||
|
||||
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() {
|
||||
for (auto &overlay : this->m_overlays)
|
||||
this->deleteOverlay(overlay);
|
||||
this->close();
|
||||
}
|
||||
|
||||
void Provider::read(u64 offset, void *buffer, size_t size, bool overlays) {
|
||||
@@ -28,6 +30,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 +39,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 +58,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 +76,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 +113,7 @@ namespace hex::prv {
|
||||
for (auto &[patchAddress, patch] : getPatches()) {
|
||||
this->writeRaw(patchAddress - this->getBaseAddress(), &patch, 1);
|
||||
}
|
||||
this->markDirty();
|
||||
}
|
||||
|
||||
|
||||
@@ -122,7 +132,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 +147,7 @@ namespace hex::prv {
|
||||
|
||||
void Provider::setBaseAddress(u64 address) {
|
||||
this->m_baseAddress = address;
|
||||
this->m_patternLanguageRuntime->setDataBaseAddress(address);
|
||||
this->markDirty();
|
||||
}
|
||||
|
||||
u64 Provider::getBaseAddress() const {
|
||||
@@ -161,6 +171,14 @@ namespace hex::prv {
|
||||
return page;
|
||||
}
|
||||
|
||||
bool Provider::open() {
|
||||
EventManager::post<EventProviderOpened>(this);
|
||||
return true;
|
||||
}
|
||||
void Provider::close() {
|
||||
EventManager::post<EventProviderClosed>(this);
|
||||
}
|
||||
|
||||
void Provider::addPatch(u64 offset, const void *buffer, size_t size, bool createUndo) {
|
||||
if (this->m_patchTreeOffset > 0) {
|
||||
auto iter = this->m_patches.end();
|
||||
@@ -184,6 +202,8 @@ namespace hex::prv {
|
||||
else
|
||||
getPatches()[offset + i] = patch;
|
||||
}
|
||||
|
||||
this->markDirty();
|
||||
}
|
||||
|
||||
void Provider::createUndoPoint() {
|
||||
@@ -208,6 +228,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 +250,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 {
|
||||
|
||||
@@ -59,18 +59,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 +173,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 +214,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();
|
||||
|
||||
@@ -8,51 +8,61 @@
|
||||
#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)
|
||||
EventManager::post<RequestOpenFile>(argv[1]);
|
||||
else {
|
||||
hex::log::fatal("Usage: {} [<file_name>]", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -159,10 +161,11 @@ namespace hex {
|
||||
auto message = reinterpret_cast<COPYDATASTRUCT *>(lParam);
|
||||
if (message == nullptr) break;
|
||||
|
||||
auto path = reinterpret_cast<const char *>(message->lpData);
|
||||
if (path == nullptr) break;
|
||||
auto data = reinterpret_cast<const char8_t *>(message->lpData);
|
||||
if (data == nullptr) break;
|
||||
|
||||
log::info("Opening file in existing instance: {}", path);
|
||||
std::fs::path path = data;
|
||||
log::info("Opening file in existing instance: {}", path.string());
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
break;
|
||||
}
|
||||
@@ -263,6 +266,21 @@ 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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void Window::beginNativeWindowFrame() {
|
||||
|
||||
@@ -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,28 +99,28 @@ 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()) {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
if (!windowTitle.empty())
|
||||
title += " - " + windowTitle;
|
||||
|
||||
if (ProjectFile::hasUnsavedChanges())
|
||||
if (provider->isDirty())
|
||||
title += " (*)";
|
||||
|
||||
if (!ImHexApi::Provider::get()->isWritable())
|
||||
if (!provider->isWritable())
|
||||
title += " (Read Only)";
|
||||
}
|
||||
|
||||
@@ -114,11 +133,11 @@ namespace hex {
|
||||
EventManager::subscribe<EventAbnormalTermination>(this, [this, CrashBackupFileName](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 +146,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 +179,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 +200,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 +424,6 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this->m_popupsToOpen.remove_if([](const auto &name) {
|
||||
if (ImGui::IsPopupOpen(name.c_str()))
|
||||
return true;
|
||||
@@ -423,17 +433,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 +449,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 +483,8 @@ namespace hex {
|
||||
void Window::frameEnd() {
|
||||
EventManager::post<EventFrameEnd>();
|
||||
|
||||
TaskManager::collectGarbage();
|
||||
|
||||
this->endNativeWindowFrame();
|
||||
ImGui::Render();
|
||||
|
||||
@@ -493,12 +501,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
|
||||
|
||||
@@ -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:
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
33
plugins/builtin/include/content/providers/null_provider.hpp
Normal file
33
plugins/builtin/include/content/providers/null_provider.hpp
Normal file
@@ -0,0 +1,33 @@
|
||||
#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; }
|
||||
|
||||
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,
|
||||
@@ -66,8 +69,12 @@ 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;
|
||||
|
||||
TaskHolder m_searchTask;
|
||||
bool m_settingsValid = false;
|
||||
|
||||
std::string m_currFilter;
|
||||
|
||||
@@ -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 };
|
||||
|
||||
|
||||
@@ -21,7 +21,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;
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
namespace hex {
|
||||
|
||||
template<typename T>
|
||||
concept ArrayPattern = requires(u64 displayEnd, T pattern, std::function<void(int, pl::Pattern&)> fn) {
|
||||
concept ArrayPattern = requires(u64 displayEnd, T pattern, std::function<void(int, pl::ptrn::Pattern&)> fn) {
|
||||
{ pattern.forEachArrayEntry(displayEnd, fn) } -> std::same_as<void>;
|
||||
};
|
||||
|
||||
@@ -15,32 +15,32 @@ namespace hex {
|
||||
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;
|
||||
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 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 createDefaultEntry(const pl::ptrn::Pattern &pattern, const std::string &value, pl::core::Token::Literal &&literal) const;
|
||||
void createLeafNode(const pl::ptrn::Pattern& pattern) const;
|
||||
bool createTreeNode(const pl::ptrn::Pattern& pattern) const;
|
||||
|
||||
void makeSelectable(const pl::Pattern &pattern) const;
|
||||
void makeSelectable(const pl::ptrn::Pattern &pattern) const;
|
||||
|
||||
void draw(pl::Pattern& pattern);
|
||||
void draw(pl::ptrn::Pattern& pattern);
|
||||
|
||||
template<ArrayPattern T>
|
||||
void drawArray(T& pattern) {
|
||||
@@ -56,20 +56,20 @@ namespace hex {
|
||||
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);
|
||||
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);
|
||||
|
||||
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;
|
||||
void drawCommentTooltip(const pl::ptrn::Pattern &pattern) const;
|
||||
void drawTypenameColumn(const pl::ptrn::Pattern& pattern, const std::string& pattern_name) const;
|
||||
void drawNameColumn(const pl::ptrn::Pattern& pattern) const;
|
||||
void drawColorColumn(const pl::ptrn::Pattern& pattern) const;
|
||||
void drawOffsetColumn(const pl::ptrn::Pattern& pattern) const;
|
||||
void drawSizeColumn(const pl::ptrn::Pattern& pattern) const;
|
||||
|
||||
u64& getDisplayEnd(const pl::Pattern& pattern);
|
||||
u64& getDisplayEnd(const pl::ptrn::Pattern& pattern);
|
||||
|
||||
private:
|
||||
std::map<const pl::Pattern*, u64> m_displayEnd;
|
||||
std::map<const pl::ptrn::Pattern*, u64> m_displayEnd;
|
||||
};
|
||||
};
|
||||
56
plugins/builtin/include/provider_extra_data.hpp
Normal file
56
plugins/builtin/include/provider_extra_data.hpp
Normal file
@@ -0,0 +1,56 @@
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <pl/pattern_language.hpp>
|
||||
#include <hex/data_processor/attribute.hpp>
|
||||
#include <hex/data_processor/node.hpp>
|
||||
#include <hex/data_processor/link.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
class ProviderExtraData {
|
||||
public:
|
||||
struct Data {
|
||||
bool dataDirty = false;
|
||||
|
||||
struct {
|
||||
std::string sourceCode;
|
||||
std::unique_ptr<pl::PatternLanguage> runtime;
|
||||
} patternLanguage;
|
||||
|
||||
std::list<ImHexApi::Bookmarks::Entry> bookmarks;
|
||||
|
||||
struct {
|
||||
std::list<dp::Node*> endNodes;
|
||||
std::list<std::unique_ptr<dp::Node>> nodes;
|
||||
std::list<dp::Link> links;
|
||||
|
||||
std::vector<hex::prv::Overlay *> dataOverlays;
|
||||
std::optional<dp::Node::NodeError> currNodeError;
|
||||
} dataProcessor;
|
||||
};
|
||||
|
||||
static Data& getCurrent() {
|
||||
return get(ImHexApi::Provider::get());
|
||||
}
|
||||
|
||||
static Data& get(hex::prv::Provider *provider) {
|
||||
return s_data[provider];
|
||||
}
|
||||
|
||||
static void erase(hex::prv::Provider *provider) {
|
||||
s_data.erase(provider);
|
||||
}
|
||||
|
||||
static bool markDirty() {
|
||||
return getCurrent().dataDirty = true;
|
||||
}
|
||||
|
||||
private:
|
||||
ProviderExtraData() = default;
|
||||
static inline std::map<hex::prv::Provider*, Data> s_data = {};
|
||||
};
|
||||
|
||||
}
|
||||
25
plugins/builtin/include/ui/widgets.hpp
Normal file
25
plugins/builtin/include/ui/widgets.hpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
namespace hex::plugin::builtin::ui {
|
||||
|
||||
|
||||
enum class SelectedRegion : int {
|
||||
EntireData,
|
||||
Selection
|
||||
};
|
||||
|
||||
inline void regionSelectionPicker(SelectedRegion *region, bool showHeader = true, bool firstEntry = false) {
|
||||
if (showHeader)
|
||||
ImGui::Header("hex.builtin.common.range"_lang, firstEntry);
|
||||
|
||||
if (ImGui::RadioButton("hex.builtin.common.range.entire_data"_lang, *region == SelectedRegion::EntireData))
|
||||
*region = SelectedRegion::EntireData;
|
||||
if (ImGui::RadioButton("hex.builtin.common.range.selection"_lang, *region == SelectedRegion::Selection))
|
||||
*region = SelectedRegion::Selection;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -86,7 +86,7 @@ namespace hex::plugin::builtin {
|
||||
auto format = (style == Style::Decimal) ? "{0:d}" : ((style == Style::Hexadecimal) ? hex::format("0x{{0:0{}X}}", Size * 2) : hex::format("0o{{0:0{}o}}", Size * 3));
|
||||
|
||||
T value = 0x00;
|
||||
std::memcpy(&value, buffer.data(), Size);
|
||||
std::memcpy(&value, buffer.data(), std::min(sizeof(T), Size));
|
||||
return hex::format(format, hex::changeEndianess(value, Size, endian));
|
||||
}
|
||||
|
||||
@@ -98,7 +98,7 @@ namespace hex::plugin::builtin {
|
||||
auto format = (style == Style::Decimal) ? "{0}{1:d}" : ((style == Style::Hexadecimal) ? hex::format("{{0}}0x{{1:0{}X}}", Size * 2) : hex::format("{{0}}0o{{1:0{}o}}", Size * 3));
|
||||
|
||||
T value = 0x00;
|
||||
std::memcpy(&value, buffer.data(), Size);
|
||||
std::memcpy(&value, buffer.data(), std::min(sizeof(T), Size));
|
||||
auto number = hex::signExtend(Size * 8, hex::changeEndianess(value, Size, endian));
|
||||
bool negative = number < 0;
|
||||
|
||||
|
||||
@@ -196,11 +196,11 @@ namespace hex::plugin::builtin {
|
||||
class NodeComment : public dp::Node {
|
||||
public:
|
||||
NodeComment() : Node("hex.builtin.nodes.constants.comment.header", {}) {
|
||||
this->m_comment.resize(0xFFF, 0x00);
|
||||
|
||||
}
|
||||
|
||||
void drawNode() override {
|
||||
ImGui::InputTextMultiline("##string", reinterpret_cast<char *>(this->m_comment.data()), this->m_comment.size() - 1, ImVec2(150, 100));
|
||||
ImGui::InputTextMultiline("##string", this->m_comment, scaled(ImVec2(150, 100)));
|
||||
}
|
||||
|
||||
void process() override {
|
||||
|
||||
@@ -3,58 +3,51 @@
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/helpers/project_file_handler.hpp>
|
||||
#include <hex/api/localization.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "provider_extra_data.hpp"
|
||||
|
||||
#include "content/providers/file_provider.hpp"
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
static void openFile(const std::fs::path &path) {
|
||||
hex::prv::Provider *provider = nullptr;
|
||||
EventManager::post<RequestCreateProvider>("hex.builtin.provider.file", &provider);
|
||||
|
||||
if (auto fileProvider = dynamic_cast<prv::FileProvider *>(provider)) {
|
||||
auto provider = ImHexApi::Provider::createProvider("hex.builtin.provider.file", true);
|
||||
if (auto *fileProvider = dynamic_cast<prv::FileProvider*>(provider); fileProvider != nullptr) {
|
||||
fileProvider->setPath(path);
|
||||
if (!fileProvider->open()) {
|
||||
View::showErrorPopup("hex.builtin.popup.error.open"_lang);
|
||||
ImHexApi::Provider::remove(provider);
|
||||
|
||||
return;
|
||||
}
|
||||
(void)fileProvider->open();
|
||||
}
|
||||
|
||||
if (!provider->isWritable()) {
|
||||
View::showErrorPopup("hex.builtin.popup.error.read_only"_lang);
|
||||
}
|
||||
|
||||
if (!provider->isAvailable()) {
|
||||
View::showErrorPopup("hex.builtin.popup.error.open"_lang);
|
||||
ImHexApi::Provider::remove(provider);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
ProjectFile::setFilePath(path);
|
||||
|
||||
EventManager::post<EventFileLoaded>(path);
|
||||
EventManager::post<EventDataChanged>();
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
}
|
||||
|
||||
void registerEventHandlers() {
|
||||
EventManager::subscribe<EventProjectFileLoad>([]() {
|
||||
EventManager::post<RequestOpenFile>(ProjectFile::getFilePath());
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventWindowClosing>([](GLFWwindow *window) {
|
||||
if (ProjectFile::hasUnsavedChanges()) {
|
||||
if (ImHexApi::Provider::isDirty()) {
|
||||
glfwSetWindowShouldClose(window, GLFW_FALSE);
|
||||
ImHexApi::Tasks::doLater([] { ImGui::OpenPopup("hex.builtin.popup.exit_application.title"_lang); });
|
||||
TaskManager::doLater([] { ImGui::OpenPopup("hex.builtin.popup.exit_application.title"_lang); });
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderClosing>([](hex::prv::Provider *provider, bool *shouldClose) {
|
||||
if (provider->isDirty()) {
|
||||
*shouldClose = false;
|
||||
TaskManager::doLater([] { ImGui::OpenPopup("hex.builtin.popup.close_provider.title"_lang); });
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderChanged>([](hex::prv::Provider *oldProvider, hex::prv::Provider *newProvider) {
|
||||
hex::unused(oldProvider);
|
||||
|
||||
if (newProvider != nullptr) {
|
||||
EventManager::post<RequestChangeWindowTitle>(newProvider->getName());
|
||||
} else {
|
||||
EventManager::post<RequestChangeWindowTitle>("");
|
||||
}
|
||||
});
|
||||
|
||||
@@ -75,9 +68,7 @@ namespace hex::plugin::builtin {
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
});
|
||||
} else if (name == "Open File") {
|
||||
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
});
|
||||
ImHexApi::Provider::createProvider("hex.builtin.provider.file");
|
||||
} else if (name == "Open Project") {
|
||||
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} },
|
||||
[](const auto &path) {
|
||||
@@ -91,9 +82,34 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderCreated>([](hex::prv::Provider *provider) {
|
||||
if (provider->hasLoadInterface())
|
||||
if (provider->shouldSkipLoadInterface())
|
||||
return;
|
||||
|
||||
if (provider->hasFilePicker()) {
|
||||
if (!provider->handleFilePicker()) {
|
||||
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
|
||||
return;
|
||||
}
|
||||
if (!provider->open()) {
|
||||
View::showErrorPopup("hex.builtin.popup.error.open"_lang);
|
||||
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (provider->hasLoadInterface())
|
||||
EventManager::post<RequestOpenPopup>(View::toWindowName("hex.builtin.view.provider_settings.load_popup"));
|
||||
else {
|
||||
if (!provider->open() || !provider->isAvailable()) {
|
||||
View::showErrorPopup("hex.builtin.popup.error.open"_lang);
|
||||
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderDeleted>([](hex::prv::Provider *provider) {
|
||||
ProviderExtraData::erase(provider);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,11 +4,10 @@
|
||||
#include <implot.h>
|
||||
|
||||
#include <hex/ui/view.hpp>
|
||||
#include <hex/helpers/project_file_handler.hpp>
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/crypto.hpp>
|
||||
|
||||
#include <thread>
|
||||
#include <hex/helpers/patches.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
@@ -19,7 +18,7 @@ namespace hex::plugin::builtin {
|
||||
ContentRegistry::Interface::registerMainMenuItem("hex.builtin.menu.file", 1000);
|
||||
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1050, [&] {
|
||||
bool taskRunning = Task::getRunningTaskCount() > 0;
|
||||
bool taskRunning = TaskManager::getRunningTaskCount() > 0;
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.open_file"_lang, "CTRL + O", false, !taskRunning)) {
|
||||
|
||||
@@ -32,7 +31,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
for (const auto &unlocalizedProviderName : ContentRegistry::Provider::getEntries()) {
|
||||
if (ImGui::MenuItem(LangEntry(unlocalizedProviderName))) {
|
||||
EventManager::post<RequestCreateProvider>(unlocalizedProviderName, nullptr);
|
||||
ImHexApi::Provider::createProvider(unlocalizedProviderName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,7 +42,7 @@ namespace hex::plugin::builtin {
|
||||
/* File open, quit imhex */
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1150, [&] {
|
||||
bool providerValid = ImHexApi::Provider::isValid();
|
||||
bool taskRunning = Task::getRunningTaskCount() > 0;
|
||||
bool taskRunning = TaskManager::getRunningTaskCount() > 0;
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.close"_lang, "CTRL + W", false, providerValid && !taskRunning)) {
|
||||
ImHexApi::Provider::remove(ImHexApi::Provider::get());
|
||||
@@ -58,7 +57,7 @@ namespace hex::plugin::builtin {
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1250, [&] {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
bool providerValid = ImHexApi::Provider::isValid();
|
||||
bool taskRunning = Task::getRunningTaskCount() > 0;
|
||||
bool taskRunning = TaskManager::getRunningTaskCount() > 0;
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.open_project"_lang, "", false, !taskRunning)) {
|
||||
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"}
|
||||
@@ -69,18 +68,14 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.save_project"_lang, "", false, providerValid && provider->isWritable())) {
|
||||
if (ProjectFile::getProjectFilePath() == "") {
|
||||
fs::openFileBrowser(fs::DialogMode::Save, { {"Project File", "hexproj"}
|
||||
},
|
||||
[](std::fs::path path) {
|
||||
if (path.extension() != ".hexproj") {
|
||||
path.replace_extension(".hexproj");
|
||||
}
|
||||
fs::openFileBrowser(fs::DialogMode::Save, { {"Project File", "hexproj"} },
|
||||
[](std::fs::path path) {
|
||||
if (path.extension() != ".hexproj") {
|
||||
path.replace_extension(".hexproj");
|
||||
}
|
||||
|
||||
ProjectFile::store(path);
|
||||
});
|
||||
} else
|
||||
ProjectFile::store();
|
||||
ProjectFile::store(path);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -88,7 +83,7 @@ namespace hex::plugin::builtin {
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 1300, [&] {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
bool providerValid = ImHexApi::Provider::isValid();
|
||||
bool taskRunning = Task::getRunningTaskCount() > 0;
|
||||
bool taskRunning = TaskManager::getRunningTaskCount() > 0;
|
||||
|
||||
/* Import */
|
||||
if (ImGui::BeginMenu("hex.builtin.menu.file.import"_lang, !taskRunning)) {
|
||||
@@ -129,9 +124,7 @@ namespace hex::plugin::builtin {
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.import.ips"_lang, nullptr, false)) {
|
||||
|
||||
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
|
||||
std::thread([path] {
|
||||
auto task = ImHexApi::Tasks::createTask("hex.builtin.common.processing", 0);
|
||||
|
||||
TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [path](auto &task) {
|
||||
auto patchData = fs::File(path, fs::File::Mode::Read).readBytes();
|
||||
auto patch = hex::loadIPSPatch(patchData);
|
||||
|
||||
@@ -147,15 +140,13 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
provider->createUndoPoint();
|
||||
}).detach();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.import.ips32"_lang, nullptr, false)) {
|
||||
fs::openFileBrowser(fs::DialogMode::Open, {}, [](const auto &path) {
|
||||
std::thread([path] {
|
||||
auto task = ImHexApi::Tasks::createTask("hex.builtin.common.processing", 0);
|
||||
|
||||
TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [path](auto &task) {
|
||||
auto patchData = fs::File(path, fs::File::Mode::Read).readBytes();
|
||||
auto patch = hex::loadIPS32Patch(patchData);
|
||||
|
||||
@@ -171,7 +162,7 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
provider->createUndoPoint();
|
||||
}).detach();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -189,12 +180,10 @@ namespace hex::plugin::builtin {
|
||||
patches[0x00454F45] = value;
|
||||
}
|
||||
|
||||
std::thread([patches] {
|
||||
auto task = ImHexApi::Tasks::createTask("hex.builtin.common.processing", 0);
|
||||
|
||||
TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [patches](auto &) {
|
||||
auto data = generateIPSPatch(patches);
|
||||
|
||||
ImHexApi::Tasks::doLater([data] {
|
||||
TaskManager::doLater([data] {
|
||||
fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const auto &path) {
|
||||
auto file = fs::File(path, fs::File::Mode::Create);
|
||||
if (!file.isValid()) {
|
||||
@@ -205,7 +194,7 @@ namespace hex::plugin::builtin {
|
||||
file.write(data);
|
||||
});
|
||||
});
|
||||
}).detach();
|
||||
});
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.export.ips32"_lang, nullptr, false)) {
|
||||
@@ -216,23 +205,21 @@ namespace hex::plugin::builtin {
|
||||
patches[0x45454F45] = value;
|
||||
}
|
||||
|
||||
std::thread([patches] {
|
||||
auto task = ImHexApi::Tasks::createTask("hex.builtin.common.processing", 0);
|
||||
|
||||
TaskManager::createTask("hex.builtin.common.processing", TaskManager::NoProgress, [patches](auto &) {
|
||||
auto data = generateIPS32Patch(patches);
|
||||
|
||||
ImHexApi::Tasks::doLater([data] {
|
||||
TaskManager::doLater([data] {
|
||||
fs::openFileBrowser(fs::DialogMode::Save, {}, [&data](const auto &path) {
|
||||
auto file = fs::File(path, fs::File::Mode::Create);
|
||||
if (!file.isValid()) {
|
||||
View::showErrorPopup("hex.builtin.menu.file.export.popup.create"_lang);
|
||||
View::showErrorPopup("hex.builtin.menu.file.export.base64.popup.export_error"_lang);
|
||||
return;
|
||||
}
|
||||
|
||||
file.write(data);
|
||||
});
|
||||
});
|
||||
}).detach();
|
||||
});
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
@@ -254,15 +241,6 @@ namespace hex::plugin::builtin {
|
||||
provider->redo();
|
||||
});
|
||||
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.edit", 1050, [&] {
|
||||
bool providerValid = ImHexApi::Provider::isValid();
|
||||
auto selection = ImHexApi::HexEditor::getSelection();
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.edit.bookmark"_lang, nullptr, false, selection.has_value() && providerValid)) {
|
||||
ImHexApi::Bookmarks::add(selection->getStartAddress(), selection->getSize(), {}, {});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
static void createViewMenu() {
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
|
||||
#include <hex/helpers/net.hpp>
|
||||
|
||||
#include <pl/token.hpp>
|
||||
#include <pl/log_console.hpp>
|
||||
#include <pl/evaluator.hpp>
|
||||
#include <pl/core/token.hpp>
|
||||
#include <pl/core/log_console.hpp>
|
||||
#include <pl/core/evaluator.hpp>
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
void registerPatternLanguageFunctions() {
|
||||
using namespace pl;
|
||||
using namespace pl::core;
|
||||
using FunctionParameterCount = pl::api::FunctionParameterCount;
|
||||
|
||||
api::Namespace nsStdHttp = { "builtin", "std", "http" };
|
||||
pl::api::Namespace nsStdHttp = { "builtin", "std", "http" };
|
||||
{
|
||||
/* get(url) */
|
||||
ContentRegistry::PatternLanguage::addDangerousFunction(nsStdHttp, "get", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
|
||||
|
||||
@@ -1,64 +1,11 @@
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <pl/evaluator.hpp>
|
||||
#include <pl/core/evaluator.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
void registerPatternLanguagePragmas() {
|
||||
ContentRegistry::PatternLanguage::addPragma("endian", [](pl::PatternLanguage &runtime, const std::string &value) {
|
||||
if (value == "big") {
|
||||
runtime.getInternals().evaluator->setDefaultEndian(std::endian::big);
|
||||
return true;
|
||||
} else if (value == "little") {
|
||||
runtime.getInternals().evaluator->setDefaultEndian(std::endian::little);
|
||||
return true;
|
||||
} else if (value == "native") {
|
||||
runtime.getInternals().evaluator->setDefaultEndian(std::endian::native);
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::PatternLanguage::addPragma("eval_depth", [](pl::PatternLanguage &runtime, const std::string &value) {
|
||||
auto limit = strtol(value.c_str(), nullptr, 0);
|
||||
|
||||
if (limit <= 0)
|
||||
return false;
|
||||
|
||||
runtime.getInternals().evaluator->setEvaluationDepth(limit);
|
||||
return true;
|
||||
});
|
||||
|
||||
ContentRegistry::PatternLanguage::addPragma("array_limit", [](pl::PatternLanguage &runtime, const std::string &value) {
|
||||
auto limit = strtol(value.c_str(), nullptr, 0);
|
||||
|
||||
if (limit <= 0)
|
||||
return false;
|
||||
|
||||
runtime.getInternals().evaluator->setArrayLimit(limit);
|
||||
return true;
|
||||
});
|
||||
|
||||
ContentRegistry::PatternLanguage::addPragma("pattern_limit", [](pl::PatternLanguage &runtime, const std::string &value) {
|
||||
auto limit = strtol(value.c_str(), nullptr, 0);
|
||||
|
||||
if (limit <= 0)
|
||||
return false;
|
||||
|
||||
runtime.getInternals().evaluator->setPatternLimit(limit);
|
||||
return true;
|
||||
});
|
||||
|
||||
ContentRegistry::PatternLanguage::addPragma("loop_limit", [](pl::PatternLanguage &runtime, const std::string &value) {
|
||||
auto limit = strtol(value.c_str(), nullptr, 0);
|
||||
|
||||
if (limit <= 0)
|
||||
return false;
|
||||
|
||||
runtime.getInternals().evaluator->setLoopLimit(limit);
|
||||
return true;
|
||||
});
|
||||
|
||||
ContentRegistry::PatternLanguage::addPragma("base_address", [](pl::PatternLanguage &runtime, const std::string &value) {
|
||||
hex::unused(runtime);
|
||||
@@ -69,18 +16,6 @@ namespace hex::plugin::builtin {
|
||||
return true;
|
||||
});
|
||||
|
||||
ContentRegistry::PatternLanguage::addPragma("bitfield_order", [](pl::PatternLanguage &runtime, const std::string &value) {
|
||||
if (value == "left_to_right") {
|
||||
runtime.getInternals().evaluator->setBitfieldOrder(pl::BitfieldOrder::LeftToRight);
|
||||
return true;
|
||||
} else if (value == "right_to_left") {
|
||||
runtime.getInternals().evaluator->setBitfieldOrder(pl::BitfieldOrder::RightToLeft);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
ContentRegistry::PatternLanguage::addPragma("MIME", [](pl::PatternLanguage&, const std::string &value) { return !value.empty(); });
|
||||
}
|
||||
|
||||
|
||||
@@ -2,15 +2,69 @@
|
||||
|
||||
#include "content/providers/gdb_provider.hpp"
|
||||
#include "content/providers/file_provider.hpp"
|
||||
#include "content/providers/null_provider.hpp"
|
||||
#include "content/providers/disk_provider.hpp"
|
||||
#include "content/providers/intel_hex_provider.hpp"
|
||||
#include "content/providers/motorola_srec_provider.hpp"
|
||||
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
void registerProviders() {
|
||||
|
||||
ContentRegistry::Provider::add<prv::FileProvider>("hex.builtin.provider.file", false);
|
||||
ContentRegistry::Provider::add<prv::GDBProvider>("hex.builtin.provider.gdb");
|
||||
ContentRegistry::Provider::add<prv::DiskProvider>("hex.builtin.provider.disk");
|
||||
ContentRegistry::Provider::add<prv::FileProvider>(false);
|
||||
ContentRegistry::Provider::add<prv::NullProvider>(false);
|
||||
ContentRegistry::Provider::add<prv::DiskProvider>();
|
||||
ContentRegistry::Provider::add<prv::GDBProvider>();
|
||||
ContentRegistry::Provider::add<prv::IntelHexProvider>();
|
||||
ContentRegistry::Provider::add<prv::MotorolaSRECProvider>();
|
||||
|
||||
ProjectFile::registerHandler({
|
||||
.basePath = "providers",
|
||||
.load = [](const std::fs::path &basePath, Tar &tar) {
|
||||
auto json = nlohmann::json::parse(tar.readString(basePath / "providers.json"));
|
||||
auto providerIds = json["providers"].get<std::vector<int>>();
|
||||
|
||||
bool success = true;
|
||||
for (const auto &id : providerIds) {
|
||||
auto providerSettings = nlohmann::json::parse(tar.readString(basePath / hex::format("{}.json", id)));
|
||||
|
||||
auto provider = ImHexApi::Provider::createProvider(providerSettings["type"].get<std::string>(), true);
|
||||
if (provider == nullptr) {
|
||||
success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
provider->loadSettings(providerSettings["settings"]);
|
||||
if (!provider->open())
|
||||
success = false;
|
||||
}
|
||||
|
||||
return success;
|
||||
},
|
||||
.store = [](const std::fs::path &basePath, Tar &tar) {
|
||||
std::vector<int> providerIds;
|
||||
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||
auto id = provider->getID();
|
||||
providerIds.push_back(id);
|
||||
|
||||
nlohmann::json json;
|
||||
json["type"] = provider->getTypeName();
|
||||
json["settings"] = provider->storeSettings();
|
||||
|
||||
tar.write(basePath / hex::format("{}.json", id), json.dump(4));
|
||||
}
|
||||
|
||||
tar.write(basePath / "providers.json",
|
||||
nlohmann::json({ {"providers", providerIds } }).dump(4)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -12,17 +12,21 @@
|
||||
#include <imgui.h>
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define lseek lseek64
|
||||
|
||||
#elif defined(OS_MACOS)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#endif
|
||||
|
||||
namespace hex::plugin::builtin::prv {
|
||||
@@ -31,16 +35,16 @@ namespace hex::plugin::builtin::prv {
|
||||
this->reloadDrives();
|
||||
}
|
||||
|
||||
DiskProvider::~DiskProvider() {
|
||||
this->close();
|
||||
}
|
||||
|
||||
bool DiskProvider::isAvailable() const {
|
||||
#if defined(OS_WINDOWS)
|
||||
return this->m_diskHandle != INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
return this->m_diskHandle != -1;
|
||||
#endif
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
return this->m_diskHandle != INVALID_HANDLE_VALUE;
|
||||
|
||||
#else
|
||||
|
||||
return this->m_diskHandle != -1;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
bool DiskProvider::isReadable() const {
|
||||
@@ -68,113 +72,120 @@ namespace hex::plugin::builtin::prv {
|
||||
this->m_readable = true;
|
||||
this->m_writable = true;
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
const auto &path = this->m_path.native();
|
||||
const auto &path = this->m_path.native();
|
||||
|
||||
this->m_diskHandle = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
if (this->m_diskHandle == INVALID_HANDLE_VALUE) {
|
||||
this->m_diskHandle = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
this->m_writable = false;
|
||||
this->m_diskHandle = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
if (this->m_diskHandle == INVALID_HANDLE_VALUE) {
|
||||
this->m_diskHandle = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
this->m_writable = false;
|
||||
|
||||
if (this->m_diskHandle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
DISK_GEOMETRY_EX diskGeometry = { };
|
||||
DWORD bytesRead = 0;
|
||||
if (DeviceIoControl(
|
||||
this->m_diskHandle,
|
||||
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
|
||||
nullptr,
|
||||
0,
|
||||
&diskGeometry,
|
||||
sizeof(DISK_GEOMETRY_EX),
|
||||
&bytesRead,
|
||||
nullptr)) {
|
||||
this->m_diskSize = diskGeometry.DiskSize.QuadPart;
|
||||
this->m_sectorSize = diskGeometry.Geometry.BytesPerSector;
|
||||
this->m_sectorBuffer.resize(this->m_sectorSize);
|
||||
if (this->m_diskHandle == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (this->m_diskHandle == nullptr || this->m_diskHandle == INVALID_HANDLE_VALUE) {
|
||||
this->m_readable = false;
|
||||
this->m_diskHandle = nullptr;
|
||||
CloseHandle(this->m_diskHandle);
|
||||
{
|
||||
DISK_GEOMETRY_EX diskGeometry = { };
|
||||
DWORD bytesRead = 0;
|
||||
if (DeviceIoControl(
|
||||
this->m_diskHandle,
|
||||
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
|
||||
nullptr,
|
||||
0,
|
||||
&diskGeometry,
|
||||
sizeof(DISK_GEOMETRY_EX),
|
||||
&bytesRead,
|
||||
nullptr)) {
|
||||
this->m_diskSize = diskGeometry.DiskSize.QuadPart;
|
||||
this->m_sectorSize = diskGeometry.Geometry.BytesPerSector;
|
||||
this->m_sectorBuffer.resize(this->m_sectorSize);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
if (this->m_diskHandle == nullptr || this->m_diskHandle == INVALID_HANDLE_VALUE) {
|
||||
this->m_readable = false;
|
||||
this->m_diskHandle = nullptr;
|
||||
CloseHandle(this->m_diskHandle);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
const auto &path = this->m_path.native();
|
||||
#else
|
||||
|
||||
struct stat driveStat;
|
||||
const auto &path = this->m_path.native();
|
||||
|
||||
if (::stat(path.c_str(), &driveStat) == 0)
|
||||
this->m_diskSize = driveStat.st_size;
|
||||
else
|
||||
this->m_diskSize = 0;
|
||||
struct stat driveStat;
|
||||
|
||||
this->m_sectorSize = 0;
|
||||
if (::stat(path.c_str(), &driveStat) == 0)
|
||||
this->m_diskSize = driveStat.st_size;
|
||||
else
|
||||
this->m_diskSize = 0;
|
||||
|
||||
this->m_diskHandle = ::open(path.c_str(), O_RDWR);
|
||||
if (this->m_diskHandle == -1) {
|
||||
this->m_diskHandle = ::open(path.c_str(), O_RDONLY);
|
||||
this->m_writable = false;
|
||||
}
|
||||
this->m_sectorSize = 0;
|
||||
|
||||
if (this->m_diskHandle == -1) {
|
||||
this->m_readable = false;
|
||||
return false;
|
||||
}
|
||||
this->m_diskHandle = ::open(path.c_str(), O_RDWR);
|
||||
if (this->m_diskHandle == -1) {
|
||||
this->m_diskHandle = ::open(path.c_str(), O_RDONLY);
|
||||
this->m_writable = false;
|
||||
}
|
||||
|
||||
#endif
|
||||
if (this->m_diskHandle == -1) {
|
||||
this->m_readable = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
Provider::resize(this->getActualSize());
|
||||
#endif
|
||||
|
||||
return true;
|
||||
return Provider::open();
|
||||
}
|
||||
|
||||
void DiskProvider::close() {
|
||||
#if defined(OS_WINDOWS)
|
||||
if (this->m_diskHandle != INVALID_HANDLE_VALUE)
|
||||
::CloseHandle(this->m_diskHandle);
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
this->m_diskHandle = INVALID_HANDLE_VALUE;
|
||||
#else
|
||||
if (this->m_diskHandle != -1)
|
||||
::close(this->m_diskHandle);
|
||||
if (this->m_diskHandle != INVALID_HANDLE_VALUE)
|
||||
::CloseHandle(this->m_diskHandle);
|
||||
|
||||
this->m_diskHandle = -1;
|
||||
#endif
|
||||
this->m_diskHandle = INVALID_HANDLE_VALUE;
|
||||
|
||||
#else
|
||||
|
||||
if (this->m_diskHandle != -1)
|
||||
::close(this->m_diskHandle);
|
||||
|
||||
this->m_diskHandle = -1;
|
||||
|
||||
#endif
|
||||
|
||||
Provider::close();
|
||||
}
|
||||
|
||||
void DiskProvider::readRaw(u64 offset, void *buffer, size_t size) {
|
||||
#if defined(OS_WINDOWS)
|
||||
DWORD bytesRead = 0;
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
u64 startOffset = offset;
|
||||
DWORD bytesRead = 0;
|
||||
|
||||
while (size > 0) {
|
||||
LARGE_INTEGER seekPosition;
|
||||
seekPosition.LowPart = (offset & 0xFFFF'FFFF) - (offset % this->m_sectorSize);
|
||||
seekPosition.HighPart = offset >> 32;
|
||||
u64 startOffset = offset;
|
||||
|
||||
if (this->m_sectorBufferAddress != static_cast<u64>(seekPosition.QuadPart)) {
|
||||
::SetFilePointer(this->m_diskHandle, seekPosition.LowPart, &seekPosition.HighPart, FILE_BEGIN);
|
||||
::ReadFile(this->m_diskHandle, this->m_sectorBuffer.data(), this->m_sectorBuffer.size(), &bytesRead, nullptr);
|
||||
this->m_sectorBufferAddress = seekPosition.QuadPart;
|
||||
while (size > 0) {
|
||||
LARGE_INTEGER seekPosition;
|
||||
seekPosition.LowPart = (offset & 0xFFFF'FFFF) - (offset % this->m_sectorSize);
|
||||
seekPosition.HighPart = offset >> 32;
|
||||
|
||||
if (this->m_sectorBufferAddress != static_cast<u64>(seekPosition.QuadPart)) {
|
||||
::SetFilePointer(this->m_diskHandle, seekPosition.LowPart, &seekPosition.HighPart, FILE_BEGIN);
|
||||
::ReadFile(this->m_diskHandle, this->m_sectorBuffer.data(), this->m_sectorBuffer.size(), &bytesRead, nullptr);
|
||||
this->m_sectorBufferAddress = seekPosition.QuadPart;
|
||||
}
|
||||
|
||||
std::memcpy(reinterpret_cast<u8 *>(buffer) + (offset - startOffset), this->m_sectorBuffer.data() + (offset & (this->m_sectorSize - 1)), std::min(this->m_sectorSize, size));
|
||||
|
||||
size = std::max<ssize_t>(static_cast<ssize_t>(size) - this->m_sectorSize, 0);
|
||||
offset += this->m_sectorSize;
|
||||
}
|
||||
|
||||
std::memcpy(reinterpret_cast<u8 *>(buffer) + (offset - startOffset), this->m_sectorBuffer.data() + (offset & (this->m_sectorSize - 1)), std::min(this->m_sectorSize, size));
|
||||
#else
|
||||
|
||||
size = std::max<ssize_t>(static_cast<ssize_t>(size) - this->m_sectorSize, 0);
|
||||
offset += this->m_sectorSize;
|
||||
}
|
||||
#else
|
||||
u64 startOffset = offset;
|
||||
|
||||
while (size > 0) {
|
||||
@@ -193,59 +204,61 @@ namespace hex::plugin::builtin::prv {
|
||||
size = std::max<ssize_t>(static_cast<ssize_t>(size) - this->m_sectorSize, 0);
|
||||
offset += this->m_sectorSize;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void DiskProvider::writeRaw(u64 offset, const void *buffer, size_t size) {
|
||||
#if defined(OS_WINDOWS)
|
||||
DWORD bytesWritten = 0;
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
u64 startOffset = offset;
|
||||
DWORD bytesWritten = 0;
|
||||
|
||||
std::vector<u8> modifiedSectorBuffer;
|
||||
modifiedSectorBuffer.resize(this->m_sectorSize);
|
||||
u64 startOffset = offset;
|
||||
|
||||
while (size > 0) {
|
||||
u64 sectorBase = offset - (offset % this->m_sectorSize);
|
||||
size_t currSize = std::min(size, this->m_sectorSize);
|
||||
std::vector<u8> modifiedSectorBuffer;
|
||||
modifiedSectorBuffer.resize(this->m_sectorSize);
|
||||
|
||||
this->readRaw(sectorBase, modifiedSectorBuffer.data(), modifiedSectorBuffer.size());
|
||||
std::memcpy(modifiedSectorBuffer.data() + ((offset - sectorBase) % this->m_sectorSize), reinterpret_cast<const u8 *>(buffer) + (startOffset - offset), currSize);
|
||||
while (size > 0) {
|
||||
u64 sectorBase = offset - (offset % this->m_sectorSize);
|
||||
size_t currSize = std::min(size, this->m_sectorSize);
|
||||
|
||||
LARGE_INTEGER seekPosition;
|
||||
seekPosition.LowPart = (offset & 0xFFFF'FFFF) - (offset % this->m_sectorSize);
|
||||
seekPosition.HighPart = offset >> 32;
|
||||
this->readRaw(sectorBase, modifiedSectorBuffer.data(), modifiedSectorBuffer.size());
|
||||
std::memcpy(modifiedSectorBuffer.data() + ((offset - sectorBase) % this->m_sectorSize), reinterpret_cast<const u8 *>(buffer) + (startOffset - offset), currSize);
|
||||
|
||||
::SetFilePointer(this->m_diskHandle, seekPosition.LowPart, &seekPosition.HighPart, FILE_BEGIN);
|
||||
::WriteFile(this->m_diskHandle, modifiedSectorBuffer.data(), modifiedSectorBuffer.size(), &bytesWritten, nullptr);
|
||||
LARGE_INTEGER seekPosition;
|
||||
seekPosition.LowPart = (offset & 0xFFFF'FFFF) - (offset % this->m_sectorSize);
|
||||
seekPosition.HighPart = offset >> 32;
|
||||
|
||||
offset += currSize;
|
||||
size -= currSize;
|
||||
}
|
||||
::SetFilePointer(this->m_diskHandle, seekPosition.LowPart, &seekPosition.HighPart, FILE_BEGIN);
|
||||
::WriteFile(this->m_diskHandle, modifiedSectorBuffer.data(), modifiedSectorBuffer.size(), &bytesWritten, nullptr);
|
||||
|
||||
#else
|
||||
offset += currSize;
|
||||
size -= currSize;
|
||||
}
|
||||
|
||||
u64 startOffset = offset;
|
||||
#else
|
||||
|
||||
std::vector<u8> modifiedSectorBuffer;
|
||||
modifiedSectorBuffer.resize(this->m_sectorSize);
|
||||
u64 startOffset = offset;
|
||||
|
||||
while (size > 0) {
|
||||
u64 sectorBase = offset - (offset % this->m_sectorSize);
|
||||
size_t currSize = std::min(size, this->m_sectorSize);
|
||||
std::vector<u8> modifiedSectorBuffer;
|
||||
modifiedSectorBuffer.resize(this->m_sectorSize);
|
||||
|
||||
this->readRaw(sectorBase, modifiedSectorBuffer.data(), modifiedSectorBuffer.size());
|
||||
std::memcpy(modifiedSectorBuffer.data() + ((offset - sectorBase) % this->m_sectorSize), reinterpret_cast<const u8 *>(buffer) + (startOffset - offset), currSize);
|
||||
while (size > 0) {
|
||||
u64 sectorBase = offset - (offset % this->m_sectorSize);
|
||||
size_t currSize = std::min(size, this->m_sectorSize);
|
||||
|
||||
::lseek(this->m_diskHandle, sectorBase, SEEK_SET);
|
||||
if (::write(this->m_diskHandle, modifiedSectorBuffer.data(), modifiedSectorBuffer.size()) < 0)
|
||||
break;
|
||||
this->readRaw(sectorBase, modifiedSectorBuffer.data(), modifiedSectorBuffer.size());
|
||||
std::memcpy(modifiedSectorBuffer.data() + ((offset - sectorBase) % this->m_sectorSize), reinterpret_cast<const u8 *>(buffer) + (startOffset - offset), currSize);
|
||||
|
||||
offset += currSize;
|
||||
size -= currSize;
|
||||
}
|
||||
::lseek(this->m_diskHandle, sectorBase, SEEK_SET);
|
||||
if (::write(this->m_diskHandle, modifiedSectorBuffer.data(), modifiedSectorBuffer.size()) < 0)
|
||||
break;
|
||||
|
||||
#endif
|
||||
offset += currSize;
|
||||
size -= currSize;
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
size_t DiskProvider::getActualSize() const {
|
||||
@@ -266,66 +279,91 @@ namespace hex::plugin::builtin::prv {
|
||||
|
||||
|
||||
void DiskProvider::reloadDrives() {
|
||||
#if defined(OS_WINDOWS)
|
||||
this->m_availableDrives.clear();
|
||||
std::bitset<32> drives = ::GetLogicalDrives();
|
||||
for (char i = 0; i < 26; i++) {
|
||||
if (drives[i])
|
||||
this->m_availableDrives.insert(hex::format(R"(\\.\{:c}:)", 'A' + i));
|
||||
}
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
auto logicalDrives = this->m_availableDrives;
|
||||
for (const auto &drive : logicalDrives) {
|
||||
auto handle = reinterpret_cast<HANDLE>(::CreateFile(drive.data(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr));
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) continue;
|
||||
|
||||
VOLUME_DISK_EXTENTS diskExtents = { };
|
||||
DWORD bytesRead = 0;
|
||||
auto result = ::DeviceIoControl(
|
||||
handle,
|
||||
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
|
||||
nullptr,
|
||||
0,
|
||||
&diskExtents,
|
||||
sizeof(VOLUME_DISK_EXTENTS),
|
||||
&bytesRead,
|
||||
nullptr);
|
||||
|
||||
if (result) {
|
||||
auto diskPath = hex::format(R"(\\.\PhysicalDrive{})", diskExtents.Extents[0].DiskNumber);
|
||||
this->m_availableDrives.insert(diskPath);
|
||||
this->m_availableDrives.clear();
|
||||
std::bitset<32> drives = ::GetLogicalDrives();
|
||||
for (char i = 0; i < 26; i++) {
|
||||
if (drives[i])
|
||||
this->m_availableDrives.insert(hex::format(R"(\\.\{:c}:)", 'A' + i));
|
||||
}
|
||||
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
#endif
|
||||
auto logicalDrives = this->m_availableDrives;
|
||||
for (const auto &drive : logicalDrives) {
|
||||
auto handle = reinterpret_cast<HANDLE>(::CreateFile(drive.data(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr));
|
||||
|
||||
if (handle == INVALID_HANDLE_VALUE) continue;
|
||||
|
||||
VOLUME_DISK_EXTENTS diskExtents = { };
|
||||
DWORD bytesRead = 0;
|
||||
auto result = ::DeviceIoControl(
|
||||
handle,
|
||||
IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
|
||||
nullptr,
|
||||
0,
|
||||
&diskExtents,
|
||||
sizeof(VOLUME_DISK_EXTENTS),
|
||||
&bytesRead,
|
||||
nullptr);
|
||||
|
||||
if (result) {
|
||||
auto diskPath = hex::format(R"(\\.\PhysicalDrive{})", diskExtents.Extents[0].DiskNumber);
|
||||
this->m_availableDrives.insert(diskPath);
|
||||
}
|
||||
|
||||
::CloseHandle(handle);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
void DiskProvider::drawLoadInterface() {
|
||||
#if defined(OS_WINDOWS)
|
||||
if (ImGui::BeginListBox("hex.builtin.provider.disk.selected_disk"_lang)) {
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
for (const auto &drive : this->m_availableDrives) {
|
||||
if (ImGui::Selectable(drive.c_str(), this->m_path == drive))
|
||||
this->m_path = drive;
|
||||
if (ImGui::BeginListBox("hex.builtin.provider.disk.selected_disk"_lang)) {
|
||||
|
||||
for (const auto &drive : this->m_availableDrives) {
|
||||
if (ImGui::Selectable(drive.c_str(), this->m_path == drive))
|
||||
this->m_path = drive;
|
||||
}
|
||||
|
||||
ImGui::EndListBox();
|
||||
}
|
||||
|
||||
ImGui::EndListBox();
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("hex.builtin.provider.disk.reload"_lang)) {
|
||||
this->reloadDrives();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
#else
|
||||
|
||||
if (ImGui::Button("hex.builtin.provider.disk.reload"_lang)) {
|
||||
this->reloadDrives();
|
||||
}
|
||||
if (ImGui::InputText("hex.builtin.provider.disk.selected_disk"_lang, this->m_pathBuffer.data(), this->m_pathBuffer.size(), ImGuiInputTextFlags_CallbackResize, ImGui::UpdateStringSizeCallback, &this->m_pathBuffer))
|
||||
this->m_path = this->m_pathBuffer;
|
||||
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
if (ImGui::InputText("hex.builtin.provider.disk.selected_disk"_lang, this->m_pathBuffer.data(), this->m_pathBuffer.size(), ImGuiInputTextFlags_CallbackResize, ImGui::UpdateStringSizeCallback, &this->m_pathBuffer))
|
||||
this->m_path = this->m_pathBuffer;
|
||||
nlohmann::json DiskProvider::storeSettings(nlohmann::json settings) const {
|
||||
settings["path"] = this->m_path.string();
|
||||
|
||||
#endif
|
||||
return Provider::storeSettings(settings);
|
||||
}
|
||||
|
||||
void DiskProvider::loadSettings(const nlohmann::json &settings) {
|
||||
Provider::loadSettings(settings);
|
||||
|
||||
this->setPath(settings["path"].get<std::string>());
|
||||
this->reloadDrives();
|
||||
}
|
||||
|
||||
std::pair<Region, bool> DiskProvider::getRegionValidity(u64 address) const {
|
||||
address -= this->getBaseAddress();
|
||||
|
||||
if (address < this->getActualSize())
|
||||
return { Region { this->getBaseAddress() + address, this->getActualSize() - address }, true };
|
||||
else
|
||||
return { Region::Invalid(), false };
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,28 +2,22 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/localization.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/project_file_handler.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace hex::plugin::builtin::prv {
|
||||
|
||||
FileProvider::FileProvider() : Provider() {
|
||||
}
|
||||
|
||||
FileProvider::~FileProvider() {
|
||||
this->close();
|
||||
}
|
||||
|
||||
|
||||
bool FileProvider::isAvailable() const {
|
||||
#if defined(OS_WINDOWS)
|
||||
return this->m_file != INVALID_HANDLE_VALUE && this->m_mapping != INVALID_HANDLE_VALUE && this->m_mappedFile != nullptr;
|
||||
#else
|
||||
return this->m_file != -1 && this->m_mappedFile != nullptr;
|
||||
#endif
|
||||
#if defined(OS_WINDOWS)
|
||||
return this->m_file != INVALID_HANDLE_VALUE && this->m_mapping != INVALID_HANDLE_VALUE && this->m_mappedFile != nullptr;
|
||||
#else
|
||||
return this->m_file != -1 && this->m_mappedFile != nullptr;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool FileProvider::isReadable() const {
|
||||
@@ -194,6 +188,12 @@ namespace hex::plugin::builtin::prv {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool FileProvider::handleFilePicker() {
|
||||
return fs::openFileBrowser(fs::DialogMode::Open, {}, [this](const auto &path) {
|
||||
this->setPath(path);
|
||||
});
|
||||
}
|
||||
|
||||
void FileProvider::setPath(const std::fs::path &path) {
|
||||
this->m_path = path;
|
||||
}
|
||||
@@ -202,121 +202,146 @@ namespace hex::plugin::builtin::prv {
|
||||
this->m_readable = true;
|
||||
this->m_writable = true;
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
const auto &path = this->m_path.native();
|
||||
#if defined(OS_WINDOWS)
|
||||
const auto &path = this->m_path.native();
|
||||
|
||||
this->m_fileStatsValid = wstat(path.c_str(), &this->m_fileStats) == 0;
|
||||
this->m_fileStatsValid = wstat(path.c_str(), &this->m_fileStats) == 0;
|
||||
|
||||
LARGE_INTEGER fileSize = {};
|
||||
this->m_file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
LARGE_INTEGER fileSize = {};
|
||||
this->m_file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
|
||||
GetFileSizeEx(this->m_file, &fileSize);
|
||||
this->m_fileSize = fileSize.QuadPart;
|
||||
CloseHandle(this->m_file);
|
||||
|
||||
this->m_file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) {
|
||||
this->m_file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
this->m_writable = false;
|
||||
}
|
||||
|
||||
auto fileCleanup = SCOPE_GUARD {
|
||||
GetFileSizeEx(this->m_file, &fileSize);
|
||||
this->m_fileSize = fileSize.QuadPart;
|
||||
CloseHandle(this->m_file);
|
||||
|
||||
this->m_readable = false;
|
||||
this->m_file = nullptr;
|
||||
};
|
||||
|
||||
if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->m_fileSize > 0) {
|
||||
this->m_mapping = CreateFileMapping(this->m_file, nullptr, PAGE_READWRITE, 0, 0, nullptr);
|
||||
if (this->m_mapping == nullptr || this->m_mapping == INVALID_HANDLE_VALUE) {
|
||||
|
||||
this->m_mapping = CreateFileMapping(this->m_file, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
|
||||
if (this->m_mapping == nullptr || this->m_mapping == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
this->m_file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) {
|
||||
this->m_file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
this->m_writable = false;
|
||||
}
|
||||
|
||||
auto mappingCleanup = SCOPE_GUARD {
|
||||
CloseHandle(this->m_mapping);
|
||||
auto fileCleanup = SCOPE_GUARD {
|
||||
CloseHandle(this->m_file);
|
||||
|
||||
this->m_mapping = nullptr;
|
||||
this->m_readable = false;
|
||||
this->m_file = nullptr;
|
||||
};
|
||||
|
||||
this->m_mappedFile = MapViewOfFile(this->m_mapping, FILE_MAP_ALL_ACCESS, 0, 0, this->m_fileSize);
|
||||
if (this->m_mappedFile == nullptr) {
|
||||
|
||||
this->m_mappedFile = MapViewOfFile(this->m_mapping, FILE_MAP_READ, 0, 0, this->m_fileSize);
|
||||
if (this->m_mappedFile == nullptr) {
|
||||
this->m_readable = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mappingCleanup.release();
|
||||
if (this->m_fileSize > 0) {
|
||||
this->m_mapping = CreateFileMapping(this->m_file, nullptr, PAGE_READWRITE, 0, 0, nullptr);
|
||||
if (this->m_mapping == nullptr || this->m_mapping == INVALID_HANDLE_VALUE) {
|
||||
|
||||
ProjectFile::setFilePath(this->m_path);
|
||||
} else if (!this->m_emptyFile) {
|
||||
this->m_emptyFile = true;
|
||||
this->resize(1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
this->m_mapping = CreateFileMapping(this->m_file, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
|
||||
fileCleanup.release();
|
||||
if (this->m_mapping == nullptr || this->m_mapping == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
const auto &path = this->m_path.native();
|
||||
this->m_fileStatsValid = stat(path.c_str(), &this->m_fileStats) == 0;
|
||||
auto mappingCleanup = SCOPE_GUARD {
|
||||
CloseHandle(this->m_mapping);
|
||||
|
||||
int mmapprot = PROT_READ | PROT_WRITE;
|
||||
this->m_mapping = nullptr;
|
||||
this->m_readable = false;
|
||||
};
|
||||
|
||||
this->m_file = ::open(path.c_str(), O_RDWR);
|
||||
if (this->m_file == -1) {
|
||||
this->m_file = ::open(path.c_str(), O_RDONLY);
|
||||
this->m_writable = false;
|
||||
mmapprot &= ~(PROT_WRITE);
|
||||
}
|
||||
this->m_mappedFile = MapViewOfFile(this->m_mapping, FILE_MAP_ALL_ACCESS, 0, 0, this->m_fileSize);
|
||||
if (this->m_mappedFile == nullptr) {
|
||||
|
||||
if (this->m_file == -1) {
|
||||
this->m_readable = false;
|
||||
return false;
|
||||
}
|
||||
this->m_mappedFile = MapViewOfFile(this->m_mapping, FILE_MAP_READ, 0, 0, this->m_fileSize);
|
||||
if (this->m_mappedFile == nullptr) {
|
||||
this->m_readable = false;
|
||||
|
||||
this->m_fileSize = this->m_fileStats.st_size;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
this->m_mappedFile = ::mmap(nullptr, this->m_fileSize, mmapprot, MAP_SHARED, this->m_file, 0);
|
||||
if (this->m_mappedFile == MAP_FAILED) {
|
||||
::close(this->m_file);
|
||||
this->m_file = -1;
|
||||
mappingCleanup.release();
|
||||
} else if (!this->m_emptyFile) {
|
||||
this->m_emptyFile = true;
|
||||
this->resize(1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
fileCleanup.release();
|
||||
|
||||
Provider::resize(this->getActualSize());
|
||||
#else
|
||||
|
||||
return true;
|
||||
const auto &path = this->m_path.native();
|
||||
this->m_fileStatsValid = stat(path.c_str(), &this->m_fileStats) == 0;
|
||||
|
||||
int mmapprot = PROT_READ | PROT_WRITE;
|
||||
|
||||
this->m_file = ::open(path.c_str(), O_RDWR);
|
||||
if (this->m_file == -1) {
|
||||
this->m_file = ::open(path.c_str(), O_RDONLY);
|
||||
this->m_writable = false;
|
||||
mmapprot &= ~(PROT_WRITE);
|
||||
}
|
||||
|
||||
if (this->m_file == -1) {
|
||||
this->m_readable = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
this->m_fileSize = this->m_fileStats.st_size;
|
||||
|
||||
this->m_mappedFile = ::mmap(nullptr, this->m_fileSize, mmapprot, MAP_SHARED, this->m_file, 0);
|
||||
if (this->m_mappedFile == MAP_FAILED) {
|
||||
::close(this->m_file);
|
||||
this->m_file = -1;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
return Provider::open();
|
||||
}
|
||||
|
||||
void FileProvider::close() {
|
||||
#if defined(OS_WINDOWS)
|
||||
if (this->m_mappedFile != nullptr)
|
||||
::UnmapViewOfFile(this->m_mappedFile);
|
||||
if (this->m_mapping != nullptr)
|
||||
::CloseHandle(this->m_mapping);
|
||||
if (this->m_file != nullptr)
|
||||
::CloseHandle(this->m_file);
|
||||
#else
|
||||
::munmap(this->m_mappedFile, this->m_fileSize);
|
||||
::close(this->m_file);
|
||||
#endif
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
if (this->m_mappedFile != nullptr)
|
||||
::UnmapViewOfFile(this->m_mappedFile);
|
||||
if (this->m_mapping != nullptr)
|
||||
::CloseHandle(this->m_mapping);
|
||||
if (this->m_file != nullptr)
|
||||
::CloseHandle(this->m_file);
|
||||
|
||||
#else
|
||||
|
||||
::munmap(this->m_mappedFile, this->m_fileSize);
|
||||
::close(this->m_file);
|
||||
|
||||
#endif
|
||||
|
||||
Provider::close();
|
||||
}
|
||||
|
||||
void FileProvider::loadSettings(const nlohmann::json &settings) {
|
||||
Provider::loadSettings(settings);
|
||||
|
||||
this->setPath(settings["path"].get<std::string>());
|
||||
}
|
||||
|
||||
nlohmann::json FileProvider::storeSettings(nlohmann::json settings) const {
|
||||
settings["path"] = this->m_path.string();
|
||||
|
||||
return Provider::storeSettings(settings);
|
||||
}
|
||||
|
||||
std::pair<Region, bool> FileProvider::getRegionValidity(u64 address) const {
|
||||
address -= this->getBaseAddress();
|
||||
|
||||
if (address < this->getActualSize())
|
||||
return { Region { this->getBaseAddress() + address, this->getActualSize() - address }, true };
|
||||
else
|
||||
return { Region::Invalid(), false };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include <hex/helpers/crypto.hpp>
|
||||
#include <hex/api/localization.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace hex::plugin::builtin::prv {
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
@@ -119,11 +121,6 @@ namespace hex::plugin::builtin::prv {
|
||||
GDBProvider::GDBProvider() : Provider(), m_size(0xFFFF'FFFF) {
|
||||
}
|
||||
|
||||
GDBProvider::~GDBProvider() {
|
||||
this->close();
|
||||
}
|
||||
|
||||
|
||||
bool GDBProvider::isAvailable() const {
|
||||
return this->m_socket.isConnected();
|
||||
}
|
||||
@@ -276,9 +273,7 @@ namespace hex::plugin::builtin::prv {
|
||||
}
|
||||
});
|
||||
|
||||
Provider::resize(this->getActualSize());
|
||||
|
||||
return true;
|
||||
return Provider::open();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
@@ -290,6 +285,8 @@ namespace hex::plugin::builtin::prv {
|
||||
if (this->m_cacheUpdateThread.joinable()) {
|
||||
this->m_cacheUpdateThread.join();
|
||||
}
|
||||
|
||||
Provider::close();
|
||||
}
|
||||
|
||||
bool GDBProvider::isConnected() const {
|
||||
@@ -311,4 +308,29 @@ namespace hex::plugin::builtin::prv {
|
||||
this->m_port = 0xFFFF;
|
||||
}
|
||||
|
||||
void GDBProvider::loadSettings(const nlohmann::json &settings) {
|
||||
Provider::loadSettings(settings);
|
||||
|
||||
this->m_ipAddress = settings["ip"].get<std::string>();
|
||||
this->m_port = settings["port"].get<int>();
|
||||
this->m_size = settings["size"].get<size_t>();
|
||||
}
|
||||
|
||||
nlohmann::json GDBProvider::storeSettings(nlohmann::json settings) const {
|
||||
settings["ip"] = this->m_ipAddress;
|
||||
settings["port"] = this->m_port;
|
||||
settings["size"] = this->m_size;
|
||||
|
||||
return Provider::storeSettings(settings);
|
||||
}
|
||||
|
||||
std::pair<Region, bool> GDBProvider::getRegionValidity(u64 address) const {
|
||||
address -= this->getBaseAddress();
|
||||
|
||||
if (address < this->getActualSize())
|
||||
return { Region { this->getBaseAddress() + address, this->getActualSize() - address }, true };
|
||||
else
|
||||
return { Region::Invalid(), false };
|
||||
}
|
||||
|
||||
}
|
||||
263
plugins/builtin/source/content/providers/intel_hex_provider.cpp
Normal file
263
plugins/builtin/source/content/providers/intel_hex_provider.cpp
Normal file
@@ -0,0 +1,263 @@
|
||||
#include "content/providers/intel_hex_provider.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/localization.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace hex::plugin::builtin::prv {
|
||||
|
||||
namespace intel_hex {
|
||||
|
||||
u8 parseHexDigit(char c) {
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
else
|
||||
throw std::runtime_error("Failed to parse hex digit");
|
||||
}
|
||||
|
||||
std::map<u64, std::vector<u8>> parseIntelHex(const std::string &string) {
|
||||
std::map<u64, std::vector<u8>> result;
|
||||
|
||||
u8 checksum = 0x00;
|
||||
u64 offset = 0x00;
|
||||
|
||||
u8 byteCount = 0x00;
|
||||
u32 segmentAddress = 0x0000'0000;
|
||||
u32 extendedLinearAddress = 0x0000'0000;
|
||||
u16 address = 0x0000;
|
||||
std::vector<u8> data;
|
||||
|
||||
enum class RecordType {
|
||||
Data = 0x00,
|
||||
EndOfFile = 0x01,
|
||||
ExtendedSegmentAddress = 0x02,
|
||||
StartSegmentAddress = 0x03,
|
||||
ExtendedLinearAddress = 0x04,
|
||||
StartLinearAddress = 0x05
|
||||
} recordType;
|
||||
|
||||
auto c = [&]() {
|
||||
while (std::isspace(string[offset]) && offset < string.length())
|
||||
offset++;
|
||||
|
||||
if (offset >= string.length())
|
||||
throw std::runtime_error("Unexpected end of file");
|
||||
|
||||
return string[offset++];
|
||||
};
|
||||
|
||||
auto parseValue = [&](u8 byteCount) {
|
||||
u64 value = 0x00;
|
||||
for (u8 i = 0; i < byteCount; i++) {
|
||||
u8 byte = (parseHexDigit(c()) << 4) | parseHexDigit(c());
|
||||
value <<= 8;
|
||||
value |= byte;
|
||||
|
||||
checksum += byte;
|
||||
}
|
||||
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
bool endOfFile = false;
|
||||
try {
|
||||
while (offset < string.length()) {
|
||||
// Parse start code
|
||||
if (c() != ':')
|
||||
return { };
|
||||
|
||||
checksum = 0x00;
|
||||
|
||||
if (endOfFile)
|
||||
throw std::runtime_error("Unexpected end of file");
|
||||
|
||||
// Parse byte count
|
||||
byteCount = parseValue(1);
|
||||
|
||||
// Parse address
|
||||
address = parseValue(2);
|
||||
|
||||
// Parse record type
|
||||
recordType = static_cast<RecordType>(parseValue(1));
|
||||
|
||||
data.clear();
|
||||
for (u32 i = 0; i < byteCount; i++) {
|
||||
data.push_back(parseValue(1));
|
||||
}
|
||||
|
||||
parseValue(1);
|
||||
if (!data.empty() && checksum != 0x00)
|
||||
throw std::runtime_error("Checksum mismatch");
|
||||
|
||||
while (std::isspace(string[offset]) && offset < string.length())
|
||||
offset++;
|
||||
|
||||
// Construct region
|
||||
switch (recordType) {
|
||||
case RecordType::Data: {
|
||||
result[extendedLinearAddress | (segmentAddress + address)] = data;
|
||||
break;
|
||||
}
|
||||
case RecordType::EndOfFile: {
|
||||
endOfFile = true;
|
||||
break;
|
||||
}
|
||||
case RecordType::ExtendedSegmentAddress: {
|
||||
if (byteCount != 2)
|
||||
throw std::runtime_error("Unexpected byte count");
|
||||
|
||||
segmentAddress = (data[0] << 8 | data[1]) * 16;
|
||||
break;
|
||||
}
|
||||
case RecordType::StartSegmentAddress: {
|
||||
if (byteCount != 4)
|
||||
throw std::runtime_error("Unexpected byte count");
|
||||
|
||||
// Can be safely ignored
|
||||
break;
|
||||
}
|
||||
case RecordType::ExtendedLinearAddress: {
|
||||
if (byteCount != 2)
|
||||
throw std::runtime_error("Unexpected byte count");
|
||||
|
||||
extendedLinearAddress = (data[0] << 8 | data[1]) << 16;
|
||||
break;
|
||||
}
|
||||
case RecordType::StartLinearAddress: {
|
||||
if (byteCount != 4)
|
||||
throw std::runtime_error("Unexpected byte count");
|
||||
|
||||
// Can be safely ignored
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (const std::runtime_error &e) {
|
||||
return { };
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void IntelHexProvider::setBaseAddress(u64 address) {
|
||||
auto oldBase = this->getBaseAddress();
|
||||
|
||||
auto intervals = this->m_data.findOverlapping(oldBase, oldBase + this->getActualSize());
|
||||
|
||||
for (auto &interval : intervals) {
|
||||
interval.start = (interval.start - oldBase) + address;
|
||||
interval.stop = (interval.stop - oldBase) + address;
|
||||
}
|
||||
|
||||
this->m_data = std::move(intervals);
|
||||
|
||||
Provider::setBaseAddress(address);
|
||||
}
|
||||
|
||||
void IntelHexProvider::readRaw(u64 offset, void *buffer, size_t size) {
|
||||
auto intervals = this->m_data.findOverlapping(offset, (offset + size) - 1);
|
||||
|
||||
std::memset(buffer, 0x00, size);
|
||||
auto bytes = reinterpret_cast<u8*>(buffer);
|
||||
for (const auto &interval : intervals) {
|
||||
for (u32 i = std::max(interval.start, offset); i <= interval.stop && (i - offset) < size; i++) {
|
||||
bytes[i - offset] = interval.value[i - interval.start];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IntelHexProvider::writeRaw(u64 offset, const void *buffer, size_t size) {
|
||||
hex::unused(offset, buffer, size);
|
||||
}
|
||||
|
||||
size_t IntelHexProvider::getActualSize() const {
|
||||
return this->m_dataSize;
|
||||
}
|
||||
|
||||
bool IntelHexProvider::open() {
|
||||
auto file = fs::File(this->m_sourceFilePath, fs::File::Mode::Read);
|
||||
if (!file.isValid())
|
||||
return false;
|
||||
|
||||
auto data = intel_hex::parseIntelHex(file.readString());
|
||||
if (data.empty())
|
||||
return false;
|
||||
|
||||
u64 maxAddress = 0x00;
|
||||
decltype(this->m_data)::interval_vector intervals;
|
||||
for (auto &[address, bytes] : data) {
|
||||
auto endAddress = (address + bytes.size()) - 1;
|
||||
intervals.emplace_back(address, endAddress, std::move(bytes));
|
||||
|
||||
if (endAddress > maxAddress)
|
||||
maxAddress = endAddress;
|
||||
}
|
||||
this->m_data = std::move(intervals);
|
||||
this->m_dataSize = maxAddress + 1;
|
||||
this->m_dataValid = true;
|
||||
|
||||
return Provider::open();
|
||||
}
|
||||
|
||||
void IntelHexProvider::close() {
|
||||
|
||||
Provider::close();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string IntelHexProvider::getName() const {
|
||||
return hex::format("hex.builtin.provider.intel_hex.name"_lang, this->m_sourceFilePath.filename().string());
|
||||
}
|
||||
|
||||
bool IntelHexProvider::handleFilePicker() {
|
||||
auto picked = fs::openFileBrowser(fs::DialogMode::Open, { { "Intel Hex File", "*" } }, [this](const std::fs::path &path) {
|
||||
this->m_sourceFilePath = path;
|
||||
});
|
||||
if (!picked)
|
||||
return false;
|
||||
if (!fs::isRegularFile(this->m_sourceFilePath))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<Region, bool> IntelHexProvider::getRegionValidity(u64 address) const {
|
||||
auto intervals = this->m_data.findOverlapping(address, address);
|
||||
if (intervals.empty()) {
|
||||
return Provider::getRegionValidity(address);
|
||||
}
|
||||
|
||||
auto closestInterval = intervals.front();
|
||||
for (const auto &interval : intervals) {
|
||||
if (interval.start < closestInterval.start)
|
||||
closestInterval = interval;
|
||||
}
|
||||
return { Region { closestInterval.start, (closestInterval.stop - closestInterval.start) + 1}, true };
|
||||
}
|
||||
|
||||
void IntelHexProvider::loadSettings(const nlohmann::json &settings) {
|
||||
Provider::loadSettings(settings);
|
||||
|
||||
this->m_sourceFilePath = settings["path"].get<std::string>();
|
||||
}
|
||||
|
||||
nlohmann::json IntelHexProvider::storeSettings(nlohmann::json settings) const {
|
||||
settings["path"] = this->m_sourceFilePath.string();
|
||||
|
||||
return Provider::storeSettings(settings);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
#include "content/providers/motorola_srec_provider.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/localization.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace hex::plugin::builtin::prv {
|
||||
|
||||
namespace motorola_srec {
|
||||
|
||||
u8 parseHexDigit(char c) {
|
||||
if (c >= '0' && c <= '9')
|
||||
return c - '0';
|
||||
else if (c >= 'A' && c <= 'F')
|
||||
return c - 'A' + 10;
|
||||
else if (c >= 'a' && c <= 'f')
|
||||
return c - 'a' + 10;
|
||||
else
|
||||
throw std::runtime_error("Failed to parse hex digit");
|
||||
}
|
||||
|
||||
std::map<u64, std::vector<u8>> parseMotorolaSREC(const std::string &string) {
|
||||
std::map<u64, std::vector<u8>> result;
|
||||
|
||||
u64 offset = 0x00;
|
||||
u8 checksum = 0x00;
|
||||
u8 byteCount = 0x00;
|
||||
u32 address = 0x0000'0000;
|
||||
std::vector<u8> data;
|
||||
|
||||
auto c = [&]() {
|
||||
while (std::isspace(string[offset]) && offset < string.length())
|
||||
offset++;
|
||||
|
||||
if (offset >= string.length())
|
||||
throw std::runtime_error("Unexpected end of file");
|
||||
|
||||
return string[offset++];
|
||||
};
|
||||
|
||||
auto parseValue = [&](u8 byteCount) {
|
||||
u64 value = 0x00;
|
||||
for (u8 i = 0; i < byteCount; i++) {
|
||||
u8 byte = (parseHexDigit(c()) << 4) | parseHexDigit(c());
|
||||
value <<= 8;
|
||||
value |= byte;
|
||||
|
||||
checksum += byte;
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
enum class RecordType {
|
||||
Header = 0x00,
|
||||
Data16 = 0x01,
|
||||
Data24 = 0x02,
|
||||
Data32 = 0x03,
|
||||
Reserved = 0x04,
|
||||
Count16 = 0x05,
|
||||
Count24 = 0x06,
|
||||
StartAddress32 = 0x07,
|
||||
StartAddress24 = 0x08,
|
||||
StartAddress16 = 0x09,
|
||||
} recordType;
|
||||
|
||||
bool endOfFile = false;
|
||||
try {
|
||||
while (offset < string.length()) {
|
||||
// Parse record start
|
||||
if (c() != 'S')
|
||||
return { };
|
||||
|
||||
if (endOfFile)
|
||||
throw std::runtime_error("Unexpected end of file");
|
||||
|
||||
// Parse record type
|
||||
{
|
||||
char typeCharacter = c();
|
||||
if (typeCharacter < '0' || typeCharacter > '9')
|
||||
throw std::runtime_error("Invalid record type");
|
||||
recordType = static_cast<RecordType>(typeCharacter - '0');
|
||||
}
|
||||
|
||||
checksum = 0x00;
|
||||
|
||||
// Parse byte count
|
||||
byteCount = parseValue(1);
|
||||
|
||||
// Parse address
|
||||
switch (recordType) {
|
||||
case RecordType::Reserved:
|
||||
break;
|
||||
case RecordType::Header:
|
||||
case RecordType::Data16:
|
||||
case RecordType::Count16:
|
||||
case RecordType::StartAddress16:
|
||||
byteCount -= 2;
|
||||
address = parseValue(2);
|
||||
break;
|
||||
case RecordType::Data24:
|
||||
case RecordType::Count24:
|
||||
case RecordType::StartAddress24:
|
||||
byteCount -= 3;
|
||||
address = parseValue(3);
|
||||
break;
|
||||
case RecordType::Data32:
|
||||
case RecordType::StartAddress32:
|
||||
byteCount -= 4;
|
||||
address = parseValue(4);
|
||||
break;
|
||||
}
|
||||
|
||||
byteCount -= 1;
|
||||
|
||||
auto readData = [&byteCount, &parseValue]() {
|
||||
std::vector<u8> bytes;
|
||||
bytes.resize(byteCount);
|
||||
for (u8 i = 0; i < byteCount; i++) {
|
||||
bytes[i] = parseValue(1);
|
||||
}
|
||||
|
||||
return bytes;
|
||||
};
|
||||
|
||||
// Parse data
|
||||
data = readData();
|
||||
|
||||
// Parse checksum
|
||||
{
|
||||
auto value = parseValue(1);
|
||||
if (((checksum - value) ^ 0xFF) != value)
|
||||
throw std::runtime_error("Invalid checksum");
|
||||
}
|
||||
|
||||
// Construct region
|
||||
switch (recordType) {
|
||||
case RecordType::Data16:
|
||||
case RecordType::Data24:
|
||||
case RecordType::Data32:
|
||||
result[address] = data;
|
||||
break;
|
||||
case RecordType::Header:
|
||||
case RecordType::Reserved:
|
||||
break;
|
||||
case RecordType::Count16:
|
||||
case RecordType::Count24:
|
||||
break;
|
||||
case RecordType::StartAddress32:
|
||||
case RecordType::StartAddress24:
|
||||
case RecordType::StartAddress16:
|
||||
endOfFile = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (const std::runtime_error &e) {
|
||||
return { };
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool MotorolaSRECProvider::open() {
|
||||
auto file = fs::File(this->m_sourceFilePath, fs::File::Mode::Read);
|
||||
if (!file.isValid())
|
||||
return false;
|
||||
|
||||
auto data = motorola_srec::parseMotorolaSREC(file.readString());
|
||||
if (data.empty())
|
||||
return false;
|
||||
|
||||
u64 maxAddress = 0x00;
|
||||
decltype(this->m_data)::interval_vector intervals;
|
||||
for (auto &[address, bytes] : data) {
|
||||
auto endAddress = (address + bytes.size()) - 1;
|
||||
intervals.emplace_back(address, endAddress, std::move(bytes));
|
||||
|
||||
if (endAddress > maxAddress)
|
||||
maxAddress = endAddress;
|
||||
}
|
||||
this->m_data = std::move(intervals);
|
||||
this->m_dataSize = maxAddress + 1;
|
||||
this->m_dataValid = true;
|
||||
|
||||
return Provider::open();
|
||||
}
|
||||
|
||||
void MotorolaSRECProvider::close() {
|
||||
Provider::close();
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string MotorolaSRECProvider::getName() const {
|
||||
return hex::format("hex.builtin.provider.motorola_srec.name"_lang, this->m_sourceFilePath.filename().string());
|
||||
}
|
||||
|
||||
bool MotorolaSRECProvider::handleFilePicker() {
|
||||
auto picked = fs::openFileBrowser(fs::DialogMode::Open, { { "Motorola SREC File", "*" } }, [this](const std::fs::path &path) {
|
||||
this->m_sourceFilePath = path;
|
||||
});
|
||||
if (!picked)
|
||||
return false;
|
||||
if (!fs::isRegularFile(this->m_sourceFilePath))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user