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:
Exzap 2024-04-10 20:22:17 +02:00
parent 33a74c2035
commit 12eda10387
9 changed files with 314 additions and 249 deletions

View File

@ -530,6 +530,7 @@ namespace CafeSystem
{ {
// entries in this list are ordered by initialization order. Shutdown in reverse order // entries in this list are ordered by initialization order. Shutdown in reverse order
iosu::kernel::GetModule(), iosu::kernel::GetModule(),
iosu::acp::GetModule(),
iosu::fpd::GetModule(), iosu::fpd::GetModule(),
iosu::pdm::GetModule(), iosu::pdm::GetModule(),
}; };

View File

@ -8,10 +8,19 @@
#include "Cafe/OS/libs/nn_acp/nn_acp.h" #include "Cafe/OS/libs/nn_acp/nn_acp.h"
#include "Cafe/OS/libs/coreinit/coreinit_FS.h" #include "Cafe/OS/libs/coreinit/coreinit_FS.h"
#include "Cafe/Filesystem/fsc.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> #include <inttypes.h>
using ACPDeviceType = iosu::acp::ACPDeviceType;
static_assert(sizeof(acpMetaXml_t) == 0x3440); static_assert(sizeof(acpMetaXml_t) == 0x3440);
static_assert(offsetof(acpMetaXml_t, title_id) == 0x0000); static_assert(offsetof(acpMetaXml_t, title_id) == 0x0000);
static_assert(offsetof(acpMetaXml_t, boss_id) == 0x0008); static_assert(offsetof(acpMetaXml_t, boss_id) == 0x0008);
@ -506,48 +515,6 @@ namespace iosu
return 0; 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() int iosuAcp_thread()
{ {
SetThreadName("iosuAcp_thread"); SetThreadName("iosuAcp_thread");
@ -584,7 +551,7 @@ namespace iosu
} }
else if (acpCemuRequest->requestCode == IOSU_ACP_CREATE_SAVE_DIR_EX) 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 else
cemu_assert_unimplemented(); cemu_assert_unimplemented();
@ -610,5 +577,237 @@ namespace iosu
return iosuAcp.isInitialized; 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

View File

@ -1,5 +1,8 @@
#pragma once #pragma once
#include "Cafe/IOSU/iosu_types_common.h"
#include "Cafe/OS/libs/nn_common.h" // for nnResult
typedef struct typedef struct
{ {
/* +0x0000 */ uint64 title_id; // parsed via GetHex64 /* +0x0000 */ uint64 title_id; // parsed via GetHex64
@ -192,4 +195,24 @@ typedef struct
namespace iosu namespace iosu
{ {
void iosuAcp_init(); 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);
}
} }

View File

@ -240,6 +240,18 @@ namespace iosu
return true; 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 class ActService : public iosu::nn::IPCService
{ {
public: public:

View File

@ -49,6 +49,7 @@ namespace iosu
bool getMii(uint8 slot, FFLData_t* fflData); bool getMii(uint8 slot, FFLData_t* fflData);
bool getScreenname(uint8 slot, uint16 screenname[ACT_NICKNAME_LENGTH]); bool getScreenname(uint8 slot, uint16 screenname[ACT_NICKNAME_LENGTH]);
bool getCountryIndex(uint8 slot, uint32* countryIndex); bool getCountryIndex(uint8 slot, uint32* countryIndex);
bool GetPersistentId(uint8 slot, uint32* persistentId);
std::string getAccountId2(uint8 slot); std::string getAccountId2(uint8 slot);

View File

@ -8,7 +8,7 @@ namespace iosu
{ {
namespace nn 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 class IPCSimpleService
{ {
public: public:
@ -88,7 +88,7 @@ namespace iosu
uint32be nnResultCode; 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 class IPCService
{ {
public: public:

View File

@ -17,6 +17,8 @@
#include "Common/FileStream.h" #include "Common/FileStream.h"
#include "Cafe/CafeSystem.h" #include "Cafe/CafeSystem.h"
using ACPDeviceType = iosu::acp::ACPDeviceType;
#define acpPrepareRequest() \ #define acpPrepareRequest() \
StackAllocator<iosuAcpCemuRequest_t> _buf_acpRequest; \ StackAllocator<iosuAcpCemuRequest_t> _buf_acpRequest; \
StackAllocator<ioBufferVector_t> _buf_bufferVector; \ StackAllocator<ioBufferVector_t> _buf_bufferVector; \
@ -30,12 +32,14 @@ namespace nn
{ {
namespace acp namespace acp
{ {
ACPStatus _ACPConvertResultToACPStatus(uint32* nnResult, const char* functionName, uint32 someConstant) ACPStatus ACPConvertResultToACPStatus(uint32* nnResult, const char* functionName, uint32 lineNumber)
{ {
// todo // todo
return ACPStatus::SUCCESS; return ACPStatus::SUCCESS;
} }
#define _ACPConvertResultToACPStatus(nnResult) ACPConvertResultToACPStatus(nnResult, __func__, __LINE__)
ACPStatus ACPGetApplicationBox(uint32be* applicationBox, uint64 titleId) ACPStatus ACPGetApplicationBox(uint32be* applicationBox, uint64 titleId)
{ {
// todo // todo
@ -43,6 +47,12 @@ namespace acp
return ACPStatus::SUCCESS; return ACPStatus::SUCCESS;
} }
ACPStatus ACPGetOlvAccesskey(uint32be* accessKey)
{
nnResult r = iosu::acp::ACPGetOlvAccesskey(accessKey);
return _ACPConvertResultToACPStatus(&r);
}
bool sSaveDirMounted{false}; bool sSaveDirMounted{false};
ACPStatus ACPMountSaveDir() ACPStatus ACPMountSaveDir()
@ -56,7 +66,7 @@ namespace acp
const auto mlc = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/user/", high, low); const auto mlc = ActiveSettings::GetMlcPath("usr/save/{:08x}/{:08x}/user/", high, low);
FSCDeviceHostFS_Mount("/vol/save/", _pathToUtf8(mlc), FSC_PRIORITY_BASE); FSCDeviceHostFS_Mount("/vol/save/", _pathToUtf8(mlc), FSC_PRIORITY_BASE);
nnResult mountResult = BUILD_NN_RESULT(NN_RESULT_LEVEL_SUCCESS, NN_RESULT_MODULE_NN_ACP, 0); 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() ACPStatus ACPUnmountSaveDir()
@ -66,201 +76,24 @@ namespace acp
return ACPStatus::SUCCESS; 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) 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; 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) ACPStatus ACPCheckApplicationDeviceEmulation(uint32be* isEmulated)
{ {
*isEmulated = 0; *isEmulated = 0;
return ACPStatus::SUCCESS; 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) nnResult ACPCreateSaveDirEx(uint8 accountSlot, uint64 titleId)
{ {
acpPrepareRequest(); acpPrepareRequest();
@ -279,7 +112,7 @@ namespace acp
ppcDefineParamU8(accountSlot, 0); ppcDefineParamU8(accountSlot, 0);
ppcDefineParamU64(titleId, 2); // index 2 because of alignment -> guessed parameters ppcDefineParamU64(titleId, 2); // index 2 because of alignment -> guessed parameters
nnResult result = ACPCreateSaveDirEx(accountSlot, titleId); nnResult result = ACPCreateSaveDirEx(accountSlot, titleId);
osLib_returnFromFunction(hCPU, _ACPConvertResultToACPStatus(&result, "ACPCreateSaveDirEx", 0x300)); osLib_returnFromFunction(hCPU, _ACPConvertResultToACPStatus(&result));
} }
void export_ACPGetSaveDataTitleIdList(PPCInterpreter_t* hCPU) void export_ACPGetSaveDataTitleIdList(PPCInterpreter_t* hCPU)
@ -511,6 +344,8 @@ namespace acp
cafeExportRegister("nn_acp", ACPGetApplicationBox, LogType::Placeholder); cafeExportRegister("nn_acp", ACPGetApplicationBox, LogType::Placeholder);
cafeExportRegister("nn_acp", ACPGetOlvAccesskey, LogType::Placeholder);
osLib_addFunction("nn_acp", "ACPIsOverAgeEx", export_ACPIsOverAgeEx); osLib_addFunction("nn_acp", "ACPIsOverAgeEx", export_ACPIsOverAgeEx);
osLib_addFunction("nn_acp", "ACPGetNetworkTime", export_ACPGetNetworkTime); osLib_addFunction("nn_acp", "ACPGetNetworkTime", export_ACPGetNetworkTime);

View File

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "Cafe/IOSU/legacy/iosu_acp.h"
namespace nn namespace nn
{ {
@ -9,20 +10,13 @@ namespace acp
SUCCESS = 0, SUCCESS = 0,
}; };
enum ACPDeviceType using ACPDeviceType = iosu::acp::ACPDeviceType;
{
UnknownType = 0,
InternalDeviceType = 1,
USBDeviceType = 3,
};
void CreateSaveMetaFiles(uint32 persistentId, uint64 titleId);
ACPStatus ACPGetApplicationBox(uint32be* applicationBox, uint64 titleId); ACPStatus ACPGetApplicationBox(uint32be* applicationBox, uint64 titleId);
ACPStatus ACPMountSaveDir(); ACPStatus ACPMountSaveDir();
ACPStatus ACPUnmountSaveDir(); ACPStatus ACPUnmountSaveDir();
ACPStatus ACPCreateSaveDir(uint32 persistentId, ACPDeviceType type); ACPStatus ACPCreateSaveDir(uint32 persistentId, iosu::acp::ACPDeviceType type);
ACPStatus ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, ACPDeviceType deviceType);; ACPStatus ACPUpdateSaveTimeStamp(uint32 persistentId, uint64 titleId, iosu::acp::ACPDeviceType deviceType);
void load(); void load();
} }

View File

@ -72,11 +72,11 @@ namespace save
return result != 0; return result != 0;
} }
bool GetCurrentTitleApplicationBox(acp::ACPDeviceType* deviceType) bool GetCurrentTitleApplicationBox(nn::acp::ACPDeviceType* deviceType)
{ {
if (deviceType) if (deviceType)
{ {
*deviceType = acp::InternalDeviceType; *deviceType = nn::acp::ACPDeviceType::InternalDeviceType;
return true; return true;
} }
return false; return false;
@ -84,7 +84,7 @@ namespace save
void UpdateSaveTimeStamp(uint32 persistentId) void UpdateSaveTimeStamp(uint32 persistentId)
{ {
acp::ACPDeviceType deviceType; nn::acp::ACPDeviceType deviceType;
if (GetCurrentTitleApplicationBox(&deviceType)) if (GetCurrentTitleApplicationBox(&deviceType))
ACPUpdateSaveTimeStamp(persistentId, CafeSystem::GetForegroundTitleId(), deviceType); ACPUpdateSaveTimeStamp(persistentId, CafeSystem::GetForegroundTitleId(), deviceType);
} }
@ -314,7 +314,7 @@ namespace save
sprintf(path, "%susr/save/%08x/%08x/meta/", "/vol/storage_mlc01/", high, low); sprintf(path, "%susr/save/%08x/%08x/meta/", "/vol/storage_mlc01/", high, low);
fsc_createDir(path, &fscStatus); fsc_createDir(path, &fscStatus);
acp::CreateSaveMetaFiles(ActiveSettings::GetPersistentId(), titleId); iosu::acp::CreateSaveMetaFiles(ActiveSettings::GetPersistentId(), titleId);
} }
return SAVE_STATUS_OK; return SAVE_STATUS_OK;
@ -669,7 +669,7 @@ namespace save
uint32 persistentId; uint32 persistentId;
if (GetPersistentIdEx(accountSlot, &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); result = ConvertACPToSaveStatus(status);
} }
else else