diff options
| author | 2023-10-31 20:11:14 -0400 | |
|---|---|---|
| committer | 2023-10-31 23:26:51 -0400 | |
| commit | b0c6bf497a1eabec14c116b710dcc757e77455bf (patch) | |
| tree | 5d682ed36f0d2e310834096886a4562fd84ce3a0 /src | |
| parent | Merge pull request #11922 from t895/simplify-card-layout (diff) | |
| download | yuzu-b0c6bf497a1eabec14c116b710dcc757e77455bf.tar.gz yuzu-b0c6bf497a1eabec14c116b710dcc757e77455bf.tar.xz yuzu-b0c6bf497a1eabec14c116b710dcc757e77455bf.zip | |
romfs: fix extraction of single-directory root
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/file_sys/romfs.cpp | 44 | ||||
| -rw-r--r-- | src/core/file_sys/romfs.h | 9 | ||||
| -rw-r--r-- | src/core/hle/service/am/applets/applet_web_browser.cpp | 3 | ||||
| -rw-r--r-- | src/yuzu/main.cpp | 2 |
4 files changed, 18 insertions, 40 deletions
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp index 1c580de57..1eb1f439a 100644 --- a/src/core/file_sys/romfs.cpp +++ b/src/core/file_sys/romfs.cpp | |||
| @@ -35,13 +35,14 @@ struct RomFSHeader { | |||
| 35 | static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size."); | 35 | static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size."); |
| 36 | 36 | ||
| 37 | struct DirectoryEntry { | 37 | struct DirectoryEntry { |
| 38 | u32_le parent; | ||
| 38 | u32_le sibling; | 39 | u32_le sibling; |
| 39 | u32_le child_dir; | 40 | u32_le child_dir; |
| 40 | u32_le child_file; | 41 | u32_le child_file; |
| 41 | u32_le hash; | 42 | u32_le hash; |
| 42 | u32_le name_length; | 43 | u32_le name_length; |
| 43 | }; | 44 | }; |
| 44 | static_assert(sizeof(DirectoryEntry) == 0x14, "DirectoryEntry has incorrect size."); | 45 | static_assert(sizeof(DirectoryEntry) == 0x18, "DirectoryEntry has incorrect size."); |
| 45 | 46 | ||
| 46 | struct FileEntry { | 47 | struct FileEntry { |
| 47 | u32_le parent; | 48 | u32_le parent; |
| @@ -64,25 +65,22 @@ std::pair<Entry, std::string> GetEntry(const VirtualFile& file, std::size_t offs | |||
| 64 | return {entry, string}; | 65 | return {entry, string}; |
| 65 | } | 66 | } |
| 66 | 67 | ||
| 67 | void ProcessFile(VirtualFile file, std::size_t file_offset, std::size_t data_offset, | 68 | void ProcessFile(const VirtualFile& file, std::size_t file_offset, std::size_t data_offset, |
| 68 | u32 this_file_offset, std::shared_ptr<VectorVfsDirectory> parent) { | 69 | u32 this_file_offset, std::shared_ptr<VectorVfsDirectory>& parent) { |
| 69 | while (true) { | 70 | while (this_file_offset != ROMFS_ENTRY_EMPTY) { |
| 70 | auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset); | 71 | auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset); |
| 71 | 72 | ||
| 72 | parent->AddFile(std::make_shared<OffsetVfsFile>( | 73 | parent->AddFile(std::make_shared<OffsetVfsFile>( |
| 73 | file, entry.first.size, entry.first.offset + data_offset, entry.second)); | 74 | file, entry.first.size, entry.first.offset + data_offset, entry.second)); |
| 74 | 75 | ||
| 75 | if (entry.first.sibling == ROMFS_ENTRY_EMPTY) | ||
| 76 | break; | ||
| 77 | |||
| 78 | this_file_offset = entry.first.sibling; | 76 | this_file_offset = entry.first.sibling; |
| 79 | } | 77 | } |
| 80 | } | 78 | } |
| 81 | 79 | ||
| 82 | void ProcessDirectory(VirtualFile file, std::size_t dir_offset, std::size_t file_offset, | 80 | void ProcessDirectory(const VirtualFile& file, std::size_t dir_offset, std::size_t file_offset, |
| 83 | std::size_t data_offset, u32 this_dir_offset, | 81 | std::size_t data_offset, u32 this_dir_offset, |
| 84 | std::shared_ptr<VectorVfsDirectory> parent) { | 82 | std::shared_ptr<VectorVfsDirectory>& parent) { |
| 85 | while (true) { | 83 | while (this_dir_offset != ROMFS_ENTRY_EMPTY) { |
| 86 | auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset); | 84 | auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset); |
| 87 | auto current = std::make_shared<VectorVfsDirectory>( | 85 | auto current = std::make_shared<VectorVfsDirectory>( |
| 88 | std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, entry.second); | 86 | std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, entry.second); |
| @@ -97,14 +95,12 @@ void ProcessDirectory(VirtualFile file, std::size_t dir_offset, std::size_t file | |||
| 97 | } | 95 | } |
| 98 | 96 | ||
| 99 | parent->AddDirectory(current); | 97 | parent->AddDirectory(current); |
| 100 | if (entry.first.sibling == ROMFS_ENTRY_EMPTY) | ||
| 101 | break; | ||
| 102 | this_dir_offset = entry.first.sibling; | 98 | this_dir_offset = entry.first.sibling; |
| 103 | } | 99 | } |
| 104 | } | 100 | } |
| 105 | } // Anonymous namespace | 101 | } // Anonymous namespace |
| 106 | 102 | ||
| 107 | VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) { | 103 | VirtualDir ExtractRomFS(VirtualFile file) { |
| 108 | RomFSHeader header{}; | 104 | RomFSHeader header{}; |
| 109 | if (file->ReadObject(&header) != sizeof(RomFSHeader)) | 105 | if (file->ReadObject(&header) != sizeof(RomFSHeader)) |
| 110 | return nullptr; | 106 | return nullptr; |
| @@ -113,27 +109,17 @@ VirtualDir ExtractRomFS(VirtualFile file, RomFSExtractionType type) { | |||
| 113 | return nullptr; | 109 | return nullptr; |
| 114 | 110 | ||
| 115 | const u64 file_offset = header.file_meta.offset; | 111 | const u64 file_offset = header.file_meta.offset; |
| 116 | const u64 dir_offset = header.directory_meta.offset + 4; | 112 | const u64 dir_offset = header.directory_meta.offset; |
| 117 | |||
| 118 | auto root = | ||
| 119 | std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, | ||
| 120 | file->GetName(), file->GetContainingDirectory()); | ||
| 121 | |||
| 122 | ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root); | ||
| 123 | 113 | ||
| 124 | VirtualDir out = std::move(root); | 114 | auto root_container = std::make_shared<VectorVfsDirectory>(); |
| 125 | 115 | ||
| 126 | if (type == RomFSExtractionType::SingleDiscard) | 116 | ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root_container); |
| 127 | return out->GetSubdirectories().front(); | ||
| 128 | 117 | ||
| 129 | while (out->GetSubdirectories().size() == 1 && out->GetFiles().empty()) { | 118 | if (auto root = root_container->GetSubdirectory(""); root) { |
| 130 | if (Common::ToLower(out->GetSubdirectories().front()->GetName()) == "data" && | 119 | return std::make_shared<CachedVfsDirectory>(std::move(root)); |
| 131 | type == RomFSExtractionType::Truncated) | ||
| 132 | break; | ||
| 133 | out = out->GetSubdirectories().front(); | ||
| 134 | } | 120 | } |
| 135 | 121 | ||
| 136 | return std::make_shared<CachedVfsDirectory>(std::move(out)); | 122 | return nullptr; |
| 137 | } | 123 | } |
| 138 | 124 | ||
| 139 | VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) { | 125 | VirtualFile CreateRomFS(VirtualDir dir, VirtualDir ext) { |
diff --git a/src/core/file_sys/romfs.h b/src/core/file_sys/romfs.h index 5d7f0c2a8..b75ff1aad 100644 --- a/src/core/file_sys/romfs.h +++ b/src/core/file_sys/romfs.h | |||
| @@ -7,16 +7,9 @@ | |||
| 7 | 7 | ||
| 8 | namespace FileSys { | 8 | namespace FileSys { |
| 9 | 9 | ||
| 10 | enum class RomFSExtractionType { | ||
| 11 | Full, // Includes data directory | ||
| 12 | Truncated, // Traverses into data directory | ||
| 13 | SingleDiscard, // Traverses into the first subdirectory of root | ||
| 14 | }; | ||
| 15 | |||
| 16 | // Converts a RomFS binary blob to VFS Filesystem | 10 | // Converts a RomFS binary blob to VFS Filesystem |
| 17 | // Returns nullptr on failure | 11 | // Returns nullptr on failure |
| 18 | VirtualDir ExtractRomFS(VirtualFile file, | 12 | VirtualDir ExtractRomFS(VirtualFile file); |
| 19 | RomFSExtractionType type = RomFSExtractionType::Truncated); | ||
| 20 | 13 | ||
| 21 | // Converts a VFS filesystem into a RomFS binary | 14 | // Converts a VFS filesystem into a RomFS binary |
| 22 | // Returns nullptr on failure | 15 | // Returns nullptr on failure |
diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp index 1c9a1dc29..b0ea2b381 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.cpp +++ b/src/core/hle/service/am/applets/applet_web_browser.cpp | |||
| @@ -330,8 +330,7 @@ void WebBrowser::ExtractOfflineRomFS() { | |||
| 330 | LOG_DEBUG(Service_AM, "Extracting RomFS to {}", | 330 | LOG_DEBUG(Service_AM, "Extracting RomFS to {}", |
| 331 | Common::FS::PathToUTF8String(offline_cache_dir)); | 331 | Common::FS::PathToUTF8String(offline_cache_dir)); |
| 332 | 332 | ||
| 333 | const auto extracted_romfs_dir = | 333 | const auto extracted_romfs_dir = FileSys::ExtractRomFS(offline_romfs); |
| 334 | FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard); | ||
| 335 | 334 | ||
| 336 | const auto temp_dir = system.GetFilesystem()->CreateDirectory( | 335 | const auto temp_dir = system.GetFilesystem()->CreateDirectory( |
| 337 | Common::FS::PathToUTF8String(offline_cache_dir), FileSys::Mode::ReadWrite); | 336 | Common::FS::PathToUTF8String(offline_cache_dir), FileSys::Mode::ReadWrite); |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 0df163029..db9da6dc8 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -2737,7 +2737,7 @@ void GMainWindow::OnGameListDumpRomFS(u64 program_id, const std::string& game_pa | |||
| 2737 | return; | 2737 | return; |
| 2738 | } | 2738 | } |
| 2739 | 2739 | ||
| 2740 | const auto extracted = FileSys::ExtractRomFS(romfs, FileSys::RomFSExtractionType::Full); | 2740 | const auto extracted = FileSys::ExtractRomFS(romfs); |
| 2741 | if (extracted == nullptr) { | 2741 | if (extracted == nullptr) { |
| 2742 | failed(); | 2742 | failed(); |
| 2743 | return; | 2743 | return; |