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 "AbstractStdTable.h"
|
||||||
#include "Bridge.h"
|
#include "Bridge.h"
|
||||||
#include "RichTextPainter.h"
|
#include <Utils/RichTextPainter.h>
|
||||||
|
|
||||||
AbstractStdTable::AbstractStdTable(QWidget* parent) : AbstractTableView(parent)
|
AbstractStdTable::AbstractStdTable(QWidget* parent) : AbstractTableView(parent)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#include "AbstractTableView.h"
|
#include "AbstractTableView.h"
|
||||||
#include <QStyleOptionButton>
|
#include <QStyleOptionButton>
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
#include "ColumnReorderDialog.h"
|
#include <Gui/ColumnReorderDialog.h>
|
||||||
#include "CachedFontMetrics.h"
|
#include <Utils/CachedFontMetrics.h>
|
||||||
#include "Bridge.h"
|
#include "Bridge.h"
|
||||||
#include "MethodInvoker.h"
|
#include <Utils/MethodInvoker.h>
|
||||||
|
|
||||||
AbstractTableScrollBar::AbstractTableScrollBar(QScrollBar* scrollbar)
|
AbstractTableScrollBar::AbstractTableScrollBar(QScrollBar* scrollbar)
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,9 +9,9 @@
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
#include "MenuBuilder.h"
|
#include <Utils/MenuBuilder.h>
|
||||||
#include "MiscUtil.h"
|
#include "MiscUtil.h"
|
||||||
#include "ActionHelpers.h"
|
#include <Utils/ActionHelpers.h>
|
||||||
|
|
||||||
class CachedFontMetrics;
|
class CachedFontMetrics;
|
||||||
class ColumnReorderDialog;
|
class ColumnReorderDialog;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
#include "Disassembly.h"
|
#include "Disassembly.h"
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
#include "CodeFolding.h"
|
#include <Utils/CodeFolding.h>
|
||||||
#include "EncodeMap.h"
|
#include <Utils/EncodeMap.h>
|
||||||
#include "Bridge.h"
|
#include "Bridge.h"
|
||||||
#include "CachedFontMetrics.h"
|
#include <Utils/CachedFontMetrics.h>
|
||||||
#include "QZydis.h"
|
#include <Disassembler/QZydis.h>
|
||||||
#include "MemoryPage.h"
|
#include <Memory/MemoryPage.h>
|
||||||
#include "DisassemblyPopup.h"
|
#include <Gui/DisassemblyPopup.h>
|
||||||
|
|
||||||
Disassembly::Disassembly(Architecture* architecture, bool isMain, QWidget* parent)
|
Disassembly::Disassembly(Architecture* architecture, bool isMain, QWidget* parent)
|
||||||
: AbstractTableView(parent),
|
: AbstractTableView(parent),
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "AbstractTableView.h"
|
#include "AbstractTableView.h"
|
||||||
#include "QZydis.h"
|
#include <Disassembler/QZydis.h>
|
||||||
#include <QTextLayout>
|
#include <QTextLayout>
|
||||||
#include "Architecture.h"
|
#include <Disassembler/Architecture.h>
|
||||||
|
|
||||||
class CodeFoldingHelper;
|
class CodeFoldingHelper;
|
||||||
class MemoryPage;
|
class MemoryPage;
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "AbstractTableView.h"
|
#include "AbstractTableView.h"
|
||||||
#include "RichTextPainter.h"
|
#include <Utils/RichTextPainter.h>
|
||||||
#include "MemoryPage.h"
|
#include <Memory/MemoryPage.h>
|
||||||
#include "VaHistory.h"
|
#include <Utils/VaHistory.h>
|
||||||
|
#include <Disassembler/Architecture.h>
|
||||||
|
|
||||||
class HexDump : public AbstractTableView
|
class HexDump : public AbstractTableView
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#include "QZydis.h"
|
#include "QZydis.h"
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "EncodeMap.h"
|
#include <Utils/EncodeMap.h>
|
||||||
#include "CodeFolding.h"
|
#include <Utils/CodeFolding.h>
|
||||||
#include "Bridge.h"
|
#include <Bridge.h>
|
||||||
|
|
||||||
#ifndef _countof
|
#ifndef _countof
|
||||||
#define _countof(array) (sizeof(array) / sizeof(array[0]))
|
#define _countof(array) (sizeof(array) / sizeof(array[0]))
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#include "ZydisTokenizer.h"
|
#include "ZydisTokenizer.h"
|
||||||
#include "Configuration.h"
|
#include "Configuration.h"
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "CachedFontMetrics.h"
|
#include <Utils/CachedFontMetrics.h>
|
||||||
#include "Bridge.h"
|
#include <Bridge.h>
|
||||||
|
|
||||||
ZydisTokenizer::ZydisTokenizer(int maxModuleLength, Architecture* architecture)
|
ZydisTokenizer::ZydisTokenizer(int maxModuleLength, Architecture* architecture)
|
||||||
: mMaxModuleLength(maxModuleLength),
|
: mMaxModuleLength(maxModuleLength),
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <zydis_wrapper.h>
|
#include <zydis_wrapper.h>
|
||||||
#include "RichTextPainter.h"
|
#include <Utils/RichTextPainter.h>
|
||||||
#include "Configuration.h"
|
#include <Configuration.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <QHash>
|
#include <QHash>
|
||||||
#include <QtCore>
|
#include <QtCore>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include "BrowseDialog.h"
|
#include "BrowseDialog.h"
|
||||||
#include "ui_BrowseDialog.h"
|
#include "ui_BrowseDialog.h"
|
||||||
#include "MiscUtil.h"
|
#include "MiscUtil.h"
|
||||||
#include <QDirModel>
|
#include <QFileSystemModel>
|
||||||
#include <QCompleter>
|
#include <QCompleter>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <Configuration.h>
|
#include <Configuration.h>
|
||||||
|
@ -26,7 +26,7 @@ BrowseDialog::BrowseDialog(QWidget* parent, const QString & title, const QString
|
||||||
ui->lineEdit->setSelection(lastSlashIdx + 1, periodIdx - lastSlashIdx - 1);
|
ui->lineEdit->setSelection(lastSlashIdx + 1, periodIdx - lastSlashIdx - 1);
|
||||||
}
|
}
|
||||||
QCompleter* completer = new QCompleter(ui->lineEdit);
|
QCompleter* completer = new QCompleter(ui->lineEdit);
|
||||||
completer->setModel(new QDirModel(completer));
|
completer->setModel(new QFileSystemModel(completer));
|
||||||
ui->lineEdit->setCompleter(completer);
|
ui->lineEdit->setCompleter(completer);
|
||||||
Config()->loadWindowGeometry(this);
|
Config()->loadWindowGeometry(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "ColumnReorderDialog.h"
|
#include "ColumnReorderDialog.h"
|
||||||
#include "ui_ColumnReorderDialog.h"
|
#include "ui_ColumnReorderDialog.h"
|
||||||
#include "AbstractTableView.h"
|
#include <BasicView/AbstractTableView.h>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
||||||
ColumnReorderDialog::ColumnReorderDialog(AbstractTableView* parent) :
|
ColumnReorderDialog::ColumnReorderDialog(AbstractTableView* parent) :
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
#include "DisassemblyPopup.h"
|
#include "DisassemblyPopup.h"
|
||||||
#include "CachedFontMetrics.h"
|
#include <Utils/CachedFontMetrics.h>
|
||||||
#include "Configuration.h"
|
#include <Configuration.h>
|
||||||
#include "StringUtil.h"
|
#include <StringUtil.h>
|
||||||
#include "MiscUtil.h"
|
#include <MiscUtil.h>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QStyleOptionFrame>
|
#include <QStyleOptionFrame>
|
||||||
#include "Bridge.h"
|
#include <Bridge.h>
|
||||||
|
|
||||||
DisassemblyPopup::DisassemblyPopup(AbstractTableView* parent, Architecture* architecture) :
|
DisassemblyPopup::DisassemblyPopup(AbstractTableView* parent, Architecture* architecture) :
|
||||||
QFrame(parent, Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus),
|
QFrame(parent, Qt::Tool | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint | Qt::WindowDoesNotAcceptFocus),
|
||||||
|
|
|
@ -1,10 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QFrame>
|
#include <QFrame>
|
||||||
#include "Imports.h"
|
#include <Imports.h>
|
||||||
#include "QZydis.h"
|
#include <Disassembler/QZydis.h>
|
||||||
#include "AbstractTableView.h"
|
#include <BasicView/AbstractTableView.h>
|
||||||
#include "StdSearchListView.h"
|
|
||||||
|
|
||||||
class CachedFontMetrics;
|
class CachedFontMetrics;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "MemoryPage.h"
|
#include "MemoryPage.h"
|
||||||
|
#include <Bridge.h>
|
||||||
|
|
||||||
MemoryPage::MemoryPage(duint parBase, duint parSize, QObject* parent) : QObject(parent), mBase(0), mSize(0)
|
MemoryPage::MemoryPage(duint parBase, duint parSize, QObject* parent) : QObject(parent), mBase(0), mSize(0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include "Imports.h"
|
#include <Imports.h>
|
||||||
|
|
||||||
class MemoryPage : public QObject
|
class MemoryPage : public QObject
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include <QAction>
|
#include <QAction>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "Configuration.h"
|
#include <Configuration.h>
|
||||||
|
|
||||||
using SlotFunc = std::function<void()>;
|
using SlotFunc = std::function<void()>;
|
||||||
using MakeMenuFunc1 = std::function<QMenu*(const QString &)>;
|
using MakeMenuFunc1 = std::function<QMenu*(const QString &)>;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
#include "BackgroundFlickerThread.h"
|
#include "BackgroundFlickerThread.h"
|
||||||
#include "Configuration.h"
|
#include <Configuration.h>
|
||||||
#include <Windows.h>
|
#include <Windows.h>
|
||||||
|
|
||||||
BackgroundFlickerThread::BackgroundFlickerThread(QWidget* widget, QColor & background, QObject* parent) : QThread(parent), background(background)
|
BackgroundFlickerThread::BackgroundFlickerThread(QWidget* widget, QColor & background, QObject* parent) : QThread(parent), background(background)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Imports.h"
|
#include <Imports.h>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
class CodeFoldingHelper
|
class CodeFoldingHelper
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "Configuration.h"
|
#include <Configuration.h>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QFontInfo>
|
#include <QFontInfo>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include "EncodeMap.h"
|
#include "EncodeMap.h"
|
||||||
|
#include "Bridge.h"
|
||||||
|
|
||||||
EncodeMap::EncodeMap(QObject* parent)
|
EncodeMap::EncodeMap(QObject* parent)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
|
@ -23,7 +24,7 @@ void EncodeMap::setMemoryRegion(duint addr)
|
||||||
|
|
||||||
if(mBuffer)
|
if(mBuffer)
|
||||||
DbgReleaseEncodeTypeBuffer(mBuffer);
|
DbgReleaseEncodeTypeBuffer(mBuffer);
|
||||||
mBuffer = (byte*)DbgGetEncodeTypeBuffer(addr, &mBufferSize);
|
mBuffer = (uint8_t*)DbgGetEncodeTypeBuffer(addr, &mBufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EncodeMap::setDataType(duint va, ENCODETYPE type)
|
void EncodeMap::setDataType(duint va, ENCODETYPE type)
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include "Imports.h"
|
#include <Imports.h>
|
||||||
|
|
||||||
class EncodeMap : public QObject
|
class EncodeMap : public QObject
|
||||||
{
|
{
|
||||||
|
@ -81,6 +83,6 @@ public:
|
||||||
protected:
|
protected:
|
||||||
duint mBase;
|
duint mBase;
|
||||||
duint mSize;
|
duint mSize;
|
||||||
byte* mBuffer;
|
uint8_t* mBuffer;
|
||||||
duint mBufferSize;
|
duint mBufferSize;
|
||||||
};
|
};
|
||||||
|
|
|
@ -74,7 +74,7 @@ bool MenuBuilder::build(QMenu* menu) const
|
||||||
if(_callback && !_callback(menu))
|
if(_callback && !_callback(menu))
|
||||||
return false;
|
return false;
|
||||||
QMenu* submenu;
|
QMenu* submenu;
|
||||||
if(id != 0)
|
if(!id.isEmpty())
|
||||||
submenu = new QMenu(tr("More commands"), menu);
|
submenu = new QMenu(tr("More commands"), menu);
|
||||||
else
|
else
|
||||||
submenu = nullptr;
|
submenu = nullptr;
|
||||||
|
@ -82,7 +82,7 @@ bool MenuBuilder::build(QMenu* menu) const
|
||||||
{
|
{
|
||||||
const Container & container = _containers.at(i);
|
const Container & container = _containers.at(i);
|
||||||
QMenu* _menu;
|
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;
|
_menu = submenu;
|
||||||
else
|
else
|
||||||
_menu = menu;
|
_menu = menu;
|
||||||
|
@ -104,7 +104,7 @@ bool MenuBuilder::build(QMenu* menu) const
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(id != 0 && !submenu->actions().isEmpty())
|
if(!id.isEmpty() && !submenu->actions().isEmpty())
|
||||||
{
|
{
|
||||||
menu->addSeparator();
|
menu->addSeparator();
|
||||||
menu->addMenu(submenu);
|
menu->addMenu(submenu);
|
||||||
|
|
|
@ -13,7 +13,7 @@ class MenuBuilder : public QObject
|
||||||
public:
|
public:
|
||||||
typedef std::function<bool(QMenu*)> BuildCallback;
|
typedef std::function<bool(QMenu*)> BuildCallback;
|
||||||
|
|
||||||
inline MenuBuilder(QObject* parent, BuildCallback callback = nullptr)
|
explicit MenuBuilder(QObject* parent, BuildCallback callback = nullptr)
|
||||||
: QObject(parent),
|
: QObject(parent),
|
||||||
_callback(callback)
|
_callback(callback)
|
||||||
{
|
{
|
||||||
|
@ -21,24 +21,24 @@ public:
|
||||||
|
|
||||||
void loadFromConfig();
|
void loadFromConfig();
|
||||||
|
|
||||||
inline void addSeparator()
|
void addSeparator()
|
||||||
{
|
{
|
||||||
_containers.push_back(Container());
|
_containers.push_back(Container());
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QAction* addAction(QAction* action)
|
QAction* addAction(QAction* action)
|
||||||
{
|
{
|
||||||
_containers.push_back(Container(action));
|
_containers.push_back(Container(action));
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QAction* addAction(QAction* action, BuildCallback callback)
|
QAction* addAction(QAction* action, BuildCallback callback)
|
||||||
{
|
{
|
||||||
addBuilder(new MenuBuilder(action->parent(), callback))->addAction(action);
|
addBuilder(new MenuBuilder(action->parent(), callback))->addAction(action);
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline QMenu* addMenu(QMenu* menu)
|
QMenu* addMenu(QMenu* menu)
|
||||||
{
|
{
|
||||||
_containers.push_back(Container(menu));
|
_containers.push_back(Container(menu));
|
||||||
return menu;
|
return menu;
|
||||||
|
@ -48,7 +48,7 @@ public:
|
||||||
|
|
||||||
QMenu* addMenu(QMenu* submenu, MenuBuilder* builder);
|
QMenu* addMenu(QMenu* submenu, MenuBuilder* builder);
|
||||||
|
|
||||||
inline MenuBuilder* addBuilder(MenuBuilder* builder)
|
MenuBuilder* addBuilder(MenuBuilder* builder)
|
||||||
{
|
{
|
||||||
_containers.push_back(Container(builder));
|
_containers.push_back(Container(builder));
|
||||||
return builder;
|
return builder;
|
||||||
|
@ -63,7 +63,7 @@ public:
|
||||||
|
|
||||||
bool build(QMenu* menu) const;
|
bool build(QMenu* menu) const;
|
||||||
|
|
||||||
inline bool empty() const
|
bool empty() const
|
||||||
{
|
{
|
||||||
return _containers.empty();
|
return _containers.empty();
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
#include "StringUtil.h"
|
#include "StringUtil.h"
|
||||||
#include "MiscUtil.h"
|
#include "MiscUtil.h"
|
||||||
#include "ldconvert.h"
|
#include "ldconvert.h"
|
||||||
#include "Configuration.h"
|
#include <Configuration.h>
|
||||||
|
|
||||||
QString ToLongDoubleString(const void* buffer)
|
QString ToLongDoubleString(const void* buffer)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#include "SymbolAutoCompleteModel.h"
|
#include "SymbolAutoCompleteModel.h"
|
||||||
#include "MiscUtil.h"
|
#include "MiscUtil.h"
|
||||||
#include "Configuration.h"
|
#include <Configuration.h>
|
||||||
|
|
||||||
SymbolAutoCompleteModel::SymbolAutoCompleteModel(std::function<QString()> getTextProc, QObject* parent)
|
SymbolAutoCompleteModel::SymbolAutoCompleteModel(std::function<QString()> getTextProc, QObject* parent)
|
||||||
: QAbstractItemModel(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