mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-22 08:33:12 -05:00
192 lines
7.3 KiB
C++
192 lines
7.3 KiB
C++
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <stdexcept>
|
|
|
|
extern "C" {
|
|
void APS5_VABI _ZN3sce2Np9CppWebApi6Common6StringC1EPNS2_10LibContextE(void* self, void* libContext);
|
|
void APS5_VABI _ZN3sce2Np9CppWebApi6Common6StringD1Ev(void* self);
|
|
int APS5_VABI _ZN3sce2Np9CppWebApi6Common6String6appendEPKc(void* self, const char* text);
|
|
const char* APS5_VABI _ZNK3sce2Np9CppWebApi6Common6String5c_strEv(const void* self);
|
|
void APS5_VABI _ZN3sce2Np9CppWebApi6Common6VectorINS2_6StringEEC1EPNS2_10LibContextE(void* self, void* libContext);
|
|
void APS5_VABI _ZN3sce2Np9CppWebApi6Common6VectorINS2_6StringEED1Ev(void* self);
|
|
int APS5_VABI _ZN3sce2Np9CppWebApi6Common6VectorINS2_6StringEE8pushBackERKS4_(void* self, const void* element);
|
|
}
|
|
|
|
namespace {
|
|
|
|
void Require(bool value) { if (!value) std::abort(); }
|
|
|
|
constexpr std::size_t kStringSize = 0x20;
|
|
constexpr std::size_t kGuardSize = 0x10;
|
|
constexpr std::size_t kReferenceCountOffset = 0x00;
|
|
constexpr std::size_t kBufferOffset = 0x08;
|
|
constexpr std::size_t kBufferSizeOffset = 0x10;
|
|
constexpr std::size_t kLibContextOffset = 0x18;
|
|
constexpr unsigned char kFill = 0xA5;
|
|
|
|
constexpr std::size_t kVectorSize = 0x18;
|
|
constexpr std::size_t kObjectOffset = 0x00;
|
|
constexpr std::size_t kBodyMagicOffset = 0x00;
|
|
constexpr std::size_t kBodyReferenceCountOffset = 0x30;
|
|
constexpr std::size_t kBodyElementKindOffset = 0x34;
|
|
constexpr std::size_t kBodyElementsOffset = 0x38;
|
|
constexpr std::size_t kBodySizeOffset = 0x40;
|
|
|
|
struct Storage {
|
|
alignas(8) unsigned char bytes[kStringSize + kGuardSize];
|
|
};
|
|
|
|
struct VectorStorage {
|
|
alignas(8) unsigned char bytes[kVectorSize + kGuardSize];
|
|
};
|
|
|
|
template <typename TValue>
|
|
TValue Load(const Storage& storage, std::size_t offset) {
|
|
TValue value;
|
|
std::memcpy(&value, storage.bytes + offset, sizeof(value));
|
|
return value;
|
|
}
|
|
|
|
template <typename TValue>
|
|
void Store(Storage& storage, std::size_t offset, TValue value) {
|
|
std::memcpy(storage.bytes + offset, &value, sizeof(value));
|
|
}
|
|
|
|
template <typename TValue>
|
|
TValue LoadBody(const void* body, std::size_t offset) {
|
|
TValue value;
|
|
std::memcpy(&value, static_cast<const unsigned char*>(body) + offset, sizeof(value));
|
|
return value;
|
|
}
|
|
|
|
bool GuardIntact(const Storage& storage) {
|
|
for (std::size_t i = kStringSize; i < sizeof(storage.bytes); i++) {
|
|
if (storage.bytes[i] != kFill) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool VectorGuardIntact(const VectorStorage& storage) {
|
|
for (std::size_t i = kVectorSize; i < sizeof(storage.bytes); i++) {
|
|
if (storage.bytes[i] != kFill) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void TestConstructedStringIsEmpty() {
|
|
std::uint64_t libContext = 1;
|
|
Storage storage;
|
|
std::memset(storage.bytes, kFill, sizeof(storage.bytes));
|
|
|
|
_ZN3sce2Np9CppWebApi6Common6StringC1EPNS2_10LibContextE(storage.bytes, &libContext);
|
|
|
|
Require(Load<std::int32_t>(storage, kReferenceCountOffset) == 0);
|
|
Require(Load<char*>(storage, kBufferOffset) == nullptr);
|
|
Require(Load<std::uint64_t>(storage, kBufferSizeOffset) == 0);
|
|
Require(Load<void*>(storage, kLibContextOffset) == &libContext);
|
|
Require(GuardIntact(storage));
|
|
|
|
const char* text = _ZNK3sce2Np9CppWebApi6Common6String5c_strEv(storage.bytes);
|
|
Require(text != nullptr && text[0] == '\0');
|
|
|
|
_ZN3sce2Np9CppWebApi6Common6StringD1Ev(storage.bytes);
|
|
Require(Load<char*>(storage, kBufferOffset) == nullptr);
|
|
Require(Load<std::uint64_t>(storage, kBufferSizeOffset) == 0);
|
|
Require(GuardIntact(storage));
|
|
}
|
|
|
|
void TestNullLibContextIsStored() {
|
|
Storage storage;
|
|
std::memset(storage.bytes, kFill, sizeof(storage.bytes));
|
|
|
|
_ZN3sce2Np9CppWebApi6Common6StringC1EPNS2_10LibContextE(storage.bytes, nullptr);
|
|
|
|
Require(Load<void*>(storage, kLibContextOffset) == nullptr);
|
|
Require(Load<char*>(storage, kBufferOffset) == nullptr);
|
|
Require(_ZNK3sce2Np9CppWebApi6Common6String5c_strEv(storage.bytes)[0] == '\0');
|
|
_ZN3sce2Np9CppWebApi6Common6StringD1Ev(storage.bytes);
|
|
}
|
|
|
|
void TestAppendBuildsAndClearsBuffer() {
|
|
std::uint64_t libContext = 1;
|
|
Storage storage;
|
|
std::memset(storage.bytes, kFill, sizeof(storage.bytes));
|
|
|
|
_ZN3sce2Np9CppWebApi6Common6StringC1EPNS2_10LibContextE(storage.bytes, &libContext);
|
|
|
|
Require(_ZN3sce2Np9CppWebApi6Common6String6appendEPKc(storage.bytes, "rank") == 0);
|
|
Require(std::strcmp(_ZNK3sce2Np9CppWebApi6Common6String5c_strEv(storage.bytes), "rank") == 0);
|
|
Require(_ZN3sce2Np9CppWebApi6Common6String6appendEPKc(storage.bytes, "ing") == 0);
|
|
Require(std::strcmp(_ZNK3sce2Np9CppWebApi6Common6String5c_strEv(storage.bytes), "ranking") == 0);
|
|
Require(Load<char*>(storage, kBufferOffset) != nullptr);
|
|
Require(GuardIntact(storage));
|
|
|
|
_ZN3sce2Np9CppWebApi6Common6StringD1Ev(storage.bytes);
|
|
Require(Load<char*>(storage, kBufferOffset) == nullptr);
|
|
Require(Load<std::uint64_t>(storage, kBufferSizeOffset) == 0);
|
|
Require(GuardIntact(storage));
|
|
}
|
|
|
|
void TestAppendNullKeepsEmpty() {
|
|
std::uint64_t libContext = 1;
|
|
Storage storage;
|
|
std::memset(storage.bytes, kFill, sizeof(storage.bytes));
|
|
|
|
_ZN3sce2Np9CppWebApi6Common6StringC1EPNS2_10LibContextE(storage.bytes, &libContext);
|
|
Require(_ZN3sce2Np9CppWebApi6Common6String6appendEPKc(storage.bytes, nullptr) == 0);
|
|
Require(Load<char*>(storage, kBufferOffset) == nullptr);
|
|
Require(_ZNK3sce2Np9CppWebApi6Common6String5c_strEv(storage.bytes)[0] == '\0');
|
|
_ZN3sce2Np9CppWebApi6Common6StringD1Ev(storage.bytes);
|
|
}
|
|
|
|
void TestVectorPushBackCopiesStringContent() {
|
|
std::uint64_t libContext = 1;
|
|
VectorStorage vector;
|
|
Storage element;
|
|
std::memset(vector.bytes, kFill, sizeof(vector.bytes));
|
|
std::memset(element.bytes, kFill, sizeof(element.bytes));
|
|
|
|
_ZN3sce2Np9CppWebApi6Common6VectorINS2_6StringEEC1EPNS2_10LibContextE(vector.bytes, &libContext);
|
|
Require(VectorGuardIntact(vector));
|
|
|
|
_ZN3sce2Np9CppWebApi6Common6StringC1EPNS2_10LibContextE(element.bytes, &libContext);
|
|
Require(_ZN3sce2Np9CppWebApi6Common6String6appendEPKc(element.bytes, "privilege") == 0);
|
|
char* elementBuffer = Load<char*>(element, kBufferOffset);
|
|
Require(elementBuffer != nullptr);
|
|
|
|
Require(_ZN3sce2Np9CppWebApi6Common6VectorINS2_6StringEE8pushBackERKS4_(vector.bytes, element.bytes) == 0);
|
|
|
|
void* body;
|
|
std::memcpy(&body, vector.bytes + kObjectOffset, sizeof(body));
|
|
Require(body != nullptr);
|
|
Require(LoadBody<std::int32_t>(body, kBodyReferenceCountOffset) == 1);
|
|
Require(LoadBody<std::int32_t>(body, kBodyElementKindOffset) == 2);
|
|
Require(LoadBody<std::uint64_t>(body, kBodySizeOffset) == 1);
|
|
|
|
void* elements = LoadBody<void*>(body, kBodyElementsOffset);
|
|
char* storedBuffer;
|
|
std::memcpy(&storedBuffer, static_cast<unsigned char*>(elements) + kBufferOffset, sizeof(storedBuffer));
|
|
Require(storedBuffer != nullptr);
|
|
Require(storedBuffer != elementBuffer);
|
|
Require(std::strcmp(storedBuffer, "privilege") == 0);
|
|
|
|
_ZN3sce2Np9CppWebApi6Common6StringD1Ev(element.bytes);
|
|
Require(std::strcmp(storedBuffer, "privilege") == 0);
|
|
|
|
_ZN3sce2Np9CppWebApi6Common6VectorINS2_6StringEED1Ev(vector.bytes);
|
|
Require(VectorGuardIntact(vector));
|
|
}
|
|
|
|
}
|
|
|
|
int main() {
|
|
TestConstructedStringIsEmpty();
|
|
TestNullLibContextIsStored();
|
|
TestAppendBuildsAndClearsBuffer();
|
|
TestAppendNullKeepsEmpty();
|
|
TestVectorPushBackCopiesStringContent();
|
|
}
|