SaveData compatibility with old firmwares

This commit is contained in:
Vinicius Rangel 2024-09-22 20:50:10 -03:00
parent 646b2f4679
commit 00c2a5a1eb
No known key found for this signature in database
GPG Key ID: A5B154D904B761D9
5 changed files with 171 additions and 75 deletions

View File

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/elf_info.h"
#include "common/logging/log.h"
#include "core/libraries/libs.h"
#include "core/libraries/system/commondialog.h"

View File

@ -15,6 +15,7 @@
using namespace ImGui;
using namespace Libraries::CommonDialog;
using Common::ElfInfo;
constexpr u32 OrbisSaveDataBlockSize = 32768; // 32 KiB
@ -48,7 +49,7 @@ void SaveDialogResult::CopyTo(OrbisSaveDataDialogResult& result) const {
result.mode = this->mode;
result.result = this->result;
result.buttonId = this->button_id;
if (has_item) {
if (mode == SaveDataDialogMode::LIST || ElfInfo::Instance().FirmwareVer() >= ElfInfo::FW_45) {
if (result.dirName != nullptr) {
result.dirName->data.FromString(this->dir_name);
}
@ -202,6 +203,7 @@ SaveDialogState::SystemState::SystemState(const SaveDialogState& state,
auto& sys = *param.sysMsgParam;
switch (sys.msgType) {
case SystemMessageType::NODATA: {
return_cancel = true;
this->msg = "There is no saved data";
} break;
case SystemMessageType::CONFIRM:
@ -214,6 +216,7 @@ SaveDialogState::SystemState::SystemState(const SaveDialogState& state,
M("Do you want to overwrite the existing saved data?", "##UNKNOWN##", "##UNKNOWN##");
break;
case SystemMessageType::NOSPACE:
return_cancel = true;
M(fmt::format(
"There is not enough space to save the data. To continue {} free space is required.",
SpaceSizeToString(sys.value * OrbisSaveDataBlockSize)),
@ -225,12 +228,15 @@ SaveDialogState::SystemState::SystemState(const SaveDialogState& state,
M("Saving...", "Loading...", "Deleting...");
break;
case SystemMessageType::FILE_CORRUPTED:
return_cancel = true;
this->msg = "The saved data is corrupted.";
break;
case SystemMessageType::FINISHED:
return_cancel = true;
M("Saved successfully.", "Loading complete.", "Deletion complete.");
break;
case SystemMessageType::NOSPACE_CONTINUABLE:
return_cancel = true;
M(fmt::format("There is not enough space to save the data. {} free space is required.",
SpaceSizeToString(sys.value * OrbisSaveDataBlockSize)),
"##UNKNOWN##", "##UNKNOWN##");
@ -282,29 +288,36 @@ SaveDialogState::ErrorCodeState::ErrorCodeState(const OrbisSaveDataDialogParam&
}
SaveDialogState::ProgressBarState::ProgressBarState(const SaveDialogState& state,
const OrbisSaveDataDialogParam& param) {
static auto fw_ver = ElfInfo::Instance().FirmwareVer();
this->progress = 0;
auto& bar = *param.progressBarParam;
switch (bar.sysMsgType) {
case ProgressSystemMessageType::INVALID:
this->msg = bar.msg != nullptr ? std::string{bar.msg} : std::string{};
break;
case ProgressSystemMessageType::PROGRESS:
switch (state.type) {
case DialogType::SAVE:
this->msg = "Saving...";
if (bar.msg != nullptr) {
this->msg = std::string{bar.msg};
} else {
switch (bar.sysMsgType) {
case ProgressSystemMessageType::INVALID:
this->msg = "INVALID";
break;
case DialogType::LOAD:
this->msg = "Loading...";
case ProgressSystemMessageType::PROGRESS:
switch (state.type) {
case DialogType::SAVE:
this->msg = "Saving...";
break;
case DialogType::LOAD:
this->msg = "Loading...";
break;
case DialogType::DELETE:
this->msg = "Deleting...";
break;
}
break;
case DialogType::DELETE:
this->msg = "Deleting...";
case ProgressSystemMessageType::RESTORE:
this->msg = "Restoring saved data...";
break;
}
break;
case ProgressSystemMessageType::RESTORE:
this->msg = "Restoring saved data...";
break;
}
}
@ -352,11 +365,8 @@ void SaveDialogUi::Finish(ButtonId buttonId, Result r) {
result->result = r;
result->button_id = buttonId;
result->user_data = this->state->user_data;
if (state) {
if (state->mode != SaveDataDialogMode::LIST && !state->save_list.empty()) {
result->dir_name = state->save_list.front().dir_name;
}
result->has_item = state->mode == SaveDataDialogMode::LIST || !state->save_list.empty();
if (state && state->mode != SaveDataDialogMode::LIST && !state->save_list.empty()) {
result->dir_name = state->save_list.front().dir_name;
}
}
if (status) {
@ -642,6 +652,8 @@ void SaveDialogUi::DrawUser() {
if (!state->save_list.empty()) {
DrawItem(0, state->save_list.front(), false);
} else if (state->new_item) {
DrawItem(0, *state->new_item, false);
}
auto has_btn = btn_type != ButtonType::NONE;
@ -666,7 +678,7 @@ void SaveDialogUi::DrawUser() {
if (has_btn) {
int count = 1;
if (btn_type == ButtonType::YESNO || btn_type == ButtonType::ONCANCEL) {
if (btn_type == ButtonType::YESNO || btn_type == ButtonType::OKCANCEL) {
++count;
}
@ -682,19 +694,28 @@ void SaveDialogUi::DrawUser() {
}
SameLine();
if (Button("No", BUTTON_SIZE)) {
Finish(ButtonId::NO);
if (ElfInfo::Instance().FirmwareVer() < ElfInfo::FW_45) {
Finish(ButtonId::INVALID, Result::USER_CANCELED);
} else {
Finish(ButtonId::NO);
}
}
if (first_render || IsKeyPressed(ImGuiKey_GamepadFaceRight)) {
SetItemCurrentNavFocus();
}
} else {
if (Button("OK", BUTTON_SIZE)) {
Finish(ButtonId::OK);
if (btn_type == ButtonType::OK &&
ElfInfo::Instance().FirmwareVer() < ElfInfo::FW_45) {
Finish(ButtonId::INVALID, Result::USER_CANCELED);
} else {
Finish(ButtonId::OK);
}
}
if (first_render) {
SetItemCurrentNavFocus();
}
if (btn_type == ButtonType::ONCANCEL) {
if (btn_type == ButtonType::OKCANCEL) {
SameLine();
if (Button("Cancel", BUTTON_SIZE)) {
Finish(ButtonId::INVALID, Result::USER_CANCELED);
@ -713,6 +734,8 @@ void SaveDialogUi::DrawSystemMessage() {
if (!state->save_list.empty()) {
DrawItem(0, state->save_list.front(), false);
} else if (state->new_item) {
DrawItem(0, *state->new_item, false);
}
const auto ws = GetWindowSize();
@ -736,12 +759,20 @@ void SaveDialogUi::DrawSystemMessage() {
});
BeginGroup();
if (Button(sys_state.show_no ? "Yes" : "OK", BUTTON_SIZE)) {
Finish(ButtonId::YES);
if (sys_state.return_cancel && ElfInfo::Instance().FirmwareVer() < ElfInfo::FW_45) {
Finish(ButtonId::INVALID, Result::USER_CANCELED);
} else {
Finish(ButtonId::YES);
}
}
SameLine();
if (sys_state.show_no) {
if (Button("No", BUTTON_SIZE)) {
Finish(ButtonId::NO);
if (ElfInfo::Instance().FirmwareVer() < ElfInfo::FW_45) {
Finish(ButtonId::INVALID, Result::USER_CANCELED);
} else {
Finish(ButtonId::NO);
}
}
} else if (sys_state.show_cancel) {
if (Button("Cancel", BUTTON_SIZE)) {
@ -759,6 +790,8 @@ void SaveDialogUi::DrawErrorCode() {
if (!state->save_list.empty()) {
DrawItem(0, state->save_list.front(), false);
} else if (state->new_item) {
DrawItem(0, *state->new_item, false);
}
const auto ws = GetWindowSize();
@ -774,7 +807,11 @@ void SaveDialogUi::DrawErrorCode() {
ws.y - FOOTER_HEIGHT + 5.0f,
});
if (Button("OK", BUTTON_SIZE)) {
Finish(ButtonId::OK);
if (ElfInfo::Instance().FirmwareVer() < ElfInfo::FW_45) {
Finish(ButtonId::INVALID, Result::USER_CANCELED);
} else {
Finish(ButtonId::OK);
}
}
if (first_render) {
SetItemCurrentNavFocus();
@ -788,6 +825,8 @@ void SaveDialogUi::DrawProgressBar() {
if (!state->save_list.empty()) {
DrawItem(0, state->save_list.front(), false);
} else if (state->new_item) {
DrawItem(0, *state->new_item, false);
}
const auto& msg = bar_state.msg;

View File

@ -48,7 +48,7 @@ enum class ButtonType : u32 {
OK = 0,
YESNO = 1,
NONE = 2,
ONCANCEL = 3,
OKCANCEL = 3,
};
enum class UserMessageType : u32 {
@ -201,7 +201,6 @@ struct SaveDialogResult {
std::string dir_name{};
PSF param{};
void* user_data{};
bool has_item{false};
void CopyTo(OrbisSaveDataDialogResult& result) const;
};
@ -223,6 +222,8 @@ public:
bool show_no{}; // Yes instead of OK
bool show_cancel{};
bool return_cancel{};
SystemState(const SaveDialogState& state, const OrbisSaveDataDialogParam& param);
};
struct ErrorCodeState {

View File

@ -28,11 +28,13 @@ namespace fs = std::filesystem;
namespace chrono = std::chrono;
using Common::CString;
using Common::ElfInfo;
namespace Libraries::SaveData {
enum class Error : u32 {
OK = 0,
USER_SERVICE_NOT_INITIALIZED = 0x80960002,
PARAMETER = 0x809F0000,
NOT_INITIALIZED = 0x809F0001,
OUT_OF_MEMORY = 0x809F0002,
@ -191,7 +193,9 @@ struct OrbisSaveDataMemorySetup2 {
OrbisUserServiceUserId userId;
size_t memorySize;
size_t iconMemorySize;
// +4.5
const OrbisSaveDataParam* initParam;
// +4.5
const OrbisSaveDataIcon* initIcon;
std::array<u8, 24> _reserved;
};
@ -241,6 +245,7 @@ struct OrbisSaveDataMountResult {
OrbisSaveDataMountPoint mount_point;
OrbisSaveDataBlocks required_blocks;
u32 _unused;
// +4.5
OrbisSaveDataMountStatus mount_status;
std::array<u8, 28> _reserved;
s32 : 32;
@ -278,8 +283,11 @@ struct OrbisSaveDataDirNameSearchResult {
int : 32;
OrbisSaveDataDirName* dirNames;
u32 dirNamesNum;
// +1.7
u32 setNum;
// +1.7
OrbisSaveDataParam* params;
// +2.5
OrbisSaveDataSearchInfo* infos;
std::array<u8, 12> _reserved;
int : 32;
@ -303,11 +311,13 @@ struct OrbisSaveDataEvent {
static bool g_initialized = false;
static std::string g_game_serial;
static u32 g_fw_ver;
static std::array<std::optional<SaveInstance>, 16> g_mount_slots;
static void initialize() {
g_initialized = true;
g_game_serial = Common::ElfInfo::Instance().GameSerial();
g_game_serial = ElfInfo::Instance().GameSerial();
g_fw_ver = ElfInfo::Instance().FirmwareVer();
}
// game_00other | game*other
@ -336,6 +346,16 @@ static bool match(std::string_view str, std::string_view pattern) {
return str_it == str.end() && pat_it == pattern.end();
}
static Error setNotInitializedError() {
if (g_fw_ver < ElfInfo::FW_20) {
return Error::INTERNAL;
}
if (g_fw_ver < ElfInfo::FW_25) {
return Error::USER_SERVICE_NOT_INITIALIZED;
}
return Error::NOT_INITIALIZED;
}
static Error saveDataMount(const OrbisSaveDataMount2* mount_info,
OrbisSaveDataMountResult* mount_result) {
@ -351,7 +371,7 @@ static Error saveDataMount(const OrbisSaveDataMount2* mount_info,
{
const auto save_path = SaveInstance::MakeDirSavePath(mount_info->userId, g_game_serial,
mount_info->dirName->data);
if (Backup::IsBackupExecutingFor(save_path)) {
if (Backup::IsBackupExecutingFor(save_path) && g_fw_ver) {
return Error::BACKUP_BUSY;
}
}
@ -360,11 +380,14 @@ static Error saveDataMount(const OrbisSaveDataMount2* mount_info,
const bool is_ro = True(mount_mode & OrbisSaveDataMountMode::RDONLY);
const bool create = True(mount_mode & OrbisSaveDataMountMode::CREATE);
const bool create_if_not_exist = True(mount_mode & OrbisSaveDataMountMode::CREATE2);
const bool create_if_not_exist =
True(mount_mode & OrbisSaveDataMountMode::CREATE2) && g_fw_ver >= ElfInfo::FW_45;
ASSERT(!create || !create_if_not_exist); // Can't have both
const bool copy_icon = True(mount_mode & OrbisSaveDataMountMode::COPY_ICON);
const bool ignore_corrupt = True(mount_mode & OrbisSaveDataMountMode::DESTRUCT_OFF);
const bool ignore_corrupt =
True(mount_mode & OrbisSaveDataMountMode::DESTRUCT_OFF) || g_fw_ver < ElfInfo::FW_16;
const std::string_view dir_name{mount_info->dirName->data};
@ -436,9 +459,11 @@ static Error saveDataMount(const OrbisSaveDataMount2* mount_info,
mount_result->mount_point.data.FromString(save_instance.GetMountPoint());
mount_result->mount_status = create_if_not_exist && to_be_created
? OrbisSaveDataMountStatus::CREATED
: OrbisSaveDataMountStatus::NOTHING;
if (g_fw_ver >= ElfInfo::FW_45) {
mount_result->mount_status = create_if_not_exist && to_be_created
? OrbisSaveDataMountStatus::CREATED
: OrbisSaveDataMountStatus::NOTHING;
}
g_mount_slots[slot_num].emplace(std::move(save_instance));
@ -448,7 +473,7 @@ static Error saveDataMount(const OrbisSaveDataMount2* mount_info,
static Error Umount(const OrbisSaveDataMountPoint* mountPoint, bool call_backup = false) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (mountPoint == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -501,7 +526,7 @@ int PS4_SYSV_ABI sceSaveDataAbort() {
Error PS4_SYSV_ABI sceSaveDataBackup(const OrbisSaveDataBackup* backup) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (backup == nullptr || backup->dirName == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -550,7 +575,7 @@ int PS4_SYSV_ABI sceSaveDataChangeInternal() {
Error PS4_SYSV_ABI sceSaveDataCheckBackupData(const OrbisSaveDataCheckBackupData* check) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (check == nullptr || check->dirName == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -635,7 +660,7 @@ int PS4_SYSV_ABI sceSaveDataCheckSaveDataVersionLatest() {
Error PS4_SYSV_ABI sceSaveDataClearProgress() {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
LOG_DEBUG(Lib_SaveData, "called");
Backup::ClearProgress();
@ -690,7 +715,7 @@ int PS4_SYSV_ABI sceSaveDataDebugTarget() {
Error PS4_SYSV_ABI sceSaveDataDelete(const OrbisSaveDataDelete* del) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (del == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -742,7 +767,7 @@ Error PS4_SYSV_ABI sceSaveDataDirNameSearch(const OrbisSaveDataDirNameSearchCond
OrbisSaveDataDirNameSearchResult* result) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (cond == nullptr || result == nullptr || cond->key > OrbisSaveDataSortKey::FREE_BLOCKS ||
cond->order > OrbisSaveDataSortOrder::DESCENT) {
@ -757,7 +782,9 @@ Error PS4_SYSV_ABI sceSaveDataDirNameSearch(const OrbisSaveDataDirNameSearchCond
if (!fs::exists(save_path)) {
result->hitNum = 0;
result->setNum = 0;
if (g_fw_ver >= ElfInfo::FW_17) {
result->setNum = 0;
}
return Error::OK;
}
@ -825,21 +852,25 @@ Error PS4_SYSV_ABI sceSaveDataDirNameSearch(const OrbisSaveDataDirNameSearchCond
std::ranges::reverse(dir_list);
}
result->hitNum = dir_list.size();
size_t max_count = std::min(static_cast<size_t>(result->dirNamesNum), dir_list.size());
result->setNum = max_count;
if (g_fw_ver >= ElfInfo::FW_17) {
result->hitNum = dir_list.size();
result->setNum = max_count;
} else {
result->hitNum = max_count;
}
for (size_t i = 0; i < max_count; i++) {
auto& name_data = result->dirNames[i].data;
name_data.FromString(dir_list[i]);
if (result->params != nullptr) {
if (g_fw_ver >= ElfInfo::FW_17 && result->params != nullptr) {
auto& sfo = map_dir_sfo.at(dir_list[i]);
auto& param_data = result->params[i];
param_data.FromSFO(sfo);
}
if (result->infos != nullptr) {
if (g_fw_ver >= ElfInfo::FW_25 && result->infos != nullptr) {
auto& info = result->infos[i];
info.blocks = map_max_blocks.at(dir_list[i]);
info.freeBlocks = map_free_size.at(dir_list[i]);
@ -913,7 +944,7 @@ Error PS4_SYSV_ABI sceSaveDataGetEventResult(const OrbisSaveDataEventParam*,
OrbisSaveDataEvent* event) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (event == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -949,7 +980,7 @@ Error PS4_SYSV_ABI sceSaveDataGetMountInfo(const OrbisSaveDataMountPoint* mountP
OrbisSaveDataMountInfo* info) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (mountPoint == nullptr || info == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -974,7 +1005,7 @@ Error PS4_SYSV_ABI sceSaveDataGetParam(const OrbisSaveDataMountPoint* mountPoint
size_t paramBufSize, size_t* gotSize) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (paramType > OrbisSaveDataParamType::MTIME || paramBuf == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1049,7 +1080,7 @@ Error PS4_SYSV_ABI sceSaveDataGetParam(const OrbisSaveDataMountPoint* mountPoint
Error PS4_SYSV_ABI sceSaveDataGetProgress(float* progress) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (progress == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1083,7 +1114,7 @@ Error PS4_SYSV_ABI sceSaveDataGetSaveDataMemory(const OrbisUserServiceUserId use
Error PS4_SYSV_ABI sceSaveDataGetSaveDataMemory2(OrbisSaveDataMemoryGet2* getParam) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (getParam == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1179,7 +1210,7 @@ Error PS4_SYSV_ABI sceSaveDataLoadIcon(const OrbisSaveDataMountPoint* mountPoint
OrbisSaveDataIcon* icon) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (mountPoint == nullptr || icon == nullptr || icon->buf == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1208,7 +1239,7 @@ Error PS4_SYSV_ABI sceSaveDataMount(const OrbisSaveDataMount* mount,
OrbisSaveDataMountResult* mount_result) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (mount == nullptr && mount->dirName != nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1229,7 +1260,7 @@ Error PS4_SYSV_ABI sceSaveDataMount2(const OrbisSaveDataMount2* mount,
OrbisSaveDataMountResult* mount_result) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (mount == nullptr && mount->dirName != nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1273,7 +1304,7 @@ int PS4_SYSV_ABI sceSaveDataRegisterEventCallback() {
Error PS4_SYSV_ABI sceSaveDataRestoreBackupData(const OrbisSaveDataRestoreBackupData* restore) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (restore == nullptr || restore->dirName == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1324,7 +1355,7 @@ Error PS4_SYSV_ABI sceSaveDataSaveIcon(const OrbisSaveDataMountPoint* mountPoint
const OrbisSaveDataIcon* icon) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (mountPoint == nullptr || icon == nullptr || icon->buf == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1372,7 +1403,7 @@ Error PS4_SYSV_ABI sceSaveDataSetParam(const OrbisSaveDataMountPoint* mountPoint
size_t paramBufSize) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (paramType > OrbisSaveDataParamType::USER_PARAM || mountPoint == nullptr ||
paramBuf == nullptr) {
@ -1437,13 +1468,15 @@ Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory(OrbisUserServiceUserId userId, v
OrbisSaveDataMemorySet2 setParam{};
setParam.userId = userId;
setParam.data = &data;
setParam.param = nullptr;
setParam.icon = nullptr;
return sceSaveDataSetSaveDataMemory2(&setParam);
}
Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2* setParam) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (setParam == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1476,17 +1509,35 @@ Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2*
return Error::OK;
}
int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory(/*u32 userId, size_t memorySize,
OrbisSaveDataParam* param*/) {
LOG_ERROR(Lib_SaveData, "(STUBBED) called");
return ORBIS_OK;
Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory(OrbisUserServiceUserId userId, size_t memorySize,
OrbisSaveDataParam* param) {
LOG_DEBUG(Lib_SaveData, "called: userId = {}, memorySize = {}", userId, memorySize);
OrbisSaveDataMemorySetup2 setupParam{};
setupParam.userId = userId;
setupParam.memorySize = memorySize;
setupParam.initParam = nullptr;
setupParam.initIcon = nullptr;
OrbisSaveDataMemorySetupResult result{};
const auto res = sceSaveDataSetupSaveDataMemory2(&setupParam, &result);
if (res != Error::OK) {
return res;
}
if (param != nullptr) {
OrbisSaveDataMemorySet2 setParam{};
setParam.userId = userId;
setParam.data = nullptr;
setParam.param = param;
setParam.icon = nullptr;
sceSaveDataSetSaveDataMemory2(&setParam);
}
return Error::OK;
}
Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetup2* setupParam,
OrbisSaveDataMemorySetupResult* result) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (setupParam == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1506,20 +1557,20 @@ Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetu
try {
size_t existed_size = SaveMemory::CreateSaveMemory(setupParam->memorySize);
if (existed_size == 0) { // Just created
if (setupParam->initParam != nullptr) {
if (g_fw_ver >= ElfInfo::FW_45 && setupParam->initParam != nullptr) {
auto& sfo = SaveMemory::GetParamSFO();
setupParam->initParam->ToSFO(sfo);
}
SaveMemory::SaveSFO();
auto init_icon = setupParam->initIcon;
if (init_icon != nullptr) {
if (g_fw_ver >= ElfInfo::FW_45 && init_icon != nullptr) {
SaveMemory::SetIcon(init_icon->buf, init_icon->bufSize);
} else {
SaveMemory::SetIcon(nullptr, 0);
}
}
if (result != nullptr) {
if (g_fw_ver >= ElfInfo::FW_45 && result != nullptr) {
result->existedMemorySize = existed_size;
}
} catch (const fs::filesystem_error& e) {
@ -1555,7 +1606,7 @@ int PS4_SYSV_ABI sceSaveDataSyncCloudList() {
Error PS4_SYSV_ABI sceSaveDataSyncSaveDataMemory(OrbisSaveDataMemorySync* syncParam) {
if (!g_initialized) {
LOG_INFO(Lib_SaveData, "called without initialize");
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
if (syncParam == nullptr) {
LOG_INFO(Lib_SaveData, "called with invalid parameter");
@ -1576,11 +1627,15 @@ Error PS4_SYSV_ABI sceSaveDataSyncSaveDataMemory(OrbisSaveDataMemorySync* syncPa
Error PS4_SYSV_ABI sceSaveDataTerminate() {
LOG_DEBUG(Lib_SaveData, "called");
if (!g_initialized) {
return Error::NOT_INITIALIZED;
return setNotInitializedError();
}
for (const auto& instance : g_mount_slots) {
for (auto& instance : g_mount_slots) {
if (instance.has_value()) {
return Error::BUSY;
if (g_fw_ver >= ElfInfo::FW_40) {
return Error::BUSY;
}
instance->Umount();
instance.reset();
}
}
g_initialized = false;

View File

@ -165,8 +165,8 @@ int PS4_SYSV_ABI sceSaveDataSetSaveDataLibraryUser();
Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory(OrbisUserServiceUserId userId, void* buf,
size_t bufSize, int64_t offset);
Error PS4_SYSV_ABI sceSaveDataSetSaveDataMemory2(const OrbisSaveDataMemorySet2* setParam);
int PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory(/*u32 userId, size_t memorySize,
OrbisSaveDataParam* param*/);
Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory(OrbisUserServiceUserId userId, size_t memorySize,
OrbisSaveDataParam* param);
Error PS4_SYSV_ABI sceSaveDataSetupSaveDataMemory2(const OrbisSaveDataMemorySetup2* setupParam,
OrbisSaveDataMemorySetupResult* result);
int PS4_SYSV_ABI sceSaveDataShutdownStart();