// Copyright 2020 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include #include #include #include #include "common/common_types.h" #include "common/swap.h" #include "core/file_sys/romfs_reader.h" namespace FileSys { struct RomFSHeader { struct Descriptor { u32_le offset; u32_le length; }; u32_le header_length; Descriptor directory_hash_table; Descriptor directory_metadata_table; Descriptor file_hash_table; Descriptor file_metadata_table; u32_le file_data_offset; }; static_assert(sizeof(RomFSHeader) == 0x28, "Size of RomFSHeader is not correct"); /** * LayeredFS implementation. This basically adds a layer to another RomFSReader. * * patch_path: Path for RomFS replacements. Files present in this path replace or create * corresponding files in RomFS. * patch_ext_path: Path for RomFS extensions. Files present in this path: * - When with an extension of ".stub", remove the corresponding file in the RomFS. * - When with an extension of ".ips" or ".bps", patch the file in the RomFS. */ class LayeredFS : public RomFSReader { public: explicit LayeredFS(std::shared_ptr romfs, std::string patch_path, std::string patch_ext_path); ~LayeredFS() override; std::size_t GetSize() const override; std::size_t ReadFile(std::size_t offset, std::size_t length, u8* buffer) override; private: struct File; struct Directory { std::string name; std::string path; // with trailing '/' std::vector> files; std::vector> directories; Directory* parent; }; std::string ReadName(u32 offset, u32 name_length); // Loads the current directory, then its siblings, and then its children. void LoadDirectory(Directory& current, u32 offset); // Load the file at offset, and then its siblings. void LoadFile(Directory& parent, u32 offset); // Load replace/create relocations void LoadRelocations(); // Load patch/remove relocations void LoadExtRelocations(); // Calculate the offset of a single directory add it to the map and list of directories void PrepareBuildDirectory(Directory& current); // Calculate the offset of a single file add it to the map and list of files void PrepareBuildFile(File& current); // Recursively generate a sequence of files and directories and their offsets for all // children of current. (The current directory itself is not handled.) void PrepareBuild(Directory& current); void BuildDirectories(); void BuildFiles(); void RebuildMetadata(); std::shared_ptr romfs; std::string patch_path; std::string patch_ext_path; RomFSHeader header; Directory root; std::unordered_map file_path_map; std::unordered_map directory_path_map; std::map data_offset_map; // assigned data offset -> file std::vector metadata; // Includes header, hash table and metadata // Used for rebuilding header std::vector directory_hash_table; std::vector file_hash_table; std::unordered_map directory_metadata_offset_map; // directory -> metadata offset std::vector directory_list; // sequence of directories to be written to metadata u64 current_directory_offset{}; // current directory metadata offset std::vector directory_metadata_table; // rebuilt directory metadata table std::unordered_map file_metadata_offset_map; // file -> metadata offset std::vector file_list; // sequence of files to be written to metadata u64 current_file_offset{}; // current file metadata offset std::vector file_metadata_table; // rebuilt file metadata table u64 current_data_offset{}; // current assigned data offset }; } // namespace FileSys