diff --git a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp index 497b8cd32b..67b2d4c3e9 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp +++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.cpp @@ -244,6 +244,14 @@ void fmt_class_string::format(std::string& out, u64 fmt::append(out, "%s", sign.data); } +template <> +void fmt_class_string::format(std::string& out, u64 arg) +{ + const auto& id = get_object(arg); + + fmt::append(out, "{ data='%s', term='%s' (0x%x), num=%d, dummy=%d }", id.data, std::isprint(id.data[9]) ? fmt::format("%c", id.data[9]) : "", id.data[9], id.num, id.dummy); +} + // Helpers static error_code NpTrophyGetTrophyInfo(const trophy_context_t* ctxt, s32 trophyId, SceNpTrophyDetails* details, SceNpTrophyData* data); @@ -442,27 +450,48 @@ error_code sceNpTrophyCreateContext(vm::ptr context, vm::cptrnum > 99) + const s32 comm_num = commId->num; + if (comm_num > 99) { return SCE_NP_TROPHY_ERROR_INVALID_NP_COMM_ID; } // NOTE: commId->term is unused in our code (at least until someone finds out if we need to account for it) - // generate trophy context name, limited to 9 characters - std::string_view name_sv(commId->data, 9); + // Generate trophy context name, limited to 9 characters + // Read once for thread-safety reasons + std::string name_str(commId->data, 9); // resize the name if it was shorter than expected - if (const auto pos = name_sv.find_first_of('\0'); pos != std::string_view::npos) + if (const auto pos = name_str.find_first_of('\0'); pos != std::string_view::npos) { - name_sv = name_sv.substr(0, pos); + name_str = name_str.substr(0, pos); } - sceNpTrophy.warning("sceNpTrophyCreateContext(): data='%s' term=0x%x (0x%x) num=%d", name_sv, commId->data[9], commId->data[9], commId->num); + const SceNpCommunicationSignature commSign_data = *commSign; + + if (read_from_ptr>(commSign_data.data, 0) != NP_TROPHY_COMM_SIGN_MAGIC) + { + return SCE_NP_TROPHY_ERROR_INVALID_NP_COMM_ID; + } + + if (std::basic_string_view(&commSign_data.data[6], 6).find_first_not_of('\0') != umax) + { + // 6 padding bytes - must be 0 + return SCE_NP_TROPHY_ERROR_INVALID_NP_COMM_ID; + } + + if (read_from_ptr>(commSign_data.data, 4) != 0x100) + { + // Signifies version (1.00), although only one constant is allowed + return SCE_NP_TROPHY_ERROR_INVALID_NP_COMM_ID; + } // append the commId number as "_xx" - std::string name = fmt::format("%s_%02d", name_sv, commId->num); + std::string name = fmt::format("%s_%02d", name_str, comm_num); // create trophy context const auto ctxt = idm::make_ptr(); diff --git a/rpcs3/Emu/Cell/Modules/sceNpTrophy.h b/rpcs3/Emu/Cell/Modules/sceNpTrophy.h index 0f3cc729cb..565f7d0b5d 100644 --- a/rpcs3/Emu/Cell/Modules/sceNpTrophy.h +++ b/rpcs3/Emu/Cell/Modules/sceNpTrophy.h @@ -151,6 +151,11 @@ enum SCE_NP_TROPHY_STATUS_CHANGES_DETECTED = 9, }; +enum : u32 +{ + NP_TROPHY_COMM_SIGN_MAGIC = 0xB9DDE13B, +}; + using SceNpTrophyStatusCallback = s32(u32 context, u32 status, s32 completed, s32 total, vm::ptr arg); // Forward declare this function since trophyunlock needs it