mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-28 12:05:06 +00:00
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01RoucYS7mQpV23WDUEwXLuU
154 lines
7.4 KiB
C++
154 lines
7.4 KiB
C++
#include "prx/libSceInvitationDialog/include/Api.hpp"
|
|
#include "prx/libSceCommonDialog/include/Api.hpp"
|
|
#include "prx/libSceCommonDialog/include/DialogUse.hpp"
|
|
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <stdexcept>
|
|
#include <string>
|
|
|
|
namespace {
|
|
|
|
constexpr int StatusNone = 0;
|
|
constexpr int StatusInitialized = 1;
|
|
constexpr int StatusFinished = 3;
|
|
constexpr int NotSystemInitialized = static_cast<int>(0x80B80001u);
|
|
constexpr int NotInitialized = static_cast<int>(0x80B80003u);
|
|
constexpr int AlreadyInitialized = static_cast<int>(0x80B80004u);
|
|
constexpr int NotFinished = static_cast<int>(0x80B80005u);
|
|
constexpr int Busy = static_cast<int>(0x80B80008u);
|
|
constexpr int ArgNull = static_cast<int>(0x80B8000Du);
|
|
constexpr std::int32_t ResultUserCanceled = 1;
|
|
constexpr std::int32_t ModeSend = 1;
|
|
constexpr std::int32_t ModeRecv = 2;
|
|
|
|
void Require(bool condition, const char* message) {
|
|
if (!condition) {
|
|
std::fprintf(stderr, "InvitationDialog: %s\n", message);
|
|
std::abort();
|
|
}
|
|
}
|
|
|
|
template <typename TCall>
|
|
void RequireUnsettled(TCall call, const char* message) {
|
|
bool threw = false;
|
|
try {
|
|
call();
|
|
} catch (const std::runtime_error& error) {
|
|
threw = std::string(error.what()).find("not implemented") == std::string::npos;
|
|
}
|
|
Require(threw, message);
|
|
}
|
|
|
|
InvitationDialogParam MakeParam(std::int32_t mode, void* callbackArg) {
|
|
InvitationDialogParam param{};
|
|
param.baseParam.size = sizeof(CommonDialogBaseParam);
|
|
param.size = sizeof(InvitationDialogParam);
|
|
param.mode = mode;
|
|
param.userId = 0x10000000;
|
|
param.callbackArg = callbackArg;
|
|
return param;
|
|
}
|
|
|
|
void TestBeforeInitialize() {
|
|
InvitationDialogResult result{};
|
|
Require(sceInvitationDialogUpdateStatus() == StatusNone, "status before initialization");
|
|
Require(sceInvitationDialogGetResult(&result) == NotInitialized, "result before initialization");
|
|
Require(sceInvitationDialogGetResult(nullptr) == NotInitialized, "null result before initialization");
|
|
Require(sceInvitationDialogClose() == NotInitialized, "close before initialization");
|
|
Require(sceInvitationDialogTerminate() == NotInitialized, "terminate before initialization");
|
|
const InvitationDialogParam param = MakeParam(ModeSend, nullptr);
|
|
RequireUnsettled([&] { sceInvitationDialogOpen(¶m); }, "open before initialization");
|
|
}
|
|
|
|
void TestCommonDialogPreconditions() {
|
|
Require(sceInvitationDialogInitialize() == NotSystemInitialized, "initialize before sceCommonDialogInitialize");
|
|
Require(sceInvitationDialogUpdateStatus() == StatusNone && !sceCommonDialogIsUsed(), "a failed initialization leaves no state");
|
|
Require(sceCommonDialogInitialize() == 0, "initialize the common dialog system");
|
|
|
|
Require(CommonDialogAcquire_nid_no_patch(), "another common dialog takes the system");
|
|
Require(sceInvitationDialogInitialize() == Busy, "initialize while another common dialog is in use");
|
|
Require(sceInvitationDialogUpdateStatus() == StatusNone, "a busy initialization leaves the status");
|
|
CommonDialogRelease_nid_no_patch();
|
|
|
|
Require(sceInvitationDialogInitialize() == 0 && sceCommonDialogIsUsed(), "the dialog takes the system");
|
|
Require(!CommonDialogAcquire_nid_no_patch(), "another common dialog is busy while this one is initialized");
|
|
Require(sceInvitationDialogTerminate() == 0 && !sceCommonDialogIsUsed(), "termination frees the system");
|
|
}
|
|
|
|
void TestOpenChecks() {
|
|
InvitationDialogResult result{};
|
|
Require(sceInvitationDialogInitialize() == 0, "initialize");
|
|
Require(sceInvitationDialogInitialize() == AlreadyInitialized, "initialize twice");
|
|
Require(sceCommonDialogIsUsed(), "the system stays in use after a repeated initialization");
|
|
Require(sceInvitationDialogUpdateStatus() == StatusInitialized, "status after initialization");
|
|
Require(sceInvitationDialogGetResult(&result) == NotFinished, "result before the dialog opened");
|
|
Require(sceInvitationDialogGetResult(nullptr) == NotFinished, "null result before the dialog finished");
|
|
RequireUnsettled([] { sceInvitationDialogClose(); }, "close of a dialog that is not running");
|
|
|
|
Require(sceInvitationDialogOpen(nullptr) == ArgNull, "open without a param");
|
|
InvitationDialogParam param = MakeParam(ModeSend, nullptr);
|
|
param.size = sizeof(InvitationDialogParam) - 8;
|
|
RequireUnsettled([&] { sceInvitationDialogOpen(¶m); }, "open with another param size");
|
|
param = MakeParam(0, nullptr);
|
|
RequireUnsettled([&] { sceInvitationDialogOpen(¶m); }, "open in the invalid mode");
|
|
param = MakeParam(3, nullptr);
|
|
RequireUnsettled([&] { sceInvitationDialogOpen(¶m); }, "open in an unknown mode");
|
|
Require(sceInvitationDialogUpdateStatus() == StatusInitialized, "a rejected open leaves the status");
|
|
}
|
|
|
|
void TestCanceled() {
|
|
int first = 0;
|
|
int second = 0;
|
|
const InvitationDialogParam send = MakeParam(ModeSend, &first);
|
|
Require(sceInvitationDialogOpen(&send) == 0, "open to send");
|
|
Require(sceInvitationDialogUpdateStatus() == StatusFinished, "the dialog finishes at once");
|
|
RequireUnsettled([] { sceInvitationDialogClose(); }, "close of a finished dialog");
|
|
|
|
Require(sceInvitationDialogGetResult(nullptr) == ArgNull, "null result after the dialog finished");
|
|
InvitationDialogResult result{};
|
|
result.reserved[31] = 1;
|
|
RequireUnsettled([&] { sceInvitationDialogGetResult(&result); }, "result with a non-zero reserved byte");
|
|
|
|
InvitationDialogRecipients recipients{};
|
|
recipients.count = 5;
|
|
std::memset(recipients.onlineIds, 'x', sizeof(recipients.onlineIds));
|
|
result = InvitationDialogResult{};
|
|
result.errorCode = 7;
|
|
result.result = 7;
|
|
result.recipients = &recipients;
|
|
Require(sceInvitationDialogGetResult(&result) == 0, "result of the canceled dialog");
|
|
Require(result.callbackArg == &first, "the result carries the callback argument");
|
|
Require(result.errorCode == 0 && result.result == ResultUserCanceled, "the user canceled");
|
|
Require(result.recipients == &recipients && recipients.count == 0, "no invitation was sent");
|
|
Require(recipients.onlineIds[0].data[0] == 'x' && recipients.onlineIds[15].pad[2] == 'x', "the online ids are left alone");
|
|
for (const std::uint8_t value : result.reserved) Require(value == 0, "the reserved bytes stay zero");
|
|
|
|
result = InvitationDialogResult{};
|
|
Require(sceInvitationDialogGetResult(&result) == 0 && result.recipients == nullptr, "result without a recipient list");
|
|
|
|
const InvitationDialogParam receive = MakeParam(ModeRecv, &second);
|
|
Require(sceInvitationDialogOpen(&receive) == 0, "open again to receive");
|
|
result = InvitationDialogResult{};
|
|
Require(sceInvitationDialogGetResult(&result) == 0 && result.callbackArg == &second, "the second open carries its own callback argument");
|
|
|
|
Require(sceInvitationDialogTerminate() == 0 && !sceCommonDialogIsUsed(), "terminate");
|
|
Require(sceInvitationDialogUpdateStatus() == StatusNone, "status after termination");
|
|
Require(sceInvitationDialogGetResult(&result) == NotInitialized, "result after termination");
|
|
Require(sceInvitationDialogInitialize() == 0 && sceInvitationDialogGetResult(&result) == NotFinished, "a new initialization forgets the result");
|
|
Require(sceInvitationDialogTerminate() == 0, "terminate again");
|
|
}
|
|
|
|
}
|
|
|
|
int main() {
|
|
TestBeforeInitialize();
|
|
TestCommonDialogPreconditions();
|
|
TestOpenChecks();
|
|
TestCanceled();
|
|
return 0;
|
|
}
|