Skip to content
Closed
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
3 changes: 2 additions & 1 deletion core/libs/prx/libSceWebBrowserDialog/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ configure_windows_unwind(libSceWebBrowserDialog)
if(BUILD_TESTING)
add_test_executable(guest_web_browser_dialog_tests ${LIBS_INCLUDE_DIR}/tests/GuestWebBrowserDialog.cpp)
target_include_directories(guest_web_browser_dialog_tests PRIVATE ${LIBS_INCLUDE_DIR})
target_link_libraries(guest_web_browser_dialog_tests PRIVATE libSceWebBrowserDialog)
target_link_libraries(guest_web_browser_dialog_tests PRIVATE libSceWebBrowserDialog libc)
configure_windows_unwind(guest_web_browser_dialog_tests)
add_test(NAME guest_web_browser_dialog COMMAND guest_web_browser_dialog_tests)
if(WIN32)
set_tests_properties(guest_web_browser_dialog PROPERTIES ENVIRONMENT_MODIFICATION
Expand Down
18 changes: 16 additions & 2 deletions core/libs/prx/libSceWebBrowserDialog/Export.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ constexpr int COMMON_DIALOG_ERROR_NOT_INITIALIZED = static_cast<int>(0x80B80003u
constexpr int COMMON_DIALOG_ERROR_NOT_FINISHED = static_cast<int>(0x80B80005u);
constexpr int COMMON_DIALOG_ERROR_BUSY = static_cast<int>(0x80B80007u);
constexpr int COMMON_DIALOG_ERROR_ARG_NULL = static_cast<int>(0x80B8000Du);

struct PredeterminedContentParam {
std::uint64_t size;
const char* domain[20];
std::uint8_t reserved[256];
};
static_assert(sizeof(PredeterminedContentParam) == 424);
}

extern "C" {
Expand Down Expand Up @@ -71,8 +78,15 @@ int APS5_VABI sceWebBrowserDialogSetCookie(void) {
return 0;
}

int APS5_VABI sceWebBrowserDialogOpenForPredeterminedContent() {
NotImplemented_nid_no_patch(__func__);
int APS5_VABI sceWebBrowserDialogOpenForPredeterminedContent(const void* param, const void* contentParam) {
const int status = g_status.load();
if (status == COMMON_DIALOG_STATUS_NONE) return COMMON_DIALOG_ERROR_NOT_INITIALIZED;
if (status == COMMON_DIALOG_STATUS_RUNNING) return COMMON_DIALOG_ERROR_BUSY;
if (param == nullptr) return COMMON_DIALOG_ERROR_ARG_NULL;
if (contentParam == nullptr) throw std::invalid_argument("sceWebBrowserDialogOpenForPredeterminedContent: null predetermined content parameter");
if (static_cast<const PredeterminedContentParam*>(contentParam)->size != sizeof(PredeterminedContentParam))
throw std::invalid_argument("sceWebBrowserDialogOpenForPredeterminedContent: unexpected predetermined content parameter size");
g_status = COMMON_DIALOG_STATUS_FINISHED;
return 0;
}

Expand Down
42 changes: 42 additions & 0 deletions core/libs/tests/GuestWebBrowserDialog.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstdint>
#include <cstdlib>
#include <stdexcept>

extern "C" {
int APS5_VABI sceWebBrowserDialogInitialize(void);
Expand All @@ -10,6 +11,7 @@ int APS5_VABI sceWebBrowserDialogClose(void);
int APS5_VABI sceWebBrowserDialogGetStatus(void);
int APS5_VABI sceWebBrowserDialogUpdateStatus(void);
int APS5_VABI sceWebBrowserDialogGetResult(void* result);
int APS5_VABI sceWebBrowserDialogOpenForPredeterminedContent(const void* param, const void* contentParam);
}

namespace {
Expand All @@ -24,6 +26,45 @@ constexpr int COMMON_DIALOG_ERROR_ARG_NULL = static_cast<int>(0x80B8000Du);

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

struct PredeterminedContentParam {
std::uint64_t size;
const char* domain[20];
std::uint8_t reserved[256];
};
static_assert(sizeof(PredeterminedContentParam) == 424);

template <typename TAction>
bool ThrowsInvalidArgument(TAction action) {
try {
action();
} catch (const std::invalid_argument&) {
return true;
}
return false;
}

void CheckPredeterminedContent(std::uint8_t* param) {
PredeterminedContentParam content{};
content.size = sizeof(content);
content.domain[0] = "https://example.com";
std::int32_t result = 0x5a5a5a5a;

Require(sceWebBrowserDialogOpenForPredeterminedContent(param, &content) == COMMON_DIALOG_ERROR_NOT_INITIALIZED);
Require(sceWebBrowserDialogInitialize() == 0);
Require(sceWebBrowserDialogOpenForPredeterminedContent(nullptr, &content) == COMMON_DIALOG_ERROR_ARG_NULL);
Require(ThrowsInvalidArgument([&] { sceWebBrowserDialogOpenForPredeterminedContent(param, nullptr); }));
content.size = sizeof(content) - 8;
Require(ThrowsInvalidArgument([&] { sceWebBrowserDialogOpenForPredeterminedContent(param, &content); }));
Require(sceWebBrowserDialogGetStatus() == COMMON_DIALOG_STATUS_INITIALIZED);
content.size = sizeof(content);
Require(sceWebBrowserDialogOpenForPredeterminedContent(param, &content) == 0);
Require(sceWebBrowserDialogGetStatus() == COMMON_DIALOG_STATUS_FINISHED);
Require(sceWebBrowserDialogGetResult(&result) == 0 && result == COMMON_DIALOG_RESULT_USER_CANCELED);
Require(sceWebBrowserDialogOpenForPredeterminedContent(param, &content) == 0);
Require(sceWebBrowserDialogTerminate() == 0);
Require(sceWebBrowserDialogGetStatus() == COMMON_DIALOG_STATUS_NONE);
}

}

int main() {
Expand Down Expand Up @@ -59,5 +100,6 @@ int main() {
Require(sceWebBrowserDialogTerminate() == 0);
Require(sceWebBrowserDialogGetStatus() == COMMON_DIALOG_STATUS_NONE);

CheckPredeterminedContent(param);
return 0;
}
5 changes: 5 additions & 0 deletions docs/dev/debt/libSceWebBrowserDialog.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# libSceWebBrowserDialog technical debt

### Unknown function info

- [sceWebBrowserDialogOpenForPredeterminedContent](../../../core/libs/prx/libSceWebBrowserDialog/Export.cpp) (libSceWebBrowserDialog) - the `(param, predeterminedContentParam)` signature and the 424-byte predetermined content parameter (a 64-bit size, 20 allowed domain pointers and 256 reserved bytes) follow SharpProspero's [parameter layout](https://github.com/SvenGDK/SharpProspero/blob/5dfdb4b0b166e83dc9ae275001afb695f12c7174/src/SharpProspero/Interop/Dialog/WebBrowserDialog.cs#L138-L155) and [import](https://github.com/SvenGDK/SharpProspero/blob/5dfdb4b0b166e83dc9ae275001afb695f12c7174/src/SharpProspero/Interop/Dialog/WebBrowserDialog.cs#L246-L254); the PS5 behaviour is unverified. It answers as `sceWebBrowserDialogOpen`: `NOT_INITIALIZED` before `sceWebBrowserDialogInitialize`, `BUSY` while running and `ARG_NULL` for a null dialog parameter, and otherwise finishes at once with the user-cancelled result, since there is no browser to show. A null predetermined content parameter or a size other than 424 throws, as its error code is unknown, and the allowed domains are not read
Loading