forked from eden-emu/eden
		
	registration: Update documentation and style
This commit is contained in:
		
							parent
							
								
									22bdddd6f0
								
							
						
					
					
						commit
						893447b6b0
					
				
					 5 changed files with 69 additions and 42 deletions
				
			
		|  | @ -4,36 +4,44 @@ | ||||||
| 
 | 
 | ||||||
| #include <cstring> | #include <cstring> | ||||||
| #include "common/common_funcs.h" | #include "common/common_funcs.h" | ||||||
|  | #include "common/logging/log.h" | ||||||
| #include "common/swap.h" | #include "common/swap.h" | ||||||
| #include "content_archive.h" | #include "content_archive.h" | ||||||
| #include "core/file_sys/nca_metadata.h" | #include "core/file_sys/nca_metadata.h" | ||||||
| 
 | 
 | ||||||
| namespace FileSys { | namespace FileSys { | ||||||
| 
 | 
 | ||||||
| CNMT::CNMT(VirtualFile file) : header(std::make_unique<CNMTHeader>()) { | bool operator>=(TitleType lhs, TitleType rhs) { | ||||||
|     if (file->ReadObject(header.get()) != sizeof(CNMTHeader)) |     return static_cast<size_t>(lhs) >= static_cast<size_t>(rhs); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool operator<=(TitleType lhs, TitleType rhs) { | ||||||
|  |     return static_cast<size_t>(lhs) <= static_cast<size_t>(rhs); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | CNMT::CNMT(VirtualFile file) { | ||||||
|  |     if (file->ReadObject(&header) != sizeof(CNMTHeader)) | ||||||
|         return; |         return; | ||||||
| 
 | 
 | ||||||
|     // If type is {Application, Update, AOC} has opt-header.
 |     // If type is {Application, Update, AOC} has opt-header.
 | ||||||
|     if (static_cast<u8>(header->type) >= 0x80 && static_cast<u8>(header->type) <= 0x82) { |     if (header.type >= TitleType::Application && header.type <= TitleType::AOC) { | ||||||
|         opt_header = std::make_unique<OptionalHeader>(); |         if (file->ReadObject(&opt_header, sizeof(CNMTHeader)) != sizeof(OptionalHeader)) { | ||||||
|         if (file->ReadObject(opt_header.get(), sizeof(CNMTHeader)) != sizeof(OptionalHeader)) { |             LOG_WARNING(Loader, "Failed to read optional header."); | ||||||
|             opt_header = nullptr; |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for (u16 i = 0; i < header->number_content_entries; ++i) { |     for (u16 i = 0; i < header.number_content_entries; ++i) { | ||||||
|         auto& next = content_records.emplace_back(ContentRecord{}); |         auto& next = content_records.emplace_back(ContentRecord{}); | ||||||
|         if (file->ReadObject(&next, sizeof(CNMTHeader) + i * sizeof(ContentRecord) + |         if (file->ReadObject(&next, sizeof(CNMTHeader) + i * sizeof(ContentRecord) + | ||||||
|                                         header->table_offset) != sizeof(ContentRecord)) { |                                         header.table_offset) != sizeof(ContentRecord)) { | ||||||
|             content_records.erase(content_records.end() - 1); |             content_records.erase(content_records.end() - 1); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for (u16 i = 0; i < header->number_meta_entries; ++i) { |     for (u16 i = 0; i < header.number_meta_entries; ++i) { | ||||||
|         auto& next = meta_records.emplace_back(MetaRecord{}); |         auto& next = meta_records.emplace_back(MetaRecord{}); | ||||||
|         if (file->ReadObject(&next, sizeof(CNMTHeader) + i * sizeof(MetaRecord) + |         if (file->ReadObject(&next, sizeof(CNMTHeader) + i * sizeof(MetaRecord) + | ||||||
|                                         header->table_offset) != sizeof(MetaRecord)) { |                                         header.table_offset) != sizeof(MetaRecord)) { | ||||||
|             meta_records.erase(meta_records.end() - 1); |             meta_records.erase(meta_records.end() - 1); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -41,20 +49,19 @@ CNMT::CNMT(VirtualFile file) : header(std::make_unique<CNMTHeader>()) { | ||||||
| 
 | 
 | ||||||
| CNMT::CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records, | CNMT::CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records, | ||||||
|            std::vector<MetaRecord> meta_records) |            std::vector<MetaRecord> meta_records) | ||||||
|     : header(std::make_unique<CNMTHeader>(std::move(header))), |     : header(std::move(header)), opt_header(std::move(opt_header)), | ||||||
|       opt_header(std::make_unique<OptionalHeader>(std::move(opt_header))), |  | ||||||
|       content_records(std::move(content_records)), meta_records(std::move(meta_records)) {} |       content_records(std::move(content_records)), meta_records(std::move(meta_records)) {} | ||||||
| 
 | 
 | ||||||
| u64 CNMT::GetTitleID() const { | u64 CNMT::GetTitleID() const { | ||||||
|     return header->title_id; |     return header.title_id; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| u32 CNMT::GetTitleVersion() const { | u32 CNMT::GetTitleVersion() const { | ||||||
|     return header->title_version; |     return header.title_version; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| TitleType CNMT::GetType() const { | TitleType CNMT::GetType() const { | ||||||
|     return header->type; |     return header.type; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| const std::vector<ContentRecord>& CNMT::GetContentRecords() const { | const std::vector<ContentRecord>& CNMT::GetContentRecords() const { | ||||||
|  | @ -74,7 +81,7 @@ bool CNMT::UnionRecords(const CNMT& other) { | ||||||
|                                        }); |                                        }); | ||||||
|         if (iter == content_records.end()) { |         if (iter == content_records.end()) { | ||||||
|             content_records.emplace_back(rec); |             content_records.emplace_back(rec); | ||||||
|             ++header->number_content_entries; |             ++header.number_content_entries; | ||||||
|             change = true; |             change = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -86,7 +93,7 @@ bool CNMT::UnionRecords(const CNMT& other) { | ||||||
|             }); |             }); | ||||||
|         if (iter == meta_records.end()) { |         if (iter == meta_records.end()) { | ||||||
|             meta_records.emplace_back(rec); |             meta_records.emplace_back(rec); | ||||||
|             ++header->number_meta_entries; |             ++header.number_meta_entries; | ||||||
|             change = true; |             change = true; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | @ -94,30 +101,30 @@ bool CNMT::UnionRecords(const CNMT& other) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::vector<u8> CNMT::Serialize() const { | std::vector<u8> CNMT::Serialize() const { | ||||||
|     if (header == nullptr) |     const bool has_opt_header = | ||||||
|         return {}; |         header.type >= TitleType::Application && header.type <= TitleType::AOC; | ||||||
|     std::vector<u8> out(sizeof(CNMTHeader)); |     std::vector<u8> out(sizeof(CNMTHeader) + (has_opt_header ? sizeof(OptionalHeader) : 0)); | ||||||
|     out.reserve(0x100); // Avoid resizing -- average size.
 |     memcpy(out.data(), &header, sizeof(CNMTHeader)); | ||||||
|     memcpy(out.data(), header.get(), sizeof(CNMTHeader)); | 
 | ||||||
|     if (opt_header != nullptr) { |     // Optional Header
 | ||||||
|         out.resize(out.size() + sizeof(OptionalHeader)); |     if (has_opt_header) { | ||||||
|         memcpy(out.data() + sizeof(CNMTHeader), opt_header.get(), sizeof(OptionalHeader)); |         memcpy(out.data() + sizeof(CNMTHeader), &opt_header, sizeof(OptionalHeader)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     auto offset = header->table_offset; |     auto offset = header.table_offset; | ||||||
| 
 | 
 | ||||||
|     const auto dead_zone = offset + sizeof(CNMTHeader) - out.size(); |     const auto dead_zone = offset + sizeof(CNMTHeader) - out.size(); | ||||||
|     if (dead_zone > 0) |     if (dead_zone > 0) | ||||||
|         out.resize(offset + sizeof(CNMTHeader)); |         out.resize(offset + sizeof(CNMTHeader)); | ||||||
| 
 | 
 | ||||||
|  |     out.resize(out.size() + content_records.size() * sizeof(ContentRecord)); | ||||||
|     for (const auto& rec : content_records) { |     for (const auto& rec : content_records) { | ||||||
|         out.resize(out.size() + sizeof(ContentRecord)); |  | ||||||
|         memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(ContentRecord)); |         memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(ContentRecord)); | ||||||
|         offset += sizeof(ContentRecord); |         offset += sizeof(ContentRecord); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     out.resize(out.size() + content_records.size() * sizeof(MetaRecord)); | ||||||
|     for (const auto& rec : meta_records) { |     for (const auto& rec : meta_records) { | ||||||
|         out.resize(out.size() + sizeof(MetaRecord)); |  | ||||||
|         memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(MetaRecord)); |         memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(MetaRecord)); | ||||||
|         offset += sizeof(MetaRecord); |         offset += sizeof(MetaRecord); | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  | @ -29,6 +29,9 @@ enum class TitleType : u8 { | ||||||
|     DeltaTitle = 0x83, |     DeltaTitle = 0x83, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  | bool operator>=(TitleType lhs, TitleType rhs); | ||||||
|  | bool operator<=(TitleType lhs, TitleType rhs); | ||||||
|  | 
 | ||||||
| enum class ContentRecordType : u8 { | enum class ContentRecordType : u8 { | ||||||
|     Meta = 0, |     Meta = 0, | ||||||
|     Program = 1, |     Program = 1, | ||||||
|  | @ -96,8 +99,8 @@ public: | ||||||
|     std::vector<u8> Serialize() const; |     std::vector<u8> Serialize() const; | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     std::unique_ptr<CNMTHeader> header; |     CNMTHeader header; | ||||||
|     std::unique_ptr<OptionalHeader> opt_header; |     OptionalHeader opt_header; | ||||||
|     std::vector<ContentRecord> content_records; |     std::vector<ContentRecord> content_records; | ||||||
|     std::vector<MetaRecord> meta_records; |     std::vector<MetaRecord> meta_records; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -23,13 +23,14 @@ bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool FollowsTwoDigitDirFormat(std::string_view name) { | static bool FollowsTwoDigitDirFormat(std::string_view name) { | ||||||
|     static const std::regex two_digit_regex( |     static const std::regex two_digit_regex("000000[0-9A-F]{2}", std::regex_constants::ECMAScript | | ||||||
|         "000000[0123456789abcdefABCDEF][0123456789abcdefABCDEF]"); |                                                                      std::regex_constants::icase); | ||||||
|     return std::regex_match(name.begin(), name.end(), two_digit_regex); |     return std::regex_match(name.begin(), name.end(), two_digit_regex); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static bool FollowsNcaIdFormat(std::string_view name) { | static bool FollowsNcaIdFormat(std::string_view name) { | ||||||
|     static const std::regex nca_id_regex("[0123456789abcdefABCDEF]+.nca"); |     static const std::regex nca_id_regex("[0-9A-F]{32}.nca", std::regex_constants::ECMAScript | | ||||||
|  |                                                                  std::regex_constants::icase); | ||||||
|     return name.size() == 36 && std::regex_match(name.begin(), name.end(), nca_id_regex); |     return name.size() == 36 && std::regex_match(name.begin(), name.end(), nca_id_regex); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -57,8 +58,9 @@ static std::string GetCNMTName(TitleType type, u64 title_id) { | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     auto index = static_cast<size_t>(type); |     auto index = static_cast<size_t>(type); | ||||||
|     if (index >= 0x80) |     // If the index is after the jump in TitleType, subtract it out.
 | ||||||
|         index -= 0x80; |     if (index >= static_cast<size_t>(TitleType::Application)) | ||||||
|  |         index -= static_cast<size_t>(TitleType::Application); | ||||||
|     return fmt::format("{}_{:016x}.cnmt", TITLE_TYPE_NAMES[index], title_id); |     return fmt::format("{}_{:016x}.cnmt", TITLE_TYPE_NAMES[index], title_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -120,9 +122,15 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, | ||||||
| 
 | 
 | ||||||
| VirtualFile RegisteredCache::GetFileAtID(NcaID id) const { | VirtualFile RegisteredCache::GetFileAtID(NcaID id) const { | ||||||
|     VirtualFile file; |     VirtualFile file; | ||||||
|  |     // Try all four modes of file storage:
 | ||||||
|  |     // (bit 1 = uppercase/lower, bit 0 = within a two-digit dir)
 | ||||||
|  |     // 00: /000000**/{:032X}.nca
 | ||||||
|  |     // 01: /{:032X}.nca
 | ||||||
|  |     // 10: /000000**/{:032x}.nca
 | ||||||
|  |     // 11: /{:032x}.nca
 | ||||||
|     for (u8 i = 0; i < 4; ++i) { |     for (u8 i = 0; i < 4; ++i) { | ||||||
|         file = OpenFileOrDirectoryConcat( |         const auto path = GetRelativePathFromNcaID(id, (i & 0b10) == 0, (i & 0b01) == 0); | ||||||
|             dir, GetRelativePathFromNcaID(id, (i & 0b10) == 0, (i & 0b01) == 0)); |         file = OpenFileOrDirectoryConcat(dir, path); | ||||||
|         if (file != nullptr) |         if (file != nullptr) | ||||||
|             return file; |             return file; | ||||||
|     } |     } | ||||||
|  | @ -420,6 +428,7 @@ bool RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunct | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) { | bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) { | ||||||
|  |     // Reasoning behind this method can be found in the comment for InstallEntry, NCA overload.
 | ||||||
|     const auto dir = this->dir->CreateDirectoryRelative("yuzu_meta"); |     const auto dir = this->dir->CreateDirectoryRelative("yuzu_meta"); | ||||||
|     const auto filename = GetCNMTName(cnmt.GetType(), cnmt.GetTitleID()); |     const auto filename = GetCNMTName(cnmt.GetType(), cnmt.GetTitleID()); | ||||||
|     if (dir->GetFile(filename) == nullptr) { |     if (dir->GetFile(filename) == nullptr) { | ||||||
|  |  | ||||||
|  | @ -68,6 +68,7 @@ size_t ConcatenatedVfsFile::Read(u8* data, size_t length, size_t offset) const { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     // Check if the entry should be the last one. The loop above will make it end().
 | ||||||
|     if (entry == files.end() && offset < files.rbegin()->first + files.rbegin()->second->GetSize()) |     if (entry == files.end() && offset < files.rbegin()->first + files.rbegin()->second->GetSize()) | ||||||
|         --entry; |         --entry; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -83,10 +83,12 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { | ||||||
| 
 | 
 | ||||||
| VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { | VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { | ||||||
|     const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); |     const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); | ||||||
|     if (!FileUtil::Exists(path) && |     if (!FileUtil::Exists(path)) | ||||||
|         !FileUtil::CreateFullPath( |         return nullptr; | ||||||
|             FileUtil::SanitizePath(path, FileUtil::DirectorySeparator::ForwardSlash)) && |     if (!FileUtil::CreateFullPath( | ||||||
|         !FileUtil::CreateEmptyFile(path)) |             FileUtil::SanitizePath(path, FileUtil::DirectorySeparator::ForwardSlash))) | ||||||
|  |         return nullptr; | ||||||
|  |     if (!FileUtil::CreateEmptyFile(path)) | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     return OpenFile(path, perms); |     return OpenFile(path, perms); | ||||||
| } | } | ||||||
|  | @ -143,7 +145,12 @@ VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) | ||||||
| 
 | 
 | ||||||
| VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { | VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { | ||||||
|     const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); |     const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); | ||||||
|     if (!FileUtil::Exists(path) && !FileUtil::CreateDir(path)) |     if (!FileUtil::Exists(path)) | ||||||
|  |         return nullptr; | ||||||
|  |     if (!FileUtil::CreateFullPath( | ||||||
|  |             FileUtil::SanitizePath(path, FileUtil::DirectorySeparator::ForwardSlash))) | ||||||
|  |         return nullptr; | ||||||
|  |     if (!FileUtil::CreateDir(path)) | ||||||
|         return nullptr; |         return nullptr; | ||||||
|     // Cannot use make_shared as RealVfsDirectory constructor is private
 |     // Cannot use make_shared as RealVfsDirectory constructor is private
 | ||||||
|     return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms)); |     return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms)); | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Zach Hilman
						Zach Hilman