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.cpp124
1 files changed, 124 insertions, 0 deletions
diff --git a/src/core/file_sys/romfs.cpp b/src/core/file_sys/romfs.cpp
new file mode 100644
index 000000000..ff3ddb29c
--- /dev/null
+++ b/src/core/file_sys/romfs.cpp
@@ -0,0 +1,124 @@
1// Copyright 2018 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/common_types.h"
6#include "common/swap.h"
7#include "core/file_sys/romfs.h"
8#include "core/file_sys/vfs.h"
9#include "core/file_sys/vfs_offset.h"
10#include "core/file_sys/vfs_vector.h"
11
12namespace FileSys {
13
14constexpr u32 ROMFS_ENTRY_EMPTY = 0xFFFFFFFF;
15
16struct TableLocation {
17 u64_le offset;
18 u64_le size;
19};
20static_assert(sizeof(TableLocation) == 0x10, "TableLocation has incorrect size.");
21
22struct RomFSHeader {
23 u64_le header_size;
24 TableLocation directory_hash;
25 TableLocation directory_meta;
26 TableLocation file_hash;
27 TableLocation file_meta;
28 u64_le data_offset;
29};
30static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size.");
31
32struct DirectoryEntry {
33 u32_le sibling;
34 u32_le child_dir;
35 u32_le child_file;
36 u32_le hash;
37 u32_le name_length;
38};
39static_assert(sizeof(DirectoryEntry) == 0x14, "DirectoryEntry has incorrect size.");
40
41struct FileEntry {
42 u32_le parent;
43 u32_le sibling;
44 u64_le offset;
45 u64_le size;
46 u32_le hash;
47 u32_le name_length;
48};
49static_assert(sizeof(FileEntry) == 0x20, "FileEntry has incorrect size.");
50
51template <typename Entry>
52static std::pair<Entry, std::string> GetEntry(const VirtualFile& file, size_t offset) {
53 Entry entry{};
54 if (file->ReadObject(&entry, offset) != sizeof(Entry))
55 return {};
56 std::string string(entry.name_length, '\0');
57 if (file->ReadArray(&string[0], string.size(), offset + sizeof(Entry)) != string.size())
58 return {};
59 return {entry, string};
60}
61
62void ProcessFile(VirtualFile file, size_t file_offset, size_t data_offset, u32 this_file_offset,
63 std::shared_ptr<VectorVfsDirectory> parent) {
64 while (true) {
65 auto entry = GetEntry<FileEntry>(file, file_offset + this_file_offset);
66
67 parent->AddFile(std::make_shared<OffsetVfsFile>(
68 file, entry.first.size, entry.first.offset + data_offset, entry.second, parent));
69
70 if (entry.first.sibling == ROMFS_ENTRY_EMPTY)
71 break;
72
73 this_file_offset = entry.first.sibling;
74 }
75}
76
77void ProcessDirectory(VirtualFile file, size_t dir_offset, size_t file_offset, size_t data_offset,
78 u32 this_dir_offset, std::shared_ptr<VectorVfsDirectory> parent) {
79 while (true) {
80 auto entry = GetEntry<DirectoryEntry>(file, dir_offset + this_dir_offset);
81 auto current = std::make_shared<VectorVfsDirectory>(
82 std::vector<VirtualFile>{}, std::vector<VirtualDir>{}, parent, entry.second);
83
84 if (entry.first.child_file != ROMFS_ENTRY_EMPTY) {
85 ProcessFile(file, file_offset, data_offset, entry.first.child_file, current);
86 }
87
88 if (entry.first.child_dir != ROMFS_ENTRY_EMPTY) {
89 ProcessDirectory(file, dir_offset, file_offset, data_offset, entry.first.child_dir,
90 current);
91 }
92
93 parent->AddDirectory(current);
94 if (entry.first.sibling == ROMFS_ENTRY_EMPTY)
95 break;
96 this_dir_offset = entry.first.sibling;
97 }
98}
99
100VirtualDir ExtractRomFS(VirtualFile file) {
101 RomFSHeader header{};
102 if (file->ReadObject(&header) != sizeof(RomFSHeader))
103 return nullptr;
104
105 if (header.header_size != sizeof(RomFSHeader))
106 return nullptr;
107
108 const u64 file_offset = header.file_meta.offset;
109 const u64 dir_offset = header.directory_meta.offset + 4;
110
111 const auto root =
112 std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{}, std::vector<VirtualDir>{},
113 file->GetContainingDirectory(), file->GetName());
114
115 ProcessDirectory(file, dir_offset, file_offset, header.data_offset, 0, root);
116
117 VirtualDir out = std::move(root);
118
119 while (out->GetSubdirectory("") != nullptr)
120 out = out->GetSubdirectory("");
121
122 return out;
123}
124} // namespace FileSys