#include "prx/libSceNpCppWebApi/include/Api.hpp" #include "prx/libc/include/general/VabiMacros.hpp" #include #include #include #include #include #include namespace { void Require(bool value, std::source_location at = std::source_location::current()) { if (!value) { std::fprintf(stderr, "requirement failed at %s:%u\n", at.file_name(), at.line()); std::abort(); } } constexpr std::size_t kBinarySize = 0x20; constexpr std::size_t kGuardSize = 0x10; constexpr std::size_t kReferenceCountOffset = 0x00; constexpr std::size_t kBufferOffset = 0x08; constexpr std::size_t kDataSizeOffset = 0x10; constexpr std::size_t kLibContextOffset = 0x18; constexpr int kInvalidArgument = static_cast(0x80553503); constexpr unsigned char kFill = 0xA5; struct Storage { alignas(8) unsigned char bytes[kBinarySize + kGuardSize]; }; template TValue Load(const Storage& storage, std::size_t offset) { TValue value; std::memcpy(&value, storage.bytes + offset, sizeof(value)); return value; } bool GuardIntact(const Storage& storage) { for (std::size_t index = kBinarySize; index < sizeof(storage.bytes); ++index) { if (storage.bytes[index] != kFill) return false; } return true; } void TestConstructedBinaryIsEmpty() { std::uint64_t libContext = 1; Storage storage; std::memset(storage.bytes, kFill, sizeof(storage.bytes)); _ZN3sce2Np9CppWebApi6Common6BinaryC1EPNS2_10LibContextE(reinterpret_cast(storage.bytes), &libContext); Require(Load(storage, kReferenceCountOffset) == 0); Require(Load(storage, kBufferOffset) == nullptr); Require(Load(storage, kDataSizeOffset) == 0); Require(Load(storage, kLibContextOffset) == &libContext); Require(_ZNK3sce2Np9CppWebApi6Common6Binary9getBinaryEv(reinterpret_cast(storage.bytes)) == nullptr); Require(_ZNK3sce2Np9CppWebApi6Common6Binary4sizeEv(reinterpret_cast(storage.bytes)) == 0); Require(GuardIntact(storage)); _ZN3sce2Np9CppWebApi6Common6BinaryD1Ev(reinterpret_cast(storage.bytes)); Require(GuardIntact(storage)); } void TestSetAndAppend() { std::uint64_t libContext = 1; Storage storage; std::memset(storage.bytes, kFill, sizeof(storage.bytes)); auto* binary = reinterpret_cast(storage.bytes); _ZN3sce2Np9CppWebApi6Common6BinaryC2EPNS2_10LibContextE(binary, &libContext); Require(_ZN3sce2Np9CppWebApi6Common6Binary9setBinaryEPKvm(binary, "abc", 3) == 0); Require(Load(storage, kDataSizeOffset) == 3); Require(std::memcmp(_ZNK3sce2Np9CppWebApi6Common6Binary9getBinaryEv(reinterpret_cast(storage.bytes)), "abc", 3) == 0); Require(_ZNK3sce2Np9CppWebApi6Common6Binary4sizeEv(reinterpret_cast(storage.bytes)) == 3); Require(_ZN3sce2Np9CppWebApi6Common6Binary12appendBinaryEPKvm(binary, "de", 2) == 0); Require(Load(storage, kDataSizeOffset) == 5); Require(std::memcmp(_ZNK3sce2Np9CppWebApi6Common6Binary9getBinaryEv(reinterpret_cast(storage.bytes)), "abcde", 5) == 0); Require(_ZN3sce2Np9CppWebApi6Common6Binary12appendBinaryEPKvm(binary, nullptr, 1) == kInvalidArgument); Require(Load(storage, kDataSizeOffset) == 5); Require(std::memcmp(_ZNK3sce2Np9CppWebApi6Common6Binary9getBinaryEv(reinterpret_cast(storage.bytes)), "abcde", 5) == 0); Require(_ZN3sce2Np9CppWebApi6Common6Binary9setBinaryEPKvm(binary, nullptr, 1) == kInvalidArgument); Require(Load(storage, kDataSizeOffset) == 5); Require(std::memcmp(_ZNK3sce2Np9CppWebApi6Common6Binary9getBinaryEv(reinterpret_cast(storage.bytes)), "abcde", 5) == 0); Require(_ZN3sce2Np9CppWebApi6Common6Binary9setBinaryEPKvm(binary, nullptr, 0) == 0); Require(_ZN3sce2Np9CppWebApi6Common6Binary12appendBinaryEPKvm(binary, "xy", 2) == 0); Require(Load(storage, kDataSizeOffset) == 2); Require(std::memcmp(_ZNK3sce2Np9CppWebApi6Common6Binary9getBinaryEv(reinterpret_cast(storage.bytes)), "xy", 2) == 0); Require(_ZN3sce2Np9CppWebApi6Common6Binary9setBinaryEPKvm(binary, _ZNK3sce2Np9CppWebApi6Common6Binary9getBinaryEv(reinterpret_cast(storage.bytes)), 2) == 0); Require(Load(storage, kDataSizeOffset) == 2); Require(std::memcmp(_ZNK3sce2Np9CppWebApi6Common6Binary9getBinaryEv(reinterpret_cast(storage.bytes)), "xy", 2) == 0); Require(_ZN3sce2Np9CppWebApi6Common6Binary12appendBinaryEPKvm(binary, _ZNK3sce2Np9CppWebApi6Common6Binary9getBinaryEv(reinterpret_cast(storage.bytes)), 2) == 0); Require(Load(storage, kDataSizeOffset) == 4); Require(std::memcmp(_ZNK3sce2Np9CppWebApi6Common6Binary9getBinaryEv(reinterpret_cast(storage.bytes)), "xyxy", 4) == 0); Require(Load(storage, kReferenceCountOffset) == 0); Require(_ZN3sce2Np9CppWebApi6Common6Binary21intrusive_ptr_add_refEPS3_(binary) == 1); Require(_ZN3sce2Np9CppWebApi6Common6Binary21intrusive_ptr_add_refEPS3_(binary) == 2); Require(_ZN3sce2Np9CppWebApi6Common6Binary21intrusive_ptr_sub_refEPS3_(binary) == 2); Require(Load(storage, kReferenceCountOffset) == 1); _ZN3sce2Np9CppWebApi6Common6Binary5clearEv(binary); Require(Load(storage, kBufferOffset) == nullptr); Require(Load(storage, kDataSizeOffset) == 0); Require(GuardIntact(storage)); _ZN3sce2Np9CppWebApi6Common6BinaryD2Ev(binary); Require(Load(storage, kBufferOffset) == nullptr); Require(Load(storage, kDataSizeOffset) == 0); Require(GuardIntact(storage)); } } int main() { TestConstructedBinaryIsEmpty(); TestSetAndAppend(); return 0; }