Просмотр исходного кода

romfs: cache file and directory metadata tables

Liam 2 лет назад
Родитель
Сommit
4bc932261b
1 измененных файлов с 55 добавлено и 28 удалено
  1. 55 28
      src/core/file_sys/romfs.cpp

+ 55 - 28
src/core/file_sys/romfs.cpp

@@ -55,44 +55,68 @@ struct FileEntry {
 };
 };
 static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size.");
 static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size.");
 
 
-template <typename Entry>
-std::pair<Entry, std::string> GetEntry(const VirtualFile& file, std::size_t offset) {
-    Entry entry{};
-    if (file->ReadObject(&entry, offset) != sizeof(Entry))
-        return {};
-    std::string string(entry.name_length, '\0');
-    if (file->ReadArray(&string[0], string.size(), offset + sizeof(Entry)) != string.size())
+struct RomFSTraversalContext {
+    RomFSHeader header;
+    VirtualFile file;
+    std::vector<u8> directory_meta;
+    std::vector<u8> file_meta;
+};
+
+template <typename EntryType, auto Member>
+std::pair<EntryType, std::string> GetEntry(const RomFSTraversalContext& ctx, size_t offset) {
+    const size_t entry_end = offset + sizeof(EntryType);
+    const std::vector<u8>& vec = ctx.*Member;
+    const size_t size = vec.size();
+    const u8* data = vec.data();
+    EntryType entry{};
+
+    if (entry_end > size) {
         return {};
         return {};
-    return {entry, string};
+    }
+    std::memcpy(&entry, data + offset, sizeof(EntryType));
+
+    const size_t name_length = std::min(entry_end + entry.name_length, size) - entry_end;
+    std::string name(reinterpret_cast<const char*>(data + entry_end), name_length);
+
+    return {entry, std::move(name)};
+}
+
+std::pair<DirectoryEntry, std::string> GetDirectoryEntry(const RomFSTraversalContext& ctx,
+                                                         size_t directory_offset) {
+    return GetEntry<DirectoryEntry, &RomFSTraversalContext::directory_meta>(ctx, directory_offset);
+}
+
+std::pair<FileEntry, std::string> GetFileEntry(const RomFSTraversalContext& ctx,
+                                               size_t file_offset) {
+    return GetEntry<FileEntry, &RomFSTraversalContext::file_meta>(ctx, file_offset);
 }
 }
 
 
-void ProcessFile(const VirtualFile& file, std::size_t file_offset, std::size_t data_offset,
-                 u32 this_file_offset, std::shared_ptr<VectorVfsDirectory>& parent) {
+void ProcessFile(const RomFSTraversalContext& ctx, u32 this_file_offset,
+                 std::shared_ptr<VectorVfsDirectory>& parent) {
     while (this_file_offset != ROMFS_ENTRY_EMPTY) {
     while (this_file_offset != ROMFS_ENTRY_EMPTY) {
-        auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset);
+        auto entry = GetFileEntry(ctx, this_file_offset);
 
 
-        parent->AddFile(std::make_shared<OffsetVfsFile>(
-            file, entry.first.size, entry.first.offset + data_offset, entry.second));
+        parent->AddFile(std::make_shared<OffsetVfsFile>(ctx.file, entry.first.size,
+                                                        entry.first.offset + ctx.header.data_offset,
+                                                        std::move(entry.second)));
 
 
         this_file_offset = entry.first.sibling;
         this_file_offset = entry.first.sibling;
     }
     }
 }
 }
 
 
-void ProcessDirectory(const VirtualFile& file, std::size_t dir_offset, std::size_t file_offset,
-                      std::size_t data_offset, u32 this_dir_offset,
+void ProcessDirectory(const RomFSTraversalContext& ctx, u32 this_dir_offset,
                       std::shared_ptr<VectorVfsDirectory>& parent) {
                       std::shared_ptr<VectorVfsDirectory>& parent) {
     while (this_dir_offset != ROMFS_ENTRY_EMPTY) {
     while (this_dir_offset != ROMFS_ENTRY_EMPTY) {
-        auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset);
+        auto entry = GetDirectoryEntry(ctx, this_dir_offset);
         auto current = std::make_shared<VectorVfsDirectory>(
         auto current = std::make_shared<VectorVfsDirectory>(
             std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, entry.second);
             std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, entry.second);
 
 
         if (entry.first.child_file != ROMFS_ENTRY_EMPTY) {
         if (entry.first.child_file != ROMFS_ENTRY_EMPTY) {
-            ProcessFile(file, file_offset, data_offset, entry.first.child_file, current);
+            ProcessFile(ctx, entry.first.child_file, current);
         }
         }
 
 
         if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) {
         if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) {
-            ProcessDirectory(file, dir_offset, file_offset, data_offset, entry.first.child_dir,
-                             current);
+            ProcessDirectory(ctx, entry.first.child_dir, current);
         }
         }
 
 
         parent->AddDirectory(current);
         parent->AddDirectory(current);
@@ -107,22 +131,25 @@ VirtualDir ExtractRomFS(VirtualFile file) {
         return root_container;
         return root_container;
     }
     }
 
 
-    RomFSHeader header{};
-    if (file->ReadObject(&header) != sizeof(RomFSHeader)) {
-        return root_container;
+    RomFSTraversalContext ctx{};
+
+    if (file->ReadObject(&ctx.header) != sizeof(RomFSHeader)) {
+        return nullptr;
     }
     }
 
 
-    if (header.header_size != sizeof(RomFSHeader)) {
-        return root_container;
+    if (ctx.header.header_size != sizeof(RomFSHeader)) {
+        return nullptr;
     }
     }
 
 
-    const u64 file_offset = header.file_meta.offset;
-    const u64 dir_offset = header.directory_meta.offset;
+    ctx.file = file;
+    ctx.directory_meta =
+        file->ReadBytes(ctx.header.directory_meta.size, ctx.header.directory_meta.offset);
+    ctx.file_meta = file->ReadBytes(ctx.header.file_meta.size, ctx.header.file_meta.offset);
 
 
-    ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root_container);
+    ProcessDirectory(ctx, 0, root_container);
 
 
     if (auto root = root_container->GetSubdirectory(""); root) {
     if (auto root = root_container->GetSubdirectory(""); root) {
-        return std::make_shared<CachedVfsDirectory>(std::move(root));
+        return root;
     }
     }
 
 
     ASSERT(false);
     ASSERT(false);