mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	file_sys/title_metadata: Allow loading from both files, FileBackends, and data
This commit is contained in:
		
							parent
							
								
									b3e87d01fb
								
							
						
					
					
						commit
						ce806dcdf6
					
				
					 3 changed files with 56 additions and 36 deletions
				
			
		|  | @ -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)) { | ||||
|             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<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…
	
	Add table
		Add a link
		
	
		Reference in a new issue