diff options
Diffstat (limited to 'src/core/file_sys/romfs.cpp')
| -rw-r--r-- | src/core/file_sys/romfs.cpp | 83 |
1 files changed, 55 insertions, 28 deletions
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); |