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
7 changes: 4 additions & 3 deletions core/libs/prx/libSceNpEntitlementAccess/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ static constexpr int SCE_NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER = static_cast<int
static constexpr int SCE_NP_ENTITLEMENT_ACCESS_ERROR_NOT_FOUND = static_cast<int>(0x80558007);
static constexpr int SCE_NP_ERROR_SIGNED_OUT = static_cast<int>(0x80550006);
static constexpr uint32_t SKU_FLAG_FULL = 3;
static constexpr std::int32_t USER_ID_INVALID = -1;

namespace {

Expand Down Expand Up @@ -198,9 +199,9 @@ int APS5_VABI sceNpEntitlementAccessRequestUnifiedEntitlementInfoList(std::int32
return SCE_NP_ERROR_SIGNED_OUT;
}

int APS5_VABI sceNpEntitlementAccessGetAddcontEntitlementInfoIndividual() {
NotImplemented_nid_no_patch(__func__);
return 0;
int APS5_VABI sceNpEntitlementAccessGetAddcontEntitlementInfoIndividual(std::int32_t user_id, uint32_t service_label, const NpUnifiedEntitlementLabel* entitlement_label, NpEntitlementAccessAddcontEntitlementInfo* info) {
if (user_id == USER_ID_INVALID) return SCE_NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
return sceNpEntitlementAccessGetAddcontEntitlementInfo(service_label, entitlement_label, info);
}

int APS5_VABI sceNpEntitlementAccessPollConsumableEntitlementInfo() {
Expand Down
2 changes: 1 addition & 1 deletion core/libs/prx/libSceNpEntitlementAccess/include/Api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ int APS5_VABI sceNpEntitlementAccessPollServiceEntitlementInfoList(std::int64_t
int APS5_VABI sceNpEntitlementAccessPollUnifiedEntitlementInfoList(std::int64_t requestId, std::int32_t* result, NpEntitlementAccessUnifiedInfo* infos, std::uint32_t capacity, std::int32_t* firstResult, std::int32_t* secondResult, std::int32_t* thirdResult);
int APS5_VABI sceNpEntitlementAccessRequestServiceEntitlementInfoList(std::int32_t userId, std::uint32_t serviceLabel, const NpServiceEntitlementLabel* entitlementLabels, std::uint32_t labelCount, const NpEntitlementAccessListParameter* parameter, std::int64_t* requestId);
int APS5_VABI sceNpEntitlementAccessRequestUnifiedEntitlementInfoList(std::int32_t userId, std::uint32_t serviceLabel, const NpUnifiedEntitlementLabel* entitlementLabels, std::uint32_t labelCount, const NpEntitlementAccessListParameter* parameter, std::int64_t* requestId);
int APS5_VABI sceNpEntitlementAccessGetAddcontEntitlementInfoIndividual();
int APS5_VABI sceNpEntitlementAccessGetAddcontEntitlementInfoIndividual(std::int32_t userId, uint32_t serviceLabel, const NpUnifiedEntitlementLabel* entitlementLabel, NpEntitlementAccessAddcontEntitlementInfo* info);
int APS5_VABI sceNpEntitlementAccessPollConsumableEntitlementInfo();
int APS5_VABI sceNpEntitlementAccessRequestConsumableEntitlementInfo();
int APS5_VABI sceNpEntitlementAccessRequestConsumeEntitlement();
Expand Down
27 changes: 27 additions & 0 deletions core/libs/tests/GuestEntitlements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,33 @@ int main(int argc, char** argv) {
NpEntitlementAccessAddcontEntitlementInfo info{};
Require(sceNpEntitlementAccessGetAddcontEntitlementInfo(0, &label, &info) == 0);
Require(std::strcmp(info.entitlement_label.data, "SECONDADDON") == 0 && info.package_type == 3 && info.download_status == 4);
for (std::int32_t userId : {1, 0x10000000, std::numeric_limits<std::int32_t>::min()}) {
NpEntitlementAccessAddcontEntitlementInfo individual{};
Require(sceNpEntitlementAccessGetAddcontEntitlementInfoIndividual(userId, 0, &label, &individual) == 0);
Require(std::memcmp(&individual, &info, sizeof(info)) == 0);
}
NpEntitlementAccessAddcontEntitlementInfo untouched{};
std::memset(&untouched, 0x5a, sizeof(untouched));
const auto original = untouched;
NpUnifiedEntitlementLabel unlisted{};
std::memcpy(unlisted.data, "UNLISTEDADDON", 13);
Require(sceNpEntitlementAccessGetAddcontEntitlementInfoIndividual(1, 0, &unlisted, &untouched) == static_cast<int>(0x80558007));
Require(sceNpEntitlementAccessGetAddcontEntitlementInfoIndividual(-1, 0, &label, &untouched) == static_cast<int>(0x80558003));
Require(sceNpEntitlementAccessGetAddcontEntitlementInfoIndividual(-1, 0, nullptr, nullptr) == static_cast<int>(0x80558003));
Require(std::memcmp(&untouched, &original, sizeof(original)) == 0);
Require(sceNpEntitlementAccessGetAddcontEntitlementInfoIndividual(1, 0, nullptr, &untouched) == static_cast<int>(0x80558003));
Require(sceNpEntitlementAccessGetAddcontEntitlementInfoIndividual(1, 0, &label, nullptr) == static_cast<int>(0x80558003));
NpUnifiedEntitlementLabel empty{};
Require(sceNpEntitlementAccessGetAddcontEntitlementInfoIndividual(1, 0, &empty, &untouched) == static_cast<int>(0x80558007));
NpUnifiedEntitlementLabel unterminated{};
std::memset(unterminated.data, 'A', sizeof(unterminated.data));
Require(sceNpEntitlementAccessGetAddcontEntitlementInfoIndividual(1, 0, &unterminated, &untouched) == static_cast<int>(0x80558007));
Require(std::memcmp(&untouched, &original, sizeof(original)) == 0);
auto padded = label;
std::memset(padded.padding, 0x5a, sizeof(padded.padding));
NpEntitlementAccessAddcontEntitlementInfo paddedInfo{};
Require(sceNpEntitlementAccessGetAddcontEntitlementInfoIndividual(1, 0, &padded, &paddedInfo) == 0);
Require(std::memcmp(&paddedInfo, &info, sizeof(info)) == 0);
NpEntitlementAccessEntitlementKey key{};
Require(sceNpEntitlementAccessGetEntitlementKey(0, nullptr, &key) == static_cast<int>(0x817D0002));
Require(sceNpEntitlementAccessGetEntitlementKey(0, &label, nullptr) == static_cast<int>(0x817D0002));
Expand Down
3 changes: 2 additions & 1 deletion docs/dev/debt/libSceNpEntitlementAccess.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@

### Unknown function info

- [sceNpEntitlementAccessGetAddcontEntitlementInfoIndividual, sceNpEntitlementAccessPollConsumableEntitlementInfo, sceNpEntitlementAccessRequestConsumableEntitlementInfo, sceNpEntitlementAccessRequestConsumeEntitlement](../../../core/libs/prx/libSceNpEntitlementAccess/Export.cpp) (libSceNpEntitlementAccess) - their names and NIDs are in the [PS5 3.20 export inventory](https://github.com/DNNDHH/PS5-3.20_Libs/blob/b2a77c09cd71c01f34c790cfbe98c751a13262ad/libSceNpEntitlementAccess.c), but no credible prototypes were found. They are declared without parameters solely to resolve known imports; this is not an ABI claim
- [sceNpEntitlementAccessGetAddcontEntitlementInfoIndividual](../../../core/libs/prx/libSceNpEntitlementAccess/Export.cpp) - the prototype is not from the SDK and no title call site was read: the user ID, service label, entitlement label and info follow the runtime declaration of [dlc_emu](https://github.com/drakmor/dlc_emu/blob/fcf69b16d46a/src/dlc_modules/scenpentitlementaccess_exports.cpp#L102-L115), a replacement module. The user ID is not checked against the signed-in users: only `-1` returns the parameter error `0x80558003`, before the null checks, as in dlc_emu; any other ID gets the result of `sceNpEntitlementAccessGetAddcontEntitlementInfo`, which ignores the service label and the initialization state and returns `0x80558007` for an unlisted label where dlc_emu returns its no-entitlement error. dlc_emu also returns the parameter error for an empty or unterminated label or nonzero padding; here the first two give `0x80558007` and padding is ignored. None of this is measured
- [sceNpEntitlementAccessPollConsumableEntitlementInfo, sceNpEntitlementAccessRequestConsumableEntitlementInfo, sceNpEntitlementAccessRequestConsumeEntitlement](../../../core/libs/prx/libSceNpEntitlementAccess/Export.cpp) (libSceNpEntitlementAccess) - their names and NIDs come from the export inventory cited by [the entry on main](https://github.com/boykopovar/AnyPS5/blob/ed1e0ed08fc2/docs/dev/debt/libSceNpEntitlementAccess.md#L11), but no credible prototypes were found. They are declared without parameters solely to resolve known imports; this is not an ABI claim
- [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. PPSA03984 01.020.000 (at 0x5949837) and PPSA30839 01.003.000 (0x4505EC5), disassembled for this entry, pass service label 0, a pointer into an array of their own with 28-byte elements and a stack output, one call per element in a loop; after a failure (a negative result in PPSA03984, any nonzero one in PPSA30839) they go on with the next element, and on success PPSA03984 reads 16 bytes of the output
- [Entitlement requests and polls](../../../core/libs/prx/libSceNpEntitlementAccess/Export.cpp): native argument lists are restored for single-item, list and consume operations, plus abort/delete. Request IDs are 64-bit, labels occupy 20 bytes and transaction IDs occupy 72 bytes. List options occupy 32 bytes and results have a 64-byte stride; their field semantics and three list-result scalars remain unresolved. The existing signed-out responses do not reproduce native initialization, validation or asynchronous request handling; no request can be created while signed out, so the library keeps no request table.

Expand Down
Loading