diff --git a/.gitmodules b/.gitmodules
index 38aed89a0..b8d1544e4 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -108,8 +108,12 @@
branch = dist
[submodule "externals/MoltenVK"]
path = externals/MoltenVK
- url = https://github.com/KhronosGroup/MoltenVK.git
+ url = https://github.com/shadPS4-emu/ext-MoltenVK.git
shallow = true
[submodule "externals/json"]
path = externals/json
url = https://github.com/nlohmann/json.git
+[submodule "externals/sdl3_mixer"]
+ path = externals/sdl3_mixer
+ url = https://github.com/libsdl-org/SDL_mixer
+ shallow = true
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a4afd5d44..36cea49f4 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -203,7 +203,7 @@ execute_process(
# Set Version
set(EMULATOR_VERSION_MAJOR "0")
set(EMULATOR_VERSION_MINOR "12")
-set(EMULATOR_VERSION_PATCH "1")
+set(EMULATOR_VERSION_PATCH "6")
set_source_files_properties(src/shadps4.rc PROPERTIES COMPILE_DEFINITIONS "EMULATOR_VERSION_MAJOR=${EMULATOR_VERSION_MAJOR};EMULATOR_VERSION_MINOR=${EMULATOR_VERSION_MINOR};EMULATOR_VERSION_PATCH=${EMULATOR_VERSION_PATCH}")
@@ -229,6 +229,7 @@ find_package(magic_enum 0.9.7 CONFIG)
find_package(PNG 1.6 MODULE)
find_package(RenderDoc 1.6.0 MODULE)
find_package(SDL3 3.1.2 CONFIG)
+find_package(SDL3_mixer 2.8.1 CONFIG)
find_package(stb MODULE)
find_package(toml11 4.2.0 CONFIG)
find_package(tsl-robin-map 1.3.0 CONFIG)
@@ -463,6 +464,12 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp
src/core/libraries/mouse/mouse.h
src/core/libraries/web_browser_dialog/webbrowserdialog.cpp
src/core/libraries/web_browser_dialog/webbrowserdialog.h
+ src/core/libraries/font/font.cpp
+ src/core/libraries/font/font.h
+ src/core/libraries/font/fontft.cpp
+ src/core/libraries/font/fontft.h
+ src/core/libraries/font/font_error.h
+
)
set(VIDEOOUT_LIB src/core/libraries/videoout/buffer.h
@@ -535,6 +542,10 @@ set(RANDOM_LIB src/core/libraries/random/random.cpp
set(USBD_LIB src/core/libraries/usbd/usbd.cpp
src/core/libraries/usbd/usbd.h
src/core/libraries/usbd/usb_backend.h
+ src/core/libraries/usbd/emulated/dimensions.cpp
+ src/core/libraries/usbd/emulated/dimensions.h
+ src/core/libraries/usbd/emulated/infinity.cpp
+ src/core/libraries/usbd/emulated/infinity.h
src/core/libraries/usbd/emulated/skylander.cpp
src/core/libraries/usbd/emulated/skylander.h
)
@@ -951,6 +962,8 @@ set(VIDEO_CORE src/video_core/amdgpu/cb_db_extent.h
src/video_core/buffer_cache/buffer.h
src/video_core/buffer_cache/buffer_cache.cpp
src/video_core/buffer_cache/buffer_cache.h
+ src/video_core/buffer_cache/fault_manager.cpp
+ src/video_core/buffer_cache/fault_manager.h
src/video_core/buffer_cache/memory_tracker.h
src/video_core/buffer_cache/range_set.h
src/video_core/buffer_cache/region_definitions.h
@@ -1062,7 +1075,7 @@ add_executable(shadps4
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 libusb::usb lfreist-hwinfo::hwinfo nlohmann_json::nlohmann_json)
+target_link_libraries(shadps4 PRIVATE Boost::headers GPUOpen::VulkanMemoryAllocator LibAtrac9 sirit Vulkan::Headers xxHash::xxhash Zydis::Zydis glslang::glslang SDL3::SDL3 SDL3_mixer::SDL3_mixer pugixml::pugixml stb::headers libusb::usb lfreist-hwinfo::hwinfo nlohmann_json::nlohmann_json)
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")
diff --git a/dist/net.shadps4.shadPS4.metainfo.xml b/dist/net.shadps4.shadPS4.metainfo.xml
index ae07e79d8..5798876f6 100644
--- a/dist/net.shadps4.shadPS4.metainfo.xml
+++ b/dist/net.shadps4.shadPS4.metainfo.xml
@@ -37,6 +37,9 @@
Game
+
+ https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.12.5
+
https://github.com/shadps4-emu/shadPS4/releases/tag/v.0.12.0
diff --git a/documents/building-windows.md b/documents/building-windows.md
index aa7213abc..88c5b6830 100644
--- a/documents/building-windows.md
+++ b/documents/building-windows.md
@@ -36,16 +36,11 @@ Go through the Git for Windows installation as normal
1. Open up Visual Studio, select `Open a local folder` and select the folder with the shadPS4 source code. The folder should contain `CMakeLists.txt`
2. Change Clang x64 Debug to Clang x64 Release if you want a regular, non-debug build.
-3. If you want to build shadPS4 with the Qt Gui, simply select Clang x64 Release with Qt instead.
-4. Change the project to build to shadps4.exe
-5. Build -> Build All
+3. Change the project to build to shadps4.exe
+4. Build -> Build All
Your shadps4.exe will be in `C:\path\to\source\Build\x64-Clang-Release\`
-To automatically populate the necessary files to run shadPS4.exe, run in a command prompt or terminal:
-`C:\Qt\\msvc2022_64\bin\windeployqt6.exe "C:\path\to\shadps4.exe"`
-(Change Qt path if you've installed it to non-default path)
-
## Option 2: MSYS2/MinGW
> [!IMPORTANT]
@@ -73,7 +68,6 @@ ARM64-based computers, follow:
1. Open "MSYS2 CLANGARM64" from your new applications
2. Run `pacman -Syu`, let it complete;
3. Run `pacman -S --needed git mingw-w64-clang-aarch64-binutils mingw-w64-clang-aarch64-clang mingw-w64-clang-aarch64-rapidjson mingw-w64-clang-aarch64-cmake mingw-w64-clang-aarch64-ninja mingw-w64-clang-aarch64-ffmpeg`
- 1. Optional (Qt only): run `pacman -S --needed mingw-w64-clang-aarch64-qt6-base mingw-w64-clang-aarch64-qt6-tools mingw-w64-clang-aarch64-qt6-multimedia`
4. Run `git clone --depth 1 --recursive https://github.com/shadps4-emu/shadPS4`
5. Run `cd shadPS4`
6. Run `cmake -S . -B build -DCMAKE_C_COMPILER="clang.exe" -DCMAKE_CXX_COMPILER="clang++.exe" -DCMAKE_CXX_FLAGS="-O2 -march=native"`
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt
index a26f58d69..5f7ae94c4 100644
--- a/externals/CMakeLists.txt
+++ b/externals/CMakeLists.txt
@@ -63,6 +63,18 @@ if (NOT TARGET SDL3::SDL3)
add_subdirectory(sdl3)
endif()
+# SDL3_mixer
+if (NOT TARGET SDL3_mixer::SDL3_mixer)
+ set(SDLMIXER_FLAC OFF)
+ set(SDLMIXER_OGG OFF)
+ set(SDLMIXER_MOD OFF)
+ set(SDLMIXER_MIDI OFF)
+ set(SDLMIXER_OPUS OFF)
+ set(SDLMIXER_WAVPACK OFF)
+ set(BUILD_SHARED_LIBS OFF)
+ add_subdirectory(sdl3_mixer)
+endif()
+
# vulkan-headers
if (NOT TARGET Vulkan::Headers)
set(VULKAN_HEADERS_ENABLE_MODULE OFF)
diff --git a/externals/MoltenVK b/externals/MoltenVK
index b23d42534..f168dec05 160000
--- a/externals/MoltenVK
+++ b/externals/MoltenVK
@@ -1 +1 @@
-Subproject commit b23d42534622cd9926fe526fec1b7f8795a2853c
+Subproject commit f168dec05998ab0ca09a400bab6831a95c0bdb2e
diff --git a/externals/sdl3_mixer b/externals/sdl3_mixer
new file mode 160000
index 000000000..4182794ea
--- /dev/null
+++ b/externals/sdl3_mixer
@@ -0,0 +1 @@
+Subproject commit 4182794ea45fe28568728670c6f1583855d0e85c
diff --git a/shell.nix b/shell.nix
index 50336d1b2..611095268 100644
--- a/shell.nix
+++ b/shell.nix
@@ -6,42 +6,43 @@ with import (fetchTarball "https://github.com/nixos/nixpkgs/archive/cfd19cdc5468
pkgs.mkShell {
name = "shadps4-build-env";
- nativeBuildInputs = [
- pkgs.llvmPackages_18.clang
- pkgs.cmake
- pkgs.pkg-config
- pkgs.git
+ nativeBuildInputs = with pkgs; [
+ llvmPackages_18.clang
+ cmake
+ pkg-config
+ git
+ util-linux
];
- buildInputs = [
- pkgs.alsa-lib
- pkgs.libpulseaudio
- pkgs.openal
- pkgs.zlib
- pkgs.libedit
- pkgs.udev
- pkgs.libevdev
- pkgs.SDL2
- pkgs.jack2
- pkgs.sndio
+ buildInputs = with pkgs; [
+ alsa-lib
+ libpulseaudio
+ openal
+ zlib
+ libedit
+ udev
+ libevdev
+ SDL2
+ jack2
+ sndio
- pkgs.vulkan-headers
- pkgs.vulkan-utility-libraries
- pkgs.vulkan-tools
+ vulkan-headers
+ vulkan-utility-libraries
+ vulkan-tools
- pkgs.ffmpeg
- pkgs.fmt
- pkgs.glslang
- pkgs.libxkbcommon
- pkgs.wayland
- pkgs.xorg.libxcb
- pkgs.xorg.xcbutil
- pkgs.xorg.xcbutilkeysyms
- pkgs.xorg.xcbutilwm
- pkgs.sdl3
- pkgs.stb
- pkgs.wayland-protocols
- pkgs.libpng
+ ffmpeg
+ fmt
+ glslang
+ libxkbcommon
+ wayland
+ xorg.libxcb
+ xorg.xcbutil
+ xorg.xcbutilkeysyms
+ xorg.xcbutilwm
+ sdl3
+ stb
+ wayland-protocols
+ libpng
];
shellHook = ''
diff --git a/src/common/elf_info.h b/src/common/elf_info.h
index 2f2f150b2..0b2589e95 100644
--- a/src/common/elf_info.h
+++ b/src/common/elf_info.h
@@ -68,6 +68,7 @@ class ElfInfo {
std::string app_ver{};
u32 firmware_ver = 0;
u32 raw_firmware_ver = 0;
+ u32 sdk_ver = 0;
PSFAttributes psf_attributes{};
std::filesystem::path splash_path{};
@@ -117,6 +118,11 @@ public:
return raw_firmware_ver;
}
+ [[nodiscard]] u32 CompiledSdkVer() const {
+ ASSERT(initialized);
+ return sdk_ver;
+ }
+
[[nodiscard]] const PSFAttributes& GetPSFAttributes() const {
ASSERT(initialized);
return psf_attributes;
diff --git a/src/common/io_file.cpp b/src/common/io_file.cpp
index 6fa9062a7..249d0e0f4 100644
--- a/src/common/io_file.cpp
+++ b/src/common/io_file.cpp
@@ -40,28 +40,30 @@ namespace {
switch (mode) {
case FileAccessMode::Read:
return L"rb";
- case FileAccessMode::Write:
- return L"wb";
case FileAccessMode::Append:
return L"ab";
+ case FileAccessMode::Write:
case FileAccessMode::ReadWrite:
return L"r+b";
case FileAccessMode::ReadAppend:
return L"a+b";
+ case FileAccessMode::Create:
+ return L"wb";
}
break;
case FileType::TextFile:
switch (mode) {
case FileAccessMode::Read:
return L"r";
- case FileAccessMode::Write:
- return L"w";
case FileAccessMode::Append:
return L"a";
+ case FileAccessMode::Write:
case FileAccessMode::ReadWrite:
return L"r+";
case FileAccessMode::ReadAppend:
return L"a+";
+ case FileAccessMode::Create:
+ return L"w";
}
break;
}
@@ -91,28 +93,30 @@ namespace {
switch (mode) {
case FileAccessMode::Read:
return "rb";
- case FileAccessMode::Write:
- return "wb";
case FileAccessMode::Append:
return "ab";
+ case FileAccessMode::Write:
case FileAccessMode::ReadWrite:
return "r+b";
case FileAccessMode::ReadAppend:
return "a+b";
+ case FileAccessMode::Create:
+ return "wb";
}
break;
case FileType::TextFile:
switch (mode) {
case FileAccessMode::Read:
return "r";
- case FileAccessMode::Write:
- return "w";
case FileAccessMode::Append:
return "a";
+ case FileAccessMode::Write:
case FileAccessMode::ReadWrite:
return "r+";
case FileAccessMode::ReadAppend:
return "a+";
+ case FileAccessMode::Create:
+ return "w";
}
break;
}
diff --git a/src/common/io_file.h b/src/common/io_file.h
index c6eb3b563..d4e4b2e47 100644
--- a/src/common/io_file.h
+++ b/src/common/io_file.h
@@ -21,9 +21,8 @@ enum class FileAccessMode {
*/
Read = 1 << 0,
/**
- * If the file at path exists, the existing contents of the file are erased.
- * The empty file is then opened for writing.
- * If the file at path does not exist, it creates and opens a new empty file for writing.
+ * If the file at path exists, it opens the file for writing.
+ * If the file at path does not exist, it fails to open the file.
*/
Write = 1 << 1,
/**
@@ -42,6 +41,12 @@ enum class FileAccessMode {
* reading and appending.
*/
ReadAppend = Read | Append,
+ /**
+ * If the file at path exists, the existing contents of the file are erased.
+ * The empty file is then opened for writing.
+ * If the file at path does not exist, it creates and opens a new empty file for writing.
+ */
+ Create = 1 << 3,
};
DECLARE_ENUM_FLAG_OPERATORS(FileAccessMode);
@@ -102,6 +107,11 @@ public:
return file != nullptr;
}
+ bool IsWriteOnly() const {
+ return file_access_mode == FileAccessMode::Append ||
+ file_access_mode == FileAccessMode::Write;
+ }
+
uintptr_t GetFileMapping();
int Open(const std::filesystem::path& path, FileAccessMode mode,
@@ -210,7 +220,7 @@ public:
}
static size_t WriteBytes(const std::filesystem::path path, const auto& data) {
- IOFile out(path, FileAccessMode::Write);
+ IOFile out(path, FileAccessMode::Create);
return out.Write(data);
}
std::FILE* file = nullptr;
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index ce9386853..4a85c4cde 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -62,7 +62,7 @@ private:
class FileBackend {
public:
explicit FileBackend(const std::filesystem::path& filename, bool should_append = false)
- : file{filename, should_append ? FS::FileAccessMode::Append : FS::FileAccessMode::Write,
+ : file{filename, should_append ? FS::FileAccessMode::Append : FS::FileAccessMode::Create,
FS::FileType::TextFile} {}
~FileBackend() = default;
@@ -182,7 +182,13 @@ public:
}
void PushEntry(Class log_class, Level log_level, const char* filename, unsigned int line_num,
- const char* function, std::string message) {
+ const char* function, const char* format, const fmt::format_args& args) {
+ if (!filter.CheckMessage(log_class, log_level) || !Config::getLoggingEnabled()) {
+ return;
+ }
+
+ const auto message = fmt::vformat(format, args);
+
// Propagate important log messages to the profiler
if (IsProfilerConnected()) {
const auto& msg_str = fmt::format("[{}] {}", GetLogClassName(log_class), message);
@@ -201,10 +207,6 @@ public:
}
}
- if (!filter.CheckMessage(log_class, log_level) || !Config::getLoggingEnabled()) {
- return;
- }
-
using std::chrono::duration_cast;
using std::chrono::microseconds;
using std::chrono::steady_clock;
@@ -324,8 +326,8 @@ void FmtLogMessageImpl(Class log_class, Level log_level, const char* filename,
unsigned int line_num, const char* function, const char* format,
const fmt::format_args& args) {
if (!initialization_in_progress_suppress_logging) [[likely]] {
- Impl::Instance().PushEntry(log_class, log_level, filename, line_num, function,
- fmt::vformat(format, args));
+ Impl::Instance().PushEntry(log_class, log_level, filename, line_num, function, format,
+ args);
}
}
} // namespace Common::Log
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
index 2f98f07a0..bf6844c7d 100644
--- a/src/common/logging/filter.cpp
+++ b/src/common/logging/filter.cpp
@@ -140,6 +140,8 @@ bool ParseFilterRule(Filter& instance, Iterator begin, Iterator end) {
SUB(Lib, NpParty) \
SUB(Lib, Zlib) \
SUB(Lib, Hmd) \
+ SUB(Lib, Font) \
+ SUB(Lib, FontFt) \
SUB(Lib, HmdSetupDialog) \
SUB(Lib, SigninDialog) \
SUB(Lib, Camera) \
diff --git a/src/common/logging/types.h b/src/common/logging/types.h
index eee9d4ca2..035a959db 100644
--- a/src/common/logging/types.h
+++ b/src/common/logging/types.h
@@ -114,6 +114,8 @@ enum class Class : u8 {
Lib_CompanionHttpd, ///< The LibCompanionHttpd implementation.
Lib_CompanionUtil, ///< The LibCompanionUtil implementation.
Lib_VrTracker, ///< The LibSceVrTracker implementation.
+ Lib_Font, ///< The libSceFont implementation.
+ Lib_FontFt, ///< The libSceFontFt implementation.
Frontend, ///< Emulator UI
Render, ///< Video Core
Render_Vulkan, ///< Vulkan backend
diff --git a/src/core/address_space.cpp b/src/core/address_space.cpp
index 3f2d94cbf..3f063ea76 100644
--- a/src/core/address_space.cpp
+++ b/src/core/address_space.cpp
@@ -6,6 +6,7 @@
#include "common/arch.h"
#include "common/assert.h"
#include "common/config.h"
+#include "common/elf_info.h"
#include "common/error.h"
#include "core/address_space.h"
#include "core/libraries/kernel/memory.h"
@@ -103,8 +104,8 @@ struct AddressSpace::Impl {
GetSystemInfo(&sys_info);
u64 alignment = sys_info.dwAllocationGranularity;
- // Determine the host OS build number
- // Retrieve module handle for ntdll
+ // Older Windows builds have a severe performance issue with VirtualAlloc2.
+ // We need to get the host's Windows version, then determine if it needs a workaround.
auto ntdll_handle = GetModuleHandleW(L"ntdll.dll");
ASSERT_MSG(ntdll_handle, "Failed to retrieve ntdll handle");
@@ -120,12 +121,20 @@ struct AddressSpace::Impl {
u64 supported_user_max = USER_MAX;
// This is the build number for Windows 11 22H2
static constexpr s32 AffectedBuildNumber = 22621;
- if (os_version_info.dwBuildNumber <= AffectedBuildNumber) {
- // Older Windows builds have an issue with VirtualAlloc2 on higher addresses.
- // To prevent regressions, limit the maximum address we reserve for this platform.
- supported_user_max = 0x11000000000ULL;
- LOG_WARNING(Core, "Windows 10 detected, reducing user max to {:#x} to avoid problems",
- supported_user_max);
+
+ // Higher PS4 firmware versions prevent higher address mappings too.
+ s32 sdk_ver = Common::ElfInfo::Instance().CompiledSdkVer();
+ if (os_version_info.dwBuildNumber <= AffectedBuildNumber ||
+ sdk_ver >= Common::ElfInfo::FW_30) {
+ supported_user_max = 0x10000000000ULL;
+ // Only log the message if we're restricting the user max due to operating system.
+ // Since higher compiled SDK versions also get reduced max, we don't need to log there.
+ if (sdk_ver < Common::ElfInfo::FW_30) {
+ LOG_WARNING(
+ Core,
+ "Older Windows version detected, reducing user max to {:#x} to avoid problems",
+ supported_user_max);
+ }
}
// Determine the free address ranges we can access.
diff --git a/src/core/devtools/widget/common.h b/src/core/devtools/widget/common.h
index 4684f6e3b..1c79ffcac 100644
--- a/src/core/devtools/widget/common.h
+++ b/src/core/devtools/widget/common.h
@@ -152,7 +152,7 @@ inline std::string RunDisassembler(const std::string& disassembler_cli, const T&
}
} else {
cli.replace(pos, src_arg.size(), "\"" + bin_path.string() + "\"");
- Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Write);
+ Common::FS::IOFile file(bin_path, Common::FS::FileAccessMode::Create);
file.Write(shader_code);
file.Close();
diff --git a/src/core/devtools/widget/frame_dump.cpp b/src/core/devtools/widget/frame_dump.cpp
index 1eaa78897..06b65b0ba 100644
--- a/src/core/devtools/widget/frame_dump.cpp
+++ b/src/core/devtools/widget/frame_dump.cpp
@@ -123,7 +123,7 @@ void FrameDumpViewer::Draw() {
const auto fname = fmt::format("{:%F %H-%M-%S} {}_{}_{}.bin", now_time,
magic_enum::enum_name(selected_queue_type),
selected_submit_num, selected_queue_num2);
- Common::FS::IOFile file(fname, Common::FS::FileAccessMode::Write);
+ Common::FS::IOFile file(fname, Common::FS::FileAccessMode::Create);
const auto& data = frame_dump->queues[selected_cmd].data;
if (file.IsOpen()) {
DebugState.ShowDebugMessage(fmt::format("Dumping cmd as {}", fname));
diff --git a/src/core/file_format/psf.cpp b/src/core/file_format/psf.cpp
index 7e0ffc9a3..047828330 100644
--- a/src/core/file_format/psf.cpp
+++ b/src/core/file_format/psf.cpp
@@ -99,7 +99,7 @@ bool PSF::Open(const std::vector& psf_buffer) {
}
bool PSF::Encode(const std::filesystem::path& filepath) const {
- Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Write);
+ Common::FS::IOFile file(filepath, Common::FS::FileAccessMode::Create);
if (!file.IsOpen()) {
return false;
}
diff --git a/src/core/libraries/font/font.cpp b/src/core/libraries/font/font.cpp
new file mode 100644
index 000000000..1454004aa
--- /dev/null
+++ b/src/core/libraries/font/font.cpp
@@ -0,0 +1,1611 @@
+// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/logging/log.h"
+#include "core/libraries/error_codes.h"
+#include "core/libraries/font/font.h"
+#include "core/libraries/libs.h"
+#include "font_error.h"
+
+namespace Libraries::Font {
+
+s32 PS4_SYSV_ABI sceFontAttachDeviceCacheBuffer() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontBindRenderer() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontCharacterGetBidiLevel(OrbisFontTextCharacter* textCharacter,
+ int* bidiLevel) {
+ if (!textCharacter || !bidiLevel) {
+ LOG_DEBUG(Lib_Font, "Invalid parameter");
+ return ORBIS_FONT_ERROR_INVALID_PARAMETER;
+ }
+
+ *bidiLevel = textCharacter->bidiLevel;
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontCharacterGetSyllableStringState() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontCharacterGetTextFontCode() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontCharacterGetTextOrder(OrbisFontTextCharacter* textCharacter,
+ void** pTextOrder) {
+ if (!pTextOrder) {
+ LOG_DEBUG(Lib_Font, "Invalid parameter");
+ return ORBIS_FONT_ERROR_INVALID_PARAMETER;
+ }
+
+ if (!textCharacter) {
+ LOG_DEBUG(Lib_Font, "Invalid parameter");
+ *pTextOrder = NULL;
+ return ORBIS_FONT_ERROR_INVALID_PARAMETER;
+ }
+
+ // Retrieve text order
+ *pTextOrder = textCharacter->textOrder;
+ return ORBIS_OK;
+}
+
+u32 PS4_SYSV_ABI sceFontCharacterLooksFormatCharacters(OrbisFontTextCharacter* textCharacter) {
+ if (!textCharacter) {
+ return 0;
+ }
+
+ // Check if the format flag (bit 2) is set
+ return (textCharacter->formatFlags & 0x04) ? textCharacter->characterCode : 0;
+}
+
+u32 PS4_SYSV_ABI sceFontCharacterLooksWhiteSpace(OrbisFontTextCharacter* textCharacter) {
+ if (!textCharacter) {
+ return 0;
+ }
+
+ return (textCharacter->charType == 0x0E) ? textCharacter->characterCode : 0;
+}
+
+OrbisFontTextCharacter* PS4_SYSV_ABI
+sceFontCharacterRefersTextBack(OrbisFontTextCharacter* textCharacter) {
+ if (!textCharacter)
+ return NULL; // Check if input is NULL
+
+ OrbisFontTextCharacter* current = textCharacter->prev; // Move backward instead of forward
+ while (current) {
+ if (current->unkn_0x31 == 0 && current->unkn_0x33 == 0) {
+ return current; // Return the first matching node
+ }
+ current = current->prev; // Move to the previous node
+ }
+
+ return NULL; // No valid node found
+}
+
+OrbisFontTextCharacter* PS4_SYSV_ABI
+sceFontCharacterRefersTextNext(OrbisFontTextCharacter* textCharacter) {
+ if (!textCharacter)
+ return NULL; // Null check
+
+ OrbisFontTextCharacter* current = textCharacter->next;
+ while (current) {
+ if (current->unkn_0x31 == 0 && current->unkn_0x33 == 0) {
+ return current; // Found a match
+ }
+ current = current->next; // Move to the next node
+ }
+
+ return NULL; // No matching node found
+}
+
+s32 PS4_SYSV_ABI sceFontCharactersRefersTextCodes() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontClearDeviceCache() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontCloseFont() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontControl() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontCreateGraphicsDevice() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontCreateGraphicsService() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontCreateGraphicsServiceWithEdition() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontCreateLibrary() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontCreateLibraryWithEdition() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontCreateRenderer() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontCreateRendererWithEdition() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontCreateString() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontCreateWords() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontCreateWritingLine() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontDefineAttribute() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontDeleteGlyph() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontDestroyGraphicsDevice() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontDestroyGraphicsService() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontDestroyLibrary() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontDestroyRenderer() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontDestroyString() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontDestroyWords() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontDestroyWritingLine() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontDettachDeviceCacheBuffer() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGenerateCharGlyph() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetAttribute() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetCharGlyphCode() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetCharGlyphMetrics() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetEffectSlant() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetEffectWeight() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetFontGlyphsCount() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetFontGlyphsOutlineProfile() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetFontMetrics() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetFontResolution() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetFontStyleInformation() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetGlyphExpandBufferState() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetHorizontalLayout() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetKerning() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetLibrary() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetPixelResolution() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetRenderCharGlyphMetrics() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetRenderEffectSlant() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetRenderEffectWeight() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetRenderScaledKerning() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetRenderScalePixel() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetRenderScalePoint() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetResolutionDpi() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetScalePixel() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetScalePoint() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetScriptLanguage() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetTypographicDesign() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGetVerticalLayout() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGlyphDefineAttribute() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGlyphGetAttribute() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGlyphGetGlyphForm() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGlyphGetMetricsForm() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGlyphGetScalePixel() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGlyphRefersMetrics() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGlyphRefersMetricsHorizontal() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGlyphRefersMetricsHorizontalAdvance() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGlyphRefersMetricsHorizontalX() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGlyphRefersOutline() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGlyphRenderImage() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGlyphRenderImageHorizontal() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGlyphRenderImageVertical() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsBeginFrame() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsDrawingCancel() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsDrawingFinish() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsEndFrame() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsExchangeResource() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsFillMethodInit() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsFillPlotInit() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsFillPlotSetLayout() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsFillPlotSetMapping() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsFillRatesInit() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsFillRatesSetFillEffect() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsFillRatesSetLayout() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsFillRatesSetMapping() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsGetDeviceUsage() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsRegionInit() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsRegionInitCircular() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsRegionInitRoundish() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsRelease() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsRenderResource() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsSetFramePolicy() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsSetupClipping() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsSetupColorRates() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsSetupFillMethod() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsSetupFillRates() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsSetupGlyphFill() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsSetupGlyphFillPlot() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsSetupHandleDefault() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsSetupLocation() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsSetupPositioning() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsSetupRotation() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsSetupScaling() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsSetupShapeFill() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsSetupShapeFillPlot() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsStructureCanvas() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsStructureCanvasSequence() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsStructureDesign() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsStructureDesignResource() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsStructureSurfaceTexture() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateClipping() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateColorRates() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateFillMethod() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateFillRates() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateGlyphFill() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateGlyphFillPlot() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateLocation() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsUpdatePositioning() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateRotation() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateScaling() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateShapeFill() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateShapeFillPlot() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontMemoryInit() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontMemoryTerm() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontOpenFontFile() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontOpenFontInstance() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontOpenFontMemory() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontOpenFontSet() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontRebindRenderer() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontRenderCharGlyphImage() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontRenderCharGlyphImageHorizontal() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontRenderCharGlyphImageVertical() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontRendererGetOutlineBufferSize() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontRendererResetOutlineBuffer() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontRendererSetOutlineBufferPolicy() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+void PS4_SYSV_ABI sceFontRenderSurfaceInit(OrbisFontRenderSurface* renderSurface, void* buffer,
+ int bufWidthByte, int pixelSizeByte, int widthPixel,
+ int heightPixel) {
+ if (renderSurface) { // Ensure surface is not NULL before modifying it
+ renderSurface->buffer = buffer;
+ renderSurface->widthByte = bufWidthByte;
+ renderSurface->pixelSizeByte = pixelSizeByte;
+
+ // Initialize unknown fields (likely reserved or flags)
+ renderSurface->unkn_0xd = 0;
+ renderSurface->styleFlag = 0;
+ renderSurface->unkn_0xf = 0;
+
+ // Ensure width and height are non-negative
+ renderSurface->width = (widthPixel < 0) ? 0 : widthPixel;
+ renderSurface->height = (heightPixel < 0) ? 0 : heightPixel;
+
+ // Set the clipping/scaling rectangle
+ renderSurface->sc_x0 = 0;
+ renderSurface->sc_y0 = 0;
+ renderSurface->sc_x1 = renderSurface->width;
+ renderSurface->sc_y1 = renderSurface->height;
+ }
+}
+
+void PS4_SYSV_ABI sceFontRenderSurfaceSetScissor(OrbisFontRenderSurface* renderSurface, int x0,
+ int y0, int w, int h) {
+ if (!renderSurface)
+ return; // Null check
+
+ // Handle horizontal clipping
+ int surfaceWidth = renderSurface->width;
+ int clip_x0, clip_x1;
+
+ if (surfaceWidth != 0) {
+ if (x0 < 0) { // Adjust for negative x0
+ clip_x0 = 0;
+ clip_x1 = (w + x0 > surfaceWidth) ? surfaceWidth : w + x0;
+ if (w <= -x0)
+ clip_x1 = 0; // Entire width is clipped
+ } else {
+ clip_x0 = (x0 > surfaceWidth) ? surfaceWidth : x0;
+ clip_x1 = (w + x0 > surfaceWidth) ? surfaceWidth : w + x0;
+ }
+ renderSurface->sc_x0 = clip_x0;
+ renderSurface->sc_x1 = clip_x1;
+ }
+
+ // Handle vertical clipping
+ int surfaceHeight = renderSurface->height;
+ int clip_y0, clip_y1;
+
+ if (surfaceHeight != 0) {
+ if (y0 < 0) { // Adjust for negative y0
+ clip_y0 = 0;
+ clip_y1 = (h + y0 > surfaceHeight) ? surfaceHeight : h + y0;
+ if (h <= -y0)
+ clip_y1 = 0; // Entire height is clipped
+ } else {
+ clip_y0 = (y0 > surfaceHeight) ? surfaceHeight : y0;
+ clip_y1 = (h + y0 > surfaceHeight) ? surfaceHeight : h + y0;
+ }
+ renderSurface->sc_y0 = clip_y0;
+ renderSurface->sc_y1 = clip_y1;
+ }
+}
+
+s32 PS4_SYSV_ABI sceFontRenderSurfaceSetStyleFrame(OrbisFontRenderSurface* renderSurface,
+ OrbisFontStyleFrame* styleFrame) {
+ if (!renderSurface) {
+ LOG_ERROR(Lib_Font, "Invalid Parameter");
+ return ORBIS_FONT_ERROR_INVALID_PARAMETER;
+ }
+
+ if (!styleFrame) {
+ renderSurface->styleFlag &= 0xFE; // Clear style flag
+ } else {
+ // Validate magic number
+ if (styleFrame->magic != 0xF09) {
+ LOG_ERROR(Lib_Font, "Invalid magic");
+ return ORBIS_FONT_ERROR_INVALID_PARAMETER;
+ }
+
+ renderSurface->styleFlag |= 1; // Set style flag
+ }
+
+ // Assign style frame pointer
+ renderSurface->unkn_28[0] = styleFrame;
+ *(uint32_t*)(renderSurface->unkn_28 + 1) = 0; // Reset related field
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSetEffectSlant() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSetEffectWeight() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSetFontsOpenMode() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSetResolutionDpi() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSetScalePixel() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSetScalePoint() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSetScriptLanguage() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSetTypographicDesign() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSetupRenderEffectSlant() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSetupRenderEffectWeight() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSetupRenderScalePixel() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSetupRenderScalePoint() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStringGetTerminateCode() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStringGetTerminateOrder() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStringGetWritingForm() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStringRefersRenderCharacters() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStringRefersTextCharacters() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStyleFrameGetEffectSlant(OrbisFontStyleFrame* styleFrame,
+ float* slantRatio) {
+ if (!styleFrame) {
+ LOG_ERROR(Lib_Font, "Invalid Parameter");
+ return ORBIS_FONT_ERROR_INVALID_PARAMETER;
+ }
+
+ // Validate the magic number
+ if (styleFrame->magic != 0xF09) {
+ LOG_ERROR(Lib_Font, "Invalid Magic");
+ return ORBIS_FONT_ERROR_INVALID_PARAMETER;
+ }
+
+ // Check if the slant effect is enabled (bit 1 in flags)
+ if (!(styleFrame->flags & 0x02)) {
+ LOG_ERROR(Lib_Font, "Flag not set");
+ return ORBIS_FONT_ERROR_UNSET_PARAMETER;
+ }
+
+ if (!slantRatio) {
+ LOG_ERROR(Lib_Font, "Invalid Parameter");
+ return ORBIS_FONT_ERROR_INVALID_PARAMETER;
+ }
+
+ // Retrieve slant ratio
+ *slantRatio = styleFrame->slantRatio;
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStyleFrameGetEffectWeight(OrbisFontStyleFrame* fontStyleFrame,
+ float* weightXScale, float* weightYScale,
+ uint32_t* mode) {
+ if (!fontStyleFrame) {
+ LOG_ERROR(Lib_Font, "Invalid Parameter");
+ return ORBIS_FONT_ERROR_INVALID_PARAMETER;
+ }
+
+ // Validate the magic number
+ if (fontStyleFrame->magic != 0xF09) {
+ LOG_ERROR(Lib_Font, "Magic not set");
+ return ORBIS_FONT_ERROR_INVALID_PARAMETER;
+ }
+
+ // Check if the weight effect is enabled (bit 2 in flags)
+ if (!(fontStyleFrame->flags & 0x04)) {
+ LOG_ERROR(Lib_Font, "Flag not set");
+ return ORBIS_FONT_ERROR_UNSET_PARAMETER;
+ }
+
+ // Retrieve weight scales (default is +1.0 to maintain normal weight)
+ if (weightXScale) {
+ *weightXScale = fontStyleFrame->weightXScale + 1.0f;
+ }
+ if (weightYScale) {
+ *weightYScale = fontStyleFrame->weightYScale + 1.0f;
+ }
+
+ // Reset mode if provided
+ if (mode) {
+ *mode = 0;
+ }
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStyleFrameGetResolutionDpi() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStyleFrameGetScalePixel(OrbisFontStyleFrame* styleFrame, float* w,
+ float* h) {
+ if (!styleFrame) {
+ LOG_ERROR(Lib_Font, "Invalid Parameter");
+ return ORBIS_FONT_ERROR_INVALID_PARAMETER;
+ }
+
+ if (styleFrame->magic != 0xF09) {
+ LOG_ERROR(Lib_Font, "Invalid magic");
+ return ORBIS_FONT_ERROR_INVALID_PARAMETER;
+ }
+
+ if (!(styleFrame->flags & 0x01)) {
+ LOG_ERROR(Lib_Font, "Scaling effect parameter not set");
+ return ORBIS_FONT_ERROR_UNSET_PARAMETER;
+ }
+
+ // Check if scaling is allowed
+ int isScalingEnabled = styleFrame->scalingFlag;
+ if (w) {
+ *w = styleFrame->scaleWidth;
+ if (isScalingEnabled && styleFrame->dpiX) {
+ *w *= ((float)styleFrame->dpiX / 72.0f);
+ }
+ }
+
+ if (h) {
+ *h = styleFrame->scaleHeight;
+ if (isScalingEnabled && styleFrame->dpiY) {
+ *h *= ((float)styleFrame->dpiY / 72.0f);
+ }
+ }
+
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStyleFrameGetScalePoint() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStyleFrameInit() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStyleFrameSetEffectSlant() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStyleFrameSetEffectWeight() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStyleFrameSetResolutionDpi() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStyleFrameSetScalePixel() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStyleFrameSetScalePoint() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStyleFrameUnsetEffectSlant() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStyleFrameUnsetEffectWeight() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontStyleFrameUnsetScale() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSupportExternalFonts() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSupportGlyphs() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSupportSystemFonts() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontTextCodesStepBack() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontTextCodesStepNext() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontTextSourceInit() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontTextSourceRewind() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontTextSourceSetDefaultFont() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontTextSourceSetWritingForm() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontUnbindRenderer() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontWordsFindWordCharacters() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontWritingGetRenderMetrics() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontWritingInit() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontWritingLineClear() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontWritingLineGetOrderingSpace() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontWritingLineGetRenderMetrics() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontWritingLineRefersRenderStep() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontWritingLineWritesOrder() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontWritingRefersRenderStep() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontWritingRefersRenderStepCharacter() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontWritingSetMaskInvisible() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_00F4D778F1C88CB3() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_03C650025FBB0DE7() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_07EAB8A163B27E1A() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_09408E88E4F97CE3() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_09F92905ED82A814() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_0D142CEE1AB21ABE() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_14BD2E9E119C16F2() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_1AC53C9EDEAE8D75() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_1D401185D5E24C3D() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_1E83CD20C2CC996F() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_314B1F765B9FE78A() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_350E6725FEDE29E1() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_3DB773F0A604BF39() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_4FF49DD21E311B1C() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_526287664A493981() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_55CA718DBC84A6E9() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_563FC5F0706A8B4D() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_569E2ECD34290F45() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_5A04775B6BE47685() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_5FD93BCAB6F79750() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_62B5398F864BD3B4() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_6F9010294D822367() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_7757E947423A7A67() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_7E06BA52077F54FA() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_93B36DEA021311D6() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_94B0891E7111598A() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_9785C9128C2FE7CD() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_97DFBC9B65FBC0E1() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_ACD9717405D7D3CA() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_B19A8AEC3FD4F16F() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_C10F488AD7CF103D() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_D0C8B5FF4A6826C7() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_E48D3CD01C342A33() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_EAC96B2186B71E14() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_FE4788A96EF46256() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI Func_FE7E5AE95D3058F5() {
+ LOG_ERROR(Lib_Font, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+void RegisterlibSceFont(Core::Loader::SymbolsResolver* sym) {
+ LIB_FUNCTION("CUKn5pX-NVY", "libSceFont", 1, "libSceFont", sceFontAttachDeviceCacheBuffer);
+ LIB_FUNCTION("3OdRkSjOcog", "libSceFont", 1, "libSceFont", sceFontBindRenderer);
+ LIB_FUNCTION("6DFUkCwQLa8", "libSceFont", 1, "libSceFont", sceFontCharacterGetBidiLevel);
+ LIB_FUNCTION("coCrV6IWplE", "libSceFont", 1, "libSceFont",
+ sceFontCharacterGetSyllableStringState);
+ LIB_FUNCTION("zN3+nuA0SFQ", "libSceFont", 1, "libSceFont", sceFontCharacterGetTextFontCode);
+ LIB_FUNCTION("mxgmMj-Mq-o", "libSceFont", 1, "libSceFont", sceFontCharacterGetTextOrder);
+ LIB_FUNCTION("-P6X35Rq2-E", "libSceFont", 1, "libSceFont",
+ sceFontCharacterLooksFormatCharacters);
+ LIB_FUNCTION("SaRlqtqaCew", "libSceFont", 1, "libSceFont", sceFontCharacterLooksWhiteSpace);
+ LIB_FUNCTION("6Gqlv5KdTbU", "libSceFont", 1, "libSceFont", sceFontCharacterRefersTextBack);
+ LIB_FUNCTION("BkjBP+YC19w", "libSceFont", 1, "libSceFont", sceFontCharacterRefersTextNext);
+ LIB_FUNCTION("lVSR5ftvNag", "libSceFont", 1, "libSceFont", sceFontCharactersRefersTextCodes);
+ LIB_FUNCTION("I9R5VC6eZWo", "libSceFont", 1, "libSceFont", sceFontClearDeviceCache);
+ LIB_FUNCTION("vzHs3C8lWJk", "libSceFont", 1, "libSceFont", sceFontCloseFont);
+ LIB_FUNCTION("MpKSBaYKluo", "libSceFont", 1, "libSceFont", sceFontControl);
+ LIB_FUNCTION("WBNBaj9XiJU", "libSceFont", 1, "libSceFont", sceFontCreateGraphicsDevice);
+ LIB_FUNCTION("4So0MC3oBIM", "libSceFont", 1, "libSceFont", sceFontCreateGraphicsService);
+ LIB_FUNCTION("NlO5Qlhjkng", "libSceFont", 1, "libSceFont",
+ sceFontCreateGraphicsServiceWithEdition);
+ LIB_FUNCTION("nWrfPI4Okmg", "libSceFont", 1, "libSceFont", sceFontCreateLibrary);
+ LIB_FUNCTION("n590hj5Oe-k", "libSceFont", 1, "libSceFont", sceFontCreateLibraryWithEdition);
+ LIB_FUNCTION("u5fZd3KZcs0", "libSceFont", 1, "libSceFont", sceFontCreateRenderer);
+ LIB_FUNCTION("WaSFJoRWXaI", "libSceFont", 1, "libSceFont", sceFontCreateRendererWithEdition);
+ LIB_FUNCTION("MO24vDhmS4E", "libSceFont", 1, "libSceFont", sceFontCreateString);
+ LIB_FUNCTION("cYrMGk1wrMA", "libSceFont", 1, "libSceFont", sceFontCreateWords);
+ LIB_FUNCTION("7rogx92EEyc", "libSceFont", 1, "libSceFont", sceFontCreateWritingLine);
+ LIB_FUNCTION("8h-SOB-asgk", "libSceFont", 1, "libSceFont", sceFontDefineAttribute);
+ LIB_FUNCTION("LHDoRWVFGqk", "libSceFont", 1, "libSceFont", sceFontDeleteGlyph);
+ LIB_FUNCTION("5QG71IjgOpQ", "libSceFont", 1, "libSceFont", sceFontDestroyGraphicsDevice);
+ LIB_FUNCTION("zZQD3EwJo3c", "libSceFont", 1, "libSceFont", sceFontDestroyGraphicsService);
+ LIB_FUNCTION("FXP359ygujs", "libSceFont", 1, "libSceFont", sceFontDestroyLibrary);
+ LIB_FUNCTION("exAxkyVLt0s", "libSceFont", 1, "libSceFont", sceFontDestroyRenderer);
+ LIB_FUNCTION("SSCaczu2aMQ", "libSceFont", 1, "libSceFont", sceFontDestroyString);
+ LIB_FUNCTION("hWE4AwNixqY", "libSceFont", 1, "libSceFont", sceFontDestroyWords);
+ LIB_FUNCTION("PEjv7CVDRYs", "libSceFont", 1, "libSceFont", sceFontDestroyWritingLine);
+ LIB_FUNCTION("UuY-OJF+f0k", "libSceFont", 1, "libSceFont", sceFontDettachDeviceCacheBuffer);
+ LIB_FUNCTION("C-4Qw5Srlyw", "libSceFont", 1, "libSceFont", sceFontGenerateCharGlyph);
+ LIB_FUNCTION("5kx49CAlO-M", "libSceFont", 1, "libSceFont", sceFontGetAttribute);
+ LIB_FUNCTION("OINC0X9HGBY", "libSceFont", 1, "libSceFont", sceFontGetCharGlyphCode);
+ LIB_FUNCTION("L97d+3OgMlE", "libSceFont", 1, "libSceFont", sceFontGetCharGlyphMetrics);
+ LIB_FUNCTION("ynSqYL8VpoA", "libSceFont", 1, "libSceFont", sceFontGetEffectSlant);
+ LIB_FUNCTION("d7dDgRY+Bzw", "libSceFont", 1, "libSceFont", sceFontGetEffectWeight);
+ LIB_FUNCTION("ZB8xRemRRG8", "libSceFont", 1, "libSceFont", sceFontGetFontGlyphsCount);
+ LIB_FUNCTION("4X14YSK4Ldk", "libSceFont", 1, "libSceFont", sceFontGetFontGlyphsOutlineProfile);
+ LIB_FUNCTION("eb9S3zNlV5o", "libSceFont", 1, "libSceFont", sceFontGetFontMetrics);
+ LIB_FUNCTION("tiIlroGki+g", "libSceFont", 1, "libSceFont", sceFontGetFontResolution);
+ LIB_FUNCTION("3hVv3SNoL6E", "libSceFont", 1, "libSceFont", sceFontGetFontStyleInformation);
+ LIB_FUNCTION("gVQpMBuB7fE", "libSceFont", 1, "libSceFont", sceFontGetGlyphExpandBufferState);
+ LIB_FUNCTION("imxVx8lm+KM", "libSceFont", 1, "libSceFont", sceFontGetHorizontalLayout);
+ LIB_FUNCTION("sDuhHGNhHvE", "libSceFont", 1, "libSceFont", sceFontGetKerning);
+ LIB_FUNCTION("LzmHDnlcwfQ", "libSceFont", 1, "libSceFont", sceFontGetLibrary);
+ LIB_FUNCTION("BozJej5T6fs", "libSceFont", 1, "libSceFont", sceFontGetPixelResolution);
+ LIB_FUNCTION("IQtleGLL5pQ", "libSceFont", 1, "libSceFont", sceFontGetRenderCharGlyphMetrics);
+ LIB_FUNCTION("Gqa5Pp7y4MU", "libSceFont", 1, "libSceFont", sceFontGetRenderEffectSlant);
+ LIB_FUNCTION("woOjHrkjIYg", "libSceFont", 1, "libSceFont", sceFontGetRenderEffectWeight);
+ LIB_FUNCTION("ryPlnDDI3rU", "libSceFont", 1, "libSceFont", sceFontGetRenderScaledKerning);
+ LIB_FUNCTION("EY38A01lq2k", "libSceFont", 1, "libSceFont", sceFontGetRenderScalePixel);
+ LIB_FUNCTION("FEafYUcxEGo", "libSceFont", 1, "libSceFont", sceFontGetRenderScalePoint);
+ LIB_FUNCTION("8REoLjNGCpM", "libSceFont", 1, "libSceFont", sceFontGetResolutionDpi);
+ LIB_FUNCTION("CkVmLoCNN-8", "libSceFont", 1, "libSceFont", sceFontGetScalePixel);
+ LIB_FUNCTION("GoF2bhB7LYk", "libSceFont", 1, "libSceFont", sceFontGetScalePoint);
+ LIB_FUNCTION("IrXeG0Lc6nA", "libSceFont", 1, "libSceFont", sceFontGetScriptLanguage);
+ LIB_FUNCTION("7-miUT6pNQw", "libSceFont", 1, "libSceFont", sceFontGetTypographicDesign);
+ LIB_FUNCTION("3BrWWFU+4ts", "libSceFont", 1, "libSceFont", sceFontGetVerticalLayout);
+ LIB_FUNCTION("8-zmgsxkBek", "libSceFont", 1, "libSceFont", sceFontGlyphDefineAttribute);
+ LIB_FUNCTION("oO33Uex4Ui0", "libSceFont", 1, "libSceFont", sceFontGlyphGetAttribute);
+ LIB_FUNCTION("PXlA0M8ax40", "libSceFont", 1, "libSceFont", sceFontGlyphGetGlyphForm);
+ LIB_FUNCTION("XUfSWpLhrUw", "libSceFont", 1, "libSceFont", sceFontGlyphGetMetricsForm);
+ LIB_FUNCTION("lNnUqa1zA-M", "libSceFont", 1, "libSceFont", sceFontGlyphGetScalePixel);
+ LIB_FUNCTION("ntrc3bEWlvQ", "libSceFont", 1, "libSceFont", sceFontGlyphRefersMetrics);
+ LIB_FUNCTION("9kTbF59TjLs", "libSceFont", 1, "libSceFont", sceFontGlyphRefersMetricsHorizontal);
+ LIB_FUNCTION("nJavPEdMDvM", "libSceFont", 1, "libSceFont",
+ sceFontGlyphRefersMetricsHorizontalAdvance);
+ LIB_FUNCTION("JCnVgZgcucs", "libSceFont", 1, "libSceFont",
+ sceFontGlyphRefersMetricsHorizontalX);
+ LIB_FUNCTION("R1T4i+DOhNY", "libSceFont", 1, "libSceFont", sceFontGlyphRefersOutline);
+ LIB_FUNCTION("RmkXfBcZnrM", "libSceFont", 1, "libSceFont", sceFontGlyphRenderImage);
+ LIB_FUNCTION("r4KEihtwxGs", "libSceFont", 1, "libSceFont", sceFontGlyphRenderImageHorizontal);
+ LIB_FUNCTION("n22d-HIdmMg", "libSceFont", 1, "libSceFont", sceFontGlyphRenderImageVertical);
+ LIB_FUNCTION("RL2cAQgyXR8", "libSceFont", 1, "libSceFont", sceFontGraphicsBeginFrame);
+ LIB_FUNCTION("dUmIK6QjT7E", "libSceFont", 1, "libSceFont", sceFontGraphicsDrawingCancel);
+ LIB_FUNCTION("X2Vl3yU19Zw", "libSceFont", 1, "libSceFont", sceFontGraphicsDrawingFinish);
+ LIB_FUNCTION("DOmdOwV3Aqw", "libSceFont", 1, "libSceFont", sceFontGraphicsEndFrame);
+ LIB_FUNCTION("zdYdKRQC3rw", "libSceFont", 1, "libSceFont", sceFontGraphicsExchangeResource);
+ LIB_FUNCTION("UkMUIoj-e9s", "libSceFont", 1, "libSceFont", sceFontGraphicsFillMethodInit);
+ LIB_FUNCTION("DJURdcnVUqo", "libSceFont", 1, "libSceFont", sceFontGraphicsFillPlotInit);
+ LIB_FUNCTION("eQac6ftmBQQ", "libSceFont", 1, "libSceFont", sceFontGraphicsFillPlotSetLayout);
+ LIB_FUNCTION("PEYQJa+MWnk", "libSceFont", 1, "libSceFont", sceFontGraphicsFillPlotSetMapping);
+ LIB_FUNCTION("21g4m4kYF6g", "libSceFont", 1, "libSceFont", sceFontGraphicsFillRatesInit);
+ LIB_FUNCTION("pJzji5FvdxU", "libSceFont", 1, "libSceFont",
+ sceFontGraphicsFillRatesSetFillEffect);
+ LIB_FUNCTION("scaro-xEuUM", "libSceFont", 1, "libSceFont", sceFontGraphicsFillRatesSetLayout);
+ LIB_FUNCTION("W66Kqtt0xU0", "libSceFont", 1, "libSceFont", sceFontGraphicsFillRatesSetMapping);
+ LIB_FUNCTION("FzpLsBQEegQ", "libSceFont", 1, "libSceFont", sceFontGraphicsGetDeviceUsage);
+ LIB_FUNCTION("W80hs0g5d+E", "libSceFont", 1, "libSceFont", sceFontGraphicsRegionInit);
+ LIB_FUNCTION("S48+njg9p-o", "libSceFont", 1, "libSceFont", sceFontGraphicsRegionInitCircular);
+ LIB_FUNCTION("wcOQ8Fz73+M", "libSceFont", 1, "libSceFont", sceFontGraphicsRegionInitRoundish);
+ LIB_FUNCTION("YBaw2Yyfd5E", "libSceFont", 1, "libSceFont", sceFontGraphicsRelease);
+ LIB_FUNCTION("qkySrQ4FGe0", "libSceFont", 1, "libSceFont", sceFontGraphicsRenderResource);
+ LIB_FUNCTION("qzNjJYKVli0", "libSceFont", 1, "libSceFont", sceFontGraphicsSetFramePolicy);
+ LIB_FUNCTION("9iRbHCtcx-o", "libSceFont", 1, "libSceFont", sceFontGraphicsSetupClipping);
+ LIB_FUNCTION("KZ3qPyz5Opc", "libSceFont", 1, "libSceFont", sceFontGraphicsSetupColorRates);
+ LIB_FUNCTION("LqclbpVzRvM", "libSceFont", 1, "libSceFont", sceFontGraphicsSetupFillMethod);
+ LIB_FUNCTION("Wl4FiI4qKY0", "libSceFont", 1, "libSceFont", sceFontGraphicsSetupFillRates);
+ LIB_FUNCTION("WC7s95TccVo", "libSceFont", 1, "libSceFont", sceFontGraphicsSetupGlyphFill);
+ LIB_FUNCTION("zC6I4ty37NA", "libSceFont", 1, "libSceFont", sceFontGraphicsSetupGlyphFillPlot);
+ LIB_FUNCTION("drZUF0XKTEI", "libSceFont", 1, "libSceFont", sceFontGraphicsSetupHandleDefault);
+ LIB_FUNCTION("MEAmHMynQXE", "libSceFont", 1, "libSceFont", sceFontGraphicsSetupLocation);
+ LIB_FUNCTION("XRUOmQhnYO4", "libSceFont", 1, "libSceFont", sceFontGraphicsSetupPositioning);
+ LIB_FUNCTION("98XGr2Bkklg", "libSceFont", 1, "libSceFont", sceFontGraphicsSetupRotation);
+ LIB_FUNCTION("Nj-ZUVOVAvc", "libSceFont", 1, "libSceFont", sceFontGraphicsSetupScaling);
+ LIB_FUNCTION("p0avT2ggev0", "libSceFont", 1, "libSceFont", sceFontGraphicsSetupShapeFill);
+ LIB_FUNCTION("0C5aKg9KghY", "libSceFont", 1, "libSceFont", sceFontGraphicsSetupShapeFillPlot);
+ LIB_FUNCTION("4pA3qqAcYco", "libSceFont", 1, "libSceFont", sceFontGraphicsStructureCanvas);
+ LIB_FUNCTION("cpjgdlMYdOM", "libSceFont", 1, "libSceFont",
+ sceFontGraphicsStructureCanvasSequence);
+ LIB_FUNCTION("774Mee21wKk", "libSceFont", 1, "libSceFont", sceFontGraphicsStructureDesign);
+ LIB_FUNCTION("Hp3NIFhUXvQ", "libSceFont", 1, "libSceFont",
+ sceFontGraphicsStructureDesignResource);
+ LIB_FUNCTION("bhmZlml6NBs", "libSceFont", 1, "libSceFont",
+ sceFontGraphicsStructureSurfaceTexture);
+ LIB_FUNCTION("5sAWgysOBfE", "libSceFont", 1, "libSceFont", sceFontGraphicsUpdateClipping);
+ LIB_FUNCTION("W4e8obm+w6o", "libSceFont", 1, "libSceFont", sceFontGraphicsUpdateColorRates);
+ LIB_FUNCTION("EgIn3QBajPs", "libSceFont", 1, "libSceFont", sceFontGraphicsUpdateFillMethod);
+ LIB_FUNCTION("MnUYAs2jVuU", "libSceFont", 1, "libSceFont", sceFontGraphicsUpdateFillRates);
+ LIB_FUNCTION("R-oVDMusYbc", "libSceFont", 1, "libSceFont", sceFontGraphicsUpdateGlyphFill);
+ LIB_FUNCTION("b9R+HQuHSMI", "libSceFont", 1, "libSceFont", sceFontGraphicsUpdateGlyphFillPlot);
+ LIB_FUNCTION("IN4P5pJADQY", "libSceFont", 1, "libSceFont", sceFontGraphicsUpdateLocation);
+ LIB_FUNCTION("U+LLXdr2DxM", "libSceFont", 1, "libSceFont", sceFontGraphicsUpdatePositioning);
+ LIB_FUNCTION("yStTYSeb4NM", "libSceFont", 1, "libSceFont", sceFontGraphicsUpdateRotation);
+ LIB_FUNCTION("eDxmMoxE5xU", "libSceFont", 1, "libSceFont", sceFontGraphicsUpdateScaling);
+ LIB_FUNCTION("Ax6LQJJq6HQ", "libSceFont", 1, "libSceFont", sceFontGraphicsUpdateShapeFill);
+ LIB_FUNCTION("I5Rf2rXvBKQ", "libSceFont", 1, "libSceFont", sceFontGraphicsUpdateShapeFillPlot);
+ LIB_FUNCTION("whrS4oksXc4", "libSceFont", 1, "libSceFont", sceFontMemoryInit);
+ LIB_FUNCTION("h6hIgxXEiEc", "libSceFont", 1, "libSceFont", sceFontMemoryTerm);
+ LIB_FUNCTION("RvXyHMUiLhE", "libSceFont", 1, "libSceFont", sceFontOpenFontFile);
+ LIB_FUNCTION("JzCH3SCFnAU", "libSceFont", 1, "libSceFont", sceFontOpenFontInstance);
+ LIB_FUNCTION("KXUpebrFk1U", "libSceFont", 1, "libSceFont", sceFontOpenFontMemory);
+ LIB_FUNCTION("cKYtVmeSTcw", "libSceFont", 1, "libSceFont", sceFontOpenFontSet);
+ LIB_FUNCTION("Z2cdsqJH+5k", "libSceFont", 1, "libSceFont", sceFontRebindRenderer);
+ LIB_FUNCTION("3G4zhgKuxE8", "libSceFont", 1, "libSceFont", sceFontRenderCharGlyphImage);
+ LIB_FUNCTION("kAenWy1Zw5o", "libSceFont", 1, "libSceFont",
+ sceFontRenderCharGlyphImageHorizontal);
+ LIB_FUNCTION("i6UNdSig1uE", "libSceFont", 1, "libSceFont", sceFontRenderCharGlyphImageVertical);
+ LIB_FUNCTION("amcmrY62BD4", "libSceFont", 1, "libSceFont", sceFontRendererGetOutlineBufferSize);
+ LIB_FUNCTION("ai6AfGrBs4o", "libSceFont", 1, "libSceFont", sceFontRendererResetOutlineBuffer);
+ LIB_FUNCTION("ydF+WuH0fAk", "libSceFont", 1, "libSceFont",
+ sceFontRendererSetOutlineBufferPolicy);
+ LIB_FUNCTION("gdUCnU0gHdI", "libSceFont", 1, "libSceFont", sceFontRenderSurfaceInit);
+ LIB_FUNCTION("vRxf4d0ulPs", "libSceFont", 1, "libSceFont", sceFontRenderSurfaceSetScissor);
+ LIB_FUNCTION("0hr-w30SjiI", "libSceFont", 1, "libSceFont", sceFontRenderSurfaceSetStyleFrame);
+ LIB_FUNCTION("TMtqoFQjjbA", "libSceFont", 1, "libSceFont", sceFontSetEffectSlant);
+ LIB_FUNCTION("v0phZwa4R5o", "libSceFont", 1, "libSceFont", sceFontSetEffectWeight);
+ LIB_FUNCTION("kihFGYJee7o", "libSceFont", 1, "libSceFont", sceFontSetFontsOpenMode);
+ LIB_FUNCTION("I1acwR7Qp8E", "libSceFont", 1, "libSceFont", sceFontSetResolutionDpi);
+ LIB_FUNCTION("N1EBMeGhf7E", "libSceFont", 1, "libSceFont", sceFontSetScalePixel);
+ LIB_FUNCTION("sw65+7wXCKE", "libSceFont", 1, "libSceFont", sceFontSetScalePoint);
+ LIB_FUNCTION("PxSR9UfJ+SQ", "libSceFont", 1, "libSceFont", sceFontSetScriptLanguage);
+ LIB_FUNCTION("SnsZua35ngs", "libSceFont", 1, "libSceFont", sceFontSetTypographicDesign);
+ LIB_FUNCTION("lz9y9UFO2UU", "libSceFont", 1, "libSceFont", sceFontSetupRenderEffectSlant);
+ LIB_FUNCTION("XIGorvLusDQ", "libSceFont", 1, "libSceFont", sceFontSetupRenderEffectWeight);
+ LIB_FUNCTION("6vGCkkQJOcI", "libSceFont", 1, "libSceFont", sceFontSetupRenderScalePixel);
+ LIB_FUNCTION("nMZid4oDfi4", "libSceFont", 1, "libSceFont", sceFontSetupRenderScalePoint);
+ LIB_FUNCTION("ObkDGDBsVtw", "libSceFont", 1, "libSceFont", sceFontStringGetTerminateCode);
+ LIB_FUNCTION("+B-xlbiWDJ4", "libSceFont", 1, "libSceFont", sceFontStringGetTerminateOrder);
+ LIB_FUNCTION("o1vIEHeb6tw", "libSceFont", 1, "libSceFont", sceFontStringGetWritingForm);
+ LIB_FUNCTION("hq5LffQjz-s", "libSceFont", 1, "libSceFont", sceFontStringRefersRenderCharacters);
+ LIB_FUNCTION("Avv7OApgCJk", "libSceFont", 1, "libSceFont", sceFontStringRefersTextCharacters);
+ LIB_FUNCTION("lOfduYnjgbo", "libSceFont", 1, "libSceFont", sceFontStyleFrameGetEffectSlant);
+ LIB_FUNCTION("HIUdjR-+Wl8", "libSceFont", 1, "libSceFont", sceFontStyleFrameGetEffectWeight);
+ LIB_FUNCTION("VSw18Aqzl0U", "libSceFont", 1, "libSceFont", sceFontStyleFrameGetResolutionDpi);
+ LIB_FUNCTION("2QfqfeLblbg", "libSceFont", 1, "libSceFont", sceFontStyleFrameGetScalePixel);
+ LIB_FUNCTION("7x2xKiiB7MA", "libSceFont", 1, "libSceFont", sceFontStyleFrameGetScalePoint);
+ LIB_FUNCTION("la2AOWnHEAc", "libSceFont", 1, "libSceFont", sceFontStyleFrameInit);
+ LIB_FUNCTION("394sckksiCU", "libSceFont", 1, "libSceFont", sceFontStyleFrameSetEffectSlant);
+ LIB_FUNCTION("faw77-pEBmU", "libSceFont", 1, "libSceFont", sceFontStyleFrameSetEffectWeight);
+ LIB_FUNCTION("dB4-3Wdwls8", "libSceFont", 1, "libSceFont", sceFontStyleFrameSetResolutionDpi);
+ LIB_FUNCTION("da4rQ4-+p-4", "libSceFont", 1, "libSceFont", sceFontStyleFrameSetScalePixel);
+ LIB_FUNCTION("O997laxY-Ys", "libSceFont", 1, "libSceFont", sceFontStyleFrameSetScalePoint);
+ LIB_FUNCTION("dUmABkAnVgk", "libSceFont", 1, "libSceFont", sceFontStyleFrameUnsetEffectSlant);
+ LIB_FUNCTION("hwsuXgmKdaw", "libSceFont", 1, "libSceFont", sceFontStyleFrameUnsetEffectWeight);
+ LIB_FUNCTION("bePC0L0vQWY", "libSceFont", 1, "libSceFont", sceFontStyleFrameUnsetScale);
+ LIB_FUNCTION("mz2iTY0MK4A", "libSceFont", 1, "libSceFont", sceFontSupportExternalFonts);
+ LIB_FUNCTION("71w5DzObuZI", "libSceFont", 1, "libSceFont", sceFontSupportGlyphs);
+ LIB_FUNCTION("SsRbbCiWoGw", "libSceFont", 1, "libSceFont", sceFontSupportSystemFonts);
+ LIB_FUNCTION("IPoYwwlMx-g", "libSceFont", 1, "libSceFont", sceFontTextCodesStepBack);
+ LIB_FUNCTION("olSmXY+XP1E", "libSceFont", 1, "libSceFont", sceFontTextCodesStepNext);
+ LIB_FUNCTION("oaJ1BpN2FQk", "libSceFont", 1, "libSceFont", sceFontTextSourceInit);
+ LIB_FUNCTION("VRFd3diReec", "libSceFont", 1, "libSceFont", sceFontTextSourceRewind);
+ LIB_FUNCTION("eCRMCSk96NU", "libSceFont", 1, "libSceFont", sceFontTextSourceSetDefaultFont);
+ LIB_FUNCTION("OqQKX0h5COw", "libSceFont", 1, "libSceFont", sceFontTextSourceSetWritingForm);
+ LIB_FUNCTION("1QjhKxrsOB8", "libSceFont", 1, "libSceFont", sceFontUnbindRenderer);
+ LIB_FUNCTION("H-FNq8isKE0", "libSceFont", 1, "libSceFont", sceFontWordsFindWordCharacters);
+ LIB_FUNCTION("fljdejMcG1c", "libSceFont", 1, "libSceFont", sceFontWritingGetRenderMetrics);
+ LIB_FUNCTION("fD5rqhEXKYQ", "libSceFont", 1, "libSceFont", sceFontWritingInit);
+ LIB_FUNCTION("1+DgKL0haWQ", "libSceFont", 1, "libSceFont", sceFontWritingLineClear);
+ LIB_FUNCTION("JQKWIsS9joE", "libSceFont", 1, "libSceFont", sceFontWritingLineGetOrderingSpace);
+ LIB_FUNCTION("nlU2VnfpqTM", "libSceFont", 1, "libSceFont", sceFontWritingLineGetRenderMetrics);
+ LIB_FUNCTION("+FYcYefsVX0", "libSceFont", 1, "libSceFont", sceFontWritingLineRefersRenderStep);
+ LIB_FUNCTION("wyKFUOWdu3Q", "libSceFont", 1, "libSceFont", sceFontWritingLineWritesOrder);
+ LIB_FUNCTION("W-2WOXEHGck", "libSceFont", 1, "libSceFont", sceFontWritingRefersRenderStep);
+ LIB_FUNCTION("f4Onl7efPEY", "libSceFont", 1, "libSceFont",
+ sceFontWritingRefersRenderStepCharacter);
+ LIB_FUNCTION("BbCZjJizU4A", "libSceFont", 1, "libSceFont", sceFontWritingSetMaskInvisible);
+ LIB_FUNCTION("APTXePHIjLM", "libSceFont", 1, "libSceFont", Func_00F4D778F1C88CB3);
+ LIB_FUNCTION("A8ZQAl+7Dec", "libSceFont", 1, "libSceFont", Func_03C650025FBB0DE7);
+ LIB_FUNCTION("B+q4oWOyfho", "libSceFont", 1, "libSceFont", Func_07EAB8A163B27E1A);
+ LIB_FUNCTION("CUCOiOT5fOM", "libSceFont", 1, "libSceFont", Func_09408E88E4F97CE3);
+ LIB_FUNCTION("CfkpBe2CqBQ", "libSceFont", 1, "libSceFont", Func_09F92905ED82A814);
+ LIB_FUNCTION("DRQs7hqyGr4", "libSceFont", 1, "libSceFont", Func_0D142CEE1AB21ABE);
+ LIB_FUNCTION("FL0unhGcFvI", "libSceFont", 1, "libSceFont", Func_14BD2E9E119C16F2);
+ LIB_FUNCTION("GsU8nt6ujXU", "libSceFont", 1, "libSceFont", Func_1AC53C9EDEAE8D75);
+ LIB_FUNCTION("HUARhdXiTD0", "libSceFont", 1, "libSceFont", Func_1D401185D5E24C3D);
+ LIB_FUNCTION("HoPNIMLMmW8", "libSceFont", 1, "libSceFont", Func_1E83CD20C2CC996F);
+ LIB_FUNCTION("MUsfdluf54o", "libSceFont", 1, "libSceFont", Func_314B1F765B9FE78A);
+ LIB_FUNCTION("NQ5nJf7eKeE", "libSceFont", 1, "libSceFont", Func_350E6725FEDE29E1);
+ LIB_FUNCTION("Pbdz8KYEvzk", "libSceFont", 1, "libSceFont", Func_3DB773F0A604BF39);
+ LIB_FUNCTION("T-Sd0h4xGxw", "libSceFont", 1, "libSceFont", Func_4FF49DD21E311B1C);
+ LIB_FUNCTION("UmKHZkpJOYE", "libSceFont", 1, "libSceFont", Func_526287664A493981);
+ LIB_FUNCTION("VcpxjbyEpuk", "libSceFont", 1, "libSceFont", Func_55CA718DBC84A6E9);
+ LIB_FUNCTION("Vj-F8HBqi00", "libSceFont", 1, "libSceFont", Func_563FC5F0706A8B4D);
+ LIB_FUNCTION("Vp4uzTQpD0U", "libSceFont", 1, "libSceFont", Func_569E2ECD34290F45);
+ LIB_FUNCTION("WgR3W2vkdoU", "libSceFont", 1, "libSceFont", Func_5A04775B6BE47685);
+ LIB_FUNCTION("X9k7yrb3l1A", "libSceFont", 1, "libSceFont", Func_5FD93BCAB6F79750);
+ LIB_FUNCTION("YrU5j4ZL07Q", "libSceFont", 1, "libSceFont", Func_62B5398F864BD3B4);
+ LIB_FUNCTION("b5AQKU2CI2c", "libSceFont", 1, "libSceFont", Func_6F9010294D822367);
+ LIB_FUNCTION("d1fpR0I6emc", "libSceFont", 1, "libSceFont", Func_7757E947423A7A67);
+ LIB_FUNCTION("fga6Ugd-VPo", "libSceFont", 1, "libSceFont", Func_7E06BA52077F54FA);
+ LIB_FUNCTION("k7Nt6gITEdY", "libSceFont", 1, "libSceFont", Func_93B36DEA021311D6);
+ LIB_FUNCTION("lLCJHnERWYo", "libSceFont", 1, "libSceFont", Func_94B0891E7111598A);
+ LIB_FUNCTION("l4XJEowv580", "libSceFont", 1, "libSceFont", Func_9785C9128C2FE7CD);
+ LIB_FUNCTION("l9+8m2X7wOE", "libSceFont", 1, "libSceFont", Func_97DFBC9B65FBC0E1);
+ LIB_FUNCTION("rNlxdAXX08o", "libSceFont", 1, "libSceFont", Func_ACD9717405D7D3CA);
+ LIB_FUNCTION("sZqK7D-U8W8", "libSceFont", 1, "libSceFont", Func_B19A8AEC3FD4F16F);
+ LIB_FUNCTION("wQ9IitfPED0", "libSceFont", 1, "libSceFont", Func_C10F488AD7CF103D);
+ LIB_FUNCTION("0Mi1-0poJsc", "libSceFont", 1, "libSceFont", Func_D0C8B5FF4A6826C7);
+ LIB_FUNCTION("5I080Bw0KjM", "libSceFont", 1, "libSceFont", Func_E48D3CD01C342A33);
+ LIB_FUNCTION("6slrIYa3HhQ", "libSceFont", 1, "libSceFont", Func_EAC96B2186B71E14);
+ LIB_FUNCTION("-keIqW70YlY", "libSceFont", 1, "libSceFont", Func_FE4788A96EF46256);
+ LIB_FUNCTION("-n5a6V0wWPU", "libSceFont", 1, "libSceFont", Func_FE7E5AE95D3058F5);
+};
+
+} // namespace Libraries::Font
\ No newline at end of file
diff --git a/src/core/libraries/font/font.h b/src/core/libraries/font/font.h
new file mode 100644
index 000000000..a8e239126
--- /dev/null
+++ b/src/core/libraries/font/font.h
@@ -0,0 +1,299 @@
+// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/types.h"
+
+namespace Core::Loader {
+class SymbolsResolver;
+}
+
+namespace Libraries::Font {
+
+struct OrbisFontTextCharacter {
+ // Other fields...
+ struct OrbisFontTextCharacter* next; // Pointer to the next node 0x00
+ struct OrbisFontTextCharacter* prev; // Pointer to the next node 0x08
+ void* textOrder; // Field at offset 0x10 (pointer to text order info)
+ u32 characterCode; // Field assumed at offset 0x28
+ u8 unkn_0x31; // Offset 0x31
+ u8 unkn_0x33; // Offset 0x33
+ u8 charType; // Field assumed at offset 0x39
+ u8 bidiLevel; // Field assumed at offset 0x3B stores the Bidi level
+ u8 formatFlags; // Field at offset 0x3D (stores format-related flags)
+};
+
+struct OrbisFontRenderSurface {
+ void* buffer;
+ s32 widthByte;
+ s8 pixelSizeByte;
+ u8 unkn_0xd;
+ u8 styleFlag;
+ u8 unkn_0xf;
+ s32 width, height;
+ u32 sc_x0;
+ u32 sc_y0;
+ u32 sc_x1;
+ u32 sc_y1;
+ void* unkn_28[3];
+};
+
+struct OrbisFontStyleFrame {
+ /*0x00*/ u16 magic; // Expected to be 0xF09
+ /*0x02*/ u16 flags;
+ /*0x04*/ s32 dpiX; // DPI scaling factor for width
+ /*0x08*/ s32 dpiY; // DPI scaling factor for height
+ /*0x0c*/ s32 scalingFlag; // Indicates whether scaling is enabled
+ /*0x10*/
+ /*0x14*/ float scaleWidth; // Width scaling factor
+ /*0x18*/ float scaleHeight; // Height scaling factor
+ /*0x1c*/ float weightXScale;
+ /*0x20*/ float weightYScale;
+ /*0x24*/ float slantRatio;
+};
+
+s32 PS4_SYSV_ABI sceFontAttachDeviceCacheBuffer();
+s32 PS4_SYSV_ABI sceFontBindRenderer();
+s32 PS4_SYSV_ABI sceFontCharacterGetBidiLevel(OrbisFontTextCharacter* textCharacter,
+ int* bidiLevel);
+s32 PS4_SYSV_ABI sceFontCharacterGetSyllableStringState();
+s32 PS4_SYSV_ABI sceFontCharacterGetTextFontCode();
+s32 PS4_SYSV_ABI sceFontCharacterGetTextOrder(OrbisFontTextCharacter* textCharacter,
+ void** pTextOrder);
+u32 PS4_SYSV_ABI sceFontCharacterLooksFormatCharacters(OrbisFontTextCharacter* textCharacter);
+u32 PS4_SYSV_ABI sceFontCharacterLooksWhiteSpace(OrbisFontTextCharacter* textCharacter);
+OrbisFontTextCharacter* PS4_SYSV_ABI
+sceFontCharacterRefersTextBack(OrbisFontTextCharacter* textCharacter);
+OrbisFontTextCharacter* PS4_SYSV_ABI
+sceFontCharacterRefersTextNext(OrbisFontTextCharacter* textCharacter);
+s32 PS4_SYSV_ABI sceFontCharactersRefersTextCodes();
+s32 PS4_SYSV_ABI sceFontClearDeviceCache();
+s32 PS4_SYSV_ABI sceFontCloseFont();
+s32 PS4_SYSV_ABI sceFontControl();
+s32 PS4_SYSV_ABI sceFontCreateGraphicsDevice();
+s32 PS4_SYSV_ABI sceFontCreateGraphicsService();
+s32 PS4_SYSV_ABI sceFontCreateGraphicsServiceWithEdition();
+s32 PS4_SYSV_ABI sceFontCreateLibrary();
+s32 PS4_SYSV_ABI sceFontCreateLibraryWithEdition();
+s32 PS4_SYSV_ABI sceFontCreateRenderer();
+s32 PS4_SYSV_ABI sceFontCreateRendererWithEdition();
+s32 PS4_SYSV_ABI sceFontCreateString();
+s32 PS4_SYSV_ABI sceFontCreateWords();
+s32 PS4_SYSV_ABI sceFontCreateWritingLine();
+s32 PS4_SYSV_ABI sceFontDefineAttribute();
+s32 PS4_SYSV_ABI sceFontDeleteGlyph();
+s32 PS4_SYSV_ABI sceFontDestroyGraphicsDevice();
+s32 PS4_SYSV_ABI sceFontDestroyGraphicsService();
+s32 PS4_SYSV_ABI sceFontDestroyLibrary();
+s32 PS4_SYSV_ABI sceFontDestroyRenderer();
+s32 PS4_SYSV_ABI sceFontDestroyString();
+s32 PS4_SYSV_ABI sceFontDestroyWords();
+s32 PS4_SYSV_ABI sceFontDestroyWritingLine();
+s32 PS4_SYSV_ABI sceFontDettachDeviceCacheBuffer();
+s32 PS4_SYSV_ABI sceFontGenerateCharGlyph();
+s32 PS4_SYSV_ABI sceFontGetAttribute();
+s32 PS4_SYSV_ABI sceFontGetCharGlyphCode();
+s32 PS4_SYSV_ABI sceFontGetCharGlyphMetrics();
+s32 PS4_SYSV_ABI sceFontGetEffectSlant();
+s32 PS4_SYSV_ABI sceFontGetEffectWeight();
+s32 PS4_SYSV_ABI sceFontGetFontGlyphsCount();
+s32 PS4_SYSV_ABI sceFontGetFontGlyphsOutlineProfile();
+s32 PS4_SYSV_ABI sceFontGetFontMetrics();
+s32 PS4_SYSV_ABI sceFontGetFontResolution();
+s32 PS4_SYSV_ABI sceFontGetFontStyleInformation();
+s32 PS4_SYSV_ABI sceFontGetGlyphExpandBufferState();
+s32 PS4_SYSV_ABI sceFontGetHorizontalLayout();
+s32 PS4_SYSV_ABI sceFontGetKerning();
+s32 PS4_SYSV_ABI sceFontGetLibrary();
+s32 PS4_SYSV_ABI sceFontGetPixelResolution();
+s32 PS4_SYSV_ABI sceFontGetRenderCharGlyphMetrics();
+s32 PS4_SYSV_ABI sceFontGetRenderEffectSlant();
+s32 PS4_SYSV_ABI sceFontGetRenderEffectWeight();
+s32 PS4_SYSV_ABI sceFontGetRenderScaledKerning();
+s32 PS4_SYSV_ABI sceFontGetRenderScalePixel();
+s32 PS4_SYSV_ABI sceFontGetRenderScalePoint();
+s32 PS4_SYSV_ABI sceFontGetResolutionDpi();
+s32 PS4_SYSV_ABI sceFontGetScalePixel();
+s32 PS4_SYSV_ABI sceFontGetScalePoint();
+s32 PS4_SYSV_ABI sceFontGetScriptLanguage();
+s32 PS4_SYSV_ABI sceFontGetTypographicDesign();
+s32 PS4_SYSV_ABI sceFontGetVerticalLayout();
+s32 PS4_SYSV_ABI sceFontGlyphDefineAttribute();
+s32 PS4_SYSV_ABI sceFontGlyphGetAttribute();
+s32 PS4_SYSV_ABI sceFontGlyphGetGlyphForm();
+s32 PS4_SYSV_ABI sceFontGlyphGetMetricsForm();
+s32 PS4_SYSV_ABI sceFontGlyphGetScalePixel();
+s32 PS4_SYSV_ABI sceFontGlyphRefersMetrics();
+s32 PS4_SYSV_ABI sceFontGlyphRefersMetricsHorizontal();
+s32 PS4_SYSV_ABI sceFontGlyphRefersMetricsHorizontalAdvance();
+s32 PS4_SYSV_ABI sceFontGlyphRefersMetricsHorizontalX();
+s32 PS4_SYSV_ABI sceFontGlyphRefersOutline();
+s32 PS4_SYSV_ABI sceFontGlyphRenderImage();
+s32 PS4_SYSV_ABI sceFontGlyphRenderImageHorizontal();
+s32 PS4_SYSV_ABI sceFontGlyphRenderImageVertical();
+s32 PS4_SYSV_ABI sceFontGraphicsBeginFrame();
+s32 PS4_SYSV_ABI sceFontGraphicsDrawingCancel();
+s32 PS4_SYSV_ABI sceFontGraphicsDrawingFinish();
+s32 PS4_SYSV_ABI sceFontGraphicsEndFrame();
+s32 PS4_SYSV_ABI sceFontGraphicsExchangeResource();
+s32 PS4_SYSV_ABI sceFontGraphicsFillMethodInit();
+s32 PS4_SYSV_ABI sceFontGraphicsFillPlotInit();
+s32 PS4_SYSV_ABI sceFontGraphicsFillPlotSetLayout();
+s32 PS4_SYSV_ABI sceFontGraphicsFillPlotSetMapping();
+s32 PS4_SYSV_ABI sceFontGraphicsFillRatesInit();
+s32 PS4_SYSV_ABI sceFontGraphicsFillRatesSetFillEffect();
+s32 PS4_SYSV_ABI sceFontGraphicsFillRatesSetLayout();
+s32 PS4_SYSV_ABI sceFontGraphicsFillRatesSetMapping();
+s32 PS4_SYSV_ABI sceFontGraphicsGetDeviceUsage();
+s32 PS4_SYSV_ABI sceFontGraphicsRegionInit();
+s32 PS4_SYSV_ABI sceFontGraphicsRegionInitCircular();
+s32 PS4_SYSV_ABI sceFontGraphicsRegionInitRoundish();
+s32 PS4_SYSV_ABI sceFontGraphicsRelease();
+s32 PS4_SYSV_ABI sceFontGraphicsRenderResource();
+s32 PS4_SYSV_ABI sceFontGraphicsSetFramePolicy();
+s32 PS4_SYSV_ABI sceFontGraphicsSetupClipping();
+s32 PS4_SYSV_ABI sceFontGraphicsSetupColorRates();
+s32 PS4_SYSV_ABI sceFontGraphicsSetupFillMethod();
+s32 PS4_SYSV_ABI sceFontGraphicsSetupFillRates();
+s32 PS4_SYSV_ABI sceFontGraphicsSetupGlyphFill();
+s32 PS4_SYSV_ABI sceFontGraphicsSetupGlyphFillPlot();
+s32 PS4_SYSV_ABI sceFontGraphicsSetupHandleDefault();
+s32 PS4_SYSV_ABI sceFontGraphicsSetupLocation();
+s32 PS4_SYSV_ABI sceFontGraphicsSetupPositioning();
+s32 PS4_SYSV_ABI sceFontGraphicsSetupRotation();
+s32 PS4_SYSV_ABI sceFontGraphicsSetupScaling();
+s32 PS4_SYSV_ABI sceFontGraphicsSetupShapeFill();
+s32 PS4_SYSV_ABI sceFontGraphicsSetupShapeFillPlot();
+s32 PS4_SYSV_ABI sceFontGraphicsStructureCanvas();
+s32 PS4_SYSV_ABI sceFontGraphicsStructureCanvasSequence();
+s32 PS4_SYSV_ABI sceFontGraphicsStructureDesign();
+s32 PS4_SYSV_ABI sceFontGraphicsStructureDesignResource();
+s32 PS4_SYSV_ABI sceFontGraphicsStructureSurfaceTexture();
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateClipping();
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateColorRates();
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateFillMethod();
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateFillRates();
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateGlyphFill();
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateGlyphFillPlot();
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateLocation();
+s32 PS4_SYSV_ABI sceFontGraphicsUpdatePositioning();
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateRotation();
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateScaling();
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateShapeFill();
+s32 PS4_SYSV_ABI sceFontGraphicsUpdateShapeFillPlot();
+s32 PS4_SYSV_ABI sceFontMemoryInit();
+s32 PS4_SYSV_ABI sceFontMemoryTerm();
+s32 PS4_SYSV_ABI sceFontOpenFontFile();
+s32 PS4_SYSV_ABI sceFontOpenFontInstance();
+s32 PS4_SYSV_ABI sceFontOpenFontMemory();
+s32 PS4_SYSV_ABI sceFontOpenFontSet();
+s32 PS4_SYSV_ABI sceFontRebindRenderer();
+s32 PS4_SYSV_ABI sceFontRenderCharGlyphImage();
+s32 PS4_SYSV_ABI sceFontRenderCharGlyphImageHorizontal();
+s32 PS4_SYSV_ABI sceFontRenderCharGlyphImageVertical();
+s32 PS4_SYSV_ABI sceFontRendererGetOutlineBufferSize();
+s32 PS4_SYSV_ABI sceFontRendererResetOutlineBuffer();
+s32 PS4_SYSV_ABI sceFontRendererSetOutlineBufferPolicy();
+void PS4_SYSV_ABI sceFontRenderSurfaceInit(OrbisFontRenderSurface* renderSurface, void* buffer,
+ int bufWidthByte, int pixelSizeByte, int widthPixel,
+ int heightPixel);
+void PS4_SYSV_ABI sceFontRenderSurfaceSetScissor(OrbisFontRenderSurface* renderSurface, int x0,
+ int y0, int w, int h);
+s32 PS4_SYSV_ABI sceFontRenderSurfaceSetStyleFrame(OrbisFontRenderSurface* renderSurface,
+ OrbisFontStyleFrame* styleFrame);
+s32 PS4_SYSV_ABI sceFontSetEffectSlant();
+s32 PS4_SYSV_ABI sceFontSetEffectWeight();
+s32 PS4_SYSV_ABI sceFontSetFontsOpenMode();
+s32 PS4_SYSV_ABI sceFontSetResolutionDpi();
+s32 PS4_SYSV_ABI sceFontSetScalePixel();
+s32 PS4_SYSV_ABI sceFontSetScalePoint();
+s32 PS4_SYSV_ABI sceFontSetScriptLanguage();
+s32 PS4_SYSV_ABI sceFontSetTypographicDesign();
+s32 PS4_SYSV_ABI sceFontSetupRenderEffectSlant();
+s32 PS4_SYSV_ABI sceFontSetupRenderEffectWeight();
+s32 PS4_SYSV_ABI sceFontSetupRenderScalePixel();
+s32 PS4_SYSV_ABI sceFontSetupRenderScalePoint();
+s32 PS4_SYSV_ABI sceFontStringGetTerminateCode();
+s32 PS4_SYSV_ABI sceFontStringGetTerminateOrder();
+s32 PS4_SYSV_ABI sceFontStringGetWritingForm();
+s32 PS4_SYSV_ABI sceFontStringRefersRenderCharacters();
+s32 PS4_SYSV_ABI sceFontStringRefersTextCharacters();
+s32 PS4_SYSV_ABI sceFontStyleFrameGetEffectSlant(OrbisFontStyleFrame* styleFrame,
+ float* slantRatio);
+s32 PS4_SYSV_ABI sceFontStyleFrameGetEffectWeight(OrbisFontStyleFrame* fontStyleFrame,
+ float* weightXScale, float* weightYScale,
+ uint32_t* mode);
+s32 PS4_SYSV_ABI sceFontStyleFrameGetResolutionDpi();
+s32 PS4_SYSV_ABI sceFontStyleFrameGetScalePixel(OrbisFontStyleFrame* styleFrame, float* w,
+ float* h);
+s32 PS4_SYSV_ABI sceFontStyleFrameGetScalePoint();
+s32 PS4_SYSV_ABI sceFontStyleFrameInit();
+s32 PS4_SYSV_ABI sceFontStyleFrameSetEffectSlant();
+s32 PS4_SYSV_ABI sceFontStyleFrameSetEffectWeight();
+s32 PS4_SYSV_ABI sceFontStyleFrameSetResolutionDpi();
+s32 PS4_SYSV_ABI sceFontStyleFrameSetScalePixel();
+s32 PS4_SYSV_ABI sceFontStyleFrameSetScalePoint();
+s32 PS4_SYSV_ABI sceFontStyleFrameUnsetEffectSlant();
+s32 PS4_SYSV_ABI sceFontStyleFrameUnsetEffectWeight();
+s32 PS4_SYSV_ABI sceFontStyleFrameUnsetScale();
+s32 PS4_SYSV_ABI sceFontSupportExternalFonts();
+s32 PS4_SYSV_ABI sceFontSupportGlyphs();
+s32 PS4_SYSV_ABI sceFontSupportSystemFonts();
+s32 PS4_SYSV_ABI sceFontTextCodesStepBack();
+s32 PS4_SYSV_ABI sceFontTextCodesStepNext();
+s32 PS4_SYSV_ABI sceFontTextSourceInit();
+s32 PS4_SYSV_ABI sceFontTextSourceRewind();
+s32 PS4_SYSV_ABI sceFontTextSourceSetDefaultFont();
+s32 PS4_SYSV_ABI sceFontTextSourceSetWritingForm();
+s32 PS4_SYSV_ABI sceFontUnbindRenderer();
+s32 PS4_SYSV_ABI sceFontWordsFindWordCharacters();
+s32 PS4_SYSV_ABI sceFontWritingGetRenderMetrics();
+s32 PS4_SYSV_ABI sceFontWritingInit();
+s32 PS4_SYSV_ABI sceFontWritingLineClear();
+s32 PS4_SYSV_ABI sceFontWritingLineGetOrderingSpace();
+s32 PS4_SYSV_ABI sceFontWritingLineGetRenderMetrics();
+s32 PS4_SYSV_ABI sceFontWritingLineRefersRenderStep();
+s32 PS4_SYSV_ABI sceFontWritingLineWritesOrder();
+s32 PS4_SYSV_ABI sceFontWritingRefersRenderStep();
+s32 PS4_SYSV_ABI sceFontWritingRefersRenderStepCharacter();
+s32 PS4_SYSV_ABI sceFontWritingSetMaskInvisible();
+s32 PS4_SYSV_ABI Func_00F4D778F1C88CB3();
+s32 PS4_SYSV_ABI Func_03C650025FBB0DE7();
+s32 PS4_SYSV_ABI Func_07EAB8A163B27E1A();
+s32 PS4_SYSV_ABI Func_09408E88E4F97CE3();
+s32 PS4_SYSV_ABI Func_09F92905ED82A814();
+s32 PS4_SYSV_ABI Func_0D142CEE1AB21ABE();
+s32 PS4_SYSV_ABI Func_14BD2E9E119C16F2();
+s32 PS4_SYSV_ABI Func_1AC53C9EDEAE8D75();
+s32 PS4_SYSV_ABI Func_1D401185D5E24C3D();
+s32 PS4_SYSV_ABI Func_1E83CD20C2CC996F();
+s32 PS4_SYSV_ABI Func_314B1F765B9FE78A();
+s32 PS4_SYSV_ABI Func_350E6725FEDE29E1();
+s32 PS4_SYSV_ABI Func_3DB773F0A604BF39();
+s32 PS4_SYSV_ABI Func_4FF49DD21E311B1C();
+s32 PS4_SYSV_ABI Func_526287664A493981();
+s32 PS4_SYSV_ABI Func_55CA718DBC84A6E9();
+s32 PS4_SYSV_ABI Func_563FC5F0706A8B4D();
+s32 PS4_SYSV_ABI Func_569E2ECD34290F45();
+s32 PS4_SYSV_ABI Func_5A04775B6BE47685();
+s32 PS4_SYSV_ABI Func_5FD93BCAB6F79750();
+s32 PS4_SYSV_ABI Func_62B5398F864BD3B4();
+s32 PS4_SYSV_ABI Func_6F9010294D822367();
+s32 PS4_SYSV_ABI Func_7757E947423A7A67();
+s32 PS4_SYSV_ABI Func_7E06BA52077F54FA();
+s32 PS4_SYSV_ABI Func_93B36DEA021311D6();
+s32 PS4_SYSV_ABI Func_94B0891E7111598A();
+s32 PS4_SYSV_ABI Func_9785C9128C2FE7CD();
+s32 PS4_SYSV_ABI Func_97DFBC9B65FBC0E1();
+s32 PS4_SYSV_ABI Func_ACD9717405D7D3CA();
+s32 PS4_SYSV_ABI Func_B19A8AEC3FD4F16F();
+s32 PS4_SYSV_ABI Func_C10F488AD7CF103D();
+s32 PS4_SYSV_ABI Func_D0C8B5FF4A6826C7();
+s32 PS4_SYSV_ABI Func_E48D3CD01C342A33();
+s32 PS4_SYSV_ABI Func_EAC96B2186B71E14();
+s32 PS4_SYSV_ABI Func_FE4788A96EF46256();
+s32 PS4_SYSV_ABI Func_FE7E5AE95D3058F5();
+
+void RegisterlibSceFont(Core::Loader::SymbolsResolver* sym);
+} // namespace Libraries::Font
\ No newline at end of file
diff --git a/src/core/libraries/font/font_error.h b/src/core/libraries/font/font_error.h
new file mode 100644
index 000000000..64e8fc6a7
--- /dev/null
+++ b/src/core/libraries/font/font_error.h
@@ -0,0 +1,44 @@
+// 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_FONT_ERROR_FATAL = 0x80460001;
+constexpr int ORBIS_FONT_ERROR_INVALID_PARAMETER = 0x80460002;
+constexpr int ORBIS_FONT_ERROR_INVALID_MEMORY = 0x80460003;
+constexpr int ORBIS_FONT_ERROR_INVALID_LIBRARY = 0x80460004;
+constexpr int ORBIS_FONT_ERROR_INVALID_FONT_HANDLE = 0x80460005;
+constexpr int ORBIS_FONT_ERROR_INVALID_GLYPH = 0x80460006;
+constexpr int ORBIS_FONT_ERROR_INVALID_RENDERER = 0x80460007;
+constexpr int ORBIS_FONT_ERROR_INVALID_TEXT_SOURCE = 0x80460008;
+constexpr int ORBIS_FONT_ERROR_INVALID_STRING = 0x80460009;
+constexpr int ORBIS_FONT_ERROR_INVALID_WRITING = 0x8046000A;
+constexpr int ORBIS_FONT_ERROR_INVALID_WORDS = 0x8046000B;
+constexpr int ORBIS_FONT_ERROR_ALLOCATION_FAILED = 0x80460010;
+constexpr int ORBIS_FONT_ERROR_FS_OPEN_FAILED = 0x80460011;
+constexpr int ORBIS_FONT_ERROR_NO_SUPPORT_LIBRARY = 0x80460018;
+constexpr int ORBIS_FONT_ERROR_NO_SUPPORT_FORMAT = 0x80460019;
+constexpr int ORBIS_FONT_ERROR_NO_SUPPORT_FUNCTION = 0x80460020;
+constexpr int ORBIS_FONT_ERROR_ALREADY_SPECIFIED = 0x80460021;
+constexpr int ORBIS_FONT_ERROR_ALREADY_ATTACHED = 0x80460022;
+constexpr int ORBIS_FONT_ERROR_ALREADY_OPENED = 0x80460023;
+constexpr int ORBIS_FONT_ERROR_NOT_ATTACHED_CACHE_BUFFER = 0x80460025;
+constexpr int ORBIS_FONT_ERROR_NO_SUPPORT_FONTSET = 0x80460031;
+constexpr int ORBIS_FONT_ERROR_FONT_OPEN_MAX = 0x80460033;
+constexpr int ORBIS_FONT_ERROR_FONT_OPEN_FAILED = 0x80460036;
+constexpr int ORBIS_FONT_ERROR_FONT_CLOSE_FAILED = 0x80460037;
+constexpr int ORBIS_FONT_ERROR_NO_SUPPORT_TYPOGRAPHY = 0x80460040;
+constexpr int ORBIS_FONT_ERROR_NO_SUPPORT_CODE = 0x80460041;
+constexpr int ORBIS_FONT_ERROR_NO_SUPPORT_GLYPH = 0x80460042;
+constexpr int ORBIS_FONT_ERROR_NO_SUPPORT_SCRIPT = 0x80460043;
+constexpr int ORBIS_FONT_ERROR_NO_SUPPORT_LANGUAGE = 0x80460044;
+constexpr int ORBIS_FONT_ERROR_NO_SUPPORT_SURFACE = 0x80460050;
+constexpr int ORBIS_FONT_ERROR_UNSET_PARAMETER = 0x80460058;
+constexpr int ORBIS_FONT_ERROR_FUNCTIONAL_LIMIT = 0x8046005C;
+constexpr int ORBIS_FONT_ERROR_ALREADY_BOUND_RENDERER = 0x80460060;
+constexpr int ORBIS_FONT_ERROR_NOT_BOUND_RENDERER = 0x80460061;
+constexpr int ORBIS_FONT_ERROR_RENDERER_ALLOCATION_FAILED = 0x80460063;
+constexpr int ORBIS_FONT_ERROR_RENDERER_ALLOCATION_LIMITED = 0x80460064;
+constexpr int ORBIS_FONT_ERROR_RENDERER_RENDER_FAILED = 0x80460065;
diff --git a/src/core/libraries/font/fontft.cpp b/src/core/libraries/font/fontft.cpp
new file mode 100644
index 000000000..4a1dbb989
--- /dev/null
+++ b/src/core/libraries/font/fontft.cpp
@@ -0,0 +1,140 @@
+// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/logging/log.h"
+#include "core/libraries/error_codes.h"
+#include "core/libraries/font/fontft.h"
+#include "core/libraries/libs.h"
+
+namespace Libraries::FontFt {
+
+s32 PS4_SYSV_ABI sceFontFtInitAliases() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSetAliasFont() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSetAliasPath() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSupportBdf() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSupportCid() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSupportFontFormats() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSupportOpenType() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSupportOpenTypeOtf() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSupportOpenTypeTtf() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSupportPcf() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSupportPfr() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSupportSystemFonts() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSupportTrueType() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSupportTrueTypeGx() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSupportType1() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSupportType42() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtSupportWinFonts() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontFtTermAliases() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSelectGlyphsFt() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSelectLibraryFt() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+s32 PS4_SYSV_ABI sceFontSelectRendererFt() {
+ LOG_ERROR(Lib_FontFt, "(STUBBED) called");
+ return ORBIS_OK;
+}
+
+void RegisterlibSceFontFt(Core::Loader::SymbolsResolver* sym) {
+ LIB_FUNCTION("e60aorDdpB8", "libSceFontFt", 1, "libSceFontFt", sceFontFtInitAliases);
+ LIB_FUNCTION("BxcmiMc3UaA", "libSceFontFt", 1, "libSceFontFt", sceFontFtSetAliasFont);
+ LIB_FUNCTION("MEWjebIzDEI", "libSceFontFt", 1, "libSceFontFt", sceFontFtSetAliasPath);
+ LIB_FUNCTION("ZcQL0iSjvFw", "libSceFontFt", 1, "libSceFontFt", sceFontFtSupportBdf);
+ LIB_FUNCTION("LADHEyFTxRQ", "libSceFontFt", 1, "libSceFontFt", sceFontFtSupportCid);
+ LIB_FUNCTION("+jqQjsancTs", "libSceFontFt", 1, "libSceFontFt", sceFontFtSupportFontFormats);
+ LIB_FUNCTION("oakL15-mBtc", "libSceFontFt", 1, "libSceFontFt", sceFontFtSupportOpenType);
+ LIB_FUNCTION("dcQeaDr8UJc", "libSceFontFt", 1, "libSceFontFt", sceFontFtSupportOpenTypeOtf);
+ LIB_FUNCTION("2KXS-HkZT3c", "libSceFontFt", 1, "libSceFontFt", sceFontFtSupportOpenTypeTtf);
+ LIB_FUNCTION("H0mJnhKwV-s", "libSceFontFt", 1, "libSceFontFt", sceFontFtSupportPcf);
+ LIB_FUNCTION("S2mw3sYplAI", "libSceFontFt", 1, "libSceFontFt", sceFontFtSupportPfr);
+ LIB_FUNCTION("+ehNXJPUyhk", "libSceFontFt", 1, "libSceFontFt", sceFontFtSupportSystemFonts);
+ LIB_FUNCTION("4BAhDLdrzUI", "libSceFontFt", 1, "libSceFontFt", sceFontFtSupportTrueType);
+ LIB_FUNCTION("Utlzbdf+g9o", "libSceFontFt", 1, "libSceFontFt", sceFontFtSupportTrueTypeGx);
+ LIB_FUNCTION("nAfQ6qaL1fU", "libSceFontFt", 1, "libSceFontFt", sceFontFtSupportType1);
+ LIB_FUNCTION("X9+pzrGtBus", "libSceFontFt", 1, "libSceFontFt", sceFontFtSupportType42);
+ LIB_FUNCTION("w0hI3xsK-hc", "libSceFontFt", 1, "libSceFontFt", sceFontFtSupportWinFonts);
+ LIB_FUNCTION("w5sfH9r8ZJ4", "libSceFontFt", 1, "libSceFontFt", sceFontFtTermAliases);
+ LIB_FUNCTION("ojW+VKl4Ehs", "libSceFontFt", 1, "libSceFontFt", sceFontSelectGlyphsFt);
+ LIB_FUNCTION("oM+XCzVG3oM", "libSceFontFt", 1, "libSceFontFt", sceFontSelectLibraryFt);
+ LIB_FUNCTION("Xx974EW-QFY", "libSceFontFt", 1, "libSceFontFt", sceFontSelectRendererFt);
+};
+
+} // namespace Libraries::FontFt
\ No newline at end of file
diff --git a/src/core/libraries/font/fontft.h b/src/core/libraries/font/fontft.h
new file mode 100644
index 000000000..cec6d7872
--- /dev/null
+++ b/src/core/libraries/font/fontft.h
@@ -0,0 +1,37 @@
+// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include "common/types.h"
+
+namespace Core::Loader {
+class SymbolsResolver;
+}
+
+namespace Libraries::FontFt {
+
+s32 PS4_SYSV_ABI sceFontFtInitAliases();
+s32 PS4_SYSV_ABI sceFontFtSetAliasFont();
+s32 PS4_SYSV_ABI sceFontFtSetAliasPath();
+s32 PS4_SYSV_ABI sceFontFtSupportBdf();
+s32 PS4_SYSV_ABI sceFontFtSupportCid();
+s32 PS4_SYSV_ABI sceFontFtSupportFontFormats();
+s32 PS4_SYSV_ABI sceFontFtSupportOpenType();
+s32 PS4_SYSV_ABI sceFontFtSupportOpenTypeOtf();
+s32 PS4_SYSV_ABI sceFontFtSupportOpenTypeTtf();
+s32 PS4_SYSV_ABI sceFontFtSupportPcf();
+s32 PS4_SYSV_ABI sceFontFtSupportPfr();
+s32 PS4_SYSV_ABI sceFontFtSupportSystemFonts();
+s32 PS4_SYSV_ABI sceFontFtSupportTrueType();
+s32 PS4_SYSV_ABI sceFontFtSupportTrueTypeGx();
+s32 PS4_SYSV_ABI sceFontFtSupportType1();
+s32 PS4_SYSV_ABI sceFontFtSupportType42();
+s32 PS4_SYSV_ABI sceFontFtSupportWinFonts();
+s32 PS4_SYSV_ABI sceFontFtTermAliases();
+s32 PS4_SYSV_ABI sceFontSelectGlyphsFt();
+s32 PS4_SYSV_ABI sceFontSelectLibraryFt();
+s32 PS4_SYSV_ABI sceFontSelectRendererFt();
+
+void RegisterlibSceFontFt(Core::Loader::SymbolsResolver* sym);
+} // namespace Libraries::FontFt
\ No newline at end of file
diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp
index 2c4b4a670..7ded1f33e 100644
--- a/src/core/libraries/kernel/file_system.cpp
+++ b/src/core/libraries/kernel/file_system.cpp
@@ -140,7 +140,7 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
return -1;
}
// Create a file if it doesn't exist
- Common::FS::IOFile out(file->m_host_name, Common::FS::FileAccessMode::Write);
+ Common::FS::IOFile out(file->m_host_name, Common::FS::FileAccessMode::Create);
}
} else if (!exists) {
// If we're not creating a file, and it doesn't exist, return ENOENT
@@ -205,22 +205,30 @@ s32 PS4_SYSV_ABI open(const char* raw_path, s32 flags, u16 mode) {
}
if (read) {
- // Read only
+ // Open exclusively for reading
e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Read);
} else if (read_only) {
// Can't open files with write/read-write access in a read only directory
h->DeleteHandle(handle);
*__Error() = POSIX_EROFS;
return -1;
- } else if (append) {
- // Append can be specified with rdwr or write, but we treat it as a separate mode.
- e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Append);
} else if (write) {
- // Write only
- e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Write);
+ if (append) {
+ // Open exclusively for appending
+ e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Append);
+ } else {
+ // Open exclusively for writing
+ e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::Write);
+ }
} else if (rdwr) {
// Read and write
- e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadWrite);
+ if (append) {
+ // Open for reading and appending
+ e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadAppend);
+ } else {
+ // Open for reading and writing
+ e = file->f.Open(file->m_host_name, Common::FS::FileAccessMode::ReadWrite);
+ }
}
}
@@ -354,6 +362,12 @@ s64 PS4_SYSV_ABI readv(s32 fd, const OrbisKernelIovec* iov, s32 iovcnt) {
}
return result;
}
+
+ if (file->f.IsWriteOnly()) {
+ *__Error() = POSIX_EBADF;
+ return -1;
+ }
+
s64 total_read = 0;
for (s32 i = 0; i < iovcnt; i++) {
total_read += ReadFile(file->f, iov[i].iov_base, iov[i].iov_len);
@@ -509,6 +523,12 @@ s64 PS4_SYSV_ABI read(s32 fd, void* buf, u64 nbytes) {
// Socket functions handle errnos internally.
return file->socket->ReceivePacket(buf, nbytes, 0, nullptr, 0);
}
+
+ if (file->f.IsWriteOnly()) {
+ *__Error() = POSIX_EBADF;
+ return -1;
+ }
+
return ReadFile(file->f, buf, nbytes);
}
@@ -620,17 +640,29 @@ s32 PS4_SYSV_ABI posix_stat(const char* path, OrbisKernelStat* sb) {
*__Error() = POSIX_ENOENT;
return -1;
}
+
+ // get the difference between file clock and system clock
+ const auto now_sys = std::chrono::system_clock::now();
+ const auto now_file = std::filesystem::file_time_type::clock::now();
+ // calculate the file modified time
+ const auto mtime = std::filesystem::last_write_time(path_name);
+ const auto mtimestamp = now_sys + (mtime - now_file);
+
if (std::filesystem::is_directory(path_name)) {
sb->st_mode = 0000777u | 0040000u;
sb->st_size = 65536;
sb->st_blksize = 65536;
sb->st_blocks = 128;
+ sb->st_mtim.tv_sec =
+ std::chrono::duration_cast(mtimestamp.time_since_epoch()).count();
// TODO incomplete
} else {
sb->st_mode = 0000777u | 0100000u;
sb->st_size = static_cast(std::filesystem::file_size(path_name));
sb->st_blksize = 512;
sb->st_blocks = (sb->st_size + 511) / 512;
+ sb->st_mtim.tv_sec =
+ std::chrono::duration_cast(mtimestamp.time_since_epoch()).count();
// TODO incomplete
}
@@ -801,11 +833,7 @@ s32 PS4_SYSV_ABI posix_rename(const char* from, const char* to) {
auto* h = Common::Singleton::Instance();
auto file = h->GetFile(src_path);
if (file) {
- // We need to force ReadWrite if the file had Write access before
- // Otherwise f.Open will clear the file contents.
- auto access_mode = file->f.GetAccessMode() == Common::FS::FileAccessMode::Write
- ? Common::FS::FileAccessMode::ReadWrite
- : file->f.GetAccessMode();
+ auto access_mode = file->f.GetAccessMode();
file->f.Close();
std::filesystem::remove(src_path);
file->f.Open(dst_path, access_mode);
@@ -855,6 +883,11 @@ s64 PS4_SYSV_ABI posix_preadv(s32 fd, OrbisKernelIovec* iov, s32 iovcnt, s64 off
return result;
}
+ if (file->f.IsWriteOnly()) {
+ *__Error() = POSIX_EBADF;
+ return -1;
+ }
+
const s64 pos = file->f.Tell();
SCOPE_EXIT {
file->f.Seek(pos);
diff --git a/src/core/libraries/kernel/kernel.cpp b/src/core/libraries/kernel/kernel.cpp
index 054f34c15..6594bfab2 100644
--- a/src/core/libraries/kernel/kernel.cpp
+++ b/src/core/libraries/kernel/kernel.cpp
@@ -236,15 +236,24 @@ s32 PS4_SYSV_ABI sceKernelSetGPO() {
return ORBIS_OK;
}
+s32 PS4_SYSV_ABI sceKernelGetAllowedSdkVersionOnSystem(s32* ver) {
+ if (ver == nullptr) {
+ return ORBIS_KERNEL_ERROR_EINVAL;
+ }
+ // Returns the highest game SDK version this PS4 allows.
+ *ver = CURRENT_FIRMWARE_VERSION | 0xfff;
+ LOG_INFO(Lib_Kernel, "called, returned sw version: {}", *ver);
+ return ORBIS_OK;
+}
+
s32 PS4_SYSV_ABI sceKernelGetSystemSwVersion(SwVersionStruct* ret) {
if (ret == nullptr) {
- return ORBIS_OK; // but why?
+ return ORBIS_OK;
}
- ASSERT(ret->struct_size == 40);
- u32 fake_fw = Common::ElfInfo::Instance().RawFirmwareVer();
+ u32 fake_fw = CURRENT_FIRMWARE_VERSION;
ret->hex_representation = fake_fw;
std::snprintf(ret->text_representation, 28, "%2x.%03x.%03x", fake_fw >> 0x18,
- fake_fw >> 0xc & 0xfff, fake_fw & 0xfff); // why %2x?
+ fake_fw >> 0xc & 0xfff, fake_fw & 0xfff);
LOG_INFO(Lib_Kernel, "called, returned sw version: {}", ret->text_representation);
return ORBIS_OK;
}
@@ -257,9 +266,13 @@ const char** PS4_SYSV_ABI getargv() {
return entry_params.argv;
}
-s32 PS4_SYSV_ABI get_authinfo(int pid, AuthInfoData* p2) {
+s32 PS4_SYSV_ABI get_authinfo(s32 pid, AuthInfoData* p2) {
LOG_WARNING(Lib_Kernel, "(STUBBED) called, pid: {}", pid);
- if ((pid != 0) && (pid != GLOBAL_PID)) {
+ if (p2 == nullptr) {
+ *Kernel::__Error() = POSIX_EPERM;
+ return -1;
+ }
+ if (pid != 0 && pid != GLOBAL_PID) {
*Kernel::__Error() = POSIX_ESRCH;
return -1;
}
@@ -269,6 +282,22 @@ s32 PS4_SYSV_ABI get_authinfo(int pid, AuthInfoData* p2) {
return ORBIS_OK;
}
+s32 PS4_SYSV_ABI sceKernelGetAppInfo(s32 pid, OrbisKernelAppInfo* app_info) {
+ LOG_WARNING(Lib_Kernel, "(STUBBED) called, pid: {}", pid);
+ if (pid != GLOBAL_PID) {
+ return ORBIS_KERNEL_ERROR_EPERM;
+ }
+ if (app_info == nullptr) {
+ return ORBIS_OK;
+ }
+
+ auto& game_info = Common::ElfInfo::Instance();
+ *app_info = {};
+ app_info->has_param_sfo = 1;
+ strncpy(app_info->cusa_name, game_info.GameSerial().data(), 10);
+ return ORBIS_OK;
+}
+
void RegisterLib(Core::Loader::SymbolsResolver* sym) {
service_thread = std::jthread{KernelServiceThread};
@@ -285,8 +314,10 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", &g_stack_chk_guard);
LIB_FUNCTION("D4yla3vx4tY", "libkernel", 1, "libkernel", sceKernelError);
+ LIB_FUNCTION("YeU23Szo3BM", "libkernel", 1, "libkernel", sceKernelGetAllowedSdkVersionOnSystem);
LIB_FUNCTION("Mv1zUObHvXI", "libkernel", 1, "libkernel", sceKernelGetSystemSwVersion);
LIB_FUNCTION("igMefp4SAv0", "libkernel", 1, "libkernel", get_authinfo);
+ LIB_FUNCTION("G-MYv5erXaU", "libkernel", 1, "libkernel", sceKernelGetAppInfo);
LIB_FUNCTION("PfccT7qURYE", "libkernel", 1, "libkernel", kernel_ioctl);
LIB_FUNCTION("wW+k21cmbwQ", "libkernel", 1, "libkernel", kernel_ioctl);
LIB_FUNCTION("JGfTMBOdUJo", "libkernel", 1, "libkernel", sceKernelGetFsSandboxRandomWord);
diff --git a/src/core/libraries/kernel/kernel.h b/src/core/libraries/kernel/kernel.h
index 74c457dc5..91fac4c71 100644
--- a/src/core/libraries/kernel/kernel.h
+++ b/src/core/libraries/kernel/kernel.h
@@ -36,6 +36,8 @@ struct OrbisWrapperImpl {
#define ORBIS(func) (Libraries::Kernel::OrbisWrapperImpl::wrap)
+#define CURRENT_FIRMWARE_VERSION 0x13020011
+
s32* PS4_SYSV_ABI __Error();
struct SwVersionStruct {
@@ -51,6 +53,30 @@ struct AuthInfoData {
u64 ucred[8];
};
+struct OrbisKernelTitleWorkaround {
+ s32 version;
+ s32 align;
+ u64 ids[2];
+};
+
+struct OrbisKernelAppInfo {
+ s32 app_id;
+ s32 mmap_flags;
+ s32 attribute_exe;
+ s32 attribute2;
+ char cusa_name[10];
+ u8 debug_level;
+ u8 slv_flags;
+ u8 mini_app_dmem_flags;
+ u8 render_mode;
+ u8 mdbg_out;
+ u8 required_hdcp_type;
+ u64 preload_prx_flags;
+ s32 attribute1;
+ s32 has_param_sfo;
+ OrbisKernelTitleWorkaround title_workaround;
+};
+
void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Kernel
diff --git a/src/core/libraries/kernel/process.cpp b/src/core/libraries/kernel/process.cpp
index 0e168e43a..02da041c3 100644
--- a/src/core/libraries/kernel/process.cpp
+++ b/src/core/libraries/kernel/process.cpp
@@ -21,8 +21,22 @@ s32 PS4_SYSV_ABI sceKernelIsNeoMode() {
Common::ElfInfo::Instance().GetPSFAttributes().support_neo_mode;
}
+s32 PS4_SYSV_ABI sceKernelHasNeoMode() {
+ return Config::isNeoModeConsole();
+}
+
+s32 PS4_SYSV_ABI sceKernelGetMainSocId() {
+ // These hardcoded values are based on hardware observations.
+ // Different models of PS4/PS4 Pro likely return slightly different values.
+ LOG_DEBUG(Lib_Kernel, "called");
+ if (Config::isNeoModeConsole()) {
+ return 0x740f30;
+ }
+ return 0x710f10;
+}
+
s32 PS4_SYSV_ABI sceKernelGetCompiledSdkVersion(s32* ver) {
- s32 version = Common::ElfInfo::Instance().RawFirmwareVer();
+ s32 version = Common::ElfInfo::Instance().CompiledSdkVer();
*ver = version;
return (version >= 0) ? ORBIS_OK : ORBIS_KERNEL_ERROR_EINVAL;
}
@@ -31,6 +45,11 @@ s32 PS4_SYSV_ABI sceKernelGetCpumode() {
return 0;
}
+s32 PS4_SYSV_ABI sceKernelGetCurrentCpu() {
+ LOG_DEBUG(Lib_Kernel, "called");
+ return 0;
+}
+
void* PS4_SYSV_ABI sceKernelGetProcParam() {
auto* linker = Common::Singleton::Instance();
return linker->GetProcParam();
@@ -208,7 +227,10 @@ void RegisterProcess(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("xeu-pV8wkKs", "libkernel", 1, "libkernel", sceKernelIsInSandbox);
LIB_FUNCTION("WB66evu8bsU", "libkernel", 1, "libkernel", sceKernelGetCompiledSdkVersion);
LIB_FUNCTION("WslcK1FQcGI", "libkernel", 1, "libkernel", sceKernelIsNeoMode);
+ LIB_FUNCTION("rNRtm1uioyY", "libkernel", 1, "libkernel", sceKernelHasNeoMode);
+ LIB_FUNCTION("0vTn5IDMU9A", "libkernel", 1, "libkernel", sceKernelGetMainSocId);
LIB_FUNCTION("VOx8NGmHXTs", "libkernel", 1, "libkernel", sceKernelGetCpumode);
+ LIB_FUNCTION("g0VTBxfJyu0", "libkernel", 1, "libkernel", sceKernelGetCurrentCpu);
LIB_FUNCTION("959qrazPIrg", "libkernel", 1, "libkernel", sceKernelGetProcParam);
LIB_FUNCTION("wzvqT4UqKX8", "libkernel", 1, "libkernel", sceKernelLoadStartModule);
LIB_FUNCTION("LwG8g3niqwA", "libkernel", 1, "libkernel", sceKernelDlsym);
diff --git a/src/core/libraries/kernel/threads/condvar.cpp b/src/core/libraries/kernel/threads/condvar.cpp
index 98f7397ad..9d429ed7d 100644
--- a/src/core/libraries/kernel/threads/condvar.cpp
+++ b/src/core/libraries/kernel/threads/condvar.cpp
@@ -354,6 +354,8 @@ void RegisterCond(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("Op8TBGY5KHg", "libkernel", 1, "libkernel", posix_pthread_cond_wait);
LIB_FUNCTION("mkx2fVhNMsg", "libkernel", 1, "libkernel", posix_pthread_cond_broadcast);
LIB_FUNCTION("2MOy+rUfuhQ", "libkernel", 1, "libkernel", posix_pthread_cond_signal);
+ LIB_FUNCTION("RXXqi4CtF8w", "libkernel", 1, "libkernel", posix_pthread_cond_destroy);
+ LIB_FUNCTION("27bAgiJmOh0", "libkernel", 1, "libkernel", posix_pthread_cond_timedwait);
LIB_FUNCTION("mKoTx03HRWA", "libkernel", 1, "libkernel", posix_pthread_condattr_init);
LIB_FUNCTION("dJcuQVn6-Iw", "libkernel", 1, "libkernel", posix_pthread_condattr_destroy);
diff --git a/src/core/libraries/kernel/threads/mutex.cpp b/src/core/libraries/kernel/threads/mutex.cpp
index 505bd0d9d..5d97c5dc1 100644
--- a/src/core/libraries/kernel/threads/mutex.cpp
+++ b/src/core/libraries/kernel/threads/mutex.cpp
@@ -442,6 +442,8 @@ void RegisterMutex(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("ltCfaGr2JGE", "libkernel", 1, "libkernel", posix_pthread_mutex_destroy);
LIB_FUNCTION("dQHWEsJtoE4", "libkernel", 1, "libkernel", posix_pthread_mutexattr_init);
LIB_FUNCTION("mDmgMOGVUqg", "libkernel", 1, "libkernel", posix_pthread_mutexattr_settype);
+ LIB_FUNCTION("HF7lK46xzjY", "libkernel", 1, "libkernel", posix_pthread_mutexattr_destroy);
+ LIB_FUNCTION("K-jXhbt2gn4", "libkernel", 1, "libkernel", posix_pthread_mutex_trylock);
// Orbis
LIB_FUNCTION("cmo1RIYva9o", "libkernel", 1, "libkernel", ORBIS(scePthreadMutexInit));
diff --git a/src/core/libraries/kernel/threads/pthread.cpp b/src/core/libraries/kernel/threads/pthread.cpp
index 09e8b9558..8ab8b72c3 100644
--- a/src/core/libraries/kernel/threads/pthread.cpp
+++ b/src/core/libraries/kernel/threads/pthread.cpp
@@ -663,6 +663,9 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("Z4QosVuAsA0", "libkernel", 1, "libkernel", posix_pthread_once);
LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", posix_pthread_self);
LIB_FUNCTION("OxhIB8LB-PQ", "libkernel", 1, "libkernel", posix_pthread_create);
+ LIB_FUNCTION("+U1R4WtXvoc", "libkernel", 1, "libkernel", posix_pthread_detach);
+ LIB_FUNCTION("7Xl257M4VNI", "libkernel", 1, "libkernel", posix_pthread_equal);
+ LIB_FUNCTION("h9CcP3J0oVM", "libkernel", 1, "libkernel", posix_pthread_join);
LIB_FUNCTION("Jb2uGFMr688", "libkernel", 1, "libkernel", posix_pthread_getaffinity_np);
LIB_FUNCTION("5KWrg7-ZqvE", "libkernel", 1, "libkernel", posix_pthread_setaffinity_np);
LIB_FUNCTION("3eqs37G74-s", "libkernel", 1, "libkernel", posix_pthread_getthreadid_np);
diff --git a/src/core/libraries/network/http.cpp b/src/core/libraries/network/http.cpp
index 63e82ce81..1ae48dfed 100644
--- a/src/core/libraries/network/http.cpp
+++ b/src/core/libraries/network/http.cpp
@@ -9,6 +9,35 @@
namespace Libraries::Http {
+static bool g_isHttpInitialized = true; // TODO temp always inited
+
+void NormalizeAndAppendPath(char* dest, char* src) {
+ char* lastSlash;
+ u64 length;
+
+ lastSlash = strrchr(dest, '/');
+ if (lastSlash == NULL) {
+ length = strlen(dest);
+ dest[length] = '/';
+ dest[length + 1] = '\0';
+ } else {
+ lastSlash[1] = '\0';
+ }
+ if (*src == '/') {
+ dest[0] = '\0';
+ }
+ length = strnlen(dest, 0x3fff);
+ strncat(dest, src, 0x3fff - length);
+ return;
+}
+
+int HttpRequestInternal_Acquire(HttpRequestInternal** outRequest, u32 requestId) {
+ return 0; // TODO dummy
+}
+int HttpRequestInternal_Release(HttpRequestInternal* request) {
+ return 0; // TODO dummy
+}
+
int PS4_SYSV_ABI sceHttpAbortRequest() {
LOG_ERROR(Lib_Http, "(STUBBED) called");
return ORBIS_OK;
@@ -34,8 +63,9 @@ int PS4_SYSV_ABI sceHttpAddQuery() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceHttpAddRequestHeader() {
- LOG_ERROR(Lib_Http, "(STUBBED) called");
+int PS4_SYSV_ABI sceHttpAddRequestHeader(int id, const char* name, const char* value, s32 mode) {
+ LOG_ERROR(Lib_Http, "(STUBBED) called id= {} name = {} value = {} mode = {}", id,
+ std::string(name), std::string(value), mode);
return ORBIS_OK;
}
@@ -84,8 +114,9 @@ int PS4_SYSV_ABI sceHttpCreateConnection() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceHttpCreateConnectionWithURL() {
- LOG_ERROR(Lib_Http, "(STUBBED) called");
+int PS4_SYSV_ABI sceHttpCreateConnectionWithURL(int tmplId, const char* url, bool enableKeepalive) {
+ LOG_ERROR(Lib_Http, "(STUBBED) called tmpid = {} url = {} enableKeepalive = {}", tmplId,
+ std::string(url), enableKeepalive ? 1 : 0);
return ORBIS_OK;
}
@@ -104,8 +135,10 @@ int PS4_SYSV_ABI sceHttpCreateRequest2() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceHttpCreateRequestWithURL() {
- LOG_ERROR(Lib_Http, "(STUBBED) called");
+int PS4_SYSV_ABI sceHttpCreateRequestWithURL(int connId, s32 method, const char* url,
+ u64 contentLength) {
+ LOG_ERROR(Lib_Http, "(STUBBED) called connId = {} method = {} url={} contentLength={}", connId,
+ method, url, contentLength);
return ORBIS_OK;
}
@@ -184,7 +217,7 @@ int PS4_SYSV_ABI sceHttpGetAcceptEncodingGZIPEnabled() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceHttpGetAllResponseHeaders() {
+int PS4_SYSV_ABI sceHttpGetAllResponseHeaders(int reqId, char** header, u64* headerSize) {
LOG_ERROR(Lib_Http, "(STUBBED) called");
return ORBIS_FAIL;
}
@@ -254,12 +287,42 @@ int PS4_SYSV_ABI sceHttpGetResponseContentLength() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceHttpGetStatusCode() {
- LOG_ERROR(Lib_Http, "(STUBBED) called");
+int PS4_SYSV_ABI sceHttpGetStatusCode(int reqId, int* statusCode) {
+ LOG_ERROR(Lib_Http, "(STUBBED) called reqId = {}", reqId);
+#if 0
+ if (!g_isHttpInitialized)
+ return ORBIS_HTTP_ERROR_BEFORE_INIT;
+
+ if (statusCode == nullptr)
+ return ORBIS_HTTP_ERROR_INVALID_VALUE;
+
+ int ret = 0;
+ // Lookup HttpRequestInternal by reqId
+ HttpRequestInternal* request = nullptr;
+ ret = HttpRequestInternal_Acquire(&request, reqId);
+ if (ret < 0)
+ return ret;
+ request->m_mutex.lock();
+ if (request->state > 0x11) {
+ if (request->state == 0x16) {
+ ret = request->errorCode;
+ } else {
+ *statusCode = request->httpStatusCode;
+ ret = 0;
+ }
+ } else {
+ ret = ORBIS_HTTP_ERROR_BEFORE_SEND;
+ }
+ request->m_mutex.unlock();
+ HttpRequestInternal_Release(request);
+
+ return ret;
+#else
return ORBIS_OK;
+#endif
}
-int PS4_SYSV_ABI sceHttpInit(int libnetMemId, int libsslCtxId, std::size_t poolSize) {
+int PS4_SYSV_ABI sceHttpInit(int libnetMemId, int libsslCtxId, u64 poolSize) {
LOG_ERROR(Lib_Http, "(DUMMY) called libnetMemId = {} libsslCtxId = {} poolSize = {}",
libnetMemId, libsslCtxId, poolSize);
// return a value >1
@@ -267,14 +330,104 @@ int PS4_SYSV_ABI sceHttpInit(int libnetMemId, int libsslCtxId, std::size_t poolS
return ++id;
}
-int PS4_SYSV_ABI sceHttpParseResponseHeader() {
+int PS4_SYSV_ABI sceHttpParseResponseHeader(const char* header, u64 headerLen, const char* fieldStr,
+ const char** fieldValue, u64* valueLen) {
LOG_ERROR(Lib_Http, "(STUBBED) called");
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceHttpParseStatusLine() {
- LOG_ERROR(Lib_Http, "(STUBBED) called");
- return ORBIS_OK;
+int PS4_SYSV_ABI sceHttpParseStatusLine(const char* statusLine, u64 lineLen, int32_t* httpMajorVer,
+ int32_t* httpMinorVer, int32_t* responseCode,
+ const char** reasonPhrase, u64* phraseLen) {
+ if (!statusLine) {
+ LOG_ERROR(Lib_Http, "Invalid response");
+ return ORBIS_HTTP_ERROR_PARSE_HTTP_INVALID_RESPONSE;
+ }
+ if (!httpMajorVer || !httpMinorVer || !responseCode || !reasonPhrase || !phraseLen) {
+ LOG_ERROR(Lib_Http, "Invalid value");
+ return ORBIS_HTTP_ERROR_PARSE_HTTP_INVALID_VALUE;
+ }
+ *httpMajorVer = 0;
+ *httpMinorVer = 0;
+ if (lineLen < 8) {
+ LOG_ERROR(Lib_Http, "Linelen is smaller than 8");
+ return ORBIS_HTTP_ERROR_PARSE_HTTP_INVALID_RESPONSE;
+ }
+ if (strncmp(statusLine, "HTTP/", 5) != 0) {
+ LOG_ERROR(Lib_Http, "statusLine doesn't start with HTTP/");
+ return ORBIS_HTTP_ERROR_PARSE_HTTP_INVALID_RESPONSE;
+ }
+
+ u64 index = 5;
+
+ if (!isdigit(statusLine[index])) {
+ LOG_ERROR(Lib_Http, "Invalid response");
+
+ return ORBIS_HTTP_ERROR_PARSE_HTTP_INVALID_RESPONSE;
+ }
+
+ while (isdigit(statusLine[index])) {
+ *httpMajorVer = *httpMajorVer * 10 + (statusLine[index] - '0');
+ index++;
+ }
+
+ if (statusLine[index] != '.') {
+ LOG_ERROR(Lib_Http, "Invalid response");
+ return ORBIS_HTTP_ERROR_PARSE_HTTP_INVALID_RESPONSE;
+ }
+ index++;
+
+ if (!isdigit(statusLine[index])) {
+ LOG_ERROR(Lib_Http, "Invalid response");
+ return ORBIS_HTTP_ERROR_PARSE_HTTP_INVALID_RESPONSE;
+ }
+
+ while (isdigit(statusLine[index])) {
+ *httpMinorVer = *httpMinorVer * 10 + (statusLine[index] - '0');
+ index++;
+ }
+
+ if (statusLine[index] != ' ') {
+ LOG_ERROR(Lib_Http, "Invalid response");
+ return ORBIS_HTTP_ERROR_PARSE_HTTP_INVALID_RESPONSE;
+ }
+ index++;
+
+ // Validate and parse the 3-digit HTTP response code
+ if (lineLen - index < 3 || !isdigit(statusLine[index]) || !isdigit(statusLine[index + 1]) ||
+ !isdigit(statusLine[index + 2])) {
+ LOG_ERROR(Lib_Http, "Invalid response");
+ return ORBIS_HTTP_ERROR_PARSE_HTTP_INVALID_RESPONSE;
+ }
+
+ *responseCode = (statusLine[index] - '0') * 100 + (statusLine[index + 1] - '0') * 10 +
+ (statusLine[index + 2] - '0');
+ index += 3;
+
+ if (statusLine[index] != ' ') {
+ LOG_ERROR(Lib_Http, "Invalid response");
+ return ORBIS_HTTP_ERROR_PARSE_HTTP_INVALID_RESPONSE;
+ }
+ index++;
+
+ // Set the reason phrase start position
+ *reasonPhrase = &statusLine[index];
+ u64 phraseStart = index;
+
+ while (index < lineLen && statusLine[index] != '\n') {
+ index++;
+ }
+
+ // Determine the length of the reason phrase, excluding trailing \r if present
+ if (index == phraseStart) {
+ *phraseLen = 0;
+ } else {
+ *phraseLen =
+ (statusLine[index - 1] == '\r') ? (index - phraseStart - 1) : (index - phraseStart);
+ }
+
+ // Return the number of bytes processed
+ return index + 1;
}
int PS4_SYSV_ABI sceHttpReadData() {
@@ -317,8 +470,8 @@ int PS4_SYSV_ABI sceHttpsEnableOptionPrivate() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceHttpSendRequest() {
- LOG_ERROR(Lib_Http, "(STUBBED) called");
+int PS4_SYSV_ABI sceHttpSendRequest(int reqId, const void* postData, u64 size) {
+ LOG_ERROR(Lib_Http, "(STUBBED) called reqId = {} size = {}", reqId, size);
return ORBIS_OK;
}
@@ -548,7 +701,8 @@ int PS4_SYSV_ABI sceHttpUnsetEpoll() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceHttpUriBuild() {
+int PS4_SYSV_ABI sceHttpUriBuild(char* out, u64* require, u64 prepare,
+ const OrbisHttpUriElement* srcElement, u32 option) {
LOG_ERROR(Lib_Http, "(STUBBED) called");
return ORBIS_OK;
}
@@ -563,13 +717,97 @@ int PS4_SYSV_ABI sceHttpUriEscape() {
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceHttpUriMerge() {
- LOG_ERROR(Lib_Http, "(STUBBED) called");
- return ORBIS_OK;
+int PS4_SYSV_ABI sceHttpUriMerge(char* mergedUrl, char* url, char* relativeUri, u64* require,
+ u64 prepare, u32 option) {
+ u64 requiredLength;
+ int returnValue;
+ u64 baseUrlLength;
+ u64 relativeUriLength;
+ u64 totalLength;
+ u64 combinedLength;
+ int parseResult;
+ u64 localSizeRelativeUri;
+ u64 localSizeBaseUrl;
+ OrbisHttpUriElement parsedUriElement;
+
+ if (option != 0 || url == NULL || relativeUri == NULL) {
+ LOG_ERROR(Lib_Http, "Invalid value");
+ return ORBIS_HTTP_ERROR_INVALID_VALUE;
+ }
+
+ returnValue = sceHttpUriParse(NULL, url, NULL, &localSizeBaseUrl, 0);
+ if (returnValue < 0) {
+ LOG_ERROR(Lib_Http, "returning {:#x}", returnValue);
+ return returnValue;
+ }
+
+ returnValue = sceHttpUriParse(NULL, relativeUri, NULL, &localSizeRelativeUri, 0);
+ if (returnValue < 0) {
+ LOG_ERROR(Lib_Http, "returning {:#x}", returnValue);
+ return returnValue;
+ }
+
+ baseUrlLength = strnlen(url, 0x3fff);
+ relativeUriLength = strnlen(relativeUri, 0x3fff);
+ requiredLength = localSizeBaseUrl + 2 + (relativeUriLength + baseUrlLength) * 2;
+
+ if (require) {
+ *require = requiredLength;
+ }
+
+ if (mergedUrl == NULL) {
+ return ORBIS_OK;
+ }
+
+ if (prepare < requiredLength) {
+ LOG_ERROR(Lib_Http, "Error Out of memory");
+ return ORBIS_HTTP_ERROR_OUT_OF_MEMORY;
+ }
+
+ totalLength = strnlen(url, 0x3fff);
+ baseUrlLength = strnlen(relativeUri, 0x3fff);
+ combinedLength = totalLength + 1 + baseUrlLength;
+ relativeUriLength = prepare - combinedLength;
+
+ returnValue =
+ sceHttpUriParse(&parsedUriElement, relativeUri, mergedUrl + totalLength + baseUrlLength + 1,
+ &localSizeRelativeUri, relativeUriLength);
+ if (returnValue < 0) {
+ LOG_ERROR(Lib_Http, "returning {:#x}", returnValue);
+ return returnValue;
+ }
+ if (parsedUriElement.scheme == NULL) {
+ strncpy(mergedUrl, relativeUri, requiredLength);
+ if (require) {
+ *require = strnlen(relativeUri, 0x3fff) + 1;
+ }
+ return ORBIS_OK;
+ }
+
+ returnValue =
+ sceHttpUriParse(&parsedUriElement, url, mergedUrl + totalLength + baseUrlLength + 1,
+ &localSizeBaseUrl, relativeUriLength);
+ if (returnValue < 0) {
+ LOG_ERROR(Lib_Http, "returning {:#x}", returnValue);
+ return returnValue;
+ }
+
+ combinedLength += localSizeBaseUrl;
+ strncpy(mergedUrl + combinedLength, parsedUriElement.path, prepare - combinedLength);
+ NormalizeAndAppendPath(mergedUrl + combinedLength, relativeUri);
+
+ returnValue = sceHttpUriBuild(mergedUrl, 0, ~(baseUrlLength + totalLength) + prepare,
+ &parsedUriElement, 0x3f);
+ if (returnValue >= 0) {
+ return ORBIS_OK;
+ } else {
+ LOG_ERROR(Lib_Http, "returning {:#x}", returnValue);
+ return returnValue;
+ }
}
int PS4_SYSV_ABI sceHttpUriParse(OrbisHttpUriElement* out, const char* srcUri, void* pool,
- size_t* require, size_t prepare) {
+ u64* require, u64 prepare) {
LOG_INFO(Lib_Http, "srcUri = {}", std::string(srcUri));
if (!srcUri) {
LOG_ERROR(Lib_Http, "invalid url");
@@ -586,10 +824,10 @@ int PS4_SYSV_ABI sceHttpUriParse(OrbisHttpUriElement* out, const char* srcUri, v
}
// Track the total required buffer size
- size_t requiredSize = 0;
+ u64 requiredSize = 0;
// Parse the scheme (e.g., "http:", "https:", "file:")
- size_t schemeLength = 0;
+ u64 schemeLength = 0;
while (srcUri[schemeLength] && srcUri[schemeLength] != ':') {
if (!isalnum(srcUri[schemeLength])) {
LOG_ERROR(Lib_Http, "invalid url");
@@ -611,7 +849,7 @@ int PS4_SYSV_ABI sceHttpUriParse(OrbisHttpUriElement* out, const char* srcUri, v
requiredSize += schemeLength + 1;
// Move past the scheme and ':' character
- size_t offset = schemeLength + 1;
+ u64 offset = schemeLength + 1;
// Check if "//" appears after the scheme
if (strncmp(srcUri + offset, "//", 2) == 0) {
@@ -638,7 +876,7 @@ int PS4_SYSV_ABI sceHttpUriParse(OrbisHttpUriElement* out, const char* srcUri, v
// Parse the path (everything after the slashes)
char* pathStart = (char*)srcUri + offset;
- size_t pathLength = 0;
+ u64 pathLength = 0;
while (pathStart[pathLength] && pathStart[pathLength] != '?' &&
pathStart[pathLength] != '#') {
pathLength++;
@@ -689,7 +927,7 @@ int PS4_SYSV_ABI sceHttpUriParse(OrbisHttpUriElement* out, const char* srcUri, v
hostStart++;
}
- size_t hostLength = 0;
+ u64 hostLength = 0;
while (hostStart[hostLength] && hostStart[hostLength] != '/' &&
hostStart[hostLength] != '?' && hostStart[hostLength] != ':') {
hostLength++;
@@ -714,7 +952,7 @@ int PS4_SYSV_ABI sceHttpUriParse(OrbisHttpUriElement* out, const char* srcUri, v
// Parse the port (if present)
if (hostStart[hostLength] == ':') {
char* portStart = hostStart + hostLength + 1;
- size_t portLength = 0;
+ u64 portLength = 0;
while (portStart[portLength] && isdigit(portStart[portLength])) {
portLength++;
}
@@ -754,7 +992,7 @@ int PS4_SYSV_ABI sceHttpUriParse(OrbisHttpUriElement* out, const char* srcUri, v
// Parse the path (if present)
if (srcUri[offset] == '/') {
char* pathStart = (char*)srcUri + offset;
- size_t pathLength = 0;
+ u64 pathLength = 0;
while (pathStart[pathLength] && pathStart[pathLength] != '?' &&
pathStart[pathLength] != '#') {
pathLength++;
@@ -780,7 +1018,7 @@ int PS4_SYSV_ABI sceHttpUriParse(OrbisHttpUriElement* out, const char* srcUri, v
// Parse the query (if present)
if (srcUri[offset] == '?') {
char* queryStart = (char*)srcUri + offset + 1;
- size_t queryLength = 0;
+ u64 queryLength = 0;
while (queryStart[queryLength] && queryStart[queryLength] != '#') {
queryLength++;
}
@@ -805,7 +1043,7 @@ int PS4_SYSV_ABI sceHttpUriParse(OrbisHttpUriElement* out, const char* srcUri, v
// Parse the fragment (if present)
if (srcUri[offset] == '#') {
char* fragmentStart = (char*)srcUri + offset + 1;
- size_t fragmentLength = 0;
+ u64 fragmentLength = 0;
while (fragmentStart[fragmentLength]) {
fragmentLength++;
}
@@ -833,12 +1071,12 @@ int PS4_SYSV_ABI sceHttpUriParse(OrbisHttpUriElement* out, const char* srcUri, v
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceHttpUriSweepPath(char* dst, const char* src, size_t srcSize) {
+int PS4_SYSV_ABI sceHttpUriSweepPath(char* dst, const char* src, u64 srcSize) {
LOG_ERROR(Lib_Http, "(STUBBED) called");
return ORBIS_OK;
}
-int PS4_SYSV_ABI sceHttpUriUnescape(char* out, size_t* require, size_t prepare, const char* in) {
+int PS4_SYSV_ABI sceHttpUriUnescape(char* out, u64* require, u64 prepare, const char* in) {
LOG_ERROR(Lib_Http, "(STUBBED) called");
return ORBIS_OK;
}
diff --git a/src/core/libraries/network/http.h b/src/core/libraries/network/http.h
index 228080207..701bb0e05 100644
--- a/src/core/libraries/network/http.h
+++ b/src/core/libraries/network/http.h
@@ -3,6 +3,7 @@
#pragma once
+#include
#include "common/types.h"
#include "core/libraries/network/ssl.h"
@@ -25,6 +26,12 @@ struct OrbisHttpUriElement {
u8 reserved[10];
};
+struct HttpRequestInternal {
+ int state; // +0x20
+ int errorCode; // +0x28
+ int httpStatusCode; // +0x20C
+ std::mutex m_mutex;
+};
using OrbisHttpsCaList = Libraries::Ssl::OrbisSslCaList;
int PS4_SYSV_ABI sceHttpAbortRequest();
@@ -32,7 +39,7 @@ int PS4_SYSV_ABI sceHttpAbortRequestForce();
int PS4_SYSV_ABI sceHttpAbortWaitRequest();
int PS4_SYSV_ABI sceHttpAddCookie();
int PS4_SYSV_ABI sceHttpAddQuery();
-int PS4_SYSV_ABI sceHttpAddRequestHeader();
+int PS4_SYSV_ABI sceHttpAddRequestHeader(int id, const char* name, const char* value, s32 mode);
int PS4_SYSV_ABI sceHttpAddRequestHeaderRaw();
int PS4_SYSV_ABI sceHttpAuthCacheExport();
int PS4_SYSV_ABI sceHttpAuthCacheFlush();
@@ -42,11 +49,12 @@ int PS4_SYSV_ABI sceHttpCookieExport();
int PS4_SYSV_ABI sceHttpCookieFlush();
int PS4_SYSV_ABI sceHttpCookieImport();
int PS4_SYSV_ABI sceHttpCreateConnection();
-int PS4_SYSV_ABI sceHttpCreateConnectionWithURL();
+int PS4_SYSV_ABI sceHttpCreateConnectionWithURL(int tmplId, const char* url, bool enableKeepalive);
int PS4_SYSV_ABI sceHttpCreateEpoll();
int PS4_SYSV_ABI sceHttpCreateRequest();
int PS4_SYSV_ABI sceHttpCreateRequest2();
-int PS4_SYSV_ABI sceHttpCreateRequestWithURL();
+int PS4_SYSV_ABI sceHttpCreateRequestWithURL(int connId, s32 method, const char* url,
+ u64 contentLength);
int PS4_SYSV_ABI sceHttpCreateRequestWithURL2();
int PS4_SYSV_ABI sceHttpCreateTemplate();
int PS4_SYSV_ABI sceHttpDbgEnableProfile();
@@ -62,7 +70,7 @@ int PS4_SYSV_ABI sceHttpDeleteRequest();
int PS4_SYSV_ABI sceHttpDeleteTemplate();
int PS4_SYSV_ABI sceHttpDestroyEpoll();
int PS4_SYSV_ABI sceHttpGetAcceptEncodingGZIPEnabled();
-int PS4_SYSV_ABI sceHttpGetAllResponseHeaders();
+int PS4_SYSV_ABI sceHttpGetAllResponseHeaders(int reqId, char** header, u64* headerSize);
int PS4_SYSV_ABI sceHttpGetAuthEnabled();
int PS4_SYSV_ABI sceHttpGetAutoRedirect();
int PS4_SYSV_ABI sceHttpGetConnectionStat();
@@ -76,10 +84,13 @@ int PS4_SYSV_ABI sceHttpGetMemoryPoolStats();
int PS4_SYSV_ABI sceHttpGetNonblock();
int PS4_SYSV_ABI sceHttpGetRegisteredCtxIds();
int PS4_SYSV_ABI sceHttpGetResponseContentLength();
-int PS4_SYSV_ABI sceHttpGetStatusCode();
-int PS4_SYSV_ABI sceHttpInit(int libnetMemId, int libsslCtxId, std::size_t poolSize);
-int PS4_SYSV_ABI sceHttpParseResponseHeader();
-int PS4_SYSV_ABI sceHttpParseStatusLine();
+int PS4_SYSV_ABI sceHttpGetStatusCode(int reqId, int* statusCode);
+int PS4_SYSV_ABI sceHttpInit(int libnetMemId, int libsslCtxId, u64 poolSize);
+int PS4_SYSV_ABI sceHttpParseResponseHeader(const char* header, u64 headerLen, const char* fieldStr,
+ const char** fieldValue, u64* valueLen);
+int PS4_SYSV_ABI sceHttpParseStatusLine(const char* statusLine, u64 lineLen, int32_t* httpMajorVer,
+ int32_t* httpMinorVer, int32_t* responseCode,
+ const char** reasonPhrase, u64* phraseLen);
int PS4_SYSV_ABI sceHttpReadData();
int PS4_SYSV_ABI sceHttpRedirectCacheFlush();
int PS4_SYSV_ABI sceHttpRemoveRequestHeader();
@@ -88,7 +99,7 @@ int PS4_SYSV_ABI sceHttpsDisableOption();
int PS4_SYSV_ABI sceHttpsDisableOptionPrivate();
int PS4_SYSV_ABI sceHttpsEnableOption();
int PS4_SYSV_ABI sceHttpsEnableOptionPrivate();
-int PS4_SYSV_ABI sceHttpSendRequest();
+int PS4_SYSV_ABI sceHttpSendRequest(int reqId, const void* postData, u64 size);
int PS4_SYSV_ABI sceHttpSetAcceptEncodingGZIPEnabled();
int PS4_SYSV_ABI sceHttpSetAuthEnabled();
int PS4_SYSV_ABI sceHttpSetAuthInfoCallback();
@@ -134,14 +145,16 @@ int PS4_SYSV_ABI sceHttpTerm();
int PS4_SYSV_ABI sceHttpTryGetNonblock();
int PS4_SYSV_ABI sceHttpTrySetNonblock();
int PS4_SYSV_ABI sceHttpUnsetEpoll();
-int PS4_SYSV_ABI sceHttpUriBuild();
+int PS4_SYSV_ABI sceHttpUriBuild(char* out, u64* require, u64 prepare,
+ const OrbisHttpUriElement* srcElement, u32 option);
int PS4_SYSV_ABI sceHttpUriCopy();
int PS4_SYSV_ABI sceHttpUriEscape();
-int PS4_SYSV_ABI sceHttpUriMerge();
+int PS4_SYSV_ABI sceHttpUriMerge(char* mergedUrl, char* url, char* relativeUri, u64* require,
+ u64 prepare, u32 option);
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);
+ u64* require, u64 prepare);
+int PS4_SYSV_ABI sceHttpUriSweepPath(char* dst, const char* src, u64 srcSize);
+int PS4_SYSV_ABI sceHttpUriUnescape(char* out, u64* require, u64 prepare, const char* in);
int PS4_SYSV_ABI sceHttpWaitRequest();
void RegisterLib(Core::Loader::SymbolsResolver* sym);
diff --git a/src/core/libraries/network/net.cpp b/src/core/libraries/network/net.cpp
index d9ef76afc..97005813b 100644
--- a/src/core/libraries/network/net.cpp
+++ b/src/core/libraries/network/net.cpp
@@ -1285,7 +1285,8 @@ u16 PS4_SYSV_ABI sceNetNtohs(u16 net16) {
int PS4_SYSV_ABI sceNetPoolCreate(const char* name, int size, int flags) {
LOG_ERROR(Lib_Net, "(DUMMY) name = {} size = {} flags = {} ", std::string(name), size, flags);
- return ORBIS_OK;
+ static s32 id = 1;
+ return id++;
}
int PS4_SYSV_ABI sceNetPoolDestroy() {
diff --git a/src/core/libraries/np/trophy_ui.cpp b/src/core/libraries/np/trophy_ui.cpp
index 94e7eb5f2..b803403c4 100644
--- a/src/core/libraries/np/trophy_ui.cpp
+++ b/src/core/libraries/np/trophy_ui.cpp
@@ -5,7 +5,6 @@
#include
#include
#include
-#include
#include
#include
@@ -92,59 +91,45 @@ TrophyUI::TrophyUI(const std::filesystem::path& trophyIconPath, const std::strin
AddLayer(this);
- bool customsoundplayed = false;
-#ifdef ENABLE_QT_GUI
- 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(musicPathWav, false);
- customsoundplayed = true;
- } else if (fs::exists(musicPathMp3.toStdString())) {
- BackgroundMusicPlayer::getInstance().setVolume(100);
- BackgroundMusicPlayer::getInstance().playMusic(musicPathMp3, false);
- customsoundplayed = true;
+ MIX_Init();
+ mixer = MIX_CreateMixerDevice(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, NULL);
+ if (!mixer) {
+ LOG_ERROR(Lib_NpTrophy, "Could not initialize SDL Mixer, {}", SDL_GetError());
+ return;
}
-#endif
- if (!customsoundplayed) {
+ MIX_SetMasterGain(mixer, static_cast(Config::getVolumeSlider() / 100.f));
+ auto musicPathMp3 = CustomTrophy_Dir / "trophy.mp3";
+ auto musicPathWav = CustomTrophy_Dir / "trophy.wav";
+
+ if (std::filesystem::exists(musicPathMp3)) {
+ audio = MIX_LoadAudio(mixer, musicPathMp3.string().c_str(), false);
+ } else if (std::filesystem::exists(musicPathWav)) {
+ audio = MIX_LoadAudio(mixer, musicPathWav.string().c_str(), false);
+ } else {
auto soundFile = resource.open("src/images/trophy.wav");
std::vector soundData = std::vector(soundFile.begin(), soundFile.end());
+ audio =
+ MIX_LoadAudio_IO(mixer, SDL_IOFromMem(soundData.data(), soundData.size()), false, true);
+ // due to low volume of default sound file
+ MIX_SetMasterGain(mixer, MIX_GetMasterGain(mixer) * 1.3f);
+ }
- SDL_AudioSpec spec;
- Uint8* audioBuf;
- Uint32 audioLen;
+ if (!audio) {
+ LOG_ERROR(Lib_NpTrophy, "Could not loud audio file, {}", SDL_GetError());
+ return;
+ }
- if (!SDL_LoadWAV_IO(SDL_IOFromMem(soundData.data(), soundData.size()), true, &spec,
- &audioBuf, &audioLen)) {
- LOG_ERROR(Lib_NpTrophy, "Cannot load trophy sound: {}", SDL_GetError());
- SDL_free(audioBuf);
- return;
- }
-
- SDL_AudioStream* stream =
- SDL_OpenAudioDeviceStream(SDL_AUDIO_DEVICE_DEFAULT_PLAYBACK, &spec, nullptr, nullptr);
- if (!stream) {
- LOG_ERROR(Lib_NpTrophy, "Cannot create audio stream for trophy sound: {}",
- SDL_GetError());
- SDL_free(audioBuf);
- return;
- }
-
- if (!SDL_PutAudioStreamData(stream, audioBuf, audioLen)) {
- LOG_ERROR(Lib_NpTrophy, "Cannot add trophy sound data to stream: {}", SDL_GetError());
- SDL_free(audioBuf);
- return;
- }
-
- // Set audio gain 20% higher since audio file itself is soft
- SDL_SetAudioStreamGain(stream, Config::getVolumeSlider() / 100.0f * 1.2f);
- SDL_ResumeAudioStreamDevice(stream);
- SDL_free(audioBuf);
+ if (!MIX_PlayAudio(mixer, audio)) {
+ LOG_ERROR(Lib_NpTrophy, "Could not play audio file, {}", SDL_GetError());
}
}
TrophyUI::~TrophyUI() {
+ MIX_DestroyAudio(audio);
+ MIX_DestroyMixer(mixer);
+ MIX_Quit();
+
Finish();
}
diff --git a/src/core/libraries/np/trophy_ui.h b/src/core/libraries/np/trophy_ui.h
index fbadac8f4..2734471b3 100644
--- a/src/core/libraries/np/trophy_ui.h
+++ b/src/core/libraries/np/trophy_ui.h
@@ -5,6 +5,7 @@
#include
#include
+#include
#include
#include "common/fixed_value.h"
@@ -30,6 +31,9 @@ private:
std::string_view trophy_type;
ImGui::RefCountedTexture trophy_icon;
ImGui::RefCountedTexture trophy_type_icon;
+
+ MIX_Mixer* mixer;
+ MIX_Audio* audio;
};
struct TrophyInfo {
diff --git a/src/core/libraries/save_data/save_instance.cpp b/src/core/libraries/save_data/save_instance.cpp
index 05253eb23..75a644fdb 100644
--- a/src/core/libraries/save_data/save_instance.cpp
+++ b/src/core/libraries/save_data/save_instance.cpp
@@ -180,7 +180,7 @@ void SaveInstance::SetupAndMount(bool read_only, bool copy_icon, bool ignore_cor
}
if (!ignore_corrupt && !read_only) {
- Common::FS::IOFile f(corrupt_file_path, Common::FS::FileAccessMode::Write);
+ Common::FS::IOFile f(corrupt_file_path, Common::FS::FileAccessMode::Create);
f.Close();
}
diff --git a/src/core/libraries/save_data/save_memory.cpp b/src/core/libraries/save_data/save_memory.cpp
index 4080362eb..5f5ba8fea 100644
--- a/src/core/libraries/save_data/save_memory.cpp
+++ b/src/core/libraries/save_data/save_memory.cpp
@@ -59,7 +59,7 @@ void PersistMemory(u32 slot_id, bool lock) {
while (n++ < 10) {
try {
IOFile f;
- int r = f.Open(memoryPath, Common::FS::FileAccessMode::Write);
+ int r = f.Open(memoryPath, Common::FS::FileAccessMode::Create);
if (f.IsOpen()) {
f.WriteRaw(data.memory_cache.data(), data.memory_cache.size());
f.Close();
@@ -148,7 +148,7 @@ void SetIcon(u32 slot_id, void* buf, size_t buf_size) {
fs::copy_file(src_icon, icon_path);
}
} else {
- IOFile file(icon_path, Common::FS::FileAccessMode::Write);
+ IOFile file(icon_path, Common::FS::FileAccessMode::Create);
file.WriteRaw(buf, buf_size);
file.Close();
}
diff --git a/src/core/libraries/save_data/savedata.cpp b/src/core/libraries/save_data/savedata.cpp
index aec7c1d54..7fba8ed21 100644
--- a/src/core/libraries/save_data/savedata.cpp
+++ b/src/core/libraries/save_data/savedata.cpp
@@ -1389,7 +1389,7 @@ Error PS4_SYSV_ABI sceSaveDataSaveIcon(const OrbisSaveDataMountPoint* mountPoint
}
try {
- const Common::FS::IOFile file(path, Common::FS::FileAccessMode::Write);
+ const Common::FS::IOFile file(path, Common::FS::FileAccessMode::Create);
file.WriteRaw(icon->buf, std::min(icon->bufSize, icon->dataSize));
} catch (const fs::filesystem_error& e) {
LOG_ERROR(Lib_SaveData, "Failed to load icon: {}", e.what());
diff --git a/src/core/libraries/usbd/emulated/dimensions.cpp b/src/core/libraries/usbd/emulated/dimensions.cpp
new file mode 100644
index 000000000..272f2f649
--- /dev/null
+++ b/src/core/libraries/usbd/emulated/dimensions.cpp
@@ -0,0 +1,651 @@
+// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "dimensions.h"
+
+#include
+#include
+
+namespace Libraries::Usbd {
+
+static constexpr std::array COMMAND_KEY = {0x55, 0xFE, 0xF6, 0xB0, 0x62, 0xBF, 0x0B, 0x41,
+ 0xC9, 0xB3, 0x7C, 0xB4, 0x97, 0x3E, 0x29, 0x7B};
+
+static constexpr std::array CHAR_CONSTANT = {0xB7, 0xD5, 0xD7, 0xE6, 0xE7, 0xBA,
+ 0x3C, 0xA8, 0xD8, 0x75, 0x47, 0x68,
+ 0xCF, 0x23, 0xE9, 0xFE, 0xAA};
+
+static constexpr std::array PWD_CONSTANT = {
+ 0x28, 0x63, 0x29, 0x20, 0x43, 0x6F, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74,
+ 0x20, 0x4C, 0x45, 0x47, 0x4F, 0x20, 0x32, 0x30, 0x31, 0x34, 0xAA, 0xAA};
+
+DimensionsToypad::DimensionsToypad() {}
+
+void DimensionsToypad::LoadFigure(std::string file_name, u8 pad, u8 index) {
+ Common::FS::IOFile file(file_name, Common::FS::FileAccessMode::ReadWrite);
+ std::array data;
+ ASSERT(file.Read(data) == data.size());
+ LoadDimensionsFigure(data, std::move(file), pad, index);
+}
+
+u32 DimensionsToypad::LoadDimensionsFigure(const std::array& buf,
+ Common::FS::IOFile file, u8 pad, u8 index) {
+ std::lock_guard lock(m_dimensions_mutex);
+
+ const u32 id = GetFigureId(buf);
+
+ DimensionsFigure& figure = GetFigureByIndex(index);
+ figure.dimFile = std::move(file);
+ figure.id = id;
+ figure.pad = pad;
+ figure.index = index + 1;
+ figure.data = buf;
+ // When a figure is added to the toypad, respond to the game with the pad they were added to,
+ // their index, the direction (0x00 in byte 6 for added) and their UID
+ std::array figureChangeResponse = {0x56, 0x0b, figure.pad, 0x00, figure.index,
+ 0x00, buf[0], buf[1], buf[2], buf[4],
+ buf[5], buf[6], buf[7]};
+ figureChangeResponse[13] = GenerateChecksum(figureChangeResponse, 13);
+ m_figure_added_removed_responses.push(figureChangeResponse);
+
+ return id;
+}
+
+void DimensionsToypad::RemoveFigure(u8 pad, u8 index, bool fullRemove) {
+ std::lock_guard lock(m_dimensions_mutex);
+
+ DimensionsFigure& figure = GetFigureByIndex(index);
+ if (figure.index == 255)
+ return;
+
+ // When a figure is removed from the toypad, respond to the game with the pad they were removed
+ // from, their index, the direction (0x01 in byte 6 for removed) and their UID
+ if (fullRemove) {
+ std::array figureChangeResponse = {
+ 0x56, 0x0b, figure.pad, 0x00, figure.index,
+ 0x01, figure.data[0], figure.data[1], figure.data[2], figure.data[4],
+ figure.data[5], figure.data[6], figure.data[7]};
+ figureChangeResponse[13] = GenerateChecksum(figureChangeResponse, 13);
+ m_figure_added_removed_responses.push(figureChangeResponse);
+ figure.Save();
+ figure.dimFile.Close();
+ }
+
+ figure.index = 255;
+ figure.pad = 255;
+ figure.id = 0;
+}
+
+void DimensionsToypad::MoveFigure(u8 new_pad, u8 new_index, u8 old_pad, u8 old_index) {
+ if (old_index == new_index) {
+ // Don't bother removing and loading again, just send response to the game
+ CancelRemoveFigure(new_index);
+ return;
+ }
+
+ // When moving figures between spaces on the toypad, remove any figure from the space they are
+ // moving to, then remove them from their current space, then load them to the space they are
+ // moving to
+ RemoveFigure(new_pad, new_index, true);
+
+ DimensionsFigure& figure = GetFigureByIndex(old_index);
+ const std::array data = figure.data;
+ Common::FS::IOFile inFile = std::move(figure.dimFile);
+
+ RemoveFigure(old_pad, old_index, false);
+
+ LoadDimensionsFigure(data, std::move(inFile), new_pad, new_index);
+}
+
+void DimensionsToypad::TempRemoveFigure(u8 index) {
+ std::lock_guard lock(m_dimensions_mutex);
+
+ DimensionsFigure& figure = GetFigureByIndex(index);
+ if (figure.index == 255)
+ return;
+
+ // Send a response to the game that the figure has been "Picked up" from existing slot,
+ // until either the movement is cancelled, or user chooses a space to move to
+ std::array figureChangeResponse = {
+ 0x56, 0x0b, figure.pad, 0x00, figure.index,
+ 0x01, figure.data[0], figure.data[1], figure.data[2], figure.data[4],
+ figure.data[5], figure.data[6], figure.data[7]};
+
+ figureChangeResponse[13] = GenerateChecksum(figureChangeResponse, 13);
+ m_figure_added_removed_responses.push(figureChangeResponse);
+}
+
+void DimensionsToypad::CancelRemoveFigure(u8 index) {
+ std::lock_guard lock(m_dimensions_mutex);
+
+ DimensionsFigure& figure = GetFigureByIndex(index);
+ if (figure.index == 255)
+ return;
+
+ // Cancel the previous movement of the figure
+ std::array figureChangeResponse = {
+ 0x56, 0x0b, figure.pad, 0x00, figure.index,
+ 0x00, figure.data[0], figure.data[1], figure.data[2], figure.data[4],
+ figure.data[5], figure.data[6], figure.data[7]};
+
+ figureChangeResponse[13] = GenerateChecksum(figureChangeResponse, 13);
+ m_figure_added_removed_responses.push(figureChangeResponse);
+}
+
+u8 DimensionsToypad::GenerateChecksum(const std::array& data, u32 num_of_bytes) {
+ int checksum = 0;
+ ASSERT(num_of_bytes <= data.size());
+ for (u8 i = 0; i < num_of_bytes; i++) {
+ checksum += data[i];
+ }
+ return (checksum & 0xFF);
+}
+
+void DimensionsToypad::GetBlankResponse(u8 type, u8 sequence, std::array& reply_buf) {
+ reply_buf[0] = 0x55;
+ reply_buf[1] = type;
+ reply_buf[2] = sequence;
+ reply_buf[3] = GenerateChecksum(reply_buf, 3);
+}
+
+void DimensionsToypad::GenerateRandomNumber(const u8* buf, u8 sequence,
+ std::array& reply_buf) {
+ // Decrypt payload into an 8 byte array
+ const std::array value = Decrypt(buf, std::nullopt);
+ // Seed is the first 4 bytes (little endian) of the decrypted payload
+ const u32 seed = (u32&)value[0];
+ // Confirmation is the second 4 bytes (big endian) of the decrypted payload
+ // const u32 conf = (u32be&)value[4];
+ // Initialize rng using the seed from decrypted payload
+ InitializeRNG(seed);
+ // Encrypt 8 bytes, first 4 bytes is the decrypted confirmation from payload, 2nd 4 bytes are
+ // blank
+ std::array value_to_encrypt = {value[4], value[5], value[6], value[7], 0, 0, 0, 0};
+ const std::array encrypted = Encrypt(value_to_encrypt.data(), std::nullopt);
+ reply_buf[0] = 0x55;
+ reply_buf[1] = 0x09;
+ reply_buf[2] = sequence;
+ // Copy encrypted value to response data
+ std::memcpy(&reply_buf[3], encrypted.data(), encrypted.size());
+ reply_buf[11] = GenerateChecksum(reply_buf, 11);
+}
+
+void DimensionsToypad::InitializeRNG(u32 seed) {
+ m_random_a = 0xF1EA5EED;
+ m_random_b = seed;
+ m_random_c = seed;
+ m_random_d = seed;
+
+ for (int i = 0; i < 42; i++) {
+ GetNext();
+ }
+}
+
+u32 DimensionsToypad::GetNext() {
+ const u32 e = m_random_a - std::rotl(m_random_b, 21);
+ m_random_a = m_random_b ^ std::rotl(m_random_c, 19);
+ m_random_b = m_random_c + std::rotl(m_random_d, 6);
+ m_random_c = m_random_d + e;
+ m_random_d = e + m_random_a;
+ return m_random_d;
+}
+
+std::array DimensionsToypad::Decrypt(const u8* buf, std::optional> key) {
+ // Value to decrypt is separated in to two little endian 32 bit unsigned integers
+ u32 data_one = u32(buf[0]) | (u32(buf[1]) << 8) | (u32(buf[2]) << 16) | (u32(buf[3]) << 24);
+ u32 data_two = u32(buf[4]) | (u32(buf[5]) << 8) | (u32(buf[6]) << 16) | (u32(buf[7]) << 24);
+
+ // Use the key as 4 32 bit little endian unsigned integers
+ u32 key_one;
+ u32 key_two;
+ u32 key_three;
+ u32 key_four;
+
+ if (key) {
+ key_one = u32(key.value()[0]) | (u32(key.value()[1]) << 8) | (u32(key.value()[2]) << 16) |
+ (u32(key.value()[3]) << 24);
+ key_two = u32(key.value()[4]) | (u32(key.value()[5]) << 8) | (u32(key.value()[6]) << 16) |
+ (u32(key.value()[7]) << 24);
+ key_three = u32(key.value()[8]) | (u32(key.value()[9]) << 8) |
+ (u32(key.value()[10]) << 16) | (u32(key.value()[11]) << 24);
+ key_four = u32(key.value()[12]) | (u32(key.value()[13]) << 8) |
+ (u32(key.value()[14]) << 16) | (u32(key.value()[15]) << 24);
+ } else {
+ key_one = u32(COMMAND_KEY[0]) | (u32(COMMAND_KEY[1]) << 8) | (u32(COMMAND_KEY[2]) << 16) |
+ (u32(COMMAND_KEY[3]) << 24);
+ key_two = u32(COMMAND_KEY[4]) | (u32(COMMAND_KEY[5]) << 8) | (u32(COMMAND_KEY[6]) << 16) |
+ (u32(COMMAND_KEY[7]) << 24);
+ key_three = u32(COMMAND_KEY[8]) | (u32(COMMAND_KEY[9]) << 8) |
+ (u32(COMMAND_KEY[10]) << 16) | (u32(COMMAND_KEY[11]) << 24);
+ key_four = u32(COMMAND_KEY[12]) | (u32(COMMAND_KEY[13]) << 8) |
+ (u32(COMMAND_KEY[14]) << 16) | (u32(COMMAND_KEY[15]) << 24);
+ }
+
+ u32 sum = 0xC6EF3720;
+ constexpr u32 delta = 0x9E3779B9;
+
+ for (int i = 0; i < 32; i++) {
+ data_two -=
+ (((data_one << 4) + key_three) ^ (data_one + sum) ^ ((data_one >> 5) + key_four));
+ data_one -= (((data_two << 4) + key_one) ^ (data_two + sum) ^ ((data_two >> 5) + key_two));
+ sum -= delta;
+ }
+
+ ASSERT_MSG(sum == 0, "Decryption failed, sum inequal to 0");
+
+ std::array decrypted = {u8(data_one & 0xFF), u8((data_one >> 8) & 0xFF),
+ u8((data_one >> 16) & 0xFF), u8((data_one >> 24) & 0xFF),
+ u8(data_two & 0xFF), u8((data_two >> 8) & 0xFF),
+ u8((data_two >> 16) & 0xFF), u8((data_two >> 24) & 0xFF)};
+ return decrypted;
+}
+
+std::array DimensionsToypad::Encrypt(const u8* buf, std::optional> key) {
+ // Value to encrypt is separated in to two little endian 32 bit unsigned integers
+ u32 data_one = u32(buf[0]) | (u32(buf[1]) << 8) | (u32(buf[2]) << 16) | (u32(buf[3]) << 24);
+ u32 data_two = u32(buf[4]) | (u32(buf[5]) << 8) | (u32(buf[6]) << 16) | (u32(buf[7]) << 24);
+
+ // Use the key as 4 32 bit little endian unsigned integers
+ u32 key_one;
+ u32 key_two;
+ u32 key_three;
+ u32 key_four;
+
+ if (key) {
+ key_one = u32(key.value()[0]) | (u32(key.value()[1]) << 8) | (u32(key.value()[2]) << 16) |
+ (u32(key.value()[3]) << 24);
+ key_two = u32(key.value()[4]) | (u32(key.value()[5]) << 8) | (u32(key.value()[6]) << 16) |
+ (u32(key.value()[7]) << 24);
+ key_three = u32(key.value()[8]) | (u32(key.value()[9]) << 8) |
+ (u32(key.value()[10]) << 16) | (u32(key.value()[11]) << 24);
+ key_four = u32(key.value()[12]) | (u32(key.value()[13]) << 8) |
+ (u32(key.value()[14]) << 16) | (u32(key.value()[15]) << 24);
+ } else {
+ key_one = u32(COMMAND_KEY[0]) | (u32(COMMAND_KEY[1]) << 8) | (u32(COMMAND_KEY[2]) << 16) |
+ (u32(COMMAND_KEY[3]) << 24);
+ key_two = u32(COMMAND_KEY[4]) | (u32(COMMAND_KEY[5]) << 8) | (u32(COMMAND_KEY[6]) << 16) |
+ (u32(COMMAND_KEY[7]) << 24);
+ key_three = u32(COMMAND_KEY[8]) | (u32(COMMAND_KEY[9]) << 8) |
+ (u32(COMMAND_KEY[10]) << 16) | (u32(COMMAND_KEY[11]) << 24);
+ key_four = u32(COMMAND_KEY[12]) | (u32(COMMAND_KEY[13]) << 8) |
+ (u32(COMMAND_KEY[14]) << 16) | (u32(COMMAND_KEY[15]) << 24);
+ }
+
+ u32 sum = 0;
+ u32 delta = 0x9E3779B9;
+
+ for (int i = 0; i < 32; i++) {
+ sum += delta;
+ data_one += (((data_two << 4) + key_one) ^ (data_two + sum) ^ ((data_two >> 5) + key_two));
+ data_two +=
+ (((data_one << 4) + key_three) ^ (data_one + sum) ^ ((data_one >> 5) + key_four));
+ }
+
+ std::array encrypted = {u8(data_one & 0xFF), u8((data_one >> 8) & 0xFF),
+ u8((data_one >> 16) & 0xFF), u8((data_one >> 24) & 0xFF),
+ u8(data_two & 0xFF), u8((data_two >> 8) & 0xFF),
+ u8((data_two >> 16) & 0xFF), u8((data_two >> 24) & 0xFF)};
+ return encrypted;
+}
+
+std::array DimensionsToypad::GenerateFigureKey(const std::array& buf) {
+ std::array uid = {buf[0], buf[1], buf[2], buf[4], buf[5], buf[6], buf[7]};
+
+ u32 scrambleA = Scramble(uid, 3);
+ u32 scrambleB = Scramble(uid, 4);
+ u32 scrambleC = Scramble(uid, 5);
+ u32 scrambleD = Scramble(uid, 6);
+
+ return {
+ u8((scrambleA >> 24) & 0xFF), u8((scrambleA >> 16) & 0xFF), u8((scrambleA >> 8) & 0xFF),
+ u8(scrambleA & 0xFF), u8((scrambleB >> 24) & 0xFF), u8((scrambleB >> 16) & 0xFF),
+ u8((scrambleB >> 8) & 0xFF), u8(scrambleB & 0xFF), u8((scrambleC >> 24) & 0xFF),
+ u8((scrambleC >> 16) & 0xFF), u8((scrambleC >> 8) & 0xFF), u8(scrambleC & 0xFF),
+ u8((scrambleD >> 24) & 0xFF), u8((scrambleD >> 16) & 0xFF), u8((scrambleD >> 8) & 0xFF),
+ u8(scrambleD & 0xFF)};
+}
+
+u32 DimensionsToypad::Scramble(const std::array& uid, u8 count) {
+ std::vector to_scramble;
+ to_scramble.reserve(uid.size() + CHAR_CONSTANT.size());
+ for (u8 x : uid) {
+ to_scramble.push_back(x);
+ }
+ for (u8 c : CHAR_CONSTANT) {
+ to_scramble.push_back(c);
+ }
+ to_scramble[(count * 4) - 1] = 0xaa;
+
+ std::array randomized = DimensionsRandomize(to_scramble, count);
+
+ return (u32(randomized[0]) << 24) | (u32(randomized[1]) << 16) | (u32(randomized[2]) << 8) |
+ u32(randomized[3]);
+}
+
+std::array DimensionsToypad::PWDGenerate(const std::array& uid) {
+ std::vector pwdCalc = {PWD_CONSTANT.begin(), PWD_CONSTANT.end() - 1};
+ for (u8 i = 0; i < uid.size(); i++) {
+ pwdCalc.insert(pwdCalc.begin() + i, uid[i]);
+ }
+
+ return DimensionsRandomize(pwdCalc, 8);
+}
+
+std::array DimensionsToypad::DimensionsRandomize(const std::vector& key, u8 count) {
+ u32 scrambled = 0;
+ for (u8 i = 0; i < count; i++) {
+ const u32 v4 = std::rotr(scrambled, 25);
+ const u32 v5 = std::rotr(scrambled, 10);
+ const u32 b = u32(key[i * 4]) | (u32(key[(i * 4) + 1]) << 8) |
+ (u32(key[(i * 4) + 2]) << 16) | (u32(key[(i * 4) + 3]) << 24);
+ scrambled = b + v4 + v5 - scrambled;
+ }
+ return {u8(scrambled & 0xFF), u8(scrambled >> 8 & 0xFF), u8(scrambled >> 16 & 0xFF),
+ u8(scrambled >> 24 & 0xFF)};
+}
+
+u32 DimensionsToypad::GetFigureId(const std::array& buf) {
+ const std::array figure_key = GenerateFigureKey(buf);
+
+ const std::array decrypted = Decrypt(&buf[36 * 4], figure_key);
+
+ const u32 fig_num = u32(decrypted[0]) | (u32(decrypted[1]) << 8) | (u32(decrypted[2]) << 16) |
+ (u32(decrypted[3]) << 24);
+ // Characters have their model number encrypted in page 36
+ if (fig_num < 1000) {
+ return fig_num;
+ }
+ // Vehicles/Gadgets have their model number written as little endian in page 36
+ return u32(buf[36 * 4]) | (u32(buf[(36 * 4) + 1]) << 8) | (u32(buf[(36 * 4) + 2]) << 16) |
+ (u32(buf[(36 * 4) + 3]) << 24);
+}
+
+DimensionsFigure& DimensionsToypad::GetFigureByIndex(u8 index) {
+ return m_figures[index];
+}
+
+void DimensionsToypad::RandomUID(u8* uid_buffer) {
+ uid_buffer[0] = 0x04;
+ uid_buffer[7] = 0x80;
+
+ for (u8 i = 1; i < 7; i++) {
+ u8 random = rand() % 255;
+ uid_buffer[i] = random;
+ }
+}
+
+void DimensionsToypad::GetChallengeResponse(const u8* buf, u8 sequence,
+ std::array& reply_buf) {
+ // Decrypt payload into an 8 byte array
+ const std::array value = Decrypt(buf, std::nullopt);
+ // Confirmation is the first 4 bytes of the decrypted payload
+ // const u32 conf = read_from_ptr>(value);
+ // Generate next random number based on RNG
+ const u32 next_random = GetNext();
+ // Encrypt an 8 byte array, first 4 bytes are the next random number (little endian)
+ // followed by the confirmation from the decrypted payload
+ std::array value_to_encrypt = {u8(next_random & 0xFF),
+ u8((next_random >> 8) & 0xFF),
+ u8((next_random >> 16) & 0xFF),
+ u8((next_random >> 24) & 0xFF),
+ value[0],
+ value[1],
+ value[2],
+ value[3]};
+ const std::array encrypted = Encrypt(value_to_encrypt.data(), std::nullopt);
+ reply_buf[0] = 0x55;
+ reply_buf[1] = 0x09;
+ reply_buf[2] = sequence;
+ // Copy encrypted value to response data
+ std::memcpy(&reply_buf[3], encrypted.data(), encrypted.size());
+ reply_buf[11] = GenerateChecksum(reply_buf, 11);
+}
+
+void DimensionsToypad::QueryBlock(u8 index, u8 page, std::array& reply_buf, u8 sequence) {
+ std::lock_guard lock(m_dimensions_mutex);
+
+ reply_buf[0] = 0x55;
+ reply_buf[1] = 0x12;
+ reply_buf[2] = sequence;
+ reply_buf[3] = 0x00;
+
+ // Index from game begins at 1 rather than 0, so minus 1 here
+ if (const u8 figure_index = index - 1; figure_index < MAX_DIMENSIONS_FIGURES) {
+ const DimensionsFigure& figure = GetFigureByIndex(figure_index);
+
+ // Query 4 pages of 4 bytes from the figure, copy this to the response
+ if (figure.index != 255 && (4 * page) < ((0x2D * 4) - 16)) {
+ std::memcpy(&reply_buf[4], figure.data.data() + (4 * page), 16);
+ }
+ }
+ reply_buf[20] = GenerateChecksum(reply_buf, 20);
+}
+
+void DimensionsToypad::WriteBlock(u8 index, u8 page, const u8* to_write_buf,
+ std::array& reply_buf, u8 sequence) {
+ std::lock_guard lock(m_dimensions_mutex);
+
+ reply_buf[0] = 0x55;
+ reply_buf[1] = 0x02;
+ reply_buf[2] = sequence;
+ reply_buf[3] = 0x00;
+
+ // Index from game begins at 1 rather than 0, so minus 1 here
+ if (const u8 figure_index = index - 1; figure_index < MAX_DIMENSIONS_FIGURES) {
+ DimensionsFigure& figure = GetFigureByIndex(figure_index);
+
+ // Copy 4 bytes to the page on the figure requested by the game
+ if (figure.index != 255 && page < 0x2D) {
+ // Id is written to page 36
+ if (page == 36) {
+ figure.id = u32(to_write_buf[0]) | (u32(to_write_buf[1]) << 8) |
+ (u32(to_write_buf[2]) << 16) | (u32(to_write_buf[3]) << 24);
+ }
+ std::memcpy(figure.data.data() + (page * 4), to_write_buf, 4);
+ figure.Save();
+ }
+ }
+ reply_buf[4] = GenerateChecksum(reply_buf, 4);
+}
+
+void DimensionsToypad::GetModel(const u8* buf, u8 sequence, std::array& reply_buf) {
+ // Decrypt payload to 8 byte array, byte 1 is the index, 4-7 are the confirmation
+ const std::array value = Decrypt(buf, std::nullopt);
+ const u8 index = value[0];
+ // const u32 conf = read_from_ptr>(value, 4);
+ std::array value_to_encrypt = {};
+ // Response is the figure's id (little endian) followed by the confirmation from payload
+ // Index from game begins at 1 rather than 0, so minus 1 here
+ if (const u8 figure_index = index - 1; figure_index < MAX_DIMENSIONS_FIGURES) {
+ const DimensionsFigure& figure = GetFigureByIndex(figure_index);
+ value_to_encrypt = {u8(figure.id & 0xFF),
+ u8((figure.id >> 8) & 0xFF),
+ u8((figure.id >> 16) & 0xFF),
+ u8((figure.id >> 24) & 0xFF),
+ value[4],
+ value[5],
+ value[6],
+ value[7]};
+ }
+ const std::array encrypted = Encrypt(value_to_encrypt.data(), std::nullopt);
+ reply_buf[0] = 0x55;
+ reply_buf[1] = 0x0a;
+ reply_buf[2] = sequence;
+ reply_buf[3] = 0x00;
+ // Copy encrypted message to response
+ std::memcpy(&reply_buf[4], encrypted.data(), encrypted.size());
+ reply_buf[12] = GenerateChecksum(reply_buf, 12);
+}
+
+std::optional> DimensionsToypad::PopAddedRemovedResponse() {
+ std::lock_guard lock(m_dimensions_mutex);
+
+ if (m_figure_added_removed_responses.empty()) {
+ return std::nullopt;
+ }
+
+ std::array response = m_figure_added_removed_responses.front();
+ m_figure_added_removed_responses.pop();
+ return response;
+}
+
+libusb_endpoint_descriptor* DimensionsBackend::FillEndpointDescriptorPair() {
+ return m_endpoint_descriptors.data();
+}
+
+libusb_interface_descriptor* DimensionsBackend::FillInterfaceDescriptor(
+ libusb_endpoint_descriptor* descs) {
+ m_interface_descriptors[0].endpoint = descs;
+ return m_interface_descriptors.data();
+}
+
+libusb_config_descriptor* DimensionsBackend::FillConfigDescriptor(libusb_interface* inter) {
+ m_config_descriptors[0].interface = inter;
+ return m_config_descriptors.data();
+}
+
+libusb_device_descriptor* DimensionsBackend::FillDeviceDescriptor() {
+ return m_device_descriptors.data();
+}
+
+libusb_transfer_status DimensionsBackend::HandleAsyncTransfer(libusb_transfer* transfer) {
+ ASSERT(transfer->length == 32);
+
+ switch (transfer->endpoint) {
+ case 0x81: {
+ // Read Endpoint, wait to respond with either an added/removed figure response, or a queued
+ // response from a previous write
+ bool responded = false;
+ while (!responded) {
+ std::lock_guard lock(m_query_mutex);
+ std::optional> response =
+ m_dimensions_toypad->PopAddedRemovedResponse();
+ if (response) {
+ std::memcpy(transfer->buffer, response.value().data(), 0x20);
+ transfer->length = 32;
+ responded = true;
+ } else if (!m_queries.empty()) {
+ std::memcpy(transfer->buffer, m_queries.front().data(), 0x20);
+ transfer->length = 32;
+ m_queries.pop();
+ responded = true;
+ }
+ }
+ break;
+ }
+ case 0x01: {
+ // Write endpoint, similar structure of request to the Infinity Base with a command for byte
+ // 3, sequence for byte 4, the payload after that, then a checksum for the final byte.
+
+ const u8 command = transfer->buffer[2];
+ const u8 sequence = transfer->buffer[3];
+
+ std::array q_result{};
+
+ switch (command) {
+ case 0xB0: // Wake
+ {
+ // Consistent device response to the wake command
+ q_result = {0x55, 0x0e, 0x01, 0x28, 0x63, 0x29, 0x20, 0x4c, 0x45,
+ 0x47, 0x4f, 0x20, 0x32, 0x30, 0x31, 0x34, 0x46};
+ break;
+ }
+ case 0xB1: // Seed
+ {
+ // Initialise a random number generator using the seed provided
+ m_dimensions_toypad->GenerateRandomNumber(&transfer->buffer[4], sequence, q_result);
+ break;
+ }
+ case 0xB3: // Challenge
+ {
+ // Get the next number in the sequence based on the RNG from 0xB1 command
+ m_dimensions_toypad->GetChallengeResponse(&transfer->buffer[4], sequence, q_result);
+ break;
+ }
+ case 0xC0: // Color
+ case 0xC1: // Get Pad Color
+ case 0xC2: // Fade
+ case 0xC3: // Flash
+ case 0xC4: // Fade Random
+ case 0xC6: // Fade All
+ case 0xC7: // Flash All
+ case 0xC8: // Color All
+ {
+ // Send a blank response to acknowledge color has been sent to toypad
+ m_dimensions_toypad->GetBlankResponse(0x01, sequence, q_result);
+ break;
+ }
+ case 0xD2: // Read
+ {
+ // Read 4 pages from the figure at index (buf[4]), starting with page buf[5]
+ m_dimensions_toypad->QueryBlock(transfer->buffer[4], transfer->buffer[5], q_result,
+ sequence);
+ break;
+ }
+ case 0xD3: // Write
+ {
+ // Write 4 bytes to page buf[5] to the figure at index buf[4]
+ m_dimensions_toypad->WriteBlock(transfer->buffer[4], transfer->buffer[5],
+ &transfer->buffer[6], q_result, sequence);
+ break;
+ }
+ case 0xD4: // Model
+ {
+ // Get the model id of the figure at index buf[4]
+ m_dimensions_toypad->GetModel(&transfer->buffer[4], sequence, q_result);
+ break;
+ }
+ case 0xD0: // Tag List
+ case 0xE1: // PWD
+ case 0xE5: // Active
+ case 0xFF: // LEDS Query
+ {
+ // Further investigation required
+ LOG_ERROR(Lib_Usbd, "Unimplemented LD Function: {:x}", command);
+ break;
+ }
+ default: {
+ LOG_ERROR(Lib_Usbd, "Unknown LD Function: {:x}", command);
+ break;
+ }
+ }
+ std::lock_guard lock(m_query_mutex);
+ m_queries.push(q_result);
+ break;
+ }
+ default:
+ break;
+ }
+ return LIBUSB_TRANSFER_COMPLETED;
+}
+
+s32 DimensionsBackend::SubmitTransfer(libusb_transfer* transfer) {
+ if (transfer->endpoint == 0x01) {
+ std::thread write_thread([this, transfer] {
+ HandleAsyncTransfer(transfer);
+
+ const u8 flags = transfer->flags;
+ transfer->status = LIBUSB_TRANSFER_COMPLETED;
+ transfer->actual_length = transfer->length;
+ if (transfer->callback) {
+ transfer->callback(transfer);
+ }
+ if (flags & LIBUSB_TRANSFER_FREE_TRANSFER) {
+ libusb_free_transfer(transfer);
+ }
+ });
+ write_thread.detach();
+ return LIBUSB_SUCCESS;
+ }
+
+ return UsbEmulatedBackend::SubmitTransfer(transfer);
+}
+
+void DimensionsFigure::Save() {
+ if (!dimFile.IsOpen())
+ return;
+
+ dimFile.Seek(0);
+ dimFile.Write(data);
+}
+} // namespace Libraries::Usbd
\ No newline at end of file
diff --git a/src/core/libraries/usbd/emulated/dimensions.h b/src/core/libraries/usbd/emulated/dimensions.h
new file mode 100644
index 000000000..d9573b5f4
--- /dev/null
+++ b/src/core/libraries/usbd/emulated/dimensions.h
@@ -0,0 +1,118 @@
+// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include
+#include