diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/core.cpp | 2 | ||||
| -rw-r--r-- | src/core/file_sys/fsmitm_romfsbuild.cpp | 35 | ||||
| -rw-r--r-- | src/core/file_sys/patch_manager.cpp | 56 | ||||
| -rw-r--r-- | src/core/file_sys/registered_cache.cpp | 2 | ||||
| -rw-r--r-- | src/core/file_sys/romfs.cpp | 2 | ||||
| -rw-r--r-- | src/core/file_sys/vfs.cpp | 6 | ||||
| -rw-r--r-- | src/core/file_sys/vfs.h | 9 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_concat.cpp | 45 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_concat.h | 44 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_layered.cpp | 15 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_layered.h | 8 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_static.h | 21 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_vector.cpp | 6 | ||||
| -rw-r--r-- | src/core/file_sys/vfs_vector.h | 8 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 88 |
15 files changed, 172 insertions, 175 deletions
diff --git a/src/core/core.cpp b/src/core/core.cpp index 50f0a42fb..7666354dc 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -64,7 +64,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, | |||
| 64 | if (concat.empty()) | 64 | if (concat.empty()) |
| 65 | return nullptr; | 65 | return nullptr; |
| 66 | 66 | ||
| 67 | return FileSys::ConcatenateFiles(concat, dir->GetName()); | 67 | return FileSys::ConcatenatedVfsFile::MakeConcatenatedFile(concat, dir->GetName()); |
| 68 | } | 68 | } |
| 69 | 69 | ||
| 70 | return vfs->OpenFile(path, FileSys::Mode::Read); | 70 | return vfs->OpenFile(path, FileSys::Mode::Read); |
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp index 21fc3d796..07b074817 100644 --- a/src/core/file_sys/fsmitm_romfsbuild.cpp +++ b/src/core/file_sys/fsmitm_romfsbuild.cpp | |||
| @@ -73,7 +73,7 @@ static_assert(sizeof(RomFSFileEntry) == 0x20, "RomFSFileEntry has incorrect size | |||
| 73 | struct RomFSBuildFileContext; | 73 | struct RomFSBuildFileContext; |
| 74 | 74 | ||
| 75 | struct RomFSBuildDirectoryContext { | 75 | struct RomFSBuildDirectoryContext { |
| 76 | std::string path = ""; | 76 | std::string path; |
| 77 | u32 cur_path_ofs = 0; | 77 | u32 cur_path_ofs = 0; |
| 78 | u32 path_len = 0; | 78 | u32 path_len = 0; |
| 79 | u32 entry_offset = 0; | 79 | u32 entry_offset = 0; |
| @@ -84,7 +84,7 @@ struct RomFSBuildDirectoryContext { | |||
| 84 | }; | 84 | }; |
| 85 | 85 | ||
| 86 | struct RomFSBuildFileContext { | 86 | struct RomFSBuildFileContext { |
| 87 | std::string path = ""; | 87 | std::string path; |
| 88 | u32 cur_path_ofs = 0; | 88 | u32 cur_path_ofs = 0; |
| 89 | u32 path_len = 0; | 89 | u32 path_len = 0; |
| 90 | u32 entry_offset = 0; | 90 | u32 entry_offset = 0; |
| @@ -92,12 +92,10 @@ struct RomFSBuildFileContext { | |||
| 92 | u64 size = 0; | 92 | u64 size = 0; |
| 93 | std::shared_ptr<RomFSBuildDirectoryContext> parent; | 93 | std::shared_ptr<RomFSBuildDirectoryContext> parent; |
| 94 | std::shared_ptr<RomFSBuildFileContext> sibling; | 94 | std::shared_ptr<RomFSBuildFileContext> sibling; |
| 95 | VirtualFile source = nullptr; | 95 | VirtualFile source; |
| 96 | |||
| 97 | RomFSBuildFileContext() : path(""), cur_path_ofs(0), path_len(0) {} | ||
| 98 | }; | 96 | }; |
| 99 | 97 | ||
| 100 | static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, size_t path_len) { | 98 | static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, std::size_t path_len) { |
| 101 | u32 hash = parent ^ 123456789; | 99 | u32 hash = parent ^ 123456789; |
| 102 | for (u32 i = 0; i < path_len; i++) { | 100 | for (u32 i = 0; i < path_len; i++) { |
| 103 | hash = (hash >> 5) | (hash << 27); | 101 | hash = (hash >> 5) | (hash << 27); |
| @@ -107,13 +105,16 @@ static u32 romfs_calc_path_hash(u32 parent, std::string path, u32 start, size_t | |||
| 107 | return hash; | 105 | return hash; |
| 108 | } | 106 | } |
| 109 | 107 | ||
| 110 | static u32 romfs_get_hash_table_count(u32 num_entries) { | 108 | static u64 romfs_get_hash_table_count(u64 num_entries) { |
| 111 | if (num_entries < 3) { | 109 | if (num_entries < 3) { |
| 112 | return 3; | 110 | return 3; |
| 113 | } else if (num_entries < 19) { | 111 | } |
| 112 | |||
| 113 | if (num_entries < 19) { | ||
| 114 | return num_entries | 1; | 114 | return num_entries | 1; |
| 115 | } | 115 | } |
| 116 | u32 count = num_entries; | 116 | |
| 117 | u64 count = num_entries; | ||
| 117 | while (count % 2 == 0 || count % 3 == 0 || count % 5 == 0 || count % 7 == 0 || | 118 | while (count % 2 == 0 || count % 3 == 0 || count % 5 == 0 || count % 7 == 0 || |
| 118 | count % 11 == 0 || count % 13 == 0 || count % 17 == 0) { | 119 | count % 11 == 0 || count % 13 == 0 || count % 17 == 0) { |
| 119 | count++; | 120 | count++; |
| @@ -139,7 +140,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, | |||
| 139 | const auto child = std::make_shared<RomFSBuildDirectoryContext>(); | 140 | const auto child = std::make_shared<RomFSBuildDirectoryContext>(); |
| 140 | // Set child's path. | 141 | // Set child's path. |
| 141 | child->cur_path_ofs = parent->path_len + 1; | 142 | child->cur_path_ofs = parent->path_len + 1; |
| 142 | child->path_len = child->cur_path_ofs + kv.first.size(); | 143 | child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size()); |
| 143 | child->path = parent->path + "/" + kv.first; | 144 | child->path = parent->path + "/" + kv.first; |
| 144 | 145 | ||
| 145 | // Sanity check on path_len | 146 | // Sanity check on path_len |
| @@ -152,7 +153,7 @@ void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, | |||
| 152 | const auto child = std::make_shared<RomFSBuildFileContext>(); | 153 | const auto child = std::make_shared<RomFSBuildFileContext>(); |
| 153 | // Set child's path. | 154 | // Set child's path. |
| 154 | child->cur_path_ofs = parent->path_len + 1; | 155 | child->cur_path_ofs = parent->path_len + 1; |
| 155 | child->path_len = child->cur_path_ofs + kv.first.size(); | 156 | child->path_len = child->cur_path_ofs + static_cast<u32>(kv.first.size()); |
| 156 | child->path = parent->path + "/" + kv.first; | 157 | child->path = parent->path + "/" + kv.first; |
| 157 | 158 | ||
| 158 | // Sanity check on path_len | 159 | // Sanity check on path_len |
| @@ -219,8 +220,8 @@ RomFSBuildContext::RomFSBuildContext(VirtualDir base_) : base(std::move(base_)) | |||
| 219 | RomFSBuildContext::~RomFSBuildContext() = default; | 220 | RomFSBuildContext::~RomFSBuildContext() = default; |
| 220 | 221 | ||
| 221 | std::map<u64, VirtualFile> RomFSBuildContext::Build() { | 222 | std::map<u64, VirtualFile> RomFSBuildContext::Build() { |
| 222 | const auto dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); | 223 | const u64 dir_hash_table_entry_count = romfs_get_hash_table_count(num_dirs); |
| 223 | const auto file_hash_table_entry_count = romfs_get_hash_table_count(num_files); | 224 | const u64 file_hash_table_entry_count = romfs_get_hash_table_count(num_files); |
| 224 | dir_hash_table_size = 4 * dir_hash_table_entry_count; | 225 | dir_hash_table_size = 4 * dir_hash_table_entry_count; |
| 225 | file_hash_table_size = 4 * file_hash_table_entry_count; | 226 | file_hash_table_size = 4 * file_hash_table_entry_count; |
| 226 | 227 | ||
| @@ -233,12 +234,6 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 233 | std::vector<u8> dir_table(dir_table_size); | 234 | std::vector<u8> dir_table(dir_table_size); |
| 234 | std::vector<u8> file_table(file_table_size); | 235 | std::vector<u8> file_table(file_table_size); |
| 235 | 236 | ||
| 236 | // Clear out hash tables. | ||
| 237 | for (u32 i = 0; i < dir_hash_table_entry_count; i++) | ||
| 238 | dir_hash_table[i] = ROMFS_ENTRY_EMPTY; | ||
| 239 | for (u32 i = 0; i < file_hash_table_entry_count; i++) | ||
| 240 | file_hash_table[i] = ROMFS_ENTRY_EMPTY; | ||
| 241 | |||
| 242 | std::shared_ptr<RomFSBuildFileContext> cur_file; | 237 | std::shared_ptr<RomFSBuildFileContext> cur_file; |
| 243 | 238 | ||
| 244 | // Determine file offsets. | 239 | // Determine file offsets. |
| @@ -355,7 +350,7 @@ std::map<u64, VirtualFile> RomFSBuildContext::Build() { | |||
| 355 | 350 | ||
| 356 | std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size + | 351 | std::vector<u8> metadata(file_hash_table_size + file_table_size + dir_hash_table_size + |
| 357 | dir_table_size); | 352 | dir_table_size); |
| 358 | auto index = 0; | 353 | std::size_t index = 0; |
| 359 | std::memcpy(metadata.data(), dir_hash_table.data(), dir_hash_table.size() * sizeof(u32)); | 354 | std::memcpy(metadata.data(), dir_hash_table.data(), dir_hash_table.size() * sizeof(u32)); |
| 360 | index += dir_hash_table.size() * sizeof(u32); | 355 | index += dir_hash_table.size() * sizeof(u32); |
| 361 | std::memcpy(metadata.data() + index, dir_table.data(), dir_table.size()); | 356 | std::memcpy(metadata.data() + index, dir_table.data(), dir_table.size()); |
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index af3f9a78f..4b3b5e665 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp | |||
| @@ -70,38 +70,40 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { | |||
| 70 | 70 | ||
| 71 | static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { | 71 | static void ApplyLayeredFS(VirtualFile& romfs, u64 title_id, ContentRecordType type) { |
| 72 | const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); | 72 | const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); |
| 73 | if (type == ContentRecordType::Program && load_dir != nullptr && load_dir->GetSize() > 0) { | 73 | if (type != ContentRecordType::Program || load_dir == nullptr || load_dir->GetSize() <= 0) { |
| 74 | auto extracted = ExtractRomFS(romfs); | 74 | return; |
| 75 | 75 | } | |
| 76 | if (extracted != nullptr) { | ||
| 77 | auto patch_dirs = load_dir->GetSubdirectories(); | ||
| 78 | std::sort(patch_dirs.begin(), patch_dirs.end(), | ||
| 79 | [](const VirtualDir& l, const VirtualDir& r) { | ||
| 80 | return l->GetName() < r->GetName(); | ||
| 81 | }); | ||
| 82 | |||
| 83 | std::vector<VirtualDir> layers; | ||
| 84 | layers.reserve(patch_dirs.size() + 1); | ||
| 85 | for (const auto& subdir : patch_dirs) { | ||
| 86 | auto romfs_dir = subdir->GetSubdirectory("romfs"); | ||
| 87 | if (romfs_dir != nullptr) | ||
| 88 | layers.push_back(std::move(romfs_dir)); | ||
| 89 | } | ||
| 90 | 76 | ||
| 91 | layers.push_back(std::move(extracted)); | 77 | auto extracted = ExtractRomFS(romfs); |
| 78 | if (extracted == nullptr) { | ||
| 79 | return; | ||
| 80 | } | ||
| 92 | 81 | ||
| 93 | const auto layered = LayerDirectories(layers); | 82 | auto patch_dirs = load_dir->GetSubdirectories(); |
| 83 | std::sort(patch_dirs.begin(), patch_dirs.end(), | ||
| 84 | [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); }); | ||
| 94 | 85 | ||
| 95 | if (layered != nullptr) { | 86 | std::vector<VirtualDir> layers; |
| 96 | auto packed = CreateRomFS(layered); | 87 | layers.reserve(patch_dirs.size() + 1); |
| 88 | for (const auto& subdir : patch_dirs) { | ||
| 89 | auto romfs_dir = subdir->GetSubdirectory("romfs"); | ||
| 90 | if (romfs_dir != nullptr) | ||
| 91 | layers.push_back(std::move(romfs_dir)); | ||
| 92 | } | ||
| 93 | layers.push_back(std::move(extracted)); | ||
| 97 | 94 | ||
| 98 | if (packed != nullptr) { | 95 | auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers)); |
| 99 | LOG_INFO(Loader, " RomFS: LayeredFS patches applied successfully"); | 96 | if (layered == nullptr) { |
| 100 | romfs = std::move(packed); | 97 | return; |
| 101 | } | 98 | } |
| 102 | } | 99 | |
| 103 | } | 100 | auto packed = CreateRomFS(std::move(layered)); |
| 101 | if (packed == nullptr) { | ||
| 102 | return; | ||
| 104 | } | 103 | } |
| 104 | |||
| 105 | LOG_INFO(Loader, " RomFS: LayeredFS patches applied successfully"); | ||
| 106 | romfs = std::move(packed); | ||
| 105 | } | 107 | } |
| 106 | 108 | ||
| 107 | VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, | 109 | VirtualFile PatchManager::PatchRomFS(VirtualFile romfs, u64 ivfc_offset, |
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index 653ef2e7b..e9b040689 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp | |||
| @@ -125,7 +125,7 @@ VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir, | |||
| 125 | if (concat.empty()) | 125 | if (concat.empty()) |
| 126 | return nullptr; | 126 | return nullptr; |
| 127 | 127 | ||
| 128 | file = FileSys::ConcatenateFiles(concat, concat.front()->GetName()); | 128 | file = ConcatenatedVfsFile::MakeConcatenatedFile(concat, concat.front()->GetName()); |
| 129 | } | 129 | } |
| 130 | 130 | ||
| 131 | return file; | 131 | return file; |
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp index 205284a4d..5910f7046 100644 --- a/src/core/file_sys/romfs.cpp +++ b/src/core/file_sys/romfs.cpp | |||
| @@ -134,7 +134,7 @@ VirtualFile CreateRomFS(VirtualDir dir) { | |||
| 134 | return nullptr; | 134 | return nullptr; |
| 135 | 135 | ||
| 136 | RomFSBuildContext ctx{dir}; | 136 | RomFSBuildContext ctx{dir}; |
| 137 | return ConcatenateFiles<0>(ctx.Build(), dir->GetName()); | 137 | return ConcatenatedVfsFile::MakeConcatenatedFile(0, ctx.Build(), dir->GetName()); |
| 138 | } | 138 | } |
| 139 | 139 | ||
| 140 | } // namespace FileSys | 140 | } // namespace FileSys |
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index 5fbea1739..bfe50da73 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp | |||
| @@ -463,14 +463,14 @@ bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, std::size_t | |||
| 463 | return true; | 463 | return true; |
| 464 | } | 464 | } |
| 465 | 465 | ||
| 466 | bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_size) { | 466 | bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, std::size_t block_size) { |
| 467 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) | 467 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) |
| 468 | return false; | 468 | return false; |
| 469 | if (!dest->Resize(src->GetSize())) | 469 | if (!dest->Resize(src->GetSize())) |
| 470 | return false; | 470 | return false; |
| 471 | 471 | ||
| 472 | std::vector<u8> temp(std::min(block_size, src->GetSize())); | 472 | std::vector<u8> temp(std::min(block_size, src->GetSize())); |
| 473 | for (size_t i = 0; i < src->GetSize(); i += block_size) { | 473 | for (std::size_t i = 0; i < src->GetSize(); i += block_size) { |
| 474 | const auto read = std::min(block_size, src->GetSize() - i); | 474 | const auto read = std::min(block_size, src->GetSize() - i); |
| 475 | const auto block = src->Read(temp.data(), read, i); | 475 | const auto block = src->Read(temp.data(), read, i); |
| 476 | 476 | ||
| @@ -481,7 +481,7 @@ bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_si | |||
| 481 | return true; | 481 | return true; |
| 482 | } | 482 | } |
| 483 | 483 | ||
| 484 | bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, size_t block_size) { | 484 | bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, std::size_t block_size) { |
| 485 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) | 485 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) |
| 486 | return false; | 486 | return false; |
| 487 | 487 | ||
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index cea4aa8b8..270291631 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h | |||
| @@ -315,18 +315,19 @@ public: | |||
| 315 | bool Rename(std::string_view name) override; | 315 | bool Rename(std::string_view name) override; |
| 316 | }; | 316 | }; |
| 317 | 317 | ||
| 318 | // Compare the two files, byte-for-byte, in increments specificed by block_size | 318 | // Compare the two files, byte-for-byte, in increments specified by block_size |
| 319 | bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, size_t block_size = 0x1000); | 319 | bool DeepEquals(const VirtualFile& file1, const VirtualFile& file2, |
| 320 | std::size_t block_size = 0x1000); | ||
| 320 | 321 | ||
| 321 | // A method that copies the raw data between two different implementations of VirtualFile. If you | 322 | // A method that copies the raw data between two different implementations of VirtualFile. If you |
| 322 | // are using the same implementation, it is probably better to use the Copy method in the parent | 323 | // are using the same implementation, it is probably better to use the Copy method in the parent |
| 323 | // directory of src/dest. | 324 | // directory of src/dest. |
| 324 | bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, size_t block_size = 0x1000); | 325 | bool VfsRawCopy(const VirtualFile& src, const VirtualFile& dest, std::size_t block_size = 0x1000); |
| 325 | 326 | ||
| 326 | // A method that performs a similar function to VfsRawCopy above, but instead copies entire | 327 | // A method that performs a similar function to VfsRawCopy above, but instead copies entire |
| 327 | // directories. It suffers the same performance penalties as above and an implementation-specific | 328 | // directories. It suffers the same performance penalties as above and an implementation-specific |
| 328 | // Copy should always be preferred. | 329 | // Copy should always be preferred. |
| 329 | bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, size_t block_size = 0x1000); | 330 | bool VfsRawCopyD(const VirtualDir& src, const VirtualDir& dest, std::size_t block_size = 0x1000); |
| 330 | 331 | ||
| 331 | // Checks if the directory at path relative to rel exists. If it does, returns that. If it does not | 332 | // Checks if the directory at path relative to rel exists. If it does, returns that. If it does not |
| 332 | // it attempts to create it and returns the new dir or nullptr on failure. | 333 | // it attempts to create it and returns the new dir or nullptr on failure. |
diff --git a/src/core/file_sys/vfs_concat.cpp b/src/core/file_sys/vfs_concat.cpp index d9f9911da..16d801c0c 100644 --- a/src/core/file_sys/vfs_concat.cpp +++ b/src/core/file_sys/vfs_concat.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | 7 | ||
| 8 | #include "common/assert.h" | 8 | #include "common/assert.h" |
| 9 | #include "core/file_sys/vfs_concat.h" | 9 | #include "core/file_sys/vfs_concat.h" |
| 10 | #include "core/file_sys/vfs_static.h" | ||
| 10 | 11 | ||
| 11 | namespace FileSys { | 12 | namespace FileSys { |
| 12 | 13 | ||
| @@ -22,15 +23,6 @@ static bool VerifyConcatenationMapContinuity(const std::map<u64, VirtualFile>& m | |||
| 22 | return map.begin()->first == 0; | 23 | return map.begin()->first == 0; |
| 23 | } | 24 | } |
| 24 | 25 | ||
| 25 | VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name) { | ||
| 26 | if (files.empty()) | ||
| 27 | return nullptr; | ||
| 28 | if (files.size() == 1) | ||
| 29 | return files[0]; | ||
| 30 | |||
| 31 | return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); | ||
| 32 | } | ||
| 33 | |||
| 34 | ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name) | 26 | ConcatenatedVfsFile::ConcatenatedVfsFile(std::vector<VirtualFile> files_, std::string name) |
| 35 | : name(std::move(name)) { | 27 | : name(std::move(name)) { |
| 36 | std::size_t next_offset = 0; | 28 | std::size_t next_offset = 0; |
| @@ -47,6 +39,41 @@ ConcatenatedVfsFile::ConcatenatedVfsFile(std::map<u64, VirtualFile> files_, std: | |||
| 47 | 39 | ||
| 48 | ConcatenatedVfsFile::~ConcatenatedVfsFile() = default; | 40 | ConcatenatedVfsFile::~ConcatenatedVfsFile() = default; |
| 49 | 41 | ||
| 42 | VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(std::vector<VirtualFile> files, | ||
| 43 | std::string name) { | ||
| 44 | if (files.empty()) | ||
| 45 | return nullptr; | ||
| 46 | if (files.size() == 1) | ||
| 47 | return files[0]; | ||
| 48 | |||
| 49 | return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); | ||
| 50 | } | ||
| 51 | |||
| 52 | VirtualFile ConcatenatedVfsFile::MakeConcatenatedFile(u8 filler_byte, | ||
| 53 | std::map<u64, VirtualFile> files, | ||
| 54 | std::string name) { | ||
| 55 | if (files.empty()) | ||
| 56 | return nullptr; | ||
| 57 | if (files.size() == 1) | ||
| 58 | return files.begin()->second; | ||
| 59 | |||
| 60 | const auto last_valid = --files.end(); | ||
| 61 | for (auto iter = files.begin(); iter != last_valid;) { | ||
| 62 | const auto old = iter++; | ||
| 63 | if (old->first + old->second->GetSize() != iter->first) { | ||
| 64 | files.emplace(old->first + old->second->GetSize(), | ||
| 65 | std::make_shared<StaticVfsFile>(filler_byte, iter->first - old->first - | ||
| 66 | old->second->GetSize())); | ||
| 67 | } | ||
| 68 | } | ||
| 69 | |||
| 70 | // Ensure the map starts at offset 0 (start of file), otherwise pad to fill. | ||
| 71 | if (files.begin()->first != 0) | ||
| 72 | files.emplace(0, std::make_shared<StaticVfsFile>(filler_byte, files.begin()->first)); | ||
| 73 | |||
| 74 | return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); | ||
| 75 | } | ||
| 76 | |||
| 50 | std::string ConcatenatedVfsFile::GetName() const { | 77 | std::string ConcatenatedVfsFile::GetName() const { |
| 51 | if (files.empty()) | 78 | if (files.empty()) |
| 52 | return ""; | 79 | return ""; |
diff --git a/src/core/file_sys/vfs_concat.h b/src/core/file_sys/vfs_concat.h index 76211d38a..c90f9d5d1 100644 --- a/src/core/file_sys/vfs_concat.h +++ b/src/core/file_sys/vfs_concat.h | |||
| @@ -7,26 +7,27 @@ | |||
| 7 | #include <map> | 7 | #include <map> |
| 8 | #include <memory> | 8 | #include <memory> |
| 9 | #include <string_view> | 9 | #include <string_view> |
| 10 | #include <boost/container/flat_map.hpp> | ||
| 11 | #include "core/file_sys/vfs.h" | 10 | #include "core/file_sys/vfs.h" |
| 12 | #include "core/file_sys/vfs_static.h" | ||
| 13 | 11 | ||
| 14 | namespace FileSys { | 12 | namespace FileSys { |
| 15 | 13 | ||
| 16 | // Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently | 14 | // Class that wraps multiple vfs files and concatenates them, making reads seamless. Currently |
| 17 | // read-only. | 15 | // read-only. |
| 18 | class ConcatenatedVfsFile : public VfsFile { | 16 | class ConcatenatedVfsFile : public VfsFile { |
| 19 | friend VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name); | ||
| 20 | |||
| 21 | template <u8 filler_byte> | ||
| 22 | friend VirtualFile ConcatenateFiles(std::map<u64, VirtualFile> files, std::string name); | ||
| 23 | |||
| 24 | ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name); | 17 | ConcatenatedVfsFile(std::vector<VirtualFile> files, std::string name); |
| 25 | ConcatenatedVfsFile(std::map<u64, VirtualFile> files, std::string name); | 18 | ConcatenatedVfsFile(std::map<u64, VirtualFile> files, std::string name); |
| 26 | 19 | ||
| 27 | public: | 20 | public: |
| 28 | ~ConcatenatedVfsFile() override; | 21 | ~ConcatenatedVfsFile() override; |
| 29 | 22 | ||
| 23 | /// Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases. | ||
| 24 | static VirtualFile MakeConcatenatedFile(std::vector<VirtualFile> files, std::string name); | ||
| 25 | |||
| 26 | /// Convenience function that turns a map of offsets to files into a concatenated file, filling | ||
| 27 | /// gaps with a given filler byte. | ||
| 28 | static VirtualFile MakeConcatenatedFile(u8 filler_byte, std::map<u64, VirtualFile> files, | ||
| 29 | std::string name); | ||
| 30 | |||
| 30 | std::string GetName() const override; | 31 | std::string GetName() const override; |
| 31 | std::size_t GetSize() const override; | 32 | std::size_t GetSize() const override; |
| 32 | bool Resize(std::size_t new_size) override; | 33 | bool Resize(std::size_t new_size) override; |
| @@ -43,33 +44,4 @@ private: | |||
| 43 | std::string name; | 44 | std::string name; |
| 44 | }; | 45 | }; |
| 45 | 46 | ||
| 46 | // Wrapper function to allow for more efficient handling of files.size() == 0, 1 cases. | ||
| 47 | VirtualFile ConcatenateFiles(std::vector<VirtualFile> files, std::string name); | ||
| 48 | |||
| 49 | // Convenience function that turns a map of offsets to files into a concatenated file, filling gaps | ||
| 50 | // with template parameter. | ||
| 51 | template <u8 filler_byte> | ||
| 52 | VirtualFile ConcatenateFiles(std::map<u64, VirtualFile> files, std::string name) { | ||
| 53 | if (files.empty()) | ||
| 54 | return nullptr; | ||
| 55 | if (files.size() == 1) | ||
| 56 | return files.begin()->second; | ||
| 57 | |||
| 58 | const auto last_valid = --files.end(); | ||
| 59 | for (auto iter = files.begin(); iter != last_valid;) { | ||
| 60 | const auto old = iter++; | ||
| 61 | if (old->first + old->second->GetSize() != iter->first) { | ||
| 62 | files.emplace(old->first + old->second->GetSize(), | ||
| 63 | std::make_shared<StaticVfsFile<filler_byte>>(iter->first - old->first - | ||
| 64 | old->second->GetSize())); | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 68 | // Ensure the map starts at offset 0 (start of file), otherwise pad to fill. | ||
| 69 | if (files.begin()->first != 0) | ||
| 70 | files.emplace(0, std::make_shared<StaticVfsFile<filler_byte>>(files.begin()->first)); | ||
| 71 | |||
| 72 | return std::shared_ptr<VfsFile>(new ConcatenatedVfsFile(std::move(files), std::move(name))); | ||
| 73 | } | ||
| 74 | |||
| 75 | } // namespace FileSys | 47 | } // namespace FileSys |
diff --git a/src/core/file_sys/vfs_layered.cpp b/src/core/file_sys/vfs_layered.cpp index 45563d7ae..bfee01725 100644 --- a/src/core/file_sys/vfs_layered.cpp +++ b/src/core/file_sys/vfs_layered.cpp | |||
| @@ -8,7 +8,13 @@ | |||
| 8 | 8 | ||
| 9 | namespace FileSys { | 9 | namespace FileSys { |
| 10 | 10 | ||
| 11 | VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name) { | 11 | LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name) |
| 12 | : dirs(std::move(dirs)), name(std::move(name)) {} | ||
| 13 | |||
| 14 | LayeredVfsDirectory::~LayeredVfsDirectory() = default; | ||
| 15 | |||
| 16 | VirtualDir LayeredVfsDirectory::MakeLayeredDirectory(std::vector<VirtualDir> dirs, | ||
| 17 | std::string name) { | ||
| 12 | if (dirs.empty()) | 18 | if (dirs.empty()) |
| 13 | return nullptr; | 19 | return nullptr; |
| 14 | if (dirs.size() == 1) | 20 | if (dirs.size() == 1) |
| @@ -17,11 +23,6 @@ VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name) { | |||
| 17 | return std::shared_ptr<VfsDirectory>(new LayeredVfsDirectory(std::move(dirs), std::move(name))); | 23 | return std::shared_ptr<VfsDirectory>(new LayeredVfsDirectory(std::move(dirs), std::move(name))); |
| 18 | } | 24 | } |
| 19 | 25 | ||
| 20 | LayeredVfsDirectory::LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name) | ||
| 21 | : dirs(std::move(dirs)), name(std::move(name)) {} | ||
| 22 | |||
| 23 | LayeredVfsDirectory::~LayeredVfsDirectory() = default; | ||
| 24 | |||
| 25 | std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFileRelative(std::string_view path) const { | 26 | std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFileRelative(std::string_view path) const { |
| 26 | for (const auto& layer : dirs) { | 27 | for (const auto& layer : dirs) { |
| 27 | const auto file = layer->GetFileRelative(path); | 28 | const auto file = layer->GetFileRelative(path); |
| @@ -41,7 +42,7 @@ std::shared_ptr<VfsDirectory> LayeredVfsDirectory::GetDirectoryRelative( | |||
| 41 | out.push_back(std::move(dir)); | 42 | out.push_back(std::move(dir)); |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | return LayerDirectories(std::move(out)); | 45 | return MakeLayeredDirectory(std::move(out)); |
| 45 | } | 46 | } |
| 46 | 47 | ||
| 47 | std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFile(std::string_view name) const { | 48 | std::shared_ptr<VfsFile> LayeredVfsDirectory::GetFile(std::string_view name) const { |
diff --git a/src/core/file_sys/vfs_layered.h b/src/core/file_sys/vfs_layered.h index 4f6e341ab..d85310f57 100644 --- a/src/core/file_sys/vfs_layered.h +++ b/src/core/file_sys/vfs_layered.h | |||
| @@ -9,20 +9,18 @@ | |||
| 9 | 9 | ||
| 10 | namespace FileSys { | 10 | namespace FileSys { |
| 11 | 11 | ||
| 12 | // Wrapper function to allow for more efficient handling of dirs.size() == 0, 1 cases. | ||
| 13 | VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name = ""); | ||
| 14 | |||
| 15 | // Class that stacks multiple VfsDirectories on top of each other, attempting to read from the first | 12 | // Class that stacks multiple VfsDirectories on top of each other, attempting to read from the first |
| 16 | // one and falling back to the one after. The highest priority directory (overwrites all others) | 13 | // one and falling back to the one after. The highest priority directory (overwrites all others) |
| 17 | // should be element 0 in the dirs vector. | 14 | // should be element 0 in the dirs vector. |
| 18 | class LayeredVfsDirectory : public VfsDirectory { | 15 | class LayeredVfsDirectory : public VfsDirectory { |
| 19 | friend VirtualDir LayerDirectories(std::vector<VirtualDir> dirs, std::string name); | ||
| 20 | |||
| 21 | LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name); | 16 | LayeredVfsDirectory(std::vector<VirtualDir> dirs, std::string name); |
| 22 | 17 | ||
| 23 | public: | 18 | public: |
| 24 | ~LayeredVfsDirectory() override; | 19 | ~LayeredVfsDirectory() override; |
| 25 | 20 | ||
| 21 | /// Wrapper function to allow for more efficient handling of dirs.size() == 0, 1 cases. | ||
| 22 | static VirtualDir MakeLayeredDirectory(std::vector<VirtualDir> dirs, std::string name = ""); | ||
| 23 | |||
| 26 | std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override; | 24 | std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override; |
| 27 | std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override; | 25 | std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override; |
| 28 | std::shared_ptr<VfsFile> GetFile(std::string_view name) const override; | 26 | std::shared_ptr<VfsFile> GetFile(std::string_view name) const override; |
diff --git a/src/core/file_sys/vfs_static.h b/src/core/file_sys/vfs_static.h index 4dd47ffcc..44fab51d1 100644 --- a/src/core/file_sys/vfs_static.h +++ b/src/core/file_sys/vfs_static.h | |||
| @@ -12,21 +12,21 @@ | |||
| 12 | 12 | ||
| 13 | namespace FileSys { | 13 | namespace FileSys { |
| 14 | 14 | ||
| 15 | template <u8 value> | ||
| 16 | class StaticVfsFile : public VfsFile { | 15 | class StaticVfsFile : public VfsFile { |
| 17 | public: | 16 | public: |
| 18 | explicit StaticVfsFile(size_t size = 0, std::string name = "", VirtualDir parent = nullptr) | 17 | explicit StaticVfsFile(u8 value, std::size_t size = 0, std::string name = "", |
| 19 | : size(size), name(std::move(name)), parent(std::move(parent)) {} | 18 | VirtualDir parent = nullptr) |
| 19 | : value{value}, size{size}, name{std::move(name)}, parent{std::move(parent)} {} | ||
| 20 | 20 | ||
| 21 | std::string GetName() const override { | 21 | std::string GetName() const override { |
| 22 | return name; | 22 | return name; |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | size_t GetSize() const override { | 25 | std::size_t GetSize() const override { |
| 26 | return size; | 26 | return size; |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | bool Resize(size_t new_size) override { | 29 | bool Resize(std::size_t new_size) override { |
| 30 | size = new_size; | 30 | size = new_size; |
| 31 | return true; | 31 | return true; |
| 32 | } | 32 | } |
| @@ -43,23 +43,23 @@ public: | |||
| 43 | return true; | 43 | return true; |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | size_t Read(u8* data, size_t length, size_t offset) const override { | 46 | std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override { |
| 47 | const auto read = std::min(length, size - offset); | 47 | const auto read = std::min(length, size - offset); |
| 48 | std::fill(data, data + read, value); | 48 | std::fill(data, data + read, value); |
| 49 | return read; | 49 | return read; |
| 50 | } | 50 | } |
| 51 | 51 | ||
| 52 | size_t Write(const u8* data, size_t length, size_t offset) override { | 52 | std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override { |
| 53 | return 0; | 53 | return 0; |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | boost::optional<u8> ReadByte(size_t offset) const override { | 56 | boost::optional<u8> ReadByte(std::size_t offset) const override { |
| 57 | if (offset < size) | 57 | if (offset < size) |
| 58 | return value; | 58 | return value; |
| 59 | return boost::none; | 59 | return boost::none; |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | std::vector<u8> ReadBytes(size_t length, size_t offset) const override { | 62 | std::vector<u8> ReadBytes(std::size_t length, std::size_t offset) const override { |
| 63 | const auto read = std::min(length, size - offset); | 63 | const auto read = std::min(length, size - offset); |
| 64 | return std::vector<u8>(read, value); | 64 | return std::vector<u8>(read, value); |
| 65 | } | 65 | } |
| @@ -70,7 +70,8 @@ public: | |||
| 70 | } | 70 | } |
| 71 | 71 | ||
| 72 | private: | 72 | private: |
| 73 | size_t size; | 73 | u8 value; |
| 74 | std::size_t size; | ||
| 74 | std::string name; | 75 | std::string name; |
| 75 | VirtualDir parent; | 76 | VirtualDir parent; |
| 76 | }; | 77 | }; |
diff --git a/src/core/file_sys/vfs_vector.cpp b/src/core/file_sys/vfs_vector.cpp index 7033e2c88..389c7e003 100644 --- a/src/core/file_sys/vfs_vector.cpp +++ b/src/core/file_sys/vfs_vector.cpp | |||
| @@ -9,7 +9,7 @@ | |||
| 9 | 9 | ||
| 10 | namespace FileSys { | 10 | namespace FileSys { |
| 11 | VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name, VirtualDir parent) | 11 | VectorVfsFile::VectorVfsFile(std::vector<u8> initial_data, std::string name, VirtualDir parent) |
| 12 | : data(std::move(initial_data)), name(std::move(name)), parent(std::move(parent)) {} | 12 | : data(std::move(initial_data)), parent(std::move(parent)), name(std::move(name)) {} |
| 13 | 13 | ||
| 14 | VectorVfsFile::~VectorVfsFile() = default; | 14 | VectorVfsFile::~VectorVfsFile() = default; |
| 15 | 15 | ||
| @@ -38,13 +38,13 @@ bool VectorVfsFile::IsReadable() const { | |||
| 38 | return true; | 38 | return true; |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | size_t VectorVfsFile::Read(u8* data_, size_t length, size_t offset) const { | 41 | std::size_t VectorVfsFile::Read(u8* data_, std::size_t length, std::size_t offset) const { |
| 42 | const auto read = std::min(length, data.size() - offset); | 42 | const auto read = std::min(length, data.size() - offset); |
| 43 | std::memcpy(data_, data.data() + offset, read); | 43 | std::memcpy(data_, data.data() + offset, read); |
| 44 | return read; | 44 | return read; |
| 45 | } | 45 | } |
| 46 | 46 | ||
| 47 | size_t VectorVfsFile::Write(const u8* data_, size_t length, size_t offset) { | 47 | std::size_t VectorVfsFile::Write(const u8* data_, std::size_t length, std::size_t offset) { |
| 48 | if (offset + length > data.size()) | 48 | if (offset + length > data.size()) |
| 49 | data.resize(offset + length); | 49 | data.resize(offset + length); |
| 50 | const auto write = std::min(length, data.size() - offset); | 50 | const auto write = std::min(length, data.size() - offset); |
diff --git a/src/core/file_sys/vfs_vector.h b/src/core/file_sys/vfs_vector.h index 115c3ae95..48a414c98 100644 --- a/src/core/file_sys/vfs_vector.h +++ b/src/core/file_sys/vfs_vector.h | |||
| @@ -16,13 +16,13 @@ public: | |||
| 16 | ~VectorVfsFile() override; | 16 | ~VectorVfsFile() override; |
| 17 | 17 | ||
| 18 | std::string GetName() const override; | 18 | std::string GetName() const override; |
| 19 | size_t GetSize() const override; | 19 | std::size_t GetSize() const override; |
| 20 | bool Resize(size_t new_size) override; | 20 | bool Resize(std::size_t new_size) override; |
| 21 | std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; | 21 | std::shared_ptr<VfsDirectory> GetContainingDirectory() const override; |
| 22 | bool IsWritable() const override; | 22 | bool IsWritable() const override; |
| 23 | bool IsReadable() const override; | 23 | bool IsReadable() const override; |
| 24 | size_t Read(u8* data, size_t length, size_t offset) const override; | 24 | std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override; |
| 25 | size_t Write(const u8* data, size_t length, size_t offset) override; | 25 | std::size_t Write(const u8* data, std::size_t length, std::size_t offset) override; |
| 26 | bool Rename(std::string_view name) override; | 26 | bool Rename(std::string_view name) override; |
| 27 | 27 | ||
| 28 | virtual void Assign(std::vector<u8> new_data); | 28 | virtual void Assign(std::vector<u8> new_data); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index dc8b5407d..d74489935 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -756,11 +756,51 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target | |||
| 756 | QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); | 756 | QDesktopServices::openUrl(QUrl::fromLocalFile(qpath)); |
| 757 | } | 757 | } |
| 758 | 758 | ||
| 759 | static std::size_t CalculateRomFSEntrySize(const FileSys::VirtualDir& dir, bool full) { | ||
| 760 | std::size_t out = 0; | ||
| 761 | |||
| 762 | for (const auto& subdir : dir->GetSubdirectories()) { | ||
| 763 | out += 1 + CalculateRomFSEntrySize(subdir, full); | ||
| 764 | } | ||
| 765 | |||
| 766 | return out + (full ? dir->GetFiles().size() : 0); | ||
| 767 | } | ||
| 768 | |||
| 769 | static bool RomFSRawCopy(QProgressDialog& dialog, const FileSys::VirtualDir& src, | ||
| 770 | const FileSys::VirtualDir& dest, std::size_t block_size, bool full) { | ||
| 771 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) | ||
| 772 | return false; | ||
| 773 | if (dialog.wasCanceled()) | ||
| 774 | return false; | ||
| 775 | |||
| 776 | if (full) { | ||
| 777 | for (const auto& file : src->GetFiles()) { | ||
| 778 | const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName()); | ||
| 779 | if (!FileSys::VfsRawCopy(file, out, block_size)) | ||
| 780 | return false; | ||
| 781 | dialog.setValue(dialog.value() + 1); | ||
| 782 | if (dialog.wasCanceled()) | ||
| 783 | return false; | ||
| 784 | } | ||
| 785 | } | ||
| 786 | |||
| 787 | for (const auto& dir : src->GetSubdirectories()) { | ||
| 788 | const auto out = dest->CreateSubdirectory(dir->GetName()); | ||
| 789 | if (!RomFSRawCopy(dialog, dir, out, block_size, full)) | ||
| 790 | return false; | ||
| 791 | dialog.setValue(dialog.value() + 1); | ||
| 792 | if (dialog.wasCanceled()) | ||
| 793 | return false; | ||
| 794 | } | ||
| 795 | |||
| 796 | return true; | ||
| 797 | } | ||
| 798 | |||
| 759 | void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) { | 799 | void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_path) { |
| 760 | const auto path = fmt::format("{}{:016X}/romfs", | 800 | const auto path = fmt::format("{}{:016X}/romfs", |
| 761 | FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), program_id); | 801 | FileUtil::GetUserPath(FileUtil::UserPath::DumpDir), program_id); |
| 762 | 802 | ||
| 763 | auto failed = [this, &path]() { | 803 | const auto failed = [this, &path] { |
| 764 | QMessageBox::warning(this, tr("RomFS Extraction Failed!"), | 804 | QMessageBox::warning(this, tr("RomFS Extraction Failed!"), |
| 765 | tr("There was an error copying the RomFS files or the user " | 805 | tr("There was an error copying the RomFS files or the user " |
| 766 | "cancelled the operation.")); | 806 | "cancelled the operation.")); |
| @@ -808,53 +848,13 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa | |||
| 808 | failed(); | 848 | failed(); |
| 809 | 849 | ||
| 810 | const auto full = res == "Full"; | 850 | const auto full = res == "Full"; |
| 811 | 851 | const auto entry_size = CalculateRomFSEntrySize(extracted, full); | |
| 812 | const static std::function<size_t(const FileSys::VirtualDir&, bool)> calculate_entry_size = | ||
| 813 | [](const FileSys::VirtualDir& dir, bool full) { | ||
| 814 | size_t out = 0; | ||
| 815 | for (const auto& subdir : dir->GetSubdirectories()) | ||
| 816 | out += 1 + calculate_entry_size(subdir, full); | ||
| 817 | return out + full ? dir->GetFiles().size() : 0; | ||
| 818 | }; | ||
| 819 | const auto entry_size = calculate_entry_size(extracted, full); | ||
| 820 | 852 | ||
| 821 | QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0, entry_size, this); | 853 | QProgressDialog progress(tr("Extracting RomFS..."), tr("Cancel"), 0, entry_size, this); |
| 822 | progress.setWindowModality(Qt::WindowModal); | 854 | progress.setWindowModality(Qt::WindowModal); |
| 823 | progress.setMinimumDuration(100); | 855 | progress.setMinimumDuration(100); |
| 824 | 856 | ||
| 825 | const static std::function<bool(QProgressDialog&, const FileSys::VirtualDir&, | 857 | if (RomFSRawCopy(progress, extracted, out, 0x400000, full)) { |
| 826 | const FileSys::VirtualDir&, size_t, bool)> | ||
| 827 | qt_raw_copy = [](QProgressDialog& dialog, const FileSys::VirtualDir& src, | ||
| 828 | const FileSys::VirtualDir& dest, size_t block_size, bool full) { | ||
| 829 | if (src == nullptr || dest == nullptr || !src->IsReadable() || !dest->IsWritable()) | ||
| 830 | return false; | ||
| 831 | if (dialog.wasCanceled()) | ||
| 832 | return false; | ||
| 833 | |||
| 834 | if (full) { | ||
| 835 | for (const auto& file : src->GetFiles()) { | ||
| 836 | const auto out = VfsDirectoryCreateFileWrapper(dest, file->GetName()); | ||
| 837 | if (!FileSys::VfsRawCopy(file, out, block_size)) | ||
| 838 | return false; | ||
| 839 | dialog.setValue(dialog.value() + 1); | ||
| 840 | if (dialog.wasCanceled()) | ||
| 841 | return false; | ||
| 842 | } | ||
| 843 | } | ||
| 844 | |||
| 845 | for (const auto& dir : src->GetSubdirectories()) { | ||
| 846 | const auto out = dest->CreateSubdirectory(dir->GetName()); | ||
| 847 | if (!qt_raw_copy(dialog, dir, out, block_size, full)) | ||
| 848 | return false; | ||
| 849 | dialog.setValue(dialog.value() + 1); | ||
| 850 | if (dialog.wasCanceled()) | ||
| 851 | return false; | ||
| 852 | } | ||
| 853 | |||
| 854 | return true; | ||
| 855 | }; | ||
| 856 | |||
| 857 | if (qt_raw_copy(progress, extracted, out, 0x400000, full)) { | ||
| 858 | progress.close(); | 858 | progress.close(); |
| 859 | QMessageBox::information(this, tr("RomFS Extraction Succeeded!"), | 859 | QMessageBox::information(this, tr("RomFS Extraction Succeeded!"), |
| 860 | tr("The operation completed successfully.")); | 860 | tr("The operation completed successfully.")); |
| @@ -931,7 +931,7 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 931 | } | 931 | } |
| 932 | 932 | ||
| 933 | const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, | 933 | const auto qt_raw_copy = [this](const FileSys::VirtualFile& src, |
| 934 | const FileSys::VirtualFile& dest, size_t block_size) { | 934 | const FileSys::VirtualFile& dest, std::size_t block_size) { |
| 935 | if (src == nullptr || dest == nullptr) | 935 | if (src == nullptr || dest == nullptr) |
| 936 | return false; | 936 | return false; |
| 937 | if (!dest->Resize(src->GetSize())) | 937 | if (!dest->Resize(src->GetSize())) |