summaryrefslogtreecommitdiff
path: root/src/core/file_sys/romfs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/file_sys/romfs.cpp')
-rw-r--r--src/core/file_sys/romfs.cpp83
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};
56static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size."); 56static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size.");
57 57
58template <typename Entry> 58struct RomFSTraversalContext {
59std::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
65template <typename EntryType, auto Member>
66std::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
84std::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
89std::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
69void ProcessFile(const VirtualFile& file, std::size_t file_offset, std::size_t data_offset, 94void 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
81void ProcessDirectory(const VirtualFile& file, std::size_t dir_offset, std::size_t file_offset, 107void 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);