mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-06 22:25:41 +12:00
commit
572e8ea1f7
6 changed files with 94 additions and 2 deletions
|
@ -246,6 +246,11 @@ public:
|
|||
Helpers::panic("Unimplemented Format for %s archive", name().c_str());
|
||||
}
|
||||
|
||||
virtual HorizonResult renameFile(const FSPath& oldPath, const FSPath& newPath) {
|
||||
Helpers::panic("Unimplemented RenameFile for %s archive", name().c_str());
|
||||
return Result::Success;
|
||||
}
|
||||
|
||||
// Read size bytes from a file starting at offset "offset" into a certain buffer in memory
|
||||
// Returns the number of bytes read, or nullopt if the read failed
|
||||
virtual std::optional<u32> readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) = 0;
|
||||
|
|
|
@ -23,6 +23,7 @@ class CFGService {
|
|||
void genUniqueConsoleHash(u32 messagePointer);
|
||||
void secureInfoGetByte101(u32 messagePointer);
|
||||
void secureInfoGetRegion(u32 messagePointer);
|
||||
void translateCountryInfo(u32 messagePointer);
|
||||
|
||||
void getConfigInfo(u32 output, u32 blockID, u32 size, u32 permissionMask);
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ class FSService {
|
|||
void openDirectory(u32 messagePointer);
|
||||
void openFile(u32 messagePointer);
|
||||
void openFileDirectly(u32 messagePointer);
|
||||
void renameFile(u32 messagePointer);
|
||||
void setArchivePriority(u32 messagePointer);
|
||||
void setPriority(u32 messagePointer);
|
||||
void setThisSaveDataSecureValue(u32 messagePointer);
|
||||
|
|
|
@ -74,12 +74,13 @@ std::optional<u32> NCCHArchive::readFile(FileSession* file, u64 offset, u32 size
|
|||
const u32 lowProgramID = *(u32*)&archivePath[0];
|
||||
const u32 highProgramID = *(u32*)&archivePath[4];
|
||||
|
||||
// High Title ID of the archive (from Citra). https://3dbrew.org/wiki/Title_list.
|
||||
// High Title ID of the archive: https://3dbrew.org/wiki/Title_list.
|
||||
constexpr u32 sharedDataArchive = 0x0004009B;
|
||||
constexpr u32 systemDataArchive = 0x000400DB;
|
||||
|
||||
// Low ID (taken from Citra)
|
||||
// Low IDs
|
||||
constexpr u32 miiData = 0x00010202;
|
||||
constexpr u32 tlsRootCertificates = 0x00010602;
|
||||
constexpr u32 regionManifest = 0x00010402;
|
||||
constexpr u32 badWordList = 0x00010302;
|
||||
constexpr u32 sharedFont = 0x00014002;
|
||||
|
@ -88,6 +89,10 @@ std::optional<u32> NCCHArchive::readFile(FileSession* file, u64 offset, u32 size
|
|||
if (highProgramID == sharedDataArchive) {
|
||||
if (lowProgramID == miiData) fileData = std::vector<u8>(std::begin(MII_DATA), std::end(MII_DATA));
|
||||
else if (lowProgramID == regionManifest) fileData = std::vector<u8>(std::begin(COUNTRY_LIST_DATA), std::end(COUNTRY_LIST_DATA));
|
||||
else if (lowProgramID == tlsRootCertificates) {
|
||||
Helpers::warn("Read from Shared Data archive 00010602");
|
||||
return 0;
|
||||
}
|
||||
else Helpers::panic("[NCCH archive] Read unimplemented NAND file. ID: %08X", lowProgramID);
|
||||
} else if (highProgramID == systemDataArchive && lowProgramID == badWordList) {
|
||||
fileData = std::vector<u8>(std::begin(BAD_WORD_LIST_DATA), std::end(BAD_WORD_LIST_DATA));
|
||||
|
|
|
@ -16,6 +16,7 @@ namespace CFGCommands {
|
|||
GenHashConsoleUnique = 0x00030040,
|
||||
GetRegionCanadaUSA = 0x00040000,
|
||||
GetSystemModel = 0x00050000,
|
||||
TranslateCountryInfo = 0x00080080,
|
||||
GetCountryCodeID = 0x000A0040,
|
||||
|
||||
GetLocalFriendCodeSeed = 0x04050000,
|
||||
|
@ -34,6 +35,7 @@ void CFGService::handleSyncRequest(u32 messagePointer, CFGService::Type type) {
|
|||
case CFGCommands::GetSystemModel: getSystemModel(messagePointer); break;
|
||||
case CFGCommands::GenHashConsoleUnique: genUniqueConsoleHash(messagePointer); break;
|
||||
case CFGCommands::SecureInfoGetRegion: secureInfoGetRegion(messagePointer); break;
|
||||
case CFGCommands::TranslateCountryInfo: translateCountryInfo(messagePointer); break;
|
||||
|
||||
default:
|
||||
if (type == Type::S) {
|
||||
|
@ -256,4 +258,38 @@ void CFGService::getLocalFriendCodeSeed(u32 messagePointer) {
|
|||
mem.write32(messagePointer, IPC::responseHeader(0x405, 3, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write64(messagePointer + 8, 0);
|
||||
}
|
||||
|
||||
// https://www.3dbrew.org/wiki/Cfg:TranslateCountryInfo
|
||||
void CFGService::translateCountryInfo(u32 messagePointer) {
|
||||
const u32 country = mem.read32(messagePointer + 4);
|
||||
const u8 direction = mem.read8(messagePointer + 8);
|
||||
log("CFG::TranslateCountryInfo (country = %d, direction = %d)\n", country, direction);
|
||||
|
||||
// By default the translated code is the input
|
||||
u32 result = country;
|
||||
|
||||
if (direction == 0) { // Translate from version B to version A
|
||||
switch (country) {
|
||||
case 0x6E040000: result = 0x6E030000; break;
|
||||
case 0x6E050000: result = 0x6E040000; break;
|
||||
case 0x6E060000: result = 0x6E050000; break;
|
||||
case 0x6E070000: result = 0x6E060000; break;
|
||||
case 0x6E030000: result = 0x6E070000; break;
|
||||
default: break;
|
||||
}
|
||||
} else if (direction == 1) { // Translate from version A to version B
|
||||
switch (country) {
|
||||
case 0x6E030000: result = 0x6E040000; break;
|
||||
case 0x6E040000: result = 0x6E050000; break;
|
||||
case 0x6E050000: result = 0x6E060000; break;
|
||||
case 0x6E060000: result = 0x6E070000; break;
|
||||
case 0x6E070000: result = 0x6E030000; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x8, 2, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write32(messagePointer + 8, result);
|
||||
}
|
|
@ -16,6 +16,7 @@ namespace FSCommands {
|
|||
OpenFile = 0x080201C2,
|
||||
OpenFileDirectly = 0x08030204,
|
||||
DeleteFile = 0x08040142,
|
||||
RenameFile = 0x08050244,
|
||||
DeleteDirectory = 0x08060142,
|
||||
DeleteDirectoryRecursively = 0x08070142,
|
||||
CreateFile = 0x08080202,
|
||||
|
@ -187,6 +188,7 @@ void FSService::handleSyncRequest(u32 messagePointer) {
|
|||
case FSCommands::OpenDirectory: openDirectory(messagePointer); break;
|
||||
case FSCommands::OpenFile: [[likely]] openFile(messagePointer); break;
|
||||
case FSCommands::OpenFileDirectly: [[likely]] openFileDirectly(messagePointer); break;
|
||||
case FSCommands::RenameFile: renameFile(messagePointer); break;
|
||||
case FSCommands::SetArchivePriority: setArchivePriority(messagePointer); break;
|
||||
case FSCommands::SetPriority: setPriority(messagePointer); break;
|
||||
case FSCommands::SetThisSaveDataSecureValue: setThisSaveDataSecureValue(messagePointer); break;
|
||||
|
@ -716,4 +718,46 @@ void FSService::cardSlotIsInserted(u32 messagePointer) {
|
|||
mem.write32(messagePointer, IPC::responseHeader(0x821, 2, 0));
|
||||
mem.write32(messagePointer + 4, Result::Success);
|
||||
mem.write8(messagePointer + 8, cardInserted ? 1 : 0);
|
||||
}
|
||||
|
||||
void FSService::renameFile(u32 messagePointer) {
|
||||
log("FS::RenameFile\n");
|
||||
|
||||
mem.write32(messagePointer, IPC::responseHeader(0x805, 1, 0));
|
||||
|
||||
const Handle sourceArchiveHandle = mem.read64(messagePointer + 8);
|
||||
const Handle destArchiveHandle = mem.read64(messagePointer + 24);
|
||||
|
||||
// Read path info
|
||||
const u32 sourcePathType = mem.read32(messagePointer + 16);
|
||||
const u32 sourcePathSize = mem.read32(messagePointer + 20);
|
||||
const u32 sourcePathPointer = mem.read32(messagePointer + 44);
|
||||
const FSPath sourcePath = readPath(sourcePathType, sourcePathPointer, sourcePathSize);
|
||||
|
||||
const u32 destPathType = mem.read32(messagePointer + 32);
|
||||
const u32 destPathSize = mem.read32(messagePointer + 36);
|
||||
const u32 destPathPointer = mem.read32(messagePointer + 52);
|
||||
const FSPath destPath = readPath(destPathType, destPathPointer, destPathSize);
|
||||
|
||||
const auto sourceArchiveObject = kernel.getObject(sourceArchiveHandle, KernelObjectType::Archive);
|
||||
const auto destArchiveObject = kernel.getObject(destArchiveHandle, KernelObjectType::Archive);
|
||||
|
||||
if (sourceArchiveObject == nullptr || destArchiveObject == nullptr) {
|
||||
Helpers::panic("FS::RenameFile: One of the archive handles is invalid");
|
||||
}
|
||||
|
||||
const auto sourceArchive = sourceArchiveObject->getData<ArchiveSession>();
|
||||
const auto destArchive = destArchiveObject->getData<ArchiveSession>();
|
||||
if (!sourceArchive->isOpen || !destArchive->isOpen) {
|
||||
Helpers::warn("FS::RenameFile: Not both archive sessions are open");
|
||||
}
|
||||
|
||||
// This returns error 0xE0C046F8 according to 3DBrew
|
||||
if (sourceArchive->archive->name() != destArchive->archive->name()) {
|
||||
Helpers::panic("FS::RenameFile: Both archive handles should belong to the same archive");
|
||||
}
|
||||
|
||||
// Everything is OK, let's do the rename. Both archives should match so we don't need the dest anymore
|
||||
const HorizonResult res = sourceArchive->archive->renameFile(sourcePath, destPath);
|
||||
mem.write32(messagePointer + 4, static_cast<u32>(res));
|
||||
}
|
Loading…
Add table
Reference in a new issue