diff options
| author | 2023-12-08 12:25:58 -0500 | |
|---|---|---|
| committer | 2023-12-08 12:25:58 -0500 | |
| commit | 13131e602fd26614a88efa8bb16b2dc611866ebc (patch) | |
| tree | 24ae0823389770c5d27d1b463c3b635f33ad7d56 /src | |
| parent | Merge pull request #11214 from lat9nq/ff-deprecated (diff) | |
| parent | fsmitm_romfsbuild: optimize for data locality (diff) | |
| download | yuzu-13131e602fd26614a88efa8bb16b2dc611866ebc.tar.gz yuzu-13131e602fd26614a88efa8bb16b2dc611866ebc.tar.xz yuzu-13131e602fd26614a88efa8bb16b2dc611866ebc.zip | |
Merge pull request #12208 from liamwhite/romfs
romfs: optimize parsing and building
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/file_sys/fsmitm_romfsbuild.cpp | 134 | ||||
| -rw-r--r-- | src/core/file_sys/fsmitm_romfsbuild.h | 6 | ||||
| -rw-r--r-- | src/core/file_sys/romfs.cpp | 83 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_concat.cpp | 4 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_concat.h | 2 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_layered.cpp | 21 |
6 files changed, 137 insertions, 113 deletions
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp index f1d3e4129..dd9cca103 100644 --- a/src/core/file_sys/fsmitm_romfsbuild.cpp +++ b/src/core/file_sys/fsmitm_romfsbuild.cpp | |||
| @@ -2,6 +2,7 @@ | |||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | 2 | // SPDX-License-Identifier: GPL-2.0-or-later |
| 3 | 3 | ||
| 4 | #include <cstring> | 4 | #include <cstring> |
| 5 | #include <span> | ||
| 5 | #include <string_view> | 6 | #include <string_view> |
| 6 | #include "common/alignment.h" | 7 | #include "common/alignment.h" |
| 7 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| @@ -134,7 +135,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir romfs_dir, VirtualDir ext_dir, | |||
| 134 | 135 | ||
| 135 | child->size = child->source->GetSize(); | 136 | child->size = child->source->GetSize(); |
| 136 | 137 | ||
| 137 | AddFile(parent, child); | 138 | AddFile(parent, std::move(child)); |
| 138 | } | 139 | } |
| 139 | 140 | ||
| 140 | for (auto& child_romfs_dir : romfs_dir->GetSubdirectories()) { | 141 | for (auto& child_romfs_dir : romfs_dir->GetSubdirectories()) { |
| @@ -163,36 +164,24 @@ void RomFSBuildContext::VisitDirectory(VirtualDir romfs_dir, VirtualDir ext_dir, | |||
| 163 | 164 | ||
| 164 | bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, | 165 | bool RomFSBuildContext::AddDirectory(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, |
| 165 | std::shared_ptr<RomFSBuildDirectoryContext> dir_ctx) { | 166 | std::shared_ptr<RomFSBuildDirectoryContext> dir_ctx) { |
| 166 | // Check whether it's already in the known directories. | ||
| 167 | const auto [it, is_new] = directories.emplace(dir_ctx->path, nullptr); | ||
| 168 | if (!is_new) { | ||
| 169 | return false; | ||
| 170 | } | ||
| 171 | |||
| 172 | // Add a new directory. | 167 | // Add a new directory. |
| 173 | num_dirs++; | 168 | num_dirs++; |
| 174 | dir_table_size += | 169 | dir_table_size += |
| 175 | sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4); | 170 | sizeof(RomFSDirectoryEntry) + Common::AlignUp(dir_ctx->path_len - dir_ctx->cur_path_ofs, 4); |
| 176 | dir_ctx->parent = parent_dir_ctx; | 171 | dir_ctx->parent = std::move(parent_dir_ctx); |
| 177 | it->second = dir_ctx; | 172 | directories.emplace_back(std::move(dir_ctx)); |
| 178 | 173 | ||
| 179 | return true; | 174 | return true; |
| 180 | } | 175 | } |
| 181 | 176 | ||
| 182 | bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, | 177 | bool RomFSBuildContext::AddFile(std::shared_ptr<RomFSBuildDirectoryContext> parent_dir_ctx, |
| 183 | std::shared_ptr<RomFSBuildFileContext> file_ctx) { | 178 | std::shared_ptr<RomFSBuildFileContext> file_ctx) { |
| 184 | // Check whether it's already in the known files. | ||
| 185 | const auto [it, is_new] = files.emplace(file_ctx->path, nullptr); | ||
| 186 | if (!is_new) { | ||
| 187 | return false; | ||
| 188 | } | ||
| 189 | |||
| 190 | // Add a new file. | 179 | // Add a new file. |
| 191 | num_files++; | 180 | num_files++; |
| 192 | file_table_size += | 181 | file_table_size += |
| 193 | sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4); | 182 | sizeof(RomFSFileEntry) + Common::AlignUp(file_ctx->path_len - file_ctx->cur_path_ofs, 4); |
| 194 | file_ctx->parent = parent_dir_ctx; | 183 | file_ctx->parent = std::move(parent_dir_ctx); |
| 195 | it->second = file_ctx; | 184 | files.emplace_back(std::move(file_ctx)); |
| 196 | 185 | ||
| 197 | return true; | 186 | return true; |
| 198 | } | 187 | } |
| @@ -201,7 +190,7 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_, VirtualDir ext_) | |||
| 201 | : base(std::move(base_)), ext(std::move(ext_)) { | 190 | : base(std::move(base_)), ext(std::move(ext_)) { |
| 202 | root = std::make_shared<RomFSBuildDirectoryContext>(); | 191 | root = std::make_shared<RomFSBuildDirectoryContext>(); |
| 203 | root->path = "\0"; | 192 | root->path = "\0"; |
| 204 | directories.emplace(root->path, root); | 193 | directories.emplace_back(root); |
| 205 | num_dirs = 1; | 194 | num_dirs = 1; |
| 206 | dir_table_size = 0x18; | 195 | dir_table_size = 0x18; |
| 207 | 196 | ||
| @@ -210,28 +199,43 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_, VirtualDir ext_) | |||
| 210 | 199 | ||
| 211 | RomFSBuildContext::~RomFSBuildContext() = default; | 200 | RomFSBuildContext::~RomFSBuildContext() = default; |
| 212 | 201 | ||
| 213 | std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { | 202 | std::vector<std::pair<u64, VirtualFile>> RomFSBuildContext::Build() { |
| 214 | const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); | 203 | const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); |
| 215 | const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files); | 204 | const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files); |
| 216 | dir_hash_table_size = 4 * dir_hash_table_entry_count; | 205 | dir_hash_table_size = 4 * dir_hash_table_entry_count; |
| 217 | file_hash_table_size = 4 * file_hash_table_entry_count; | 206 | file_hash_table_size = 4 * file_hash_table_entry_count; |
| 218 | 207 | ||
| 219 | // Assign metadata pointers | 208 | // Assign metadata pointers. |
| 220 | RomFSHeader header{}; | 209 | RomFSHeader header{}; |
| 221 | 210 | ||
| 222 | std::vector<u32> dir_hash_table(dir_hash_table_entry_count, ROMFS_ENTRY_EMPTY); | 211 | std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size + |
| 223 | std::vector<u32> file_hash_table(file_hash_table_entry_count, ROMFS_ENTRY_EMPTY); | 212 | dir_table_size); |
| 224 | 213 | u32* const dir_hash_table_pointer = reinterpret_cast<u32*>(metadata.data()); | |
| 225 | std::vector<u8> dir_table(dir_table_size); | 214 | u8* const dir_table_pointer = metadata.data() + dir_hash_table_size; |
| 226 | std::vector<u8> file_table(file_table_size); | 215 | u32* const file_hash_table_pointer = |
| 227 | 216 | reinterpret_cast<u32*>(metadata.data() + dir_hash_table_size + dir_table_size); | |
| 228 | std::shared_ptr<RomFSBuildFileContext> cur_file; | 217 | u8* const file_table_pointer = |
| 218 | metadata.data() + dir_hash_table_size + dir_table_size + file_hash_table_size; | ||
| 219 | |||
| 220 | std::span<u32> dir_hash_table(dir_hash_table_pointer, dir_hash_table_entry_count); | ||
| 221 | std::span<u32> file_hash_table(file_hash_table_pointer, file_hash_table_entry_count); | ||
| 222 | std::span<u8> dir_table(dir_table_pointer, dir_table_size); | ||
| 223 | std::span<u8> file_table(file_table_pointer, file_table_size); | ||
| 224 | |||
| 225 | // Initialize hash tables. | ||
| 226 | std::memset(dir_hash_table.data(), 0xFF, dir_hash_table.size_bytes()); | ||
| 227 | std::memset(file_hash_table.data(), 0xFF, file_hash_table.size_bytes()); | ||
| 228 | |||
| 229 | // Sort tables by name. | ||
| 230 | std::sort(files.begin(), files.end(), | ||
| 231 | [](const auto& a, const auto& b) { return a->path < b->path; }); | ||
| 232 | std::sort(directories.begin(), directories.end(), | ||
| 233 | [](const auto& a, const auto& b) { return a->path < b->path; }); | ||
| 229 | 234 | ||
| 230 | // Determine file offsets. | 235 | // Determine file offsets. |
| 231 | u32 entry_offset = 0; | 236 | u32 entry_offset = 0; |
| 232 | std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr; | 237 | std::shared_ptr<RomFSBuildFileContext> prev_file = nullptr; |
| 233 | for (const auto& it : files) { | 238 | for (const auto& cur_file : files) { |
| 234 | cur_file = it.second; | ||
| 235 | file_partition_size = Common::AlignUp(file_partition_size, 16); | 239 | file_partition_size = Common::AlignUp(file_partition_size, 16); |
| 236 | cur_file->offset = file_partition_size; | 240 | cur_file->offset = file_partition_size; |
| 237 | file_partition_size += cur_file->size; | 241 | file_partition_size += cur_file->size; |
| @@ -243,34 +247,48 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 243 | } | 247 | } |
| 244 | // Assign deferred parent/sibling ownership. | 248 | // Assign deferred parent/sibling ownership. |
| 245 | for (auto it = files.rbegin(); it != files.rend(); ++it) { | 249 | for (auto it = files.rbegin(); it != files.rend(); ++it) { |
| 246 | cur_file = it->second; | 250 | auto& cur_file = *it; |
| 247 | cur_file->sibling = cur_file->parent->file; | 251 | cur_file->sibling = cur_file->parent->file; |
| 248 | cur_file->parent->file = cur_file; | 252 | cur_file->parent->file = cur_file; |
| 249 | } | 253 | } |
| 250 | 254 | ||
| 251 | std::shared_ptr<RomFSBuildDirectoryContext> cur_dir; | ||
| 252 | |||
| 253 | // Determine directory offsets. | 255 | // Determine directory offsets. |
| 254 | entry_offset = 0; | 256 | entry_offset = 0; |
| 255 | for (const auto& it : directories) { | 257 | for (const auto& cur_dir : directories) { |
| 256 | cur_dir = it.second; | ||
| 257 | cur_dir->entry_offset = entry_offset; | 258 | cur_dir->entry_offset = entry_offset; |
| 258 | entry_offset += | 259 | entry_offset += |
| 259 | static_cast<u32>(sizeof(RomFSDirectoryEntry) + | 260 | static_cast<u32>(sizeof(RomFSDirectoryEntry) + |
| 260 | Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4)); | 261 | Common::AlignUp(cur_dir->path_len - cur_dir->cur_path_ofs, 4)); |
| 261 | } | 262 | } |
| 262 | // Assign deferred parent/sibling ownership. | 263 | // Assign deferred parent/sibling ownership. |
| 263 | for (auto it = directories.rbegin(); it->second != root; ++it) { | 264 | for (auto it = directories.rbegin(); (*it) != root; ++it) { |
| 264 | cur_dir = it->second; | 265 | auto& cur_dir = *it; |
| 265 | cur_dir->sibling = cur_dir->parent->child; | 266 | cur_dir->sibling = cur_dir->parent->child; |
| 266 | cur_dir->parent->child = cur_dir; | 267 | cur_dir->parent->child = cur_dir; |
| 267 | } | 268 | } |
| 268 | 269 | ||
| 269 | std::multimap<u64, VirtualFile> out; | 270 | // Create output map. |
| 271 | std::vector<std::pair<u64, VirtualFile>> out; | ||
| 272 | out.reserve(num_files + 2); | ||
| 273 | |||
| 274 | // Set header fields. | ||
| 275 | header.header_size = sizeof(RomFSHeader); | ||
| 276 | header.file_hash_table_size = file_hash_table_size; | ||
| 277 | header.file_table_size = file_table_size; | ||
| 278 | header.dir_hash_table_size = dir_hash_table_size; | ||
| 279 | header.dir_table_size = dir_table_size; | ||
| 280 | header.file_partition_ofs = ROMFS_FILEPARTITION_OFS; | ||
| 281 | header.dir_hash_table_ofs = Common::AlignUp(header.file_partition_ofs + file_partition_size, 4); | ||
| 282 | header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size; | ||
| 283 | header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size; | ||
| 284 | header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size; | ||
| 285 | |||
| 286 | std::vector<u8> header_data(sizeof(RomFSHeader)); | ||
| 287 | std::memcpy(header_data.data(), &header, header_data.size()); | ||
| 288 | out.emplace_back(0, std::make_shared<VectorVfsFile>(std::move(header_data))); | ||
| 270 | 289 | ||
| 271 | // Populate file tables. | 290 | // Populate file tables. |
| 272 | for (const auto& it : files) { | 291 | for (const auto& cur_file : files) { |
| 273 | cur_file = it.second; | ||
| 274 | RomFSFileEntry cur_entry{}; | 292 | RomFSFileEntry cur_entry{}; |
| 275 | 293 | ||
| 276 | cur_entry.parent = cur_file->parent->entry_offset; | 294 | cur_entry.parent = cur_file->parent->entry_offset; |
| @@ -287,7 +305,7 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 287 | 305 | ||
| 288 | cur_entry.name_size = name_size; | 306 | cur_entry.name_size = name_size; |
| 289 | 307 | ||
| 290 | out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, std::move(cur_file->source)); | 308 | out.emplace_back(cur_file->offset + ROMFS_FILEPARTITION_OFS, std::move(cur_file->source)); |
| 291 | std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry)); | 309 | std::memcpy(file_table.data() + cur_file->entry_offset, &cur_entry, sizeof(RomFSFileEntry)); |
| 292 | std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0, | 310 | std::memset(file_table.data() + cur_file->entry_offset + sizeof(RomFSFileEntry), 0, |
| 293 | Common::AlignUp(cur_entry.name_size, 4)); | 311 | Common::AlignUp(cur_entry.name_size, 4)); |
| @@ -296,8 +314,7 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 296 | } | 314 | } |
| 297 | 315 | ||
| 298 | // Populate dir tables. | 316 | // Populate dir tables. |
| 299 | for (const auto& it : directories) { | 317 | for (const auto& cur_dir : directories) { |
| 300 | cur_dir = it.second; | ||
| 301 | RomFSDirectoryEntry cur_entry{}; | 318 | RomFSDirectoryEntry cur_entry{}; |
| 302 | 319 | ||
| 303 | cur_entry.parent = cur_dir == root ? 0 : cur_dir->parent->entry_offset; | 320 | cur_entry.parent = cur_dir == root ? 0 : cur_dir->parent->entry_offset; |
| @@ -323,34 +340,13 @@ std::multimap<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 323 | cur_dir->path.data() + cur_dir->cur_path_ofs, name_size); | 340 | cur_dir->path.data() + cur_dir->cur_path_ofs, name_size); |
| 324 | } | 341 | } |
| 325 | 342 | ||
| 326 | // Set header fields. | 343 | // Write metadata. |
| 327 | header.header_size = sizeof(RomFSHeader); | 344 | out.emplace_back(header.dir_hash_table_ofs, |
| 328 | header.file_hash_table_size = file_hash_table_size; | 345 | std::make_shared<VectorVfsFile>(std::move(metadata))); |
| 329 | header.file_table_size = file_table_size; | ||
| 330 | header.dir_hash_table_size = dir_hash_table_size; | ||
| 331 | header.dir_table_size = dir_table_size; | ||
| 332 | header.file_partition_ofs = ROMFS_FILEPARTITION_OFS; | ||
| 333 | header.dir_hash_table_ofs = Common::AlignUp(header.file_partition_ofs + file_partition_size, 4); | ||
| 334 | header.dir_table_ofs = header.dir_hash_table_ofs + header.dir_hash_table_size; | ||
| 335 | header.file_hash_table_ofs = header.dir_table_ofs + header.dir_table_size; | ||
| 336 | header.file_table_ofs = header.file_hash_table_ofs + header.file_hash_table_size; | ||
| 337 | |||
| 338 | std::vector<u8> header_data(sizeof(RomFSHeader)); | ||
| 339 | std::memcpy(header_data.data(), &header, header_data.size()); | ||
| 340 | out.emplace(0, std::make_shared<VectorVfsFile>(std::move(header_data))); | ||
| 341 | 346 | ||
| 342 | std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size + | 347 | // Sort the output. |
| 343 | dir_table_size); | 348 | std::sort(out.begin(), out.end(), |
| 344 | std::size_t index = 0; | 349 | [](const auto& a, const auto& b) { return a.first < b.first; }); |
| 345 | std::memcpy(metadata.data(), dir_hash_table.data(), dir_hash_table.size() * sizeof(u32)); | ||
| 346 | index += dir_hash_table.size() * sizeof(u32); | ||
| 347 | std::memcpy(metadata.data() + index, dir_table.data(), dir_table.size()); | ||
| 348 | index += dir_table.size(); | ||
| 349 | std::memcpy(metadata.data() + index, file_hash_table.data(), | ||
| 350 | file_hash_table.size() * sizeof(u32)); | ||
| 351 | index += file_hash_table.size() * sizeof(u32); | ||
| 352 | std::memcpy(metadata.data() + index, file_table.data(), file_table.size()); | ||
| 353 | out.emplace(header.dir_hash_table_ofs, std::make_shared<VectorVfsFile>(std::move(metadata))); | ||
| 354 | 350 | ||
| 355 | return out; | 351 | return out; |
| 356 | } | 352 | } |
diff --git a/src/core/file_sys/fsmitm_romfsbuild.h b/src/core/file_sys/fsmitm_romfsbuild.h index 06e5d5a47..f387c79f1 100644 --- a/src/core/file_sys/fsmitm_romfsbuild.h +++ b/src/core/file_sys/fsmitm_romfsbuild.h | |||
| @@ -22,14 +22,14 @@ public: | |||
| 22 | ~RomFSBuildContext(); | 22 | ~RomFSBuildContext(); |
| 23 | 23 | ||
| 24 | // This finalizes the context. | 24 | // This finalizes the context. |
| 25 | std::multimap<u64, VirtualFile> Build(); | 25 | std::vector<std::pair<u64, VirtualFile>> Build(); |
| 26 | 26 | ||
| 27 | private: | 27 | private: |
| 28 | VirtualDir base; | 28 | VirtualDir base; |
| 29 | VirtualDir ext; | 29 | VirtualDir ext; |
| 30 | std::shared_ptr<RomFSBuildDirectoryContext> root; | 30 | std::shared_ptr<RomFSBuildDirectoryContext> root; |
| 31 | std::map<std::string, std::shared_ptr<RomFSBuildDirectoryContext>, std::less<>> directories; | 31 | std::vector<std::shared_ptr<RomFSBuildDirectoryContext>> directories; |
| 32 | std::map<std::string, std::shared_ptr<RomFSBuildFileContext>, std::less<>> files; | 32 | std::vector<std::shared_ptr<RomFSBuildFileContext>> files; |
| 33 | u64 num_dirs = 0; | 33 | u64 num_dirs = 0; |
| 34 | u64 num_files = 0; | 34 | u64 num_files = 0; |
| 35 | u64 dir_table_size = 0; | 35 | u64 dir_table_size = 0; |
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp index 6de2103a0..6182598ae 100644 --- a/src/core/file_sys/romfs.cpp +++ b/src/core/file_sys/romfs.cpp | |||
| @@ -55,44 +55,68 @@ struct FileEntry { | |||
| 55 | }; | 55 | }; |
| 56 | static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size."); | 56 | static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size."); |
| 57 | 57 | ||
| 58 | template <typename Entry> | 58 | struct RomFSTraversalContext { |
| 59 | std::pair<Entry, std::string> GetEntry(const VirtualFile& file, std::size_t offset) { | 59 | RomFSHeader header; |
| 60 | Entry entry{}; | 60 | VirtualFile file; |
| 61 | if (file->ReadObject(&entry, offset) != sizeof(Entry)) | 61 | std::vector<u8> directory_meta; |
| 62 | return {}; | 62 | std::vector<u8> file_meta; |
| 63 | std::string string(entry.name_length, '\0'); | 63 | }; |
| 64 | if (file->ReadArray(&string[0], string.size(), offset + sizeof(Entry)) != string.size()) | 64 | |
| 65 | template <typename EntryType, auto Member> | ||
| 66 | std::pair<EntryType, std::string> GetEntry(const RomFSTraversalContext& ctx, size_t offset) { | ||
| 67 | const size_t entry_end = offset + sizeof(EntryType); | ||
| 68 | const std::vector<u8>& vec = ctx.*Member; | ||
| 69 | const size_t size = vec.size(); | ||
| 70 | const u8* data = vec.data(); | ||
| 71 | EntryType entry{}; | ||
| 72 | |||
| 73 | if (entry_end > size) { | ||
| 65 | return {}; | 74 | return {}; |
| 66 | return {entry, string}; | 75 | } |
| 76 | std::memcpy(&entry, data + offset, sizeof(EntryType)); | ||
| 77 | |||
| 78 | const size_t name_length = std::min(entry_end + entry.name_length, size) - entry_end; | ||
| 79 | std::string name(reinterpret_cast<const char*>(data + entry_end), name_length); | ||
| 80 | |||
| 81 | return {entry, std::move(name)}; | ||
| 82 | } | ||
| 83 | |||
| 84 | std::pair<DirectoryEntry, std::string> GetDirectoryEntry(const RomFSTraversalContext& ctx, | ||
| 85 | size_t directory_offset) { | ||
| 86 | return GetEntry<DirectoryEntry, &RomFSTraversalContext::directory_meta>(ctx, directory_offset); | ||
| 87 | } | ||
| 88 | |||
| 89 | std::pair<FileEntry, std::string> GetFileEntry(const RomFSTraversalContext& ctx, | ||
| 90 | size_t file_offset) { | ||
| 91 | return GetEntry<FileEntry, &RomFSTraversalContext::file_meta>(ctx, file_offset); | ||
| 67 | } | 92 | } |
| 68 | 93 | ||
| 69 | void ProcessFile(const VirtualFile& file, std::size_t file_offset, std::size_t data_offset, | 94 | void ProcessFile(const RomFSTraversalContext& ctx, u32 this_file_offset, |
| 70 | u32 this_file_offset, std::shared_ptr<VectorVfsDirectory>& parent) { | 95 | std::shared_ptr<VectorVfsDirectory>& parent) { |
| 71 | while (this_file_offset != ROMFS_ENTRY_EMPTY) { | 96 | while (this_file_offset != ROMFS_ENTRY_EMPTY) { |
| 72 | auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset); | 97 | auto entry = GetFileEntry(ctx, this_file_offset); |
| 73 | 98 | ||
| 74 | parent->AddFile(std::make_shared<OffsetVfsFile>( | 99 | parent->AddFile(std::make_shared<OffsetVfsFile>(ctx.file, entry.first.size, |
| 75 | file, entry.first.size, entry.first.offset + data_offset, entry.second)); | 100 | entry.first.offset + ctx.header.data_offset, |
| 101 | std::move(entry.second))); | ||
| 76 | 102 | ||
| 77 | this_file_offset = entry.first.sibling; | 103 | this_file_offset = entry.first.sibling; |
| 78 | } | 104 | } |
| 79 | } | 105 | } |
| 80 | 106 | ||
| 81 | void ProcessDirectory(const VirtualFile& file, std::size_t dir_offset, std::size_t file_offset, | 107 | void ProcessDirectory(const RomFSTraversalContext& ctx, u32 this_dir_offset, |
| 82 | std::size_t data_offset, u32 this_dir_offset, | ||
| 83 | std::shared_ptr<VectorVfsDirectory>& parent) { | 108 | std::shared_ptr<VectorVfsDirectory>& parent) { |
| 84 | while (this_dir_offset != ROMFS_ENTRY_EMPTY) { | 109 | while (this_dir_offset != ROMFS_ENTRY_EMPTY) { |
| 85 | auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset); | 110 | auto entry = GetDirectoryEntry(ctx, this_dir_offset); |
| 86 | auto current = std::make_shared<VectorVfsDirectory>( | 111 | auto current = std::make_shared<VectorVfsDirectory>( |
| 87 | std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, entry.second); | 112 | std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, entry.second); |
| 88 | 113 | ||
| 89 | if (entry.first.child_file != ROMFS_ENTRY_EMPTY) { | 114 | if (entry.first.child_file != ROMFS_ENTRY_EMPTY) { |
| 90 | ProcessFile(file, file_offset, data_offset, entry.first.child_file, current); | 115 | ProcessFile(ctx, entry.first.child_file, current); |
| 91 | } | 116 | } |
| 92 | 117 | ||
| 93 | if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) { | 118 | if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) { |
| 94 | ProcessDirectory(file, dir_offset, file_offset, data_offset, entry.first.child_dir, | 119 | ProcessDirectory(ctx, entry.first.child_dir, current); |
| 95 | current); | ||
| 96 | } | 120 | } |
| 97 | 121 | ||
| 98 | parent->AddDirectory(current); | 122 | parent->AddDirectory(current); |
| @@ -107,22 +131,25 @@ VirtualDir ExtractRomFS(VirtualFile file) { | |||
| 107 | return root_container; | 131 | return root_container; |
| 108 | } | 132 | } |
| 109 | 133 | ||
| 110 | RomFSHeader header{}; | 134 | RomFSTraversalContext ctx{}; |
| 111 | if (file->ReadObject(&header) != sizeof(RomFSHeader)) { | 135 | |
| 112 | return root_container; | 136 | if (file->ReadObject(&ctx.header) != sizeof(RomFSHeader)) { |
| 137 | return nullptr; | ||
| 113 | } | 138 | } |
| 114 | 139 | ||
| 115 | if (header.header_size != sizeof(RomFSHeader)) { | 140 | if (ctx.header.header_size != sizeof(RomFSHeader)) { |
| 116 | return root_container; | 141 | return nullptr; |
| 117 | } | 142 | } |
| 118 | 143 | ||
| 119 | const u64 file_offset = header.file_meta.offset; | 144 | ctx.file = file; |
| 120 | const u64 dir_offset = header.directory_meta.offset; | 145 | ctx.directory_meta = |
| 146 | file->ReadBytes(ctx.header.directory_meta.size, ctx.header.directory_meta.offset); | ||
| 147 | ctx.file_meta = file->ReadBytes(ctx.header.file_meta.size, ctx.header.file_meta.offset); | ||
| 121 | 148 | ||
| 122 | ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root_container); | 149 | ProcessDirectory(ctx, 0, root_container); |
| 123 | 150 | ||
| 124 | if (auto root = root_container->GetSubdirectory(""); root) { | 151 | if (auto root = root_container->GetSubdirectory(""); root) { |
| 125 | return std::make_shared<CachedVfsDirectory>(std::move(root)); | 152 | return root; |
| 126 | } | 153 | } |
| 127 | 154 | ||
| 128 | ASSERT(false); | 155 | ASSERT(false); |
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp index 168b9cbec..7c7298527 100644 --- a/src/core/file_sys/vfs_concat.cpp +++ b/src/core/file_sys/vfs_concat.cpp | |||
| @@ -59,8 +59,8 @@ VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::string&& name, | |||
| 59 | return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map))); | 59 | return VirtualFile(new ConcatenatedVfsFile(std::move(name), std::move(concatenation_map))); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, std::string&& name, | 62 | VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile( |
| 63 | std::multimap<u64, VirtualFile>&& files) { | 63 | u8 filler_byte, std::string&& name, std::vector<std::pair<u64, VirtualFile>>&& files) { |
| 64 | // Fold trivial cases. | 64 | // Fold trivial cases. |
| 65 | if (files.empty()) { | 65 | if (files.empty()) { |
| 66 | return nullptr; | 66 | return nullptr; |
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h index cbddd12bd..b5f3d72e3 100644 --- a/src/core/file_sys/vfs_concat.h +++ b/src/core/file_sys/vfs_concat.h | |||
| @@ -37,7 +37,7 @@ public: | |||
| 37 | /// Convenience function that turns a map of offsets to files into a concatenated file, filling | 37 | /// Convenience function that turns a map of offsets to files into a concatenated file, filling |
| 38 | /// gaps with a given filler byte. | 38 | /// gaps with a given filler byte. |
| 39 | static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::string&& name, | 39 | static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::string&& name, |
| 40 | std::multimap<u64, VirtualFile>&& files); | 40 | std::vector<std::pair<u64, VirtualFile>>&& files); |
| 41 | 41 | ||
| 42 | std::string GetName() const override; | 42 | std::string GetName() const override; |
| 43 | std::size_t GetSize() const override; | 43 | std::size_t GetSize() const override; |
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp index 08daca397..5551743fb 100644 --- a/src/core/file_sys/vfs_layered.cpp +++ b/src/core/file_sys/vfs_layered.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | 3 | ||
| 4 | #include <algorithm> | 4 | #include <algorithm> |
| 5 | #include <set> | 5 | #include <set> |
| 6 | #include <unordered_set> | ||
| 6 | #include <utility> | 7 | #include <utility> |
| 7 | #include "core/file_sys/vfs_layered.h" | 8 | #include "core/file_sys/vfs_layered.h" |
| 8 | 9 | ||
| @@ -59,13 +60,12 @@ std::string LayeredVfsDirectory::GetFullPath() const { | |||
| 59 | 60 | ||
| 60 | std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const { | 61 | std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const { |
| 61 | std::vector<VirtualFile> out; | 62 | std::vector<VirtualFile> out; |
| 62 | std::set<std::string, std::less<>> out_names; | 63 | std::unordered_set<std::string> out_names; |
| 63 | 64 | ||
| 64 | for (const auto& layer : dirs) { | 65 | for (const auto& layer : dirs) { |
| 65 | for (auto& file : layer->GetFiles()) { | 66 | for (auto& file : layer->GetFiles()) { |
| 66 | auto file_name = file->GetName(); | 67 | const auto [it, is_new] = out_names.emplace(file->GetName()); |
| 67 | if (!out_names.contains(file_name)) { | 68 | if (is_new) { |
| 68 | out_names.emplace(std::move(file_name)); | ||
| 69 | out.emplace_back(std::move(file)); | 69 | out.emplace_back(std::move(file)); |
| 70 | } | 70 | } |
| 71 | } | 71 | } |
| @@ -75,18 +75,19 @@ std::vector<VirtualFile> LayeredVfsDirectory::GetFiles() const { | |||
| 75 | } | 75 | } |
| 76 | 76 | ||
| 77 | std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const { | 77 | std::vector<VirtualDir> LayeredVfsDirectory::GetSubdirectories() const { |
| 78 | std::vector<std::string> names; | 78 | std::vector<VirtualDir> out; |
| 79 | std::unordered_set<std::string> out_names; | ||
| 80 | |||
| 79 | for (const auto& layer : dirs) { | 81 | for (const auto& layer : dirs) { |
| 80 | for (const auto& sd : layer->GetSubdirectories()) { | 82 | for (const auto& sd : layer->GetSubdirectories()) { |
| 81 | if (std::find(names.begin(), names.end(), sd->GetName()) == names.end()) | 83 | out_names.emplace(sd->GetName()); |
| 82 | names.push_back(sd->GetName()); | ||
| 83 | } | 84 | } |
| 84 | } | 85 | } |
| 85 | 86 | ||
| 86 | std::vector<VirtualDir> out; | 87 | out.reserve(out_names.size()); |
| 87 | out.reserve(names.size()); | 88 | for (const auto& subdir : out_names) { |
| 88 | for (const auto& subdir : names) | ||
| 89 | out.emplace_back(GetSubdirectory(subdir)); | 89 | out.emplace_back(GetSubdirectory(subdir)); |
| 90 | } | ||
| 90 | 91 | ||
| 91 | return out; | 92 | return out; |
| 92 | } | 93 | } |