diff options
Diffstat (limited to '')
| -rw-r--r-- | src/core/file_sys/fsmitm_romfsbuild.cpp | 368 | ||||
| -rw-r--r-- | src/core/file_sys/fsmitm_romfsbuild.hpp | 106 |
2 files changed, 474 insertions, 0 deletions
diff --git a/src/core/file_sys/fsmitm_romfsbuild.cpp b/src/core/file_sys/fsmitm_romfsbuild.cpp new file mode 100644 index 000000000..a6fe6719d --- /dev/null +++ b/src/core/file_sys/fsmitm_romfsbuild.cpp | |||
| @@ -0,0 +1,368 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2018 Atmosphère-NX | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* | ||
| 18 | * Adapted by DarkLordZach for use/interaction with yuzu | ||
| 19 | * | ||
| 20 | * Modifications Copyright 2018 yuzu emulator team | ||
| 21 | * Licensed under GPLv2 or any later version | ||
| 22 | * Refer to the license.txt file included. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #include <cstring> | ||
| 26 | #include "common/assert.h" | ||
| 27 | #include "fsmitm_romfsbuild.hpp" | ||
| 28 | #include "vfs.h" | ||
| 29 | #include "vfs_vector.h" | ||
| 30 | |||
| 31 | namespace FileSys { | ||
| 32 | |||
| 33 | constexpr u64 FS_MAX_PATH = 0x301; | ||
| 34 | |||
| 35 | constexpr u32 ROMFS_ENTRY_EMPTY = 0xFFFFFFFF; | ||
| 36 | constexpr u32 ROMFS_FILEPARTITION_OFS = 0x200; | ||
| 37 | |||
| 38 | /* Types for building a RomFS. */ | ||
| 39 | struct RomFSHeader { | ||
| 40 | u64 header_size; | ||
| 41 | u64 dir_hash_table_ofs; | ||
| 42 | u64 dir_hash_table_size; | ||
| 43 | u64 dir_table_ofs; | ||
| 44 | u64 dir_table_size; | ||
| 45 | u64 file_hash_table_ofs; | ||
| 46 | u64 file_hash_table_size; | ||
| 47 | u64 file_table_ofs; | ||
| 48 | u64 file_table_size; | ||
| 49 | u64 file_partition_ofs; | ||
| 50 | }; | ||
| 51 | static_assert(sizeof(RomFSHeader) == 0x50, "RomFSHeader has incorrect size."); | ||
| 52 | |||
| 53 | struct RomFSDirectoryEntry { | ||
| 54 | u32 parent; | ||
| 55 | u32 sibling; | ||
| 56 | u32 child; | ||
| 57 | u32 file; | ||
| 58 | u32 hash; | ||
| 59 | u32 name_size; | ||
| 60 | char name[]; | ||
| 61 | }; | ||
| 62 | static_assert(sizeof(RomFSDirectoryEntry) == 0x18, "RomFSDirectoryEntry has incorrect size."); | ||
| 63 | |||
| 64 | struct RomFSFileEntry { | ||
| 65 | u32 parent; | ||
| 66 | u32 sibling; | ||
| 67 | u64 offset; | ||
| 68 | u64 size; | ||
| 69 | u32 hash; | ||
| 70 | u32 name_size; | ||
| 71 | char name[]; | ||
| 72 | }; | ||
| 73 | static_assert(sizeof(RomFSFileEntry) == 0x20, "RomFSFileEntry has incorrect size."); | ||
| 74 | |||
| 75 | struct RomFSBuildFileContext; | ||
| 76 | |||
| 77 | struct RomFSBuildDirectoryContext { | ||
| 78 | char* path; | ||
| 79 | u32 cur_path_ofs; | ||
| 80 | u32 path_len; | ||
| 81 | u32 entry_offset = 0; | ||
| 82 | RomFSBuildDirectoryContext* parent = nullptr; | ||
| 83 | RomFSBuildDirectoryContext* child = nullptr; | ||
| 84 | RomFSBuildDirectoryContext* sibling = nullptr; | ||
| 85 | RomFSBuildFileContext* file = nullptr; | ||
| 86 | }; | ||
| 87 | |||
| 88 | struct RomFSBuildFileContext { | ||
| 89 | char* path; | ||
| 90 | u32 cur_path_ofs; | ||
| 91 | u32 path_len; | ||
| 92 | u32 entry_offset = 0; | ||
| 93 | u64 offset = 0; | ||
| 94 | u64 size = 0; | ||
| 95 | RomFSBuildDirectoryContext* parent = nullptr; | ||
| 96 | RomFSBuildFileContext* sibling = nullptr; | ||
| 97 | VirtualFile source = nullptr; | ||
| 98 | }; | ||
| 99 | |||
| 100 | void RomFSBuildContext::VisitDirectory(VirtualDir root_romfs, RomFSBuildDirectoryContext* parent) { | ||
| 101 | std::vector<RomFSBuildDirectoryContext*> child_dirs; | ||
| 102 | |||
| 103 | VirtualDir dir; | ||
| 104 | |||
| 105 | if (parent->path_len == 0) | ||
| 106 | dir = root_romfs; | ||
| 107 | else | ||
| 108 | dir = root_romfs->GetDirectoryRelative(parent->path); | ||
| 109 | |||
| 110 | const auto entries = dir->GetEntries(); | ||
| 111 | |||
| 112 | for (const auto& kv : entries) { | ||
| 113 | if (kv.second == VfsEntryType::Directory) { | ||
| 114 | RomFSBuildDirectoryContext* child = new RomFSBuildDirectoryContext({0}); | ||
| 115 | /* Set child's path. */ | ||
| 116 | child->cur_path_ofs = parent->path_len + 1; | ||
| 117 | child->path_len = child->cur_path_ofs + kv.first.size(); | ||
| 118 | child->path = new char[child->path_len + 1]; | ||
| 119 | strcpy(child->path, parent->path); | ||
| 120 | ASSERT(child->path_len < FS_MAX_PATH); | ||
| 121 | strcat(child->path + parent->path_len, "/"); | ||
| 122 | strcat(child->path + parent->path_len, kv.first.c_str()); | ||
| 123 | |||
| 124 | if (!this->AddDirectory(parent, child, nullptr)) { | ||
| 125 | delete child->path; | ||
| 126 | delete child; | ||
| 127 | } else { | ||
| 128 | child_dirs.push_back(child); | ||
| 129 | } | ||
| 130 | } else { | ||
| 131 | RomFSBuildFileContext* child = new RomFSBuildFileContext({0}); | ||
| 132 | /* Set child's path. */ | ||
| 133 | child->cur_path_ofs = parent->path_len + 1; | ||
| 134 | child->path_len = child->cur_path_ofs + kv.first.size(); | ||
| 135 | child->path = new char[child->path_len + 1]; | ||
| 136 | strcpy(child->path, parent->path); | ||
| 137 | ASSERT(child->path_len < FS_MAX_PATH); | ||
| 138 | strcat(child->path + parent->path_len, "/"); | ||
| 139 | strcat(child->path + parent->path_len, kv.first.c_str()); | ||
| 140 | |||
| 141 | child->source = root_romfs->GetFileRelative(child->path); | ||
| 142 | |||
| 143 | child->size = child->source->GetSize(); | ||
| 144 | |||
| 145 | if (!this->AddFile(parent, child)) { | ||
| 146 | delete child->path; | ||
| 147 | delete child; | ||
| 148 | } | ||
| 149 | } | ||
| 150 | } | ||
| 151 | |||
| 152 | for (auto& child : child_dirs) { | ||
| 153 | this->VisitDirectory(root_romfs, child); | ||
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 | bool RomFSBuildContext::AddDirectory(RomFSBuildDirectoryContext* parent_dir_ctx, | ||
| 158 | RomFSBuildDirectoryContext* dir_ctx, | ||
| 159 | RomFSBuildDirectoryContext** out_dir_ctx) { | ||
| 160 | /* Check whether it's already in the known directories. */ | ||
| 161 | auto existing = this->directories.find(dir_ctx->path); | ||
| 162 | if (existing != this->directories.end()) { | ||
| 163 | if (out_dir_ctx) { | ||
| 164 | *out_dir_ctx = existing->second; | ||
| 165 | } | ||
| 166 | return false; | ||
| 167 | } | ||
| 168 | |||
| 169 | /* Add a new directory. */ | ||
| 170 | this->num_dirs++; | ||
| 171 | this->dir_table_size += | ||
| 172 | sizeof(RomFSDirectoryEntry) + ((dir_ctx->path_len - dir_ctx->cur_path_ofs + 3) & ~3); | ||
| 173 | dir_ctx->parent = parent_dir_ctx; | ||
| 174 | this->directories.insert({dir_ctx->path, dir_ctx}); | ||
| 175 | |||
| 176 | if (out_dir_ctx) { | ||
| 177 | *out_dir_ctx = dir_ctx; | ||
| 178 | } | ||
| 179 | return true; | ||
| 180 | } | ||
| 181 | |||
| 182 | bool RomFSBuildContext::AddFile(RomFSBuildDirectoryContext* parent_dir_ctx, | ||
| 183 | RomFSBuildFileContext* file_ctx) { | ||
| 184 | /* Check whether it's already in the known files. */ | ||
| 185 | auto existing = this->files.find(file_ctx->path); | ||
| 186 | if (existing != this->files.end()) { | ||
| 187 | return false; | ||
| 188 | } | ||
| 189 | |||
| 190 | /* Add a new file. */ | ||
| 191 | this->num_files++; | ||
| 192 | this->file_table_size += | ||
| 193 | sizeof(RomFSFileEntry) + ((file_ctx->path_len - file_ctx->cur_path_ofs + 3) & ~3); | ||
| 194 | file_ctx->parent = parent_dir_ctx; | ||
| 195 | this->files.insert({file_ctx->path, file_ctx}); | ||
| 196 | |||
| 197 | return true; | ||
| 198 | } | ||
| 199 | |||
| 200 | RomFSBuildContext::RomFSBuildContext(VirtualDir base_) : base(std::move(base_)) { | ||
| 201 | this->root = new RomFSBuildDirectoryContext({0}); | ||
| 202 | this->root->path = new char[1]; | ||
| 203 | this->root->path[0] = '\x00'; | ||
| 204 | this->directories.insert({this->root->path, this->root}); | ||
| 205 | this->num_dirs = 1; | ||
| 206 | this->dir_table_size = 0x18; | ||
| 207 | |||
| 208 | VisitDirectory(base, this->root); | ||
| 209 | } | ||
| 210 | |||
| 211 | std::map<u64, VirtualFile> RomFSBuildContext::Build() { | ||
| 212 | std::map<u64, VirtualFile> out; | ||
| 213 | RomFSBuildFileContext* cur_file; | ||
| 214 | RomFSBuildDirectoryContext* cur_dir; | ||
| 215 | |||
| 216 | const auto dir_hash_table_entry_count = romfs_get_hash_table_count(this->num_dirs); | ||
| 217 | const auto file_hash_table_entry_count = romfs_get_hash_table_count(this->num_files); | ||
| 218 | this->dir_hash_table_size = 4 * dir_hash_table_entry_count; | ||
| 219 | this->file_hash_table_size = 4 * file_hash_table_entry_count; | ||
| 220 | |||
| 221 | /* Assign metadata pointers */ | ||
| 222 | RomFSHeader* header = new RomFSHeader({0}); | ||
| 223 | auto metadata = new u8[this->dir_hash_table_size + this->dir_table_size + | ||
| 224 | this->file_hash_table_size + this->file_table_size]; | ||
| 225 | auto dir_hash_table = reinterpret_cast<u32*>(metadata); | ||
| 226 | const auto dir_table = reinterpret_cast<RomFSDirectoryEntry*>( | ||
| 227 | reinterpret_cast<uintptr_t>(dir_hash_table) + this->dir_hash_table_size); | ||
| 228 | auto file_hash_table = | ||
| 229 | reinterpret_cast<u32*>(reinterpret_cast<uintptr_t>(dir_table) + this->dir_table_size); | ||
| 230 | const auto file_table = reinterpret_cast<RomFSFileEntry*>( | ||
| 231 | reinterpret_cast<uintptr_t>(file_hash_table) + this->file_hash_table_size); | ||
| 232 | |||
| 233 | /* Clear out hash tables. */ | ||
| 234 | for (u32 i = 0; i < dir_hash_table_entry_count; i++) | ||
| 235 | dir_hash_table[i] = ROMFS_ENTRY_EMPTY; | ||
| 236 | for (u32 i = 0; i < file_hash_table_entry_count; i++) | ||
| 237 | file_hash_table[i] = ROMFS_ENTRY_EMPTY; | ||
| 238 | |||
| 239 | out.clear(); | ||
| 240 | |||
| 241 | /* Determine file offsets. */ | ||
| 242 | u32 entry_offset = 0; | ||
| 243 | RomFSBuildFileContext* prev_file = nullptr; | ||
| 244 | for (const auto& it : this->files) { | ||
| 245 | cur_file = it.second; | ||
| 246 | this->file_partition_size = (this->file_partition_size + 0xFULL) & ~0xFULL; | ||
| 247 | cur_file->offset = this->file_partition_size; | ||
| 248 | this->file_partition_size += cur_file->size; | ||
| 249 | cur_file->entry_offset = entry_offset; | ||
| 250 | entry_offset += | ||
| 251 | sizeof(RomFSFileEntry) + ((cur_file->path_len - cur_file->cur_path_ofs + 3) & ~3); | ||
| 252 | prev_file = cur_file; | ||
| 253 | } | ||
| 254 | /* Assign deferred parent/sibling ownership. */ | ||
| 255 | for (auto it = this->files.rbegin(); it != this->files.rend(); it++) { | ||
| 256 | cur_file = it->second; | ||
| 257 | cur_file->sibling = cur_file->parent->file; | ||
| 258 | cur_file->parent->file = cur_file; | ||
| 259 | } | ||
| 260 | |||
| 261 | /* Determine directory offsets. */ | ||
| 262 | entry_offset = 0; | ||
| 263 | for (const auto& it : this->directories) { | ||
| 264 | cur_dir = it.second; | ||
| 265 | cur_dir->entry_offset = entry_offset; | ||
| 266 | entry_offset += | ||
| 267 | sizeof(RomFSDirectoryEntry) + ((cur_dir->path_len - cur_dir->cur_path_ofs + 3) & ~3); | ||
| 268 | } | ||
| 269 | /* Assign deferred parent/sibling ownership. */ | ||
| 270 | for (auto it = this->directories.rbegin(); it->second != this->root; it++) { | ||
| 271 | cur_dir = it->second; | ||
| 272 | cur_dir->sibling = cur_dir->parent->child; | ||
| 273 | cur_dir->parent->child = cur_dir; | ||
| 274 | } | ||
| 275 | |||
| 276 | /* Populate file tables. */ | ||
| 277 | for (const auto& it : this->files) { | ||
| 278 | cur_file = it.second; | ||
| 279 | RomFSFileEntry* cur_entry = romfs_get_fentry(file_table, cur_file->entry_offset); | ||
| 280 | |||
| 281 | cur_entry->parent = cur_file->parent->entry_offset; | ||
| 282 | cur_entry->sibling = | ||
| 283 | (cur_file->sibling == nullptr) ? ROMFS_ENTRY_EMPTY : cur_file->sibling->entry_offset; | ||
| 284 | cur_entry->offset = cur_file->offset; | ||
| 285 | cur_entry->size = cur_file->size; | ||
| 286 | |||
| 287 | const auto name_size = cur_file->path_len - cur_file->cur_path_ofs; | ||
| 288 | const auto hash = romfs_calc_path_hash(cur_file->parent->entry_offset, | ||
| 289 | reinterpret_cast<unsigned char*>(cur_file->path) + | ||
| 290 | cur_file->cur_path_ofs, | ||
| 291 | 0, name_size); | ||
| 292 | cur_entry->hash = file_hash_table[hash % file_hash_table_entry_count]; | ||
| 293 | file_hash_table[hash % file_hash_table_entry_count] = cur_file->entry_offset; | ||
| 294 | |||
| 295 | cur_entry->name_size = name_size; | ||
| 296 | memset(cur_entry->name, 0, (cur_entry->name_size + 3) & ~3); | ||
| 297 | memcpy(cur_entry->name, cur_file->path + cur_file->cur_path_ofs, name_size); | ||
| 298 | |||
| 299 | out.emplace(cur_file->offset + ROMFS_FILEPARTITION_OFS, cur_file->source); | ||
| 300 | } | ||
| 301 | |||
| 302 | /* Populate dir tables. */ | ||
| 303 | for (const auto& it : this->directories) { | ||
| 304 | cur_dir = it.second; | ||
| 305 | RomFSDirectoryEntry* cur_entry = romfs_get_direntry(dir_table, cur_dir->entry_offset); | ||
| 306 | cur_entry->parent = cur_dir == this->root ? 0 : cur_dir->parent->entry_offset; | ||
| 307 | cur_entry->sibling = | ||
| 308 | (cur_dir->sibling == nullptr) ? ROMFS_ENTRY_EMPTY : cur_dir->sibling->entry_offset; | ||
| 309 | cur_entry->child = | ||
| 310 | (cur_dir->child == nullptr) ? ROMFS_ENTRY_EMPTY : cur_dir->child->entry_offset; | ||
| 311 | cur_entry->file = | ||
| 312 | (cur_dir->file == nullptr) ? ROMFS_ENTRY_EMPTY : cur_dir->file->entry_offset; | ||
| 313 | |||
| 314 | u32 name_size = cur_dir->path_len - cur_dir->cur_path_ofs; | ||
| 315 | u32 hash = romfs_calc_path_hash( | ||
| 316 | cur_dir == this->root ? 0 : cur_dir->parent->entry_offset, | ||
| 317 | reinterpret_cast<unsigned char*>(cur_dir->path) + cur_dir->cur_path_ofs, 0, name_size); | ||
| 318 | cur_entry->hash = dir_hash_table[hash % dir_hash_table_entry_count]; | ||
| 319 | dir_hash_table[hash % dir_hash_table_entry_count] = cur_dir->entry_offset; | ||
| 320 | |||
| 321 | cur_entry->name_size = name_size; | ||
| 322 | memset(cur_entry->name, 0, (cur_entry->name_size + 3) & ~3); | ||
| 323 | memcpy(cur_entry->name, cur_dir->path + cur_dir->cur_path_ofs, name_size); | ||
| 324 | } | ||
| 325 | |||
| 326 | /* Delete directories. */ | ||
| 327 | for (const auto& it : this->directories) { | ||
| 328 | cur_dir = it.second; | ||
| 329 | delete cur_dir->path; | ||
| 330 | delete cur_dir; | ||
| 331 | } | ||
| 332 | this->root = nullptr; | ||
| 333 | this->directories.clear(); | ||
| 334 | |||
| 335 | /* Delete files. */ | ||
| 336 | for (const auto& it : this->files) { | ||
| 337 | cur_file = it.second; | ||
| 338 | delete cur_file->path; | ||
| 339 | delete cur_file; | ||
| 340 | } | ||
| 341 | this->files.clear(); | ||
| 342 | |||
| 343 | /* Set header fields. */ | ||
| 344 | header->header_size = sizeof(*header); | ||
| 345 | header->file_hash_table_size = this->file_hash_table_size; | ||
| 346 | header->file_table_size = this->file_table_size; | ||
| 347 | header->dir_hash_table_size = this->dir_hash_table_size; | ||
| 348 | header->dir_table_size = this->dir_table_size; | ||
| 349 | header->file_partition_ofs = ROMFS_FILEPARTITION_OFS; | ||
| 350 | header->dir_hash_table_ofs = | ||
| 351 | (header->file_partition_ofs + this->file_partition_size + 3ULL) & ~3ULL; | ||
| 352 | header->dir_table_ofs = header->dir_hash_table_ofs + header->dir_hash_table_size; | ||
| 353 | header->file_hash_table_ofs = header->dir_table_ofs + header->dir_table_size; | ||
| 354 | header->file_table_ofs = header->file_hash_table_ofs + header->file_hash_table_size; | ||
| 355 | |||
| 356 | std::vector<u8> header_data(sizeof(RomFSHeader)); | ||
| 357 | std::memcpy(header_data.data(), header, header_data.size()); | ||
| 358 | out.emplace(0, std::make_shared<VectorVfsFile>(header_data)); | ||
| 359 | |||
| 360 | std::vector<u8> meta_out(this->file_hash_table_size + this->file_table_size + | ||
| 361 | this->dir_hash_table_size + this->dir_table_size); | ||
| 362 | std::memcpy(meta_out.data(), metadata, meta_out.size()); | ||
| 363 | out.emplace(header->dir_hash_table_ofs, std::make_shared<VectorVfsFile>(meta_out)); | ||
| 364 | |||
| 365 | return out; | ||
| 366 | } | ||
| 367 | |||
| 368 | } // namespace FileSys | ||
diff --git a/src/core/file_sys/fsmitm_romfsbuild.hpp b/src/core/file_sys/fsmitm_romfsbuild.hpp new file mode 100644 index 000000000..b897aab21 --- /dev/null +++ b/src/core/file_sys/fsmitm_romfsbuild.hpp | |||
| @@ -0,0 +1,106 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (c) 2018 Atmosphère-NX | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify it | ||
| 5 | * under the terms and conditions of the GNU General Public License, | ||
| 6 | * version 2, as published by the Free Software Foundation. | ||
| 7 | * | ||
| 8 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
| 9 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
| 10 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
| 11 | * more details. | ||
| 12 | * | ||
| 13 | * You should have received a copy of the GNU General Public License | ||
| 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 15 | */ | ||
| 16 | |||
| 17 | /* | ||
| 18 | * Adapted by DarkLordZach for use/interaction with yuzu | ||
| 19 | * | ||
| 20 | * Modifications Copyright 2018 yuzu emulator team | ||
| 21 | * Licensed under GPLv2 or any later version | ||
| 22 | * Refer to the license.txt file included. | ||
| 23 | */ | ||
| 24 | |||
| 25 | #pragma once | ||
| 26 | #include <map> | ||
| 27 | #include <boost/detail/container_fwd.hpp> | ||
| 28 | #include "common/common_types.h" | ||
| 29 | #include "vfs.h" | ||
| 30 | |||
| 31 | namespace FileSys { | ||
| 32 | |||
| 33 | /* Used as comparator for std::map<char *, RomFSBuild*Context> */ | ||
| 34 | struct build_ctx_cmp { | ||
| 35 | bool operator()(const char* a, const char* b) const { | ||
| 36 | return strcmp(a, b) < 0; | ||
| 37 | } | ||
| 38 | }; | ||
| 39 | |||
| 40 | struct RomFSDirectoryEntry; | ||
| 41 | struct RomFSFileEntry; | ||
| 42 | struct RomFSBuildDirectoryContext; | ||
| 43 | struct RomFSBuildFileContext; | ||
| 44 | |||
| 45 | class RomFSBuildContext { | ||
| 46 | private: | ||
| 47 | VirtualDir base; | ||
| 48 | RomFSBuildDirectoryContext* root; | ||
| 49 | std::map<char*, RomFSBuildDirectoryContext*, build_ctx_cmp> directories; | ||
| 50 | std::map<char*, RomFSBuildFileContext*, build_ctx_cmp> files; | ||
| 51 | u64 num_dirs = 0; | ||
| 52 | u64 num_files = 0; | ||
| 53 | u64 dir_table_size = 0; | ||
| 54 | u64 file_table_size = 0; | ||
| 55 | u64 dir_hash_table_size = 0; | ||
| 56 | u64 file_hash_table_size = 0; | ||
| 57 | u64 file_partition_size = 0; | ||
| 58 | |||
| 59 | void VisitDirectory(VirtualDir filesys, RomFSBuildDirectoryContext* parent); | ||
| 60 | |||
| 61 | bool AddDirectory(RomFSBuildDirectoryContext* parent_dir_ctx, | ||
| 62 | RomFSBuildDirectoryContext* dir_ctx, | ||
| 63 | RomFSBuildDirectoryContext** out_dir_ctx); | ||
| 64 | bool AddFile(RomFSBuildDirectoryContext* parent_dir_ctx, RomFSBuildFileContext* file_ctx); | ||
| 65 | |||
| 66 | public: | ||
| 67 | explicit RomFSBuildContext(VirtualDir base); | ||
| 68 | |||
| 69 | /* This finalizes the context. */ | ||
| 70 | std::map<u64, VirtualFile> Build(); | ||
| 71 | }; | ||
| 72 | |||
| 73 | static inline RomFSDirectoryEntry* romfs_get_direntry(void* directories, uint32_t offset) { | ||
| 74 | return (RomFSDirectoryEntry*)((uintptr_t)directories + offset); | ||
| 75 | } | ||
| 76 | |||
| 77 | static inline RomFSFileEntry* romfs_get_fentry(void* files, uint32_t offset) { | ||
| 78 | return (RomFSFileEntry*)((uintptr_t)files + offset); | ||
| 79 | } | ||
| 80 | |||
| 81 | static inline uint32_t romfs_calc_path_hash(uint32_t parent, const unsigned char* path, | ||
| 82 | uint32_t start, size_t path_len) { | ||
| 83 | uint32_t hash = parent ^ 123456789; | ||
| 84 | for (uint32_t i = 0; i < path_len; i++) { | ||
| 85 | hash = (hash >> 5) | (hash << 27); | ||
| 86 | hash ^= path[start + i]; | ||
| 87 | } | ||
| 88 | |||
| 89 | return hash; | ||
| 90 | } | ||
| 91 | |||
| 92 | static inline uint32_t romfs_get_hash_table_count(uint32_t num_entries) { | ||
| 93 | if (num_entries < 3) { | ||
| 94 | return 3; | ||
| 95 | } else if (num_entries < 19) { | ||
| 96 | return num_entries | 1; | ||
| 97 | } | ||
| 98 | uint32_t count = num_entries; | ||
| 99 | while (count % 2 == 0 || count % 3 == 0 || count % 5 == 0 || count % 7 == 0 || | ||
| 100 | count % 11 == 0 || count % 13 == 0 || count % 17 == 0) { | ||
| 101 | count++; | ||
| 102 | } | ||
| 103 | return count; | ||
| 104 | } | ||
| 105 | |||
| 106 | } // namespace FileSys | ||