mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-22 09:09:18 +01:00
nn_acp: Implement ACPGetOlvAccesskey + code clean up
Added ACPGetOlvAccesskey() which is used by Super Mario Maker iosu acp, nn_acp and nn_save all cross talk with each other and are mostly legacy code. Modernized it a tiny bit and moved functions to where they should be. A larger refactor should be done in the future but for now this works ok
This commit is contained in:
parent
33a74c2035
commit
12eda10387
@ -530,6 +530,7 @@ namespace CafeSystem
|
||||
{
|
||||
// entries in this list are ordered by initialization order. Shutdown in reverse order
|
||||
iosu::kernel::GetModule(),
|
||||
iosu::acp::GetModule(),
|
||||
iosu::fpd::GetModule(),
|
||||
iosu::pdm::GetModule(),
|
||||
};
|
||||
|
@ -8,10 +8,19 @@
|
||||
#include "Cafe/OS/libs/nn_acp/nn_acp.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_FS.h"
|
||||
#include "Cafe/Filesystem/fsc.h"
|
||||
#include "Cafe/HW/Espresso/PPCState.h"
|
||||
//#include "Cafe/HW/Espresso/PPCState.h"
|
||||
|
||||
#include "Cafe/IOSU/iosu_types_common.h"
|
||||
#include "Cafe/IOSU/nn/iosu_nn_service.h"
|
||||
|
||||
#include "Cafe/IOSU/legacy/iosu_act.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
|
||||
using ACPDeviceType = iosu::acp::ACPDeviceType;
|
||||
|
||||
static_assert(sizeof(acpMetaXml_t) == 0x3440);
|
||||
static_assert(offsetof(acpMetaXml_t, title_id) == 0x0000);
|
||||
static_assert(offsetof(acpMetaXml_t, boss_id) == 0x0008);
|
||||
@ -506,48 +515,6 @@ namespace iosu
|
||||
return 0;
|
||||
}
|
||||
|
||||
sint32 ACPCreateSaveDirEx(uint8 accountSlot, uint64 titleId)
|
||||
{
|
||||
uint32 persistentId = 0;
|
||||
nn::save::GetPersistentIdEx(accountSlot, &persistentId);
|
||||
|
||||
uint32 high = GetTitleIdHigh(titleId) & (~0xC);
|
||||
uint32 low = GetTitleIdLow(titleId);
|
||||
|
||||
sint32 fscStatus = FSC_STATUS_FILE_NOT_FOUND;
|
||||
char path[256];
|
||||
|
||||
sprintf(path, "%susr/boss/", "/vol/storage_mlc01/");
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/", "/vol/storage_mlc01/", high);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/common", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/%08x/", "/vol/storage_mlc01/", high, low, persistentId == 0 ? 0x80000001 : persistentId);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
|
||||
sprintf(path, "%susr/save/%08x/", "/vol/storage_mlc01/", high);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/meta/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/common", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/%08x", "/vol/storage_mlc01/", high, low, persistentId == 0 ? 0x80000001 : persistentId);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
|
||||
// copy xml meta files
|
||||
nn::acp::CreateSaveMetaFiles(persistentId, titleId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int iosuAcp_thread()
|
||||
{
|
||||
SetThreadName("iosuAcp_thread");
|
||||
@ -584,7 +551,7 @@ namespace iosu
|
||||
}
|
||||
else if (acpCemuRequest->requestCode == IOSU_ACP_CREATE_SAVE_DIR_EX)
|
||||
{
|
||||
acpCemuRequest->returnCode = ACPCreateSaveDirEx(acpCemuRequest->accountSlot, acpCemuRequest->titleId);
|
||||
acpCemuRequest->returnCode = acp::ACPCreateSaveDirEx(acpCemuRequest->accountSlot, acpCemuRequest->titleId);
|
||||
}
|
||||
else
|
||||
cemu_assert_unimplemented();
|
||||
@ -610,5 +577,237 @@ namespace iosu
|
||||
return iosuAcp.isInitialized;
|
||||
}
|
||||
|
||||
/* Above is the legacy implementation. Below is the new style implementation which also matches the official IPC protocol and works with the real nn_acp.rpl */
|
||||
|
||||
}
|
||||
namespace acp
|
||||
{
|
||||
|
||||
uint64 _ACPGetTimestamp()
|
||||
{
|
||||
return coreinit::coreinit_getOSTime() / ESPRESSO_TIMER_CLOCK;
|
||||
}
|
||||
|
||||
nnResult ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, ACPDeviceType deviceType)
|
||||
{
|
||||
if (deviceType == ACPDeviceType::UnknownType)
|
||||
{
|
||||
return (nnResult)0xA030FB80;
|
||||
}
|
||||
|
||||
// create or modify the saveinfo
|
||||
const auto saveinfoPath = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/meta/saveinfo.xml", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
auto saveinfoData = FileStream::LoadIntoMemory(saveinfoPath);
|
||||
if (saveinfoData && !saveinfoData->empty())
|
||||
{
|
||||
namespace xml = tinyxml2;
|
||||
xml::XMLDocument doc;
|
||||
tinyxml2::XMLError xmlError = doc.Parse((const char*)saveinfoData->data(), saveinfoData->size());
|
||||
if (xmlError == xml::XML_SUCCESS || xmlError == xml::XML_ERROR_EMPTY_DOCUMENT)
|
||||
{
|
||||
xml::XMLNode* child = doc.FirstChild();
|
||||
// check for declaration -> <?xml version="1.0" encoding="utf-8"?>
|
||||
if (!child || !child->ToDeclaration())
|
||||
{
|
||||
xml::XMLDeclaration* decl = doc.NewDeclaration();
|
||||
doc.InsertFirstChild(decl);
|
||||
}
|
||||
|
||||
xml::XMLElement* info = doc.FirstChildElement("info");
|
||||
if (!info)
|
||||
{
|
||||
info = doc.NewElement("info");
|
||||
doc.InsertEndChild(info);
|
||||
}
|
||||
|
||||
// find node with persistentId
|
||||
char tmp[64];
|
||||
sprintf(tmp, "%08x", persistentId);
|
||||
bool foundNode = false;
|
||||
for (xml::XMLElement* account = info->FirstChildElement("account"); account; account = account->NextSiblingElement("account"))
|
||||
{
|
||||
if (account->Attribute("persistentId", tmp))
|
||||
{
|
||||
// found the entry! -> update timestamp
|
||||
xml::XMLElement* timestamp = account->FirstChildElement("timestamp");
|
||||
sprintf(tmp, "%" PRIx64, _ACPGetTimestamp());
|
||||
if (timestamp)
|
||||
timestamp->SetText(tmp);
|
||||
else
|
||||
{
|
||||
timestamp = doc.NewElement("timestamp");
|
||||
account->InsertFirstChild(timestamp);
|
||||
}
|
||||
|
||||
foundNode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundNode)
|
||||
{
|
||||
tinyxml2::XMLElement* account = doc.NewElement("account");
|
||||
{
|
||||
sprintf(tmp, "%08x", persistentId);
|
||||
account->SetAttribute("persistentId", tmp);
|
||||
|
||||
tinyxml2::XMLElement* timestamp = doc.NewElement("timestamp");
|
||||
{
|
||||
sprintf(tmp, "%" PRIx64, _ACPGetTimestamp());
|
||||
timestamp->SetText(tmp);
|
||||
}
|
||||
|
||||
account->InsertFirstChild(timestamp);
|
||||
}
|
||||
|
||||
info->InsertFirstChild(account);
|
||||
}
|
||||
|
||||
// update file
|
||||
tinyxml2::XMLPrinter printer;
|
||||
doc.Print(&printer);
|
||||
FileStream* fs = FileStream::createFile2(saveinfoPath);
|
||||
if (fs)
|
||||
{
|
||||
fs->writeString(printer.CStr());
|
||||
delete fs;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NN_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void CreateSaveMetaFiles(uint32 persistentId, uint64 titleId)
|
||||
{
|
||||
std::string titlePath = CafeSystem::GetMlcStoragePath(CafeSystem::GetForegroundTitleId());
|
||||
|
||||
sint32 fscStatus;
|
||||
FSCVirtualFile* fscFile = fsc_open((titlePath + "/meta/meta.xml").c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &fscStatus);
|
||||
if (fscFile)
|
||||
{
|
||||
sint32 fileSize = fsc_getFileSize(fscFile);
|
||||
|
||||
std::unique_ptr<uint8[]> fileContent = std::make_unique<uint8[]>(fileSize);
|
||||
fsc_readFile(fscFile, fileContent.get(), fileSize);
|
||||
fsc_close(fscFile);
|
||||
|
||||
const auto outPath = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/meta/meta.xml", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
|
||||
std::ofstream myFile(outPath, std::ios::out | std::ios::binary);
|
||||
myFile.write((char*)fileContent.get(), fileSize);
|
||||
myFile.close();
|
||||
}
|
||||
|
||||
fscFile = fsc_open((titlePath + "/meta/iconTex.tga").c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &fscStatus);
|
||||
if (fscFile)
|
||||
{
|
||||
sint32 fileSize = fsc_getFileSize(fscFile);
|
||||
|
||||
std::unique_ptr<uint8[]> fileContent = std::make_unique<uint8[]>(fileSize);
|
||||
fsc_readFile(fscFile, fileContent.get(), fileSize);
|
||||
fsc_close(fscFile);
|
||||
|
||||
const auto outPath = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/meta/iconTex.tga", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
|
||||
std::ofstream myFile(outPath, std::ios::out | std::ios::binary);
|
||||
myFile.write((char*)fileContent.get(), fileSize);
|
||||
myFile.close();
|
||||
}
|
||||
|
||||
ACPUpdateSaveTimeStamp(persistentId, titleId, iosu::acp::ACPDeviceType::InternalDeviceType);
|
||||
}
|
||||
|
||||
|
||||
sint32 _ACPCreateSaveDir(uint32 persistentId, uint64 titleId, ACPDeviceType type)
|
||||
{
|
||||
uint32 high = GetTitleIdHigh(titleId) & (~0xC);
|
||||
uint32 low = GetTitleIdLow(titleId);
|
||||
|
||||
sint32 fscStatus = FSC_STATUS_FILE_NOT_FOUND;
|
||||
char path[256];
|
||||
|
||||
sprintf(path, "%susr/boss/", "/vol/storage_mlc01/");
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/", "/vol/storage_mlc01/", high);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/common", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/%08x/", "/vol/storage_mlc01/", high, low, persistentId == 0 ? 0x80000001 : persistentId);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
|
||||
sprintf(path, "%susr/save/%08x/", "/vol/storage_mlc01/", high);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/meta/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/common", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/%08x", "/vol/storage_mlc01/", high, low, persistentId == 0 ? 0x80000001 : persistentId);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
|
||||
// copy xml meta files
|
||||
CreateSaveMetaFiles(persistentId, titleId);
|
||||
return 0;
|
||||
}
|
||||
|
||||
nnResult ACPCreateSaveDir(uint32 persistentId, ACPDeviceType type)
|
||||
{
|
||||
uint64 titleId = CafeSystem::GetForegroundTitleId();
|
||||
return _ACPCreateSaveDir(persistentId, titleId, type);
|
||||
}
|
||||
|
||||
sint32 ACPCreateSaveDirEx(uint8 accountSlot, uint64 titleId)
|
||||
{
|
||||
uint32 persistentId = 0;
|
||||
cemu_assert_debug(accountSlot >= 1 && accountSlot <= 13); // outside valid slot range?
|
||||
bool r = iosu::act::GetPersistentId(accountSlot, &persistentId);
|
||||
cemu_assert_debug(r);
|
||||
return _ACPCreateSaveDir(persistentId, titleId, ACPDeviceType::InternalDeviceType);
|
||||
}
|
||||
|
||||
nnResult ACPGetOlvAccesskey(uint32be* accessKey)
|
||||
{
|
||||
*accessKey = CafeSystem::GetForegroundTitleOlvAccesskey();
|
||||
return 0;
|
||||
}
|
||||
|
||||
class AcpMainService : public iosu::nn::IPCService
|
||||
{
|
||||
public:
|
||||
AcpMainService() : iosu::nn::IPCService("/dev/acp_main") {}
|
||||
|
||||
nnResult ServiceCall(uint32 serviceId, void* request, void* response) override
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Unsupported service call to /dev/acp_main");
|
||||
cemu_assert_unimplemented();
|
||||
return BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_ACP, 0);
|
||||
}
|
||||
};
|
||||
|
||||
AcpMainService gACPMainService;
|
||||
|
||||
class : public ::IOSUModule
|
||||
{
|
||||
void TitleStart() override
|
||||
{
|
||||
gACPMainService.Start();
|
||||
// gACPMainService.SetTimerUpdate(1000); // call TimerUpdate() once a second
|
||||
}
|
||||
void TitleStop() override
|
||||
{
|
||||
gACPMainService.Stop();
|
||||
}
|
||||
}sIOSUModuleNNACP;
|
||||
|
||||
IOSUModule* GetModule()
|
||||
{
|
||||
return static_cast<IOSUModule*>(&sIOSUModuleNNACP);
|
||||
}
|
||||
} // namespace acp
|
||||
} // namespace iosu
|
||||
|
@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "Cafe/IOSU/iosu_types_common.h"
|
||||
#include "Cafe/OS/libs/nn_common.h" // for nnResult
|
||||
|
||||
typedef struct
|
||||
{
|
||||
/* +0x0000 */ uint64 title_id; // parsed via GetHex64
|
||||
@ -192,4 +195,24 @@ typedef struct
|
||||
namespace iosu
|
||||
{
|
||||
void iosuAcp_init();
|
||||
|
||||
namespace acp
|
||||
{
|
||||
enum ACPDeviceType
|
||||
{
|
||||
UnknownType = 0,
|
||||
InternalDeviceType = 1,
|
||||
USBDeviceType = 3,
|
||||
};
|
||||
|
||||
class IOSUModule* GetModule();
|
||||
|
||||
void CreateSaveMetaFiles(uint32 persistentId, uint64 titleId);
|
||||
nnResult ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, ACPDeviceType deviceType);
|
||||
|
||||
nnResult ACPCreateSaveDir(uint32 persistentId, ACPDeviceType type);
|
||||
sint32 ACPCreateSaveDirEx(uint8 accountSlot, uint64 titleId);
|
||||
nnResult ACPGetOlvAccesskey(uint32be* accessKey);
|
||||
}
|
||||
|
||||
}
|
@ -240,6 +240,18 @@ namespace iosu
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GetPersistentId(uint8 slot, uint32* persistentId)
|
||||
{
|
||||
sint32 accountIndex = iosuAct_getAccountIndexBySlot(slot);
|
||||
if(!_actAccountData[accountIndex].isValid)
|
||||
{
|
||||
*persistentId = 0;
|
||||
return false;
|
||||
}
|
||||
*persistentId = _actAccountData[accountIndex].persistentId;
|
||||
return true;
|
||||
}
|
||||
|
||||
class ActService : public iosu::nn::IPCService
|
||||
{
|
||||
public:
|
||||
|
@ -49,6 +49,7 @@ namespace iosu
|
||||
bool getMii(uint8 slot, FFLData_t* fflData);
|
||||
bool getScreenname(uint8 slot, uint16 screenname[ACT_NICKNAME_LENGTH]);
|
||||
bool getCountryIndex(uint8 slot, uint32* countryIndex);
|
||||
bool GetPersistentId(uint8 slot, uint32* persistentId);
|
||||
|
||||
std::string getAccountId2(uint8 slot);
|
||||
|
||||
|
@ -8,7 +8,7 @@ namespace iosu
|
||||
{
|
||||
namespace nn
|
||||
{
|
||||
// a simple service interface which wraps handle management and Ioctlv/IoctlvAsync
|
||||
// a simple service interface which wraps handle management and Ioctlv/IoctlvAsync (used by /dev/fpd and others are still to be determined)
|
||||
class IPCSimpleService
|
||||
{
|
||||
public:
|
||||
@ -88,7 +88,7 @@ namespace iosu
|
||||
uint32be nnResultCode;
|
||||
};
|
||||
|
||||
// a complex service interface which wraps Ioctlv and adds an additional service channel, used by /dev/act, ?
|
||||
// a complex service interface which wraps Ioctlv and adds an additional service channel, used by /dev/act, /dev/acp_main, ?
|
||||
class IPCService
|
||||
{
|
||||
public:
|
||||
|
@ -17,6 +17,8 @@
|
||||
#include "Common/FileStream.h"
|
||||
#include "Cafe/CafeSystem.h"
|
||||
|
||||
using ACPDeviceType = iosu::acp::ACPDeviceType;
|
||||
|
||||
#define acpPrepareRequest() \
|
||||
StackAllocator<iosuAcpCemuRequest_t> _buf_acpRequest; \
|
||||
StackAllocator<ioBufferVector_t> _buf_bufferVector; \
|
||||
@ -30,12 +32,14 @@ namespace nn
|
||||
{
|
||||
namespace acp
|
||||
{
|
||||
ACPStatus _ACPConvertResultToACPStatus(uint32* nnResult, const char* functionName, uint32 someConstant)
|
||||
ACPStatus ACPConvertResultToACPStatus(uint32* nnResult, const char* functionName, uint32 lineNumber)
|
||||
{
|
||||
// todo
|
||||
return ACPStatus::SUCCESS;
|
||||
}
|
||||
|
||||
#define _ACPConvertResultToACPStatus(nnResult) ACPConvertResultToACPStatus(nnResult, __func__, __LINE__)
|
||||
|
||||
ACPStatus ACPGetApplicationBox(uint32be* applicationBox, uint64 titleId)
|
||||
{
|
||||
// todo
|
||||
@ -43,6 +47,12 @@ namespace acp
|
||||
return ACPStatus::SUCCESS;
|
||||
}
|
||||
|
||||
ACPStatus ACPGetOlvAccesskey(uint32be* accessKey)
|
||||
{
|
||||
nnResult r = iosu::acp::ACPGetOlvAccesskey(accessKey);
|
||||
return _ACPConvertResultToACPStatus(&r);
|
||||
}
|
||||
|
||||
bool sSaveDirMounted{false};
|
||||
|
||||
ACPStatus ACPMountSaveDir()
|
||||
@ -56,7 +66,7 @@ namespace acp
|
||||
const auto mlc = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/user/", high, low);
|
||||
FSCDeviceHostFS_Mount("/vol/save/", _pathToUtf8(mlc), FSC_PRIORITY_BASE);
|
||||
nnResult mountResult = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_ACP, 0);
|
||||
return _ACPConvertResultToACPStatus(&mountResult, "ACPMountSaveDir", 0x60);
|
||||
return _ACPConvertResultToACPStatus(&mountResult);
|
||||
}
|
||||
|
||||
ACPStatus ACPUnmountSaveDir()
|
||||
@ -66,201 +76,24 @@ namespace acp
|
||||
return ACPStatus::SUCCESS;
|
||||
}
|
||||
|
||||
uint64 _acpGetTimestamp()
|
||||
{
|
||||
return coreinit::coreinit_getOSTime() / ESPRESSO_TIMER_CLOCK;
|
||||
}
|
||||
|
||||
nnResult __ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, ACPDeviceType deviceType)
|
||||
{
|
||||
if (deviceType == UnknownType)
|
||||
{
|
||||
return (nnResult)0xA030FB80;
|
||||
}
|
||||
|
||||
// create or modify the saveinfo
|
||||
const auto saveinfoPath = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/meta/saveinfo.xml", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
auto saveinfoData = FileStream::LoadIntoMemory(saveinfoPath);
|
||||
if (saveinfoData && !saveinfoData->empty())
|
||||
{
|
||||
namespace xml = tinyxml2;
|
||||
xml::XMLDocument doc;
|
||||
tinyxml2::XMLError xmlError = doc.Parse((const char*)saveinfoData->data(), saveinfoData->size());
|
||||
if (xmlError == xml::XML_SUCCESS || xmlError == xml::XML_ERROR_EMPTY_DOCUMENT)
|
||||
{
|
||||
xml::XMLNode* child = doc.FirstChild();
|
||||
// check for declaration -> <?xml version="1.0" encoding="utf-8"?>
|
||||
if (!child || !child->ToDeclaration())
|
||||
{
|
||||
xml::XMLDeclaration* decl = doc.NewDeclaration();
|
||||
doc.InsertFirstChild(decl);
|
||||
}
|
||||
|
||||
xml::XMLElement* info = doc.FirstChildElement("info");
|
||||
if (!info)
|
||||
{
|
||||
info = doc.NewElement("info");
|
||||
doc.InsertEndChild(info);
|
||||
}
|
||||
|
||||
// find node with persistentId
|
||||
char tmp[64];
|
||||
sprintf(tmp, "%08x", persistentId);
|
||||
bool foundNode = false;
|
||||
for (xml::XMLElement* account = info->FirstChildElement("account"); account; account = account->NextSiblingElement("account"))
|
||||
{
|
||||
if (account->Attribute("persistentId", tmp))
|
||||
{
|
||||
// found the entry! -> update timestamp
|
||||
xml::XMLElement* timestamp = account->FirstChildElement("timestamp");
|
||||
sprintf(tmp, "%" PRIx64, _acpGetTimestamp());
|
||||
if (timestamp)
|
||||
timestamp->SetText(tmp);
|
||||
else
|
||||
{
|
||||
timestamp = doc.NewElement("timestamp");
|
||||
account->InsertFirstChild(timestamp);
|
||||
}
|
||||
|
||||
foundNode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundNode)
|
||||
{
|
||||
tinyxml2::XMLElement* account = doc.NewElement("account");
|
||||
{
|
||||
sprintf(tmp, "%08x", persistentId);
|
||||
account->SetAttribute("persistentId", tmp);
|
||||
|
||||
tinyxml2::XMLElement* timestamp = doc.NewElement("timestamp");
|
||||
{
|
||||
sprintf(tmp, "%" PRIx64, _acpGetTimestamp());
|
||||
timestamp->SetText(tmp);
|
||||
}
|
||||
|
||||
account->InsertFirstChild(timestamp);
|
||||
}
|
||||
|
||||
info->InsertFirstChild(account);
|
||||
}
|
||||
|
||||
// update file
|
||||
tinyxml2::XMLPrinter printer;
|
||||
doc.Print(&printer);
|
||||
FileStream* fs = FileStream::createFile2(saveinfoPath);
|
||||
if (fs)
|
||||
{
|
||||
fs->writeString(printer.CStr());
|
||||
delete fs;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NN_RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ACPStatus ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, ACPDeviceType deviceType)
|
||||
{
|
||||
nnResult r = __ACPUpdateSaveTimeStamp(persistentId, titleId, deviceType);
|
||||
nnResult r = iosu::acp::ACPUpdateSaveTimeStamp(persistentId, titleId, deviceType);
|
||||
return ACPStatus::SUCCESS;
|
||||
}
|
||||
|
||||
void CreateSaveMetaFiles(uint32 persistentId, uint64 titleId)
|
||||
{
|
||||
std::string titlePath = CafeSystem::GetMlcStoragePath(CafeSystem::GetForegroundTitleId());
|
||||
|
||||
sint32 fscStatus;
|
||||
FSCVirtualFile* fscFile = fsc_open((titlePath + "/meta/meta.xml").c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &fscStatus);
|
||||
if (fscFile)
|
||||
{
|
||||
sint32 fileSize = fsc_getFileSize(fscFile);
|
||||
|
||||
std::unique_ptr<uint8[]> fileContent = std::make_unique<uint8[]>(fileSize);
|
||||
fsc_readFile(fscFile, fileContent.get(), fileSize);
|
||||
fsc_close(fscFile);
|
||||
|
||||
const auto outPath = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/meta/meta.xml", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
|
||||
std::ofstream myFile(outPath, std::ios::out | std::ios::binary);
|
||||
myFile.write((char*)fileContent.get(), fileSize);
|
||||
myFile.close();
|
||||
}
|
||||
|
||||
fscFile = fsc_open((titlePath + "/meta/iconTex.tga").c_str(), FSC_ACCESS_FLAG::OPEN_FILE | FSC_ACCESS_FLAG::READ_PERMISSION, &fscStatus);
|
||||
if (fscFile)
|
||||
{
|
||||
sint32 fileSize = fsc_getFileSize(fscFile);
|
||||
|
||||
std::unique_ptr<uint8[]> fileContent = std::make_unique<uint8[]>(fileSize);
|
||||
fsc_readFile(fscFile, fileContent.get(), fileSize);
|
||||
fsc_close(fscFile);
|
||||
|
||||
const auto outPath = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/meta/iconTex.tga", GetTitleIdHigh(titleId), GetTitleIdLow(titleId));
|
||||
|
||||
std::ofstream myFile(outPath, std::ios::out | std::ios::binary);
|
||||
myFile.write((char*)fileContent.get(), fileSize);
|
||||
myFile.close();
|
||||
}
|
||||
|
||||
ACPUpdateSaveTimeStamp(persistentId, titleId, InternalDeviceType);
|
||||
}
|
||||
|
||||
nnResult CreateSaveDir(uint32 persistentId, ACPDeviceType type)
|
||||
{
|
||||
uint64 titleId = CafeSystem::GetForegroundTitleId();
|
||||
uint32 high = GetTitleIdHigh(titleId) & (~0xC);
|
||||
uint32 low = GetTitleIdLow(titleId);
|
||||
|
||||
sint32 fscStatus = FSC_STATUS_FILE_NOT_FOUND;
|
||||
char path[256];
|
||||
|
||||
sprintf(path, "%susr/save/%08x/", "/vol/storage_mlc01/", high);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/meta/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/common", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/save/%08x/%08x/user/%08x", "/vol/storage_mlc01/", high, low, persistentId == 0 ? 0x80000001 : persistentId);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
|
||||
// not sure about this
|
||||
sprintf(path, "%susr/boss/", "/vol/storage_mlc01/");
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/", "/vol/storage_mlc01/", high);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/common", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
sprintf(path, "%susr/boss/%08x/%08x/user/%08x/", "/vol/storage_mlc01/", high, low, persistentId == 0 ? 0x80000001 : persistentId);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
|
||||
// copy xml meta files
|
||||
CreateSaveMetaFiles(persistentId, titleId);
|
||||
|
||||
nnResult result = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_ACP, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
ACPStatus ACPCreateSaveDir(uint32 persistentId, ACPDeviceType type)
|
||||
{
|
||||
nnResult result = CreateSaveDir(persistentId, type);
|
||||
return _ACPConvertResultToACPStatus(&result, "ACPCreateSaveDir", 0x2FA);
|
||||
}
|
||||
|
||||
ACPStatus ACPCheckApplicationDeviceEmulation(uint32be* isEmulated)
|
||||
{
|
||||
*isEmulated = 0;
|
||||
return ACPStatus::SUCCESS;
|
||||
}
|
||||
|
||||
ACPStatus ACPCreateSaveDir(uint32 persistentId, ACPDeviceType type)
|
||||
{
|
||||
nnResult result = iosu::acp::ACPCreateSaveDir(persistentId, type);
|
||||
return _ACPConvertResultToACPStatus(&result);
|
||||
}
|
||||
|
||||
nnResult ACPCreateSaveDirEx(uint8 accountSlot, uint64 titleId)
|
||||
{
|
||||
acpPrepareRequest();
|
||||
@ -279,7 +112,7 @@ namespace acp
|
||||
ppcDefineParamU8(accountSlot, 0);
|
||||
ppcDefineParamU64(titleId, 2); // index 2 because of alignment -> guessed parameters
|
||||
nnResult result = ACPCreateSaveDirEx(accountSlot, titleId);
|
||||
osLib_returnFromFunction(hCPU, _ACPConvertResultToACPStatus(&result, "ACPCreateSaveDirEx", 0x300));
|
||||
osLib_returnFromFunction(hCPU, _ACPConvertResultToACPStatus(&result));
|
||||
}
|
||||
|
||||
void export_ACPGetSaveDataTitleIdList(PPCInterpreter_t* hCPU)
|
||||
@ -511,6 +344,8 @@ namespace acp
|
||||
|
||||
cafeExportRegister("nn_acp", ACPGetApplicationBox, LogType::Placeholder);
|
||||
|
||||
cafeExportRegister("nn_acp", ACPGetOlvAccesskey, LogType::Placeholder);
|
||||
|
||||
osLib_addFunction("nn_acp", "ACPIsOverAgeEx", export_ACPIsOverAgeEx);
|
||||
|
||||
osLib_addFunction("nn_acp", "ACPGetNetworkTime", export_ACPGetNetworkTime);
|
||||
|
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
#include "Cafe/IOSU/legacy/iosu_acp.h"
|
||||
|
||||
namespace nn
|
||||
{
|
||||
@ -9,20 +10,13 @@ namespace acp
|
||||
SUCCESS = 0,
|
||||
};
|
||||
|
||||
enum ACPDeviceType
|
||||
{
|
||||
UnknownType = 0,
|
||||
InternalDeviceType = 1,
|
||||
USBDeviceType = 3,
|
||||
};
|
||||
|
||||
void CreateSaveMetaFiles(uint32 persistentId, uint64 titleId);
|
||||
using ACPDeviceType = iosu::acp::ACPDeviceType;
|
||||
|
||||
ACPStatus ACPGetApplicationBox(uint32be* applicationBox, uint64 titleId);
|
||||
ACPStatus ACPMountSaveDir();
|
||||
ACPStatus ACPUnmountSaveDir();
|
||||
ACPStatus ACPCreateSaveDir(uint32 persistentId, ACPDeviceType type);
|
||||
ACPStatus ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, ACPDeviceType deviceType);;
|
||||
ACPStatus ACPCreateSaveDir(uint32 persistentId, iosu::acp::ACPDeviceType type);
|
||||
ACPStatus ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, iosu::acp::ACPDeviceType deviceType);
|
||||
|
||||
void load();
|
||||
}
|
||||
|
@ -72,11 +72,11 @@ namespace save
|
||||
return result != 0;
|
||||
}
|
||||
|
||||
bool GetCurrentTitleApplicationBox(acp::ACPDeviceType* deviceType)
|
||||
bool GetCurrentTitleApplicationBox(nn::acp::ACPDeviceType* deviceType)
|
||||
{
|
||||
if (deviceType)
|
||||
{
|
||||
*deviceType = acp::InternalDeviceType;
|
||||
*deviceType = nn::acp::ACPDeviceType::InternalDeviceType;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -84,7 +84,7 @@ namespace save
|
||||
|
||||
void UpdateSaveTimeStamp(uint32 persistentId)
|
||||
{
|
||||
acp::ACPDeviceType deviceType;
|
||||
nn::acp::ACPDeviceType deviceType;
|
||||
if (GetCurrentTitleApplicationBox(&deviceType))
|
||||
ACPUpdateSaveTimeStamp(persistentId, CafeSystem::GetForegroundTitleId(), deviceType);
|
||||
}
|
||||
@ -314,7 +314,7 @@ namespace save
|
||||
sprintf(path, "%susr/save/%08x/%08x/meta/", "/vol/storage_mlc01/", high, low);
|
||||
fsc_createDir(path, &fscStatus);
|
||||
|
||||
acp::CreateSaveMetaFiles(ActiveSettings::GetPersistentId(), titleId);
|
||||
iosu::acp::CreateSaveMetaFiles(ActiveSettings::GetPersistentId(), titleId);
|
||||
}
|
||||
|
||||
return SAVE_STATUS_OK;
|
||||
@ -669,7 +669,7 @@ namespace save
|
||||
uint32 persistentId;
|
||||
if (GetPersistentIdEx(accountSlot, &persistentId))
|
||||
{
|
||||
acp::ACPStatus status = ACPCreateSaveDir(persistentId, acp::InternalDeviceType);
|
||||
acp::ACPStatus status = nn::acp::ACPCreateSaveDir(persistentId, iosu::acp::ACPDeviceType::InternalDeviceType);
|
||||
result = ConvertACPToSaveStatus(status);
|
||||
}
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user