Add some cross platform example projects
This commit is contained in:
parent
2223a7f10b
commit
b89af0c51e
|
@ -0,0 +1,3 @@
|
|||
# cmkr
|
||||
/**/CMakeLists.txt linguist-generated
|
||||
/**/cmkr.cmake linguist-vendored
|
|
@ -0,0 +1,133 @@
|
|||
# This file is automatically generated from cmake.toml - DO NOT EDIT
|
||||
# See https://github.com/build-cpp/cmkr for more information
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
|
||||
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
|
||||
message(FATAL_ERROR "In-tree builds are not supported. Run CMake from a separate directory: cmake -B build")
|
||||
endif()
|
||||
|
||||
set(CMKR_ROOT_PROJECT OFF)
|
||||
if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR)
|
||||
set(CMKR_ROOT_PROJECT ON)
|
||||
|
||||
# Bootstrap cmkr and automatically regenerate CMakeLists.txt
|
||||
include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT)
|
||||
if(CMKR_INCLUDE_RESULT)
|
||||
cmkr()
|
||||
endif()
|
||||
|
||||
# Enable folder support
|
||||
set_property(GLOBAL PROPERTY USE_FOLDERS ON)
|
||||
|
||||
# Create a configure-time dependency on cmake.toml to improve IDE support
|
||||
configure_file(cmake.toml cmake.toml COPYONLY)
|
||||
endif()
|
||||
|
||||
project(cross)
|
||||
|
||||
include("gui/Qt.cmake")
|
||||
|
||||
# Subdirectory: gui
|
||||
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
|
||||
if(CMAKE_FOLDER)
|
||||
set(CMAKE_FOLDER "${CMAKE_FOLDER}/gui")
|
||||
else()
|
||||
set(CMAKE_FOLDER gui)
|
||||
endif()
|
||||
add_subdirectory(gui)
|
||||
set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
|
||||
|
||||
# Subdirectory: vendor
|
||||
set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER})
|
||||
if(CMAKE_FOLDER)
|
||||
set(CMAKE_FOLDER "${CMAKE_FOLDER}/vendor")
|
||||
else()
|
||||
set(CMAKE_FOLDER vendor)
|
||||
endif()
|
||||
add_subdirectory(vendor)
|
||||
set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER})
|
||||
|
||||
# Target: minidump
|
||||
set(minidump_SOURCES
|
||||
"minidump/GotoDialog.cpp"
|
||||
"minidump/MainWindow.cpp"
|
||||
"minidump/MiniDisassembly.cpp"
|
||||
"minidump/MiniDump.cpp"
|
||||
"minidump/MiniHexDump.cpp"
|
||||
"minidump/MiniMemoryMap.cpp"
|
||||
"minidump/Navigation.cpp"
|
||||
"minidump/REToolSync.cpp"
|
||||
"minidump/main.cpp"
|
||||
"minidump/GotoDialog.h"
|
||||
"minidump/MainWindow.h"
|
||||
"minidump/MiniDisassembly.h"
|
||||
"minidump/MiniDump.h"
|
||||
"minidump/MiniHexDump.h"
|
||||
"minidump/MiniMemoryMap.h"
|
||||
"minidump/Navigation.h"
|
||||
"minidump/REToolSync.h"
|
||||
"minidump/udmp-parser.h"
|
||||
"minidump/udmp-utils.h"
|
||||
"minidump/MainWindow.ui"
|
||||
cmake.toml
|
||||
)
|
||||
|
||||
qt_executable(minidump ${minidump_SOURCES})
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${minidump_SOURCES})
|
||||
|
||||
target_compile_features(minidump PRIVATE
|
||||
cxx_std_17
|
||||
)
|
||||
|
||||
target_link_libraries(minidump PRIVATE
|
||||
${QT_LIBRARIES}
|
||||
widgets
|
||||
cpp-httplib
|
||||
)
|
||||
|
||||
get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT)
|
||||
if(NOT CMKR_VS_STARTUP_PROJECT)
|
||||
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT minidump)
|
||||
endif()
|
||||
|
||||
set(CMKR_TARGET minidump)
|
||||
qt_finalize_executable(${CMKR_TARGET})
|
||||
|
||||
# Target: remote_table
|
||||
set(remote_table_SOURCES
|
||||
"remote_table/JsonRpcClient.cpp"
|
||||
"remote_table/MainWindow.cpp"
|
||||
"remote_table/RemoteTable.cpp"
|
||||
"remote_table/TableServer.cpp"
|
||||
"remote_table/main.cpp"
|
||||
"remote_table/JsonRpcClient.h"
|
||||
"remote_table/MainWindow.h"
|
||||
"remote_table/RemoteTable.h"
|
||||
"remote_table/TableRpcData.h"
|
||||
"remote_table/TableServer.h"
|
||||
"remote_table/MainWindow.ui"
|
||||
"remote_table/json.hpp"
|
||||
cmake.toml
|
||||
)
|
||||
|
||||
qt_executable(remote_table ${remote_table_SOURCES})
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${remote_table_SOURCES})
|
||||
|
||||
target_compile_features(remote_table PRIVATE
|
||||
cxx_std_17
|
||||
)
|
||||
|
||||
target_link_libraries(remote_table PRIVATE
|
||||
${QT_LIBRARIES}
|
||||
widgets
|
||||
)
|
||||
|
||||
get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT)
|
||||
if(NOT CMKR_VS_STARTUP_PROJECT)
|
||||
set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT remote_table)
|
||||
endif()
|
||||
|
||||
set(CMKR_TARGET remote_table)
|
||||
qt_finalize_executable(${CMKR_TARGET})
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
# Reference: https://build-cpp.github.io/cmkr/cmake-toml
|
||||
[project]
|
||||
name = "cross"
|
||||
include-after = ["gui/Qt.cmake"]
|
||||
|
||||
[subdir.gui]
|
||||
|
||||
[subdir.vendor]
|
||||
|
||||
[template.qt_executable]
|
||||
type = "executable"
|
||||
add-function = "qt_executable"
|
||||
pass-sources = true
|
||||
|
||||
[target.minidump]
|
||||
type = "qt_executable"
|
||||
sources = [
|
||||
"minidump/*.cpp",
|
||||
"minidump/*.h",
|
||||
"minidump/*.ui",
|
||||
"minidump/*.qrc",
|
||||
]
|
||||
link-libraries = [
|
||||
"${QT_LIBRARIES}",
|
||||
"widgets",
|
||||
"cpp-httplib",
|
||||
]
|
||||
compile-features = ["cxx_std_17"]
|
||||
cmake-after = """
|
||||
qt_finalize_executable(${CMKR_TARGET})
|
||||
"""
|
||||
|
||||
[target.remote_table]
|
||||
type = "qt_executable"
|
||||
sources = [
|
||||
"remote_table/*.cpp",
|
||||
"remote_table/*.h",
|
||||
"remote_table/*.ui",
|
||||
"remote_table/*.qrc",
|
||||
"remote_table/json.hpp",
|
||||
]
|
||||
link-libraries = [
|
||||
"${QT_LIBRARIES}",
|
||||
"widgets",
|
||||
]
|
||||
compile-features = ["cxx_std_17"]
|
||||
cmake-after = """
|
||||
qt_finalize_executable(${CMKR_TARGET})
|
||||
"""
|
|
@ -0,0 +1,253 @@
|
|||
include_guard()
|
||||
|
||||
# Change these defaults to point to your infrastructure if desired
|
||||
set(CMKR_REPO "https://github.com/build-cpp/cmkr" CACHE STRING "cmkr git repository" FORCE)
|
||||
set(CMKR_TAG "v0.2.23" CACHE STRING "cmkr git tag (this needs to be available forever)" FORCE)
|
||||
set(CMKR_COMMIT_HASH "" CACHE STRING "cmkr git commit hash (optional)" FORCE)
|
||||
|
||||
# To bootstrap/generate a cmkr project: cmake -P cmkr.cmake
|
||||
if(CMAKE_SCRIPT_MODE_FILE)
|
||||
set(CMAKE_BINARY_DIR "${CMAKE_BINARY_DIR}/build")
|
||||
set(CMAKE_CURRENT_BINARY_DIR "${CMAKE_BINARY_DIR}")
|
||||
file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}")
|
||||
endif()
|
||||
|
||||
# Set these from the command line to customize for development/debugging purposes
|
||||
set(CMKR_EXECUTABLE "" CACHE FILEPATH "cmkr executable")
|
||||
set(CMKR_SKIP_GENERATION OFF CACHE BOOL "skip automatic cmkr generation")
|
||||
set(CMKR_BUILD_TYPE "Debug" CACHE STRING "cmkr build configuration")
|
||||
mark_as_advanced(CMKR_REPO CMKR_TAG CMKR_COMMIT_HASH CMKR_EXECUTABLE CMKR_SKIP_GENERATION CMKR_BUILD_TYPE)
|
||||
|
||||
# Disable cmkr if generation is disabled
|
||||
if(DEFINED ENV{CI} OR CMKR_SKIP_GENERATION OR CMKR_BUILD_SKIP_GENERATION)
|
||||
message(STATUS "[cmkr] Skipping automatic cmkr generation")
|
||||
unset(CMKR_BUILD_SKIP_GENERATION CACHE)
|
||||
macro(cmkr)
|
||||
endmacro()
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Disable cmkr if no cmake.toml file is found
|
||||
if(NOT CMAKE_SCRIPT_MODE_FILE AND NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml")
|
||||
message(AUTHOR_WARNING "[cmkr] Not found: ${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml")
|
||||
macro(cmkr)
|
||||
endmacro()
|
||||
return()
|
||||
endif()
|
||||
|
||||
# Convert a Windows native path to CMake path
|
||||
if(CMKR_EXECUTABLE MATCHES "\\\\")
|
||||
string(REPLACE "\\" "/" CMKR_EXECUTABLE_CMAKE "${CMKR_EXECUTABLE}")
|
||||
set(CMKR_EXECUTABLE "${CMKR_EXECUTABLE_CMAKE}" CACHE FILEPATH "" FORCE)
|
||||
unset(CMKR_EXECUTABLE_CMAKE)
|
||||
endif()
|
||||
|
||||
# Helper macro to execute a process (COMMAND_ERROR_IS_FATAL ANY is 3.19 and higher)
|
||||
function(cmkr_exec)
|
||||
execute_process(COMMAND ${ARGV} RESULT_VARIABLE CMKR_EXEC_RESULT)
|
||||
if(NOT CMKR_EXEC_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "cmkr_exec(${ARGV}) failed (exit code ${CMKR_EXEC_RESULT})")
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
# Windows-specific hack (CMAKE_EXECUTABLE_PREFIX is not set at the moment)
|
||||
if(WIN32)
|
||||
set(CMKR_EXECUTABLE_NAME "cmkr.exe")
|
||||
else()
|
||||
set(CMKR_EXECUTABLE_NAME "cmkr")
|
||||
endif()
|
||||
|
||||
# Use cached cmkr if found
|
||||
if(DEFINED ENV{CMKR_CACHE})
|
||||
set(CMKR_DIRECTORY_PREFIX "$ENV{CMKR_CACHE}")
|
||||
string(REPLACE "\\" "/" CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}")
|
||||
if(NOT CMKR_DIRECTORY_PREFIX MATCHES "\\/$")
|
||||
set(CMKR_DIRECTORY_PREFIX "${CMKR_DIRECTORY_PREFIX}/")
|
||||
endif()
|
||||
# Build in release mode for the cache
|
||||
set(CMKR_BUILD_TYPE "Release")
|
||||
else()
|
||||
set(CMKR_DIRECTORY_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/_cmkr_")
|
||||
endif()
|
||||
set(CMKR_DIRECTORY "${CMKR_DIRECTORY_PREFIX}${CMKR_TAG}")
|
||||
set(CMKR_CACHED_EXECUTABLE "${CMKR_DIRECTORY}/bin/${CMKR_EXECUTABLE_NAME}")
|
||||
|
||||
# Helper function to check if a string starts with a prefix
|
||||
# Cannot use MATCHES, see: https://github.com/build-cpp/cmkr/issues/61
|
||||
function(cmkr_startswith str prefix result)
|
||||
string(LENGTH "${prefix}" prefix_length)
|
||||
string(LENGTH "${str}" str_length)
|
||||
if(prefix_length LESS_EQUAL str_length)
|
||||
string(SUBSTRING "${str}" 0 ${prefix_length} str_prefix)
|
||||
if(prefix STREQUAL str_prefix)
|
||||
set("${result}" ON PARENT_SCOPE)
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
set("${result}" OFF PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
# Handle upgrading logic
|
||||
if(CMKR_EXECUTABLE AND NOT CMKR_CACHED_EXECUTABLE STREQUAL CMKR_EXECUTABLE)
|
||||
cmkr_startswith("${CMKR_EXECUTABLE}" "${CMAKE_CURRENT_BINARY_DIR}/_cmkr" CMKR_STARTSWITH_BUILD)
|
||||
cmkr_startswith("${CMKR_EXECUTABLE}" "${CMKR_DIRECTORY_PREFIX}" CMKR_STARTSWITH_CACHE)
|
||||
if(CMKR_STARTSWITH_BUILD)
|
||||
if(DEFINED ENV{CMKR_CACHE})
|
||||
message(AUTHOR_WARNING "[cmkr] Switching to cached cmkr: '${CMKR_CACHED_EXECUTABLE}'")
|
||||
if(EXISTS "${CMKR_CACHED_EXECUTABLE}")
|
||||
set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE)
|
||||
else()
|
||||
unset(CMKR_EXECUTABLE CACHE)
|
||||
endif()
|
||||
else()
|
||||
message(AUTHOR_WARNING "[cmkr] Upgrading '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'")
|
||||
unset(CMKR_EXECUTABLE CACHE)
|
||||
endif()
|
||||
elseif(DEFINED ENV{CMKR_CACHE} AND CMKR_STARTSWITH_CACHE)
|
||||
message(AUTHOR_WARNING "[cmkr] Upgrading cached '${CMKR_EXECUTABLE}' to '${CMKR_CACHED_EXECUTABLE}'")
|
||||
unset(CMKR_EXECUTABLE CACHE)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(CMKR_EXECUTABLE AND EXISTS "${CMKR_EXECUTABLE}")
|
||||
message(VERBOSE "[cmkr] Found cmkr: '${CMKR_EXECUTABLE}'")
|
||||
elseif(CMKR_EXECUTABLE AND NOT CMKR_EXECUTABLE STREQUAL CMKR_CACHED_EXECUTABLE)
|
||||
message(FATAL_ERROR "[cmkr] '${CMKR_EXECUTABLE}' not found")
|
||||
elseif(NOT CMKR_EXECUTABLE AND EXISTS "${CMKR_CACHED_EXECUTABLE}")
|
||||
set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE)
|
||||
message(STATUS "[cmkr] Found cached cmkr: '${CMKR_EXECUTABLE}'")
|
||||
else()
|
||||
set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE)
|
||||
message(VERBOSE "[cmkr] Bootstrapping '${CMKR_EXECUTABLE}'")
|
||||
|
||||
message(STATUS "[cmkr] Fetching cmkr...")
|
||||
if(EXISTS "${CMKR_DIRECTORY}")
|
||||
cmkr_exec("${CMAKE_COMMAND}" -E rm -rf "${CMKR_DIRECTORY}")
|
||||
endif()
|
||||
find_package(Git QUIET REQUIRED)
|
||||
cmkr_exec("${GIT_EXECUTABLE}"
|
||||
clone
|
||||
--config advice.detachedHead=false
|
||||
--branch ${CMKR_TAG}
|
||||
--depth 1
|
||||
${CMKR_REPO}
|
||||
"${CMKR_DIRECTORY}"
|
||||
)
|
||||
if(CMKR_COMMIT_HASH)
|
||||
execute_process(
|
||||
COMMAND "${GIT_EXECUTABLE}" checkout -q "${CMKR_COMMIT_HASH}"
|
||||
RESULT_VARIABLE CMKR_EXEC_RESULT
|
||||
WORKING_DIRECTORY "${CMKR_DIRECTORY}"
|
||||
)
|
||||
if(NOT CMKR_EXEC_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "Tag '${CMKR_TAG}' hash is not '${CMKR_COMMIT_HASH}'")
|
||||
endif()
|
||||
endif()
|
||||
message(STATUS "[cmkr] Building cmkr (using system compiler)...")
|
||||
cmkr_exec("${CMAKE_COMMAND}"
|
||||
--no-warn-unused-cli
|
||||
"${CMKR_DIRECTORY}"
|
||||
"-B${CMKR_DIRECTORY}/build"
|
||||
"-DCMAKE_BUILD_TYPE=${CMKR_BUILD_TYPE}"
|
||||
"-DCMAKE_UNITY_BUILD=ON"
|
||||
"-DCMAKE_INSTALL_PREFIX=${CMKR_DIRECTORY}"
|
||||
"-DCMKR_GENERATE_DOCUMENTATION=OFF"
|
||||
)
|
||||
cmkr_exec("${CMAKE_COMMAND}"
|
||||
--build "${CMKR_DIRECTORY}/build"
|
||||
--config "${CMKR_BUILD_TYPE}"
|
||||
--parallel
|
||||
)
|
||||
cmkr_exec("${CMAKE_COMMAND}"
|
||||
--install "${CMKR_DIRECTORY}/build"
|
||||
--config "${CMKR_BUILD_TYPE}"
|
||||
--prefix "${CMKR_DIRECTORY}"
|
||||
--component cmkr
|
||||
)
|
||||
if(NOT EXISTS ${CMKR_EXECUTABLE})
|
||||
message(FATAL_ERROR "[cmkr] Failed to bootstrap '${CMKR_EXECUTABLE}'")
|
||||
endif()
|
||||
cmkr_exec("${CMKR_EXECUTABLE}" version)
|
||||
message(STATUS "[cmkr] Bootstrapped ${CMKR_EXECUTABLE}")
|
||||
endif()
|
||||
execute_process(COMMAND "${CMKR_EXECUTABLE}" version
|
||||
RESULT_VARIABLE CMKR_EXEC_RESULT
|
||||
)
|
||||
if(NOT CMKR_EXEC_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "[cmkr] Failed to get version, try clearing the cache and rebuilding")
|
||||
endif()
|
||||
|
||||
# Use cmkr.cmake as a script
|
||||
if(CMAKE_SCRIPT_MODE_FILE)
|
||||
if(NOT EXISTS "${CMAKE_SOURCE_DIR}/cmake.toml")
|
||||
execute_process(COMMAND "${CMKR_EXECUTABLE}" init
|
||||
RESULT_VARIABLE CMKR_EXEC_RESULT
|
||||
)
|
||||
if(NOT CMKR_EXEC_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "[cmkr] Failed to bootstrap cmkr project. Please report an issue: https://github.com/build-cpp/cmkr/issues/new")
|
||||
else()
|
||||
message(STATUS "[cmkr] Modify cmake.toml and then configure using: cmake -B build")
|
||||
endif()
|
||||
else()
|
||||
execute_process(COMMAND "${CMKR_EXECUTABLE}" gen
|
||||
RESULT_VARIABLE CMKR_EXEC_RESULT
|
||||
)
|
||||
if(NOT CMKR_EXEC_RESULT EQUAL 0)
|
||||
message(FATAL_ERROR "[cmkr] Failed to generate project.")
|
||||
else()
|
||||
message(STATUS "[cmkr] Configure using: cmake -B build")
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# This is the macro that contains black magic
|
||||
macro(cmkr)
|
||||
# When this macro is called from the generated file, fake some internal CMake variables
|
||||
get_source_file_property(CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}" CMKR_CURRENT_LIST_FILE)
|
||||
if(CMKR_CURRENT_LIST_FILE)
|
||||
set(CMAKE_CURRENT_LIST_FILE "${CMKR_CURRENT_LIST_FILE}")
|
||||
get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY)
|
||||
endif()
|
||||
|
||||
# File-based include guard (include_guard is not documented to work)
|
||||
get_source_file_property(CMKR_INCLUDE_GUARD "${CMAKE_CURRENT_LIST_FILE}" CMKR_INCLUDE_GUARD)
|
||||
if(NOT CMKR_INCLUDE_GUARD)
|
||||
set_source_files_properties("${CMAKE_CURRENT_LIST_FILE}" PROPERTIES CMKR_INCLUDE_GUARD TRUE)
|
||||
|
||||
file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_PRE)
|
||||
|
||||
# Generate CMakeLists.txt
|
||||
cmkr_exec("${CMKR_EXECUTABLE}" gen
|
||||
WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
)
|
||||
|
||||
file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_POST)
|
||||
|
||||
# Delete the temporary file if it was left for some reason
|
||||
set(CMKR_TEMP_FILE "${CMAKE_CURRENT_SOURCE_DIR}/CMakerLists.txt")
|
||||
if(EXISTS "${CMKR_TEMP_FILE}")
|
||||
file(REMOVE "${CMKR_TEMP_FILE}")
|
||||
endif()
|
||||
|
||||
if(NOT CMKR_LIST_FILE_SHA256_PRE STREQUAL CMKR_LIST_FILE_SHA256_POST)
|
||||
# Copy the now-generated CMakeLists.txt to CMakerLists.txt
|
||||
# This is done because you cannot include() a file you are currently in
|
||||
configure_file(CMakeLists.txt "${CMKR_TEMP_FILE}" COPYONLY)
|
||||
|
||||
# Add the macro required for the hack at the start of the cmkr macro
|
||||
set_source_files_properties("${CMKR_TEMP_FILE}" PROPERTIES
|
||||
CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}"
|
||||
)
|
||||
|
||||
# 'Execute' the newly-generated CMakeLists.txt
|
||||
include("${CMKR_TEMP_FILE}")
|
||||
|
||||
# Delete the generated file
|
||||
file(REMOVE "${CMKR_TEMP_FILE}")
|
||||
|
||||
# Do not execute the rest of the original CMakeLists.txt
|
||||
return()
|
||||
endif()
|
||||
# Resume executing the unmodified CMakeLists.txt
|
||||
endif()
|
||||
endmacro()
|
|
@ -0,0 +1,334 @@
|
|||
#include <cstdio>
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QClipboard>
|
||||
|
||||
#include "Bridge.h"
|
||||
|
||||
#include "Types.h"
|
||||
#include "Bridge.h"
|
||||
#include <zydis_wrapper.h>
|
||||
|
||||
struct InvalidMemoryProvider : MemoryProvider
|
||||
{
|
||||
bool read(duint addr, void* dest, duint size) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool getRange(duint addr, duint & base, duint & size) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isCodePtr(duint addr) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isValidPtr(duint addr) override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
} gInvalidMemoryProvider;
|
||||
|
||||
static MemoryProvider* gMemory = &gInvalidMemoryProvider;
|
||||
|
||||
void DbgSetMemoryProvider(MemoryProvider* provider)
|
||||
{
|
||||
gMemory = provider ? provider : &gInvalidMemoryProvider;
|
||||
}
|
||||
|
||||
// BRIDGE
|
||||
|
||||
bool BridgeSettingGet(const char* section, const char* key, char* value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BridgeSettingSet(const char* section, const char* key, const char* value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BridgeSettingGetUint(const char* section, const char* key, duint* value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BridgeSettingSetUint(const char* section, const char* key, duint value)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const wchar_t* BridgeUserDirectory()
|
||||
{
|
||||
return L".";
|
||||
}
|
||||
|
||||
void* BridgeAlloc(size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void BridgeFree(void* ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
// DBG
|
||||
|
||||
bool DbgIsDebugging()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
DBGFUNCTIONS* DbgFunctions()
|
||||
{
|
||||
static DBGFUNCTIONS* cache = []
|
||||
{
|
||||
static DBGFUNCTIONS f;
|
||||
f.GetTraceRecordHitCount = [](duint addr) -> duint
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
f.ModBaseFromAddr = [](duint addr) -> duint
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
f.ModNameFromAddr = [](duint addr, char* name, bool extension)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
f.StringFormatInline = [](char* dest, duint size, const char* format)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
f.MemIsCodePage = [](duint addr, bool refresh)
|
||||
{
|
||||
return gMemory->isCodePtr(addr);
|
||||
};
|
||||
f.GetMnemonicBrief = [](const char* mnem, size_t resultSize, char* result)
|
||||
{
|
||||
*result = '\0';
|
||||
};
|
||||
f.ModRelocationAtAddr = [](duint addr, DBGRELOCATIONINFO * relocation)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
f.PatchGetEx = [](duint addr, DBGPATCHINFO * info)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
f.ValFromString = [](const char* expr, duint * value)
|
||||
{
|
||||
bool success = false;
|
||||
*value = DbgEval(expr, &success);
|
||||
return success;
|
||||
};
|
||||
f.ModGetParty = [](duint addr)
|
||||
{
|
||||
return 0;
|
||||
};
|
||||
f.PatchInRange = [](duint start, duint end)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
f.MemPatch = [](duint start, const unsigned char* data, duint size)
|
||||
{
|
||||
return false;
|
||||
};
|
||||
return &f;
|
||||
}();
|
||||
return cache;
|
||||
}
|
||||
|
||||
bool DbgGetLabelAt(duint addr, SEGTYPE seg, char* label)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DbgGetModuleAt(duint addr, char* module)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DbgGetCommentAt(duint addr, char* comment)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DbgGetBookmarkAt(duint addr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BPXTYPE DbgGetBpxTypeAt(duint addr)
|
||||
{
|
||||
return bp_none;
|
||||
}
|
||||
|
||||
bool DbgMemIsValidReadPtr(duint addr)
|
||||
{
|
||||
return gMemory->isValidPtr(addr);
|
||||
}
|
||||
|
||||
bool DbgGetStringAt(duint addr, char* str)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DbgEval(const char* expr, bool* success)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
duint DbgValFromString(const char* expr)
|
||||
{
|
||||
duint result = 0;
|
||||
if(!DbgEval(expr))
|
||||
result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool DbgCmdExec(const char* cmd)
|
||||
{
|
||||
printf("DbgCmdExec(\"%s\")\n", cmd);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DbgCmdExecDirect(const char* cmd)
|
||||
{
|
||||
printf("DbgCmdExecDirect(\"%s\")\n", cmd);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool DbgCmdExec(const QString & cmd)
|
||||
{
|
||||
return DbgCmdExec(cmd.toUtf8().constData());
|
||||
}
|
||||
|
||||
bool DbgCmdExecDirect(const QString & cmd)
|
||||
{
|
||||
return DbgCmdExecDirect(cmd.toUtf8().constData());
|
||||
}
|
||||
|
||||
duint DbgMemFindBaseAddr(duint addr, duint* size)
|
||||
{
|
||||
duint rangeBase = 0;
|
||||
duint rangeSize = 0;
|
||||
if(!gMemory->getRange(addr, rangeBase, rangeSize))
|
||||
return 0;
|
||||
|
||||
if(size != nullptr)
|
||||
*size = rangeSize;
|
||||
|
||||
return rangeBase;
|
||||
}
|
||||
|
||||
bool DbgMemRead(duint addr, void* dest, size_t size)
|
||||
{
|
||||
return gMemory->read(addr, dest, size);
|
||||
}
|
||||
|
||||
FUNCTYPE DbgGetFunctionTypeAt(duint addr)
|
||||
{
|
||||
return FUNC_NONE;
|
||||
}
|
||||
|
||||
XREFTYPE DbgGetXrefTypeAt(duint addr)
|
||||
{
|
||||
return XREF_NONE;
|
||||
}
|
||||
|
||||
ARGTYPE DbgGetArgTypeAt(duint addr)
|
||||
{
|
||||
return ARG_NONE;
|
||||
}
|
||||
|
||||
LOOPTYPE DbgGetLoopTypeAt(duint addr, int depth)
|
||||
{
|
||||
return LOOP_NONE;
|
||||
}
|
||||
|
||||
duint DbgGetBranchDestination(duint addr)
|
||||
{
|
||||
uint8_t data[MAX_DISASM_BUFFER];
|
||||
if(!DbgMemRead(addr, data, sizeof(data)))
|
||||
return 0;
|
||||
Zydis zydis(true); // TODO: architecture
|
||||
if(!zydis.Disassemble(addr, data))
|
||||
return 0;
|
||||
return zydis.BranchDestination();
|
||||
}
|
||||
|
||||
bool DbgIsJumpGoingToExecute(duint addr)
|
||||
{
|
||||
return false; // TODO
|
||||
}
|
||||
|
||||
bool DbgXrefGet(duint addr, XREF_INFO* info)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void DbgReleaseEncodeTypeBuffer(void* buffer)
|
||||
{
|
||||
BridgeFree(buffer);
|
||||
}
|
||||
|
||||
void* DbgGetEncodeTypeBuffer(duint addr, duint* size)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool DbgSetEncodeType(duint addr, duint size, ENCODETYPE type)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
void DbgDelEncodeTypeRange(duint start, duint end)
|
||||
{
|
||||
}
|
||||
|
||||
void DbgDelEncodeTypeSegment(duint start)
|
||||
{
|
||||
}
|
||||
|
||||
// GUI
|
||||
|
||||
void GuiExecuteOnGuiThreadEx(GuiCallback callback, void* data)
|
||||
{
|
||||
// TODO: force schedule on the GUI thread
|
||||
callback(data);
|
||||
}
|
||||
|
||||
void GuiAddLogMessage(const char* msg)
|
||||
{
|
||||
Bridge::getBridge()->addMsgToLog(msg);
|
||||
}
|
||||
|
||||
void GuiUpdateAllViews()
|
||||
{
|
||||
Bridge::getBridge()->repaintTableView();
|
||||
}
|
||||
|
||||
void GuiUpdatePatches()
|
||||
{
|
||||
}
|
||||
|
||||
Bridge* Bridge::getBridge()
|
||||
{
|
||||
static Bridge i;
|
||||
return &i;
|
||||
}
|
||||
|
||||
void Bridge::CopyToClipboard(const QString & str)
|
||||
{
|
||||
QGuiApplication::clipboard()->setText(str);
|
||||
}
|
||||
|
||||
void Bridge::addMsgToLog(const QByteArray & bytes)
|
||||
{
|
||||
printf("addMsgToLog: %s\n", bytes.data());
|
||||
}
|
|
@ -0,0 +1,172 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QDebug>
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
#define MAX_SETTING_SIZE 4096
|
||||
|
||||
bool BridgeSettingGet(const char* section, const char* key, char* value);
|
||||
bool BridgeSettingSet(const char* section, const char* key, const char* value);
|
||||
bool BridgeSettingGetUint(const char* section, const char* key, duint* value);
|
||||
bool BridgeSettingSetUint(const char* section, const char* key, duint value);
|
||||
const wchar_t* BridgeUserDirectory();
|
||||
void* BridgeAlloc(size_t size);
|
||||
void BridgeFree(void* ptr);
|
||||
|
||||
#define MAX_LABEL_SIZE 256
|
||||
#define MAX_MODULE_SIZE 256
|
||||
#define MAX_COMMENT_SIZE 256
|
||||
#define MAX_STRING_SIZE 2048
|
||||
|
||||
enum SEGTYPE
|
||||
{
|
||||
SEG_DEFAULT,
|
||||
SEG_ES,
|
||||
SEG_DS,
|
||||
SEG_FS,
|
||||
SEG_GS,
|
||||
SEG_CS,
|
||||
SEG_SS,
|
||||
};
|
||||
|
||||
enum BPXTYPE
|
||||
{
|
||||
bp_none,
|
||||
bp_normal,
|
||||
bp_hardware,
|
||||
bp_memory,
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FUNC_NONE,
|
||||
FUNC_BEGIN,
|
||||
FUNC_MIDDLE,
|
||||
FUNC_END,
|
||||
FUNC_SINGLE
|
||||
} FUNCTYPE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
LOOP_NONE,
|
||||
LOOP_BEGIN,
|
||||
LOOP_MIDDLE,
|
||||
LOOP_ENTRY,
|
||||
LOOP_END,
|
||||
LOOP_SINGLE
|
||||
} LOOPTYPE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
ARG_NONE,
|
||||
ARG_BEGIN,
|
||||
ARG_MIDDLE,
|
||||
ARG_END,
|
||||
ARG_SINGLE
|
||||
} ARGTYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t rva;
|
||||
uint8_t type;
|
||||
uint16_t size;
|
||||
} DBGRELOCATIONINFO;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char mod[MAX_MODULE_SIZE];
|
||||
duint addr;
|
||||
unsigned char oldbyte;
|
||||
unsigned char newbyte;
|
||||
} DBGPATCHINFO;
|
||||
|
||||
struct DBGFUNCTIONS
|
||||
{
|
||||
duint(*GetTraceRecordHitCount)(duint addr);
|
||||
duint(*ModBaseFromAddr)(duint addr);
|
||||
bool (*ModNameFromAddr)(duint base, char* name, bool extension);
|
||||
bool (*StringFormatInline)(char* dest, duint size, const char* format);
|
||||
bool (*MemIsCodePage)(duint addr, bool refresh);
|
||||
void (*GetMnemonicBrief)(const char* mnem, size_t resultSize, char* result);
|
||||
bool (*ModRelocationAtAddr)(duint addr, DBGRELOCATIONINFO* relocation);
|
||||
bool (*PatchGetEx)(duint addr, DBGPATCHINFO* info);
|
||||
bool (*ValFromString)(const char* expr, duint* value);
|
||||
int (*ModGetParty)(duint addr);
|
||||
bool (*PatchInRange)(duint start, duint end);
|
||||
bool (*MemPatch)(duint start, const unsigned char* data, duint size);
|
||||
};
|
||||
|
||||
struct MemoryProvider
|
||||
{
|
||||
virtual ~MemoryProvider() = default;
|
||||
virtual bool read(duint addr, void* dest, duint size) = 0;
|
||||
virtual bool getRange(duint addr, duint & base, duint & size) = 0;
|
||||
virtual bool isCodePtr(duint addr) = 0;
|
||||
virtual bool isValidPtr(duint addr) = 0;
|
||||
};
|
||||
|
||||
void DbgSetMemoryProvider(MemoryProvider* provider);
|
||||
|
||||
bool DbgIsDebugging();
|
||||
DBGFUNCTIONS* DbgFunctions();
|
||||
bool DbgGetLabelAt(duint addr, SEGTYPE seg, char* label);
|
||||
bool DbgGetModuleAt(duint addr, char* module);
|
||||
bool DbgGetCommentAt(duint addr, char* comment);
|
||||
bool DbgGetBookmarkAt(duint addr);
|
||||
BPXTYPE DbgGetBpxTypeAt(duint addr);
|
||||
bool DbgMemIsValidReadPtr(duint addr);
|
||||
bool DbgGetStringAt(duint addr, char* str);
|
||||
bool DbgEval(const char* expr, bool* success = nullptr);
|
||||
duint DbgValFromString(const char* expr);
|
||||
bool DbgCmdExec(const char* cmd);
|
||||
bool DbgCmdExecDirect(const char* cmd);
|
||||
duint DbgMemFindBaseAddr(duint addr, duint* size);
|
||||
bool DbgMemRead(duint addr, void* dest, size_t size);
|
||||
FUNCTYPE DbgGetFunctionTypeAt(duint addr);
|
||||
XREFTYPE DbgGetXrefTypeAt(duint addr);
|
||||
ARGTYPE DbgGetArgTypeAt(duint addr);
|
||||
LOOPTYPE DbgGetLoopTypeAt(duint addr, int depth);
|
||||
duint DbgGetBranchDestination(duint addr);
|
||||
bool DbgIsJumpGoingToExecute(duint addr);
|
||||
bool DbgXrefGet(duint addr, XREF_INFO* info);
|
||||
void DbgReleaseEncodeTypeBuffer(void* buffer);
|
||||
void* DbgGetEncodeTypeBuffer(duint addr, duint* size);
|
||||
bool DbgSetEncodeType(duint addr, duint size, ENCODETYPE type);
|
||||
void DbgDelEncodeTypeRange(duint start, duint end);
|
||||
void DbgDelEncodeTypeSegment(duint start);
|
||||
|
||||
using GuiCallback = void(*)(void*);
|
||||
|
||||
void GuiExecuteOnGuiThreadEx(GuiCallback callback, void* data);
|
||||
void GuiAddLogMessage(const char* msg);
|
||||
void GuiUpdateAllViews();
|
||||
void GuiUpdatePatches();
|
||||
|
||||
// QString helpers
|
||||
bool DbgCmdExec(const QString & cmd);
|
||||
bool DbgCmdExecDirect(const QString & cmd);
|
||||
|
||||
class Bridge : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Bridge() = default;
|
||||
|
||||
signals:
|
||||
void close();
|
||||
void repaintTableView();
|
||||
void updateDump();
|
||||
void updateDisassembly();
|
||||
void dbgStateChanged(DBGSTATE state);
|
||||
|
||||
public:
|
||||
static Bridge* getBridge();
|
||||
static void CopyToClipboard(const QString & str);
|
||||
|
||||
void addMsgToLog(const QByteArray & bytes);
|
||||
|
||||
duint mLastCip = 0;
|
||||
bool mIsRunning = true;
|
||||
};
|
|
@ -0,0 +1,100 @@
|
|||
set(widgets_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../gui/Src")
|
||||
|
||||
add_subdirectory(
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../../zydis_wrapper
|
||||
${CMAKE_CURRENT_BINARY_DIR}/zydis_wrapper
|
||||
)
|
||||
|
||||
include(Qt.cmake)
|
||||
|
||||
set(hook_SOURCES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Bridge.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Bridge.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Configuration.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Configuration.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/MagicMenu.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/MiscUtil.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/MiscUtil.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/StringUtil.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/StringUtil.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Types.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/Imports.h
|
||||
)
|
||||
|
||||
set(widgets_SOURCES
|
||||
${widgets_SOURCE_DIR}/BasicView/AbstractStdTable.cpp
|
||||
${widgets_SOURCE_DIR}/BasicView/AbstractStdTable.h
|
||||
${widgets_SOURCE_DIR}/BasicView/AbstractTableView.cpp
|
||||
${widgets_SOURCE_DIR}/BasicView/AbstractTableView.h
|
||||
${widgets_SOURCE_DIR}/BasicView/Disassembly.cpp
|
||||
${widgets_SOURCE_DIR}/BasicView/Disassembly.h
|
||||
${widgets_SOURCE_DIR}/BasicView/HexDump.cpp
|
||||
${widgets_SOURCE_DIR}/BasicView/HexDump.h
|
||||
${widgets_SOURCE_DIR}/BasicView/HistoryLineEdit.cpp
|
||||
${widgets_SOURCE_DIR}/BasicView/HistoryLineEdit.h
|
||||
${widgets_SOURCE_DIR}/BasicView/StdTable.cpp
|
||||
${widgets_SOURCE_DIR}/BasicView/StdTable.h
|
||||
${widgets_SOURCE_DIR}/Disassembler/Architecture.cpp
|
||||
${widgets_SOURCE_DIR}/Disassembler/Architecture.h
|
||||
${widgets_SOURCE_DIR}/Disassembler/QZydis.cpp
|
||||
${widgets_SOURCE_DIR}/Disassembler/QZydis.h
|
||||
${widgets_SOURCE_DIR}/Disassembler/ZydisTokenizer.cpp
|
||||
${widgets_SOURCE_DIR}/Disassembler/ZydisTokenizer.h
|
||||
${widgets_SOURCE_DIR}/Gui/BrowseDialog.cpp
|
||||
${widgets_SOURCE_DIR}/Gui/BrowseDialog.h
|
||||
${widgets_SOURCE_DIR}/Gui/BrowseDialog.ui
|
||||
${widgets_SOURCE_DIR}/Gui/ColumnReorderDialog.cpp
|
||||
${widgets_SOURCE_DIR}/Gui/ColumnReorderDialog.h
|
||||
${widgets_SOURCE_DIR}/Gui/ColumnReorderDialog.ui
|
||||
${widgets_SOURCE_DIR}/Gui/ComboBoxDialog.cpp
|
||||
${widgets_SOURCE_DIR}/Gui/ComboBoxDialog.h
|
||||
${widgets_SOURCE_DIR}/Gui/ComboBoxDialog.ui
|
||||
${widgets_SOURCE_DIR}/Gui/DisassemblyPopup.cpp
|
||||
${widgets_SOURCE_DIR}/Gui/DisassemblyPopup.h
|
||||
${widgets_SOURCE_DIR}/Gui/LineEditDialog.cpp
|
||||
${widgets_SOURCE_DIR}/Gui/LineEditDialog.h
|
||||
${widgets_SOURCE_DIR}/Gui/LineEditDialog.ui
|
||||
${widgets_SOURCE_DIR}/Memory/MemoryPage.cpp
|
||||
${widgets_SOURCE_DIR}/Memory/MemoryPage.h
|
||||
${widgets_SOURCE_DIR}/Utils/ActionHelpers.h
|
||||
${widgets_SOURCE_DIR}/Utils/CachedFontMetrics.h
|
||||
${widgets_SOURCE_DIR}/Utils/CodeFolding.cpp
|
||||
${widgets_SOURCE_DIR}/Utils/CodeFolding.h
|
||||
${widgets_SOURCE_DIR}/Utils/EncodeMap.cpp
|
||||
${widgets_SOURCE_DIR}/Utils/EncodeMap.h
|
||||
${widgets_SOURCE_DIR}/Utils/MenuBuilder.cpp
|
||||
${widgets_SOURCE_DIR}/Utils/MenuBuilder.h
|
||||
${widgets_SOURCE_DIR}/Utils/MethodInvoker.h
|
||||
${widgets_SOURCE_DIR}/Utils/RichTextPainter.cpp
|
||||
${widgets_SOURCE_DIR}/Utils/RichTextPainter.h
|
||||
${widgets_SOURCE_DIR}/Utils/VaHistory.h
|
||||
)
|
||||
|
||||
include_directories(BEFORE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
|
||||
add_library(widgets STATIC
|
||||
${hook_SOURCES}
|
||||
${widgets_SOURCES}
|
||||
)
|
||||
|
||||
target_include_directories(widgets PUBLIC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${widgets_SOURCE_DIR}
|
||||
)
|
||||
|
||||
source_group(TREE ${widgets_SOURCE_DIR} FILES ${widgets_SOURCES})
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} PREFIX hook FILES ${hook_SOURCES})
|
||||
|
||||
target_compile_definitions(widgets PRIVATE
|
||||
QT_NO_DEPRECATED_WARNINGS
|
||||
)
|
||||
|
||||
target_link_libraries(widgets PUBLIC
|
||||
${QT_LIBRARIES}
|
||||
zydis_wrapper
|
||||
)
|
||||
|
||||
# https://doc.qt.io/qt-6/wasm.html#asyncify
|
||||
if(EMSCRIPTEN)
|
||||
#target_link_options(${CMKR_TARGET} PUBLIC -sASYNCIFY -Os)
|
||||
endif()
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,132 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QKeySequence>
|
||||
#include <QMap>
|
||||
#include <QColor>
|
||||
#include <QFont>
|
||||
#include "Types.h"
|
||||
|
||||
// TODO: declare AppearanceDialog and SettingsDialog entries here, so that you only have to do it in once place
|
||||
#define Config() (Configuration::instance())
|
||||
#define ConfigColor(x) (Config()->getColor(x))
|
||||
#define ConfigBool(x,y) (Config()->getBool(x,y))
|
||||
#define ConfigUint(x,y) (Config()->getUint(x,y))
|
||||
#define ConfigFont(x) (Config()->getFont(x))
|
||||
#define ConfigShortcut(x) (Config()->getShortcut(x).Hotkey)
|
||||
#define ConfigHScrollBarStyle() "QScrollBar:horizontal{border:1px solid grey;background:#f1f1f1;height:10px}QScrollBar::handle:horizontal{background:#aaaaaa;min-width:20px;margin:1px}QScrollBar::add-line:horizontal,QScrollBar::sub-line:horizontal{width:0;height:0}"
|
||||
#define ConfigVScrollBarStyle() "QScrollBar:vertical{border:1px solid grey;background:#f1f1f1;width:10px}QScrollBar::handle:vertical{background:#aaaaaa;min-height:20px;margin:1px}QScrollBar::add-line:vertical,QScrollBar::sub-line:vertical{width:0;height:0}"
|
||||
|
||||
class MenuBuilder;
|
||||
class QAction;
|
||||
class QWheelEvent;
|
||||
|
||||
class Configuration : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
//Structures
|
||||
struct Shortcut
|
||||
{
|
||||
QString Name;
|
||||
QKeySequence Hotkey;
|
||||
bool GlobalShortcut;
|
||||
|
||||
Shortcut(QString name = QString(), QString hotkey = QString(), bool global = false)
|
||||
: Name(name), Hotkey(hotkey, QKeySequence::PortableText), GlobalShortcut(global) { }
|
||||
|
||||
Shortcut(std::initializer_list<QString> names, QString hotkey = QString(), bool global = false)
|
||||
: Shortcut(QStringList(names).join(" -> "), hotkey, global) { }
|
||||
};
|
||||
|
||||
//Functions
|
||||
Configuration();
|
||||
static Configuration* instance();
|
||||
void load();
|
||||
void save();
|
||||
void readColors();
|
||||
void writeColors();
|
||||
void readBools();
|
||||
void writeBools();
|
||||
void readUints();
|
||||
void writeUints();
|
||||
void readFonts();
|
||||
void writeFonts();
|
||||
void readShortcuts();
|
||||
void writeShortcuts();
|
||||
void registerMenuBuilder(MenuBuilder* menu, size_t count);
|
||||
void registerMainMenuStringList(QList<QAction*>* menu);
|
||||
|
||||
const QColor getColor(const QString & id) const;
|
||||
const bool getBool(const QString & category, const QString & id) const;
|
||||
void setBool(const QString & category, const QString & id, const bool b);
|
||||
const duint getUint(const QString & category, const QString & id) const;
|
||||
void setUint(const QString & category, const QString & id, const duint i);
|
||||
const QFont getFont(const QString & id) const;
|
||||
const Shortcut getShortcut(const QString & key_id) const;
|
||||
void setShortcut(const QString & key_id, const QKeySequence key_sequence);
|
||||
void setPluginShortcut(const QString & key_id, QString description, QString defaultShortcut, bool global);
|
||||
void loadWindowGeometry(QWidget* window);
|
||||
void saveWindowGeometry(QWidget* window);
|
||||
|
||||
void zoomFont(const QString & fontName, QWheelEvent* event);
|
||||
|
||||
//default setting maps
|
||||
QMap<QString, QColor> defaultColors;
|
||||
QMap<QString, QMap<QString, bool>> defaultBools;
|
||||
QMap<QString, QMap<QString, duint>> defaultUints;
|
||||
QMap<QString, QFont> defaultFonts;
|
||||
QMap<QString, Shortcut> defaultShortcuts;
|
||||
|
||||
//public variables
|
||||
QMap<QString, QColor> Colors;
|
||||
QMap<QString, QMap<QString, bool>> Bools;
|
||||
QMap<QString, QMap<QString, duint>> Uints;
|
||||
QMap<QString, QFont> Fonts;
|
||||
QMap<QString, Shortcut> Shortcuts;
|
||||
|
||||
//custom menu maps
|
||||
struct MenuMap
|
||||
{
|
||||
union
|
||||
{
|
||||
QList<QAction*>* mainMenuList;
|
||||
MenuBuilder* builder;
|
||||
};
|
||||
int type;
|
||||
size_t count;
|
||||
|
||||
MenuMap() { }
|
||||
MenuMap(QList<QAction*>* mainMenuList, size_t count)
|
||||
: mainMenuList(mainMenuList), type(1), count(count) { }
|
||||
MenuMap(MenuBuilder* builder, size_t count)
|
||||
: builder(builder), type(0), count(count) { }
|
||||
};
|
||||
|
||||
QList<MenuMap> NamedMenuBuilders;
|
||||
|
||||
static Configuration* mPtr;
|
||||
|
||||
signals:
|
||||
void colorsUpdated();
|
||||
void fontsUpdated();
|
||||
void guiOptionsUpdated();
|
||||
void shortcutsUpdated();
|
||||
void tokenizerConfigUpdated();
|
||||
void disableAutoCompleteUpdated();
|
||||
|
||||
private:
|
||||
QColor colorFromConfig(const QString & id);
|
||||
bool colorToConfig(const QString & id, const QColor color);
|
||||
bool boolFromConfig(const QString & category, const QString & id);
|
||||
bool boolToConfig(const QString & category, const QString & id, bool bBool);
|
||||
duint uintFromConfig(const QString & category, const QString & id);
|
||||
bool uintToConfig(const QString & category, const QString & id, duint i);
|
||||
QFont fontFromConfig(const QString & id);
|
||||
bool fontToConfig(const QString & id, const QFont font);
|
||||
QString shortcutFromConfig(const QString & id);
|
||||
bool shortcutToConfig(const QString & id, const QKeySequence shortcut);
|
||||
|
||||
mutable bool noMoreMsgbox;
|
||||
QMap<QString, int> mZoomFontDelta;
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
#pragma once
|
||||
|
||||
#include "Types.h"
|
|
@ -0,0 +1,120 @@
|
|||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include "Utils/MenuBuilder.h"
|
||||
#include <QCoreApplication>
|
||||
#include <QDebug>
|
||||
|
||||
// TODO: support QT_TR_NOOP in linguist
|
||||
#define TR(str) TranslatedText(str)
|
||||
|
||||
template<class Base>
|
||||
class MagicMenu
|
||||
{
|
||||
MenuBuilder* mMenuBuilder = nullptr;
|
||||
|
||||
Base* base()
|
||||
{
|
||||
return static_cast<Base*>(this);
|
||||
}
|
||||
|
||||
public:
|
||||
struct TranslatedText
|
||||
{
|
||||
const char* text = nullptr;
|
||||
|
||||
explicit TranslatedText(const char* text)
|
||||
: text(text)
|
||||
{
|
||||
}
|
||||
|
||||
TranslatedText(const TranslatedText &) = delete;
|
||||
TranslatedText(TranslatedText &&) = delete;
|
||||
};
|
||||
|
||||
// TODO: see if it's possible to support ActionDescription("Goto", "G") directly in linguist
|
||||
struct TableAction
|
||||
{
|
||||
const char* name = nullptr;
|
||||
const char* defaultShortcut = nullptr;
|
||||
|
||||
TableAction(const TranslatedText & name, const char* defaultShortcut = nullptr)
|
||||
: name(name.text), defaultShortcut(defaultShortcut)
|
||||
{
|
||||
}
|
||||
|
||||
TableAction(const TableAction &) = delete;
|
||||
TableAction(TableAction &&) = delete;
|
||||
|
||||
QAction* buildAction(QWidget* widget) const
|
||||
{
|
||||
auto className = widget->metaObject()->className();
|
||||
qDebug() << "Register shortcut action:" << className << ":" << name;
|
||||
auto qAction = new QAction(QCoreApplication::translate(className, name));
|
||||
// TODO: set shortcut based on configuration
|
||||
qAction->setShortcut(QKeySequence(defaultShortcut));
|
||||
qAction->setShortcutContext(Qt::WidgetShortcut);
|
||||
// TODO: allow shortcut to update dynamically
|
||||
widget->addAction(qAction);
|
||||
return qAction;
|
||||
}
|
||||
};
|
||||
|
||||
MagicMenu()
|
||||
{
|
||||
mMenuBuilder = new MenuBuilder(base());
|
||||
|
||||
base()->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||
QObject::connect(base(), &QWidget::customContextMenuRequested, [this](const QPoint & pos)
|
||||
{
|
||||
if(pos.y() < base()->getHeaderHeight())
|
||||
return;
|
||||
auto wMenu = new QMenu(base());
|
||||
mMenuBuilder->build(wMenu);
|
||||
if(wMenu->actions().length())
|
||||
{
|
||||
wMenu->popup(base()->mapToGlobal(pos));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
MenuBuilder* menuBuilder()
|
||||
{
|
||||
return mMenuBuilder;
|
||||
}
|
||||
|
||||
// TODO: support conditional actions
|
||||
template<typename SlotFn>
|
||||
void addMenuAction(const TableAction & action, SlotFn && slot)
|
||||
{
|
||||
auto qAction = action.buildAction(base());
|
||||
QObject::connect(qAction, &QAction::triggered, base(), slot);
|
||||
mMenuBuilder->addAction(qAction);
|
||||
}
|
||||
|
||||
template<typename SlotFn>
|
||||
void addMenuAction(const TableAction & action, SlotFn && slot, const std::function<bool()> & condition)
|
||||
{
|
||||
auto qAction = action.buildAction(base());
|
||||
QObject::connect(qAction, &QAction::triggered, base(), slot);
|
||||
mMenuBuilder->addAction(qAction, [condition](QMenu*)
|
||||
{
|
||||
return condition();
|
||||
});
|
||||
}
|
||||
|
||||
/*void addMenuAction(const TableAction& action, const char* slot)
|
||||
{
|
||||
auto qAction = action.buildAction(base());
|
||||
QObject::connect(qAction, SIGNAL(triggered(bool)), base(), SLOT(slot));
|
||||
mMenuBuilder->addAction(qAction);
|
||||
}*/
|
||||
|
||||
void addMenuBuilder(const TranslatedText & title, MenuBuilder::BuildCallback && callback)
|
||||
{
|
||||
auto trTitle = QCoreApplication::translate(base()->metaObject()->className(), title.text);
|
||||
auto qMenu = new QMenu(trTitle, base());
|
||||
mMenuBuilder->addMenu(qMenu, std::move(callback));
|
||||
}
|
||||
};
|
|
@ -0,0 +1,404 @@
|
|||
#include "MiscUtil.h"
|
||||
//#include <QtWin>
|
||||
#include <QApplication>
|
||||
#include <QMessageBox>
|
||||
#include <QDir>
|
||||
#include <Gui/LineEditDialog.h>
|
||||
#include <Gui/ComboBoxDialog.h>
|
||||
#include "StringUtil.h"
|
||||
#include <Gui/BrowseDialog.h>
|
||||
#include "Bridge.h"
|
||||
#include <thread>
|
||||
|
||||
#if 0
|
||||
void SetApplicationIcon(WId winId)
|
||||
{
|
||||
std::thread([winId]
|
||||
{
|
||||
HICON hIcon = LoadIcon(GetModuleHandleW(0), MAKEINTRESOURCE(100));
|
||||
SendMessageW((HWND)winId, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
|
||||
DestroyIcon(hIcon);
|
||||
}).detach();
|
||||
}
|
||||
#endif // 0
|
||||
|
||||
QByteArray & ByteReverse(QByteArray & array)
|
||||
{
|
||||
int length = array.length();
|
||||
for(int i = 0; i < length / 2; i++)
|
||||
{
|
||||
char temp = array[i];
|
||||
array[i] = array[length - i - 1];
|
||||
array[length - i - 1] = temp;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
QByteArray ByteReverse(QByteArray && array)
|
||||
{
|
||||
int length = array.length();
|
||||
for(int i = 0; i < length / 2; i++)
|
||||
{
|
||||
char temp = array[i];
|
||||
array[i] = array[length - i - 1];
|
||||
array[length - i - 1] = temp;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
bool SimpleInputBox(QWidget* parent, const QString & title, QString defaultValue, QString & output, const QString & placeholderText, const QIcon* icon)
|
||||
{
|
||||
LineEditDialog mEdit(parent);
|
||||
mEdit.setWindowIcon(icon ? *icon : parent->windowIcon());
|
||||
mEdit.setText(defaultValue);
|
||||
mEdit.setPlaceholderText(placeholderText);
|
||||
mEdit.setWindowTitle(title);
|
||||
mEdit.setCheckBox(false);
|
||||
// TODO: WebAssembly support
|
||||
if(mEdit.exec() == QDialog::Accepted)
|
||||
{
|
||||
output = mEdit.editText;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SimpleChoiceBox(QWidget* parent, const QString & title, QString defaultValue, const QStringList & choices, QString & output, bool editable, const QString & placeholderText, const QIcon* icon, int minimumContentsLength)
|
||||
{
|
||||
ComboBoxDialog mChoice(parent);
|
||||
mChoice.setWindowIcon(icon ? *icon : parent->windowIcon());
|
||||
mChoice.setEditable(editable);
|
||||
mChoice.setItems(choices);
|
||||
mChoice.setText(defaultValue);
|
||||
mChoice.setPlaceholderText(placeholderText);
|
||||
mChoice.setWindowTitle(title);
|
||||
mChoice.setCheckBox(false);
|
||||
if(minimumContentsLength >= 0)
|
||||
mChoice.setMinimumContentsLength(minimumContentsLength);
|
||||
// TODO: WebAssembly support
|
||||
if(mChoice.exec() == QDialog::Accepted)
|
||||
{
|
||||
output = mChoice.currentText();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void SimpleErrorBox(QWidget* parent, const QString & title, const QString & text)
|
||||
{
|
||||
QMessageBox msg(QMessageBox::Critical, title, text, QMessageBox::NoButton, parent);
|
||||
msg.setWindowIcon(DIcon("fatal-error"));
|
||||
msg.setParent(parent, Qt::Dialog);
|
||||
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
// TODO: WebAssembly support
|
||||
msg.exec();
|
||||
}
|
||||
|
||||
void SimpleWarningBox(QWidget* parent, const QString & title, const QString & text)
|
||||
{
|
||||
QMessageBox msg(QMessageBox::Warning, title, text, QMessageBox::NoButton, parent);
|
||||
msg.setWindowIcon(DIcon("exclamation"));
|
||||
msg.setParent(parent, Qt::Dialog);
|
||||
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
// TODO: WebAssembly support
|
||||
msg.exec();
|
||||
}
|
||||
|
||||
void SimpleInfoBox(QWidget* parent, const QString & title, const QString & text)
|
||||
{
|
||||
QMessageBox msg(QMessageBox::Information, title, text, QMessageBox::NoButton, parent);
|
||||
msg.setWindowIcon(DIcon("information"));
|
||||
msg.setParent(parent, Qt::Dialog);
|
||||
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
msg.exec();
|
||||
}
|
||||
|
||||
QString getSymbolicName(duint addr)
|
||||
{
|
||||
char labelText[MAX_LABEL_SIZE] = "";
|
||||
char moduleText[MAX_MODULE_SIZE] = "";
|
||||
bool bHasLabel = DbgGetLabelAt(addr, SEG_DEFAULT, labelText);
|
||||
bool bHasModule = (DbgGetModuleAt(addr, moduleText) && !QString(labelText).startsWith("JMP.&"));
|
||||
QString addrText = ToPtrString(addr);
|
||||
|
||||
if(bHasLabel && bHasModule) // <module.label>
|
||||
return QString("%1 <%2.%3>").arg(addrText).arg(moduleText).arg(labelText);
|
||||
else if(bHasModule) // module.addr
|
||||
return QString("%1.%2").arg(moduleText).arg(addrText);
|
||||
else if(bHasLabel) // <label>
|
||||
return QString("<%1>").arg(labelText);
|
||||
else
|
||||
return addrText;
|
||||
}
|
||||
|
||||
QString getSymbolicNameStr(duint addr)
|
||||
{
|
||||
char labelText[MAX_LABEL_SIZE] = "";
|
||||
char moduleText[MAX_MODULE_SIZE] = "";
|
||||
char string[MAX_STRING_SIZE] = "";
|
||||
bool bHasString = DbgGetStringAt(addr, string);
|
||||
bool bHasLabel = DbgGetLabelAt(addr, SEG_DEFAULT, labelText);
|
||||
bool bHasModule = (DbgGetModuleAt(addr, moduleText) && !QString(labelText).startsWith("JMP.&"));
|
||||
QString addrText = DbgMemIsValidReadPtr(addr) ? ToPtrString(addr) : ToHexString(addr);
|
||||
QString finalText;
|
||||
if(bHasString)
|
||||
finalText = addrText + " " + QString(string);
|
||||
else if(bHasLabel && bHasModule) //<module.label>
|
||||
finalText = QString("<%1.%2>").arg(moduleText).arg(labelText);
|
||||
else if(bHasModule) //module.addr
|
||||
finalText = QString("%1.%2").arg(moduleText).arg(addrText);
|
||||
else if(bHasLabel) //<label>
|
||||
finalText = QString("<%1>").arg(labelText);
|
||||
else
|
||||
{
|
||||
finalText = addrText;
|
||||
if(addr == (addr & 0xFF))
|
||||
{
|
||||
QChar c = QChar((char)addr);
|
||||
if(c.isPrint() || c.isSpace())
|
||||
finalText += QString(" '%1'").arg(EscapeCh(c));
|
||||
}
|
||||
else if(addr == (addr & 0xFFF)) //UNICODE?
|
||||
{
|
||||
QChar c = QChar((ushort)addr);
|
||||
if(c.isPrint() || c.isSpace())
|
||||
finalText += QString(" L'%1'").arg(EscapeCh(c));
|
||||
}
|
||||
}
|
||||
return finalText;
|
||||
}
|
||||
|
||||
QIcon getFileIcon(QString file)
|
||||
{
|
||||
#if 0
|
||||
SHFILEINFO info;
|
||||
if(SHGetFileInfoW((const wchar_t*)file.utf16(), 0, &info, sizeof(info), SHGFI_ICON) == 0)
|
||||
return QIcon(); //API error
|
||||
QIcon result = QIcon(QtWin::fromHICON(info.hIcon));
|
||||
DestroyIcon(info.hIcon);
|
||||
return result;
|
||||
#endif // 0
|
||||
return QIcon();
|
||||
}
|
||||
|
||||
//Export table in CSV. TODO: Display a dialog where the user choose what column to export and in which encoding
|
||||
bool ExportCSV(dsint rows, dsint columns, std::vector<QString> headers, std::function<QString(dsint, dsint)> getCellContent)
|
||||
{
|
||||
BrowseDialog browse(
|
||||
nullptr,
|
||||
QApplication::translate("ExportCSV", "Export data in CSV format"),
|
||||
QApplication::translate("ExportCSV", "Enter the CSV file name to export"),
|
||||
QApplication::translate("ExportCSV", "CSV files (*.csv);;All files (*.*)"),
|
||||
getDbPath("export.csv", true),
|
||||
true
|
||||
);
|
||||
browse.setWindowIcon(DIcon("database-export"));
|
||||
// TODO: WebAssembly support
|
||||
if(browse.exec() == QDialog::Accepted)
|
||||
{
|
||||
FILE* csv;
|
||||
bool utf16;
|
||||
csv = fopen(browse.path.toUtf8().data(), "wb");
|
||||
if(csv == NULL)
|
||||
{
|
||||
GuiAddLogMessage(QApplication::translate("ExportCSV", "CSV export error\n").toUtf8().constData());
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
duint setting;
|
||||
if(BridgeSettingGetUint("Misc", "Utf16LogRedirect", &setting))
|
||||
utf16 = !!setting;
|
||||
else
|
||||
utf16 = false;
|
||||
if(utf16 && ftell(csv) == 0)
|
||||
{
|
||||
unsigned short BOM = 0xfeff;
|
||||
fwrite(&BOM, 2, 1, csv);
|
||||
}
|
||||
dsint row, column;
|
||||
QString text;
|
||||
QString cell;
|
||||
if(headers.size() > 0)
|
||||
{
|
||||
for(column = 0; column < columns; column++)
|
||||
{
|
||||
cell = headers.at(column);
|
||||
if(cell.contains('"') || cell.contains(',') || cell.contains('\r') || cell.contains('\n'))
|
||||
{
|
||||
if(cell.contains('"'))
|
||||
cell = cell.replace("\"", "\"\"");
|
||||
cell = "\"" + cell + "\"";
|
||||
}
|
||||
if(column != columns - 1)
|
||||
cell = cell + ",";
|
||||
text = text + cell;
|
||||
}
|
||||
if(utf16)
|
||||
{
|
||||
text = text + "\r\n";
|
||||
if(!fwrite(text.utf16(), text.length(), 2, csv))
|
||||
{
|
||||
fclose(csv);
|
||||
GuiAddLogMessage(QApplication::translate("ExportCSV", "CSV export error\n").toUtf8().constData());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
text = text + "\n";
|
||||
QByteArray utf8;
|
||||
utf8 = text.toUtf8();
|
||||
if(!fwrite(utf8.constData(), utf8.size(), 1, csv))
|
||||
{
|
||||
fclose(csv);
|
||||
GuiAddLogMessage(QApplication::translate("ExportCSV", "CSV export error\n").toUtf8().constData());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
for(row = 0; row < rows; row++)
|
||||
{
|
||||
text.clear();
|
||||
for(column = 0; column < columns; column++)
|
||||
{
|
||||
cell = getCellContent(row, column);
|
||||
if(cell.contains('"') || cell.contains(',') || cell.contains('\r') || cell.contains('\n'))
|
||||
{
|
||||
if(cell.contains('"'))
|
||||
cell = cell.replace("\"", "\"\"");
|
||||
cell = "\"" + cell + "\"";
|
||||
}
|
||||
if(column != columns - 1)
|
||||
cell = cell + ",";
|
||||
text = text + cell;
|
||||
}
|
||||
if(utf16)
|
||||
{
|
||||
text = text + "\r\n";
|
||||
if(!fwrite(text.utf16(), text.length(), 2, csv))
|
||||
{
|
||||
fclose(csv);
|
||||
GuiAddLogMessage(QApplication::translate("ExportCSV", "CSV export error\n").toUtf8().constData());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
text = text + "\n";
|
||||
QByteArray utf8;
|
||||
utf8 = text.toUtf8();
|
||||
if(!fwrite(utf8.constData(), utf8.size(), 1, csv))
|
||||
{
|
||||
fclose(csv);
|
||||
GuiAddLogMessage(QApplication::translate("ExportCSV", "CSV export error\n").toUtf8().constData());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(csv);
|
||||
GuiAddLogMessage(QApplication::translate("ExportCSV", "Saved CSV data at %1\n").arg(browse.path).toUtf8().constData());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool allowSeasons()
|
||||
{
|
||||
//srand(time());
|
||||
duint setting = 0;
|
||||
return !BridgeSettingGetUint("Gui", "NoSeasons", &setting) || !setting;
|
||||
}
|
||||
|
||||
static bool isChristmas()
|
||||
{
|
||||
auto date = QDateTime::currentDateTime().date();
|
||||
return date.month() == 12 && date.day() >= 23 && date.day() <= 26;
|
||||
}
|
||||
|
||||
//https://www.daniweb.com/programming/software-development/threads/463261/c-easter-day-calculation
|
||||
bool isEaster()
|
||||
{
|
||||
auto date = QDateTime::currentDateTime().date();
|
||||
int K, M, S, A, D, R, OG, SZ, OE, X = date.year();
|
||||
K = X / 100; // Secular number
|
||||
M = 15 + (3 * K + 3) / 4 - (8 * K + 13) / 25; // Secular Moon shift
|
||||
S = 2 - (3 * K + 3) / 4; // Secular sun shift
|
||||
A = X % 19; // Moon parameter
|
||||
D = (19 * A + M) % 30; // Seed for 1st full Moon in spring
|
||||
R = D / 29 + (D / 28 - D / 29) * (A / 11); // Calendarian correction quantity
|
||||
OG = 21 + D - R; // Easter limit
|
||||
SZ = 7 - (X + X / 4 + S) % 7; // 1st sunday in March
|
||||
OE = 7 - (OG - SZ) % 7; // Distance Easter sunday from Easter limit in days
|
||||
int MM = ((OG + OE) > 31) ? 4 : 3;
|
||||
int DD = (((OG + OE) % 31) == 0) ? 31 : ((OG + OE) % 31);
|
||||
return date.month() == MM && date.day() >= DD - 2 && date.day() <= DD + 1;
|
||||
}
|
||||
|
||||
bool isSeasonal()
|
||||
{
|
||||
return (isChristmas() || isEaster());
|
||||
}
|
||||
|
||||
QIcon DIconHelper(QString name)
|
||||
{
|
||||
if(name.endsWith(".png"))
|
||||
name = name.left(name.length() - 4);
|
||||
static bool seasons = allowSeasons();
|
||||
static bool christmas = isChristmas();
|
||||
static bool easter = isEaster();
|
||||
if(seasons)
|
||||
{
|
||||
if(christmas)
|
||||
name = QString("christmas%1").arg(rand() % 8 + 1);
|
||||
else if(easter)
|
||||
name = QString("easter%1").arg(rand() % 8 + 1);
|
||||
}
|
||||
return QIcon::fromTheme(name);
|
||||
}
|
||||
|
||||
QString getDbPath(const QString & filename, bool addDateTimeSuffix)
|
||||
{
|
||||
auto path = QString("%1/db").arg(QString::fromWCharArray(BridgeUserDirectory()));
|
||||
if(!filename.isEmpty())
|
||||
{
|
||||
path += '/';
|
||||
path += filename;
|
||||
// Add a date suffix before the extension
|
||||
if(addDateTimeSuffix)
|
||||
{
|
||||
auto extensionIdx = path.lastIndexOf('.');
|
||||
if(extensionIdx == -1)
|
||||
{
|
||||
extensionIdx = path.length();
|
||||
}
|
||||
auto now = QDateTime::currentDateTime();
|
||||
char suffix[64];
|
||||
sprintf_s(suffix, "-%04d%02d%02d-%02d%02d%02d",
|
||||
now.date().year(),
|
||||
now.date().month(),
|
||||
now.date().day(),
|
||||
now.time().hour(),
|
||||
now.time().minute(),
|
||||
now.time().second()
|
||||
);
|
||||
path.insert(extensionIdx, suffix);
|
||||
}
|
||||
}
|
||||
return QDir::toNativeSeparators(path);
|
||||
}
|
||||
|
||||
QString mainModuleName(bool extension)
|
||||
{
|
||||
auto base = DbgEval("mod.main()");
|
||||
char name[MAX_MODULE_SIZE] = "";
|
||||
if(base && DbgFunctions()->ModNameFromAddr(base, name, extension))
|
||||
{
|
||||
return name;
|
||||
}
|
||||
return QString();
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include <QIcon>
|
||||
#include <functional>
|
||||
#include "Types.h"
|
||||
|
||||
class QWidget;
|
||||
class QByteArray;
|
||||
|
||||
//void SetApplicationIcon(WId winId);
|
||||
QByteArray & ByteReverse(QByteArray & array);
|
||||
QByteArray ByteReverse(QByteArray && array);
|
||||
bool SimpleInputBox(QWidget* parent, const QString & title, QString defaultValue, QString & output, const QString & placeholderText, const QIcon* icon = nullptr);
|
||||
bool SimpleChoiceBox(QWidget* parent, const QString & title, QString defaultValue, const QStringList & choices, QString & output, bool editable, const QString & placeholderText, const QIcon* icon = nullptr, int minimumContentsLength = -1);
|
||||
void SimpleErrorBox(QWidget* parent, const QString & title, const QString & text);
|
||||
void SimpleWarningBox(QWidget* parent, const QString & title, const QString & text);
|
||||
void SimpleInfoBox(QWidget* parent, const QString & title, const QString & text);
|
||||
QString getSymbolicName(duint addr);
|
||||
QString getSymbolicNameStr(duint addr);
|
||||
bool ExportCSV(dsint rows, dsint columns, std::vector<QString> headers, std::function<QString(dsint, dsint)> getCellContent);
|
||||
bool isEaster();
|
||||
bool isSeasonal();
|
||||
QIcon getFileIcon(QString file);
|
||||
QIcon DIconHelper(QString name);
|
||||
QString getDbPath(const QString & filename = QString(), bool addDateTimeSuffix = false);
|
||||
QString mainModuleName(bool extension = false);
|
||||
|
||||
#define DIcon(name) [](QString arg) { static QIcon icon(DIconHelper(std::move(arg))); return icon; }(name)
|
|
@ -0,0 +1,63 @@
|
|||
include_guard(DIRECTORY)
|
||||
|
||||
# https://www.kdab.com/wp-content/uploads/stories/QTVTC20-Using-Modern-CMake-Kevin-Funk.pdf
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
set(CMAKE_AUTORCC ON)
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
#set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
set(CMAKE_GLOBAL_AUTOGEN_TARGET ON)
|
||||
set_property(GLOBAL PROPERTY AUTOGEN_SOURCE_GROUP "Qt")
|
||||
set_property(GLOBAL PROPERTY AUTOGEN_TARGETS_FOLDER "Qt")
|
||||
set_property(GLOBAL PROPERTY AUTOMOC_SOURCE_GROUP "Qt")
|
||||
set_property(GLOBAL PROPERTY AUTOMOC_TARGETS_FOLDER "Qt")
|
||||
set_property(GLOBAL PROPERTY AUTORCC_SOURCE_GROUP "Qt")
|
||||
set_property(GLOBAL PROPERTY AUTOUIC_SOURCE_GROUP "Qt")
|
||||
|
||||
# Find whether we are using Qt5 or Qt6
|
||||
# NOTE: do not add components here, it doesn't work
|
||||
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
|
||||
set(QT_PACKAGE "Qt${QT_VERSION_MAJOR}")
|
||||
|
||||
# Find the exact Qt version
|
||||
set(QT_LIBRARIES
|
||||
${QT_PACKAGE}::Widgets
|
||||
${QT_PACKAGE}::Svg
|
||||
${QT_PACKAGE}::WebSockets
|
||||
)
|
||||
if("${QT_PACKAGE}" STREQUAL "Qt6")
|
||||
set(ADDITIONAL_COMPONENTS OpenGLWidgets)
|
||||
list(APPEND QT_LIBRARIES Qt6::OpenGLWidgets)
|
||||
else()
|
||||
set(ADDITIONAL_COMPONENTS "")
|
||||
endif()
|
||||
find_package(${QT_PACKAGE} COMPONENTS Widgets Svg PrintSupport WebSockets ${ADDITIONAL_COMPONENTS} REQUIRED)
|
||||
message(STATUS "Found ${QT_PACKAGE}: ${${QT_PACKAGE}_DIR}")
|
||||
|
||||
# https://stackoverflow.com/a/41199492/1806760
|
||||
# TODO: set VCINSTALLDIR environment variable
|
||||
# TODO: move to a custom target you can trigger manually
|
||||
# TODO: support macdeployqt
|
||||
if(${QT_PACKAGE}_FOUND AND WIN32 AND TARGET ${QT_PACKAGE}::qmake AND NOT TARGET ${QT_PACKAGE}::windeployqt)
|
||||
get_target_property(_qt_qmake_location ${QT_PACKAGE}::qmake IMPORTED_LOCATION)
|
||||
|
||||
execute_process(
|
||||
COMMAND "${_qt_qmake_location}" -query QT_INSTALL_PREFIX
|
||||
RESULT_VARIABLE return_code
|
||||
OUTPUT_VARIABLE qt_install_prefix
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
)
|
||||
|
||||
set(imported_location "${qt_install_prefix}/bin/windeployqt.exe")
|
||||
|
||||
if(EXISTS ${imported_location})
|
||||
add_executable(${QT_PACKAGE}::windeployqt IMPORTED)
|
||||
|
||||
set_target_properties(${QT_PACKAGE}::windeployqt PROPERTIES
|
||||
IMPORTED_LOCATION ${imported_location}
|
||||
)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
function(qt_executable tgt)
|
||||
qt_add_executable(${tgt} MANUAL_FINALIZATION ${ARGN})
|
||||
endfunction()
|
|
@ -0,0 +1,284 @@
|
|||
#include <stdint.h>
|
||||
//#include "main.h"
|
||||
#include "StringUtil.h"
|
||||
#include "MiscUtil.h"
|
||||
//#include "ldconvert.h"
|
||||
#include "Configuration.h"
|
||||
#include "Bridge.h"
|
||||
|
||||
QString ToLongDoubleString(const void* buffer)
|
||||
{
|
||||
char str[32];
|
||||
//ld2str(buffer, str);
|
||||
return str;
|
||||
}
|
||||
|
||||
QString EscapeCh(QChar ch)
|
||||
{
|
||||
switch(ch.unicode())
|
||||
{
|
||||
case '\0':
|
||||
return "\\0";
|
||||
case '\t':
|
||||
return "\\t";
|
||||
case '\f':
|
||||
return "\\f";
|
||||
case '\v':
|
||||
return "\\v";
|
||||
case '\n':
|
||||
return "\\n";
|
||||
case '\r':
|
||||
return "\\r";
|
||||
case '\\':
|
||||
return "\\\\";
|
||||
case '\"':
|
||||
return "\\\"";
|
||||
case '\a':
|
||||
return "\\a";
|
||||
case '\b':
|
||||
return "\\b";
|
||||
default:
|
||||
return QString(1, QChar(ch));
|
||||
}
|
||||
}
|
||||
|
||||
QString fillValue(const char* value, int valsize, bool bFpuRegistersLittleEndian)
|
||||
{
|
||||
if(bFpuRegistersLittleEndian)
|
||||
return QString(QByteArray(value, valsize).toHex()).toUpper();
|
||||
else // Big Endian
|
||||
return QString(ByteReverse(QByteArray(value, valsize)).toHex()).toUpper();
|
||||
}
|
||||
|
||||
QString composeRegTextXMM(const char* value, int mode)
|
||||
{
|
||||
bool bFpuRegistersLittleEndian = ConfigBool("Gui", "FpuRegistersLittleEndian");
|
||||
QString valueText;
|
||||
switch(mode)
|
||||
{
|
||||
default:
|
||||
case 0:
|
||||
{
|
||||
valueText = fillValue(value, 16, bFpuRegistersLittleEndian);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
{
|
||||
const double* dbl_values = reinterpret_cast<const double*>(value);
|
||||
if(bFpuRegistersLittleEndian)
|
||||
valueText = ToDoubleString(&dbl_values[0]) + ' ' + ToDoubleString(&dbl_values[1]);
|
||||
else // Big Endian
|
||||
valueText = ToDoubleString(&dbl_values[1]) + ' ' + ToDoubleString(&dbl_values[0]);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
const float* flt_values = reinterpret_cast<const float*>(value);
|
||||
if(bFpuRegistersLittleEndian)
|
||||
valueText = ToFloatString(&flt_values[0]) + ' ' + ToFloatString(&flt_values[1]) + ' '
|
||||
+ ToFloatString(&flt_values[2]) + ' ' + ToFloatString(&flt_values[3]);
|
||||
else // Big Endian
|
||||
valueText = ToFloatString(&flt_values[3]) + ' ' + ToFloatString(&flt_values[2]) + ' '
|
||||
+ ToFloatString(&flt_values[1]) + ' ' + ToFloatString(&flt_values[0]);
|
||||
}
|
||||
break;
|
||||
case 9:
|
||||
{
|
||||
if(bFpuRegistersLittleEndian)
|
||||
valueText = fillValue(value) + ' ' + fillValue(value + 1 * 2) + ' ' + fillValue(value + 2 * 2) + ' ' + fillValue(value + 3 * 2)
|
||||
+ ' ' + fillValue(value + 4 * 2) + ' ' + fillValue(value + 5 * 2) + ' ' + fillValue(value + 6 * 2) + ' ' + fillValue(value + 7 * 2);
|
||||
else // Big Endian
|
||||
valueText = fillValue(value + 7 * 2) + ' ' + fillValue(value + 6 * 2) + ' ' + fillValue(value + 5 * 2) + ' ' + fillValue(value + 4 * 2)
|
||||
+ ' ' + fillValue(value + 3 * 2) + ' ' + fillValue(value + 2 * 2) + ' ' + fillValue(value + 1 * 2) + ' ' + fillValue(value);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
{
|
||||
const short* sword_values = reinterpret_cast<const short*>(value);
|
||||
if(bFpuRegistersLittleEndian)
|
||||
valueText = QString::number(sword_values[0]) + ' ' + QString::number(sword_values[1]) + ' ' + QString::number(sword_values[2]) + ' ' + QString::number(sword_values[3])
|
||||
+ ' ' + QString::number(sword_values[4]) + ' ' + QString::number(sword_values[5]) + ' ' + QString::number(sword_values[6]) + ' ' + QString::number(sword_values[7]);
|
||||
else // Big Endian
|
||||
valueText = QString::number(sword_values[7]) + ' ' + QString::number(sword_values[6]) + ' ' + QString::number(sword_values[5]) + ' ' + QString::number(sword_values[4])
|
||||
+ ' ' + QString::number(sword_values[3]) + ' ' + QString::number(sword_values[2]) + ' ' + QString::number(sword_values[1]) + ' ' + QString::number(sword_values[0]);
|
||||
}
|
||||
break;
|
||||
case 6:
|
||||
{
|
||||
const unsigned short* uword_values = reinterpret_cast<const unsigned short*>(value);
|
||||
if(bFpuRegistersLittleEndian)
|
||||
valueText = QString::number(uword_values[0]) + ' ' + QString::number(uword_values[1]) + ' ' + QString::number(uword_values[2]) + ' ' + QString::number(uword_values[3])
|
||||
+ ' ' + QString::number(uword_values[4]) + ' ' + QString::number(uword_values[5]) + ' ' + QString::number(uword_values[6]) + ' ' + QString::number(uword_values[7]);
|
||||
else // Big Endian
|
||||
valueText = QString::number(uword_values[7]) + ' ' + QString::number(uword_values[6]) + ' ' + QString::number(uword_values[5]) + ' ' + QString::number(uword_values[4])
|
||||
+ ' ' + QString::number(uword_values[3]) + ' ' + QString::number(uword_values[2]) + ' ' + QString::number(uword_values[1]) + ' ' + QString::number(uword_values[0]);
|
||||
}
|
||||
break;
|
||||
case 10:
|
||||
{
|
||||
if(bFpuRegistersLittleEndian)
|
||||
valueText = fillValue(value, 4) + ' ' + fillValue(value + 1 * 4, 4) + ' ' + fillValue(value + 2 * 4, 4) + ' ' + fillValue(value + 3 * 4, 4);
|
||||
else // Big Endian
|
||||
valueText = fillValue(value + 3 * 4, 4) + ' ' + fillValue(value + 2 * 4, 4) + ' ' + fillValue(value + 1 * 4, 4) + ' ' + fillValue(value, 4);
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
const int* sdword_values = reinterpret_cast<const int*>(value);
|
||||
if(bFpuRegistersLittleEndian)
|
||||
valueText = QString::number(sdword_values[0]) + ' ' + QString::number(sdword_values[1]) + ' ' + QString::number(sdword_values[2]) + ' ' + QString::number(sdword_values[3]);
|
||||
else // Big Endian
|
||||
valueText = QString::number(sdword_values[3]) + ' ' + QString::number(sdword_values[2]) + ' ' + QString::number(sdword_values[1]) + ' ' + QString::number(sdword_values[0]);
|
||||
}
|
||||
break;
|
||||
case 7:
|
||||
{
|
||||
const unsigned int* udword_values = reinterpret_cast<const unsigned int*>(value);
|
||||
if(bFpuRegistersLittleEndian)
|
||||
valueText = QString::number(udword_values[0]) + ' ' + QString::number(udword_values[1]) + ' ' + QString::number(udword_values[2]) + ' ' + QString::number(udword_values[3]);
|
||||
else // Big Endian
|
||||
valueText = QString::number(udword_values[3]) + ' ' + QString::number(udword_values[2]) + ' ' + QString::number(udword_values[1]) + ' ' + QString::number(udword_values[0]);
|
||||
}
|
||||
break;
|
||||
case 11:
|
||||
{
|
||||
if(bFpuRegistersLittleEndian)
|
||||
valueText = fillValue(value, 8) + ' ' + fillValue(value + 8, 8);
|
||||
else // Big Endian
|
||||
valueText = fillValue(value + 8, 8) + ' ' + fillValue(value, 8);
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
const long long* sqword_values = reinterpret_cast<const long long*>(value);
|
||||
if(bFpuRegistersLittleEndian)
|
||||
valueText = QString::number(sqword_values[0]) + ' ' + QString::number(sqword_values[1]);
|
||||
else // Big Endian
|
||||
valueText = QString::number(sqword_values[1]) + ' ' + QString::number(sqword_values[0]);
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
{
|
||||
const unsigned long long* uqword_values = reinterpret_cast<const unsigned long long*>(value);
|
||||
if(bFpuRegistersLittleEndian)
|
||||
valueText = QString::number(uqword_values[0]) + ' ' + QString::number(uqword_values[1]);
|
||||
else // Big Endian
|
||||
valueText = QString::number(uqword_values[1]) + ' ' + QString::number(uqword_values[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return valueText;
|
||||
}
|
||||
|
||||
QString composeRegTextYMM(const char* value, int mode)
|
||||
{
|
||||
bool bFpuRegistersLittleEndian = ConfigBool("Gui", "FpuRegistersLittleEndian");
|
||||
if(mode == 0)
|
||||
return fillValue(value, 32, bFpuRegistersLittleEndian);
|
||||
else if(bFpuRegistersLittleEndian)
|
||||
return composeRegTextXMM(value, mode) + ' ' + composeRegTextXMM(value + 16, mode);
|
||||
else
|
||||
return composeRegTextXMM(value + 16, mode) + ' ' + composeRegTextXMM(value, mode);
|
||||
}
|
||||
|
||||
QString GetDataTypeString(const void* buffer, duint size, ENCODETYPE type)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case enc_byte:
|
||||
return ToIntegralString<unsigned char>(buffer);
|
||||
case enc_word:
|
||||
return ToIntegralString<unsigned short>(buffer);
|
||||
case enc_dword:
|
||||
return ToIntegralString<unsigned int>(buffer);
|
||||
case enc_fword:
|
||||
return QString(ByteReverse(QByteArray((const char*)buffer, 6)).toHex());
|
||||
case enc_qword:
|
||||
return ToIntegralString<unsigned long long int>(buffer);
|
||||
case enc_tbyte:
|
||||
return QString(ByteReverse(QByteArray((const char*)buffer, 10)).toHex());
|
||||
case enc_oword:
|
||||
return QString(ByteReverse(QByteArray((const char*)buffer, 16)).toHex());
|
||||
case enc_mmword:
|
||||
return QString(QByteArray((const char*)buffer, size).toHex());
|
||||
case enc_xmmword:
|
||||
return composeRegTextXMM((const char*)buffer, ConfigUint("Gui", "SIMDRegistersDisplayMode"));
|
||||
case enc_ymmword:
|
||||
return composeRegTextYMM((const char*)buffer, ConfigUint("Gui", "SIMDRegistersDisplayMode"));
|
||||
case enc_real4:
|
||||
return ToFloatString(buffer);
|
||||
case enc_real8:
|
||||
return ToDoubleString(buffer);
|
||||
case enc_real10:
|
||||
return ToLongDoubleString(buffer);
|
||||
case enc_ascii:
|
||||
return EscapeCh(*(const char*)buffer);
|
||||
case enc_unicode:
|
||||
return EscapeCh(QChar((uchar) * (const wchar_t*)buffer));
|
||||
default:
|
||||
return ToIntegralString<unsigned char>(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
QString ToDateString(const QDate & date)
|
||||
{
|
||||
static const char* months[] =
|
||||
{
|
||||
"Jan",
|
||||
"Feb",
|
||||
"Mar",
|
||||
"Apr",
|
||||
"May",
|
||||
"Jun",
|
||||
"Jul",
|
||||
"Aug",
|
||||
"Sep",
|
||||
"Oct",
|
||||
"Nov",
|
||||
"Dec"
|
||||
};
|
||||
char result[32];
|
||||
sprintf_s(result, "%s %d %d", months[date.month() - 1], date.day(), date.year());
|
||||
return result;
|
||||
}
|
||||
|
||||
#if 0
|
||||
QString FILETIMEToDate(const FILETIME & date)
|
||||
{
|
||||
FILETIME localdate;
|
||||
FileTimeToLocalFileTime(&date, &localdate);
|
||||
SYSTEMTIME systime;
|
||||
FileTimeToSystemTime(&localdate, &systime);
|
||||
QDate qdate = QDate(systime.wYear, systime.wMonth, systime.wDay);
|
||||
quint64 time100ns = (quint64)localdate.dwHighDateTime << 32 | (quint64)localdate.dwLowDateTime;
|
||||
time100ns %= (1000ull * 60ull * 60ull * 24ull * 10000ull);
|
||||
localdate.dwHighDateTime = time100ns >> 32;
|
||||
localdate.dwLowDateTime = time100ns & 0xFFFFFFFF;
|
||||
if(qdate != QDate::currentDate())
|
||||
return QLocale(QString(currentLocale)).toString(qdate) + FILETIMEToTime(localdate);
|
||||
else // today
|
||||
return FILETIMEToTime(localdate);
|
||||
}
|
||||
#endif // 0
|
||||
|
||||
bool GetCommentFormat(duint addr, QString & comment, bool* autoComment)
|
||||
{
|
||||
comment.clear();
|
||||
char commentData[MAX_COMMENT_SIZE] = "";
|
||||
if(!DbgGetCommentAt(addr, commentData))
|
||||
return false;
|
||||
auto a = *commentData == '\1';
|
||||
if(autoComment)
|
||||
*autoComment = a;
|
||||
if(!strstr(commentData, "{"))
|
||||
{
|
||||
comment = commentData + a;
|
||||
return true;
|
||||
}
|
||||
char commentFormat[MAX_SETTING_SIZE] = "";
|
||||
if(DbgFunctions()->StringFormatInline(commentData + a, MAX_SETTING_SIZE, commentFormat))
|
||||
comment = commentFormat;
|
||||
else
|
||||
comment = commentData + a;
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,137 @@
|
|||
#pragma once
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <QString>
|
||||
#include <QDateTime>
|
||||
#include <QLocale>
|
||||
#include "Types.h"
|
||||
|
||||
// Hack for compatibility: https://stackoverflow.com/a/75748797/1806760
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
|
||||
namespace Qt
|
||||
{
|
||||
constexpr auto KeepEmptyParts = QString::KeepEmptyParts;
|
||||
constexpr auto SkipEmptyParts = QString::SkipEmptyParts;
|
||||
}
|
||||
#endif // QT_VERSION
|
||||
|
||||
inline QString ToPtrString(duint Address)
|
||||
{
|
||||
//
|
||||
// This function exists because of how QT handles
|
||||
// variables in strings.
|
||||
//
|
||||
// QString::arg():
|
||||
// ((int32)0xFFFF0000) == 0xFFFFFFFFFFFF0000 with sign extension
|
||||
//
|
||||
|
||||
char temp[32];
|
||||
sprintf_s(temp, "%016llX", Address);
|
||||
return QString(temp);
|
||||
}
|
||||
|
||||
inline QString ToLongLongHexString(unsigned long long Value)
|
||||
{
|
||||
char temp[32];
|
||||
sprintf_s(temp, "%llX", Value);
|
||||
return QString(temp);
|
||||
}
|
||||
|
||||
inline QString ToHexString(duint Value)
|
||||
{
|
||||
char temp[32];
|
||||
sprintf_s(temp, "%llX", Value);
|
||||
return QString(temp);
|
||||
}
|
||||
|
||||
inline QString ToDecString(dsint Value)
|
||||
{
|
||||
char temp[32];
|
||||
sprintf_s(temp, "%lld", Value);
|
||||
return QString(temp);
|
||||
}
|
||||
|
||||
inline QString ToByteString(unsigned char Value)
|
||||
{
|
||||
char temp[4];
|
||||
sprintf_s(temp, "%02X", Value);
|
||||
return QString(temp);
|
||||
}
|
||||
|
||||
inline QString ToWordString(unsigned short Value)
|
||||
{
|
||||
char temp[8];
|
||||
sprintf_s(temp, "%04X", Value);
|
||||
return QString(temp);
|
||||
}
|
||||
|
||||
inline QString ToDwordString(unsigned int Value)
|
||||
{
|
||||
char temp[16];
|
||||
sprintf_s(temp, "%08X", Value);
|
||||
return QString(temp);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline QString ToFloatingString(const void* buffer, int precision)
|
||||
{
|
||||
auto value = *(const T*)buffer;
|
||||
std::stringstream wFloatingStr;
|
||||
wFloatingStr << std::setprecision(precision) << value;
|
||||
return QString::fromStdString(wFloatingStr.str());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline QString ToIntegralString(const void* buffer)
|
||||
{
|
||||
auto value = *(const T*)buffer;
|
||||
return ToLongLongHexString(value);
|
||||
}
|
||||
|
||||
inline QString ToFloatString(const void* buffer, int precision = std::numeric_limits<float>::digits10)
|
||||
{
|
||||
return ToFloatingString<float>(buffer, precision);
|
||||
}
|
||||
|
||||
inline QString ToDoubleString(const void* buffer, int precision = std::numeric_limits<double>::digits10)
|
||||
{
|
||||
return ToFloatingString<double>(buffer, precision);
|
||||
}
|
||||
|
||||
QString ToLongDoubleString(const void* buffer);
|
||||
|
||||
QString ToDateString(const QDate & date);
|
||||
|
||||
QString fillValue(const char* value, int valsize = 2, bool bFpuRegistersLittleEndian = false);
|
||||
QString composeRegTextXMM(const char* value, int mode);
|
||||
QString composeRegTextYMM(const char* value, int mode);
|
||||
|
||||
QString GetDataTypeString(const void* buffer, duint size, ENCODETYPE type);
|
||||
|
||||
inline QDate GetCompileDate()
|
||||
{
|
||||
return QLocale("en_US").toDate(QString(__DATE__).simplified(), "MMM d yyyy");
|
||||
}
|
||||
|
||||
#if 0
|
||||
// Format : d:hh:mm:ss.1234567
|
||||
inline QString FILETIMEToTime(const FILETIME & time)
|
||||
{
|
||||
// FILETIME is in 100ns
|
||||
quint64 time100ns = (quint64)time.dwHighDateTime << 32 | (quint64)time.dwLowDateTime;
|
||||
quint64 milliseconds = time100ns / 10000;
|
||||
quint64 days = milliseconds / (1000 * 60 * 60 * 24);
|
||||
QTime qtime = QTime::fromMSecsSinceStartOfDay(milliseconds % (1000 * 60 * 60 * 24));
|
||||
if(days == 0) // 0 days
|
||||
return QString().sprintf("%02d:%02d:%02d.%07lld", qtime.hour(), qtime.minute(), qtime.second(), time100ns % 10000000);
|
||||
else
|
||||
return QString().sprintf("%lld:%02d:%02d:%02d.%07lld", days, qtime.hour(), qtime.minute(), qtime.second(), time100ns % 10000000);
|
||||
}
|
||||
|
||||
QString FILETIMEToDate(const FILETIME & date);
|
||||
#endif // 0
|
||||
|
||||
bool GetCommentFormat(duint addr, QString & comment, bool* autoComment = nullptr);
|
||||
|
||||
QString EscapeCh(QChar ch);
|
|
@ -0,0 +1,76 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
|
||||
// TODO: do something cross platform
|
||||
using duint = uint64_t;
|
||||
using dsint = int64_t;
|
||||
|
||||
#ifndef _WIN32
|
||||
template<size_t Count, class... Args>
|
||||
int sprintf_s(char (&Dest)[Count], const char* fmt, Args... args)
|
||||
{
|
||||
return snprintf(Dest, Count, fmt, args...);
|
||||
}
|
||||
|
||||
inline size_t strcpy_s(char* dst, size_t size, const char* src)
|
||||
{
|
||||
return strlcpy(dst, src, size);
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
// These types are needed in very deep UI components
|
||||
typedef enum
|
||||
{
|
||||
enc_unknown, //must be 0
|
||||
enc_byte, //1 byte
|
||||
enc_word, //2 bytes
|
||||
enc_dword, //4 bytes
|
||||
enc_fword, //6 bytes
|
||||
enc_qword, //8 bytes
|
||||
enc_tbyte, //10 bytes
|
||||
enc_oword, //16 bytes
|
||||
enc_mmword, //8 bytes
|
||||
enc_xmmword, //16 bytes
|
||||
enc_ymmword, //32 bytes
|
||||
enc_zmmword, //64 bytes avx512 not supported
|
||||
enc_real4, //4 byte float
|
||||
enc_real8, //8 byte double
|
||||
enc_real10, //10 byte decimal
|
||||
enc_ascii, //ascii sequence
|
||||
enc_unicode, //unicode sequence
|
||||
enc_code, //start of code
|
||||
enc_junk, //junk code
|
||||
enc_middle //middle of data
|
||||
} ENCODETYPE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
initialized,
|
||||
paused,
|
||||
running,
|
||||
stopped
|
||||
} DBGSTATE;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
XREF_NONE,
|
||||
XREF_DATA,
|
||||
XREF_JMP,
|
||||
XREF_CALL
|
||||
} XREFTYPE;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
duint addr;
|
||||
XREFTYPE type;
|
||||
} XREF_RECORD;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
duint refcount;
|
||||
XREF_RECORD* references;
|
||||
} XREF_INFO;
|
|
@ -0,0 +1,62 @@
|
|||
#include "JsonRpcClient.h"
|
||||
|
||||
JsonRpcClient::JsonRpcClient(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
connect(&mSocket, &QWebSocket::connected, this, &JsonRpcClient::connected);
|
||||
connect(&mSocket, &QWebSocket::disconnected, this, &JsonRpcClient::disconnected);
|
||||
connect(&mSocket, &QWebSocket::textMessageReceived, this, &JsonRpcClient::textMessageReceivedSlot);
|
||||
}
|
||||
|
||||
void JsonRpcClient::open(const QUrl & url)
|
||||
{
|
||||
mSocket.open(url);
|
||||
}
|
||||
|
||||
bool JsonRpcClient::isConnected()
|
||||
{
|
||||
return mSocket.state() == QAbstractSocket::ConnectedState;
|
||||
}
|
||||
|
||||
void JsonRpcClient::call(const QString & method, nlohmann::json params, Callback finished)
|
||||
{
|
||||
auto id = mRequestId++;
|
||||
nlohmann::json request;
|
||||
request["jsonrpc"] = "2.0";
|
||||
request["method"] = method.toStdString();
|
||||
request["params"] = std::move(params);
|
||||
request["id"] = id;
|
||||
// TODO: timeout
|
||||
mCalls.emplace(id, std::move(finished));
|
||||
mSocket.sendTextMessage(QString::fromStdString(request.dump()));
|
||||
}
|
||||
|
||||
void JsonRpcClient::textMessageReceivedSlot(const QString & message)
|
||||
{
|
||||
//qDebug() << "[client] textMessageReceivedSlot" << message;
|
||||
// This is fine 🔥
|
||||
auto response = nlohmann::json::parse(message.toStdString());
|
||||
// TODO: rewrite to not use exceptions for WASM
|
||||
try
|
||||
{
|
||||
auto magic = response.at("jsonrpc").get<std::string>();
|
||||
if(magic != "2.0")
|
||||
{
|
||||
qDebug() << "[client] Invalid magic:" << magic;
|
||||
return;
|
||||
}
|
||||
auto result = response.at("result");
|
||||
auto id = response.at("id").get<uint64_t>();
|
||||
auto itr = mCalls.find(id);
|
||||
if(itr == mCalls.end())
|
||||
{
|
||||
qDebug() << "[client] Unknown response id:" << id;
|
||||
return;
|
||||
}
|
||||
itr->second(result);
|
||||
}
|
||||
catch(std::exception & x)
|
||||
{
|
||||
qDebug() << "[client] JSON exception:" << x.what();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include <QWebSocket>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include "json.hpp"
|
||||
|
||||
// https://www.jsonrpc.org/specification
|
||||
class JsonRpcClient : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
using Callback = std::function<void(const nlohmann::json &)>;
|
||||
|
||||
JsonRpcClient(QObject* parent = nullptr);
|
||||
void open(const QUrl & url);
|
||||
bool isConnected();
|
||||
void call(const QString & method, nlohmann::json params, Callback finished);
|
||||
|
||||
template<class Response, class Request>
|
||||
void call(const Request & params, const std::function<void(Response)> & finished)
|
||||
{
|
||||
if(strcmp(Request::method, Response::method) != 0)
|
||||
throw std::runtime_error("Mismatching method name");
|
||||
nlohmann::json jparams;
|
||||
nlohmann::to_json(jparams, params);
|
||||
call(Request::method, std::move(jparams), [finished](const nlohmann::json & response)
|
||||
{
|
||||
Response r;
|
||||
nlohmann::from_json(response, r);
|
||||
finished(std::move(r));
|
||||
});
|
||||
}
|
||||
|
||||
signals:
|
||||
void connected();
|
||||
void disconnected();
|
||||
|
||||
private slots:
|
||||
void textMessageReceivedSlot(const QString & message);
|
||||
|
||||
private:
|
||||
uint64_t mRequestId = 0;
|
||||
QWebSocket mSocket;
|
||||
std::unordered_map<int, Callback> mCalls;
|
||||
};
|
|
@ -0,0 +1,33 @@
|
|||
#include "MainWindow.h"
|
||||
#include "./ui_MainWindow.h"
|
||||
#include <QDebug>
|
||||
#include <QMessageBox>
|
||||
#include <QVBoxLayout>
|
||||
#include <QFileDialog>
|
||||
#include "StringUtil.h"
|
||||
#include <fstream>
|
||||
|
||||
MainWindow::MainWindow(QWidget* parent)
|
||||
: QMainWindow(parent)
|
||||
, ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
setupWidgets();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void MainWindow::closeEvent(QCloseEvent* event)
|
||||
{
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
void MainWindow::setupWidgets()
|
||||
{
|
||||
mTable = new RemoteTable(this);
|
||||
ui->tabWidget->addTab(mTable, "Remote Table");
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#include "RemoteTable.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui { class MainWindow; }
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainWindow(QWidget* parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
protected:
|
||||
void closeEvent(QCloseEvent* event) override;
|
||||
|
||||
private:
|
||||
void setupWidgets();
|
||||
|
||||
private:
|
||||
Ui::MainWindow* ui = nullptr;
|
||||
RemoteTable* mTable = nullptr;
|
||||
};
|
||||
#endif // MAINWINDOW_H
|
|
@ -0,0 +1,47 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1280</width>
|
||||
<height>800</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Remote Table</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>-1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>1280</width>
|
||||
<height>22</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menu_File">
|
||||
<property name="title">
|
||||
<string>&File</string>
|
||||
</property>
|
||||
</widget>
|
||||
<addaction name="menu_File"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,197 @@
|
|||
#include "RemoteTable.h"
|
||||
#include "StringUtil.h"
|
||||
#include "Bridge.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QTimer>
|
||||
|
||||
RemoteTable::RemoteTable(QWidget* parent)
|
||||
: AbstractStdTable(parent)
|
||||
{
|
||||
std::map<ColumnIndex, std::pair<int, QString>> columns;
|
||||
columns[ColAddress] = { 50, tr("Address") };
|
||||
columns[ColData] = { 50, tr("Data") };
|
||||
|
||||
int col = 0;
|
||||
for(const auto & itr : columns)
|
||||
{
|
||||
if(itr.first != col)
|
||||
{
|
||||
qDebug() << "Bad column index" << col << "!=" << itr.first;
|
||||
QApplication::exit(1);
|
||||
}
|
||||
addColumnAt(calculateColumnWidth(itr.second.first), itr.second.second, true);
|
||||
col++;
|
||||
}
|
||||
|
||||
setupMenu();
|
||||
|
||||
mRpc.open(QUrl("ws://127.0.0.1:42069"));
|
||||
connect(&mRpc, &JsonRpcClient::connected, this, [this]()
|
||||
{
|
||||
prepareData();
|
||||
});
|
||||
|
||||
// Test
|
||||
setRowCount(0x2000ull);
|
||||
}
|
||||
|
||||
QString RemoteTable::getCellContent(duint row, duint col)
|
||||
{
|
||||
auto relativeRow = row - getTableOffset();
|
||||
auto base = QString("row: %1, col: %2").arg(row, 5).arg(col);
|
||||
if(relativeRow < mRemoteData.size())
|
||||
{
|
||||
auto data = QString::fromStdString(mRemoteData[relativeRow][col]);
|
||||
return base + " " + data;
|
||||
}
|
||||
else
|
||||
{
|
||||
return "(FETCHING DATA...)";
|
||||
return QString();
|
||||
return base + " (FETCHING DATA...)";
|
||||
}
|
||||
}
|
||||
|
||||
bool RemoteTable::isValidIndex(duint row, duint col)
|
||||
{
|
||||
if(row >= getRowCount())
|
||||
return false;
|
||||
|
||||
return col >= ColAddress && col <= ColData;
|
||||
}
|
||||
|
||||
void RemoteTable::sortRows(duint column, bool ascending)
|
||||
{
|
||||
}
|
||||
|
||||
duint RemoteTable::sliderMovedHook(QScrollBar::SliderAction action, duint value, dsint delta)
|
||||
{
|
||||
auto actionName = [action]()
|
||||
{
|
||||
switch(action)
|
||||
{
|
||||
case QScrollBar::SliderNoAction:
|
||||
return "SliderNoAction";
|
||||
case QScrollBar::SliderSingleStepAdd:
|
||||
return "SliderSingleStepAdd";
|
||||
case QScrollBar::SliderSingleStepSub:
|
||||
return "SliderSingleStepSub";
|
||||
case QScrollBar::SliderPageStepAdd:
|
||||
return "SliderPageStepAdd";
|
||||
case QScrollBar::SliderPageStepSub:
|
||||
return "SliderPageStepSub";
|
||||
case QScrollBar::SliderToMinimum:
|
||||
return "SliderToMinimum";
|
||||
case QScrollBar::SliderToMaximum:
|
||||
return "SliderToMaximum";
|
||||
case QScrollBar::SliderMove:
|
||||
return "SliderMove";
|
||||
default:
|
||||
return "<unknown>";
|
||||
}
|
||||
}();
|
||||
//qDebug() << "sliderMovedHook" << actionName << "value" << value << "delta" << delta;
|
||||
return AbstractStdTable::sliderMovedHook(action, value, delta);
|
||||
}
|
||||
|
||||
void RemoteTable::prepareData()
|
||||
{
|
||||
AbstractStdTable::prepareData();
|
||||
|
||||
if(!mRpc.isConnected())
|
||||
{
|
||||
qDebug() << "socket not ready bro";
|
||||
return;
|
||||
}
|
||||
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - mLastPrepare).count();
|
||||
mLastPrepare = now;
|
||||
|
||||
auto linesToPrint = getNbrOfLineToPrint();
|
||||
auto offset = getTableOffset();
|
||||
|
||||
//qDebug() << "offset" << offset << "lines" << linesToPrint << "last" << offset + linesToPrint - 1 << "elapsed" << elapsedMs;
|
||||
|
||||
#if 0
|
||||
const uint32_t totalRefreshMs = 300;
|
||||
const uint32_t scrollDebounceMs = 300;
|
||||
|
||||
if(elapsedMs >= totalRefreshMs)
|
||||
{
|
||||
qDebug() << "100% send request";
|
||||
}
|
||||
else if(elapsedMs < scrollDebounceMs)
|
||||
{
|
||||
qDebug() << "scroll debounce";
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "unclear request";
|
||||
}
|
||||
#endif
|
||||
|
||||
//mRemoteData.clear();
|
||||
//qDebug() << "prepareData";
|
||||
|
||||
// TODO: do some cooldown and don't enqueue unnecessary requests
|
||||
// TODO: use the average/median/last latency of the connection as a debouncing timer
|
||||
// TODO: use some basic prediction heuristics (scroll direction etc) to anticipate the scroll
|
||||
// TODO: measure the ping
|
||||
|
||||
TableRequest r;
|
||||
r.offset = offset;
|
||||
r.lines = linesToPrint;
|
||||
r.scroll = 0; // TODO
|
||||
|
||||
if(!mCurrentSent)
|
||||
{
|
||||
if(mNextRequired) __debugbreak();
|
||||
mCurrentSent = true;
|
||||
|
||||
qDebug() << "send rpc request";
|
||||
mCurrentRequest = r;
|
||||
mRpc.call<TableResponse>(r, [this](TableResponse response) { handleTableResponse(response); });
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "add rpc to backlog";
|
||||
mNextRequest = r;
|
||||
mNextRequired = true;
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteTable::handleTableResponse(const TableResponse & response)
|
||||
{
|
||||
if(mNextRequired)
|
||||
{
|
||||
mNextRequired = false;
|
||||
mCurrentRequest = mNextRequest;
|
||||
if(!mCurrentSent) __debugbreak();
|
||||
|
||||
qDebug() << "send rpc request (backlog)";
|
||||
|
||||
mRpc.call<TableResponse>(mCurrentRequest, [this](TableResponse response) { handleTableResponse(response); });
|
||||
}
|
||||
else
|
||||
{
|
||||
mCurrentSent = false;
|
||||
qDebug() << "final response";
|
||||
}
|
||||
|
||||
mRemoteData = std::move(response.rows);
|
||||
updateViewport();
|
||||
}
|
||||
|
||||
void RemoteTable::setupMenu()
|
||||
{
|
||||
addMenuAction(TableAction(TR("Goto line"), "G"), [this]()
|
||||
{
|
||||
qDebug() << "scroll select";
|
||||
auto ok = scrollSelect(5000);
|
||||
if(!ok)
|
||||
qDebug() << "failz";
|
||||
reloadData();
|
||||
});
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
#pragma once
|
||||
|
||||
#include <BasicView/AbstractStdTable.h>
|
||||
#include "MagicMenu.h"
|
||||
#include "JsonRpcClient.h"
|
||||
#include "TableRpcData.h"
|
||||
|
||||
#include <QWebSocket>
|
||||
|
||||
class RemoteTable : public AbstractStdTable, public MagicMenu<RemoteTable>
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit RemoteTable(QWidget* parent = nullptr);
|
||||
|
||||
protected:
|
||||
QString getCellContent(duint row, duint col) override;
|
||||
bool isValidIndex(duint row, duint col) override;
|
||||
void sortRows(duint column, bool ascending) override;
|
||||
duint sliderMovedHook(QScrollBar::SliderAction action, duint value, dsint delta) override;
|
||||
void prepareData() override;
|
||||
|
||||
private:
|
||||
enum ColumnIndex
|
||||
{
|
||||
ColAddress,
|
||||
ColData,
|
||||
};
|
||||
|
||||
std::vector<std::vector<std::string>> mRemoteData;
|
||||
std::chrono::time_point<std::chrono::system_clock> mLastPrepare;
|
||||
|
||||
QWebSocket mSocket;
|
||||
JsonRpcClient mRpc;
|
||||
|
||||
TableRequest mCurrentRequest;
|
||||
bool mCurrentSent = false;
|
||||
|
||||
TableRequest mNextRequest;
|
||||
bool mNextRequired = false;
|
||||
|
||||
void handleTableResponse(const TableResponse & response);
|
||||
void setupMenu();
|
||||
void setupConnection();
|
||||
};
|
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "Types.h"
|
||||
#include "json.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
struct TableRequest
|
||||
{
|
||||
static constexpr const char* method = "table";
|
||||
|
||||
duint offset = 0;
|
||||
duint lines = 0;
|
||||
dsint scroll = 0;
|
||||
};
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(TableRequest, offset, lines, scroll);
|
||||
|
||||
struct TableResponse
|
||||
{
|
||||
static constexpr const char* method = "table";
|
||||
|
||||
std::vector<std::vector<std::string>> rows;
|
||||
};
|
||||
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE(TableResponse, rows);
|
||||
|
||||
|
||||
//QString jsonRpcRequest(const QString& method, )
|
|
@ -0,0 +1,106 @@
|
|||
#include "TableServer.h"
|
||||
#include "TableRpcData.h"
|
||||
|
||||
#include <QWebSocketServer>
|
||||
#include <QWebSocket>
|
||||
#include <QDebug>
|
||||
#include <QThread>
|
||||
#include <QApplication>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
TableServer::TableServer(QObject* parent)
|
||||
: QObject(parent)
|
||||
, mServer(new QWebSocketServer("TableServer", QWebSocketServer::NonSecureMode))
|
||||
{
|
||||
if(mServer->listen(QHostAddress::LocalHost, 42069))
|
||||
{
|
||||
qDebug() << "[server] Listening on ws://127.0.0.1:42069";
|
||||
connect(mServer, &QWebSocketServer::newConnection, this, [this]()
|
||||
{
|
||||
auto socket = mServer->nextPendingConnection();
|
||||
connect(socket, &QWebSocket::textMessageReceived, this, [this](QString message)
|
||||
{
|
||||
//qDebug() << "[server] textMessageReceived:" << message;
|
||||
|
||||
auto client = qobject_cast<QWebSocket*>(sender());
|
||||
|
||||
try
|
||||
{
|
||||
auto request = nlohmann::json::parse(message.toStdString());
|
||||
auto magic = request["jsonrpc"].get<std::string>();
|
||||
if(magic != "2.0")
|
||||
{
|
||||
qDebug() << "[server] Invalid magic:" << magic;
|
||||
return;
|
||||
}
|
||||
auto method = request["method"].get<std::string>();
|
||||
auto id = request["id"].get<uint64_t>();
|
||||
auto params = request["params"];
|
||||
nlohmann::json response;
|
||||
response["jsonrpc"] = "2.0";
|
||||
response["id"] = id;
|
||||
nlohmann::json & result = response["result"];
|
||||
if(method == "table")
|
||||
{
|
||||
TableRequest request;
|
||||
nlohmann::from_json(params, request);
|
||||
|
||||
TableResponse response{};
|
||||
|
||||
if(!table(request, response))
|
||||
{
|
||||
// TODO: write error response
|
||||
qDebug() << "[server] bad fail";
|
||||
}
|
||||
|
||||
nlohmann::to_json(result, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "[server] unknown method:" << method.c_str();
|
||||
return;
|
||||
}
|
||||
|
||||
client->sendTextMessage(QString::fromStdString(response.dump()));
|
||||
}
|
||||
catch(std::exception & x)
|
||||
{
|
||||
qDebug() << "[server] JSON error:" << x.what();
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
mClients << socket;
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
qDebug() << "[server] Error listening";
|
||||
}
|
||||
}
|
||||
|
||||
bool TableServer::table(const TableRequest & request, TableResponse & response)
|
||||
{
|
||||
response.rows.resize(request.lines);
|
||||
for(uint64_t line = 0; line < request.lines; line++)
|
||||
{
|
||||
auto & row = response.rows[line];
|
||||
row.resize(2);
|
||||
row[0] = "address: " + std::to_string(line + request.offset);
|
||||
row[1] = "data: " + std::to_string(line + request.offset);
|
||||
}
|
||||
|
||||
// Sleep without hanging event loop
|
||||
auto start = std::chrono::system_clock::now();
|
||||
while(true)
|
||||
{
|
||||
auto now = std::chrono::system_clock::now();
|
||||
auto elapsedMs = std::chrono::duration_cast<std::chrono::milliseconds>(now - start).count();
|
||||
if(elapsedMs >= 500)
|
||||
break;
|
||||
QApplication::processEvents();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include "TableRpcData.h"
|
||||
|
||||
QT_FORWARD_DECLARE_CLASS(QWebSocketServer)
|
||||
QT_FORWARD_DECLARE_CLASS(QWebSocket)
|
||||
|
||||
class TableServer : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TableServer(QObject* parent = nullptr);
|
||||
|
||||
private:
|
||||
bool table(const TableRequest & request, TableResponse & response);
|
||||
|
||||
private:
|
||||
QWebSocketServer* mServer = nullptr;
|
||||
QList<QWebSocket*> mClients;
|
||||
};
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,20 @@
|
|||
#include <QApplication>
|
||||
#include <QThread>
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "Configuration.h"
|
||||
#include "TableServer.h"
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(5, 12, 0)
|
||||
#error Your Qt version is likely too old, upgrade to 5.12 or higher
|
||||
#endif // QT_VERSION
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
Configuration config;
|
||||
TableServer server;
|
||||
MainWindow w;
|
||||
w.show();
|
||||
return a.exec();
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
# This file is automatically generated from cmake.toml - DO NOT EDIT
|
||||
# See https://github.com/build-cpp/cmkr for more information
|
||||
|
||||
# Create a configure-time dependency on cmake.toml to improve IDE support
|
||||
if(CMKR_ROOT_PROJECT)
|
||||
configure_file(cmake.toml cmake.toml COPYONLY)
|
||||
endif()
|
||||
|
||||
# Target: cpp-httplib
|
||||
add_library(cpp-httplib INTERFACE)
|
||||
|
||||
target_include_directories(cpp-httplib INTERFACE
|
||||
cpp-httplib
|
||||
)
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
[target.cpp-httplib]
|
||||
type = "interface"
|
||||
include-directories = ["cpp-httplib"]
|
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
#include "AbstractStdTable.h"
|
||||
#include "Bridge.h"
|
||||
#include "RichTextPainter.h"
|
||||
#include <Utils/RichTextPainter.h>
|
||||
|
||||
AbstractStdTable::AbstractStdTable(QWidget* parent) : AbstractTableView(parent)
|
||||
{
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
#include "AbstractTableView.h"
|
||||
#include <QStyleOptionButton>
|
||||
#include "Configuration.h"
|
||||
#include "ColumnReorderDialog.h"
|
||||
#include "CachedFontMetrics.h"
|
||||
#include <Gui/ColumnReorderDialog.h>
|
||||
#include <Utils/CachedFontMetrics.h>
|
||||
#include "Bridge.h"
|
||||
#include "MethodInvoker.h"
|
||||
#include <Utils/MethodInvoker.h>
|
||||
|
||||
AbstractTableScrollBar::AbstractTableScrollBar(QScrollBar* scrollbar)
|
||||
{
|
||||
|
|
|
@ -9,9 +9,9 @@
|
|||
#include <QMenu>
|
||||
#include "StringUtil.h"
|
||||
#include "Configuration.h"
|
||||
#include "MenuBuilder.h"
|
||||
#include <Utils/MenuBuilder.h>
|
||||
#include "MiscUtil.h"
|
||||
#include "ActionHelpers.h"
|
||||
#include <Utils/ActionHelpers.h>
|
||||
|
||||
class CachedFontMetrics;
|
||||
class ColumnReorderDialog;
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#include "Disassembly.h"
|
||||
#include "Configuration.h"
|
||||
#include "CodeFolding.h"
|
||||
#include "EncodeMap.h"
|
||||
#include <Utils/CodeFolding.h>
|
||||
#include <Utils/EncodeMap.h>
|
||||
#include "Bridge.h"
|
||||
#include "CachedFontMetrics.h"
|
||||
#include "QZydis.h"
|
||||
#include "MemoryPage.h"
|
||||
#include "DisassemblyPopup.h"
|
||||
#include <Utils/CachedFontMetrics.h>
|
||||
#include <Disassembler/QZydis.h>
|
||||
#include <Memory/MemoryPage.h>
|
||||
#include <Gui/DisassemblyPopup.h>
|
||||
|
||||
Disassembly::Disassembly(Architecture* architecture, bool isMain, QWidget* parent)
|
||||
: AbstractTableView(parent),
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractTableView.h"
|
||||
#include "QZydis.h"
|
||||
#include <Disassembler/QZydis.h>
|
||||
#include <QTextLayout>
|
||||
#include "Architecture.h"
|
||||
#include <Disassembler/Architecture.h>
|
||||
|
||||
class CodeFoldingHelper;
|
||||
class MemoryPage;
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include "AbstractTableView.h"
|
||||
#include "RichTextPainter.h"
|
||||
#include "MemoryPage.h"
|
||||
#include "VaHistory.h"
|
||||
#include <Utils/RichTextPainter.h>
|
||||
#include <Memory/MemoryPage.h>
|
||||
#include <Utils/VaHistory.h>
|
||||
#include <Disassembler/Architecture.h>
|
||||
|
||||
class HexDump : public AbstractTableView
|
||||
{
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "QZydis.h"
|
||||
#include "StringUtil.h"
|
||||
#include "EncodeMap.h"
|
||||
#include "CodeFolding.h"
|
||||
#include "Bridge.h"
|
||||
#include <Utils/EncodeMap.h>
|
||||
#include <Utils/CodeFolding.h>
|
||||
#include <Bridge.h>
|
||||
|
||||
#ifndef _countof
|
||||
#define _countof(array) (sizeof(array) / sizeof(array[0]))
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#include "ZydisTokenizer.h"
|
||||
#include "Configuration.h"
|
||||
#include "StringUtil.h"
|
||||
#include "CachedFontMetrics.h"
|
||||
#include "Bridge.h"
|
||||
#include <Utils/CachedFontMetrics.h>
|
||||
#include <Bridge.h>
|
||||
|
||||
ZydisTokenizer::ZydisTokenizer(int maxModuleLength, Architecture* architecture)
|
||||
: mMaxModuleLength(maxModuleLength),
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <zydis_wrapper.h>
|
||||
#include "RichTextPainter.h"
|
||||
#include "Configuration.h"
|
||||
#include <Utils/RichTextPainter.h>
|
||||
#include <Configuration.h>
|
||||
#include <map>
|
||||
#include <QHash>
|
||||
#include <QtCore>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "BrowseDialog.h"
|
||||
#include "ui_BrowseDialog.h"
|
||||
#include "MiscUtil.h"
|
||||
#include <QDirModel>
|
||||
#include <QFileSystemModel>
|
||||
#include <QCompleter>
|
||||
#include <QFileDialog>
|
||||
#include <Configuration.h>
|
||||
|
@ -26,7 +26,7 @@ BrowseDialog::BrowseDialog(QWidget* parent, const QString & title, const QString
|
|||
ui->lineEdit->setSelection(lastSlashIdx + 1, periodIdx - lastSlashIdx - 1);
|
||||
}
|
||||
QCompleter* completer = new QCompleter(ui->lineEdit);
|
||||
completer->setModel(new QDirModel(completer));
|
||||
completer->setModel(new QFileSystemModel(completer));
|
||||
ui->lineEdit->setCompleter(completer);
|
||||
Config()->loadWindowGeometry(this);
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "ColumnReorderDialog.h"
|
||||
#include "ui_ColumnReorderDialog.h"
|
||||
#include "AbstractTableView.h"
|
||||
#include <BasicView/AbstractTableView.h>
|
||||
#include <QMessageBox>
|
||||
|
||||
ColumnReorderDialog::ColumnReorderDialog(AbstractTableView* parent) :
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
#include "DisassemblyPopup.h"
|
||||
#include "CachedFontMetrics.h"
|
||||
#include "Configuration.h"
|
||||
#include "StringUtil.h"
|
||||
#include "MiscUtil.h"
|
||||
#include <Utils/CachedFontMetrics.h>
|
||||
#include <Configuration.h>
|
||||
#include <StringUtil.h>
|
||||
#include <MiscUtil.h>
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionFrame>
|
||||
#include "Bridge.h"
|
||||
#include <Bridge.h>
|
||||
|
||||
DisassemblyPopup::DisassemblyPopup(AbstractTableView* parent, Architecture* architecture) :
|
||||
QFrame(parent, Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus),
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <QFrame>
|
||||
#include "Imports.h"
|
||||
#include "QZydis.h"
|
||||
#include "AbstractTableView.h"
|
||||
#include "StdSearchListView.h"
|
||||
#include <Imports.h>
|
||||
#include <Disassembler/QZydis.h>
|
||||
#include <BasicView/AbstractTableView.h>
|
||||
|
||||
class CachedFontMetrics;
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "MemoryPage.h"
|
||||
#include <Bridge.h>
|
||||
|
||||
MemoryPage::MemoryPage(duint parBase, duint parSize, QObject* parent) : QObject(parent), mBase(0), mSize(0)
|
||||
{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
#include "Imports.h"
|
||||
#include <Imports.h>
|
||||
|
||||
class MemoryPage : public QObject
|
||||
{
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include <QAction>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
#include "Configuration.h"
|
||||
#include <Configuration.h>
|
||||
|
||||
using SlotFunc = std::function<void()>;
|
||||
using MakeMenuFunc1 = std::function<QMenu*(const QString &)>;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "BackgroundFlickerThread.h"
|
||||
#include "Configuration.h"
|
||||
#include <Configuration.h>
|
||||
#include <Windows.h>
|
||||
|
||||
BackgroundFlickerThread::BackgroundFlickerThread(QWidget* widget, QColor & background, QObject* parent) : QThread(parent), background(background)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "Imports.h"
|
||||
#include <Imports.h>
|
||||
#include <map>
|
||||
|
||||
class CodeFoldingHelper
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#include "Configuration.h"
|
||||
#include <Configuration.h>
|
||||
#include <QApplication>
|
||||
#include <QFontInfo>
|
||||
#include <QMessageBox>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "EncodeMap.h"
|
||||
#include "Bridge.h"
|
||||
|
||||
EncodeMap::EncodeMap(QObject* parent)
|
||||
: QObject(parent),
|
||||
|
@ -23,7 +24,7 @@ void EncodeMap::setMemoryRegion(duint addr)
|
|||
|
||||
if(mBuffer)
|
||||
DbgReleaseEncodeTypeBuffer(mBuffer);
|
||||
mBuffer = (byte*)DbgGetEncodeTypeBuffer(addr, &mBufferSize);
|
||||
mBuffer = (uint8_t*)DbgGetEncodeTypeBuffer(addr, &mBufferSize);
|
||||
}
|
||||
|
||||
void EncodeMap::setDataType(duint va, ENCODETYPE type)
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include <QObject>
|
||||
#include "Imports.h"
|
||||
#include <Imports.h>
|
||||
|
||||
class EncodeMap : public QObject
|
||||
{
|
||||
|
@ -81,6 +83,6 @@ public:
|
|||
protected:
|
||||
duint mBase;
|
||||
duint mSize;
|
||||
byte* mBuffer;
|
||||
uint8_t* mBuffer;
|
||||
duint mBufferSize;
|
||||
};
|
||||
|
|
|
@ -74,7 +74,7 @@ bool MenuBuilder::build(QMenu* menu) const
|
|||
if(_callback && !_callback(menu))
|
||||
return false;
|
||||
QMenu* submenu;
|
||||
if(id != 0)
|
||||
if(!id.isEmpty())
|
||||
submenu = new QMenu(tr("More commands"), menu);
|
||||
else
|
||||
submenu = nullptr;
|
||||
|
@ -82,7 +82,7 @@ bool MenuBuilder::build(QMenu* menu) const
|
|||
{
|
||||
const Container & container = _containers.at(i);
|
||||
QMenu* _menu;
|
||||
if(id != 0 && container.type != Container::Separator && Config()->getBool("Gui", QString("Menu%1Hidden%2").arg(id).arg(i)))
|
||||
if(!id.isEmpty() && container.type != Container::Separator && Config()->getBool("Gui", QString("Menu%1Hidden%2").arg(id).arg(i)))
|
||||
_menu = submenu;
|
||||
else
|
||||
_menu = menu;
|
||||
|
@ -104,7 +104,7 @@ bool MenuBuilder::build(QMenu* menu) const
|
|||
break;
|
||||
}
|
||||
}
|
||||
if(id != 0 && !submenu->actions().isEmpty())
|
||||
if(!id.isEmpty() && !submenu->actions().isEmpty())
|
||||
{
|
||||
menu->addSeparator();
|
||||
menu->addMenu(submenu);
|
||||
|
|
|
@ -13,7 +13,7 @@ class MenuBuilder : public QObject
|
|||
public:
|
||||
typedef std::function<bool(QMenu*)> BuildCallback;
|
||||
|
||||
inline MenuBuilder(QObject* parent, BuildCallback callback = nullptr)
|
||||
explicit MenuBuilder(QObject* parent, BuildCallback callback = nullptr)
|
||||
: QObject(parent),
|
||||
_callback(callback)
|
||||
{
|
||||
|
@ -21,24 +21,24 @@ public:
|
|||
|
||||
void loadFromConfig();
|
||||
|
||||
inline void addSeparator()
|
||||
void addSeparator()
|
||||
{
|
||||
_containers.push_back(Container());
|
||||
}
|
||||
|
||||
inline QAction* addAction(QAction* action)
|
||||
QAction* addAction(QAction* action)
|
||||
{
|
||||
_containers.push_back(Container(action));
|
||||
return action;
|
||||
}
|
||||
|
||||
inline QAction* addAction(QAction* action, BuildCallback callback)
|
||||
QAction* addAction(QAction* action, BuildCallback callback)
|
||||
{
|
||||
addBuilder(new MenuBuilder(action->parent(), callback))->addAction(action);
|
||||
return action;
|
||||
}
|
||||
|
||||
inline QMenu* addMenu(QMenu* menu)
|
||||
QMenu* addMenu(QMenu* menu)
|
||||
{
|
||||
_containers.push_back(Container(menu));
|
||||
return menu;
|
||||
|
@ -48,7 +48,7 @@ public:
|
|||
|
||||
QMenu* addMenu(QMenu* submenu, MenuBuilder* builder);
|
||||
|
||||
inline MenuBuilder* addBuilder(MenuBuilder* builder)
|
||||
MenuBuilder* addBuilder(MenuBuilder* builder)
|
||||
{
|
||||
_containers.push_back(Container(builder));
|
||||
return builder;
|
||||
|
@ -63,7 +63,7 @@ public:
|
|||
|
||||
bool build(QMenu* menu) const;
|
||||
|
||||
inline bool empty() const
|
||||
bool empty() const
|
||||
{
|
||||
return _containers.empty();
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
#include "StringUtil.h"
|
||||
#include "MiscUtil.h"
|
||||
#include "ldconvert.h"
|
||||
#include "Configuration.h"
|
||||
#include <Configuration.h>
|
||||
|
||||
QString ToLongDoubleString(const void* buffer)
|
||||
{
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "SymbolAutoCompleteModel.h"
|
||||
#include "MiscUtil.h"
|
||||
#include "Configuration.h"
|
||||
#include <Configuration.h>
|
||||
|
||||
SymbolAutoCompleteModel::SymbolAutoCompleteModel(std::function<QString()> getTextProc, QObject* parent)
|
||||
: QAbstractItemModel(parent),
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
set(zydis_wrapper_SOURCES
|
||||
Zydis/Zydis.c
|
||||
Zydis/Zydis.h
|
||||
zydis_wrapper.cpp
|
||||
zydis_wrapper.h
|
||||
)
|
||||
|
||||
add_library(zydis_wrapper STATIC)
|
||||
|
||||
target_sources(zydis_wrapper PRIVATE ${zydis_wrapper_SOURCES})
|
||||
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${zydis_wrapper_SOURCES})
|
||||
|
||||
target_compile_definitions(zydis_wrapper PUBLIC
|
||||
ZYCORE_STATIC_BUILD
|
||||
ZYDIS_STATIC_BUILD
|
||||
)
|
||||
|
||||
target_compile_features(zydis_wrapper PUBLIC
|
||||
cxx_std_11
|
||||
)
|
||||
|
||||
target_include_directories(zydis_wrapper PUBLIC
|
||||
.
|
||||
)
|
||||
|
||||
target_include_directories(zydis_wrapper PRIVATE
|
||||
Zydis
|
||||
)
|
||||
|
Loading…
Reference in New Issue