Compare commits
102 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86e33a1ee9 | ||
|
|
37850ad85a | ||
|
|
daca49658e | ||
|
|
6975d7e2cd | ||
|
|
5b8bed6083 | ||
|
|
7474aa3e5d | ||
|
|
c6d2d51d4c | ||
|
|
9055105627 | ||
|
|
a44de63e24 | ||
|
|
8fc7931132 | ||
|
|
4070833229 | ||
|
|
3a9c3f939e | ||
|
|
aa42fb5076 | ||
|
|
50158a7977 | ||
|
|
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 |
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
|
||||
...
|
||||
|
||||
12
.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}}
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -15,7 +15,7 @@ These builds are not guaranteed to be stable and may contain bugs, however they
|
||||
|
||||
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)
|
||||
- macOS: [Link](dist/compiling/macOS.md)
|
||||
- Linux: [Link](dist/compiling/linux.md)
|
||||
|
||||
## Package managers
|
||||
|
||||
@@ -408,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}")
|
||||
|
||||
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 \
|
||||
|
||||
2
lib/external/curl
vendored
2
lib/external/fmt
vendored
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)
|
||||
@@ -136,6 +137,7 @@ set(LIBIMHEX_SOURCES
|
||||
source/helpers/encoding_file.cpp
|
||||
source/helpers/logger.cpp
|
||||
source/helpers/tar.cpp
|
||||
source/helpers/types.cpp
|
||||
|
||||
source/providers/provider.cpp
|
||||
|
||||
@@ -172,4 +174,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)
|
||||
|
||||
@@ -1,8 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
|
||||
#include <hex/helpers/types.hpp>
|
||||
#include <hex/helpers/intrinsics.hpp>
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
@@ -51,15 +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; };
|
||||
@@ -86,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();
|
||||
@@ -100,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())
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -60,6 +61,7 @@ namespace hex {
|
||||
|
||||
private:
|
||||
CURL *m_ctx;
|
||||
mbedtls_x509_crt m_caCert;
|
||||
curl_slist *m_headers = nullptr;
|
||||
|
||||
std::mutex m_transmissionActive;
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
|
||||
using u8 = std::uint8_t;
|
||||
using u16 = std::uint16_t;
|
||||
using u32 = std::uint32_t;
|
||||
@@ -20,29 +23,14 @@ namespace hex {
|
||||
u64 address;
|
||||
size_t size;
|
||||
|
||||
[[nodiscard]] constexpr bool isWithin(const Region &other) const {
|
||||
return (this->getStartAddress() >= other.getStartAddress()) && (this->getEndAddress() <= other.getEndAddress()) && *this != Invalid() && other != Invalid();
|
||||
}
|
||||
[[nodiscard]] bool isWithin(const Region &other) const;
|
||||
[[nodiscard]] bool overlaps(const Region &other) const;
|
||||
|
||||
[[nodiscard]] constexpr bool overlaps(const Region &other) const {
|
||||
return (this->getEndAddress() >= other.getStartAddress()) && (this->getStartAddress() < other.getEndAddress()) && *this != Invalid() && other != Invalid();
|
||||
}
|
||||
[[nodiscard]] u64 getStartAddress() const;
|
||||
[[nodiscard]] u64 getEndAddress() const;
|
||||
[[nodiscard]] size_t getSize() const;
|
||||
|
||||
[[nodiscard]] constexpr u64 getStartAddress() const {
|
||||
return this->address;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr u64 getEndAddress() const {
|
||||
return this->address + this->size - 1;
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr size_t getSize() const {
|
||||
return this->size;
|
||||
}
|
||||
|
||||
constexpr bool operator==(const Region &other) const {
|
||||
return this->address == other.address && this->size == other.size;
|
||||
}
|
||||
bool operator==(const Region &other) const;
|
||||
|
||||
constexpr static Region Invalid() {
|
||||
return { 0, 0 };
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -86,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);
|
||||
@@ -98,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);
|
||||
|
||||
@@ -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 {
|
||||
@@ -385,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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -392,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,59 +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() {
|
||||
if (!this->isFinished())
|
||||
this->interrupt();
|
||||
|
||||
this->m_thread.join();
|
||||
}
|
||||
|
||||
void Task::update(u64 value) {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
|
||||
this->m_currValue = value;
|
||||
|
||||
if (this->m_shouldInterrupt)
|
||||
@@ -64,15 +51,11 @@ 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)
|
||||
@@ -83,27 +66,23 @@ namespace hex {
|
||||
this->m_interruptCallback = std::move(callback);
|
||||
}
|
||||
|
||||
bool Task::isFinished() const {
|
||||
std::scoped_lock lock(this->m_mutex);
|
||||
bool Task::isBackgroundTask() const {
|
||||
return this->m_background;
|
||||
}
|
||||
|
||||
bool Task::isFinished() const {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -126,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;
|
||||
}
|
||||
|
||||
@@ -146,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(); });
|
||||
}
|
||||
|
||||
@@ -178,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,7 +188,7 @@ namespace hex {
|
||||
curl_mime *mime = curl_mime_init(this->m_ctx);
|
||||
curl_mimepart *part = curl_mime_addpart(mime);
|
||||
|
||||
auto fileName = filePath.filename().string();
|
||||
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);
|
||||
|
||||
41
lib/libimhex/source/helpers/types.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
#include <hex/helpers/types.hpp>
|
||||
|
||||
namespace hex {
|
||||
|
||||
[[nodiscard]] bool Region::isWithin(const Region &other) const {
|
||||
if (*this == Invalid() || other == Invalid())
|
||||
return false;
|
||||
|
||||
if (this->getStartAddress() >= other.getStartAddress() && this->getEndAddress() <= other.getEndAddress())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool Region::overlaps(const Region &other) const {
|
||||
if (*this == Invalid() || other == Invalid())
|
||||
return false;
|
||||
|
||||
if (this->getEndAddress() >= other.getStartAddress() && this->getStartAddress() <= other.getEndAddress())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 Region::getStartAddress() const {
|
||||
return this->address;
|
||||
}
|
||||
|
||||
[[nodiscard]] u64 Region::getEndAddress() const {
|
||||
return this->address + this->size - 1;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t Region::getSize() const {
|
||||
return this->size;
|
||||
}
|
||||
|
||||
bool Region::operator==(const Region &other) const {
|
||||
return this->address == other.address && this->size == other.size;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -113,6 +113,8 @@ namespace hex::prv {
|
||||
this->writeRaw(patchAddress - this->getBaseAddress(), &patch, 1);
|
||||
}
|
||||
this->markDirty();
|
||||
|
||||
this->m_patches.emplace_back();
|
||||
}
|
||||
|
||||
|
||||
@@ -288,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
|
||||
@@ -53,11 +54,21 @@ int main(int argc, char **argv, char **envp) {
|
||||
if (argc == 1)
|
||||
; // No arguments provided
|
||||
else if (argc >= 2) {
|
||||
for (auto i = 1; i < argc; i++)
|
||||
EventManager::post<RequestOpenFile>(argv[i]);
|
||||
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);
|
||||
|
||||
@@ -43,7 +43,7 @@ namespace hex {
|
||||
if (data == nullptr) break;
|
||||
|
||||
std::fs::path path = data;
|
||||
log::info("Opening file in existing instance: {}", path.string());
|
||||
log::info("Opening file in existing instance: {}", hex::toUTF8String(path));
|
||||
EventManager::post<RequestOpenFile>(path);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
{
|
||||
@@ -132,18 +133,20 @@ namespace hex {
|
||||
constexpr static auto CrashBackupFileName = "crash_backup.hexproj";
|
||||
|
||||
EventManager::subscribe<EventAbnormalTermination>(this, [this](int) {
|
||||
ImGui::SaveIniSettingsToDisk(this->m_imguiSettingsPath.string().c_str());
|
||||
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();
|
||||
|
||||
@@ -84,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();
|
||||
@@ -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;
|
||||
|
||||
@@ -6,11 +6,6 @@
|
||||
|
||||
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;
|
||||
@@ -36,27 +31,13 @@ namespace hex {
|
||||
private:
|
||||
void draw(pl::ptrn::Pattern& pattern);
|
||||
|
||||
template<ArrayPattern T>
|
||||
void drawArray(T& pattern) {
|
||||
bool opened = this->drawArrayRoot(pattern, pattern.getEntryCount(), pattern.isInlined());
|
||||
|
||||
if (opened) {
|
||||
auto& displayEnd = this->getDisplayEnd(pattern);
|
||||
pattern.forEachArrayEntry(displayEnd, [&] (u64 idx, auto &entry){
|
||||
this->drawArrayNode(idx, displayEnd, entry);
|
||||
});
|
||||
}
|
||||
|
||||
this->drawArrayEnd(pattern, opened, pattern.isInlined());
|
||||
}
|
||||
|
||||
bool drawArrayRoot(pl::ptrn::Pattern& pattern, size_t entryCount, bool isInlined);
|
||||
void drawArrayNode(u64 idx, u64& displayEnd, pl::ptrn::Pattern& pattern);
|
||||
void drawArrayEnd(pl::ptrn::Pattern& pattern, bool opened, bool inlined);
|
||||
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;
|
||||
|
||||
|
||||
@@ -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,7 +57,7 @@ namespace hex::plugin::builtin {
|
||||
bool m_lineFeeds = false;
|
||||
} strings;
|
||||
|
||||
struct Bytes {
|
||||
struct Sequence {
|
||||
std::string sequence;
|
||||
} bytes;
|
||||
|
||||
@@ -68,6 +70,18 @@ namespace hex::plugin::builtin {
|
||||
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>;
|
||||
@@ -80,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,19 +50,29 @@ 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() {
|
||||
void jumpToSelection(bool center = true) {
|
||||
this->m_shouldJumpToSelection = true;
|
||||
|
||||
if (center)
|
||||
this->m_centerOnJump = true;
|
||||
}
|
||||
|
||||
void scrollToSelection() {
|
||||
@@ -110,6 +114,7 @@ namespace hex::plugin::builtin {
|
||||
void drawFooter(const ImVec2 &size);
|
||||
|
||||
void handleSelection(u64 address, u32 bytesPerCell, const u8 *data, bool cellHovered);
|
||||
std::optional<color_t> applySelectionColor(u64 byteAddress, std::optional<color_t> color);
|
||||
|
||||
private:
|
||||
u16 m_bytesPerRow = 16;
|
||||
@@ -117,12 +122,12 @@ namespace hex::plugin::builtin {
|
||||
ContentRegistry::HexEditor::DataVisualizer *m_currDataVisualizer;
|
||||
|
||||
bool m_shouldJumpToSelection = false;
|
||||
bool m_centerOnJump = 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 +141,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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
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 |
@@ -64,7 +64,7 @@ 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) {
|
||||
|
||||
@@ -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,46 @@ 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());
|
||||
|
||||
auto string = std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t>("Invalid").to_bytes(stringBuffer.data());
|
||||
value = copyValue = hex::encodeByteString({ string.begin(), string.end() });
|
||||
|
||||
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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -78,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);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -121,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
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -345,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;
|
||||
@@ -382,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)
|
||||
@@ -407,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>
|
||||
@@ -435,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>
|
||||
|
||||
@@ -34,6 +34,43 @@ namespace hex {
|
||||
|
||||
using namespace ::std::literals::string_literals;
|
||||
|
||||
bool isPatternSelected(u64 address, u64 size) {
|
||||
auto currSelection = ImHexApi::HexEditor::getSelection();
|
||||
if (!currSelection.has_value())
|
||||
return false;
|
||||
|
||||
return Region{ address, size }.overlaps(*currSelection);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto highlightWhenSelected(u64 address, u64 size, const T &callback) {
|
||||
constexpr bool HasReturn = !requires(T t) { { t() } -> std::same_as<void>; };
|
||||
|
||||
auto selected = isPatternSelected(address, size);
|
||||
|
||||
if (selected)
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyleColorVec4(ImGuiCol_HeaderActive));
|
||||
|
||||
if constexpr (HasReturn) {
|
||||
auto result = callback();
|
||||
|
||||
if (selected)
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
return result;
|
||||
} else {
|
||||
callback();
|
||||
|
||||
if (selected)
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
auto highlightWhenSelected(const pl::ptrn::Pattern& pattern, const T &callback) {
|
||||
return highlightWhenSelected(pattern.getOffset(), pattern.getSize(), callback);
|
||||
}
|
||||
|
||||
void createLeafNode(const pl::ptrn::Pattern& pattern) {
|
||||
ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_Leaf |
|
||||
ImGuiTreeNodeFlags_NoTreePushOnOpen |
|
||||
@@ -44,12 +81,13 @@ namespace hex {
|
||||
bool createTreeNode(const pl::ptrn::Pattern& pattern) {
|
||||
if (pattern.isSealed()) {
|
||||
ImGui::Indent();
|
||||
ImGui::TextUnformatted(pattern.getDisplayName().c_str());
|
||||
highlightWhenSelected(pattern, [&]{ ImGui::TextUnformatted(pattern.getDisplayName().c_str()); });
|
||||
ImGui::Unindent();
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);
|
||||
else {
|
||||
return highlightWhenSelected(pattern, [&]{ return ImGui::TreeNodeEx(pattern.getDisplayName().c_str(), ImGuiTreeNodeFlags_SpanFullWidth);});
|
||||
}
|
||||
}
|
||||
|
||||
void drawTypenameColumn(const pl::ptrn::Pattern& pattern, const std::string& pattern_name) {
|
||||
@@ -60,7 +98,7 @@ namespace hex {
|
||||
}
|
||||
|
||||
void drawNameColumn(const pl::ptrn::Pattern& pattern) {
|
||||
ImGui::TextUnformatted(pattern.getDisplayName().c_str());
|
||||
highlightWhenSelected(pattern, [&]{ ImGui::TextUnformatted(pattern.getDisplayName().c_str()); });
|
||||
ImGui::TableNextColumn();
|
||||
}
|
||||
|
||||
@@ -119,12 +157,14 @@ namespace hex {
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
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) {
|
||||
@@ -272,8 +312,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
if (open) {
|
||||
pattern.forEachMember([&](auto &member){
|
||||
this->draw(member);
|
||||
pattern.forEachEntry(0, pattern.getMembers().size(), [&](u64, auto *member){
|
||||
this->draw(*member);
|
||||
});
|
||||
|
||||
if (!pattern.isInlined())
|
||||
@@ -302,8 +342,8 @@ namespace hex {
|
||||
}
|
||||
|
||||
if (open) {
|
||||
pattern.forEachMember([&](auto &member) {
|
||||
this->draw(member);
|
||||
pattern.forEachEntry(0, pattern.getEntryCount(), [&](u64, auto *member) {
|
||||
this->draw(*member);
|
||||
});
|
||||
|
||||
if (!pattern.isInlined())
|
||||
@@ -331,9 +371,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) {
|
||||
@@ -354,7 +394,7 @@ 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("]");
|
||||
|
||||
@@ -362,35 +402,60 @@ namespace hex {
|
||||
ImGui::TextFormatted("{}", pattern.getFormattedValue());
|
||||
}
|
||||
|
||||
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(reinterpret_cast<void*>(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;
|
||||
|
||||
ImGui::PopID();
|
||||
}
|
||||
auto chunkOpen = highlightWhenSelected(startOffset, ((endOffset + endSize) - startOffset) - 1, [&]{ return ImGui::TreeNodeEx(hex::format("[{} ... {}]", i, endIndex - 1).c_str(), ImGuiTreeNodeFlags_SpanFullWidth); });
|
||||
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);
|
||||
|
||||
void PatternDrawer::drawArrayEnd(pl::ptrn::Pattern& pattern, bool opened, bool inlined) {
|
||||
if (opened) {
|
||||
if (!inlined)
|
||||
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();
|
||||
} else {
|
||||
auto& displayEnd = this->getDisplayEnd(pattern);
|
||||
displayEnd = DisplayEndDefault;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,4 +468,4 @@ namespace hex {
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <pl/core/evaluator.hpp>
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
|
||||
#include <llvm/Demangle/Demangle.h>
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
void registerPatternLanguageFunctions() {
|
||||
@@ -16,7 +17,7 @@ namespace hex::plugin::builtin {
|
||||
pl::api::Namespace nsHexCore = { "builtin", "hex", "core" };
|
||||
{
|
||||
/* get_selection() */
|
||||
ContentRegistry::PatternLanguage::addDangerousFunction(nsHexCore, "get_selection", FunctionParameterCount::none(), [](Evaluator *, auto) -> std::optional<Token::Literal> {
|
||||
ContentRegistry::PatternLanguage::addFunction(nsHexCore, "get_selection", FunctionParameterCount::none(), [](Evaluator *, auto) -> std::optional<Token::Literal> {
|
||||
if (!ImHexApi::HexEditor::isSelectionValid())
|
||||
return std::numeric_limits<u128>::max();
|
||||
|
||||
@@ -26,6 +27,16 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
}
|
||||
|
||||
pl::api::Namespace nsHexDec = { "builtin", "hex", "dec" };
|
||||
{
|
||||
/* demangle(mangled_string) */
|
||||
ContentRegistry::PatternLanguage::addFunction(nsHexDec, "demangle", FunctionParameterCount::exactly(1), [](Evaluator *, auto params) -> std::optional<Token::Literal> {
|
||||
const auto mangledString = Token::literalToString(params[0], false);
|
||||
|
||||
return llvm::demangle(mangledString);
|
||||
});
|
||||
}
|
||||
|
||||
pl::api::Namespace nsHexHttp = { "builtin", "hex", "http" };
|
||||
{
|
||||
/* get(url) */
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
ProjectFile::registerHandler({
|
||||
.basePath = "providers",
|
||||
.required = true,
|
||||
.load = [](const std::fs::path &basePath, Tar &tar) {
|
||||
auto json = nlohmann::json::parse(tar.readString(basePath / "providers.json"));
|
||||
auto providerIds = json["providers"].get<std::vector<int>>();
|
||||
@@ -33,13 +34,15 @@ namespace hex::plugin::builtin {
|
||||
auto providerSettings = nlohmann::json::parse(tar.readString(basePath / hex::format("{}.json", id)));
|
||||
|
||||
auto provider = ImHexApi::Provider::createProvider(providerSettings["type"].get<std::string>(), true);
|
||||
ON_SCOPE_EXIT { if (!success) ImHexApi::Provider::remove(provider, true); };
|
||||
if (provider == nullptr) {
|
||||
success = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
provider->setID(id);
|
||||
provider->loadSettings(providerSettings["settings"]);
|
||||
if (!provider->open())
|
||||
if (!provider->open() || !provider->isAvailable() || !provider->isReadable())
|
||||
success = false;
|
||||
else
|
||||
EventManager::post<EventProviderOpened>(provider);
|
||||
|
||||
@@ -11,22 +11,17 @@
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#if defined(OS_WINDOWS)
|
||||
#include <winioctl.h>
|
||||
#elif defined(OS_LINUX) || defined(OS_MACOS)
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#if defined(OS_LINUX)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#define lseek lseek64
|
||||
|
||||
#elif defined(OS_MACOS)
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#endif
|
||||
|
||||
namespace hex::plugin::builtin::prv {
|
||||
@@ -264,14 +259,14 @@ namespace hex::plugin::builtin::prv {
|
||||
}
|
||||
|
||||
std::string DiskProvider::getName() const {
|
||||
return this->m_path.string();
|
||||
return hex::toUTF8String(this->m_path);
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> DiskProvider::getDataInformation() const {
|
||||
return {
|
||||
{"hex.builtin.provider.disk.selected_disk"_lang, this->m_path.string() },
|
||||
{ "hex.builtin.provider.disk.disk_size"_lang, hex::toByteString(this->m_diskSize) },
|
||||
{ "hex.builtin.provider.disk.sector_size"_lang, hex::toByteString(this->m_sectorSize)}
|
||||
{ "hex.builtin.provider.disk.selected_disk"_lang, hex::toUTF8String(this->m_path) },
|
||||
{ "hex.builtin.provider.disk.disk_size"_lang, hex::toByteString(this->m_diskSize) },
|
||||
{ "hex.builtin.provider.disk.sector_size"_lang, hex::toByteString(this->m_sectorSize) }
|
||||
};
|
||||
}
|
||||
|
||||
@@ -346,7 +341,7 @@ namespace hex::plugin::builtin::prv {
|
||||
}
|
||||
|
||||
nlohmann::json DiskProvider::storeSettings(nlohmann::json settings) const {
|
||||
settings["path"] = this->m_path.string();
|
||||
settings["path"] = hex::toUTF8String(this->m_path);
|
||||
|
||||
return Provider::storeSettings(settings);
|
||||
}
|
||||
@@ -354,7 +349,8 @@ namespace hex::plugin::builtin::prv {
|
||||
void DiskProvider::loadSettings(const nlohmann::json &settings) {
|
||||
Provider::loadSettings(settings);
|
||||
|
||||
this->setPath(settings["path"].get<std::string>());
|
||||
auto path = settings["path"].get<std::string>();
|
||||
this->setPath(std::u8string(path.begin(), path.end()));
|
||||
this->reloadDrives();
|
||||
}
|
||||
|
||||
|
||||
@@ -13,11 +13,7 @@
|
||||
namespace hex::plugin::builtin::prv {
|
||||
|
||||
bool FileProvider::isAvailable() const {
|
||||
#if defined(OS_WINDOWS)
|
||||
return this->m_file != INVALID_HANDLE_VALUE && this->m_mapping != INVALID_HANDLE_VALUE && this->m_mappedFile != nullptr;
|
||||
#else
|
||||
return this->m_file != -1 && this->m_mappedFile != nullptr;
|
||||
#endif
|
||||
return this->m_mappedFile != nullptr;
|
||||
}
|
||||
|
||||
bool FileProvider::isReadable() const {
|
||||
@@ -59,7 +55,7 @@ namespace hex::plugin::builtin::prv {
|
||||
}
|
||||
|
||||
void FileProvider::readRaw(u64 offset, void *buffer, size_t size) {
|
||||
if ((offset + size) > this->getRealTimeSize() || buffer == nullptr || size == 0)
|
||||
if ((offset + size) > this->getActualSize() || buffer == nullptr || size == 0)
|
||||
return;
|
||||
|
||||
std::memcpy(buffer, reinterpret_cast<u8 *>(this->m_mappedFile) + offset, size);
|
||||
@@ -151,32 +147,18 @@ namespace hex::plugin::builtin::prv {
|
||||
Provider::insert(offset, size);
|
||||
}
|
||||
|
||||
size_t FileProvider::getRealTimeSize() {
|
||||
#if defined(OS_LINUX)
|
||||
if (struct stat newStats; (this->m_fileStatsValid = fstat(this->m_file, &newStats) == 0)) {
|
||||
if (static_cast<off_t>(this->m_fileSize) != newStats.st_size ||
|
||||
std::memcmp(&newStats.st_mtim, &this->m_fileStats.st_mtim, sizeof(newStats.st_mtim))) {
|
||||
this->m_fileStats = newStats;
|
||||
this->m_fileSize = this->m_fileStats.st_size;
|
||||
msync(this->m_mappedFile, this->m_fileStats.st_size, MS_INVALIDATE);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return getActualSize();
|
||||
}
|
||||
|
||||
size_t FileProvider::getActualSize() const {
|
||||
return this->m_fileSize;
|
||||
}
|
||||
|
||||
std::string FileProvider::getName() const {
|
||||
return std::fs::path(this->m_path).filename().string();
|
||||
return hex::toUTF8String(this->m_path.filename());
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string>> FileProvider::getDataInformation() const {
|
||||
std::vector<std::pair<std::string, std::string>> result;
|
||||
|
||||
result.emplace_back("hex.builtin.provider.file.path"_lang, this->m_path.string());
|
||||
result.emplace_back("hex.builtin.provider.file.path"_lang, hex::toUTF8String(this->m_path));
|
||||
result.emplace_back("hex.builtin.provider.file.size"_lang, hex::toByteString(this->getActualSize()));
|
||||
|
||||
if (this->m_fileStatsValid) {
|
||||
@@ -208,67 +190,51 @@ namespace hex::plugin::builtin::prv {
|
||||
this->m_fileStatsValid = wstat(path.c_str(), &this->m_fileStats) == 0;
|
||||
|
||||
LARGE_INTEGER fileSize = {};
|
||||
this->m_file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
auto file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
|
||||
GetFileSizeEx(this->m_file, &fileSize);
|
||||
GetFileSizeEx(file, &fileSize);
|
||||
this->m_fileSize = fileSize.QuadPart;
|
||||
CloseHandle(this->m_file);
|
||||
CloseHandle(file);
|
||||
|
||||
this->m_file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) {
|
||||
this->m_file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
if (file == nullptr || file == INVALID_HANDLE_VALUE) {
|
||||
file = reinterpret_cast<HANDLE>(CreateFileW(path.c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr));
|
||||
this->m_writable = false;
|
||||
}
|
||||
|
||||
auto fileCleanup = SCOPE_GUARD {
|
||||
CloseHandle(this->m_file);
|
||||
|
||||
this->m_readable = false;
|
||||
this->m_file = nullptr;
|
||||
};
|
||||
|
||||
if (this->m_file == nullptr || this->m_file == INVALID_HANDLE_VALUE) {
|
||||
if (file == nullptr || file == INVALID_HANDLE_VALUE) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ON_SCOPE_EXIT { CloseHandle(file); };
|
||||
|
||||
if (this->m_fileSize > 0) {
|
||||
this->m_mapping = CreateFileMapping(this->m_file, nullptr, PAGE_READWRITE, 0, 0, nullptr);
|
||||
if (this->m_mapping == nullptr || this->m_mapping == INVALID_HANDLE_VALUE) {
|
||||
HANDLE mapping = CreateFileMapping(file, nullptr, PAGE_READWRITE, 0, 0, nullptr);
|
||||
ON_SCOPE_EXIT { CloseHandle(mapping); };
|
||||
|
||||
this->m_mapping = CreateFileMapping(this->m_file, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
if (mapping == nullptr || mapping == INVALID_HANDLE_VALUE) {
|
||||
mapping = CreateFileMapping(file, nullptr, PAGE_READONLY, 0, 0, nullptr);
|
||||
|
||||
if (this->m_mapping == nullptr || this->m_mapping == INVALID_HANDLE_VALUE)
|
||||
if (mapping == nullptr || mapping == INVALID_HANDLE_VALUE)
|
||||
return false;
|
||||
}
|
||||
|
||||
auto mappingCleanup = SCOPE_GUARD {
|
||||
CloseHandle(this->m_mapping);
|
||||
|
||||
this->m_mapping = nullptr;
|
||||
this->m_readable = false;
|
||||
};
|
||||
|
||||
this->m_mappedFile = MapViewOfFile(this->m_mapping, FILE_MAP_ALL_ACCESS, 0, 0, this->m_fileSize);
|
||||
this->m_mappedFile = MapViewOfFile(mapping, FILE_MAP_ALL_ACCESS, 0, 0, this->m_fileSize);
|
||||
if (this->m_mappedFile == nullptr) {
|
||||
|
||||
this->m_mappedFile = MapViewOfFile(this->m_mapping, FILE_MAP_READ, 0, 0, this->m_fileSize);
|
||||
this->m_mappedFile = MapViewOfFile(mapping, FILE_MAP_READ, 0, 0, this->m_fileSize);
|
||||
if (this->m_mappedFile == nullptr) {
|
||||
this->m_readable = false;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
mappingCleanup.release();
|
||||
} else if (!this->m_emptyFile) {
|
||||
this->m_emptyFile = true;
|
||||
this->resize(1);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
fileCleanup.release();
|
||||
|
||||
#else
|
||||
|
||||
const auto &path = this->m_path.native();
|
||||
@@ -276,27 +242,25 @@ namespace hex::plugin::builtin::prv {
|
||||
|
||||
int mmapprot = PROT_READ | PROT_WRITE;
|
||||
|
||||
this->m_file = ::open(path.c_str(), O_RDWR);
|
||||
if (this->m_file == -1) {
|
||||
this->m_file = ::open(path.c_str(), O_RDONLY);
|
||||
auto file = ::open(path.c_str(), O_RDWR);
|
||||
if (file == -1) {
|
||||
file = ::open(path.c_str(), O_RDONLY);
|
||||
this->m_writable = false;
|
||||
mmapprot &= ~(PROT_WRITE);
|
||||
}
|
||||
|
||||
if (this->m_file == -1) {
|
||||
if (file == -1) {
|
||||
this->m_readable = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
ON_SCOPE_EXIT { ::close(file); };
|
||||
|
||||
this->m_fileSize = this->m_fileStats.st_size;
|
||||
|
||||
this->m_mappedFile = ::mmap(nullptr, this->m_fileSize, mmapprot, MAP_SHARED, this->m_file, 0);
|
||||
if (this->m_mappedFile == MAP_FAILED) {
|
||||
::close(this->m_file);
|
||||
this->m_file = -1;
|
||||
|
||||
this->m_mappedFile = ::mmap(nullptr, this->m_fileSize, mmapprot, MAP_SHARED, file, 0);
|
||||
if (this->m_mappedFile == MAP_FAILED)
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -308,15 +272,11 @@ namespace hex::plugin::builtin::prv {
|
||||
|
||||
if (this->m_mappedFile != nullptr)
|
||||
::UnmapViewOfFile(this->m_mappedFile);
|
||||
if (this->m_mapping != nullptr)
|
||||
::CloseHandle(this->m_mapping);
|
||||
if (this->m_file != nullptr)
|
||||
::CloseHandle(this->m_file);
|
||||
|
||||
#else
|
||||
|
||||
::munmap(this->m_mappedFile, this->m_fileSize);
|
||||
::close(this->m_file);
|
||||
if (this->m_mappedFile != nullptr)
|
||||
::munmap(this->m_mappedFile, this->m_fileSize);
|
||||
|
||||
#endif
|
||||
}
|
||||
@@ -324,11 +284,12 @@ namespace hex::plugin::builtin::prv {
|
||||
void FileProvider::loadSettings(const nlohmann::json &settings) {
|
||||
Provider::loadSettings(settings);
|
||||
|
||||
this->setPath(settings["path"].get<std::string>());
|
||||
auto path = settings["path"].get<std::string>();
|
||||
this->setPath(std::u8string(path.begin(), path.end()));
|
||||
}
|
||||
|
||||
nlohmann::json FileProvider::storeSettings(nlohmann::json settings) const {
|
||||
settings["path"] = this->m_path.string();
|
||||
settings["path"] = hex::toUTF8String(this->m_path);
|
||||
|
||||
return Provider::storeSettings(settings);
|
||||
}
|
||||
|
||||
@@ -218,7 +218,7 @@ namespace hex::plugin::builtin::prv {
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string IntelHexProvider::getName() const {
|
||||
return hex::format("hex.builtin.provider.intel_hex.name"_lang, this->m_sourceFilePath.filename().string());
|
||||
return hex::format("hex.builtin.provider.intel_hex.name"_lang, hex::toUTF8String(this->m_sourceFilePath.filename()));
|
||||
}
|
||||
|
||||
bool IntelHexProvider::handleFilePicker() {
|
||||
@@ -250,11 +250,12 @@ namespace hex::plugin::builtin::prv {
|
||||
void IntelHexProvider::loadSettings(const nlohmann::json &settings) {
|
||||
Provider::loadSettings(settings);
|
||||
|
||||
this->m_sourceFilePath = settings["path"].get<std::string>();
|
||||
auto path = settings["path"].get<std::string>();
|
||||
this->m_sourceFilePath = std::u8string(path.begin(), path.end());
|
||||
}
|
||||
|
||||
nlohmann::json IntelHexProvider::storeSettings(nlohmann::json settings) const {
|
||||
settings["path"] = this->m_sourceFilePath.string();
|
||||
settings["path"] = hex::toUTF8String(this->m_sourceFilePath);
|
||||
|
||||
return Provider::storeSettings(settings);
|
||||
}
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
#include "content/providers/motorola_srec_provider.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <hex/api/imhex_api.hpp>
|
||||
#include <hex/api/localization.hpp>
|
||||
#include <hex/helpers/utils.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
#include <hex/helpers/fmt.hpp>
|
||||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace hex::plugin::builtin::prv {
|
||||
|
||||
namespace motorola_srec {
|
||||
@@ -198,7 +194,7 @@ namespace hex::plugin::builtin::prv {
|
||||
}
|
||||
|
||||
[[nodiscard]] std::string MotorolaSRECProvider::getName() const {
|
||||
return hex::format("hex.builtin.provider.motorola_srec.name"_lang, this->m_sourceFilePath.filename().string());
|
||||
return hex::format("hex.builtin.provider.motorola_srec.name"_lang, hex::toUTF8String(this->m_sourceFilePath.filename()));
|
||||
}
|
||||
|
||||
bool MotorolaSRECProvider::handleFilePicker() {
|
||||
|
||||
@@ -14,8 +14,10 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace {
|
||||
static std::vector<std::fs::path> userFolders;
|
||||
static void loadUserFoldersFromSetting(nlohmann::json &setting) {
|
||||
|
||||
std::vector<std::fs::path> userFolders;
|
||||
|
||||
void loadUserFoldersFromSetting(nlohmann::json &setting) {
|
||||
userFolders.clear();
|
||||
std::vector<std::string> paths = setting;
|
||||
for (const auto &path : paths) {
|
||||
@@ -24,7 +26,8 @@ namespace {
|
||||
userFolders.emplace_back(uString);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
@@ -182,6 +185,17 @@ namespace hex::plugin::builtin {
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.interface", "hex.builtin.setting.interface.multi_windows", 1, [](auto name, nlohmann::json &setting) {
|
||||
static bool enabled = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &enabled)) {
|
||||
setting = static_cast<int>(enabled);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}, true);
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.highlight_color", 0x60C08080, [](auto name, nlohmann::json &setting) {
|
||||
static auto color = static_cast<color_t>(setting);
|
||||
|
||||
@@ -283,6 +297,39 @@ namespace hex::plugin::builtin {
|
||||
return result;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.sync_scrolling", 0, [](auto name, nlohmann::json &setting) {
|
||||
static bool syncScrolling = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::Checkbox(name.data(), &syncScrolling)) {
|
||||
setting = static_cast<int>(syncScrolling);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.byte_padding", 0, [](auto name, nlohmann::json &setting) {
|
||||
static int padding = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::SliderInt(name.data(), &padding, 0, 50)) {
|
||||
setting = padding;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
ContentRegistry::Settings::add("hex.builtin.setting.hex_editor", "hex.builtin.setting.hex_editor.char_padding", 0, [](auto name, nlohmann::json &setting) {
|
||||
static int padding = static_cast<int>(setting);
|
||||
|
||||
if (ImGui::SliderInt(name.data(), &padding, 0, 50)) {
|
||||
setting = padding;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
|
||||
|
||||
/* Fonts */
|
||||
|
||||
@@ -301,7 +348,7 @@ namespace hex::plugin::builtin {
|
||||
if (ImGui::IconButton(ICON_VS_FOLDER_OPENED, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
|
||||
return fs::openFileBrowser(fs::DialogMode::Open, { {"TTF Font", "ttf"} },
|
||||
[&](const std::fs::path &path) {
|
||||
fontPath = path.string();
|
||||
fontPath = hex::toUTF8String(path);
|
||||
setting = fontPath;
|
||||
});
|
||||
}
|
||||
@@ -360,7 +407,7 @@ namespace hex::plugin::builtin {
|
||||
} else {
|
||||
for (size_t n = 0; n < userFolders.size(); n++) {
|
||||
const bool isSelected = (currentItemIndex == n);
|
||||
if (ImGui::Selectable(userFolders.at(n).string().c_str(), isSelected)) { currentItemIndex = n; }
|
||||
if (ImGui::Selectable(hex::toUTF8String(userFolders.at(n)).c_str(), isSelected)) { currentItemIndex = n; }
|
||||
if (isSelected) { ImGui::SetItemDefaultFocus(); }
|
||||
}
|
||||
ImGui::EndListBox();
|
||||
@@ -475,7 +522,7 @@ namespace hex::plugin::builtin {
|
||||
for (const auto &dir : fs::getDefaultPaths(fs::ImHexPath::Resources)) {
|
||||
auto path = dir / "font.ttf";
|
||||
if (fs::exists(path)) {
|
||||
log::info("Loading custom front from {}", path.string());
|
||||
log::info("Loading custom front from {}", hex::toUTF8String(path));
|
||||
|
||||
fontFile = path;
|
||||
break;
|
||||
@@ -483,11 +530,11 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
}
|
||||
|
||||
ImHexApi::System::impl::setCustomFontPath(fontFile);
|
||||
|
||||
// If a custom font has been loaded now, also load the font size
|
||||
float fontSize = ImHexApi::System::DefaultFontSize * ImHexApi::System::getGlobalScale();
|
||||
if (!fontFile.empty()) {
|
||||
ImHexApi::System::impl::setCustomFontPath(fontFile);
|
||||
|
||||
fontSize = ContentRegistry::Settings::read("hex.builtin.setting.font", "hex.builtin.setting.font.font_size", 13) * ImHexApi::System::getGlobalScale();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#include <hex/api/keybinding.hpp>
|
||||
#include <hex/api/event.hpp>
|
||||
|
||||
#include <hex/providers/provider.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
void registerShortcuts() {
|
||||
@@ -16,7 +18,19 @@ namespace hex::plugin::builtin {
|
||||
|
||||
// Close file
|
||||
ShortcutManager::addGlobalShortcut(CTRL + Keys::W, [] {
|
||||
ImHexApi::Provider::remove(ImHexApi::Provider::get());
|
||||
if (ImHexApi::Provider::isValid())
|
||||
ImHexApi::Provider::remove(ImHexApi::Provider::get());
|
||||
});
|
||||
|
||||
// Reload file
|
||||
ShortcutManager::addGlobalShortcut(CTRL + Keys::R, [] {
|
||||
if (ImHexApi::Provider::isValid()) {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
provider->close();
|
||||
if (!provider->open())
|
||||
ImHexApi::Provider::remove(provider, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include <chrono>
|
||||
#include <random>
|
||||
#include <regex>
|
||||
#include <limits>
|
||||
|
||||
#include <llvm/Demangle/Demangle.h>
|
||||
#include <content/helpers/math_evaluator.hpp>
|
||||
@@ -75,9 +74,8 @@ namespace hex::plugin::builtin {
|
||||
|
||||
ImGui::TableHeadersRow();
|
||||
|
||||
u32 rowCount = 0;
|
||||
for (u8 i = 0; i < 0x80 / 4; i++) {
|
||||
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
|
||||
ImGui::TableNextRow();
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{0:03d}", i + 32 * tablePart);
|
||||
@@ -92,10 +90,6 @@ namespace hex::plugin::builtin {
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextFormatted("{0}", hex::makePrintable(i + 32 * tablePart));
|
||||
|
||||
ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, ((rowCount % 2) == 0) ? 0xFF101010 : 0xFF303030);
|
||||
|
||||
rowCount++;
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
@@ -113,8 +107,8 @@ namespace hex::plugin::builtin {
|
||||
static auto replacePattern = [] { std::string s; s.reserve(0xFFF); return s; }();
|
||||
static auto regexOutput = [] { std::string s; s.reserve(0xFFF); return s; }();
|
||||
|
||||
bool changed1 = ImGui::InputText("hex.builtin.tools.regex_replacer.pattern"_lang, regexPattern);
|
||||
bool changed2 = ImGui::InputText("hex.builtin.tools.regex_replacer.replace"_lang, replacePattern);
|
||||
bool changed1 = ImGui::InputTextIcon("hex.builtin.tools.regex_replacer.pattern"_lang, ICON_VS_REGEX, regexPattern);
|
||||
bool changed2 = ImGui::InputTextIcon("hex.builtin.tools.regex_replacer.replace"_lang, ICON_VS_REGEX, replacePattern);
|
||||
bool changed3 = ImGui::InputTextMultiline("hex.builtin.tools.regex_replacer.input"_lang, regexInput, ImVec2(0, 0));
|
||||
|
||||
if (changed1 || changed2 || changed3) {
|
||||
@@ -391,7 +385,12 @@ namespace hex::plugin::builtin {
|
||||
ImGui::TableSetupColumn("hex.builtin.tools.value"_lang);
|
||||
|
||||
ImGui::TableHeadersRow();
|
||||
for (const auto &[name, value] : mathEvaluator.getVariables()) {
|
||||
for (const auto &[name, variable] : mathEvaluator.getVariables()) {
|
||||
const auto &[value, constant] = variable;
|
||||
|
||||
if (constant)
|
||||
continue;
|
||||
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::TextUnformatted(name.c_str());
|
||||
@@ -420,7 +419,7 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
|
||||
if (ImGui::InputText("##input", mathInput, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll)) {
|
||||
if (ImGui::InputTextIcon("##input", ICON_VS_SYMBOL_OPERATOR, mathInput, ImGuiInputTextFlags_EnterReturnsTrue | ImGuiInputTextFlags_AutoSelectAll)) {
|
||||
ImGui::SetKeyboardFocusHere();
|
||||
evaluate = true;
|
||||
}
|
||||
@@ -434,10 +433,9 @@ namespace hex::plugin::builtin {
|
||||
if (evaluate) {
|
||||
try {
|
||||
auto result = mathEvaluator.evaluate(mathInput);
|
||||
|
||||
mathInput.clear();
|
||||
if (result.has_value()) {
|
||||
mathHistory.push_back(result.value());
|
||||
mathInput.clear();
|
||||
lastMathError.clear();
|
||||
}
|
||||
|
||||
@@ -448,75 +446,45 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
void drawBaseConverter() {
|
||||
static char buffer[4][0x1000] = { { '0' }, { '0' }, { '0' }, { '0' } };
|
||||
|
||||
static auto CharFilter = [](ImGuiInputTextCallbackData *data) -> int {
|
||||
switch (*static_cast<u32 *>(data->UserData)) {
|
||||
case 16:
|
||||
return std::isxdigit(data->EventChar);
|
||||
case 10:
|
||||
return std::isdigit(data->EventChar);
|
||||
case 8:
|
||||
return std::isdigit(data->EventChar) && data->EventChar < '8';
|
||||
case 2:
|
||||
return data->EventChar == '0' || data->EventChar == '1';
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
};
|
||||
static std::array<std::string, 4> buffers;
|
||||
|
||||
static auto ConvertBases = [](u8 base) {
|
||||
u64 number;
|
||||
|
||||
errno = 0;
|
||||
switch (base) {
|
||||
case 16:
|
||||
number = std::strtoull(buffer[1], nullptr, base);
|
||||
number = std::strtoull(buffers[1].c_str(), nullptr, base);
|
||||
break;
|
||||
case 10:
|
||||
number = std::strtoull(buffer[0], nullptr, base);
|
||||
number = std::strtoull(buffers[0].c_str(), nullptr, base);
|
||||
break;
|
||||
case 8:
|
||||
number = std::strtoull(buffer[2], nullptr, base);
|
||||
number = std::strtoull(buffers[2].c_str(), nullptr, base);
|
||||
break;
|
||||
case 2:
|
||||
number = std::strtoull(buffer[3], nullptr, base);
|
||||
number = std::strtoull(buffers[3].c_str(), nullptr, base);
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
auto base10String = std::to_string(number);
|
||||
auto base16String = hex::format("0x{0:X}", number);
|
||||
auto base8String = hex::format("{0:#o}", number);
|
||||
auto base2String = hex::toBinaryString(number);
|
||||
|
||||
std::strncpy(buffer[0], base10String.c_str(), sizeof(buffer[0]) - 1);
|
||||
std::strncpy(buffer[1], base16String.c_str(), sizeof(buffer[1]) - 1);
|
||||
std::strncpy(buffer[2], base8String.c_str(), sizeof(buffer[2]) - 1);
|
||||
std::strncpy(buffer[3], base2String.c_str(), sizeof(buffer[3]) - 1);
|
||||
|
||||
buffer[0][0xFFF] = '\x00';
|
||||
buffer[1][0xFFF] = '\x00';
|
||||
buffer[2][0xFFF] = '\x00';
|
||||
buffer[3][0xFFF] = '\x00';
|
||||
buffers[0] = std::to_string(number);
|
||||
buffers[1] = hex::format("0x{0:X}", number);
|
||||
buffers[2] = hex::format("{0:#o}", number);
|
||||
buffers[3] = hex::toBinaryString(number);
|
||||
};
|
||||
|
||||
u8 base = 10;
|
||||
if (ImGui::InputText("hex.builtin.tools.base_converter.dec"_lang, buffer[0], 20 + 1, ImGuiInputTextFlags_CallbackCharFilter, CharFilter, &base))
|
||||
ConvertBases(base);
|
||||
if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.dec"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[0]))
|
||||
ConvertBases(10);
|
||||
|
||||
base = 16;
|
||||
if (ImGui::InputText("hex.builtin.tools.base_converter.hex"_lang, buffer[1], 16 + 1, ImGuiInputTextFlags_CallbackCharFilter, CharFilter, &base))
|
||||
ConvertBases(base);
|
||||
if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.hex"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[1]))
|
||||
ConvertBases(16);
|
||||
|
||||
base = 8;
|
||||
if (ImGui::InputText("hex.builtin.tools.base_converter.oct"_lang, buffer[2], 22 + 1, ImGuiInputTextFlags_CallbackCharFilter, CharFilter, &base))
|
||||
ConvertBases(base);
|
||||
if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.oct"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[2]))
|
||||
ConvertBases(8);
|
||||
|
||||
base = 2;
|
||||
if (ImGui::InputText("hex.builtin.tools.base_converter.bin"_lang, buffer[3], 64 + 1, ImGuiInputTextFlags_CallbackCharFilter, CharFilter, &base))
|
||||
ConvertBases(base);
|
||||
if (ImGui::InputTextIcon("hex.builtin.tools.base_converter.bin"_lang, ICON_VS_SYMBOL_NUMERIC, buffers[3]))
|
||||
ConvertBases(2);
|
||||
}
|
||||
|
||||
void drawPermissionsCalculator() {
|
||||
@@ -652,9 +620,11 @@ namespace hex::plugin::builtin {
|
||||
if (response.code == 200) {
|
||||
try {
|
||||
auto json = nlohmann::json::parse(response.body);
|
||||
links.push_back({ currFile.filename().string(),
|
||||
links.push_back({
|
||||
hex::toUTF8String(currFile.filename()),
|
||||
json["data"]["file"]["url"]["short"],
|
||||
json["data"]["file"]["metadata"]["size"]["readable"] });
|
||||
json["data"]["file"]["metadata"]["size"]["readable"]
|
||||
});
|
||||
} catch (...) {
|
||||
View::showErrorPopup("hex.builtin.tools.file_uploader.invalid_response"_lang);
|
||||
}
|
||||
@@ -691,7 +661,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
bool startSearch;
|
||||
|
||||
startSearch = ImGui::InputText("##search", searchString, ImGuiInputTextFlags_EnterReturnsTrue);
|
||||
startSearch = ImGui::InputTextIcon("##search", ICON_VS_SYMBOL_KEY, searchString, ImGuiInputTextFlags_EnterReturnsTrue);
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::BeginDisabled((searchProcess.valid() && searchProcess.wait_for(0s) != std::future_status::ready) || searchString.empty());
|
||||
@@ -1007,7 +977,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
u32 index = 0;
|
||||
for (auto &file : files) {
|
||||
if (ImGui::Selectable(std::fs::path(file).filename().string().c_str(), index == selectedIndex))
|
||||
if (ImGui::Selectable(hex::toUTF8String(file).c_str(), index == selectedIndex))
|
||||
selectedIndex = index;
|
||||
index++;
|
||||
}
|
||||
@@ -1099,7 +1069,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
fs::File input(file, fs::File::Mode::Read);
|
||||
if (!input.isValid()) {
|
||||
View::showErrorPopup(hex::format("hex.builtin.tools.file_tools.combiner.open_input"_lang, std::fs::path(file).filename().string()));
|
||||
View::showErrorPopup(hex::format("hex.builtin.tools.file_tools.combiner.open_input"_lang, hex::toUTF8String(file)));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -127,7 +127,7 @@ namespace hex::plugin::builtin {
|
||||
u32 index = 0;
|
||||
for (auto &path : s_selectableFiles) {
|
||||
ImGui::PushID(index);
|
||||
if (ImGui::Selectable(path.filename().string().c_str(), index == s_selectableFileIndex))
|
||||
if (ImGui::Selectable(hex::toUTF8String(path.filename()).c_str(), index == s_selectableFileIndex))
|
||||
s_selectableFileIndex = index;
|
||||
ImGui::PopID();
|
||||
|
||||
@@ -245,6 +245,9 @@ namespace hex::plugin::builtin {
|
||||
|
||||
if (ImGui::BeginPopupContextItem("FrontTask", ImGuiPopupFlags_MouseButtonLeft)) {
|
||||
for (const auto &task : tasks) {
|
||||
if (task->isBackgroundTask())
|
||||
continue;
|
||||
|
||||
ImGui::PushID(&task);
|
||||
ImGui::TextFormatted("{}", LangEntry(task->getUnlocalizedName()));
|
||||
ImGui::SameLine();
|
||||
|
||||
@@ -25,10 +25,6 @@ namespace hex::plugin::builtin {
|
||||
});
|
||||
}
|
||||
|
||||
ViewAbout::~ViewAbout() {
|
||||
ImGui::UnloadImage(this->m_logoTexture);
|
||||
}
|
||||
|
||||
static void link(const std::string &name, const std::string &author, const std::string &url) {
|
||||
if (ImGui::BulletHyperlink(name.c_str()))
|
||||
hex::openWebpage(url);
|
||||
@@ -50,12 +46,12 @@ namespace hex::plugin::builtin {
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (!this->m_logoTexture.valid()) {
|
||||
if (!this->m_logoTexture.isValid()) {
|
||||
auto logo = romfs::get("logo.png");
|
||||
this->m_logoTexture = ImGui::LoadImageFromMemory(reinterpret_cast<const ImU8 *>(logo.data()), logo.size());
|
||||
this->m_logoTexture = ImGui::Texture(reinterpret_cast<const ImU8 *>(logo.data()), logo.size());
|
||||
}
|
||||
|
||||
ImGui::Image(this->m_logoTexture.textureId, scaled({ 64, 64 }));
|
||||
ImGui::Image(this->m_logoTexture, scaled({ 64, 64 }));
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
ImGui::TextFormatted("ImHex Hex Editor v{} by WerWolv - " ICON_FA_CODE_BRANCH, IMHEX_VERSION);
|
||||
@@ -166,7 +162,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
for (auto &path : fs::getDefaultPaths(type))
|
||||
ImGui::TextUnformatted(path.string().c_str());
|
||||
ImGui::TextUnformatted(hex::toUTF8String(path).c_str());
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <cstring>
|
||||
|
||||
#include <provider_extra_data.hpp>
|
||||
#include <content/helpers/provider_extra_data.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
@@ -33,7 +33,7 @@ namespace hex::plugin::builtin {
|
||||
ImHexApi::Provider::markDirty();
|
||||
});
|
||||
|
||||
ImHexApi::HexEditor::addBackgroundHighlightingProvider([](u64 address, const u8* data, size_t size) -> std::optional<color_t> {
|
||||
ImHexApi::HexEditor::addBackgroundHighlightingProvider([](u64 address, const u8* data, size_t size, bool) -> std::optional<color_t> {
|
||||
hex::unused(data);
|
||||
|
||||
for (const auto &bookmark : ProviderExtraData::getCurrent().bookmarks) {
|
||||
@@ -103,6 +103,7 @@ namespace hex::plugin::builtin {
|
||||
|
||||
ProjectFile::registerPerProviderHandler({
|
||||
.basePath = "bookmarks.json",
|
||||
.required = false,
|
||||
.load = [](prv::Provider *provider, const std::fs::path &basePath, Tar &tar) -> bool {
|
||||
auto fileContent = tar.read(basePath);
|
||||
if (fileContent.empty())
|
||||
@@ -130,6 +131,42 @@ namespace hex::plugin::builtin {
|
||||
EventManager::unsubscribe<EventProviderDeleted>(this);
|
||||
}
|
||||
|
||||
static void drawColorPopup(ImColor &color) {
|
||||
static auto Palette = []{
|
||||
constexpr static auto ColorCount = 36;
|
||||
std::array<ImColor, ColorCount> result = { 0 };
|
||||
|
||||
u32 counter = 0;
|
||||
for (auto &color : result) {
|
||||
ImGui::ColorConvertHSVtoRGB(float(counter) / float(ColorCount - 1), 0.8F, 0.8F, color.Value.x, color.Value.y, color.Value.z);
|
||||
color.Value.w = 0.7f;
|
||||
|
||||
counter++;
|
||||
}
|
||||
|
||||
return result;
|
||||
}();
|
||||
|
||||
ImGui::ColorPicker4("##picker", (float*)&color, ImGuiColorEditFlags_NoSidePreview | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoSmallPreview);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
int id = 0;
|
||||
for (const auto &paletteColor : Palette) {
|
||||
ImGui::PushID(id);
|
||||
if ((id % 9) != 0)
|
||||
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemSpacing.y);
|
||||
|
||||
constexpr static ImGuiColorEditFlags flags = ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoPicker | ImGuiColorEditFlags_NoDragDrop;
|
||||
if (ImGui::ColorButton("##palette", paletteColor.Value, flags, ImVec2(20, 20))) {
|
||||
color = paletteColor;
|
||||
}
|
||||
|
||||
ImGui::PopID();
|
||||
id++;
|
||||
}
|
||||
}
|
||||
|
||||
void ViewBookmarks::drawContent() {
|
||||
if (ImGui::Begin(View::toWindowName("hex.builtin.view.bookmarks.name").c_str(), &this->getWindowOpenState())) {
|
||||
|
||||
@@ -145,7 +182,7 @@ namespace hex::plugin::builtin {
|
||||
ImGui::TextFormattedCentered("hex.builtin.view.bookmarks.no_bookmarks"_lang);
|
||||
}
|
||||
|
||||
u32 id = 1;
|
||||
int id = 1;
|
||||
auto bookmarkToRemove = bookmarks.end();
|
||||
for (auto iter = bookmarks.begin(); iter != bookmarks.end(); iter++) {
|
||||
auto &[region, name, comment, color, locked] = *iter;
|
||||
@@ -164,8 +201,25 @@ namespace hex::plugin::builtin {
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderActive, color);
|
||||
ImGui::PushStyleColor(ImGuiCol_HeaderHovered, u32(hoverColor));
|
||||
|
||||
ON_SCOPE_EXIT {
|
||||
ImGui::PopID();
|
||||
ImGui::PopStyleColor(3);
|
||||
id++;
|
||||
};
|
||||
|
||||
bool open = true;
|
||||
if (ImGui::CollapsingHeader(hex::format("{}###bookmark", name).c_str(), &open)) {
|
||||
if (!ImGui::CollapsingHeader(hex::format("{}###bookmark", name).c_str(), &open)) {
|
||||
if (ImGui::IsMouseClicked(0) && ImGui::IsItemActivated() && this->m_dragStartIterator == bookmarks.end())
|
||||
this->m_dragStartIterator = iter;
|
||||
|
||||
if (ImGui::IsItemHovered() && this->m_dragStartIterator != bookmarks.end()) {
|
||||
std::iter_swap(iter, this->m_dragStartIterator);
|
||||
this->m_dragStartIterator = iter;
|
||||
}
|
||||
|
||||
if (!ImGui::IsMouseDown(0))
|
||||
this->m_dragStartIterator = bookmarks.end();
|
||||
} else {
|
||||
ImGui::TextUnformatted("hex.builtin.view.bookmarks.title.info"_lang);
|
||||
ImGui::Separator();
|
||||
ImGui::TextFormatted("hex.builtin.view.bookmarks.address"_lang, region.address, region.address + region.size - 1, region.size);
|
||||
@@ -229,8 +283,17 @@ namespace hex::plugin::builtin {
|
||||
ImGui::TextUnformatted("hex.builtin.view.bookmarks.header.name"_lang);
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::ColorEdit4("hex.builtin.view.bookmarks.header.color"_lang, (float *)&headerColor.Value, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoAlpha | (locked ? ImGuiColorEditFlags_NoPicker : ImGuiColorEditFlags_None));
|
||||
color = headerColor;
|
||||
if (ImGui::ColorButton("hex.builtin.view.bookmarks.header.color"_lang, headerColor.Value, ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoAlpha)) {
|
||||
if (!locked)
|
||||
ImGui::OpenPopup("hex.builtin.view.bookmarks.header.color"_lang);
|
||||
}
|
||||
|
||||
if (ImGui::BeginPopup("hex.builtin.view.bookmarks.header.color"_lang)) {
|
||||
drawColorPopup(headerColor);
|
||||
color = headerColor;
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (locked)
|
||||
@@ -252,10 +315,6 @@ namespace hex::plugin::builtin {
|
||||
|
||||
if (!open)
|
||||
bookmarkToRemove = iter;
|
||||
|
||||
ImGui::PopID();
|
||||
ImGui::PopStyleColor(3);
|
||||
id++;
|
||||
}
|
||||
|
||||
if (bookmarkToRemove != bookmarks.end()) {
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace hex::plugin::builtin {
|
||||
this->m_constants.push_back(constant);
|
||||
}
|
||||
} catch (...) {
|
||||
log::error("Failed to parse constants file {}", file.path().string());
|
||||
log::error("Failed to parse constants file {}", hex::toUTF8String(file.path()));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,13 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include <hex/helpers/logger.hpp>
|
||||
#include <hex/helpers/file.hpp>
|
||||
|
||||
#include <pl/pattern_language.hpp>
|
||||
#include <pl/core/evaluator.hpp>
|
||||
#include <pl/patterns/pattern.hpp>
|
||||
|
||||
namespace hex::plugin::builtin {
|
||||
|
||||
using NumberDisplayStyle = ContentRegistry::DataInspector::NumberDisplayStyle;
|
||||
@@ -17,7 +24,7 @@ namespace hex::plugin::builtin {
|
||||
if (!ImHexApi::Provider::isValid() || region.address == (size_t)-1) {
|
||||
this->m_validBytes = 0;
|
||||
} else {
|
||||
this->m_validBytes = u64(provider->getSize() - region.address);
|
||||
this->m_validBytes = u64(provider->getActualSize() - region.address);
|
||||
this->m_startAddress = region.address;
|
||||
}
|
||||
|
||||
@@ -30,27 +37,106 @@ namespace hex::plugin::builtin {
|
||||
}
|
||||
|
||||
void ViewDataInspector::drawContent() {
|
||||
if (this->m_shouldInvalidate) {
|
||||
this->m_shouldInvalidate = false;
|
||||
|
||||
this->m_cachedData.clear();
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
for (auto &entry : ContentRegistry::DataInspector::getEntries()) {
|
||||
if (this->m_validBytes < entry.requiredSize)
|
||||
continue;
|
||||
|
||||
std::vector<u8> buffer(this->m_validBytes > entry.maxSize ? entry.maxSize : this->m_validBytes);
|
||||
provider->read(this->m_startAddress, buffer.data(), buffer.size());
|
||||
|
||||
if (this->m_invert) {
|
||||
for (auto &byte : buffer)
|
||||
byte ^= 0xFF;
|
||||
}
|
||||
|
||||
this->m_cachedData.push_back({ entry.unlocalizedName, entry.generatorFunction(buffer, this->m_endian, this->m_numberDisplayStyle), entry.editingFunction, false });
|
||||
}
|
||||
if (this->m_dataValid) {
|
||||
this->m_dataValid = false;
|
||||
this->m_cachedData = std::move(this->m_workData);
|
||||
}
|
||||
|
||||
if (this->m_shouldInvalidate && !this->m_updateTask.isRunning()) {
|
||||
this->m_shouldInvalidate = false;
|
||||
|
||||
this->m_updateTask = TaskManager::createBackgroundTask("Update Inspector",
|
||||
[this, validBytes = this->m_validBytes, startAddress = this->m_startAddress, endian = this->m_endian, invert = this->m_invert, numberDisplayStyle = this->m_numberDisplayStyle](auto &) {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||
this->m_workData.clear();
|
||||
|
||||
// Decode bytes using registered inspectors
|
||||
for (auto &entry : ContentRegistry::DataInspector::getEntries()) {
|
||||
if (validBytes < entry.requiredSize)
|
||||
continue;
|
||||
|
||||
std::vector<u8> buffer(validBytes > entry.maxSize ? entry.maxSize : validBytes);
|
||||
provider->read(startAddress, buffer.data(), buffer.size());
|
||||
|
||||
if (invert) {
|
||||
for (auto &byte : buffer)
|
||||
byte ^= 0xFF;
|
||||
}
|
||||
|
||||
this->m_workData.push_back({
|
||||
entry.unlocalizedName,
|
||||
entry.generatorFunction(buffer, endian, numberDisplayStyle),
|
||||
entry.editingFunction,
|
||||
false
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
// Decode bytes using custom inspectors defined using the pattern language
|
||||
const std::map<std::string, pl::core::Token::Literal> inVariables = {
|
||||
{ "numberDisplayStyle", u128(numberDisplayStyle) }
|
||||
};
|
||||
|
||||
pl::PatternLanguage runtime;
|
||||
ContentRegistry::PatternLanguage::configureRuntime(runtime, nullptr);
|
||||
|
||||
runtime.setDataSource([invert, provider](u64 offset, u8 *buffer, size_t size) {
|
||||
provider->read(offset, buffer, size);
|
||||
|
||||
if (invert) {
|
||||
for (size_t i = 0; i < size; i++)
|
||||
buffer[i] ^= 0xFF;
|
||||
}
|
||||
}, provider->getBaseAddress(), provider->getActualSize());
|
||||
|
||||
runtime.setDangerousFunctionCallHandler([]{ return false; });
|
||||
runtime.setDefaultEndian(endian);
|
||||
runtime.setStartAddress(startAddress);
|
||||
|
||||
for (const auto &folderPath : fs::getDefaultPaths(fs::ImHexPath::Inspectors)) {
|
||||
for (const auto &filePath : std::fs::recursive_directory_iterator(folderPath)) {
|
||||
if (!filePath.exists() || !filePath.is_regular_file() || filePath.path().extension() != ".hexpat")
|
||||
continue;
|
||||
|
||||
fs::File file(filePath, fs::File::Mode::Read);
|
||||
if (file.isValid()) {
|
||||
auto inspectorCode = file.readString();
|
||||
|
||||
if (!inspectorCode.empty()) {
|
||||
if (runtime.executeString(inspectorCode, {}, inVariables, true)) {
|
||||
const auto &patterns = runtime.getAllPatterns();
|
||||
|
||||
for (const auto &pattern : patterns) {
|
||||
if (pattern->isHidden())
|
||||
continue;
|
||||
|
||||
this->m_workData.push_back({
|
||||
pattern->getDisplayName(),
|
||||
[value = pattern->getFormattedValue()]() {
|
||||
ImGui::TextUnformatted(value.c_str());
|
||||
return value;
|
||||
},
|
||||
std::nullopt,
|
||||
false
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const auto& error = runtime.getError();
|
||||
|
||||
log::error("Failed to execute inspectors.hexpat!");
|
||||
if (error.has_value())
|
||||
log::error("{}", error.value().what());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->m_dataValid = true;
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
if (ImGui::Begin(View::toWindowName("hex.builtin.view.data_inspector.name").c_str(), &this->getWindowOpenState(), ImGuiWindowFlags_NoCollapse)) {
|
||||
auto provider = ImHexApi::Provider::get();
|
||||
|
||||