mirror of
https://github.com/wheremyfoodat/Panda3DS.git
synced 2025-04-19 20:19:13 +12:00
[NCCH] Add support for reading Miis out of NAND
This commit is contained in:
parent
4e64f722e5
commit
a1cb50925f
8 changed files with 6307 additions and 15 deletions
|
@ -1,22 +1,156 @@
|
|||
#include "fs/archive_ncch.hpp"
|
||||
#include "fs/mii_data.hpp"
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
|
||||
namespace PathType {
|
||||
enum : u32 {
|
||||
RomFS = 0,
|
||||
Code = 1,
|
||||
ExeFS = 2,
|
||||
};
|
||||
};
|
||||
|
||||
namespace MediaType {
|
||||
enum : u8 {
|
||||
NAND = 0,
|
||||
SD = 1,
|
||||
Gamecard = 2
|
||||
};
|
||||
};
|
||||
|
||||
CreateFileResult NCCHArchive::createFile(const FSPath& path, u64 size) {
|
||||
Helpers::panic("[NCCH] CreateFile not yet supported");
|
||||
return CreateFileResult::Success;
|
||||
}
|
||||
|
||||
FileDescriptor NCCHArchive::openFile(const FSPath& path, const FilePerms& perms) {
|
||||
Helpers::panic("NCCHArchive::OpenFile: Unimplemented");
|
||||
return FileError;
|
||||
if (path.type != PathType::Binary || path.binary.size() != 20) {
|
||||
Helpers::panic("NCCHArchive::OpenFile: Invalid path");
|
||||
}
|
||||
|
||||
const u32 media = *(u32*)&path.binary[0]; // 0 for NCCH, 1 for SaveData
|
||||
if (media != 0)
|
||||
Helpers::panic("NCCHArchive::OpenFile: Tried to read non-NCCH file");
|
||||
|
||||
// Third word of the binary path indicates what we're reading from.
|
||||
const u32 type = *(u32*)&path.binary[8];
|
||||
if (media == 0 && type > 2)
|
||||
Helpers::panic("NCCHArchive::OpenFile: Invalid file path type");
|
||||
|
||||
return NoFile;
|
||||
}
|
||||
|
||||
ArchiveBase* NCCHArchive::openArchive(const FSPath& path) {
|
||||
Helpers::panic("NCCHArchive::OpenArchive: Unimplemented");
|
||||
return nullptr;
|
||||
if (path.type != PathType::Binary || path.binary.size() != 16) {
|
||||
Helpers::panic("NCCHArchive::OpenArchive: Invalid path");
|
||||
}
|
||||
|
||||
const u32 mediaType = path.binary[8];
|
||||
if (mediaType != 0)
|
||||
Helpers::panic("NCCH archive. Tried to access a mediatype other than the NAND. Type: %d", mediaType);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
std::optional<u32> NCCHArchive::readFile(FileSession* file, u64 offset, u32 size, u32 dataPointer) {
|
||||
Helpers::panic("NCCHArchive::ReadFile: Unimplemented");
|
||||
return std::nullopt;
|
||||
const auto& path = file->path.binary; // Path of the file
|
||||
const auto& archivePath = file->archivePath.binary; // Path of the archive
|
||||
|
||||
const auto mediaType = archivePath[8];
|
||||
|
||||
const auto media = *(u32*)&path[0]; // 0 for NCCH, 1 for savedata
|
||||
const auto partition = *(u32*)&path[4];
|
||||
const auto type = *(u32*)&path[8]; // Type of the path
|
||||
|
||||
if (mediaType == MediaType::NAND) {
|
||||
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.
|
||||
constexpr u32 sharedDataArchive = 0x0004009B;
|
||||
constexpr u32 systemDataArchive = 0x000400DB;
|
||||
|
||||
// Low ID (taken from Citra)
|
||||
constexpr u32 miiData = 0x00010202;
|
||||
constexpr u32 regionManifest = 0x00010402;
|
||||
constexpr u32 badWordList = 0x00010302;
|
||||
constexpr u32 sharedFont = 0x00014002;
|
||||
std::vector<u8> fileData;
|
||||
|
||||
if (highProgramID == sharedDataArchive) {
|
||||
if (lowProgramID == miiData) fileData = std::vector<u8>(std::begin(MII_DATA), std::end(MII_DATA));
|
||||
else Helpers::panic("[NCCH archive] Read unimplemented NAND file");
|
||||
} else {
|
||||
Helpers::panic("[NCCH archive] Read from NAND but not the shared data archive");
|
||||
}
|
||||
|
||||
if (offset >= fileData.size()) {
|
||||
Helpers::panic("[NCCH archive] Out of bounds read from NAND file");
|
||||
}
|
||||
|
||||
u32 availableBytes = u32(fileData.size() - offset); // How many bytes we can read from the file
|
||||
u32 bytesRead = std::min<u32>(size, availableBytes); // Cap the amount of bytes to read if we're going to go out of bounds
|
||||
for (u32 i = 0; i < bytesRead; i++) {
|
||||
mem.write8(dataPointer + i, fileData[offset + i]);
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
} else {
|
||||
Helpers::panic("NCCH archive tried to read non-NAND file");
|
||||
}
|
||||
|
||||
// Code below is for mediaType == 2 (gamecard). Currently unused
|
||||
if (partition != 0)
|
||||
Helpers::panic("[NCCH] Tried to read from non-zero partition");
|
||||
|
||||
if (type == PathType::RomFS && !hasRomFS()) {
|
||||
Helpers::panic("Tried to read file from non-existent RomFS");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (type == PathType::ExeFS && !hasExeFS()) {
|
||||
Helpers::panic("Tried to read file from non-existent RomFS");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if (!file->isOpen) {
|
||||
printf("Tried to read from closed NCCH file session");
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto cxi = mem.getCXI();
|
||||
IOFile& ioFile = mem.CXIFile;
|
||||
|
||||
// Seek to file offset depending on if we're reading from RomFS, ExeFS, etc
|
||||
switch (type) {
|
||||
case PathType::RomFS: {
|
||||
const u32 romFSSize = cxi->romFS.size;
|
||||
const u32 romFSOffset = cxi->romFS.offset;
|
||||
if ((offset >> 32) || (offset >= romFSSize) || (offset + size >= romFSSize)) {
|
||||
Helpers::panic("Tried to read from NCCH with too big of an offset");
|
||||
}
|
||||
|
||||
if (!ioFile.seek(cxi->fileOffset + romFSOffset + offset + 0x1000)) {
|
||||
Helpers::panic("Failed to seek while reading from RomFS");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
Helpers::panic("Unimplemented file path type for NCCH archive");
|
||||
}
|
||||
|
||||
std::unique_ptr<u8[]> data(new u8[size]);
|
||||
auto [success, bytesRead] = ioFile.readBytes(&data[0], size);
|
||||
|
||||
if (!success) {
|
||||
Helpers::panic("Failed to read from NCCH archive");
|
||||
}
|
||||
|
||||
for (u64 i = 0; i < bytesRead; i++) {
|
||||
mem.write8(dataPointer + i, data[i]);
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue