Merge branch 'main' into usbd-libusb

This commit is contained in:
georgemoralis 2025-03-28 23:01:46 +02:00 committed by GitHub
commit b3feada3a6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
191 changed files with 26531 additions and 5302 deletions

4
.gitmodules vendored
View File

@ -6,10 +6,6 @@
path = externals/cryptopp
url = https://github.com/shadps4-emu/ext-cryptopp.git
shallow = true
[submodule "externals/cryptoppwin"]
path = externals/cryptoppwin
url = https://github.com/shadps4-emu/ext-cryptoppwin.git
shallow = true
[submodule "externals/zlib-ng"]
path = externals/zlib-ng
url = https://github.com/shadps4-emu/ext-zlib-ng.git

View File

@ -37,8 +37,10 @@ option(ENABLE_UPDATER "Enables the options to updater" ON)
# First, determine whether to use CMAKE_OSX_ARCHITECTURES or CMAKE_SYSTEM_PROCESSOR.
if (APPLE AND CMAKE_OSX_ARCHITECTURES)
set(BASE_ARCHITECTURE "${CMAKE_OSX_ARCHITECTURES}")
else()
elseif (CMAKE_SYSTEM_PROCESSOR)
set(BASE_ARCHITECTURE "${CMAKE_SYSTEM_PROCESSOR}")
else()
set(BASE_ARCHITECTURE "${CMAKE_HOST_SYSTEM_PROCESSOR}")
endif()
# Next, match common architecture strings down to a known common value.
@ -50,7 +52,12 @@ else()
message(FATAL_ERROR "Unsupported CPU architecture: ${BASE_ARCHITECTURE}")
endif()
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
if (ARCHITECTURE STREQUAL "x86_64")
# Set x86_64 target level to Sandy Bridge to generally match what is supported for PS4 guest code with CPU patches.
add_compile_options(-march=sandybridge)
endif()
if (APPLE AND ARCHITECTURE STREQUAL "x86_64" AND CMAKE_HOST_SYSTEM_PROCESSOR STREQUAL "arm64")
# Exclude ARM homebrew path to avoid conflicts when cross compiling.
list(APPEND CMAKE_IGNORE_PREFIX_PATH "/opt/homebrew")
@ -106,28 +113,39 @@ git_describe(GIT_DESC --always --long --dirty)
git_branch_name(GIT_BRANCH)
string(TIMESTAMP BUILD_DATE "%Y-%m-%d %H:%M:%S")
message("start git things")
# Try to get the upstream remote and branch
message("check for remote and branch")
execute_process(
COMMAND git rev-parse --abbrev-ref --symbolic-full-name @{u}
OUTPUT_VARIABLE GIT_REMOTE_NAME
RESULT_VARIABLE GIT_BRANCH_RESULT
RESULT_VARIABLE GIT_REMOTE_RESULT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# If there's no upstream set or the command failed, check remote.pushDefault
if (GIT_BRANCH_RESULT OR GIT_REMOTE_NAME STREQUAL "")
if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
message("check default push")
execute_process(
COMMAND git config --get remote.pushDefault
OUTPUT_VARIABLE GIT_REMOTE_NAME
RESULT_VARIABLE GIT_PUSH_DEFAULT_RESULT
RESULT_VARIABLE GIT_REMOTE_RESULT
ERROR_QUIET
OUTPUT_STRIP_TRAILING_WHITESPACE
)
# If remote.pushDefault is not set or fails, default to origin
if (GIT_PUSH_DEFAULT_RESULT OR GIT_REMOTE_NAME STREQUAL "")
set(GIT_REMOTE_NAME "origin")
endif()
# If running in GitHub Actions and the above fails
if (GIT_REMOTE_RESULT OR GIT_REMOTE_NAME STREQUAL "")
message("check github")
set(GIT_REMOTE_NAME "origin")
if (DEFINED ENV{GITHUB_HEAD_REF}) # PR branch name
set(GIT_BRANCH "pr-$ENV{GITHUB_HEAD_REF}")
elseif (DEFINED ENV{GITHUB_REF}) # Normal branch name
string(REGEX REPLACE "^refs/[^/]*/" "" GIT_BRANCH "$ENV{GITHUB_REF}")
else()
message("couldn't find branch")
set(GIT_BRANCH "detached-head")
endif()
else()
# Extract remote name if the output contains a remote/branch format
@ -141,6 +159,7 @@ else()
endif()
# Get remote link
message("getting remote link")
execute_process(
COMMAND git config --get remote.${GIT_REMOTE_NAME}.url
OUTPUT_VARIABLE GIT_REMOTE_URL
@ -149,6 +168,8 @@ execute_process(
configure_file("${CMAKE_CURRENT_SOURCE_DIR}/src/common/scm_rev.cpp.in" "${CMAKE_CURRENT_BINARY_DIR}/src/common/scm_rev.cpp" @ONLY)
message("end git things, remote: ${GIT_REMOTE_NAME}, branch: ${GIT_BRANCH}")
find_package(Boost 1.84.0 CONFIG)
find_package(FFmpeg 5.1.2 MODULE)
find_package(fmt 10.2.0 CONFIG)
@ -299,6 +320,7 @@ set(KERNEL_LIB src/core/libraries/kernel/sync/mutex.cpp
set(NETWORK_LIBS src/core/libraries/network/http.cpp
src/core/libraries/network/http.h
src/core/libraries/network/http_error.h
src/core/libraries/network/http2.cpp
src/core/libraries/network/http2.h
src/core/libraries/network/net.cpp
@ -371,6 +393,24 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
src/core/libraries/ngs2/ngs2_error.h
src/core/libraries/ngs2/ngs2_impl.cpp
src/core/libraries/ngs2/ngs2_impl.h
src/core/libraries/ngs2/ngs2_custom.cpp
src/core/libraries/ngs2/ngs2_custom.h
src/core/libraries/ngs2/ngs2_reverb.cpp
src/core/libraries/ngs2/ngs2_reverb.h
src/core/libraries/ngs2/ngs2_geom.cpp
src/core/libraries/ngs2/ngs2_geom.h
src/core/libraries/ngs2/ngs2_pan.cpp
src/core/libraries/ngs2/ngs2_pan.h
src/core/libraries/ngs2/ngs2_report.cpp
src/core/libraries/ngs2/ngs2_report.h
src/core/libraries/ngs2/ngs2_eq.cpp
src/core/libraries/ngs2/ngs2_eq.h
src/core/libraries/ngs2/ngs2_mastering.cpp
src/core/libraries/ngs2/ngs2_mastering.h
src/core/libraries/ngs2/ngs2_sampler.cpp
src/core/libraries/ngs2/ngs2_sampler.h
src/core/libraries/ngs2/ngs2_submixer.cpp
src/core/libraries/ngs2/ngs2_submixer.h
src/core/libraries/ajm/ajm_error.h
src/core/libraries/audio3d/audio3d.cpp
src/core/libraries/audio3d/audio3d.h
@ -584,6 +624,7 @@ set(COMMON src/common/logging/backend.cpp
src/common/spin_lock.h
src/common/stb.cpp
src/common/stb.h
src/common/string_literal.h
src/common/string_util.cpp
src/common/string_util.h
src/common/thread.cpp
@ -613,9 +654,6 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/aerolib/aerolib.h
src/core/address_space.cpp
src/core/address_space.h
src/core/crypto/crypto.cpp
src/core/crypto/crypto.h
src/core/crypto/keys.h
src/core/devices/base_device.cpp
src/core/devices/base_device.h
src/core/devices/ioccom.h
@ -633,22 +671,14 @@ set(CORE src/core/aerolib/stubs.cpp
src/core/devices/srandom_device.cpp
src/core/devices/srandom_device.h
src/core/file_format/pfs.h
src/core/file_format/pkg.cpp
src/core/file_format/pkg.h
src/core/file_format/pkg_type.cpp
src/core/file_format/pkg_type.h
src/core/file_format/psf.cpp
src/core/file_format/psf.h
src/core/file_format/playgo_chunk.cpp
src/core/file_format/playgo_chunk.h
src/core/file_format/trp.cpp
src/core/file_format/trp.h
src/core/file_format/splash.h
src/core/file_format/splash.cpp
src/core/file_sys/fs.cpp
src/core/file_sys/fs.h
src/core/loader.cpp
src/core/loader.h
src/core/loader/dwarf.cpp
src/core/loader/dwarf.h
src/core/loader/elf.cpp
@ -765,6 +795,7 @@ set(SHADER_RECOMPILER src/shader_recompiler/exception.h
src/shader_recompiler/ir/passes/identity_removal_pass.cpp
src/shader_recompiler/ir/passes/ir_passes.h
src/shader_recompiler/ir/passes/lower_buffer_format_to_raw.cpp
src/shader_recompiler/ir/passes/readlane_elimination_pass.cpp
src/shader_recompiler/ir/passes/resource_tracking_pass.cpp
src/shader_recompiler/ir/passes/ring_access_elimination.cpp
src/shader_recompiler/ir/passes/shader_info_collection_pass.cpp
@ -845,6 +876,10 @@ set(VIDEO_CORE src/video_core/amdgpu/liverpool.cpp
src/video_core/renderer_vulkan/vk_shader_util.h
src/video_core/renderer_vulkan/vk_swapchain.cpp
src/video_core/renderer_vulkan/vk_swapchain.h
src/video_core/renderer_vulkan/host_passes/fsr_pass.cpp
src/video_core/renderer_vulkan/host_passes/fsr_pass.h
src/video_core/renderer_vulkan/host_passes/pp_pass.cpp
src/video_core/renderer_vulkan/host_passes/pp_pass.h
src/video_core/texture_cache/image.cpp
src/video_core/texture_cache/image.h
src/video_core/texture_cache/image_info.cpp
@ -917,6 +952,9 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
src/qt_gui/control_settings.cpp
src/qt_gui/control_settings.h
src/qt_gui/control_settings.ui
src/qt_gui/kbm_gui.cpp
src/qt_gui/kbm_gui.h
src/qt_gui/kbm_gui.ui
src/qt_gui/main_window_ui.h
src/qt_gui/main_window.cpp
src/qt_gui/main_window.h
@ -930,10 +968,6 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
src/qt_gui/game_grid_frame.h
src/qt_gui/game_install_dialog.cpp
src/qt_gui/game_install_dialog.h
src/qt_gui/install_dir_select.cpp
src/qt_gui/install_dir_select.h
src/qt_gui/pkg_viewer.cpp
src/qt_gui/pkg_viewer.h
src/qt_gui/trophy_viewer.cpp
src/qt_gui/trophy_viewer.h
src/qt_gui/elf_viewer.cpp
@ -989,7 +1023,7 @@ endif()
create_target_directory_groups(shadps4)
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak::xbyak Tracy::TracyClient RenderDoc::API FFmpeg::ffmpeg Dear_ImGui gcn half::half ZLIB::ZLIB PNG::PNG)
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 pugixml::pugixml stb::headers usb-1.0)
target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 pugixml::pugixml stb::headers usb-1.0 cryptopp::cryptopp)
target_compile_definitions(shadps4 PRIVATE IMGUI_USER_CONFIG="imgui/imgui_config.h")
target_compile_definitions(Dear_ImGui PRIVATE IMGUI_USER_CONFIG="${PROJECT_SOURCE_DIR}/src/imgui/imgui_config.h")
@ -1038,12 +1072,6 @@ if (NOT ENABLE_QT_GUI)
target_link_libraries(shadps4 PRIVATE SDL3::SDL3)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND MSVC)
target_link_libraries(shadps4 PRIVATE cryptoppwin)
else()
target_link_libraries(shadps4 PRIVATE cryptopp::cryptopp)
endif()
if (ENABLE_QT_GUI)
target_link_libraries(shadps4 PRIVATE Qt6::Widgets Qt6::Concurrent Qt6::Network Qt6::Multimedia)
add_definitions(-DENABLE_QT_GUI)
@ -1114,7 +1142,6 @@ cmrc_add_resource_library(embedded-resources
src/images/gold.png
src/images/platinum.png
src/images/silver.png)
target_link_libraries(shadps4 PRIVATE res::embedded)
# ImGui resources

View File

@ -30,6 +30,7 @@ path = [
"src/images/dump_icon.png",
"src/images/exit_icon.png",
"src/images/file_icon.png",
"src/images/trophy_icon.png",
"src/images/flag_china.png",
"src/images/flag_eu.png",
"src/images/flag_jp.png",
@ -41,14 +42,17 @@ path = [
"src/images/grid_icon.png",
"src/images/keyboard_icon.png",
"src/images/iconsize_icon.png",
"src/images/KBM.png",
"src/images/ko-fi.png",
"src/images/list_icon.png",
"src/images/list_mode_icon.png",
"src/images/pause_icon.png",
"src/images/play_icon.png",
"src/images/ps4_controller.png",
"src/images/refresh_icon.png",
"src/images/restart_game_icon.png",
"src/images/refreshlist_icon.png",
"src/images/settings_icon.png",
"src/images/fullscreen_icon.png",
"src/images/stop_icon.png",
"src/images/utils_icon.png",
"src/images/shadPS4.icns",
@ -110,4 +114,9 @@ SPDX-License-Identifier = "CC0-1.0"
[[annotations]]
path = "cmake/CMakeRC.cmake"
SPDX-FileCopyrightText = "Copyright (c) 2017 vector-of-bool <vectorofbool@gmail.com>"
SPDX-License-Identifier = "MIT"
SPDX-License-Identifier = "MIT"
[[annotations]]
path = "src/video_core/host_shaders/fsr/*"
SPDX-FileCopyrightText = "Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved."
SPDX-License-Identifier = "MIT"

View File

@ -37,6 +37,9 @@
<category translate="no">Game</category>
</categories>
<releases>
<release version="0.7.0" date="2025-03-23">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.7.0</url>
</release>
<release version="0.6.0" date="2025-01-31">
<url>https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.6.0</url>
</release>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 658 KiB

View File

@ -13,7 +13,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
- [**RAM**](#ram)
- [**OS**](#os)
- [**Have the latest WIP version**](#how-to-run-the-latest-work-in-progress-builds-of-shadps4)
- [**Install PKG files (Games and Updates)**](#install-pkg-files)
- [**Configure the emulator**](#configure-the-emulator)
## Minimum PC requirements
@ -48,13 +47,7 @@ SPDX-License-Identifier: GPL-2.0-or-later
2. Once downloaded, extract to its own folder, and run shadPS4's executable from the extracted folder.
3. Upon first launch, shadPS4 will prompt you to select a folder to store your installed games in. Select "Browse" and then select a folder that shadPS4 can use to install your PKG files to.
## Install PKG files
To install PKG files (game and updates), you will need the Qt application (with UI). You will have to go to "File" then to "Install Packages (PKG)", a window will open then you will have to select the files. You can install multiple PKG files at once. Once finished, the game should appear in the application.
<img src="https://github.com/shadps4-emu/shadPS4/blob/main/documents/Quickstart/2.png" width="800">
3. Upon first launch, shadPS4 will prompt you to select a folder to store your installed games in. Select "Browse" and then select a folder that contains your dumped games.
## Configure the emulator

View File

@ -108,7 +108,7 @@ Now run the emulator. If Qt was enabled at configure time:
./build/shadps4
```
Otherwise, specify the path to your PKG's boot file:
Otherwise, specify the path to your game's boot file:
```bash
./build/shadps4 /"PATH"/"TO"/"GAME"/"FOLDER"/eboot.bin

View File

@ -26,22 +26,19 @@ if (NOT TARGET fmt::fmt)
add_subdirectory(fmt)
endif()
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND MSVC)
# If it is clang and MSVC we will add a static lib
# CryptoPP
add_subdirectory(cryptoppwin)
target_include_directories(cryptoppwin INTERFACE cryptoppwin/include)
else()
# CryptoPP
if (NOT TARGET cryptopp::cryptopp)
set(CRYPTOPP_INSTALL OFF)
set(CRYPTOPP_BUILD_TESTING OFF)
set(CRYPTOPP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/cryptopp)
add_subdirectory(cryptopp-cmake)
file(COPY cryptopp DESTINATION cryptopp FILES_MATCHING PATTERN "*.h")
# remove externals/cryptopp from include directories because it contains a conflicting zlib.h file
set_target_properties(cryptopp PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/cryptopp")
endif()
# CryptoPP
if (NOT TARGET cryptopp::cryptopp)
set(CRYPTOPP_INSTALL OFF)
set(CRYPTOPP_BUILD_TESTING OFF)
set(CRYPTOPP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/cryptopp)
# cryptopp instruction set checks do not account for added compile options,
# so disable extensions in the library config to match our chosen target CPU.
set(CRYPTOPP_DISABLE_AESNI ON)
set(CRYPTOPP_DISABLE_AVX2 ON)
add_subdirectory(cryptopp-cmake)
file(COPY cryptopp DESTINATION cryptopp FILES_MATCHING PATTERN "*.h")
# remove externals/cryptopp from include directories because it contains a conflicting zlib.h file
set_target_properties(cryptopp PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${CMAKE_CURRENT_BINARY_DIR}/cryptopp")
endif()
if (NOT TARGET FFmpeg::ffmpeg)

2
externals/cryptopp vendored

@ -1 +1 @@
Subproject commit 60f81a77e0c9a0e7ffc1ca1bc438ddfa2e43b78e
Subproject commit effed0d0b865afc23ed67e0916f83734e4b9b3b7

@ -1 +0,0 @@
Subproject commit bc3441dd2d6a9728e747dc0180bc8b9065a2923c

View File

@ -32,6 +32,7 @@ std::filesystem::path find_fs_path_or(const basic_value<TC>& v, const K& ky,
namespace Config {
static bool isNeo = false;
static bool isDevKit = false;
static bool playBGM = false;
static bool isTrophyPopupDisabled = false;
static int BGMvolume = 50;
@ -40,7 +41,7 @@ static u32 screenWidth = 1280;
static u32 screenHeight = 720;
static s32 gpuId = -1; // Vulkan physical device index. Set to negative for auto select
static std::string logFilter;
static std::string logType = "async";
static std::string logType = "sync";
static std::string userName = "shadPS4";
static std::string updateChannel;
static std::string chooseHomeTab;
@ -53,7 +54,7 @@ static bool isShaderDebug = false;
static bool isShowSplash = false;
static bool isAutoUpdate = false;
static bool isAlwaysShowChangelog = false;
static bool isLeftSideTrophy = false;
static std::string isSideTrophy = "right";
static bool isNullGpu = false;
static bool shouldCopyGPUBuffers = false;
static bool shouldDumpShaders = false;
@ -81,7 +82,8 @@ static std::string trophyKey;
// Gui
static bool load_game_size = true;
std::vector<std::filesystem::path> settings_install_dirs = {};
static std::vector<GameInstallDir> settings_install_dirs = {};
std::vector<bool> install_dirs_enabled = {};
std::filesystem::path settings_addon_install_dir = {};
std::filesystem::path save_data_path = {};
u32 main_window_geometry_x = 400;
@ -96,7 +98,6 @@ u32 m_slider_pos_grid = 0;
u32 m_table_mode = 0;
u32 m_window_size_W = 1280;
u32 m_window_size_H = 720;
std::vector<std::string> m_pkg_viewer;
std::vector<std::string> m_elf_viewer;
std::vector<std::string> m_recent_files;
std::string emulator_language = "en_US";
@ -105,6 +106,7 @@ static bool showBackgroundImage = true;
static bool isFullscreen = false;
static std::string fullscreenMode = "Windowed";
static bool isHDRAllowed = false;
static bool showLabelsUnderIcons = true;
// Language
u32 m_language = 1; // english
@ -166,10 +168,22 @@ bool isNeoModeConsole() {
return isNeo;
}
bool isDevKitConsole() {
return isDevKit;
}
bool getIsFullscreen() {
return isFullscreen;
}
bool getShowLabelsUnderIcons() {
return showLabelsUnderIcons;
}
bool setShowLabelsUnderIcons() {
return false;
}
std::string getFullscreenMode() {
return fullscreenMode;
}
@ -270,8 +284,8 @@ bool alwaysShowChangelog() {
return isAlwaysShowChangelog;
}
bool leftSideTrophy() {
return isLeftSideTrophy;
std::string sideTrophy() {
return isSideTrophy;
}
bool nullGpu() {
@ -381,8 +395,9 @@ void setAutoUpdate(bool enable) {
void setAlwaysShowChangelog(bool enable) {
isAlwaysShowChangelog = enable;
}
void setLeftSideTrophy(bool enable) {
isLeftSideTrophy = enable;
void setSideTrophy(std::string side) {
isSideTrophy = side;
}
void setNullGpu(bool enable) {
@ -420,6 +435,9 @@ void setVblankDiv(u32 value) {
void setIsFullscreen(bool enable) {
isFullscreen = enable;
}
static void setShowLabelsUnderIcons(bool enable) {
showLabelsUnderIcons = enable;
}
void setFullscreenMode(std::string mode) {
fullscreenMode = mode;
@ -518,22 +536,34 @@ void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h) {
main_window_geometry_h = h;
}
bool addGameInstallDir(const std::filesystem::path& dir) {
if (std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir) ==
settings_install_dirs.end()) {
settings_install_dirs.push_back(dir);
return true;
bool addGameInstallDir(const std::filesystem::path& dir, bool enabled) {
for (const auto& install_dir : settings_install_dirs) {
if (install_dir.path == dir) {
return false;
}
}
return false;
settings_install_dirs.push_back({dir, enabled});
return true;
}
void removeGameInstallDir(const std::filesystem::path& dir) {
auto iterator = std::find(settings_install_dirs.begin(), settings_install_dirs.end(), dir);
auto iterator =
std::find_if(settings_install_dirs.begin(), settings_install_dirs.end(),
[&dir](const GameInstallDir& install_dir) { return install_dir.path == dir; });
if (iterator != settings_install_dirs.end()) {
settings_install_dirs.erase(iterator);
}
}
void setGameInstallDirEnabled(const std::filesystem::path& dir, bool enabled) {
auto iterator =
std::find_if(settings_install_dirs.begin(), settings_install_dirs.end(),
[&dir](const GameInstallDir& install_dir) { return install_dir.path == dir; });
if (iterator != settings_install_dirs.end()) {
iterator->enabled = enabled;
}
}
void setAddonInstallDir(const std::filesystem::path& dir) {
settings_addon_install_dir = dir;
}
@ -570,11 +600,6 @@ void setMainWindowHeight(u32 height) {
m_window_size_H = height;
}
void setPkgViewer(const std::vector<std::string>& pkgList) {
m_pkg_viewer.resize(pkgList.size());
m_pkg_viewer = pkgList;
}
void setElfViewer(const std::vector<std::string>& elfList) {
m_elf_viewer.resize(elfList.size());
m_elf_viewer = elfList;
@ -589,8 +614,15 @@ void setEmulatorLanguage(std::string language) {
emulator_language = language;
}
void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_install_dirs_config) {
settings_install_dirs = settings_install_dirs_config;
void setGameInstallDirs(const std::vector<std::filesystem::path>& dirs_config) {
settings_install_dirs.clear();
for (const auto& dir : dirs_config) {
settings_install_dirs.push_back({dir, true});
}
}
void setAllGameInstallDirs(const std::vector<GameInstallDir>& dirs_config) {
settings_install_dirs = dirs_config;
}
void setSaveDataPath(const std::filesystem::path& path) {
@ -613,8 +645,22 @@ u32 getMainWindowGeometryH() {
return main_window_geometry_h;
}
const std::vector<std::filesystem::path>& getGameInstallDirs() {
return settings_install_dirs;
const std::vector<std::filesystem::path> getGameInstallDirs() {
std::vector<std::filesystem::path> enabled_dirs;
for (const auto& dir : settings_install_dirs) {
if (dir.enabled) {
enabled_dirs.push_back(dir.path);
}
}
return enabled_dirs;
}
const std::vector<bool> getGameInstallDirsEnabled() {
std::vector<bool> enabled_dirs;
for (const auto& dir : settings_install_dirs) {
enabled_dirs.push_back(dir.enabled);
}
return enabled_dirs;
}
std::filesystem::path getAddonInstallDir() {
@ -657,10 +703,6 @@ u32 getMainWindowHeight() {
return m_window_size_H;
}
std::vector<std::string> getPkgViewer() {
return m_pkg_viewer;
}
std::vector<std::string> getElfViewer() {
return m_elf_viewer;
}
@ -720,6 +762,7 @@ void load(const std::filesystem::path& path) {
const toml::value& general = data.at("General");
isNeo = toml::find_or<bool>(general, "isPS4Pro", false);
isDevKit = toml::find_or<bool>(general, "isDevKit", false);
playBGM = toml::find_or<bool>(general, "playBGM", false);
isTrophyPopupDisabled = toml::find_or<bool>(general, "isTrophyPopupDisabled", false);
trophyNotificationDuration =
@ -737,7 +780,7 @@ void load(const std::filesystem::path& path) {
isShowSplash = toml::find_or<bool>(general, "showSplash", true);
isAutoUpdate = toml::find_or<bool>(general, "autoUpdate", false);
isAlwaysShowChangelog = toml::find_or<bool>(general, "alwaysShowChangelog", false);
isLeftSideTrophy = toml::find_or<bool>(general, "leftSideTrophy", false);
isSideTrophy = toml::find_or<std::string>(general, "sideTrophy", "right");
separateupdatefolder = toml::find_or<bool>(general, "separateUpdateEnabled", false);
compatibilityData = toml::find_or<bool>(general, "compatibilityEnabled", false);
checkCompatibilityOnStartup =
@ -808,8 +851,22 @@ void load(const std::filesystem::path& path) {
const auto install_dir_array =
toml::find_or<std::vector<std::string>>(gui, "installDirs", {});
for (const auto& dir : install_dir_array) {
addGameInstallDir(std::filesystem::path{dir});
try {
install_dirs_enabled = toml::find<std::vector<bool>>(gui, "installDirsEnabled");
} catch (...) {
// If it does not exist, assume that all are enabled.
install_dirs_enabled.resize(install_dir_array.size(), true);
}
if (install_dirs_enabled.size() < install_dir_array.size()) {
install_dirs_enabled.resize(install_dir_array.size(), true);
}
settings_install_dirs.clear();
for (size_t i = 0; i < install_dir_array.size(); i++) {
settings_install_dirs.push_back(
{std::filesystem::path{install_dir_array[i]}, install_dirs_enabled[i]});
}
save_data_path = toml::find_fs_path_or(gui, "saveDataPath", {});
@ -819,7 +876,6 @@ void load(const std::filesystem::path& path) {
main_window_geometry_y = toml::find_or<int>(gui, "geometry_y", 0);
main_window_geometry_w = toml::find_or<int>(gui, "geometry_w", 0);
main_window_geometry_h = toml::find_or<int>(gui, "geometry_h", 0);
m_pkg_viewer = toml::find_or<std::vector<std::string>>(gui, "pkgDirs", {});
m_elf_viewer = toml::find_or<std::vector<std::string>>(gui, "elfDirs", {});
m_recent_files = toml::find_or<std::vector<std::string>>(gui, "recentFiles", {});
m_table_mode = toml::find_or<int>(gui, "gameTableMode", 0);
@ -852,6 +908,37 @@ void load(const std::filesystem::path& path) {
}
}
void sortTomlSections(toml::ordered_value& data) {
toml::ordered_value ordered_data;
std::vector<std::string> section_order = {"General", "Input", "GPU", "Vulkan",
"Debug", "Keys", "GUI", "Settings"};
for (const auto& section : section_order) {
if (data.contains(section)) {
std::vector<std::string> keys;
for (const auto& item : data.at(section).as_table()) {
keys.push_back(item.first);
}
std::sort(keys.begin(), keys.end(), [](const std::string& a, const std::string& b) {
return std::lexicographical_compare(
a.begin(), a.end(), b.begin(), b.end(), [](char a_char, char b_char) {
return std::tolower(a_char) < std::tolower(b_char);
});
});
toml::ordered_value ordered_section;
for (const auto& key : keys) {
ordered_section[key] = data.at(section).at(key);
}
ordered_data[section] = ordered_section;
}
}
data = ordered_data;
}
void save(const std::filesystem::path& path) {
toml::ordered_value data;
@ -875,6 +962,7 @@ void save(const std::filesystem::path& path) {
}
data["General"]["isPS4Pro"] = isNeo;
data["General"]["isDevKit"] = isDevKit;
data["General"]["isTrophyPopupDisabled"] = isTrophyPopupDisabled;
data["General"]["trophyNotificationDuration"] = trophyNotificationDuration;
data["General"]["playBGM"] = playBGM;
@ -888,7 +976,7 @@ void save(const std::filesystem::path& path) {
data["General"]["showSplash"] = isShowSplash;
data["General"]["autoUpdate"] = isAutoUpdate;
data["General"]["alwaysShowChangelog"] = isAlwaysShowChangelog;
data["General"]["leftSideTrophy"] = isLeftSideTrophy;
data["General"]["sideTrophy"] = isSideTrophy;
data["General"]["separateUpdateEnabled"] = separateupdatefolder;
data["General"]["compatibilityEnabled"] = compatibilityData;
data["General"]["checkCompatibilityOnStartup"] = checkCompatibilityOnStartup;
@ -921,14 +1009,37 @@ void save(const std::filesystem::path& path) {
data["Debug"]["CollectShader"] = isShaderDebug;
data["Debug"]["isSeparateLogFilesEnabled"] = isSeparateLogFilesEnabled;
data["Debug"]["FPSColor"] = isFpsColor;
data["Keys"]["TrophyKey"] = trophyKey;
std::vector<std::string> install_dirs;
for (const auto& dirString : settings_install_dirs) {
install_dirs.emplace_back(std::string{fmt::UTF(dirString.u8string()).data});
std::vector<bool> install_dirs_enabled;
// temporary structure for ordering
struct DirEntry {
std::string path_str;
bool enabled;
};
std::vector<DirEntry> sorted_dirs;
for (const auto& dirInfo : settings_install_dirs) {
sorted_dirs.push_back(
{std::string{fmt::UTF(dirInfo.path.u8string()).data}, dirInfo.enabled});
}
// Sort directories alphabetically
std::sort(sorted_dirs.begin(), sorted_dirs.end(), [](const DirEntry& a, const DirEntry& b) {
return std::lexicographical_compare(
a.path_str.begin(), a.path_str.end(), b.path_str.begin(), b.path_str.end(),
[](char a_char, char b_char) { return std::tolower(a_char) < std::tolower(b_char); });
});
for (const auto& entry : sorted_dirs) {
install_dirs.push_back(entry.path_str);
install_dirs_enabled.push_back(entry.enabled);
}
data["GUI"]["installDirs"] = install_dirs;
data["GUI"]["installDirsEnabled"] = install_dirs_enabled;
data["GUI"]["saveDataPath"] = std::string{fmt::UTF(save_data_path.u8string()).data};
data["GUI"]["loadGameSizeEnabled"] = load_game_size;
@ -939,9 +1050,13 @@ void save(const std::filesystem::path& path) {
data["GUI"]["showBackgroundImage"] = showBackgroundImage;
data["Settings"]["consoleLanguage"] = m_language;
// Sorting of TOML sections
sortTomlSections(data);
std::ofstream file(path, std::ios::binary);
file << data;
file.close();
saveMainWindow(path);
}
@ -979,10 +1094,12 @@ void saveMainWindow(const std::filesystem::path& path) {
data["GUI"]["geometry_y"] = main_window_geometry_y;
data["GUI"]["geometry_w"] = main_window_geometry_w;
data["GUI"]["geometry_h"] = main_window_geometry_h;
data["GUI"]["pkgDirs"] = m_pkg_viewer;
data["GUI"]["elfDirs"] = m_elf_viewer;
data["GUI"]["recentFiles"] = m_recent_files;
// Sorting of TOML sections
sortTomlSections(data);
std::ofstream file(path, std::ios::binary);
file << data;
file.close();
@ -991,6 +1108,7 @@ void saveMainWindow(const std::filesystem::path& path) {
void setDefaultValues() {
isHDRAllowed = false;
isNeo = false;
isDevKit = false;
isFullscreen = false;
isTrophyPopupDisabled = false;
playBGM = false;
@ -999,7 +1117,7 @@ void setDefaultValues() {
screenWidth = 1280;
screenHeight = 720;
logFilter = "";
logType = "async";
logType = "sync";
userName = "shadPS4";
if (Common::isRelease) {
updateChannel = "Release";
@ -1018,7 +1136,7 @@ void setDefaultValues() {
isShowSplash = false;
isAutoUpdate = false;
isAlwaysShowChangelog = false;
isLeftSideTrophy = false;
isSideTrophy = "right";
isNullGpu = false;
shouldDumpShaders = false;
vblankDivider = 1;

View File

@ -9,6 +9,11 @@
namespace Config {
struct GameInstallDir {
std::filesystem::path path;
bool enabled;
};
enum HideCursorState : s16 { Never, Idle, Always };
void load(const std::filesystem::path& path);
@ -21,8 +26,11 @@ bool GetLoadGameSizeEnabled();
std::filesystem::path GetSaveDataPath();
void setLoadGameSizeEnabled(bool enable);
bool getIsFullscreen();
bool getShowLabelsUnderIcons();
bool setShowLabelsUnderIcons();
std::string getFullscreenMode();
bool isNeoModeConsole();
bool isDevKitConsole();
bool getPlayBGM();
int getBGMvolume();
bool getisTrophyPopupDisabled();
@ -63,7 +71,7 @@ bool collectShadersForDebug();
bool showSplash();
bool autoUpdate();
bool alwaysShowChangelog();
bool leftSideTrophy();
std::string sideTrophy();
bool nullGpu();
bool copyGPUCmdBuffers();
bool dumpShaders();
@ -77,7 +85,7 @@ void setCollectShaderForDebug(bool enable);
void setShowSplash(bool enable);
void setAutoUpdate(bool enable);
void setAlwaysShowChangelog(bool enable);
void setLeftSideTrophy(bool enable);
void setSideTrophy(std::string side);
void setNullGpu(bool enable);
void setAllowHDR(bool enable);
void setCopyGPUCmdBuffers(bool enable);
@ -98,7 +106,8 @@ void setUserName(const std::string& type);
void setUpdateChannel(const std::string& type);
void setChooseHomeTab(const std::string& type);
void setSeparateUpdateEnabled(bool use);
void setGameInstallDirs(const std::vector<std::filesystem::path>& settings_install_dirs_config);
void setGameInstallDirs(const std::vector<std::filesystem::path>& dirs_config);
void setAllGameInstallDirs(const std::vector<GameInstallDir>& dirs_config);
void setSaveDataPath(const std::filesystem::path& path);
void setCompatibilityEnabled(bool use);
void setCheckCompatibilityOnStartup(bool use);
@ -133,8 +142,9 @@ void setVkGuestMarkersEnabled(bool enable);
// Gui
void setMainWindowGeometry(u32 x, u32 y, u32 w, u32 h);
bool addGameInstallDir(const std::filesystem::path& dir);
bool addGameInstallDir(const std::filesystem::path& dir, bool enabled = true);
void removeGameInstallDir(const std::filesystem::path& dir);
void setGameInstallDirEnabled(const std::filesystem::path& dir, bool enabled);
void setAddonInstallDir(const std::filesystem::path& dir);
void setMainWindowTheme(u32 theme);
void setIconSize(u32 size);
@ -144,7 +154,6 @@ void setSliderPositionGrid(u32 pos);
void setTableMode(u32 mode);
void setMainWindowWidth(u32 width);
void setMainWindowHeight(u32 height);
void setPkgViewer(const std::vector<std::string>& pkgList);
void setElfViewer(const std::vector<std::string>& elfList);
void setRecentFiles(const std::vector<std::string>& recentFiles);
void setEmulatorLanguage(std::string language);
@ -153,7 +162,8 @@ u32 getMainWindowGeometryX();
u32 getMainWindowGeometryY();
u32 getMainWindowGeometryW();
u32 getMainWindowGeometryH();
const std::vector<std::filesystem::path>& getGameInstallDirs();
const std::vector<std::filesystem::path> getGameInstallDirs();
const std::vector<bool> getGameInstallDirsEnabled();
std::filesystem::path getAddonInstallDir();
u32 getMainWindowTheme();
u32 getIconSize();
@ -163,7 +173,6 @@ u32 getSliderPositionGrid();
u32 getTableMode();
u32 getMainWindowWidth();
u32 getMainWindowHeight();
std::vector<std::string> getPkgViewer();
std::vector<std::string> getElfViewer();
std::vector<std::string> getRecentFiles();
std::string getEmulatorLanguage();

View File

@ -3,6 +3,7 @@
#pragma once
#include <filesystem>
#include <string>
#include <string_view>
@ -69,6 +70,8 @@ class ElfInfo {
u32 raw_firmware_ver = 0;
PSFAttributes psf_attributes{};
std::filesystem::path splash_path{};
public:
static constexpr u32 FW_15 = 0x1500000;
static constexpr u32 FW_16 = 0x1600000;
@ -116,6 +119,10 @@ public:
ASSERT(initialized);
return psf_attributes;
}
[[nodiscard]] const std::filesystem::path& GetSplashPath() const {
return splash_path;
}
};
} // namespace Common

View File

@ -125,12 +125,15 @@ namespace {
[[nodiscard]] constexpr int ToSeekOrigin(SeekOrigin origin) {
switch (origin) {
case SeekOrigin::SetOrigin:
default:
return SEEK_SET;
case SeekOrigin::CurrentPosition:
return SEEK_CUR;
case SeekOrigin::End:
return SEEK_END;
default:
LOG_ERROR(Common_Filesystem, "Unsupported origin {}, defaulting to SEEK_SET",
static_cast<u32>(origin));
return SEEK_SET;
}
}
@ -377,20 +380,6 @@ bool IOFile::Seek(s64 offset, SeekOrigin origin) const {
return false;
}
if (False(file_access_mode & (FileAccessMode::Write | FileAccessMode::Append))) {
u64 size = GetSize();
if (origin == SeekOrigin::CurrentPosition && Tell() + offset > size) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
} else if (origin == SeekOrigin::SetOrigin && (u64)offset > size) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
} else if (origin == SeekOrigin::End && offset > 0) {
LOG_ERROR(Common_Filesystem, "Seeking past the end of the file");
return false;
}
}
errno = 0;
const auto seek_result = fseeko(file, offset, ToSeekOrigin(origin)) == 0;

View File

@ -61,6 +61,8 @@ enum class SeekOrigin : u32 {
SetOrigin, // Seeks from the start of the file.
CurrentPosition, // Seeks from the current file pointer position.
End, // Seeks from the end of the file.
SeekHole, // Seeks from the start of the next hole in the file.
SeekData, // Seeks from the start of the next non-hole region in the file.
};
class IOFile final {

View File

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <fstream>
#include <unordered_map>
#include "common/logging/log.h"
#include "common/path_util.h"
@ -16,6 +17,8 @@
#ifdef _WIN32
// This is the maximum number of UTF-16 code units permissible in Windows file paths
#define MAX_PATH 260
#include <Shlobj.h>
#include <windows.h>
#else
// This is the maximum number of UTF-8 code units permissible in all other OSes' file paths
#define MAX_PATH 1024
@ -105,6 +108,10 @@ static auto UserPaths = [] {
} else {
user_dir = std::filesystem::path(getenv("HOME")) / ".local" / "share" / "shadPS4";
}
#elif _WIN32
TCHAR appdata[MAX_PATH] = {0};
SHGetFolderPath(NULL, CSIDL_APPDATA, NULL, 0, appdata);
user_dir = std::filesystem::path(appdata) / "shadPS4";
#endif
}
@ -130,6 +137,21 @@ static auto UserPaths = [] {
create_path(PathType::MetaDataDir, user_dir / METADATA_DIR);
create_path(PathType::CustomTrophy, user_dir / CUSTOM_TROPHY);
std::ofstream notice_file(user_dir / CUSTOM_TROPHY / "Notice.txt");
if (notice_file.is_open()) {
notice_file
<< "++++++++++++++++++++++++++++++++\n+ Custom Trophy Images / Sound "
"+\n++++++++++++++++++++++++++++++++\n\nYou can add custom images to the "
"trophies.\n*We recommend a square resolution image, for example 200x200, 500x500, "
"the same size as the height and width.\nIn this folder ('user\\custom_trophy'), "
"add the files with the following "
"names:\n\nbronze.png\nsilver.png\ngold.png\nplatinum.png\n\nYou can add a custom "
"sound for trophy notifications.\n*By default, no audio is played unless it is in "
"this folder and you are using the QT version.\nIn this folder "
"('user\\custom_trophy'), add the files with the following names:\n\ntrophy.mp3";
notice_file.close();
}
return paths;
}();
@ -223,4 +245,4 @@ std::filesystem::path PathFromQString(const QString& path) {
}
#endif
} // namespace Common::FS
} // namespace Common::FS

View File

@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
template <size_t N, typename C = char>
struct StringLiteral {
static constexpr size_t len = N;
constexpr StringLiteral(const C (&str)[N]) {
std::copy_n(str, N, value);
}
C value[N]{};
};

View File

@ -8,7 +8,7 @@
namespace Common {
constexpr char VERSION[] = "0.6.1 WIP";
constexpr char VERSION[] = "0.7.1 WIP";
constexpr bool isRelease = false;
} // namespace Common

View File

@ -180,28 +180,44 @@ static void RestoreStack(Xbyak::CodeGenerator& c) {
c.mov(rsp, qword[reinterpret_cast<void*>(stack_pointer_slot * sizeof(void*))]);
}
/// Validates that the dst register is supported given the SaveStack/RestoreStack implementation.
static void ValidateDst(const Xbyak::Reg& dst) {
// No restrictions.
}
#else
// These utilities are not implemented as we can't save anything to thread local storage without
// temporary registers.
void InitializeThreadPatchStack() {
// No-op
}
// NOTE: Since stack pointer here is subtracted through safe zone and not saved anywhere,
// it must not be modified during the instruction. Otherwise, we will not be able to find
// and load registers back from where they were saved. Thus, a limitation is placed on
// instructions, that they must not use the stack pointer register as a destination.
/// Saves the stack pointer to thread local storage and loads the patch stack.
static void SaveStack(Xbyak::CodeGenerator& c) {
UNIMPLEMENTED();
c.lea(rsp, ptr[rsp - 128]); // red zone
}
/// Restores the stack pointer from thread local storage.
static void RestoreStack(Xbyak::CodeGenerator& c) {
UNIMPLEMENTED();
c.lea(rsp, ptr[rsp + 128]); // red zone
}
/// Validates that the dst register is supported given the SaveStack/RestoreStack implementation.
static void ValidateDst(const Xbyak::Reg& dst) {
// Stack pointer is not preserved, so it can't be used as a dst.
ASSERT_MSG(dst.getIdx() != rsp.getIdx(), "Stack pointer not supported as destination.");
}
#endif
/// Switches to the patch stack, saves registers, and restores the original stack.
static void SaveRegisters(Xbyak::CodeGenerator& c, const std::initializer_list<Xbyak::Reg> regs) {
// Uses a more robust solution for saving registers on MacOS to avoid potential stack corruption
// if games decide to not follow the ABI and use the red zone.
SaveStack(c);
for (const auto& reg : regs) {
c.push(reg.cvt64());
@ -257,12 +273,11 @@ static void RestoreContext(Xbyak::CodeGenerator& c, const Xbyak::Operand& dst,
RestoreStack(c);
}
#ifdef __APPLE__
static void GenerateANDN(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src1 = ZydisToXbyakRegisterOperand(operands[1]);
const auto src2 = ZydisToXbyakOperand(operands[2]);
ValidateDst(dst);
// Check if src2 is a memory operand or a register different to dst.
// In those cases, we don't need to use a temporary register and are free to modify dst.
@ -301,6 +316,7 @@ static void GenerateBEXTR(const ZydisDecodedOperand* operands, Xbyak::CodeGenera
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
const auto start_len = ZydisToXbyakRegisterOperand(operands[2]);
ValidateDst(dst);
const Xbyak::Reg32e shift(Xbyak::Operand::RCX, static_cast<int>(start_len.getBit()));
const auto scratch1 =
@ -338,6 +354,7 @@ static void GenerateBEXTR(const ZydisDecodedOperand* operands, Xbyak::CodeGenera
static void GenerateBLSI(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
ValidateDst(dst);
const auto scratch = AllocateScratchRegister({&dst, src.get()}, dst.getBit());
@ -367,6 +384,7 @@ static void GenerateBLSI(const ZydisDecodedOperand* operands, Xbyak::CodeGenerat
static void GenerateBLSMSK(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
ValidateDst(dst);
const auto scratch = AllocateScratchRegister({&dst, src.get()}, dst.getBit());
@ -395,9 +413,37 @@ static void GenerateBLSMSK(const ZydisDecodedOperand* operands, Xbyak::CodeGener
RestoreRegisters(c, {scratch});
}
static void GenerateTZCNT(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
ValidateDst(dst);
Xbyak::Label src_zero, end;
c.cmp(*src, 0);
c.je(src_zero);
// If src is not zero, functions like a BSF, but also clears the CF
c.bsf(dst, *src);
c.clc();
c.jmp(end);
c.L(src_zero);
c.mov(dst, operands[0].size);
// Since dst is not zero, also set ZF to zero. Testing dst with itself when we know
// it isn't zero is a good way to do this.
// Use cvt32 to avoid REX/Operand size prefixes.
c.test(dst.cvt32(), dst.cvt32());
// When source is zero, TZCNT also sets CF.
c.stc();
c.L(end);
}
static void GenerateBLSR(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
const auto dst = ZydisToXbyakRegisterOperand(operands[0]);
const auto src = ZydisToXbyakOperand(operands[1]);
ValidateDst(dst);
const auto scratch = AllocateScratchRegister({&dst, src.get()}, dst.getBit());
@ -426,6 +472,8 @@ static void GenerateBLSR(const ZydisDecodedOperand* operands, Xbyak::CodeGenerat
RestoreRegisters(c, {scratch});
}
#ifdef __APPLE__
static __attribute__((sysv_abi)) void PerformVCVTPH2PS(float* out, const half_float::half* in,
const u32 count) {
for (u32 i = 0; i < count; i++) {
@ -616,6 +664,11 @@ static bool FilterNoSSE4a(const ZydisDecodedOperand*) {
return !cpu.has(Cpu::tSSE4a);
}
static bool FilterNoBMI1(const ZydisDecodedOperand*) {
Cpu cpu;
return !cpu.has(Cpu::tBMI1);
}
static void GenerateEXTRQ(const ZydisDecodedOperand* operands, Xbyak::CodeGenerator& c) {
bool immediateForm = operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
operands[2].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
@ -897,14 +950,16 @@ static const std::unordered_map<ZydisMnemonic, PatchInfo> Patches = {
{ZYDIS_MNEMONIC_EXTRQ, {FilterNoSSE4a, GenerateEXTRQ, true}},
{ZYDIS_MNEMONIC_INSERTQ, {FilterNoSSE4a, GenerateINSERTQ, true}},
// BMI1
{ZYDIS_MNEMONIC_ANDN, {FilterNoBMI1, GenerateANDN, true}},
{ZYDIS_MNEMONIC_BEXTR, {FilterNoBMI1, GenerateBEXTR, true}},
{ZYDIS_MNEMONIC_BLSI, {FilterNoBMI1, GenerateBLSI, true}},
{ZYDIS_MNEMONIC_BLSMSK, {FilterNoBMI1, GenerateBLSMSK, true}},
{ZYDIS_MNEMONIC_BLSR, {FilterNoBMI1, GenerateBLSR, true}},
{ZYDIS_MNEMONIC_TZCNT, {FilterNoBMI1, GenerateTZCNT, true}},
#ifdef __APPLE__
// Patches for instruction sets not supported by Rosetta 2.
// BMI1
{ZYDIS_MNEMONIC_ANDN, {FilterRosetta2Only, GenerateANDN, true}},
{ZYDIS_MNEMONIC_BEXTR, {FilterRosetta2Only, GenerateBEXTR, true}},
{ZYDIS_MNEMONIC_BLSI, {FilterRosetta2Only, GenerateBLSI, true}},
{ZYDIS_MNEMONIC_BLSMSK, {FilterRosetta2Only, GenerateBLSMSK, true}},
{ZYDIS_MNEMONIC_BLSR, {FilterRosetta2Only, GenerateBLSR, true}},
// F16C
{ZYDIS_MNEMONIC_VCVTPH2PS, {FilterRosetta2Only, GenerateVCVTPH2PS, true}},
{ZYDIS_MNEMONIC_VCVTPS2PH, {FilterRosetta2Only, GenerateVCVTPS2PH, true}},

View File

@ -1,215 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <array>
#include "crypto.h"
CryptoPP::RSA::PrivateKey Crypto::key_pkg_derived_key3_keyset_init() {
CryptoPP::InvertibleRSAFunction params;
params.SetPrime1(CryptoPP::Integer(PkgDerivedKey3Keyset::Prime1, 0x80));
params.SetPrime2(CryptoPP::Integer(PkgDerivedKey3Keyset::Prime2, 0x80));
params.SetPublicExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::PublicExponent, 4));
params.SetPrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::PrivateExponent, 0x100));
params.SetModPrime1PrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::Exponent1, 0x80));
params.SetModPrime2PrivateExponent(CryptoPP::Integer(PkgDerivedKey3Keyset::Exponent2, 0x80));
params.SetModulus(CryptoPP::Integer(PkgDerivedKey3Keyset::Modulus, 0x100));
params.SetMultiplicativeInverseOfPrime2ModPrime1(
CryptoPP::Integer(PkgDerivedKey3Keyset::Coefficient, 0x80));
CryptoPP::RSA::PrivateKey privateKey(params);
return privateKey;
}
CryptoPP::RSA::PrivateKey Crypto::FakeKeyset_keyset_init() {
CryptoPP::InvertibleRSAFunction params;
params.SetPrime1(CryptoPP::Integer(FakeKeyset::Prime1, 0x80));
params.SetPrime2(CryptoPP::Integer(FakeKeyset::Prime2, 0x80));
params.SetPublicExponent(CryptoPP::Integer(FakeKeyset::PublicExponent, 4));
params.SetPrivateExponent(CryptoPP::Integer(FakeKeyset::PrivateExponent, 0x100));
params.SetModPrime1PrivateExponent(CryptoPP::Integer(FakeKeyset::Exponent1, 0x80));
params.SetModPrime2PrivateExponent(CryptoPP::Integer(FakeKeyset::Exponent2, 0x80));
params.SetModulus(CryptoPP::Integer(FakeKeyset::Modulus, 0x100));
params.SetMultiplicativeInverseOfPrime2ModPrime1(
CryptoPP::Integer(FakeKeyset::Coefficient, 0x80));
CryptoPP::RSA::PrivateKey privateKey(params);
return privateKey;
}
CryptoPP::RSA::PrivateKey Crypto::DebugRifKeyset_init() {
CryptoPP::InvertibleRSAFunction params;
params.SetPrime1(CryptoPP::Integer(DebugRifKeyset::Prime1, sizeof(DebugRifKeyset::Prime1)));
params.SetPrime2(CryptoPP::Integer(DebugRifKeyset::Prime2, sizeof(DebugRifKeyset::Prime2)));
params.SetPublicExponent(
CryptoPP::Integer(DebugRifKeyset::PublicExponent, sizeof(DebugRifKeyset::PublicExponent)));
params.SetPrivateExponent(CryptoPP::Integer(DebugRifKeyset::PrivateExponent,
sizeof(DebugRifKeyset::PrivateExponent)));
params.SetModPrime1PrivateExponent(
CryptoPP::Integer(DebugRifKeyset::Exponent1, sizeof(DebugRifKeyset::Exponent1)));
params.SetModPrime2PrivateExponent(
CryptoPP::Integer(DebugRifKeyset::Exponent2, sizeof(DebugRifKeyset::Exponent2)));
params.SetModulus(CryptoPP::Integer(DebugRifKeyset::Modulus, sizeof(DebugRifKeyset::Modulus)));
params.SetMultiplicativeInverseOfPrime2ModPrime1(
CryptoPP::Integer(DebugRifKeyset::Coefficient, sizeof(DebugRifKeyset::Coefficient)));
CryptoPP::RSA::PrivateKey privateKey(params);
return privateKey;
}
void Crypto::RSA2048Decrypt(std::span<CryptoPP::byte, 32> dec_key,
std::span<const CryptoPP::byte, 256> ciphertext,
bool is_dk3) { // RSAES_PKCS1v15_
// Create an RSA decryptor
CryptoPP::RSA::PrivateKey privateKey;
if (is_dk3) {
privateKey = key_pkg_derived_key3_keyset_init();
} else {
privateKey = FakeKeyset_keyset_init();
}
CryptoPP::RSAES_PKCS1v15_Decryptor rsaDecryptor(privateKey);
// Allocate memory for the decrypted data
std::array<CryptoPP::byte, 256> decrypted;
// Perform the decryption
CryptoPP::AutoSeededRandomPool rng;
CryptoPP::DecodingResult result =
rsaDecryptor.Decrypt(rng, ciphertext.data(), decrypted.size(), decrypted.data());
std::copy(decrypted.begin(), decrypted.begin() + dec_key.size(), dec_key.begin());
}
void Crypto::ivKeyHASH256(std::span<const CryptoPP::byte, 64> cipher_input,
std::span<CryptoPP::byte, 32> ivkey_result) {
CryptoPP::SHA256 sha256;
std::array<CryptoPP::byte, CryptoPP::SHA256::DIGESTSIZE> hashResult;
auto array_sink = new CryptoPP::ArraySink(hashResult.data(), CryptoPP::SHA256::DIGESTSIZE);
auto filter = new CryptoPP::HashFilter(sha256, array_sink);
CryptoPP::ArraySource r(cipher_input.data(), cipher_input.size(), true, filter);
std::copy(hashResult.begin(), hashResult.begin() + ivkey_result.size(), ivkey_result.begin());
}
void Crypto::aesCbcCfb128Decrypt(std::span<const CryptoPP::byte, 32> ivkey,
std::span<const CryptoPP::byte, 256> ciphertext,
std::span<CryptoPP::byte, 256> decrypted) {
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> key;
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> iv;
std::copy(ivkey.begin() + 16, ivkey.begin() + 16 + key.size(), key.begin());
std::copy(ivkey.begin(), ivkey.begin() + iv.size(), iv.begin());
CryptoPP::AES::Decryption aesDecryption(key.data(), CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
cbcDecryption.ProcessData(decrypted.data() + i, ciphertext.data() + i,
CryptoPP::AES::BLOCKSIZE);
}
}
void Crypto::aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
std::span<CryptoPP::byte> ciphertext,
std::span<CryptoPP::byte> decrypted) {
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> key;
std::array<CryptoPP::byte, CryptoPP::AES::DEFAULT_KEYLENGTH> iv;
std::copy(ivkey.begin() + 16, ivkey.begin() + 16 + key.size(), key.begin());
std::copy(ivkey.begin(), ivkey.begin() + iv.size(), iv.begin());
CryptoPP::AES::Decryption aesDecryption(key.data(), CryptoPP::AES::DEFAULT_KEYLENGTH);
CryptoPP::CBC_Mode_ExternalCipher::Decryption cbcDecryption(aesDecryption, iv.data());
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
cbcDecryption.ProcessData(decrypted.data() + i, ciphertext.data() + i,
CryptoPP::AES::BLOCKSIZE);
}
}
void Crypto::decryptEFSM(std::span<CryptoPP::byte, 16> trophyKey,
std::span<CryptoPP::byte, 16> NPcommID,
std::span<CryptoPP::byte, 16> efsmIv, std::span<CryptoPP::byte> ciphertext,
std::span<CryptoPP::byte> decrypted) {
// step 1: Encrypt NPcommID
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encrypt;
std::vector<CryptoPP::byte> trophyIv(16, 0);
std::vector<CryptoPP::byte> trpKey(16);
encrypt.SetKeyWithIV(trophyKey.data(), trophyKey.size(), trophyIv.data());
encrypt.ProcessData(trpKey.data(), NPcommID.data(), 16);
// step 2: decrypt efsm.
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decrypt;
decrypt.SetKeyWithIV(trpKey.data(), trpKey.size(), efsmIv.data());
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
decrypt.ProcessData(decrypted.data() + i, ciphertext.data() + i, CryptoPP::AES::BLOCKSIZE);
}
}
void Crypto::PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs,
std::span<const CryptoPP::byte, 16> seed,
std::span<CryptoPP::byte, 16> dataKey,
std::span<CryptoPP::byte, 16> tweakKey) {
CryptoPP::HMAC<CryptoPP::SHA256> hmac(ekpfs.data(), ekpfs.size());
CryptoPP::SecByteBlock d(20); // Use Crypto++ SecByteBlock for better memory management
// Copy the bytes of 'index' to the 'd' array
uint32_t index = 1;
std::memcpy(d, &index, sizeof(uint32_t));
// Copy the bytes of 'seed' to the 'd' array starting from index 4
std::memcpy(d + sizeof(uint32_t), seed.data(), seed.size());
// Allocate memory for 'u64' using new
std::vector<CryptoPP::byte> data_tweak_key(hmac.DigestSize());
// Calculate the HMAC
hmac.CalculateDigest(data_tweak_key.data(), d, d.size());
std::copy(data_tweak_key.begin(), data_tweak_key.begin() + dataKey.size(), tweakKey.begin());
std::copy(data_tweak_key.begin() + tweakKey.size(),
data_tweak_key.begin() + tweakKey.size() + dataKey.size(), dataKey.begin());
}
void Crypto::decryptPFS(std::span<const CryptoPP::byte, 16> dataKey,
std::span<const CryptoPP::byte, 16> tweakKey, std::span<const u8> src_image,
std::span<CryptoPP::byte> dst_image, u64 sector) {
// Start at 0x10000 to keep the header when decrypting the whole pfs_image.
for (int i = 0; i < src_image.size(); i += 0x1000) {
const u64 current_sector = sector + (i / 0x1000);
CryptoPP::ECB_Mode<CryptoPP::AES>::Encryption encrypt(tweakKey.data(), tweakKey.size());
CryptoPP::ECB_Mode<CryptoPP::AES>::Decryption decrypt(dataKey.data(), dataKey.size());
std::array<CryptoPP::byte, 16> tweak{};
std::array<CryptoPP::byte, 16> encryptedTweak;
std::array<CryptoPP::byte, 16> xorBuffer;
std::memcpy(tweak.data(), &current_sector, sizeof(u64));
// Encrypt the tweak for each sector.
encrypt.ProcessData(encryptedTweak.data(), tweak.data(), 16);
for (int plaintextOffset = 0; plaintextOffset < 0x1000; plaintextOffset += 16) {
xtsXorBlock(xorBuffer.data(), src_image.data() + i + plaintextOffset,
encryptedTweak.data()); // x, c, t
decrypt.ProcessData(xorBuffer.data(), xorBuffer.data(), 16); // x, x
xtsXorBlock(dst_image.data() + i + plaintextOffset, xorBuffer.data(),
encryptedTweak.data()); //(p) c, x , t
xtsMult(encryptedTweak);
}
}
}

View File

@ -1,63 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <span>
#include <cryptopp/aes.h>
#include <cryptopp/filters.h>
#include <cryptopp/modes.h>
#include <cryptopp/oaep.h>
#include <cryptopp/osrng.h>
#include <cryptopp/rsa.h>
#include <cryptopp/sha.h>
#include "common/types.h"
#include "keys.h"
class Crypto {
public:
CryptoPP::RSA::PrivateKey key_pkg_derived_key3_keyset_init();
CryptoPP::RSA::PrivateKey FakeKeyset_keyset_init();
CryptoPP::RSA::PrivateKey DebugRifKeyset_init();
void RSA2048Decrypt(std::span<CryptoPP::byte, 32> dk3,
std::span<const CryptoPP::byte, 256> ciphertext,
bool is_dk3); // RSAES_PKCS1v15_
void ivKeyHASH256(std::span<const CryptoPP::byte, 64> cipher_input,
std::span<CryptoPP::byte, 32> ivkey_result);
void aesCbcCfb128Decrypt(std::span<const CryptoPP::byte, 32> ivkey,
std::span<const CryptoPP::byte, 256> ciphertext,
std::span<CryptoPP::byte, 256> decrypted);
void aesCbcCfb128DecryptEntry(std::span<const CryptoPP::byte, 32> ivkey,
std::span<CryptoPP::byte> ciphertext,
std::span<CryptoPP::byte> decrypted);
void decryptEFSM(std::span<CryptoPP::byte, 16> trophyKey,
std::span<CryptoPP::byte, 16> NPcommID, std::span<CryptoPP::byte, 16> efsmIv,
std::span<CryptoPP::byte> ciphertext, std::span<CryptoPP::byte> decrypted);
void PfsGenCryptoKey(std::span<const CryptoPP::byte, 32> ekpfs,
std::span<const CryptoPP::byte, 16> seed,
std::span<CryptoPP::byte, 16> dataKey,
std::span<CryptoPP::byte, 16> tweakKey);
void decryptPFS(std::span<const CryptoPP::byte, 16> dataKey,
std::span<const CryptoPP::byte, 16> tweakKey, std::span<const u8> src_image,
std::span<CryptoPP::byte> dst_image, u64 sector);
void xtsXorBlock(CryptoPP::byte* x, const CryptoPP::byte* a, const CryptoPP::byte* b) {
for (int i = 0; i < 16; i++) {
x[i] = a[i] ^ b[i];
}
}
void xtsMult(std::span<CryptoPP::byte, 16> encryptedTweak) {
int feedback = 0;
for (int k = 0; k < encryptedTweak.size(); k++) {
const auto tmp = (encryptedTweak[k] >> 7) & 1;
encryptedTweak[k] = ((encryptedTweak[k] << 1) + feedback) & 0xFF;
feedback = tmp;
}
if (feedback != 0) {
encryptedTweak[0] ^= 0x87;
}
}
};

View File

@ -1,305 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <cryptopp/rsa.h>
class FakeKeyset {
public:
// Constructor
static constexpr CryptoPP::byte Exponent1[] = {
0x6D, 0x48, 0xE0, 0x54, 0x40, 0x25, 0xC8, 0x41, 0x29, 0x52, 0x42, 0x27, 0xEB, 0xD2, 0xC7,
0xAB, 0x6B, 0x9C, 0x27, 0x0A, 0xB4, 0x1F, 0x94, 0x4E, 0xFA, 0x42, 0x1D, 0xB7, 0xBC, 0xB9,
0xAE, 0xBC, 0x04, 0x6F, 0x75, 0x8F, 0x10, 0x5F, 0x89, 0xAC, 0xAB, 0x9C, 0xD2, 0xFA, 0xE6,
0xA4, 0x13, 0x83, 0x68, 0xD4, 0x56, 0x38, 0xFE, 0xE5, 0x2B, 0x78, 0x44, 0x9C, 0x34, 0xE6,
0x5A, 0xA0, 0xBE, 0x05, 0x70, 0xAD, 0x15, 0xC3, 0x2D, 0x31, 0xAC, 0x97, 0x5D, 0x88, 0xFC,
0xC1, 0x62, 0x3D, 0xE2, 0xED, 0x11, 0xDB, 0xB6, 0x9E, 0xFC, 0x5A, 0x5A, 0x03, 0xF6, 0xCF,
0x08, 0xD4, 0x5D, 0x90, 0xC9, 0x2A, 0xB9, 0x9B, 0xCF, 0xC8, 0x1A, 0x65, 0xF3, 0x5B, 0xE8,
0x7F, 0xCF, 0xA5, 0xA6, 0x4C, 0x5C, 0x2A, 0x12, 0x0F, 0x92, 0xA5, 0xE3, 0xF0, 0x17, 0x1E,
0x9A, 0x97, 0x45, 0x86, 0xFD, 0xDB, 0x54, 0x25};
// exponent2 = d mod (q - 1)
static constexpr CryptoPP::byte Exponent2[] = {
0x2A, 0x51, 0xCE, 0x02, 0x44, 0x28, 0x50, 0xE8, 0x30, 0x20, 0x7C, 0x9C, 0x55, 0xBF, 0x60,
0x39, 0xBC, 0xD1, 0xF0, 0xE7, 0x68, 0xF8, 0x08, 0x5B, 0x61, 0x1F, 0xA7, 0xBF, 0xD0, 0xE8,
0x8B, 0xB5, 0xB1, 0xD5, 0xD9, 0x16, 0xAC, 0x75, 0x0C, 0x6D, 0xF2, 0xE0, 0xB5, 0x97, 0x75,
0xD2, 0x68, 0x16, 0x1F, 0x00, 0x7D, 0x8B, 0x17, 0xE8, 0x78, 0x48, 0x41, 0x71, 0x2B, 0x18,
0x96, 0x80, 0x11, 0xDB, 0x68, 0x39, 0x9C, 0xD6, 0xE0, 0x72, 0x42, 0x86, 0xF0, 0x1B, 0x16,
0x0D, 0x3E, 0x12, 0x94, 0x3D, 0x25, 0xA8, 0xA9, 0x30, 0x9E, 0x54, 0x5A, 0xD6, 0x36, 0x6C,
0xD6, 0x8C, 0x20, 0x62, 0x8F, 0xA1, 0x6B, 0x1F, 0x7C, 0x6D, 0xB2, 0xB1, 0xC1, 0x2E, 0xAD,
0x36, 0x02, 0x9C, 0x3A, 0xCA, 0x2F, 0x09, 0xD2, 0x45, 0x9E, 0xEB, 0xF2, 0xBC, 0x6C, 0xAA,
0x3B, 0x3E, 0x90, 0xBC, 0x38, 0x67, 0x35, 0x4D};
// e
static constexpr CryptoPP::byte PublicExponent[] = {0, 1, 0, 1};
// (InverseQ)(q) = 1 mod p
static constexpr CryptoPP::byte Coefficient[] = {
0x0B, 0x67, 0x1C, 0x0D, 0x6C, 0x57, 0xD3, 0xE7, 0x05, 0x65, 0x94, 0x31, 0x56, 0x55, 0xFD,
0x28, 0x08, 0xFA, 0x05, 0x8A, 0xCC, 0x55, 0x39, 0x61, 0x97, 0x63, 0xA0, 0x16, 0x27, 0x3D,
0xED, 0xC1, 0x16, 0x40, 0x2A, 0x12, 0xEA, 0x6F, 0xD9, 0xD8, 0x58, 0x56, 0xA8, 0x56, 0x8B,
0x0D, 0x38, 0x5E, 0x1E, 0x80, 0x3B, 0x5F, 0x40, 0x80, 0x6F, 0x62, 0x4F, 0x28, 0xA2, 0x69,
0xF3, 0xD3, 0xF7, 0xFD, 0xB2, 0xC3, 0x52, 0x43, 0x20, 0x92, 0x9D, 0x97, 0x8D, 0xA0, 0x15,
0x07, 0x15, 0x6E, 0xA4, 0x0D, 0x56, 0xD3, 0x37, 0x1A, 0xC4, 0x9E, 0xDF, 0x02, 0x49, 0xB8,
0x0A, 0x84, 0x62, 0xF5, 0xFA, 0xB9, 0x3F, 0xA4, 0x09, 0x76, 0xCC, 0xAA, 0xB9, 0x9B, 0xA6,
0x4F, 0xC1, 0x6A, 0x64, 0xCE, 0xD8, 0x77, 0xAB, 0x4B, 0xF9, 0xA0, 0xAE, 0xDA, 0xF1, 0x67,
0x87, 0x7C, 0x98, 0x5C, 0x7E, 0xB8, 0x73, 0xF5};
// n = p * q
static constexpr CryptoPP::byte Modulus[] = {
0xC6, 0xCF, 0x71, 0xE7, 0xE5, 0x9A, 0xF0, 0xD1, 0x2A, 0x2C, 0x45, 0x8B, 0xF9, 0x2A, 0x0E,
0xC1, 0x43, 0x05, 0x8B, 0xC3, 0x71, 0x17, 0x80, 0x1D, 0xCD, 0x49, 0x7D, 0xDE, 0x35, 0x9D,
0x25, 0x9B, 0xA0, 0xD7, 0xA0, 0xF2, 0x7D, 0x6C, 0x08, 0x7E, 0xAA, 0x55, 0x02, 0x68, 0x2B,
0x23, 0xC6, 0x44, 0xB8, 0x44, 0x18, 0xEB, 0x56, 0xCF, 0x16, 0xA2, 0x48, 0x03, 0xC9, 0xE7,
0x4F, 0x87, 0xEB, 0x3D, 0x30, 0xC3, 0x15, 0x88, 0xBF, 0x20, 0xE7, 0x9D, 0xFF, 0x77, 0x0C,
0xDE, 0x1D, 0x24, 0x1E, 0x63, 0xA9, 0x4F, 0x8A, 0xBF, 0x5B, 0xBE, 0x60, 0x19, 0x68, 0x33,
0x3B, 0xFC, 0xED, 0x9F, 0x47, 0x4E, 0x5F, 0xF8, 0xEA, 0xCB, 0x3D, 0x00, 0xBD, 0x67, 0x01,
0xF9, 0x2C, 0x6D, 0xC6, 0xAC, 0x13, 0x64, 0xE7, 0x67, 0x14, 0xF3, 0xDC, 0x52, 0x69, 0x6A,
0xB9, 0x83, 0x2C, 0x42, 0x30, 0x13, 0x1B, 0xB2, 0xD8, 0xA5, 0x02, 0x0D, 0x79, 0xED, 0x96,
0xB1, 0x0D, 0xF8, 0xCC, 0x0C, 0xDF, 0x81, 0x95, 0x4F, 0x03, 0x58, 0x09, 0x57, 0x0E, 0x80,
0x69, 0x2E, 0xFE, 0xFF, 0x52, 0x77, 0xEA, 0x75, 0x28, 0xA8, 0xFB, 0xC9, 0xBE, 0xBF, 0x9F,
0xBB, 0xB7, 0x79, 0x8E, 0x18, 0x05, 0xE1, 0x80, 0xBD, 0x50, 0x34, 0x94, 0x81, 0xD3, 0x53,
0xC2, 0x69, 0xA2, 0xD2, 0x4C, 0xCF, 0x6C, 0xF4, 0x57, 0x2C, 0x10, 0x4A, 0x3F, 0xFB, 0x22,
0xFD, 0x8B, 0x97, 0xE2, 0xC9, 0x5B, 0xA6, 0x2B, 0xCD, 0xD6, 0x1B, 0x6B, 0xDB, 0x68, 0x7F,
0x4B, 0xC2, 0xA0, 0x50, 0x34, 0xC0, 0x05, 0xE5, 0x8D, 0xEF, 0x24, 0x67, 0xFF, 0x93, 0x40,
0xCF, 0x2D, 0x62, 0xA2, 0xA0, 0x50, 0xB1, 0xF1, 0x3A, 0xA8, 0x3D, 0xFD, 0x80, 0xD1, 0xF9,
0xB8, 0x05, 0x22, 0xAF, 0xC8, 0x35, 0x45, 0x90, 0x58, 0x8E, 0xE3, 0x3A, 0x7C, 0xBD, 0x3E,
0x27};
// p
static constexpr CryptoPP::byte Prime1[] = {
0xFE, 0xF6, 0xBF, 0x1D, 0x69, 0xAB, 0x16, 0x25, 0x08, 0x47, 0x55, 0x6B, 0x86, 0xE4, 0x35,
0x88, 0x72, 0x2A, 0xB1, 0x3D, 0xF8, 0xB6, 0x44, 0xCA, 0xB3, 0xAB, 0x19, 0xD1, 0x04, 0x24,
0x28, 0x0A, 0x74, 0x55, 0xB8, 0x15, 0x45, 0x09, 0xCC, 0x13, 0x1C, 0xF2, 0xBA, 0x37, 0xA9,
0x03, 0x90, 0x8F, 0x02, 0x10, 0xFF, 0x25, 0x79, 0x86, 0xCC, 0x18, 0x50, 0x9A, 0x10, 0x5F,
0x5B, 0x4C, 0x1C, 0x4E, 0xB0, 0xA7, 0xE3, 0x59, 0xB1, 0x2D, 0xA0, 0xC6, 0xB0, 0x20, 0x2C,
0x21, 0x33, 0x12, 0xB3, 0xAF, 0x72, 0x34, 0x83, 0xCD, 0x52, 0x2F, 0xAF, 0x0F, 0x20, 0x5A,
0x1B, 0xC0, 0xE2, 0xA3, 0x76, 0x34, 0x0F, 0xD7, 0xFC, 0xC1, 0x41, 0xC9, 0xF9, 0x79, 0x40,
0x17, 0x42, 0x21, 0x3E, 0x9D, 0xFD, 0xC7, 0xC1, 0x50, 0xDE, 0x44, 0x5A, 0xC9, 0x31, 0x89,
0x6A, 0x78, 0x05, 0xBE, 0x65, 0xB4, 0xE8, 0x2D};
// q
static constexpr CryptoPP::byte Prime2[] = {
0xC7, 0x9E, 0x47, 0x58, 0x00, 0x7D, 0x62, 0x82, 0xB0, 0xD2, 0x22, 0x81, 0xD4, 0xA8, 0x97,
0x1B, 0x79, 0x0C, 0x3A, 0xB0, 0xD7, 0xC9, 0x30, 0xE3, 0xC3, 0x53, 0x8E, 0x57, 0xEF, 0xF0,
0x9B, 0x9F, 0xB3, 0x90, 0x52, 0xC6, 0x94, 0x22, 0x36, 0xAA, 0xE6, 0x4A, 0x5F, 0x72, 0x1D,
0x70, 0xE8, 0x76, 0x58, 0xC8, 0xB2, 0x91, 0xCE, 0x9C, 0xC3, 0xE9, 0x09, 0x7F, 0x2E, 0x47,
0x97, 0xCC, 0x90, 0x39, 0x15, 0x35, 0x31, 0xDE, 0x1F, 0x0C, 0x8C, 0x0D, 0xC1, 0xC2, 0x92,
0xBE, 0x97, 0xBF, 0x2F, 0x91, 0xA1, 0x8C, 0x7D, 0x50, 0xA8, 0x21, 0x2F, 0xD7, 0xA2, 0x9A,
0x7E, 0xB5, 0xA7, 0x2A, 0x90, 0x02, 0xD9, 0xF3, 0x3D, 0xD1, 0xEB, 0xB8, 0xE0, 0x5A, 0x79,
0x9E, 0x7D, 0x8D, 0xCA, 0x18, 0x6D, 0xBD, 0x9E, 0xA1, 0x80, 0x28, 0x6B, 0x2A, 0xFE, 0x51,
0x24, 0x9B, 0x6F, 0x4D, 0x84, 0x77, 0x80, 0x23};
static constexpr CryptoPP::byte PrivateExponent[] = {
0x7F, 0x76, 0xCD, 0x0E, 0xE2, 0xD4, 0xDE, 0x05, 0x1C, 0xC6, 0xD9, 0xA8, 0x0E, 0x8D, 0xFA,
0x7B, 0xCA, 0x1E, 0xAA, 0x27, 0x1A, 0x40, 0xF8, 0xF1, 0x22, 0x87, 0x35, 0xDD, 0xDB, 0xFD,
0xEE, 0xF8, 0xC2, 0xBC, 0xBD, 0x01, 0xFB, 0x8B, 0xE2, 0x3E, 0x63, 0xB2, 0xB1, 0x22, 0x5C,
0x56, 0x49, 0x6E, 0x11, 0xBE, 0x07, 0x44, 0x0B, 0x9A, 0x26, 0x66, 0xD1, 0x49, 0x2C, 0x8F,
0xD3, 0x1B, 0xCF, 0xA4, 0xA1, 0xB8, 0xD1, 0xFB, 0xA4, 0x9E, 0xD2, 0x21, 0x28, 0x83, 0x09,
0x8A, 0xF6, 0xA0, 0x0B, 0xA3, 0xD6, 0x0F, 0x9B, 0x63, 0x68, 0xCC, 0xBC, 0x0C, 0x4E, 0x14,
0x5B, 0x27, 0xA4, 0xA9, 0xF4, 0x2B, 0xB9, 0xB8, 0x7B, 0xC0, 0xE6, 0x51, 0xAD, 0x1D, 0x77,
0xD4, 0x6B, 0xB9, 0xCE, 0x20, 0xD1, 0x26, 0x66, 0x7E, 0x5E, 0x9E, 0xA2, 0xE9, 0x6B, 0x90,
0xF3, 0x73, 0xB8, 0x52, 0x8F, 0x44, 0x11, 0x03, 0x0C, 0x13, 0x97, 0x39, 0x3D, 0x13, 0x22,
0x58, 0xD5, 0x43, 0x82, 0x49, 0xDA, 0x6E, 0x7C, 0xA1, 0xC5, 0x8C, 0xA5, 0xB0, 0x09, 0xE0,
0xCE, 0x3D, 0xDF, 0xF4, 0x9D, 0x3C, 0x97, 0x15, 0xE2, 0x6A, 0xC7, 0x2B, 0x3C, 0x50, 0x93,
0x23, 0xDB, 0xBA, 0x4A, 0x22, 0x66, 0x44, 0xAC, 0x78, 0xBB, 0x0E, 0x1A, 0x27, 0x43, 0xB5,
0x71, 0x67, 0xAF, 0xF4, 0xAB, 0x48, 0x46, 0x93, 0x73, 0xD0, 0x42, 0xAB, 0x93, 0x63, 0xE5,
0x6C, 0x9A, 0xDE, 0x50, 0x24, 0xC0, 0x23, 0x7D, 0x99, 0x79, 0x3F, 0x22, 0x07, 0xE0, 0xC1,
0x48, 0x56, 0x1B, 0xDF, 0x83, 0x09, 0x12, 0xB4, 0x2D, 0x45, 0x6B, 0xC9, 0xC0, 0x68, 0x85,
0x99, 0x90, 0x79, 0x96, 0x1A, 0xD7, 0xF5, 0x4D, 0x1F, 0x37, 0x83, 0x40, 0x4A, 0xEC, 0x39,
0x37, 0xA6, 0x80, 0x92, 0x7D, 0xC5, 0x80, 0xC7, 0xD6, 0x6F, 0xFE, 0x8A, 0x79, 0x89, 0xC6,
0xB1};
};
class DebugRifKeyset {
public:
// std::uint8_t* PrivateExponent;
static constexpr CryptoPP::byte Exponent1[] = {
0xCD, 0x9A, 0x61, 0xB0, 0xB8, 0xD5, 0xB4, 0xE4, 0xE4, 0xF6, 0xAB, 0xF7, 0x27, 0xB7, 0x56,
0x59, 0x6B, 0xB9, 0x11, 0xE7, 0xF4, 0x83, 0xAF, 0xB9, 0x73, 0x99, 0x7F, 0x49, 0xA2, 0x9C,
0xF0, 0xB5, 0x6D, 0x37, 0x82, 0x14, 0x15, 0xF1, 0x04, 0x8A, 0xD4, 0x8E, 0xEB, 0x2E, 0x1F,
0xE2, 0x81, 0xA9, 0x62, 0x6E, 0xB1, 0x68, 0x75, 0x62, 0xF3, 0x0F, 0xFE, 0xD4, 0x91, 0x87,
0x98, 0x78, 0xBF, 0x26, 0xB5, 0x07, 0x58, 0xD0, 0xEE, 0x3F, 0x21, 0xE8, 0xC8, 0x0F, 0x5F,
0xFA, 0x1C, 0x64, 0x74, 0x49, 0x52, 0xEB, 0xE7, 0xEE, 0xDE, 0xBA, 0x23, 0x26, 0x4A, 0xF6,
0x9C, 0x1A, 0x09, 0x3F, 0xB9, 0x0B, 0x36, 0x26, 0x1A, 0xBE, 0xA9, 0x76, 0xE6, 0xF2, 0x69,
0xDE, 0xFF, 0xAF, 0xCC, 0x0C, 0x9A, 0x66, 0x03, 0x86, 0x0A, 0x1F, 0x49, 0xA4, 0x10, 0xB6,
0xBC, 0xC3, 0x7C, 0x88, 0xE8, 0xCE, 0x4B, 0xD9};
// exponent2 = d mod (q - 1)
static constexpr CryptoPP::byte Exponent2[] = {
0xB3, 0x73, 0xA3, 0x59, 0xE6, 0x97, 0xC0, 0xAB, 0x3B, 0x68, 0xFC, 0x39, 0xAC, 0xDB, 0x44,
0xB1, 0xB4, 0x9E, 0x35, 0x4D, 0xBE, 0xC5, 0x36, 0x69, 0x6C, 0x3D, 0xC5, 0xFC, 0xFE, 0x4B,
0x2F, 0xDC, 0x86, 0x80, 0x46, 0x96, 0x40, 0x1A, 0x0D, 0x6E, 0xFA, 0x8C, 0xE0, 0x47, 0x91,
0xAC, 0xAD, 0x95, 0x2B, 0x8E, 0x1F, 0xF2, 0x0A, 0x45, 0xF8, 0x29, 0x95, 0x70, 0xC6, 0x88,
0x5F, 0x71, 0x03, 0x99, 0x79, 0xBC, 0x84, 0x71, 0xBD, 0xE8, 0x84, 0x8C, 0x0E, 0xD4, 0x7B,
0x30, 0x74, 0x57, 0x1A, 0x95, 0xE7, 0x90, 0x19, 0x8D, 0xAD, 0x8B, 0x4C, 0x4E, 0xC3, 0xE7,
0x6B, 0x23, 0x86, 0x01, 0xEE, 0x9B, 0xE0, 0x2F, 0x15, 0xA2, 0x2C, 0x4C, 0x39, 0xD3, 0xDF,
0x9C, 0x39, 0x01, 0xF1, 0x8C, 0x44, 0x4A, 0x15, 0x44, 0xDC, 0x51, 0xF7, 0x22, 0xD7, 0x7F,
0x41, 0x7F, 0x68, 0xFA, 0xEE, 0x56, 0xE8, 0x05};
// e
static constexpr CryptoPP::byte PublicExponent[] = {0x00, 0x01, 0x00, 0x01};
// (InverseQ)(q) = 1 mod p
static constexpr CryptoPP::byte Coefficient[] = {
0xC0, 0x32, 0x43, 0xD3, 0x8C, 0x3D, 0xB4, 0xD2, 0x48, 0x8C, 0x42, 0x41, 0x24, 0x94, 0x6C,
0x80, 0xC9, 0xC1, 0x79, 0x36, 0x7F, 0xAC, 0xC3, 0xFF, 0x6A, 0x25, 0xEB, 0x2C, 0xFB, 0xD4,
0x2B, 0xA0, 0xEB, 0xFE, 0x25, 0xE9, 0xC6, 0x77, 0xCE, 0xFE, 0x2D, 0x23, 0xFE, 0xD0, 0xF4,
0x0F, 0xD9, 0x7E, 0xD5, 0xA5, 0x7D, 0x1F, 0xC0, 0xE8, 0xE8, 0xEC, 0x80, 0x5B, 0xC7, 0xFD,
0xE2, 0xBD, 0x94, 0xA6, 0x2B, 0xDD, 0x6A, 0x60, 0x45, 0x54, 0xAB, 0xCA, 0x42, 0x9C, 0x6A,
0x6C, 0xBF, 0x3C, 0x84, 0xF9, 0xA5, 0x0E, 0x63, 0x0C, 0x51, 0x58, 0x62, 0x6D, 0x5A, 0xB7,
0x3C, 0x3F, 0x49, 0x1A, 0xD0, 0x93, 0xB8, 0x4F, 0x1A, 0x6C, 0x5F, 0xC5, 0xE5, 0xA9, 0x75,
0xD4, 0x86, 0x9E, 0xDF, 0x87, 0x0F, 0x27, 0xB0, 0x26, 0x78, 0x4E, 0xFB, 0xC1, 0x8A, 0x4A,
0x24, 0x3F, 0x7F, 0x8F, 0x9A, 0x12, 0x51, 0xCB};
// n = p * q
static constexpr CryptoPP::byte Modulus[] = {
0xC2, 0xD2, 0x44, 0xBC, 0xDD, 0x84, 0x3F, 0xD9, 0xC5, 0x22, 0xAF, 0xF7, 0xFC, 0x88, 0x8A,
0x33, 0x80, 0xED, 0x8E, 0xE2, 0xCC, 0x81, 0xF7, 0xEC, 0xF8, 0x1C, 0x79, 0xBF, 0x02, 0xBB,
0x12, 0x8E, 0x61, 0x68, 0x29, 0x1B, 0x15, 0xB6, 0x5E, 0xC6, 0xF8, 0xBF, 0x5A, 0xE0, 0x3B,
0x6A, 0x6C, 0xD9, 0xD6, 0xF5, 0x75, 0xAB, 0xA0, 0x6F, 0x34, 0x81, 0x34, 0x9A, 0x5B, 0xAD,
0xED, 0x31, 0xE3, 0xC6, 0xEA, 0x1A, 0xD1, 0x13, 0x22, 0xBB, 0xB3, 0xDA, 0xB3, 0xB2, 0x53,
0xBD, 0x45, 0x79, 0x87, 0xAD, 0x0A, 0x01, 0x72, 0x18, 0x10, 0x29, 0x49, 0xF4, 0x41, 0x7F,
0xD6, 0x47, 0x0C, 0x72, 0x92, 0x9E, 0xE9, 0xBB, 0x95, 0xA9, 0x5D, 0x79, 0xEB, 0xE4, 0x30,
0x76, 0x90, 0x45, 0x4B, 0x9D, 0x9C, 0xCF, 0x92, 0x03, 0x60, 0x8C, 0x4B, 0x6C, 0xB3, 0x7A,
0x3A, 0x05, 0x39, 0xA0, 0x66, 0xA9, 0x35, 0xCF, 0xB9, 0xFA, 0xAD, 0x9C, 0xAB, 0xEB, 0xE4,
0x6A, 0x8C, 0xE9, 0x3B, 0xCC, 0x72, 0x12, 0x62, 0x63, 0xBD, 0x80, 0xC4, 0xEE, 0x37, 0x2B,
0x32, 0x03, 0xA3, 0x09, 0xF7, 0xA0, 0x61, 0x57, 0xAD, 0x0D, 0xCF, 0x15, 0x98, 0x9E, 0x4E,
0x49, 0xF8, 0xB5, 0xA3, 0x5C, 0x27, 0xEE, 0x45, 0x04, 0xEA, 0xE4, 0x4B, 0xBC, 0x8F, 0x87,
0xED, 0x19, 0x1E, 0x46, 0x75, 0x63, 0xC4, 0x5B, 0xD5, 0xBC, 0x09, 0x2F, 0x02, 0x73, 0x19,
0x3C, 0x58, 0x55, 0x49, 0x66, 0x4C, 0x11, 0xEC, 0x0F, 0x09, 0xFA, 0xA5, 0x56, 0x0A, 0x5A,
0x63, 0x56, 0xAD, 0xA0, 0x0D, 0x86, 0x08, 0xC1, 0xE6, 0xB6, 0x13, 0x22, 0x49, 0x2F, 0x7C,
0xDB, 0x4C, 0x56, 0x97, 0x0E, 0xC2, 0xD9, 0x2E, 0x87, 0xBC, 0x0E, 0x67, 0xC0, 0x1B, 0x58,
0xBC, 0x64, 0x2B, 0xC2, 0x6E, 0xE2, 0x93, 0x2E, 0xB5, 0x6B, 0x70, 0xA4, 0x42, 0x9F, 0x64,
0xC1};
// p
static constexpr CryptoPP::byte Prime1[] = {
0xE5, 0x62, 0xE1, 0x7F, 0x9F, 0x86, 0x08, 0xE2, 0x61, 0xD3, 0xD0, 0x42, 0xE2, 0xC4, 0xB6,
0xA8, 0x51, 0x09, 0x19, 0x14, 0xA4, 0x3A, 0x11, 0x4C, 0x33, 0xA5, 0x9C, 0x01, 0x5E, 0x34,
0xB6, 0x3F, 0x02, 0x1A, 0xCA, 0x47, 0xF1, 0x4F, 0x3B, 0x35, 0x2A, 0x07, 0x20, 0xEC, 0xD8,
0xC1, 0x15, 0xD9, 0xCA, 0x03, 0x4F, 0xB8, 0xE8, 0x09, 0x73, 0x3F, 0x85, 0xB7, 0x41, 0xD5,
0x51, 0x3E, 0x7B, 0xE3, 0x53, 0x2B, 0x48, 0x8B, 0x8E, 0xCB, 0xBA, 0xF7, 0xE0, 0x60, 0xF5,
0x35, 0x0E, 0x6F, 0xB0, 0xD9, 0x2A, 0x99, 0xD0, 0xFF, 0x60, 0x14, 0xED, 0x40, 0xEA, 0xF8,
0xD7, 0x0B, 0xC3, 0x8D, 0x8C, 0xE8, 0x81, 0xB3, 0x75, 0x93, 0x15, 0xB3, 0x7D, 0xF6, 0x39,
0x60, 0x1A, 0x00, 0xE7, 0xC3, 0x27, 0xAD, 0xA4, 0x33, 0xD5, 0x3E, 0xA4, 0x35, 0x48, 0x6F,
0x22, 0xEF, 0x5D, 0xDD, 0x7D, 0x7B, 0x61, 0x05};
// q
static constexpr CryptoPP::byte Prime2[] = {
0xD9, 0x6C, 0xC2, 0x0C, 0xF7, 0xAE, 0xD1, 0xF3, 0x3B, 0x3B, 0x49, 0x1E, 0x9F, 0x12, 0x9C,
0xA1, 0x78, 0x1F, 0x35, 0x1D, 0x98, 0x26, 0x13, 0x71, 0xF9, 0x09, 0xFD, 0xF0, 0xAD, 0x38,
0x55, 0xB7, 0xEE, 0x61, 0x04, 0x72, 0x51, 0x87, 0x2E, 0x05, 0x84, 0xB1, 0x1D, 0x0C, 0x0D,
0xDB, 0xD4, 0x25, 0x3E, 0x26, 0xED, 0xEA, 0xB8, 0xF7, 0x49, 0xFE, 0xA2, 0x94, 0xE6, 0xF2,
0x08, 0x92, 0xA7, 0x85, 0xF5, 0x30, 0xB9, 0x84, 0x22, 0xBF, 0xCA, 0xF0, 0x5F, 0xCB, 0x31,
0x20, 0x34, 0x49, 0x16, 0x76, 0x34, 0xCC, 0x7A, 0xCB, 0x96, 0xFE, 0x78, 0x7A, 0x41, 0xFE,
0x9A, 0xA2, 0x23, 0xF7, 0x68, 0x80, 0xD6, 0xCE, 0x4A, 0x78, 0xA5, 0xB7, 0x05, 0x77, 0x81,
0x1F, 0xDE, 0x5E, 0xA8, 0x6E, 0x3E, 0x87, 0xEC, 0x44, 0xD2, 0x69, 0xC6, 0x54, 0x91, 0x6B,
0x5E, 0x13, 0x8A, 0x03, 0x87, 0x05, 0x31, 0x8D};
static constexpr CryptoPP::byte PrivateExponent[] = {
0x01, 0x61, 0xAD, 0xD8, 0x9C, 0x06, 0x89, 0xD0, 0x60, 0xC8, 0x41, 0xF0, 0xB3, 0x83, 0x01,
0x5D, 0xE3, 0xA2, 0x6B, 0xA2, 0xBA, 0x9A, 0x0A, 0x58, 0xCD, 0x1A, 0xA0, 0x97, 0x64, 0xEC,
0xD0, 0x31, 0x1F, 0xCA, 0x36, 0x0E, 0x69, 0xDD, 0x40, 0xF7, 0x4E, 0xC0, 0xC6, 0xA3, 0x73,
0xF0, 0x69, 0x84, 0xB2, 0xF4, 0x4B, 0x29, 0x14, 0x2A, 0x6D, 0xB8, 0x23, 0xD8, 0x1B, 0x61,
0xD4, 0x9E, 0x87, 0xB3, 0xBB, 0xA9, 0xC4, 0x85, 0x4A, 0xF8, 0x03, 0x4A, 0xBF, 0xFE, 0xF9,
0xFE, 0x8B, 0xDD, 0x54, 0x83, 0xBA, 0xE0, 0x2F, 0x3F, 0xB1, 0xEF, 0xA5, 0x05, 0x5D, 0x28,
0x8B, 0xAB, 0xB5, 0xD0, 0x23, 0x2F, 0x8A, 0xCF, 0x48, 0x7C, 0xAA, 0xBB, 0xC8, 0x5B, 0x36,
0x27, 0xC5, 0x16, 0xA4, 0xB6, 0x61, 0xAC, 0x0C, 0x28, 0x47, 0x79, 0x3F, 0x38, 0xAE, 0x5E,
0x25, 0xC6, 0xAF, 0x35, 0xAE, 0xBC, 0xB0, 0xF3, 0xBC, 0xBD, 0xFD, 0xA4, 0x87, 0x0D, 0x14,
0x3D, 0x90, 0xE4, 0xDE, 0x5D, 0x1D, 0x46, 0x81, 0xF1, 0x28, 0x6D, 0x2F, 0x2C, 0x5E, 0x97,
0x2D, 0x89, 0x2A, 0x51, 0x72, 0x3C, 0x20, 0x02, 0x59, 0xB1, 0x98, 0x93, 0x05, 0x1E, 0x3F,
0xA1, 0x8A, 0x69, 0x30, 0x0E, 0x70, 0x84, 0x8B, 0xAE, 0x97, 0xA1, 0x08, 0x95, 0x63, 0x4C,
0xC7, 0xE8, 0x5D, 0x59, 0xCA, 0x78, 0x2A, 0x23, 0x87, 0xAC, 0x6F, 0x04, 0x33, 0xB1, 0x61,
0xB9, 0xF0, 0x95, 0xDA, 0x33, 0xCC, 0xE0, 0x4C, 0x82, 0x68, 0x82, 0x14, 0x51, 0xBE, 0x49,
0x1C, 0x58, 0xA2, 0x8B, 0x05, 0x4E, 0x98, 0x37, 0xEB, 0x94, 0x0B, 0x01, 0x22, 0xDC, 0xB3,
0x19, 0xCA, 0x77, 0xA6, 0x6E, 0x97, 0xFF, 0x8A, 0x53, 0x5A, 0xC5, 0x24, 0xE4, 0xAF, 0x6E,
0xA8, 0x2B, 0x53, 0xA4, 0xBE, 0x96, 0xA5, 0x7B, 0xCE, 0x22, 0x56, 0xA3, 0xF1, 0xCF, 0x14,
0xA5};
};
class PkgDerivedKey3Keyset {
public:
// std::uint8_t* PrivateExponent;
static constexpr CryptoPP::byte Exponent1[] = {
0x52, 0xCC, 0x2D, 0xA0, 0x9C, 0x9E, 0x75, 0xE7, 0x28, 0xEE, 0x3D, 0xDE, 0xE3, 0x45, 0xD1,
0x4F, 0x94, 0x1C, 0xCC, 0xC8, 0x87, 0x29, 0x45, 0x3B, 0x8D, 0x6E, 0xAB, 0x6E, 0x2A, 0xA7,
0xC7, 0x15, 0x43, 0xA3, 0x04, 0x8F, 0x90, 0x5F, 0xEB, 0xF3, 0x38, 0x4A, 0x77, 0xFA, 0x36,
0xB7, 0x15, 0x76, 0xB6, 0x01, 0x1A, 0x8E, 0x25, 0x87, 0x82, 0xF1, 0x55, 0xD8, 0xC6, 0x43,
0x2A, 0xC0, 0xE5, 0x98, 0xC9, 0x32, 0xD1, 0x94, 0x6F, 0xD9, 0x01, 0xBA, 0x06, 0x81, 0xE0,
0x6D, 0x88, 0xF2, 0x24, 0x2A, 0x25, 0x01, 0x64, 0x5C, 0xBF, 0xF2, 0xD9, 0x99, 0x67, 0x3E,
0xF6, 0x72, 0xEE, 0xE4, 0xE2, 0x33, 0x5C, 0xF8, 0x00, 0x40, 0xE3, 0x2A, 0x9A, 0xF4, 0x3D,
0x22, 0x86, 0x44, 0x3C, 0xFB, 0x0A, 0xA5, 0x7C, 0x3F, 0xCC, 0xF5, 0xF1, 0x16, 0xC4, 0xAC,
0x88, 0xB4, 0xDE, 0x62, 0x94, 0x92, 0x6A, 0x13};
// exponent2 = d mod (q - 1)
static constexpr CryptoPP::byte Exponent2[] = {
0x7C, 0x9D, 0xAD, 0x39, 0xE0, 0xD5, 0x60, 0x14, 0x94, 0x48, 0x19, 0x7F, 0x88, 0x95, 0xD5,
0x8B, 0x80, 0xAD, 0x85, 0x8A, 0x4B, 0x77, 0x37, 0x85, 0xD0, 0x77, 0xBB, 0xBF, 0x89, 0x71,
0x4A, 0x72, 0xCB, 0x72, 0x68, 0x38, 0xEC, 0x02, 0xC6, 0x7D, 0xC6, 0x44, 0x06, 0x33, 0x51,
0x1C, 0xC0, 0xFF, 0x95, 0x8F, 0x0D, 0x75, 0xDC, 0x25, 0xBB, 0x0B, 0x73, 0x91, 0xA9, 0x6D,
0x42, 0xD8, 0x03, 0xB7, 0x68, 0xD4, 0x1E, 0x75, 0x62, 0xA3, 0x70, 0x35, 0x79, 0x78, 0x00,
0xC8, 0xF5, 0xEF, 0x15, 0xB9, 0xFC, 0x4E, 0x47, 0x5A, 0xC8, 0x70, 0x70, 0x5B, 0x52, 0x98,
0xC0, 0xC2, 0x58, 0x4A, 0x70, 0x96, 0xCC, 0xB8, 0x10, 0xE1, 0x2F, 0x78, 0x8B, 0x2B, 0xA1,
0x7F, 0xF9, 0xAC, 0xDE, 0xF0, 0xBB, 0x2B, 0xE2, 0x66, 0xE3, 0x22, 0x92, 0x31, 0x21, 0x57,
0x92, 0xC4, 0xB8, 0xF2, 0x3E, 0x76, 0x20, 0x37};
// e
static constexpr CryptoPP::byte PublicExponent[] = {0, 1, 0, 1};
// (InverseQ)(q) = 1 mod p
static constexpr CryptoPP::byte Coefficient[] = {
0x45, 0x97, 0x55, 0xD4, 0x22, 0x08, 0x5E, 0xF3, 0x5C, 0xB4, 0x05, 0x7A, 0xFD, 0xAA, 0x42,
0x42, 0xAD, 0x9A, 0x8C, 0xA0, 0x6C, 0xBB, 0x1D, 0x68, 0x54, 0x54, 0x6E, 0x3E, 0x32, 0xE3,
0x53, 0x73, 0x76, 0xF1, 0x3E, 0x01, 0xEA, 0xD3, 0xCF, 0xEB, 0xEB, 0x23, 0x3E, 0xC0, 0xBE,
0xCE, 0xEC, 0x2C, 0x89, 0x5F, 0xA8, 0x27, 0x3A, 0x4C, 0xB7, 0xE6, 0x74, 0xBC, 0x45, 0x4C,
0x26, 0xC8, 0x25, 0xFF, 0x34, 0x63, 0x25, 0x37, 0xE1, 0x48, 0x10, 0xC1, 0x93, 0xA6, 0xAF,
0xEB, 0xBA, 0xE3, 0xA2, 0xF1, 0x3D, 0xEF, 0x63, 0xD8, 0xF4, 0xFD, 0xD3, 0xEE, 0xE2, 0x5D,
0xE9, 0x33, 0xCC, 0xAD, 0xBA, 0x75, 0x5C, 0x85, 0xAF, 0xCE, 0xA9, 0x3D, 0xD1, 0xA2, 0x17,
0xF3, 0xF6, 0x98, 0xB3, 0x50, 0x8E, 0x5E, 0xF6, 0xEB, 0x02, 0x8E, 0xA1, 0x62, 0xA7, 0xD6,
0x2C, 0xEC, 0x91, 0xFF, 0x15, 0x40, 0xD2, 0xE3};
// n = p * q
static constexpr CryptoPP::byte Modulus[] = {
0xd2, 0x12, 0xfc, 0x33, 0x5f, 0x6d, 0xdb, 0x83, 0x16, 0x09, 0x62, 0x8b, 0x03, 0x56, 0x27,
0x37, 0x82, 0xd4, 0x77, 0x85, 0x35, 0x29, 0x39, 0x2d, 0x52, 0x6b, 0x8c, 0x4c, 0x8c, 0xfb,
0x06, 0xc1, 0x84, 0x5b, 0xe7, 0xd4, 0xf7, 0xbc, 0xd2, 0x4e, 0x62, 0x45, 0xcd, 0x2a, 0xbb,
0xd7, 0x77, 0x76, 0x45, 0x36, 0x55, 0x27, 0x3f, 0xb3, 0xf5, 0xf9, 0x8e, 0xda, 0x4b, 0xef,
0xaa, 0x59, 0xae, 0xb3, 0x9b, 0xea, 0x54, 0x98, 0xd2, 0x06, 0x32, 0x6a, 0x58, 0x31, 0x2a,
0xe0, 0xd4, 0x4f, 0x90, 0xb5, 0x0a, 0x7d, 0xec, 0xf4, 0x3a, 0x9c, 0x52, 0x67, 0x2d, 0x99,
0x31, 0x8e, 0x0c, 0x43, 0xe6, 0x82, 0xfe, 0x07, 0x46, 0xe1, 0x2e, 0x50, 0xd4, 0x1f, 0x2d,
0x2f, 0x7e, 0xd9, 0x08, 0xba, 0x06, 0xb3, 0xbf, 0x2e, 0x20, 0x3f, 0x4e, 0x3f, 0xfe, 0x44,
0xff, 0xaa, 0x50, 0x43, 0x57, 0x91, 0x69, 0x94, 0x49, 0x15, 0x82, 0x82, 0xe4, 0x0f, 0x4c,
0x8d, 0x9d, 0x2c, 0xc9, 0x5b, 0x1d, 0x64, 0xbf, 0x88, 0x8b, 0xd4, 0xc5, 0x94, 0xe7, 0x65,
0x47, 0x84, 0x1e, 0xe5, 0x79, 0x10, 0xfb, 0x98, 0x93, 0x47, 0xb9, 0x7d, 0x85, 0x12, 0xa6,
0x40, 0x98, 0x2c, 0xf7, 0x92, 0xbc, 0x95, 0x19, 0x32, 0xed, 0xe8, 0x90, 0x56, 0x0d, 0x65,
0xc1, 0xaa, 0x78, 0xc6, 0x2e, 0x54, 0xfd, 0x5f, 0x54, 0xa1, 0xf6, 0x7e, 0xe5, 0xe0, 0x5f,
0x61, 0xc1, 0x20, 0xb4, 0xb9, 0xb4, 0x33, 0x08, 0x70, 0xe4, 0xdf, 0x89, 0x56, 0xed, 0x01,
0x29, 0x46, 0x77, 0x5f, 0x8c, 0xb8, 0xa9, 0xf5, 0x1e, 0x2e, 0xb3, 0xb9, 0xbf, 0xe0, 0x09,
0xb7, 0x8d, 0x28, 0xd4, 0xa6, 0xc3, 0xb8, 0x1e, 0x1f, 0x07, 0xeb, 0xb4, 0x12, 0x0b, 0x95,
0xb8, 0x85, 0x30, 0xfd, 0xdc, 0x39, 0x13, 0xd0, 0x7c, 0xdc, 0x8f, 0xed, 0xf9, 0xc9, 0xa3,
0xc1};
// p
static constexpr CryptoPP::byte Prime1[] = {
0xF9, 0x67, 0xAD, 0x99, 0x12, 0x31, 0x0C, 0x56, 0xA2, 0x2E, 0x16, 0x1C, 0x46, 0xB3, 0x4D,
0x5B, 0x43, 0xBE, 0x42, 0xA2, 0xF6, 0x86, 0x96, 0x80, 0x42, 0xC3, 0xC7, 0x3F, 0xC3, 0x42,
0xF5, 0x87, 0x49, 0x33, 0x9F, 0x07, 0x5D, 0x6E, 0x2C, 0x04, 0xFD, 0xE3, 0xE1, 0xB2, 0xAE,
0x0A, 0x0C, 0xF0, 0xC7, 0xA6, 0x1C, 0xA1, 0x63, 0x50, 0xC8, 0x09, 0x9C, 0x51, 0x24, 0x52,
0x6C, 0x5E, 0x5E, 0xBD, 0x1E, 0x27, 0x06, 0xBB, 0xBC, 0x9E, 0x94, 0xE1, 0x35, 0xD4, 0x6D,
0xB3, 0xCB, 0x3C, 0x68, 0xDD, 0x68, 0xB3, 0xFE, 0x6C, 0xCB, 0x8D, 0x82, 0x20, 0x76, 0x23,
0x63, 0xB7, 0xE9, 0x68, 0x10, 0x01, 0x4E, 0xDC, 0xBA, 0x27, 0x5D, 0x01, 0xC1, 0x2D, 0x80,
0x5E, 0x2B, 0xAF, 0x82, 0x6B, 0xD8, 0x84, 0xB6, 0x10, 0x52, 0x86, 0xA7, 0x89, 0x8E, 0xAE,
0x9A, 0xE2, 0x89, 0xC6, 0xF7, 0xD5, 0x87, 0xFB};
// q
static constexpr CryptoPP::byte Prime2[] = {
0xD7, 0xA1, 0x0F, 0x9A, 0x8B, 0xF2, 0xC9, 0x11, 0x95, 0x32, 0x9A, 0x8C, 0xF0, 0xD9, 0x40,
0x47, 0xF5, 0x68, 0xA0, 0x0D, 0xBD, 0xC1, 0xFC, 0x43, 0x2F, 0x65, 0xF9, 0xC3, 0x61, 0x0F,
0x25, 0x77, 0x54, 0xAD, 0xD7, 0x58, 0xAC, 0x84, 0x40, 0x60, 0x8D, 0x3F, 0xF3, 0x65, 0x89,
0x75, 0xB5, 0xC6, 0x2C, 0x51, 0x1A, 0x2F, 0x1F, 0x22, 0xE4, 0x43, 0x11, 0x54, 0xBE, 0xC9,
0xB4, 0xC7, 0xB5, 0x1B, 0x05, 0x0B, 0xBC, 0x56, 0x9A, 0xCD, 0x4A, 0xD9, 0x73, 0x68, 0x5E,
0x5C, 0xFB, 0x92, 0xB7, 0x8B, 0x0D, 0xFF, 0xF5, 0x07, 0xCA, 0xB4, 0xC8, 0x9B, 0x96, 0x3C,
0x07, 0x9E, 0x3E, 0x6B, 0x2A, 0x11, 0xF2, 0x8A, 0xB1, 0x8A, 0xD7, 0x2E, 0x1B, 0xA5, 0x53,
0x24, 0x06, 0xED, 0x50, 0xB8, 0x90, 0x67, 0xB1, 0xE2, 0x41, 0xC6, 0x92, 0x01, 0xEE, 0x10,
0xF0, 0x61, 0xBB, 0xFB, 0xB2, 0x7D, 0x4A, 0x73};
static constexpr CryptoPP::byte PrivateExponent[] = {
0x32, 0xD9, 0x03, 0x90, 0x8F, 0xBD, 0xB0, 0x8F, 0x57, 0x2B, 0x28, 0x5E, 0x0B, 0x8D, 0xB3,
0xEA, 0x5C, 0xD1, 0x7E, 0xA8, 0x90, 0x88, 0x8C, 0xDD, 0x6A, 0x80, 0xBB, 0xB1, 0xDF, 0xC1,
0xF7, 0x0D, 0xAA, 0x32, 0xF0, 0xB7, 0x7C, 0xCB, 0x88, 0x80, 0x0E, 0x8B, 0x64, 0xB0, 0xBE,
0x4C, 0xD6, 0x0E, 0x9B, 0x8C, 0x1E, 0x2A, 0x64, 0xE1, 0xF3, 0x5C, 0xD7, 0x76, 0x01, 0x41,
0x5E, 0x93, 0x5C, 0x94, 0xFE, 0xDD, 0x46, 0x62, 0xC3, 0x1B, 0x5A, 0xE2, 0xA0, 0xBC, 0x2D,
0xEB, 0xC3, 0x98, 0x0A, 0xA7, 0xB7, 0x85, 0x69, 0x70, 0x68, 0x2B, 0x64, 0x4A, 0xB3, 0x1F,
0xCC, 0x7D, 0xDC, 0x7C, 0x26, 0xF4, 0x77, 0xF6, 0x5C, 0xF2, 0xAE, 0x5A, 0x44, 0x2D, 0xD3,
0xAB, 0x16, 0x62, 0x04, 0x19, 0xBA, 0xFB, 0x90, 0xFF, 0xE2, 0x30, 0x50, 0x89, 0x6E, 0xCB,
0x56, 0xB2, 0xEB, 0xC0, 0x91, 0x16, 0x92, 0x5E, 0x30, 0x8E, 0xAE, 0xC7, 0x94, 0x5D, 0xFD,
0x35, 0xE1, 0x20, 0xF8, 0xAD, 0x3E, 0xBC, 0x08, 0xBF, 0xC0, 0x36, 0x74, 0x9F, 0xD5, 0xBB,
0x52, 0x08, 0xFD, 0x06, 0x66, 0xF3, 0x7A, 0xB3, 0x04, 0xF4, 0x75, 0x29, 0x5D, 0xE9, 0x5F,
0xAA, 0x10, 0x30, 0xB2, 0x0F, 0x5A, 0x1A, 0xC1, 0x2A, 0xB3, 0xFE, 0xCB, 0x21, 0xAD, 0x80,
0xEC, 0x8F, 0x20, 0x09, 0x1C, 0xDB, 0xC5, 0x58, 0x94, 0xC2, 0x9C, 0xC6, 0xCE, 0x82, 0x65,
0x3E, 0x57, 0x90, 0xBC, 0xA9, 0x8B, 0x06, 0xB4, 0xF0, 0x72, 0xF6, 0x77, 0xDF, 0x98, 0x64,
0xF1, 0xEC, 0xFE, 0x37, 0x2D, 0xBC, 0xAE, 0x8C, 0x08, 0x81, 0x1F, 0xC3, 0xC9, 0x89, 0x1A,
0xC7, 0x42, 0x82, 0x4B, 0x2E, 0xDC, 0x8E, 0x8D, 0x73, 0xCE, 0xB1, 0xCC, 0x01, 0xD9, 0x08,
0x70, 0x87, 0x3C, 0x44, 0x08, 0xEC, 0x49, 0x8F, 0x81, 0x5A, 0xE2, 0x40, 0xFF, 0x77, 0xFC,
0x0D};
};

View File

@ -158,6 +158,10 @@ public:
float Framerate = 1.0f / 60.0f;
float FrameDeltaTime;
std::pair<u32, u32> game_resolution{};
std::pair<u32, u32> output_resolution{};
bool is_using_fsr{};
void ShowDebugMessage(std::string message) {
if (message.empty()) {
return;

View File

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "SDL3/SDL_log.h"
#include "layer.h"
#include <imgui.h>
@ -21,8 +22,8 @@
extern std::unique_ptr<Vulkan::Presenter> presenter;
using namespace ImGui;
using namespace Core::Devtools;
using L = Core::Devtools::Layer;
using namespace ::Core::Devtools;
using L = ::Core::Devtools::Layer;
static bool show_simple_fps = false;
static bool visibility_toggled = false;
@ -81,8 +82,24 @@ void L::DrawMenuBar() {
ImGui::EndMenu();
}
if (BeginMenu("Display")) {
auto& pp_settings = presenter->GetPPSettingsRef();
if (BeginMenu("Brightness")) {
SliderFloat("Gamma", &presenter->GetGammaRef(), 0.1f, 2.0f);
SliderFloat("Gamma", &pp_settings.gamma, 0.1f, 2.0f);
ImGui::EndMenu();
}
if (BeginMenu("FSR")) {
auto& fsr = presenter->GetFsrSettingsRef();
Checkbox("FSR Enabled", &fsr.enable);
BeginDisabled(!fsr.enable);
{
Checkbox("RCAS", &fsr.use_rcas);
BeginDisabled(!fsr.use_rcas);
{
SliderFloat("RCAS Attenuation", &fsr.rcas_attenuation, 0.0, 3.0);
}
EndDisabled();
}
EndDisabled();
ImGui::EndMenu();
}
ImGui::EndMenu();
@ -101,22 +118,6 @@ void L::DrawMenuBar() {
EndMainMenuBar();
}
if (IsKeyPressed(ImGuiKey_F9, false)) {
if (io.KeyCtrl && io.KeyAlt) {
if (!DebugState.ShouldPauseInSubmit()) {
DebugState.RequestFrameDump(dump_frame_count);
}
}
if (!io.KeyCtrl && !io.KeyAlt) {
if (isSystemPaused) {
DebugState.ResumeGuestThreads();
} else {
DebugState.PauseGuestThreads();
}
}
}
if (open_popup_options) {
OpenPopup("GPU Tools Options");
just_opened_options = true;
@ -365,6 +366,32 @@ void L::Draw() {
visibility_toggled = true;
}
if (IsKeyPressed(ImGuiKey_F9, false)) {
if (io.KeyCtrl && io.KeyAlt) {
if (!DebugState.ShouldPauseInSubmit()) {
DebugState.RequestFrameDump(dump_frame_count);
}
} else {
if (DebugState.IsGuestThreadsPaused()) {
DebugState.ResumeGuestThreads();
SDL_Log("Game resumed from Keyboard");
show_pause_status = false;
} else {
DebugState.PauseGuestThreads();
SDL_Log("Game paused from Keyboard");
show_pause_status = true;
}
visibility_toggled = true;
}
}
if (show_pause_status) {
ImVec2 pos = ImVec2(10, 10);
ImU32 color = IM_COL32(255, 255, 255, 255);
ImGui::GetForegroundDrawList()->AddText(pos, color, "Game Paused Press F9 to Resume");
}
if (show_simple_fps) {
if (Begin("Video Info", nullptr,
ImGuiWindowFlags_NoNav | ImGuiWindowFlags_NoDecoration |

View File

@ -19,6 +19,7 @@ public:
static void SetupSettings();
void Draw() override;
bool show_pause_status = false;
};
} // namespace Core::Devtools

View File

@ -74,7 +74,7 @@ void FrameGraph::Draw() {
if (!is_open) {
return;
}
SetNextWindowSize({340.0, 185.0f}, ImGuiCond_FirstUseEver);
SetNextWindowSize({308.0, 270.0f}, ImGuiCond_FirstUseEver);
if (Begin("Video debug info", &is_open)) {
const auto& ctx = *GImGui;
const auto& io = ctx.IO;
@ -88,13 +88,20 @@ void FrameGraph::Draw() {
frameRate = 1000.0f / deltaTime;
}
SeparatorText("Frame graph");
DrawFrameGraph();
SeparatorText("Renderer info");
Text("Frame time: %.3f ms (%.1f FPS)", deltaTime, frameRate);
Text("Presenter time: %.3f ms (%.1f FPS)", io.DeltaTime * 1000.0f, 1.0f / io.DeltaTime);
Text("Flip frame: %d Gnm submit frame: %d", DebugState.flip_frame_count.load(),
DebugState.gnm_frame_count.load());
SeparatorText("Frame graph");
DrawFrameGraph();
Text("Game Res: %dx%d", DebugState.game_resolution.first,
DebugState.game_resolution.second);
Text("Output Res: %dx%d", DebugState.output_resolution.first,
DebugState.output_resolution.second);
Text("FSR: %s", DebugState.is_using_fsr ? "on" : "off");
}
End();
}

View File

@ -1,473 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <zlib.h>
#include "common/io_file.h"
#include "common/logging/formatter.h"
#include "core/file_format/pkg.h"
#include "core/file_format/pkg_type.h"
static void DecompressPFSC(std::span<char> compressed_data, std::span<char> decompressed_data) {
z_stream decompressStream;
decompressStream.zalloc = Z_NULL;
decompressStream.zfree = Z_NULL;
decompressStream.opaque = Z_NULL;
if (inflateInit(&decompressStream) != Z_OK) {
// std::cerr << "Error initializing zlib for deflation." << std::endl;
}
decompressStream.avail_in = compressed_data.size();
decompressStream.next_in = reinterpret_cast<unsigned char*>(compressed_data.data());
decompressStream.avail_out = decompressed_data.size();
decompressStream.next_out = reinterpret_cast<unsigned char*>(decompressed_data.data());
if (inflate(&decompressStream, Z_FINISH)) {
}
if (inflateEnd(&decompressStream) != Z_OK) {
// std::cerr << "Error ending zlib inflate" << std::endl;
}
}
u32 GetPFSCOffset(std::span<const u8> pfs_image) {
static constexpr u32 PfscMagic = 0x43534650;
u32 value;
for (u32 i = 0x20000; i < pfs_image.size(); i += 0x10000) {
std::memcpy(&value, &pfs_image[i], sizeof(u32));
if (value == PfscMagic)
return i;
}
return -1;
}
PKG::PKG() = default;
PKG::~PKG() = default;
bool PKG::Open(const std::filesystem::path& filepath, std::string& failreason) {
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
if (!file.IsOpen()) {
return false;
}
pkgSize = file.GetSize();
file.Read(pkgheader);
if (pkgheader.magic != 0x7F434E54)
return false;
for (const auto& flag : flagNames) {
if (isFlagSet(pkgheader.pkg_content_flags, flag.first)) {
if (!pkgFlags.empty())
pkgFlags += (", ");
pkgFlags += (flag.second);
}
}
// Find title id it is part of pkg_content_id starting at offset 0x40
file.Seek(0x47); // skip first 7 characters of content_id
file.Read(pkgTitleID);
u32 offset = pkgheader.pkg_table_entry_offset;
u32 n_files = pkgheader.pkg_table_entry_count;
if (!file.Seek(offset)) {
failreason = "Failed to seek to PKG table entry offset";
return false;
}
for (int i = 0; i < n_files; i++) {
PKGEntry entry{};
file.Read(entry.id);
file.Read(entry.filename_offset);
file.Read(entry.flags1);
file.Read(entry.flags2);
file.Read(entry.offset);
file.Read(entry.size);
file.Seek(8, Common::FS::SeekOrigin::CurrentPosition);
// Try to figure out the name
const auto name = GetEntryNameByType(entry.id);
if (name == "param.sfo") {
sfo.clear();
if (!file.Seek(entry.offset)) {
failreason = "Failed to seek to param.sfo offset";
return false;
}
sfo.resize(entry.size);
file.ReadRaw<u8>(sfo.data(), entry.size);
}
}
file.Close();
return true;
}
bool PKG::Extract(const std::filesystem::path& filepath, const std::filesystem::path& extract,
std::string& failreason) {
extract_path = extract;
pkgpath = filepath;
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
if (!file.IsOpen()) {
return false;
}
pkgSize = file.GetSize();
file.ReadRaw<u8>(&pkgheader, sizeof(PKGHeader));
if (pkgheader.magic != 0x7F434E54)
return false;
if (pkgheader.pkg_size > pkgSize) {
failreason = "PKG file size is different";
return false;
}
if ((pkgheader.pkg_content_size + pkgheader.pkg_content_offset) > pkgheader.pkg_size) {
failreason = "Content size is bigger than pkg size";
return false;
}
u32 offset = pkgheader.pkg_table_entry_offset;
u32 n_files = pkgheader.pkg_table_entry_count;
std::array<u8, 64> concatenated_ivkey_dk3;
std::array<u8, 32> seed_digest;
std::array<std::array<u8, 32>, 7> digest1;
std::array<std::array<u8, 256>, 7> key1;
std::array<u8, 256> imgkeydata;
if (!file.Seek(offset)) {
failreason = "Failed to seek to PKG table entry offset";
return false;
}
for (int i = 0; i < n_files; i++) {
PKGEntry entry{};
file.Read(entry.id);
file.Read(entry.filename_offset);
file.Read(entry.flags1);
file.Read(entry.flags2);
file.Read(entry.offset);
file.Read(entry.size);
file.Seek(8, Common::FS::SeekOrigin::CurrentPosition);
auto currentPos = file.Tell();
// Try to figure out the name
const auto name = GetEntryNameByType(entry.id);
const auto filepath = extract_path / "sce_sys" / name;
std::filesystem::create_directories(filepath.parent_path());
if (name.empty()) {
// Just print with id
Common::FS::IOFile out(extract_path / "sce_sys" / std::to_string(entry.id),
Common::FS::FileAccessMode::Write);
if (!file.Seek(entry.offset)) {
failreason = "Failed to seek to PKG entry offset";
return false;
}
std::vector<u8> data;
data.resize(entry.size);
file.ReadRaw<u8>(data.data(), entry.size);
out.WriteRaw<u8>(data.data(), entry.size);
out.Close();
file.Seek(currentPos);
continue;
}
if (entry.id == 0x1) { // DIGESTS, seek;
// file.Seek(entry.offset, fsSeekSet);
} else if (entry.id == 0x10) { // ENTRY_KEYS, seek;
file.Seek(entry.offset);
file.Read(seed_digest);
for (int i = 0; i < 7; i++) {
file.Read(digest1[i]);
}
for (int i = 0; i < 7; i++) {
file.Read(key1[i]);
}
PKG::crypto.RSA2048Decrypt(dk3_, key1[3], true); // decrypt DK3
} else if (entry.id == 0x20) { // IMAGE_KEY, seek; IV_KEY
file.Seek(entry.offset);
file.Read(imgkeydata);
// The Concatenated iv + dk3 imagekey for HASH256
std::memcpy(concatenated_ivkey_dk3.data(), &entry, sizeof(entry));
std::memcpy(concatenated_ivkey_dk3.data() + sizeof(entry), dk3_.data(), sizeof(dk3_));
PKG::crypto.ivKeyHASH256(concatenated_ivkey_dk3, ivKey); // ivkey_
// imgkey_ to use for last step to get ekpfs
PKG::crypto.aesCbcCfb128Decrypt(ivKey, imgkeydata, imgKey);
// ekpfs key to get data and tweak keys.
PKG::crypto.RSA2048Decrypt(ekpfsKey, imgKey, false);
} else if (entry.id == 0x80) {
// GENERAL_DIGESTS, seek;
// file.Seek(entry.offset, fsSeekSet);
}
Common::FS::IOFile out(extract_path / "sce_sys" / name, Common::FS::FileAccessMode::Write);
if (!file.Seek(entry.offset)) {
failreason = "Failed to seek to PKG entry offset";
return false;
}
std::vector<u8> data;
data.resize(entry.size);
file.ReadRaw<u8>(data.data(), entry.size);
out.WriteRaw<u8>(data.data(), entry.size);
out.Close();
// Decrypt Np stuff and overwrite.
if (entry.id == 0x400 || entry.id == 0x401 || entry.id == 0x402 ||
entry.id == 0x403) { // somehow 0x401 is not decrypting
decNp.resize(entry.size);
if (!file.Seek(entry.offset)) {
failreason = "Failed to seek to PKG entry offset";
return false;
}
std::vector<u8> data;
data.resize(entry.size);
file.ReadRaw<u8>(data.data(), entry.size);
std::span<u8> cipherNp(data.data(), entry.size);
std::array<u8, 64> concatenated_ivkey_dk3_;
std::memcpy(concatenated_ivkey_dk3_.data(), &entry, sizeof(entry));
std::memcpy(concatenated_ivkey_dk3_.data() + sizeof(entry), dk3_.data(), sizeof(dk3_));
PKG::crypto.ivKeyHASH256(concatenated_ivkey_dk3_, ivKey);
PKG::crypto.aesCbcCfb128DecryptEntry(ivKey, cipherNp, decNp);
Common::FS::IOFile out(extract_path / "sce_sys" / name,
Common::FS::FileAccessMode::Write);
out.Write(decNp);
out.Close();
}
file.Seek(currentPos);
}
// Read the seed
std::array<u8, 16> seed;
if (!file.Seek(pkgheader.pfs_image_offset + 0x370)) {
failreason = "Failed to seek to PFS image offset";
return false;
}
file.Read(seed);
// Get data and tweak keys.
PKG::crypto.PfsGenCryptoKey(ekpfsKey, seed, dataKey, tweakKey);
const u32 length = pkgheader.pfs_cache_size * 0x2; // Seems to be ok.
int num_blocks = 0;
std::vector<u8> pfsc(length);
if (length != 0) {
// Read encrypted pfs_image
std::vector<u8> pfs_encrypted(length);
file.Seek(pkgheader.pfs_image_offset);
file.Read(pfs_encrypted);
file.Close();
// Decrypt the pfs_image.
std::vector<u8> pfs_decrypted(length);
PKG::crypto.decryptPFS(dataKey, tweakKey, pfs_encrypted, pfs_decrypted, 0);
// Retrieve PFSC from decrypted pfs_image.
pfsc_offset = GetPFSCOffset(pfs_decrypted);
std::memcpy(pfsc.data(), pfs_decrypted.data() + pfsc_offset, length - pfsc_offset);
PFSCHdr pfsChdr;
std::memcpy(&pfsChdr, pfsc.data(), sizeof(pfsChdr));
num_blocks = (int)(pfsChdr.data_length / pfsChdr.block_sz2);
sectorMap.resize(num_blocks + 1); // 8 bytes, need extra 1 to get the last offset.
for (int i = 0; i < num_blocks + 1; i++) {
std::memcpy(&sectorMap[i], pfsc.data() + pfsChdr.block_offsets + i * 8, 8);
}
}
u32 ent_size = 0;
u32 ndinode = 0;
int ndinode_counter = 0;
bool dinode_reached = false;
bool uroot_reached = false;
std::vector<char> compressedData;
std::vector<char> decompressedData(0x10000);
// Get iNdoes and Dirents.
for (int i = 0; i < num_blocks; i++) {
const u64 sectorOffset = sectorMap[i];
const u64 sectorSize = sectorMap[i + 1] - sectorOffset;
compressedData.resize(sectorSize);
std::memcpy(compressedData.data(), pfsc.data() + sectorOffset, sectorSize);
if (sectorSize == 0x10000) // Uncompressed data
std::memcpy(decompressedData.data(), compressedData.data(), 0x10000);
else if (sectorSize < 0x10000) // Compressed data
DecompressPFSC(compressedData, decompressedData);
if (i == 0) {
std::memcpy(&ndinode, decompressedData.data() + 0x30, 4); // number of folders and files
}
int occupied_blocks =
(ndinode * 0xA8) / 0x10000; // how many blocks(0x10000) are taken by iNodes.
if (((ndinode * 0xA8) % 0x10000) != 0)
occupied_blocks += 1;
if (i >= 1 && i <= occupied_blocks) { // Get all iNodes, gives type, file size and location.
for (int p = 0; p < 0x10000; p += 0xA8) {
Inode node;
std::memcpy(&node, &decompressedData[p], sizeof(node));
if (node.Mode == 0) {
break;
}
iNodeBuf.push_back(node);
}
}
// let's deal with the root/uroot entries here.
// Sometimes it's more than 2 entries (Tomb Raider Remastered)
const std::string_view flat_path_table(&decompressedData[0x10], 15);
if (flat_path_table == "flat_path_table") {
uroot_reached = true;
}
if (uroot_reached) {
for (int i = 0; i < 0x10000; i += ent_size) {
Dirent dirent;
std::memcpy(&dirent, &decompressedData[i], sizeof(dirent));
ent_size = dirent.entsize;
if (dirent.ino != 0) {
ndinode_counter++;
} else {
// Set the the folder according to the current inode.
// Can be 2 or more (rarely)
auto parent_path = extract_path.parent_path();
auto title_id = GetTitleID();
if (parent_path.filename() != title_id &&
!fmt::UTF(extract_path.u8string()).data.ends_with("-UPDATE")) {
extractPaths[ndinode_counter] = parent_path / title_id;
} else {
// DLCs path has different structure
extractPaths[ndinode_counter] = extract_path;
}
uroot_reached = false;
break;
}
}
}
const char dot = decompressedData[0x10];
const std::string_view dotdot(&decompressedData[0x28], 2);
if (dot == '.' && dotdot == "..") {
dinode_reached = true;
}
// Get folder and file names.
bool end_reached = false;
if (dinode_reached) {
for (int j = 0; j < 0x10000; j += ent_size) { // Skip the first parent and child.
Dirent dirent;
std::memcpy(&dirent, &decompressedData[j], sizeof(dirent));
// Stop here and continue the main loop
if (dirent.ino == 0) {
break;
}
ent_size = dirent.entsize;
auto& table = fsTable.emplace_back();
table.name = std::string(dirent.name, dirent.namelen);
table.inode = dirent.ino;
table.type = dirent.type;
if (table.type == PFS_CURRENT_DIR) {
current_dir = extractPaths[table.inode];
}
extractPaths[table.inode] = current_dir / std::filesystem::path(table.name);
if (table.type == PFS_FILE || table.type == PFS_DIR) {
if (table.type == PFS_DIR) { // Create dirs.
std::filesystem::create_directory(extractPaths[table.inode]);
}
ndinode_counter++;
if ((ndinode_counter + 1) == ndinode) // 1 for the image itself (root).
end_reached = true;
}
}
if (end_reached) {
break;
}
}
}
return true;
}
void PKG::ExtractFiles(const int index) {
int inode_number = fsTable[index].inode;
int inode_type = fsTable[index].type;
std::string inode_name = fsTable[index].name;
if (inode_type == PFS_FILE) {
int sector_loc = iNodeBuf[inode_number].loc;
int nblocks = iNodeBuf[inode_number].Blocks;
int bsize = iNodeBuf[inode_number].Size;
Common::FS::IOFile inflated;
inflated.Open(extractPaths[inode_number], Common::FS::FileAccessMode::Write);
Common::FS::IOFile pkgFile; // Open the file for each iteration to avoid conflict.
pkgFile.Open(pkgpath, Common::FS::FileAccessMode::Read);
int size_decompressed = 0;
std::vector<char> compressedData;
std::vector<char> decompressedData(0x10000);
u64 pfsc_buf_size = 0x11000; // extra 0x1000
std::vector<u8> pfsc(pfsc_buf_size);
std::vector<u8> pfs_decrypted(pfsc_buf_size);
for (int j = 0; j < nblocks; j++) {
u64 sectorOffset =
sectorMap[sector_loc + j]; // offset into PFSC_image and not pfs_image.
u64 sectorSize = sectorMap[sector_loc + j + 1] -
sectorOffset; // indicates if data is compressed or not.
u64 fileOffset = (pkgheader.pfs_image_offset + pfsc_offset + sectorOffset);
u64 currentSector1 =
(pfsc_offset + sectorOffset) / 0x1000; // block size is 0x1000 for xts decryption.
int sectorOffsetMask = (sectorOffset + pfsc_offset) & 0xFFFFF000;
int previousData = (sectorOffset + pfsc_offset) - sectorOffsetMask;
pkgFile.Seek(fileOffset - previousData);
pkgFile.Read(pfsc);
PKG::crypto.decryptPFS(dataKey, tweakKey, pfsc, pfs_decrypted, currentSector1);
compressedData.resize(sectorSize);
std::memcpy(compressedData.data(), pfs_decrypted.data() + previousData, sectorSize);
if (sectorSize == 0x10000) // Uncompressed data
std::memcpy(decompressedData.data(), compressedData.data(), 0x10000);
else if (sectorSize < 0x10000) // Compressed data
DecompressPFSC(compressedData, decompressedData);
size_decompressed += 0x10000;
if (j < nblocks - 1) {
inflated.WriteRaw<u8>(decompressedData.data(), decompressedData.size());
} else {
// This is to remove the zeros at the end of the file.
const u32 write_size = decompressedData.size() - (size_decompressed - bsize);
inflated.WriteRaw<u8>(decompressedData.data(), write_size);
}
}
pkgFile.Close();
inflated.Close();
}
}

View File

@ -1,174 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <filesystem>
#include <string>
#include <unordered_map>
#include <vector>
#include "common/endian.h"
#include "core/crypto/crypto.h"
#include "pfs.h"
#include "trp.h"
struct PKGHeader {
u32_be magic; // Magic
u32_be pkg_type;
u32_be pkg_0x8; // unknown field
u32_be pkg_file_count;
u32_be pkg_table_entry_count;
u16_be pkg_sc_entry_count;
u16_be pkg_table_entry_count_2; // same as pkg_entry_count
u32_be pkg_table_entry_offset; // file table offset
u32_be pkg_sc_entry_data_size;
u64_be pkg_body_offset; // offset of PKG entries
u64_be pkg_body_size; // length of all PKG entries
u64_be pkg_content_offset;
u64_be pkg_content_size;
u8 pkg_content_id[0x24]; // packages' content ID as a 36-byte string
u8 pkg_padding[0xC]; // padding
u32_be pkg_drm_type; // DRM type
u32_be pkg_content_type; // Content type
u32_be pkg_content_flags; // Content flags
u32_be pkg_promote_size;
u32_be pkg_version_date;
u32_be pkg_version_hash;
u32_be pkg_0x088;
u32_be pkg_0x08C;
u32_be pkg_0x090;
u32_be pkg_0x094;
u32_be pkg_iro_tag;
u32_be pkg_drm_type_version;
u8 pkg_zeroes_1[0x60];
/* Digest table */
u8 digest_entries1[0x20]; // sha256 digest for main entry 1
u8 digest_entries2[0x20]; // sha256 digest for main entry 2
u8 digest_table_digest[0x20]; // sha256 digest for digest table
u8 digest_body_digest[0x20]; // sha256 digest for main table
u8 pkg_zeroes_2[0x280];
u32_be pkg_0x400;
u32_be pfs_image_count; // count of PFS images
u64_be pfs_image_flags; // PFS flags
u64_be pfs_image_offset; // offset to start of external PFS image
u64_be pfs_image_size; // size of external PFS image
u64_be mount_image_offset;
u64_be mount_image_size;
u64_be pkg_size;
u32_be pfs_signed_size;
u32_be pfs_cache_size;
u8 pfs_image_digest[0x20];
u8 pfs_signed_digest[0x20];
u64_be pfs_split_size_nth_0;
u64_be pfs_split_size_nth_1;
u8 pkg_zeroes_3[0xB50];
u8 pkg_digest[0x20];
};
enum class PKGContentFlag {
FIRST_PATCH = 0x100000,
PATCHGO = 0x200000,
REMASTER = 0x400000,
PS_CLOUD = 0x800000,
GD_AC = 0x2000000,
NON_GAME = 0x4000000,
UNKNOWN_0x8000000 = 0x8000000,
SUBSEQUENT_PATCH = 0x40000000,
DELTA_PATCH = 0x41000000,
CUMULATIVE_PATCH = 0x60000000
};
struct PKGEntry {
u32_be id; // File ID, useful for files without a filename entry
u32_be filename_offset; // Offset into the filenames table (ID 0x200) where this file's name is
// located
u32_be flags1; // Flags including encrypted flag, etc
u32_be flags2; // Flags including encryption key index, etc
u32_be offset; // Offset into PKG to find the file
u32_be size; // Size of the file
u64_be padding; // blank padding
};
static_assert(sizeof(PKGEntry) == 32);
class PKG {
public:
PKG();
~PKG();
bool Open(const std::filesystem::path& filepath, std::string& failreason);
void ExtractFiles(const int index);
bool Extract(const std::filesystem::path& filepath, const std::filesystem::path& extract,
std::string& failreason);
std::vector<u8> sfo;
u32 GetNumberOfFiles() {
return fsTable.size();
}
u64 GetPkgSize() {
return pkgSize;
}
std::string GetPkgFlags() {
return pkgFlags;
}
std::string_view GetTitleID() {
return std::string_view(pkgTitleID, 9);
}
PKGHeader GetPkgHeader() {
return pkgheader;
}
static bool isFlagSet(u32_be variable, PKGContentFlag flag) {
return (variable) & static_cast<u32>(flag);
}
static constexpr std::array<std::pair<PKGContentFlag, std::string_view>, 10> flagNames = {
{{PKGContentFlag::FIRST_PATCH, "FIRST_PATCH"},
{PKGContentFlag::PATCHGO, "PATCHGO"},
{PKGContentFlag::REMASTER, "REMASTER"},
{PKGContentFlag::PS_CLOUD, "PS_CLOUD"},
{PKGContentFlag::GD_AC, "GD_AC"},
{PKGContentFlag::NON_GAME, "NON_GAME"},
{PKGContentFlag::UNKNOWN_0x8000000, "UNKNOWN_0x8000000"},
{PKGContentFlag::SUBSEQUENT_PATCH, "SUBSEQUENT_PATCH"},
{PKGContentFlag::DELTA_PATCH, "DELTA_PATCH"},
{PKGContentFlag::CUMULATIVE_PATCH, "CUMULATIVE_PATCH"}}};
private:
Crypto crypto;
TRP trp;
u64 pkgSize = 0;
char pkgTitleID[9];
PKGHeader pkgheader;
std::string pkgFlags;
std::unordered_map<int, std::filesystem::path> extractPaths;
std::vector<pfs_fs_table> fsTable;
std::vector<Inode> iNodeBuf;
std::vector<u64> sectorMap;
u64 pfsc_offset;
std::array<u8, 32> dk3_;
std::array<u8, 32> ivKey;
std::array<u8, 256> imgKey;
std::array<u8, 32> ekpfsKey;
std::array<u8, 16> dataKey;
std::array<u8, 16> tweakKey;
std::vector<u8> decNp;
std::filesystem::path pkgpath;
std::filesystem::path current_dir;
std::filesystem::path extract_path;
};

View File

@ -1,638 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
#include <array>
#include "pkg_type.h"
struct PkgEntryValue {
u32 type;
std::string_view name;
operator u32() const noexcept {
return type;
}
};
constexpr static std::array<PkgEntryValue, 611> PkgEntries = {{
{0x0001, "digests"},
{0x0010, "entry_keys"},
{0x0020, "image_key"},
{0x0080, "general_digests"},
{0x0100, "metas"},
{0x0200, "entry_names"},
{0x0400, "license.dat"},
{0x0401, "license.info"},
{0x0402, "nptitle.dat"},
{0x0403, "npbind.dat"},
{0x0404, "selfinfo.dat"},
{0x0406, "imageinfo.dat"},
{0x0407, "target-deltainfo.dat"},
{0x0408, "origin-deltainfo.dat"},
{0x0409, "psreserved.dat"},
{0x1000, "param.sfo"},
{0x1001, "playgo-chunk.dat"},
{0x1002, "playgo-chunk.sha"},
{0x1003, "playgo-manifest.xml"},
{0x1004, "pronunciation.xml"},
{0x1005, "pronunciation.sig"},
{0x1006, "pic1.png"},
{0x1007, "pubtoolinfo.dat"},
{0x1008, "app/playgo-chunk.dat"},
{0x1009, "app/playgo-chunk.sha"},
{0x100A, "app/playgo-manifest.xml"},
{0x100B, "shareparam.json"},
{0x100C, "shareoverlayimage.png"},
{0x100D, "save_data.png"},
{0x100E, "shareprivacyguardimage.png"},
{0x1200, "icon0.png"},
{0x1201, "icon0_00.png"},
{0x1202, "icon0_01.png"},
{0x1203, "icon0_02.png"},
{0x1204, "icon0_03.png"},
{0x1205, "icon0_04.png"},
{0x1206, "icon0_05.png"},
{0x1207, "icon0_06.png"},
{0x1208, "icon0_07.png"},
{0x1209, "icon0_08.png"},
{0x120A, "icon0_09.png"},
{0x120B, "icon0_10.png"},
{0x120C, "icon0_11.png"},
{0x120D, "icon0_12.png"},
{0x120E, "icon0_13.png"},
{0x120F, "icon0_14.png"},
{0x1210, "icon0_15.png"},
{0x1211, "icon0_16.png"},
{0x1212, "icon0_17.png"},
{0x1213, "icon0_18.png"},
{0x1214, "icon0_19.png"},
{0x1215, "icon0_20.png"},
{0x1216, "icon0_21.png"},
{0x1217, "icon0_22.png"},
{0x1218, "icon0_23.png"},
{0x1219, "icon0_24.png"},
{0x121A, "icon0_25.png"},
{0x121B, "icon0_26.png"},
{0x121C, "icon0_27.png"},
{0x121D, "icon0_28.png"},
{0x121E, "icon0_29.png"},
{0x121F, "icon0_30.png"},
{0x1220, "pic0.png"},
{0x1240, "snd0.at9"},
{0x1241, "pic1_00.png"},
{0x1242, "pic1_01.png"},
{0x1243, "pic1_02.png"},
{0x1244, "pic1_03.png"},
{0x1245, "pic1_04.png"},
{0x1246, "pic1_05.png"},
{0x1247, "pic1_06.png"},
{0x1248, "pic1_07.png"},
{0x1249, "pic1_08.png"},
{0x124A, "pic1_09.png"},
{0x124B, "pic1_10.png"},
{0x124C, "pic1_11.png"},
{0x124D, "pic1_12.png"},
{0x124E, "pic1_13.png"},
{0x124F, "pic1_14.png"},
{0x1250, "pic1_15.png"},
{0x1251, "pic1_16.png"},
{0x1252, "pic1_17.png"},
{0x1253, "pic1_18.png"},
{0x1254, "pic1_19.png"},
{0x1255, "pic1_20.png"},
{0x1256, "pic1_21.png"},
{0x1257, "pic1_22.png"},
{0x1258, "pic1_23.png"},
{0x1259, "pic1_24.png"},
{0x125A, "pic1_25.png"},
{0x125B, "pic1_26.png"},
{0x125C, "pic1_27.png"},
{0x125D, "pic1_28.png"},
{0x125E, "pic1_29.png"},
{0x125F, "pic1_30.png"},
{0x1260, "changeinfo/changeinfo.xml"},
{0x1261, "changeinfo/changeinfo_00.xml"},
{0x1262, "changeinfo/changeinfo_01.xml"},
{0x1263, "changeinfo/changeinfo_02.xml"},
{0x1264, "changeinfo/changeinfo_03.xml"},
{0x1265, "changeinfo/changeinfo_04.xml"},
{0x1266, "changeinfo/changeinfo_05.xml"},
{0x1267, "changeinfo/changeinfo_06.xml"},
{0x1268, "changeinfo/changeinfo_07.xml"},
{0x1269, "changeinfo/changeinfo_08.xml"},
{0x126A, "changeinfo/changeinfo_09.xml"},
{0x126B, "changeinfo/changeinfo_10.xml"},
{0x126C, "changeinfo/changeinfo_11.xml"},
{0x126D, "changeinfo/changeinfo_12.xml"},
{0x126E, "changeinfo/changeinfo_13.xml"},
{0x126F, "changeinfo/changeinfo_14.xml"},
{0x1270, "changeinfo/changeinfo_15.xml"},
{0x1271, "changeinfo/changeinfo_16.xml"},
{0x1272, "changeinfo/changeinfo_17.xml"},
{0x1273, "changeinfo/changeinfo_18.xml"},
{0x1274, "changeinfo/changeinfo_19.xml"},
{0x1275, "changeinfo/changeinfo_20.xml"},
{0x1276, "changeinfo/changeinfo_21.xml"},
{0x1277, "changeinfo/changeinfo_22.xml"},
{0x1278, "changeinfo/changeinfo_23.xml"},
{0x1279, "changeinfo/changeinfo_24.xml"},
{0x127A, "changeinfo/changeinfo_25.xml"},
{0x127B, "changeinfo/changeinfo_26.xml"},
{0x127C, "changeinfo/changeinfo_27.xml"},
{0x127D, "changeinfo/changeinfo_28.xml"},
{0x127E, "changeinfo/changeinfo_29.xml"},
{0x127F, "changeinfo/changeinfo_30.xml"},
{0x1280, "icon0.dds"},
{0x1281, "icon0_00.dds"},
{0x1282, "icon0_01.dds"},
{0x1283, "icon0_02.dds"},
{0x1284, "icon0_03.dds"},
{0x1285, "icon0_04.dds"},
{0x1286, "icon0_05.dds"},
{0x1287, "icon0_06.dds"},
{0x1288, "icon0_07.dds"},
{0x1289, "icon0_08.dds"},
{0x128A, "icon0_09.dds"},
{0x128B, "icon0_10.dds"},
{0x128C, "icon0_11.dds"},
{0x128D, "icon0_12.dds"},
{0x128E, "icon0_13.dds"},
{0x128F, "icon0_14.dds"},
{0x1290, "icon0_15.dds"},
{0x1291, "icon0_16.dds"},
{0x1292, "icon0_17.dds"},
{0x1293, "icon0_18.dds"},
{0x1294, "icon0_19.dds"},
{0x1295, "icon0_20.dds"},
{0x1296, "icon0_21.dds"},
{0x1297, "icon0_22.dds"},
{0x1298, "icon0_23.dds"},
{0x1299, "icon0_24.dds"},
{0x129A, "icon0_25.dds"},
{0x129B, "icon0_26.dds"},
{0x129C, "icon0_27.dds"},
{0x129D, "icon0_28.dds"},
{0x129E, "icon0_29.dds"},
{0x129F, "icon0_30.dds"},
{0x12A0, "pic0.dds"},
{0x12C0, "pic1.dds"},
{0x12C1, "pic1_00.dds"},
{0x12C2, "pic1_01.dds"},
{0x12C3, "pic1_02.dds"},
{0x12C4, "pic1_03.dds"},
{0x12C5, "pic1_04.dds"},
{0x12C6, "pic1_05.dds"},
{0x12C7, "pic1_06.dds"},
{0x12C8, "pic1_07.dds"},
{0x12C9, "pic1_08.dds"},
{0x12CA, "pic1_09.dds"},
{0x12CB, "pic1_10.dds"},
{0x12CC, "pic1_11.dds"},
{0x12CD, "pic1_12.dds"},
{0x12CE, "pic1_13.dds"},
{0x12CF, "pic1_14.dds"},
{0x12D0, "pic1_15.dds"},
{0x12D1, "pic1_16.dds"},
{0x12D2, "pic1_17.dds"},
{0x12D3, "pic1_18.dds"},
{0x12D4, "pic1_19.dds"},
{0x12D5, "pic1_20.dds"},
{0x12D6, "pic1_21.dds"},
{0x12D7, "pic1_22.dds"},
{0x12D8, "pic1_23.dds"},
{0x12D9, "pic1_24.dds"},
{0x12DA, "pic1_25.dds"},
{0x12DB, "pic1_26.dds"},
{0x12DC, "pic1_27.dds"},
{0x12DD, "pic1_28.dds"},
{0x12DE, "pic1_29.dds"},
{0x12DF, "pic1_30.dds"},
{0x1400, "trophy/trophy00.trp"},
{0x1401, "trophy/trophy01.trp"},
{0x1402, "trophy/trophy02.trp"},
{0x1403, "trophy/trophy03.trp"},
{0x1404, "trophy/trophy04.trp"},
{0x1405, "trophy/trophy05.trp"},
{0x1406, "trophy/trophy06.trp"},
{0x1407, "trophy/trophy07.trp"},
{0x1408, "trophy/trophy08.trp"},
{0x1409, "trophy/trophy09.trp"},
{0x140A, "trophy/trophy10.trp"},
{0x140B, "trophy/trophy11.trp"},
{0x140C, "trophy/trophy12.trp"},
{0x140D, "trophy/trophy13.trp"},
{0x140E, "trophy/trophy14.trp"},
{0x140F, "trophy/trophy15.trp"},
{0x1410, "trophy/trophy16.trp"},
{0x1411, "trophy/trophy17.trp"},
{0x1412, "trophy/trophy18.trp"},
{0x1413, "trophy/trophy19.trp"},
{0x1414, "trophy/trophy20.trp"},
{0x1415, "trophy/trophy21.trp"},
{0x1416, "trophy/trophy22.trp"},
{0x1417, "trophy/trophy23.trp"},
{0x1418, "trophy/trophy24.trp"},
{0x1419, "trophy/trophy25.trp"},
{0x141A, "trophy/trophy26.trp"},
{0x141B, "trophy/trophy27.trp"},
{0x141C, "trophy/trophy28.trp"},
{0x141D, "trophy/trophy29.trp"},
{0x141E, "trophy/trophy30.trp"},
{0x141F, "trophy/trophy31.trp"},
{0x1420, "trophy/trophy32.trp"},
{0x1421, "trophy/trophy33.trp"},
{0x1422, "trophy/trophy34.trp"},
{0x1423, "trophy/trophy35.trp"},
{0x1424, "trophy/trophy36.trp"},
{0x1425, "trophy/trophy37.trp"},
{0x1426, "trophy/trophy38.trp"},
{0x1427, "trophy/trophy39.trp"},
{0x1428, "trophy/trophy40.trp"},
{0x1429, "trophy/trophy41.trp"},
{0x142A, "trophy/trophy42.trp"},
{0x142B, "trophy/trophy43.trp"},
{0x142C, "trophy/trophy44.trp"},
{0x142D, "trophy/trophy45.trp"},
{0x142E, "trophy/trophy46.trp"},
{0x142F, "trophy/trophy47.trp"},
{0x1430, "trophy/trophy48.trp"},
{0x1431, "trophy/trophy49.trp"},
{0x1432, "trophy/trophy50.trp"},
{0x1433, "trophy/trophy51.trp"},
{0x1434, "trophy/trophy52.trp"},
{0x1435, "trophy/trophy53.trp"},
{0x1436, "trophy/trophy54.trp"},
{0x1437, "trophy/trophy55.trp"},
{0x1438, "trophy/trophy56.trp"},
{0x1439, "trophy/trophy57.trp"},
{0x143A, "trophy/trophy58.trp"},
{0x143B, "trophy/trophy59.trp"},
{0x143C, "trophy/trophy60.trp"},
{0x143D, "trophy/trophy61.trp"},
{0x143E, "trophy/trophy62.trp"},
{0x143F, "trophy/trophy63.trp"},
{0x1440, "trophy/trophy64.trp"},
{0x1441, "trophy/trophy65.trp"},
{0x1442, "trophy/trophy66.trp"},
{0x1443, "trophy/trophy67.trp"},
{0x1444, "trophy/trophy68.trp"},
{0x1445, "trophy/trophy69.trp"},
{0x1446, "trophy/trophy70.trp"},
{0x1447, "trophy/trophy71.trp"},
{0x1448, "trophy/trophy72.trp"},
{0x1449, "trophy/trophy73.trp"},
{0x144A, "trophy/trophy74.trp"},
{0x144B, "trophy/trophy75.trp"},
{0x144C, "trophy/trophy76.trp"},
{0x144D, "trophy/trophy77.trp"},
{0x144E, "trophy/trophy78.trp"},
{0x144F, "trophy/trophy79.trp"},
{0x1450, "trophy/trophy80.trp"},
{0x1451, "trophy/trophy81.trp"},
{0x1452, "trophy/trophy82.trp"},
{0x1453, "trophy/trophy83.trp"},
{0x1454, "trophy/trophy84.trp"},
{0x1455, "trophy/trophy85.trp"},
{0x1456, "trophy/trophy86.trp"},
{0x1457, "trophy/trophy87.trp"},
{0x1458, "trophy/trophy88.trp"},
{0x1459, "trophy/trophy89.trp"},
{0x145A, "trophy/trophy90.trp"},
{0x145B, "trophy/trophy91.trp"},
{0x145C, "trophy/trophy92.trp"},
{0x145D, "trophy/trophy93.trp"},
{0x145E, "trophy/trophy94.trp"},
{0x145F, "trophy/trophy95.trp"},
{0x1460, "trophy/trophy96.trp"},
{0x1461, "trophy/trophy97.trp"},
{0x1462, "trophy/trophy98.trp"},
{0x1463, "trophy/trophy99.trp"},
{0x1600, "keymap_rp/001.png"},
{0x1601, "keymap_rp/002.png"},
{0x1602, "keymap_rp/003.png"},
{0x1603, "keymap_rp/004.png"},
{0x1604, "keymap_rp/005.png"},
{0x1605, "keymap_rp/006.png"},
{0x1606, "keymap_rp/007.png"},
{0x1607, "keymap_rp/008.png"},
{0x1608, "keymap_rp/009.png"},
{0x1609, "keymap_rp/010.png"},
{0x1610, "keymap_rp/00/001.png"},
{0x1611, "keymap_rp/00/002.png"},
{0x1612, "keymap_rp/00/003.png"},
{0x1613, "keymap_rp/00/004.png"},
{0x1614, "keymap_rp/00/005.png"},
{0x1615, "keymap_rp/00/006.png"},
{0x1616, "keymap_rp/00/007.png"},
{0x1617, "keymap_rp/00/008.png"},
{0x1618, "keymap_rp/00/009.png"},
{0x1619, "keymap_rp/00/010.png"},
{0x1620, "keymap_rp/01/001.png"},
{0x1621, "keymap_rp/01/002.png"},
{0x1622, "keymap_rp/01/003.png"},
{0x1623, "keymap_rp/01/004.png"},
{0x1624, "keymap_rp/01/005.png"},
{0x1625, "keymap_rp/01/006.png"},
{0x1626, "keymap_rp/01/007.png"},
{0x1627, "keymap_rp/01/008.png"},
{0x1628, "keymap_rp/01/009.png"},
{0x1629, "keymap_rp/01/010.png"},
{0x1630, "keymap_rp/02/001.png"},
{0x1631, "keymap_rp/02/002.png"},
{0x1632, "keymap_rp/02/003.png"},
{0x1633, "keymap_rp/02/004.png"},
{0x1634, "keymap_rp/02/005.png"},
{0x1635, "keymap_rp/02/006.png"},
{0x1636, "keymap_rp/02/007.png"},
{0x1637, "keymap_rp/02/008.png"},
{0x1638, "keymap_rp/02/009.png"},
{0x1639, "keymap_rp/02/010.png"},
{0x1640, "keymap_rp/03/001.png"},
{0x1641, "keymap_rp/03/002.png"},
{0x1642, "keymap_rp/03/003.png"},
{0x1643, "keymap_rp/03/004.png"},
{0x1644, "keymap_rp/03/005.png"},
{0x1645, "keymap_rp/03/006.png"},
{0x1646, "keymap_rp/03/007.png"},
{0x1647, "keymap_rp/03/008.png"},
{0x1648, "keymap_rp/03/0010.png"},
{0x1650, "keymap_rp/04/001.png"},
{0x1651, "keymap_rp/04/002.png"},
{0x1652, "keymap_rp/04/003.png"},
{0x1653, "keymap_rp/04/004.png"},
{0x1654, "keymap_rp/04/005.png"},
{0x1655, "keymap_rp/04/006.png"},
{0x1656, "keymap_rp/04/007.png"},
{0x1657, "keymap_rp/04/008.png"},
{0x1658, "keymap_rp/04/009.png"},
{0x1659, "keymap_rp/04/010.png"},
{0x1660, "keymap_rp/05/001.png"},
{0x1661, "keymap_rp/05/002.png"},
{0x1662, "keymap_rp/05/003.png"},
{0x1663, "keymap_rp/05/004.png"},
{0x1664, "keymap_rp/05/005.png"},
{0x1665, "keymap_rp/05/006.png"},
{0x1666, "keymap_rp/05/007.png"},
{0x1667, "keymap_rp/05/008.png"},
{0x1668, "keymap_rp/05/009.png"},
{0x1669, "keymap_rp/05/010.png"},
{0x1670, "keymap_rp/06/001.png"},
{0x1671, "keymap_rp/06/002.png"},
{0x1672, "keymap_rp/06/003.png"},
{0x1673, "keymap_rp/06/004.png"},
{0x1674, "keymap_rp/06/005.png"},
{0x1675, "keymap_rp/06/006.png"},
{0x1676, "keymap_rp/06/007.png"},
{0x1677, "keymap_rp/06/008.png"},
{0x1678, "keymap_rp/06/009.png"},
{0x1679, "keymap_rp/06/010.png"},
{0x1680, "keymap_rp/07/001.png"},
{0x1681, "keymap_rp/07/002.png"},
{0x1682, "keymap_rp/07/003.png"},
{0x1683, "keymap_rp/07/004.png"},
{0x1684, "keymap_rp/07/005.png"},
{0x1685, "keymap_rp/07/006.png"},
{0x1686, "keymap_rp/07/007.png"},
{0x1687, "keymap_rp/07/008.png"},
{0x1688, "keymap_rp/07/009.png"},
{0x1689, "keymap_rp/07/010.png"},
{0x1690, "keymap_rp/08/001.png"},
{0x1691, "keymap_rp/08/002.png"},
{0x1692, "keymap_rp/08/003.png"},
{0x1693, "keymap_rp/08/004.png"},
{0x1694, "keymap_rp/08/005.png"},
{0x1695, "keymap_rp/08/006.png"},
{0x1696, "keymap_rp/08/007.png"},
{0x1697, "keymap_rp/08/008.png"},
{0x1698, "keymap_rp/08/009.png"},
{0x1699, "keymap_rp/08/010.png"},
{0x16A0, "keymap_rp/09/001.png"},
{0x16A1, "keymap_rp/09/002.png"},
{0x16A2, "keymap_rp/09/003.png"},
{0x16A3, "keymap_rp/09/004.png"},
{0x16A4, "keymap_rp/09/005.png"},
{0x16A5, "keymap_rp/09/006.png"},
{0x16A6, "keymap_rp/09/007.png"},
{0x16A7, "keymap_rp/09/008.png"},
{0x16A8, "keymap_rp/09/009.png"},
{0x16A9, "keymap_rp/09/010.png"},
{0x16B0, "keymap_rp/10/001.png"},
{0x16B1, "keymap_rp/10/002.png"},
{0x16B2, "keymap_rp/10/003.png"},
{0x16B3, "keymap_rp/10/004.png"},
{0x16B4, "keymap_rp/10/005.png"},
{0x16B5, "keymap_rp/10/006.png"},
{0x16B6, "keymap_rp/10/007.png"},
{0x16B7, "keymap_rp/10/008.png"},
{0x16B8, "keymap_rp/10/009.png"},
{0x16B9, "keymap_rp/10/010.png"},
{0x16C0, "keymap_rp/11/001.png"},
{0x16C1, "keymap_rp/11/002.png"},
{0x16C2, "keymap_rp/11/003.png"},
{0x16C3, "keymap_rp/11/004.png"},
{0x16C4, "keymap_rp/11/005.png"},
{0x16C5, "keymap_rp/11/006.png"},
{0x16C6, "keymap_rp/11/007.png"},
{0x16C7, "keymap_rp/11/008.png"},
{0x16C8, "keymap_rp/11/009.png"},
{0x16C9, "keymap_rp/11/010.png"},
{0x16D0, "keymap_rp/12/001.png"},
{0x16D1, "keymap_rp/12/002.png"},
{0x16D2, "keymap_rp/12/003.png"},
{0x16D3, "keymap_rp/12/004.png"},
{0x16D4, "keymap_rp/12/005.png"},
{0x16D5, "keymap_rp/12/006.png"},
{0x16D6, "keymap_rp/12/007.png"},
{0x16D7, "keymap_rp/12/008.png"},
{0x16D8, "keymap_rp/12/009.png"},
{0x16D9, "keymap_rp/12/010.png"},
{0x16E0, "keymap_rp/13/001.png"},
{0x16E1, "keymap_rp/13/002.png"},
{0x16E2, "keymap_rp/13/003.png"},
{0x16E3, "keymap_rp/13/004.png"},
{0x16E4, "keymap_rp/13/005.png"},
{0x16E5, "keymap_rp/13/006.png"},
{0x16E6, "keymap_rp/13/007.png"},
{0x16E7, "keymap_rp/13/008.png"},
{0x16E8, "keymap_rp/13/009.png"},
{0x16E9, "keymap_rp/13/010.png"},
{0x16F0, "keymap_rp/14/001.png"},
{0x16F1, "keymap_rp/14/002.png"},
{0x16F2, "keymap_rp/14/003.png"},
{0x16F3, "keymap_rp/14/004.png"},
{0x16F4, "keymap_rp/14/005.png"},
{0x16F5, "keymap_rp/14/006.png"},
{0x16F6, "keymap_rp/14/007.png"},
{0x16F7, "keymap_rp/14/008.png"},
{0x16F8, "keymap_rp/14/009.png"},
{0x16F9, "keymap_rp/14/010.png"},
{0x1700, "keymap_rp/15/001.png"},
{0x1701, "keymap_rp/15/002.png"},
{0x1702, "keymap_rp/15/003.png"},
{0x1703, "keymap_rp/15/004.png"},
{0x1704, "keymap_rp/15/005.png"},
{0x1705, "keymap_rp/15/006.png"},
{0x1706, "keymap_rp/15/007.png"},
{0x1707, "keymap_rp/15/008.png"},
{0x1708, "keymap_rp/15/009.png"},
{0x1709, "keymap_rp/15/010.png"},
{0x1710, "keymap_rp/16/001.png"},
{0x1711, "keymap_rp/16/002.png"},
{0x1712, "keymap_rp/16/003.png"},
{0x1713, "keymap_rp/16/004.png"},
{0x1714, "keymap_rp/16/005.png"},
{0x1715, "keymap_rp/16/006.png"},
{0x1716, "keymap_rp/16/007.png"},
{0x1717, "keymap_rp/16/008.png"},
{0x1718, "keymap_rp/16/009.png"},
{0x1719, "keymap_rp/16/010.png"},
{0x1720, "keymap_rp/17/001.png"},
{0x1721, "keymap_rp/17/002.png"},
{0x1722, "keymap_rp/17/003.png"},
{0x1723, "keymap_rp/17/004.png"},
{0x1724, "keymap_rp/17/005.png"},
{0x1725, "keymap_rp/17/006.png"},
{0x1726, "keymap_rp/17/007.png"},
{0x1727, "keymap_rp/17/008.png"},
{0x1728, "keymap_rp/17/009.png"},
{0x1729, "keymap_rp/17/010.png"},
{0x1730, "keymap_rp/18/001.png"},
{0x1731, "keymap_rp/18/002.png"},
{0x1732, "keymap_rp/18/003.png"},
{0x1733, "keymap_rp/18/004.png"},
{0x1734, "keymap_rp/18/005.png"},
{0x1735, "keymap_rp/18/006.png"},
{0x1736, "keymap_rp/18/007.png"},
{0x1737, "keymap_rp/18/008.png"},
{0x1738, "keymap_rp/18/009.png"},
{0x1739, "keymap_rp/18/010.png"},
{0x1740, "keymap_rp/19/001.png"},
{0x1741, "keymap_rp/19/002.png"},
{0x1742, "keymap_rp/19/003.png"},
{0x1743, "keymap_rp/19/004.png"},
{0x1744, "keymap_rp/19/005.png"},
{0x1745, "keymap_rp/19/006.png"},
{0x1746, "keymap_rp/19/007.png"},
{0x1747, "keymap_rp/19/008.png"},
{0x1748, "keymap_rp/19/009.png"},
{0x1749, "keymap_rp/19/010.png"},
{0x1750, "keymap_rp/20/001.png"},
{0x1751, "keymap_rp/20/002.png"},
{0x1752, "keymap_rp/20/003.png"},
{0x1753, "keymap_rp/20/004.png"},
{0x1754, "keymap_rp/20/005.png"},
{0x1755, "keymap_rp/20/006.png"},
{0x1756, "keymap_rp/20/007.png"},
{0x1757, "keymap_rp/20/008.png"},
{0x1758, "keymap_rp/20/009.png"},
{0x1759, "keymap_rp/20/010.png"},
{0x1760, "keymap_rp/21/001.png"},
{0x1761, "keymap_rp/21/002.png"},
{0x1762, "keymap_rp/21/003.png"},
{0x1763, "keymap_rp/21/004.png"},
{0x1764, "keymap_rp/21/005.png"},
{0x1765, "keymap_rp/21/006.png"},
{0x1766, "keymap_rp/21/007.png"},
{0x1767, "keymap_rp/21/008.png"},
{0x1768, "keymap_rp/21/009.png"},
{0x1769, "keymap_rp/21/010.png"},
{0x1770, "keymap_rp/22/001.png"},
{0x1771, "keymap_rp/22/002.png"},
{0x1772, "keymap_rp/22/003.png"},
{0x1773, "keymap_rp/22/004.png"},
{0x1774, "keymap_rp/22/005.png"},
{0x1775, "keymap_rp/22/006.png"},
{0x1776, "keymap_rp/22/007.png"},
{0x1777, "keymap_rp/22/008.png"},
{0x1778, "keymap_rp/22/009.png"},
{0x1779, "keymap_rp/22/010.png"},
{0x1780, "keymap_rp/23/001.png"},
{0x1781, "keymap_rp/23/002.png"},
{0x1782, "keymap_rp/23/003.png"},
{0x1783, "keymap_rp/23/004.png"},
{0x1784, "keymap_rp/23/005.png"},
{0x1785, "keymap_rp/23/006.png"},
{0x1786, "keymap_rp/23/007.png"},
{0x1787, "keymap_rp/23/008.png"},
{0x1788, "keymap_rp/23/009.png"},
{0x1789, "keymap_rp/23/010.png"},
{0x1790, "keymap_rp/24/001.png"},
{0x1791, "keymap_rp/24/002.png"},
{0x1792, "keymap_rp/24/003.png"},
{0x1793, "keymap_rp/24/004.png"},
{0x1794, "keymap_rp/24/005.png"},
{0x1795, "keymap_rp/24/006.png"},
{0x1796, "keymap_rp/24/007.png"},
{0x1797, "keymap_rp/24/008.png"},
{0x1798, "keymap_rp/24/009.png"},
{0x1799, "keymap_rp/24/010.png"},
{0x17A0, "keymap_rp/25/001.png"},
{0x17A1, "keymap_rp/25/002.png"},
{0x17A2, "keymap_rp/25/003.png"},
{0x17A3, "keymap_rp/25/004.png"},
{0x17A4, "keymap_rp/25/005.png"},
{0x17A5, "keymap_rp/25/006.png"},
{0x17A6, "keymap_rp/25/007.png"},
{0x17A7, "keymap_rp/25/008.png"},
{0x17A8, "keymap_rp/25/009.png"},
{0x17A9, "keymap_rp/25/010.png"},
{0x17B0, "keymap_rp/26/001.png"},
{0x17B1, "keymap_rp/26/002.png"},
{0x17B2, "keymap_rp/26/003.png"},
{0x17B3, "keymap_rp/26/004.png"},
{0x17B4, "keymap_rp/26/005.png"},
{0x17B5, "keymap_rp/26/006.png"},
{0x17B6, "keymap_rp/26/007.png"},
{0x17B7, "keymap_rp/26/008.png"},
{0x17B8, "keymap_rp/26/009.png"},
{0x17B9, "keymap_rp/26/010.png"},
{0x17C0, "keymap_rp/27/001.png"},
{0x17C1, "keymap_rp/27/002.png"},
{0x17C2, "keymap_rp/27/003.png"},
{0x17C3, "keymap_rp/27/004.png"},
{0x17C4, "keymap_rp/27/005.png"},
{0x17C5, "keymap_rp/27/006.png"},
{0x17C6, "keymap_rp/27/007.png"},
{0x17C7, "keymap_rp/27/008.png"},
{0x17C8, "keymap_rp/27/009.png"},
{0x17C9, "keymap_rp/27/010.png"},
{0x17D0, "keymap_rp/28/001.png"},
{0x17D1, "keymap_rp/28/002.png"},
{0x17D2, "keymap_rp/28/003.png"},
{0x17D3, "keymap_rp/28/004.png"},
{0x17D4, "keymap_rp/28/005.png"},
{0x17D5, "keymap_rp/28/006.png"},
{0x17D6, "keymap_rp/28/007.png"},
{0x17D7, "keymap_rp/28/008.png"},
{0x17D8, "keymap_rp/28/009.png"},
{0x17D9, "keymap_rp/28/010.png"},
{0x17E0, "keymap_rp/29/001.png"},
{0x17E1, "keymap_rp/29/002.png"},
{0x17E2, "keymap_rp/29/003.png"},
{0x17E3, "keymap_rp/29/004.png"},
{0x17E4, "keymap_rp/29/005.png"},
{0x17E5, "keymap_rp/29/006.png"},
{0x17E6, "keymap_rp/29/007.png"},
{0x17E7, "keymap_rp/29/008.png"},
{0x17E8, "keymap_rp/29/009.png"},
{0x17E9, "keymap_rp/29/010.png"},
{0x17F0, "keymap_rp/30/001.png"},
{0x17F1, "keymap_rp/30/002.png"},
{0x17F2, "keymap_rp/30/003.png"},
{0x17F3, "keymap_rp/30/004.png"},
{0x17F4, "keymap_rp/30/005.png"},
{0x17F5, "keymap_rp/30/006.png"},
{0x17F6, "keymap_rp/30/007.png"},
{0x17F7, "keymap_rp/30/008.png"},
{0x17F8, "keymap_rp/30/009.png"},
{0x17F9, "keymap_rp/30/010.png"},
}};
std::string_view GetEntryNameByType(u32 type) {
const auto key = PkgEntryValue{type};
const auto it = std::ranges::lower_bound(PkgEntries, key);
if (it != PkgEntries.end() && it->type == type) {
return it->name;
}
return "";
}

View File

@ -1,10 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string_view>
#include "common/types.h"
/// Retrieves the PKG entry name from its type identifier.
std::string_view GetEntryNameByType(u32 type);

View File

@ -1,38 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <fstream>
#include "common/assert.h"
#include "common/io_file.h"
#include "common/stb.h"
#include "splash.h"
bool Splash::Open(const std::filesystem::path& filepath) {
ASSERT_MSG(filepath.extension().string() == ".png", "Unexpected file format passed");
Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Read);
if (!file.IsOpen()) {
return false;
}
std::vector<u8> png_file{};
const auto png_size = file.GetSize();
png_file.resize(png_size);
file.Seek(0);
file.Read(png_file);
auto* img_mem = stbi_load_from_memory(png_file.data(), png_file.size(),
reinterpret_cast<int*>(&img_info.width),
reinterpret_cast<int*>(&img_info.height),
reinterpret_cast<int*>(&img_info.num_channels), 4);
if (!img_mem) {
return false;
}
const auto img_size = img_info.GetSizeBytes();
img_data.resize(img_size);
std::memcpy(img_data.data(), img_mem, img_size);
stbi_image_free(img_mem);
return true;
}

View File

@ -1,42 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <filesystem>
#include <string>
#include <vector>
#include "common/types.h"
class Splash {
public:
struct ImageInfo {
u32 width;
u32 height;
u32 num_channels;
u32 GetSizeBytes() const {
return width * height * 4; // we always forcing rgba8 for simplicity
}
};
Splash() = default;
~Splash() = default;
bool Open(const std::filesystem::path& filepath);
[[nodiscard]] bool IsLoaded() const {
return img_data.size();
}
const auto& GetImageData() const {
return img_data;
}
ImageInfo GetImageInfo() const {
return img_info;
}
private:
ImageInfo img_info{};
std::vector<u8> img_data{};
};

View File

@ -1,10 +1,36 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <cryptopp/aes.h>
#include <cryptopp/modes.h>
#include "common/config.h"
#include "common/logging/log.h"
#include "common/path_util.h"
#include "trp.h"
#include "core/file_format/trp.h"
static void DecryptEFSM(std::span<CryptoPP::byte, 16> trophyKey,
std::span<CryptoPP::byte, 16> NPcommID,
std::span<CryptoPP::byte, 16> efsmIv, std::span<CryptoPP::byte> ciphertext,
std::span<CryptoPP::byte> decrypted) {
// step 1: Encrypt NPcommID
CryptoPP::CBC_Mode<CryptoPP::AES>::Encryption encrypt;
std::vector<CryptoPP::byte> trophyIv(16, 0);
std::vector<CryptoPP::byte> trpKey(16);
encrypt.SetKeyWithIV(trophyKey.data(), trophyKey.size(), trophyIv.data());
encrypt.ProcessData(trpKey.data(), NPcommID.data(), 16);
// step 2: decrypt efsm.
CryptoPP::CBC_Mode<CryptoPP::AES>::Decryption decrypt;
decrypt.SetKeyWithIV(trpKey.data(), trpKey.size(), efsmIv.data());
for (size_t i = 0; i < decrypted.size(); i += CryptoPP::AES::BLOCKSIZE) {
decrypt.ProcessData(decrypted.data() + i, ciphertext.data() + i, CryptoPP::AES::BLOCKSIZE);
}
}
TRP::TRP() = default;
TRP::~TRP() = default;
@ -115,7 +141,7 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, const std::string tit
return false;
}
file.Read(ESFM);
crypto.decryptEFSM(user_key, np_comm_id, esfmIv, ESFM, XML); // decrypt
DecryptEFSM(user_key, np_comm_id, esfmIv, ESFM, XML); // decrypt
removePadding(XML);
std::string xml_name = entry.entry_name;
size_t pos = xml_name.find("ESFM");

View File

@ -7,7 +7,6 @@
#include "common/endian.h"
#include "common/io_file.h"
#include "common/types.h"
#include "core/crypto/crypto.h"
struct TrpHeader {
u32_be magic; // (0xDCA24D00)
@ -37,10 +36,9 @@ public:
void GetNPcommID(const std::filesystem::path& trophyPath, int index);
private:
Crypto crypto;
std::vector<u8> NPcommID = std::vector<u8>(12);
std::array<u8, 16> np_comm_id{};
std::array<u8, 16> esfmIv{};
std::filesystem::path trpFilesPath;
static constexpr int iv_len = 16;
};
};

View File

@ -70,6 +70,10 @@ std::filesystem::path MntPoints::GetHostPath(std::string_view path, bool* is_rea
std::filesystem::path host_path = mount->host_path / rel_path;
std::filesystem::path patch_path = mount->host_path;
patch_path += "-UPDATE";
if (!std::filesystem::exists(patch_path)) {
patch_path = mount->host_path;
patch_path += "-patch";
}
patch_path /= rel_path;
if ((corrected_path.starts_with("/app0") || corrected_path.starts_with("/hostapp")) &&

View File

@ -9,29 +9,29 @@
namespace Libraries::DiscMap {
int PS4_SYSV_ABI sceDiscMapGetPackageSize() {
LOG_WARNING(Lib_DiscMap, "(DUMMY) called");
int PS4_SYSV_ABI sceDiscMapGetPackageSize(s64 fflags, int* ret1, int* ret2) {
return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO;
}
int PS4_SYSV_ABI sceDiscMapIsRequestOnHDD() {
LOG_WARNING(Lib_DiscMap, "(DUMMY) called");
int PS4_SYSV_ABI sceDiscMapIsRequestOnHDD(char* path, s64 offset, s64 nbytes, int* ret) {
return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO;
}
int PS4_SYSV_ABI Func_7C980FFB0AA27E7A() {
LOG_ERROR(Lib_DiscMap, "(STUBBED) called");
int PS4_SYSV_ABI Func_7C980FFB0AA27E7A(char* path, s64 offset, s64 nbytes, int* flags, int* ret1,
int* ret2) {
*flags = 0;
*ret1 = 0;
*ret2 = 0;
return ORBIS_OK;
}
int PS4_SYSV_ABI Func_8A828CAEE7EDD5E9() {
LOG_ERROR(Lib_DiscMap, "(STUBBED) called");
return ORBIS_OK;
int PS4_SYSV_ABI Func_8A828CAEE7EDD5E9(char* path, s64 offset, s64 nbytes, int* flags, int* ret1,
int* ret2) {
return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO;
}
int PS4_SYSV_ABI Func_E7EBCE96E92F91F8() {
LOG_ERROR(Lib_DiscMap, "(STUBBED) called");
return ORBIS_OK;
return ORBIS_DISC_MAP_ERROR_NO_BITMAP_INFO;
}
void RegisterlibSceDiscMap(Core::Loader::SymbolsResolver* sym) {

View File

@ -10,10 +10,12 @@ class SymbolsResolver;
}
namespace Libraries::DiscMap {
int PS4_SYSV_ABI sceDiscMapGetPackageSize();
int PS4_SYSV_ABI sceDiscMapIsRequestOnHDD();
int PS4_SYSV_ABI Func_7C980FFB0AA27E7A();
int PS4_SYSV_ABI Func_8A828CAEE7EDD5E9();
int PS4_SYSV_ABI sceDiscMapGetPackageSize(s64 fflags, int* ret1, int* ret2);
int PS4_SYSV_ABI sceDiscMapIsRequestOnHDD(char* path, s64 offset, s64 nbytes, int* ret);
int PS4_SYSV_ABI Func_7C980FFB0AA27E7A(char* path, s64 offset, s64 nbytes, int* flags, int* ret1,
int* ret2);
int PS4_SYSV_ABI Func_8A828CAEE7EDD5E9(char* path, s64 offset, s64 nbytes, int* flags, int* ret1,
int* ret2);
int PS4_SYSV_ABI Func_E7EBCE96E92F91F8();
void RegisterlibSceDiscMap(Core::Loader::SymbolsResolver* sym);

View File

@ -1087,7 +1087,8 @@ s32 PS4_SYSV_ABI sceGnmInsertWaitFlipDone(u32* cmdbuf, u32 size, s32 vo_handle,
}
uintptr_t label_addr{};
VideoOut::sceVideoOutGetBufferLabelAddress(vo_handle, &label_addr);
ASSERT_MSG(VideoOut::sceVideoOutGetBufferLabelAddress(vo_handle, &label_addr) == 16,
"sceVideoOutGetBufferLabelAddress call failed");
auto* wait_reg_mem = reinterpret_cast<PM4CmdWaitRegMem*>(cmdbuf);
wait_reg_mem->header = PM4Type3Header{PM4ItOpcode::WaitRegMem, 5};
@ -2041,7 +2042,8 @@ static inline s32 PatchFlipRequest(u32* cmdbuf, u32 size, u32 vo_handle, u32 buf
}
uintptr_t label_addr{};
VideoOut::sceVideoOutGetBufferLabelAddress(vo_handle, &label_addr);
ASSERT_MSG(VideoOut::sceVideoOutGetBufferLabelAddress(vo_handle, &label_addr) == 16,
"sceVideoOutGetBufferLabelAddress call failed");
// Write event to lock the VO surface
auto* write_lock = reinterpret_cast<PM4CmdWriteData*>(cmdbuf);

File diff suppressed because it is too large Load Diff

View File

@ -65,10 +65,10 @@ constexpr int ORBIS_KERNEL_O_DSYNC = 0x1000;
constexpr int ORBIS_KERNEL_O_DIRECT = 0x00010000;
constexpr int ORBIS_KERNEL_O_DIRECTORY = 0x00020000;
s64 PS4_SYSV_ABI sceKernelWrite(int d, const void* buf, size_t nbytes);
s64 PS4_SYSV_ABI sceKernelRead(int d, void* buf, size_t nbytes);
s64 PS4_SYSV_ABI sceKernelPread(int d, void* buf, size_t nbytes, s64 offset);
s64 PS4_SYSV_ABI sceKernelPwrite(int d, void* buf, size_t nbytes, s64 offset);
s64 PS4_SYSV_ABI sceKernelWrite(s32 fd, const void* buf, size_t nbytes);
s64 PS4_SYSV_ABI sceKernelRead(s32 fd, void* buf, size_t nbytes);
s64 PS4_SYSV_ABI sceKernelPread(s32 fd, void* buf, size_t nbytes, s64 offset);
s64 PS4_SYSV_ABI sceKernelPwrite(s32 fd, void* buf, size_t nbytes, s64 offset);
void RegisterFileSystem(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel

View File

@ -85,17 +85,23 @@ int ErrnoToSceKernelError(int error) {
}
void SetPosixErrno(int e) {
// Some error numbers are different between supported OSes or the PS4
// Some error numbers are different between supported OSes
switch (e) {
case EPERM:
g_posix_errno = POSIX_EPERM;
break;
case EAGAIN:
g_posix_errno = POSIX_EAGAIN;
case ENOENT:
g_posix_errno = POSIX_ENOENT;
break;
case EDEADLK:
g_posix_errno = POSIX_EDEADLK;
break;
case ENOMEM:
g_posix_errno = POSIX_ENOMEM;
break;
case EACCES:
g_posix_errno = POSIX_EACCES;
break;
case EINVAL:
g_posix_errno = POSIX_EINVAL;
break;
@ -105,13 +111,14 @@ void SetPosixErrno(int e) {
case ERANGE:
g_posix_errno = POSIX_ERANGE;
break;
case EDEADLK:
g_posix_errno = POSIX_EDEADLK;
case EAGAIN:
g_posix_errno = POSIX_EAGAIN;
break;
case ETIMEDOUT:
g_posix_errno = POSIX_ETIMEDOUT;
break;
default:
LOG_WARNING(Kernel, "Unhandled errno {}", e);
g_posix_errno = e;
}
}
@ -133,14 +140,6 @@ void PS4_SYSV_ABI sceLibcHeapGetTraceInfo(HeapInfoInfo* info) {
info->getSegmentInfo = 0;
}
s64 PS4_SYSV_ABI ps4__write(int d, const char* buf, std::size_t nbytes) {
return sceKernelWrite(d, buf, nbytes);
}
s64 PS4_SYSV_ABI ps4__read(int d, void* buf, u64 nbytes) {
return sceKernelRead(d, buf, nbytes);
}
struct OrbisKernelUuid {
u32 timeLow;
u16 timeMid;
@ -229,13 +228,10 @@ void RegisterKernel(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("Xjoosiw+XPI", "libkernel", 1, "libkernel", 1, 1, sceKernelUuidCreate);
LIB_FUNCTION("Ou3iL1abvng", "libkernel", 1, "libkernel", 1, 1, stack_chk_fail);
LIB_FUNCTION("9BcDykPmo1I", "libkernel", 1, "libkernel", 1, 1, __Error);
LIB_FUNCTION("DRuBt2pvICk", "libkernel", 1, "libkernel", 1, 1, ps4__read);
LIB_FUNCTION("k+AXqu2-eBc", "libkernel", 1, "libkernel", 1, 1, posix_getpagesize);
LIB_FUNCTION("k+AXqu2-eBc", "libScePosix", 1, "libkernel", 1, 1, posix_getpagesize);
LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1,
sceLibcHeapGetTraceInfo);
LIB_FUNCTION("FxVZqBAA7ks", "libkernel", 1, "libkernel", 1, 1, ps4__write);
LIB_FUNCTION("FN4gaPmuFV8", "libScePosix", 1, "libkernel", 1, 1, ps4__write);
}
} // namespace Libraries::Kernel

View File

@ -5,6 +5,7 @@
#include <algorithm>
#include <fmt/core.h>
#include "common/string_literal.h"
#include "common/types.h"
#include "core/libraries/kernel/orbis_error.h"
@ -18,15 +19,6 @@ void ErrSceToPosix(int result);
int ErrnoToSceKernelError(int e);
void SetPosixErrno(int e);
template <size_t N>
struct StringLiteral {
constexpr StringLiteral(const char (&str)[N]) {
std::copy_n(str, N, value);
}
char value[N];
};
template <StringLiteral name, class F, F f>
struct WrapperImpl;

View File

@ -79,6 +79,9 @@ s32 PS4_SYSV_ABI sceKernelAllocateMainDirectMemory(size_t len, size_t alignment,
}
s32 PS4_SYSV_ABI sceKernelCheckedReleaseDirectMemory(u64 start, size_t len) {
if (len == 0) {
return ORBIS_OK;
}
LOG_INFO(Kernel_Vmm, "called start = {:#x}, len = {:#x}", start, len);
auto* memory = Core::Memory::Instance();
memory->Free(start, len);
@ -86,6 +89,9 @@ s32 PS4_SYSV_ABI sceKernelCheckedReleaseDirectMemory(u64 start, size_t len) {
}
s32 PS4_SYSV_ABI sceKernelReleaseDirectMemory(u64 start, size_t len) {
if (len == 0) {
return ORBIS_OK;
}
auto* memory = Core::Memory::Instance();
memory->Free(start, len);
return ORBIS_OK;
@ -507,7 +513,7 @@ s32 PS4_SYSV_ABI sceKernelConfiguredFlexibleMemorySize(u64* sizeOut) {
int PS4_SYSV_ABI sceKernelMunmap(void* addr, size_t len) {
LOG_INFO(Kernel_Vmm, "addr = {}, len = {:#x}", fmt::ptr(addr), len);
if (len == 0) {
return ORBIS_OK;
return ORBIS_KERNEL_ERROR_EINVAL;
}
auto* memory = Core::Memory::Instance();
return memory->UnmapMemory(std::bit_cast<VAddr>(addr), len);

View File

@ -32,44 +32,44 @@ void* PS4_SYSV_ABI sceKernelGetProcParam() {
return linker->GetProcParam();
}
s32 PS4_SYSV_ABI sceKernelLoadStartModule(const char* moduleFileName, size_t args, const void* argp,
s32 PS4_SYSV_ABI sceKernelLoadStartModule(const char* moduleFileName, u64 args, const void* argp,
u32 flags, const void* pOpt, int* pRes) {
LOG_INFO(Lib_Kernel, "called filename = {}, args = {}", moduleFileName, args);
if (flags != 0) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
ASSERT(flags == 0);
auto* mnt = Common::Singleton<Core::FileSys::MntPoints>::Instance();
const auto path = mnt->GetHostPath(moduleFileName);
// Load PRX module and relocate any modules that import it.
auto* linker = Common::Singleton<Core::Linker>::Instance();
u32 handle = linker->FindByName(path);
if (handle != -1) {
return handle;
}
handle = linker->LoadModule(path, true);
if (handle == -1) {
return ORBIS_KERNEL_ERROR_ESRCH;
}
auto* module = linker->GetModule(handle);
linker->RelocateAnyImports(module);
// If the new module has a TLS image, trigger its load when TlsGetAddr is called.
if (module->tls.image_size != 0) {
linker->AdvanceGenerationCounter();
std::filesystem::path path;
std::string guest_path(moduleFileName);
s32 handle = -1;
if (guest_path[0] == '/') {
// try load /system/common/lib/ +path
// try load /system/priv/lib/ +path
path = mnt->GetHostPath(guest_path);
handle = linker->LoadAndStartModule(path, args, argp, pRes);
if (handle != -1)
return handle;
} else {
if (!guest_path.contains('/')) {
path = mnt->GetHostPath("/app0/" + guest_path);
handle = linker->LoadAndStartModule(path, args, argp, pRes);
if (handle != -1)
return handle;
// if ((flags & 0x10000) != 0)
// try load /system/priv/lib/ +basename
// try load /system/common/lib/ +basename
} else {
path = mnt->GetHostPath(guest_path);
handle = linker->LoadAndStartModule(path, args, argp, pRes);
if (handle != -1)
return handle;
}
}
// Retrieve and verify proc param according to libkernel.
u64* param = module->GetProcParam<u64*>();
ASSERT_MSG(!param || param[0] >= 0x18, "Invalid module param size: {}", param[0]);
s32 ret = module->Start(args, argp, param);
if (pRes) {
*pRes = ret;
}
return handle;
return ORBIS_KERNEL_ERROR_ENOENT;
}
s32 PS4_SYSV_ABI sceKernelDlsym(s32 handle, const char* symbol, void** addrp) {
@ -85,19 +85,7 @@ s32 PS4_SYSV_ABI sceKernelDlsym(s32 handle, const char* symbol, void** addrp) {
return ORBIS_OK;
}
static constexpr size_t ORBIS_DBG_MAX_NAME_LENGTH = 256;
struct OrbisModuleInfoForUnwind {
u64 st_size;
std::array<char, ORBIS_DBG_MAX_NAME_LENGTH> name;
VAddr eh_frame_hdr_addr;
VAddr eh_frame_addr;
u64 eh_frame_size;
VAddr seg0_addr;
u64 seg0_size;
};
s32 PS4_SYSV_ABI sceKernelGetModuleInfoForUnwind(VAddr addr, int flags,
s32 PS4_SYSV_ABI sceKernelGetModuleInfoForUnwind(VAddr addr, s32 flags,
OrbisModuleInfoForUnwind* info) {
if (flags >= 3) {
std::memset(info, 0, sizeof(OrbisModuleInfoForUnwind));

View File

@ -11,10 +11,25 @@ class SymbolsResolver;
namespace Libraries::Kernel {
static constexpr size_t ORBIS_DBG_MAX_NAME_LENGTH = 256;
struct OrbisModuleInfoForUnwind {
u64 st_size;
std::array<char, ORBIS_DBG_MAX_NAME_LENGTH> name;
VAddr eh_frame_hdr_addr;
VAddr eh_frame_addr;
u64 eh_frame_size;
VAddr seg0_addr;
u64 seg0_size;
};
int PS4_SYSV_ABI sceKernelIsNeoMode();
int PS4_SYSV_ABI sceKernelGetCompiledSdkVersion(int* ver);
s32 PS4_SYSV_ABI sceKernelGetModuleInfoForUnwind(VAddr addr, s32 flags,
OrbisModuleInfoForUnwind* info);
void RegisterProcess(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel

View File

@ -5,6 +5,7 @@
#include "common/assert.h"
#include "common/native_clock.h"
#include "core/libraries/kernel/kernel.h"
#include "core/libraries/kernel/orbis_error.h"
#include "core/libraries/kernel/time.h"
#include "core/libraries/libs.h"
@ -19,6 +20,7 @@
#if __APPLE__
#include <date/tz.h>
#endif
#include <sys/resource.h>
#include <sys/time.h>
#include <time.h>
#include <unistd.h>
@ -93,44 +95,189 @@ u32 PS4_SYSV_ABI sceKernelSleep(u32 seconds) {
return 0;
}
int PS4_SYSV_ABI sceKernelClockGettime(s32 clock_id, OrbisKernelTimespec* tp) {
if (tp == nullptr) {
#ifdef _WIN64
#ifndef CLOCK_REALTIME
#define CLOCK_REALTIME 0
#endif
#ifndef CLOCK_MONOTONIC
#define CLOCK_MONOTONIC 1
#endif
#ifndef CLOCK_PROCESS_CPUTIME_ID
#define CLOCK_PROCESS_CPUTIME_ID 2
#endif
#ifndef CLOCK_THREAD_CPUTIME_ID
#define CLOCK_THREAD_CPUTIME_ID 3
#endif
#ifndef CLOCK_REALTIME_COARSE
#define CLOCK_REALTIME_COARSE 5
#endif
#ifndef CLOCK_MONOTONIC_COARSE
#define CLOCK_MONOTONIC_COARSE 6
#endif
#define DELTA_EPOCH_IN_100NS 116444736000000000ULL
static u64 FileTimeTo100Ns(FILETIME& ft) {
return *reinterpret_cast<u64*>(&ft);
}
static s32 clock_gettime(u32 clock_id, struct timespec* ts) {
switch (clock_id) {
case CLOCK_REALTIME:
case CLOCK_REALTIME_COARSE: {
FILETIME ft;
GetSystemTimeAsFileTime(&ft);
const u64 ns = FileTimeTo100Ns(ft) - DELTA_EPOCH_IN_100NS;
ts->tv_sec = ns / 10'000'000;
ts->tv_nsec = (ns % 10'000'000) * 100;
return 0;
}
case CLOCK_MONOTONIC:
case CLOCK_MONOTONIC_COARSE: {
static LARGE_INTEGER pf = [] {
LARGE_INTEGER res{};
QueryPerformanceFrequency(&pf);
return res;
}();
LARGE_INTEGER pc{};
QueryPerformanceCounter(&pc);
ts->tv_sec = pc.QuadPart / pf.QuadPart;
ts->tv_nsec = ((pc.QuadPart % pf.QuadPart) * 1000'000'000) / pf.QuadPart;
return 0;
}
case CLOCK_PROCESS_CPUTIME_ID: {
FILETIME ct, et, kt, ut;
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
return EFAULT;
}
const u64 ns = FileTimeTo100Ns(ut) + FileTimeTo100Ns(kt);
ts->tv_sec = ns / 10'000'000;
ts->tv_nsec = (ns % 10'000'000) * 100;
return 0;
}
case CLOCK_THREAD_CPUTIME_ID: {
FILETIME ct, et, kt, ut;
if (!GetThreadTimes(GetCurrentThread(), &ct, &et, &kt, &ut)) {
return EFAULT;
}
const u64 ns = FileTimeTo100Ns(ut) + FileTimeTo100Ns(kt);
ts->tv_sec = ns / 10'000'000;
ts->tv_nsec = (ns % 10'000'000) * 100;
return 0;
}
default:
return EINVAL;
}
}
#endif
int PS4_SYSV_ABI orbis_clock_gettime(s32 clock_id, struct OrbisKernelTimespec* ts) {
if (ts == nullptr) {
return ORBIS_KERNEL_ERROR_EFAULT;
}
clockid_t pclock_id = CLOCK_REALTIME;
clockid_t pclock_id = CLOCK_MONOTONIC;
switch (clock_id) {
case ORBIS_CLOCK_REALTIME:
case ORBIS_CLOCK_REALTIME_PRECISE:
case ORBIS_CLOCK_REALTIME_FAST:
pclock_id = CLOCK_REALTIME;
break;
case ORBIS_CLOCK_SECOND:
case ORBIS_CLOCK_REALTIME_FAST:
#ifndef __APPLE__
pclock_id = CLOCK_REALTIME_COARSE;
#else
pclock_id = CLOCK_REALTIME;
#endif
break;
case ORBIS_CLOCK_UPTIME:
case ORBIS_CLOCK_UPTIME_PRECISE:
case ORBIS_CLOCK_MONOTONIC:
case ORBIS_CLOCK_MONOTONIC_PRECISE:
case ORBIS_CLOCK_MONOTONIC_FAST:
pclock_id = CLOCK_MONOTONIC;
break;
default:
LOG_ERROR(Lib_Kernel, "unsupported = {} using CLOCK_REALTIME", clock_id);
case ORBIS_CLOCK_UPTIME_FAST:
case ORBIS_CLOCK_MONOTONIC_FAST:
#ifndef __APPLE__
pclock_id = CLOCK_MONOTONIC_COARSE;
#else
pclock_id = CLOCK_MONOTONIC;
#endif
break;
case ORBIS_CLOCK_THREAD_CPUTIME_ID:
pclock_id = CLOCK_THREAD_CPUTIME_ID;
break;
case ORBIS_CLOCK_PROCTIME: {
const auto us = sceKernelGetProcessTime();
ts->tv_sec = us / 1'000'000;
ts->tv_nsec = (us % 1'000'000) * 1000;
return 0;
}
case ORBIS_CLOCK_VIRTUAL: {
#ifdef _WIN64
FILETIME ct, et, kt, ut;
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
return EFAULT;
}
const u64 ns = FileTimeTo100Ns(ut);
ts->tv_sec = ns / 10'000'000;
ts->tv_nsec = (ns % 10'000'000) * 100;
#else
struct rusage ru;
const auto res = getrusage(RUSAGE_SELF, &ru);
if (res < 0) {
return res;
}
ts->tv_sec = ru.ru_utime.tv_sec;
ts->tv_nsec = ru.ru_utime.tv_usec * 1000;
#endif
return 0;
}
case ORBIS_CLOCK_PROF: {
#ifdef _WIN64
FILETIME ct, et, kt, ut;
if (!GetProcessTimes(GetCurrentProcess(), &ct, &et, &kt, &ut)) {
return EFAULT;
}
const u64 ns = FileTimeTo100Ns(kt);
ts->tv_sec = ns / 10'000'000;
ts->tv_nsec = (ns % 10'000'000) * 100;
#else
struct rusage ru;
const auto res = getrusage(RUSAGE_SELF, &ru);
if (res < 0) {
return res;
}
ts->tv_sec = ru.ru_stime.tv_sec;
ts->tv_nsec = ru.ru_stime.tv_usec * 1000;
#endif
return 0;
}
case ORBIS_CLOCK_EXT_NETWORK:
case ORBIS_CLOCK_EXT_DEBUG_NETWORK:
case ORBIS_CLOCK_EXT_AD_NETWORK:
case ORBIS_CLOCK_EXT_RAW_NETWORK:
pclock_id = CLOCK_MONOTONIC;
LOG_ERROR(Lib_Kernel, "unsupported = {} using CLOCK_MONOTONIC", clock_id);
break;
default:
return EINVAL;
}
timespec t{};
int result = clock_gettime(pclock_id, &t);
tp->tv_sec = t.tv_sec;
tp->tv_nsec = t.tv_nsec;
if (result == 0) {
return ORBIS_OK;
}
return ORBIS_KERNEL_ERROR_EINVAL;
ts->tv_sec = t.tv_sec;
ts->tv_nsec = t.tv_nsec;
return result;
}
int PS4_SYSV_ABI posix_clock_gettime(s32 clock_id, OrbisKernelTimespec* time) {
int result = sceKernelClockGettime(clock_id, time);
if (result < 0) {
UNREACHABLE(); // TODO return posix error code
int PS4_SYSV_ABI sceKernelClockGettime(s32 clock_id, OrbisKernelTimespec* tp) {
const auto res = orbis_clock_gettime(clock_id, tp);
if (res < 0) {
return ErrnoToSceKernelError(res);
}
return result;
return ORBIS_OK;
}
int PS4_SYSV_ABI posix_nanosleep(const OrbisKernelTimespec* rqtp, OrbisKernelTimespec* rmtp) {
@ -316,11 +463,11 @@ void RegisterTime(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("yS8U2TGCe1A", "libScePosix", 1, "libkernel", 1, 1, posix_nanosleep);
LIB_FUNCTION("QBi7HCK03hw", "libkernel", 1, "libkernel", 1, 1, sceKernelClockGettime);
LIB_FUNCTION("kOcnerypnQA", "libkernel", 1, "libkernel", 1, 1, sceKernelGettimezone);
LIB_FUNCTION("lLMT9vJAck0", "libkernel", 1, "libkernel", 1, 1, posix_clock_gettime);
LIB_FUNCTION("lLMT9vJAck0", "libScePosix", 1, "libkernel", 1, 1, posix_clock_gettime);
LIB_FUNCTION("lLMT9vJAck0", "libkernel", 1, "libkernel", 1, 1, orbis_clock_gettime);
LIB_FUNCTION("lLMT9vJAck0", "libScePosix", 1, "libkernel", 1, 1, orbis_clock_gettime);
LIB_FUNCTION("smIj7eqzZE8", "libScePosix", 1, "libkernel", 1, 1, posix_clock_getres);
LIB_FUNCTION("0NTHN1NKONI", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertLocaltimeToUtc);
LIB_FUNCTION("-o5uEDpN+oY", "libkernel", 1, "libkernel", 1, 1, sceKernelConvertUtcToLocaltime);
}
} // namespace Libraries::Kernel
} // namespace Libraries::Kernel

View File

@ -115,6 +115,7 @@ void InitHLELibs(Core::Loader::SymbolsResolver* sym) {
Libraries::NpParty::RegisterlibSceNpParty(sym);
Libraries::Zlib::RegisterlibSceZlib(sym);
Libraries::Hmd::RegisterlibSceHmd(sym);
Libraries::DiscMap::RegisterlibSceDiscMap(sym);
}
} // namespace Libraries

View File

@ -5,6 +5,7 @@
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "core/libraries/network/http.h"
#include "http_error.h"
namespace Libraries::Http {
@ -566,17 +567,277 @@ int PS4_SYSV_ABI sceHttpUriMerge() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceHttpUriParse() {
int PS4_SYSV_ABI sceHttpUriParse(OrbisHttpUriElement* out, const char* srcUri, void* pool,
size_t* require, size_t prepare) {
LOG_INFO(Lib_Http, "srcUri = {}", std::string(srcUri));
if (!srcUri) {
LOG_ERROR(Lib_Http, "invalid url");
return ORBIS_HTTP_ERROR_INVALID_URL;
}
if (!out && !pool && !require) {
LOG_ERROR(Lib_Http, "invalid values");
return ORBIS_HTTP_ERROR_INVALID_VALUE;
}
if (out && pool) {
memset(out, 0, sizeof(OrbisHttpUriElement));
out->scheme = (char*)pool;
}
// Track the total required buffer size
size_t requiredSize = 0;
// Parse the scheme (e.g., "http:", "https:", "file:")
size_t schemeLength = 0;
while (srcUri[schemeLength] && srcUri[schemeLength] != ':') {
if (!isalnum(srcUri[schemeLength])) {
LOG_ERROR(Lib_Http, "invalid url");
return ORBIS_HTTP_ERROR_INVALID_URL;
}
schemeLength++;
}
if (pool && prepare < schemeLength + 1) {
LOG_ERROR(Lib_Http, "out of memory");
return ORBIS_HTTP_ERROR_OUT_OF_MEMORY;
}
if (out && pool) {
memcpy(out->scheme, srcUri, schemeLength);
out->scheme[schemeLength] = '\0';
}
requiredSize += schemeLength + 1;
// Move past the scheme and ':' character
size_t offset = schemeLength + 1;
// Check if "//" appears after the scheme
if (strncmp(srcUri + offset, "//", 2) == 0) {
// "//" is present
if (out) {
out->opaque = false;
}
offset += 2; // Move past "//"
} else {
// "//" is not present
if (out) {
out->opaque = true;
}
}
// Handle "file" scheme
if (strncmp(srcUri, "file", 4) == 0) {
// File URIs typically start with "file://"
if (out && !out->opaque) {
// Skip additional slashes (e.g., "////")
while (srcUri[offset] == '/') {
offset++;
}
// Parse the path (everything after the slashes)
char* pathStart = (char*)srcUri + offset;
size_t pathLength = 0;
while (pathStart[pathLength] && pathStart[pathLength] != '?' &&
pathStart[pathLength] != '#') {
pathLength++;
}
// Ensure the path starts with '/'
if (pathLength > 0 && pathStart[0] != '/') {
// Prepend '/' to the path
requiredSize += pathLength + 2; // Include '/' and null terminator
if (pool && prepare < requiredSize) {
LOG_ERROR(Lib_Http, "out of memory");
return ORBIS_HTTP_ERROR_OUT_OF_MEMORY;
}
if (out && pool) {
out->path = (char*)pool + (requiredSize - pathLength - 2);
out->path[0] = '/'; // Add leading '/'
memcpy(out->path + 1, pathStart, pathLength);
out->path[pathLength + 1] = '\0';
}
} else {
// Path already starts with '/'
requiredSize += pathLength + 1;
if (pool && prepare < requiredSize) {
LOG_ERROR(Lib_Http, "out of memory");
return ORBIS_HTTP_ERROR_OUT_OF_MEMORY;
}
if (out && pool) {
memcpy((char*)pool + (requiredSize - pathLength - 1), pathStart, pathLength);
out->path = (char*)pool + (requiredSize - pathLength - 1);
out->path[pathLength] = '\0';
}
}
// Move past the path
offset += pathLength;
}
}
// Handle non-file schemes (e.g., "http", "https")
else {
// Parse the host and port
char* hostStart = (char*)srcUri + offset;
while (*hostStart == '/') {
hostStart++;
}
size_t hostLength = 0;
while (hostStart[hostLength] && hostStart[hostLength] != '/' &&
hostStart[hostLength] != '?' && hostStart[hostLength] != ':') {
hostLength++;
}
requiredSize += hostLength + 1;
if (pool && prepare < requiredSize) {
LOG_ERROR(Lib_Http, "out of memory");
return ORBIS_HTTP_ERROR_OUT_OF_MEMORY;
}
if (out && pool) {
memcpy((char*)pool + (requiredSize - hostLength - 1), hostStart, hostLength);
out->hostname = (char*)pool + (requiredSize - hostLength - 1);
out->hostname[hostLength] = '\0';
}
// Move past the host
offset += hostLength;
// Parse the port (if present)
if (hostStart[hostLength] == ':') {
char* portStart = hostStart + hostLength + 1;
size_t portLength = 0;
while (portStart[portLength] && isdigit(portStart[portLength])) {
portLength++;
}
requiredSize += portLength + 1;
if (pool && prepare < requiredSize) {
LOG_ERROR(Lib_Http, "out of memory");
return ORBIS_HTTP_ERROR_OUT_OF_MEMORY;
}
// Convert the port string to a uint16_t
char portStr[6]; // Max length for a port number (65535)
if (portLength > 5) {
LOG_ERROR(Lib_Http, "invalid url");
return ORBIS_HTTP_ERROR_INVALID_URL;
}
memcpy(portStr, portStart, portLength);
portStr[portLength] = '\0';
uint16_t port = (uint16_t)atoi(portStr);
if (port == 0 && portStr[0] != '0') {
LOG_ERROR(Lib_Http, "invalid url");
return ORBIS_HTTP_ERROR_INVALID_URL;
}
// Set the port in the output structure
if (out) {
out->port = port;
}
// Move past the port
offset += portLength + 1;
}
}
// Parse the path (if present)
if (srcUri[offset] == '/') {
char* pathStart = (char*)srcUri + offset;
size_t pathLength = 0;
while (pathStart[pathLength] && pathStart[pathLength] != '?' &&
pathStart[pathLength] != '#') {
pathLength++;
}
requiredSize += pathLength + 1;
if (pool && prepare < requiredSize) {
LOG_ERROR(Lib_Http, "out of memory");
return ORBIS_HTTP_ERROR_OUT_OF_MEMORY;
}
if (out && pool) {
memcpy((char*)pool + (requiredSize - pathLength - 1), pathStart, pathLength);
out->path = (char*)pool + (requiredSize - pathLength - 1);
out->path[pathLength] = '\0';
}
// Move past the path
offset += pathLength;
}
// Parse the query (if present)
if (srcUri[offset] == '?') {
char* queryStart = (char*)srcUri + offset + 1;
size_t queryLength = 0;
while (queryStart[queryLength] && queryStart[queryLength] != '#') {
queryLength++;
}
requiredSize += queryLength + 1;
if (pool && prepare < requiredSize) {
LOG_ERROR(Lib_Http, "out of memory");
return ORBIS_HTTP_ERROR_OUT_OF_MEMORY;
}
if (out && pool) {
memcpy((char*)pool + (requiredSize - queryLength - 1), queryStart, queryLength);
out->query = (char*)pool + (requiredSize - queryLength - 1);
out->query[queryLength] = '\0';
}
// Move past the query
offset += queryLength + 1;
}
// Parse the fragment (if present)
if (srcUri[offset] == '#') {
char* fragmentStart = (char*)srcUri + offset + 1;
size_t fragmentLength = 0;
while (fragmentStart[fragmentLength]) {
fragmentLength++;
}
requiredSize += fragmentLength + 1;
if (pool && prepare < requiredSize) {
LOG_ERROR(Lib_Http, "out of memory");
return ORBIS_HTTP_ERROR_OUT_OF_MEMORY;
}
if (out && pool) {
memcpy((char*)pool + (requiredSize - fragmentLength - 1), fragmentStart,
fragmentLength);
out->fragment = (char*)pool + (requiredSize - fragmentLength - 1);
out->fragment[fragmentLength] = '\0';
}
}
// Calculate the total required buffer size
if (require) {
*require = requiredSize; // Update with actual required size
}
return ORBIS_OK;
}
int PS4_SYSV_ABI sceHttpUriSweepPath(char* dst, const char* src, size_t srcSize) {
LOG_ERROR(Lib_Http, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceHttpUriSweepPath() {
LOG_ERROR(Lib_Http, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceHttpUriUnescape() {
int PS4_SYSV_ABI sceHttpUriUnescape(char* out, size_t* require, size_t prepare, const char* in) {
LOG_ERROR(Lib_Http, "(STUBBED) called");
return ORBIS_OK;
}

View File

@ -11,6 +11,19 @@ class SymbolsResolver;
namespace Libraries::Http {
struct OrbisHttpUriElement {
bool opaque;
char* scheme;
char* username;
char* password;
char* hostname;
char* path;
char* query;
char* fragment;
u16 port;
u8 reserved[10];
};
int PS4_SYSV_ABI sceHttpAbortRequest();
int PS4_SYSV_ABI sceHttpAbortRequestForce();
int PS4_SYSV_ABI sceHttpAbortWaitRequest();
@ -122,9 +135,10 @@ int PS4_SYSV_ABI sceHttpUriBuild();
int PS4_SYSV_ABI sceHttpUriCopy();
int PS4_SYSV_ABI sceHttpUriEscape();
int PS4_SYSV_ABI sceHttpUriMerge();
int PS4_SYSV_ABI sceHttpUriParse();
int PS4_SYSV_ABI sceHttpUriSweepPath();
int PS4_SYSV_ABI sceHttpUriUnescape();
int PS4_SYSV_ABI sceHttpUriParse(OrbisHttpUriElement* out, const char* srcUri, void* pool,
size_t* require, size_t prepare);
int PS4_SYSV_ABI sceHttpUriSweepPath(char* dst, const char* src, size_t srcSize);
int PS4_SYSV_ABI sceHttpUriUnescape(char* out, size_t* require, size_t prepare, const char* in);
int PS4_SYSV_ABI sceHttpWaitRequest();
void RegisterlibSceHttp(Core::Loader::SymbolsResolver* sym);

View File

@ -0,0 +1,66 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/libraries/error_codes.h"
constexpr int ORBIS_HTTP_ERROR_BEFORE_INIT = 0x80431001;
constexpr int ORBIS_HTTP_ERROR_ALREADY_INITED = 0x80431020;
constexpr int ORBIS_HTTP_ERROR_BUSY = 0x80431021;
constexpr int ORBIS_HTTP_ERROR_OUT_OF_MEMORY = 0x80431022;
constexpr int ORBIS_HTTP_ERROR_NOT_FOUND = 0x80431025;
constexpr int ORBIS_HTTP_ERROR_INVALID_VERSION = 0x8043106a;
constexpr int ORBIS_HTTP_ERROR_INVALID_ID = 0x80431100;
constexpr int ORBIS_HTTP_ERROR_OUT_OF_SIZE = 0x80431104;
constexpr int ORBIS_HTTP_ERROR_INVALID_VALUE = 0x804311fe;
constexpr int ORBIS_HTTP_ERROR_INVALID_URL = 0x80433060;
constexpr int ORBIS_HTTP_ERROR_UNKNOWN_SCHEME = 0x80431061;
constexpr int ORBIS_HTTP_ERROR_NETWORK = 0x80431063;
constexpr int ORBIS_HTTP_ERROR_BAD_RESPONSE = 0x80431064;
constexpr int ORBIS_HTTP_ERROR_BEFORE_SEND = 0x80431065;
constexpr int ORBIS_HTTP_ERROR_AFTER_SEND = 0x80431066;
constexpr int ORBIS_HTTP_ERROR_TIMEOUT = 0x80431068;
constexpr int ORBIS_HTTP_ERROR_UNKNOWN_AUTH_TYPE = 0x80431069;
constexpr int ORBIS_HTTP_ERROR_UNKNOWN_METHOD = 0x8043106b;
constexpr int ORBIS_HTTP_ERROR_READ_BY_HEAD_METHOD = 0x8043106f;
constexpr int ORBIS_HTTP_ERROR_NOT_IN_COM = 0x80431070;
constexpr int ORBIS_HTTP_ERROR_NO_CONTENT_LENGTH = 0x80431071;
constexpr int ORBIS_HTTP_ERROR_CHUNK_ENC = 0x80431072;
constexpr int ORBIS_HTTP_ERROR_TOO_LARGE_RESPONSE_HEADER = 0x80431073;
constexpr int ORBIS_HTTP_ERROR_SSL = 0x80431075;
constexpr int ORBIS_HTTP_ERROR_INSUFFICIENT_STACKSIZE = 0x80431076;
constexpr int ORBIS_HTTP_ERROR_ABORTED = 0x80431080;
constexpr int ORBIS_HTTP_ERROR_UNKNOWN = 0x80431081;
constexpr int ORBIS_HTTP_ERROR_EAGAIN = 0x80431082;
constexpr int ORBIS_HTTP_ERROR_PROXY = 0x80431084;
constexpr int ORBIS_HTTP_ERROR_BROKEN = 0x80431085;
constexpr int ORBIS_HTTP_ERROR_PARSE_HTTP_NOT_FOUND = 0x80432025;
constexpr int ORBIS_HTTP_ERROR_PARSE_HTTP_INVALID_RESPONSE = 0x80432060;
constexpr int ORBIS_HTTP_ERROR_PARSE_HTTP_INVALID_VALUE = 0x804321fe;
constexpr int ORBIS_HTTP_ERROR_RESOLVER_EPACKET = 0x80436001;
constexpr int ORBIS_HTTP_ERROR_RESOLVER_ENODNS = 0x80436002;
constexpr int ORBIS_HTTP_ERROR_RESOLVER_ETIMEDOUT = 0x80436003;
constexpr int ORBIS_HTTP_ERROR_RESOLVER_ENOSUPPORT = 0x80436004;
constexpr int ORBIS_HTTP_ERROR_RESOLVER_EFORMAT = 0x80436005;
constexpr int ORBIS_HTTP_ERROR_RESOLVER_ESERVERFAILURE = 0x80436006;
constexpr int ORBIS_HTTP_ERROR_RESOLVER_ENOHOST = 0x80436007;
constexpr int ORBIS_HTTP_ERROR_RESOLVER_ENOTIMPLEMENTED = 0x80436008;
constexpr int ORBIS_HTTP_ERROR_RESOLVER_ESERVERREFUSED = 0x80436009;
constexpr int ORBIS_HTTP_ERROR_RESOLVER_ENORECORD = 0x8043600a;
constexpr int ORBIS_HTTPS_ERROR_CERT = 0x80435060;
constexpr int ORBIS_HTTPS_ERROR_HANDSHAKE = 0x80435061;
constexpr int ORBIS_HTTPS_ERROR_IO = 0x80435062;
constexpr int ORBIS_HTTPS_ERROR_INTERNAL = 0x80435063;
constexpr int ORBIS_HTTPS_ERROR_PROXY = 0x80435064;
constexpr int ORBIS_HTTPS_ERROR_SSL_INTERNAL = 0x01;
constexpr int ORBIS_HTTPS_ERROR_SSL_INVALID_CERT = 0x02;
constexpr int ORBIS_HTTPS_ERROR_SSL_CN_CHECK = 0x04;
constexpr int ORBIS_HTTPS_ERROR_SSL_NOT_AFTER_CHECK = 0x08;
constexpr int ORBIS_HTTPS_ERROR_SSL_NOT_BEFORE_CHECK = 0x10;
constexpr int ORBIS_HTTPS_ERROR_SSL_UNKNOWN_CA = 0x20;

View File

@ -5,21 +5,480 @@
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "core/libraries/ngs2/ngs2.h"
#include "core/libraries/ngs2/ngs2_custom.h"
#include "core/libraries/ngs2/ngs2_error.h"
#include "core/libraries/ngs2/ngs2_geom.h"
#include "core/libraries/ngs2/ngs2_impl.h"
#include "core/libraries/ngs2/ngs2_pan.h"
#include "core/libraries/ngs2/ngs2_report.h"
namespace Libraries::Ngs2 {
int PS4_SYSV_ABI sceNgs2CalcWaveformBlock() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
// Ngs2
s32 PS4_SYSV_ABI sceNgs2CalcWaveformBlock(const OrbisNgs2WaveformFormat* format, u32 samplePos,
u32 numSamples, OrbisNgs2WaveformBlock* outBlock) {
LOG_INFO(Lib_Ngs2, "samplePos = {}, numSamples = {}", samplePos, numSamples);
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2CustomRackGetModuleInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
s32 PS4_SYSV_ABI sceNgs2GetWaveformFrameInfo(const OrbisNgs2WaveformFormat* format,
u32* outFrameSize, u32* outNumFrameSamples,
u32* outUnitsPerFrame, u32* outNumDelaySamples) {
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2ParseWaveformData(const void* data, size_t dataSize,
OrbisNgs2WaveformInfo* outInfo) {
LOG_INFO(Lib_Ngs2, "dataSize = {}", dataSize);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2ParseWaveformFile(const char* path, u64 offset,
OrbisNgs2WaveformInfo* outInfo) {
LOG_INFO(Lib_Ngs2, "path = {}, offset = {}", path, offset);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2ParseWaveformUser(OrbisNgs2ParseReadHandler handler, uintptr_t userData,
OrbisNgs2WaveformInfo* outInfo) {
LOG_INFO(Lib_Ngs2, "userData = {}", userData);
if (!handler) {
LOG_ERROR(Lib_Ngs2, "handler is nullptr");
return ORBIS_NGS2_ERROR_INVALID_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackCreate(OrbisNgs2Handle systemHandle, u32 rackId,
const OrbisNgs2RackOption* option,
const OrbisNgs2ContextBufferInfo* bufferInfo,
OrbisNgs2Handle* outHandle) {
LOG_INFO(Lib_Ngs2, "rackId = {}", rackId);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackCreateWithAllocator(OrbisNgs2Handle systemHandle, u32 rackId,
const OrbisNgs2RackOption* option,
const OrbisNgs2BufferAllocator* allocator,
OrbisNgs2Handle* outHandle) {
LOG_INFO(Lib_Ngs2, "rackId = {}", rackId);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackDestroy(OrbisNgs2Handle rackHandle,
OrbisNgs2ContextBufferInfo* outBufferInfo) {
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackGetInfo(OrbisNgs2Handle rackHandle, OrbisNgs2RackInfo* outInfo,
size_t infoSize) {
LOG_INFO(Lib_Ngs2, "infoSize = {}", infoSize);
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackGetUserData(OrbisNgs2Handle rackHandle, uintptr_t* outUserData) {
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackGetVoiceHandle(OrbisNgs2Handle rackHandle, u32 voiceIndex,
OrbisNgs2Handle* outHandle) {
LOG_INFO(Lib_Ngs2, "voiceIndex = {}", voiceIndex);
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackLock(OrbisNgs2Handle rackHandle) {
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackQueryBufferSize(u32 rackId, const OrbisNgs2RackOption* option,
OrbisNgs2ContextBufferInfo* outBufferInfo) {
LOG_INFO(Lib_Ngs2, "rackId = {}", rackId);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackSetUserData(OrbisNgs2Handle rackHandle, uintptr_t userData) {
LOG_INFO(Lib_Ngs2, "userData = {}", userData);
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2RackUnlock(OrbisNgs2Handle rackHandle) {
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemCreate(const OrbisNgs2SystemOption* option,
const OrbisNgs2ContextBufferInfo* bufferInfo,
OrbisNgs2Handle* outHandle) {
s32 result;
OrbisNgs2ContextBufferInfo localInfo;
if (!bufferInfo || !outHandle) {
if (!bufferInfo) {
result = ORBIS_NGS2_ERROR_INVALID_BUFFER_INFO;
LOG_ERROR(Lib_Ngs2, "Invalid system buffer info {}", (void*)bufferInfo);
} else {
result = ORBIS_NGS2_ERROR_INVALID_OUT_ADDRESS;
LOG_ERROR(Lib_Ngs2, "Invalid system handle address {}", (void*)outHandle);
}
// TODO: Report errors?
} else {
// Make bufferInfo copy
localInfo.hostBuffer = bufferInfo->hostBuffer;
localInfo.hostBufferSize = bufferInfo->hostBufferSize;
for (int i = 0; i < 5; i++) {
localInfo.reserved[i] = bufferInfo->reserved[i];
}
localInfo.userData = bufferInfo->userData;
result = SystemSetup(option, &localInfo, 0, outHandle);
}
// TODO: API reporting?
LOG_INFO(Lib_Ngs2, "called");
return result;
}
s32 PS4_SYSV_ABI sceNgs2SystemCreateWithAllocator(const OrbisNgs2SystemOption* option,
const OrbisNgs2BufferAllocator* allocator,
OrbisNgs2Handle* outHandle) {
s32 result;
if (allocator && allocator->allocHandler != 0) {
OrbisNgs2BufferAllocHandler hostAlloc = allocator->allocHandler;
if (outHandle) {
OrbisNgs2BufferFreeHandler hostFree = allocator->freeHandler;
OrbisNgs2ContextBufferInfo* bufferInfo = 0;
result = SystemSetup(option, bufferInfo, 0, 0);
if (result >= 0) {
uintptr_t sysUserData = allocator->userData;
result = hostAlloc(bufferInfo);
if (result >= 0) {
OrbisNgs2Handle* handleCopy = outHandle;
result = SystemSetup(option, bufferInfo, hostFree, handleCopy);
if (result < 0) {
if (hostFree) {
hostFree(bufferInfo);
}
}
}
}
} else {
result = ORBIS_NGS2_ERROR_INVALID_OUT_ADDRESS;
LOG_ERROR(Lib_Ngs2, "Invalid system handle address {}", (void*)outHandle);
}
} else {
result = ORBIS_NGS2_ERROR_INVALID_BUFFER_ALLOCATOR;
LOG_ERROR(Lib_Ngs2, "Invalid system buffer allocator {}", (void*)allocator);
}
LOG_INFO(Lib_Ngs2, "called");
return result;
}
s32 PS4_SYSV_ABI sceNgs2SystemDestroy(OrbisNgs2Handle systemHandle,
OrbisNgs2ContextBufferInfo* outBufferInfo) {
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemEnumHandles(OrbisNgs2Handle* aOutHandle, u32 maxHandles) {
LOG_INFO(Lib_Ngs2, "maxHandles = {}", maxHandles);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemEnumRackHandles(OrbisNgs2Handle systemHandle,
OrbisNgs2Handle* aOutHandle, u32 maxHandles) {
LOG_INFO(Lib_Ngs2, "maxHandles = {}", maxHandles);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemGetInfo(OrbisNgs2Handle rackHandle, OrbisNgs2SystemInfo* outInfo,
size_t infoSize) {
LOG_INFO(Lib_Ngs2, "infoSize = {}", infoSize);
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemGetUserData(OrbisNgs2Handle systemHandle, uintptr_t* outUserData) {
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemLock(OrbisNgs2Handle systemHandle) {
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemQueryBufferSize(const OrbisNgs2SystemOption* option,
OrbisNgs2ContextBufferInfo* outBufferInfo) {
s32 result;
if (outBufferInfo) {
result = SystemSetup(option, outBufferInfo, 0, 0);
LOG_INFO(Lib_Ngs2, "called");
} else {
result = ORBIS_NGS2_ERROR_INVALID_OUT_ADDRESS;
LOG_ERROR(Lib_Ngs2, "Invalid system buffer info {}", (void*)outBufferInfo);
}
return result;
}
s32 PS4_SYSV_ABI sceNgs2SystemRender(OrbisNgs2Handle systemHandle,
const OrbisNgs2RenderBufferInfo* aBufferInfo,
u32 numBufferInfo) {
LOG_INFO(Lib_Ngs2, "numBufferInfo = {}", numBufferInfo);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
return ORBIS_OK;
}
static s32 PS4_SYSV_ABI sceNgs2SystemResetOption(OrbisNgs2SystemOption* outOption) {
static const OrbisNgs2SystemOption option = {
sizeof(OrbisNgs2SystemOption), "", 0, 512, 256, 48000, {0}};
if (!outOption) {
LOG_ERROR(Lib_Ngs2, "Invalid system option address {}", (void*)outOption);
return ORBIS_NGS2_ERROR_INVALID_OPTION_ADDRESS;
}
*outOption = option;
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemSetGrainSamples(OrbisNgs2Handle systemHandle, u32 numSamples) {
LOG_INFO(Lib_Ngs2, "numSamples = {}", numSamples);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemSetSampleRate(OrbisNgs2Handle systemHandle, u32 sampleRate) {
LOG_INFO(Lib_Ngs2, "sampleRate = {}", sampleRate);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemSetUserData(OrbisNgs2Handle systemHandle, uintptr_t userData) {
LOG_INFO(Lib_Ngs2, "userData = {}", userData);
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2SystemUnlock(OrbisNgs2Handle systemHandle) {
if (!systemHandle) {
LOG_ERROR(Lib_Ngs2, "systemHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceControl(OrbisNgs2Handle voiceHandle,
const OrbisNgs2VoiceParamHeader* paramList) {
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceGetMatrixInfo(OrbisNgs2Handle voiceHandle, u32 matrixId,
OrbisNgs2VoiceMatrixInfo* outInfo, size_t outInfoSize) {
LOG_INFO(Lib_Ngs2, "matrixId = {}, outInfoSize = {}", matrixId, outInfoSize);
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceGetOwner(OrbisNgs2Handle voiceHandle, OrbisNgs2Handle* outRackHandle,
u32* outVoiceId) {
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceGetPortInfo(OrbisNgs2Handle voiceHandle, u32 port,
OrbisNgs2VoicePortInfo* outInfo, size_t outInfoSize) {
LOG_INFO(Lib_Ngs2, "port = {}, outInfoSize = {}", port, outInfoSize);
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceGetState(OrbisNgs2Handle voiceHandle, OrbisNgs2VoiceState* outState,
size_t stateSize) {
LOG_INFO(Lib_Ngs2, "stateSize = {}", stateSize);
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2VoiceGetStateFlags(OrbisNgs2Handle voiceHandle, u32* outStateFlags) {
if (!voiceHandle) {
LOG_ERROR(Lib_Ngs2, "voiceHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
// Ngs2Custom
s32 PS4_SYSV_ABI sceNgs2CustomRackGetModuleInfo(OrbisNgs2Handle rackHandle, u32 moduleIndex,
OrbisNgs2CustomModuleInfo* outInfo,
size_t infoSize) {
LOG_INFO(Lib_Ngs2, "moduleIndex = {}, infoSize = {}", moduleIndex, infoSize);
if (!rackHandle) {
LOG_ERROR(Lib_Ngs2, "rackHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
}
return ORBIS_OK;
}
// Ngs2Geom
s32 PS4_SYSV_ABI sceNgs2GeomResetListenerParam(OrbisNgs2GeomListenerParam* outListenerParam) {
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2GeomResetSourceParam(OrbisNgs2GeomSourceParam* outSourceParam) {
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2GeomCalcListener(const OrbisNgs2GeomListenerParam* param,
OrbisNgs2GeomListenerWork* outWork, u32 flags) {
LOG_INFO(Lib_Ngs2, "flags = {}", flags);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2GeomApply(const OrbisNgs2GeomListenerWork* listener,
const OrbisNgs2GeomSourceParam* source,
OrbisNgs2GeomAttribute* outAttrib, u32 flags) {
LOG_INFO(Lib_Ngs2, "flags = {}", flags);
return ORBIS_OK;
}
// Ngs2Pan
s32 PS4_SYSV_ABI sceNgs2PanInit(OrbisNgs2PanWork* work, const float* aSpeakerAngle, float unitAngle,
u32 numSpeakers) {
LOG_INFO(Lib_Ngs2, "aSpeakerAngle = {}, unitAngle = {}, numSpeakers = {}", *aSpeakerAngle,
unitAngle, numSpeakers);
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2PanGetVolumeMatrix(OrbisNgs2PanWork* work, const OrbisNgs2PanParam* aParam,
u32 numParams, u32 matrixFormat,
float* outVolumeMatrix) {
LOG_INFO(Lib_Ngs2, "numParams = {}, matrixFormat = {}", numParams, matrixFormat);
return ORBIS_OK;
}
// Ngs2Report
s32 PS4_SYSV_ABI sceNgs2ReportRegisterHandler(u32 reportType, OrbisNgs2ReportHandler handler,
uintptr_t userData, OrbisNgs2Handle* outHandle) {
LOG_INFO(Lib_Ngs2, "reportType = {}, userData = {}", reportType, userData);
if (!handler) {
LOG_ERROR(Lib_Ngs2, "handler is nullptr");
return ORBIS_NGS2_ERROR_INVALID_REPORT_HANDLE;
}
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNgs2ReportUnregisterHandler(OrbisNgs2Handle reportHandle) {
if (!reportHandle) {
LOG_ERROR(Lib_Ngs2, "reportHandle is nullptr");
return ORBIS_NGS2_ERROR_INVALID_REPORT_HANDLE;
}
LOG_INFO(Lib_Ngs2, "called");
return ORBIS_OK;
}
// Unknown
int PS4_SYSV_ABI sceNgs2FftInit() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
@ -35,31 +494,6 @@ int PS4_SYSV_ABI sceNgs2FftQuerySize() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2GeomApply() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2GeomCalcListener() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2GeomResetListenerParam() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2GeomResetSourceParam() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2GetWaveformFrameInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2JobSchedulerResetOption() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
@ -80,71 +514,6 @@ int PS4_SYSV_ABI sceNgs2ModuleQueueEnumItems() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2PanGetVolumeMatrix() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2PanInit() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2ParseWaveformData() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2ParseWaveformFile() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2ParseWaveformUser() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackCreate() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackCreateWithAllocator() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackDestroy() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackGetInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackGetUserData() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackGetVoiceHandle() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackLock() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackQueryBufferSize() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackQueryInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
@ -155,116 +524,21 @@ int PS4_SYSV_ABI sceNgs2RackRunCommands() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackSetUserData() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2RackUnlock() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2ReportRegisterHandler() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2ReportUnregisterHandler() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemCreate() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemCreateWithAllocator() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemDestroy() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemEnumHandles() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemEnumRackHandles() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemGetInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemGetUserData() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemLock() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemQueryBufferSize() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemQueryInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemRender() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemResetOption() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemRunCommands() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemSetGrainSamples() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemSetLoudThreshold() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemSetSampleRate() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemSetUserData() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2SystemUnlock() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2StreamCreate() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
@ -300,36 +574,6 @@ int PS4_SYSV_ABI sceNgs2StreamRunCommands() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2VoiceControl() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2VoiceGetMatrixInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2VoiceGetOwner() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2VoiceGetPortInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2VoiceGetState() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2VoiceGetStateFlags() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;
}
int PS4_SYSV_ABI sceNgs2VoiceQueryInfo() {
LOG_ERROR(Lib_Ngs2, "(STUBBED) called");
return ORBIS_OK;

View File

@ -3,7 +3,11 @@
#pragma once
#include "core/libraries/ngs2/ngs2_impl.h"
#include <atomic>
#include <mutex>
#include <vector>
#include "common/types.h"
namespace Core::Loader {
@ -12,60 +16,253 @@ class SymbolsResolver;
namespace Libraries::Ngs2 {
class Ngs2;
typedef s32 (*OrbisNgs2ParseReadHandler)(uintptr_t userData, u32 offset, void* data, size_t size);
using SceNgs2Handle = Ngs2*;
enum class SceNgs2HandleType : u32 {
System = 0,
enum class OrbisNgs2HandleType : u32 {
Invalid = 0,
System = 1,
Rack = 2,
Voice = 3,
VoiceControl = 6
};
struct Ngs2Handle {
void* selfPointer;
void* dataPointer;
std::atomic<u32>* atomicPtr;
u32 handleType;
u32 flags_unk;
static const int ORBIS_NGS2_MAX_VOICE_CHANNELS = 8;
static const int ORBIS_NGS2_WAVEFORM_INFO_MAX_BLOCKS = 4;
static const int ORBIS_NGS2_MAX_MATRIX_LEVELS =
(ORBIS_NGS2_MAX_VOICE_CHANNELS * ORBIS_NGS2_MAX_VOICE_CHANNELS);
u32 uid;
u16 maxGrainSamples;
u16 minGrainSamples;
u16 currentGrainSamples;
u16 numGrainSamples;
u16 unknown2;
struct OrbisNgs2WaveformFormat {
u32 waveformType;
u32 numChannels;
u32 sampleRate;
u32 unknown3;
void* flushMutex;
u32 flushMutexInitialized;
void* processMutex;
u32 processMutexInitialized;
// Linked list pointers for system list
Ngs2Handle* prev;
Ngs2Handle* next;
u32 configData;
u32 frameOffset;
u32 frameMargin;
};
struct SystemOptions {
char padding[6];
s32 maxGrainSamples;
s32 numGrainSamples;
s32 sampleRate;
struct OrbisNgs2WaveformBlock {
u32 dataOffset;
u32 dataSize;
u32 numRepeats;
u32 numSkipSamples;
u32 numSamples;
u32 reserved;
uintptr_t userData;
};
struct SystemState {
// TODO
struct OrbisNgs2WaveformInfo {
OrbisNgs2WaveformFormat format;
u32 dataOffset;
u32 dataSize;
u32 loopBeginPosition;
u32 loopEndPosition;
u32 numSamples;
u32 audioUnitSize;
u32 numAudioUnitSamples;
u32 numAudioUnitPerFrame;
u32 audioFrameSize;
u32 numAudioFrameSamples;
u32 numDelaySamples;
u32 numBlocks;
OrbisNgs2WaveformBlock aBlock[ORBIS_NGS2_WAVEFORM_INFO_MAX_BLOCKS];
};
struct StackBuffer {
void** top;
void* base;
void* curr;
size_t usedSize;
size_t totalSize;
size_t alignment;
char isVerifyEnabled;
char padding[7];
struct OrbisNgs2EnvelopePoint {
u32 curve;
u32 duration;
float height;
};
struct OrbisNgs2UserFxProcessContext {
float** aChannelData;
uintptr_t userData0;
uintptr_t userData1;
uintptr_t userData2;
u32 flags;
u32 numChannels;
u32 numGrainSamples;
u32 sampleRate;
};
typedef s32 (*OrbisNgs2UserFxProcessHandler)(OrbisNgs2UserFxProcessContext* context);
struct OrbisNgs2UserFx2SetupContext {
void* common;
void* param;
void* work;
uintptr_t userData;
u32 maxVoices;
u32 voiceIndex;
u64 reserved[4];
};
typedef s32 (*OrbisNgs2UserFx2SetupHandler)(OrbisNgs2UserFx2SetupContext* context);
struct OrbisNgs2UserFx2CleanupContext {
void* common;
void* param;
void* work;
uintptr_t userData;
u32 maxVoices;
u32 voiceIndex;
u64 reserved[4];
};
typedef s32 (*OrbisNgs2UserFx2CleanupHandler)(OrbisNgs2UserFx2CleanupContext* context);
struct OrbisNgs2UserFx2ControlContext {
const void* data;
size_t dataSize;
void* common;
void* param;
uintptr_t userData;
u64 reserved[4];
};
typedef s32 (*OrbisNgs2UserFx2ControlHandler)(OrbisNgs2UserFx2ControlContext* context);
struct OrbisNgs2UserFx2ProcessContext {
float** aChannelData;
void* common;
const void* param;
void* work;
void* state;
uintptr_t userData;
u32 flags;
u32 numInputChannels;
u32 numOutputChannels;
u32 numGrainSamples;
u32 sampleRate;
u32 reserved;
u64 reserved2[4];
};
typedef s32 (*OrbisNgs2UserFx2ProcessHandler)(OrbisNgs2UserFx2ProcessContext* context);
struct OrbisNgs2BufferAllocator {
OrbisNgs2BufferAllocHandler allocHandler;
OrbisNgs2BufferFreeHandler freeHandler;
uintptr_t userData;
};
struct OrbisNgs2RenderBufferInfo {
void* buffer;
size_t bufferSize;
u32 waveformType;
u32 numChannels;
};
struct OrbisNgs2RackOption {
size_t size;
char name[ORBIS_NGS2_RACK_NAME_LENGTH];
u32 flags;
u32 maxGrainSamples;
u32 maxVoices;
u32 maxInputDelayBlocks;
u32 maxMatrices;
u32 maxPorts;
u32 aReserved[20];
};
struct OrbisNgs2VoiceParamHeader {
u16 size;
s16 next;
u32 id;
};
struct OrbisNgs2VoiceMatrixLevelsParam {
OrbisNgs2VoiceParamHeader header;
u32 matrixId;
u32 numLevels;
const float* aLevel;
};
struct OrbisNgs2VoicePortMatrixParam {
OrbisNgs2VoiceParamHeader header;
u32 port;
s32 matrixId;
};
struct OrbisNgs2VoicePortVolumeParam {
OrbisNgs2VoiceParamHeader header;
u32 port;
float level;
};
struct OrbisNgs2VoicePortDelayParam {
OrbisNgs2VoiceParamHeader header;
u32 port;
u32 numSamples;
};
struct OrbisNgs2VoicePatchParam {
OrbisNgs2VoiceParamHeader header;
u32 port;
u32 destInputId;
OrbisNgs2Handle destHandle;
};
struct OrbisNgs2VoiceEventParam {
OrbisNgs2VoiceParamHeader header;
u32 eventId;
};
struct OrbisNgs2VoiceCallbackInfo {
uintptr_t callbackData;
OrbisNgs2Handle voiceHandle;
u32 flag;
u32 reserved;
union {
struct {
uintptr_t userData;
const void* data;
u32 dataSize;
u32 repeatedCount;
u32 attributeFlags;
u32 reserved2;
} waveformBlock;
} param;
};
typedef void (*OrbisNgs2VoiceCallbackHandler)(const OrbisNgs2VoiceCallbackInfo* info);
struct OrbisNgs2VoiceCallbackParam {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2VoiceCallbackHandler callbackHandler;
uintptr_t callbackData;
u32 flags;
u32 reserved;
};
struct OrbisNgs2VoicePortInfo {
s32 matrixId;
float volume;
u32 numDelaySamples;
u32 destInputId;
OrbisNgs2Handle destHandle;
};
struct OrbisNgs2VoiceMatrixInfo {
u32 numLevels;
float aLevel[ORBIS_NGS2_MAX_MATRIX_LEVELS];
};
struct OrbisNgs2VoiceState {
u32 stateFlags;
};
void RegisterlibSceNgs2(Core::Loader::SymbolsResolver* sym);

View File

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View File

@ -0,0 +1,444 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
#include "ngs2_reverb.h"
namespace Libraries::Ngs2 {
class Ngs2Custom;
static const int ORBIS_NGS2_CUSTOM_MAX_MODULES = 24;
static const int ORBIS_NGS2_CUSTOM_MAX_PORTS = 16;
static const int ORBIS_NGS2_CUSTOM_DELAY_MAX_TAPS = 8;
struct OrbisNgs2CustomModuleOption {
u32 size;
};
struct OrbisNgs2CustomEnvelopeModuleOption {
OrbisNgs2CustomModuleOption customModuleOption;
u32 maxPoints;
u32 reserved;
};
struct OrbisNgs2CustomReverbModuleOption {
OrbisNgs2CustomModuleOption customModuleOption;
u32 reverbSize;
u32 reserved;
};
struct OrbisNgs2CustomChorusModuleOption {
OrbisNgs2CustomModuleOption customModuleOption;
u32 maxPhases;
u32 reserved;
} OrbisNgs2CustomChorusModuleOption;
struct OrbisNgs2CustomPeakMeterModuleOption {
OrbisNgs2CustomModuleOption customModuleOption;
u32 numBlocks;
u32 reserved;
};
struct OrbisNgs2CustomDelayModuleOption {
OrbisNgs2CustomModuleOption customModuleOption;
u32 type;
u32 maxTaps;
float maxLength;
u32 reserved;
};
struct OrbisNgs2CustomPitchShiftModuleOption {
OrbisNgs2CustomModuleOption customModuleOption;
u32 quality;
};
struct OrbisNgs2CustomUserFx2ModuleOption {
OrbisNgs2CustomModuleOption customModuleOption;
OrbisNgs2UserFx2SetupHandler setupHandler;
OrbisNgs2UserFx2CleanupHandler cleanupHandler;
OrbisNgs2UserFx2ControlHandler controlHandler;
OrbisNgs2UserFx2ProcessHandler processHandler;
size_t commonSize;
size_t paramSize;
size_t workSize;
uintptr_t userData;
};
struct OrbisNgs2CustomRackModuleInfo {
const OrbisNgs2CustomModuleOption* option;
u32 moduleId;
u32 sourceBufferId;
u32 extraBufferId;
u32 destBufferId;
u32 stateOffset;
u32 stateSize;
u32 reserved;
u32 reserved2;
};
struct OrbisNgs2CustomRackPortInfo {
u32 sourceBufferId;
u32 reserved;
};
struct OrbisNgs2CustomRackOption {
OrbisNgs2RackOption rackOption;
u32 stateSize;
u32 numBuffers;
u32 numModules;
u32 reserved;
OrbisNgs2CustomRackModuleInfo aModule[ORBIS_NGS2_CUSTOM_MAX_MODULES];
OrbisNgs2CustomRackPortInfo aPort[ORBIS_NGS2_CUSTOM_MAX_PORTS];
};
struct OrbisNgs2CustomSamplerRackOption {
OrbisNgs2CustomRackOption customRackOption;
u32 maxChannelWorks;
u32 maxWaveformBlocks;
u32 maxAtrac9Decoders;
u32 maxAtrac9ChannelWorks;
u32 maxAjmAtrac9Decoders;
u32 maxCodecCaches;
};
struct OrbisNgs2CustomSubmixerRackOption {
OrbisNgs2CustomRackOption customRackOption;
u32 maxChannels;
u32 maxInputs;
};
struct OrbisNgs2CustomMasteringRackOption {
OrbisNgs2CustomRackOption customRackOption;
u32 maxChannels;
u32 maxInputs;
};
struct OrbisNgs2CustomSamplerVoiceSetupParam {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2WaveformFormat format;
u32 flags;
u32 reserved;
};
struct OrbisNgs2CustomSamplerVoiceWaveformBlocksParam {
OrbisNgs2VoiceParamHeader header;
const void* data;
u32 flags;
u32 numBlocks;
const OrbisNgs2WaveformBlock* aBlock;
};
struct OrbisNgs2CustomSamplerVoiceWaveformAddressParam {
OrbisNgs2VoiceParamHeader header;
const void* from;
const void* to;
};
struct OrbisNgs2CustomSamplerVoiceWaveformFrameOffsetParam {
OrbisNgs2VoiceParamHeader header;
u32 frameOffset;
u32 reserved;
};
struct OrbisNgs2CustomSamplerVoiceExitLoopParam {
OrbisNgs2VoiceParamHeader header;
};
struct OrbisNgs2CustomSamplerVoicePitchParam {
OrbisNgs2VoiceParamHeader header;
float ratio;
u32 reserved;
};
struct OrbisNgs2CustomSamplerVoiceState {
OrbisNgs2VoiceState voiceState;
char padding[32];
const void* waveformData;
u64 numDecodedSamples;
u64 decodedDataSize;
u64 userData;
u32 reserved;
u32 reserved2;
};
struct OrbisNgs2CustomSubmixerVoiceSetupParam {
OrbisNgs2VoiceParamHeader header;
u32 numInputChannels;
u32 numOutputChannels;
u32 flags;
u32 reserved;
};
struct OrbisNgs2CustomSubmixerVoiceState {
OrbisNgs2VoiceState voiceState; // Voice state
u32 reserved;
u32 reserved2;
};
struct OrbisNgs2CustomMasteringVoiceSetupParam {
OrbisNgs2VoiceParamHeader header;
u32 numInputChannels;
u32 flags;
};
struct OrbisNgs2CustomMasteringVoiceOutputParam {
OrbisNgs2VoiceParamHeader header;
u32 outputId;
u32 reserved;
};
struct OrbisNgs2CustomMasteringVoiceState {
OrbisNgs2VoiceState voiceState;
u32 reserved;
u32 reserved2;
};
struct OrbisNgs2CustomVoiceEnvelopeParam {
OrbisNgs2VoiceParamHeader header;
u32 numForwardPoints;
u32 numReleasePoints;
const OrbisNgs2EnvelopePoint* aPoint;
};
struct OrbisNgs2CustomVoiceDistortionParam {
OrbisNgs2VoiceParamHeader header;
u32 flags;
float a;
float b;
float clip;
float gate;
float wetLevel;
float dryLevel;
u32 reserved;
};
struct OrbisNgs2CustomVoiceCompressorParam {
OrbisNgs2VoiceParamHeader header;
u32 flags;
float threshold;
float ratio;
float knee;
float attackTime;
float releaseTime;
float level;
u32 reserved;
};
struct OrbisNgs2CustomVoiceFilterParam {
OrbisNgs2VoiceParamHeader header;
u32 type;
u32 channelMask;
union {
struct {
float i0;
float i1;
float i2;
float o1;
float o2;
} direct;
struct {
float fc;
float q;
float level;
u32 reserved;
u32 reserved2;
} fcq;
} param;
u32 reserved3;
};
struct OrbisNgs2CustomVoiceLfeFilterParam {
OrbisNgs2VoiceParamHeader header;
u32 enableFlag;
u32 fc;
};
struct OrbisNgs2CustomVoiceGainParam {
OrbisNgs2VoiceParamHeader header;
float aLevel[ORBIS_NGS2_MAX_VOICE_CHANNELS];
};
struct OrbisNgs2CustomVoiceMixerParam {
OrbisNgs2VoiceParamHeader header;
float aSourceLevel[ORBIS_NGS2_MAX_VOICE_CHANNELS];
float aDestLevel[ORBIS_NGS2_MAX_VOICE_CHANNELS];
};
struct OrbisNgs2CustomVoiceChannelMixerParam {
OrbisNgs2VoiceParamHeader header;
float aLevel[ORBIS_NGS2_MAX_VOICE_CHANNELS][ORBIS_NGS2_MAX_VOICE_CHANNELS];
};
struct OrbisNgs2CustomVoiceUserFxParam {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2UserFxProcessHandler handler;
uintptr_t userData0;
uintptr_t userData1;
uintptr_t userData2;
};
struct OrbisNgs2CustomVoiceUserFx2Param {
OrbisNgs2VoiceParamHeader header;
const void* data;
size_t dataSize;
};
struct OrbisNgs2CustomVoiceOutputParam {
OrbisNgs2VoiceParamHeader header;
u32 outputId;
u32 reserved;
};
struct OrbisNgs2CustomVoicePeakMeterParam {
OrbisNgs2VoiceParamHeader header;
u32 enableFlag;
u32 reserved;
} OrbisNgs2CustomVoicePeakMeterParam;
struct OrbisNgs2CustomVoiceReverbParam {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2ReverbI3DL2Param i3dl2;
};
struct OrbisNgs2CustomVoiceChorusParam {
OrbisNgs2VoiceParamHeader header;
u32 flags;
u32 numPhases;
u32 channelMask;
float inputLevel;
float delayTime;
float modulationRatio;
float modulationDepth;
float feedbackLevel;
float wetLevel;
float dryLevel;
};
struct OrbisNgs2DelayTapInfo {
float tapLevel;
float delayTime;
};
struct OrbisNgs2CustomVoiceDelayParam {
OrbisNgs2VoiceParamHeader header;
float dryLevel;
float wetLevel;
float inputLevel;
float feedbackLevel;
float lowpassFc;
u32 numTaps;
OrbisNgs2DelayTapInfo aTap[ORBIS_NGS2_CUSTOM_DELAY_MAX_TAPS];
float aInputMixLevel[ORBIS_NGS2_MAX_VOICE_CHANNELS];
u32 channelMask;
u32 flags;
};
struct OrbisNgs2CustomVoiceNoiseGateParam {
OrbisNgs2VoiceParamHeader header;
u32 flags;
float threshold;
float attackTime;
float releaseTime;
};
struct OrbisNgs2CustomVoicePitchShiftParam {
OrbisNgs2VoiceParamHeader header;
s32 cent;
};
struct OrbisNgs2CustomEnvelopeModuleState {
float height;
u32 reserved;
};
struct OrbisNgs2CustomCompressorModuleState {
float peakHeight;
float compressorHeight;
};
struct OrbisNgs2CustomPeakMeterModuleState {
float peak;
float aChannelPeak[ORBIS_NGS2_MAX_VOICE_CHANNELS];
u32 reserved;
};
struct OrbisNgs2CustomNoiseGateModuleState {
float gateHeight;
};
struct OrbisNgs2CustomRackInfo {
OrbisNgs2RackInfo rackInfo;
u32 stateSize;
u32 numBuffers;
u32 numModules;
u32 reserved;
OrbisNgs2CustomRackModuleInfo aModule[ORBIS_NGS2_CUSTOM_MAX_MODULES];
OrbisNgs2CustomRackPortInfo aPort[ORBIS_NGS2_CUSTOM_MAX_PORTS];
};
struct OrbisNgs2CustomSamplerRackInfo {
OrbisNgs2CustomRackInfo customRackInfo;
u32 maxChannelWorks;
u32 maxWaveformBlocks;
u32 maxAtrac9Decoders;
u32 maxAtrac9ChannelWorks;
u32 maxAjmAtrac9Decoders;
u32 maxCodecCaches;
};
struct OrbisNgs2CustomSubmixerRackInfo {
OrbisNgs2CustomRackInfo customRackInfo;
u32 maxChannels;
u32 maxInputs;
};
struct OrbisNgs2CustomMasteringRackInfo {
OrbisNgs2CustomRackInfo customRackInfo;
u32 maxChannels;
u32 maxInputs;
};
struct OrbisNgs2CustomModuleInfo {
u32 moduleId;
u32 sourceBufferId;
u32 extraBufferId;
u32 destBufferId;
u32 stateOffset;
u32 stateSize;
u32 reserved;
u32 reserved2;
};
struct OrbisNgs2CustomEnvelopeModuleInfo {
OrbisNgs2CustomModuleInfo moduleInfo;
u32 maxPoints;
u32 reserved;
};
struct OrbisNgs2CustomReverbModuleInfo {
OrbisNgs2CustomModuleInfo moduleInfo;
u32 reverbSize;
u32 reserved;
};
} // namespace Libraries::Ngs2

View File

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View File

@ -0,0 +1,41 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
namespace Libraries::Ngs2 {
class Ngs2Eq;
struct OrbisNgs2EqVoiceSetupParam {
u32 numChannels;
};
struct OrbisNgs2EqVoiceFilterParam {
u32 type;
u32 channelMask;
union {
struct {
float i0;
float i1;
float i2;
float o1;
float o2;
} direct;
struct {
float fc;
float q;
float level;
u32 reserved;
u32 reserved2;
} fcq;
} param;
};
struct OrbisNgs2EqVoiceState {
u32 stateFlags;
};
} // namespace Libraries::Ngs2

View File

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View File

@ -0,0 +1,80 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
namespace Libraries::Ngs2 {
class Ngs2Geom;
struct OrbisNgs2GeomVector {
float x;
float y;
float z;
};
struct OrbisNgs2GeomCone {
float innerLevel;
float innerAngle;
float outerLevel;
float outerAngle;
};
struct OrbisNgs2GeomRolloff {
u32 model;
float maxDistance;
float rolloffFactor;
float referenceDistance;
};
struct OrbisNgs2GeomListenerParam {
OrbisNgs2GeomVector position;
OrbisNgs2GeomVector orientFront;
OrbisNgs2GeomVector orientUp;
OrbisNgs2GeomVector velocity;
float soundSpeed;
u32 reserved[2];
};
struct OrbisNgs2GeomListenerWork {
float matrix[4][4];
OrbisNgs2GeomVector velocity;
float soundSpeed;
u32 coordinate;
u32 reserved[3];
};
struct OrbisNgs2GeomSourceParam {
OrbisNgs2GeomVector position;
OrbisNgs2GeomVector velocity;
OrbisNgs2GeomVector direction;
OrbisNgs2GeomCone cone;
OrbisNgs2GeomRolloff rolloff;
float dopplerFactor;
float fbwLevel;
float lfeLevel;
float maxLevel;
float minLevel;
float radius;
u32 numSpeakers;
u32 matrixFormat;
u32 reserved[2];
};
struct OrbisNgs2GeomA3dAttribute {
OrbisNgs2GeomVector position;
float volume;
u32 reserved[4];
};
struct OrbisNgs2GeomAttribute {
float pitchRatio;
float aLevel[ORBIS_NGS2_MAX_VOICE_CHANNELS * ORBIS_NGS2_MAX_VOICE_CHANNELS];
OrbisNgs2GeomA3dAttribute a3dAttrib;
u32 reserved[4];
};
} // namespace Libraries::Ngs2

View File

@ -12,153 +12,171 @@ using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {
s32 Ngs2::ReportInvalid(Ngs2Handle* handle, u32 handle_type) const {
uintptr_t hAddress = reinterpret_cast<uintptr_t>(handle);
switch (handle_type) {
s32 HandleReportInvalid(OrbisNgs2Handle handle, u32 handleType) {
switch (handleType) {
case 1:
LOG_ERROR(Lib_Ngs2, "Invalid system handle {}", hAddress);
LOG_ERROR(Lib_Ngs2, "Invalid system handle {}", handle);
return ORBIS_NGS2_ERROR_INVALID_SYSTEM_HANDLE;
case 2:
LOG_ERROR(Lib_Ngs2, "Invalid rack handle {}", hAddress);
LOG_ERROR(Lib_Ngs2, "Invalid rack handle {}", handle);
return ORBIS_NGS2_ERROR_INVALID_RACK_HANDLE;
case 4:
LOG_ERROR(Lib_Ngs2, "Invalid voice handle {}", hAddress);
LOG_ERROR(Lib_Ngs2, "Invalid voice handle {}", handle);
return ORBIS_NGS2_ERROR_INVALID_VOICE_HANDLE;
case 8:
LOG_ERROR(Lib_Ngs2, "Invalid report handle {}", hAddress);
LOG_ERROR(Lib_Ngs2, "Invalid report handle {}", handle);
return ORBIS_NGS2_ERROR_INVALID_REPORT_HANDLE;
default:
LOG_ERROR(Lib_Ngs2, "Invalid handle {}", hAddress);
LOG_ERROR(Lib_Ngs2, "Invalid handle {}", handle);
return ORBIS_NGS2_ERROR_INVALID_HANDLE;
}
}
s32 Ngs2::HandleSetup(Ngs2Handle* handle, void* data, std::atomic<u32>* atomic, u32 type,
u32 flags) {
handle->dataPointer = data;
handle->atomicPtr = atomic;
handle->handleType = type;
handle->flags_unk = flags;
return ORBIS_OK;
void* MemoryClear(void* buffer, size_t size) {
return memset(buffer, 0, size);
}
s32 Ngs2::HandleCleanup(Ngs2Handle* handle, u32 hType, void* dataOut) {
if (handle && handle->selfPointer == handle) {
std::atomic<u32>* tmp_atomic = handle->atomicPtr;
if (tmp_atomic && handle->handleType == hType) {
while (tmp_atomic->load() != 0) {
u32 expected = 1;
if (tmp_atomic->compare_exchange_strong(expected, 0)) {
if (dataOut) {
dataOut = handle->dataPointer;
}
// sceNgs2MemoryClear(handle, 32);
return ORBIS_OK;
}
tmp_atomic = handle->atomicPtr;
}
}
}
return this->ReportInvalid(handle, hType);
}
s32 Ngs2::HandleEnter(Ngs2Handle* handle, u32 hType, Ngs2Handle* handleOut) {
if (!handle) {
return this->ReportInvalid(handle, 0);
}
if (handle->selfPointer != handle || !handle->atomicPtr || !handle->dataPointer ||
(~hType & handle->handleType)) {
return this->ReportInvalid(handle, handle->handleType);
}
std::atomic<u32>* atomic = handle->atomicPtr;
while (true) {
u32 i = atomic->load();
if (i == 0) {
return this->ReportInvalid(handle, handle->handleType);
}
if (atomic->compare_exchange_strong(i, i + 1)) {
break;
}
}
if (handleOut) {
handleOut = handle;
s32 StackBufferClose(StackBuffer* stackBuffer, size_t* outTotalSize) {
if (outTotalSize) {
*outTotalSize = stackBuffer->usedSize + stackBuffer->alignment;
}
return ORBIS_OK;
}
s32 Ngs2::HandleLeave(Ngs2Handle* handle) {
std::atomic<u32>* tmp_atomic;
u32 i;
do {
tmp_atomic = handle->atomicPtr;
i = tmp_atomic->load();
} while (!tmp_atomic->compare_exchange_strong(i, i - 1));
return ORBIS_OK;
}
s32 StackBufferOpen(StackBuffer* stackBuffer, void* bufferStart, size_t bufferSize,
void** outBuffer, u8 flags) {
stackBuffer->top = outBuffer;
stackBuffer->base = bufferStart;
stackBuffer->size = (size_t)bufferStart;
stackBuffer->currentOffset = (size_t)bufferStart;
stackBuffer->usedSize = 0;
stackBuffer->totalSize = bufferSize;
stackBuffer->alignment = 8; // this is a fixed value
stackBuffer->flags = flags;
s32 Ngs2::StackBufferOpen(StackBuffer* buf, void* base_addr, size_t size, void** stackTop,
bool verify) {
buf->top = stackTop;
buf->base = base_addr;
buf->curr = base_addr;
buf->usedSize = 0;
buf->totalSize = size;
buf->alignment = 8;
buf->isVerifyEnabled = verify;
if (stackTop) {
*stackTop = nullptr;
if (outBuffer != NULL) {
*outBuffer = NULL;
}
return ORBIS_OK;
}
s32 Ngs2::StackBufferClose(StackBuffer* buf, size_t* usedSize) {
if (usedSize) {
*usedSize = buf->usedSize + buf->alignment;
s32 SystemCleanup(OrbisNgs2Handle systemHandle, OrbisNgs2ContextBufferInfo* outInfo) {
if (!systemHandle) {
return ORBIS_NGS2_ERROR_INVALID_HANDLE;
}
// TODO
return ORBIS_OK;
}
s32 Ngs2::SystemSetupCore(StackBuffer* buf, SystemOptions* options, Ngs2Handle** sysOut) {
s32 SystemSetupCore(StackBuffer* stackBuffer, const OrbisNgs2SystemOption* option,
SystemInternal* outSystem) {
u32 maxGrainSamples = 512;
u32 numGrainSamples = 256;
u32 sampleRate = 48000;
if (options) {
maxGrainSamples = options->maxGrainSamples;
numGrainSamples = options->numGrainSamples;
sampleRate = options->sampleRate;
if (option) {
sampleRate = option->sampleRate;
maxGrainSamples = option->maxGrainSamples;
numGrainSamples = option->numGrainSamples;
}
// Validate maxGrainSamples
if (maxGrainSamples < 64 || maxGrainSamples > 1024 || (maxGrainSamples & 0x3F) != 0) {
if (maxGrainSamples < 64 || maxGrainSamples > 1024 || (maxGrainSamples & 63) != 0) {
LOG_ERROR(Lib_Ngs2, "Invalid system option (maxGrainSamples={},x64)", maxGrainSamples);
return ORBIS_NGS2_ERROR_INVALID_MAX_GRAIN_SAMPLES;
}
// Validate numGrainSamples
if (numGrainSamples < 64 || numGrainSamples > 1024 || (numGrainSamples & 0x3F) != 0) {
if (numGrainSamples < 64 || numGrainSamples > 1024 || (numGrainSamples & 63) != 0) {
LOG_ERROR(Lib_Ngs2, "Invalid system option (numGrainSamples={},x64)", numGrainSamples);
return ORBIS_NGS2_ERROR_INVALID_NUM_GRAIN_SAMPLES;
}
// Validate sampleRate
if (sampleRate != 11025 && sampleRate != 12000 && sampleRate != 22050 && sampleRate != 24000 &&
sampleRate != 44100 && sampleRate != 48000 && sampleRate != 88200 && sampleRate != 96000) {
sampleRate != 44100 && sampleRate != 48000 && sampleRate != 88200 && sampleRate != 96000 &&
sampleRate != 176400 && sampleRate != 192000) {
LOG_ERROR(Lib_Ngs2, "Invalid system option(sampleRate={}:44.1/48kHz series)", sampleRate);
return ORBIS_NGS2_ERROR_INVALID_SAMPLE_RATE;
}
int result = ORBIS_OK;
return ORBIS_OK;
}
s32 SystemSetup(const OrbisNgs2SystemOption* option, OrbisNgs2ContextBufferInfo* hostBufferInfo,
OrbisNgs2BufferFreeHandler hostFree, OrbisNgs2Handle* outHandle) {
u8 optionFlags = 0;
StackBuffer stackBuffer;
SystemInternal setupResult;
void* systemList = NULL;
size_t requiredBufferSize = 0;
u32 result = ORBIS_NGS2_ERROR_INVALID_BUFFER_SIZE;
if (option) {
if (option->size != 64) {
LOG_ERROR(Lib_Ngs2, "Invalid system option size ({})", option->size);
return ORBIS_NGS2_ERROR_INVALID_OPTION_SIZE;
}
optionFlags = option->flags >> 31;
}
// Init
StackBufferOpen(&stackBuffer, NULL, 0, NULL, optionFlags);
result = SystemSetupCore(&stackBuffer, option, 0);
if (result < 0) {
return result;
}
StackBufferClose(&stackBuffer, &requiredBufferSize);
// outHandle unprovided
if (!outHandle) {
hostBufferInfo->hostBuffer = NULL;
hostBufferInfo->hostBufferSize = requiredBufferSize;
MemoryClear(&hostBufferInfo->reserved, sizeof(hostBufferInfo->reserved));
return ORBIS_OK;
}
if (!hostBufferInfo->hostBuffer) {
LOG_ERROR(Lib_Ngs2, "Invalid system buffer address ({})", hostBufferInfo->hostBuffer);
return ORBIS_NGS2_ERROR_INVALID_BUFFER_ADDRESS;
}
if (hostBufferInfo->hostBufferSize < requiredBufferSize) {
LOG_ERROR(Lib_Ngs2, "Invalid system buffer size ({}<{}[byte])",
hostBufferInfo->hostBufferSize, requiredBufferSize);
return ORBIS_NGS2_ERROR_INVALID_BUFFER_SIZE;
}
// Setup
StackBufferOpen(&stackBuffer, hostBufferInfo->hostBuffer, hostBufferInfo->hostBufferSize,
&systemList, optionFlags);
result = SystemSetupCore(&stackBuffer, option, &setupResult);
if (result < 0) {
return result;
}
StackBufferClose(&stackBuffer, &requiredBufferSize);
// Copy buffer results
setupResult.bufferInfo = *hostBufferInfo;
setupResult.hostFree = hostFree;
// TODO
// setupResult.systemList = systemList;
return result; // Success
OrbisNgs2Handle systemHandle = setupResult.systemHandle;
if (hostBufferInfo->hostBufferSize >= requiredBufferSize) {
*outHandle = systemHandle;
return ORBIS_OK;
}
SystemCleanup(systemHandle, 0);
LOG_ERROR(Lib_Ngs2, "Invalid system buffer size ({}<{}[byte])", hostBufferInfo->hostBufferSize,
requiredBufferSize);
return ORBIS_NGS2_ERROR_INVALID_BUFFER_SIZE;
}
} // namespace Libraries::Ngs2

View File

@ -3,23 +3,176 @@
#pragma once
#include "ngs2.h"
#include "core/libraries/kernel/threads/pthread.h"
namespace Libraries::Ngs2 {
class Ngs2 {
public:
s32 ReportInvalid(Ngs2Handle* handle, u32 handle_type) const;
s32 HandleSetup(Ngs2Handle* handle, void* data, std::atomic<u32>* atomic, u32 type, u32 flags);
s32 HandleCleanup(Ngs2Handle* handle, u32 hType, void* dataOut);
s32 HandleEnter(Ngs2Handle* handle, u32 hType, Ngs2Handle* handleOut);
s32 HandleLeave(Ngs2Handle* handle);
s32 StackBufferOpen(StackBuffer* buf, void* base_addr, size_t size, void** stackTop,
bool verify);
s32 StackBufferClose(StackBuffer* buf, size_t* usedSize);
s32 SystemSetupCore(StackBuffer* buf, SystemOptions* options, Ngs2Handle** sysOut);
static const int ORBIS_NGS2_SYSTEM_NAME_LENGTH = 16;
static const int ORBIS_NGS2_RACK_NAME_LENGTH = 16;
private:
typedef uintptr_t OrbisNgs2Handle;
struct OrbisNgs2ContextBufferInfo {
void* hostBuffer;
size_t hostBufferSize;
uintptr_t reserved[5];
uintptr_t userData;
};
struct OrbisNgs2SystemOption {
size_t size;
char name[ORBIS_NGS2_SYSTEM_NAME_LENGTH];
u32 flags;
u32 maxGrainSamples;
u32 numGrainSamples;
u32 sampleRate;
u32 aReserved[6];
};
typedef s32 (*OrbisNgs2BufferAllocHandler)(OrbisNgs2ContextBufferInfo* ioBufferInfo);
typedef s32 (*OrbisNgs2BufferFreeHandler)(OrbisNgs2ContextBufferInfo* ioBufferInfo);
struct OrbisNgs2SystemInfo {
char name[ORBIS_NGS2_SYSTEM_NAME_LENGTH]; // 0
OrbisNgs2Handle systemHandle; // 16
OrbisNgs2ContextBufferInfo bufferInfo; // 24
u32 uid; // 88
u32 minGrainSamples; // 92
u32 maxGrainSamples; // 96
u32 stateFlags; // 100
u32 rackCount; // 104
float lastRenderRatio; // 108
s64 lastRenderTick; // 112
s64 renderCount; // 120
u32 sampleRate; // 128
u32 numGrainSamples; // 132
};
struct OrbisNgs2RackInfo {
char name[ORBIS_NGS2_RACK_NAME_LENGTH]; // 0
OrbisNgs2Handle rackHandle; // 16
OrbisNgs2ContextBufferInfo bufferInfo; // 24
OrbisNgs2Handle ownerSystemHandle; // 88
u32 type; // 96
u32 rackId; // 100
u32 uid; // 104
u32 minGrainSamples; // 108
u32 maxGrainSamples; // 112
u32 maxVoices; // 116
u32 maxChannelWorks; // 120
u32 maxInputs; // 124
u32 maxMatrices; // 128
u32 maxPorts; // 132
u32 stateFlags; // 136
float lastProcessRatio; // 140
u64 lastProcessTick; // 144
u64 renderCount; // 152
u32 activeVoiceCount; // 160
u32 activeChannelWorkCount; // 164
};
struct StackBuffer {
void** top;
void* base;
size_t size;
size_t currentOffset;
size_t usedSize;
size_t totalSize;
size_t alignment;
u8 flags;
char padding[7];
};
struct SystemInternal {
// setup init
char name[ORBIS_NGS2_SYSTEM_NAME_LENGTH]; // 0
OrbisNgs2ContextBufferInfo bufferInfo; // 16
OrbisNgs2BufferFreeHandler hostFree; // 80
OrbisNgs2Handle systemHandle; // 88
void* unknown1; // 96
void* unknown2; // 104
OrbisNgs2Handle rackHandle; // 112
uintptr_t* userData; // 120
SystemInternal* systemList; // 128
StackBuffer* stackBuffer; // 136
OrbisNgs2SystemInfo ownerSystemInfo; // 144
struct rackList {
void* prev;
void* next;
void* unknown;
};
rackList rackListPreset; // 152
rackList rackListNormal; // 176
rackList rackListMaster; // 200
void* unknown3; // 208
void* systemListPrev; // 216
void* unknown4; // 224
void* systemListNext; // 232
void* rackFunction; // 240
Kernel::PthreadMutex processLock; // 248
u32 hasProcessMutex; // 256
u32 unknown5; // 260
Kernel::PthreadMutex flushLock; // 264
u32 hasFlushMutex; // 272
u32 unknown6; // 276
// info
u64 lastRenderTick; // 280
u64 renderCount; // 288
u32 isActive; // 296
std::atomic<int> lockCount; // 300
u32 uid; // 304
u32 systemType; // 308
struct {
u8 isBufferValid : 1;
u8 isRendering : 1;
u8 isSorted : 1;
u8 isFlushReady : 1;
} flags; // 312
u16 currentMaxGrainSamples; // 316
u16 minGrainSamples; // 318
u16 maxGrainSamples; // 320
u16 numGrainSamples; // 322
u32 currentNumGrainSamples; // 324
u32 sampleRate; // 328
u32 currentSampleRate; // 332
u32 rackCount; // 336
float lastRenderRatio; // 340
float cpuLoad; // 344
};
struct HandleInternal {
HandleInternal* selfPtr; // 0
SystemInternal* systemData; // 8
std::atomic<int> refCount; // 16
u32 handleType; // 24
u32 handleID; // 28
};
s32 StackBufferClose(StackBuffer* stackBuffer, size_t* outTotalSize);
s32 StackBufferOpen(StackBuffer* stackBuffer, void* buffer, size_t bufferSize, void** outBuffer,
u8 flags);
s32 SystemSetupCore(StackBuffer* stackBuffer, const OrbisNgs2SystemOption* option,
SystemInternal* outSystem);
s32 HandleReportInvalid(OrbisNgs2Handle handle, u32 handleType);
void* MemoryClear(void* buffer, size_t size);
s32 SystemCleanup(OrbisNgs2Handle systemHandle, OrbisNgs2ContextBufferInfo* outInfo);
s32 SystemSetup(const OrbisNgs2SystemOption* option, OrbisNgs2ContextBufferInfo* hostBufferInfo,
OrbisNgs2BufferFreeHandler hostFree, OrbisNgs2Handle* outHandle);
} // namespace Libraries::Ngs2

View File

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View File

@ -0,0 +1,81 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
namespace Libraries::Ngs2 {
class Ngs2Mastering;
struct OrbisNgs2MasteringRackOption {
OrbisNgs2RackOption rackOption;
u32 maxChannels;
u32 numPeakMeterBlocks;
};
struct OrbisNgs2MasteringVoiceSetupParam {
OrbisNgs2VoiceParamHeader header;
u32 numInputChannels;
u32 flags;
};
struct OrbisNgs2MasteringVoiceMatrixParam {
OrbisNgs2VoiceParamHeader header;
u32 type;
u32 numLevels;
const float* aLevel;
};
struct OrbisNgs2MasteringVoiceLfeParam {
OrbisNgs2VoiceParamHeader header;
u32 enableFlag;
u32 fc;
};
struct OrbisNgs2MasteringVoiceLimiterParam {
OrbisNgs2VoiceParamHeader header;
u32 enableFlag;
float threshold;
};
struct OrbisNgs2MasteringVoiceGainParam {
OrbisNgs2VoiceParamHeader header;
float fbwLevel;
float lfeLevel;
};
struct OrbisNgs2MasteringVoiceOutputParam {
OrbisNgs2VoiceParamHeader header;
u32 outputId;
u32 reserved;
};
struct OrbisNgs2MasteringVoicePeakMeterParam {
OrbisNgs2VoiceParamHeader header;
u32 enableFlag;
u32 reserved;
};
struct OrbisNgs2MasteringVoiceState {
OrbisNgs2VoiceState voiceState;
float limiterPeakLevel;
float limiterPressLevel;
float aInputPeakHeight[ORBIS_NGS2_MAX_VOICE_CHANNELS];
float aOutputPeakHeight[ORBIS_NGS2_MAX_VOICE_CHANNELS];
};
struct OrbisNgs2MasteringRackInfo {
OrbisNgs2RackInfo rackInfo;
u32 maxChannels;
u32 reserved;
};
} // namespace Libraries::Ngs2

View File

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View File

@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
namespace Libraries::Ngs2 {
class Ngs2Pan;
struct OrbisNgs2PanParam {
float angle;
float distance;
float fbwLevel;
float lfeLevel;
};
struct OrbisNgs2PanWork {
float aSpeakerAngle[ORBIS_NGS2_MAX_VOICE_CHANNELS];
float unitAngle;
u32 numSpeakers;
};
} // namespace Libraries::Ngs2

View File

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View File

@ -0,0 +1,78 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
#include <stdarg.h> // va_list
namespace Libraries::Ngs2 {
class Ngs2Report;
struct OrbisNgs2ReportDataHeader {
size_t size;
OrbisNgs2Handle handle;
u32 type;
s32 result;
};
typedef void (*OrbisNgs2ReportHandler)(const OrbisNgs2ReportDataHeader* data, uintptr_t userData);
struct OrbisNgs2ReportMessageData {
OrbisNgs2ReportDataHeader header;
const char* message;
};
struct OrbisNgs2ReportApiData {
OrbisNgs2ReportDataHeader header;
const char* functionName;
const char* format;
va_list argument;
};
struct OrbisNgs2ReportControlData {
OrbisNgs2ReportDataHeader header;
const OrbisNgs2VoiceParamHeader* param;
};
struct OrbisNgs2ReportOutputData {
OrbisNgs2ReportDataHeader header;
const OrbisNgs2RenderBufferInfo* bufferInfo;
u32 bufferIndex;
u32 sampleRate;
u32 numGrainSamples;
u32 reserved;
};
struct OrbisNgs2ReportCpuLoadData {
OrbisNgs2ReportDataHeader header;
float totalRatio;
float flushRatio;
float processRatio;
float feedbackRatio;
};
struct OrbisNgs2ReportRenderStateData {
OrbisNgs2ReportDataHeader header;
u32 state;
u32 reserved;
};
struct OrbisNgs2ReportVoiceWaveformData {
OrbisNgs2ReportDataHeader header;
u32 location;
u32 waveformType;
u32 numChannels;
u32 sampleRate;
u32 numGrainSamples;
u32 reserved;
void* const* aData;
};
s32 PS4_SYSV_ABI sceNgs2ReportRegisterHandler(u32 reportType, OrbisNgs2ReportHandler handler,
uintptr_t userData, OrbisNgs2Handle* outHandle);
} // namespace Libraries::Ngs2

View File

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View File

@ -0,0 +1,61 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
namespace Libraries::Ngs2 {
class Ngs2Reverb;
struct OrbisNgs2ReverbRackOption {
OrbisNgs2RackOption rackOption;
u32 maxChannels;
u32 reverbSize;
};
struct OrbisNgs2ReverbI3DL2Param {
float wet;
float dry;
s32 room;
s32 roomHF;
u32 reflectionPattern;
float decayTime;
float decayHFRatio;
s32 reflections;
float reflectionsDelay;
s32 reverb;
float reverbDelay;
float diffusion;
float density;
float HFReference;
u32 reserve[8];
};
struct OrbisNgs2ReverbVoiceSetupParam {
OrbisNgs2VoiceParamHeader header;
u32 numInputChannels;
u32 numOutputChannels;
u32 flags;
u32 reserved;
};
struct OrbisNgs2ReverbVoiceI3DL2Param {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2ReverbI3DL2Param i3dl2;
};
struct OrbisNgs2ReverbVoiceState {
OrbisNgs2VoiceState voiceState;
};
struct OrbisNgs2ReverbRackInfo {
OrbisNgs2RackInfo rackInfo;
u32 maxChannels;
u32 reverbSize;
};
} // namespace Libraries::Ngs2

View File

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View File

@ -0,0 +1,162 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
namespace Libraries::Ngs2 {
class Ngs2Sampler;
struct OrbisNgs2SamplerRackOption {
OrbisNgs2RackOption rackOption;
u32 maxChannelWorks;
u32 maxCodecCaches;
u32 maxWaveformBlocks;
u32 maxEnvelopePoints;
u32 maxFilters;
u32 maxAtrac9Decoders;
u32 maxAtrac9ChannelWorks;
u32 maxAjmAtrac9Decoders;
u32 numPeakMeterBlocks;
};
struct OrbisNgs2SamplerVoiceSetupParam {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2WaveformFormat format;
u32 flags;
u32 reserved;
};
struct OrbisNgs2SamplerVoiceWaveformBlocksParam {
OrbisNgs2VoiceParamHeader header;
const void* data;
u32 flags;
u32 numBlocks;
const OrbisNgs2WaveformBlock* aBlock;
// Blocks
};
struct OrbisNgs2SamplerVoiceWaveformAddressParam {
OrbisNgs2VoiceParamHeader header;
const void* from;
const void* to;
};
struct OrbisNgs2SamplerVoiceWaveformFrameOffsetParam {
OrbisNgs2VoiceParamHeader header;
u32 frameOffset;
u32 reserved;
};
struct OrbisNgs2SamplerVoiceExitLoopParam {
OrbisNgs2VoiceParamHeader header;
};
struct OrbisNgs2SamplerVoicePitchParam {
OrbisNgs2VoiceParamHeader header;
float ratio;
u32 reserved;
};
struct OrbisNgs2SamplerVoiceEnvelopeParam {
OrbisNgs2VoiceParamHeader header;
u32 numForwardPoints;
u32 numReleasePoints;
const OrbisNgs2EnvelopePoint* aPoint;
};
struct OrbisNgs2SamplerVoiceDistortionParam {
OrbisNgs2VoiceParamHeader header;
u32 flags;
float a;
float b;
float clip;
float gate;
float wetLevel;
float dryLevel;
u32 reserved;
};
struct OrbisNgs2SamplerVoiceUserFxParam {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2UserFxProcessHandler handler;
uintptr_t userData0;
uintptr_t userData1;
uintptr_t userData2;
};
struct OrbisNgs2SamplerVoicePeakMeterParam {
OrbisNgs2VoiceParamHeader header;
u32 enableFlag;
u32 reserved;
};
struct OrbisNgs2SamplerVoiceFilterParam {
OrbisNgs2VoiceParamHeader header;
u32 index;
u32 location;
u32 type;
u32 channelMask;
union {
struct {
float i0;
float i1;
float i2;
float o1;
float o2;
} direct;
struct {
float fc;
float q;
float level;
u32 reserved;
u32 reserved2;
} fcq;
} param;
u32 reserved3;
};
struct OrbisNgs2SamplerVoiceNumFilters {
OrbisNgs2VoiceParamHeader header;
u32 numFilters;
u32 reserved;
};
struct OrbisNgs2SamplerVoiceState {
OrbisNgs2VoiceState voiceState;
float envelopeHeight;
float peakHeight;
u32 reserved;
u64 numDecodedSamples;
u64 decodedDataSize;
u64 userData;
const void* waveformData;
};
struct OrbisNgs2SamplerRackInfo {
OrbisNgs2RackInfo rackInfo;
u32 maxChannelWorks;
u32 maxCodecCaches;
u32 maxWaveformBlocks;
u32 maxEnvelopePoints;
u32 maxFilters;
u32 maxAtrac9Decoders;
u32 maxAtrac9ChannelWorks;
u32 maxAjmAtrac9Decoders;
};
} // namespace Libraries::Ngs2

View File

@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "ngs2_error.h"
#include "ngs2_impl.h"
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
using namespace Libraries::Kernel;
namespace Libraries::Ngs2 {} // namespace Libraries::Ngs2

View File

@ -0,0 +1,126 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "ngs2.h"
namespace Libraries::Ngs2 {
class Ngs2Submixer;
struct OrbisNgs2SubmixerRackOption {
OrbisNgs2RackOption rackOption;
u32 maxChannels;
u32 maxEnvelopePoints;
u32 maxFilters;
u32 maxInputs;
u32 numPeakMeterBlocks;
};
struct OrbisNgs2SubmixerVoiceSetupParam {
OrbisNgs2VoiceParamHeader header;
u32 numIoChannels;
u32 flags;
};
struct OrbisNgs2SubmixerVoiceEnvelopeParam {
OrbisNgs2VoiceParamHeader header;
u32 numForwardPoints;
u32 numReleasePoints;
const OrbisNgs2EnvelopePoint* aPoint;
};
struct OrbisNgs2SubmixerVoiceCompressorParam {
OrbisNgs2VoiceParamHeader header;
u32 flags;
float threshold;
float ratio;
float knee;
float attackTime;
float releaseTime;
float level;
u32 reserved;
};
struct OrbisNgs2SubmixerVoiceDistortionParam {
OrbisNgs2VoiceParamHeader header;
u32 flags;
float a;
float b;
float clip;
float gate;
float wetLevel;
float dryLevel;
u32 reserved;
};
struct OrbisNgs2SubmixerVoiceUserFxParam {
OrbisNgs2VoiceParamHeader header;
OrbisNgs2UserFxProcessHandler handler;
uintptr_t userData0;
uintptr_t userData1;
uintptr_t userData2;
};
struct OrbisNgs2SubmixerVoicePeakMeterParam {
OrbisNgs2VoiceParamHeader header;
u32 enableFlag;
u32 reserved;
};
struct OrbisNgs2SubmixerVoiceFilterParam {
OrbisNgs2VoiceParamHeader header;
u32 index;
u32 location;
u32 type;
u32 channelMask;
union {
struct {
float i0;
float i1;
float i2;
float o1;
float o2;
} direct;
struct {
float fc;
float q;
float level;
u32 reserved;
u32 reserved2;
} fcq;
} param;
u32 reserved3;
};
struct OrbisNgs2SubmixerVoiceNumFilters {
OrbisNgs2VoiceParamHeader header;
u32 numFilters;
u32 reserved;
};
struct OrbisNgs2SubmixerVoiceState {
OrbisNgs2VoiceState voiceState;
float envelopeHeight;
float peakHeight;
float compressorHeight;
};
struct OrbisNgs2SubmixerRackInfo {
OrbisNgs2RackInfo rackInfo;
u32 maxChannels;
u32 maxEnvelopePoints;
u32 maxFilters;
u32 maxInputs;
};
} // namespace Libraries::Ngs2

View File

@ -27,14 +27,17 @@ namespace Libraries::NpTrophy {
std::optional<TrophyUI> current_trophy_ui;
std::queue<TrophyInfo> trophy_queue;
std::mutex queueMtx;
bool isLeftSide;
std::string side = "right";
double trophy_timer;
TrophyUI::TrophyUI(const std::filesystem::path& trophyIconPath, const std::string& trophyName,
const std::string_view& rarity)
: trophy_name(trophyName), trophy_type(rarity) {
isLeftSide = Config::leftSideTrophy();
side = Config::sideTrophy();
trophy_timer = Config::getTrophyNotificationDuration();
if (std::filesystem::exists(trophyIconPath)) {
@ -89,10 +92,14 @@ TrophyUI::TrophyUI(const std::filesystem::path& trophyIconPath, const std::strin
AddLayer(this);
#ifdef ENABLE_QT_GUI
QString musicPath = QString::fromStdString(CustomTrophy_Dir.string() + "/trophy.mp3");
if (fs::exists(musicPath.toStdString())) {
QString musicPathWav = QString::fromStdString(CustomTrophy_Dir.string() + "/trophy.wav");
QString musicPathMp3 = QString::fromStdString(CustomTrophy_Dir.string() + "/trophy.mp3");
if (fs::exists(musicPathWav.toStdString())) {
BackgroundMusicPlayer::getInstance().setVolume(100);
BackgroundMusicPlayer::getInstance().playMusic(musicPath, false);
BackgroundMusicPlayer::getInstance().playMusic(musicPathWav, false);
} else if (fs::exists(musicPathMp3.toStdString())) {
BackgroundMusicPlayer::getInstance().setVolume(100);
BackgroundMusicPlayer::getInstance().playMusic(musicPathMp3, false);
}
#endif
}
@ -115,8 +122,8 @@ float fade_out_duration = 0.5f; // Final fade duration
void TrophyUI::Draw() {
const auto& io = GetIO();
float AdjustWidth = io.DisplaySize.x / 1280;
float AdjustHeight = io.DisplaySize.y / 720;
float AdjustWidth = io.DisplaySize.x / 1920;
float AdjustHeight = io.DisplaySize.y / 1080;
const ImVec2 window_size{
std::min(io.DisplaySize.x, (350 * AdjustWidth)),
std::min(io.DisplaySize.y, (70 * AdjustHeight)),
@ -125,21 +132,38 @@ void TrophyUI::Draw() {
elapsed_time += io.DeltaTime;
float progress = std::min(elapsed_time / animation_duration, 1.0f);
// left or right position
float final_pos_x;
if (isLeftSide) {
start_pos.x = -window_size.x;
float final_pos_x, start_x;
float final_pos_y, start_y;
if (side == "top") {
start_x = (io.DisplaySize.x - window_size.x) * 0.5f;
start_y = -window_size.y;
final_pos_x = start_x;
final_pos_y = 20 * AdjustHeight;
} else if (side == "left") {
start_x = -window_size.x;
start_y = 50 * AdjustHeight;
final_pos_x = 20 * AdjustWidth;
} else {
start_pos.x = io.DisplaySize.x;
final_pos_y = start_y;
} else if (side == "right") {
start_x = io.DisplaySize.x;
start_y = 50 * AdjustHeight;
final_pos_x = io.DisplaySize.x - window_size.x - 20 * AdjustWidth;
final_pos_y = start_y;
} else if (side == "bottom") {
start_x = (io.DisplaySize.x - window_size.x) * 0.5f;
start_y = io.DisplaySize.y;
final_pos_x = start_x;
final_pos_y = io.DisplaySize.y - window_size.y - 20 * AdjustHeight;
}
ImVec2 current_pos = ImVec2(start_pos.x + (final_pos_x - start_pos.x) * progress,
start_pos.y + (target_pos.y - start_pos.y) * progress);
ImVec2 current_pos = ImVec2(start_x + (final_pos_x - start_x) * progress,
start_y + (final_pos_y - start_y) * progress);
trophy_timer -= io.DeltaTime;
ImGui::SetNextWindowPos(current_pos);
// If the remaining time of the trophy is less than or equal to 1 second, the fade-out begins.
if (trophy_timer <= 1.0f) {
float fade_out_time = 1.0f - (trophy_timer / 1.0f);
@ -192,6 +216,13 @@ void TrophyUI::Draw() {
const float text_height = ImGui::CalcTextSize(combinedString.c_str()).y;
SetCursorPosY((window_size.y - text_height) * 0.5);
}
if (side == "top" || side == "bottom") {
float text_width = ImGui::CalcTextSize(trophy_name.c_str()).x;
float centered_x = (window_size.x - text_width) * 0.5f;
ImGui::SetCursorPosX(std::max(centered_x, 10.0f * AdjustWidth));
}
ImGui::PushTextWrapPos(window_size.x - (60 * AdjustWidth));
TextWrapped("Trophy earned!\n%s", trophy_name.c_str());
ImGui::SameLine(window_size.x - (60 * AdjustWidth));

View File

@ -7,6 +7,7 @@
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/process.h"
#include "core/libraries/libs.h"
#include "core/libraries/system/sysmodule.h"
#include "core/libraries/system/system_error.h"
@ -18,9 +19,12 @@ int PS4_SYSV_ABI sceSysmoduleGetModuleHandleInternal() {
return ORBIS_OK;
}
int PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind() {
s32 PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind(VAddr addr, s32 flags, void* info) {
LOG_ERROR(Lib_SysModule, "(STUBBED) called");
return ORBIS_OK;
Kernel::OrbisModuleInfoForUnwind module_info;
module_info.st_size = 0x130;
s32 res = Kernel::sceKernelGetModuleInfoForUnwind(addr, flags, &module_info);
return res;
}
int PS4_SYSV_ABI sceSysmoduleIsCalledFromSysModule() {

View File

@ -152,7 +152,7 @@ enum class OrbisSysModuleInternal : u32 {
};
int PS4_SYSV_ABI sceSysmoduleGetModuleHandleInternal();
int PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind();
s32 PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind(VAddr addr, s32 flags, void* info);
int PS4_SYSV_ABI sceSysmoduleIsCalledFromSysModule();
int PS4_SYSV_ABI sceSysmoduleIsCameraPreloaded();
int PS4_SYSV_ABI sceSysmoduleIsLoaded(OrbisSysModule id);

View File

@ -1893,7 +1893,7 @@ int PS4_SYSV_ABI sceSystemServiceNavigateToGoHome() {
s32 PS4_SYSV_ABI sceSystemServiceParamGetInt(OrbisSystemServiceParamId param_id, int* value) {
// TODO this probably should be stored in config for UI configuration
LOG_INFO(Lib_SystemService, "called param_id {}", u32(param_id));
LOG_DEBUG(Lib_SystemService, "called param_id {}", u32(param_id));
if (value == nullptr) {
LOG_ERROR(Lib_SystemService, "value is null");
return ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER;

View File

@ -1043,7 +1043,7 @@ int PS4_SYSV_ABI sceUserServiceGetTraditionalChineseInputType() {
s32 PS4_SYSV_ABI sceUserServiceGetUserColor(int user_id, OrbisUserServiceUserColor* color) {
// TODO fix me better
LOG_INFO(Lib_UserService, "called user_id = {}", user_id);
LOG_DEBUG(Lib_UserService, "called user_id = {}", user_id);
if (color == nullptr) {
LOG_ERROR(Lib_UserService, "color is null");
return ORBIS_USER_SERVICE_ERROR_INVALID_ARGUMENT;
@ -1068,7 +1068,7 @@ int PS4_SYSV_ABI sceUserServiceGetUserGroupNum() {
}
s32 PS4_SYSV_ABI sceUserServiceGetUserName(int user_id, char* user_name, std::size_t size) {
LOG_INFO(Lib_UserService, "called user_id = {} ,size = {} ", user_id, size);
LOG_DEBUG(Lib_UserService, "called user_id = {} ,size = {} ", user_id, size);
if (user_name == nullptr) {
LOG_ERROR(Lib_UserService, "user_name is null");
return ORBIS_USER_SERVICE_ERROR_INVALID_ARGUMENT;

View File

@ -63,6 +63,7 @@ void VideoOutDriver::Close(s32 handle) {
main_port.is_open = false;
main_port.flip_rate = 0;
main_port.prev_index = -1;
ASSERT(main_port.flip_events.empty());
}
@ -133,6 +134,10 @@ int VideoOutDriver::RegisterBuffers(VideoOutPort* port, s32 startIndex, void* co
.address_right = 0,
};
// Reset flip label also when registering buffer
port->buffer_labels[startIndex + i] = 0;
port->SignalVoLabel();
presenter->RegisterVideoOutSurface(group, address);
LOG_INFO(Lib_VideoOut, "buffers[{}] = {:#x}", i + startIndex, address);
}
@ -160,11 +165,8 @@ int VideoOutDriver::UnregisterBuffers(VideoOutPort* port, s32 attributeIndex) {
}
void VideoOutDriver::Flip(const Request& req) {
// Whatever the game is rendering show splash if it is active
if (!presenter->ShowSplash(req.frame)) {
// Present the frame.
presenter->Present(req.frame);
}
// Present the frame.
presenter->Present(req.frame);
// Update flip status.
auto* port = req.port;
@ -193,17 +195,16 @@ void VideoOutDriver::Flip(const Request& req) {
}
}
// Reset flip label
if (req.index != -1) {
port->buffer_labels[req.index] = 0;
// Reset prev flip label
if (port->prev_index != -1) {
port->buffer_labels[port->prev_index] = 0;
port->SignalVoLabel();
}
// save to prev buf index
port->prev_index = req.index;
}
void VideoOutDriver::DrawBlankFrame() {
if (presenter->ShowSplash(nullptr)) {
return;
}
const auto empty_frame = presenter->PrepareBlankFrame(false);
presenter->Present(empty_frame);
}

View File

@ -32,6 +32,7 @@ struct VideoOutPort {
std::condition_variable vo_cv;
std::condition_variable vblank_cv;
int flip_rate = 0;
int prev_index = -1;
bool is_open = false;
bool is_mode_changing = false; // Used to prevent flip during mode change

View File

@ -295,10 +295,16 @@ s32 PS4_SYSV_ABI sceVideoOutUnregisterBuffers(s32 handle, s32 attributeIndex) {
return driver->UnregisterBuffers(port, attributeIndex);
}
void sceVideoOutGetBufferLabelAddress(s32 handle, uintptr_t* label_addr) {
s32 PS4_SYSV_ABI sceVideoOutGetBufferLabelAddress(s32 handle, uintptr_t* label_addr) {
if (label_addr == nullptr) {
return ORBIS_VIDEO_OUT_ERROR_INVALID_ADDRESS;
}
auto* port = driver->GetPort(handle);
ASSERT(port);
if (!port) {
return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE;
}
*label_addr = reinterpret_cast<uintptr_t>(port->buffer_labels.data());
return 16;
}
s32 sceVideoOutSubmitEopFlip(s32 handle, u32 buf_id, u32 mode, u32 arg, void** unk) {
@ -360,7 +366,7 @@ s32 PS4_SYSV_ABI sceVideoOutAdjustColor(s32 handle, const SceVideoOutColorSettin
return ORBIS_VIDEO_OUT_ERROR_INVALID_HANDLE;
}
presenter->GetGammaRef() = settings->gamma;
presenter->GetPPSettingsRef().gamma = settings->gamma;
return ORBIS_OK;
}
@ -430,6 +436,8 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) {
sceVideoOutIsFlipPending);
LIB_FUNCTION("N5KDtkIjjJ4", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
sceVideoOutUnregisterBuffers);
LIB_FUNCTION("OcQybQejHEY", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
sceVideoOutGetBufferLabelAddress);
LIB_FUNCTION("uquVH4-Du78", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutClose);
LIB_FUNCTION("1FZBKy8HeNU", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
sceVideoOutGetVblankStatus);
@ -460,6 +468,8 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) {
sceVideoOutSetBufferAttribute);
LIB_FUNCTION("w3BY+tAEiQY", "libSceVideoOut", 1, "libSceVideoOut", 1, 1,
sceVideoOutRegisterBuffers);
LIB_FUNCTION("OcQybQejHEY", "libSceVideoOut", 1, "libSceVideoOut", 1, 1,
sceVideoOutGetBufferLabelAddress);
LIB_FUNCTION("U46NwOiJpys", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutSubmitFlip);
LIB_FUNCTION("SbU3dwp80lQ", "libSceVideoOut", 1, "libSceVideoOut", 1, 1,
sceVideoOutGetFlipStatus);

View File

@ -118,6 +118,7 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle,
s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handle, void* udata);
s32 PS4_SYSV_ABI sceVideoOutRegisterBuffers(s32 handle, s32 startIndex, void* const* addresses,
s32 bufferNum, const BufferAttribute* attribute);
s32 PS4_SYSV_ABI sceVideoOutGetBufferLabelAddress(s32 handle, uintptr_t* label_addr);
s32 PS4_SYSV_ABI sceVideoOutSetFlipRate(s32 handle, s32 rate);
s32 PS4_SYSV_ABI sceVideoOutIsFlipPending(s32 handle);
s32 PS4_SYSV_ABI sceVideoOutWaitVblank(s32 handle);
@ -133,7 +134,6 @@ s32 PS4_SYSV_ABI sceVideoOutColorSettingsSetGamma(SceVideoOutColorSettings* sett
s32 PS4_SYSV_ABI sceVideoOutAdjustColor(s32 handle, const SceVideoOutColorSettings* settings);
// Internal system functions
void sceVideoOutGetBufferLabelAddress(s32 handle, uintptr_t* label_addr);
s32 sceVideoOutSubmitEopFlip(s32 handle, u32 buf_id, u32 mode, u32 arg, void** unk);
void RegisterLib(Core::Loader::SymbolsResolver* sym);

View File

@ -139,6 +139,35 @@ s32 Linker::LoadModule(const std::filesystem::path& elf_name, bool is_dynamic) {
return m_modules.size() - 1;
}
s32 Linker::LoadAndStartModule(const std::filesystem::path& path, u64 args, const void* argp,
int* pRes) {
u32 handle = FindByName(path);
if (handle != -1) {
return handle;
}
handle = LoadModule(path, true);
if (handle == -1) {
return -1;
}
auto* module = GetModule(handle);
RelocateAnyImports(module);
// If the new module has a TLS image, trigger its load when TlsGetAddr is called.
if (module->tls.image_size != 0) {
AdvanceGenerationCounter();
}
// Retrieve and verify proc param according to libkernel.
u64* param = module->GetProcParam<u64*>();
ASSERT_MSG(!param || param[0] >= 0x18, "Invalid module param size: {}", param[0]);
s32 ret = module->Start(args, argp, param);
if (pRes) {
*pRes = ret;
}
return handle;
}
Module* Linker::FindByAddress(VAddr address) {
for (auto& module : m_modules) {
const VAddr base = module->GetBaseAddress();

View File

@ -144,6 +144,8 @@ public:
void FreeTlsForNonPrimaryThread(void* pointer);
s32 LoadModule(const std::filesystem::path& elf_name, bool is_dynamic = false);
s32 LoadAndStartModule(const std::filesystem::path& path, u64 args, const void* argp,
int* pRes);
Module* FindByAddress(VAddr address);
void Relocate(Module* module);

View File

@ -1,28 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/io_file.h"
#include "common/types.h"
#include "loader.h"
namespace Loader {
FileTypes DetectFileType(const std::filesystem::path& filepath) {
// No file loaded
if (filepath.empty()) {
return FileTypes::Unknown;
}
Common::FS::IOFile file;
file.Open(filepath, Common::FS::FileAccessMode::Read);
file.Seek(0);
u32 magic;
file.Read(magic);
file.Close();
switch (magic) {
case PkgMagic:
return FileTypes::Pkg;
}
return FileTypes::Unknown;
}
} // namespace Loader

View File

@ -1,18 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string>
namespace Loader {
constexpr static u32 PkgMagic = 0x544e437f;
enum class FileTypes {
Unknown,
Pkg,
};
FileTypes DetectFileType(const std::filesystem::path& filepath);
} // namespace Loader

View File

@ -38,6 +38,16 @@ void MemoryManager::SetupMemoryRegions(u64 flexible_size, bool use_extended_mem1
bool use_extended_mem2) {
const bool is_neo = ::Libraries::Kernel::sceKernelIsNeoMode();
auto total_size = is_neo ? SCE_KERNEL_TOTAL_MEM_PRO : SCE_KERNEL_TOTAL_MEM;
if (Config::isDevKitConsole()) {
const auto old_size = total_size;
// Assuming 2gb is neo for now, will need to link it with sceKernelIsDevKit
total_size += is_neo ? 2_GB : 768_MB;
LOG_WARNING(Kernel_Vmm,
"Config::isDevKitConsole is enabled! Added additional {:s} of direct memory.",
is_neo ? "2 GB" : "768 MB");
LOG_WARNING(Kernel_Vmm, "Old Direct Size: {:#x} -> New Direct Size: {:#x}", old_size,
total_size);
}
if (!use_extended_mem1 && is_neo) {
total_size -= 256_MB;
}

View File

@ -94,7 +94,7 @@ Module::Module(Core::MemoryManager* memory_, const std::filesystem::path& file_,
Module::~Module() = default;
s32 Module::Start(size_t args, const void* argp, void* param) {
s32 Module::Start(u64 args, const void* argp, void* param) {
LOG_INFO(Core_Linker, "Module started : {}", name);
const VAddr addr = dynamic_info.init_virtual_addr + GetBaseAddress();
return ExecuteGuest(reinterpret_cast<EntryFunc>(addr), args, argp, param);

View File

@ -203,7 +203,7 @@ public:
return (rela_bits[index >> 3] >> (index & 7)) & 1;
}
s32 Start(size_t args, const void* argp, void* param);
s32 Start(u64 args, const void* argp, void* param);
void LoadModuleToMemory(u32& max_tls_index);
void LoadDynamicInfo();
void LoadSymbols();

View File

@ -24,7 +24,6 @@
#include "common/singleton.h"
#include "common/version.h"
#include "core/file_format/psf.h"
#include "core/file_format/splash.h"
#include "core/file_format/trp.h"
#include "core/file_sys/fs.h"
#include "core/libraries/disc_map/disc_map.h"
@ -81,7 +80,7 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
const auto eboot_name = file.filename().string();
auto game_folder = file.parent_path();
if (const auto game_folder_name = game_folder.filename().string();
game_folder_name.ends_with("-UPDATE")) {
game_folder_name.ends_with("-UPDATE") || game_folder_name.ends_with("-patch")) {
// If an executable was launched from a separate update directory,
// use the base game directory as the game folder.
const auto base_name = game_folder_name.substr(0, game_folder_name.size() - 7);
@ -185,12 +184,7 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
const auto pic1_path = mnt->GetHostPath("/app0/sce_sys/pic1.png");
if (std::filesystem::exists(pic1_path)) {
auto* splash = Common::Singleton<Splash>::Instance();
if (!splash->IsLoaded()) {
if (!splash->Open(pic1_path)) {
LOG_ERROR(Loader, "Game splash: unable to open file");
}
}
game_info.splash_path = pic1_path;
}
game_info.initialized = true;
@ -295,13 +289,12 @@ void Emulator::Run(const std::filesystem::path& file, const std::vector<std::str
}
void Emulator::LoadSystemModules(const std::string& game_serial) {
constexpr std::array<SysModules, 11> ModulesToLoad{
constexpr std::array<SysModules, 10> ModulesToLoad{
{{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterlibSceNgs2},
{"libSceUlt.sprx", nullptr},
{"libSceJson.sprx", nullptr},
{"libSceJson2.sprx", nullptr},
{"libSceLibcInternal.sprx", &Libraries::LibcInternal::RegisterlibSceLibcInternal},
{"libSceDiscMap.sprx", &Libraries::DiscMap::RegisterlibSceDiscMap},
{"libSceRtc.sprx", &Libraries::Rtc::RegisterlibSceRtc},
{"libSceCesCs.sprx", nullptr},
{"libSceFont.sprx", nullptr},

BIN
src/images/KBM.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 965 B

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 658 B

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
src/images/trophy_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Some files were not shown because too many files have changed in this diff Show More