From ce806dcdf64f80b02e7f85726b8129a0b1714bd3 Mon Sep 17 00:00:00 2001 From: shinyquagsire23 Date: Sat, 21 Oct 2017 16:52:48 -0600 Subject: [PATCH] file_sys/title_metadata: Allow loading from both files, FileBackends, and data --- src/core/file_sys/title_metadata.cpp | 64 +++++++++++++++++++--------- src/core/file_sys/title_metadata.h | 8 ++-- src/core/hle/service/am/am.cpp | 20 ++++----- 3 files changed, 56 insertions(+), 36 deletions(-) diff --git a/src/core/file_sys/title_metadata.cpp b/src/core/file_sys/title_metadata.cpp index fa99da1be..2df0bbd41 100644 --- a/src/core/file_sys/title_metadata.cpp +++ b/src/core/file_sys/title_metadata.cpp @@ -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 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 file_data, size_t offset) { + size_t total_size = static_cast(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)) { - 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; - } + + memcpy(&chunk, &file_data[offset + body_end + (i * sizeof(ContentChunk))], + sizeof(ContentChunk)); + tmd_chunks.push_back(chunk); } 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(tmd_body.content_count)); + LOG_DEBUG(Service_FS, "%u chunks", static_cast(tmd_body.content_count)); // Content info describes ranges of content chunks LOG_DEBUG(Service_FS, "Content info:"); diff --git a/src/core/file_sys/title_metadata.h b/src/core/file_sys/title_metadata.h index a52641251..42884040c 100644 --- a/src/core/file_sys/title_metadata.h +++ b/src/core/file_sys/title_metadata.h @@ -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 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 tmd_signature; std::vector tmd_chunks; - - std::string filepath; }; } // namespace FileSys diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 6bbcd96fc..6aee15e94 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -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 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(tmd.GetContentCount())); for (u32 i = start_index; i < copied; i++) { std::shared_ptr romfs_file; @@ -313,8 +313,8 @@ ResultCode GetTitleInfoFromList(const std::vector& 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(tmd.GetContentCount()); } else { rb.Push(1); // Number of content infos plus one