mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-08 07:05:40 +12:00
SaveIcon and ReadExtSaveDataIcon
This commit is contained in:
parent
556b3b8913
commit
d4594446bd
6 changed files with 110 additions and 18 deletions
|
@ -57,6 +57,14 @@ namespace ArchiveID {
|
|||
}
|
||||
}
|
||||
|
||||
namespace MediaType {
|
||||
enum : u8 {
|
||||
NAND = 0,
|
||||
SD = 1,
|
||||
Gamecard = 2
|
||||
};
|
||||
};
|
||||
|
||||
struct FSPath {
|
||||
u32 type = PathType::Invalid;
|
||||
|
||||
|
|
|
@ -22,6 +22,9 @@ public:
|
|||
std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) override;
|
||||
void format(const FSPath& path, const FormatInfo& info) override;
|
||||
Rust::Result<FormatInfo, HorizonResult> getFormatInfo(const FSPath& path) override;
|
||||
void clear(const FSPath& path) const;
|
||||
void saveIcon(const std::vector<u8>& data) const;
|
||||
Rust::Result<std::vector<u8>, HorizonResult> loadIcon() const;
|
||||
|
||||
std::filesystem::path getFormatInfoPath(const FSPath& path) const;
|
||||
std::filesystem::path getUserDataPath() const;
|
||||
|
|
|
@ -42,6 +42,7 @@ class FSService {
|
|||
Rust::Result<Handle, HorizonResult> openDirectoryHandle(ArchiveBase* archive, const FSPath& path);
|
||||
std::optional<Handle> openFileHandle(ArchiveBase* archive, const FSPath& path, const FSPath& archivePath, const FilePerms& perms);
|
||||
FSPath readPath(u32 type, u32 pointer, u32 size);
|
||||
void writePointer(const u8* data, u32 pointer, u32 size);
|
||||
|
||||
const EmulatorConfig& config;
|
||||
|
||||
|
@ -78,6 +79,7 @@ class FSService {
|
|||
void setArchivePriority(u32 messagePointer);
|
||||
void setPriority(u32 messagePointer);
|
||||
void setThisSaveDataSecureValue(u32 messagePointer);
|
||||
void readExtSaveDataIcon(u32 messagePointer);
|
||||
|
||||
// Used for set/get priority: Not sure what sort of priority this is referring to
|
||||
u32 priority;
|
||||
|
|
|
@ -221,6 +221,35 @@ void ExtSaveDataArchive::format(const FSPath& path, const FormatInfo& info) {
|
|||
file.close();
|
||||
}
|
||||
|
||||
void ExtSaveDataArchive::clear(const FSPath& path) const {
|
||||
const fs::path saveDataPath = IOFile::getAppData() / backingFolder;
|
||||
const fs::path formatInfoPath = getFormatInfoPath(path);
|
||||
|
||||
fs::remove_all(saveDataPath);
|
||||
fs::remove(formatInfoPath);
|
||||
}
|
||||
|
||||
void ExtSaveDataArchive::saveIcon(const std::vector<u8>& data) const {
|
||||
const fs::path iconPath = IOFile::getAppData() / backingFolder / "icon";
|
||||
IOFile file(iconPath, "wb");
|
||||
file.setSize(data.size());
|
||||
file.writeBytes(data.data(), data.size());
|
||||
file.flush();
|
||||
file.close();
|
||||
}
|
||||
|
||||
Rust::Result<std::vector<u8>, HorizonResult> ExtSaveDataArchive::loadIcon() const {
|
||||
const fs::path iconPath = IOFile::getAppData() / backingFolder / "icon";
|
||||
IOFile file(iconPath, "rb");
|
||||
const s32 size = static_cast<s32>(file.size().value_or(-1));
|
||||
if(size < 0) {
|
||||
return Err(Result::FS::NotFoundInvalid);
|
||||
}
|
||||
std::unique_ptr<u8[]> data(new u8[size]);
|
||||
file.readBytes(data.get(), size);
|
||||
return Ok(std::vector(data.get(), data.get() + size));
|
||||
}
|
||||
|
||||
std::filesystem::path ExtSaveDataArchive::getFormatInfoPath(const FSPath& path) const {
|
||||
return IOFile::getAppData() / "FormatInfo" / (getExtSaveDataPathFromBinary(path) + ".format");
|
||||
}
|
||||
|
|
|
@ -13,14 +13,6 @@ namespace PathType {
|
|||
};
|
||||
};
|
||||
|
||||
namespace MediaType {
|
||||
enum : u8 {
|
||||
NAND = 0,
|
||||
SD = 1,
|
||||
Gamecard = 2
|
||||
};
|
||||
};
|
||||
|
||||
HorizonResult NCCHArchive::createFile(const FSPath& path, u64 size) {
|
||||
Helpers::panic("[NCCH] CreateFile not yet supported");
|
||||
return Result::Success;
|
||||
|
|
|
@ -37,6 +37,7 @@ namespace FSCommands {
|
|||
FormatSaveData = 0x084C0242,
|
||||
CreateExtSaveData = 0x08510242,
|
||||
DeleteExtSaveData = 0x08520100,
|
||||
ReadExtSaveDataIcon = 0x08530142,
|
||||
SetArchivePriority = 0x085A00C0,
|
||||
InitializeWithSdkVersion = 0x08610042,
|
||||
SetPriority = 0x08620040,
|
||||
|
@ -163,6 +164,11 @@ FSPath FSService::readPath(u32 type, u32 pointer, u32 size) {
|
|||
return FSPath(type, data);
|
||||
}
|
||||
|
||||
void FSService::writePointer(const u8* data, u32 pointer, u32 size) {
|
||||
for (u32 i = 0; i < size; i++)
|
||||
mem.write8(pointer + i, data[i]);
|
||||
}
|
||||
|
||||
void FSService::handleSyncRequest(u32 messagePointer) {
|
||||
const u32 command = mem.read32(messagePointer);
|
||||
switch (command) {
|
||||
|
@ -197,6 +203,7 @@ void FSService::handleSyncRequest(u32 messagePointer) {
|
|||
case FSCommands::SetPriority: setPriority(messagePointer); break;
|
||||
case FSCommands::SetThisSaveDataSecureValue: setThisSaveDataSecureValue(messagePointer); break;
|
||||
case FSCommands::AbnegateAccessRight: abnegateAccessRight(messagePointer); break;
|
||||
case FSCommands::ReadExtSaveDataIcon: readExtSaveDataIcon(messagePointer); break;
|
||||
case FSCommands::TheGameboyVCFunction: theGameboyVCFunction(messagePointer); break;
|
||||
default: Helpers::panic("FS service requested. Command: %08X\n", command);
|
||||
}
|
||||
|
@ -432,7 +439,7 @@ void FSService::deleteDirectory(u32 messagePointer) {
|
|||
const u32 filePathPointer = mem.read32(messagePointer + 28);
|
||||
log("FS::DeleteDirectory\n");
|
||||
|
||||
Helpers::warn("Stubbed FS::DeleteDirectory call!"); // note: should we ensure the system isn't about to delete things outside of the VFS?
|
||||
Helpers::warn("Stubbed FS::DeleteDirectory call!");
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x806, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
@ -444,7 +451,7 @@ void FSService::deleteDirectoryRecursively(u32 messagePointer) {
|
|||
const u32 filePathPointer = mem.read32(messagePointer + 28);
|
||||
log("FS::DeleteDirectoryRecursively\n");
|
||||
|
||||
Helpers::warn("Stubbed FS::DeleteDirectoryRecursively call!"); // note: should we ensure the system isn't about to delete things outside of the VFS?
|
||||
Helpers::warn("Stubbed FS::DeleteDirectoryRecursively call!");
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x807, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
@ -524,26 +531,40 @@ void FSService::deleteExtSaveData(u32 messagePointer) {
|
|||
const u64 saveID = mem.read64(messagePointer + 8);
|
||||
log("FS::DeleteExtSaveData (media type = %d, saveID = %llx) (stubbed)\n", mediaType, saveID);
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x0852, 1, 0));
|
||||
// TODO: We can't properly implement this yet until we properly support title/save IDs. We will stub this and insert a warning for now. Required for Planet Robobot
|
||||
// When we properly implement it, it will just be a recursive directory deletion
|
||||
/*
|
||||
FSPath path = readPath(PathType::Binary, messagePointer + 4, 8);
|
||||
|
||||
switch(mediaType) {
|
||||
case MediaType::NAND:
|
||||
sharedExtSaveData_nand.clear(path);
|
||||
break;
|
||||
case MediaType::SD:
|
||||
extSaveData_sdmc.clear(path);
|
||||
break;
|
||||
default:
|
||||
Helpers::warn("FS::DeleteExtSaveData - Unhandled ExtSaveData MediaType %d", static_cast<s32>(mediaType));
|
||||
break;
|
||||
}
|
||||
*/
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x0852, 1, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
void FSService::createExtSaveData(u32 messagePointer) {
|
||||
Helpers::warn("Stubbed call to FS::CreateExtSaveData!");
|
||||
log("FS::CreateExtSaveData\n");
|
||||
// First 4 words of parameters are the ExtSaveData info
|
||||
// https://www.3dbrew.org/wiki/Filesystem_services#ExtSaveDataInfo
|
||||
// This creates the ExtSaveData with the specified saveid in the specified media type. It stores the SMDH as "icon" in the root of the created directory.
|
||||
const u8 mediaType = mem.read8(messagePointer + 4);
|
||||
const u64 saveID = mem.read64(messagePointer + 8);
|
||||
const u64 saveID = mem.read64(messagePointer + 8); // todo: <-- how should this be used? ATM everything is in the same space.
|
||||
const u32 numOfDirectories = mem.read32(messagePointer + 20);
|
||||
const u32 numOfFiles = mem.read32(messagePointer + 24);
|
||||
const u64 sizeLimit = mem.read64(messagePointer + 28);
|
||||
const u32 smdhSize = mem.read32(messagePointer + 36);
|
||||
const u32 smdhPointer = mem.read32(messagePointer + 44);
|
||||
|
||||
log("FS::CreateExtSaveData\n");
|
||||
ArchiveBase::FormatInfo info {
|
||||
.size = (u32) (sizeLimit * 0x200),
|
||||
.numOfDirectories = numOfDirectories,
|
||||
|
@ -554,14 +575,16 @@ void FSService::createExtSaveData(u32 messagePointer) {
|
|||
FSPath smdh = readPath(PathType::Binary, smdhPointer, smdhSize);
|
||||
|
||||
switch(mediaType) {
|
||||
case 0:
|
||||
case MediaType::NAND:
|
||||
sharedExtSaveData_nand.format(path, info);
|
||||
sharedExtSaveData_nand.saveIcon(smdh.binary);
|
||||
break;
|
||||
case 1:
|
||||
case MediaType::SD:
|
||||
extSaveData_sdmc.format(path, info);
|
||||
extSaveData_sdmc.saveIcon(smdh.binary);
|
||||
break;
|
||||
default:
|
||||
Helpers::warn("Unhandled ExtSaveData MediaType %d", static_cast<s32>(mediaType));
|
||||
Helpers::warn("FS::CreateExtSaveData - Unhandled ExtSaveData MediaType %d", static_cast<s32>(mediaType));
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -569,6 +592,41 @@ void FSService::createExtSaveData(u32 messagePointer) {
|
|||
mem.write32(messagePointer + 4, Result::Success);
|
||||
}
|
||||
|
||||
void FSService::readExtSaveDataIcon(u32 messagePointer) {
|
||||
log("FS::ReadExtSaveDataIcon\n");
|
||||
const u8 mediaType = mem.read8(messagePointer + 4);
|
||||
const u64 saveID = mem.read64(messagePointer + 8); // todo: <-- is this used?
|
||||
const u32 smdhSize = mem.read32(messagePointer + 20);
|
||||
const u32 smdhPointer = mem.read32(messagePointer + 28);
|
||||
|
||||
ExtSaveDataArchive* selected = nullptr;
|
||||
switch(mediaType) {
|
||||
case MediaType::NAND:
|
||||
selected = &sharedExtSaveData_nand;
|
||||
break;
|
||||
case MediaType::SD:
|
||||
selected = &extSaveData_sdmc;
|
||||
break;
|
||||
default:
|
||||
Helpers::warn("FS::ReadExtSaveDataIcon - Unhandled ExtSaveData MediaType %d", static_cast<s32>(mediaType));
|
||||
break;
|
||||
}
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x0851, 1, 0));
|
||||
|
||||
Rust::Result<std::vector<u8>, HorizonResult> data = selected == nullptr ? Err(Result::FS::NotFoundInvalid) : selected->loadIcon();
|
||||
if(data.isErr()) {
|
||||
mem.write32(messagePointer + 4, data.unwrapErr());;
|
||||
mem.write32(messagePointer + 8, 0);
|
||||
} else {
|
||||
const std::vector<u8> buffer = data.unwrap<std::vector<u8>>();
|
||||
const u32 copySize = std::min(smdhSize, static_cast<u32>(buffer.size()));
|
||||
writePointer(buffer.data(), smdhPointer, copySize);
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write32(messagePointer + 8, copySize);
|
||||
}
|
||||
}
|
||||
|
||||
void FSService::formatThisUserSaveData(u32 messagePointer) {
|
||||
log("FS::FormatThisUserSaveData\n");
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue