mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-29 12:15:39 +00:00
PS4 titles import save data from libSceSaveData and libSceSaveDataDialog, and a converted title loads exactly the modules its DT_NEEDED names. Those two libraries were separate, older implementations that export only 9 and 8 functions, while libSceSaveData.native and libSceSaveDataDialog.native carry sceSaveDataDelete, sceSaveDataDirNameSearch, sceSaveDataSetParam, sceSaveDataSaveIcon, sceSaveDataDialogUpdateStatus and the rest. A PS4 title importing any of those failed at startup with unresolved imports. Both plain libraries are now built from the native sources, the way libSceNgs2 is built from libSceNgs2.native, and the old implementation and its test variant are removed. The earlier implementation's save-data memory and mount alias files are not read; that is recorded in the debt file. Co-Authored-By: Claude Opus 5.5 <[email protected]>
71 lines
2.5 KiB
C++
71 lines
2.5 KiB
C++
#include "SceTypes.hpp"
|
|
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
|
|
#include <algorithm>
|
|
#include <chrono>
|
|
#include <cstddef>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
#include <iterator>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
extern "C" {
|
|
int APS5_VABI sceSaveDataInitialize3(const void*);
|
|
int APS5_VABI sceSaveDataTerminate(void);
|
|
int APS5_VABI sceSaveDataSetupSaveDataMemory2(const SaveDataMemorySetup2*, SaveDataMemorySetupResult*);
|
|
}
|
|
|
|
static void Check(bool value, int line) {
|
|
if (!value) {
|
|
std::fprintf(stderr, "Save-data replacement check failed at line %d\n", line);
|
|
std::abort();
|
|
}
|
|
}
|
|
#define Require(value) Check((value), __LINE__)
|
|
|
|
int main() {
|
|
const auto originalDirectory = std::filesystem::current_path();
|
|
const auto root = std::filesystem::temp_directory_path() /
|
|
("anyps5-savedata-replacement-" +
|
|
std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
|
|
Require(std::filesystem::create_directory(root));
|
|
std::filesystem::current_path(root);
|
|
|
|
constexpr std::int32_t userId = 7531;
|
|
const auto savePath = std::filesystem::path("_sd_mem") / ("u" + std::to_string(userId)) / "slot0.bin";
|
|
std::filesystem::create_directories(savePath.parent_path());
|
|
const std::vector<char> oldData{'o', 'l', 'd'};
|
|
{
|
|
std::ofstream file(savePath, std::ios::binary);
|
|
Require(file.is_open());
|
|
file.write(oldData.data(), static_cast<std::streamsize>(oldData.size()));
|
|
Require(static_cast<bool>(file));
|
|
}
|
|
|
|
Require(sceSaveDataInitialize3(nullptr) == 0);
|
|
SaveDataMemorySetup2 setup{};
|
|
setup.user_id = userId;
|
|
setup.memory_size = oldData.size() + 3;
|
|
SaveDataMemorySetupResult result{};
|
|
const int status = sceSaveDataSetupSaveDataMemory2(&setup, &result);
|
|
|
|
Require(result.existed_memory_size == oldData.size());
|
|
Require(status == 0);
|
|
std::vector<char> savedData;
|
|
{
|
|
std::ifstream savedFile(savePath, std::ios::binary);
|
|
savedData.assign(std::istreambuf_iterator<char>(savedFile), std::istreambuf_iterator<char>());
|
|
}
|
|
Require(savedData.size() == setup.memory_size);
|
|
Require(std::equal(oldData.begin(), oldData.end(), savedData.begin()));
|
|
Require(std::all_of(savedData.begin() + static_cast<std::ptrdiff_t>(oldData.size()),
|
|
savedData.end(), [](char byte) { return byte == 0; }));
|
|
|
|
Require(sceSaveDataTerminate() == 0);
|
|
std::filesystem::current_path(originalDirectory);
|
|
std::filesystem::remove_all(root);
|
|
}
|