mirror of
https://github.com/citra-emu/citra.git
synced 2024-12-22 04:40:04 +00:00
file_sys/title_metadata: Allow loading from both files, FileBackends, and data
This commit is contained in:
parent
b3e87d01fb
commit
ce806dcdf6
@ -29,47 +29,70 @@ static u32 GetSignatureSize(u32 signature_type) {
|
||||
case EcdsaSha256:
|
||||
return 0x3C;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loader::ResultStatus TitleMetadata::Load() {
|
||||
FileUtil::IOFile file(filepath, "rb");
|
||||
Loader::ResultStatus TitleMetadata::Load(const std::string& file_path) {
|
||||
FileUtil::IOFile file(file_path, "rb");
|
||||
if (!file.IsOpen())
|
||||
return Loader::ResultStatus::Error;
|
||||
|
||||
if (!file.ReadBytes(&signature_type, sizeof(u32_be)))
|
||||
std::vector<u8> file_data(file.GetSize());
|
||||
|
||||
if (!file.ReadBytes(file_data.data(), file.GetSize()))
|
||||
return Loader::ResultStatus::Error;
|
||||
|
||||
Loader::ResultStatus result = Load(file_data);
|
||||
if (result != Loader::ResultStatus::Success)
|
||||
LOG_ERROR(Service_FS, "Failed to load TMD from file %s!", file_path.c_str());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Loader::ResultStatus TitleMetadata::Load(const std::vector<u8> file_data, size_t offset) {
|
||||
size_t total_size = static_cast<size_t>(file_data.size() - offset);
|
||||
if (total_size < sizeof(u32_be))
|
||||
return Loader::ResultStatus::Error;
|
||||
|
||||
memcpy(&signature_type, &file_data[offset], sizeof(u32_be));
|
||||
|
||||
// Signature lengths are variable, and the body follows the signature
|
||||
u32 signature_size = GetSignatureSize(signature_type);
|
||||
|
||||
tmd_signature.resize(signature_size);
|
||||
if (!file.ReadBytes(&tmd_signature[0], signature_size))
|
||||
return Loader::ResultStatus::Error;
|
||||
|
||||
// The TMD body start position is rounded to the nearest 0x40 after the signature
|
||||
size_t body_start = Common::AlignUp(signature_size + sizeof(u32), 0x40);
|
||||
file.Seek(body_start, SEEK_SET);
|
||||
size_t body_end = body_start + sizeof(Body);
|
||||
|
||||
// Read our TMD body, then load the amount of ContentChunks specified
|
||||
if (file.ReadBytes(&tmd_body, sizeof(TitleMetadata::Body)) != sizeof(TitleMetadata::Body))
|
||||
if (total_size < body_end)
|
||||
return Loader::ResultStatus::Error;
|
||||
|
||||
// Read signature + TMD body, then load the amount of ContentChunks specified
|
||||
tmd_signature.resize(signature_size);
|
||||
memcpy(tmd_signature.data(), &file_data[offset + sizeof(u32_be)], signature_size);
|
||||
memcpy(&tmd_body, &file_data[offset + body_start], sizeof(TitleMetadata::Body));
|
||||
|
||||
size_t expected_size =
|
||||
body_start + sizeof(Body) + tmd_body.content_count * sizeof(ContentChunk);
|
||||
if (total_size < expected_size) {
|
||||
LOG_ERROR(Service_FS, "Malformed TMD, expected size 0x%zx, got 0x%zx!", expected_size,
|
||||
total_size);
|
||||
return Loader::ResultStatus::ErrorInvalidFormat;
|
||||
}
|
||||
|
||||
for (u16 i = 0; i < tmd_body.content_count; i++) {
|
||||
ContentChunk chunk;
|
||||
if (file.ReadBytes(&chunk, sizeof(ContentChunk)) == sizeof(ContentChunk)) {
|
||||
|
||||
memcpy(&chunk, &file_data[offset + body_end + (i * sizeof(ContentChunk))],
|
||||
sizeof(ContentChunk));
|
||||
tmd_chunks.push_back(chunk);
|
||||
} else {
|
||||
LOG_ERROR(Service_FS, "Malformed TMD %s, failed to load content chunk index %u!",
|
||||
filepath.c_str(), i);
|
||||
return Loader::ResultStatus::ErrorInvalidFormat;
|
||||
}
|
||||
}
|
||||
|
||||
return Loader::ResultStatus::Success;
|
||||
}
|
||||
|
||||
Loader::ResultStatus TitleMetadata::Save() {
|
||||
FileUtil::IOFile file(filepath, "wb");
|
||||
Loader::ResultStatus TitleMetadata::Save(const std::string& file_path) {
|
||||
FileUtil::IOFile file(file_path, "wb");
|
||||
if (!file.IsOpen())
|
||||
return Loader::ResultStatus::Error;
|
||||
|
||||
@ -186,8 +209,7 @@ void TitleMetadata::AddContentChunk(const ContentChunk& chunk) {
|
||||
}
|
||||
|
||||
void TitleMetadata::Print() const {
|
||||
LOG_DEBUG(Service_FS, "%s - %u chunks", filepath.c_str(),
|
||||
static_cast<u32>(tmd_body.content_count));
|
||||
LOG_DEBUG(Service_FS, "%u chunks", static_cast<u32>(tmd_body.content_count));
|
||||
|
||||
// Content info describes ranges of content chunks
|
||||
LOG_DEBUG(Service_FS, "Content info:");
|
||||
|
@ -92,9 +92,9 @@ public:
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
explicit TitleMetadata(std::string& path) : filepath(std::move(path)) {}
|
||||
Loader::ResultStatus Load();
|
||||
Loader::ResultStatus Save();
|
||||
Loader::ResultStatus Load(const std::string& file_path);
|
||||
Loader::ResultStatus Load(const std::vector<u8> file_data, size_t offset = 0);
|
||||
Loader::ResultStatus Save(const std::string& file_path);
|
||||
|
||||
u64 GetTitleID() const;
|
||||
u32 GetTitleType() const;
|
||||
@ -121,8 +121,6 @@ private:
|
||||
u32_be signature_type;
|
||||
std::vector<u8> tmd_signature;
|
||||
std::vector<ContentChunk> tmd_chunks;
|
||||
|
||||
std::string filepath;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
@ -98,8 +98,8 @@ std::string GetTitleContentPath(Service::FS::MediaType media_type, u64 tid, u16
|
||||
std::string tmd_path = GetTitleMetadataPath(media_type, tid);
|
||||
|
||||
u32 content_id = 0;
|
||||
FileSys::TitleMetadata tmd(tmd_path);
|
||||
if (tmd.Load() == Loader::ResultStatus::Success) {
|
||||
FileSys::TitleMetadata tmd;
|
||||
if (tmd.LoadFromFile(tmd_path) == Loader::ResultStatus::Success) {
|
||||
content_id = tmd.GetContentIDByIndex(index);
|
||||
|
||||
// TODO(shinyquagsire23): how does DLC actually get this folder on hardware?
|
||||
@ -199,8 +199,8 @@ void FindContentInfos(Service::Interface* self) {
|
||||
std::string tmd_path = GetTitleMetadataPath(media_type, title_id);
|
||||
|
||||
u32 content_read = 0;
|
||||
FileSys::TitleMetadata tmd(tmd_path);
|
||||
if (tmd.Load() == Loader::ResultStatus::Success) {
|
||||
FileSys::TitleMetadata tmd;
|
||||
if (tmd.LoadFromFile(tmd_path) == Loader::ResultStatus::Success) {
|
||||
// Get info for each content index requested
|
||||
for (size_t i = 0; i < content_count; i++) {
|
||||
std::shared_ptr<FileUtil::IOFile> romfs_file;
|
||||
@ -238,8 +238,8 @@ void ListContentInfos(Service::Interface* self) {
|
||||
std::string tmd_path = GetTitleMetadataPath(media_type, title_id);
|
||||
|
||||
u32 copied = 0;
|
||||
FileSys::TitleMetadata tmd(tmd_path);
|
||||
if (tmd.Load() == Loader::ResultStatus::Success) {
|
||||
FileSys::TitleMetadata tmd;
|
||||
if (tmd.LoadFromFile(tmd_path) == Loader::ResultStatus::Success) {
|
||||
copied = std::min(content_count, static_cast<u32>(tmd.GetContentCount()));
|
||||
for (u32 i = start_index; i < copied; i++) {
|
||||
std::shared_ptr<FileUtil::IOFile> romfs_file;
|
||||
@ -313,8 +313,8 @@ ResultCode GetTitleInfoFromList(const std::vector<u64>& title_id_list,
|
||||
TitleInfo title_info = {};
|
||||
title_info.tid = title_id_list[i];
|
||||
|
||||
FileSys::TitleMetadata tmd(tmd_path);
|
||||
if (tmd.Load() == Loader::ResultStatus::Success) {
|
||||
FileSys::TitleMetadata tmd;
|
||||
if (tmd.LoadFromFile(tmd_path) == Loader::ResultStatus::Success) {
|
||||
// TODO(shinyquagsire23): This is the total size of all files this process owns,
|
||||
// including savefiles and other content. This comes close but is off.
|
||||
title_info.size = tmd.GetContentSizeByIndex(FileSys::TMDContentIndex::Main);
|
||||
@ -462,8 +462,8 @@ void GetNumContentInfos(Service::Interface* self) {
|
||||
|
||||
std::string tmd_path = GetTitleMetadataPath(media_type, title_id);
|
||||
|
||||
FileSys::TitleMetadata tmd(tmd_path);
|
||||
if (tmd.Load() == Loader::ResultStatus::Success) {
|
||||
FileSys::TitleMetadata tmd;
|
||||
if (tmd.LoadFromFile(tmd_path) == Loader::ResultStatus::Success)
|
||||
rb.Push<u32>(tmd.GetContentCount());
|
||||
} else {
|
||||
rb.Push<u32>(1); // Number of content infos plus one
|
||||
|
Loading…
Reference in New Issue
Block a user