diff options
| author | 2018-08-11 15:39:09 -0400 | |
|---|---|---|
| committer | 2018-08-11 22:50:48 -0400 | |
| commit | 893447b6b0f5068f3cc2111b5f21c3cff68002e2 (patch) | |
| tree | f2451fcb2478243621b6952ca5b006f22f957022 /src | |
| parent | nca_metadata: Remove unnecessary reference to base file (diff) | |
| download | yuzu-893447b6b0f5068f3cc2111b5f21c3cff68002e2.tar.gz yuzu-893447b6b0f5068f3cc2111b5f21c3cff68002e2.tar.xz yuzu-893447b6b0f5068f3cc2111b5f21c3cff68002e2.zip | |
registration: Update documentation and style
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/file_sys/nca_metadata.cpp | 63 | ||||
| -rw-r--r-- | src/core/file_sys/nca_metadata.h | 7 | ||||
| -rw-r--r-- | src/core/file_sys/registered_cache.cpp | 23 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_concat.cpp | 1 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_real.cpp | 17 |
5 files changed, 69 insertions, 42 deletions
diff --git a/src/core/file_sys/nca_metadata.cpp b/src/core/file_sys/nca_metadata.cpp index 38b5eae80..234d70199 100644 --- a/src/core/file_sys/nca_metadata.cpp +++ b/src/core/file_sys/nca_metadata.cpp | |||
| @@ -4,36 +4,44 @@ | |||
| 4 | 4 | ||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | #include "common/common_funcs.h" | 6 | #include "common/common_funcs.h" |
| 7 | #include "common/logging/log.h" | ||
| 7 | #include "common/swap.h" | 8 | #include "common/swap.h" |
| 8 | #include "content_archive.h" | 9 | #include "content_archive.h" |
| 9 | #include "core/file_sys/nca_metadata.h" | 10 | #include "core/file_sys/nca_metadata.h" |
| 10 | 11 | ||
| 11 | namespace FileSys { | 12 | namespace FileSys { |
| 12 | 13 | ||
| 13 | CNMT::CNMT(VirtualFile file) : header(std::make_unique<CNMTHeader>()) { | 14 | bool operator>=(TitleType lhs, TitleType rhs) { |
| 14 | if (file->ReadObject(header.get()) != sizeof(CNMTHeader)) | 15 | return static_cast<size_t>(lhs) >= static_cast<size_t>(rhs); |
| 16 | } | ||
| 17 | |||
| 18 | bool operator<=(TitleType lhs, TitleType rhs) { | ||
| 19 | return static_cast<size_t>(lhs) <= static_cast<size_t>(rhs); | ||
| 20 | } | ||
| 21 | |||
| 22 | CNMT::CNMT(VirtualFile file) { | ||
| 23 | if (file->ReadObject(&header) != sizeof(CNMTHeader)) | ||
| 15 | return; | 24 | return; |
| 16 | 25 | ||
| 17 | // If type is {Application, Update, AOC} has opt-header. | 26 | // If type is {Application, Update, AOC} has opt-header. |
| 18 | if (static_cast<u8>(header->type) >= 0x80 && static_cast<u8>(header->type) <= 0x82) { | 27 | if (header.type >= TitleType::Application && header.type <= TitleType::AOC) { |
| 19 | opt_header = std::make_unique<OptionalHeader>(); | 28 | if (file->ReadObject(&opt_header, sizeof(CNMTHeader)) != sizeof(OptionalHeader)) { |
| 20 | if (file->ReadObject(opt_header.get(), sizeof(CNMTHeader)) != sizeof(OptionalHeader)) { | 29 | LOG_WARNING(Loader, "Failed to read optional header."); |
| 21 | opt_header = nullptr; | ||
| 22 | } | 30 | } |
| 23 | } | 31 | } |
| 24 | 32 | ||
| 25 | for (u16 i = 0; i < header->number_content_entries; ++i) { | 33 | for (u16 i = 0; i < header.number_content_entries; ++i) { |
| 26 | auto& next = content_records.emplace_back(ContentRecord{}); | 34 | auto& next = content_records.emplace_back(ContentRecord{}); |
| 27 | if (file->ReadObject(&next, sizeof(CNMTHeader) + i * sizeof(ContentRecord) + | 35 | if (file->ReadObject(&next, sizeof(CNMTHeader) + i * sizeof(ContentRecord) + |
| 28 | header->table_offset) != sizeof(ContentRecord)) { | 36 | header.table_offset) != sizeof(ContentRecord)) { |
| 29 | content_records.erase(content_records.end() - 1); | 37 | content_records.erase(content_records.end() - 1); |
| 30 | } | 38 | } |
| 31 | } | 39 | } |
| 32 | 40 | ||
| 33 | for (u16 i = 0; i < header->number_meta_entries; ++i) { | 41 | for (u16 i = 0; i < header.number_meta_entries; ++i) { |
| 34 | auto& next = meta_records.emplace_back(MetaRecord{}); | 42 | auto& next = meta_records.emplace_back(MetaRecord{}); |
| 35 | if (file->ReadObject(&next, sizeof(CNMTHeader) + i * sizeof(MetaRecord) + | 43 | if (file->ReadObject(&next, sizeof(CNMTHeader) + i * sizeof(MetaRecord) + |
| 36 | header->table_offset) != sizeof(MetaRecord)) { | 44 | header.table_offset) != sizeof(MetaRecord)) { |
| 37 | meta_records.erase(meta_records.end() - 1); | 45 | meta_records.erase(meta_records.end() - 1); |
| 38 | } | 46 | } |
| 39 | } | 47 | } |
| @@ -41,20 +49,19 @@ CNMT::CNMT(VirtualFile file) : header(std::make_unique<CNMTHeader>()) { | |||
| 41 | 49 | ||
| 42 | CNMT::CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records, | 50 | CNMT::CNMT(CNMTHeader header, OptionalHeader opt_header, std::vector<ContentRecord> content_records, |
| 43 | std::vector<MetaRecord> meta_records) | 51 | std::vector<MetaRecord> meta_records) |
| 44 | : header(std::make_unique<CNMTHeader>(std::move(header))), | 52 | : header(std::move(header)), opt_header(std::move(opt_header)), |
| 45 | opt_header(std::make_unique<OptionalHeader>(std::move(opt_header))), | ||
| 46 | content_records(std::move(content_records)), meta_records(std::move(meta_records)) {} | 53 | content_records(std::move(content_records)), meta_records(std::move(meta_records)) {} |
| 47 | 54 | ||
| 48 | u64 CNMT::GetTitleID() const { | 55 | u64 CNMT::GetTitleID() const { |
| 49 | return header->title_id; | 56 | return header.title_id; |
| 50 | } | 57 | } |
| 51 | 58 | ||
| 52 | u32 CNMT::GetTitleVersion() const { | 59 | u32 CNMT::GetTitleVersion() const { |
| 53 | return header->title_version; | 60 | return header.title_version; |
| 54 | } | 61 | } |
| 55 | 62 | ||
| 56 | TitleType CNMT::GetType() const { | 63 | TitleType CNMT::GetType() const { |
| 57 | return header->type; | 64 | return header.type; |
| 58 | } | 65 | } |
| 59 | 66 | ||
| 60 | const std::vector<ContentRecord>& CNMT::GetContentRecords() const { | 67 | const std::vector<ContentRecord>& CNMT::GetContentRecords() const { |
| @@ -74,7 +81,7 @@ bool CNMT::UnionRecords(const CNMT& other) { | |||
| 74 | }); | 81 | }); |
| 75 | if (iter == content_records.end()) { | 82 | if (iter == content_records.end()) { |
| 76 | content_records.emplace_back(rec); | 83 | content_records.emplace_back(rec); |
| 77 | ++header->number_content_entries; | 84 | ++header.number_content_entries; |
| 78 | change = true; | 85 | change = true; |
| 79 | } | 86 | } |
| 80 | } | 87 | } |
| @@ -86,7 +93,7 @@ bool CNMT::UnionRecords(const CNMT& other) { | |||
| 86 | }); | 93 | }); |
| 87 | if (iter == meta_records.end()) { | 94 | if (iter == meta_records.end()) { |
| 88 | meta_records.emplace_back(rec); | 95 | meta_records.emplace_back(rec); |
| 89 | ++header->number_meta_entries; | 96 | ++header.number_meta_entries; |
| 90 | change = true; | 97 | change = true; |
| 91 | } | 98 | } |
| 92 | } | 99 | } |
| @@ -94,30 +101,30 @@ bool CNMT::UnionRecords(const CNMT& other) { | |||
| 94 | } | 101 | } |
| 95 | 102 | ||
| 96 | std::vector<u8> CNMT::Serialize() const { | 103 | std::vector<u8> CNMT::Serialize() const { |
| 97 | if (header == nullptr) | 104 | const bool has_opt_header = |
| 98 | return {}; | 105 | header.type >= TitleType::Application && header.type <= TitleType::AOC; |
| 99 | std::vector<u8> out(sizeof(CNMTHeader)); | 106 | std::vector<u8> out(sizeof(CNMTHeader) + (has_opt_header ? sizeof(OptionalHeader) : 0)); |
| 100 | out.reserve(0x100); // Avoid resizing -- average size. | 107 | memcpy(out.data(), &header, sizeof(CNMTHeader)); |
| 101 | memcpy(out.data(), header.get(), sizeof(CNMTHeader)); | 108 | |
| 102 | if (opt_header != nullptr) { | 109 | // Optional Header |
| 103 | out.resize(out.size() + sizeof(OptionalHeader)); | 110 | if (has_opt_header) { |
| 104 | memcpy(out.data() + sizeof(CNMTHeader), opt_header.get(), sizeof(OptionalHeader)); | 111 | memcpy(out.data() + sizeof(CNMTHeader), &opt_header, sizeof(OptionalHeader)); |
| 105 | } | 112 | } |
| 106 | 113 | ||
| 107 | auto offset = header->table_offset; | 114 | auto offset = header.table_offset; |
| 108 | 115 | ||
| 109 | const auto dead_zone = offset + sizeof(CNMTHeader) - out.size(); | 116 | const auto dead_zone = offset + sizeof(CNMTHeader) - out.size(); |
| 110 | if (dead_zone > 0) | 117 | if (dead_zone > 0) |
| 111 | out.resize(offset + sizeof(CNMTHeader)); | 118 | out.resize(offset + sizeof(CNMTHeader)); |
| 112 | 119 | ||
| 120 | out.resize(out.size() + content_records.size() * sizeof(ContentRecord)); | ||
| 113 | for (const auto& rec : content_records) { | 121 | for (const auto& rec : content_records) { |
| 114 | out.resize(out.size() + sizeof(ContentRecord)); | ||
| 115 | memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(ContentRecord)); | 122 | memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(ContentRecord)); |
| 116 | offset += sizeof(ContentRecord); | 123 | offset += sizeof(ContentRecord); |
| 117 | } | 124 | } |
| 118 | 125 | ||
| 126 | out.resize(out.size() + content_records.size() * sizeof(MetaRecord)); | ||
| 119 | for (const auto& rec : meta_records) { | 127 | for (const auto& rec : meta_records) { |
| 120 | out.resize(out.size() + sizeof(MetaRecord)); | ||
| 121 | memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(MetaRecord)); | 128 | memcpy(out.data() + offset + sizeof(CNMTHeader), &rec, sizeof(MetaRecord)); |
| 122 | offset += sizeof(MetaRecord); | 129 | offset += sizeof(MetaRecord); |
| 123 | } | 130 | } |
diff --git a/src/core/file_sys/nca_metadata.h b/src/core/file_sys/nca_metadata.h index c1ca9b061..88e66d4da 100644 --- a/src/core/file_sys/nca_metadata.h +++ b/src/core/file_sys/nca_metadata.h | |||
| @@ -29,6 +29,9 @@ enum class TitleType : u8 { | |||
| 29 | DeltaTitle = 0x83, | 29 | DeltaTitle = 0x83, |
| 30 | }; | 30 | }; |
| 31 | 31 | ||
| 32 | bool operator>=(TitleType lhs, TitleType rhs); | ||
| 33 | bool operator<=(TitleType lhs, TitleType rhs); | ||
| 34 | |||
| 32 | enum class ContentRecordType : u8 { | 35 | enum class ContentRecordType : u8 { |
| 33 | Meta = 0, | 36 | Meta = 0, |
| 34 | Program = 1, | 37 | Program = 1, |
| @@ -96,8 +99,8 @@ public: | |||
| 96 | std::vector<u8> Serialize() const; | 99 | std::vector<u8> Serialize() const; |
| 97 | 100 | ||
| 98 | private: | 101 | private: |
| 99 | std::unique_ptr<CNMTHeader> header; | 102 | CNMTHeader header; |
| 100 | std::unique_ptr<OptionalHeader> opt_header; | 103 | OptionalHeader opt_header; |
| 101 | std::vector<ContentRecord> content_records; | 104 | std::vector<ContentRecord> content_records; |
| 102 | std::vector<MetaRecord> meta_records; | 105 | std::vector<MetaRecord> meta_records; |
| 103 | 106 | ||
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index aaadb7463..20fec2391 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp | |||
| @@ -23,13 +23,14 @@ bool operator<(const RegisteredCacheEntry& lhs, const RegisteredCacheEntry& rhs) | |||
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | static bool FollowsTwoDigitDirFormat(std::string_view name) { | 25 | static bool FollowsTwoDigitDirFormat(std::string_view name) { |
| 26 | static const std::regex two_digit_regex( | 26 | static const std::regex two_digit_regex("000000[0-9A-F]{2}", std::regex_constants::ECMAScript | |
| 27 | "000000[0123456789abcdefABCDEF][0123456789abcdefABCDEF]"); | 27 | std::regex_constants::icase); |
| 28 | return std::regex_match(name.begin(), name.end(), two_digit_regex); | 28 | return std::regex_match(name.begin(), name.end(), two_digit_regex); |
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | static bool FollowsNcaIdFormat(std::string_view name) { | 31 | static bool FollowsNcaIdFormat(std::string_view name) { |
| 32 | static const std::regex nca_id_regex("[0123456789abcdefABCDEF]+.nca"); | 32 | static const std::regex nca_id_regex("[0-9A-F]{32}.nca", std::regex_constants::ECMAScript | |
| 33 | std::regex_constants::icase); | ||
| 33 | return name.size() == 36 && std::regex_match(name.begin(), name.end(), nca_id_regex); | 34 | return name.size() == 36 && std::regex_match(name.begin(), name.end(), nca_id_regex); |
| 34 | } | 35 | } |
| 35 | 36 | ||
| @@ -57,8 +58,9 @@ static std::string GetCNMTName(TitleType type, u64 title_id) { | |||
| 57 | }; | 58 | }; |
| 58 | 59 | ||
| 59 | auto index = static_cast<size_t>(type); | 60 | auto index = static_cast<size_t>(type); |
| 60 | if (index >= 0x80) | 61 | // If the index is after the jump in TitleType, subtract it out. |
| 61 | index -= 0x80; | 62 | if (index >= static_cast<size_t>(TitleType::Application)) |
| 63 | index -= static_cast<size_t>(TitleType::Application); | ||
| 62 | return fmt::format("{}_{:016x}.cnmt", TITLE_TYPE_NAMES[index], title_id); | 64 | return fmt::format("{}_{:016x}.cnmt", TITLE_TYPE_NAMES[index], title_id); |
| 63 | } | 65 | } |
| 64 | 66 | ||
| @@ -120,9 +122,15 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, | |||
| 120 | 122 | ||
| 121 | VirtualFile RegisteredCache::GetFileAtID(NcaID id) const { | 123 | VirtualFile RegisteredCache::GetFileAtID(NcaID id) const { |
| 122 | VirtualFile file; | 124 | VirtualFile file; |
| 125 | // Try all four modes of file storage: | ||
| 126 | // (bit 1 = uppercase/lower, bit 0 = within a two-digit dir) | ||
| 127 | // 00: /000000**/{:032X}.nca | ||
| 128 | // 01: /{:032X}.nca | ||
| 129 | // 10: /000000**/{:032x}.nca | ||
| 130 | // 11: /{:032x}.nca | ||
| 123 | for (u8 i = 0; i < 4; ++i) { | 131 | for (u8 i = 0; i < 4; ++i) { |
| 124 | file = OpenFileOrDirectoryConcat( | 132 | const auto path = GetRelativePathFromNcaID(id, (i & 0b10) == 0, (i & 0b01) == 0); |
| 125 | dir, GetRelativePathFromNcaID(id, (i & 0b10) == 0, (i & 0b01) == 0)); | 133 | file = OpenFileOrDirectoryConcat(dir, path); |
| 126 | if (file != nullptr) | 134 | if (file != nullptr) |
| 127 | return file; | 135 | return file; |
| 128 | } | 136 | } |
| @@ -420,6 +428,7 @@ bool RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunct | |||
| 420 | } | 428 | } |
| 421 | 429 | ||
| 422 | bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) { | 430 | bool RegisteredCache::RawInstallYuzuMeta(const CNMT& cnmt) { |
| 431 | // Reasoning behind this method can be found in the comment for InstallEntry, NCA overload. | ||
| 423 | const auto dir = this->dir->CreateDirectoryRelative("yuzu_meta"); | 432 | const auto dir = this->dir->CreateDirectoryRelative("yuzu_meta"); |
| 424 | const auto filename = GetCNMTName(cnmt.GetType(), cnmt.GetTitleID()); | 433 | const auto filename = GetCNMTName(cnmt.GetType(), cnmt.GetTitleID()); |
| 425 | if (dir->GetFile(filename) == nullptr) { | 434 | if (dir->GetFile(filename) == nullptr) { |
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp index 88a9a5259..e6bf586a3 100644 --- a/src/core/file_sys/vfs_concat.cpp +++ b/src/core/file_sys/vfs_concat.cpp | |||
| @@ -68,6 +68,7 @@ size_t ConcatenatedVfsFile::Read(u8* data, size_t length, size_t offset) const { | |||
| 68 | } | 68 | } |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | // Check if the entry should be the last one. The loop above will make it end(). | ||
| 71 | if (entry == files.end() && offset < files.rbegin()->first + files.rbegin()->second->GetSize()) | 72 | if (entry == files.end() && offset < files.rbegin()->first + files.rbegin()->second->GetSize()) |
| 72 | --entry; | 73 | --entry; |
| 73 | 74 | ||
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index fa682153c..33ab35fcd 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp | |||
| @@ -83,10 +83,12 @@ VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { | |||
| 83 | 83 | ||
| 84 | VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { | 84 | VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { |
| 85 | const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); | 85 | const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); |
| 86 | if (!FileUtil::Exists(path) && | 86 | if (!FileUtil::Exists(path)) |
| 87 | !FileUtil::CreateFullPath( | 87 | return nullptr; |
| 88 | FileUtil::SanitizePath(path, FileUtil::DirectorySeparator::ForwardSlash)) && | 88 | if (!FileUtil::CreateFullPath( |
| 89 | !FileUtil::CreateEmptyFile(path)) | 89 | FileUtil::SanitizePath(path, FileUtil::DirectorySeparator::ForwardSlash))) |
| 90 | return nullptr; | ||
| 91 | if (!FileUtil::CreateEmptyFile(path)) | ||
| 90 | return nullptr; | 92 | return nullptr; |
| 91 | return OpenFile(path, perms); | 93 | return OpenFile(path, perms); |
| 92 | } | 94 | } |
| @@ -143,7 +145,12 @@ VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) | |||
| 143 | 145 | ||
| 144 | VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { | 146 | VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { |
| 145 | const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); | 147 | const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); |
| 146 | if (!FileUtil::Exists(path) && !FileUtil::CreateDir(path)) | 148 | if (!FileUtil::Exists(path)) |
| 149 | return nullptr; | ||
| 150 | if (!FileUtil::CreateFullPath( | ||
| 151 | FileUtil::SanitizePath(path, FileUtil::DirectorySeparator::ForwardSlash))) | ||
| 152 | return nullptr; | ||
| 153 | if (!FileUtil::CreateDir(path)) | ||
| 147 | return nullptr; | 154 | return nullptr; |
| 148 | // Cannot use make_shared as RealVfsDirectory constructor is private | 155 | // Cannot use make_shared as RealVfsDirectory constructor is private |
| 149 | return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms)); | 156 | return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms)); |