Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions core/libs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,15 @@ endforeach()
add_custom_target(libs DEPENDS ${PATCHED_OUTPUTS})

if(BUILD_TESTING)
add_test_executable(guest_offline_imports_tests tests/GuestOfflineImports.cpp)
target_include_directories(guest_offline_imports_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(guest_offline_imports_tests PRIVATE libSceHttp libSceNpEntitlementAccess libSceRudp libc)
configure_windows_unwind(guest_offline_imports_tests)
add_test(NAME guest_offline_imports COMMAND guest_offline_imports_tests)
if(WIN32)
set_tests_properties(guest_offline_imports PROPERTIES ENVIRONMENT_MODIFICATION
"PATH=path_list_prepend:$<TARGET_FILE_DIR:libSceHttp>")
endif()
add_test_executable(savedata_memory_metadata_tests tests/SaveDataMemoryMetadata.cpp)
target_include_directories(savedata_memory_metadata_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_link_libraries(savedata_memory_metadata_tests PRIVATE libSceSaveData.native)
Expand Down
4 changes: 4 additions & 0 deletions core/libs/SceTypes.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -1274,6 +1274,10 @@ struct NpEntitlementAccessAddcontEntitlementInfo {
std::uint32_t download_status;
};

struct NpEntitlementAccessEntitlementKey {
std::uint8_t data[16];
};



struct NpUniversalDataSystemInitParam {
Expand Down
7 changes: 7 additions & 0 deletions core/libs/prx/libSceHttp/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,13 @@ int APS5_VABI sceHttpSetAuthEnabled(int id, int enable) {
return 0;
}

int APS5_VABI sceHttpSetCookieEnabled(int id, int enable) {
(void)id;
if (static_cast<uint32_t>(enable) > 1) return ERROR_INVALID_VALUE;
if (enable != 0) NotImplemented_nid_no_patch(__func__);
return 0;
}

int APS5_VABI sceHttpSetAutoRedirect(int id, int enable) {
(void)id;
(void)enable;
Expand Down
10 changes: 10 additions & 0 deletions core/libs/prx/libSceNpEntitlementAccess/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,16 @@ int APS5_VABI sceNpEntitlementAccessGetSkuFlag(uint32_t* sku_flag) {
return 0;
}

int APS5_VABI sceNpEntitlementAccessGetEntitlementKey(
uint32_t serviceLabel, const NpUnifiedEntitlementLabel* entitlementLabel,
NpEntitlementAccessEntitlementKey* key) {
(void)serviceLabel;
constexpr int errorParameter = static_cast<int>(0x817D0002);
constexpr int errorNoEntitlement = static_cast<int>(0x817D0007);
if (!entitlementLabel || !key) return errorParameter;
return errorNoEntitlement;
}

int APS5_VABI sceNpEntitlementAccessInitialize(const NpEntitlementAccessInitParam* init_param, NpEntitlementAccessBootParam* boot_param) {
(void)init_param;
(void)boot_param;
Expand Down
7 changes: 7 additions & 0 deletions core/libs/prx/libSceRudp/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ int APS5_VABI sceRudpActivate() {
return 0;
}

int APS5_VABI sceRudpGetStatus(void* status, std::size_t size) {
(void)status;
(void)size;
NotImplemented_nid_no_patch(__func__);
return 0;
}

int APS5_VABI sceRudpEnd(int ctx_id) {
std::lock_guard<std::mutex> lk(g_mutex);
if (!g_inited) {
Expand Down
79 changes: 79 additions & 0 deletions core/libs/tests/GuestOfflineImports.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
#include "SceTypes.hpp"

#include <array>
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <string_view>

extern "C" {
int APS5_VABI sceHttpSetCookieEnabled(int, int);
int APS5_VABI sceHttpSendRequest(int, const void*, std::size_t);
int APS5_VABI sceNpEntitlementAccessGetEntitlementKey(
std::uint32_t, const NpUnifiedEntitlementLabel*, NpEntitlementAccessEntitlementKey*);
int APS5_VABI sceRudpInit_nid_postfix(void*, int);
int APS5_VABI sceRudpGetStatus(void*, std::size_t);
int APS5_VABI sceRudpTerminate();
}

static void Require(bool value) { if (!value) std::abort(); }

int main() {
constexpr int invalidValue = static_cast<int>(0x804311FE);
constexpr int network = static_cast<int>(0x80431063);
Require(sceHttpSetCookieEnabled(1, 0) == 0);
Require(sceHttpSendRequest(1, nullptr, 0) == network);
bool cookieUnsupported = false;
try {
sceHttpSetCookieEnabled(1, 1);
} catch (const std::runtime_error& error) {
cookieUnsupported = std::string_view(error.what()) == "sceHttpSetCookieEnabled not implemented";
}
Require(cookieUnsupported);
for (int enabled : {-1, 2, 0x100}) {
Require(sceHttpSetCookieEnabled(1, enabled) == invalidValue);
}

constexpr int parameter = static_cast<int>(0x817D0002);
constexpr int noEntitlement = static_cast<int>(0x817D0007);
static_assert(sizeof(NpEntitlementAccessEntitlementKey) == 16);
NpUnifiedEntitlementLabel label{};
std::memcpy(label.data, "unowned-addon", 14);
struct KeyBuffer {
std::uint64_t before;
NpEntitlementAccessEntitlementKey key;
std::uint64_t after;
} output;
std::memset(&output, 0xa5, sizeof(output));
std::array<unsigned char, sizeof(output)> original{};
std::memcpy(original.data(), &output, sizeof(output));
Require(sceNpEntitlementAccessGetEntitlementKey(0, nullptr, &output.key) == parameter);
Require(sceNpEntitlementAccessGetEntitlementKey(0, &label, nullptr) == parameter);
Require(sceNpEntitlementAccessGetEntitlementKey(0, nullptr, nullptr) == parameter);
for (std::uint32_t serviceLabel : {0u, 1u, 0xffffffffu}) {
Require(sceNpEntitlementAccessGetEntitlementKey(serviceLabel, &label, &output.key) == noEntitlement);
Require(std::memcmp(&output, original.data(), sizeof(output)) == 0);
}

std::array<unsigned char, 248> status;
status.fill(0x5a);
const auto originalStatus = status;
auto unsupported = [](void* data, std::size_t size) {
try {
sceRudpGetStatus(data, size);
} catch (const std::runtime_error& error) {
return std::string_view(error.what()) == "sceRudpGetStatus not implemented";
}
return false;
};
Require(unsupported(status.data(), status.size()));
Require(status == originalStatus);
Require(sceRudpInit_nid_postfix(nullptr, 0) == 0);
Require(unsupported(status.data(), status.size()));
Require(status == originalStatus);
Require(unsupported(nullptr, 0));
Require(sceRudpTerminate() == 0);
return 0;
}
4 changes: 4 additions & 0 deletions docs/dev/TechnicalDebt.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ Throughout the project, every function at every stage either **does exactly what

### Unknown function info

- [sceNpEntitlementAccessGetEntitlementKey](../../core/libs/prx/libSceNpEntitlementAccess/Export.cpp) - the three-argument signature, 16-byte key and errors `0x817D0002`/`0x817D0007` follow [KytyPS5](https://github.com/KytyPS5/KytyPS5/blob/main/src/libs/libNet.cpp); PPSA01521 passes a service label, entitlement label and output pointer. Only the no-key path is implemented: local entitlement labels carry no keys, and the output is untouched on failure. Console error precedence and key provisioning are unverified
- [sceRudpGetStatus](../../core/libs/prx/libSceRudp/Export.cpp) - PPSA01521 passes an output pointer and byte count `0xF8`; the status layout, size rules and error behavior are unknown. The export throws without writing output, including after initialization. [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/rudp/rudp.cpp) declares it without arguments and returns success without writing status
- [sceHttpSetCookieEnabled](../../core/libs/prx/libSceHttp/Export.cpp) - the two-argument signature and 0/1 enable values follow [VitaSDK](https://github.com/vitasdk/vita-headers/blob/master/include/psp2/net/http.h) and [shadPS4](https://github.com/shadps4-emu/shadPS4/blob/main/src/core/libraries/network/http.cpp); PPSA01521 passes 0 to disable cookies. Disabling succeeds because the offline HTTP backend has no cookie engine; enabling throws. Invalid enable values use the same error as `sceHttpSetInflateGZIPEnabled`. Like the existing offline HTTP setters, the handle is not validated; requests still fail with the network error. Console behavior is unverified

- [sceHmd2Initialize](../../core/libs/prx/libSceHmd2/Export.cpp) (libSceHmd2) - the error the console returns when the PS VR2 runtime is unavailable is unknown; it returns libSceHmd's `UNSUPPORTED_FEATURE` (0x81110016). PPSA01317 passes a pointer to 16 zeroed bytes and only tests the result for non-zero
- PPSA01317 imports declared without parameters, signatures unknown: the remaining [libSceHmd2](../../core/libs/prx/libSceHmd2/Export.cpp) and [libSceVrTracker2](../../core/libs/prx/libSceVrTracker2/Export.cpp) exports. Names from the aerolib NID list
- [libSceMbus](../../core/libs/prx/libSceMbus/Export.cpp) (`libSceDeviceService`) - signatures taken from PPSA01317, which calls `sceDeviceServiceInitialize(3, 0)`, polls `sceDeviceServiceGetEventState(1)` and queries again when bit 0 or 1 is set, and calls `sceDeviceServiceQueryDeviceInfo_(0x7001, 0, 0, infos, 1, &count, &unknown, 0x70)`, treating a negative result as an error and `count` as the number of entries. The host has no devices: the event state is 0 and a query returns 0 with `count` 0
Expand Down
Loading