#include "prx/libSceCamera/libSceCamera.hpp" #include "prx/libSceCamera/include/Camera.hpp" #include "prx/libc/include/general/VabiMacros.hpp" #include #include #include #include #include #include #include #include namespace { constexpr int ErrorParam = static_cast(0x8A760000); constexpr int ErrorNotInit = static_cast(0x8A760002); constexpr int ErrorCameraOpen = static_cast(0x8A760015); using NoArgumentFn = int (APS5_VABI*)(); using HandleFn = int (APS5_VABI*)(std::int32_t); using OpenFn = int (APS5_VABI*)(std::int32_t, std::int32_t, std::int32_t, void*); void Require(bool condition, const char* message) { if (condition) return; std::fprintf(stderr, "Camera2: %s\n", message); std::abort(); } template Function As(Export function) { return reinterpret_cast(function); } bool InitializeThrows(NoArgumentFn initialize) { try { initialize(); } catch (const std::runtime_error&) { return true; } return false; } } int main() { const auto original = std::filesystem::current_path(); const auto directory = original / ("camera2-test-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count())); Require(std::filesystem::create_directory(directory), "the test directory could not be created"); std::filesystem::current_path(directory); std::filesystem::create_directories("app0/sce_sys"); { std::ofstream param("app0/sce_sys/param.json", std::ios::binary); param << R"({"titleId":"PPSA00000","localizedParameters":{"en-US":{"titleName":"Example"}}})"; Require(static_cast(param), "param.json could not be written"); } const auto initialize = As(&sceCamera2Initialize); const auto finalize = As(&sceCamera2Finalize); const auto open = As(&sceCamera2Open); const auto isAttached = As(&sceCamera2IsAttached); const HandleFn handleCalls[] = { As(&sceCamera2Close), As(&sceCamera2GetAttribute), As(&sceCamera2SetAttribute), As(&sceCamera2GetAutoExposureGain), As(&sceCamera2SetAutoExposureGain), As(&sceCamera2GetAutoWhiteBalance), As(&sceCamera2SetAutoWhiteBalance), As(&sceCamera2GetConfig), As(&sceCamera2SetConfig), As(&sceCamera2GetContrast), As(&sceCamera2SetContrast), As(&sceCamera2GetExposureGain), As(&sceCamera2SetExposureGain), As(&sceCamera2GetGamma), As(&sceCamera2SetGamma), As(&sceCamera2GetHue), As(&sceCamera2SetHue), As(&sceCamera2GetSaturation), As(&sceCamera2SetSaturation), As(&sceCamera2GetSharpness), As(&sceCamera2SetSharpness), As(&sceCamera2GetWhiteBalance), As(&sceCamera2SetWhiteBalance), As(&sceCamera2GetFieldOfView), As(&sceCamera2GetFrameData), As(&sceCamera2IsValidFrameData), As(&sceCamera2SetVideoSync), As(&sceCamera2Start), As(&sceCamera2Stop), }; for (const std::int32_t handle : {0, 1, 2, -1}) { for (const auto call : handleCalls) Require(call(handle) == ErrorParam, "a handle that sceCamera2Open never returned was accepted"); } Require(open(0xFE, 0, 0, nullptr) == ErrorParam, "sceCamera2Open took a user other than the system user"); Require(open(0xFF, 1, 0, nullptr) == ErrorParam && open(0xFF, 0, 1, nullptr) == ErrorParam, "sceCamera2Open took a nonzero type or index"); Require(isAttached(0) == ErrorParam && isAttached(2) == ErrorParam, "sceCamera2IsAttached took a device other than 1"); Require(initialize() == 0 && initialize() == 0, "sceCamera2Initialize failed"); for (const auto call : handleCalls) Require(call(1) == ErrorParam, "an initialized Camera2 accepted a handle it never opened"); Require(finalize() == 0, "sceCamera2Finalize failed with no camera open"); const int camera = sceCameraOpen(0xFF, 0, 0, nullptr); Require(camera > 0, "sceCameraOpen failed"); Require(finalize() == ErrorCameraOpen, "sceCamera2Finalize ran while a camera was open"); Require(sceCameraClose(camera) == 0, "sceCameraClose failed"); Require(finalize() == 0, "sceCamera2Finalize failed after the camera closed"); const std::uint32_t checked = 0; SetCamera2AppCategoryForTest_nid_no_patch(&checked); for (const auto call : handleCalls) Require(call(1) == ErrorNotInit, "a category below 0x1000000 skipped the initialization check"); Require(finalize() == ErrorNotInit && open(0xFF, 0, 0, nullptr) == ErrorNotInit, "a checked category finalized or opened before sceCamera2Initialize"); Require(InitializeThrows(initialize), "sceCamera2Initialize answered for a checked category it doesn't model"); const std::uint32_t exempt = 0x20F00; SetCamera2AppCategoryForTest_nid_no_patch(&exempt); for (const auto call : handleCalls) Require(call(1) == ErrorParam, "category 0x20F00 was checked for initialization"); Require(initialize() == 0, "sceCamera2Initialize failed for category 0x20F00"); SetCamera2AppCategoryForTest_nid_no_patch(&checked); for (const auto call : handleCalls) Require(call(1) == ErrorParam, "a checked category stayed uninitialized after sceCamera2Initialize"); Require(finalize() == 0, "sceCamera2Finalize failed for an initialized checked category"); const std::uint32_t unchecked = 0x1000000; SetCamera2AppCategoryForTest_nid_no_patch(&unchecked); for (const auto call : handleCalls) Require(call(1) == ErrorParam, "category 0x1000000 was checked for initialization"); Require(initialize() == 0 && finalize() == 0, "sceCamera2Initialize or Finalize failed for category 0x1000000"); SetCamera2AppCategoryForTest_nid_no_patch(nullptr); std::filesystem::current_path(original); std::filesystem::remove_all(directory); std::puts("Camera2 tests passed"); return 0; }