feat(libs): implement sceGameUpdateGetAddcontLatestVersion
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
0c4b80dc61
commit
58fce8ab1c
|
|
@ -0,0 +1,21 @@
|
|||
add_library(libSceGameUpdate SHARED EXCLUDE_FROM_ALL Export.cpp)
|
||||
target_include_directories(libSceGameUpdate PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
configure_windows_unwind(libSceGameUpdate)
|
||||
|
||||
if(MINGW)
|
||||
foreach(runtimeLinkFlag IN ITEMS -static-libgcc -static-libstdc++ -static)
|
||||
string(REPLACE "${runtimeLinkFlag}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}")
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_test_executable(guest_gameupdate_tests ${LIBS_INCLUDE_DIR}/tests/GuestGameUpdate.cpp)
|
||||
target_include_directories(guest_gameupdate_tests PRIVATE ${LIBS_INCLUDE_DIR})
|
||||
target_link_libraries(guest_gameupdate_tests PRIVATE libSceGameUpdate libc)
|
||||
configure_windows_unwind(guest_gameupdate_tests)
|
||||
add_test(NAME guest_gameupdate COMMAND guest_gameupdate_tests)
|
||||
if(WIN32)
|
||||
set_tests_properties(guest_gameupdate PROPERTIES ENVIRONMENT_MODIFICATION
|
||||
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceGameUpdate>")
|
||||
endif()
|
||||
endif()
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
#include <atomic>
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include "SceTypes.hpp"
|
||||
|
|
@ -5,6 +6,11 @@
|
|||
|
||||
// Update checks need the network, which is not available; requests fail so the game skips the check.
|
||||
static constexpr int SCE_GAME_UPDATE_ERROR_OFFLINE = static_cast<int>(0x80D50001);
|
||||
static constexpr int SCE_GAME_UPDATE_ERROR_NOT_INITIALIZED = static_cast<int>(0x80412801);
|
||||
static constexpr int SCE_GAME_UPDATE_ERROR_INVALID_ARGUMENT = static_cast<int>(0x80412803);
|
||||
static constexpr int SCE_GAME_UPDATE_ERROR_INVALID_SIZE = static_cast<int>(0x80412804);
|
||||
|
||||
static std::atomic<bool> g_initialized{false};
|
||||
|
||||
extern "C" {
|
||||
|
||||
|
|
@ -30,18 +36,33 @@ int APS5_VABI sceGameUpdateDeleteRequest(int request_id) {
|
|||
}
|
||||
|
||||
int APS5_VABI sceGameUpdateGetAddcontLatestVersion(uint32_t service_label, const void* entitlement_label, GameUpdateAddcontVersionInfo* info) {
|
||||
(void)service_label;
|
||||
(void)entitlement_label;
|
||||
(void)info;
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
return 0;
|
||||
(void)service_label;
|
||||
if (!g_initialized.load()) {
|
||||
return SCE_GAME_UPDATE_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (info == nullptr) {
|
||||
return SCE_GAME_UPDATE_ERROR_INVALID_ARGUMENT;
|
||||
}
|
||||
if (entitlement_label == nullptr) {
|
||||
NotImplemented_nid_no_patch(__func__);
|
||||
}
|
||||
if (info->size < sizeof(GameUpdateAddcontVersionInfo)) {
|
||||
return SCE_GAME_UPDATE_ERROR_INVALID_SIZE;
|
||||
}
|
||||
const std::size_t size = info->size;
|
||||
*info = {};
|
||||
info->size = size;
|
||||
info->found = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceGameUpdateInitialize(void) {
|
||||
g_initialized.store(true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int APS5_VABI sceGameUpdateTerminate(void) {
|
||||
g_initialized.store(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
#include "SceTypes.hpp"
|
||||
#include "prx/libc/include/general/VabiMacros.hpp"
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <stdexcept>
|
||||
|
||||
extern "C" {
|
||||
int APS5_VABI sceGameUpdateInitialize(void);
|
||||
int APS5_VABI sceGameUpdateTerminate(void);
|
||||
int APS5_VABI sceGameUpdateGetAddcontLatestVersion(std::uint32_t, const void*, GameUpdateAddcontVersionInfo*);
|
||||
}
|
||||
|
||||
static void Require(bool value) { if (!value) std::abort(); }
|
||||
|
||||
int main() {
|
||||
constexpr int notInitialized = static_cast<int>(0x80412801);
|
||||
constexpr int invalidArgument = static_cast<int>(0x80412803);
|
||||
constexpr int invalidSize = static_cast<int>(0x80412804);
|
||||
|
||||
static_assert(sizeof(GameUpdateAddcontVersionInfo) == 0x30);
|
||||
const std::uint8_t label[16] = {};
|
||||
GameUpdateAddcontVersionInfo info{};
|
||||
info.size = sizeof(info);
|
||||
|
||||
Require(sceGameUpdateGetAddcontLatestVersion(0, label, &info) == notInitialized);
|
||||
Require(sceGameUpdateInitialize() == 0);
|
||||
Require(sceGameUpdateGetAddcontLatestVersion(0, label, nullptr) == invalidArgument);
|
||||
|
||||
bool threw = false;
|
||||
try { sceGameUpdateGetAddcontLatestVersion(0, nullptr, &info); }
|
||||
catch (const std::runtime_error&) { threw = true; }
|
||||
Require(threw);
|
||||
|
||||
info.size = sizeof(info) - 1;
|
||||
Require(sceGameUpdateGetAddcontLatestVersion(0, label, &info) == invalidSize);
|
||||
|
||||
std::memset(&info, 0xAB, sizeof(info));
|
||||
info.size = sizeof(info) + 8;
|
||||
Require(sceGameUpdateGetAddcontLatestVersion(0, label, &info) == 0);
|
||||
Require(info.size == sizeof(info) + 8 && !info.found);
|
||||
const auto* bytes = reinterpret_cast<const std::uint8_t*>(&info);
|
||||
for (std::size_t i = sizeof(info.size); i < sizeof(info); ++i) Require(bytes[i] == 0);
|
||||
|
||||
Require(sceGameUpdateTerminate() == 0);
|
||||
info.size = sizeof(info);
|
||||
Require(sceGameUpdateGetAddcontLatestVersion(0, label, &info) == notInitialized);
|
||||
}
|
||||
|
|
@ -92,6 +92,7 @@ Throughout the project, every function at every stage either **does exactly what
|
|||
- [sceNpSessionSignalingGetConnectionStatistics](../../core/libs/prx/libSceNpSessionSignaling/Export.cpp) (libSceNpSessionSignaling) - unknown signature
|
||||
- [sce::Np::CppWebApi::Common::String](../../core/libs/prx/libSceNpCppWebApi/Export.cpp) (libSceNpCppWebApi) - the 0x20-byte layout (32-bit reference count, buffer at 0x08, buffer size at 0x10, `LibContext*` at 0x18) comes from the module bundled with one title (PPSA21564); other SDK versions are not checked. The destructor throws for a non-null buffer: releasing it needs the `LibContext` allocator, which is not implemented
|
||||
- [sceUserServiceGetAgeLevel](../../core/libs/prx/libSceUserService/Export.cpp) (libSceUserService) - the meaning of the value is unknown; 0 is reported, as for the unset game presets. PPSA12544 (Unity) only stores it for its user profile
|
||||
- [sceGameUpdateGetAddcontLatestVersion](../../core/libs/prx/libSceGameUpdate/Export.cpp) (libSceGameUpdate) - a null `entitlement_label` throws: KytyPS5 accepts it, prosper returns `0x80412803`. Bytes after `found` are zeroed as in KytyPS5; prosper leaves them untouched
|
||||
- [sceSystemServiceDisableMediaPlay](../../core/libs/prx/libSceSystemService/Export.cpp) (libSceSystemService) - unknown signature
|
||||
- [sceSystemServiceReenableMediaPlay](../../core/libs/prx/libSceSystemService/Export.cpp) (libSceSystemService) - unknown signature
|
||||
- [sceSystemServiceParamGetString](../../core/libs/prx/libSceSystemService/Export.cpp) (libSceSystemService) - the system name (parameter 6) is the fixed `PS5`, not the console's name; other parameters and buffers of 1 to 64 bytes throw
|
||||
|
|
|
|||
Loading…
Reference in New Issue