Compare commits
151 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f2ded359d8 | ||
|
|
0e358bbefe | ||
|
|
2cea561468 | ||
|
|
8024b0a186 | ||
|
|
2b135cf7e0 | ||
|
|
ce8c64a679 | ||
|
|
f0da6ec82f | ||
|
|
46e3b9b5d6 | ||
|
|
d5a08ae568 | ||
|
|
11f63f9b02 | ||
|
|
5694eaba8c | ||
|
|
484481f886 | ||
|
|
210106901e | ||
|
|
eb247b8607 | ||
|
|
fb1453d98a | ||
|
|
b734fb5511 | ||
|
|
2cd6cb8814 | ||
|
|
2a93eab14c | ||
|
|
f039ea68d0 | ||
|
|
e0c35e0002 | ||
|
|
5ace199dc4 | ||
|
|
556895744b | ||
|
|
7f2c60b0d7 | ||
|
|
7bb9e7ee82 | ||
|
|
26be4c3ac8 | ||
|
|
b80517ab15 | ||
|
|
b17cd3696c | ||
|
|
accd554600 | ||
|
|
8bf586cfa9 | ||
|
|
ebea409e6a | ||
|
|
6fdba3d555 | ||
|
|
e865883611 | ||
|
|
9c484e7b57 | ||
|
|
b365e16cc9 | ||
|
|
6a07a2f85d | ||
|
|
0fd7461266 | ||
|
|
62eb0ccd1d | ||
|
|
3367237da3 | ||
|
|
3504987ab3 | ||
|
|
554e625bda | ||
|
|
84530e0817 | ||
|
|
663fb88367 | ||
|
|
4d99c4b59d | ||
|
|
12ee235380 | ||
|
|
e30ed35d69 | ||
|
|
e2f8c7d989 | ||
|
|
ca6a8a7a46 | ||
|
|
f52dae4297 | ||
|
|
d643f8f8f7 | ||
|
|
08a12dd2b0 | ||
|
|
b33dd5d4f5 | ||
|
|
e797ac3a57 | ||
|
|
8bd31f6375 | ||
|
|
d3f83e63c9 | ||
|
|
b450f4797e | ||
|
|
0552084673 | ||
|
|
d021e2b362 | ||
|
|
c769e9cc32 | ||
|
|
639390115b | ||
|
|
ceaf80a186 | ||
|
|
86274b8b94 | ||
|
|
669427eb24 | ||
|
|
5ba22e7554 | ||
|
|
65ad88eed9 | ||
|
|
e34703ea5a | ||
|
|
55bd2c6da6 | ||
|
|
96b5221c1d | ||
|
|
3a94be9abb | ||
|
|
9656b40d53 | ||
|
|
7e61b513f3 | ||
|
|
1d4cbbe418 | ||
|
|
e0e2996e25 | ||
|
|
a102f5fcbf | ||
|
|
4e5d56e2c0 | ||
|
|
a55177edfa | ||
|
|
4c01a749de | ||
|
|
7b61268f22 | ||
|
|
b11dbe4fe1 | ||
|
|
6dbff81f95 | ||
|
|
9893e7a965 | ||
|
|
814c595c12 | ||
|
|
f8b4d04713 | ||
|
|
3cdc8c5884 | ||
|
|
5eabc05396 | ||
|
|
b2932773b9 | ||
|
|
59a04e6dbf | ||
|
|
ddf1e8a179 | ||
|
|
17cc87d633 | ||
|
|
fd7beb642f | ||
|
|
b766cf0807 | ||
|
|
6c9469961b | ||
|
|
d8844236d0 | ||
|
|
60eb59c605 | ||
|
|
6a7bbb8752 | ||
|
|
e4431749e1 | ||
|
|
c587b357eb | ||
|
|
7357c26d54 | ||
|
|
73ca45ad3d | ||
|
|
bf00503d1f | ||
|
|
44a90f5c7d | ||
|
|
5c3ee9f499 | ||
|
|
03f357efd1 | ||
|
|
5462575f5c | ||
|
|
120e2bc300 | ||
|
|
c3137df83c | ||
|
|
737155a226 | ||
|
|
66d64cf020 | ||
|
|
42f5c0f484 | ||
|
|
75047e26e2 | ||
|
|
9fa6d82775 | ||
|
|
d1468984e7 | ||
|
|
20a2331504 | ||
|
|
5b00c8ee08 | ||
|
|
bda4aadc54 | ||
|
|
9d7e2eccac | ||
|
|
8c219b981c | ||
|
|
7d87c8bb98 | ||
|
|
13afd96806 | ||
|
|
4fb74a1769 | ||
|
|
aa658b7dbc | ||
|
|
7e3601989a | ||
|
|
3a1c0f8d66 | ||
|
|
91160b4311 | ||
|
|
83f4093796 | ||
|
|
f219395b25 | ||
|
|
ae6a7ad8e5 | ||
|
|
d990ee102a | ||
|
|
cfde9939b4 | ||
|
|
a22725bb67 | ||
|
|
7a4040f6ec | ||
|
|
2fbb351314 | ||
|
|
96e85c0685 | ||
|
|
50577c9ea0 | ||
|
|
073323b517 | ||
|
|
37cc8f3aae | ||
|
|
6367152650 | ||
|
|
ffbaef3872 | ||
|
|
a0b2473bf4 | ||
|
|
95a3104a56 | ||
|
|
2d5f77730b | ||
|
|
033a0dfbb9 | ||
|
|
cb682b6e21 | ||
|
|
7312908d4d | ||
|
|
b44f6035b3 | ||
|
|
b6bc8abf83 | ||
|
|
c60c1154b9 | ||
|
|
219afb6244 | ||
|
|
22b6bdb5cf | ||
|
|
d9a47fe815 | ||
|
|
45e987b413 | ||
|
|
a920696d03 |
178
.clang-format
@@ -1,178 +0,0 @@
|
||||
---
|
||||
Language: Cpp
|
||||
# BasedOnStyle: LLVM
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: false
|
||||
AlignArrayOfStructures: Left
|
||||
AlignConsecutiveMacros: Consecutive
|
||||
AlignConsecutiveAssignments: Consecutive
|
||||
AlignConsecutiveBitFields: AcrossEmptyLinesAndComments
|
||||
AlignConsecutiveDeclarations: None
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: Align
|
||||
AlignTrailingComments: true
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: true
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortEnumsOnASingleLine: false
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortCaseLabelsOnASingleLine: false
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortLambdasOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
AttributeMacros:
|
||||
- __capability
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: Never
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: false
|
||||
BeforeElse: false
|
||||
BeforeLambdaBody: false
|
||||
BeforeWhile: false
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeConceptDeclarations: false
|
||||
BreakBeforeBraces: Attach
|
||||
BreakBeforeInheritanceComma: false
|
||||
BreakInheritanceList: AfterComma
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: false
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakAfterJavaFieldAnnotations: false
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 0
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: false
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: false
|
||||
DeriveLineEnding: true
|
||||
DerivePointerAlignment: false
|
||||
DisableFormat: false
|
||||
EmptyLineAfterAccessModifier: Never
|
||||
EmptyLineBeforeAccessModifier: LogicalBlock
|
||||
ExperimentalAutoDetectBinPacking: true
|
||||
FixNamespaceComments: false
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IfMacros:
|
||||
- KJ_IF_MAYBE
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
SortPriority: 0
|
||||
CaseSensitive: false
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
IncludeIsMainSourceRegex: ''
|
||||
IndentAccessModifiers: false
|
||||
IndentCaseLabels: true
|
||||
IndentCaseBlocks: true
|
||||
IndentGotoLabels: true
|
||||
IndentPPDirectives: BeforeHash
|
||||
IndentExternBlock: Indent
|
||||
IndentRequires: false
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
InsertTrailingCommas: None
|
||||
JavaScriptQuotes: Leave
|
||||
JavaScriptWrapImports: true
|
||||
KeepEmptyLinesAtTheStartOfBlocks: true
|
||||
LambdaBodyIndentation: Signature
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 2
|
||||
NamespaceIndentation: All
|
||||
ObjCBinPackProtocolList: Auto
|
||||
ObjCBlockIndentWidth: 4
|
||||
ObjCBreakBeforeNestedBlockParam: true
|
||||
ObjCSpaceAfterProperty: false
|
||||
ObjCSpaceBeforeProtocolList: true
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 19
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PenaltyIndentedWhitespace: 0
|
||||
PointerAlignment: Right
|
||||
PPIndentWidth: 4
|
||||
ReferenceAlignment: Pointer
|
||||
ReflowComments: true
|
||||
ShortNamespaceLines: 5
|
||||
SortIncludes: Never
|
||||
SortJavaStaticImport: Before
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: false
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCaseColon: false
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceAroundPointerQualifiers: Default
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyBlock: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 4
|
||||
SpacesInAngles: Never
|
||||
SpacesInConditionalStatement: false
|
||||
SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInLineCommentPrefix:
|
||||
Minimum: 1
|
||||
Maximum: -1
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
SpaceBeforeSquareBrackets: false
|
||||
BitFieldColonSpacing: Both
|
||||
Standard: Latest
|
||||
StatementAttributeLikeMacros:
|
||||
- Q_EMIT
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 4
|
||||
UseCRLF: false
|
||||
UseTab: Never
|
||||
WhitespaceSensitiveMacros:
|
||||
- STRINGIZE
|
||||
- PP_STRINGIZE
|
||||
- BOOST_PP_STRINGIZE
|
||||
- NS_SWIFT_NAME
|
||||
- CF_SWIFT_NAME
|
||||
...
|
||||
|
||||
28
.github/workflows/build.yml
vendored
@@ -101,6 +101,17 @@ jobs:
|
||||
cpack
|
||||
echo "ImHex checks for the existence of this file to determine if it is running in portable mode. You should not delete this file" > $PWD/install/PORTABLE
|
||||
|
||||
#- name: 🗝️ Sign Windows Installer
|
||||
# if: github.event_name == 'push' && github.ref == 'refs/heads/master'
|
||||
# shell: powershell
|
||||
# env:
|
||||
# WIN_SIGN_CERT: ${{ secrets.WIN_SIGN_CERT }}
|
||||
# WIN_SIGN_PW: ${{ secrets.WIN_SIGN_PW }}
|
||||
# run: |
|
||||
# $buffer = [System.Convert]::FromBase64String($env:WIN_SIGN_CERT)
|
||||
# $certificate = [System.Security.Cryptography.X509Certificates.X509Certificate2]::New($buffer, $env:WIN_SIGN_PW)
|
||||
# Get-ChildItem -Path ./build -Filter *.msi -Recurse | Set-AuthenticodeSignature -HashAlgorithm SHA256 -Certificate $certificate -TimestampServer http://timestamp.digicert.com
|
||||
|
||||
- name: ⬆️ Upload Windows Installer
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
@@ -174,6 +185,7 @@ jobs:
|
||||
- name: ⬇️ Install dependencies
|
||||
run: |
|
||||
brew bundle --no-lock --file dist/Brewfile
|
||||
rm -rf /usr/local/Cellar/capstone
|
||||
|
||||
- name: ⬇️ Install classic glfw
|
||||
if: ${{! matrix.custom_glfw}}
|
||||
@@ -321,7 +333,7 @@ jobs:
|
||||
run: |
|
||||
cp -r build/DEBIAN build/DebDir
|
||||
dpkg-deb -Zgzip --build build/DebDir
|
||||
mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}.deb
|
||||
mv build/DebDir.deb imhex-${{env.IMHEX_VERSION}}-Ubuntu-22.04.deb
|
||||
|
||||
# AppImage cmake build
|
||||
- name: 🛠️ Reconfigure build for AppImage
|
||||
@@ -345,10 +357,8 @@ jobs:
|
||||
- name: 📦 Bundle AppImage
|
||||
run: |
|
||||
cd build-appimage
|
||||
mkdir -p ./AppDir/usr/share/metainfo
|
||||
cp ../dist/imhex.appdata.xml ./AppDir/usr/share/metainfo/imhex.appdata.xml
|
||||
export VERSION=${{env.IMHEX_VERSION}}
|
||||
appimage-builder --recipe ../dist/AppImageBuilder.yml
|
||||
mv ImHex-AppImage-x86_64.AppImage ../imhex-${{env.IMHEX_VERSION}}.AppImage
|
||||
cd ..
|
||||
|
||||
#- name: ⬆️ Upload Flatpak
|
||||
@@ -361,14 +371,20 @@ jobs:
|
||||
- name: ⬆️ Upload DEB
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Linux DEB (Ubuntu 22.04)
|
||||
name: Ubuntu 22.04 DEB
|
||||
path: '*.deb'
|
||||
|
||||
- name: ⬆️ Upload AppImage
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Linux AppImage
|
||||
path: '*.AppImage'
|
||||
path: 'build-appimage/*.AppImage'
|
||||
|
||||
- name: ⬆️ Upload AppImage zsync
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: Linux AppImage zsync
|
||||
path: 'build-appimage/*.AppImage.zsync'
|
||||
|
||||
# ArchLinux build
|
||||
archlinux-build:
|
||||
|
||||
6
.github/workflows/release.yml
vendored
@@ -116,6 +116,9 @@ jobs:
|
||||
|
||||
- name: ✉️ Update C++ Plugin Template
|
||||
uses: mvasigh/dispatch-action@main
|
||||
env:
|
||||
RELEASE_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.RELEASE_TOKEN != '' }}"
|
||||
with:
|
||||
token: ${{ secrets.RELEASE_TOKEN }}
|
||||
repo: ImHex-Cpp-Plugin-Template
|
||||
@@ -130,11 +133,12 @@ jobs:
|
||||
- name: ⬇️ Download dependencies
|
||||
shell: pwsh
|
||||
run: |
|
||||
iwr https://github.com/microsoft/winget-create/releases/download/v1.0.4.0/wingetcreate.exe -OutFile wingetcreate.exe
|
||||
iwr https://github.com/microsoft/winget-create/releases/download/v1.1.2.0/wingetcreate.exe -OutFile wingetcreate.exe
|
||||
- name: ⬆️ Update winget manifest
|
||||
shell: pwsh
|
||||
env:
|
||||
WINGET_GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
if: "${{ env.WINGET_GITHUB_TOKEN != '' }}"
|
||||
run: |
|
||||
$tagname = $env:GITHUB_REF.Replace("refs/tags/", "")
|
||||
$version = $tagname.Replace("v", "")
|
||||
|
||||
1
.idea/vcs.xml
generated
@@ -8,6 +8,7 @@
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/libromfs" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/nativefiledialog" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language/external/cli11" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/pattern_language/external/fmt" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/xdgpp" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/lib/external/yara/yara" vcs="Git" />
|
||||
|
||||
@@ -11,6 +11,7 @@ option(IMHEX_IGNORE_BAD_COMPILER "Allow compiling with an unsupported compiler"
|
||||
|
||||
# Basic compiler and cmake configurations
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
set(CMAKE_INCLUDE_DIRECTORIES_BEFORE ON)
|
||||
set(IMHEX_BASE_FOLDER ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
set(CMAKE_MODULE_PATH "${IMHEX_BASE_FOLDER}/cmake/modules")
|
||||
include("${IMHEX_BASE_FOLDER}/cmake/build_helpers.cmake")
|
||||
|
||||
52
INSTALL.md
Normal file
@@ -0,0 +1,52 @@
|
||||
# Installing ImHex
|
||||
|
||||
## Official Releases
|
||||
|
||||
The easiest way to install ImHex is to download the latest release from the [GitHub releases page](github.com/WerWolv/ImHex/releases/latest).
|
||||
|
||||
There's also a NoGPU version available for users who don't have a GPU or want to run ImHex in a VM without GPU passthrough.
|
||||
|
||||
## Nighly Builds
|
||||
|
||||
The GitHub Actions CI builds a new release package on every commit made to repository. These builds are available on the [GitHub Actions page](https://github.com/WerWolv/ImHex/actions?query=workflow%3A%22Build%22).
|
||||
These builds are not guaranteed to be stable and may contain bugs, however they also contain new features that are not yet available in the official releases.
|
||||
|
||||
## Building from source
|
||||
|
||||
Build instructions for Windows, Linux and macOS can be found under `/dist/compiling`:
|
||||
- Windows: [Link](dist/compiling/windows.md)
|
||||
- macOS: [Link](dist/compiling/macOS.md)
|
||||
- Linux: [Link](dist/compiling/linux.md)
|
||||
|
||||
## Package managers
|
||||
|
||||
ImHex is also available on various package managers. The officially supported ones are listed here:
|
||||
|
||||
### Windows
|
||||
|
||||
- **Cocolatey**
|
||||
- [imhex](https://community.chocolatey.org/packages/imhex) (Thanks to @Jarcho)
|
||||
- `choco install imhex`
|
||||
- **winget**
|
||||
- [WerWolv.ImHex](https://github.com/microsoft/winget-pkgs/tree/master/manifests/w/WerWolv/ImHex)
|
||||
- `winget install WerWolv.ImHex`
|
||||
|
||||
### Linux
|
||||
- **Arch Linux AUR**
|
||||
- [imhex-bin](https://aur.archlinux.org/packages/imhex-bin/) (Thanks to @iTrooz)
|
||||
- `yay -S imhex-bin`
|
||||
- [imhex](https://aur.archlinux.org/packages/imhex/) (Thanks to @KokaKiwi)
|
||||
- `yay -S imhex`
|
||||
- **Fedora**
|
||||
- [imhex](https://src.fedoraproject.org/rpms/imhex/) (Thanks to @jonathanspw)
|
||||
- `dnf install imhex`
|
||||
- **Flatpak**
|
||||
- [net.werwolv.Imhex](https://flathub.org/apps/details/net.werwolv.ImHex) (Thanks to @Mailaender)
|
||||
- `flatpak install flathub net.werwolv.ImHex`
|
||||
|
||||
### Available on other package managers
|
||||
|
||||
Packages that aren't explicitly mentioned above are not officially supported but they will most likely still work.
|
||||
Contact the maintainer of the package if you have any issues.
|
||||
|
||||
[](https://repology.org/project/imhex/versions)
|
||||
59
README.md
@@ -1,4 +1,4 @@
|
||||
<a href="https://imhex.werwolv.net"><h1 align="center" >:mag: ImHex</h1></a>
|
||||
<a href="https://imhex.werwolv.net"><h1 align="center" ><img height="100px" src="resources/projects/logo_text.svg"></h1></a>
|
||||
|
||||
<p align="center">A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM.</p>
|
||||
|
||||
@@ -104,7 +104,11 @@ If you like my work, please consider supporting me on GitHub Sponsors, Patreon o
|
||||
|
||||
## Pattern Language
|
||||
|
||||
The custom C-like Pattern Language developed and used by ImHex is easy to read, understand and learn. A guide with all features of the language can be found [on the docs page](http://imhex.werwolv.net/docs).
|
||||
The Pattern Language is the completely custom programming language developed for ImHex.
|
||||
It allows you to define structures and data types in a C-like syntax and then use them to parse and highlight a file's content.
|
||||
|
||||
- Source Code: [Link](https://github.com/WerWolv/PatternLanguage/)
|
||||
- Documentation: [Link](https://imhex.werwolv.net/docs/)
|
||||
|
||||
## Database
|
||||
|
||||
@@ -116,53 +120,15 @@ 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 7 or higher, macOS 10.15 (Catalina) or higher, "Modern" Linux (Ubuntu 22.04+, Fedora Stable/Rawhide, and Arch Linux are officially supported)
|
||||
- **OS**: Windows 7 or higher, macOS 10.15 (Catalina) or higher, "Modern" Linux (Ubuntu 22.04, Fedora Stable/Rawhide, and Arch Linux have official packages, other distributions can use the AppImage)
|
||||
- **CPU**: x86_64 (64 Bit)
|
||||
- **GPU**: OpenGL 3.0 or higher (preferable a dedicated GPU and not Intel HD Graphics)
|
||||
- **RAM**: 512MB, more may be required for more complicated analysis
|
||||
- **Storage**: 100MB
|
||||
|
||||
## Plugin development
|
||||
|
||||
To develop plugins for ImHex, use one of the following two templates projects to get started. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
|
||||
- [C++ Plugin Template](https://github.com/WerWolv/ImHex-Cpp-Plugin-Template)
|
||||
- [Rust Plugin Template](https://github.com/WerWolv/ImHex-Rust-Plugin-Template)
|
||||
|
||||
## Installing
|
||||
The following OSs have packages available in their respositories making it easy to install ImHex.
|
||||
### Fedora (36+)
|
||||
```
|
||||
dnf install imhex
|
||||
```
|
||||
|
||||
### RHEL 9 / AlmaLinux 9 (coming soon)
|
||||
|
||||
### Arch Linux (AUR)
|
||||
```
|
||||
yay install imhex
|
||||
```
|
||||
|
||||
## Third Party Repositories
|
||||
|
||||
ImHex is available in various thid party repositores.
|
||||
|
||||
[](https://repology.org/project/imhex/versions)
|
||||
|
||||
## Nightly builds
|
||||
|
||||
Nightlies are available via GitHub Actions [here](https://github.com/WerWolv/ImHex/actions?query=workflow%3ABuild).
|
||||
|
||||
- Windows • __x86_64__
|
||||
- [Installer](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Installer.zip)
|
||||
- [Portable](https://nightly.link/WerWolv/ImHex/workflows/build/master/Windows%20Portable.zip)
|
||||
- MacOS • __x86_64__
|
||||
- [DMG](https://nightly.link/WerWolv/ImHex/workflows/build/master/macOS%20DMG.zip)
|
||||
- Linux • __x86_64__
|
||||
- [Ubuntu DEB](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20DEB%20%28Ubuntu%2022.04%29.zip)
|
||||
- [AppImage](https://nightly.link/WerWolv/ImHex/workflows/build/master/Linux%20AppImage.zip)
|
||||
- [Arch Package](https://nightly.link/WerWolv/ImHex/workflows/build/master/ArchLinux%20.pkg.tar.zst.zip)
|
||||
- [Fedora Rawhide RPM](https://nightly.link/WerWolv/ImHex/workflows/build/master/Fedora%20Rawhide%20RPM.zip)
|
||||
- [Fedora Stable RPM](https://nightly.link/WerWolv/ImHex/workflows/build/master/Fedora%20Latest%20RPM.zip)
|
||||
Information on how to install ImHex can be found in the [Install](/INSTALL.md) guide
|
||||
|
||||
## Compiling
|
||||
|
||||
@@ -173,6 +139,15 @@ All releases are being built using latest available GCC.
|
||||
Many dependencies are bundled into the repository using submodules so make sure to clone it using the `--recurse-submodules` option.
|
||||
All dependencies that aren't bundled, can be installed using the dependency installer scripts found in the `/dist` folder.
|
||||
|
||||
For more information, check out the [Compiling](/dist/compiling) guide.
|
||||
|
||||
## Plugin development
|
||||
|
||||
To develop plugins for ImHex, use one of the following two templates projects to get started. You then have access to the entirety of libimhex as well as the ImHex API and the Content Registry to interact with ImHex or to add new content.
|
||||
- [C++ Plugin Template](https://github.com/WerWolv/ImHex-Cpp-Plugin-Template)
|
||||
- [Rust Plugin Template](https://github.com/WerWolv/ImHex-Rust-Plugin-Template)
|
||||
|
||||
|
||||
## Credits
|
||||
|
||||
### Contributors
|
||||
|
||||
@@ -265,6 +265,14 @@ macro(createPackage)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/icon.png DESTINATION ${CMAKE_INSTALL_PREFIX}/share/pixmaps RENAME imhex.png)
|
||||
install(FILES "$<TARGET_FILE:libimhex>" DESTINATION "${CMAKE_INSTALL_LIBDIR}" PERMISSIONS ${LIBRARY_PERMISSIONS})
|
||||
downloadImHexPatternsFiles("./share/imhex")
|
||||
|
||||
# install AppStream file
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/dist/net.werwolv.imhex.metainfo.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/metainfo)
|
||||
|
||||
# install symlink for the old standard name
|
||||
file(CREATE_LINK net.werwolv.imhex.metainfo.xml ${CMAKE_CURRENT_BINARY_DIR}/net.werwolv.imhex.appdata.xml SYMBOLIC)
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/net.werwolv.imhex.appdata.xml DESTINATION ${CMAKE_INSTALL_PREFIX}/share/metainfo)
|
||||
|
||||
endif()
|
||||
|
||||
if (CREATE_BUNDLE)
|
||||
@@ -323,7 +331,9 @@ macro(setDefaultBuiltTypeIfUnset)
|
||||
endmacro()
|
||||
|
||||
function(loadVersion version)
|
||||
file(READ "${CMAKE_CURRENT_SOURCE_DIR}/VERSION" read_version)
|
||||
set(VERSION_FILE "${CMAKE_CURRENT_SOURCE_DIR}/VERSION")
|
||||
set_property(DIRECTORY APPEND PROPERTY CMAKE_CONFIGURE_DEPENDS ${VERSION_FILE})
|
||||
file(READ "${VERSION_FILE}" read_version)
|
||||
set(${version} ${read_version} PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
@@ -382,6 +392,12 @@ function(downloadImHexPatternsFiles dest)
|
||||
|
||||
FetchContent_Populate(imhex_patterns)
|
||||
|
||||
else ()
|
||||
# Maybe patterns are cloned to a subdirectory
|
||||
set(imhex_patterns_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ImHex-Patterns")
|
||||
endif ()
|
||||
|
||||
if (EXISTS ${imhex_patterns_SOURCE_DIR})
|
||||
set(PATTERNS_FOLDERS_TO_INSTALL constants encodings includes patterns magic)
|
||||
foreach (FOLDER ${PATTERNS_FOLDERS_TO_INSTALL})
|
||||
install(DIRECTORY "${imhex_patterns_SOURCE_DIR}/${FOLDER}" DESTINATION ${dest})
|
||||
@@ -392,7 +408,7 @@ endfunction()
|
||||
|
||||
macro(setupCompilerWarnings target)
|
||||
set(IMHEX_COMMON_FLAGS "-Wall -Wextra -Werror")
|
||||
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread")
|
||||
set(IMHEX_C_FLAGS "${IMHEX_COMMON_FLAGS} -Wno-restrict -Wno-stringop-overread -Wno-stringop-overflow")
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${IMHEX_C_FLAGS}")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${IMHEX_C_FLAGS}")
|
||||
|
||||
5
dist/AppImageBuilder.yml
vendored
@@ -6,7 +6,7 @@ AppDir:
|
||||
id: imhex
|
||||
name: ImHex
|
||||
icon: imhex
|
||||
version: AppImage
|
||||
version: "{{VERSION}}"
|
||||
exec: usr/bin/imhex
|
||||
exec_args: $@
|
||||
apt:
|
||||
@@ -136,4 +136,5 @@ AppDir:
|
||||
- usr/share/doc/*/TODO.*
|
||||
AppImage:
|
||||
arch: x86_64
|
||||
update-information: guess
|
||||
update-information: gh-releases-zsync|WerWolv|ImHex|latest|imhex-*.AppImage.zsync
|
||||
file_name: imhex-{{VERSION}}.AppImage
|
||||
|
||||
33
dist/Arch/PKGBUILD
vendored
@@ -1,40 +1,29 @@
|
||||
# Maintainer: iTrooz_ <itrooz at protonmail dot com>
|
||||
# Contributor: Morten Linderud <foxboron@archlinux.org>
|
||||
|
||||
pkgname=imhex-bin
|
||||
pkgver=%version%
|
||||
pkgrel=1
|
||||
pkgdesc="A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM. "
|
||||
arch=("x86_64")
|
||||
url="https://github.com/WerWolv/ImHex"
|
||||
repo=$url
|
||||
license=('GPL 2.0')
|
||||
groups=()
|
||||
license=('GPL2')
|
||||
depends=(glfw mbedtls python freetype2 libglvnd dbus xdg-desktop-portal curl fmt yara nlohmann-json)
|
||||
makedepends=(git)
|
||||
checkdepends=()
|
||||
optdepends=()
|
||||
provides=(imhex)
|
||||
conflicts=(imhex)
|
||||
replaces=()
|
||||
backup=()
|
||||
options=()
|
||||
source=($repo"/releases/download/v$pkgver/imhex-$pkgver-ArchLinux.pkg.tar.zst")
|
||||
noextract=()
|
||||
source=("$url/releases/download/v$pkgver/imhex-$pkgver-ArchLinux.pkg.tar.zst")
|
||||
md5sums=(SKIP)
|
||||
validpgpkeys=()
|
||||
|
||||
package() {
|
||||
tar -xf imhex-$pkgver-ArchLinux.pkg.tar.zst
|
||||
install -Dm755 "$srcdir/usr/bin/imhex" "$pkgdir/usr/bin/imhex"
|
||||
install -Dm644 "$srcdir/usr/lib/libimhex.so.$pkgver" "$pkgdir/usr/lib/libimhex.so.$pkgver"
|
||||
|
||||
install -DT $srcdir/usr/bin/imhex $pkgdir/usr/bin/imhex
|
||||
install -DT $srcdir/usr/lib/libimhex.so.$pkgver $pkgdir/usr/lib/libimhex.so.$pkgver
|
||||
|
||||
for plugin in $srcdir/usr/lib/imhex/plugins/*.hexplug;
|
||||
do
|
||||
install -DT $plugin $pkgdir/usr/lib/imhex/plugins/`basename $plugin`
|
||||
for plugin in "$srcdir/usr/lib/imhex/plugins/"*.hexplug; do
|
||||
install -Dm644 "$plugin" "$pkgdir/usr/lib/imhex/plugins/${plugin##*/}"
|
||||
done
|
||||
|
||||
mkdir -p $pkgdir/usr/share/imhex
|
||||
cp -r $srcdir/usr/share/imhex/{constants,encodings,includes,magic,patterns} $pkgdir/usr/share/imhex
|
||||
cp -r $srcdir/usr/share/{applications,licenses} $pkgdir/usr/share
|
||||
install -d $pkgdir/usr/share
|
||||
install -d "$pkgdir/usr/share/imhex"
|
||||
cp -r "$srcdir/usr/share/imhex/"{constants,encodings,includes,magic,patterns} "$pkgdir/usr/share/imhex"
|
||||
cp -r "$srcdir/usr/share/"{applications,licenses} "$pkgdir/usr/share"
|
||||
}
|
||||
|
||||
1
dist/Brewfile
vendored
@@ -7,3 +7,4 @@ brew "freetype2"
|
||||
brew "libmagic"
|
||||
brew "pkg-config"
|
||||
brew "gcc@12"
|
||||
brew "llvm"
|
||||
|
||||
4
dist/Dockerfile
vendored
@@ -1,6 +1,6 @@
|
||||
FROM archlinux:latest
|
||||
|
||||
MAINTAINER WerWolv "hey@werwolv.net"
|
||||
LABEL maintainer="hey@werwolv.net" = WerWolv
|
||||
|
||||
# Install dependencies
|
||||
RUN pacman -Syy --needed --noconfirm
|
||||
@@ -25,4 +25,4 @@ RUN git clone https://github.com/WerWolv/ImHex --recurse-submodules /root/ImHex
|
||||
RUN mkdir /root/ImHex/build
|
||||
WORKDIR /root/ImHex/build
|
||||
RUN cmake .. && make -j
|
||||
WORKDIR /root/ImHex
|
||||
WORKDIR /root/ImHex
|
||||
|
||||
2
dist/compiling/macOS.md
vendored
@@ -16,7 +16,7 @@ OBJCXX=$(brew --prefix llvm)/bin/clang++ \
|
||||
PKG_CONFIG_PATH="$(brew --prefix openssl)/lib/pkgconfig":"$(brew --prefix)/lib/pkgconfig" \
|
||||
MACOSX_DEPLOYMENT_TARGET="10.15" \
|
||||
cmake \
|
||||
-DCMAKE_BUILD_TYPE=$BUILD_TYPE \
|
||||
-DCMAKE_BUILD_TYPE=Release \
|
||||
-DCREATE_BUNDLE=ON \
|
||||
-DCREATE_PACKAGE=ON \
|
||||
-DCMAKE_C_COMPILER_LAUNCHER=ccache \
|
||||
|
||||
22
dist/imhex.appdata.xml
vendored
@@ -1,22 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>imhex</id>
|
||||
<metadata_license>GPL-2.0</metadata_license>
|
||||
<project_license>GPL-2.0</project_license>
|
||||
<name>ImHex</name>
|
||||
<summary>A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM</summary>
|
||||
<description>
|
||||
<p>ImHex is a feature-rich Hex Editor aimed towards Reverse Engineers working with foreign data formats, malware, executables and raw memory.
|
||||
Besides all the features a common Hex Editor has, ImHex also features a custom scripting language used to declare and dissect data structures, support for running YARA rules, a node-based graphical data pre-processor and support for various data sources such as files, raw disks or GDB Servers.</p>
|
||||
</description>
|
||||
<launchable type="desktop-id">imhex.desktop</launchable>
|
||||
<url type="homepage">https://imhex.werwolv.net</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://user-images.githubusercontent.com/10835354/139717326-8044769d-527b-4d88-8adf-2d4ecafdca1f.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
<provides>
|
||||
<id>imhex.desktop</id>
|
||||
</provides>
|
||||
</component>
|
||||
34
dist/net.werwolv.imhex.metainfo.xml
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop-application">
|
||||
<id>imhex</id>
|
||||
<metadata_license>CC0-1.0</metadata_license>
|
||||
<project_license>GPL-2.0</project_license>
|
||||
<name>ImHex</name>
|
||||
<developer_name>WerWolv</developer_name>
|
||||
<update_contact>hey@werwolv.net</update_contact>
|
||||
<summary>A Hex Editor for Reverse Engineers, Programmers and people who value their retinas when working at 3 AM</summary>
|
||||
<description>
|
||||
<p>ImHex is a feature-rich Hex Editor aimed towards Reverse Engineers working with foreign data formats, malware, executables and raw memory.
|
||||
Besides all the features a common Hex Editor has, ImHex also features a custom scripting language used to declare and dissect data structures, support for running YARA rules, a node-based graphical data pre-processor and support for various data sources such as files, raw disks or GDB Servers.</p>
|
||||
</description>
|
||||
<launchable type="desktop-id">imhex.desktop</launchable>
|
||||
<url type="homepage">https://imhex.werwolv.net</url>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://user-images.githubusercontent.com/10835354/139717326-8044769d-527b-4d88-8adf-2d4ecafdca1f.png</image>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://user-images.githubusercontent.com/10835354/139717323-1f8c9d52-f7eb-4f43-9f11-097ac728ed6c.png</image>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
|
||||
<provides>
|
||||
<id>imhex.desktop</id>
|
||||
</provides>
|
||||
|
||||
<categories>
|
||||
<category>Development</category>
|
||||
</categories>
|
||||
|
||||
|
||||
</component>
|
||||
2
dist/rpm/imhex.spec
vendored
@@ -84,5 +84,7 @@ desktop-file-validate %{buildroot}%{_datadir}/applications/imhex.desktop
|
||||
%{_datadir}/applications/imhex.desktop
|
||||
%{_prefix}/lib64/libimhex.so.%{_version}
|
||||
%{_prefix}/lib64/imhex/plugins/*
|
||||
%{_metainfodir}/net.werwolv.imhex.metainfo.xml
|
||||
%{_metainfodir}/net.werwolv.imhex.appdata.xml
|
||||
|
||||
%changelog
|
||||
|
||||
2
lib/external/curl
vendored
2
lib/external/fmt
vendored
2
lib/external/imgui/include/imconfig.h
vendored
@@ -99,7 +99,7 @@
|
||||
// Your renderer backend will need to support it (most example renderer backends support both 16/32-bit indices).
|
||||
// Another way to allow large meshes while keeping 16-bit indices is to handle ImDrawCmd::VtxOffset in your renderer.
|
||||
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
|
||||
//#define ImDrawIdx unsigned int
|
||||
#define ImDrawIdx unsigned int
|
||||
|
||||
//---- Override ImDrawCallback signature (will need to modify renderer backends accordingly)
|
||||
//struct ImDrawList;
|
||||
|
||||
11
lib/external/imgui/source/imgui_impl_glfw.cpp
vendored
@@ -164,7 +164,10 @@ static void ImGui_ImplGlfw_ShutdownPlatformInterface();
|
||||
// Functions
|
||||
static const char* ImGui_ImplGlfw_GetClipboardText(void* user_data)
|
||||
{
|
||||
return glfwGetClipboardString((GLFWwindow*)user_data);
|
||||
// IMHEX PATCH BEGIN
|
||||
const char *data = glfwGetClipboardString((GLFWwindow*)user_data);
|
||||
return data == nullptr ? "" : data;
|
||||
// IMHEX PATCH END
|
||||
}
|
||||
|
||||
static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||
@@ -179,12 +182,12 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.ClipboardHandlerData.clear();
|
||||
if (!::OpenClipboard(NULL))
|
||||
return NULL;
|
||||
return "";
|
||||
HANDLE wbuf_handle = ::GetClipboardData(CF_UNICODETEXT);
|
||||
if (wbuf_handle == NULL)
|
||||
{
|
||||
::CloseClipboard();
|
||||
return NULL;
|
||||
return "";
|
||||
}
|
||||
if (const WCHAR* wbuf_global = (const WCHAR*)::GlobalLock(wbuf_handle))
|
||||
{
|
||||
@@ -194,7 +197,7 @@ static void ImGui_ImplGlfw_SetClipboardText(void* user_data, const char* text)
|
||||
}
|
||||
::GlobalUnlock(wbuf_handle);
|
||||
::CloseClipboard();
|
||||
return g.ClipboardHandlerData.Data;
|
||||
return g.ClipboardHandlerData.Data == nullptr ? "" : g.ClipboardHandlerData.Data;
|
||||
}
|
||||
|
||||
static void ImGui_ImplWin_SetClipboardText(void*, const char* text)
|
||||
|
||||
2
lib/external/libromfs
vendored
2
lib/external/nativefiledialog
vendored
2
lib/external/pattern_language
vendored
2
lib/external/yara/yara
vendored
@@ -11,8 +11,9 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../external/microtar ${CMAKE_CURREN
|
||||
set_target_properties(microtar PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
|
||||
set(LIBROMFS_RESOURCE_LOCATION ${IMHEX_BASE_FOLDER}/resources/romfs)
|
||||
set(LIBROMFS_PROJECT_NAME imhex)
|
||||
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)
|
||||
set_target_properties(${LIBROMFS_LIBRARY} 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)
|
||||
@@ -172,4 +173,5 @@ if (APPLE)
|
||||
target_link_libraries(libimhex PUBLIC ${FOUNDATION})
|
||||
endif ()
|
||||
|
||||
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)
|
||||
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} libpl intervaltree)
|
||||
target_link_libraries(libimhex PRIVATE libromfs-imhex)
|
||||
|
||||
@@ -20,10 +20,6 @@
|
||||
using ImGuiDataType = int;
|
||||
using ImGuiInputTextFlags = int;
|
||||
|
||||
namespace pl {
|
||||
class Evaluator;
|
||||
}
|
||||
|
||||
namespace hex {
|
||||
|
||||
class View;
|
||||
@@ -61,7 +57,7 @@ namespace hex {
|
||||
return name < other.name;
|
||||
}
|
||||
|
||||
operator const std::string &() const {
|
||||
explicit operator const std::string &() const {
|
||||
return name;
|
||||
}
|
||||
};
|
||||
@@ -136,7 +132,7 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
std::unique_ptr<pl::PatternLanguage> createDefaultRuntime(prv::Provider *provider);
|
||||
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider);
|
||||
|
||||
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler);
|
||||
|
||||
@@ -435,7 +431,7 @@ namespace hex {
|
||||
|
||||
class Hash {
|
||||
public:
|
||||
Hash(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
|
||||
explicit Hash(std::string unlocalizedName) : m_unlocalizedName(std::move(unlocalizedName)) {}
|
||||
|
||||
class Function {
|
||||
public:
|
||||
@@ -498,6 +494,6 @@ namespace hex {
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ namespace hex {
|
||||
|
||||
namespace impl {
|
||||
|
||||
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t)>;
|
||||
using HighlightingFunction = std::function<std::optional<color_t>(u64, const u8*, size_t, bool)>;
|
||||
|
||||
std::map<u32, Highlighting> &getBackgroundHighlights();
|
||||
std::map<u32, HighlightingFunction> &getBackgroundHighlightingFunctions();
|
||||
@@ -171,6 +171,8 @@ namespace hex {
|
||||
void setGPUVendor(const std::string &vendor);
|
||||
|
||||
void setPortableVersion(bool enabled);
|
||||
|
||||
void addInitArgument(const std::string &key, const std::string &value = { });
|
||||
}
|
||||
|
||||
struct ProgramArguments {
|
||||
@@ -186,6 +188,7 @@ namespace hex {
|
||||
};
|
||||
|
||||
const ProgramArguments &getProgramArguments();
|
||||
std::optional<std::u8string> getProgramArgument(int index);
|
||||
|
||||
float getTargetFPS();
|
||||
void setTargetFPS(float fps);
|
||||
|
||||
@@ -179,10 +179,10 @@ namespace hex {
|
||||
return result;
|
||||
}
|
||||
|
||||
static constexpr auto CTRL = Key(static_cast<Keys>(0x1000'0000));
|
||||
static constexpr auto ALT = Key(static_cast<Keys>(0x2000'0000));
|
||||
static constexpr auto SHIFT = Key(static_cast<Keys>(0x4000'0000));
|
||||
static constexpr auto SUPER = Key(static_cast<Keys>(0x8000'0000));
|
||||
constexpr static auto CTRL = Key(static_cast<Keys>(0x1000'0000));
|
||||
constexpr static auto ALT = Key(static_cast<Keys>(0x2000'0000));
|
||||
constexpr static auto SHIFT = Key(static_cast<Keys>(0x4000'0000));
|
||||
constexpr static auto SUPER = Key(static_cast<Keys>(0x8000'0000));
|
||||
|
||||
class ShortcutManager {
|
||||
public:
|
||||
|
||||
@@ -19,12 +19,14 @@ namespace hex {
|
||||
struct Handler {
|
||||
using Function = std::function<bool(const std::fs::path &, Tar &tar)>;
|
||||
std::fs::path basePath;
|
||||
bool required;
|
||||
Function load, store;
|
||||
};
|
||||
|
||||
struct ProviderHandler {
|
||||
using Function = std::function<bool(prv::Provider *provider, const std::fs::path &, Tar &tar)>;
|
||||
std::fs::path basePath;
|
||||
bool required;
|
||||
Function load, store;
|
||||
};
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <condition_variable>
|
||||
|
||||
namespace hex {
|
||||
|
||||
@@ -19,7 +20,7 @@ namespace hex {
|
||||
class Task {
|
||||
public:
|
||||
Task() = default;
|
||||
Task(std::string unlocalizedName, u64 maxValue, std::function<void(Task &)> function);
|
||||
Task(std::string unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function);
|
||||
|
||||
Task(const Task&) = delete;
|
||||
Task(Task &&other) noexcept;
|
||||
@@ -28,6 +29,7 @@ namespace hex {
|
||||
void update(u64 value = 0);
|
||||
void setMaxValue(u64 value);
|
||||
|
||||
[[nodiscard]] bool isBackgroundTask() const;
|
||||
[[nodiscard]] bool isFinished() const;
|
||||
[[nodiscard]] bool hadException() const;
|
||||
[[nodiscard]] bool wasInterrupted() const;
|
||||
@@ -40,6 +42,8 @@ namespace hex {
|
||||
|
||||
void interrupt();
|
||||
|
||||
void setInterruptCallback(std::function<void()> callback);
|
||||
|
||||
private:
|
||||
void finish();
|
||||
void interruption();
|
||||
@@ -49,14 +53,16 @@ namespace hex {
|
||||
mutable std::mutex m_mutex;
|
||||
|
||||
std::string m_unlocalizedName;
|
||||
u64 m_currValue, m_maxValue;
|
||||
std::thread m_thread;
|
||||
std::atomic<u64> m_currValue = 0, m_maxValue = 0;
|
||||
std::function<void()> m_interruptCallback;
|
||||
std::function<void(Task &)> m_function;
|
||||
|
||||
bool m_shouldInterrupt = false;
|
||||
std::atomic<bool> m_shouldInterrupt = false;
|
||||
std::atomic<bool> m_background = true;
|
||||
|
||||
bool m_interrupted = false;
|
||||
bool m_finished = false;
|
||||
bool m_hadException = false;
|
||||
std::atomic<bool> m_interrupted = false;
|
||||
std::atomic<bool> m_finished = false;
|
||||
std::atomic<bool> m_hadException = false;
|
||||
std::string m_exceptionMessage;
|
||||
|
||||
struct TaskInterruptor { virtual ~TaskInterruptor() = default; };
|
||||
@@ -83,9 +89,14 @@ namespace hex {
|
||||
public:
|
||||
TaskManager() = delete;
|
||||
|
||||
static void init();
|
||||
static void exit();
|
||||
|
||||
constexpr static auto NoProgress = 0;
|
||||
|
||||
static TaskHolder createTask(std::string name, u64 maxValue, std::function<void(Task &)> function);
|
||||
static TaskHolder createBackgroundTask(std::string name, std::function<void(Task &)> function);
|
||||
|
||||
static void collectGarbage();
|
||||
|
||||
static size_t getRunningTaskCount();
|
||||
@@ -97,7 +108,14 @@ namespace hex {
|
||||
static std::mutex s_deferredCallsMutex;
|
||||
|
||||
static std::list<std::shared_ptr<Task>> s_tasks;
|
||||
static std::list<std::shared_ptr<Task>> s_taskQueue;
|
||||
static std::list<std::function<void()>> s_deferredCalls;
|
||||
|
||||
static std::mutex s_queueMutex;
|
||||
static std::condition_variable s_jobCondVar;
|
||||
static std::vector<std::jthread> s_workers;
|
||||
|
||||
static void runner(const std::stop_token &stopToken);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -27,32 +27,32 @@ namespace hex::dp {
|
||||
Attribute(IOType ioType, Type type, std::string unlocalizedName);
|
||||
~Attribute();
|
||||
|
||||
[[nodiscard]] u32 getId() const { return this->m_id; }
|
||||
void setId(u32 id) { this->m_id = id; }
|
||||
[[nodiscard]] int getId() const { return this->m_id; }
|
||||
void setId(int id) { this->m_id = id; }
|
||||
|
||||
[[nodiscard]] IOType getIOType() const { return this->m_ioType; }
|
||||
[[nodiscard]] Type getType() const { return this->m_type; }
|
||||
[[nodiscard]] const std::string &getUnlocalizedName() const { return this->m_unlocalizedName; }
|
||||
|
||||
void addConnectedAttribute(u32 linkId, Attribute *to) { this->m_connectedAttributes.insert({ linkId, to }); }
|
||||
void removeConnectedAttribute(u32 linkId) { this->m_connectedAttributes.erase(linkId); }
|
||||
[[nodiscard]] std::map<u32, Attribute *> &getConnectedAttributes() { return this->m_connectedAttributes; }
|
||||
void addConnectedAttribute(int linkId, Attribute *to) { this->m_connectedAttributes.insert({ linkId, to }); }
|
||||
void removeConnectedAttribute(int linkId) { this->m_connectedAttributes.erase(linkId); }
|
||||
[[nodiscard]] std::map<int, Attribute *> &getConnectedAttributes() { return this->m_connectedAttributes; }
|
||||
|
||||
[[nodiscard]] Node *getParentNode() { return this->m_parentNode; }
|
||||
|
||||
[[nodiscard]] std::optional<std::vector<u8>> &getOutputData() { return this->m_outputData; }
|
||||
|
||||
static void setIdCounter(u32 id) {
|
||||
static void setIdCounter(int id) {
|
||||
if (id > Attribute::s_idCounter)
|
||||
Attribute::s_idCounter = id;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_id;
|
||||
int m_id;
|
||||
IOType m_ioType;
|
||||
Type m_type;
|
||||
std::string m_unlocalizedName;
|
||||
std::map<u32, Attribute *> m_connectedAttributes;
|
||||
std::map<int, Attribute *> m_connectedAttributes;
|
||||
Node *m_parentNode = nullptr;
|
||||
|
||||
std::optional<std::vector<u8>> m_outputData;
|
||||
@@ -60,7 +60,7 @@ namespace hex::dp {
|
||||
friend class Node;
|
||||
void setParentNode(Node *node) { this->m_parentNode = node; }
|
||||
|
||||
static u32 s_idCounter;
|
||||
static int s_idCounter;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -6,24 +6,24 @@ namespace hex::dp {
|
||||
|
||||
class Link {
|
||||
public:
|
||||
Link(u32 from, u32 to);
|
||||
Link(int from, int to);
|
||||
|
||||
[[nodiscard]] u32 getId() const { return this->m_id; }
|
||||
void setID(u32 id) { this->m_id = id; }
|
||||
[[nodiscard]] int getId() const { return this->m_id; }
|
||||
void setID(int id) { this->m_id = id; }
|
||||
|
||||
[[nodiscard]] u32 getFromId() const { return this->m_from; }
|
||||
[[nodiscard]] u32 getToId() const { return this->m_to; }
|
||||
[[nodiscard]] int getFromId() const { return this->m_from; }
|
||||
[[nodiscard]] int getToId() const { return this->m_to; }
|
||||
|
||||
static void setIdCounter(u32 id) {
|
||||
static void setIdCounter(int id) {
|
||||
if (id > Link::s_idCounter)
|
||||
Link::s_idCounter = id;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_id;
|
||||
u32 m_from, m_to;
|
||||
int m_id;
|
||||
int m_from, m_to;
|
||||
|
||||
static u32 s_idCounter;
|
||||
static int s_idCounter;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <imgui.h>
|
||||
|
||||
namespace hex::prv {
|
||||
class Provider;
|
||||
@@ -23,8 +24,8 @@ namespace hex::dp {
|
||||
|
||||
virtual ~Node() = default;
|
||||
|
||||
[[nodiscard]] u32 getId() const { return this->m_id; }
|
||||
void setId(u32 id) { this->m_id = id; }
|
||||
[[nodiscard]] int getId() const { return this->m_id; }
|
||||
void setId(int id) { this->m_id = id; }
|
||||
|
||||
[[nodiscard]] const std::string &getUnlocalizedName() const { return this->m_unlocalizedName; }
|
||||
void setUnlocalizedName(const std::string &unlocalizedName) { this->m_unlocalizedName = unlocalizedName; }
|
||||
@@ -56,19 +57,28 @@ namespace hex::dp {
|
||||
this->m_processedInputs.clear();
|
||||
}
|
||||
|
||||
static void setIdCounter(u32 id) {
|
||||
void setPosition(ImVec2 pos) {
|
||||
this->m_position = pos;
|
||||
}
|
||||
|
||||
[[nodiscard]] ImVec2 getPosition() const {
|
||||
return this->m_position;
|
||||
}
|
||||
|
||||
static void setIdCounter(int id) {
|
||||
if (id > Node::s_idCounter)
|
||||
Node::s_idCounter = id;
|
||||
}
|
||||
|
||||
private:
|
||||
u32 m_id;
|
||||
int m_id;
|
||||
std::string m_unlocalizedTitle, m_unlocalizedName;
|
||||
std::vector<Attribute> m_attributes;
|
||||
std::set<u32> m_processedInputs;
|
||||
prv::Overlay *m_overlay = nullptr;
|
||||
ImVec2 m_position;
|
||||
|
||||
static u32 s_idCounter;
|
||||
static int s_idCounter;
|
||||
|
||||
Attribute *getConnectedInputAttribute(u32 index) {
|
||||
if (index >= this->getAttributes().size())
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace hex {
|
||||
|
||||
class Disassembler {
|
||||
public:
|
||||
static constexpr cs_arch toCapstoneArchitecture(Architecture architecture) {
|
||||
constexpr static cs_arch toCapstoneArchitecture(Architecture architecture) {
|
||||
return static_cast<cs_arch>(architecture);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
@@ -66,7 +68,7 @@ namespace hex::fs {
|
||||
}
|
||||
|
||||
static inline bool isSubPath(const std::fs::path& base, const std::fs::path& destination) {
|
||||
const auto relative = std::fs::relative(destination, base).string();
|
||||
const auto relative = std::fs::relative(destination, base).u8string();
|
||||
|
||||
return relative.size() == 1 || (relative[0] != '.' && relative[1] != '.');
|
||||
}
|
||||
@@ -75,18 +77,17 @@ namespace hex::fs {
|
||||
|
||||
std::fs::path toShortPath(const std::fs::path &path);
|
||||
|
||||
enum class DialogMode
|
||||
{
|
||||
enum class DialogMode {
|
||||
Open,
|
||||
Save,
|
||||
Folder
|
||||
};
|
||||
|
||||
void setFileBrowserErrorCallback(const std::function<void()> &callback);
|
||||
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath = {});
|
||||
|
||||
enum class ImHexPath
|
||||
{
|
||||
Patterns,
|
||||
enum class ImHexPath : u32 {
|
||||
Patterns = 0,
|
||||
PatternsInclude,
|
||||
Magic,
|
||||
Python,
|
||||
@@ -97,7 +98,11 @@ namespace hex::fs {
|
||||
Constants,
|
||||
Encodings,
|
||||
Logs,
|
||||
Recent
|
||||
Recent,
|
||||
Scripts,
|
||||
Inspectors,
|
||||
|
||||
END
|
||||
};
|
||||
|
||||
std::optional<std::fs::path> getExecutablePath();
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <chrono>
|
||||
#include <mutex>
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <fmt/color.h>
|
||||
@@ -30,6 +31,9 @@ namespace hex::log {
|
||||
|
||||
template<typename... T>
|
||||
[[maybe_unused]] void print(const fmt::text_style &ts, const std::string &level, const std::string &fmt, auto... args) {
|
||||
static std::mutex logMutex;
|
||||
std::scoped_lock lock(logMutex);
|
||||
|
||||
auto dest = getDestination();
|
||||
|
||||
printPrefix(dest, ts, level);
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include <nlohmann/json_fwd.hpp>
|
||||
#include <curl/system.h>
|
||||
#include <mbedtls/ssl.h>
|
||||
|
||||
#include <hex/helpers/fs.hpp>
|
||||
|
||||
@@ -35,7 +36,7 @@ namespace hex {
|
||||
Net();
|
||||
~Net();
|
||||
|
||||
static constexpr u32 DefaultTimeout = 2'000;
|
||||
constexpr static u32 DefaultTimeout = 2'000;
|
||||
|
||||
std::future<Response<std::string>> getString(const std::string &url, u32 timeout = DefaultTimeout);
|
||||
std::future<Response<nlohmann::json>> getJson(const std::string &url, u32 timeout = DefaultTimeout);
|
||||
@@ -60,6 +61,7 @@ namespace hex {
|
||||
|
||||
private:
|
||||
CURL *m_ctx;
|
||||
mbedtls_x509_crt m_caCert;
|
||||
curl_slist *m_headers = nullptr;
|
||||
|
||||
std::mutex m_transmissionActive;
|
||||
|
||||
@@ -27,8 +27,8 @@ struct ImVec2;
|
||||
|
||||
namespace hex {
|
||||
|
||||
long double operator""_scaled(long double value);
|
||||
long double operator""_scaled(unsigned long long value);
|
||||
float operator""_scaled(long double value);
|
||||
float operator""_scaled(unsigned long long value);
|
||||
ImVec2 scaled(const ImVec2 &vector);
|
||||
|
||||
template<typename T>
|
||||
@@ -275,6 +275,13 @@ namespace hex {
|
||||
return iter != a.end();
|
||||
}
|
||||
|
||||
template<typename T> requires requires(T t) { t.u8string(); }
|
||||
std::string toUTF8String(const T &value) {
|
||||
auto result = value.u8string();
|
||||
|
||||
return { result.begin(), result.end() };
|
||||
}
|
||||
|
||||
template<typename T, typename... VariantTypes>
|
||||
T get_or(const std::variant<VariantTypes...> &variant, T alt) {
|
||||
const T *value = std::get_if<T>(&variant);
|
||||
@@ -297,6 +304,13 @@ namespace hex {
|
||||
|
||||
std::optional<std::string> getEnvironmentVariable(const std::string &env);
|
||||
|
||||
inline std::string limitStringLength(const std::string &string, size_t maxLength) {
|
||||
if (string.length() <= maxLength)
|
||||
return string;
|
||||
|
||||
return string.substr(0, maxLength - 3) + "...";
|
||||
}
|
||||
|
||||
namespace scope_guard {
|
||||
|
||||
#define SCOPE_GUARD ::hex::scope_guard::ScopeGuardOnExit() + [&]()
|
||||
@@ -335,7 +349,7 @@ namespace hex {
|
||||
|
||||
namespace first_time_exec {
|
||||
|
||||
#define FIRST_TIME [[maybe_unused]] static auto ANONYMOUS_VARIABLE(FIRST_TIME_) = ::hex::first_time_exec::FirstTimeExecutor() + [&]()
|
||||
#define FIRST_TIME [[maybe_unused]] static auto ANONYMOUS_VARIABLE(FIRST_TIME_) = ::hex::first_time_exec::FirstTimeExecutor() + [&]()
|
||||
|
||||
template<class F>
|
||||
class FirstTimeExecute {
|
||||
@@ -358,7 +372,7 @@ namespace hex {
|
||||
|
||||
namespace final_cleanup {
|
||||
|
||||
#define FINAL_CLEANUP [[maybe_unused]] static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]()
|
||||
#define FINAL_CLEANUP [[maybe_unused]] static auto ANONYMOUS_VARIABLE(ON_EXIT_) = ::hex::final_cleanup::FinalCleanupExecutor() + [&]()
|
||||
|
||||
template<class F>
|
||||
class FinalCleanupExecute {
|
||||
|
||||
@@ -24,6 +24,9 @@ namespace hex::prv {
|
||||
}
|
||||
|
||||
void setEndAddress(u64 address) {
|
||||
if (address >= this->m_provider->getActualSize())
|
||||
address = this->m_provider->getActualSize() - 1;
|
||||
|
||||
this->m_endAddress = address;
|
||||
}
|
||||
|
||||
@@ -256,7 +259,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) - 1;
|
||||
const auto remainingBytes = (this->m_endAddress - address) + 1;
|
||||
if (remainingBytes < this->m_maxBufferSize)
|
||||
this->m_buffer.resize(remainingBytes);
|
||||
else
|
||||
|
||||
@@ -14,10 +14,6 @@
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace pl {
|
||||
class PatternLanguage;
|
||||
}
|
||||
|
||||
namespace hex::prv {
|
||||
|
||||
class Provider {
|
||||
@@ -70,8 +66,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();
|
||||
virtual void close();
|
||||
[[nodiscard]] virtual bool open() = 0;
|
||||
virtual void close() = 0;
|
||||
|
||||
void addPatch(u64 offset, const void *buffer, size_t size, bool createUndo = false);
|
||||
void createUndoPoint();
|
||||
@@ -90,9 +86,8 @@ namespace hex::prv {
|
||||
virtual void drawLoadInterface();
|
||||
virtual void drawInterface();
|
||||
|
||||
[[nodiscard]] u32 getID() const {
|
||||
return this->m_id;
|
||||
}
|
||||
[[nodiscard]] u32 getID() const;
|
||||
void setID(u32 id);
|
||||
|
||||
[[nodiscard]] virtual nlohmann::json storeSettings(nlohmann::json settings = { }) const;
|
||||
virtual void loadSettings(const nlohmann::json &settings);
|
||||
@@ -102,7 +97,7 @@ namespace hex::prv {
|
||||
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;
|
||||
[[nodiscard]] virtual std::pair<Region, bool> getRegionValidity(u64 address) const;
|
||||
|
||||
void skipLoadInterface() { this->m_skipLoadInterface = true; }
|
||||
[[nodiscard]] bool shouldSkipLoadInterface() const { return this->m_skipLoadInterface; }
|
||||
|
||||
@@ -31,27 +31,40 @@ enum ImGuiCustomCol {
|
||||
|
||||
namespace ImGui {
|
||||
|
||||
struct Texture {
|
||||
ImTextureID textureId = nullptr;
|
||||
int width = 0, height = 0;
|
||||
class Texture {
|
||||
public:
|
||||
Texture() = default;
|
||||
Texture(const ImU8 *buffer, int size);
|
||||
explicit Texture(const char *path);
|
||||
Texture(const Texture&) = delete;
|
||||
Texture(Texture&& other) noexcept;
|
||||
|
||||
[[nodiscard]] constexpr bool valid() const noexcept {
|
||||
return this->textureId != nullptr;
|
||||
~Texture();
|
||||
|
||||
Texture& operator=(const Texture&) = delete;
|
||||
Texture& operator=(Texture&& other) noexcept;
|
||||
|
||||
[[nodiscard]] constexpr bool isValid() const noexcept {
|
||||
return this->m_textureId != nullptr;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr operator ImTextureID() {
|
||||
return this->textureId;
|
||||
return this->m_textureId;
|
||||
}
|
||||
|
||||
[[nodiscard]] auto size() const noexcept {
|
||||
return ImVec2(this->width, this->height);
|
||||
[[nodiscard]] auto getSize() const noexcept {
|
||||
return ImVec2(this->m_width, this->m_height);
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr auto aspectRatio() const noexcept {
|
||||
if (this->height == 0) return 1.0F;
|
||||
[[nodiscard]] constexpr auto getAspectRatio() const noexcept {
|
||||
if (this->m_height == 0) return 1.0F;
|
||||
|
||||
return float(this->width) / float(this->height);
|
||||
return float(this->m_width) / float(this->m_height);
|
||||
}
|
||||
|
||||
private:
|
||||
ImTextureID m_textureId = nullptr;
|
||||
int m_width = 0, m_height = 0;
|
||||
};
|
||||
|
||||
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data);
|
||||
@@ -82,10 +95,6 @@ namespace ImGui {
|
||||
return static_cast<ImU32>(ImGui::GetTime() * 100) % 100 <= static_cast<ImU32>(ImGui::GetIO().DeltaTime * 100);
|
||||
}
|
||||
|
||||
Texture LoadImageFromPath(const char *path);
|
||||
Texture LoadImageFromMemory(const ImU8 *buffer, int size);
|
||||
void UnloadImage(Texture &texture);
|
||||
|
||||
void OpenPopupInWindow(const char *window_name, const char *popup_name);
|
||||
|
||||
struct ImHexCustomData {
|
||||
@@ -130,6 +139,7 @@ namespace ImGui {
|
||||
}
|
||||
|
||||
bool InputText(const char* label, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputTextIcon(const char* label, const char *icon, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputText(const char *label, std::u8string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputTextMultiline(const char* label, std::string &buffer, const ImVec2& size = ImVec2(0, 0), ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
bool InputTextWithHint(const char *label, const char *hint, std::string &buffer, ImGuiInputTextFlags flags = ImGuiInputTextFlags_None);
|
||||
|
||||
@@ -241,29 +241,30 @@ namespace hex {
|
||||
return functionName;
|
||||
}
|
||||
|
||||
std::unique_ptr<pl::PatternLanguage> createDefaultRuntime(prv::Provider *provider) {
|
||||
auto runtime = std::make_unique<pl::PatternLanguage>();
|
||||
void configureRuntime(pl::PatternLanguage &runtime, prv::Provider *provider) {
|
||||
runtime.reset();
|
||||
|
||||
if (provider != nullptr) {
|
||||
runtime->setDataSource([provider](u64 offset, u8 *buffer, size_t size) {
|
||||
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) | fs::getDefaultPaths(fs::ImHexPath::Patterns));
|
||||
runtime.setIncludePaths(fs::getDefaultPaths(fs::ImHexPath::PatternsInclude) | fs::getDefaultPaths(fs::ImHexPath::Patterns));
|
||||
|
||||
for (const auto &func : getFunctions()) {
|
||||
if (func.dangerous)
|
||||
runtime->addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
runtime.addDangerousFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
else
|
||||
runtime->addFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
runtime.addFunction(func.ns, func.name, func.parameterCount, func.callback);
|
||||
}
|
||||
|
||||
for (const auto &[name, callback] : getPragmas()) {
|
||||
runtime->addPragma(name, callback);
|
||||
runtime.addPragma(name, callback);
|
||||
}
|
||||
|
||||
return runtime;
|
||||
runtime.addDefine("__IMHEX__");
|
||||
runtime.addDefine("__IMHEX_VERSION__", IMHEX_VERSION);
|
||||
}
|
||||
|
||||
void addPragma(const std::string &name, const pl::api::PragmaHandler &handler) {
|
||||
|
||||
@@ -11,6 +11,12 @@
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <shellapi.h>
|
||||
#endif
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace ImHexApi::Common {
|
||||
@@ -208,7 +214,7 @@ namespace hex {
|
||||
|
||||
namespace ImHexApi::Provider {
|
||||
|
||||
static u32 s_currentProvider = std::numeric_limits<u32>::max();
|
||||
static i64 s_currentProvider = -1;
|
||||
static std::vector<prv::Provider *> s_providers;
|
||||
|
||||
namespace impl {
|
||||
@@ -247,7 +253,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
bool isValid() {
|
||||
return !s_providers.empty() && s_currentProvider < s_providers.size();
|
||||
return !s_providers.empty() && s_currentProvider >= 0 && s_currentProvider < i64(s_providers.size());
|
||||
}
|
||||
|
||||
void markDirty() {
|
||||
@@ -308,6 +314,8 @@ namespace hex {
|
||||
setCurrentProvider(0);
|
||||
|
||||
provider->close();
|
||||
EventManager::post<EventProviderClosed>(provider);
|
||||
|
||||
delete provider;
|
||||
}
|
||||
|
||||
@@ -383,6 +391,13 @@ namespace hex {
|
||||
s_portableVersion = enabled;
|
||||
}
|
||||
|
||||
void addInitArgument(const std::string &key, const std::string &value) {
|
||||
static std::mutex initArgumentsMutex;
|
||||
std::scoped_lock lock(initArgumentsMutex);
|
||||
|
||||
getInitArguments()[key] = value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -390,6 +405,21 @@ namespace hex {
|
||||
return impl::s_programArguments;
|
||||
}
|
||||
|
||||
std::optional<std::u8string> getProgramArgument(int index) {
|
||||
if (index >= impl::s_programArguments.argc) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
std::wstring wideArg = ::CommandLineToArgvW(::GetCommandLineW(), &impl::s_programArguments.argc)[index];
|
||||
std::string byteArg = std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>, wchar_t>().to_bytes(wideArg);
|
||||
|
||||
return std::u8string(byteArg.begin(), byteArg.end());
|
||||
#else
|
||||
return std::u8string(reinterpret_cast<const char8_t *>(impl::s_programArguments.argv[index]));
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static float s_targetFPS = 60.0F;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include <hex/api/plugin_manager.hpp>
|
||||
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
#include <filesystem>
|
||||
#include <system_error>
|
||||
@@ -16,7 +17,7 @@ namespace hex {
|
||||
return;
|
||||
}
|
||||
#else
|
||||
this->m_handle = dlopen(path.string().c_str(), RTLD_LAZY);
|
||||
this->m_handle = dlopen(hex::toUTF8String(path).c_str(), RTLD_LAZY);
|
||||
|
||||
if (this->m_handle == nullptr) {
|
||||
log::error("dlopen failed: {}!", dlerror());
|
||||
@@ -68,7 +69,7 @@ namespace hex {
|
||||
bool Plugin::initializePlugin() const {
|
||||
const auto requestedVersion = getCompatibleVersion();
|
||||
if (requestedVersion != IMHEX_VERSION) {
|
||||
log::error("Refused to load plugin '{}' which was built for a different version of ImHex: '{}'", this->m_path.filename().string(), requestedVersion);
|
||||
log::error("Refused to load plugin '{}' which was built for a different version of ImHex: '{}'", hex::toUTF8String(this->m_path.filename()), requestedVersion);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,10 @@ namespace hex {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||
ImHexApi::Provider::remove(provider);
|
||||
}
|
||||
|
||||
bool result = true;
|
||||
for (const auto &handler : ProjectFile::getHandlers()) {
|
||||
try {
|
||||
@@ -45,6 +49,10 @@ namespace hex {
|
||||
log::info("{}", e.what());
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result && handler.required) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &provider : ImHexApi::Provider::getProviders()) {
|
||||
@@ -57,12 +65,16 @@ namespace hex {
|
||||
log::info("{}", e.what());
|
||||
result = false;
|
||||
}
|
||||
|
||||
if (!result && handler.required) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ProjectFile::s_currProjectPath = filePath;
|
||||
|
||||
return result;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ProjectFile::store(std::optional<std::fs::path> filePath) {
|
||||
|
||||
@@ -4,57 +4,46 @@
|
||||
#include <hex/helpers/logger.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <ranges>
|
||||
|
||||
namespace hex {
|
||||
|
||||
std::mutex TaskManager::s_deferredCallsMutex;
|
||||
|
||||
std::list<std::shared_ptr<Task>> TaskManager::s_tasks;
|
||||
std::list<std::shared_ptr<Task>> TaskManager::s_tasks, TaskManager::s_taskQueue;
|
||||
std::list<std::function<void()>> TaskManager::s_deferredCalls;
|
||||
|
||||
Task::Task(std::string unlocalizedName, u64 maxValue, std::function<void(Task &)> function)
|
||||
: m_unlocalizedName(std::move(unlocalizedName)), m_currValue(0), m_maxValue(maxValue) {
|
||||
this->m_thread = std::thread([this, func = std::move(function)] {
|
||||
try {
|
||||
func(*this);
|
||||
} catch (const TaskInterruptor &) {
|
||||
this->interruption();
|
||||
} catch (const std::exception &e) {
|
||||
log::error("Exception in task {}: {}", this->m_unlocalizedName, e.what());
|
||||
this->exception(e.what());
|
||||
} catch (...) {
|
||||
log::error("Exception in task {}", this->m_unlocalizedName);
|
||||
this->exception("Unknown Exception");
|
||||
}
|
||||
std::mutex TaskManager::s_queueMutex;
|
||||
std::condition_variable TaskManager::s_jobCondVar;
|
||||
std::vector<std::jthread> TaskManager::s_workers;
|
||||
|
||||
this->finish();
|
||||
});
|
||||
}
|
||||
Task::Task(std::string unlocalizedName, u64 maxValue, bool background, std::function<void(Task &)> function)
|
||||
: m_unlocalizedName(std::move(unlocalizedName)), m_currValue(0), m_maxValue(maxValue), m_function(std::move(function)), m_background(background) { }
|
||||
|
||||
Task::Task(hex::Task &&other) noexcept {
|
||||
std::scoped_lock thisLock(this->m_mutex);
|
||||
std::scoped_lock otherLock(other.m_mutex);
|
||||
{
|
||||
std::scoped_lock thisLock(this->m_mutex);
|
||||
std::scoped_lock otherLock(other.m_mutex);
|
||||
|
||||
this->m_thread = std::move(other.m_thread);
|
||||
this->m_unlocalizedName = std::move(other.m_unlocalizedName);
|
||||
this->m_function = std::move(other.m_function);
|
||||
this->m_unlocalizedName = std::move(other.m_unlocalizedName);
|
||||
}
|
||||
|
||||
this->m_maxValue = other.m_maxValue;
|
||||
this->m_currValue = other.m_currValue;
|
||||
this->m_maxValue = u64(other.m_maxValue);
|
||||
this->m_currValue = u64(other.m_currValue);
|
||||
|
||||
this->m_finished = other.m_finished;
|
||||
this->m_hadException = other.m_hadException;
|
||||
this->m_interrupted = other.m_interrupted;
|
||||
this->m_shouldInterrupt = other.m_shouldInterrupt;
|
||||
this->m_finished = bool(other.m_finished);
|
||||
this->m_hadException = bool(other.m_hadException);
|
||||
this->m_interrupted = bool(other.m_interrupted);
|
||||
this->m_shouldInterrupt = bool(other.m_shouldInterrupt);
|
||||
}
|
||||
|
||||
Task::~Task() {
|
||||
this->interrupt();
|
||||
this->m_thread.join();
|
||||
if (!this->isFinished())
|
||||
this->interrupt();
|
||||
}
|
||||
|
||||
void Task::update(u64 value) {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
this->m_currValue = value;
|
||||
|
||||
if (this->m_shouldInterrupt)
|
||||
@@ -62,39 +51,38 @@ namespace hex {
|
||||
}
|
||||
|
||||
void Task::setMaxValue(u64 value) {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
this->m_maxValue = value;
|
||||
}
|
||||
|
||||
|
||||
void Task::interrupt() {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
this->m_shouldInterrupt = true;
|
||||
|
||||
if (this->m_interruptCallback)
|
||||
this->m_interruptCallback();
|
||||
}
|
||||
|
||||
void Task::setInterruptCallback(std::function<void()> callback) {
|
||||
this->m_interruptCallback = std::move(callback);
|
||||
}
|
||||
|
||||
bool Task::isBackgroundTask() const {
|
||||
return this->m_background;
|
||||
}
|
||||
|
||||
bool Task::isFinished() const {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
return this->m_finished;
|
||||
}
|
||||
|
||||
bool Task::hadException() const {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
return this->m_hadException;
|
||||
}
|
||||
|
||||
bool Task::wasInterrupted() const {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
return this->m_interrupted;
|
||||
}
|
||||
|
||||
void Task::clearException() {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
this->m_hadException = false;
|
||||
}
|
||||
|
||||
@@ -117,14 +105,10 @@ namespace hex {
|
||||
}
|
||||
|
||||
void Task::finish() {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
this->m_finished = true;
|
||||
}
|
||||
|
||||
void Task::interruption() {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
this->m_interrupted = true;
|
||||
}
|
||||
|
||||
@@ -137,30 +121,112 @@ namespace hex {
|
||||
|
||||
|
||||
bool TaskHolder::isRunning() const {
|
||||
return !m_task.expired() && !m_task.lock()->isFinished();
|
||||
if (this->m_task.expired())
|
||||
return false;
|
||||
|
||||
auto task = this->m_task.lock();
|
||||
return !task->isFinished();
|
||||
}
|
||||
|
||||
bool TaskHolder::hadException() const {
|
||||
return m_task.expired() || m_task.lock()->hadException();
|
||||
if (this->m_task.expired())
|
||||
return false;
|
||||
|
||||
auto task = this->m_task.lock();
|
||||
return !task->hadException();
|
||||
}
|
||||
|
||||
bool TaskHolder::wasInterrupted() const {
|
||||
return m_task.expired() || m_task.lock()->wasInterrupted();
|
||||
if (this->m_task.expired())
|
||||
return false;
|
||||
|
||||
auto task = this->m_task.lock();
|
||||
return !task->wasInterrupted();
|
||||
}
|
||||
|
||||
void TaskHolder::interrupt() {
|
||||
if (!this->m_task.expired())
|
||||
this->m_task.lock()->interrupt();
|
||||
if (this->m_task.expired())
|
||||
return;
|
||||
|
||||
auto task = this->m_task.lock();
|
||||
task->interrupt();
|
||||
}
|
||||
|
||||
|
||||
void TaskManager::init() {
|
||||
for (u32 i = 0; i < std::thread::hardware_concurrency(); i++)
|
||||
TaskManager::s_workers.emplace_back(TaskManager::runner);
|
||||
}
|
||||
|
||||
void TaskManager::exit() {
|
||||
for (auto &task : TaskManager::s_tasks)
|
||||
task->interrupt();
|
||||
|
||||
for (auto &thread : TaskManager::s_workers)
|
||||
thread.request_stop();
|
||||
|
||||
s_jobCondVar.notify_all();
|
||||
|
||||
TaskManager::s_workers.clear();
|
||||
}
|
||||
|
||||
void TaskManager::runner(const std::stop_token &stopToken) {
|
||||
std::mutex mutex;
|
||||
while (true) {
|
||||
std::shared_ptr<Task> task;
|
||||
{
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
s_jobCondVar.wait(lock, [&] {
|
||||
return !s_taskQueue.empty() || stopToken.stop_requested();
|
||||
});
|
||||
if (stopToken.stop_requested())
|
||||
break;
|
||||
|
||||
task = std::move(s_taskQueue.front());
|
||||
s_taskQueue.pop_front();
|
||||
}
|
||||
|
||||
try {
|
||||
task->m_function(*task);
|
||||
} catch (const Task::TaskInterruptor &) {
|
||||
task->interruption();
|
||||
} catch (const std::exception &e) {
|
||||
log::error("Exception in task {}: {}", task->m_unlocalizedName, e.what());
|
||||
task->exception(e.what());
|
||||
} catch (...) {
|
||||
log::error("Exception in task {}", task->m_unlocalizedName);
|
||||
task->exception("Unknown Exception");
|
||||
}
|
||||
|
||||
task->finish();
|
||||
}
|
||||
}
|
||||
|
||||
TaskHolder TaskManager::createTask(std::string name, u64 maxValue, std::function<void(Task &)> function) {
|
||||
s_tasks.emplace_back(std::make_shared<Task>(std::move(name), maxValue, std::move(function)));
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
auto task = std::make_shared<Task>(std::move(name), maxValue, false, std::move(function));
|
||||
s_tasks.emplace_back(task);
|
||||
s_taskQueue.emplace_back(task);
|
||||
|
||||
s_jobCondVar.notify_one();
|
||||
|
||||
return TaskHolder(s_tasks.back());
|
||||
}
|
||||
|
||||
TaskHolder TaskManager::createBackgroundTask(std::string name, std::function<void(Task &)> function) {
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
|
||||
auto task = std::make_shared<Task>(std::move(name), 0, true, std::move(function));
|
||||
s_tasks.emplace_back(task);
|
||||
s_taskQueue.emplace_back(task);
|
||||
|
||||
s_jobCondVar.notify_one();
|
||||
|
||||
return TaskHolder(s_tasks.back());
|
||||
}
|
||||
|
||||
void TaskManager::collectGarbage() {
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
std::erase_if(s_tasks, [](const auto &task) { return task->isFinished() && !task->hadException(); });
|
||||
}
|
||||
|
||||
@@ -169,7 +235,11 @@ namespace hex {
|
||||
}
|
||||
|
||||
size_t TaskManager::getRunningTaskCount() {
|
||||
return s_tasks.size();
|
||||
std::unique_lock lock(s_queueMutex);
|
||||
|
||||
return std::count_if(s_tasks.begin(), s_tasks.end(), [](const auto &task){
|
||||
return !task->isBackgroundTask();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
namespace hex::dp {
|
||||
|
||||
u32 Attribute::s_idCounter = 1;
|
||||
int Attribute::s_idCounter = 1;
|
||||
|
||||
Attribute::Attribute(IOType ioType, Type type, std::string unlocalizedName) : m_id(Attribute::s_idCounter++), m_ioType(ioType), m_type(type), m_unlocalizedName(std::move(unlocalizedName)) {
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
|
||||
namespace hex::dp {
|
||||
|
||||
u32 Link::s_idCounter = 1;
|
||||
int Link::s_idCounter = 1;
|
||||
|
||||
Link::Link(u32 from, u32 to) : m_id(Link::s_idCounter++), m_from(from), m_to(to) { }
|
||||
Link::Link(int from, int to) : m_id(Link::s_idCounter++), m_from(from), m_to(to) { }
|
||||
|
||||
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
namespace hex::dp {
|
||||
|
||||
u32 Node::s_idCounter = 1;
|
||||
int Node::s_idCounter = 1;
|
||||
|
||||
Node::Node(std::string unlocalizedTitle, std::vector<Attribute> attributes) : m_id(Node::s_idCounter++), m_unlocalizedTitle(std::move(unlocalizedTitle)), m_attributes(std::move(attributes)) {
|
||||
for (auto &attr : this->m_attributes)
|
||||
|
||||
@@ -17,12 +17,12 @@ namespace hex::fs {
|
||||
this->m_file = _wfopen(path.c_str(), L"w+b");
|
||||
#else
|
||||
if (mode == File::Mode::Read)
|
||||
this->m_file = fopen64(path.string().c_str(), "rb");
|
||||
this->m_file = fopen64(hex::toUTF8String(path).c_str(), "rb");
|
||||
else if (mode == File::Mode::Write)
|
||||
this->m_file = fopen64(path.string().c_str(), "r+b");
|
||||
this->m_file = fopen64(hex::toUTF8String(path).c_str(), "r+b");
|
||||
|
||||
if (mode == File::Mode::Create || (mode == File::Mode::Write && this->m_file == nullptr))
|
||||
this->m_file = fopen64(path.string().c_str(), "w+b");
|
||||
this->m_file = fopen64(hex::toUTF8String(path).c_str(), "w+b");
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace hex::fs {
|
||||
|
||||
bool File::remove() {
|
||||
this->close();
|
||||
return std::remove(this->m_path.string().c_str()) == 0;
|
||||
return std::remove(hex::toUTF8String(this->m_path).c_str()) == 0;
|
||||
}
|
||||
|
||||
void File::disableBuffering() {
|
||||
|
||||
@@ -75,6 +75,11 @@ namespace hex::fs {
|
||||
return result;
|
||||
}
|
||||
|
||||
static std::function<void()> s_fileBrowserErrorCallback;
|
||||
void setFileBrowserErrorCallback(const std::function<void()> &callback) {
|
||||
s_fileBrowserErrorCallback = callback;
|
||||
}
|
||||
|
||||
bool openFileBrowser(DialogMode mode, const std::vector<nfdfilteritem_t> &validExtensions, const std::function<void(std::fs::path)> &callback, const std::string &defaultPath) {
|
||||
NFD::Init();
|
||||
|
||||
@@ -94,9 +99,14 @@ namespace hex::fs {
|
||||
hex::unreachable();
|
||||
}
|
||||
|
||||
if (result == NFD_OKAY && outPath != nullptr) {
|
||||
callback(reinterpret_cast<char8_t*>(outPath));
|
||||
NFD::FreePath(outPath);
|
||||
if (result == NFD_OKAY){
|
||||
if(outPath != nullptr) {
|
||||
callback(reinterpret_cast<char8_t*>(outPath));
|
||||
NFD::FreePath(outPath);
|
||||
}
|
||||
} else if (result==NFD_ERROR) {
|
||||
if (s_fileBrowserErrorCallback != nullptr)
|
||||
s_fileBrowserErrorCallback();
|
||||
}
|
||||
|
||||
NFD::Quit();
|
||||
@@ -184,7 +194,7 @@ namespace hex::fs {
|
||||
path = path / folder;
|
||||
|
||||
return paths;
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<std::fs::path> getPluginPaths() {
|
||||
std::vector<std::fs::path> paths = getDataPaths();
|
||||
@@ -199,6 +209,8 @@ namespace hex::fs {
|
||||
std::vector<std::fs::path> result;
|
||||
|
||||
switch (path) {
|
||||
case ImHexPath::END:
|
||||
return { };
|
||||
case ImHexPath::Constants:
|
||||
result = appendPath(getDataPaths(), "constants");
|
||||
break;
|
||||
@@ -235,6 +247,12 @@ namespace hex::fs {
|
||||
case ImHexPath::Recent:
|
||||
result = appendPath(getConfigPaths(), "recent");
|
||||
break;
|
||||
case ImHexPath::Scripts:
|
||||
result = appendPath(getDataPaths(), "scripts");
|
||||
break;
|
||||
case ImHexPath::Inspectors:
|
||||
result = appendPath(getDefaultPaths(ImHexPath::Scripts), "inspectors");
|
||||
break;
|
||||
}
|
||||
|
||||
if (!listNonExisting) {
|
||||
|
||||
@@ -27,7 +27,7 @@ namespace hex::magic {
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Magic)) {
|
||||
for (const auto &entry : std::fs::directory_iterator(dir, error)) {
|
||||
if (entry.is_regular_file() && ((sourceFiles && entry.path().extension().empty()) || (!sourceFiles && entry.path().extension() == ".mgc"))) {
|
||||
magicFiles += fs::toShortPath(entry.path()).string() + MAGIC_PATH_SEPARATOR;
|
||||
magicFiles += hex::toUTF8String(fs::toShortPath(entry.path())) + MAGIC_PATH_SEPARATOR;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,6 @@
|
||||
#include <filesystem>
|
||||
#include <cstdio>
|
||||
|
||||
#include <mbedtls/ssl.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
@@ -52,13 +50,13 @@ namespace hex {
|
||||
|
||||
auto *cfg = static_cast<mbedtls_ssl_config *>(sslctx);
|
||||
|
||||
static mbedtls_x509_crt crt;
|
||||
mbedtls_x509_crt_init(&crt);
|
||||
auto crt = static_cast<mbedtls_x509_crt*>(userData);
|
||||
mbedtls_x509_crt_init(crt);
|
||||
|
||||
auto cacert = romfs::get("cacert.pem").string();
|
||||
mbedtls_x509_crt_parse(&crt, reinterpret_cast<const u8 *>(cacert.data()), cacert.size());
|
||||
mbedtls_x509_crt_parse(crt, reinterpret_cast<const u8 *>(cacert.data()), cacert.size());
|
||||
|
||||
mbedtls_ssl_conf_ca_chain(cfg, &crt, nullptr);
|
||||
mbedtls_ssl_conf_ca_chain(cfg, crt, nullptr);
|
||||
|
||||
return CURLE_OK;
|
||||
}
|
||||
@@ -114,6 +112,7 @@ namespace hex {
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_CAPATH, nullptr);
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_SSLCERTTYPE, "PEM");
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_FUNCTION, sslCtxFunction);
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_SSL_CTX_DATA, &this->m_caCert);
|
||||
#endif
|
||||
|
||||
curl_easy_setopt(this->m_ctx, CURLOPT_PROXY, Net::s_proxyUrl.c_str());
|
||||
@@ -189,16 +188,27 @@ namespace hex {
|
||||
curl_mime *mime = curl_mime_init(this->m_ctx);
|
||||
curl_mimepart *part = curl_mime_addpart(mime);
|
||||
|
||||
auto fileName = filePath.filename().string();
|
||||
curl_mime_data_cb(
|
||||
part, file.getSize(), [](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
|
||||
auto fileName = hex::toUTF8String(filePath.filename());
|
||||
curl_mime_data_cb(part, file.getSize(),
|
||||
[](char *buffer, size_t size, size_t nitems, void *arg) -> size_t {
|
||||
auto file = static_cast<FILE*>(arg);
|
||||
return fread(buffer, size, nitems, file); }, [](void *arg, curl_off_t offset, int origin) -> int {
|
||||
|
||||
return fread(buffer, size, nitems, file);
|
||||
},
|
||||
[](void *arg, curl_off_t offset, int origin) -> int {
|
||||
auto file = static_cast<FILE*>(arg);
|
||||
fseek(file, offset, origin);
|
||||
return CURL_SEEKFUNC_OK; }, [](void *arg) {
|
||||
|
||||
if (fseek(file, offset, origin) != 0)
|
||||
return CURL_SEEKFUNC_CANTSEEK;
|
||||
else
|
||||
return CURL_SEEKFUNC_OK;
|
||||
},
|
||||
[](void *arg) {
|
||||
auto file = static_cast<FILE*>(arg);
|
||||
fclose(file); }, file.getHandle());
|
||||
|
||||
fclose(file);
|
||||
},
|
||||
file.getHandle());
|
||||
curl_mime_filename(part, fileName.c_str());
|
||||
curl_mime_name(part, "file");
|
||||
|
||||
|
||||
@@ -22,11 +22,11 @@
|
||||
|
||||
namespace hex {
|
||||
|
||||
long double operator""_scaled(long double value) {
|
||||
float operator""_scaled(long double value) {
|
||||
return value * ImHexApi::System::getGlobalScale();
|
||||
}
|
||||
|
||||
long double operator""_scaled(unsigned long long value) {
|
||||
float operator""_scaled(unsigned long long value) {
|
||||
return value * ImHexApi::System::getGlobalScale();
|
||||
}
|
||||
|
||||
@@ -233,7 +233,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
std::string toEngineeringString(double value) {
|
||||
constexpr std::array Suffixes = { "a", "f", "p", "n", "u", "m", "", "k", "M", "G", "T", "P", "E" };
|
||||
constexpr static std::array Suffixes = { "a", "f", "p", "n", "u", "m", "", "k", "M", "G", "T", "P", "E" };
|
||||
|
||||
int8_t suffixIndex = 6;
|
||||
|
||||
@@ -339,7 +339,7 @@ namespace hex {
|
||||
auto c = [&] { return string[offset]; };
|
||||
|
||||
if (c() == '\\') {
|
||||
if ((offset + 2) >= string.length()) return {};
|
||||
if ((offset + 2) > string.length()) return {};
|
||||
|
||||
offset++;
|
||||
|
||||
|
||||
@@ -113,6 +113,8 @@ namespace hex::prv {
|
||||
this->writeRaw(patchAddress - this->getBaseAddress(), &patch, 1);
|
||||
}
|
||||
this->markDirty();
|
||||
|
||||
this->m_patches.emplace_back();
|
||||
}
|
||||
|
||||
|
||||
@@ -170,14 +172,6 @@ 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();
|
||||
@@ -296,4 +290,15 @@ namespace hex::prv {
|
||||
return { Region { address, *nextRegionAddress - address }, insideValidRegion };
|
||||
}
|
||||
|
||||
|
||||
u32 Provider::getID() const {
|
||||
return this->m_id;
|
||||
}
|
||||
|
||||
void Provider::setID(u32 id) {
|
||||
this->m_id = id;
|
||||
if (id > s_idCounter)
|
||||
s_idCounter = id + 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_freetype.h>
|
||||
#define IMGUI_DEFINE_MATH_OPERATORS
|
||||
#include <imgui_internal.h>
|
||||
#undef IMGUI_DEFINE_MATH_OPERATORS
|
||||
@@ -17,6 +16,76 @@
|
||||
|
||||
namespace ImGui {
|
||||
|
||||
Texture::Texture(const ImU8 *buffer, int size) {
|
||||
unsigned char *imageData = stbi_load_from_memory(buffer, size, &this->m_width, &this->m_height, nullptr, 4);
|
||||
if (imageData == nullptr)
|
||||
return;
|
||||
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
#if defined(GL_UNPACK_ROW_LENGTH)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->m_width, this->m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
|
||||
stbi_image_free(imageData);
|
||||
|
||||
this->m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
|
||||
}
|
||||
|
||||
Texture::Texture(const char *path) {
|
||||
unsigned char *imageData = stbi_load(path, &this->m_width, &this->m_height, nullptr, 4);
|
||||
if (imageData == nullptr)
|
||||
return;
|
||||
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
#if defined(GL_UNPACK_ROW_LENGTH)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, this->m_width, this->m_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
|
||||
stbi_image_free(imageData);
|
||||
|
||||
this->m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
|
||||
}
|
||||
|
||||
Texture::Texture(Texture&& other) noexcept {
|
||||
this->m_textureId = other.m_textureId;
|
||||
this->m_width = other.m_width;
|
||||
this->m_height = other.m_height;
|
||||
|
||||
other.m_textureId = nullptr;
|
||||
}
|
||||
|
||||
Texture& Texture::operator=(Texture&& other) noexcept {
|
||||
this->m_textureId = other.m_textureId;
|
||||
this->m_width = other.m_width;
|
||||
this->m_height = other.m_height;
|
||||
|
||||
other.m_textureId = nullptr;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Texture::~Texture() {
|
||||
if (this->m_textureId == nullptr)
|
||||
return;
|
||||
|
||||
auto glTextureId = static_cast<GLuint>(reinterpret_cast<intptr_t>(this->m_textureId));
|
||||
glDeleteTextures(1, &glTextureId);
|
||||
}
|
||||
|
||||
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data) {
|
||||
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
|
||||
auto &string = *static_cast<std::string *>(data->UserData);
|
||||
@@ -35,8 +104,8 @@ namespace ImGui {
|
||||
|
||||
ImGuiContext &g = *GImGui;
|
||||
const ImGuiID id = window->GetID(label);
|
||||
ImVec2 label_size = CalcTextSize(icon, NULL, false);
|
||||
label_size.x += CalcTextSize(" ", NULL, false).x + CalcTextSize(label, NULL, false).x;
|
||||
ImVec2 label_size = CalcTextSize(icon, nullptr, false);
|
||||
label_size.x += CalcTextSize(" ", nullptr, false).x + CalcTextSize(label, nullptr, false).x;
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
|
||||
@@ -69,7 +138,7 @@ namespace ImGui {
|
||||
|
||||
ImGuiContext &g = *GImGui;
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
|
||||
@@ -86,7 +155,7 @@ namespace ImGui {
|
||||
// Render
|
||||
const ImU32 col = hovered ? GetColorU32(ImGuiCol_ButtonHovered) : GetColorU32(ImGuiCol_ButtonActive);
|
||||
PushStyleColor(ImGuiCol_Text, ImU32(col));
|
||||
TextEx(label, NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
|
||||
TextEx(label, nullptr, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
|
||||
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(col));
|
||||
PopStyleColor();
|
||||
|
||||
@@ -102,7 +171,7 @@ namespace ImGui {
|
||||
ImGuiContext &g = *GImGui;
|
||||
const ImGuiStyle &style = g.Style;
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y) + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0f);
|
||||
@@ -137,8 +206,8 @@ namespace ImGui {
|
||||
ImGuiContext &g = *GImGui;
|
||||
const ImGuiStyle &style = g.Style;
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const ImVec2 text_size = CalcTextSize((std::string(label) + "\n " + std::string(description)).c_str(), NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
const ImVec2 text_size = CalcTextSize((std::string(label) + "\n " + std::string(description)).c_str(), nullptr, true);
|
||||
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
|
||||
@@ -166,7 +235,7 @@ namespace ImGui {
|
||||
RenderTextWrapped(bb.Min + style.FramePadding * 2, label, nullptr, CalcWrapWidthForPos(window->DC.CursorPos, window->DC.TextWrapPos));
|
||||
PopStyleColor();
|
||||
PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_Text));
|
||||
RenderTextClipped(bb.Min + style.FramePadding * 2 + ImVec2(style.FramePadding.x * 2, label_size.y), bb.Max - style.FramePadding, description, NULL, &text_size, style.ButtonTextAlign, &bb);
|
||||
RenderTextClipped(bb.Min + style.FramePadding * 2 + ImVec2(style.FramePadding.x * 2, label_size.y), bb.Max - style.FramePadding, description, nullptr, &text_size, style.ButtonTextAlign, &bb);
|
||||
PopStyleColor();
|
||||
|
||||
ImGui::PopStyleVar();
|
||||
@@ -182,13 +251,13 @@ namespace ImGui {
|
||||
void UnderlinedText(const char *label, ImColor color, const ImVec2 &size_arg) {
|
||||
ImGuiWindow *window = GetCurrentWindow();
|
||||
|
||||
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
|
||||
|
||||
PushStyleColor(ImGuiCol_Text, ImU32(color));
|
||||
TextEx(label, NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
|
||||
TextEx(label, nullptr, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
|
||||
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(color));
|
||||
PopStyleColor();
|
||||
}
|
||||
@@ -298,66 +367,6 @@ namespace ImGui {
|
||||
colors[ImGuiCustomCol_Highlight] = ImColor(77, 198, 155);
|
||||
}
|
||||
|
||||
Texture LoadImageFromPath(const char *path) {
|
||||
int imageWidth = 0;
|
||||
int imageHeight = 0;
|
||||
|
||||
unsigned char *imageData = stbi_load(path, &imageWidth, &imageHeight, nullptr, 4);
|
||||
if (imageData == nullptr)
|
||||
return { nullptr, -1, -1 };
|
||||
|
||||
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
#if defined(GL_UNPACK_ROW_LENGTH)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
|
||||
stbi_image_free(imageData);
|
||||
|
||||
return { reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture)), imageWidth, imageHeight };
|
||||
}
|
||||
|
||||
Texture LoadImageFromMemory(const ImU8 *buffer, int size) {
|
||||
int imageWidth = 0;
|
||||
int imageHeight = 0;
|
||||
|
||||
|
||||
unsigned char *imageData = stbi_load_from_memory(buffer, size, &imageWidth, &imageHeight, nullptr, 4);
|
||||
if (imageData == nullptr)
|
||||
return { nullptr, -1, -1 };
|
||||
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
|
||||
#if defined(GL_UNPACK_ROW_LENGTH)
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
#endif
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageWidth, imageHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
|
||||
stbi_image_free(imageData);
|
||||
|
||||
return { reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture)), imageWidth, imageHeight };
|
||||
}
|
||||
|
||||
void UnloadImage(Texture &texture) {
|
||||
if (texture.textureId == nullptr)
|
||||
return;
|
||||
|
||||
auto glTextureId = static_cast<GLuint>(reinterpret_cast<intptr_t>(texture.textureId));
|
||||
glDeleteTextures(1, &glTextureId);
|
||||
|
||||
texture = { nullptr, 0, 0 };
|
||||
}
|
||||
|
||||
void OpenPopupInWindow(const char *window_name, const char *popup_name) {
|
||||
if (ImGui::Begin(window_name)) {
|
||||
ImGui::OpenPopup(popup_name);
|
||||
@@ -374,7 +383,7 @@ namespace ImGui {
|
||||
ImGuiContext &g = *GImGui;
|
||||
const ImGuiStyle &style = g.Style;
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
|
||||
@@ -393,7 +402,7 @@ namespace ImGui {
|
||||
: ImGuiCol_Button);
|
||||
RenderNavHighlight(bb, id);
|
||||
RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
|
||||
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);
|
||||
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, label, nullptr, &label_size, style.ButtonTextAlign, &bb);
|
||||
|
||||
// Automatically close popups
|
||||
// if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
|
||||
@@ -413,7 +422,7 @@ namespace ImGui {
|
||||
ImGuiContext &g = *GImGui;
|
||||
const ImGuiStyle &style = g.Style;
|
||||
const ImGuiID id = window->GetID(symbol);
|
||||
const ImVec2 label_size = CalcTextSize(symbol, NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(symbol, nullptr, true);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
|
||||
@@ -434,7 +443,7 @@ namespace ImGui {
|
||||
: ImGuiCol_MenuBarBg);
|
||||
RenderNavHighlight(bb, id);
|
||||
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
|
||||
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, NULL, &label_size, style.ButtonTextAlign, &bb);
|
||||
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
|
||||
|
||||
PopStyleColor();
|
||||
|
||||
@@ -456,7 +465,7 @@ namespace ImGui {
|
||||
ImGuiContext &g = *GImGui;
|
||||
const ImGuiStyle &style = g.Style;
|
||||
const ImGuiID id = window->GetID(symbol);
|
||||
const ImVec2 label_size = CalcTextSize(symbol, NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(symbol, nullptr, true);
|
||||
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
|
||||
@@ -477,7 +486,7 @@ namespace ImGui {
|
||||
: ImGuiCol_Button);
|
||||
RenderNavHighlight(bb, id);
|
||||
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
|
||||
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, NULL, &label_size, style.ButtonTextAlign, &bb);
|
||||
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1, 2), bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
|
||||
|
||||
PopStyleColor();
|
||||
|
||||
@@ -555,6 +564,33 @@ namespace ImGui {
|
||||
return ImGui::InputText(label, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
|
||||
}
|
||||
|
||||
bool InputTextIcon(const char *label, const char *icon, std::string &buffer, ImGuiInputTextFlags flags) {
|
||||
auto window = ImGui::GetCurrentWindow();
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const ImGuiStyle &style = GImGui->Style;
|
||||
|
||||
|
||||
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
|
||||
const ImVec2 icon_frame_size = CalcTextSize(icon) + style.FramePadding * 2.0f;
|
||||
const ImVec2 frame_size = CalcItemSize(ImVec2(0, 0), icon_frame_size.x, label_size.y + style.FramePadding.y * 2.0f);
|
||||
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
|
||||
|
||||
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + frame_size.x);
|
||||
|
||||
bool value_changed = ImGui::InputTextEx(label, nullptr, buffer.data(), buffer.size() + 1, ImVec2(CalcItemWidth() - frame_size.x, label_size.y + style.FramePadding.y * 2.0f), ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
|
||||
|
||||
if (value_changed)
|
||||
MarkItemEdited(GImGui->LastItemData.ID);
|
||||
|
||||
RenderNavHighlight(frame_bb, id);
|
||||
RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
|
||||
|
||||
RenderFrame(frame_bb.Min, frame_bb.Min + icon_frame_size, GetColorU32(ImGuiCol_TableBorderStrong), true, style.FrameRounding);
|
||||
RenderText(ImVec2(frame_bb.Min.x + style.FramePadding.x, frame_bb.Min.y + style.FramePadding.y * 2), icon);
|
||||
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
bool InputTextWithHint(const char *label, const char *hint, std::string &buffer, ImGuiInputTextFlags flags) {
|
||||
return ImGui::InputTextWithHint(label, hint, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGui::UpdateStringSizeCallback, &buffer);
|
||||
}
|
||||
@@ -574,7 +610,7 @@ namespace ImGui {
|
||||
|
||||
ImGuiContext& g = *GImGui;
|
||||
|
||||
if (format == NULL)
|
||||
if (format == nullptr)
|
||||
format = DataTypeGetInfo(data_type)->PrintFmt;
|
||||
|
||||
char buf[64];
|
||||
@@ -613,7 +649,7 @@ namespace ImGui {
|
||||
ImGuiContext& g = *GImGui;
|
||||
const ImGuiStyle& style = g.Style;
|
||||
const ImGuiID id = window->GetID(label);
|
||||
const ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
|
||||
|
||||
const ImVec2 size = ImVec2(CalcTextSize("0").x + style.FramePadding.x * 2, GetFrameHeight());
|
||||
const ImVec2 pos = window->DC.CursorPos;
|
||||
|
||||
@@ -26,9 +26,9 @@ set_target_properties(main PROPERTIES
|
||||
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||
|
||||
if (WIN32)
|
||||
target_link_libraries(main PUBLIC usp10 libimhex wsock32 ws2_32 Dwmapi.lib)
|
||||
target_link_libraries(main PRIVATE usp10 libimhex libromfs-imhex wsock32 ws2_32 Dwmapi.lib)
|
||||
else ()
|
||||
target_link_libraries(main PUBLIC libimhex pthread)
|
||||
target_link_libraries(main PRIVATE libimhex libromfs-imhex pthread)
|
||||
endif ()
|
||||
|
||||
if (APPLE)
|
||||
|
||||
@@ -19,14 +19,14 @@ namespace hex::init {
|
||||
|
||||
bool loop();
|
||||
|
||||
void addStartupTask(const std::string &taskName, const TaskFunction &task) {
|
||||
this->m_tasks.emplace_back(taskName, task);
|
||||
void addStartupTask(const std::string &taskName, const TaskFunction &task, bool async) {
|
||||
this->m_tasks.emplace_back(taskName, task, async);
|
||||
}
|
||||
|
||||
private:
|
||||
GLFWwindow *m_window;
|
||||
std::mutex m_progressMutex;
|
||||
float m_progress = 0;
|
||||
std::atomic<float> m_progress = 0;
|
||||
std::string m_currTaskName;
|
||||
|
||||
void initGLFW();
|
||||
@@ -37,7 +37,7 @@ namespace hex::init {
|
||||
|
||||
std::future<bool> processTasksAsync();
|
||||
|
||||
std::vector<std::pair<std::string, TaskFunction>> m_tasks;
|
||||
std::vector<std::tuple<std::string, TaskFunction, bool>> m_tasks;
|
||||
|
||||
std::string m_gpuVendor;
|
||||
};
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace hex::init {
|
||||
struct Task {
|
||||
std::string name;
|
||||
std::function<bool()> function;
|
||||
bool async;
|
||||
};
|
||||
|
||||
std::vector<Task> getInitTasks();
|
||||
|
||||
@@ -50,8 +50,9 @@ namespace hex {
|
||||
|
||||
double m_lastFrameTime = 0;
|
||||
|
||||
ImGui::Texture m_logoTexture = { nullptr };
|
||||
ImGui::Texture m_logoTexture;
|
||||
|
||||
std::mutex m_popupMutex;
|
||||
std::list<std::string> m_popupsToOpen;
|
||||
std::vector<int> m_pressedKeys;
|
||||
|
||||
|
||||
@@ -43,28 +43,41 @@ namespace hex::init {
|
||||
return std::async(std::launch::async, [this] {
|
||||
bool status = true;
|
||||
|
||||
for (const auto &[name, task] : this->m_tasks) {
|
||||
{
|
||||
std::lock_guard guard(this->m_progressMutex);
|
||||
this->m_currTaskName = name;
|
||||
}
|
||||
std::atomic<u32> tasksCompleted = 0;
|
||||
for (const auto &[name, task, async] : this->m_tasks) {
|
||||
auto runTask = [&, task = task, name = name] {
|
||||
{
|
||||
std::lock_guard guard(this->m_progressMutex);
|
||||
this->m_currTaskName = name;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!task())
|
||||
status = false;
|
||||
|
||||
tasksCompleted++;
|
||||
|
||||
this->m_progress = float(tasksCompleted) / this->m_tasks.size();
|
||||
};
|
||||
|
||||
try {
|
||||
if (async) {
|
||||
TaskManager::createBackgroundTask(name, [runTask](auto&){ runTask(); });
|
||||
} else {
|
||||
runTask();
|
||||
}
|
||||
|
||||
} catch (std::exception &e) {
|
||||
log::error("Init task '{}' threw an exception: {}", name, e.what());
|
||||
status = false;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::lock_guard guard(this->m_progressMutex);
|
||||
this->m_progress += 1.0F / this->m_tasks.size();
|
||||
}
|
||||
while (tasksCompleted < this->m_tasks.size()) {
|
||||
std::this_thread::sleep_for(100ms);
|
||||
}
|
||||
|
||||
// Small extra delay so the last progress step is visible
|
||||
std::this_thread::sleep_for(200ms);
|
||||
std::this_thread::sleep_for(100ms);
|
||||
|
||||
return status;
|
||||
});
|
||||
@@ -72,15 +85,13 @@ namespace hex::init {
|
||||
|
||||
bool WindowSplash::loop() {
|
||||
auto splash = romfs::get("splash.png");
|
||||
ImGui::Texture splashTexture = ImGui::LoadImageFromMemory(reinterpret_cast<const ImU8 *>(splash.data()), splash.size());
|
||||
ImGui::Texture splashTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(splash.data()), splash.size());
|
||||
|
||||
if (splashTexture == nullptr) {
|
||||
if (!splashTexture.isValid()) {
|
||||
log::fatal("Could not load splash screen image!");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
ON_SCOPE_EXIT { ImGui::UnloadImage(splashTexture); };
|
||||
|
||||
auto tasksSucceeded = processTasksAsync();
|
||||
|
||||
auto scale = ImHexApi::System::getGlobalScale();
|
||||
@@ -97,7 +108,7 @@ namespace hex::init {
|
||||
|
||||
auto drawList = ImGui::GetForegroundDrawList();
|
||||
|
||||
drawList->AddImage(splashTexture, ImVec2(0, 0), splashTexture.size() * scale);
|
||||
drawList->AddImage(splashTexture, ImVec2(0, 0), splashTexture.getSize() * scale);
|
||||
|
||||
drawList->AddText(ImVec2(15, 120) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("WerWolv 2020 - {0}", &__DATE__[7]).c_str());
|
||||
|
||||
@@ -107,15 +118,15 @@ namespace hex::init {
|
||||
drawList->AddText(ImVec2(15, 140) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("{0}", IMHEX_VERSION).c_str());
|
||||
#endif
|
||||
|
||||
drawList->AddRectFilled(ImVec2(0, splashTexture.size().y - 5) * scale, ImVec2(splashTexture.size().x * this->m_progress, splashTexture.size().y) * scale, 0xFFFFFFFF);
|
||||
drawList->AddText(ImVec2(15, splashTexture.size().y - 25) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("[{}] {}", "|/-\\"[ImU32(ImGui::GetTime() * 15) % 4], this->m_currTaskName).c_str());
|
||||
drawList->AddRectFilled(ImVec2(0, splashTexture.getSize().y - 5) * scale, ImVec2(splashTexture.getSize().x * this->m_progress, splashTexture.getSize().y) * scale, 0xFFFFFFFF);
|
||||
drawList->AddText(ImVec2(15, splashTexture.getSize().y - 25) * scale, ImColor(0xFF, 0xFF, 0xFF, 0xFF), hex::format("[{}] {}", "|/-\\"[ImU32(ImGui::GetTime() * 15) % 4], this->m_currTaskName).c_str());
|
||||
}
|
||||
|
||||
ImGui::Render();
|
||||
int display_w, display_h;
|
||||
glfwGetFramebufferSize(this->m_window, &display_w, &display_h);
|
||||
glViewport(0, 0, display_w, display_h);
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClearColor(0.00F, 0.00F, 0.00F, 0.00F);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace hex::init {
|
||||
auto latestVersion = releases.body["tag_name"].get<std::string_view>();
|
||||
|
||||
if (latestVersion != currVersion)
|
||||
ImHexApi::System::getInitArguments().insert({ "update-available", latestVersion.data() });
|
||||
ImHexApi::System::impl::addInitArgument("update-available", latestVersion.data());
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -52,7 +52,7 @@ namespace hex::init {
|
||||
if (tip.code != 200)
|
||||
return false;
|
||||
|
||||
ImHexApi::System::getInitArguments().insert({ "tip-of-the-day", tip.body });
|
||||
ImHexApi::System::impl::addInitArgument("tip-of-the-day", tip.body);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -61,20 +61,6 @@ namespace hex::init {
|
||||
bool result = true;
|
||||
|
||||
using enum fs::ImHexPath;
|
||||
constexpr std::array paths = {
|
||||
Patterns,
|
||||
PatternsInclude,
|
||||
Magic,
|
||||
Plugins,
|
||||
Resources,
|
||||
Config,
|
||||
Constants,
|
||||
Yara,
|
||||
Encodings,
|
||||
Python,
|
||||
Logs,
|
||||
Recent
|
||||
};
|
||||
|
||||
// Check if ImHex is installed in portable mode
|
||||
{
|
||||
@@ -87,19 +73,19 @@ namespace hex::init {
|
||||
}
|
||||
|
||||
// Create all folders
|
||||
for (auto path : paths) {
|
||||
for (auto &folder : fs::getDefaultPaths(path, true)) {
|
||||
for (u32 path = 0; path < u32(fs::ImHexPath::END); path++) {
|
||||
for (auto &folder : fs::getDefaultPaths(static_cast<fs::ImHexPath>(path), true)) {
|
||||
try {
|
||||
fs::createDirectories(folder);
|
||||
} catch (...) {
|
||||
log::error("Failed to create folder {}!", folder.string());
|
||||
log::error("Failed to create folder {}!", hex::toUTF8String(folder));
|
||||
result = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!result)
|
||||
ImHexApi::System::getInitArguments().insert({ "folder-creation-error", {} });
|
||||
ImHexApi::System::impl::addInitArgument("folder-creation-error");
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -133,7 +119,7 @@ namespace hex::init {
|
||||
0x0100, 0xFFF0, 0
|
||||
};
|
||||
|
||||
auto fontFile = ImHexApi::System::getCustomFontPath();
|
||||
const auto &fontFile = ImHexApi::System::getCustomFontPath();
|
||||
float fontSize = ImHexApi::System::getFontSize();
|
||||
if (fontFile.empty()) {
|
||||
// Load default font if no custom one has been specified
|
||||
@@ -149,7 +135,7 @@ namespace hex::init {
|
||||
cfg.OversampleH = cfg.OversampleV = 1, cfg.PixelSnapH = true;
|
||||
cfg.SizePixels = fontSize;
|
||||
|
||||
fonts->AddFontFromFileTTF(fontFile.string().c_str(), std::floor(fontSize), &cfg, ranges.Data); // Needs conversion to char for Windows
|
||||
fonts->AddFontFromFileTTF(hex::toUTF8String(fontFile).c_str(), std::floor(fontSize), &cfg, ranges.Data); // Needs conversion to char for Windows
|
||||
}
|
||||
|
||||
cfg.MergeMode = true;
|
||||
@@ -233,6 +219,8 @@ namespace hex::init {
|
||||
ProjectFile::getHandlers().clear();
|
||||
ProjectFile::getProviderHandlers().clear();
|
||||
|
||||
fs::setFileBrowserErrorCallback(nullptr);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -246,7 +234,7 @@ namespace hex::init {
|
||||
if (plugins.empty()) {
|
||||
log::error("No plugins found!");
|
||||
|
||||
ImHexApi::System::getInitArguments().insert({ "no-plugins", {} });
|
||||
ImHexApi::System::impl::addInitArgument("no-plugins");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -258,7 +246,7 @@ namespace hex::init {
|
||||
if (builtinPlugins > 1) continue;
|
||||
|
||||
if (!plugin.initializePlugin()) {
|
||||
log::error("Failed to initialize plugin {}", plugin.getPath().filename().string());
|
||||
log::error("Failed to initialize plugin {}", hex::toUTF8String(plugin.getPath().filename()));
|
||||
loadErrors++;
|
||||
}
|
||||
}
|
||||
@@ -267,24 +255,24 @@ namespace hex::init {
|
||||
if (plugin.isBuiltinPlugin()) continue;
|
||||
|
||||
if (!plugin.initializePlugin()) {
|
||||
log::error("Failed to initialize plugin {}", plugin.getPath().filename().string());
|
||||
log::error("Failed to initialize plugin {}", hex::toUTF8String(plugin.getPath().filename()));
|
||||
loadErrors++;
|
||||
}
|
||||
}
|
||||
|
||||
if (loadErrors == plugins.size()) {
|
||||
log::error("No plugins loaded successfully!");
|
||||
ImHexApi::System::getInitArguments().insert({ "no-plugins", {} });
|
||||
ImHexApi::System::impl::addInitArgument("no-plugins");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (builtinPlugins == 0) {
|
||||
log::error("Built-in plugin not found!");
|
||||
ImHexApi::System::getInitArguments().insert({ "no-builtin-plugin", {} });
|
||||
ImHexApi::System::impl::addInitArgument("no-builtin-plugin");
|
||||
return false;
|
||||
} else if (builtinPlugins > 1) {
|
||||
log::error("Found more than one built-in plugin!");
|
||||
ImHexApi::System::getInitArguments().insert({ "multiple-builtin-plugins", {} });
|
||||
ImHexApi::System::impl::addInitArgument("multiple-builtin-plugins");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -324,20 +312,20 @@ namespace hex::init {
|
||||
|
||||
std::vector<Task> getInitTasks() {
|
||||
return {
|
||||
{"Checking for updates...", checkForUpdates },
|
||||
{ "Downloading information...", downloadInformation},
|
||||
{ "Creating directories...", createDirectories },
|
||||
{ "Loading settings...", loadSettings },
|
||||
{ "Loading plugins...", loadPlugins },
|
||||
{ "Loading fonts...", loadFonts },
|
||||
{ "Creating directories...", createDirectories, false },
|
||||
{ "Loading settings...", loadSettings, false },
|
||||
{ "Loading plugins...", loadPlugins, false },
|
||||
{ "Checking for updates...", checkForUpdates, true },
|
||||
{ "Downloading information...", downloadInformation, true },
|
||||
{ "Loading fonts...", loadFonts, true },
|
||||
};
|
||||
}
|
||||
|
||||
std::vector<Task> getExitTasks() {
|
||||
return {
|
||||
{"Saving settings...", storeSettings },
|
||||
{ "Cleaning up shared data...", deleteSharedData},
|
||||
{ "Unloading plugins...", unloadPlugins },
|
||||
{ "Saving settings...", storeSettings, false },
|
||||
{ "Cleaning up shared data...", deleteSharedData, false },
|
||||
{ "Unloading plugins...", unloadPlugins, false },
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -20,9 +20,8 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
bool shouldRestart = false;
|
||||
|
||||
EventManager::subscribe<RequestRestartImHex>([&]{ shouldRestart = true; });
|
||||
|
||||
do {
|
||||
EventManager::subscribe<RequestRestartImHex>([&]{ shouldRestart = true; });
|
||||
shouldRestart = false;
|
||||
|
||||
// Initialization
|
||||
@@ -33,8 +32,9 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
init::WindowSplash splashWindow;
|
||||
|
||||
for (const auto &[name, task] : init::getInitTasks())
|
||||
splashWindow.addStartupTask(name, task);
|
||||
TaskManager::init();
|
||||
for (const auto &[name, task, async] : init::getInitTasks())
|
||||
splashWindow.addStartupTask(name, task, async);
|
||||
|
||||
if (!splashWindow.loop())
|
||||
ImHexApi::System::getInitArguments().insert({ "tasks-failed", {} });
|
||||
@@ -42,8 +42,9 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
// Clean up
|
||||
ON_SCOPE_EXIT {
|
||||
for (const auto &[name, task] : init::getExitTasks())
|
||||
for (const auto &[name, task, async] : init::getExitTasks())
|
||||
task();
|
||||
TaskManager::exit();
|
||||
};
|
||||
|
||||
// Main window
|
||||
@@ -52,14 +53,22 @@ int main(int argc, char **argv, char **envp) {
|
||||
|
||||
if (argc == 1)
|
||||
; // No arguments provided
|
||||
else if (argc == 2)
|
||||
EventManager::post<RequestOpenFile>(argv[1]);
|
||||
else {
|
||||
hex::log::fatal("Usage: {} [<file_name>]", argv[0]);
|
||||
return EXIT_FAILURE;
|
||||
else if (argc >= 2) {
|
||||
for (auto i = 1; i < argc; i++) {
|
||||
if (auto argument = ImHexApi::System::getProgramArgument(i); argument.has_value())
|
||||
EventManager::post<RequestOpenFile>(argument.value());
|
||||
}
|
||||
}
|
||||
|
||||
window.loop();
|
||||
try {
|
||||
window.loop();
|
||||
} catch (const std::exception &e) {
|
||||
log::fatal("Exception thrown in main loop: {}", e.what());
|
||||
throw;
|
||||
} catch (...) {
|
||||
log::fatal("Unknown exception thrown in main loop!");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
} while (shouldRestart);
|
||||
|
||||
@@ -32,7 +32,39 @@ namespace hex {
|
||||
static float g_titleBarHeight;
|
||||
static ImGuiMouseCursor g_mouseCursorIcon;
|
||||
|
||||
static LRESULT windowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
static LRESULT commonWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (uMsg) {
|
||||
case WM_COPYDATA:
|
||||
{
|
||||
auto message = reinterpret_cast<COPYDATASTRUCT *>(lParam);
|
||||
if (message == nullptr) break;
|
||||
|
||||
auto data = reinterpret_cast<const char8_t *>(message->lpData);
|
||||
if (data == nullptr) break;
|
||||
|
||||
std::fs::path path = data;
|
||||
log::info("Opening file in existing instance: {}", hex::toUTF8String(path));
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
break;
|
||||
}
|
||||
case WM_SETTINGCHANGE:
|
||||
{
|
||||
if (lParam == 0) break;
|
||||
|
||||
if (LPCTSTR(lParam) == std::string_view("ImmersiveColorSet")) {
|
||||
EventManager::post<EventOSThemeChanged>();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CallWindowProc((WNDPROC)g_oldWndProc, hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
static LRESULT borderlessWindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (uMsg) {
|
||||
case WM_NCACTIVATE:
|
||||
case WM_NCPAINT:
|
||||
@@ -106,11 +138,11 @@ namespace hex {
|
||||
return HTNOWHERE;
|
||||
}
|
||||
|
||||
constexpr auto RegionClient = 0b0000;
|
||||
constexpr auto RegionLeft = 0b0001;
|
||||
constexpr auto RegionRight = 0b0010;
|
||||
constexpr auto RegionTop = 0b0100;
|
||||
constexpr auto RegionBottom = 0b1000;
|
||||
constexpr static auto RegionClient = 0b0000;
|
||||
constexpr static auto RegionLeft = 0b0001;
|
||||
constexpr static auto RegionRight = 0b0010;
|
||||
constexpr static auto RegionTop = 0b0100;
|
||||
constexpr static auto RegionBottom = 0b1000;
|
||||
|
||||
const auto result =
|
||||
RegionLeft * (cursor.x < (window.left + border.x)) |
|
||||
@@ -146,35 +178,11 @@ namespace hex {
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_SETTINGCHANGE:
|
||||
{
|
||||
if (lParam == 0) break;
|
||||
|
||||
if (LPCTSTR(lParam) == std::string_view("ImmersiveColorSet")) {
|
||||
EventManager::post<EventOSThemeChanged>();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case WM_COPYDATA:
|
||||
{
|
||||
auto message = reinterpret_cast<COPYDATASTRUCT *>(lParam);
|
||||
if (message == nullptr) break;
|
||||
|
||||
auto data = reinterpret_cast<const char8_t *>(message->lpData);
|
||||
if (data == nullptr) break;
|
||||
|
||||
std::fs::path path = data;
|
||||
log::info("Opening file in existing instance: {}", path.string());
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return CallWindowProc((WNDPROC)g_oldWndProc, hwnd, uMsg, wParam, lParam);
|
||||
return commonWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
|
||||
@@ -255,7 +263,7 @@ namespace hex {
|
||||
|
||||
|
||||
if (borderlessWindowMode) {
|
||||
g_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)windowProc);
|
||||
g_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)borderlessWindowProc);
|
||||
|
||||
MARGINS borderless = { 1, 1, 1, 1 };
|
||||
::DwmExtendFrameIntoClientArea(hwnd, &borderless);
|
||||
@@ -265,6 +273,8 @@ namespace hex {
|
||||
|
||||
::SetWindowPos(hwnd, nullptr, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE);
|
||||
::SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_OVERLAPPEDWINDOW);
|
||||
} else {
|
||||
g_oldWndProc = ::SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)commonWindowProc);
|
||||
}
|
||||
|
||||
// Catch heap corruption
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/fs.hpp>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <fmt/printf.h>
|
||||
|
||||
#include <chrono>
|
||||
#include <csignal>
|
||||
@@ -80,7 +81,7 @@ namespace hex {
|
||||
#else
|
||||
std::raise(signalNumber);
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
Window::Window() {
|
||||
{
|
||||
@@ -129,21 +130,23 @@ namespace hex {
|
||||
glfwSetWindowTitle(this->m_window, title.c_str());
|
||||
});
|
||||
|
||||
constexpr auto CrashBackupFileName = "crash_backup.hexproj";
|
||||
constexpr static auto CrashBackupFileName = "crash_backup.hexproj";
|
||||
|
||||
EventManager::subscribe<EventAbnormalTermination>(this, [this, CrashBackupFileName](int) {
|
||||
ImGui::SaveIniSettingsToDisk(this->m_imguiSettingsPath.string().c_str());
|
||||
EventManager::subscribe<EventAbnormalTermination>(this, [this](int) {
|
||||
ImGui::SaveIniSettingsToDisk(hex::toUTF8String(this->m_imguiSettingsPath).c_str());
|
||||
|
||||
if (!ImHexApi::Provider::isDirty())
|
||||
return;
|
||||
|
||||
for (const auto &path : fs::getDefaultPaths(fs::ImHexPath::Config)) {
|
||||
if (ProjectFile::store((std::fs::path(path) / CrashBackupFileName).string()))
|
||||
if (ProjectFile::store(path / CrashBackupFileName))
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
EventManager::subscribe<RequestOpenPopup>(this, [this](auto name) {
|
||||
std::scoped_lock lock(this->m_popupMutex);
|
||||
|
||||
this->m_popupsToOpen.push_back(name);
|
||||
});
|
||||
|
||||
@@ -153,8 +156,8 @@ namespace hex {
|
||||
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());
|
||||
auto logoData = romfs::get("logo.png");
|
||||
this->m_logoTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(logoData.data()), logoData.size());
|
||||
|
||||
ContentRegistry::Settings::store();
|
||||
EventManager::post<EventSettingsChanged>();
|
||||
@@ -197,7 +200,6 @@ namespace hex {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this->frameBegin();
|
||||
this->frame();
|
||||
this->frameEnd();
|
||||
@@ -376,7 +378,7 @@ namespace hex {
|
||||
const auto filePath = path / "builtin.hexplug";
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(filePath.string().c_str());
|
||||
ImGui::TextUnformatted(hex::toUTF8String(filePath).c_str());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(fs::exists(filePath) ? ICON_VS_CHECK : ICON_VS_CLOSE);
|
||||
}
|
||||
@@ -424,15 +426,17 @@ namespace hex {
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
{
|
||||
std::scoped_lock lock(this->m_popupMutex);
|
||||
this->m_popupsToOpen.remove_if([](const auto &name) {
|
||||
if (ImGui::IsPopupOpen(name.c_str()))
|
||||
return true;
|
||||
else
|
||||
ImGui::OpenPopup(name.c_str());
|
||||
|
||||
this->m_popupsToOpen.remove_if([](const auto &name) {
|
||||
if (ImGui::IsPopupOpen(name.c_str()))
|
||||
return true;
|
||||
else
|
||||
ImGui::OpenPopup(name.c_str());
|
||||
|
||||
return false;
|
||||
});
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
TaskManager::runDeferredCalls();
|
||||
|
||||
@@ -492,7 +496,7 @@ namespace hex {
|
||||
int displayWidth, displayHeight;
|
||||
glfwGetFramebufferSize(this->m_window, &displayWidth, &displayHeight);
|
||||
glViewport(0, 0, displayWidth, displayHeight);
|
||||
glClearColor(0.45f, 0.55f, 0.60f, 1.00f);
|
||||
glClearColor(0.00F, 0.00F, 0.00F, 1.00f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||
|
||||
@@ -680,8 +684,9 @@ namespace hex {
|
||||
|
||||
if (glfwGetPrimaryMonitor() != nullptr) {
|
||||
auto sessionType = hex::getEnvironmentVariable("XDG_SESSION_TYPE");
|
||||
bool multiWindowEnabled = ContentRegistry::Settings::read("hex.builtin.setting.interface", "hex.builtin.setting.interface.multi_windows", 1) != 0;
|
||||
|
||||
if (!sessionType || !hex::containsIgnoreCase(*sessionType, "wayland"))
|
||||
if ((!sessionType || !hex::containsIgnoreCase(*sessionType, "wayland")) && multiWindowEnabled)
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||
}
|
||||
|
||||
@@ -742,7 +747,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
if (!this->m_imguiSettingsPath.empty() && fs::exists(this->m_imguiSettingsPath))
|
||||
ImGui::LoadIniSettingsFromDisk(this->m_imguiSettingsPath.string().c_str());
|
||||
ImGui::LoadIniSettingsFromDisk(hex::toUTF8String(this->m_imguiSettingsPath).c_str());
|
||||
|
||||
ImGui_ImplGlfw_InitForOpenGL(this->m_window, true);
|
||||
|
||||
@@ -767,7 +772,7 @@ namespace hex {
|
||||
ImNodes::PopAttributeFlag();
|
||||
ImNodes::PopAttributeFlag();
|
||||
|
||||
ImGui::SaveIniSettingsToDisk(this->m_imguiSettingsPath.string().c_str());
|
||||
ImGui::SaveIniSettingsToDisk(hex::toUTF8String(this->m_imguiSettingsPath).c_str());
|
||||
|
||||
ImGui_ImplOpenGL3_Shutdown();
|
||||
ImGui_ImplGlfw_Shutdown();
|
||||
|
||||
@@ -52,9 +52,8 @@ add_library(${PROJECT_NAME} SHARED
|
||||
source/content/views/view_provider_settings.cpp
|
||||
source/content/views/view_find.cpp
|
||||
|
||||
|
||||
source/math_evaluator.cpp
|
||||
source/pattern_drawer.cpp
|
||||
source/content/helpers/math_evaluator.cpp
|
||||
source/content/helpers/pattern_drawer.cpp
|
||||
|
||||
source/lang/de_DE.cpp
|
||||
source/lang/en_US.cpp
|
||||
@@ -85,3 +84,9 @@ endif()
|
||||
add_compile_definitions(IMHEX_PROJECT_NAME="${PROJECT_NAME}")
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
setupCompilerWarnings(${PROJECT_NAME})
|
||||
|
||||
set(LIBROMFS_RESOURCE_LOCATION ${CMAKE_CURRENT_SOURCE_DIR}/romfs)
|
||||
set(LIBROMFS_PROJECT_NAME ${PROJECT_NAME})
|
||||
add_subdirectory(../../lib/external/libromfs ${CMAKE_CURRENT_BINARY_DIR}/libromfs)
|
||||
set_target_properties(${LIBROMFS_LIBRARY} PROPERTIES POSITION_INDEPENDENT_CODE ON)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE ${LIBROMFS_LIBRARY})
|
||||
|
||||
@@ -16,15 +16,20 @@ namespace hex {
|
||||
public:
|
||||
MathEvaluator() = default;
|
||||
|
||||
struct Variable {
|
||||
T value;
|
||||
bool constant;
|
||||
};
|
||||
|
||||
std::optional<T> evaluate(const std::string &input);
|
||||
|
||||
void registerStandardVariables();
|
||||
void registerStandardFunctions();
|
||||
|
||||
void setVariable(const std::string &name, T value);
|
||||
void setVariable(const std::string &name, T value, bool constant = false);
|
||||
void setFunction(const std::string &name, const std::function<std::optional<T>(std::vector<T>)> &function, size_t minNumArgs, size_t maxNumArgs);
|
||||
|
||||
std::unordered_map<std::string, T> &getVariables() { return this->m_variables; }
|
||||
std::unordered_map<std::string, Variable> &getVariables() { return this->m_variables; }
|
||||
|
||||
[[nodiscard]] bool hasError() const {
|
||||
return this->m_lastError.has_value();
|
||||
@@ -98,7 +103,7 @@ namespace hex {
|
||||
};
|
||||
|
||||
static i16 comparePrecedence(const Operator &a, const Operator &b);
|
||||
static bool isLeftAssociative(const Operator op);
|
||||
static bool isLeftAssociative(const Operator &op);
|
||||
static std::pair<Operator, size_t> toOperator(const std::string &input);
|
||||
|
||||
private:
|
||||
@@ -106,7 +111,7 @@ namespace hex {
|
||||
std::optional<std::queue<Token>> toPostfix(std::queue<Token> inputQueue);
|
||||
std::optional<T> evaluate(std::queue<Token> postfixTokens);
|
||||
|
||||
std::unordered_map<std::string, T> m_variables;
|
||||
std::unordered_map<std::string, Variable> m_variables;
|
||||
std::unordered_map<std::string, std::function<std::optional<T>(std::vector<T>)>> m_functions;
|
||||
|
||||
std::optional<std::string> m_lastError;
|
||||
43
plugins/builtin/include/content/helpers/pattern_drawer.hpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
#include <pl/pattern_visitor.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
class PatternDrawer : public pl::PatternVisitor {
|
||||
public:
|
||||
PatternDrawer() = default;
|
||||
|
||||
void visit(pl::ptrn::PatternArrayDynamic& pattern) override;
|
||||
void visit(pl::ptrn::PatternArrayStatic& pattern) override;
|
||||
void visit(pl::ptrn::PatternBitfieldField& pattern) override;
|
||||
void visit(pl::ptrn::PatternBitfield& pattern) override;
|
||||
void visit(pl::ptrn::PatternBoolean& pattern) override;
|
||||
void visit(pl::ptrn::PatternCharacter& pattern) override;
|
||||
void visit(pl::ptrn::PatternEnum& pattern) override;
|
||||
void visit(pl::ptrn::PatternFloat& pattern) override;
|
||||
void visit(pl::ptrn::PatternPadding& pattern) override;
|
||||
void visit(pl::ptrn::PatternPointer& pattern) override;
|
||||
void visit(pl::ptrn::PatternSigned& pattern) override;
|
||||
void visit(pl::ptrn::PatternString& pattern) override;
|
||||
void visit(pl::ptrn::PatternStruct& pattern) override;
|
||||
void visit(pl::ptrn::PatternUnion& pattern) override;
|
||||
void visit(pl::ptrn::PatternUnsigned& pattern) override;
|
||||
void visit(pl::ptrn::PatternWideCharacter& pattern) override;
|
||||
void visit(pl::ptrn::PatternWideString& pattern) override;
|
||||
|
||||
private:
|
||||
void draw(pl::ptrn::Pattern& pattern);
|
||||
|
||||
constexpr static auto ChunkSize = 512;
|
||||
constexpr static auto DisplayEndStep = 64;
|
||||
|
||||
void drawArray(pl::ptrn::Pattern& pattern, pl::ptrn::Iteratable &iteratable, bool isInlined);
|
||||
u64& getDisplayEnd(const pl::ptrn::Pattern& pattern);
|
||||
|
||||
private:
|
||||
std::map<const pl::ptrn::Pattern*, u64> m_displayEnd;
|
||||
};
|
||||
}
|
||||
@@ -18,6 +18,7 @@ namespace hex::plugin::builtin {
|
||||
struct {
|
||||
std::string sourceCode;
|
||||
std::unique_ptr<pl::PatternLanguage> runtime;
|
||||
bool executionDone = true;
|
||||
} patternLanguage;
|
||||
|
||||
std::list<ImHexApi::Bookmarks::Entry> bookmarks;
|
||||
@@ -30,6 +31,11 @@ namespace hex::plugin::builtin {
|
||||
std::vector<hex::prv::Overlay *> dataOverlays;
|
||||
std::optional<dp::Node::NodeError> currNodeError;
|
||||
} dataProcessor;
|
||||
|
||||
struct {
|
||||
std::optional<u64> selectionStart, selectionEnd;
|
||||
float scrollPosition = 0.0F;
|
||||
} editor;
|
||||
};
|
||||
|
||||
static Data& getCurrent() {
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <vector>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
@@ -45,7 +46,7 @@ namespace hex::plugin::builtin::prv {
|
||||
return "hex.builtin.provider.disk";
|
||||
}
|
||||
|
||||
std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
[[nodiscard]] std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
|
||||
protected:
|
||||
void reloadDrives();
|
||||
|
||||
@@ -7,15 +7,12 @@
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
|
||||
#else
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/fcntl.h>
|
||||
|
||||
#endif
|
||||
|
||||
namespace hex::plugin::builtin::prv {
|
||||
@@ -41,7 +38,6 @@ namespace hex::plugin::builtin::prv {
|
||||
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;
|
||||
[[nodiscard]] size_t getRealTimeSize();
|
||||
|
||||
void save() override;
|
||||
void saveAs(const std::fs::path &path) override;
|
||||
@@ -49,8 +45,8 @@ 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;
|
||||
[[nodiscard]] bool hasFilePicker() const override { return true; }
|
||||
[[nodiscard]] bool handleFilePicker() override;
|
||||
|
||||
void setPath(const std::fs::path &path);
|
||||
|
||||
@@ -67,17 +63,6 @@ namespace hex::plugin::builtin::prv {
|
||||
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
|
||||
|
||||
std::fs::path m_path;
|
||||
void *m_mappedFile = nullptr;
|
||||
size_t m_fileSize = 0;
|
||||
|
||||
@@ -49,7 +49,7 @@ namespace hex::plugin::builtin::prv {
|
||||
return "hex.builtin.provider.gdb";
|
||||
}
|
||||
|
||||
std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
[[nodiscard]] std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
|
||||
protected:
|
||||
hex::Socket m_socket;
|
||||
|
||||
@@ -36,8 +36,8 @@ namespace hex::plugin::builtin::prv {
|
||||
return "hex.builtin.provider.intel_hex";
|
||||
}
|
||||
|
||||
bool hasFilePicker() const override { return true; }
|
||||
bool handleFilePicker() override;
|
||||
[[nodiscard]] bool hasFilePicker() const override { return true; }
|
||||
[[nodiscard]] bool handleFilePicker() override;
|
||||
|
||||
std::pair<Region, bool> getRegionValidity(u64 address) const override;
|
||||
|
||||
|
||||
@@ -15,6 +15,9 @@ namespace hex::plugin::builtin::prv {
|
||||
[[nodiscard]] bool isResizable() const override { return false; }
|
||||
[[nodiscard]] bool isSavable() const override { return false; }
|
||||
|
||||
[[nodiscard]] bool open() override { return true; }
|
||||
void close() override { }
|
||||
|
||||
void readRaw(u64 offset, void *buffer, size_t size) override { hex::unused(offset, buffer, size); }
|
||||
void writeRaw(u64 offset, const void *buffer, size_t size) override { hex::unused(offset, buffer, size); }
|
||||
[[nodiscard]] size_t getActualSize() const override { return 0x00; }
|
||||
|
||||
@@ -14,7 +14,6 @@ namespace hex::plugin::builtin {
|
||||
class ViewAbout : public View {
|
||||
public:
|
||||
ViewAbout();
|
||||
~ViewAbout() override;
|
||||
|
||||
void drawContent() override;
|
||||
|
||||
|
||||
@@ -21,6 +21,8 @@ namespace hex::plugin::builtin {
|
||||
void registerMenuItems();
|
||||
private:
|
||||
std::string m_currFilter;
|
||||
|
||||
std::list<ImHexApi::Bookmarks::Entry>::iterator m_dragStartIterator;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -33,7 +33,9 @@ namespace hex::plugin::builtin {
|
||||
|
||||
u64 m_startAddress = 0;
|
||||
size_t m_validBytes = 0;
|
||||
std::vector<InspectorCacheEntry> m_cachedData;
|
||||
std::atomic<bool> m_dataValid = false;
|
||||
std::vector<InspectorCacheEntry> m_cachedData, m_workData;
|
||||
TaskHolder m_updateTask;
|
||||
|
||||
std::string m_editingValue;
|
||||
};
|
||||
|
||||
@@ -20,12 +20,13 @@ namespace hex::plugin::builtin {
|
||||
void drawContent() override;
|
||||
|
||||
private:
|
||||
bool m_justSwitchedProvider = false;
|
||||
int m_rightClickedId = -1;
|
||||
ImVec2 m_rightClickedCoords;
|
||||
|
||||
bool m_continuousEvaluation = false;
|
||||
|
||||
void eraseLink(u32 id);
|
||||
void eraseLink(int id);
|
||||
void eraseNodes(const std::vector<int> &ids);
|
||||
void processNodes();
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ namespace hex::plugin::builtin {
|
||||
|
||||
struct Occurrence {
|
||||
Region region;
|
||||
enum class DecodeType { ASCII, Binary, UTF16LE, UTF16BE } decodeType;
|
||||
enum class DecodeType { ASCII, Binary, UTF16, Unsigned, Signed, Float, Double } decodeType;
|
||||
std::endian endian = std::endian::native;
|
||||
};
|
||||
|
||||
struct BinaryPattern {
|
||||
@@ -38,7 +39,8 @@ namespace hex::plugin::builtin {
|
||||
Strings,
|
||||
Sequence,
|
||||
Regex,
|
||||
BinaryPattern
|
||||
BinaryPattern,
|
||||
Value
|
||||
} mode = Mode::Strings;
|
||||
|
||||
struct Strings {
|
||||
@@ -55,18 +57,31 @@ namespace hex::plugin::builtin {
|
||||
bool m_lineFeeds = false;
|
||||
} strings;
|
||||
|
||||
struct Bytes {
|
||||
struct Sequence {
|
||||
std::string sequence;
|
||||
} bytes;
|
||||
|
||||
struct Regex {
|
||||
std::string pattern;
|
||||
bool fullMatch = true;
|
||||
} regex;
|
||||
|
||||
struct BinaryPattern {
|
||||
std::string input;
|
||||
std::vector<ViewFind::BinaryPattern> pattern;
|
||||
} binaryPattern;
|
||||
|
||||
struct Value {
|
||||
std::string inputMin, inputMax;
|
||||
std::endian endian = std::endian::native;
|
||||
|
||||
enum class Type {
|
||||
U8 = 0, U16 = 1, U32 = 2, U64 = 3,
|
||||
I8 = 4, I16 = 5, I32 = 6, I64 = 7,
|
||||
F32 = 8, F64 = 9
|
||||
} type = Type::U8;
|
||||
} value;
|
||||
|
||||
} m_searchSettings, m_decodeSettings;
|
||||
|
||||
using OccurrenceTree = interval_tree::IntervalTree<u64, Occurrence>;
|
||||
@@ -79,12 +94,14 @@ namespace hex::plugin::builtin {
|
||||
bool m_settingsValid = false;
|
||||
|
||||
private:
|
||||
static std::vector<Occurrence> searchStrings(Task &task, prv::Provider *provider, Region searchRegion, SearchSettings::Strings settings);
|
||||
static std::vector<Occurrence> searchSequence(Task &task, prv::Provider *provider, Region searchRegion, SearchSettings::Bytes settings);
|
||||
static std::vector<Occurrence> searchRegex(Task &task, prv::Provider *provider, Region searchRegion, SearchSettings::Regex settings);
|
||||
static std::vector<Occurrence> searchBinaryPattern(Task &task, prv::Provider *provider, Region searchRegion, SearchSettings::BinaryPattern settings);
|
||||
static std::vector<Occurrence> searchStrings(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Strings &settings);
|
||||
static std::vector<Occurrence> searchSequence(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Sequence &settings);
|
||||
static std::vector<Occurrence> searchRegex(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Regex &settings);
|
||||
static std::vector<Occurrence> searchBinaryPattern(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::BinaryPattern &settings);
|
||||
static std::vector<Occurrence> searchValue(Task &task, prv::Provider *provider, Region searchRegion, const SearchSettings::Value &settings);
|
||||
|
||||
static std::vector<BinaryPattern> parseBinaryPatternString(std::string string);
|
||||
static std::tuple<bool, std::variant<u64, i64, float, double>, size_t> parseNumericValueInput(const std::string &input, SearchSettings::Value::Type type);
|
||||
|
||||
void runSearch();
|
||||
std::string decodeValue(prv::Provider *provider, Occurrence occurrence) const;
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
#include <hex/helpers/encoding_file.hpp>
|
||||
|
||||
#include <content/helpers/provider_extra_data.hpp>
|
||||
|
||||
#include <algorithm>
|
||||
#include <limits>
|
||||
|
||||
@@ -18,8 +20,6 @@ namespace hex::plugin::builtin {
|
||||
void drawContent() override;
|
||||
|
||||
private:
|
||||
constexpr static auto InvalidSelection = std::numeric_limits<u64>::max();
|
||||
|
||||
void registerShortcuts();
|
||||
void registerEvents();
|
||||
void registerMenuItems();
|
||||
@@ -33,22 +33,16 @@ namespace hex::plugin::builtin {
|
||||
void setSelection(u128 start, u128 end) {
|
||||
if (!ImHexApi::Provider::isValid())
|
||||
return;
|
||||
if (start == InvalidSelection && end == InvalidSelection)
|
||||
return;
|
||||
|
||||
if (start == InvalidSelection)
|
||||
start = end;
|
||||
if (end == InvalidSelection)
|
||||
end = start;
|
||||
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
auto &data = ProviderExtraData::get(provider).editor;
|
||||
|
||||
const size_t maxAddress = provider->getActualSize() + provider->getBaseAddress() - 1;
|
||||
|
||||
this->m_selectionChanged = this->m_selectionStart != start || this->m_selectionEnd != end;
|
||||
this->m_selectionChanged = data.selectionStart != start || data.selectionEnd != end;
|
||||
|
||||
this->m_selectionStart = std::clamp<u128>(start, 0, maxAddress);
|
||||
this->m_selectionEnd = std::clamp<u128>(end, 0, maxAddress);
|
||||
data.selectionStart = std::clamp<u128>(start, 0, maxAddress);
|
||||
data.selectionEnd = std::clamp<u128>(end, 0, maxAddress);
|
||||
|
||||
if (this->m_selectionChanged) {
|
||||
EventManager::post<EventRegionSelected>(this->getSelection());
|
||||
@@ -56,15 +50,22 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
[[nodiscard]] Region getSelection() const {
|
||||
const auto start = std::min(this->m_selectionStart, this->m_selectionEnd);
|
||||
const auto end = std::max(this->m_selectionStart, this->m_selectionEnd);
|
||||
auto &data = ProviderExtraData::getCurrent().editor;
|
||||
|
||||
if (!isSelectionValid())
|
||||
return Region::Invalid();
|
||||
|
||||
const auto start = std::min(*data.selectionStart, *data.selectionEnd);
|
||||
const auto end = std::max(*data.selectionStart, *data.selectionEnd);
|
||||
const size_t size = end - start + 1;
|
||||
|
||||
return { start, size };
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isSelectionValid() const {
|
||||
return this->m_selectionStart != InvalidSelection && this->m_selectionEnd != InvalidSelection;
|
||||
auto &data = ProviderExtraData::getCurrent().editor;
|
||||
|
||||
return data.selectionStart.has_value() && data.selectionEnd.has_value();
|
||||
}
|
||||
|
||||
void jumpToSelection() {
|
||||
@@ -119,10 +120,9 @@ namespace hex::plugin::builtin {
|
||||
bool m_shouldJumpToSelection = false;
|
||||
bool m_shouldScrollToSelection = false;
|
||||
bool m_shouldJumpWhenOffScreen = false;
|
||||
bool m_shouldUpdateScrollPosition = false;
|
||||
|
||||
bool m_selectionChanged = false;
|
||||
u64 m_selectionStart = InvalidSelection;
|
||||
u64 m_selectionEnd = InvalidSelection;
|
||||
|
||||
u16 m_visibleRowCount = 0;
|
||||
|
||||
@@ -136,6 +136,8 @@ namespace hex::plugin::builtin {
|
||||
bool m_upperCaseHex = true;
|
||||
bool m_grayOutZero = true;
|
||||
bool m_showAscii = true;
|
||||
bool m_syncScrolling = false;
|
||||
u32 m_byteCellPadding = 0, m_characterCellPadding = 0;
|
||||
|
||||
bool m_shouldOpenPopup = false;
|
||||
std::unique_ptr<Popup> m_currPopup;
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace hex::plugin::builtin {
|
||||
class ViewPatches : public View {
|
||||
public:
|
||||
explicit ViewPatches();
|
||||
~ViewPatches() override;
|
||||
~ViewPatches() override = default;
|
||||
|
||||
void drawContent() override;
|
||||
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "pattern_drawer.hpp"
|
||||
|
||||
#include <hex.hpp>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/view.hpp>
|
||||
|
||||
#include <content/helpers/pattern_drawer.hpp>
|
||||
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <cstdio>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
|
||||
@@ -17,8 +17,8 @@ namespace hex::plugin::builtin {
|
||||
[[nodiscard]] bool isAvailable() const override { return true; }
|
||||
[[nodiscard]] bool hasViewMenuItemEntry() const override { return false; }
|
||||
|
||||
[[nodiscard]] ImVec2 getMinSize() const override { return { 500, 300 }; }
|
||||
[[nodiscard]] ImVec2 getMaxSize() const override { return { 500, 300 }; }
|
||||
[[nodiscard]] ImVec2 getMinSize() const override { return { 700, 400 }; }
|
||||
[[nodiscard]] ImVec2 getMaxSize() const override { return { 700, 400 }; }
|
||||
|
||||
private:
|
||||
bool m_restartRequested = false;
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
#include <pl/pattern_visitor.hpp>
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
template<typename T>
|
||||
concept ArrayPattern = requires(u64 displayEnd, T pattern, std::function<void(int, pl::ptrn::Pattern&)> fn) {
|
||||
{ pattern.forEachArrayEntry(displayEnd, fn) } -> std::same_as<void>;
|
||||
};
|
||||
|
||||
class PatternDrawer : public pl::PatternVisitor {
|
||||
public:
|
||||
PatternDrawer() = default;
|
||||
|
||||
void visit(pl::ptrn::PatternArrayDynamic& pattern) override;
|
||||
void visit(pl::ptrn::PatternArrayStatic& pattern) override;
|
||||
void visit(pl::ptrn::PatternBitfieldField& pattern) override;
|
||||
void visit(pl::ptrn::PatternBitfield& pattern) override;
|
||||
void visit(pl::ptrn::PatternBoolean& pattern) override;
|
||||
void visit(pl::ptrn::PatternCharacter& pattern) override;
|
||||
void visit(pl::ptrn::PatternEnum& pattern) override;
|
||||
void visit(pl::ptrn::PatternFloat& pattern) override;
|
||||
void visit(pl::ptrn::PatternPadding& pattern) override;
|
||||
void visit(pl::ptrn::PatternPointer& pattern) override;
|
||||
void visit(pl::ptrn::PatternSigned& pattern) override;
|
||||
void visit(pl::ptrn::PatternString& pattern) override;
|
||||
void visit(pl::ptrn::PatternStruct& pattern) override;
|
||||
void visit(pl::ptrn::PatternUnion& pattern) override;
|
||||
void visit(pl::ptrn::PatternUnsigned& pattern) override;
|
||||
void visit(pl::ptrn::PatternWideCharacter& pattern) override;
|
||||
void visit(pl::ptrn::PatternWideString& pattern) override;
|
||||
|
||||
private:
|
||||
void 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::ptrn::Pattern &pattern) const;
|
||||
|
||||
void draw(pl::ptrn::Pattern& pattern);
|
||||
|
||||
template<ArrayPattern T>
|
||||
void drawArray(T& pattern) {
|
||||
bool opened = this->drawArrayRoot(pattern, pattern.getEntryCount(), pattern.isInlined());
|
||||
|
||||
if (opened) {
|
||||
auto& displayEnd = this->getDisplayEnd(pattern);
|
||||
pattern.forEachArrayEntry(displayEnd, [&] (u64 idx, auto &entry){
|
||||
this->drawArrayNode(idx, displayEnd, entry);
|
||||
});
|
||||
}
|
||||
|
||||
this->drawArrayEnd(pattern, opened);
|
||||
}
|
||||
|
||||
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::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::ptrn::Pattern& pattern);
|
||||
|
||||
private:
|
||||
std::map<const pl::ptrn::Pattern*, u64> m_displayEnd;
|
||||
};
|
||||
};
|
||||
|
Before Width: | Height: | Size: 6.0 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
BIN
plugins/builtin/romfs/logo.png
Normal file
|
After Width: | Height: | Size: 157 KiB |
@@ -5,7 +5,7 @@
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
|
||||
#include "math_evaluator.hpp"
|
||||
#include <content/helpers/math_evaluator.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
|
||||
@@ -1,34 +1,42 @@
|
||||
#include <hex/api/content_registry.hpp>
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
#include <hex/providers/buffered_reader.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
#include <hex/helpers/crypto.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
static std::string formatLanguageArray(prv::Provider *provider, u64 offset, size_t size, const std::string &start, const std::string &byteFormat, const std::string &end) {
|
||||
constexpr auto NewLineIndent = "\n ";
|
||||
constexpr static auto NewLineIndent = "\n ";
|
||||
constexpr static auto LineLength = 16;
|
||||
|
||||
std::string result = start;
|
||||
std::string result;
|
||||
result.reserve(start.size() + hex::format(byteFormat, 0x00).size() * size + + std::string(NewLineIndent).size() / LineLength + end.size());
|
||||
|
||||
std::vector<u8> buffer(0x1'0000, 0x00);
|
||||
for (u64 i = 0; i < size; i += buffer.size()) {
|
||||
size_t readSize = std::min<u64>(buffer.size(), size - i);
|
||||
provider->read(offset, buffer.data(), readSize);
|
||||
result += start;
|
||||
|
||||
for (u32 j = 0; j < readSize; j++) {
|
||||
if (j % 0x10 == 0)
|
||||
result += NewLineIndent;
|
||||
auto reader = prv::BufferedReader(provider);
|
||||
reader.seek(offset);
|
||||
reader.setEndAddress(offset + size - 1);
|
||||
|
||||
result += hex::format(byteFormat, buffer[j]);
|
||||
}
|
||||
u64 index = 0x00;
|
||||
for (u8 byte : reader) {
|
||||
if ((index % LineLength) == 0x00)
|
||||
result += NewLineIndent;
|
||||
|
||||
// Remove trailing comma
|
||||
result += hex::format(byteFormat, byte);
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
// Remove trailing comma
|
||||
if (provider->getActualSize() > 0) {
|
||||
result.pop_back();
|
||||
result.pop_back();
|
||||
}
|
||||
|
||||
result += "\n";
|
||||
result += end;
|
||||
result += "\n" + end;
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -56,52 +64,85 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
|
||||
ContentRegistry::DataFormatter::add("hex.builtin.view.hex_editor.copy.python", [](prv::Provider *provider, u64 offset, size_t size) {
|
||||
return formatLanguageArray(provider, offset, size, "data = bytes([", "0x{0:02X}, ", "]);");
|
||||
return formatLanguageArray(provider, offset, size, "data = bytes([", "0x{0:02X}, ", "])");
|
||||
});
|
||||
|
||||
ContentRegistry::DataFormatter::add("hex.builtin.view.hex_editor.copy.js", [](prv::Provider *provider, u64 offset, size_t size) {
|
||||
return formatLanguageArray(provider, offset, size, "const data = new Uint8Array([", "0x{0:02X}, ", "]);");
|
||||
});
|
||||
|
||||
ContentRegistry::DataFormatter::add("hex.builtin.view.hex_editor.copy.lua", [](prv::Provider *provider, u64 offset, size_t size) {
|
||||
return formatLanguageArray(provider, offset, size, "data = {", "0x{0:02X}, ", "}");
|
||||
});
|
||||
|
||||
ContentRegistry::DataFormatter::add("hex.builtin.view.hex_editor.copy.go", [](prv::Provider *provider, u64 offset, size_t size) {
|
||||
return formatLanguageArray(provider, offset, size, "data := [...]byte {", "0x{0:02X}, ", "}");
|
||||
});
|
||||
|
||||
ContentRegistry::DataFormatter::add("hex.builtin.view.hex_editor.copy.crystal", [](prv::Provider *provider, u64 offset, size_t size) {
|
||||
return formatLanguageArray(provider, offset, size, "data = [", "0x{0:02X}, ", "] of UInt8");
|
||||
});
|
||||
|
||||
ContentRegistry::DataFormatter::add("hex.builtin.view.hex_editor.copy.swift", [](prv::Provider *provider, u64 offset, size_t size) {
|
||||
return formatLanguageArray(provider, offset, size, "let data: [Uint8] = [", "0x{0:02X}, ", "]");
|
||||
});
|
||||
|
||||
ContentRegistry::DataFormatter::add("hex.builtin.view.hex_editor.copy.pascal", [](prv::Provider *provider, u64 offset, size_t size) {
|
||||
return formatLanguageArray(provider, offset, size, hex::format("data: array[0..{0}] of Byte = (", size - 1), "${0:02X}, ", ")");
|
||||
});
|
||||
|
||||
ContentRegistry::DataFormatter::add("hex.builtin.view.hex_editor.copy.base64", [](prv::Provider *provider, u64 offset, size_t size) {
|
||||
std::vector<u8> data(size, 0x00);
|
||||
provider->read(offset, data.data(), size);
|
||||
|
||||
auto result = crypt::encode64(data);
|
||||
|
||||
return std::string(result.begin(), result.end());
|
||||
});
|
||||
|
||||
ContentRegistry::DataFormatter::add("hex.builtin.view.hex_editor.copy.ascii", [](prv::Provider *provider, u64 offset, size_t size) {
|
||||
std::string result = "Hex View 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n\n";
|
||||
constexpr static auto HeaderLine = "Hex View 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n";
|
||||
std::string result;
|
||||
result.reserve(std::string(HeaderLine).size() * size / 0x10);
|
||||
|
||||
std::vector<u8> buffer(0x1'0000, 0x00);
|
||||
for (u64 byte = 0; byte < size; byte += buffer.size()) {
|
||||
size_t readSize = std::min<u64>(buffer.size(), size - byte);
|
||||
provider->read(offset, buffer.data(), readSize);
|
||||
result += HeaderLine;
|
||||
|
||||
const auto end = (offset + readSize) - 1;
|
||||
auto reader = prv::BufferedReader(provider);
|
||||
reader.seek(offset);
|
||||
reader.setEndAddress((offset + size) - 1);
|
||||
|
||||
for (u32 col = offset >> 4; col <= (end >> 4); col++) {
|
||||
result += hex::format("{0:08X} ", col << 4);
|
||||
for (u64 i = 0; i < 16; i++) {
|
||||
u64 address = offset & ~u64(0x0F);
|
||||
std::string asciiRow;
|
||||
for (u8 byte : reader) {
|
||||
if ((address % 0x10) == 0) {
|
||||
result += hex::format(" {}", asciiRow);
|
||||
result += hex::format("\n{0:08X} ", address);
|
||||
|
||||
if ((col == (offset >> 4) && i < (offset & 0xF)) || (col == (end >> 4) && i > (end & 0xF)))
|
||||
asciiRow.clear();
|
||||
|
||||
if (address == (offset & ~u64(0x0F))) {
|
||||
for (u64 i = 0; i < (offset - address); i++) {
|
||||
result += " ";
|
||||
else
|
||||
result += hex::format("{0:02X} ", buffer[((col << 4) - offset) + i]);
|
||||
|
||||
if ((i & 0xF) == 0x7)
|
||||
result += " ";
|
||||
asciiRow += " ";
|
||||
}
|
||||
address = offset;
|
||||
}
|
||||
}
|
||||
|
||||
result += hex::format("{0:02X} ", byte);
|
||||
asciiRow += std::isprint(byte) ? char(byte) : '.';
|
||||
if ((address % 0x10) == 0x07)
|
||||
result += " ";
|
||||
|
||||
for (u64 i = 0; i < 16; i++) {
|
||||
|
||||
if ((col == (offset >> 4) && i < (offset & 0xF)) || (col == (end >> 4) && i > (end & 0xF)))
|
||||
result += " ";
|
||||
else {
|
||||
u8 c = buffer[((col << 4) - offset) + i];
|
||||
char displayChar = (c < 32 || c >= 128) ? '.' : c;
|
||||
result += hex::format("{0}", displayChar);
|
||||
}
|
||||
}
|
||||
|
||||
result += "\n";
|
||||
}
|
||||
address++;
|
||||
}
|
||||
|
||||
if ((address % 0x10) != 0x00)
|
||||
for (u32 i = 0; i < (0x10 - (address % 0x10)); i++)
|
||||
result += " ";
|
||||
|
||||
result += hex::format(" {}", asciiRow);
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
@@ -115,48 +156,46 @@ namespace hex::plugin::builtin {
|
||||
" .textcolumn { color:#000000 }\n"
|
||||
" </style>\n\n"
|
||||
" <code>\n"
|
||||
" <span class=\"offsetheader\">Hex View  00 01 02 03 04 05 06 07  08 09 0A 0B 0C 0D 0E 0F</span><br>\n";
|
||||
" <span class=\"offsetheader\">Hex View  00 01 02 03 04 05 06 07  08 09 0A 0B 0C 0D 0E 0F</span>";
|
||||
|
||||
auto reader = prv::BufferedReader(provider);
|
||||
reader.seek(offset);
|
||||
reader.setEndAddress((offset + size) - 1);
|
||||
|
||||
std::vector<u8> buffer(0x1'0000, 0x00);
|
||||
for (u64 byte = 0; byte < size; byte += buffer.size()) {
|
||||
size_t readSize = std::min<u64>(buffer.size(), size - byte);
|
||||
provider->read(offset, buffer.data(), readSize);
|
||||
u64 address = offset & ~u64(0x0F);
|
||||
std::string asciiRow;
|
||||
for (u8 byte : reader) {
|
||||
if ((address % 0x10) == 0) {
|
||||
result += hex::format(" {}", asciiRow);
|
||||
result += hex::format("<br>\n <span class=\"offsetcolumn\">{0:08X}</span>  <span class=\"hexcolumn\">", address);
|
||||
|
||||
const auto end = (offset + readSize) - 1;
|
||||
asciiRow.clear();
|
||||
|
||||
for (u32 col = offset >> 4; col <= (end >> 4); col++) {
|
||||
result += hex::format(" <span class=\"offsetcolumn\">{0:08X}</span>  <span class=\"hexcolumn\">", col << 4);
|
||||
for (u64 i = 0; i < 16; i++) {
|
||||
|
||||
if ((col == (offset >> 4) && i < (offset & 0xF)) || (col == (end >> 4) && i > (end & 0xF)))
|
||||
result += "   ";
|
||||
else
|
||||
result += hex::format("{0:02X} ", buffer[((col << 4) - offset) + i]);
|
||||
|
||||
if ((i & 0xF) == 0x7)
|
||||
result += " ";
|
||||
}
|
||||
|
||||
result += "</span>  <span class=\"textcolumn\">";
|
||||
|
||||
for (u64 i = 0; i < 16; i++) {
|
||||
|
||||
if ((col == (offset >> 4) && i < (offset & 0xF)) || (col == (end >> 4) && i > (end & 0xF)))
|
||||
result += " ";
|
||||
else {
|
||||
u8 c = buffer[((col << 4) - offset) + i];
|
||||
char displayChar = (c < 32 || c >= 128) ? '.' : c;
|
||||
result += hex::format("{0}", displayChar);
|
||||
if (address == (offset & ~u64(0x0F))) {
|
||||
for (u64 i = 0; i < (offset - address); i++) {
|
||||
result += "   ";
|
||||
asciiRow += " ";
|
||||
}
|
||||
address = offset;
|
||||
}
|
||||
|
||||
result += "</span><br>\n";
|
||||
result += "</span>";
|
||||
}
|
||||
|
||||
result += hex::format("{0:02X} ", byte);
|
||||
asciiRow += std::isprint(byte) ? char(byte) : '.';
|
||||
if ((address % 0x10) == 0x07)
|
||||
result += " ";
|
||||
|
||||
address++;
|
||||
}
|
||||
|
||||
for (u32 i = 0; i < (0x10 - (address % 0x10)); i++)
|
||||
result += "   ";
|
||||
result += asciiRow;
|
||||
|
||||
result +=
|
||||
" </code>\n"
|
||||
"\n </code>\n"
|
||||
"</div>\n";
|
||||
|
||||
return result;
|
||||
|
||||
@@ -396,13 +396,14 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
);
|
||||
|
||||
constexpr static auto MaxStringLength = 32;
|
||||
|
||||
ContentRegistry::DataInspector::add("hex.builtin.inspector.string", 1,
|
||||
[](auto buffer, auto endian, auto style) {
|
||||
hex::unused(buffer, endian, style);
|
||||
|
||||
auto currSelection = ImHexApi::HexEditor::getSelection();
|
||||
|
||||
constexpr static auto MaxStringLength = 32;
|
||||
|
||||
std::string value, copyValue;
|
||||
|
||||
@@ -430,6 +431,45 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
);
|
||||
|
||||
ContentRegistry::DataInspector::add("hex.builtin.inspector.string16", 2,
|
||||
[](auto buffer, auto endian, auto style) {
|
||||
hex::unused(buffer, endian, style);
|
||||
|
||||
auto currSelection = ImHexApi::HexEditor::getSelection();
|
||||
|
||||
std::string value, copyValue;
|
||||
|
||||
if (currSelection.has_value()) {
|
||||
std::u16string stringBuffer(std::min<size_t>(currSelection->size, 0x1000), 0x00);
|
||||
ImHexApi::Provider::get()->read(currSelection->address, stringBuffer.data(), stringBuffer.size());
|
||||
|
||||
for (auto &c : stringBuffer)
|
||||
c = hex::changeEndianess(c, endian);
|
||||
|
||||
auto it = std::remove_if(buffer.begin(), buffer.end(),
|
||||
[](auto c) { return c == 0x00; });
|
||||
buffer.erase(it, buffer.end());
|
||||
|
||||
value = copyValue = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>("Invalid").to_bytes(stringBuffer.data());
|
||||
|
||||
if (value.size() > MaxStringLength) {
|
||||
value.resize(MaxStringLength);
|
||||
value += "...";
|
||||
}
|
||||
} else {
|
||||
value = "";
|
||||
copyValue = "";
|
||||
}
|
||||
|
||||
return [value, copyValue] { ImGui::TextFormatted("L\"{0}\"", value.c_str()); return copyValue; };
|
||||
},
|
||||
[](const std::string &value, std::endian endian) -> std::vector<u8> {
|
||||
hex::unused(endian);
|
||||
|
||||
return hex::decodeByteString(value);
|
||||
}
|
||||
);
|
||||
|
||||
#if defined(OS_WINDOWS) && defined(ARCH_64_BIT)
|
||||
|
||||
ContentRegistry::DataInspector::add("hex.builtin.inspector.time32", sizeof(u32), [](auto buffer, auto endian, auto style) {
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include <imgui.h>
|
||||
#include <implot.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
#include <fonts/codicons_font.h>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
@@ -32,7 +33,7 @@ namespace hex::plugin::builtin {
|
||||
NodeBuffer() : Node("hex.builtin.nodes.constants.buffer.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "") }) { }
|
||||
|
||||
void drawNode() override {
|
||||
constexpr int StepSize = 1, FastStepSize = 10;
|
||||
constexpr static int StepSize = 1, FastStepSize = 10;
|
||||
|
||||
ImGui::PushItemWidth(100);
|
||||
ImGui::InputScalar("hex.builtin.nodes.constants.buffer.size"_lang, ImGuiDataType_U32, &this->m_size, &StepSize, &FastStepSize);
|
||||
@@ -66,22 +67,17 @@ namespace hex::plugin::builtin {
|
||||
class NodeString : public dp::Node {
|
||||
public:
|
||||
NodeString() : Node("hex.builtin.nodes.constants.string.header", { dp::Attribute(dp::Attribute::IOType::Out, dp::Attribute::Type::Buffer, "") }) {
|
||||
this->m_value.resize(0xFFF, 0x00);
|
||||
|
||||
}
|
||||
|
||||
void drawNode() override {
|
||||
ImGui::PushItemWidth(100);
|
||||
ImGui::InputText("##string", reinterpret_cast<char *>(this->m_value.data()), this->m_value.size() - 1);
|
||||
ImGui::InputTextIcon("##string", ICON_VS_SYMBOL_KEY, this->m_value);
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
void process() override {
|
||||
std::vector<u8> output(std::strlen(this->m_value.c_str()) + 1, 0x00);
|
||||
std::strcpy(reinterpret_cast<char *>(output.data()), this->m_value.c_str());
|
||||
|
||||
output.pop_back();
|
||||
|
||||
this->setBufferOnOutput(0, output);
|
||||
this->setBufferOnOutput(0, { this->m_value.begin(), this->m_value.end() });
|
||||
}
|
||||
|
||||
void store(nlohmann::json &j) override {
|
||||
@@ -960,10 +956,10 @@ namespace hex::plugin::builtin {
|
||||
NodeVisualizerImage() : Node("hex.builtin.nodes.visualizer.image.header", { dp::Attribute(dp::Attribute::IOType::In, dp::Attribute::Type::Buffer, "hex.builtin.nodes.common.input") }) { }
|
||||
|
||||
void drawNode() override {
|
||||
ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.aspectRatio() * 200, 200)));
|
||||
ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.getAspectRatio() * 200, 200)));
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.aspectRatio() * 600, 600)));
|
||||
ImGui::Image(this->m_texture, scaled(ImVec2(this->m_texture.getAspectRatio() * 600, 600)));
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
@@ -971,10 +967,7 @@ namespace hex::plugin::builtin {
|
||||
void process() override {
|
||||
auto rawData = this->getBufferOnInput(0);
|
||||
|
||||
if (this->m_texture.valid())
|
||||
ImGui::UnloadImage(this->m_texture);
|
||||
|
||||
this->m_texture = ImGui::LoadImageFromMemory(rawData.data(), rawData.size());
|
||||
this->m_texture = ImGui::Texture(rawData.data(), rawData.size());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
@@ -106,7 +107,7 @@ namespace hex::plugin::builtin {
|
||||
const static inline auto FormattingUpperCase = hex::format("%0{}X", CharCount);
|
||||
const static inline auto FormattingLowerCase = hex::format("%0{}x", CharCount);
|
||||
|
||||
const char *getFormatString(bool upperCase) {
|
||||
static const char *getFormatString(bool upperCase) {
|
||||
if (upperCase)
|
||||
return FormattingUpperCase.c_str();
|
||||
else
|
||||
@@ -160,7 +161,9 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
};
|
||||
|
||||
template<std::floating_point T>
|
||||
enum class Float16 : u16 {};
|
||||
|
||||
template<typename T>
|
||||
class DataVisualizerFloatingPoint : public hex::ContentRegistry::HexEditor::DataVisualizer {
|
||||
public:
|
||||
DataVisualizerFloatingPoint() : DataVisualizer(ByteCount, CharCount) { }
|
||||
@@ -206,6 +209,42 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class DataVisualizerFloatingPoint<Float16> : public hex::ContentRegistry::HexEditor::DataVisualizer {
|
||||
public:
|
||||
DataVisualizerFloatingPoint() : DataVisualizer(ByteCount, CharCount) { }
|
||||
|
||||
void draw(u64 address, const u8 *data, size_t size, bool upperCase) override {
|
||||
hex::unused(address);
|
||||
|
||||
if (size == ByteCount)
|
||||
ImGui::Text(getFormatString(upperCase), hex::float16ToFloat32(*reinterpret_cast<const u16*>(data)));
|
||||
else
|
||||
ImGui::TextFormatted("{: {}s}", CharCount);
|
||||
}
|
||||
|
||||
bool drawEditing(u64 address, u8 *data, size_t size, bool upperCase, bool startedEditing) override {
|
||||
hex::unused(startedEditing);
|
||||
|
||||
this->draw(address, data, size, upperCase);
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
constexpr static inline auto ByteCount = sizeof(Float16);
|
||||
constexpr static inline auto CharCount = 14;
|
||||
|
||||
const static inline auto FormatStringUpperCase = hex::format("%{}G", CharCount);
|
||||
const static inline auto FormatStringLowerCase = hex::format("%{}g", CharCount);
|
||||
|
||||
static const char *getFormatString(bool upperCase) {
|
||||
if (upperCase)
|
||||
return FormatStringUpperCase.c_str();
|
||||
else
|
||||
return FormatStringLowerCase.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class DataVisualizerRGBA8 : public hex::ContentRegistry::HexEditor::DataVisualizer {
|
||||
public:
|
||||
DataVisualizerRGBA8() : DataVisualizer(4, 2) { }
|
||||
@@ -262,6 +301,7 @@ namespace hex::plugin::builtin {
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<i32>>("hex.builtin.visualizer.decimal.signed.32bit");
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerDecimal<i64>>("hex.builtin.visualizer.decimal.signed.64bit");
|
||||
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerFloatingPoint<Float16>>("hex.builtin.visualizer.floating_point.16bit");
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerFloatingPoint<float>>("hex.builtin.visualizer.floating_point.32bit");
|
||||
ContentRegistry::HexEditor::addDataVisualizer<DataVisualizerFloatingPoint<double>>("hex.builtin.visualizer.floating_point.64bit");
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
#include <imgui.h>
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include "provider_extra_data.hpp"
|
||||
#include <content/helpers/provider_extra_data.hpp>
|
||||
|
||||
#include "content/providers/file_provider.hpp"
|
||||
#include <content/providers/file_provider.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
@@ -21,7 +21,8 @@ namespace hex::plugin::builtin {
|
||||
auto provider = ImHexApi::Provider::createProvider("hex.builtin.provider.file", true);
|
||||
if (auto *fileProvider = dynamic_cast<prv::FileProvider*>(provider); fileProvider != nullptr) {
|
||||
fileProvider->setPath(path);
|
||||
(void)fileProvider->open();
|
||||
if (fileProvider->open())
|
||||
EventManager::post<EventProviderOpened>(fileProvider);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +78,9 @@ namespace hex::plugin::builtin {
|
||||
} else if (name == "Open Project") {
|
||||
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"} },
|
||||
[](const auto &path) {
|
||||
ProjectFile::load(path);
|
||||
if (!ProjectFile::load(path)) {
|
||||
View::showErrorPopup("hex.builtin.popup.error.project.load"_lang);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -100,6 +103,8 @@ namespace hex::plugin::builtin {
|
||||
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
|
||||
return;
|
||||
}
|
||||
|
||||
EventManager::post<EventProviderOpened>(provider);
|
||||
}
|
||||
else if (provider->hasLoadInterface())
|
||||
EventManager::post<RequestOpenPopup>(View::toWindowName("hex.builtin.view.provider_settings.load_popup"));
|
||||
@@ -107,7 +112,10 @@ namespace hex::plugin::builtin {
|
||||
if (!provider->open() || !provider->isAvailable()) {
|
||||
View::showErrorPopup("hex.builtin.popup.error.open"_lang);
|
||||
TaskManager::doLater([provider] { ImHexApi::Provider::remove(provider); });
|
||||
return;
|
||||
}
|
||||
|
||||
EventManager::post<EventProviderOpened>(provider);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -115,6 +123,14 @@ namespace hex::plugin::builtin {
|
||||
ProviderExtraData::erase(provider);
|
||||
});
|
||||
|
||||
fs::setFileBrowserErrorCallback([]{
|
||||
#if defined(NFD_PORTAL)
|
||||
View::showErrorPopup("hex.builtin.popup.error.file_dialog.portal"_lang);
|
||||
#else
|
||||
View::showErrorPopup("hex.builtin.popup.error.file_dialog.common"_lang);
|
||||
#endif
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "math_evaluator.hpp"
|
||||
#include <content/helpers/math_evaluator.hpp>
|
||||
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/concepts.hpp>
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <string>
|
||||
#include <queue>
|
||||
#include <stack>
|
||||
#include <stdexcept>
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
@@ -19,7 +18,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
bool MathEvaluator<T>::isLeftAssociative(const Operator op) {
|
||||
bool MathEvaluator<T>::isLeftAssociative(const Operator &op) {
|
||||
return (static_cast<u32>(op) & 0xF00) == 0;
|
||||
}
|
||||
|
||||
@@ -346,7 +345,7 @@ namespace hex {
|
||||
evaluationStack.push(result);
|
||||
} else if (front.type == TokenType::Variable) {
|
||||
if (this->m_variables.contains(front.name))
|
||||
evaluationStack.push(this->m_variables.at(front.name));
|
||||
evaluationStack.push(this->m_variables.at(front.name).value);
|
||||
else {
|
||||
this->setError("Unknown variable!");
|
||||
return std::nullopt;
|
||||
@@ -383,14 +382,14 @@ namespace hex {
|
||||
template<typename T>
|
||||
std::optional<T> MathEvaluator<T>::evaluate(const std::string &input) {
|
||||
auto inputQueue = parseInput(input);
|
||||
if (!inputQueue.has_value())
|
||||
if (!inputQueue.has_value() || inputQueue->empty())
|
||||
return std::nullopt;
|
||||
|
||||
std::string resultVariable = "ans";
|
||||
|
||||
{
|
||||
auto queueCopy = *inputQueue;
|
||||
if (queueCopy.front().type == TokenType::Variable) {
|
||||
if (queueCopy.front().type == TokenType::Variable && queueCopy.size() > 2) {
|
||||
resultVariable = queueCopy.front().name;
|
||||
queueCopy.pop();
|
||||
if (queueCopy.front().type != TokenType::Operator || queueCopy.front().op != Operator::Assign)
|
||||
@@ -408,16 +407,15 @@ namespace hex {
|
||||
|
||||
auto result = evaluate(*postfixTokens);
|
||||
|
||||
if (result.has_value()) {
|
||||
if (result.has_value() && !this->getVariables()[resultVariable].constant)
|
||||
this->setVariable(resultVariable, result.value());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void MathEvaluator<T>::setVariable(const std::string &name, T value) {
|
||||
this->m_variables[name] = value;
|
||||
void MathEvaluator<T>::setVariable(const std::string &name, T value, bool constant) {
|
||||
this->m_variables[name] = { value, constant };
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -436,6 +434,9 @@ namespace hex {
|
||||
template<typename T>
|
||||
void MathEvaluator<T>::registerStandardVariables() {
|
||||
this->setVariable("ans", 0);
|
||||
this->setVariable("pi", std::numbers::pi, true);
|
||||
this->setVariable("e", std::numbers::e, true);
|
||||
this->setVariable("phi", std::numbers::phi, true);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "pattern_drawer.hpp"
|
||||
#include <content/helpers/pattern_drawer.hpp>
|
||||
|
||||
#include <pl/patterns/pattern_array_dynamic.hpp>
|
||||
#include <pl/patterns/pattern_array_static.hpp>
|
||||
@@ -25,21 +25,108 @@
|
||||
#include <imgui.h>
|
||||
#include <hex/ui/imgui_imhex_extensions.h>
|
||||
|
||||
namespace {
|
||||
constexpr static auto DisplayEndDefault = 50u;
|
||||
constexpr static auto DisplayEndStep = 50u;
|
||||
|
||||
using namespace ::std::literals::string_literals;
|
||||
};
|
||||
|
||||
namespace hex {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr auto DisplayEndDefault = 50U;
|
||||
constexpr auto DisplayEndStep = 50U;
|
||||
|
||||
using namespace ::std::literals::string_literals;
|
||||
|
||||
void createLeafNode(const pl::ptrn::Pattern& pattern) {
|
||||
ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_Leaf |
|
||||
ImGuiTreeNodeFlags_NoTreePushOnOpen |
|
||||
ImGuiTreeNodeFlags_SpanFullWidth |
|
||||
ImGuiTreeNodeFlags_AllowItemOverlap);
|
||||
}
|
||||
|
||||
bool createTreeNode(const pl::ptrn::Pattern& pattern) {
|
||||
if (pattern.isSealed()) {
|
||||
ImGui::Indent();
|
||||
ImGui::TextUnformatted(pattern.getDisplayName().c_str());
|
||||
ImGui::Unindent();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
}
|
||||
|
||||
void drawTypenameColumn(const pl::ptrn::Pattern& pattern, const std::string& pattern_name) {
|
||||
ImGui::TextFormattedColored(ImColor(0xFFD69C56), pattern_name);
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted(pattern.getTypeName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
}
|
||||
|
||||
void drawNameColumn(const pl::ptrn::Pattern& pattern) {
|
||||
ImGui::TextUnformatted(pattern.getDisplayName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
}
|
||||
|
||||
void drawColorColumn(const pl::ptrn::Pattern& pattern) {
|
||||
ImGui::ColorButton("color", ImColor(pattern.getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
|
||||
ImGui::TableNextColumn();
|
||||
}
|
||||
|
||||
void drawOffsetColumn(const pl::ptrn::Pattern& pattern) {
|
||||
ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", pattern.getOffset(), pattern.getOffset() + pattern.getSize() - (pattern.getSize() == 0 ? 0 : 1));
|
||||
ImGui::TableNextColumn();
|
||||
}
|
||||
|
||||
void drawSizeColumn(const pl::ptrn::Pattern& pattern) {
|
||||
ImGui::TextFormatted("0x{0:04X}", pattern.getSize());
|
||||
ImGui::TableNextColumn();
|
||||
}
|
||||
|
||||
void drawCommentTooltip(const pl::ptrn::Pattern &pattern) {
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && pattern.getComment() != nullptr) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted(pattern.getComment()->c_str());
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
|
||||
void makeSelectable(const pl::ptrn::Pattern &pattern) {
|
||||
ImGui::PushID(static_cast<int>(pattern.getOffset()));
|
||||
ImGui::PushID(pattern.getVariableName().c_str());
|
||||
|
||||
if (ImGui::Selectable("##PatternLine", false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
||||
ImHexApi::HexEditor::setSelection(pattern.getOffset(), pattern.getSize());
|
||||
}
|
||||
|
||||
ImGui::SameLine(0, 0);
|
||||
|
||||
ImGui::PopID();
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
void createDefaultEntry(pl::ptrn::Pattern &pattern) {
|
||||
ImGui::TableNextRow();
|
||||
createLeafNode(pattern);
|
||||
ImGui::TableNextColumn();
|
||||
makeSelectable(pattern);
|
||||
drawCommentTooltip(pattern);
|
||||
ImGui::SameLine();
|
||||
drawNameColumn(pattern);
|
||||
drawColorColumn(pattern);
|
||||
drawOffsetColumn(pattern);
|
||||
drawSizeColumn(pattern);
|
||||
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{}", pattern.getFormattedName().empty() ? pattern.getTypeName() : pattern.getFormattedName());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", pattern.getFormattedValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void PatternDrawer::visit(pl::ptrn::PatternArrayDynamic& pattern) {
|
||||
this->drawArray(pattern);
|
||||
drawArray(pattern, pattern, pattern.isInlined());
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::ptrn::PatternArrayStatic& pattern) {
|
||||
this->drawArray(pattern);
|
||||
drawArray(pattern, pattern, pattern.isInlined());
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::ptrn::PatternBitfieldField& pattern) {
|
||||
@@ -81,15 +168,12 @@ namespace hex {
|
||||
ImGui::TableNextColumn();
|
||||
makeSelectable(pattern);
|
||||
drawCommentTooltip(pattern);
|
||||
ImGui::TableNextColumn();
|
||||
drawColorColumn(pattern);
|
||||
drawOffsetColumn(pattern);
|
||||
drawSizeColumn(pattern);
|
||||
drawTypenameColumn(pattern, "bitfield");
|
||||
|
||||
ImGui::TextFormatted("{}", pattern.getFormattedValue());
|
||||
} else {
|
||||
ImGui::SameLine();
|
||||
ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf);
|
||||
}
|
||||
|
||||
if (open) {
|
||||
@@ -97,16 +181,17 @@ namespace hex {
|
||||
this->draw(field);
|
||||
});
|
||||
|
||||
ImGui::TreePop();
|
||||
if (!pattern.isInlined())
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::ptrn::PatternBoolean& pattern) {
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), bool(hex::get_or<u128>(pattern.getValue(), 0x00)));
|
||||
createDefaultEntry(pattern);
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::ptrn::PatternCharacter& pattern) {
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), pattern.getValue());
|
||||
createDefaultEntry(pattern);
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::ptrn::PatternEnum& pattern) {
|
||||
@@ -125,11 +210,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::ptrn::PatternFloat& pattern) {
|
||||
if (pattern.getSize() == 4) {
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), pattern.getValue());
|
||||
} else if (pattern.getSize() == 8) {
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), pattern.getValue());
|
||||
}
|
||||
createDefaultEntry(pattern);
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::ptrn::PatternPadding& pattern) {
|
||||
@@ -147,32 +228,29 @@ namespace hex {
|
||||
ImGui::TableNextColumn();
|
||||
makeSelectable(pattern);
|
||||
drawCommentTooltip(pattern);
|
||||
ImGui::SameLine(0, 0);
|
||||
drawColorColumn(pattern);
|
||||
drawOffsetColumn(pattern);
|
||||
drawSizeColumn(pattern);
|
||||
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{}", pattern.getFormattedName());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", pattern.getFormattedValue());
|
||||
} else {
|
||||
ImGui::SameLine();
|
||||
ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf);
|
||||
}
|
||||
|
||||
if (open) {
|
||||
pattern.getPointedAtPattern()->accept(*this);
|
||||
|
||||
ImGui::TreePop();
|
||||
if (!pattern.isInlined())
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::ptrn::PatternSigned& pattern) {
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), pattern.getValue());
|
||||
createDefaultEntry(pattern);
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::ptrn::PatternString& pattern) {
|
||||
if (pattern.getSize() > 0)
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), pattern.getValue());
|
||||
createDefaultEntry(pattern);
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::ptrn::PatternStruct& pattern) {
|
||||
@@ -185,22 +263,23 @@ namespace hex {
|
||||
ImGui::TableNextColumn();
|
||||
makeSelectable(pattern);
|
||||
drawCommentTooltip(pattern);
|
||||
ImGui::TableNextColumn();
|
||||
if (pattern.isSealed())
|
||||
drawColorColumn(pattern);
|
||||
else
|
||||
ImGui::TableNextColumn();
|
||||
drawOffsetColumn(pattern);
|
||||
drawSizeColumn(pattern);
|
||||
drawTypenameColumn(pattern, "struct");
|
||||
ImGui::TextFormatted("{}", pattern.getFormattedValue());
|
||||
} else {
|
||||
ImGui::SameLine();
|
||||
ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf);
|
||||
}
|
||||
|
||||
if (open) {
|
||||
pattern.forEachMember([&](auto &member){
|
||||
this->draw(member);
|
||||
pattern.forEachEntry(0, pattern.getMembers().size(), [&](u64, auto *member){
|
||||
this->draw(*member);
|
||||
});
|
||||
|
||||
ImGui::TreePop();
|
||||
if (!pattern.isInlined())
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,74 +293,37 @@ namespace hex {
|
||||
ImGui::TableNextColumn();
|
||||
makeSelectable(pattern);
|
||||
drawCommentTooltip(pattern);
|
||||
ImGui::TableNextColumn();
|
||||
if (pattern.isSealed())
|
||||
drawColorColumn(pattern);
|
||||
else
|
||||
ImGui::TableNextColumn();
|
||||
drawOffsetColumn(pattern);
|
||||
drawSizeColumn(pattern);
|
||||
drawTypenameColumn(pattern, "union");
|
||||
ImGui::TextFormatted("{}", pattern.getFormattedValue());
|
||||
} else {
|
||||
ImGui::SameLine();
|
||||
ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf);
|
||||
}
|
||||
|
||||
if (open) {
|
||||
pattern.forEachMember([&](auto &member) {
|
||||
this->draw(member);
|
||||
pattern.forEachEntry(0, pattern.getEntryCount(), [&](u64, auto *member) {
|
||||
this->draw(*member);
|
||||
});
|
||||
|
||||
ImGui::TreePop();
|
||||
if (!pattern.isInlined())
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::ptrn::PatternUnsigned& pattern) {
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), pattern.getValue());
|
||||
createDefaultEntry(pattern);
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::ptrn::PatternWideCharacter& pattern) {
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), pattern.getValue());
|
||||
createDefaultEntry(pattern);
|
||||
}
|
||||
|
||||
void PatternDrawer::visit(pl::ptrn::PatternWideString& pattern) {
|
||||
if (pattern.getSize() > 0)
|
||||
this->createDefaultEntry(pattern, pattern.getFormattedValue(), pattern.getValue());
|
||||
}
|
||||
|
||||
void PatternDrawer::createDefaultEntry(const pl::ptrn::Pattern &pattern, const std::string &value, pl::core::Token::Literal &&literal) const {
|
||||
ImGui::TableNextRow();
|
||||
createLeafNode(pattern);
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
makeSelectable(pattern);
|
||||
|
||||
drawCommentTooltip(pattern);
|
||||
ImGui::SameLine();
|
||||
drawNameColumn(pattern);
|
||||
drawColorColumn(pattern);
|
||||
drawOffsetColumn(pattern);
|
||||
drawSizeColumn(pattern);
|
||||
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{}", pattern.getFormattedName().empty() ? pattern.getTypeName() : pattern.getFormattedName());
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", pattern.formatDisplayValue(value, literal));
|
||||
}
|
||||
|
||||
void PatternDrawer::makeSelectable(const pl::ptrn::Pattern &pattern) const {
|
||||
ImGui::PushID(static_cast<int>(pattern.getOffset()));
|
||||
ImGui::PushID(pattern.getVariableName().c_str());
|
||||
if (ImGui::Selectable("##PatternLine", false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap)) {
|
||||
ImHexApi::HexEditor::setSelection(pattern.getOffset(), pattern.getSize());
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::PopID();
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
|
||||
void PatternDrawer::drawCommentTooltip(const pl::ptrn::Pattern &pattern) const {
|
||||
if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) && pattern.getComment() != nullptr) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted(pattern.getComment()->c_str());
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
createDefaultEntry(pattern);
|
||||
}
|
||||
|
||||
void PatternDrawer::draw(pl::ptrn::Pattern& pattern) {
|
||||
@@ -291,9 +333,9 @@ namespace hex {
|
||||
pattern.accept(*this);
|
||||
}
|
||||
|
||||
bool PatternDrawer::drawArrayRoot(pl::ptrn::Pattern& pattern, size_t entryCount, bool isInlined) {
|
||||
if (entryCount == 0)
|
||||
return false;
|
||||
void PatternDrawer::drawArray(pl::ptrn::Pattern& pattern, pl::ptrn::Iteratable &iteratable, bool isInlined) {
|
||||
if (iteratable.getEntryCount() == 0)
|
||||
return;
|
||||
|
||||
bool open = true;
|
||||
if (!isInlined) {
|
||||
@@ -303,7 +345,10 @@ namespace hex {
|
||||
ImGui::TableNextColumn();
|
||||
makeSelectable(pattern);
|
||||
drawCommentTooltip(pattern);
|
||||
ImGui::TableNextColumn();
|
||||
if (pattern.isSealed())
|
||||
drawColorColumn(pattern);
|
||||
else
|
||||
ImGui::TableNextColumn();
|
||||
drawOffsetColumn(pattern);
|
||||
drawSizeColumn(pattern);
|
||||
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{0}", pattern.getTypeName());
|
||||
@@ -311,98 +356,78 @@ namespace hex {
|
||||
|
||||
ImGui::TextUnformatted("[");
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextFormattedColored(ImColor(0xFF00FF00), "{0}", entryCount);
|
||||
ImGui::TextFormattedColored(ImColor(0xFF00FF00), "{0}", iteratable.getEntryCount());
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextUnformatted("]");
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{}", pattern.getFormattedValue());
|
||||
} else {
|
||||
ImGui::SameLine();
|
||||
ImGui::TreeNodeEx("", ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf);
|
||||
}
|
||||
|
||||
return open;
|
||||
}
|
||||
if (open) {
|
||||
u64 chunkCount = 0;
|
||||
for (u64 i = 0; i < iteratable.getEntryCount(); i += ChunkSize) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
void PatternDrawer::drawArrayNode(u64 idx, u64& displayEnd, pl::ptrn::Pattern& pattern) {
|
||||
u64 lastVisible = displayEnd - 1;
|
||||
chunkCount++;
|
||||
|
||||
ImGui::PushID(pattern.getOffset());
|
||||
auto &displayEnd = this->getDisplayEnd(pattern);
|
||||
if (chunkCount > displayEnd) {
|
||||
ImGui::Selectable("... (Double-click to see more items)", false, ImGuiSelectableFlags_SpanAllColumns);
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
|
||||
displayEnd += DisplayEndStep;
|
||||
break;
|
||||
} else {
|
||||
auto endIndex = std::min<u64>(iteratable.getEntryCount(), i + ChunkSize);
|
||||
|
||||
if (idx < lastVisible) {
|
||||
this->draw(pattern);
|
||||
} else if (idx == lastVisible) {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
auto startOffset = iteratable.getEntry(i)->getOffset();
|
||||
auto endOffset = iteratable.getEntry(endIndex - 1)->getOffset();
|
||||
auto endSize = iteratable.getEntry(endIndex - 1)->getSize();
|
||||
|
||||
ImGui::Selectable("... (Double-click to see more items)", false, ImGuiSelectableFlags_SpanAllColumns);
|
||||
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left))
|
||||
displayEnd += DisplayEndStep;
|
||||
size_t chunkSize = (endOffset - startOffset) + endSize;
|
||||
|
||||
auto chunkOpen = ImGui::TreeNode(hex::format("[{} ... {}]", i, endIndex - 1).c_str());
|
||||
ImGui::TableNextColumn();
|
||||
drawColorColumn(pattern);
|
||||
ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", startOffset, startOffset + chunkSize - (pattern.getSize() == 0 ? 0 : 1));
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("0x{0:04X}", chunkSize);
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormattedColored(ImColor(0xFF9BC64D), "{0}", pattern.getTypeName());
|
||||
ImGui::SameLine(0, 0);
|
||||
|
||||
ImGui::TextUnformatted("[");
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextFormattedColored(ImColor(0xFF00FF00), "{0}", endIndex - i);
|
||||
ImGui::SameLine(0, 0);
|
||||
ImGui::TextUnformatted("]");
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("[ ... ]");
|
||||
|
||||
if (chunkOpen) {
|
||||
iteratable.forEachEntry(i, endIndex, [&](u64, auto *entry){
|
||||
this->draw(*entry);
|
||||
});
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!isInlined)
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
void PatternDrawer::drawArrayEnd(pl::ptrn::Pattern& pattern, bool opened) {
|
||||
if (opened) {
|
||||
ImGui::TreePop();
|
||||
} else {
|
||||
auto& displayEnd = this->getDisplayEnd(pattern);
|
||||
displayEnd = DisplayEndDefault;
|
||||
}
|
||||
}
|
||||
|
||||
void PatternDrawer::createLeafNode(const pl::ptrn::Pattern& pattern) const {
|
||||
ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_Leaf |
|
||||
ImGuiTreeNodeFlags_NoTreePushOnOpen |
|
||||
ImGuiTreeNodeFlags_SpanFullWidth |
|
||||
ImGuiTreeNodeFlags_AllowItemOverlap);
|
||||
}
|
||||
|
||||
bool PatternDrawer::createTreeNode(const pl::ptrn::Pattern& pattern) const {
|
||||
if (pattern.isSealed()) {
|
||||
ImGui::Selectable(pattern.getDisplayName().c_str(), false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowItemOverlap);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
}
|
||||
|
||||
void PatternDrawer::drawTypenameColumn(const pl::ptrn::Pattern& pattern, const std::string& pattern_name) const {
|
||||
ImGui::TextFormattedColored(ImColor(0xFFD69C56), pattern_name);
|
||||
ImGui::SameLine();
|
||||
ImGui::TextUnformatted(pattern.getTypeName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
}
|
||||
|
||||
void PatternDrawer::drawNameColumn(const pl::ptrn::Pattern& pattern) const {
|
||||
ImGui::TextUnformatted(pattern.getDisplayName().c_str());
|
||||
ImGui::TableNextColumn();
|
||||
}
|
||||
|
||||
void PatternDrawer::drawColorColumn(const pl::ptrn::Pattern& pattern) const {
|
||||
ImGui::ColorButton("color", ImColor(pattern.getColor()), ImGuiColorEditFlags_NoTooltip, ImVec2(ImGui::GetColumnWidth(), ImGui::GetTextLineHeight()));
|
||||
ImGui::TableNextColumn();
|
||||
}
|
||||
|
||||
void PatternDrawer::drawOffsetColumn(const pl::ptrn::Pattern& pattern) const {
|
||||
ImGui::TextFormatted("0x{0:08X} : 0x{1:08X}", pattern.getOffset(), pattern.getOffset() + pattern.getSize() - (pattern.getSize() == 0 ? 0 : 1));
|
||||
ImGui::TableNextColumn();
|
||||
}
|
||||
|
||||
void PatternDrawer::drawSizeColumn(const pl::ptrn::Pattern& pattern) const {
|
||||
ImGui::TextFormatted("0x{0:04X}", pattern.getSize());
|
||||
ImGui::TableNextColumn();
|
||||
}
|
||||
|
||||
u64& PatternDrawer::getDisplayEnd(const pl::ptrn::Pattern& pattern) {
|
||||
auto it = m_displayEnd.find(&pattern);
|
||||
if (it != m_displayEnd.end()) {
|
||||
auto it = this->m_displayEnd.find(&pattern);
|
||||
if (it != this->m_displayEnd.end()) {
|
||||
return it->second;
|
||||
}
|
||||
|
||||
auto [inserted, success] = m_displayEnd.emplace(&pattern, DisplayEndDefault);
|
||||
return inserted->second;
|
||||
auto [value, success] = this->m_displayEnd.emplace(&pattern, DisplayEndDefault);
|
||||
return value->second;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -38,6 +38,14 @@ namespace hex::plugin::builtin {
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("hex.builtin.menu.file.reload_file"_lang, "CTRL + R", false, !taskRunning && ImHexApi::Provider::isValid())) {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
provider->close();
|
||||
if (!provider->open())
|
||||
ImHexApi::Provider::remove(provider, true);
|
||||
}
|
||||
});
|
||||
|
||||
/* File open, quit imhex */
|
||||
@@ -64,7 +72,9 @@ namespace hex::plugin::builtin {
|
||||
fs::openFileBrowser(fs::DialogMode::Open, { {"Project File", "hexproj"}
|
||||
},
|
||||
[](const auto &path) {
|
||||
ProjectFile::load(path);
|
||||
if (!ProjectFile::load(path)) {
|
||||
View::showErrorPopup("hex.builtin.popup.error.project.load"_lang);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -75,7 +85,9 @@ namespace hex::plugin::builtin {
|
||||
path.replace_extension(".hexproj");
|
||||
}
|
||||
|
||||
ProjectFile::store(path);
|
||||
if (!ProjectFile::store(path)) {
|
||||
View::showErrorPopup("hex.builtin.popup.error.project.save"_lang);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||