mirror of
https://github.com/WerWolv/ImHex.git
synced 2026-03-31 13:26:02 -05:00
Compare commits
58 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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
|
||||
|
||||
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@@ -61,4 +61,4 @@ jobs:
|
||||
- name: 🧪 Perform Unit Tests
|
||||
run: |
|
||||
cd build
|
||||
ctest
|
||||
ctest --output-on-failure
|
||||
@@ -46,4 +46,4 @@ enable_testing()
|
||||
add_subdirectory(tests EXCLUDE_FROM_ALL)
|
||||
|
||||
# Configure packaging
|
||||
createPackage()
|
||||
createPackage()
|
||||
@@ -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}")
|
||||
@@ -135,15 +136,18 @@ macro(configurePackingResources)
|
||||
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...7285b76f82
@@ -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);
|
||||
@@ -132,7 +129,7 @@ namespace hex {
|
||||
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,14 +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);
|
||||
|
||||
prv::Provider* createProvider(const std::string &unlocalizedName, bool skipLoadInterface = false);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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 };
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
|
||||
@@ -211,9 +211,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;
|
||||
@@ -240,23 +253,50 @@ namespace hex {
|
||||
return !s_providers.empty() && s_currentProvider < s_providers.size();
|
||||
}
|
||||
|
||||
void add(prv::Provider *provider) {
|
||||
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 (Task::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)
|
||||
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,12 +305,21 @@ 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);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -436,6 +485,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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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->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 { address, this->getActualSize() - address }, true };
|
||||
else
|
||||
return { Region { address, *nextRegionAddress - address }, insideValidRegion };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -8,11 +8,12 @@
|
||||
#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
|
||||
|
||||
@@ -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,6 +63,25 @@ 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()) {
|
||||
@@ -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());
|
||||
@@ -199,6 +200,13 @@ namespace hex {
|
||||
this->frameBegin();
|
||||
this->frame();
|
||||
this->frameEnd();
|
||||
|
||||
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();
|
||||
|
||||
this->m_hadEvent = false;
|
||||
}
|
||||
}
|
||||
@@ -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,50 @@
|
||||
#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 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>
|
||||
|
||||
@@ -29,9 +30,9 @@ namespace hex::plugin::builtin {
|
||||
private:
|
||||
bool m_disassembling = false;
|
||||
|
||||
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,7 +69,11 @@ 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::map<prv::Provider*, OccurrenceTree> m_occurrenceTree;
|
||||
|
||||
std::atomic<bool> m_searchRunning;
|
||||
bool m_settingsValid = false;
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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,61 +3,54 @@
|
||||
|
||||
#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); });
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderClosing>([](hex::prv::Provider *provider, bool *shouldClose) {
|
||||
if (provider->isDirty()) {
|
||||
*shouldClose = false;
|
||||
ImHexApi::Tasks::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>("");
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<RequestOpenFile>(openFile);
|
||||
|
||||
EventManager::subscribe<RequestOpenWindow>([](const std::string &name) {
|
||||
@@ -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()) {
|
||||
ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); });
|
||||
return;
|
||||
}
|
||||
if (!provider->open()) {
|
||||
View::showErrorPopup("hex.builtin.popup.error.open"_lang);
|
||||
ImHexApi::Tasks::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);
|
||||
ImHexApi::Tasks::doLater([provider] { ImHexApi::Provider::remove(provider); });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderDeleted>([](hex::prv::Provider *provider) {
|
||||
ProviderExtraData::erase(provider);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,9 +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 <hex/helpers/patches.hpp>
|
||||
|
||||
#include <thread>
|
||||
|
||||
@@ -32,7 +33,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,18 +70,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);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -254,15 +251,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>());
|
||||
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,89 @@ 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 {
|
||||
if (address < this->getActualSize())
|
||||
return { Region { 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,144 @@ 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 {
|
||||
if (address < this->getActualSize())
|
||||
return { Region { 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,27 @@ 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 {
|
||||
if (address < this->getActualSize())
|
||||
return { Region { address, this->getActualSize() - address }, true };
|
||||
else
|
||||
return { Region::Invalid(), false };
|
||||
}
|
||||
|
||||
}
|
||||
248
plugins/builtin/source/content/providers/intel_hex_provider.cpp
Normal file
248
plugins/builtin/source/content/providers/intel_hex_provider.cpp
Normal file
@@ -0,0 +1,248 @@
|
||||
#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::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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -37,15 +37,21 @@ namespace hex::plugin::builtin {
|
||||
using namespace hex::literals;
|
||||
|
||||
void drawDemangler() {
|
||||
static std::vector<char> mangledBuffer(0xF'FFFF, 0x00);
|
||||
static std::string demangledName;
|
||||
static std::string mangledName, demangledName;
|
||||
|
||||
if (ImGui::InputText("hex.builtin.tools.demangler.mangled"_lang, mangledBuffer.data(), 0xF'FFFF)) {
|
||||
demangledName = llvm::demangle(mangledBuffer.data());
|
||||
if (ImGui::InputTextWithHint("hex.builtin.tools.demangler.mangled"_lang, "Itanium, MSVC, Dlang & Rust", mangledName)) {
|
||||
demangledName = llvm::demangle(mangledName);
|
||||
|
||||
if (demangledName == mangledName) {
|
||||
demangledName = "???";
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::InputText("hex.builtin.tools.demangler.demangled"_lang, demangledName.data(), demangledName.size(), ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::NewLine();
|
||||
ImGui::Header("hex.builtin.tools.demangler.demangled"_lang);
|
||||
if (ImGui::BeginChild("demangled", ImVec2(0, 200_scaled), true)) {
|
||||
ImGui::TextFormattedWrapped("{}", demangledName);
|
||||
}
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
void drawASCIITable() {
|
||||
|
||||
@@ -28,8 +28,27 @@ namespace hex::plugin::builtin {
|
||||
ImGui::TextUnformatted("hex.builtin.popup.exit_application.desc"_lang);
|
||||
ImGui::NewLine();
|
||||
|
||||
View::confirmButtons(
|
||||
"hex.builtin.common.yes"_lang, "hex.builtin.common.no"_lang, [] { ImHexApi::Common::closeImHex(true); }, [] { ImGui::CloseCurrentPopup(); });
|
||||
View::confirmButtons("hex.builtin.common.yes"_lang, "hex.builtin.common.no"_lang,
|
||||
[] { ImHexApi::Common::closeImHex(true); },
|
||||
[] { ImGui::CloseCurrentPopup(); }
|
||||
);
|
||||
|
||||
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape)))
|
||||
ImGui::CloseCurrentPopup();
|
||||
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
// "Are you sure you want to close provider?" Popup
|
||||
if (ImGui::BeginPopupModal("hex.builtin.popup.close_provider.title"_lang, nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::NewLine();
|
||||
ImGui::TextUnformatted("hex.builtin.popup.close_provider.desc"_lang);
|
||||
ImGui::NewLine();
|
||||
|
||||
View::confirmButtons("hex.builtin.common.yes"_lang, "hex.builtin.common.no"_lang,
|
||||
[] { ImHexApi::Provider::remove(ImHexApi::Provider::impl::getClosingProvider(), true); ImGui::CloseCurrentPopup(); },
|
||||
[] { ImGui::CloseCurrentPopup(); }
|
||||
);
|
||||
|
||||
if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape)))
|
||||
ImGui::CloseCurrentPopup();
|
||||
@@ -313,7 +332,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
bool open = true;
|
||||
ImGui::PushID(tabProvider);
|
||||
if (ImGui::BeginTabItem(tabProvider->getName().c_str(), &open)) {
|
||||
if (ImGui::BeginTabItem(tabProvider->getName().c_str(), &open, provider->isDirty() ? ImGuiTabItemFlags_UnsavedDocument : ImGuiTabItemFlags_None)) {
|
||||
ImHexApi::Provider::setCurrentProvider(i);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
#include "content/views/view_bookmarks.hpp"
|
||||
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
|
||||
#include <hex/helpers/project_file_handler.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <cstring>
|
||||
|
||||
#include <provider_extra_data.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
ViewBookmarks::ViewBookmarks() : View("hex.builtin.view.bookmarks.name") {
|
||||
EventManager::subscribe<RequestAddBookmark>(this, [this](Region region, std::string name, std::string comment, color_t color) {
|
||||
EventManager::subscribe<RequestAddBookmark>(this, [](Region region, std::string name, std::string comment, color_t color) {
|
||||
if (name.empty()) {
|
||||
name = hex::format("hex.builtin.view.bookmarks.default_title"_lang, region.address, region.address + region.size - 1);
|
||||
}
|
||||
@@ -18,34 +22,21 @@ namespace hex::plugin::builtin {
|
||||
if (color == 0x00)
|
||||
color = ImGui::GetColorU32(ImGuiCol_Header);
|
||||
|
||||
|
||||
this->m_bookmarks.push_back({ region,
|
||||
ProviderExtraData::getCurrent().bookmarks.push_back({
|
||||
region,
|
||||
name,
|
||||
std::move(comment),
|
||||
color,
|
||||
false
|
||||
});
|
||||
|
||||
ProjectFile::markDirty();
|
||||
ImHexApi::Provider::markDirty();
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProjectFileLoad>(this, [this] {
|
||||
this->m_bookmarks = ProjectFile::getBookmarks();
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProjectFileStore>(this, [this] {
|
||||
ProjectFile::setBookmarks(this->m_bookmarks);
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderDeleted>(this, [this](const auto*) {
|
||||
this->m_bookmarks.clear();
|
||||
});
|
||||
|
||||
|
||||
ImHexApi::HexEditor::addBackgroundHighlightingProvider([this](u64 address, const u8* data, size_t size) -> std::optional<color_t> {
|
||||
ImHexApi::HexEditor::addBackgroundHighlightingProvider([](u64 address, const u8* data, size_t size) -> std::optional<color_t> {
|
||||
hex::unused(data);
|
||||
|
||||
for (const auto &bookmark : this->m_bookmarks) {
|
||||
for (const auto &bookmark : ProviderExtraData::getCurrent().bookmarks) {
|
||||
if (Region { address, size }.isWithin(bookmark.region))
|
||||
return bookmark.color;
|
||||
}
|
||||
@@ -53,9 +44,9 @@ namespace hex::plugin::builtin {
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) {
|
||||
ImHexApi::HexEditor::addTooltipProvider([](u64 address, const u8 *data, size_t size) {
|
||||
hex::unused(data);
|
||||
for (const auto &bookmark : this->m_bookmarks) {
|
||||
for (const auto &bookmark : ProviderExtraData::getCurrent().bookmarks) {
|
||||
if (!Region { address, size }.isWithin(bookmark.region))
|
||||
continue;
|
||||
|
||||
@@ -109,15 +100,34 @@ namespace hex::plugin::builtin {
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
});
|
||||
|
||||
ProjectFile::registerPerProviderHandler({
|
||||
.basePath = "bookmarks.json",
|
||||
.load = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool {
|
||||
auto fileContent = tar.read(basePath);
|
||||
if (fileContent.empty())
|
||||
return true;
|
||||
|
||||
auto data = nlohmann::json::parse(fileContent.begin(), fileContent.end());
|
||||
ProviderExtraData::get(provider).bookmarks.clear();
|
||||
return ViewBookmarks::importBookmarks(provider, data);
|
||||
},
|
||||
.store = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool {
|
||||
nlohmann::json data;
|
||||
|
||||
bool result = ViewBookmarks::exportBookmarks(provider, data);
|
||||
tar.write(basePath, data.dump(4));
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
||||
|
||||
this->registerMenuItems();
|
||||
}
|
||||
|
||||
ViewBookmarks::~ViewBookmarks() {
|
||||
EventManager::unsubscribe<RequestAddBookmark>(this);
|
||||
EventManager::unsubscribe<EventProjectFileLoad>(this);
|
||||
EventManager::unsubscribe<EventProjectFileStore>(this);
|
||||
EventManager::unsubscribe<EventProviderDeleted>(this);
|
||||
|
||||
this->m_bookmarks.clear();
|
||||
}
|
||||
|
||||
void ViewBookmarks::drawContent() {
|
||||
@@ -130,14 +140,14 @@ namespace hex::plugin::builtin {
|
||||
ImGui::NewLine();
|
||||
|
||||
if (ImGui::BeginChild("##bookmarks")) {
|
||||
|
||||
if (this->m_bookmarks.empty()) {
|
||||
auto &bookmarks = ProviderExtraData::getCurrent().bookmarks;
|
||||
if (bookmarks.empty()) {
|
||||
ImGui::TextFormattedCentered("hex.builtin.view.bookmarks.no_bookmarks"_lang);
|
||||
}
|
||||
|
||||
u32 id = 1;
|
||||
auto bookmarkToRemove = this->m_bookmarks.end();
|
||||
for (auto iter = this->m_bookmarks.begin(); iter != this->m_bookmarks.end(); iter++) {
|
||||
auto bookmarkToRemove = bookmarks.end();
|
||||
for (auto iter = bookmarks.begin(); iter != bookmarks.end(); iter++) {
|
||||
auto &[region, name, comment, color, locked] = *iter;
|
||||
|
||||
if (!this->m_currFilter.empty()) {
|
||||
@@ -248,9 +258,8 @@ namespace hex::plugin::builtin {
|
||||
id++;
|
||||
}
|
||||
|
||||
if (bookmarkToRemove != this->m_bookmarks.end()) {
|
||||
this->m_bookmarks.erase(bookmarkToRemove);
|
||||
ProjectFile::markDirty();
|
||||
if (bookmarkToRemove != bookmarks.end()) {
|
||||
bookmarks.erase(bookmarkToRemove);
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
@@ -258,4 +267,82 @@ namespace hex::plugin::builtin {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
bool ViewBookmarks::importBookmarks(prv::Provider *provider, const nlohmann::json &json) {
|
||||
if (!json.contains("bookmarks"))
|
||||
return false;
|
||||
|
||||
auto &bookmarks = ProviderExtraData::get(provider).bookmarks;
|
||||
for (const auto &bookmark : json["bookmarks"]) {
|
||||
if (!bookmark.contains("name") || !bookmark.contains("comment") || !bookmark.contains("color") || !bookmark.contains("region") || !bookmark.contains("locked"))
|
||||
continue;
|
||||
|
||||
const auto ®ion = bookmark["region"];
|
||||
if (!region.contains("address") || !region.contains("size"))
|
||||
continue;
|
||||
|
||||
bookmarks.push_back({
|
||||
.region = { region["address"], region["size"] },
|
||||
.name = bookmark["name"],
|
||||
.comment = bookmark["comment"],
|
||||
.color = bookmark["color"],
|
||||
.locked = bookmark["locked"]
|
||||
});
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ViewBookmarks::exportBookmarks(prv::Provider *provider, nlohmann::json &json) {
|
||||
json["bookmarks"] = nlohmann::json::array();
|
||||
size_t index = 0;
|
||||
for (const auto &bookmark : ProviderExtraData::get(provider).bookmarks) {
|
||||
json["bookmarks"][index] = {
|
||||
{ "name", bookmark.name },
|
||||
{ "comment", bookmark.comment },
|
||||
{ "color", bookmark.color },
|
||||
{ "region", {
|
||||
{ "address", bookmark.region.address },
|
||||
{ "size", bookmark.region.size }
|
||||
}
|
||||
},
|
||||
{ "locked", bookmark.locked }
|
||||
};
|
||||
index++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ViewBookmarks::registerMenuItems() {
|
||||
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.create"_lang, nullptr, false, selection.has_value() && providerValid)) {
|
||||
ImHexApi::Bookmarks::add(selection->getStartAddress(), selection->getSize(), {}, {});
|
||||
}
|
||||
});
|
||||
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 4000, [&] {
|
||||
bool providerValid = ImHexApi::Provider::isValid();
|
||||
auto selection = ImHexApi::HexEditor::getSelection();
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.bookmark.import"_lang, nullptr, false, selection.has_value() && providerValid)) {
|
||||
fs::openFileBrowser(fs::DialogMode::Open, { { "Bookmarks File", "hexbm"} }, [&](const std::fs::path &path) {
|
||||
try {
|
||||
importBookmarks(ImHexApi::Provider::get(), nlohmann::json::parse(fs::File(path, fs::File::Mode::Read).readString()));
|
||||
} catch (...) { }
|
||||
});
|
||||
}
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.bookmark.export"_lang, nullptr, false, selection.has_value() && providerValid)) {
|
||||
fs::openFileBrowser(fs::DialogMode::Save, { { "Bookmarks File", "hexbm"} }, [&](const std::fs::path &path) {
|
||||
nlohmann::json json;
|
||||
exportBookmarks(ImHexApi::Provider::get(), json);
|
||||
|
||||
fs::File(path, fs::File::Mode::Create).write(json.dump(4));
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,11 +5,13 @@
|
||||
#include <hex/helpers/file.hpp>
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/helpers/project_file_handler.hpp>
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
|
||||
#include <imnodes.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "provider_extra_data.hpp"
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
ViewDataProcessor::ViewDataProcessor() : View("hex.builtin.view.data_processor.name") {
|
||||
@@ -30,24 +32,28 @@ namespace hex::plugin::builtin {
|
||||
ImNodes::GetStyle().Flags = ImNodesStyleFlags_NodeOutline | ImNodesStyleFlags_GridLines;
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProjectFileStore>(this, [this] {
|
||||
ProjectFile::setDataProcessorContent(this->saveNodes());
|
||||
});
|
||||
ProjectFile::registerPerProviderHandler({
|
||||
.basePath = "data_processor.json",
|
||||
.load = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) {
|
||||
auto save = tar.readString(basePath);
|
||||
|
||||
EventManager::subscribe<EventProjectFileLoad>(this, [this] {
|
||||
try {
|
||||
this->loadNodes(ProjectFile::getDataProcessorContent());
|
||||
} catch (nlohmann::json::exception &e) {
|
||||
this->loadNodes(provider, save);
|
||||
|
||||
return true;
|
||||
},
|
||||
.store = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) {
|
||||
tar.write(basePath, this->saveNodes(provider));
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventFileLoaded>(this, [this](const std::fs::path &path) {
|
||||
hex::unused(path);
|
||||
|
||||
for (auto &node : this->m_nodes) {
|
||||
EventManager::subscribe<EventProviderChanged>(this, [](const auto &, const auto &) {
|
||||
auto &data = ProviderExtraData::getCurrent().dataProcessor;
|
||||
for (auto &node : data.nodes) {
|
||||
node->setCurrentOverlay(nullptr);
|
||||
}
|
||||
this->m_dataOverlays.clear();
|
||||
data.dataOverlays.clear();
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventDataChanged>(this, [this] {
|
||||
@@ -56,22 +62,25 @@ namespace hex::plugin::builtin {
|
||||
|
||||
ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 3000, [&, this] {
|
||||
bool providerValid = ImHexApi::Provider::isValid();
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
auto &data = ProviderExtraData::getCurrent().dataProcessor;
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.view.data_processor.menu.file.load_processor"_lang, nullptr, false, providerValid)) {
|
||||
fs::openFileBrowser(fs::DialogMode::Open, { {"hex.builtin.view.data_processor.name"_lang, "hexnode"} },
|
||||
[this](const std::fs::path &path) {
|
||||
[&, this](const std::fs::path &path) {
|
||||
fs::File file(path, fs::File::Mode::Read);
|
||||
if (file.isValid())
|
||||
this->loadNodes(file.readString());
|
||||
this->loadNodes(provider, file.readString());
|
||||
});
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.view.data_processor.menu.file.save_processor"_lang, nullptr, false, !this->m_nodes.empty() && providerValid)) {
|
||||
if (ImGui::MenuItem("hex.builtin.view.data_processor.menu.file.save_processor"_lang, nullptr, false, !data.nodes.empty() && providerValid)) {
|
||||
fs::openFileBrowser(fs::DialogMode::Save, { {"hex.builtin.view.data_processor.name"_lang, "hexnode"} },
|
||||
[this](const std::fs::path &path) {
|
||||
[&, this](const std::fs::path &path) {
|
||||
fs::File file(path, fs::File::Mode::Create);
|
||||
if (file.isValid())
|
||||
file.write(this->saveNodes());
|
||||
file.write(this->saveNodes(provider));
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -80,44 +89,45 @@ namespace hex::plugin::builtin {
|
||||
fs::File file(path, fs::File::Mode::Read);
|
||||
if (!file.isValid()) return false;
|
||||
|
||||
this->loadNodes(file.readString());
|
||||
this->loadNodes(ImHexApi::Provider::get(), file.readString());
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
ViewDataProcessor::~ViewDataProcessor() {
|
||||
for (auto &node : this->m_nodes)
|
||||
delete node;
|
||||
|
||||
EventManager::unsubscribe<RequestChangeTheme>(this);
|
||||
EventManager::unsubscribe<EventFileLoaded>(this);
|
||||
EventManager::unsubscribe<EventProjectFileStore>(this);
|
||||
EventManager::unsubscribe<EventProjectFileLoad>(this);
|
||||
EventManager::unsubscribe<EventDataChanged>(this);
|
||||
}
|
||||
|
||||
|
||||
void ViewDataProcessor::eraseLink(u32 id) {
|
||||
auto link = std::find_if(this->m_links.begin(), this->m_links.end(), [&id](auto link) { return link.getId() == id; });
|
||||
auto &data = ProviderExtraData::getCurrent().dataProcessor;
|
||||
|
||||
if (link == this->m_links.end())
|
||||
auto link = std::find_if(data.links.begin(), data.links.end(), [&id](auto link) { return link.getId() == id; });
|
||||
|
||||
if (link == data.links.end())
|
||||
return;
|
||||
|
||||
for (auto &node : this->m_nodes) {
|
||||
for (auto &node : data.nodes) {
|
||||
for (auto &attribute : node->getAttributes()) {
|
||||
attribute.removeConnectedAttribute(id);
|
||||
}
|
||||
}
|
||||
|
||||
this->m_links.erase(link);
|
||||
data.links.erase(link);
|
||||
|
||||
ProjectFile::markDirty();
|
||||
ImHexApi::Provider::markDirty();
|
||||
}
|
||||
|
||||
void ViewDataProcessor::eraseNodes(const std::vector<int> &ids) {
|
||||
auto &data = ProviderExtraData::getCurrent().dataProcessor;
|
||||
for (u32 id : ids) {
|
||||
auto node = std::find_if(this->m_nodes.begin(), this->m_nodes.end(), [&id](auto node) { return node->getId() == id; });
|
||||
auto node = std::find_if(data.nodes.begin(), data.nodes.end(),
|
||||
[&id](const auto &node) {
|
||||
return node->getId() == id;
|
||||
});
|
||||
|
||||
for (auto &attr : (*node)->getAttributes()) {
|
||||
std::vector<u32> linksToRemove;
|
||||
@@ -130,52 +140,51 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
for (u32 id : ids) {
|
||||
auto node = std::find_if(this->m_nodes.begin(), this->m_nodes.end(), [&id](auto node) { return node->getId() == id; });
|
||||
auto node = std::find_if(data.nodes.begin(), data.nodes.end(), [&id](const auto &node) { return node->getId() == id; });
|
||||
|
||||
std::erase_if(this->m_endNodes, [&id](auto node) { return node->getId() == id; });
|
||||
std::erase_if(data.endNodes, [&id](const auto &node) { return node->getId() == id; });
|
||||
|
||||
delete *node;
|
||||
|
||||
this->m_nodes.erase(node);
|
||||
data.nodes.erase(node);
|
||||
}
|
||||
|
||||
ProjectFile::markDirty();
|
||||
ImHexApi::Provider::markDirty();
|
||||
}
|
||||
|
||||
void ViewDataProcessor::processNodes() {
|
||||
auto &data = ProviderExtraData::getCurrent().dataProcessor;
|
||||
|
||||
if (this->m_dataOverlays.size() != this->m_endNodes.size()) {
|
||||
for (auto overlay : this->m_dataOverlays)
|
||||
if (data.dataOverlays.size() != data.endNodes.size()) {
|
||||
for (auto overlay : data.dataOverlays)
|
||||
ImHexApi::Provider::get()->deleteOverlay(overlay);
|
||||
this->m_dataOverlays.clear();
|
||||
data.dataOverlays.clear();
|
||||
|
||||
for (u32 i = 0; i < this->m_endNodes.size(); i++)
|
||||
this->m_dataOverlays.push_back(ImHexApi::Provider::get()->newOverlay());
|
||||
for (u32 i = 0; i < data.endNodes.size(); i++)
|
||||
data.dataOverlays.push_back(ImHexApi::Provider::get()->newOverlay());
|
||||
|
||||
u32 overlayIndex = 0;
|
||||
for (auto endNode : this->m_endNodes) {
|
||||
endNode->setCurrentOverlay(this->m_dataOverlays[overlayIndex]);
|
||||
for (auto endNode : data.endNodes) {
|
||||
endNode->setCurrentOverlay(data.dataOverlays[overlayIndex]);
|
||||
overlayIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
this->m_currNodeError.reset();
|
||||
data.currNodeError.reset();
|
||||
|
||||
try {
|
||||
for (auto &endNode : this->m_endNodes) {
|
||||
for (auto &endNode : data.endNodes) {
|
||||
endNode->resetOutputData();
|
||||
|
||||
for (auto &node : this->m_nodes)
|
||||
for (auto &node : data.nodes)
|
||||
node->resetProcessedInputs();
|
||||
|
||||
endNode->process();
|
||||
}
|
||||
} catch (dp::Node::NodeError &e) {
|
||||
this->m_currNodeError = e;
|
||||
data.currNodeError = e;
|
||||
|
||||
for (auto overlay : this->m_dataOverlays)
|
||||
for (auto overlay : data.dataOverlays)
|
||||
ImHexApi::Provider::get()->deleteOverlay(overlay);
|
||||
this->m_dataOverlays.clear();
|
||||
data.dataOverlays.clear();
|
||||
|
||||
} catch (std::runtime_error &e) {
|
||||
printf("Node implementation bug! %s\n", e.what());
|
||||
@@ -183,6 +192,8 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
void ViewDataProcessor::drawContent() {
|
||||
auto &data = ProviderExtraData::getCurrent().dataProcessor;
|
||||
|
||||
if (ImGui::Begin(View::toWindowName("hex.builtin.view.data_processor.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
|
||||
|
||||
if (ImGui::IsMouseReleased(ImGuiMouseButton_Right) && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows)) {
|
||||
@@ -200,7 +211,7 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup("Context Menu")) {
|
||||
dp::Node *node = nullptr;
|
||||
std::unique_ptr<dp::Node> node;
|
||||
|
||||
if (ImNodes::NumSelectedNodes() > 0 || ImNodes::NumSelectedLinks() > 0) {
|
||||
if (ImGui::MenuItem("hex.builtin.view.data_processor.name"_lang)) {
|
||||
@@ -226,13 +237,11 @@ namespace hex::plugin::builtin {
|
||||
} else if (unlocalizedCategory.empty()) {
|
||||
if (ImGui::MenuItem(LangEntry(unlocalizedName))) {
|
||||
node = function();
|
||||
ProjectFile::markDirty();
|
||||
}
|
||||
} else {
|
||||
if (ImGui::BeginMenu(LangEntry(unlocalizedCategory))) {
|
||||
if (ImGui::MenuItem(LangEntry(unlocalizedName))) {
|
||||
node = function();
|
||||
ProjectFile::markDirty();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
@@ -240,8 +249,6 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
if (node != nullptr) {
|
||||
this->m_nodes.push_back(node);
|
||||
|
||||
bool hasOutput = false;
|
||||
bool hasInput = false;
|
||||
for (auto &attr : node->getAttributes()) {
|
||||
@@ -253,9 +260,11 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
if (hasInput && !hasOutput)
|
||||
this->m_endNodes.push_back(node);
|
||||
data.endNodes.push_back(node.get());
|
||||
|
||||
ImNodes::SetNodeScreenSpacePos(node->getId(), this->m_rightClickedCoords);
|
||||
data.nodes.push_back(std::move(node));
|
||||
ImHexApi::Provider::markDirty();
|
||||
}
|
||||
|
||||
ImGui::EndPopup();
|
||||
@@ -277,11 +286,11 @@ namespace hex::plugin::builtin {
|
||||
|
||||
{
|
||||
int nodeId;
|
||||
if (ImNodes::IsNodeHovered(&nodeId) && this->m_currNodeError.has_value() && this->m_currNodeError->first->getId() == static_cast<u32>(nodeId)) {
|
||||
if (ImNodes::IsNodeHovered(&nodeId) && data.currNodeError.has_value() && data.currNodeError->node->getId() == static_cast<u32>(nodeId)) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted("hex.builtin.common.error"_lang);
|
||||
ImGui::Separator();
|
||||
ImGui::TextUnformatted(this->m_currNodeError->second.c_str());
|
||||
ImGui::TextUnformatted(data.currNodeError->message.c_str());
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
@@ -289,8 +298,8 @@ namespace hex::plugin::builtin {
|
||||
if (ImGui::BeginChild("##node_editor", ImGui::GetContentRegionAvail() - ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 1.3))) {
|
||||
ImNodes::BeginNodeEditor();
|
||||
|
||||
for (auto &node : this->m_nodes) {
|
||||
const bool hasError = this->m_currNodeError.has_value() && this->m_currNodeError->first == node;
|
||||
for (auto &node : data.nodes) {
|
||||
const bool hasError = data.currNodeError.has_value() && data.currNodeError->node == node.get();
|
||||
|
||||
if (hasError)
|
||||
ImNodes::PushColorStyle(ImNodesCol_NodeOutline, 0xFF0000FF);
|
||||
@@ -336,12 +345,12 @@ namespace hex::plugin::builtin {
|
||||
ImNodes::PopColorStyle();
|
||||
}
|
||||
|
||||
for (const auto &link : this->m_links)
|
||||
for (const auto &link : data.links)
|
||||
ImNodes::Link(link.getId(), link.getFromId(), link.getToId());
|
||||
|
||||
ImNodes::MiniMap(0.2F, ImNodesMiniMapLocation_BottomRight);
|
||||
|
||||
if (this->m_nodes.empty())
|
||||
if (data.nodes.empty())
|
||||
ImGui::TextFormattedCentered("{}", "hex.builtin.view.data_processor.help_text"_lang);
|
||||
|
||||
ImNodes::EndNodeEditor();
|
||||
@@ -367,7 +376,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
do {
|
||||
dp::Attribute *fromAttr = nullptr, *toAttr = nullptr;
|
||||
for (auto &node : this->m_nodes) {
|
||||
for (auto &node : data.nodes) {
|
||||
for (auto &attribute : node->getAttributes()) {
|
||||
if (attribute.getId() == static_cast<u32>(from))
|
||||
fromAttr = &attribute;
|
||||
@@ -388,7 +397,7 @@ namespace hex::plugin::builtin {
|
||||
if (!toAttr->getConnectedAttributes().empty())
|
||||
break;
|
||||
|
||||
auto newLink = this->m_links.emplace_back(from, to);
|
||||
auto newLink = data.links.emplace_back(from, to);
|
||||
|
||||
fromAttr->addConnectedAttribute(newLink.getId(), toAttr);
|
||||
toAttr->addConnectedAttribute(newLink.getId(), fromAttr);
|
||||
@@ -423,12 +432,14 @@ namespace hex::plugin::builtin {
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
std::string ViewDataProcessor::saveNodes() {
|
||||
std::string ViewDataProcessor::saveNodes(prv::Provider *provider) {
|
||||
auto &data = ProviderExtraData::get(provider).dataProcessor;
|
||||
|
||||
using json = nlohmann::json;
|
||||
json output;
|
||||
|
||||
output["nodes"] = json::object();
|
||||
for (auto &node : this->m_nodes) {
|
||||
for (auto &node : data.nodes) {
|
||||
auto id = node->getId();
|
||||
auto &currNodeOutput = output["nodes"][std::to_string(id)];
|
||||
auto pos = ImNodes::GetNodeGridSpacePos(id);
|
||||
@@ -453,7 +464,7 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
output["links"] = json::object();
|
||||
for (auto &link : this->m_links) {
|
||||
for (auto &link : data.links) {
|
||||
auto id = link.getId();
|
||||
auto &currOutput = output["links"][std::to_string(id)];
|
||||
|
||||
@@ -462,30 +473,29 @@ namespace hex::plugin::builtin {
|
||||
currOutput["to"] = link.getToId();
|
||||
}
|
||||
|
||||
return output.dump();
|
||||
return output.dump(4);
|
||||
}
|
||||
|
||||
void ViewDataProcessor::loadNodes(const std::string &data) {
|
||||
void ViewDataProcessor::loadNodes(prv::Provider *provider, const std::string &jsonData) {
|
||||
if (!ImHexApi::Provider::isValid()) return;
|
||||
|
||||
auto &data = ProviderExtraData::get(provider).dataProcessor;
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
json input = json::parse(data);
|
||||
json input = json::parse(jsonData);
|
||||
|
||||
u32 maxNodeId = 0;
|
||||
u32 maxAttrId = 0;
|
||||
u32 maxLinkId = 0;
|
||||
|
||||
for (auto &node : this->m_nodes)
|
||||
delete node;
|
||||
|
||||
this->m_nodes.clear();
|
||||
this->m_endNodes.clear();
|
||||
this->m_links.clear();
|
||||
data.nodes.clear();
|
||||
data.endNodes.clear();
|
||||
data.links.clear();
|
||||
|
||||
auto &nodeEntries = ContentRegistry::DataProcessorNode::getEntries();
|
||||
for (auto &node : input["nodes"]) {
|
||||
dp::Node *newNode = nullptr;
|
||||
std::unique_ptr<dp::Node> newNode;
|
||||
for (auto &entry : nodeEntries) {
|
||||
if (entry.name == node["type"])
|
||||
newNode = entry.creatorFunction();
|
||||
@@ -520,9 +530,9 @@ namespace hex::plugin::builtin {
|
||||
newNode->load(node["data"]);
|
||||
|
||||
if (hasInput && !hasOutput)
|
||||
this->m_endNodes.push_back(newNode);
|
||||
data.endNodes.push_back(newNode.get());
|
||||
|
||||
this->m_nodes.push_back(newNode);
|
||||
data.nodes.push_back(std::move(newNode));
|
||||
ImNodes::SetNodeGridSpacePos(nodeId, ImVec2(node["pos"]["x"], node["pos"]["y"]));
|
||||
}
|
||||
|
||||
@@ -533,10 +543,10 @@ namespace hex::plugin::builtin {
|
||||
maxLinkId = std::max(linkId, maxLinkId);
|
||||
|
||||
newLink.setID(linkId);
|
||||
this->m_links.push_back(newLink);
|
||||
data.links.push_back(newLink);
|
||||
|
||||
dp::Attribute *fromAttr = nullptr, *toAttr = nullptr;
|
||||
for (auto &node : this->m_nodes) {
|
||||
for (auto &node : data.nodes) {
|
||||
for (auto &attribute : node->getAttributes()) {
|
||||
if (attribute.getId() == newLink.getFromId())
|
||||
fromAttr = &attribute;
|
||||
|
||||
@@ -11,17 +11,6 @@ using namespace std::literals::string_literals;
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
ViewDisassembler::ViewDisassembler() : View("hex.builtin.view.disassembler.name") {
|
||||
EventManager::subscribe<EventRegionSelected>(this, [this](Region region) {
|
||||
if (this->m_shouldMatchSelection) {
|
||||
if (region.address == size_t(-1)) {
|
||||
this->m_codeRegion[0] = this->m_codeRegion[1] = 0;
|
||||
} else {
|
||||
this->m_codeRegion[0] = region.address;
|
||||
this->m_codeRegion[1] = region.address + region.size - 1;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderDeleted>(this, [this](const auto*) {
|
||||
this->m_disassembly.clear();
|
||||
});
|
||||
@@ -49,14 +38,14 @@ namespace hex::plugin::builtin {
|
||||
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
std::vector<u8> buffer(2048, 0x00);
|
||||
size_t size = (this->m_codeRegion[1] - this->m_codeRegion[0] + 1);
|
||||
size_t size = this->m_codeRegion.getSize();
|
||||
|
||||
auto task = ImHexApi::Tasks::createTask("hex.builtin.view.disassembler.disassembling", size);
|
||||
for (u64 address = 0; address < size; address += 2048) {
|
||||
task.update(address);
|
||||
|
||||
size_t bufferSize = std::min(u64(2048), (this->m_codeRegion[1] - this->m_codeRegion[0] + 1) - address);
|
||||
provider->read(this->m_codeRegion[0] + address, buffer.data(), bufferSize);
|
||||
size_t bufferSize = std::min(u64(2048), (size - address));
|
||||
provider->read(this->m_codeRegion.getStartAddress() + address, buffer.data(), bufferSize);
|
||||
|
||||
size_t instructionCount = cs_disasm(capstoneHandle, buffer.data(), bufferSize, this->m_baseAddress + address, 0, &instructions);
|
||||
if (instructionCount == 0)
|
||||
@@ -69,7 +58,7 @@ namespace hex::plugin::builtin {
|
||||
const auto &instr = instructions[i];
|
||||
Disassembly disassembly = { };
|
||||
disassembly.address = instr.address;
|
||||
disassembly.offset = this->m_codeRegion[0] + address + usedBytes;
|
||||
disassembly.offset = this->m_codeRegion.getStartAddress() + address + usedBytes;
|
||||
disassembly.size = instr.size;
|
||||
disassembly.mnemonic = instr.mnemonic;
|
||||
disassembly.operators = instr.op_str;
|
||||
@@ -105,10 +94,24 @@ namespace hex::plugin::builtin {
|
||||
ImGui::TextUnformatted("hex.builtin.view.disassembler.position"_lang);
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::InputScalar("hex.builtin.view.disassembler.base"_lang, ImGuiDataType_U64, &this->m_baseAddress, nullptr, nullptr, "%08llX", ImGuiInputTextFlags_CharsHexadecimal);
|
||||
ImGui::InputScalarN("hex.builtin.view.disassembler.region"_lang, ImGuiDataType_U64, this->m_codeRegion, 2, nullptr, nullptr, "%08llX", ImGuiInputTextFlags_CharsHexadecimal);
|
||||
ImGui::InputHexadecimal("hex.builtin.view.disassembler.base"_lang, &this->m_baseAddress, ImGuiInputTextFlags_CharsHexadecimal);
|
||||
|
||||
ui::regionSelectionPicker(&this->m_range);
|
||||
switch (this->m_range) {
|
||||
case ui::SelectedRegion::Selection: {
|
||||
auto region = ImHexApi::HexEditor::getSelection();
|
||||
if (region.has_value()) {
|
||||
this->m_codeRegion = region.value();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case ui::SelectedRegion::EntireData: {
|
||||
auto base = provider->getBaseAddress();
|
||||
this->m_codeRegion = { base, base + provider->getActualSize() - 1 };
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
ImGui::Checkbox("hex.builtin.common.match_selection"_lang, &this->m_shouldMatchSelection);
|
||||
if (ImGui::IsItemEdited()) {
|
||||
// Force execution of Region Selection Event
|
||||
ImHexApi::HexEditor::setSelection(0, 0);
|
||||
|
||||
@@ -16,26 +16,12 @@ namespace hex::plugin::builtin {
|
||||
ViewFind::ViewFind() : View("hex.builtin.view.find.name") {
|
||||
const static auto HighlightColor = [] { return (ImGui::GetCustomColorU32(ImGuiCustomCol_ToolbarPurple) & 0x00FFFFFF) | 0x70000000; };
|
||||
|
||||
const static auto FindOccurrence = [this](u64 address) -> std::optional<Occurrence> {
|
||||
auto &occurrences = this->m_foundOccurrences[ImHexApi::Provider::get()];
|
||||
|
||||
auto it = std::upper_bound(occurrences.begin(), occurrences.end(), address, [](u64 address, Occurrence &occurrence) {
|
||||
return address < occurrence.region.getStartAddress();
|
||||
});
|
||||
|
||||
if (it != occurrences.begin())
|
||||
it--;
|
||||
|
||||
if (it != occurrences.end() && it->region.getStartAddress() <= address && address <= it->region.getEndAddress())
|
||||
return *it;
|
||||
else
|
||||
return std::nullopt;
|
||||
};
|
||||
|
||||
ImHexApi::HexEditor::addBackgroundHighlightingProvider([](u64 address, const u8* data, size_t size) -> std::optional<color_t> {
|
||||
ImHexApi::HexEditor::addBackgroundHighlightingProvider([this](u64 address, const u8* data, size_t size) -> std::optional<color_t> {
|
||||
hex::unused(data, size);
|
||||
|
||||
if (FindOccurrence(address).has_value())
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
if (!this->m_occurrenceTree[provider].findOverlapping(address, address).empty())
|
||||
return HighlightColor();
|
||||
else
|
||||
return std::nullopt;
|
||||
@@ -44,57 +30,61 @@ namespace hex::plugin::builtin {
|
||||
ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8* data, size_t size) {
|
||||
hex::unused(data, size);
|
||||
|
||||
auto occurrence = FindOccurrence(address);
|
||||
if (!occurrence.has_value())
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
auto occurrences = this->m_occurrenceTree[provider].findOverlapping(address, address);
|
||||
if (occurrences.empty())
|
||||
return;
|
||||
|
||||
ImGui::BeginTooltip();
|
||||
|
||||
ImGui::PushID(&occurrence);
|
||||
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
for (const auto &occurrence : occurrences) {
|
||||
ImGui::PushID(&occurrence);
|
||||
if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
{
|
||||
const auto value = this->decodeValue(ImHexApi::Provider::get(), occurrence.value());
|
||||
{
|
||||
const auto value = this->decodeValue(ImHexApi::Provider::get(), occurrence.value);
|
||||
|
||||
ImGui::ColorButton("##color", ImColor(HighlightColor()));
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::TextFormatted("{}", value);
|
||||
ImGui::ColorButton("##color", ImColor(HighlightColor()));
|
||||
ImGui::SameLine(0, 10);
|
||||
ImGui::TextFormatted("{}", value);
|
||||
|
||||
if (ImGui::GetIO().KeyShift) {
|
||||
ImGui::Indent();
|
||||
if (ImGui::BeginTable("##extra_info", 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
|
||||
if (ImGui::GetIO().KeyShift) {
|
||||
ImGui::Indent();
|
||||
if (ImGui::BeginTable("##extra_info", 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) {
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}: ", "hex.builtin.common.region"_lang.get());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("[ 0x{:08X} - 0x{:08X} ]", occurrence->region.getStartAddress(), occurrence->region.getEndAddress());
|
||||
|
||||
auto demangledValue = llvm::demangle(value);
|
||||
|
||||
if (value != demangledValue) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}: ", "hex.builtin.view.find.demangled"_lang.get());
|
||||
ImGui::TextFormatted("{}: ", "hex.builtin.common.region"_lang.get());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", demangledValue);
|
||||
ImGui::TextFormatted("[ 0x{:08X} - 0x{:08X} ]", occurrence.value.region.getStartAddress(), occurrence.value.region.getEndAddress());
|
||||
|
||||
auto demangledValue = llvm::demangle(value);
|
||||
|
||||
if (value != demangledValue) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}: ", "hex.builtin.view.find.demangled"_lang.get());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", demangledValue);
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
ImGui::Unindent();
|
||||
}
|
||||
ImGui::Unindent();
|
||||
}
|
||||
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_TableRowBg, HighlightColor());
|
||||
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, HighlightColor());
|
||||
ImGui::EndTable();
|
||||
ImGui::PopStyleColor(2);
|
||||
}
|
||||
|
||||
|
||||
ImGui::PushStyleColor(ImGuiCol_TableRowBg, HighlightColor());
|
||||
ImGui::PushStyleColor(ImGuiCol_TableRowBgAlt, HighlightColor());
|
||||
ImGui::EndTable();
|
||||
ImGui::PopStyleColor(2);
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::PopID();
|
||||
|
||||
ImGui::EndTooltip();
|
||||
});
|
||||
@@ -252,7 +242,7 @@ namespace hex::plugin::builtin {
|
||||
break;
|
||||
|
||||
auto address = occurrence.getAddress();
|
||||
reader.seek(address + sequence.size());
|
||||
reader.seek(address + 1);
|
||||
results.push_back(Occurrence{ Region { address, sequence.size() }, Occurrence::DecodeType::Binary });
|
||||
task.update(address - searchRegion.getStartAddress());
|
||||
}
|
||||
@@ -294,21 +284,26 @@ namespace hex::plugin::builtin {
|
||||
reader.setEndAddress(searchRegion.getEndAddress());
|
||||
|
||||
u32 matchedBytes = 0;
|
||||
u64 address = searchRegion.getStartAddress();
|
||||
const size_t patternSize = settings.pattern.size();
|
||||
for (u8 byte : reader) {
|
||||
|
||||
for (auto it = reader.begin(); it != reader.end(); ++it) {
|
||||
auto byte = *it;
|
||||
|
||||
if ((byte & settings.pattern[matchedBytes].mask) == settings.pattern[matchedBytes].value) {
|
||||
matchedBytes++;
|
||||
if (matchedBytes == settings.pattern.size()) {
|
||||
results.push_back(Occurrence { Region { address - (patternSize - 1), patternSize }, Occurrence::DecodeType::Binary });
|
||||
task.update(address);
|
||||
auto occurrenceAddress = it.getAddress() - (patternSize - 1);
|
||||
|
||||
results.push_back(Occurrence { Region { occurrenceAddress, patternSize }, Occurrence::DecodeType::Binary });
|
||||
task.update(occurrenceAddress);
|
||||
it.setAddress(occurrenceAddress);
|
||||
matchedBytes = 0;
|
||||
}
|
||||
} else {
|
||||
if (matchedBytes > 0)
|
||||
it -= matchedBytes;
|
||||
matchedBytes = 0;
|
||||
}
|
||||
|
||||
address++;
|
||||
}
|
||||
|
||||
return results;
|
||||
@@ -316,7 +311,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
void ViewFind::runSearch() {
|
||||
Region searchRegion = [this]{
|
||||
if (this->m_searchSettings.range == 0 || !ImHexApi::HexEditor::isSelectionValid()) {
|
||||
if (this->m_searchSettings.range == ui::SelectedRegion::EntireData || !ImHexApi::HexEditor::isSelectionValid()) {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
return Region { provider->getBaseAddress(), provider->getActualSize() };
|
||||
} else {
|
||||
@@ -345,7 +340,13 @@ namespace hex::plugin::builtin {
|
||||
break;
|
||||
}
|
||||
|
||||
this->m_sortedOccurrences = this->m_foundOccurrences;
|
||||
this->m_sortedOccurrences[provider] = this->m_foundOccurrences[provider];
|
||||
|
||||
OccurrenceTree::interval_vector intervals;
|
||||
for (const auto &occurrence : this->m_foundOccurrences[provider])
|
||||
intervals.push_back(OccurrenceTree::interval(occurrence.region.getStartAddress(), occurrence.region.getEndAddress(), occurrence));
|
||||
this->m_occurrenceTree[provider] = std::move(intervals);
|
||||
|
||||
this->m_searchRunning = false;
|
||||
}).detach();
|
||||
}
|
||||
@@ -409,9 +410,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
ImGui::BeginDisabled(this->m_searchRunning);
|
||||
{
|
||||
ImGui::Header("hex.builtin.view.find.range"_lang, true);
|
||||
ImGui::RadioButton("hex.builtin.view.find.range.entire_data"_lang, &this->m_searchSettings.range, 0);
|
||||
ImGui::RadioButton("hex.builtin.view.find.range.selection"_lang, &this->m_searchSettings.range, 1);
|
||||
ui::regionSelectionPicker(&this->m_searchSettings.range, true, true);
|
||||
|
||||
ImGui::NewLine();
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "content/views/view_hex_editor.hpp"
|
||||
|
||||
#include <hex/api/content_registry.hpp>
|
||||
#include <hex/helpers/project_file_handler.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/providers/buffered_reader.hpp>
|
||||
#include <hex/helpers/crypto.hpp>
|
||||
@@ -20,8 +19,8 @@ namespace hex::plugin::builtin {
|
||||
|
||||
void draw(ViewHexEditor *editor) override {
|
||||
ImGui::TextUnformatted("hex.builtin.view.hex_editor.menu.file.goto"_lang);
|
||||
if (ImGui::BeginTabBar("hex.builtin.view.hex_editor.goto.offset.absolute"_lang)) {
|
||||
if (ImGui::BeginTabItem("Absolute")) {
|
||||
if (ImGui::BeginTabBar("goto_tabs")) {
|
||||
if (ImGui::BeginTabItem("hex.builtin.view.hex_editor.goto.offset.absolute"_lang)) {
|
||||
this->m_mode = Mode::Absolute;
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
@@ -95,6 +94,53 @@ namespace hex::plugin::builtin {
|
||||
MathEvaluator<i128> m_evaluator;
|
||||
};
|
||||
|
||||
class PopupSelect : public ViewHexEditor::Popup {
|
||||
public:
|
||||
|
||||
void draw(ViewHexEditor *editor) override {
|
||||
ImGui::TextUnformatted("hex.builtin.view.hex_editor.menu.file.select"_lang);
|
||||
if (ImGui::BeginTabBar("select_tabs")) {
|
||||
|
||||
if (ImGui::BeginTabItem("hex.builtin.view.hex_editor.select.offset.region"_lang)) {
|
||||
u64 inputA = this->m_region.getStartAddress();
|
||||
u64 inputB = this->m_region.getEndAddress();
|
||||
ImGui::InputHexadecimal("hex.builtin.view.hex_editor.select.offset.begin"_lang, &inputA, ImGuiInputTextFlags_AutoSelectAll);
|
||||
ImGui::InputHexadecimal("hex.builtin.view.hex_editor.select.offset.end"_lang, &inputB, ImGuiInputTextFlags_AutoSelectAll);
|
||||
|
||||
if (inputB < inputA)
|
||||
inputB = inputA;
|
||||
|
||||
this->m_region = { inputA, (inputB - inputA) + 1 };
|
||||
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::BeginTabItem("hex.builtin.view.hex_editor.select.offset.size"_lang)) {
|
||||
u64 inputA = this->m_region.getStartAddress();
|
||||
u64 inputB = this->m_region.getSize();
|
||||
ImGui::InputHexadecimal("hex.builtin.view.hex_editor.select.offset.begin"_lang, &inputA, ImGuiInputTextFlags_AutoSelectAll);
|
||||
ImGui::InputHexadecimal("hex.builtin.view.hex_editor.select.offset.size"_lang, &inputB, ImGuiInputTextFlags_AutoSelectAll);
|
||||
|
||||
if (inputB <= 0)
|
||||
inputB = 1;
|
||||
|
||||
this->m_region = { inputA, inputB };
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
|
||||
if (ImGui::Button("hex.builtin.view.hex_editor.select.select"_lang) || (ImGui::IsItemFocused() && (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Enter)))) {
|
||||
editor->setSelection(this->m_region.getStartAddress(), this->m_region.getEndAddress());
|
||||
editor->jumpToSelection();
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Region m_region = { 0, 1 };
|
||||
};
|
||||
|
||||
class PopupFind : public ViewHexEditor::Popup {
|
||||
public:
|
||||
void draw(ViewHexEditor *editor) override {
|
||||
@@ -252,7 +298,7 @@ namespace hex::plugin::builtin {
|
||||
ImGui::TextUnformatted("hex.builtin.view.hex_editor.menu.edit.set_base"_lang);
|
||||
|
||||
ImGui::InputHexadecimal("##base_address", &this->m_baseAddress);
|
||||
if (ImGui::IsItemFocused() && ImGui::IsKeyPressed(ImGuiKey_Enter)) {
|
||||
if (ImGui::IsItemFocused() && (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Enter))) {
|
||||
setBaseAddress(this->m_baseAddress);
|
||||
editor->closePopup();
|
||||
}
|
||||
@@ -285,7 +331,7 @@ namespace hex::plugin::builtin {
|
||||
ImGui::TextUnformatted("hex.builtin.view.hex_editor.menu.edit.resize"_lang);
|
||||
|
||||
ImGui::InputHexadecimal("##resize", &this->m_size);
|
||||
if (ImGui::IsItemFocused() && ImGui::IsKeyPressed(ImGuiKey_Enter)) {
|
||||
if (ImGui::IsItemFocused() && (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_Enter))) {
|
||||
resize(static_cast<size_t>(this->m_size));
|
||||
editor->closePopup();
|
||||
}
|
||||
@@ -533,11 +579,6 @@ namespace hex::plugin::builtin {
|
||||
ImGui::SetKeyboardFocusHere();
|
||||
ImGui::SetNextFrameWantCaptureKeyboard(true);
|
||||
|
||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) {
|
||||
this->m_editingAddress = std::nullopt;
|
||||
this->m_shouldModifyValue = false;
|
||||
}
|
||||
|
||||
if (this->m_currDataVisualizer->drawEditing(*this->m_editingAddress, this->m_editingBytes.data(), this->m_editingBytes.size(), this->m_upperCaseHex, this->m_enteredEditingMode) || this->m_shouldModifyValue) {
|
||||
|
||||
provider->write(*this->m_editingAddress, this->m_editingBytes.data(), this->m_editingBytes.size());
|
||||
@@ -558,6 +599,11 @@ namespace hex::plugin::builtin {
|
||||
this->m_shouldUpdateEditingValue = true;
|
||||
}
|
||||
|
||||
if (ImGui::IsMouseClicked(ImGuiMouseButton_Left) && !hovered) {
|
||||
this->m_editingAddress = std::nullopt;
|
||||
this->m_shouldModifyValue = false;
|
||||
}
|
||||
|
||||
this->m_enteredEditingMode = false;
|
||||
}
|
||||
}
|
||||
@@ -682,6 +728,16 @@ namespace hex::plugin::builtin {
|
||||
if (ImHexApi::Provider::isValid()) {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
std::pair<Region, bool> validRegion = { Region::Invalid(), false };
|
||||
const auto isCurrRegionValid = [&validRegion, &provider](u64 address){
|
||||
auto &[currRegion, currRegionValid] = validRegion;
|
||||
if (!Region{ address, 1 }.isWithin(currRegion)) {
|
||||
validRegion = provider->getRegionValidity(address);
|
||||
}
|
||||
|
||||
return currRegionValid;
|
||||
};
|
||||
|
||||
ImGuiListClipper clipper;
|
||||
|
||||
clipper.Begin(std::ceil(provider->getSize() / (long double)(this->m_bytesPerRow)), CharacterSize.y);
|
||||
@@ -689,7 +745,7 @@ namespace hex::plugin::builtin {
|
||||
this->m_visibleRowCount = clipper.DisplayEnd - clipper.DisplayStart;
|
||||
|
||||
// Loop over rows
|
||||
for (i128 y = clipper.DisplayStart; y < u64(clipper.DisplayEnd); y++) {
|
||||
for (u64 y = u64(clipper.DisplayStart); y < u64(clipper.DisplayEnd); y++) {
|
||||
|
||||
// Draw address column
|
||||
ImGui::TableNextRow();
|
||||
@@ -699,7 +755,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
const u8 validBytes = std::min<u64>(this->m_bytesPerRow, provider->getSize() - y * this->m_bytesPerRow);
|
||||
|
||||
std::vector<u8> bytes(validBytes);
|
||||
std::vector<u8> bytes(this->m_bytesPerRow, 0x00);
|
||||
provider->read(y * this->m_bytesPerRow + provider->getBaseAddress() + provider->getCurrentPageAddress(), bytes.data(), validBytes);
|
||||
|
||||
std::vector<std::tuple<std::optional<color_t>, std::optional<color_t>>> cellColors;
|
||||
@@ -710,7 +766,7 @@ namespace hex::plugin::builtin {
|
||||
const auto cellBytes = std::min<u64>(validBytes, bytesPerCell);
|
||||
|
||||
// Query cell colors
|
||||
if (x < validBytes / bytesPerCell) {
|
||||
if (x < std::ceil(float(validBytes) / bytesPerCell)) {
|
||||
const auto foregroundColor = queryForegroundColor(byteAddress, &bytes[x * cellBytes], cellBytes);
|
||||
const auto backgroundColor = [&]{
|
||||
auto color = queryBackgroundColor(byteAddress, &bytes[x * cellBytes], cellBytes);
|
||||
@@ -732,6 +788,11 @@ namespace hex::plugin::builtin {
|
||||
foregroundColor,
|
||||
backgroundColor
|
||||
);
|
||||
} else {
|
||||
cellColors.emplace_back(
|
||||
std::nullopt,
|
||||
std::nullopt
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -746,16 +807,17 @@ namespace hex::plugin::builtin {
|
||||
if (isColumnSeparatorColumn(x, columnCount))
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (x < validBytes / bytesPerCell) {
|
||||
if (x < std::ceil(float(validBytes) / bytesPerCell)) {
|
||||
auto cellStartPos = getCellPosition();
|
||||
auto cellSize = (CharacterSize * ImVec2(this->m_currDataVisualizer->getMaxCharsPerCell(), 1) + (ImVec2(3, 2) * ImGui::GetStyle().CellPadding) - ImVec2(1, 0) * ImGui::GetStyle().CellPadding) + ImVec2(1, 0);
|
||||
auto maxCharsPerCell = this->m_currDataVisualizer->getMaxCharsPerCell();
|
||||
|
||||
auto [foregroundColor, backgroundColor] = cellColors[x];
|
||||
|
||||
if (isColumnSeparatorColumn(x + 1, columnCount) && selectionMax != x + y * columnCount) {
|
||||
cellSize.x += SeparatorColumWidth + 1;
|
||||
}
|
||||
if (y == clipper.DisplayStart)
|
||||
if (y == u64(clipper.DisplayStart))
|
||||
cellSize.y -= (ImGui::GetStyle().CellPadding.y + 1);
|
||||
|
||||
// Draw highlights and selection
|
||||
@@ -779,8 +841,11 @@ namespace hex::plugin::builtin {
|
||||
|
||||
// Draw cell content
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
|
||||
ImGui::PushItemWidth((CharacterSize * this->m_currDataVisualizer->getMaxCharsPerCell()).x);
|
||||
this->drawCell(byteAddress, &bytes[x * bytesPerCell], bytesPerCell, cellHovered);
|
||||
ImGui::PushItemWidth((CharacterSize * maxCharsPerCell).x);
|
||||
if (isCurrRegionValid(byteAddress))
|
||||
this->drawCell(byteAddress, &bytes[x * bytesPerCell], bytesPerCell, cellHovered);
|
||||
else
|
||||
ImGui::TextFormatted("{}", std::string(maxCharsPerCell, '?'));
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
@@ -824,7 +889,9 @@ namespace hex::plugin::builtin {
|
||||
this->drawSelectionFrame(x, y, byteAddress, 1, cellStartPos, cellSize);
|
||||
}
|
||||
|
||||
if (std::isprint(bytes[x]))
|
||||
if (!isCurrRegionValid(byteAddress))
|
||||
ImGui::TextFormatted("?");
|
||||
else if (std::isprint(bytes[x]))
|
||||
ImGui::TextFormatted("{:c}", bytes[x]);
|
||||
else
|
||||
ImGui::TextDisabled(".");
|
||||
@@ -866,7 +933,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
|
||||
const auto x = address % this->m_bytesPerRow;
|
||||
if (x < validBytes / bytesPerCell) {
|
||||
if (x < validBytes && isCurrRegionValid(address)) {
|
||||
auto [foregroundColor, backgroundColor] = cellColors[x / bytesPerCell];
|
||||
|
||||
// Draw highlights and selection
|
||||
@@ -900,13 +967,13 @@ namespace hex::plugin::builtin {
|
||||
if ((ImGui::IsMouseDown(ImGuiMouseButton_Left) && this->m_selectionStart != this->m_selectionEnd)) {
|
||||
auto fractionPerLine = 1.0 / (this->m_visibleRowCount + 1);
|
||||
|
||||
if (y == clipper.DisplayStart + 2) {
|
||||
if (y == u64(clipper.DisplayStart + 2)) {
|
||||
if (i128(this->m_selectionEnd - provider->getBaseAddress() - provider->getCurrentPageAddress()) <= (i64(clipper.DisplayStart + 2) * this->m_bytesPerRow)) {
|
||||
this->m_shouldScrollToSelection = false;
|
||||
ImGui::SetScrollHereY(fractionPerLine * 4);
|
||||
|
||||
}
|
||||
} else if (y == (clipper.DisplayEnd - 2)) {
|
||||
} else if (y == u64(clipper.DisplayEnd - 2)) {
|
||||
if (i128(this->m_selectionEnd - provider->getBaseAddress() - provider->getCurrentPageAddress()) >= (i64(clipper.DisplayEnd - 2) * this->m_bytesPerRow)) {
|
||||
this->m_shouldScrollToSelection = false;
|
||||
ImGui::SetScrollHereY(fractionPerLine * (this->m_visibleRowCount - 1));
|
||||
@@ -994,8 +1061,14 @@ namespace hex::plugin::builtin {
|
||||
{
|
||||
auto selection = this->getSelection();
|
||||
std::string value;
|
||||
if (this->isSelectionValid())
|
||||
value = hex::format("0x{0:08X} - 0x{1:08X} ({2})", selection.getStartAddress(), selection.getEndAddress(), hex::toByteString(selection.getSize()));
|
||||
if (this->isSelectionValid()) {
|
||||
value = hex::format("0x{0:08X} - 0x{1:08X} (0x{2:X} | {3})",
|
||||
selection.getStartAddress(),
|
||||
selection.getEndAddress(),
|
||||
selection.getSize(),
|
||||
hex::toByteString(selection.getSize())
|
||||
);
|
||||
}
|
||||
else
|
||||
value = std::string("hex.builtin.view.hex_editor.selection.none"_lang);
|
||||
|
||||
@@ -1005,7 +1078,11 @@ namespace hex::plugin::builtin {
|
||||
// Loaded data size
|
||||
ImGui::TableNextColumn();
|
||||
{
|
||||
ImGui::TextFormatted("{0}: 0x{1:08X} ({2})", "hex.builtin.view.hex_editor.data_size"_lang, provider->getActualSize(), hex::toByteString(provider->getActualSize()));
|
||||
ImGui::TextFormatted("{0}: 0x{1:08X} (0x{2:X} | {3})", "hex.builtin.view.hex_editor.data_size"_lang,
|
||||
provider->getActualSize(),
|
||||
provider->getActualSize(),
|
||||
hex::toByteString(provider->getActualSize())
|
||||
);
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
@@ -1127,6 +1204,12 @@ namespace hex::plugin::builtin {
|
||||
this->setSelection(size_t(0), ImHexApi::Provider::get()->getActualSize());
|
||||
});
|
||||
|
||||
// Select range
|
||||
ShortcutManager::addShortcut(this, CTRL + SHIFT + Keys::A, [this] {
|
||||
if (ImHexApi::Provider::isValid())
|
||||
this->openPopup<PopupSelect>();
|
||||
});
|
||||
|
||||
// Remove selection
|
||||
ShortcutManager::addShortcut(this, Keys::Escape, [this] {
|
||||
this->m_selectionStart = InvalidSelection;
|
||||
@@ -1383,6 +1466,10 @@ namespace hex::plugin::builtin {
|
||||
if (ImGui::MenuItem("hex.builtin.view.hex_editor.menu.file.goto"_lang, "CTRL + G", false, providerValid)) {
|
||||
this->openPopup<PopupGoto>();
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.view.hex_editor.menu.file.select"_lang, "CTRL + SHIFT + A", false, providerValid)) {
|
||||
this->openPopup<PopupSelect>();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
#include <hex/helpers/project_file_handler.hpp>
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -11,22 +12,26 @@ using namespace std::literals::string_literals;
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
ViewPatches::ViewPatches() : View("hex.builtin.view.patches.name") {
|
||||
EventManager::subscribe<EventProjectFileStore>(this, [] {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
if (ImHexApi::Provider::isValid())
|
||||
ProjectFile::setPatches(provider->getPatches());
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProjectFileLoad>(this, [] {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
if (ImHexApi::Provider::isValid())
|
||||
provider->getPatches() = ProjectFile::getPatches();
|
||||
ProjectFile::registerPerProviderHandler({
|
||||
.basePath = "patches.json",
|
||||
.load = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) {
|
||||
auto json = nlohmann::json::parse(tar.read(basePath));
|
||||
provider->getPatches() = json["patches"].get<std::map<u64, u8>>();
|
||||
return true;
|
||||
},
|
||||
.store = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) {
|
||||
nlohmann::json json;
|
||||
json["patches"] = provider->getPatches();
|
||||
tar.write(basePath, json.dump(4));
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ViewPatches::~ViewPatches() {
|
||||
EventManager::unsubscribe<EventProjectFileStore>(this);
|
||||
EventManager::unsubscribe<EventProjectFileLoad>(this);
|
||||
|
||||
}
|
||||
|
||||
void ViewPatches::drawContent() {
|
||||
@@ -86,7 +91,6 @@ namespace hex::plugin::builtin {
|
||||
if (ImGui::BeginPopup("PatchContextMenu")) {
|
||||
if (ImGui::MenuItem("hex.builtin.view.patches.remove"_lang)) {
|
||||
patches.erase(this->m_selectedPatch);
|
||||
ProjectFile::markDirty();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,8 @@
|
||||
#include <pl/pattern_language.hpp>
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
|
||||
#include <provider_extra_data.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
ViewPatternData::ViewPatternData() : View("hex.builtin.view.pattern_data.name") {
|
||||
@@ -20,7 +22,7 @@ namespace hex::plugin::builtin {
|
||||
EventManager::unsubscribe<EventHighlightingChanged>(this);
|
||||
}
|
||||
|
||||
static bool sortPatterns(prv::Provider *provider, const ImGuiTableSortSpecs* sortSpecs, const pl::Pattern * left, const pl::Pattern * right) {
|
||||
static bool sortPatterns(prv::Provider *provider, const ImGuiTableSortSpecs* sortSpecs, const pl::ptrn::Pattern * left, const pl::ptrn::Pattern * right) {
|
||||
if (sortSpecs->Specs->ColumnUserID == ImGui::GetID("name")) {
|
||||
if (sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending)
|
||||
return left->getDisplayName() > right->getDisplayName();
|
||||
@@ -67,7 +69,7 @@ namespace hex::plugin::builtin {
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool beginPatternTable(prv::Provider *&provider, const std::vector<std::shared_ptr<pl::Pattern>> &patterns, std::vector<pl::Pattern*> &sortedPatterns) {
|
||||
static bool beginPatternTable(prv::Provider *&provider, const std::vector<std::shared_ptr<pl::ptrn::Pattern>> &patterns, std::vector<pl::ptrn::Pattern*> &sortedPatterns) {
|
||||
if (ImGui::BeginTable("##Patterntable", 6, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY)) {
|
||||
ImGui::TableSetupScrollFreeze(0, 1);
|
||||
ImGui::TableSetupColumn("hex.builtin.view.pattern_data.var_name"_lang, 0, 0, ImGui::GetID("name"));
|
||||
@@ -81,16 +83,16 @@ namespace hex::plugin::builtin {
|
||||
|
||||
if (sortSpecs->SpecsDirty || sortedPatterns.empty()) {
|
||||
sortedPatterns.clear();
|
||||
std::transform(patterns.begin(), patterns.end(), std::back_inserter(sortedPatterns), [](const std::shared_ptr<pl::Pattern> &pattern) {
|
||||
std::transform(patterns.begin(), patterns.end(), std::back_inserter(sortedPatterns), [](const std::shared_ptr<pl::ptrn::Pattern> &pattern) {
|
||||
return pattern.get();
|
||||
});
|
||||
|
||||
std::sort(sortedPatterns.begin(), sortedPatterns.end(), [&sortSpecs, &provider](pl::Pattern *left, pl::Pattern *right) -> bool {
|
||||
std::sort(sortedPatterns.begin(), sortedPatterns.end(), [&sortSpecs, &provider](pl::ptrn::Pattern *left, pl::ptrn::Pattern *right) -> bool {
|
||||
return sortPatterns(provider, sortSpecs, left, right);
|
||||
});
|
||||
|
||||
for (auto &pattern : sortedPatterns)
|
||||
pattern->sort([&sortSpecs, &provider](const pl::Pattern *left, const pl::Pattern *right){
|
||||
pattern->sort([&sortSpecs, &provider](const pl::ptrn::Pattern *left, const pl::ptrn::Pattern *right){
|
||||
return sortPatterns(provider, sortSpecs, left, right);
|
||||
});
|
||||
|
||||
@@ -109,7 +111,7 @@ namespace hex::plugin::builtin {
|
||||
if (ImHexApi::Provider::isValid() && provider->isReadable()) {
|
||||
|
||||
auto &sortedPatterns = this->m_sortedPatterns[ImHexApi::Provider::get()];
|
||||
if (beginPatternTable(provider, provider->getPatternLanguageRuntime().getPatterns(), sortedPatterns)) {
|
||||
if (beginPatternTable(provider, ProviderExtraData::get(provider).patternLanguage.runtime->getPatterns(), sortedPatterns)) {
|
||||
ImGui::TableHeadersRow();
|
||||
if (!sortedPatterns.empty()) {
|
||||
|
||||
|
||||
@@ -2,18 +2,20 @@
|
||||
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <pl/preprocessor.hpp>
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
#include <pl/ast/ast_node_variable_decl.hpp>
|
||||
#include <pl/ast/ast_node_type_decl.hpp>
|
||||
#include <pl/ast/ast_node_builtin_type.hpp>
|
||||
#include <pl/core/preprocessor.hpp>
|
||||
#include <pl/core/ast/ast_node_variable_decl.hpp>
|
||||
#include <pl/core/ast/ast_node_type_decl.hpp>
|
||||
#include <pl/core/ast/ast_node_builtin_type.hpp>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/project_file_handler.hpp>
|
||||
#include <hex/api/project_file_manager.hpp>
|
||||
#include <hex/helpers/magic.hpp>
|
||||
|
||||
#include <provider_extra_data.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
@@ -86,15 +88,6 @@ namespace hex::plugin::builtin {
|
||||
this->m_envVarEntries.push_back({ 0, "", 0, EnvVarType::Integer });
|
||||
this->m_envVarIdCounter = 1;
|
||||
|
||||
EventManager::subscribe<EventProjectFileStore>(this, [this]() {
|
||||
ProjectFile::setPattern(this->m_textEditor.GetText());
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProjectFileLoad>(this, [this]() {
|
||||
this->m_textEditor.SetText(ProjectFile::getPattern());
|
||||
this->evaluatePattern(this->m_textEditor.GetText());
|
||||
});
|
||||
|
||||
EventManager::subscribe<RequestSetPatternLanguageCode>(this, [this](const std::string &code) {
|
||||
this->m_textEditor.SetText(code);
|
||||
});
|
||||
@@ -115,21 +108,24 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderCreated>(this, [this](prv::Provider *provider) {
|
||||
EventManager::subscribe<EventProviderOpened>(this, [this](prv::Provider *provider) {
|
||||
auto &patternLanguageData = ProviderExtraData::get(provider).patternLanguage;
|
||||
patternLanguageData.runtime = ContentRegistry::PatternLanguage::createDefaultRuntime(provider);
|
||||
|
||||
if (!this->m_autoLoadPatterns)
|
||||
return;
|
||||
|
||||
// Copy over current pattern source code to the new provider
|
||||
if (!this->m_syncPatternSourceCode) {
|
||||
provider->getPatternLanguageSourceCode() = this->m_textEditor.GetText();
|
||||
patternLanguageData.sourceCode = this->m_textEditor.GetText();
|
||||
}
|
||||
|
||||
auto &runtime = provider->getPatternLanguageRuntime();
|
||||
auto &runtime = patternLanguageData.runtime;
|
||||
|
||||
auto mimeType = magic::getMIMEType(ImHexApi::Provider::get());
|
||||
auto mimeType = magic::getMIMEType(provider);
|
||||
|
||||
bool foundCorrectType = false;
|
||||
runtime.addPragma("MIME", [&mimeType, &foundCorrectType](pl::PatternLanguage &runtime, const std::string &value) {
|
||||
runtime->addPragma("MIME", [&mimeType, &foundCorrectType](pl::PatternLanguage &runtime, const std::string &value) {
|
||||
hex::unused(runtime);
|
||||
|
||||
if (value == mimeType) {
|
||||
@@ -152,14 +148,16 @@ namespace hex::plugin::builtin {
|
||||
if (!file.isValid())
|
||||
continue;
|
||||
|
||||
runtime.getInternals().preprocessor->preprocess(runtime, file.readString());
|
||||
runtime->getInternals().preprocessor->preprocess(*runtime, file.readString());
|
||||
|
||||
if (foundCorrectType)
|
||||
this->m_possiblePatternFiles.push_back(entry.path());
|
||||
|
||||
runtime->reset();
|
||||
}
|
||||
}
|
||||
|
||||
runtime.addPragma("MIME", [](pl::PatternLanguage&, const std::string &value) { return !value.empty(); });
|
||||
runtime->addPragma("MIME", [](pl::PatternLanguage&, const std::string &value) { return !value.empty(); });
|
||||
|
||||
if (!this->m_possiblePatternFiles.empty()) {
|
||||
this->m_selectedPatternFile = 0;
|
||||
@@ -168,14 +166,14 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderDeleted>(this, [](auto *provider) {
|
||||
provider->getPatternLanguageRuntime().abort();
|
||||
});
|
||||
|
||||
EventManager::subscribe<EventProviderChanged>(this, [this](prv::Provider *oldProvider, prv::Provider *newProvider) {
|
||||
if (!this->m_syncPatternSourceCode) {
|
||||
if (oldProvider != nullptr) oldProvider->getPatternLanguageSourceCode() = this->m_textEditor.GetText();
|
||||
if (newProvider != nullptr) this->m_textEditor.SetText(newProvider->getPatternLanguageSourceCode());
|
||||
if (oldProvider != nullptr) ProviderExtraData::get(oldProvider).patternLanguage.sourceCode = this->m_textEditor.GetText();
|
||||
|
||||
if (newProvider != nullptr)
|
||||
this->m_textEditor.SetText(ProviderExtraData::get(newProvider).patternLanguage.sourceCode);
|
||||
else
|
||||
this->m_textEditor.SetText("");
|
||||
|
||||
auto lines = this->m_textEditor.GetTextLines();
|
||||
lines.pop_back();
|
||||
@@ -255,7 +253,7 @@ namespace hex::plugin::builtin {
|
||||
return std::nullopt;
|
||||
|
||||
std::optional<ImColor> color;
|
||||
for (const auto &pattern : ImHexApi::Provider::get()->getPatternLanguageRuntime().getPatterns(address)) {
|
||||
for (const auto &pattern : ProviderExtraData::getCurrent().patternLanguage.runtime->getPatterns(address)) {
|
||||
if (pattern->isHidden())
|
||||
continue;
|
||||
|
||||
@@ -271,7 +269,7 @@ namespace hex::plugin::builtin {
|
||||
ImHexApi::HexEditor::addTooltipProvider([this](u64 address, const u8 *data, size_t size) {
|
||||
hex::unused(data, size);
|
||||
|
||||
auto patterns = ImHexApi::Provider::get()->getPatternLanguageRuntime().getPatterns(address);
|
||||
auto patterns = ProviderExtraData::getCurrent().patternLanguage.runtime->getPatterns(address);
|
||||
if (!patterns.empty() && !std::all_of(patterns.begin(), patterns.end(), [](const auto &pattern) { return pattern->isHidden(); })) {
|
||||
ImGui::BeginTooltip();
|
||||
for (const auto &pattern : patterns) {
|
||||
@@ -296,11 +294,37 @@ namespace hex::plugin::builtin {
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
});
|
||||
|
||||
ProjectFile::registerPerProviderHandler({
|
||||
.basePath = "pattern_source_code.hexpat",
|
||||
.load = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) {
|
||||
std::string sourceCode = tar.readString(basePath);
|
||||
|
||||
if (!this->m_syncPatternSourceCode)
|
||||
ProviderExtraData::get(provider).patternLanguage.sourceCode = sourceCode;
|
||||
|
||||
this->m_textEditor.SetText(sourceCode);
|
||||
|
||||
return true;
|
||||
},
|
||||
.store = [this](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) {
|
||||
std::string sourceCode;
|
||||
|
||||
if (provider == ImHexApi::Provider::get())
|
||||
ProviderExtraData::get(provider).patternLanguage.sourceCode = this->m_textEditor.GetText();
|
||||
|
||||
if (this->m_syncPatternSourceCode)
|
||||
sourceCode = this->m_textEditor.GetText();
|
||||
else
|
||||
sourceCode = ProviderExtraData::get(provider).patternLanguage.sourceCode;
|
||||
|
||||
tar.write(basePath, sourceCode);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ViewPatternEditor::~ViewPatternEditor() {
|
||||
EventManager::unsubscribe<EventProjectFileStore>(this);
|
||||
EventManager::unsubscribe<EventProjectFileLoad>(this);
|
||||
EventManager::unsubscribe<RequestSetPatternLanguageCode>(this);
|
||||
EventManager::unsubscribe<EventFileLoaded>(this);
|
||||
EventManager::unsubscribe<EventProviderDeleted>(this);
|
||||
@@ -340,10 +364,10 @@ namespace hex::plugin::builtin {
|
||||
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1);
|
||||
|
||||
auto &runtime = provider->getPatternLanguageRuntime();
|
||||
if (runtime.isRunning()) {
|
||||
auto &runtime = ProviderExtraData::getCurrent().patternLanguage.runtime;
|
||||
if (runtime->isRunning()) {
|
||||
if (ImGui::IconButton(ICON_VS_DEBUG_STOP, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed)))
|
||||
runtime.abort();
|
||||
runtime->abort();
|
||||
} else {
|
||||
if (ImGui::IconButton(ICON_VS_DEBUG_START, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen))) {
|
||||
this->evaluatePattern(this->m_textEditor.GetText());
|
||||
@@ -367,13 +391,13 @@ namespace hex::plugin::builtin {
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::TextFormatted("{} / {}",
|
||||
provider->getPatternLanguageRuntime().getCreatedPatternCount(),
|
||||
provider->getPatternLanguageRuntime().getMaximumPatternCount());
|
||||
runtime->getCreatedPatternCount(),
|
||||
runtime->getMaximumPatternCount());
|
||||
}
|
||||
|
||||
if (this->m_textEditor.IsTextChanged()) {
|
||||
ProjectFile::markDirty();
|
||||
this->m_hasUnevaluatedChanges = true;
|
||||
ImHexApi::Provider::markDirty();
|
||||
}
|
||||
|
||||
if (this->m_hasUnevaluatedChanges && this->m_runningEvaluators == 0 && this->m_runningParsers == 0) {
|
||||
@@ -418,7 +442,7 @@ namespace hex::plugin::builtin {
|
||||
if (!this->m_lastEvaluationResult) {
|
||||
if (this->m_lastEvaluationError) {
|
||||
TextEditor::ErrorMarkers errorMarkers = {
|
||||
{this->m_lastEvaluationError->getLineNumber(), this->m_lastEvaluationError->what()}
|
||||
{ this->m_lastEvaluationError->line, this->m_lastEvaluationError->message }
|
||||
};
|
||||
this->m_textEditor.SetErrorMarkers(errorMarkers);
|
||||
}
|
||||
@@ -447,16 +471,18 @@ namespace hex::plugin::builtin {
|
||||
const auto &[level, message] = this->m_console[i];
|
||||
|
||||
switch (level) {
|
||||
case pl::LogConsole::Level::Debug:
|
||||
using enum pl::core::LogConsole::Level;
|
||||
|
||||
case Debug:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::Comment)]);
|
||||
break;
|
||||
case pl::LogConsole::Level::Info:
|
||||
case Info:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::Default)]);
|
||||
break;
|
||||
case pl::LogConsole::Level::Warning:
|
||||
case Warning:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::Preprocessor)]);
|
||||
break;
|
||||
case pl::LogConsole::Level::Error:
|
||||
case Error:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::ErrorMarker)]);
|
||||
break;
|
||||
default:
|
||||
@@ -591,27 +617,27 @@ namespace hex::plugin::builtin {
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (variable.outVariable) {
|
||||
ImGui::TextUnformatted(pl::Token::literalToString(variable.value, true).c_str());
|
||||
ImGui::TextUnformatted(pl::core::Token::literalToString(variable.value, true).c_str());
|
||||
} else if (variable.inVariable) {
|
||||
const std::string label { "##" + name };
|
||||
|
||||
if (pl::Token::isSigned(variable.type)) {
|
||||
if (pl::core::Token::isSigned(variable.type)) {
|
||||
i64 value = hex::get_or<i128>(variable.value, 0);
|
||||
ImGui::InputScalar(label.c_str(), ImGuiDataType_S64, &value);
|
||||
variable.value = i128(value);
|
||||
} else if (pl::Token::isUnsigned(variable.type)) {
|
||||
} else if (pl::core::Token::isUnsigned(variable.type)) {
|
||||
u64 value = hex::get_or<u128>(variable.value, 0);
|
||||
ImGui::InputScalar(label.c_str(), ImGuiDataType_U64, &value);
|
||||
variable.value = u128(value);
|
||||
} else if (pl::Token::isFloatingPoint(variable.type)) {
|
||||
} else if (pl::core::Token::isFloatingPoint(variable.type)) {
|
||||
double value = hex::get_or<double>(variable.value, 0.0);
|
||||
ImGui::InputScalar(label.c_str(), ImGuiDataType_Double, &value);
|
||||
variable.value = value;
|
||||
} else if (variable.type == pl::Token::ValueType::Boolean) {
|
||||
} else if (variable.type == pl::core::Token::ValueType::Boolean) {
|
||||
bool value = hex::get_or<bool>(variable.value, false);
|
||||
ImGui::Checkbox(label.c_str(), &value);
|
||||
variable.value = value;
|
||||
} else if (variable.type == pl::Token::ValueType::Character) {
|
||||
} else if (variable.type == pl::core::Token::ValueType::Character) {
|
||||
char buffer[2];
|
||||
ImGui::InputText(label.c_str(), buffer, 2);
|
||||
variable.value = buffer[0];
|
||||
@@ -667,7 +693,7 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
|
||||
void ViewPatternEditor::drawPatternTooltip(pl::Pattern *pattern) {
|
||||
void ViewPatternEditor::drawPatternTooltip(pl::ptrn::Pattern *pattern) {
|
||||
ImGui::PushID(pattern);
|
||||
{
|
||||
ImGui::ColorButton(pattern->getVariableName().c_str(), ImColor(pattern->getColor()));
|
||||
@@ -689,32 +715,32 @@ namespace hex::plugin::builtin {
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("Type: ");
|
||||
ImGui::TextFormatted("{}: ", "hex.builtin.common.type"_lang);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", pattern->getTypeName());
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("Address: ");
|
||||
ImGui::TextFormatted("{}: ", "hex.builtin.common.address"_lang);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{:08X}", pattern->getOffset());
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("Size: ");
|
||||
ImGui::TextFormatted("{}: ", "hex.builtin.common.size"_lang);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{} {}", pattern->getSize(), pattern->getSize() > 1 ? "Bytes" : "Byte");
|
||||
ImGui::TextFormatted("{}", hex::toByteString(pattern->getSize()));
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("Endian: ");
|
||||
ImGui::TextFormatted("{}: ", "hex.builtin.common.endian"_lang);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", pattern->getEndian() == std::endian::little ? "Little" : "Big");
|
||||
ImGui::TextFormatted("{}", pattern->getEndian() == std::endian::little ? "hex.builtin.common.little"_lang : "hex.builtin.common.big"_lang);
|
||||
|
||||
if (const auto &comment = pattern->getComment(); comment.has_value()) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("Comment: ");
|
||||
ImGui::TextFormatted("{}: ", "hex.builtin.common.comment"_lang);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextWrapped("\"%s\"", pattern->getComment()->c_str());
|
||||
}
|
||||
@@ -741,6 +767,8 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
void ViewPatternEditor::parsePattern(const std::string &code) {
|
||||
auto task = ImHexApi::Tasks::createTask("hex.builtin.view.pattern_editor.evaluating", 1);
|
||||
|
||||
this->m_runningParsers++;
|
||||
|
||||
auto ast = this->m_parserRuntime->parseString(code);
|
||||
@@ -749,11 +777,11 @@ namespace hex::plugin::builtin {
|
||||
|
||||
if (ast) {
|
||||
for (auto &node : *ast) {
|
||||
if (auto variableDecl = dynamic_cast<pl::ASTNodeVariableDecl *>(node.get())) {
|
||||
auto type = dynamic_cast<pl::ASTNodeTypeDecl *>(variableDecl->getType().get());
|
||||
if (auto variableDecl = dynamic_cast<pl::core::ast::ASTNodeVariableDecl *>(node.get())) {
|
||||
auto type = dynamic_cast<pl::core::ast::ASTNodeTypeDecl *>(variableDecl->getType().get());
|
||||
if (type == nullptr) continue;
|
||||
|
||||
auto builtinType = dynamic_cast<pl::ASTNodeBuiltinType *>(type->getType().get());
|
||||
auto builtinType = dynamic_cast<pl::core::ast::ASTNodeBuiltinType *>(type->getType().get());
|
||||
if (builtinType == nullptr) continue;
|
||||
|
||||
PatternVariable variable = {
|
||||
@@ -779,27 +807,29 @@ namespace hex::plugin::builtin {
|
||||
|
||||
this->m_textEditor.SetErrorMarkers({});
|
||||
this->m_console.clear();
|
||||
ImHexApi::Provider::get()->getPatternLanguageRuntime().reset();
|
||||
|
||||
auto &runtime = ProviderExtraData::getCurrent().patternLanguage.runtime;
|
||||
runtime->reset();
|
||||
|
||||
EventManager::post<EventHighlightingChanged>();
|
||||
|
||||
std::thread([this, code] {
|
||||
std::map<std::string, pl::Token::Literal> envVars;
|
||||
std::thread([this, code, &runtime] {
|
||||
auto task = ImHexApi::Tasks::createTask("hex.builtin.view.pattern_editor.evaluating", 1);
|
||||
|
||||
|
||||
std::map<std::string, pl::core::Token::Literal> envVars;
|
||||
for (const auto &[id, name, value, type] : this->m_envVarEntries)
|
||||
envVars.insert({ name, value });
|
||||
|
||||
this->parsePattern(code);
|
||||
|
||||
std::map<std::string, pl::Token::Literal> inVariables;
|
||||
std::map<std::string, pl::core::Token::Literal> inVariables;
|
||||
for (auto &[name, variable] : this->m_patternVariables) {
|
||||
if (variable.inVariable)
|
||||
inVariables[name] = variable.value;
|
||||
}
|
||||
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
auto &runtime = provider->getPatternLanguageRuntime();
|
||||
|
||||
runtime.setDangerousFunctionCallHandler([this]{
|
||||
runtime->setDangerousFunctionCallHandler([this]{
|
||||
this->m_dangerousFunctionCalled = true;
|
||||
|
||||
while (this->m_dangerousFunctionsAllowed == DangerousFunctionPerms::Ask) {
|
||||
@@ -809,15 +839,15 @@ namespace hex::plugin::builtin {
|
||||
return this->m_dangerousFunctionsAllowed == DangerousFunctionPerms::Allow;
|
||||
});
|
||||
|
||||
this->m_lastEvaluationResult = runtime.executeString(code, envVars, inVariables);
|
||||
this->m_lastEvaluationResult = runtime->executeString(code, envVars, inVariables);
|
||||
if (!this->m_lastEvaluationResult) {
|
||||
this->m_lastEvaluationError = runtime.getError();
|
||||
this->m_lastEvaluationError = runtime->getError();
|
||||
}
|
||||
|
||||
runtime.flattenPatterns();
|
||||
runtime->flattenPatterns();
|
||||
|
||||
this->m_lastEvaluationLog = runtime.getConsoleLog();
|
||||
this->m_lastEvaluationOutVars = runtime.getOutVariables();
|
||||
this->m_lastEvaluationLog = runtime->getConsoleLog();
|
||||
this->m_lastEvaluationOutVars = runtime->getOutVariables();
|
||||
this->m_runningEvaluators--;
|
||||
|
||||
this->m_lastEvaluationProcessed = false;
|
||||
|
||||
@@ -28,7 +28,6 @@ namespace hex::plugin::builtin {
|
||||
if (ImGui::BeginPopupModal(View::toWindowName("hex.builtin.view.provider_settings.load_popup").c_str(), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
|
||||
auto provider = hex::ImHexApi::Provider::get();
|
||||
|
||||
if (provider != nullptr) {
|
||||
provider->drawLoadInterface();
|
||||
|
||||
@@ -36,8 +35,9 @@ namespace hex::plugin::builtin {
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::Button("hex.builtin.common.open"_lang)) {
|
||||
if (provider->open())
|
||||
if (provider->open()) {
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
else {
|
||||
View::showErrorPopup("hex.builtin.view.provider_settings.load_error"_lang);
|
||||
ImHexApi::Provider::remove(provider);
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user